Statistics
| Revision:

svn-gvsig-desktop / branches / org.gvsig.desktop-2018a / 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 @ 43847

History | View | Annotate | Download (43.3 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.io.File;
31
import java.util.Iterator;
32
import java.util.Set;
33
import java.util.TreeSet;
34
import java.util.logging.Level;
35
import java.util.logging.Logger;
36

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

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

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

    
113
    final static private org.slf4j.Logger logger
114
        = LoggerFactory.getLogger(FLyrVect.class);
115
    private final GeometryManager geomManager
116
        = GeometryLocator.getGeometryManager();
117

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

    
126
    /**
127
     * An implementation of gvSIG spatial index
128
     */
129
    // protected ISpatialIndex spatialIndex = null;
130
    private IVectorLegend loadLegend = null;
131

    
132
    private boolean isLabeled;
133
    protected ILabelingStrategy strategy;
134
//        private ReprojectDefaultGeometry reprojectTransform;
135
    private FeatureQuery baseQuery = null;
136

    
137
    public FLyrVect() {
138
        super();
139
    }
140

    
141
    @Override
142
    public String getTocImageIcon() {
143
        return MapContextLocator.getMapContextManager().getIconLayer(this.getDataStore());
144
    }
145

    
146
    /**
147
     * Return the store associated to the layer.
148
     *
149
     * @return the store
150
     */
151
    @Override
152
    public DataStore getDataStore() {
153
        return featureStore;
154
    }
155

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

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

    
179
        featureStore = (FeatureStore) dataStore;
180

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

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

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

    
192
        this.setLegend(legend);
193

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

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

    
205
        this.delegate(dataStore);
206

    
207
        dataStore.addObserver(this);
208

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

    
212
    @Override
213
    public Envelope getFullEnvelope() throws ReadException {
214
        Envelope rAux;
215
        if( getFeatureStore() == null ) {
216
            return null;
217
        }
218
        try {
219
            rAux = getFeatureStore().getEnvelope();
220
        } catch (BaseException e) {
221
            throw new ReadException(getName(), e);
222
        }
223

    
224
        if( rAux==null || rAux.isEmpty() ) {
225
            return null;
226
        }
227
        if( rAux.getMaximum(0) - rAux.getMinimum(0) == 0
228
            && rAux.getMaximum(1) - rAux.getMinimum(1) == 0 ) {
229
            logger.info("The envelope of the layer '"+this.getName()+"' is zero, get as null.");
230
            return null;
231
        }
232
        // Si existe reproyecci?n, reproyectar el extent
233
        ICoordTrans ct = getCoordTrans();
234
        if( ct != null ) {
235
            boolean originalEnvelopeIsEmpty = rAux.isEmpty();
236
            rAux = rAux.convert(ct);
237
            if( !originalEnvelopeIsEmpty && rAux.isEmpty() ) {
238
                try {
239
                    this.setAvailable(false);
240
                    throw new EnvelopeCantBeInitializedException();
241
                } catch (EnvelopeCantBeInitializedException e) {
242
                    this.addError(e);
243
                }
244
            }
245
        }
246
        return rAux;
247

    
248
    }
249

    
250
    public void setBaseQuery(FeatureQuery baseQuery) {
251
        this.baseQuery = baseQuery;
252
    }
253

    
254
    @Override
255
    public FeatureQuery getBaseQuery() {
256
        return this.baseQuery;
257
    }
258

    
259
    public void addBaseFilter(Evaluator filter) {
260
        if( this.baseQuery == null ) {
261
            this.baseQuery = this.getFeatureStore().createFeatureQuery();
262
        }
263
        this.baseQuery.addFilter(filter);
264
    }
265

    
266
    public void addBaseFilter(String filter) {
267
        try {
268
            this.addBaseFilter(DALLocator.getDataManager().createExpresion(filter));
269
        } catch (InitializeException ex) {
270
            throw new RuntimeException("Can't create filter with '" + filter + "'", ex);
271
        }
272
    }
273

    
274
    /**
275
     * Draws using IFeatureIterator. This method will replace the old draw(...)
276
     * one.
277
     *
278
     * @autor jaume dominguez faus - jaume.dominguez@iver.es
279
     * @param image
280
     * @param g
281
     * @param viewPort
282
     * @param cancel
283
     * @param scale
284
     * @throws ReadDriverException
285
     */
286
    public void draw(BufferedImage image,
287
        Graphics2D g,
288
        ViewPort viewPort,
289
        Cancellable cancel,
290
        double scale) throws ReadException {
291

    
292
        if( legend == null ) {
293
            return;
294
        }
295

    
296
        if( !this.isWithinScale(scale) ) {
297
            return;
298
        }
299
        if( cancel.isCanceled() ) {
300
            return;
301
        }
302

    
303
        if( spatialCache.isEnabled() ) {
304
            spatialCache.clearAll();
305
            legend.addDrawingObserver(this);
306
        }
307

    
308
        FeatureQuery featureQuery = createFeatureQuery();
309

    
310
        try {
311
            FeatureAttributeDescriptor featureAttributeDescriptor
312
                = getFeatureStore().getDefaultFeatureType().getDefaultTimeAttribute();
313

    
314
            if( (viewPort.getTime() != null) && (featureAttributeDescriptor != null) ) {
315
                IntersectsTimeEvaluator intersectsTimeEvaluator
316
                    = new IntersectsTimeEvaluator(viewPort.getTime(), featureAttributeDescriptor.getName());
317
                featureQuery.addFilter(intersectsTimeEvaluator);
318
            }
319
        } catch (DataException e1) {
320
            logger.error("Impossible to get the temporal filter", e1);
321
        }
322

    
323
        try {
324

    
325
            long tini = System.currentTimeMillis();
326

    
327
            legend.draw(image,
328
                g,
329
                viewPort,
330
                cancel,
331
                scale,
332
                null,
333
                getCoordTrans(),
334
                getFeatureStore(),
335
                featureQuery);
336

    
337
            logger.debug("Layer " + this.getName() + " drawn in "
338
                + (System.currentTimeMillis() - tini) + " milliseconds.");
339

    
340
        } catch (LegendException e) {
341
            this.setAvailable(false);
342
            this.setError(e);
343
            throw new ReadException(getName(), e);
344
        } finally {
345
            if( spatialCache.isEnabled() ) {
346
                legend.deleteDrawingObserver(this);
347
            }
348
        }
349
    }
350

    
351
    public void print(Graphics2D g,
352
        ViewPort viewPort,
353
        Cancellable cancel,
354
        double scale,
355
        PrintAttributes properties) throws ReadException {
356
        if( !this.isWithinScale(scale) ) {
357
            return;
358
        }
359
        if( cancel.isCanceled() ) {
360
            return;
361
        }
362
        FeatureQuery featureQuery = createFeatureQuery();
363

    
364
        try {
365
            legend.print(g,
366
                viewPort,
367
                cancel,
368
                scale,
369
                null,
370
                getCoordTrans(),
371
                getFeatureStore(),
372
                featureQuery,
373
                properties);
374

    
375
        } catch (LegendException e) {
376
            this.setVisible(false);
377
            this.setActive(false);
378
            throw new ReadException(getName(), e);
379
        }
380
    }
381

    
382
    public void setLegend(IVectorLegend legend) throws LegendLayerException {
383
        if( this.legend == legend ) {
384
            return;
385
        }
386
        if( this.legend != null && this.legend.equals(legend) ) {
387
            return;
388
        }
389
        IVectorLegend oldLegend = this.legend;
390
        this.legend = legend;
391
        if( oldLegend != null ) {
392
            oldLegend.removeLegendListener(this);
393
            oldLegend.deleteDrawingObserver(this);
394
        }
395
        if( legend != null ) {
396
            this.legend.addDrawingObserver(this);
397
            this.legend.addLegendListener(this);
398
        }
399
        LegendChangedEvent e = LegendChangedEvent.createLegendChangedEvent(oldLegend, this.legend);
400
        e.setLayer(this);
401
        updateDrawVersion();
402
        callLegendChanged(e);
403
    }
404

    
405
    /**
406
     * Devuelve la Leyenda de la capa.
407
     *
408
     * @return Leyenda.
409
     */
410
    public ILegend getLegend() {
411
        return legend;
412
    }
413

    
414
    public int getShapeType() throws ReadException {
415
        if( typeShape == -1 ) {
416
            FeatureType featureType = null;
417
            try {
418
                if( getDataStore() != null ) {
419
                    featureType
420
                        = (((FeatureStore) getDataStore()).getDefaultFeatureType());
421
                }
422
            } catch (DataException e) {
423
                throw new ReadException(getName(), e);
424
            }
425
            if( featureType != null ) {
426
                int indexGeom = featureType.getDefaultGeometryAttributeIndex();
427
                typeShape
428
                    = featureType.getAttributeDescriptor(indexGeom).getGeometryType();
429
            }
430
        }
431
        return typeShape;
432
    }
433

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

    
455
    public void saveToState(PersistentState state) throws PersistenceException {
456

    
457
        FeatureStore featureStore = null;
458

    
459
        if( !this.isAvailable() ) {
460
            logger.info("The '" + this.getName() + "' layer is not available, it will persist not.");
461
            return;
462
        }
463

    
464
        try {
465
            super.saveToState(state);
466

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

    
471
            featureStore = getFeatureStore();
472

    
473
            if( featureStore != null ) {
474
                state.set("featureStore", featureStore);
475
            }
476

    
477
            state.set("isLabeled", isLabeled);
478

    
479
            if( strategy != null ) {
480
                state.set("labelingStrategy", strategy);
481
            }
482

    
483
            if( getLinkProperties() != null ) {
484
                state.set("linkProperties", getLinkProperties());
485
            }
486

    
487
            state.set("typeShape", typeShape);
488
        } catch (PersistenceException ex) {
489
            logger.warn("Can't persist to state the layer '" + this.getName() + "'.", ex);
490
            throw ex;
491
        } catch (RuntimeException ex) {
492
            logger.warn("Can't persist to state the layer '" + this.getName() + "'.", ex);
493
            throw ex;
494
        }
495

    
496
    }
497

    
498
    @Override
499
    public void loadFromState(PersistentState state) throws PersistenceException {
500

    
501
        FeatureStore store = null;
502
        try {
503
            super.loadFromState(state);
504

    
505
            this.setIsLabeled(false);
506
            this.setLabelingStrategy(null);
507

    
508
            typeShape = state.getInt("typeShape", Geometry.TYPES.GEOMETRY);
509

    
510
            store = (FeatureStore) state.get("featureStore");
511
            if( store == null ) { // Averiguar como puede llegar aqui un null.
512
                this.setAvailable(false);
513
                this.addError(new RuntimeException("Can't retrieve store information."));
514
            } else {
515
                if( store.isBroken() ) {
516
                    this.setAvailable(false);
517
                    this.addError(store.getBreakingsCause());
518
                }
519
            }
520
            try {
521
                this.bindToDataStore(store);
522
            } catch (Exception ex) {
523
                this.setAvailable(false);
524
                this.addError(ex);
525
            }
526

    
527
            try {
528
                IVectorLegend vectorLegend = (IVectorLegend) state.get("legend");
529
                this.setLegend(vectorLegend);
530
            } catch (Exception ex) {
531
                this.setAvailable(false);
532
                this.addError(ex);
533
            }
534

    
535
            try {
536
                if( state.getBoolean("isLabeled", false) ) {
537
                    this.setIsLabeled(true);
538
                    ILabelingStrategy labelingStrategy = (ILabelingStrategy) state.get("labelingStrategy");
539
                    this.setLabelingStrategy(labelingStrategy);
540
                }
541
            } catch (Exception ex) {
542
                this.setAvailable(false);
543
                this.addError(ex);
544
            }
545

    
546
        } catch (Throwable e) {
547
            String storeName = (store == null) ? "unknow" : store.getFullName();
548
            logger.warn("can't load layer '" + this.getName() + "' (store=" + storeName + ") from persisted state.", e);
549
            this.setAvailable(false);
550
            this.addError(e);
551
        }
552

    
553
    }
554

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

    
568
        return ret; //"layer" + ret.substring(ret.indexOf('@') + 1);
569
    }
