Statistics
| Revision:

svn-gvsig-desktop / trunk / libraries / libFMap / src / com / iver / cit / gvsig / fmap / edition / writers / shp / ShpWriter.java @ 10037

History | View | Annotate | Download (10.6 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
import com.iver.utiles.xmlEntity.generate.Property;
31

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

    
37
        private File shpFile;
38

    
39
        private SHPFileWrite shpWrite;
40
        private DbaseFileWriterNIO dbfWrite;
41

    
42
        private DbaseFileHeaderNIO myHeader;
43

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

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

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

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

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

    
78
                shpFile = f;
79
        }
80

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

    
86
                File f = new File(path);
87

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

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

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

    
101
                return channel;
102
        }
103

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

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

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

    
171

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

    
178

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

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

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

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

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

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

    
231
                                dbfWrite.setCharset(charset);
232

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

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

    
243

    
244
        }
245

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

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

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

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

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

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

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

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

    
290
        }
291

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

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

    
307

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

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

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

    
371
                }
372

    
373
                return false;
374
        }
375

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

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

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

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

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

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

    
414
}