Statistics
| Revision:

root / branches / FMap_piloto_CAD_Layout_version / libraries / libFMap / src / com / iver / cit / gvsig / fmap / edition / DefaultEditableFeatureSource.java @ 1821

History | View | Annotate | Download (17.3 KB)

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

    
3
import com.iver.cit.gvsig.fmap.core.IGeometry;
4
import com.iver.cit.gvsig.fmap.drivers.DriverIOException;
5
import com.iver.cit.gvsig.fmap.layers.FBitSet;
6

    
7
import com.vividsolutions.jts.geom.Envelope;
8
import com.vividsolutions.jts.index.quadtree.Quadtree;
9

    
10
import java.awt.Image;
11
import java.awt.geom.Rectangle2D;
12

    
13
import java.io.IOException;
14

    
15
import java.util.BitSet;
16
import java.util.HashMap;
17
import java.util.List;
18

    
19

    
20
/**
21
 * DOCUMENT ME!
22
 *
23
 * @author Vicente Caballero Navarro
24
 */
25
public class DefaultEditableFeatureSource implements EditableFeatureSource {
26
        /*
27
         * Fichero en el que se guardan las nuevas geometr?as, producto de adiciones
28
         * o de modificaciones
29
         */
30
        private ExpansionFile expansionFile;
31

    
32
        /*
33
         * Fuente de datos original que se est? editando
34
         */
35
        private OriginalFeatureAdapter ofa;
36

    
37
        /*
38
         * Geometr?as modificadas de la fuente de datos original
39
         */
40
        private BitSet delgeometries = new BitSet();
41

    
42
        /*
43
         * Establece una relaci?n entre los ?ndices de las geometr?as en el EditableFeatureSource
44
         * y los ?ndices en el fichero de expansi?n
45
         */
46
        protected HashMap relations = new HashMap();
47
        private int numAdd = 0;
48

    
49
        // ?ndice espacial
50
        private Quadtree index;
51
        private Image selectionImage;
52
        protected CommandRecord cr;
53
        protected FBitSet seleccion;
54

    
55
        /**
56
         * Flag que indica que hay que tomar las siguientes operaciones como una
57
         * operaci?n at?mica
58
         */
59
        protected boolean complex = false;
60
        protected CommandCollection commands = null;
61

    
62
        /**
63
         * Crea un nuevo AbstractEditableFeatureSource.
64
         *
65
         * @param ef DOCUMENT ME!
66
         * @param ofa DOCUMENT ME!
67
         * @param bitset DOCUMENT ME!
68
         */
69
        public DefaultEditableFeatureSource(ExpansionFile ef,
70
                OriginalFeatureAdapter ofa, FBitSet bitset) {
71
                expansionFile = ef;
72
                this.ofa = ofa;
73
                this.cr = new MemoryCommandRecord();
74
                seleccion = bitset;
75
        }
76

    
77
        /**
78
         * M?todo invocado cuando se comienza la edici?n, para poner en marcha las
79
         * estructuras de datos necesarias para la misma, notificar al servidor en
80
         * protocolos en los que sea necesario, ...
81
         *
82
         * @throws EditionException
83
         */
84
        public void startEdition() throws EditionException {
85
                if (ofa != null) {
86
                        ofa.startEdition();
87
                }
88

    
89
                try {
90
                        expansionFile.open();
91
                        index = new Quadtree();
92

    
93
                        for (int i = 0; i < getGeometryCount(); i++) {
94
                                IGeometry g = getGeometry(i);
95

    
96
                                if (g == null) {
97
                                        continue;
98
                                }
99

    
100
                                Rectangle2D r = g.getBounds2D();
101
                                Envelope e = new Envelope(r.getX(), r.getX() + r.getWidth(),
102
                                                r.getY(), r.getY() + r.getHeight());
103
                                index.insert(e, new Integer(i));
104
                        }
105
                } catch (DriverIOException e) {
106
                        throw new EditionException(e);
107
                } catch (IOException e) {
108
                        throw new EditionException(e);
109
                }
110

    
111
                System.err.println("Se han metido en el ?ndice " +
112
                        index.queryAll().size() + " geometr?as");
113
        }
114

    
115
        /**
116
         * Invocado cuando termina la edici?n. En funci?n de la clase concreta que
117
         * implemente este m?todo se generar? el fichero con los resultados de la
118
         * edici?n, se realizar? una transacci?n a la base de datos, etc.
119
         *
120
         * @throws EditionException
121
         */
122
        public void stopEdition() throws EditionException {
123
                ofa.stopEdition(this);
124

    
125
                try {
126
                        expansionFile.close();
127
                } catch (IOException e) {
128
                        throw new EditionException(e);
129
                }
130
        }
131

    
132
        /**
133
         * Cancela la edici?n cerrando el fichero de expansi?n
134
         *
135
         * @throws IOException Si se produce un error cerrando el fichero de
136
         *                    expansi?n
137
         */
138
        public void cancelEdition() throws IOException {
139
                expansionFile.close();
140
        }
141

    
142
        /**
143
         * Devuelve el n?mero de geometrias que hay actualmente en edici?n.
144
         *
145
         * @return N?mero de geometr?as.
146
         *
147
         * @throws DriverIOException
148
         */
149
        public int getGeometryCount() throws DriverIOException {
150
                if (ofa != null) {
151
                        return ofa.getGeometryCount() + numAdd; //expansionFile.getGeometryCount() - relations.size();
152
                }
153

    
154
                return numAdd;
155
        }
156

    
157
        /**
158
         * Si el ?ndice se corresponde a una geometria de las originales de la capa
159
         * en edici?n y no ha sido modificada ni eliminada devuelve la geometria
160
         * original. Si ha sido modificada debera de buscar en el fichero de
161
         * expansi?n y si ha sido eliminada debera devolver null
162
         *
163
         * @param index ?ndice de la geometr?a.
164
         *
165
         * @return Geometr?a.
166
         *
167
         * @throws IOException
168
         * @throws DriverIOException
169
         */
170
        public synchronized IGeometry getGeometry(int index)
171
                throws IOException, DriverIOException {
172
                Integer integer = new Integer(index);
173

    
174
                //Si no est? en el fichero de expansi?n
175
                if (!relations.containsKey(integer)) {
176
                        //Si ha sido eliminada
177
                        if (delgeometries.get(index)) {
178
                                return null;
179
                        } else {
180
                                return ofa.getGeometry(index);
181
                        }
182
                } else {
183
                        int num = ((Integer) relations.get(integer)).intValue();
184

    
185
                        return expansionFile.getGeometry(num);
186
                }
187
        }
188

    
189
        /**
190
         * A?ade una geometria al fichero de expansi?n y guarda la correspondencia
191
         * en una tabla asociada.
192
         *
193
         * @param g geometr?a a guardar.
194
         *
195
         * @throws DriverIOException
196
         * @throws IOException
197
         */
198
        public void addGeometry(IGeometry g) throws DriverIOException, IOException {
199
                int[] virtualIndex = doAddGeometry(g);
200

    
201
                if (complex) {
202
                        commands.add(new AddGeometryCommand(this, g, virtualIndex[1]));
203
                } else {
204
                        cr.pushCommand(new AddGeometryCommand(this, g, virtualIndex[1]));
205
                }
206
        }
207

    
208
        /**
209
         * Elimina una geometria. Si es una geometr?a original de la capa en
210
         * edici?n se marca como eliminada (haya sido modificada o no). Si es una
211
         * geometr?a a?adida posteriormente se invalida en el fichero de
212
         * expansi?n, para que una futura compactaci?n termine con ella.
213
         *
214
         * @param index ?ndice de la geometr?a.
215
         *
216
         * @throws DriverIOException
217
         * @throws IOException
218
         */
219
        public void removeGeometry(int index) throws DriverIOException, IOException {
220
                if (complex) {
221
                        commands.add(new RemoveGeometryCommand(this, index));
222
                } else {
223
                        cr.pushCommand(new RemoveGeometryCommand(this, index));
224
                }
225

    
226
                doRemoveGeometry(index);
227
        }
228

    
229
        /**
230
         * Si se intenta modificar una geometr?a original de la capa en edici?n se
231
         * a?ade al fichero de expansi?n y se registra la posici?n en la que se
232
         * a?adi?. Si se intenta modificar una geometria que se encuentra en el
233
         * fichero de expansi?n (por ser nueva o original pero modificada) se
234
         * invoca el m?todo modifyGeometry y se actualiza el ?ndice de la
235
         * geometria en el fichero.
236
         *
237
         * @param index DOCUMENT ME!
238
         * @param g DOCUMENT ME!
239
         *
240
         * @throws IOException
241
         * @throws DriverIOException
242
         */
243
        public void modifyGeometry(int index, IGeometry g)
244
                throws IOException, DriverIOException {
245
                int[] pos = doModifyGeometry(index, g);
246

    
247
                if (complex) {
248
                        commands.add(new ModifyGeometryCommand(this, index, pos[0], g));
249
                } else {
250
                        cr.pushCommand(new ModifyGeometryCommand(this, index, pos[0], g));
251
                }
252
        }
253

    
254
        /**
255
         * DOCUMENT ME!
256
         *
257
         * @return DOCUMENT ME!
258
         */
259
        public OriginalFeatureAdapter getOriginalFeatureAdapter() {
260
                return ofa;
261
        }
262

    
263
        /**
264
         * @see com.iver.cit.gvsig.fmap.edition.EditableFeatureSource#compact()
265
         */
266
        public void compact() {
267
                expansionFile.compact(relations);
268
        }
269

    
270
        /**
271
         * @see com.iver.cit.gvsig.fmap.edition.EditableFeatureSource#getGeometriesIndexes(com.vividsolutions.jts.geom.Envelope)
272
         */
273
        public int[] getGeometriesIndexes(Rectangle2D r) {
274
                Envelope e = new Envelope(r.getX(), r.getX() + r.getWidth(), r.getY(),
275
                                r.getY() + r.getHeight());
276
                List l = index.query(e);
277
                int[] indexes = new int[l.size()];
278

    
279
                for (int index = 0; index < l.size(); index++) {
280
                        Integer i = (Integer) l.get(index);
281
                        indexes[index] = i.intValue();
282
                }
283

    
284
                return indexes;
285
        }
286

    
287
        /**
288
         * @see com.iver.cit.gvsig.fmap.edition.EditableFeatureSource#setImage(java.awt.Image)
289
         */
290
        public void setImage(Image i) {
291
                selectionImage = i;
292
        }
293

    
294
        /**
295
         * @see com.iver.cit.gvsig.fmap.edition.EditableFeatureSource#getImage()
296
         */
297
        public Image getImage() {
298
                return selectionImage;
299
        }
300

    
301
        /**
302
         * Se elimina del final del fichero de expansi?n poniendo el puntero de
303
         * escritura apuntando al final de la pen?ltima geometr?a. Deber? quitar
304
         * la relaci?n del mapa de relaciones
305
         *
306
         * @param index ?ndice de la geometr?a que se a?adi?
307
         *
308
         * @throws DriverIOException
309
         * @throws IOException
310
         */
311
        public void undoAddGeometry(int index)
312
                throws DriverIOException, IOException {
313
                //doRemoveGeometry(index);
314
                IGeometry g = getGeometry(index);
315
                Rectangle2D r = g.getBounds2D();
316
                this.index.remove(new Envelope(r.getX(), r.getX() + r.getWidth(),
317
                                r.getY(), r.getY() + r.getHeight()), new Integer(index));
318

    
319
                expansionFile.deleteLastGeometry();
320
                relations.remove(new Integer(index));
321
                numAdd--;
322
        }
323

    
324
        /**
325
         * Se desmarca como invalidada en el fichero de expansion o como eliminada
326
         * en el fichero original
327
         *
328
         * @param index DOCUMENT ME!
329
         *
330
         * @throws IOException
331
         * @throws DriverIOException
332
         */
333
        public void undoRemoveGeometry(int index)
334
                throws IOException, DriverIOException {
335
                // Si la relaci?n 
336
                if (relations.containsKey(new Integer(index))) {
337
                        expansionFile.validateGeometry(((Integer) relations.get(
338
                                        new Integer(index))).intValue());
339
                } else {
340
                        delgeometries.set(index, false);
341
                }
342

    
343
                IGeometry g = null;
344
                g = getGeometry(index);
345

    
346
                Rectangle2D r = g.getBounds2D();
347
                this.index.insert(new Envelope(r.getX(), r.getX() + r.getWidth(),
348
                                r.getY(), r.getY() + r.getHeight()), new Integer(index));
349
        }
350

    
351
        /**
352
         * Actualiza en el mapa de ?ndices, la posici?n en la que estaba la
353
         * geometr?a antes de ser modificada. Se marca como v?lida, en caso de que
354
         * fuera una modificaci?n de una geometr?a que estuviese en el fichero de
355
         * expansi?n antes de ser modificada y se pone el puntero de escritura del
356
         * expansion file a justo despues de la penultima geometr?a
357
         *
358
         * @param geometryIndex ?ndice de la geometr?a que se quiere deshacer su
359
         *                   modificaci?n
360
         * @param previousExpansionFileIndex ?ndice que ten?a antes la geometr?a en
361
         *                   el expansionFile. Si vale -1 quiere decir que es una
362
         *                   modificaci?n de una geometr?a original y por tanto no hay que
363
         *                   actualizar el mapa de indices sino eliminar su entrada.
364
         *
365
         * @throws IOException
366
         * @throws DriverIOException
367
         */
368
        public void undoModifyGeometry(int geometryIndex,
369
                int previousExpansionFileIndex) throws IOException, DriverIOException {
370
                /*
371
                 * Si la acci?n de modificar se realiz? sobre una geometr?a original
372
                 */
373
                if (previousExpansionFileIndex == -1) {
374
                        //Se obtiene la geometr?a para actualizar el ?ndice
375
                        IGeometry g = getGeometry(geometryIndex);
376
                        Rectangle2D r = g.getBounds2D();
377

    
378
                        //Se elimina de las relaciones y del fichero de expansi?n
379
                        relations.remove(new Integer(geometryIndex));
380
                        expansionFile.deleteLastGeometry();
381

    
382
                        //Se actualizan los ?ndices
383
                        IGeometry gAnt = getGeometry(geometryIndex);
384
                        Rectangle2D rAnt = gAnt.getBounds2D();
385
                        this.index.remove(new Envelope(r.getX(), r.getX() + r.getWidth(),
386
                                        r.getY(), r.getY() + r.getHeight()),
387
                                new Integer(geometryIndex));
388
                        this.index.insert(new Envelope(rAnt.getX(),
389
                                        rAnt.getX() + rAnt.getWidth(), rAnt.getY(),
390
                                        rAnt.getY() + rAnt.getHeight()), new Integer(geometryIndex));
391
                } else {
392
                        //Se obtiene la geometr?a para actualizar el ?ndice
393
                        IGeometry g = null;
394
                        g = getGeometry(geometryIndex);
395

    
396
                        Rectangle2D r = g.getBounds2D();
397
                        this.index.remove(new Envelope(r.getX(), r.getX() + r.getWidth(),
398
                                        r.getY(), r.getY() + r.getHeight()),
399
                                new Integer(geometryIndex));
400

    
401
                        //Se actualiza la relaci?n de ?ndices
402
                        Integer integer = new Integer(geometryIndex);
403
                        relations.put(new Integer(geometryIndex),
404
                                new Integer(previousExpansionFileIndex));
405

    
406
                        //Se recupera la geometr?a
407
                        expansionFile.validateGeometry(previousExpansionFileIndex);
408

    
409
                        //Se actualizan los ?ndices
410
                        g = getGeometry(geometryIndex);
411
                        r = g.getBounds2D();
412
                        this.index.insert(new Envelope(r.getX(), r.getX() + r.getWidth(),
413
                                        r.getY(), r.getY() + r.getHeight()),
414
                                new Integer(geometryIndex));
415
                }
416
        }
417

    
418
        /**
419
         * A?ade una geometria al fichero de expansi?n y guarda la correspondencia
420
         * en la tabla relations.
421
         *
422
         * @param g geometr?a a guardar.
423
         *
424
         * @return DOCUMENT ME!
425
         *
426
         * @throws DriverIOException
427
         * @throws IOException
428
         */
429
        public int[] doAddGeometry(IGeometry g) throws DriverIOException, IOException {
430
                int virtualIndex = 0;
431

    
432
                //A?ade la geometr?a
433
                if (ofa != null) {
434
                        virtualIndex = ofa.getGeometryCount() + numAdd;
435
                } else {
436
                        virtualIndex = numAdd;
437
                }
438

    
439
                int pos = expansionFile.addGeometry(g);
440
                relations.put(new Integer(virtualIndex), new Integer(pos));
441
                numAdd++;
442

    
443
                //Actualiza el ?ndice espacial
444
                Rectangle2D r = g.getBounds2D();
445
                index.insert(new Envelope(r.getX(), r.getX() + r.getWidth(), r.getY(),
446
                                r.getY() + r.getHeight()), new Integer(virtualIndex));
447

    
448
                return new int[]{pos,virtualIndex};
449
        }
450

    
451
        /**
452
         * Elimina una geometria. Si es una geometr?a original de la capa en
453
         * edici?n se marca como eliminada (haya sido modificada o no). Si es una
454
         * geometr?a a?adida posteriormente se invalida en el fichero de
455
         * expansi?n, para que una futura compactaci?n termine con ella.
456
         *
457
         * @param index ?ndice de la geometr?a.
458
         *
459
         * @throws DriverIOException
460
         * @throws IOException
461
         */
462
        public void doRemoveGeometry(int index)
463
                throws DriverIOException, IOException {
464
                Integer integer = new Integer(index);
465

    
466
                IGeometry g = null;
467

    
468
                //Si la geometr?a no ha sido modificada
469
                if (!relations.containsKey(integer)) {
470
                        delgeometries.set(index, true);
471
                        g = ofa.getGeometry(index);
472
                } else {
473
                        int num = ((Integer) relations.get(integer)).intValue();
474
                        g = expansionFile.getGeometry(num);
475
                        expansionFile.invalidateGeometry(num);
476
                }
477

    
478
                //Se actualiza el ?ndice
479
                if (g != null) {
480
                        Rectangle2D r = g.getBounds2D();
481
                        this.index.remove(new Envelope(r.getX(), r.getX() + r.getWidth(),
482
                                        r.getY(), r.getY() + r.getHeight()), new Integer(index));
483
                }
484
        }
485

    
486
        /**
487
         * Si se intenta modificar una geometr?a original de la capa en edici?n se
488
         * a?ade al fichero de expansi?n y se registra la posici?n en la que se
489
         * a?adi?. Si se intenta modificar una geometria que se encuentra en el
490
         * fichero de expansi?n (por ser nueva o original pero modificada) se
491
         * invoca el m?todo modifyGeometry y se actualiza el ?ndice de la
492
         * geometria en el fichero.
493
         *
494
         * @param index DOCUMENT ME!
495
         * @param g DOCUMENT ME!
496
         *
497
         * @return vector de enteros en la posici?n 0= la posici?n anterior de la
498
         *                    geometr?a y en la posici?n 1= la posici?n actual de la
499
         *                    geometr?a
500
         *
501
         * @throws IOException
502
         * @throws DriverIOException
503
         */
504
        public int[] doModifyGeometry(int index, IGeometry g)
505
                throws IOException, DriverIOException {
506
                int num = -1;
507
                int pos = -1;
508
                Integer integer = new Integer(index);
509

    
510
                IGeometry gAnt = null;
511

    
512
                //Si la geometr?a no ha sido modificada
513
                if (!relations.containsKey(integer)) {
514
                        int expansionIndex = expansionFile.addGeometry(g);
515
                        relations.put(integer, new Integer(expansionIndex));
516

    
517
                        //Se actualiza el ?ndice espacial
518
                        gAnt = ofa.getGeometry(index);
519

    
520
                        Rectangle2D rAnt = gAnt.getBounds2D();
521
                        Rectangle2D r = g.getBounds2D();
522
                        this.index.remove(new Envelope(rAnt.getX(),
523
                                        rAnt.getX() + rAnt.getWidth(), rAnt.getY(),
524
                                        rAnt.getY() + rAnt.getHeight()), new Integer(index));
525
                        this.index.insert(new Envelope(r.getX(), r.getX() + r.getWidth(),
526
                                        r.getY(), r.getY() + r.getHeight()), new Integer(index));
527
                } else {
528
                        //Obtenemos el ?ndice en el fichero de expansi?n
529
                        num = ((Integer) relations.get(integer)).intValue();
530
                        pos = num;
531

    
532
                        //Obtenemos la geometr?a para actualiza el ?ndice espacialposteriormente
533
                        gAnt = expansionFile.getGeometry(num);
534

    
535
                        /*
536
                         * Se modifica la geometr?a y nos guardamos el ?ndice dentro del fichero
537
                         * de expansi?n en el que se encuentra la geometr?a modificada
538
                         */
539
                        num = expansionFile.modifyGeometry(num, g);
540

    
541
                        /*
542
                         * Actualiza la relaci?n del ?ndice de la geometr?a al ?ndice en el fichero
543
                         * de expansi?n.
544
                         */
545
                        relations.put(integer, new Integer(num));
546

    
547
                        //Se modifica el ?ndice espacial
548
                        Rectangle2D rAnt = gAnt.getBounds2D();
549
                        Rectangle2D r = g.getBounds2D();
550
                        this.index.remove(new Envelope(rAnt.getX(),
551
                                        rAnt.getX() + rAnt.getWidth(), rAnt.getY(),
552
                                        rAnt.getY() + rAnt.getHeight()), new Integer(index));
553
                        this.index.insert(new Envelope(r.getX(), r.getX() + r.getWidth(),
554
                                        r.getY(), r.getY() + r.getHeight()), new Integer(index));
555
                }
556

    
557
                return new int[]{pos,num};
558
        }
559

    
560
        /**
561
         * DOCUMENT ME!
562
         *
563
         * @throws DriverIOException
564
         * @throws IOException
565
         *
566
         * @see com.iver.cit.gvsig.fmap.edition.EditableFeatureSource#undo()
567
         */
568
        public void undo() throws DriverIOException, IOException {
569
                seleccion.clear();
570

    
571
                if (moreUndoCommands()) {
572
                        cr.undoCommand();
573
                }
574
        }
575

    
576
        /**
577
         * DOCUMENT ME!
578
         *
579
         * @throws DriverIOException
580
         * @throws IOException
581
         *
582
         * @see com.iver.cit.gvsig.fmap.edition.EditableFeatureSource#redo()
583
         */
584
        public void redo() throws DriverIOException, IOException {
585
                seleccion.clear();
586

    
587
                if (moreRedoCommands()) {
588
                        cr.redoCommand();
589
                }
590
        }
591

    
592
        /**
593
         * @see com.iver.cit.gvsig.fmap.edition.EditableFeatureSource#moreUndoCommands()
594
         */
595
        public boolean moreUndoCommands() {
596
                return cr.moreUndoCommands();
597
        }
598

    
599
        /**
600
         * @see com.iver.cit.gvsig.fmap.edition.EditableFeatureSource#moreRedoCommands()
601
         */
602
        public boolean moreRedoCommands() {
603
                return cr.moreRedoCommands();
604
        }
605

    
606
        /**
607
         * @see com.iver.cit.gvsig.fmap.edition.EditableFeatureSource#startComplexGeometry()
608
         */
609
        public void startComplexGeometry() {
610
                complex = true;
611
                commands = new CommandCollection();
612
        }
613

    
614
        /**
615
         * DOCUMENT ME!
616
         *
617
         * @throws IOException
618
         * @throws DriverIOException
619
         *
620
         * @see com.iver.cit.gvsig.fmap.edition.EditableFeatureSource#endComplexGeometry()
621
         */
622
        public void endComplexGeometry() throws IOException, DriverIOException {
623
                cr.pushCommand(commands);
624
                complex = false;
625
        }
626
}