570

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

    
584
    public void setEditing(boolean b) throws StartEditionLayerException {
585

    
586
        try {
587
            throw new RuntimeException();
588
        } catch (Throwable th) {
589
            logger.info("This method is deprecated. ", th);
590
        }
591

    
592
        if( b == super.isEditing() ) {
593
            return;
594
        }
595

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

    
609
    /**
610
     * @deprecated Use {@link #getSpatialCache()}
611
     */
612
    public void clearSpatialCache() {
613
        spatialCache.clearAll();
614
    }
615

    
616
    /**
617
     * @deprecated Use {@link #getSpatialCache()}
618
     */
619
    public boolean isSpatialCacheEnabled() {
620
        return spatialCache.isEnabled();
621
    }
622

    
623
    /**
624
     * @deprecated Use {@link #getSpatialCache()}
625
     */
626
    public void setSpatialCacheEnabled(boolean spatialCacheEnabled) {
627
        spatialCache.setEnabled(spatialCacheEnabled);
628
    }
629

    
630
    public SpatialCache getSpatialCache() {
631
        return spatialCache;
632
    }
633

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

    
644
    }
645

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

    
657
    public void reload() throws ReloadLayerException {
658
        super.reload();
659
        try {
660
            getFeatureStore().refresh();
661
        } catch (Exception e) {
662
            throw new ReloadLayerException(getName(), e);
663
        }
664
    }
