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 / FLayers.java @ 46277

History | View | Annotate | Download (46.4 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;
24

    
25
import java.awt.Graphics2D;
26
import java.awt.Point;
27
import java.awt.image.BufferedImage;
28
import java.util.ArrayList;
29
import java.util.Collection;
30
import java.util.Collections;
31
import java.util.Iterator;
32
import java.util.List;
33
import java.util.ListIterator;
34
import java.util.Set;
35
import java.util.TreeSet;
36
import java.util.function.Predicate;
37
import org.apache.commons.lang3.StringUtils;
38
import org.cresques.cts.ICoordTrans;
39
import org.cresques.cts.IProjection;
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.FeatureSelection;
45
import org.gvsig.fmap.dal.feature.FeatureStore;
46
import org.gvsig.fmap.geom.primitive.Envelope;
47
import org.gvsig.fmap.mapcontext.MapContext;
48
import org.gvsig.fmap.mapcontext.MapContextLocator;
49
import org.gvsig.fmap.mapcontext.MapContextRuntimeException;
50
import org.gvsig.fmap.mapcontext.Messages;
51
import org.gvsig.fmap.mapcontext.ViewPort;
52
import org.gvsig.fmap.mapcontext.exceptions.LoadLayerException;
53
import org.gvsig.fmap.mapcontext.layers.operations.ComposedLayer;
54
import org.gvsig.fmap.mapcontext.layers.operations.InfoByPoint;
55
import org.gvsig.fmap.mapcontext.layers.operations.LayerCollection;
56
import org.gvsig.fmap.mapcontext.layers.operations.LayerNotFoundInCollectionException;
57
import org.gvsig.fmap.mapcontext.layers.operations.LayersVisitable;
58
import org.gvsig.fmap.mapcontext.layers.operations.LayersVisitor;
59
import org.gvsig.fmap.mapcontext.layers.operations.SingleLayer;
60
import org.gvsig.fmap.mapcontext.layers.vectorial.FLyrVect;
61
import org.gvsig.fmap.mapcontext.rendering.legend.styling.ILabelable;
62
import org.gvsig.metadata.exceptions.MetadataException;
63
import org.gvsig.tools.ToolsLocator;
64
import org.gvsig.tools.dynobject.DynObjectSet;
65
import org.gvsig.tools.dynobject.DynStruct;
66
import org.gvsig.tools.dynobject.impl.MultiDynObjectSet;
67
import org.gvsig.tools.exception.BaseException;
68
import org.gvsig.tools.persistence.PersistenceManager;
69
import org.gvsig.tools.persistence.PersistentState;
70
import org.gvsig.tools.persistence.exception.PersistenceException;
71
import org.gvsig.tools.task.Cancellable;
72
import org.gvsig.tools.util.Callable;
73
import org.gvsig.tools.visitor.Visitor;
74
import org.slf4j.Logger;
75
import org.slf4j.LoggerFactory;
76

    
77
/**
78
 * <p>
79
 * Represents a generic collection of layers, that can be represented as a node
80
 * in a tree of nodes of layers.</p>
81
 *
82
 * <p>
83
 * Adapts the basic functionality implemented for a layer in the abstract class
84
 * <code>FLyrDefault</code>, to a collection of layers, implementing, as well,
85
 * specific methods for this kind of object, defined in the interfaces
86
 * <code>VectorialData</code>, <code>LayerCollection</code>, and
87
 * <code>InfoByPoint</code>.</p>
88
 *
89
 * @see FLyrDefault
90
 */
91
public class FLayers extends FLyrDefault implements LayerCollection,
92
        InfoByPoint, List<FLayer> {
93

    
94
    /**
95
     * List with all listeners registered for this kind of node.
96
     */
97
    protected ArrayList<LayerCollectionListener> layerCollectionListeners = null;
98

    
99
    /**
100
     * A synchronized list with the layers.
101
     */
102
    protected List<FLayer> layers = null;
103

    
104
    protected MapContext fmap;
105

    
106
    /**
107
     * Useful for debug the problems during the implementation.
108
     */
109
    private static final Logger LOGGER = LoggerFactory.getLogger(FLayers.class);
110
    
111
    public static final Predicate<FLayer> LAYER_ACTIVE = new Predicate<FLayer>() {
112
        @Override
113
        public boolean test(FLayer layer) {
114
            return layer.isActive();
115
        }
116
    };
117

    
118
    public static final Predicate<FLayer> LAYER_AVALAIBLE = new Predicate<FLayer>() {
119
        @Override
120
        public boolean test(FLayer layer) {
121
            return layer.isAvailable();
122
        }
123
    };
124

    
125
    public static Predicate<FLayer> LAYER_FLYRVECT = new Predicate<FLayer>() {
126
        @Override
127
        public boolean test(FLayer layer) {
128
            return layer instanceof FLyrVect;
129
        }
130
    };
131
    public static Predicate<FLayer> LAYER_SELECTION_AVAILABLE = new Predicate<FLayer>() {
132
        @Override
133
        public boolean test(FLayer layer) {
134
            if (layer instanceof FLyrVect) {
135
                try {
136
                    FeatureStore store = ((FLyrVect) layer).getFeatureStore();
137
                    if (store.isFeatureSelectionAvailable()) {
138
                        return true;
139
                    }
140
                } catch (Exception ex) {
141
                    return false;
142
                }
143
            }
144
            return false;
145
        }
146
    };
147
    
148
    public static Predicate<FLayer> LAYER_SELECTION_EMPTY = new Predicate<FLayer>() {
149
        @Override
150
        public boolean test(FLayer layer) {
151
            if (layer instanceof FLyrVect) {
152
                try {
153
                    FeatureStore store = ((FLyrVect) layer).getFeatureStore();
154
                    if (!store.isFeatureSelectionAvailable() || store.isFeatureSelectionEmpty()) {
155
                        return true;
156
                    }
157
                    return false;
158
                } catch (Exception ex) {
159
                    return true;
160
                }
161
            } else {
162
                return true;
163
            }
164
        }
165
    };
166

    
167
    public FLayers() {
168
        super();
169
        layerCollectionListeners = new ArrayList();
170
        layers = Collections.synchronizedList(new ArrayList());
171
    }
172

    
173
    @Override
174
    public void addLayerCollectionListener(LayerCollectionListener listener) {
175
        if (!layerCollectionListeners.contains(listener)) {
176
            layerCollectionListeners.add(listener);
177
        }
178
    }
179

    
180
    /*
181
     * (non-Javadoc)
182
     * @see com.iver.cit.gvsig.fmap.layers.layerOperations.LayerCollection#setAllVisibles(boolean)
183
     */
184
    @Override
185
    public void setAllVisibles(boolean visible) {
186
        FLayer lyr;
187

    
188
        for (int i = 0; i < layers.size(); i++) {
189
            lyr = ((FLayer) layers.get(i));
190
            lyr.setVisible(visible);
191

    
192
            if (lyr instanceof LayerCollection) {
193
                ((LayerCollection) lyr).setAllVisibles(visible);
194
            }
195
        }
196
    }
197

    
198
    @Override
199
    public void removeLayerCollectionListener(LayerCollectionListener listener) {
200
        layerCollectionListeners.remove(listener);
201
    }
202

    
203
    /**
204
     * Adds a layer on an specified position in this node.
205
     *
206
     * @param pos position in the inner list where the layer will be added
207
     * @param layer a layer
208
     */
209
    private void doAddLayer(int pos, FLayer layer) {
210
        layers.add(pos, layer);
211
        ToolsLocator.getDisposableManager().bind(layer);
212
        layer.setParentLayer(this);
213
        IProjection layerProj = layer.getProjection();
214
        if (layerProj != null && fmap != null) {
215
            IProjection mapContextProj = fmap.getProjection();
216
            // TODO REVISAR ESTO !!!!
217
            // Esta condici?n puede que no fuese exacta para todos los casos
218
            if (!layerProj.getAbrev().equals(mapContextProj.getAbrev())) {
219
                ICoordTrans ct = layerProj.getCT(mapContextProj);
220
                layer.setCoordTrans(ct);
221
            } else {
222
                layer.setCoordTrans(null);
223
            }
224
        }
225
        this.updateDrawVersion();
226
    }
227

    
228
    @Override
229
    public void addLayer(FLayer layer) {
230

    
231
        MapContext mco = this.getMapContext();
232

    
233
        if (mco != null) {
234
            /*
235
             * Get order manager from map context
236
             */
237
            int position = mco.getOrderManager().getPosition(this, layer);
238
            addLayer(position, layer);
239
        } else {
240
            /*
241
             * This happens when FLayers object is not in a
242
             * map context, so no order manager is available.
243
             */
244
            addLayer(layers.size(), layer);
245
        }
246
    }
247
    
248
    public void addLayer(DataStore store) {
249
        FLayer layer;
250
        try {
251
            layer = MapContextLocator.getMapContextManager().createLayer(
252
                    store.getName(),
253
                    store
254
            );
255
            
256
        } catch (LoadLayerException ex) {
257
            throw new RuntimeException("Can't create layer from store.", ex);
258
        }
259
        this.addLayer(layer);
260
    }
261

    
262
    /**
263
     * Adds a layer in an specified position in this node.
264
     *
265
     * @param pos
266
     * @param layer a layer
267
     */
268
    public void addLayer(int pos, FLayer layer) {
269
        try {
270
            if (layer instanceof FLayers) {
271
                FLayers layersToAdd = (FLayers) layer;
272
                if( fmap != null ) {
273
                    fmap.addAsCollectionListener(layersToAdd);
274
                }
275
            }
276
            callLayerAdding(LayerCollectionEvent.createLayerAddingEvent(layer));
277

    
278
            doAddLayer(pos, layer);
279

    
280
            callLayerAdded(LayerCollectionEvent.createLayerAddedEvent(layer));
281
        } catch (CancelationException e) {
282
            LOGGER.warn(e.getMessage());
283
        }
284
    }
285

    
286
    @Override
287
    public void moveTo(int from, int to) throws CancelationException {
288
        int newfrom = layers.size() - from - 1;
289
        int newto = layers.size() - to - 1;
290
        if (newfrom < 0 || newfrom >= layers.size() || newto < 0 || newto >= layers.size()) {
291
            return;
292
        }
293
        FLayer aux = (FLayer) layers.get(newfrom);
294
        callLayerMoving(LayerPositionEvent.createLayerMovingEvent(aux, newfrom, newto));
295
        layers.remove(newfrom);
296
        layers.add(newto, aux);
297
        this.updateDrawVersion();
298
        callLayerMoved(LayerPositionEvent.createLayerMovedEvent(aux, newfrom, newto));
299
    }
300

    
301
    /**
302
     * Removes an inner layer.
303
     *
304
     * @param lyr a layer
305
     */
306
    private void doRemoveLayer(FLayer lyr) {
307
        layers.remove(lyr);
308
        lyr.dispose();
309
        this.updateDrawVersion();
310
    }
311

    
312
    @Override
313
    public void removeLayer(FLayer lyr) throws CancelationException {
314
        callLayerRemoving(LayerCollectionEvent.createLayerRemovingEvent(lyr));
315
        doRemoveLayer(lyr);
316
        callLayerRemoved(LayerCollectionEvent.createLayerRemovedEvent(lyr));
317
    }
318

    
319
    @Override
320
    public void removeLayer(int idLayer) {
321
        FLayer lyr = (FLayer) layers.get(idLayer);
322
        callLayerRemoving(LayerCollectionEvent.createLayerRemovingEvent(lyr));
323
        this.doRemoveLayer(lyr);
324
//                layers.remove(idLayer);
325
//                this.updateDrawVersion();
326
        callLayerRemoved(LayerCollectionEvent.createLayerRemovedEvent(lyr));
327
    }
328

    
329
    @Override
330
    public void removeLayer(String layerName) {
331
        FLayer lyr;
332

    
333
        for (int i = 0; i < layers.size(); i++) {
334
            lyr = ((FLayer) layers.get(i));
335

    
336
            if (lyr.getName().compareToIgnoreCase(layerName) == 0) {
337
                removeLayer(i);
338

    
339
                break;
340
            }
341
        }
342
    }
343

    
344
    /**
345
     * Replace a layer identified by its name, by another.
346
     *
347
     * @param layerName the name of the layer to be replaced
348
     * @param layer the new layer
349
     * @throws org.gvsig.fmap.mapcontext.exceptions.LoadLayerException
350
     * @deprecated use {@link FLayers#replaceLayer(FLayer, FLayer)}
351
     */
352
    public void replaceLayer(String layerName, FLayer layer) throws LoadLayerException {
353
        replaceLayer(getLayer(layerName), layer);
354
    }
355

    
356
    /**
357
     * Replace a layer by another layer. It search recursively by all the
358
     * ILayerCollection nodes
359
     *
360
     * @param layer the layer to be replaced
361
     * @param newLayer the new layer
362
     * @throws org.gvsig.fmap.mapcontext.exceptions.LoadLayerException
363
     */
364
    public void replaceLayer(FLayer layer, FLayer newLayer) throws LoadLayerException {
365
        replaceLayer(this, layer, newLayer);
366
    }
367

    
368
    /**
369
     * Replace a layer by other layer. It search recursively by all the
370
     * ILayerCollection nodes
371
     *
372
     * @param parentLayer the parent layer
373
     * @param layer the layer to be replaced
374
     * @param newLayer the new layer
375
     * @throws LoadLayerException
376
     */
377
    private void replaceLayer(FLayers parentLayer, FLayer layer, FLayer newLayer) throws LoadLayerException {
378
        FLayer lyr;
379
        for (int i = 0; i < parentLayer.getLayersCount(); i++) {
380
            lyr = ((FLayer) parentLayer.getLayer(i));
381
            if (lyr.equals(layer)) {
382
                parentLayer.removeLayer(i);
383
                parentLayer.addLayer(i, newLayer);
384
                break;
385
            }
386
            if (lyr instanceof LayerCollection) {
387
                replaceLayer((FLayers) lyr, layer, newLayer);
388
            }
389
        }
390
    }
391

    
392
    @Override
393
    public FLayer[] getVisibles() {
394
        ArrayList array = new ArrayList();
395
        LayersIterator iter = new LayersIterator(this) {
396
            @Override
397
            public boolean evaluate(FLayer layer) {
398
                return layer.isVisible();
399
            }
400

    
401
        };
402

    
403
        while (iter.hasNext()) {
404
            array.add(iter.nextLayer());
405
        }
406

    
407
        return (FLayer[]) array.toArray(new FLayer[0]);
408
    }
409

    
410
    @Override
411
    public FLayer getLayer(int index) {
412
        return (FLayer) layers.get(index);
413
    }
414

    
415
    @Override
416
    public FLayer getLayer(final String layerName) {
417
        if( StringUtils.isBlank(layerName) ) {
418
            return null;
419
        }
420
        for (FLayer layer : this.layers) {
421
            if( layer!=null && StringUtils.equalsIgnoreCase(layer.getName(), layerName) ) {
422
                return layer;
423
            }
424
            if( layer instanceof FLayers ) {
425
                List<FLayer> theLayers = this.getLayers(new Predicate<FLayer>() {
426
                    @Override
427
                    public boolean test(FLayer layer) {
428
                        return StringUtils.equalsIgnoreCase(layer.getName(), layerName);                        
429
                    }
430
                });
431
                if( theLayers.isEmpty() ) {
432
                    return null;
433
                }
434
                return theLayers.get(0);
435
            }
436
        }
437
        return null;
438
    }
439

    
440
    @Override
441
    public FLayer getLayer(final DataStore store) {
442
        List<FLayer> theLayers = this.getLayers(new Predicate<FLayer>() {
443
            @Override
444
            public boolean test(FLayer layer) {
445
                return  layer instanceof SingleLayer && store == ((SingleLayer) layer).getDataStore();
446
            }
447
        });
448
        if( theLayers.isEmpty() ) {
449
            return null;
450
        }
451
        return theLayers.get(0);
452
    }
453
    
454
    private List<FLayer> toPlainList(FLayer layer) {
455
        return toPlainList(layer, new ArrayList<FLayer>(), null);
456
    }
457

    
458
    private List<FLayer> toPlainList(FLayer layer, Predicate<FLayer> filter) {
459
        return toPlainList(layer, new ArrayList<FLayer>(), filter);
460
    }
461

    
462
    private List<FLayer> toPlainList(FLayer layer, List<FLayer> result, Predicate<FLayer> filter) {
463
        if (layer instanceof FLayers) {
464
            FLayers layerGroup = (FLayers) layer;
465
            if (filter == null || filter.test(layer)) {
466
                result.add(layer);
467
            }
468
            for (int i = 0; i < layerGroup.getLayersCount(); i++) {
469
                toPlainList(layerGroup.getLayer(i), result, filter);
470
            }
471
        } else if( filter==null || filter.test(layer) ) {
472
            result.add(layer);
473
        }
474
        return result;
475
    }
476

    
477
    @Override
478
    public int getLayersCount() {
479
        return layers.size();
480
    }
481

    
482
    @Override
483
    public void draw(BufferedImage image, Graphics2D g, ViewPort viewPort,
484
            Cancellable cancel, double scale) throws ReadException {
485
        // FIXME Arreglar este error
486
        throw new RuntimeException("Esto no deberia de llamarse");
487
    }
488

    
489
    /*
490
     * (non-Javadoc)
491
     *
492
     * @see com.iver.cit.gvsig.fmap.layers.FLayer#print(java.awt.Graphics2D,
493
     * com.iver.cit.gvsig.fmap.ViewPort,
494
     * com.iver.utiles.swing.threads.Cancellable, double,
495
     * javax.print.attribute.PrintAttributes)
496
     */
497
    @Override
498
    public void print(Graphics2D g, ViewPort viewPort, Cancellable cancel,
499
            double scale, PrintAttributes properties)
500
            throws ReadException {
501
        throw new RuntimeException("No deberia pasar por aqui");
502
    }
503

    
504
    public void print_old(Graphics2D g, ViewPort viewPort, Cancellable cancel,
505
            double scale, PrintAttributes properties)
506
            throws ReadException {
507
        this.print_old(g, viewPort, cancel, scale, properties, null);
508
    }
509

    
510
    /**
511
     * <p>
512
     * Checks all layers (each one as a sub-node of this node <i>collection of
513
     * layers</i>) of this collection and draws their requested properties. If a
514
     * node is a group of layers (<code>ComposedLayer</code>), executes it's
515
     * drawn.</p>
516
     *
517
     * <p>
518
     * All nodes which could group with the composed layer <code>group</code>,
519
     * will be drawn together. And once the <code>
520
     * group</code> is drawn, will be set to <code>null</code> if hasn't a
521
     * parent layer.</p>
522
     *
523
     * <p>
524
     * The particular implementation depends on the kind of each layer and
525
     * composed layer. And this process can be cancelled at any time by the
526
     * shared object <code>cancel</code>.</p>
527
     *
528
     * <p>
529
     * According the print quality, labels will be printed in different
530
     * resolution:
531
     * <ul>
532
     * <li><b>PrintQuality.DRAFT</b>: 72 dpi (dots per inch).</li>
533
     * <li><b>PrintQuality.NORMAL</b>: 300 dpi (dots per inch).</li>
534
     * <li><b>PrintQuality.HIGH</b>: 600 dpi (dots per inch).</li>
535
     * </ul>
536
     * </p>
537
     *
538
     * @param g for rendering 2-dimensional shapes, text and images on the
539
     * Java(tm) platform
540
     * @param viewPort the information for drawing the layers
541
     * @param cancel shared object that determines if this layer can continue
542
     * being drawn
543
     * @param scale the scale of the view. Must be between
544
     * {@linkplain FLayer#getMinScale()} and {@linkplain FLayer#getMaxScale()}.
545
     * @param properties properties that will be print
546
     * @param group a composed layer pending to paint; if this parameter is
547
     * <code>null</code>, the composed layer
548
     *
549
     * @return <code>null</code> if the layers in <code>group</code> had been
550
     * drawn or were <code>null</code>; otherwise, the <code>group</code>
551
     * @throws org.gvsig.fmap.dal.exception.ReadException
552
     *
553
     * @see FLayer#print(Graphics2D, ViewPort, Cancellable, double,
554
     * PrintAttributes)
555
     */
556
    public ComposedLayer print_old(Graphics2D g, ViewPort viewPort, Cancellable cancel, double scale, PrintAttributes properties, ComposedLayer group)
557
            throws ReadException {
558
        double dpi = 72;
559

    
560
        int resolution = properties.getPrintQuality();
561
        switch (resolution) {
562
            case PrintAttributes.PRINT_QUALITY_NORMAL:
563
                dpi = 300;
564
                break;
565
            case PrintAttributes.PRINT_QUALITY_HIGH:
566
                dpi = 600;
567
                break;
568
            case PrintAttributes.PRINT_QUALITY_DRAFT:
569
                dpi = 72;
570
                break;
571
            default:
572
                break;
573
        }
574

    
575
        // TODO: A la hora de imprimir, isWithinScale falla, porque est?
576
        // calculando la escala en pantalla, no para el layout.
577
        // Revisar esto.
578
        // TODO: We have to check when we have to call the drawLabels method when exists a ComposedLayer group.
579
        for (int i = 0; i < layers.size(); i++) {
580
            FLayer lyr = (FLayer) layers.get(i);
581
            if (!lyr.isVisible() || !lyr.isWithinScale(scale)) {
582
                continue;
583
            }
584

    
585
            try {
586

    
587
                // Checks for draw group (ComposedLayer)
588
                if (group != null) {
589
                    if (lyr instanceof FLayers) {
590
                        group = ((FLayers) lyr).print_old(g, viewPort, cancel, scale, properties, group);
591
                    } else {
592
                        // If layer can be added to the group, does it
593
                        if (lyr instanceof ILabelable
594
                                && ((ILabelable) lyr).isLabeled()
595
                                && ((ILabelable) lyr).getLabelingStrategy() != null
596
                                && ((ILabelable) lyr).getLabelingStrategy().shouldDrawLabels(scale)) {
597
                            group.add(lyr);
598
                        } else {
599
                            // draw the 'pending to draw' layer group
600
                            group.print(g, viewPort, cancel, scale, properties);
601

    
602
                            // gets a new group instance
603
                            if (lyr instanceof ILabelable
604
                                    && ((ILabelable) lyr).isLabeled()
605
                                    && ((ILabelable) lyr).getLabelingStrategy() != null
606
                                    && ((ILabelable) lyr).getLabelingStrategy().shouldDrawLabels(scale)) {
607
                                group = lyr.newComposedLayer();
608
                            } else {
609
                                group = null;
610
                            }
611
                            // if layer hasn't group, draws it inmediately
612
                            if (group == null) {
613
                                if (lyr instanceof FLayers) {
614
                                    group = ((FLayers) lyr).print_old(g, viewPort, cancel, scale, properties, group);
615
                                } else {
616
                                    lyr.print(g, viewPort, cancel, scale, properties);
617
                                    if (lyr instanceof ILabelable
618
                                            && ((ILabelable) lyr).isLabeled()
619
                                            && ((ILabelable) lyr).getLabelingStrategy() != null
620
                                            && ((ILabelable) lyr).getLabelingStrategy().shouldDrawLabels(scale)) {
621
                                        ILabelable lLayer = (ILabelable) lyr;
622
                                        lLayer.drawLabels(null, g, viewPort, cancel, scale, dpi);
623
                                    }
624
                                }
625
                            } else {
626
                                // add the layer to the group
627
                                group.setMapContext(fmap);
628
                                group.add(lyr);
629

    
630
                            }
631

    
632
                        }
633
                    }
634
                } else {
635
                    // gets a new group instance
636
                    group = lyr.newComposedLayer();
637
                    // if layer hasn't group, draws it inmediately
638
                    if (group == null) {
639
                        if (lyr instanceof FLayers) {
640
                            group = ((FLayers) lyr).print_old(g, viewPort, cancel, scale, properties, group);
641
                        } else {
642
                            lyr.print(g, viewPort, cancel, scale, properties);
643
                            if (lyr instanceof ILabelable && ((ILabelable) lyr).isLabeled()) {
644
                                ILabelable lLayer = (ILabelable) lyr;
645

    
646
                                lLayer.drawLabels(null, g, viewPort, cancel, scale, dpi);
647
                            }
648
                        }
649
                    } else {
650
                        // add the layer to the group
651
                        group.setMapContext(fmap);
652
                        group.add(lyr);
653

    
654
                    }
655
                }
656

    
657
            } catch (Exception e) {
658
                String mesg = Messages.getString("error_printing_layer") + " " + lyr.getName() + ": " + e.getMessage();
659
                if( fmap!=null ) {
660
                    fmap.addLayerError(mesg);
661
                }
662
                LOGGER.error(mesg, e);
663
            }
664

    
665
        }
666

    
667
        if (group != null && this.getParentLayer() == null) {
668
            //si tenemos un grupo pendiente de pintar, pintamos
669
            group.print(g, viewPort, cancel, scale, properties);
670
            group = null;
671

    
672
        }
673
        return group;
674
    }
675

    
676
    @Override
677
    @SuppressWarnings("UseSpecificCatch")
678
    public Envelope getFullEnvelope() {
679
        Envelope rAux = null;
680
        boolean first = true;
681

    
682
        for (FLayer capa : layers) {
683
            try {
684
                if (first) {
685
                    rAux = (Envelope) capa.getFullEnvelope().clone();
686
                    first = false;
687
                } else {
688
                    rAux.add(capa.getFullEnvelope());
689
                }
690
            } catch (Exception e) {
691
                LOGGER.warn("Can't calculate the envelope of the layer group '"+this.getName()+"'.",e);
692
            }
693
        }
694

    
695
        return rAux;
696
    }
697

    
698
    /**
699
     * Notifies all listeners associated to this collection of layers, that
700
     * another layer is going to be added or replaced in the internal list of
701
     * layers.
702
     *
703
     * @param event a layer collection event with the new layer
704
     */
705
    protected void callLayerAdding(LayerCollectionEvent event)
706
            throws CancelationException {
707
        ArrayList aux = (ArrayList) layerCollectionListeners.clone();
708
        for (Iterator iter = aux.iterator(); iter.hasNext();) {
709
            ((LayerCollectionListener) iter.next()).layerAdding(event);
710
        }
711
    }
712

    
713
    /**
714
     * Notifies all listeners associated to this collection of layers, that a
715
     * layer is going to be removed from the internal list of layers.
716
     *
717
     * @param event a layer collection event with the layer being removed
718
     *
719
     * @throws CancelationException any exception produced during the
720
     * cancellation of the driver.
721
     */
722
    protected void callLayerRemoving(LayerCollectionEvent event)
723
            throws CancelationException {
724
        ArrayList aux = (ArrayList) layerCollectionListeners.clone();
725
        for (Iterator iter = aux.iterator(); iter.hasNext();) {
726
            ((LayerCollectionListener) iter.next()).layerRemoving(event);
727
        }
728
    }
729

    
730
    /**
731
     * Notifies all listeners associated to this collection of layers, that a
732
     * layer is going to be moved in the internal list of layers.
733
     *
734
     * @param event a layer collection event with the layer being moved, and the
735
     * initial and final positions
736
     *
737
     * @throws CancelationException any exception produced during the
738
     * cancellation of the driver.
739
     */
740
    protected void callLayerMoving(LayerPositionEvent event)
741
            throws CancelationException {
742
        ArrayList aux = (ArrayList) layerCollectionListeners.clone();
743
        for (Iterator iter = aux.iterator(); iter.hasNext();) {
744
            ((LayerCollectionListener) iter.next()).layerMoving(event);
745
        }
746
    }
747

    
748
    /**
749
     * Notifies all listeners associated to this collection of layers, that
750
     * another layer has been added or replaced in the internal list of layers.
751
     *
752
     * @param event a layer collection event with the new layer
753
     */
754
    protected void callLayerAdded(LayerCollectionEvent event) {
755
        ArrayList aux = (ArrayList) layerCollectionListeners.clone();
756
        for (Iterator iter = aux.iterator(); iter.hasNext();) {
757
            ((LayerCollectionListener) iter.next()).layerAdded(event);
758
        }
759
    }
760

    
761
    /**
762
     * Notifies all listeners associated to this collection of layers, that
763
     * another layer has been removed from the internal list of layers.
764
     *
765
     * @param event a layer collection event with the layer removed
766
     */
767
    protected void callLayerRemoved(LayerCollectionEvent event) {
768
        ArrayList aux = (ArrayList) layerCollectionListeners.clone();
769
        for (Iterator iter = aux.iterator(); iter.hasNext();) {
770
            ((LayerCollectionListener) iter.next()).layerRemoved(event);
771
        }
772
    }
773

    
774
    /**
775
     * Notifies all listeners associated to this collection of layers, that
776
     * another layer has been moved in the internal list of layers.
777
     *
778
     * @param event a layer collection event with the layer moved, and the initial
779
     * and final positions
780
     */
781
    protected void callLayerMoved(LayerPositionEvent event) {
782
        ArrayList aux = (ArrayList) layerCollectionListeners.clone();
783
        for (Iterator iter = aux.iterator(); iter.hasNext();) {
784
            ((LayerCollectionListener) iter.next()).layerMoved(event);
785
        }
786
    }
787

    
788
    @Override
789
    public void saveToState(PersistentState state) throws PersistenceException {
790

    
791
        super.saveToState(state);
792

    
793
        state.set("mapContext", fmap);
794

    
795
        List layersToSave = new ArrayList();
796
        for (FLayer layer : this.layers) {
797
            if (!layer.isTemporary()) {
798
                layersToSave.add(layer);
799
            }
800
        }
801
        state.set("layers", layersToSave);
802
    }
803

    
804
    @Override
805
    public void loadFromState(PersistentState state) throws PersistenceException {
806

    
807
        super.loadFromState(state);
808

    
809
        setMapContext((MapContext) state.get("mapContext"));
810
        Iterator iter = state.getIterator("layers");
811
        while (iter.hasNext()) {
812
            FLayer item = (FLayer) iter.next();
813
            if(item == null){
814
                continue;
815
            }
816
            if (item instanceof FLayers) {
817
                FLayers layersToAdd = (FLayers) item;
818
                if (fmap != null) {
819
                    fmap.addAsCollectionListener(layersToAdd);
820
                }
821
            }
822

    
823
            // Cuando falla la carga de la capa desde la persistencia, puede
824
            // haberse perdido quien es el parent. Asi que lo asignamos aqui
825
            // por si acaso.
826
            item.setParentLayer(this);
827
            layers.add(item);
828
        }
829
    }
830

    
831
    @Override
832
    public MapContext getMapContext() {
833
        return fmap;
834
    }
835

    
836
    @Override
837
    public void setAllActives(boolean active) {
838
        FLayer lyr;
839

    
840
        for (int i = 0; i < layers.size(); i++) {
841
            lyr = ((FLayer) layers.get(i));
842
            lyr.setActive(active);
843

    
844
            if (lyr instanceof LayerCollection) {
845
                ((LayerCollection) lyr).setAllActives(active);
846
            }
847
        }
848
    }
849

    
850
    @Override
851
    public List<FLayer> getLayers(Predicate<FLayer> filter) {
852
        List<FLayer> theLayers = this.toPlainList(this, filter);
853
        return theLayers;
854
    }
855
    
856
    @Override
857
    public FLayer[] getActives() {
858
        List<FLayer> activeLayers = this.getLayers(new Predicate<FLayer>() {
859
            @Override
860
            public boolean test(FLayer layer) {
861
                return layer.isActive();
862
            }
863
        });
864
        return (FLayer[]) activeLayers.toArray(new FLayer[activeLayers.size()]);
865
    }
866
                   
867
    @Override
868
    public double getMinScale() {
869
        return -1; // La visibilidad o no la controla cada capa
870
        // dentro de una colecci?n
871
    }
872

    
873
    @Override
874
    public double getMaxScale() {
875
        return -1;
876
    }
877

    
878
    @Override
879
    public void setMinScale(double minScale) {
880
        for (FLayer lyr : layers) {
881
            lyr.setMinScale(minScale);
882
        }
883
    }
884

    
885
    @Override
886
    public void setMaxScale(double maxScale) {
887
        for (FLayer lyr : layers) {
888
            lyr.setMinScale(maxScale);
889
        }
890
    }
891

    
892
    @Override
893
    public void setActive(boolean b) {
894
        super.setActive(b);
895
        for (FLayer layer : this.layers) {
896
            layer.setActive(b);
897
        }
898
    }
899

    
900
    public void setActive(boolean active, boolean applySublayers) {
901
        super.setActive(active);
902
        if(applySublayers){
903
            for (FLayer layer : this.layers) {
904
                layer.setActive(active);
905
            }
906
        }
907
    }
908

    
909
    @Override
910
    public boolean addLayerListener(LayerListener o) {
911
        for (FLayer layer : this.layers) {
912
            layer.addLayerListener(o);
913
        }
914
        return true;
915
    }
916

    
917
    @Override
918
    public DynObjectSet getInfo(Point p, double tolerance,
919
            Cancellable cancel) throws LoadLayerException, DataException {
920
        return getInfo(this.getMapContext().getViewPort().convertToMapPoint(p), tolerance);
921
    }
922

    
923
    @Override
924
    public DynObjectSet getInfo(Point p, double tolerance, Cancellable cancel,
925
            boolean fast) throws LoadLayerException, DataException {
926
        return getInfo(this.getMapContext().getViewPort().convertToMapPoint(p), tolerance);
927
    }
928

    
929
    @Override
930
    public DynObjectSet getInfo(org.gvsig.fmap.geom.primitive.Point p,
931
            double tolerance) throws LoadLayerException, DataException {
932
        int i;
933
        FLayer layer;
934
        List res = new ArrayList();
935
        for (i = 0; i < this.layers.size(); i++) {
936
            layer = (FLayer) layers.get(i);
937
            if (layer instanceof InfoByPoint) {
938
                InfoByPoint queryable_layer = (InfoByPoint) layer;
939
                res.add(queryable_layer.getInfo(p, tolerance));
940
            }
941
        }
942
        DynObjectSet[] innerSets
943
                = (DynObjectSet[]) res.toArray(new DynObjectSet[res.size()]);
944
        return new MultiDynObjectSet(innerSets);
945
    }
946

    
947
    @Override
948
    public String getTocImageIcon() {
949
        return "layer-icon-group";
950
    }
951

    
952
    /**
953
     * <p>
954
     * Sets the <code>MapContext</code> that contains this layer node.</p>
955
     *
956
     * @param mapContext the <code>MapContext</code> that contains this layer
957
     * node
958
     */
959
    public void setMapContext(MapContext mapContext) {
960
        this.fmap = mapContext;
961
        for (FLayer lyr : this.layers) {
962
            if(lyr instanceof FLayers){
963
                ((FLayers)lyr).setMapContext(mapContext);
964
            }
965
        }
966
    }
967

    
968
    @Override
969
    public void accept(Visitor visitor) throws BaseException {
970
        for (int i = 0; i < this.getLayersCount(); i++) {
971
            FLayer layer = this.getLayer(i);
972
//            try {
973
                if (layer instanceof LayersVisitable) {
974
                    ((LayersVisitable) layer).accept(visitor);
975
                } else {
976
                    visitor.visit(layer);
977
                }
978
//            } catch (VisitCanceledException ex) {
979
//                break;
980
//            }
981
        }
982
    }
983

    
984
    @Override
985
    public void accept(LayersVisitor visitor) throws BaseException {
986
        for (int i = 0; i < this.getLayersCount(); i++) {
987
            FLayer layer = this.getLayer(i);
988
            if (layer instanceof LayersVisitable) {
989
                ((LayersVisitable) layer).accept(visitor);
990
            } else {
991
                visitor.visit(layer);
992
            }
993
        }
994
    }
995

    
996
    @Override
997
    public Object getMetadataID() throws MetadataException {
998
        StringBuilder strb = new StringBuilder();
999
        strb.append("Layers(");
1000
        strb.append(this.getName());
1001
        strb.append("):{");
1002
        Iterator iter = this.layers.iterator();
1003
        while (iter.hasNext()) {
1004
            strb.append(((FLayer) iter.next()).getMetadataID());
1005
            strb.append(",");
1006
        }
1007
        strb.append("}");
1008
        return strb.toString();
1009

    
1010
    }
1011

    
1012
    @Override
1013
    public Set getMetadataChildren() {
1014
        Set ret = new TreeSet();
1015
        Iterator iter = this.layers.iterator();
1016
        while (iter.hasNext()) {
1017
            ret.add(iter.next());
1018
        }
1019
        return ret;
1020
    }
1021

    
1022
    @Override
1023
    public String getMetadataName() throws MetadataException {
1024
        StringBuilder strb = new StringBuilder();
1025
        strb.append("Layer Group '");
1026
        strb.append(this.getName());
1027
        strb.append("': {");
1028
        Iterator iter = this.layers.iterator();
1029
        while (iter.hasNext()) {
1030
            strb.append(((FLayer) iter.next()).getMetadataName());
1031
            strb.append(",");
1032
        }
1033
        strb.append("}");
1034
        return strb.toString();
1035
    }
1036

    
1037
    @Override
1038
    public void beginDraw(Graphics2D g, ViewPort viewPort) {
1039
        if( fmap == null ) {
1040
            return;
1041
        }
1042
        LayerDrawEvent beforeEvent = new LayerDrawEvent(this, g, viewPort, LayerDrawEvent.LAYER_BEFORE_DRAW);
1043
        fmap.fireLayerDrawingEvent(beforeEvent);
1044
    }
1045

    
1046
    @Override
1047
    public void endDraw(Graphics2D g, ViewPort viewPort) {
1048
        if( fmap == null ) {
1049
            return;
1050
        }
1051
        LayerDrawEvent afterEvent = new LayerDrawEvent(this, g, viewPort, LayerDrawEvent.LAYER_AFTER_DRAW);
1052
        fmap.fireLayerDrawingEvent(afterEvent);
1053
    }
1054

    
1055
    public static class RegisterPersistence implements Callable {
1056

    
1057
        @Override
1058
        public Object call() {
1059

    
1060
            PersistenceManager manager = ToolsLocator.getPersistenceManager();
1061
            DynStruct definition = manager.addDefinition(
1062
                    FLayers.class,
1063
                    "FLayers",
1064
                    "FLayers Persistence definition",
1065
                    null,
1066
                    null
1067
            );
1068
            definition.extend(PersistenceManager.PERSISTENCE_NAMESPACE, "FLyrDefault");
1069

    
1070
            definition.addDynFieldObject("mapContext").setClassOfValue(MapContext.class).setMandatory(true);
1071
            definition.addDynFieldList("layers").setClassOfItems(FLayer.class).setMandatory(true);
1072

    
1073
            return Boolean.TRUE;
1074
        }
1075
    }
1076

    
1077
    @Override
1078
    protected void doDispose() throws BaseException {
1079
        if (layers != null) {
1080
            for (FLayer layer : this.layers) {
1081
                dispose(layer);
1082
            }
1083
        }
1084
    }
1085

    
1086
    @Override
1087
    public void move(FLayer layer, LayerCollection group, int where, FLayer adjoiningLayer) throws LayerNotFoundInCollectionException {
1088

    
1089
        callLayerRemoving(LayerCollectionEvent.createLayerRemovingEvent(layer));
1090
        group.addLayer(layer, where, adjoiningLayer);
1091
        removeLayer(layer);
1092
        this.updateDrawVersion();
1093
        callLayerRemoved(LayerCollectionEvent.createLayerRemovedEvent(layer));
1094

    
1095
    }
1096

    
1097
    public void join(FLayer layer, LayerCollection group) {
1098
        try {
1099
            layers.remove(layer);
1100
            group.addLayer(layer, END, null);
1101
            this.updateDrawVersion();
1102
        } catch (LayerNotFoundInCollectionException e) {
1103
            throw new MapContextRuntimeException(e);
1104
        }
1105
    }
1106

    
1107
    @Override
1108
    public void move(FLayer layer, LayerCollection group) {
1109
        try {
1110
            move(layer, group, END, null);
1111
        } catch (LayerNotFoundInCollectionException e) {
1112
            throw new MapContextRuntimeException(e);
1113
        }
1114
    }
1115

    
1116
    @Override
1117
    public void addLayer(FLayer layer, int where, FLayer adjoiningLayer)
1118
            throws LayerNotFoundInCollectionException {
1119

    
1120
        switch (where) {
1121
            case BEGIN:
1122
                addLayer(0, layer);
1123
                break;
1124
            case BEFORE:
1125
                if (adjoiningLayer != null) {
1126
                    if (this.layers.contains(adjoiningLayer)) {
1127
                        for (int i = 0; i < this.getLayersCount(); i++) {
1128
                            if (adjoiningLayer == this.getLayer(i)) {
1129
                                addLayer(i, layer);
1130
                                break;
1131
                            }
1132
                        }
1133
                    } else {
1134
                        throw new LayerNotFoundInCollectionException(adjoiningLayer, this);
1135
                    }
1136
                } else {
1137
                    addLayer(0, layer);
1138
                }
1139
                break;
1140
            case AFTER:
1141
                if (adjoiningLayer != null) {
1142
                    if (this.layers.contains(adjoiningLayer)) {
1143
                        for (int i = 0; i < this.getLayersCount(); i++) {
1144
                            if (adjoiningLayer == this.getLayer(i)) {
1145
                                addLayer(i + 1, layer);
1146
                                break;
1147
                            }
1148
                        }
1149
                    } else {
1150
                        throw new LayerNotFoundInCollectionException(adjoiningLayer, this);
1151
                    }
1152
                } else {
1153
                    this.addLayer(layer);
1154
                }
1155
                break;
1156
            default: // By default add layer an the end of the collection
1157
                this.addLayer(layer);
1158
                break;
1159
        }
1160

    
1161
    }
1162

    
1163
    public FLayer getFirstActiveLayer() {
1164
        List<FLayer> theLayers = this.getLayers(LAYER_ACTIVE);
1165
        if( theLayers.isEmpty() ) {
1166
            return null;
1167
        }
1168
        return theLayers.get(0);
1169
    }
1170

    
1171
    public FLyrVect getFirstActiveVectorLayer() {
1172
        List<FLayer> theLayers = this.getLayers(LAYER_ACTIVE.and(LAYER_FLYRVECT));
1173
        if( theLayers.isEmpty() ) {
1174
            return null;
1175
        }
1176
        return (FLyrVect) theLayers.get(0);
1177
    }
1178
    
1179
    @Override
1180
    public Iterator<FLayer> iterator() {
1181
        return this.layers.iterator();
1182
    }
1183

    
1184
    public Iterator<FLayer> deepiterator() {
1185
        List theLayers = toPlainList(this);
1186
        return theLayers.iterator();
1187
    }
1188
    
1189
    @Override
1190
    public int size() {
1191
        return this.layers.size();
1192
    }
1193
    
1194
    @Override
1195
    public FLayer get(int index) {
1196
        return this.layers.get(index);
1197
    }
1198
    
1199
    @Override
1200
    public boolean isEmpty() {
1201
        return this.layers.isEmpty();
1202
    }
1203

    
1204
    @Override
1205
    public boolean contains(Object o) {
1206
        return this.layers.contains(o);
1207
    }
1208

    
1209
    @Override
1210
    public Object[] toArray() {
1211
        return this.layers.toArray();
1212
    }
1213

    
1214
    @Override
1215
    public Object[] toArray(Object[] ts) {
1216
        return this.layers.toArray(ts);
1217
    }
1218

    
1219
    @Override
1220
    public boolean add(FLayer e) {
1221
        this.addLayer(e);
1222
        return true;
1223
    }
1224

    
1225
    @Override
1226
    public boolean remove(Object o) {
1227
        this.removeLayer((FLayer) o);
1228
        return true;
1229
    }
1230

    
1231
    @Override
1232
    public boolean containsAll(Collection clctn) {
1233
        return this.layers.containsAll(clctn);
1234
    }
1235

    
1236
    @Override
1237
    public void add(int i, FLayer e) {
1238
        this.addLayer(i, (FLayer) e);
1239
    }
1240

    
1241
    @Override
1242
    public FLayer remove(int i) {
1243
        FLayer o = this.getLayer(i);
1244
        this.removeLayer(i);
1245
        return o;
1246
    }
1247

    
1248
    @Override
1249
    public int indexOf(Object o) {
1250
        return this.layers.indexOf(o);
1251
    }
1252

    
1253
    @Override
1254
    public int lastIndexOf(Object o) {
1255
        return this.layers.lastIndexOf(o);
1256
    }
1257

    
1258
    @Override
1259
    public ListIterator listIterator() {
1260
        return this.layers.listIterator();
1261
    }
1262

    
1263
    @Override
1264
    public ListIterator listIterator(int i) {
1265
        return this.layers.listIterator(i);
1266
    }
1267

    
1268
    @Override
1269
    public List subList(int i, int i1) {
1270
        return this.layers.subList(i, i1);
1271
    }
1272
    
1273
    @Override
1274
    public boolean addAll(Collection clctn) {
1275
        Iterator it = clctn.iterator();
1276
        while( it.hasNext() ) {
1277
            this.add((FLayer) it.next());
1278
        }
1279
        return true;
1280
    }
1281

    
1282
    @Override
1283
    public boolean addAll(int i, Collection clctn) {
1284
        Iterator it = clctn.iterator();
1285
        while( it.hasNext() ) {
1286
            this.add(i, (FLayer) it.next());
1287
        }
1288
        return true;
1289
    }
1290

    
1291
    @Override
1292
    public boolean removeAll(Collection clctn) {
1293
        Iterator it = clctn.iterator();
1294
        while( it.hasNext() ) {
1295
            this.remove((FLayer) it.next());
1296
        }
1297
        return true;
1298
    }
1299

    
1300
    @Override
1301
    public boolean retainAll(Collection clctn) {
1302
        Iterator it = this.layers.iterator();
1303
        while( it.hasNext() ) {
1304
            Object o = it.next();
1305
            if( !clctn.contains(o) ) {
1306
                this.remove((FLayer) o);
1307
            }
1308
        }
1309
        return true;
1310
    }
1311

    
1312
    @Override
1313
    public FLayer set(int i, FLayer e) {
1314
        throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
1315
    }
1316

    
1317
    public FLayers createFLayerGroup(String name) {            
1318
        FLayers group = new FLayers();
1319
        group.setMapContext(this.getMapContext());
1320
        group.setParentLayer(this);
1321
        group.setName(name);
1322
        return group;
1323
    }
1324

    
1325
    @Override
1326
    public FLayers cloneLayer() throws Exception {
1327
        FLayers cloned = new FLayers();
1328
        
1329
        cloned.fmap = this.fmap;
1330
        for (FLayer layer : this.layers) {
1331
            FLayer l = layer.cloneLayer();
1332
            l.setParentLayer(cloned);
1333
            cloned.add(l);
1334
        }
1335
        for (LayerCollectionListener layerCollectionListener : this.layerCollectionListeners) {
1336
            cloned.addLayerCollectionListener(layerCollectionListener);
1337
        }
1338
        for (LayerListener layerListener : this.layerListeners) {
1339
            cloned.addLayerListener(layerListener);
1340
        }
1341
        cloned.setTransparency(this.getTransparency());
1342
        cloned.setMaxScale(this.getMaxScale());
1343
        cloned.setMinScale(this.getMinScale());
1344
        cloned.setCoordTrans(this.getCoordTrans());
1345
        cloned.setFLayerStatus(this.getFLayerStatus());
1346
        cloned.setTemporary(this.isTemporary());
1347
        cloned.setTocStatusImage(this.getTocStatusImage());
1348
        cloned.metadataContainer = this.metadataContainer;
1349
        cloned.setParentLayer(this.getParentLayer());
1350
        cloned.properties = this.properties;
1351
        
1352
        return cloned;
1353
    }
1354

    
1355
    @Override
1356
    public void clear() {
1357
        //Don't clear layer list for compatibility with older code
1358
//        this.layers.clear();
1359
        super.clear();
1360
    }
1361

    
1362
    public void clearMetadata() {
1363
        super.clear();
1364
    }
1365

    
1366
    /**
1367
     * Remove all layers of this object.
1368
     */
1369
    public void clearLayers() {
1370
        this.layers.clear();
1371
        this.updateDrawVersion();
1372
    }
1373
    
1374
    
1375
    
1376
    
1377
}