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 @ 42796

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

    
97
/**
98
 * Capa b?sica Vectorial.
99
 *
100
 */
101
public class FLyrVect extends FLyrDefault implements VectorLayer,
102
        LegendContentsChangedListener, Observer {
103

    
104
    final static private org.slf4j.Logger logger
105
            = LoggerFactory.getLogger(FLyrVect.class);
106
    private final GeometryManager geomManager
107
            = GeometryLocator.getGeometryManager();
108

    
109
    /**
110
     * Leyenda de la capa vectorial
111
     */
112
    private IVectorLegend legend;
113
    private int typeShape = -1;
114
    private FeatureStore featureStore = null;
115
    private SpatialCache spatialCache = new SpatialCache();
116

    
117
    /**
118
     * An implementation of gvSIG spatial index
119
     */
120
    // protected ISpatialIndex spatialIndex = null;
121
    private IVectorLegend loadLegend = null;
122

    
123
    private boolean isLabeled;
124
    protected ILabelingStrategy strategy;
125
//        private ReprojectDefaultGeometry reprojectTransform;
126
    private FeatureQuery baseQuery = null;
127

    
128
    public FLyrVect() {
129
        super();
130
    }
131

    
132
    public String getTocImageIcon() {
133
        if (this.isAvailable()) {
134
            return MapContextLocator.getMapContextManager().getIconLayer(this.getDataStore());
135
        } else {
136
            /*
137
             * data store can be be null,
138
             * for example, a layer not loaded from persistence
139
             */
140
            return "layer-icon-unavailable";
141
        }
142

    
143
    }
144

    
145
    /**
146
     * Devuelve el VectorialAdapater de la capa.
147
     *
148
     * @return VectorialAdapter.
149
     */
150
    public DataStore getDataStore() {
151
        if (!this.isAvailable()) {
152
            return null;
153
        }
154
        return featureStore;
155
    }
156

    
157
    /**
158
     * Asigna el data-store a la capa. Esta operacion no se deneria poder hacer
159
     * desde fuera de la clase.
160
     *
161
     * @param dataStore
162
     * @throws LoadLayerException
163
     * @deprecated use {@link #bindToDataStore(DataStore)}
164
     */
165
    public void setDataStore(DataStore dataStore) throws LoadLayerException {
166
        bindToDataStore(dataStore);
167
    }
168

    
169
    /**
170
     * Enlaza la capa con el DataStore indicado.
171
     *
172
     * @param dataStore
173
     * @throws LoadLayerException
174
     */
175
    protected void bindToDataStore(DataStore dataStore) throws LoadLayerException {
176
        if (this.featureStore != null && this.featureStore != dataStore) {
177
            this.featureStore.deleteObserver(this);
178
        }
179

    
180
        featureStore = (FeatureStore) dataStore;
181

    
182
        MapContextManager mapContextManager
183
                = MapContextLocator.getMapContextManager();
184

    
185
        //Set the legend
186
        IVectorLegend legend
187
                = (IVectorLegend) mapContextManager.getLegend(dataStore);
188

    
189
        if (legend == null) {
190
            throw new LegendLayerException(this.getName());
191
        }
192

    
193
        this.setLegend(legend);
194

    
195
        //Set the labeling strategy
196
        ILabelingStrategy labeler
197
                = (ILabelingStrategy) mapContextManager.getLabelingStrategy(dataStore);
198

    
199
        if (labeler != null) {
200
            labeler.setLayer(this);
201
            this.setLabelingStrategy(labeler);
202
            this.setIsLabeled(true); // TODO: ac? no s'hauria de detectar si t?
203
            // etiquetes?????
204
        }
205

    
206
        this.delegate(dataStore);
207

    
208
        dataStore.addObserver(this);
209

    
210
        ToolsLocator.getDisposableManager().bind(dataStore);
211
    }
212

    
213
    public Envelope getFullEnvelope() throws ReadException {
214
        Envelope rAux;
215
        try {
216
            rAux = getFeatureStore().getEnvelope();
217
        } catch (BaseException e) {
218
            throw new ReadException(getName(), e);
219
        }
220

    
221
        // Esto es para cuando se crea una capa nueva con el fullExtent de ancho
222
        // y alto 0.
223
        if (rAux == null || rAux.isEmpty() || rAux.getMaximum(0) - rAux.getMinimum(0) == 0
224
                && rAux.getMaximum(1) - rAux.getMinimum(1) == 0) {
225
            try {
226
                rAux
227
                        = geomManager.createEnvelope(0, 0, 90, 90, SUBTYPES.GEOM2D);
228
            } catch (CreateEnvelopeException e) {
229
                logger.error("Error creating the envelope", e);
230
                e.printStackTrace();
231
            }
232
        }
233
        // Si existe reproyecci?n, reproyectar el extent
234
        ICoordTrans ct = getCoordTrans();
235
        if (ct != null) {
236
            rAux = rAux.convert(ct);
237
        }
238
        return rAux;
239

    
240
    }
241
    
242
    public void setBaseQuery(FeatureQuery baseQuery) {
243
        this.baseQuery = baseQuery;
244
    }
245

    
246
    @Override
247
    public FeatureQuery getBaseQuery() {
248
        return this.baseQuery;
249
    }
250

    
251
    
252
    /**
253
     * Draws using IFeatureIterator. This method will replace the old draw(...)
254
     * one.
255
     *
256
     * @autor jaume dominguez faus - jaume.dominguez@iver.es
257
     * @param image
258
     * @param g
259
     * @param viewPort
260
     * @param cancel
261
     * @param scale
262
     * @throws ReadDriverException
263
     */
264
    public void draw(BufferedImage image,
265
            Graphics2D g,
266
            ViewPort viewPort,
267
            Cancellable cancel,
268
            double scale) throws ReadException {
269

    
270
        if (legend == null) {
271
            return;
272
        }
273

    
274
        if (!this.isWithinScale(scale)) {
275
            return;
276
        }
277
        if (cancel.isCanceled()) {
278
            return;
279
        }
280

    
281
        if (spatialCache.isEnabled()) {
282
            spatialCache.clearAll();
283
            legend.addDrawingObserver(this);
284
        }
285

    
286
        FeatureQuery featureQuery;
287
        if( this.getBaseQuery()==null ) {
288
            featureQuery = createFeatureQuery();
289
        } else {
290
            featureQuery = this.getBaseQuery();
291
        }
292

    
293
        try {
294
            FeatureAttributeDescriptor featureAttributeDescriptor
295
                    = getFeatureStore().getDefaultFeatureType().getDefaultTimeAttribute();
296

    
297
            if ((viewPort.getTime() != null) && (featureAttributeDescriptor != null)) {
298
                IntersectsTimeEvaluator intersectsTimeEvaluator
299
                        = new IntersectsTimeEvaluator(viewPort.getTime(), featureAttributeDescriptor.getName());
300
                featureQuery.addFilter(intersectsTimeEvaluator);
301
            }
302
        } catch (DataException e1) {
303
            logger.error("Impossible to get the temporal filter", e1);
304
        }
305

    
306
        try {
307

    
308
            long tini = System.currentTimeMillis();
309

    
310
            legend.draw(image,
311
                    g,
312
                    viewPort,
313
                    cancel,
314
                    scale,
315
                    null,
316
                    getCoordTrans(),
317
                    getFeatureStore(),
318
                    featureQuery);
319

    
320
            logger.debug("Layer " + this.getName() + " drawn in "
321
                    + (System.currentTimeMillis() - tini) + " milliseconds.");
322

    
323
        } catch (LegendException e) {
324
            this.setVisible(false);
325
            this.setActive(false);
326
            throw new ReadException(getName(), e);
327
        } finally {
328
            if (spatialCache.isEnabled()) {
329
                legend.deleteDrawingObserver(this);
330
            }
331
        }
332
    }
333

    
334
    public void print(Graphics2D g,
335
            ViewPort viewPort,
336
            Cancellable cancel,
337
            double scale,
338
            PrintAttributes properties) throws ReadException {
339
        if (!this.isWithinScale(scale)) {
340
            return;
341
        }
342
        if (cancel.isCanceled()) {
343
            return;
344
        }
345
        FeatureQuery featureQuery = createFeatureQuery();
346

    
347
        try {
348
            legend.print(g,
349
                    viewPort,
350
                    cancel,
351
                    scale,
352
                    null,
353
                    getCoordTrans(),
354
                    getFeatureStore(),
355
                    featureQuery,
356
                    properties);
357

    
358
        } catch (LegendException e) {
359
            this.setVisible(false);
360
            this.setActive(false);
361
            throw new ReadException(getName(), e);
362
        }
363
    }
364

    
365
    public void setLegend(IVectorLegend legend) throws LegendLayerException {
366
        if (this.legend == legend) {
367
            return;
368
        }
369
        if (this.legend != null && this.legend.equals(legend)) {
370
            return;
371
        }
372
        IVectorLegend oldLegend = this.legend;
373
        this.legend = legend;
374
        if (oldLegend != null) {
375
            oldLegend.removeLegendListener(this);
376
            oldLegend.deleteDrawingObserver(this);
377
        }
378
        if (legend != null) {
379
            this.legend.addDrawingObserver(this);
380
            this.legend.addLegendListener(this);
381
        }
382
        LegendChangedEvent e
383
                = LegendChangedEvent.createLegendChangedEvent(oldLegend, this.legend);
384
        e.setLayer(this);
385
        updateDrawVersion();
386
        callLegendChanged(e);
387
    }
388

    
389
    /**
390
     * Devuelve la Leyenda de la capa.
391
     *
392
     * @return Leyenda.
393
     */
394
    public ILegend getLegend() {
395
        return legend;
396
    }
397

    
398
    public int getShapeType() throws ReadException {
399
        if (typeShape == -1) {
400
            FeatureType featureType = null;
401
            try {
402
                if (getDataStore() != null) {
403
                    featureType
404
                            = (((FeatureStore) getDataStore()).getDefaultFeatureType());
405
                }
406
            } catch (DataException e) {
407
                throw new ReadException(getName(), e);
408
            }
409
            if (featureType != null) {
410
                int indexGeom = featureType.getDefaultGeometryAttributeIndex();
411
                typeShape
412
                        = featureType.getAttributeDescriptor(indexGeom).getGeometryType();
413
            }
414
        }
415
        return typeShape;
416
    }
417

    
418
    /**
419
     * Returns the layer's geometry type
420
     *
421
     * @return the geometry type
422
     *
423
     * @throws ReadException if there is an error getting the geometry type
424
     */
425
    public GeometryType getGeometryType() throws ReadException {
426
        FeatureType featureType = null;
427
        try {
428
            if (getDataStore() != null) {
429
                featureType
430
                        = (((FeatureStore) getDataStore()).getDefaultFeatureType());
431
            }
432
        } catch (DataException e) {
433
            throw new ReadException(getName(), e);
434
        }
435
        return featureType == null ? null : featureType
436
                .getDefaultGeometryAttribute().getGeomType();
437
    }
438

    
439
    public void saveToState(PersistentState state) throws PersistenceException {
440

    
441
        FeatureStore featureStore = null;
442

    
443
        if (!this.isAvailable()) {
444
            logger.info("The '" + this.getName() + "' layer is not available, it will persist not.");
445
            return;
446
        }
447

    
448
        try {
449
            super.saveToState(state);
450

    
451
            if (getLegend() != null) {
452
                state.set("legend", getLegend());
453
            }
454

    
455
            featureStore = getFeatureStore();
456

    
457
            if (featureStore != null) {
458
                state.set("featureStore", featureStore);
459
            }
460

    
461
            state.set("isLabeled", isLabeled);
462

    
463
            if (strategy != null) {
464
                state.set("labelingStrategy", strategy);
465
            }
466

    
467
            if (getLinkProperties() != null) {
468
                state.set("linkProperties", getLinkProperties());
469
            }
470

    
471
            state.set("typeShape", typeShape);
472
        } catch (PersistenceException ex) {
473
            logger.warn("Can't persist to state the layer '" + this.getName() + "'.", ex);
474
            throw ex;
475
        } catch (RuntimeException ex) {
476
            logger.warn("Can't persist to state the layer '" + this.getName() + "'.", ex);
477
            throw ex;
478
        }
479

    
480
    }
481

    
482
    public void loadFromState(PersistentState state) throws PersistenceException {
483

    
484
        DataStore store = null;
485
        IVectorLegend vectorLegend = null;
486
        ILabelingStrategy labelingStrategy = null;
487
        Boolean isLabeled = Boolean.FALSE;
488

    
489
        try {
490
            super.loadFromState(state);
491
            store = (DataStore) state.get("featureStore");
492

    
493
            try {
494
                this.bindToDataStore(store);
495
            } catch (LoadLayerException e) {
496
                throw new PersistenceException("Can't bind layer '" + this.getName() + "' to store '" + store.getFullName() + "'.", e);
497
            }
498

    
499
            vectorLegend = (IVectorLegend) state.get("legend");
500

    
501
            try {
502
                this.setLegend(vectorLegend);
503
            } catch (LegendLayerException e) {
504
                throw new PersistenceException("Can't set vector legend to the layer.", e);
505
            }
506

    
507
            try {
508
                isLabeled = (Boolean) state.get("isLabeled");
509
                if (isLabeled.booleanValue()) {
510
                    labelingStrategy = (ILabelingStrategy) state.get("labelingStrategy");
511
                }
512
            } catch (Exception ex) {
513
                throw new PersistenceException("Can't load labeling strategi from persistent state.",
514
                        ex);
515
            }
516

    
517
            if (isLabeled.booleanValue()) {
518
                this.setIsLabeled(true);
519
                this.setLabelingStrategy(labelingStrategy);
520
            } else {
521
                this.setIsLabeled(false);
522
                this.setLabelingStrategy(null);
523
            }
524

    
525
            typeShape = state.getInt("typeShape");
526

    
527
        } catch (Throwable e) {
528
            String storeName = (store == null) ? "unknow" : store.getFullName();
529
            logger.warn("can't load layer '" + this.getName() + "' (store=" + storeName + ") from persisted state.", e);
530
            this.setAvailable(false);
531
            return;
532
        }
533

    
534
    }
535

    
536
    /**
537
     * Sobreimplementaci?n del m?todo toString para que las bases de datos
538
     * identifiquen la capa.
539
     *
540
     * @return DOCUMENT ME!
541
     */
542
    public String toString() {
543
        /*
544
         * Se usa internamente para que la parte de datos identifique de forma
545
         * un?voca las tablas
546
         */
547
        String ret = super.toString();
548

    
549
        return ret ; //"layer" + ret.substring(ret.indexOf('@') + 1);
550
    }
551

    
552
    public boolean isEditing() {
553
        FeatureStore fs = getFeatureStore();
554
        if (fs == null) {
555
            /*
556
             * This happens when layer is not available, for example,
557
             * it was not possible to load from persistence
558
             */
559
            return false;
560
        } else {
561
            return fs.isEditing();
562
        }
563
    }
564

    
565
    public void setEditing(boolean b) throws StartEditionLayerException {
566

    
567
        try {
568
            throw new RuntimeException();
569
        } catch (Throwable th) {
570
            logger.info("This method is deprecated. ", th);
571
        }
572

    
573
        if (b == super.isEditing()) {
574
            return;
575
        }
576

    
577
        super.setEditing(b);
578
        FeatureStore fs = getFeatureStore();
579
        if (b) {
580
            try {
581
                fs.edit();
582
            } catch (DataException e) {
583
                throw new StartEditionLayerException(getName(), e);
584
            }
585
        }
586
        setSpatialCacheEnabled(b);
587
        callEditionChanged(LayerEvent.createEditionChangedEvent(this, "edition"));
588
    }
589

    
590
    /**
591
     * @deprecated Use {@link #getSpatialCache()}
592
     */
593
    public void clearSpatialCache() {
594
        spatialCache.clearAll();
595
    }
596

    
597
    /**
598
     * @deprecated Use {@link #getSpatialCache()}
599
     */
600
    public boolean isSpatialCacheEnabled() {
601
        return spatialCache.isEnabled();
602
    }
603

    
604
    /**
605
     * @deprecated Use {@link #getSpatialCache()}
606
     */
607
    public void setSpatialCacheEnabled(boolean spatialCacheEnabled) {
608
        spatialCache.setEnabled(spatialCacheEnabled);
609
    }
610

    
611
    public SpatialCache getSpatialCache() {
612
        return spatialCache;
613
    }
614

    
615
    /**
616
     * Siempre es un numero mayor de 1000
617
     *
618
     * @param maxFeatures
619
     */
620
    public void setMaxFeaturesInEditionCache(int maxFeatures) {
621
        if (maxFeatures > spatialCache.getMaxFeatures()) {
622
            spatialCache.setMaxFeatures(maxFeatures);
623
        }
624

    
625
    }
626

    
627
    /**
628
     * This method returns a boolean that is used by the FPopMenu to make
629
     * visible the properties menu or not. It is visible by default, and if a
630
     * later don't have to show this menu only has to override this method.
631
     *
632
     * @return If the properties menu is visible (or not)
633
     */
634
    public boolean isPropertiesMenuVisible() {
635
        return true;
636
    }
637

    
638
    public void reload() throws ReloadLayerException {
639
        super.reload();
640
        try {
641
            getFeatureStore().refresh();
642
        } catch (Exception e) {
643
            throw new ReloadLayerException(getName(), e);
644
        }
645
    }
646

    
647
    protected void setLoadSelection(Object xml) {
648
        // this.loadSelection = xml;
649
    }
650

    
651
    protected void setLoadLegend(IVectorLegend legend) {
652
        this.loadLegend = legend;
653
    }
654

    
655
    protected void putLoadSelection() {
656
        // if (this.loadSelection == null) return;
657
        // try {
658
        // this.getRecordset().getSelectionSupport().setXMLEntity(this.loadSelection);
659
        // } catch (ReadDriverException e) {
660
        // throw new XMLException(e);
661
        // }
662
        // this.loadSelection = null;
663

    
664
    }
665

    
666
    protected void putLoadLegend() throws LegendLayerException {
667
        if (this.loadLegend == null) {
668
            return;
669
        }
670
        this.setLegend(this.loadLegend);
671
        this.loadLegend = null;
672
    }
673

    
674
    protected void cleanLoadOptions() {
675
        this.loadLegend = null;
676
    }
677

    
678
    public boolean isWritable() {
679
        return getFeatureStore().allowWrite();
680
    }
681

    
682
    public FLayer cloneLayer() throws Exception {
683
        FLyrVect clonedLayer = new FLyrVect();
684
        clonedLayer.bindToDataStore(getDataStore());
685
        // if (isJoined()) {
686
        // clonedLayer.setIsJoined(true);
687
        // }
688
        clonedLayer.setVisible(isVisible());
689
        // clonedLayer.setISpatialIndex(getISpatialIndex());
690
        clonedLayer.setName(getName());
691
        clonedLayer.setCoordTrans(getCoordTrans());
692

    
693
        clonedLayer.setLegend((IVectorLegend) getLegend().cloneLegend());
694

    
695
        clonedLayer.setIsLabeled(isLabeled());
696
        ILabelingStrategy labelingStrategy = getLabelingStrategy();
697
        if (labelingStrategy != null) {
698
            clonedLayer.setLabelingStrategy(labelingStrategy);
699
        }
700

    
701
        return clonedLayer;
702
    }
703

    
704
    protected boolean isOnePoint(AffineTransform graphicsTransform,
705
            ViewPort viewPort,
706
            double dpi,
707
            CartographicSupport csSym,
708
            Geometry geom,
709
            int[] xyCoords) {
710
        return isOnePoint(graphicsTransform, viewPort, geom, xyCoords)
711
                && csSym.getCartographicSize(viewPort, dpi, geom) <= 1;
712
    }
713

    
714
    private boolean isOnePoint(AffineTransform graphicsTransform,
715
            ViewPort viewPort,
716
            Geometry geom,
717
            int[] xyCoords) {
718
        boolean onePoint = false;
719
        int type = geom.getType();
720
        if (type == Geometry.TYPES.NULL) {
721
            return false;
722
        }
723
        if (type != Geometry.TYPES.POINT && type != Geometry.TYPES.MULTIPOINT) {
724

    
725
            Envelope geomBounds = geom.getEnvelope();
726

    
727
            // ICoordTrans ct = getCoordTrans();
728
            // Se supone que la geometria ya esta reproyectada
729
            // if (ct!=null) {
730
            // // geomBounds = ct.getInverted().convert(geomBounds);
731
            // geomBounds = geomBounds.convert(ct);
732
            // }
733
            double dist1Pixel = viewPort.getDist1pixel();
734

    
735
            onePoint
736
                    = (geomBounds.getLength(0) <= dist1Pixel && geomBounds.getLength(1) <= dist1Pixel);
737

    
738
            if (onePoint) {
739
                // avoid out of range exceptions
740
                org.gvsig.fmap.geom.primitive.Point p;
741
                try {
742
                    p
743
                            = geomManager.createPoint(geomBounds.getMinimum(0),
744
                                    geomBounds.getMinimum(1),
745
                                    SUBTYPES.GEOM2D);
746
                    p.transform(viewPort.getAffineTransform());
747
                    p.transform(graphicsTransform);
748
                    xyCoords[0] = (int) p.getX();
749
                    xyCoords[1] = (int) p.getY();
750
                } catch (org.gvsig.fmap.geom.exception.CreateGeometryException e) {
751
                    logger.error("Error creating a point", e);
752
                }
753

    
754
            }
755

    
756
        }
757
        return onePoint;
758
    }
759

    
760
    public boolean isLabeled() {
761
        return isLabeled;
762
    }
763

    
764
    public void setIsLabeled(boolean isLabeled) {
765
        this.isLabeled = isLabeled;
766
    }
767

    
768
    public ILabelingStrategy getLabelingStrategy() {
769
        return strategy;
770
    }
771

    
772
    public void setLabelingStrategy(ILabelingStrategy strategy) {
773
        this.strategy = strategy;
774
        if (strategy == null) {
775
            return;
776
        }
777
        strategy.setLayer(this);
778
        updateDrawVersion();
779
    }
780

    
781
    public void drawLabels(BufferedImage image,
782
            Graphics2D g,
783
            ViewPort viewPort,
784
            Cancellable cancel,
785
            double scale,
786
            double dpi) throws ReadException {
787
        if (strategy != null && isWithinScale(scale)) {
788
            strategy.draw(image, g, scale, viewPort, cancel, dpi);
789
        }
790
    }
791

    
792
    public void printLabels(Graphics2D g,
793
            ViewPort viewPort,
794
            Cancellable cancel,
795
            double scale,
796
            PrintAttributes properties) throws ReadException {
797
        if (strategy != null) {
798
            strategy.print(g, scale, viewPort, cancel, properties);
799
        }
800
    }
801

    
802
    /**
803
     * Return true, because a Vectorial Layer supports HyperLink
804
     *
805
     * @deprecated the hiperlink functionaliti is out the layer now
806
     */
807
    public boolean allowLinks() {
808
        return false;
809
    }
810

    
811
    public void load() throws LoadLayerException {
812
        super.load();
813
    }
814

    
815
    public FeatureStore getFeatureStore() {
816
        return (FeatureStore) getDataStore();
817
    }
818

    
819
    public FeatureQuery createFeatureQuery() {
820
        if( this.baseQuery==null ) {
821
            return this.getFeatureStore().createFeatureQuery();
822
        }
823
        try {
824
            return (FeatureQuery) baseQuery.clone();
825
        } catch (CloneNotSupportedException ex) {
826
            throw new RuntimeException(ex);
827
        }
828
    }
829
    
830
    /**
831
     * @deprecated use instead
832
     * {@link #queryByPoint(org.gvsig.fmap.geom.primitive.Point, double, FeatureType)}
833
     */
834
    public FeatureSet queryByPoint(Point2D mapPoint,
835
            double tol,
836
            FeatureType featureType) throws DataException {
837
        logger.warn("Deprecated use of queryByPoint.");
838
        GeometryManager manager = GeometryLocator.getGeometryManager();
839
        org.gvsig.fmap.geom.primitive.Point center;
840
        try {
841
            center
842
                    = (org.gvsig.fmap.geom.primitive.Point) manager.create(TYPES.POINT,
843
                            SUBTYPES.GEOM2D);
844
            center.setX(mapPoint.getX());
845
            center.setY(mapPoint.getY());
846
            Circle circle
847
                    = (Circle) manager.create(TYPES.CIRCLE, SUBTYPES.GEOM2D);
848
            circle.setPoints(center, tol);
849
            return queryByGeometry(circle, featureType);
850
        } catch (org.gvsig.fmap.geom.exception.CreateGeometryException e) {
851
            throw new CreateGeometryException(TYPES.CIRCLE, SUBTYPES.GEOM2D, e);
852
        }
853
    }
854

    
855
    public FeatureSet queryByPoint(org.gvsig.fmap.geom.primitive.Point point,
856
            double tol,
857
            FeatureType featureType) throws DataException {
858
        GeometryManager manager = GeometryLocator.getGeometryManager();
859
        try {
860
            Circle circle
861
                    = (Circle) manager.create(TYPES.CIRCLE, SUBTYPES.GEOM2D);
862
            circle.setPoints(point, tol);
863
            return queryByGeometry(circle, featureType);
864
        } catch (org.gvsig.fmap.geom.exception.CreateGeometryException e) {
865
            throw new CreateGeometryException(TYPES.CIRCLE, SUBTYPES.GEOM2D, e);
866
        }
867
    }
868

    
869
    /**
870
     * Input geom must be in the CRS of the view.
871
     *
872
     * @param geom
873
     * @param featureType
874
     * @return
875
     * @throws DataException
876
     */
877
    public FeatureSet queryByGeometry(Geometry geom, FeatureType featureType) throws DataException {
878
        FeatureQuery featureQuery = createFeatureQuery();
879
        String geomName
880
                = featureStore.getDefaultFeatureType()
881
                .getDefaultGeometryAttributeName();
882
        featureQuery.setFeatureType(featureType);
883

    
884
        Geometry query_geo = this.transformToSourceCRS(geom, true);
885
        IProjection query_proj = getMapContext().getProjection();
886
        if (this.getCoordTrans() != null) {
887
            query_proj = this.getCoordTrans().getPOrig();
888
        }
889

    
890
        IntersectsGeometryEvaluator iee
891
                = new IntersectsGeometryEvaluator(
892
                        query_geo,
893
                        query_proj,
894
                        featureStore.getDefaultFeatureType(),
895
                        geomName);
896
        featureQuery.setFilter(iee);
897
        featureQuery.setAttributeNames(null);
898
        return getFeatureStore().getFeatureSet(featureQuery);
899

    
900
    }
901

    
902
    /**
903
     * It return the {@link FeatureSet} that intersects with the envelope.
904
     *
905
     * @param envelope envelope that defines the area for the query.
906
     * @param featureType only the features with this feature type are used in
907
     * the query.
908
     * @return the set of features that intersect with the envelope.
909
     * @throws DataException
910
     */
911
    public FeatureSet queryByEnvelope(Envelope envelope, FeatureType featureType) throws DataException {
912
        return queryByEnvelope(envelope, featureType, null);
913
    }
914

    
915
    /**
916
     * It return the {@link FeatureSet} that intersects with the envelope.
917
     *
918
     * @param envelope envelope that defines the area for the query in viewport
919
     * CRS
920
     * @param featureType only the features with this feature type are used in
921
     * the query.
922
     * @param names the feature attributes that have to be checked.
923
     * @return the set of features that intersect with the envelope.
924
     * @throws DataException
925
     */
926
    public FeatureSet queryByEnvelope(Envelope envelope,
927
            FeatureType featureType,
928
            String[] names) throws DataException {
929
        FeatureQuery featureQuery = createFeatureQuery();
930
        if (names == null) {
931
            featureQuery.setFeatureType(featureType);
932
        } else {
933
            featureQuery.setAttributeNames(names);
934
            featureQuery.setFeatureTypeId(featureType.getId());
935
        }
936
        String geomName = featureStore.getDefaultFeatureType()
937
                .getDefaultGeometryAttributeName();
938

    
939
        Envelope query_env = fromViewPortCRSToSourceCRS(this, envelope);
940
        IProjection query_proj = getMapContext().getProjection();
941
        if (this.getCoordTrans() != null) {
942
            query_proj = this.getCoordTrans().getPOrig();
943
        }
944

    
945
        IntersectsGeometryEvaluator iee
946
                = new IntersectsGeometryEvaluator(
947
                        query_env.getGeometry(), query_proj,
948
                        featureStore.getDefaultFeatureType(),
949
                        geomName);
950
        featureQuery.setFilter(iee);
951
        return getFeatureStore().getFeatureSet(featureQuery);
952

    
953
    }
954

    
955
    public DynObjectSet getInfo(Point p, double tolerance, Cancellable cancel) throws LoadLayerException,
956
            DataException {
957

    
958
        return getInfo(p, tolerance, cancel, true);
959
    }
960

    
961
    public DynObjectSet getInfo(Point p,
962
            double tolerance,
963
            Cancellable cancel,
964
            boolean fast) throws LoadLayerException, DataException {
965
        Point2D infop = new Point2D.Double(p.x, p.y);
966
        Point2D pReal = this.getMapContext().getViewPort().toMapPoint(infop);
967
        return queryByPoint(pReal,
968
                tolerance,
969
                getFeatureStore().getDefaultFeatureType()).getDynObjectSet(fast);
970
    }
971

    
972
    public DynObjectSet getInfo(org.gvsig.fmap.geom.primitive.Point p,
973
            double tolerance) throws LoadLayerException, DataException {
974
        return queryByPoint(p, tolerance, getFeatureStore().getDefaultFeatureType()).getDynObjectSet(false);
975
    }
976

    
977
    public void legendCleared(LegendClearEvent event) {
978
        this.updateDrawVersion();
979
        LegendChangedEvent e
980
                = LegendChangedEvent.createLegendChangedEvent(legend, legend);
981
        this.callLegendChanged(e);
982
    }
983

    
984
    public boolean symbolChanged(SymbolLegendEvent e) {
985
        this.updateDrawVersion();
986
        LegendChangedEvent ev
987
                = LegendChangedEvent.createLegendChangedEvent(legend, legend);
988
        this.callLegendChanged(ev);
989
        return true;
990
    }
991

    
992
    public void update(Observable observable, Object notification) {
993
        if (observable.equals(this.featureStore)) {
994
            if (notification instanceof FeatureStoreNotification) {
995
                FeatureStoreNotification event
996
                        = (FeatureStoreNotification) notification;
997
                if (event.getType() == FeatureStoreNotification.AFTER_DELETE
998
                        || event.getType() == FeatureStoreNotification.AFTER_UNDO
999
                        || event.getType() == FeatureStoreNotification.AFTER_REDO
1000
                        || event.getType() == FeatureStoreNotification.AFTER_REFRESH
1001
                        || event.getType() == FeatureStoreNotification.AFTER_UPDATE
1002
                        || event.getType() == FeatureStoreNotification.AFTER_UPDATE_TYPE
1003
                        || event.getType() == FeatureStoreNotification.SELECTION_CHANGE
1004
                        || event.getType() == FeatureStoreNotification.AFTER_INSERT) {
1005
                    this.updateDrawVersion();
1006

    
1007
                } else if (event.getType() == FeatureStoreNotification.AFTER_CANCELEDITING) {
1008

    
1009
                    setSpatialCacheEnabled(false);
1010
                    callEditionChanged(LayerEvent.createEditionChangedEvent(this, "edition"));
1011
                    this.updateDrawVersion();
1012

    
1013
                } else if (event.getType() == FeatureStoreNotification.AFTER_STARTEDITING) {
1014

    
1015
                    setSpatialCacheEnabled(true);
1016
                    callEditionChanged(LayerEvent.createEditionChangedEvent(this, "edition"));
1017

    
1018
                } else if (event.getType() == FeatureStoreNotification.TRANSFORM_CHANGE) {
1019
                    //If a transform has to be applied, try to reload the layer.
1020
                    try {
1021
                        reload();
1022
                    } catch (ReloadLayerException e) {
1023
                        logger.info("While reloading layer.", e);
1024
                        this.setAvailable(false);
1025
                    }
1026
                } else if (event.getType() == FeatureStoreNotification.RESOURCE_CHANGED) {
1027
                    this.setAvailable(false);
1028
                } else if (event.getType() == FeatureStoreNotification.AFTER_FINISHEDITING) {
1029
                    this.setAvailable(true);
1030
                    setSpatialCacheEnabled(false);
1031
                    callEditionChanged(LayerEvent.createEditionChangedEvent(this, "edition"));
1032
                    this.updateDrawVersion();
1033
                }
1034
            }
1035
        } else if (notification instanceof FeatureDrawnNotification
1036
                && (isEditing() || isLayerToSnap())) {
1037
            // This code is needed in editing mode
1038
            // for all layers involved in snapping
1039
            // (including the layer being edited)
1040
            Geometry geometry
1041
                    = ((FeatureDrawnNotification) notification).getDrawnGeometry();
1042
            spatialCache.insert(geometry.getEnvelope(), geometry);
1043
        }
1044
    }
1045

    
1046
    private boolean isLayerToSnap() {
1047

    
1048
        if (this.getMapContext() == null) {
1049
            /*
1050
             * This happens with the graphics layer because it has no parent
1051
             */
1052
            return false;
1053
        } else {
1054
            return this.getMapContext().getLayersToSnap().contains(this);
1055
        }
1056

    
1057
        /*
1058
         Iterator itersnap = this.getMapContext().getLayersToSnap().iterator();
1059
         Object item = null;
1060
         while (itersnap.hasNext()) {
1061
         item = itersnap.next();
1062
         if (item == this) {
1063
         return true;
1064
         }
1065
         }
1066
         return false;
1067
         */
1068
    }
1069

    
1070
    /*
1071
     * (non-Javadoc)
1072
     * 
1073
     * @see org.gvsig.metadata.Metadata#getMetadataChildren()
1074
     */
1075
    public Set getMetadataChildren() {
1076
        Set ret = new TreeSet();
1077
        ret.add(this.featureStore);
1078
        return ret;
1079
    }
1080

    
1081
    /*
1082
     * (non-Javadoc)
1083
     * 
1084
     * @see org.gvsig.metadata.Metadata#getMetadataID()
1085
     */
1086
    public Object getMetadataID() throws MetadataException {
1087
        return "Layer(" + this.getName() + "):"
1088
                + this.featureStore.getMetadataID();
1089
    }
1090

    
1091
    public GeometryType getTypeVectorLayer() throws DataException,
1092
            LocatorException,
1093
            GeometryTypeNotSupportedException,
1094
            GeometryTypeNotValidException {
1095
        // FIXME Esto deberia de pedirse a FType!!!!
1096
        FeatureStore fs = this.getFeatureStore();
1097
        FeatureType fType = fs.getDefaultFeatureType();
1098
        FeatureAttributeDescriptor attr
1099
                = fType.getAttributeDescriptor(fType.getDefaultGeometryAttributeIndex());
1100
        GeometryType geomType
1101
                = GeometryLocator.getGeometryManager()
1102
                .getGeometryType(attr.getGeometryType(),
1103
                        attr.getGeometrySubType());
1104
        return geomType;
1105
    }
1106

    
1107
    public static class RegisterPersistence implements Callable {
1108

    
1109
        public Object call() {
1110
            PersistenceManager manager = ToolsLocator.getPersistenceManager();
1111

    
1112
            DynStruct definition
1113
                    = manager.addDefinition(FLyrVect.class,
1114
                            "FLyrVect",
1115
                            "FLyrVect Persistence definition",
1116
                            null,
1117
                            null);
1118
            definition.extend(PersistenceManager.PERSISTENCE_NAMESPACE,
1119
                    "FLyrDefault");
1120

    
1121
            definition.addDynFieldObject("legend")
1122
                    .setClassOfValue(IVectorLegend.class)
1123
                    .setMandatory(true);
1124
            definition.addDynFieldObject("featureStore")
1125
                    .setClassOfValue(FeatureStore.class)
1126
                    .setMandatory(true);
1127
            definition.addDynFieldBoolean("isLabeled").setMandatory(true);
1128
            definition.addDynFieldInt("typeShape").setMandatory(true);
1129
            definition.addDynFieldObject("labelingStrategy")
1130
                    .setClassOfValue(ILabelingStrategy.class)
1131
                    .setMandatory(false);
1132

    
1133
            return Boolean.TRUE;
1134
        }
1135
    }
1136

    
1137
    protected void doDispose() throws BaseException {
1138
        dispose(featureStore);
1139
        spatialCache.clearAll();
1140
    }
1141

    
1142
    /**
1143
     * Returns envelope in layer's data source CRS from envelope provided in
1144
     * viewport CRS
1145
     *
1146
     * @param lyr
1147
     * @param env
1148
     * @return
1149
     */
1150
    public static Envelope fromViewPortCRSToSourceCRS(FLayer lyr, Envelope env) {
1151

    
1152
        if (lyr == null || env == null) {
1153
            return null;
1154
        }
1155

    
1156
        ICoordTrans ct = lyr.getCoordTrans();
1157
        if (ct == null) {
1158
            return env;
1159
        } else {
1160
            return env.convert(ct.getInverted());
1161
        }
1162
    }
1163

    
1164
    public Geometry transformToSourceCRS(Geometry geom, boolean clone) {
1165
        return fromViewPortCRSToSourceCRS(this, geom, clone);
1166
    }
1167

    
1168
    /**
1169
     * Returns geometry in layer's data source CRS from geometry provided in
1170
     * viewport CRS
1171
     *
1172
     * @param lyr
1173
     * @param geo
1174
     * @param clone
1175
     * @return
1176
     * @deprecated use the transformToSourceCRS method of layer.
1177
     */
1178
    public static Geometry fromViewPortCRSToSourceCRS(
1179
            FLayer lyr,
1180
            Geometry geo,
1181
            boolean clone) {
1182

    
1183
        if (lyr == null || geo == null) {
1184
            return null;
1185
        }
1186
        ICoordTrans ct = lyr.getCoordTrans();
1187
        Geometry resp = geo;
1188
        if (clone) {
1189
            resp = resp.cloneGeometry();
1190
        }
1191
        if (ct != null) {
1192
            resp.reProject(ct.getInverted());
1193
        }
1194
        return resp;
1195
    }
1196

    
1197
    public Iterator iterator() {
1198
        return this.getFeatureStore().iterator();
1199
    }
1200
}