665

    
666
    protected void setLoadSelection(Object xml) {
667
        // this.loadSelection = xml;
668
    }
669

    
670
    protected void setLoadLegend(IVectorLegend legend) {
671
        this.loadLegend = legend;
672
    }
673

    
674
    protected void putLoadSelection() {
675
        // if (this.loadSelection == null) return;
676
        // try {
677
        // this.getRecordset().getSelectionSupport().setXMLEntity(this.loadSelection);
678
        // } catch (ReadDriverException e) {
679
        // throw new XMLException(e);
680
        // }
681
        // this.loadSelection = null;
682

    
683
    }
684

    
685
    protected void putLoadLegend() throws LegendLayerException {
686
        if( this.loadLegend == null ) {
687
            return;
688
        }
689
        this.setLegend(this.loadLegend);
690
        this.loadLegend = null;
691
    }
692

    
693
    protected void cleanLoadOptions() {
694
        this.loadLegend = null;
695
    }
696

    
697
    public boolean isWritable() {
698
        return getFeatureStore().allowWrite();
699
    }
700

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

    
712
        clonedLayer.setLegend((IVectorLegend) getLegend().cloneLegend());
713

    
714
        clonedLayer.setIsLabeled(isLabeled());
715
        ILabelingStrategy labelingStrategy = getLabelingStrategy();
