Statistics
| Revision:

svn-gvsig-desktop / tags / v1_0_2_Build_898 / libraries / libFMap / src / com / iver / cit / gvsig / fmap / edition / writers / shp / ShpWriter.java @ 10513

History | View | Annotate | Download (10.5 KB)

1
package com.iver.cit.gvsig.fmap.edition.writers.shp;
2

    
3
import java.awt.geom.Rectangle2D;
4
import java.io.File;
5
import java.io.IOException;
6
import java.io.RandomAccessFile;
7
import java.nio.channels.FileChannel;
8
import java.nio.channels.WritableByteChannel;
9
import java.nio.charset.Charset;
10
import java.sql.Types;
11

    
12
import com.iver.cit.gvsig.fmap.DriverException;
13
import com.iver.cit.gvsig.fmap.core.FShape;
14
import com.iver.cit.gvsig.fmap.core.IFeature;
15
import com.iver.cit.gvsig.fmap.core.IGeometry;
16
import com.iver.cit.gvsig.fmap.drivers.ILayerDefinition;
17
import com.iver.cit.gvsig.fmap.drivers.ITableDefinition;
18
import com.iver.cit.gvsig.fmap.drivers.shp.DbaseFileHeaderNIO;
19
import com.iver.cit.gvsig.fmap.drivers.shp.DbaseFileWriterNIO;
20
import com.iver.cit.gvsig.fmap.drivers.shp.write.SHPFileWrite;
21
import com.iver.cit.gvsig.fmap.drivers.shp.write.ShapefileException;
22
import com.iver.cit.gvsig.fmap.edition.EditionException;
23
import com.iver.cit.gvsig.fmap.edition.IRowEdited;
24
import com.iver.cit.gvsig.fmap.edition.ISpatialWriter;
25
import com.iver.cit.gvsig.fmap.edition.writers.AbstractWriter;
26
import com.iver.cit.gvsig.fmap.layers.FBitSet;
27
import com.iver.cit.gvsig.fmap.layers.FLayer;
28
import com.iver.cit.gvsig.fmap.layers.FLyrVect;
29
import com.iver.cit.gvsig.fmap.layers.SelectableDataSource;
30

    
31
public class ShpWriter extends AbstractWriter implements ISpatialWriter {
32
        private String shpPath;
33
        private String shxPath;
34
        private String dbfPath;
35

    
36
        private File shpFile;
37

    
38
        private SHPFileWrite shpWrite;
39
        private DbaseFileWriterNIO dbfWrite;
40

    
41
        private DbaseFileHeaderNIO myHeader;
42

    
43
        private int shapeType;
44
        private int numRows;
45
        private int fileSize;
46
        private Rectangle2D fullExtent;
47
        private Object[] record;
48

    
49
        // private FLyrVect lyrVect;
50
        private FBitSet selection = null;
51
        private boolean bWriteHeaders = true;
52
        private int gvSIG_geometryType;
53
        private int[] supportedGeometryTypes = {FShape.POINT,
54
                                                                                        FShape.LINE,
55
                                                                                        FShape.MULTIPOINT,
56
                                                                                        FShape.ARC,
57
                                                                                        FShape.CIRCLE,
58
                                                                                        FShape.POLYGON,
59
                                                                                        FShape.TEXT
60
                                                                                        };
61
        private Charset charset = Charset.forName("ISO-8859-1");
62

    
63
        public ShpWriter() {
64
                super();
65
                this.capabilities.setProperty("FieldNameMaxLength","10");
66
        }
67
        public void setFile(File f)
68
        {
69
                shpPath = f.getAbsolutePath();
70

    
71
                String strFichshx = f.getAbsolutePath().replaceAll("\\.shp", ".shx");
72
                shxPath = strFichshx.replaceAll("\\.SHP", ".SHX");
73

    
74
                String strFichDbf = f.getAbsolutePath().replaceAll("\\.shp", ".dbf");
75
                dbfPath = strFichDbf.replaceAll("\\.SHP", ".DBF");
76

    
77
                shpFile = f;
78
        }
79

    
80
        private WritableByteChannel getWriteChannel(String path)
81
                                throws IOException
82
        {
83
                WritableByteChannel channel;
84

    
85
                File f = new File(path);
86

    
87
                if (!f.exists()) {
88
                        System.out.println("Creando fichero " + f.getAbsolutePath());
89

    
90
                        if (!f.createNewFile()) {
91
                                System.err.print("Error al crear el fichero " +
92
                                        f.getAbsolutePath());
93
                                throw new IOException("Cannot create file " + f);
94
                        }
95
                }
96

    
97
                RandomAccessFile raf = new RandomAccessFile(f, "rw");
98
                channel = raf.getChannel();
99

    
100
                return channel;
101
        }
102

    
103
        /**
104
         * Util para crear un fichero .shp desde cero.
105
         * @param lyrDef
106
         * @throws IOException
107
         * @throws DriverException
108
         */
109
        /*public ShpWriter(File shpFile, LayerDefinition lyrDef) throws IOException, DriverException
110
        {
111
                myHeader = DbaseFileHeaderNIO.createDbaseHeader(lyrDef.getFieldsDesc());
112
                initialize(shpFile, lyrDef.getShapeType());
113
        }
114

115
        public ShpWriter(File shpFile, FLyrVect lyrVect) throws IOException, DriverException
116
        {
117
                SelectableDataSource sds = lyrVect.getRecordset();
118
                myHeader = DbaseFileHeaderNIO.createDbaseHeader(sds);
119

120
                initialize(shpFile, lyrVect.getShapeType());
121
        }
122
        */
123
        /**
124
         * Use this function first of all, when you need to prepare a writer
125
         * having a FLayer as model.
126
         * IMPORTANT: Call setFile before calling this function.
127
         * @param lyrVect
128
         * @throws IOException
129
         * @throws DriverException
130
         */
131
        public void initialize(FLayer layer) throws EditionException{
132
                if (layer instanceof FLyrVect)
133
                {
134
                        FLyrVect lyrVect = (FLyrVect) layer;
135
                        try {
136
                                SelectableDataSource sds = lyrVect.getRecordset();
137
                                myHeader = DbaseFileHeaderNIO.createDbaseHeader(sds);
138
                                initialize(shpFile, lyrVect.getShapeType());
139
                        } catch (IOException e) {
140
                                e.printStackTrace();
141
                                throw new EditionException(e);
142
                        } catch (DriverException e) {
143
                                e.printStackTrace();
144
                                throw new EditionException(e);
145
                        }
146
                }
147
                else
148
                {
149
                        throw new EditionException("No se puede usar una capa que no es vectorial como modelo para escribir un shp.");
150
                }
151
        }
152
        /**
153
         * Useful to create a layer from scratch
154
         * Call setFile before using this function
155
         * @param lyrDef
156
         * @throws EditionException
157
         */
158
        public void initialize(ITableDefinition lyrDef) throws EditionException
159
        {
160
                super.initialize(lyrDef);
161
                myHeader = DbaseFileHeaderNIO.createDbaseHeader(lyrDef.getFieldsDesc());
162
                try {
163
                        initialize(shpFile, ((ILayerDefinition)lyrDef).getShapeType());
164
                } catch (IOException e) {
165
                        e.printStackTrace();
166
                        throw new EditionException(e);
167
                }
168
        }
169

    
170

    
171
        private void initialize(File shpFile, int typeFShape) throws IOException //, FLyrVect lyrVect, FBitSet selection) throws IOException, DriverException
172
        {
173
                // this.lyrVect = lyrVect;
174
                // this.selection = selection;
175
                setFile(shpFile);
176

    
177

    
178
                shpWrite = new SHPFileWrite((FileChannel) getWriteChannel(shpPath),
179
                                (FileChannel) getWriteChannel(shxPath));
180
                shapeType = shpWrite.getShapeType(typeFShape);
181
                gvSIG_geometryType = typeFShape;
182
                setSupportedGeometryTypes();
183
        }
184

    
185
        /**
186
         *
187
         */
188
        private void setSupportedGeometryTypes() {
189
                switch (gvSIG_geometryType)
190
                {
191
                case FShape.POINT:
192
                        supportedGeometryTypes = new int[] {FShape.POINT};
193
                        break;
194
                case FShape.MULTIPOINT:
195
                        supportedGeometryTypes = new int[] {FShape.MULTIPOINT};
196
                        break;
197
                case FShape.LINE:
198
                        supportedGeometryTypes = new int[] {FShape.LINE, FShape.ELLIPSE,
199
                                                        FShape.ARC, FShape.CIRCLE, FShape.POLYGON};
200
                        break;
201
                case FShape.POLYGON:
202
                        supportedGeometryTypes = new int[] {FShape.ELLIPSE,
203
                                FShape.CIRCLE, FShape.POLYGON};
204
                        break;
205

    
206
                default:
207
                        supportedGeometryTypes = new int[] {};
208
                }
209
        }
210

    
211
        public void preProcess() throws EditionException {
212
                // Por ahora solo escribimos los primeros bytes
213
                // de las cabeceras. Luego en el postprocess los escribiremos
214
                // correctamente, con el fullExtent y el numero de
215
                // registros que tocan.
216
                if (selection == null)
217
                {
218

    
219
                        try {
220
                                if (bWriteHeaders)
221
                                {
222
                                        shpWrite.writeHeaders(new Rectangle2D.Double(),
223
                                                shapeType, 0, 0);
224

    
225
                                }
226
                                myHeader.setNumRecords(0);
227
                                dbfWrite = new DbaseFileWriterNIO(myHeader,
228
                                        (FileChannel) getWriteChannel(dbfPath));
229

    
230
                                dbfWrite.setCharset(charset);
231

    
232
                                record = new Object[myHeader.getNumFields()];
233
                                numRows = 0;
234
                                fullExtent = null;
235

    
236
                        } catch (IOException e) {
237
                                e.printStackTrace();
238
                                throw new EditionException(e);
239
                        }
240
                }
241

    
242

    
243
        }
244

    
245
        public void process(IRowEdited row) throws EditionException {
246

    
247
                if (row.getStatus() == IRowEdited.STATUS_DELETED) return;
248

    
249
                IFeature feat = (IFeature) row.getLinkedRow();
250

    
251
                try {
252
                        /* System.out.println("Intento escribir el registro " +
253
                                        numRows + " de la capa " + lyrVect.getName()); */
254
                        IGeometry theGeom = feat.getGeometry();
255
                        // Revisamos que podemos escribir esa entidad
256
                        // En un shpFile, podemos meter pol?gonos, pero que sean como
257
                        // lineas. En cambio, en uno de puntos solo se pueden meter puntos
258
                        if (canWriteGeometry(theGeom.getGeometryType()) || canWriteGeometry(gvSIG_geometryType))
259
                        {
260
                                for (int i=0; i < record.length; i++)
261
                                        record[i] = feat.getAttribute(i);
262

    
263
                                fileSize = shpWrite.writeIGeometry(theGeom);
264
                                Rectangle2D boundsShp = theGeom.getBounds2D();
265

    
266
                                if (fullExtent == null) {
267
                                        fullExtent = boundsShp;
268
                                } else {
269
                                        fullExtent.add(boundsShp);
270
                                }
271

    
272
                                dbfWrite.write(record);
273
                                numRows++;
274
                        }
275
                        else
276
                        {
277
                                System.out.println("No se ha escrito la geometr?a "
278
                                                + row.getIndex() + " geomType=" + theGeom.getGeometryType());
279
                        }
280

    
281
                } catch (IOException e) {
282
                        e.printStackTrace();
283
                        throw new EditionException(e);
284
                } catch (ShapefileException e) {
285
                        e.printStackTrace();
286
                        throw new EditionException(e);
287
                }
288

    
289
        }
290

    
291
        public void postProcess() throws EditionException {
292
                try {
293
                        myHeader.setNumRecords(numRows);
294
                        if (fullExtent == null)
295
                                fullExtent = new Rectangle2D.Double();
296
                        shpWrite.writeHeaders(fullExtent,
297
                                        shapeType, numRows, fileSize);
298

    
299
                        dbfWrite = new DbaseFileWriterNIO(myHeader,
300
                                        (FileChannel) getWriteChannel(dbfPath));
301
                } catch (IOException e) {
302
                        e.printStackTrace();
303
                        throw new EditionException(e);
304
                }
305

    
306

    
307
        }
308
        /**
309
         * Devuelve el path del fichero Shp.
310
         *
311
         * @author azabala
312
         * @return shp path
313
         */
314
        public String getShpPath(){
315
                //Lo necesito para que el ShpSchemaManager sepa
316
                //como "construir" el esquema del fichero SHP/DBF
317
                //adem?s del ShpLayerDefinition
318
                //TODO hacer que ShpWriter implemente ISchemaManager
319
                return this.shpPath;
320
        }
321

    
322
        public String getName() {
323
                return "Shape Writer";
324
        }
325
        public boolean canWriteGeometry(int gvSIGgeometryType) {
326
                /* switch (gvSIGgeometryType)
327
                {
328
                case FShape.POINT:
329
                        return true;
330
                case FShape.LINE:
331
                        return true;
332
                case FShape.POLYGON:
333
                        return true;
334
                case FShape.ARC:
335
                        return true; // Pero convirtiendo a segmentos peque?os
336
                case FShape.ELLIPSE:
337
                        return true; // Pero convirtiendo a segmentos peque?os
338
                case FShape.MULTIPOINT:
339
                        return true;
340
                case FShape.TEXT:
341
                        return false;
342
                } */
343
                for (int i=0; i < supportedGeometryTypes.length; i++)
344
                {
345
                        if (gvSIGgeometryType == supportedGeometryTypes[i] ||
346
                                gvSIGgeometryType == (supportedGeometryTypes[i] | FShape.Z))
347
                                return true;
348
                }
349
                return false;
350
        }
351

    
352
        public boolean canWriteAttribute(int sqlType) {
353
                switch (sqlType)
354
                {
355
                case Types.DOUBLE:
356
                case Types.FLOAT:
357
                case Types.INTEGER:
358
                case Types.BIGINT:
359
                        return true;
360
                case Types.DATE:
361
                        return true;
362
                case Types.BIT:
363
                case Types.BOOLEAN:
364
                        return true;
365
                case Types.VARCHAR:
366
                case Types.CHAR:
367
                case Types.LONGVARCHAR:
368
                        return true; // TODO: Revisar esto, porque no creo que admita campos muy grandes
369

    
370
                }
371

    
372
                return false;
373
        }
374

    
375
        /**
376
         * @param dontWriteHeaders The bDontWriteHeaders to set.
377
         */
378
        public void setWriteHeaders(boolean bWriteHeaders) {
379
                this.bWriteHeaders = bWriteHeaders;
380
        }
381

    
382
//        public void setFlatness(double flatness) {
383
//                shpWrite.setFlatness(flatness);
384
//
385
//        }
386

    
387
        public boolean canAlterTable() {
388
                return true;
389
        }
390

    
391
        public boolean canSaveEdits() {
392
                if (shpFile.canWrite())
393
                {
394
                        File auxShx = new File(shxPath);
395
                        if (auxShx.canWrite())
396
                        {
397
                                File auxDbf = new File(dbfPath);
398
                                if (auxDbf.canWrite())
399
                                        return true;
400
                        }
401
                }
402
                return false;
403
        }
404

    
405
        public void setCharsetForWriting(Charset charset) {
406
                this.charset = charset;
407
        }
408

    
409
        public Charset getCharsetForWriting() {
410
                return charset;
411
        }
412

    
413
}