Statistics
| Revision:

svn-gvsig-desktop / trunk / org.gvsig.desktop / org.gvsig.desktop.compat.cdc / org.gvsig.fmap.mapcontext / org.gvsig.fmap.mapcontext.api / src / main / java / org / gvsig / fmap / mapcontext / layers / vectorial / FLyrVect.java @ 43020

History | View | Annotate | Download (42 KB)

1
/**
2
 * gvSIG. Desktop Geographic Information System.
3
 *
4
 * Copyright (C) 2007-2013 gvSIG Association.
5
 *
6
 * This program is free software; you can redistribute it and/or modify it under
7
 * the terms of the GNU General Public License as published by the Free Software
8
 * Foundation; either version 3 of the License, or (at your option) any later
9
 * version.
10
 *
11
 * This program is distributed in the hope that it will be useful, but WITHOUT
12
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
13
 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
14
 * details.
15
 *
16
 * You should have received a copy of the GNU General Public License along with
17
 * this program; if not, write to the Free Software Foundation, Inc., 51
18
 * Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19
 *
20
 * For any additional information, do not hesitate to contact us at info AT
21
 * gvsig.com, or visit our website www.gvsig.com.
22
 */
23
package org.gvsig.fmap.mapcontext.layers.vectorial;
24

    
25
import java.awt.Graphics2D;
26
import java.awt.Point;
27
import java.awt.geom.AffineTransform;
28
import java.awt.geom.Point2D;
29
import java.awt.image.BufferedImage;
30
import java.util.Iterator;
31
import java.util.Set;
32
import java.util.TreeSet;
33
import java.util.logging.Level;
34
import java.util.logging.Logger;
35

    
36
import org.cresques.cts.ICoordTrans;
37
import org.cresques.cts.IProjection;
38
import org.slf4j.LoggerFactory;
39

    
40
import org.gvsig.compat.print.PrintAttributes;
41
import org.gvsig.fmap.dal.DALLocator;
42
import org.gvsig.fmap.dal.DataStore;
43
import org.gvsig.fmap.dal.exception.DataException;
44
import org.gvsig.fmap.dal.exception.InitializeException;
45
import org.gvsig.fmap.dal.exception.ReadException;
46
import org.gvsig.fmap.dal.exception.ReadRuntimeException;
47
import org.gvsig.fmap.dal.feature.FeatureAttributeDescriptor;
48
import org.gvsig.fmap.dal.feature.FeatureQuery;
49
import org.gvsig.fmap.dal.feature.FeatureSet;
50
import org.gvsig.fmap.dal.feature.FeatureStore;
51
import org.gvsig.fmap.dal.feature.FeatureStoreNotification;
52
import org.gvsig.fmap.dal.feature.FeatureType;
53
import org.gvsig.fmap.dal.feature.exception.CreateGeometryException;
54
import org.gvsig.fmap.geom.Geometry;
55
import org.gvsig.fmap.geom.Geometry.SUBTYPES;
56
import org.gvsig.fmap.geom.Geometry.TYPES;
57
import org.gvsig.fmap.geom.GeometryLocator;
58
import org.gvsig.fmap.geom.GeometryManager;
59
import org.gvsig.fmap.geom.exception.CreateEnvelopeException;
60
import org.gvsig.fmap.geom.primitive.Circle;
61
import org.gvsig.fmap.geom.primitive.Envelope;
62
import org.gvsig.fmap.geom.type.GeometryType;
63
import org.gvsig.fmap.geom.type.GeometryTypeNotSupportedException;
64
import org.gvsig.fmap.geom.type.GeometryTypeNotValidException;
65
import org.gvsig.fmap.mapcontext.MapContextLocator;
66
import org.gvsig.fmap.mapcontext.MapContextManager;
67
import org.gvsig.fmap.mapcontext.ViewPort;
68
import org.gvsig.fmap.mapcontext.exceptions.LegendLayerException;
69
import org.gvsig.fmap.mapcontext.exceptions.LoadLayerException;
70
import org.gvsig.fmap.mapcontext.exceptions.ReloadLayerException;
71
import org.gvsig.fmap.mapcontext.exceptions.StartEditionLayerException;
72
import org.gvsig.fmap.mapcontext.layers.FLayer;
73
import org.gvsig.fmap.mapcontext.layers.FLyrDefault;
74
import org.gvsig.fmap.mapcontext.layers.LayerEvent;
75
import org.gvsig.fmap.mapcontext.layers.SpatialCache;
76
import org.gvsig.fmap.mapcontext.rendering.legend.ILegend;
77
import org.gvsig.fmap.mapcontext.rendering.legend.IVectorLegend;
78
import org.gvsig.fmap.mapcontext.rendering.legend.LegendException;
79
import org.gvsig.fmap.mapcontext.rendering.legend.events.FeatureDrawnNotification;
80
import org.gvsig.fmap.mapcontext.rendering.legend.events.LegendChangedEvent;
81
import org.gvsig.fmap.mapcontext.rendering.legend.events.LegendClearEvent;
82
import org.gvsig.fmap.mapcontext.rendering.legend.events.LegendContentsChangedListener;
83
import org.gvsig.fmap.mapcontext.rendering.legend.events.LegendEvent;
84
import org.gvsig.fmap.mapcontext.rendering.legend.events.SymbolLegendEvent;
85
import org.gvsig.fmap.mapcontext.rendering.legend.styling.ILabelingStrategy;
86
import org.gvsig.fmap.mapcontext.rendering.symbols.CartographicSupport;
87
import org.gvsig.metadata.exceptions.MetadataException;
88
import org.gvsig.tools.ToolsLocator;
89
import org.gvsig.tools.dynobject.DynObjectSet;
90
import org.gvsig.tools.dynobject.DynStruct;
91
import org.gvsig.tools.evaluator.Evaluator;
92
import org.gvsig.tools.exception.BaseException;
93
import org.gvsig.tools.exception.BaseRuntimeException;
94
import org.gvsig.tools.locator.LocatorException;
95
import org.gvsig.tools.observer.Observable;
96
import org.gvsig.tools.observer.Observer;
97
import org.gvsig.tools.persistence.PersistenceManager;
98
import org.gvsig.tools.persistence.PersistentState;
99
import org.gvsig.tools.persistence.exception.PersistenceException;
100
import org.gvsig.tools.task.Cancellable;
101
import org.gvsig.tools.util.Callable;
102

    
103
/**
104
 * Capa b?sica Vectorial.
105
 *
106
 */