716
        if( labelingStrategy != null ) {
717
            clonedLayer.setLabelingStrategy(labelingStrategy);
718
        }
719

    
720
        return clonedLayer;
721
    }
722

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

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

    
744
            Envelope geomBounds = geom.getEnvelope();
745

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

    
754
            onePoint
755
                = (geomBounds.getLength(0) <= dist1Pixel && geomBounds.getLength(1) <= dist1Pixel);
756

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

    
773
            }
774

    
775
        }
776
        return onePoint;
777
    }
778

    
779
    public boolean isLabeled() {
780
        return isLabeled;
781
    }
782

    
783
    public void setIsLabeled(boolean isLabeled) {
784
        this.isLabeled = isLabeled;
785
    }
786

    
787
    public ILabelingStrategy getLabelingStrategy() {
788
        return strategy;
789
    }
790

    
791
    public void setLabelingStrategy(ILabelingStrategy strategy) {
792
        this.strategy = strategy;
793
        if( strategy == null ) {
794
            return;
795
        }
796
        strategy.setLayer(this);
797
        updateDrawVersion();
798
    }
799

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

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

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

    
830
    public void load() throws LoadLayerException {
831
        super.load();
832
    }
833

    
834
    public FeatureStore getFeatureStore() {
835
        return (FeatureStore) getDataStore();
836
    }
837

    
838
    public FeatureQuery createFeatureQuery() {
839
        if( this.baseQuery == null ) {
840
            return this.getFeatureStore().createFeatureQuery();
841
        }
842
        try {
843
            return (FeatureQuery) baseQuery.clone();
844
        } catch (CloneNotSupportedException ex) {
845
            throw new RuntimeException(ex);
846
        }
847
    }
848

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

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

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

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

    
914
    }
915

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

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

    
951
        Envelope query_env = fromViewPortCRSToSourceCRS(this, envelope);
952
        IProjection query_proj = getMapContext().getProjection();
953
        if( this.getCoordTrans() != null ) {
954
            query_proj = this.getCoordTrans().getPOrig();
955
        }
956

    
957
        Evaluator iee = SpatialEvaluatorsFactory.getInstance().intersects(
958
            query_env.getGeometry(),
959
            query_proj,
960
            featureStore
961
        );
962
        featureQuery.setFilter(iee);
963
        return getFeatureStore().getFeatureSet(featureQuery);
964

    
965
    }
966

    
967
    public DynObjectSet getInfo(Point p, double tolerance, Cancellable cancel) throws LoadLayerException,
968
        DataException {
969

    
970
        return getInfo(p, tolerance, cancel, true);
971
    }
972

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

    
984
    public DynObjectSet getInfo(org.gvsig.fmap.geom.primitive.Point p,
985
        double tolerance) throws LoadLayerException, DataException {
986
        return queryByPoint(p, tolerance, getFeatureStore().getDefaultFeatureType()).getDynObjectSet(false);
987
    }
988

    
989
    @Override
990
    public void legendCleared(LegendClearEvent event) {
991
        this.updateDrawVersion();
992
        LegendChangedEvent e = LegendChangedEvent.createLegendChangedEvent(legend, event);
993
        this.callLegendChanged(e);
994
    }
