Statistics
| Revision:

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

History | View | Annotate | Download (10.4 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 void setFile(File f)
64
        {
65
                shpPath = f.getAbsolutePath();
66

    
67
                String strFichshx = f.getAbsolutePath().replaceAll("\\.shp", ".shx");
68
                shxPath = strFichshx.replaceAll("\\.SHP", ".SHX");
69

    
70
                String strFichDbf = f.getAbsolutePath().replaceAll("\\.shp", ".dbf");
71
                dbfPath = strFichDbf.replaceAll("\\.SHP", ".DBF");
72

    
73
                shpFile = f;
74
        }
75

    
76
        private WritableByteChannel getWriteChannel(String path)
77
                                throws IOException
78
        {
79
                WritableByteChannel channel;
80

    
81
                File f = new File(path);
82

    
83
                if (!f.exists()) {
84
                        System.out.println("Creando fichero " + f.getAbsolutePath());
85

    
86
                        if (!f.createNewFile()) {
87
                                System.err.print("Error al crear el fichero " +
88
                                        f.getAbsolutePath());
89
                                throw new IOException("Cannot create file " + f);
90
                        }
91
                }
92

    
93
                RandomAccessFile raf = new RandomAccessFile(f, "rw");
94
                channel = raf.getChannel();
95

    
96
                return channel;
97
        }
98

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

111
        public ShpWriter(File shpFile, FLyrVect lyrVect) throws IOException, DriverException
112
        {
113
                SelectableDataSource sds = lyrVect.getRecordset();
114
                myHeader = DbaseFileHeaderNIO.createDbaseHeader(sds);
115

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

    
166

    
167
        private void initialize(File shpFile, int typeFShape) throws IOException //, FLyrVect lyrVect, FBitSet selection) throws IOException, DriverException
168
        {
169
                // this.lyrVect = lyrVect;
170
                // this.selection = selection;
171
                setFile(shpFile);
172

    
173

    
174
                shpWrite = new SHPFileWrite((FileChannel) getWriteChannel(shpPath),
175
                                (FileChannel) getWriteChannel(shxPath));
176
                shapeType = shpWrite.getShapeType(typeFShape);
177
                gvSIG_geometryType = typeFShape;
178
                setSupportedGeometryTypes();
179
        }
180

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

    
202
                default:
203
                        supportedGeometryTypes = new int[] {};
204
                }
205
        }
206

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

    
215
                        try {
216
                                if (bWriteHeaders)
217
                                {
218
                                        shpWrite.writeHeaders(new Rectangle2D.Double(),
219
                                                shapeType, 0, 0);
220

    
221
                                }
222
                                myHeader.setNumRecords(0);
223
                                dbfWrite = new DbaseFileWriterNIO(myHeader,
224
                                        (FileChannel) getWriteChannel(dbfPath));
225
                                
226
                                dbfWrite.setCharset(charset);
227

    
228
                                record = new Object[myHeader.getNumFields()];
229
                                numRows = 0;
230
                                fullExtent = null;
231

    
232
                        } catch (IOException e) {
233
                                e.printStackTrace();
234
                                throw new EditionException(e);
235
                        }
236
                }
237

    
238

    
239
        }
240

    
241
        public void process(IRowEdited row) throws EditionException {
242

    
243
                if (row.getStatus() == IRowEdited.STATUS_DELETED) return;
244

    
245
                IFeature feat = (IFeature) row.getLinkedRow();
246

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

    
259
                                fileSize = shpWrite.writeIGeometry(theGeom);
260
                                Rectangle2D boundsShp = theGeom.getBounds2D();
261

    
262
                                if (fullExtent == null) {
263
                                        fullExtent = boundsShp;
264
                                } else {
265
                                        fullExtent.add(boundsShp);
266
                                }
267

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

    
277
                } catch (IOException e) {
278
                        e.printStackTrace();
279
                        throw new EditionException(e);
280
                } catch (ShapefileException e) {
281
                        e.printStackTrace();
282
                        throw new EditionException(e);
283
                }
284

    
285
        }
286

    
287
        public void postProcess() throws EditionException {
288
                try {
289
                        myHeader.setNumRecords(numRows);
290
                        if (fullExtent == null)
291
                                fullExtent = new Rectangle2D.Double();
292
                        shpWrite.writeHeaders(fullExtent,
293
                                        shapeType, numRows, fileSize);
294

    
295
                        dbfWrite = new DbaseFileWriterNIO(myHeader,
296
                                        (FileChannel) getWriteChannel(dbfPath));
297
                } catch (IOException e) {
298
                        e.printStackTrace();
299
                        throw new EditionException(e);
300
                }
301

    
302

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

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

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

    
366
                }
367

    
368
                return false;
369
        }
370

    
371
        /**
372
         * @param dontWriteHeaders The bDontWriteHeaders to set.
373
         */
374
        public void setWriteHeaders(boolean bWriteHeaders) {
375
                this.bWriteHeaders = bWriteHeaders;
376
        }
377

    
378
//        public void setFlatness(double flatness) {
379
//                shpWrite.setFlatness(flatness);
380
//
381
//        }
382

    
383
        public boolean canAlterTable() {
384
                return true;
385
        }
386

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

    
405
        public Charset getCharsetForWriting() {
406
                return charset;
407
        }
408

    
409
}