107
public class FLyrVect extends FLyrDefault implements VectorLayer,
108
        LegendContentsChangedListener, Observer {
109

    
110
    final static private org.slf4j.Logger logger
111
            = LoggerFactory.getLogger(FLyrVect.class);
112
    private final GeometryManager geomManager
113
            = GeometryLocator.getGeometryManager();
114

    
115
    /**
116
     * Leyenda de la capa vectorial
117
     */
118
    private IVectorLegend legend;
119
    private int typeShape = -1;
120
    private FeatureStore featureStore = null;
121
    private SpatialCache spatialCache = new SpatialCache();
122

    
123
    /**
124
     * An implementation of gvSIG spatial index
125
     */
126
    // protected ISpatialIndex spatialIndex = null;
127
    private IVectorLegend loadLegend = null;
128

    
129
    private boolean isLabeled;
130
    protected ILabelingStrategy strategy;
131
//        private ReprojectDefaultGeometry reprojectTransform;
132
    private FeatureQuery baseQuery = null;
133

    
134
    public FLyrVect() {
135
        super();
136
    }
137

    
138
    public String getTocImageIcon() {
139
        if (this.isAvailable()) {
140
            return MapContextLocator.getMapContextManager().getIconLayer(this.getDataStore());
141
        } else {
142
            /*
143
             * data store can be be null,
144
             * for example, a layer not loaded from persistence
145
             */
146
            return "layer-icon-unavailable";
147
        }
148

    
149
    }
150

    
151
    /**
152
     * Devuelve el VectorialAdapater de la capa.
153
     *
154
     * @return VectorialAdapter.
155
     */
156
    public DataStore getDataStore() {
157
//        if (!this.isAvailable()) {
158
//            return null;
159
//        }
160
        return featureStore;
161
    }
162

    
163
    /**
164
     * Asigna el data-store a la capa. Esta operacion no se deneria poder hacer
165
     * desde fuera de la clase.
166
     *
167
     * @param dataStore
168
     * @throws LoadLayerException
169
     * @deprecated use {@link #bindToDataStore(DataStore)}
170
     */
171
    public void setDataStore(DataStore dataStore) throws LoadLayerException {
172
        bindToDataStore(dataStore);
173
    }
174

    
175
    /**
176
     * Enlaza la capa con el DataStore indicado.
177
     *
178
     * @param dataStore
179
     * @throws LoadLayerException
180
     */
181
    protected void bindToDataStore(DataStore dataStore) throws LoadLayerException {
182
        if (this.featureStore != null && this.featureStore != dataStore) {
183
            this.featureStore.deleteObserver(this);
184
        }
185

    
186
        featureStore = (FeatureStore) dataStore;
187

    
188
        MapContextManager mapContextManager
189
                = MapContextLocator.getMapContextManager();
190

    
191
        //Set the legend
192
        IVectorLegend legend
193
                = (IVectorLegend) mapContextManager.getLegend(dataStore);
194

    
195
        if (legend == null) {
196
            throw new LegendLayerException(this.getName());
197
        }
198

    
199
        this.setLegend(legend);
200

    
201
        //Set the labeling strategy
202
        ILabelingStrategy labeler
203
                = (ILabelingStrategy) mapContextManager.getLabelingStrategy(dataStore);
204

    
205
        if (labeler != null) {
206
            labeler.setLayer(this);
207
            this.setLabelingStrategy(labeler);
208
            this.setIsLabeled(true); // TODO: ac? no s'hauria de detectar si t?
209
            // etiquetes?????
210
        }
211

    
212
        this.delegate(dataStore);
213

    
214
        dataStore.addObserver(this);
215

    
216
        ToolsLocator.getDisposableManager().bind(dataStore);
217
    }
218

    
219
    public Envelope getFullEnvelope() throws ReadException {
220
        Envelope rAux;
221
        try {
222
            rAux = getFeatureStore().getEnvelope();
223
        } catch (BaseException e) {
224
            throw new ReadException(getName(), e);
225
        }
226

    
227
        // Esto es para cuando se crea una capa nueva con el fullExtent de ancho
228
        // y alto 0.
229
        if (rAux == null || rAux.isEmpty() || rAux.getMaximum(0) - rAux.getMinimum(0) == 0
230
                && rAux.getMaximum(1) - rAux.getMinimum(1) == 0) {
231
            try {
232
                rAux
233
                        = geomManager.createEnvelope(0, 0, 90, 90, SUBTYPES.GEOM2D);
234
            } catch (CreateEnvelopeException e) {
235
                logger.error("Error creating the envelope", e);
236
                e.printStackTrace();
237
            }
238
        }
239
        // Si existe reproyecci?n, reproyectar el extent
240
        ICoordTrans ct = getCoordTrans();
241
        if (ct != null) {
242
            boolean originalEnvelopeIsEmpty = rAux.isEmpty();
243
            rAux = rAux.convert(ct);
244
            if(!originalEnvelopeIsEmpty && rAux.isEmpty()){
245
                try {
246
                    this.setAvailable(false);
247
                    throw new EnvelopeCantBeInitializedException();
248
                } catch(EnvelopeCantBeInitializedException e){
249
                    this.addError(e);
250
                }
251
            }
252
        }
253
        return rAux;
254

    
255
    }
256

    
257
    public void setBaseQuery(FeatureQuery baseQuery) {
258
        this.baseQuery = baseQuery;
259
    }
260

    
261
    @Override
262
    public FeatureQuery getBaseQuery() {
263
        return this.baseQuery;
264
    }
265

    
266
    public void addBaseFilter(Evaluator filter) {
267
        if( this.baseQuery == null ) {
268
            this.baseQuery = this.getFeatureStore().createFeatureQuery();
269
        }
270
        this.baseQuery.addFilter(filter);
271
    }
272

    
273
    public void addBaseFilter(String filter) {
274
        try {
275
            this.addBaseFilter( DALLocator.getDataManager().createExpresion(filter));
276
        } catch (InitializeException ex) {
277
            throw new RuntimeException("Can't create filter with '"+filter+"'", ex);
278
        }
279
    }
280

    
281
    /**
282
     * Draws using IFeatureIterator. This method will replace the old draw(...)
283
     * one.
284
     *
285
     * @autor jaume dominguez faus - jaume.dominguez@iver.es
286
     * @param image
287
     * @param g
288
     * @param viewPort
289
     * @param cancel
290
     * @param scale
291
     * @throws ReadDriverException
292
     */
293
    public void draw(BufferedImage image,
294
            Graphics2D g,
295
            ViewPort viewPort,
296
            Cancellable cancel,
297
            double scale) throws ReadException {
298

    
299
        if (legend == null) {
300
            return;
301
        }
302

    
303
        if (!this.isWithinScale(scale)) {
304
            return;
305
        }
306
        if (cancel.isCanceled()) {
307
            return;
308
        }
309

    
310
        if (spatialCache.isEnabled()) {
311
            spatialCache.clearAll();
312
            legend.addDrawingObserver(this);
313
        }
314

    
315
        FeatureQuery featureQuery = createFeatureQuery();
316

    
317
        try {
318
            FeatureAttributeDescriptor featureAttributeDescriptor
319
                    = getFeatureStore().getDefaultFeatureType().getDefaultTimeAttribute();
320

    
321
            if ((viewPort.getTime() != null) && (featureAttributeDescriptor != null)) {
322
                IntersectsTimeEvaluator intersectsTimeEvaluator
323
                        = new IntersectsTimeEvaluator(viewPort.getTime(), featureAttributeDescriptor.getName());
324
                featureQuery.addFilter(intersectsTimeEvaluator);
325
            }
326
        } catch (DataException e1) {
327
            logger.error("Impossible to get the temporal filter", e1);
328
        }
329

    
330
        try {
331

    
332
            long tini = System.currentTimeMillis();
333

    
334
            legend.draw(image,
335
                    g,
336
                    viewPort,
337
                    cancel,
338
                    scale,
339
                    null,
340
                    getCoordTrans(),
341
                    getFeatureStore(),
342
                    featureQuery);
343

    
344
            logger.debug("Layer " + this.getName() + " drawn in "
345
                    + (System.currentTimeMillis() - tini) + " milliseconds.");
346

    
347
        } catch (LegendException e) {
348
            this.setAvailable(false);
349
            this.setError(e);
350
            throw new ReadException(getName(), e);
351
        } finally {
352
            if (spatialCache.isEnabled()) {
353
                legend.deleteDrawingObserver(this);
354
            }
355
        }
356
    }
357

    
358
    public void print(Graphics2D g,
359
            ViewPort viewPort,
360
            Cancellable cancel,
361
            double scale,
362
            PrintAttributes properties) throws ReadException {
363
        if (!this.isWithinScale(scale)) {
364
            return;
365
        }
366
        if (cancel.isCanceled()) {
367
            return;
368
        }
369
        FeatureQuery featureQuery = createFeatureQuery();
370

    
371
        try {
372
            legend.print(g,
373
                    viewPort,
374
                    cancel,
375
                    scale,
376
                    null,
377
                    getCoordTrans(),
378
                    getFeatureStore(),
379
                    featureQuery,
380
                    properties);
381

    
382
        } catch (LegendException e) {
383
            this.setVisible(false);
384
            this.setActive(false);
385
            throw new ReadException(getName(), e);
386
        }
387
    }
388

    
389
    public void setLegend(IVectorLegend legend) throws LegendLayerException {
390
        if (this.legend == legend) {
391
            return;
392
        }
393
        if (this.legend != null && this.legend.equals(legend)) {
394
            return;
395
        }
396
        IVectorLegend oldLegend = this.legend;
397
        this.legend = legend;
398
        if (oldLegend != null) {
399
            oldLegend.removeLegendListener(this);
400
            oldLegend.deleteDrawingObserver(this);
401
        }
402
        if (legend != null) {
403
            this.legend.addDrawingObserver(this);
404
            this.legend.addLegendListener(this);
405
        }
406
        LegendChangedEvent e = LegendChangedEvent.createLegendChangedEvent(oldLegend, this.legend);
407
        e.setLayer(this);
408
        updateDrawVersion();
409
        callLegendChanged(e);
410
    }
411

    
412
    /**
413
     * Devuelve la Leyenda de la capa.
414
     *
415
     * @return Leyenda.
416
     */
417
    public ILegend getLegend() {
418
        return legend;
419
    }
420

    
421
    public int getShapeType() throws ReadException {
422
        if (typeShape == -1) {
423
            FeatureType featureType = null;
424
            try {
425
                if (getDataStore() != null) {
426
                    featureType
427
                            = (((FeatureStore) getDataStore()).getDefaultFeatureType());
428
                }
429
            } catch (DataException e) {
430
                throw new ReadException(getName(), e);
431
            }
432
            if (featureType != null) {
433
                int indexGeom = featureType.getDefaultGeometryAttributeIndex();
434
                typeShape
435
                        = featureType.getAttributeDescriptor(indexGeom).getGeometryType();
436
            }
437
        }
438
        return typeShape;
439
    }
440

    
441
    /**
442
     * Returns the layer's geometry type
443
     *
444
     * @return the geometry type
445
     *
446
     * @throws ReadException if there is an error getting the geometry type
447
     */
448
    public GeometryType getGeometryType() throws ReadException {
449
        FeatureType featureType = null;
450
        try {
451
            if (getDataStore() != null) {
452
                featureType
453
                        = (((FeatureStore) getDataStore()).getDefaultFeatureType());
454
            }
455
        } catch (DataException e) {
456
            throw new ReadException(getName(), e);
457
        }
458
        return featureType == null ? null : featureType
459
                .getDefaultGeometryAttribute().getGeomType();
460
    }
461

    
462
    public void saveToState(PersistentState state) throws PersistenceException {
463

    
464
        FeatureStore featureStore = null;
465

    
466
        if (!this.isAvailable()) {
467
            logger.info("The '" + this.getName() + "' layer is not available, it will persist not.");
468
            return;
469
        }
470

    
471
        try {
472
            super.saveToState(state);
473

    
474
            if (getLegend() != null) {
475
                state.set("legend", getLegend());
476
            }
477

    
478
            featureStore = getFeatureStore();
479

    
480
            if (featureStore != null) {
481
                state.set("featureStore", featureStore);
482
            }
483

    
484
            state.set("isLabeled", isLabeled);
485

    
486
            if (strategy != null) {
487
                state.set("labelingStrategy", strategy);
488
            }
489

    
490
            if (getLinkProperties() != null) {
491
                state.set("linkProperties", getLinkProperties());
492
            }
493

    
494
            state.set("typeShape", typeShape);
495
        } catch (PersistenceException ex) {
496
            logger.warn("Can't persist to state the layer '" + this.getName() + "'.", ex);
497
            throw ex;
498
        } catch (RuntimeException ex) {
499
            logger.warn("Can't persist to state the layer '" + this.getName() + "'.", ex);
500
            throw ex;
501
        }
502

    
503
    }
504

    
505
    public void loadFromState(PersistentState state) throws PersistenceException {
506

    
507
        DataStore store = null;
508
        IVectorLegend vectorLegend = null;
509
        ILabelingStrategy labelingStrategy = null;
510
        Boolean isLabeled = Boolean.FALSE;
511

    
512
        try {
513
            super.loadFromState(state);
514
            store = (DataStore) state.get("featureStore");
515

    
516
            try {
517
                this.bindToDataStore(store);
518
            } catch (LoadLayerException e) {
519
                throw new PersistenceException("Can't bind layer '" + this.getName() + "' to store '" + store.getFullName() + "'.", e);
520
            }
521

    
522
            vectorLegend = (IVectorLegend) state.get("legend");
523

    
524
            try {
525
                this.setLegend(vectorLegend);
526
            } catch (LegendLayerException e) {
527
                throw new PersistenceException("Can't set vector legend to the layer.", e);
528
            }
529

    
530
            try {
531
                isLabeled = (Boolean) state.get("isLabeled");
532
                if (isLabeled.booleanValue()) {
533
                    labelingStrategy = (ILabelingStrategy) state.get("labelingStrategy");
534
                }
535
            } catch (Exception ex) {
536
                throw new PersistenceException("Can't load labeling strategi from persistent state.",
537
                        ex);
538
            }
539

    
540
            if (isLabeled.booleanValue()) {
541
                this.setIsLabeled(true);
542
                this.setLabelingStrategy(labelingStrategy);
543
            } else {
544
                this.setIsLabeled(false);
545
                this.setLabelingStrategy(null);
546
            }
547

    
548
            typeShape = state.getInt("typeShape");
549

    
550
        } catch (Throwable e) {
551
            String storeName = (store == null) ? "unknow" : store.getFullName();
552
            logger.warn("can't load layer '" + this.getName() + "' (store=" + storeName + ") from persisted state.", e);
553
            this.setAvailable(false);
554
            return;
555
        }
556

    
557
    }
558

    
559
    /**
560
     * Sobreimplementaci?n del m?todo toString para que las bases de datos
561
     * identifiquen la capa.
562
     *
563
     * @return DOCUMENT ME!
564
     */
565
    public String toString() {
566
        /*
567
         * Se usa internamente para que la parte de datos identifique de forma
568
         * un?voca las tablas
569
         */
570
        String ret = super.toString();
571

    
572
        return ret ; //"layer" + ret.substring(ret.indexOf('@') + 1);
573
    }
574

    
575
    public boolean isEditing() {
576
        FeatureStore fs = getFeatureStore();
577
        if (fs == null) {
578
            /*
579
             * This happens when layer is not available, for example,
580
             * it was not possible to load from persistence
581
             */
582
            return false;
583
        } else {
584
            return fs.isEditing();
585
        }
586
    }
587

    
588
    public void setEditing(boolean b) throws StartEditionLayerException {
589

    
590
        try {
591
            throw new RuntimeException();
592
        } catch (Throwable th) {
593
            logger.info("This method is deprecated. ", th);
594
        }
595

    
596
        if (b == super.isEditing()) {
597
            return;
598
        }
599

    
600
        super.setEditing(b);
601
        FeatureStore fs = getFeatureStore();
602
        if (b) {
603
            try {
604
                fs.edit();
605
            } catch (DataException e) {
606
                throw new StartEditionLayerException(getName(), e);
607
            }
608
        }
609
        setSpatialCacheEnabled(b);
610
        callEditionChanged(LayerEvent.createEditionChangedEvent(this, "edition"));
611
    }
612

    
613
    /**
614
     * @deprecated Use {@link #getSpatialCache()}
615
     */
616
    public void clearSpatialCache() {
617
        spatialCache.clearAll();
618
    }
619

    
620
    /**
621
     * @deprecated Use {@link #getSpatialCache()}
622
     */
623
    public boolean isSpatialCacheEnabled() {
624
        return spatialCache.isEnabled();
625
    }
626

    
627
    /**
628
     * @deprecated Use {@link #getSpatialCache()}
629
     */
630
    public void setSpatialCacheEnabled(boolean spatialCacheEnabled) {
631
        spatialCache.setEnabled(spatialCacheEnabled);
632
    }
633

    
634
    public SpatialCache getSpatialCache() {
635
        return spatialCache;
636
    }
637

    
638
    /**
639
     * Siempre es un numero mayor de 1000
640
     *
641
     * @param maxFeatures
642
     */
643
    public void setMaxFeaturesInEditionCache(int maxFeatures) {
644
        if (maxFeatures > spatialCache.getMaxFeatures()) {
645
            spatialCache.setMaxFeatures(maxFeatures);
646
        }
647

    
648
    }
649

    
650
    /**
651
     * This method returns a boolean that is used by the FPopMenu to make
652
     * visible the properties menu or not. It is visible by default, and if a
653
     * later don't have to show this menu only has to override this method.
654
     *
655
     * @return If the properties menu is visible (or not)
656
     */
657
    public boolean isPropertiesMenuVisible() {
658
        return true;
659
    }
660

    
661
    public void reload() throws ReloadLayerException {
662
        super.reload();
663
        try {
664
            getFeatureStore().refresh();
665
        } catch (Exception e) {
666
            throw new ReloadLayerException(getName(), e);
667
        }
668
    }
669

    
670
    protected void setLoadSelection(Object xml) {
671
        // this.loadSelection = xml;
672
    }
673

    
674
    protected void setLoadLegend(IVectorLegend legend) {
675
        this.loadLegend = legend;
676
    }
677

    
678
    protected void putLoadSelection() {
679
        // if (this.loadSelection == null) return;
680
        // try {
681
        // this.getRecordset().getSelectionSupport().setXMLEntity(this.loadSelection);
682
        // } catch (ReadDriverException e) {
683
        // throw new XMLException(e);
684
        // }
685
        // this.loadSelection = null;
686

    
687
    }
688

    
689
    protected void putLoadLegend() throws LegendLayerException {
690
        if (this.loadLegend == null) {
691
            return;
692
        }
693
        this.setLegend(this.loadLegend);
694
        this.loadLegend = null;
695
    }
696

    
697
    protected void cleanLoadOptions() {
698
        this.loadLegend = null;
699
    }
700

    
701
    public boolean isWritable() {
702
        return getFeatureStore().allowWrite();
703
    }
704

    
705
    public FLayer cloneLayer() throws Exception {
706
        FLyrVect clonedLayer = new FLyrVect();
707
        clonedLayer.bindToDataStore(getDataStore());
708
        // if (isJoined()) {
709
        // clonedLayer.setIsJoined(true);
710
        // }
711
        clonedLayer.setVisible(isVisible());
712
        // clonedLayer.setISpatialIndex(getISpatialIndex());
713
        clonedLayer.setName(getName());
714
        clonedLayer.setCoordTrans(getCoordTrans());
715

    
716
        clonedLayer.setLegend((IVectorLegend) getLegend().cloneLegend());
717

    
718
        clonedLayer.setIsLabeled(isLabeled());
719
        ILabelingStrategy labelingStrategy = getLabelingStrategy();
720
        if (labelingStrategy != null) {
721
            clonedLayer.setLabelingStrategy(labelingStrategy);
722
        }
723

    
724
        return clonedLayer;
725
    }
726

    
727
    protected boolean isOnePoint(AffineTransform graphicsTransform,
728
            ViewPort viewPort,
729
            double dpi,
730
            CartographicSupport csSym,
731
            Geometry geom,
732
            int[] xyCoords) {
733
        return isOnePoint(graphicsTransform, viewPort, geom, xyCoords)
734
                && csSym.getCartographicSize(viewPort, dpi, geom) <= 1;
735
    }
736

    
737
    private boolean isOnePoint(AffineTransform graphicsTransform,
738
            ViewPort viewPort,
739
            Geometry geom,
740
            int[] xyCoords) {
741
        boolean onePoint = false;
742
        int type = geom.getType();
743
        if (type == Geometry.TYPES.NULL) {
744
            return false;
745
        }
746
        if (type != Geometry.TYPES.POINT && type != Geometry.TYPES.MULTIPOINT) {
747

    
748
            Envelope geomBounds = geom.getEnvelope();
749

    
750
            // ICoordTrans ct = getCoordTrans();
751
            // Se supone que la geometria ya esta reproyectada
752
            // if (ct!=null) {
753
            // // geomBounds = ct.getInverted().convert(geomBounds);
754
            // geomBounds = geomBounds.convert(ct);
755
            // }
756
            double dist1Pixel = viewPort.getDist1pixel();
757

    
758
            onePoint
759
                    = (geomBounds.getLength(0) <= dist1Pixel && geomBounds.getLength(1) <= dist1Pixel);
760

    
761
            if (onePoint) {
762
                // avoid out of range exceptions
763
                org.gvsig.fmap.geom.primitive.Point p;
764
                try {
765
                    p
766
                            = geomManager.createPoint(geomBounds.getMinimum(0),
767
                                    geomBounds.getMinimum(1),
768
                                    SUBTYPES.GEOM2D);
769
                    p.transform(viewPort.getAffineTransform());
770
                    p.transform(graphicsTransform);
771
                    xyCoords[0] = (int) p.getX();
772
                    xyCoords[1] = (int) p.getY();
773
                } catch (org.gvsig.fmap.geom.exception.CreateGeometryException e) {
774
                    logger.error("Error creating a point", e);
775
                }
776

    
777
            }
778

    
779
        }
780
        return onePoint;
781
    }
782

    
783
    public boolean isLabeled() {
784
        return isLabeled;
785
    }
786

    
787
    public void setIsLabeled(boolean isLabeled) {
788
        this.isLabeled = isLabeled;
789
    }
790

    
791
    public ILabelingStrategy getLabelingStrategy() {
792
        return strategy;
793
    }
794

    
795
    public void setLabelingStrategy(ILabelingStrategy strategy) {
796
        this.strategy = strategy;
797
        if (strategy == null) {
798
            return;
799
        }
800
        strategy.setLayer(this);
801
        updateDrawVersion();
802
    }
803

    
804
    public void drawLabels(BufferedImage image,
805
            Graphics2D g,
806
            ViewPort viewPort,
807
            Cancellable cancel,
808
            double scale,
809
            double dpi) throws ReadException {
810
        if (strategy != null && isWithinScale(scale)) {
811
            strategy.draw(image, g, scale, viewPort, cancel, dpi);
812
        }
813
    }
814

    
815
    public void printLabels(Graphics2D g,
816
            ViewPort viewPort,
817
            Cancellable cancel,
818
            double scale,
819
            PrintAttributes properties) throws ReadException {
820
        if (strategy != null) {
821
            strategy.print(g, scale, viewPort, cancel, properties);
822
        }
823
    }
824

    
825
    /**
826
     * Return true, because a Vectorial Layer supports HyperLink
827
     *
828
     * @deprecated the hiperlink functionaliti is out the layer now
829
     */
830
    public boolean allowLinks() {
831
        return false;
832
    }
833

    
834
    public void load() throws LoadLayerException {
835
        super.load();
836
    }
837

    
838
    public FeatureStore getFeatureStore() {
839
        return (FeatureStore) getDataStore();
840
    }
841

    
842
    public FeatureQuery createFeatureQuery() {
843
        if( this.baseQuery==null ) {
844
            return this.getFeatureStore().createFeatureQuery();
845
        }
846
        try {
847
            return (FeatureQuery) baseQuery.clone();
848
        } catch (CloneNotSupportedException ex) {
849
            throw new RuntimeException(ex);
850
        }
851
    }
852

    
853
    /**
854
     * @deprecated use instead
855
     * {@link #queryByPoint(org.gvsig.fmap.geom.primitive.Point, double, FeatureType)}
856
     */
857
    public FeatureSet queryByPoint(Point2D mapPoint,
858
            double tol,
859
            FeatureType featureType) throws DataException {
860
        logger.warn("Deprecated use of queryByPoint.");
861
        GeometryManager manager = GeometryLocator.getGeometryManager();
862
        org.gvsig.fmap.geom.primitive.Point center;
863
        try {
864
            center
865
                    = (org.gvsig.fmap.geom.primitive.Point) manager.create(TYPES.POINT,
866
                            SUBTYPES.GEOM2D);
867
            center.setX(mapPoint.getX());
868
            center.setY(mapPoint.getY());
869
            Circle circle
870
                    = (Circle) manager.create(TYPES.CIRCLE, SUBTYPES.GEOM2D);
871
            circle.setPoints(center, tol);
872
            return queryByGeometry(circle, featureType);
873
        } catch (org.gvsig.fmap.geom.exception.CreateGeometryException e) {
874
            throw new CreateGeometryException(TYPES.CIRCLE, SUBTYPES.GEOM2D, e);
875
        }
876
    }
877

    
878
    public FeatureSet queryByPoint(org.gvsig.fmap.geom.primitive.Point point,
879
            double tol,
880
            FeatureType featureType) throws DataException {
881
        GeometryManager manager = GeometryLocator.getGeometryManager();
882
        try {
883
            Circle circle
884
                    = (Circle) manager.create(TYPES.CIRCLE, SUBTYPES.GEOM2D);
885
            circle.setPoints(point, tol);
886
            return queryByGeometry(circle, featureType);
887
        } catch (org.gvsig.fmap.geom.exception.CreateGeometryException e) {
888
            throw new CreateGeometryException(TYPES.CIRCLE, SUBTYPES.GEOM2D, e);
889
        }
890
    }
891

    
892
    /**
893
     * Input geom must be in the CRS of the view.
894
     *
895
     * @param geom
896
     * @param featureType
897
     * @return
898
     * @throws DataException
899
     */
900
    public FeatureSet queryByGeometry(Geometry geom, FeatureType featureType) throws DataException {
901
        FeatureQuery featureQuery = createFeatureQuery();
902
        featureQuery.setFeatureType(featureType);
903

    
904
        Geometry query_geo = this.transformToSourceCRS(geom, true);
905
        IProjection query_proj = getMapContext().getProjection();
906
        if (this.getCoordTrans() != null) {
907
            query_proj = this.getCoordTrans().getPOrig();
908
        }
909
        Evaluator iee = SpatialEvaluatorsFactory.getInstance().intersects(
910
            query_geo,
911
            query_proj,
912
            featureStore
913
        );
914
        featureQuery.setFilter(iee);
915
        featureQuery.setAttributeNames(null);
916
        return getFeatureStore().getFeatureSet(featureQuery);
917

    
918
    }
919

    
920
    /**
921
     * It return the {@link FeatureSet} that intersects with the envelope.
922
     *
923
     * @param envelope envelope that defines the area for the query.
924
     * @param featureType only the features with this feature type are used in
925
     * the query.
926
     * @return the set of features that intersect with the envelope.
927
     * @throws DataException
928
     */
929
    public FeatureSet queryByEnvelope(Envelope envelope, FeatureType featureType) throws DataException {
930
        return queryByEnvelope(envelope, featureType, null);
931
    }
932

    
933
    /**
934
     * It return the {@link FeatureSet} that intersects with the envelope.
935
     *
936
     * @param envelope envelope that defines the area for the query in viewport
937
     * CRS
938
     * @param featureType only the features with this feature type are used in
939
     * the query.
940
     * @param names the feature attributes that have to be checked.
941
     * @return the set of features that intersect with the envelope.
942
     * @throws DataException
943
     */
944
    public FeatureSet queryByEnvelope(Envelope envelope,
945
            FeatureType featureType,
946
            String[] names) throws DataException {
947
        FeatureQuery featureQuery = createFeatureQuery();
948
        if (names == null) {
949
            featureQuery.setFeatureType(featureType);
950
        } else {
951
            featureQuery.setAttributeNames(names);
952
            featureQuery.setFeatureTypeId(featureType.getId());
953
        }
954

    
955
        Envelope query_env = fromViewPortCRSToSourceCRS(this, envelope);
956
        IProjection query_proj = getMapContext().getProjection();
957
        if (this.getCoordTrans() != null) {
958
            query_proj = this.getCoordTrans().getPOrig();
959
        }
960

    
961
        Evaluator iee = SpatialEvaluatorsFactory.getInstance().intersects(
962
                query_env.getGeometry(), 
963
                query_proj, 
964
                featureStore
965
        );
966
        featureQuery.setFilter(iee);
967
        return getFeatureStore().getFeatureSet(featureQuery);
968

    
969
    }
970

    
971
    public DynObjectSet getInfo(Point p, double tolerance, Cancellable cancel) throws LoadLayerException,
972
            DataException {
973

    
974
        return getInfo(p, tolerance, cancel, true);
975
    }
976

    
977
    public DynObjectSet getInfo(Point p,
978
            double tolerance,
979
            Cancellable cancel,
980
            boolean fast) throws LoadLayerException, DataException {
981
        Point2D infop = new Point2D.Double(p.x, p.y);
982
        Point2D pReal = this.getMapContext().getViewPort().toMapPoint(infop);
983
        return queryByPoint(pReal,
984
                tolerance,
985
                getFeatureStore().getDefaultFeatureType()).getDynObjectSet(fast);
986
    }
987

    
988
    public DynObjectSet getInfo(org.gvsig.fmap.geom.primitive.Point p,
989
            double tolerance) throws LoadLayerException, DataException {
990
        return queryByPoint(p, tolerance, getFeatureStore().getDefaultFeatureType()).getDynObjectSet(false);
991
    }
992

    
993
    @Override
994
    public void legendCleared(LegendClearEvent event) {
995
        this.updateDrawVersion();
996
        LegendChangedEvent e = LegendChangedEvent.createLegendChangedEvent(legend,event);
997
        this.callLegendChanged(e);
998
    }
999

    
1000
    @Override
1001
    public boolean symbolChanged(SymbolLegendEvent e) {
1002
        this.updateDrawVersion();
1003
        LegendChangedEvent ev = LegendChangedEvent.createLegendChangedEvent(legend, e);
1004
        this.callLegendChanged(ev);
1005
        return true;
1006
    }
1007

    
1008
    public void update(Observable observable, Object notification) {
1009
        if (observable.equals(this.featureStore)) {
1010
            if (notification instanceof FeatureStoreNotification) {
1011
                FeatureStoreNotification event
1012
                        = (FeatureStoreNotification) notification;
1013
                if (event.getType() == FeatureStoreNotification.AFTER_DELETE
1014
                        || event.getType() == FeatureStoreNotification.AFTER_UNDO
1015
                        || event.getType() == FeatureStoreNotification.AFTER_REDO
1016
                        || event.getType() == FeatureStoreNotification.AFTER_REFRESH
1017
                        || event.getType() == FeatureStoreNotification.AFTER_UPDATE
1018
                        || event.getType() == FeatureStoreNotification.AFTER_UPDATE_TYPE
1019
                        || event.getType() == FeatureStoreNotification.SELECTION_CHANGE
1020
                        || event.getType() == FeatureStoreNotification.AFTER_INSERT) {
1021
                    this.updateDrawVersion();
1022

    
1023
                } else if (event.getType() == FeatureStoreNotification.AFTER_CANCELEDITING) {
1024

    
1025
                    setSpatialCacheEnabled(false);
1026
                    callEditionChanged(LayerEvent.createEditionChangedEvent(this, "edition"));
1027
                    this.updateDrawVersion();
1028

    
1029
                } else if (event.getType() == FeatureStoreNotification.AFTER_STARTEDITING) {
1030

    
1031
                    setSpatialCacheEnabled(true);
1032
                    callEditionChanged(LayerEvent.createEditionChangedEvent(this, "edition"));
1033

    
1034
                } else if (event.getType() == FeatureStoreNotification.TRANSFORM_CHANGE) {
1035
                    //If a transform has to be applied, try to reload the layer.
1036
                    try {
1037
                        reload();
1038
                    } catch (ReloadLayerException e) {
1039
                        logger.info("While reloading layer.", e);
1040
                        this.setAvailable(false);
1041
                    }
1042
                } else if (event.getType() == FeatureStoreNotification.RESOURCE_CHANGED) {
1043
                    this.setAvailable(false);
1044
                } else if (event.getType() == FeatureStoreNotification.AFTER_FINISHEDITING) {
1045
                    this.setAvailable(true);
1046
                    setSpatialCacheEnabled(false);
1047
                    callEditionChanged(LayerEvent.createEditionChangedEvent(this, "edition"));
1048
                    this.updateDrawVersion();
1049
                }
1050
            }
1051
        } else if (notification instanceof FeatureDrawnNotification
1052
                && (isEditing() || isLayerToSnap())) {
1053
            // This code is needed in editing mode
1054
            // for all layers involved in snapping
1055
            // (including the layer being edited)
1056
            Geometry geometry
1057
                    = ((FeatureDrawnNotification) notification).getDrawnGeometry();
1058
            spatialCache.insert(geometry.getEnvelope(), geometry);
1059
        }
1060
    }
1061

    
1062
    private boolean isLayerToSnap() {
1063

    
1064
        if (this.getMapContext() == null) {
1065
            /*
1066
             * This happens with the graphics layer because it has no parent
1067
             */
1068
            return false;
1069
        } else {
1070
            return this.getMapContext().getLayersToSnap().contains(this);
1071
        }
1072

    
1073
        /*
1074
         Iterator itersnap = this.getMapContext().getLayersToSnap().iterator();
1075
         Object item = null;
1076
         while (itersnap.hasNext()) {
1077
         item = itersnap.next();
1078
         if (item == this) {
1079
         return true;
1080
         }
1081
         }
1082
         return false;
1083
         */
1084
    }
1085

    
1086
    /*
1087
     * (non-Javadoc)
1088
     *
1089
     * @see org.gvsig.metadata.Metadata#getMetadataChildren()
1090
     */
1091
    public Set getMetadataChildren() {
1092
        Set ret = new TreeSet();
1093
        ret.add(this.featureStore);
1094
        return ret;
1095
    }
1096

    
1097
    /*
1098
     * (non-Javadoc)
1099
     *
1100
     * @see org.gvsig.metadata.Metadata#getMetadataID()
1101
     */
1102
    public Object getMetadataID() throws MetadataException {
1103
        return "Layer(" + this.getName() + "):"
1104
                + this.featureStore.getMetadataID();
1105
    }
1106

    
1107
    public GeometryType getTypeVectorLayer() throws DataException,
1108
            LocatorException,
1109
            GeometryTypeNotSupportedException,
1110
            GeometryTypeNotValidException {
1111
        // FIXME Esto deberia de pedirse a FType!!!!
1112
        FeatureStore fs = this.getFeatureStore();
1113
        FeatureType fType = fs.getDefaultFeatureType();
1114
        FeatureAttributeDescriptor attr
1115
                = fType.getAttributeDescriptor(fType.getDefaultGeometryAttributeIndex());
1116
        GeometryType geomType
1117
                = GeometryLocator.getGeometryManager()
1118
                .getGeometryType(attr.getGeometryType(),
1119
                        attr.getGeometrySubType());
1120
        return geomType;
1121
    }
1122

    
1123
    public static class RegisterPersistence implements Callable {
1124

    
1125
        public Object call() {
1126
            PersistenceManager manager = ToolsLocator.getPersistenceManager();
1127

    
1128
            DynStruct definition
1129
                    = manager.addDefinition(FLyrVect.class,
1130
                            "FLyrVect",
1131
                            "FLyrVect Persistence definition",
1132
                            null,
1133
                            null);
1134
            definition.extend(PersistenceManager.PERSISTENCE_NAMESPACE,
1135
                    "FLyrDefault");
1136

    
1137
            definition.addDynFieldObject("legend")
1138
                    .setClassOfValue(IVectorLegend.class)
1139
                    .setMandatory(true);
1140
            definition.addDynFieldObject("featureStore")
1141
                    .setClassOfValue(FeatureStore.class)
1142
                    .setMandatory(true);
1143
            definition.addDynFieldBoolean("isLabeled").setMandatory(true);
1144
            definition.addDynFieldInt("typeShape").setMandatory(true);
1145
            definition.addDynFieldObject("labelingStrategy")
1146
                    .setClassOfValue(ILabelingStrategy.class)
1147
                    .setMandatory(false);
1148

    
1149
            return Boolean.TRUE;
1150
        }
1151
    }
1152

    
1153
    protected void doDispose() throws BaseException {
1154
        dispose(featureStore);
1155
        spatialCache.clearAll();
1156
    }
1157

    
1158
    /**
1159
     * Returns envelope in layer's data source CRS from envelope provided in
1160
     * viewport CRS
1161
     *
1162
     * @param lyr
1163
     * @param env
1164
     * @return
1165
     */
1166
    public static Envelope fromViewPortCRSToSourceCRS(FLayer lyr, Envelope env) {
1167

    
1168
        if (lyr == null || env == null) {
1169
            return null;
1170
        }
1171

    
1172
        ICoordTrans ct = lyr.getCoordTrans();
1173
        if (ct == null) {
1174
            return env;
1175
        } else {
1176
            return env.convert(ct.getInverted());
1177
        }
1178
    }
1179

    
1180
    public Geometry transformToSourceCRS(Geometry geom, boolean clone) {
1181
        return fromViewPortCRSToSourceCRS(this, geom, clone);
1182
    }
1183

    
1184
    /**
1185
     * Returns geometry in layer's data source CRS from geometry provided in
1186
     * viewport CRS
1187
     *
1188
     * @param lyr
1189
     * @param geo
1190
     * @param clone
1191
     * @return
1192
     * @deprecated use the transformToSourceCRS method of layer.
1193
     */
1194
    public static Geometry fromViewPortCRSToSourceCRS(
1195
            FLayer lyr,
1196
            Geometry geo,
1197
            boolean clone) {
1198

    
1199
        if (lyr == null || geo == null) {
1200
            return null;
1201
        }
1202
        ICoordTrans ct = lyr.getCoordTrans();
1203
        Geometry resp = geo;
1204
        if (clone) {
1205
            resp = resp.cloneGeometry();
1206
        }
1207
        if (ct != null) {
1208
            resp.reProject(ct.getInverted());
1209
        }
1210
        return resp;
1211
    }
1212

    
1213
    public Iterator iterator() {
1214
        return this.getFeatureStore().iterator();
1215
    }
1216

    
1217
    protected class EnvelopeCantBeInitializedException extends BaseException {
1218

    
1219
        /**
1220
         *
1221
         */
1222
        private static final long serialVersionUID = 4572797479347381552L;
1223
        private final static String MESSAGE_FORMAT = "The envelope can't be initialized, maybe the layer has a wrong projection. Change the projection in layer properties of the add layer dialog to try fix it.";
1224
        private final static String MESSAGE_KEY = "_EnvelopeCantBeInitializedException";
1225

    
1226
        public EnvelopeCantBeInitializedException() {
1227
            super(MESSAGE_FORMAT, null, MESSAGE_KEY, serialVersionUID);
1228
        }
1229
    }
1230

    
1231
}