995

    
996
    @Override
997
    public boolean symbolChanged(SymbolLegendEvent e) {
998
        this.updateDrawVersion();
999
        LegendChangedEvent ev = LegendChangedEvent.createLegendChangedEvent(legend, e);
1000
        this.callLegendChanged(ev);
1001
        return true;
1002
    }
1003

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

    
1019
                } else if( event.getType() == FeatureStoreNotification.AFTER_CANCELEDITING ) {
1020

    
1021
                    setSpatialCacheEnabled(false);
1022
                    callEditionChanged(LayerEvent.createEditionChangedEvent(this, "edition"));
1023
                    this.updateDrawVersion();
1024

    
1025
                } else if( event.getType() == FeatureStoreNotification.AFTER_STARTEDITING ) {
1026

    
1027
                    setSpatialCacheEnabled(true);
1028
                    callEditionChanged(LayerEvent.createEditionChangedEvent(this, "edition"));
1029

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

    
1058
    private boolean isLayerToSnap() {
1059

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

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

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

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

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

    
1119
    public static class RegisterPersistence
1120
        implements Callable {
1121

    
1122
        public Object call() {
1123
            PersistenceManager manager = ToolsLocator.getPersistenceManager();
1124

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

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

    
1146
            return Boolean.TRUE;
1147
        }
1148
    }
1149

    
1150
    protected void doDispose() throws BaseException {
1151
        dispose(featureStore);
1152
        spatialCache.clearAll();
1153
    }
1154

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

    
1165
        if( lyr == null || env == null ) {
1166
            return null;
1167
        }
1168

    
1169
        ICoordTrans ct = lyr.getCoordTrans();
1170
        if( ct == null ) {
1171
            return env;
1172
        } else {
1173
            return env.convert(ct.getInverted());
1174
        }
1175
    }
1176

    
1177
    public Geometry transformToSourceCRS(Geometry geom, boolean clone) {
1178
        return fromViewPortCRSToSourceCRS(this, geom, clone);
1179
    }
1180

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

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

    
1210
    public Iterator iterator() {
1211
        return this.getFeatureStore().iterator();
1212
    }
1213

    
1214
    protected class EnvelopeCantBeInitializedException
1215
        extends BaseException {
1216

    
1217
        /**
1218
         *
1219
         */
1220
        private static final long serialVersionUID = 4572797479347381552L;
1221
        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.";
1222
        private final static String MESSAGE_KEY = "_EnvelopeCantBeInitializedException";
1223

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

    
1229
    @Override
1230
    public String getInfoString() {
1231
        LayerInformationBuilder builder = MapContextLocator.getMapContextManager().createLayerInformationBuilder();
1232

    
1233
        if( !this.isAvailable() ) {
1234
            builder.title().labelkey("Warning");
1235
            builder.text().value("The layer is not available.");
1236
        }
1237
        
1238
        Envelope env = null;
1239
        FeatureAttributeDescriptor attrgeom = null;
1240
        
1241
        try {
1242
            env = this.getFullEnvelope();
1243
        } catch (Exception ex) {
1244
        }
1245
        FeatureStore store = this.getFeatureStore();
1246
        try {
1247
            FeatureType ft = store.getDefaultFeatureType();
1248
            attrgeom = ft.getDefaultGeometryAttribute();
1249
        } catch (Exception ex) {
1250
        }
1251

    
1252
        builder.title().labelkey("Data_source");
1253
        builder.property().labelkey("Source_type").value(store.getProviderName());
1254
        builder.property().labelkey("origen").value(store.getFullName());
1255
        if( store.getParameters() instanceof FilesystemStoreParameters ) {
1256
            File f = ((FilesystemStoreParameters) (store.getParameters())).getFile();
1257
            if( f != null && f.exists() ) {
1258
                builder.property().labelkey("_Size").value("%d bytes", f.length());
1259
            }
1260
        }
1261
        if( attrgeom != null ) {
1262
            builder.property().labelkey("_Geometry_column").value(attrgeom.getName());
1263
            builder.property().labelkey("_Geometry_type").value(attrgeom.getGeomType().getFullName());
1264
        }
1265

    
1266
        builder.title().labelkey("_Coordenadas_geograficas");
1267
        if( this.isAvailable() ) {
1268
            builder.envelope().value(env);
1269
        }
1270

    
1271
        builder.title().labelkey("_Projection");
1272
        if( this.isAvailable() ) {
1273
            builder.property().value(this.getProjection());
1274
            builder.text().asWKT(this.getProjection());
1275
        }
1276
        return builder.toString();
1277
    }
1278

    
1279
}