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 / MapContext.java @ 44369

History | View | Annotate | Download (63.8 KB)

1 40559 jjdelcerro
/**
2
 * gvSIG. Desktop Geographic Information System.
3 40435 jjdelcerro
 *
4 40559 jjdelcerro
 * Copyright (C) 2007-2013 gvSIG Association.
5 40435 jjdelcerro
 *
6 42286 jjdelcerro
 * 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 40435 jjdelcerro
 *
11 42286 jjdelcerro
 * 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 40435 jjdelcerro
 *
16 42286 jjdelcerro
 * 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 40435 jjdelcerro
 *
20 42286 jjdelcerro
 * For any additional information, do not hesitate to contact us at info AT
21
 * gvsig.com, or visit our website www.gvsig.com.
22 40435 jjdelcerro
 */
23
package org.gvsig.fmap.mapcontext;
24
25
import java.awt.Color;
26
import java.awt.Graphics;
27
import java.awt.Graphics2D;
28
import java.awt.geom.Rectangle2D;
29
import java.awt.image.BufferedImage;
30
import java.util.ArrayList;
31 44245 jjdelcerro
import java.util.Collection;
32 42293 jjdelcerro
import java.util.Iterator;
33 44224 jjdelcerro
import java.util.LinkedHashMap;
34 40435 jjdelcerro
import java.util.List;
35 44224 jjdelcerro
import java.util.Map;
36 43147 jjdelcerro
import org.apache.commons.lang3.ArrayUtils;
37 40435 jjdelcerro
38
import org.cresques.cts.ICoordTrans;
39
import org.cresques.cts.IProjection;
40
import org.cresques.geo.Projected;
41
import org.slf4j.Logger;
42
import org.slf4j.LoggerFactory;
43
44
import org.gvsig.compat.CompatLocator;
45
import org.gvsig.compat.print.PrintAttributes;
46 43618 jjdelcerro
import org.gvsig.fmap.dal.DataStore;
47 40435 jjdelcerro
import org.gvsig.fmap.dal.exception.ReadException;
48
import org.gvsig.fmap.dal.feature.FeatureStoreNotification;
49
import org.gvsig.fmap.geom.Geometry.SUBTYPES;
50
import org.gvsig.fmap.geom.GeometryLocator;
51
import org.gvsig.fmap.geom.GeometryManager;
52
import org.gvsig.fmap.geom.exception.CreateEnvelopeException;
53
import org.gvsig.fmap.geom.primitive.Envelope;
54
import org.gvsig.fmap.mapcontext.events.ErrorEvent;
55
import org.gvsig.fmap.mapcontext.events.listeners.AtomicEventListener;
56
import org.gvsig.fmap.mapcontext.events.listeners.ErrorListener;
57
import org.gvsig.fmap.mapcontext.events.listeners.EventBuffer;
58
import org.gvsig.fmap.mapcontext.exceptions.LoadLayerException;
59 41302 jjdelcerro
import org.gvsig.fmap.mapcontext.impl.DefaultMapContextManager;
60 43640 jjdelcerro
import org.gvsig.fmap.mapcontext.layers.BaseLayerCollectionListener;
61 40435 jjdelcerro
import org.gvsig.fmap.mapcontext.layers.FLayer;
62
import org.gvsig.fmap.mapcontext.layers.FLayers;
63
import org.gvsig.fmap.mapcontext.layers.LayerCollectionEvent;
64
import org.gvsig.fmap.mapcontext.layers.LayerCollectionListener;
65
import org.gvsig.fmap.mapcontext.layers.LayerDrawEvent;
66
import org.gvsig.fmap.mapcontext.layers.LayerDrawingListener;
67
import org.gvsig.fmap.mapcontext.layers.LayerPositionEvent;
68
import org.gvsig.fmap.mapcontext.layers.operations.Classifiable;
69
import org.gvsig.fmap.mapcontext.layers.operations.SingleLayer;
70 40713 jldominguez
import org.gvsig.fmap.mapcontext.layers.order.LayerOrderManager;
71 41245 jjdelcerro
import org.gvsig.fmap.mapcontext.layers.vectorial.FLyrVect;
72 40435 jjdelcerro
import org.gvsig.fmap.mapcontext.layers.vectorial.GraphicLayer;
73 44244 jjdelcerro
import org.gvsig.fmap.mapcontext.layers.vectorial.VectorLayer;
74 40435 jjdelcerro
import org.gvsig.fmap.mapcontext.rendering.legend.events.listeners.LegendListener;
75
import org.gvsig.fmap.mapcontext.rendering.strategies.SelectedEnvelopeVisitor;
76 43618 jjdelcerro
import org.gvsig.timesupport.AbsoluteInstant;
77
import org.gvsig.timesupport.AbsoluteIntervalTypeNotRegisteredException;
78
import org.gvsig.timesupport.Instant;
79
import org.gvsig.timesupport.Interval;
80
import org.gvsig.timesupport.RelativeInstant;
81
import org.gvsig.timesupport.TimeSupportLocator;
82
import org.gvsig.timesupport.TimeSupportManager;
83 40435 jjdelcerro
import org.gvsig.tools.ToolsLocator;
84
import org.gvsig.tools.dispose.impl.AbstractDisposable;
85
import org.gvsig.tools.dynobject.DynStruct;
86
import org.gvsig.tools.exception.BaseException;
87
import org.gvsig.tools.observer.Observable;
88
import org.gvsig.tools.observer.Observer;
89
import org.gvsig.tools.persistence.PersistenceManager;
90
import org.gvsig.tools.persistence.Persistent;
91
import org.gvsig.tools.persistence.PersistentState;
92
import org.gvsig.tools.persistence.exception.PersistenceException;
93
import org.gvsig.tools.task.Cancellable;
94 41840 jjdelcerro
import org.gvsig.tools.util.Callable;
95 40435 jjdelcerro
import org.gvsig.tools.visitor.Visitor;
96
97
/**
98 42286 jjdelcerro
 * <p>
99
 * The <code>MapContext</code> class represents the model and a part of the
100
 * control and view around graphical layers used by
101
 * {@link MapControl MapControl}.</p>
102 40435 jjdelcerro
 *
103 42286 jjdelcerro
 * <p>
104
 * An instance of <code>MapContext</code> is made up with:
105 40435 jjdelcerro
 * <ul>
106
 * <li>a hierarchy of {@link FLayers FLayers} nodes
107
 * <li>a {@link GraphicLayer GraphicLayer} layer
108
 * <li>a {@link ViewPort ViewPort}
109
 * <li>an {@link EventBuffer EventButter}
110 42286 jjdelcerro
 * <li>some
111
 * {@link com.iver.cit.gvsig.fmap.layers.LegendListener LegendListener}s
112 40435 jjdelcerro
 * <li>some {@link LayerDrawingListener LayerDrawingListener}s
113
 * <li>some {@link ErrorListener ErrorListener}s
114
 * </ul>
115
 * </p>
116
 */
117
public class MapContext extends AbstractDisposable implements Projected,
118 42513 jjdelcerro
        Persistent, Observer, Iterable<FLayer> {
119 40435 jjdelcerro
120 43618 jjdelcerro
    public interface MapTimeContext {
121
        public Interval getInterval();
122
        public List<Instant> getTimes();
123
    }
124
125 42286 jjdelcerro
    /**
126
     * @deprecated use getDistanceTrans2Meter()
127
     */
128
    public static final double[] CHANGEM = {1000, 1, 0.01, 0.001, 1609.344,
129
        0.9144, 0.3048, 0.0254, 1 / 8.983152841195214E-6};
130 40435 jjdelcerro
131 42286 jjdelcerro
    public static ArrayList AREANAMES = new ArrayList();
132
    public static ArrayList AREAABBR = new ArrayList();
133
    public static ArrayList AREATRANS2METER = new ArrayList();
134 40435 jjdelcerro
135 42286 jjdelcerro
    public static ArrayList DISTANCENAMES = new ArrayList();
136
    public static ArrayList DISTANCEABBR = new ArrayList();
137
    public static ArrayList DISTANCETRANS2METER = new ArrayList();
138 40435 jjdelcerro
139 42286 jjdelcerro
    static {
140
        MapContext.addDistanceUnit("Kilometros", "Km", 1000);
141
        MapContext.addDistanceUnit("Metros", "m", 1);
142
        MapContext.addDistanceUnit("Centimetros", "cm", 0.01);
143
        MapContext.addDistanceUnit("Milimetros", "mm", 0.001);
144
        MapContext.addDistanceUnit("Millas", "mi", 1609.344);
145
        MapContext.addDistanceUnit("Yardas", "Ya", 0.9144);
146
        MapContext.addDistanceUnit("Pies", "ft", 0.3048);
147
        MapContext.addDistanceUnit("Pulgadas", "inche", 0.0254);
148
        MapContext.addDistanceUnit("Grados", "?", 1 / 8.983152841195214E-6);
149 40435 jjdelcerro
150 42286 jjdelcerro
        MapContext.addAreaUnit("Kilometros", "Km", true, 1000);
151
        MapContext.addAreaUnit("Metros", "m", true, 1);
152
        MapContext.addAreaUnit("Centimetros", "cm", true, 0.01);
153
        MapContext.addAreaUnit("Milimetros", "mm", true, 0.001);
154
        MapContext.addAreaUnit("Millas", "mi", true, 1609.344);
155
        MapContext.addAreaUnit("Yardas", "Ya", true, 0.9144);
156
        MapContext.addAreaUnit("Pies", "ft", true, 0.3048);
157
        MapContext.addAreaUnit("Pulgadas", "inche", true, 0.0254);
158
        MapContext.addAreaUnit("Grados", "?", true, 1 / 8.983152841195214E-6);
159 40435 jjdelcerro
160
    }
161
162 42286 jjdelcerro
    private static final GeometryManager geomManager = GeometryLocator.getGeometryManager();
163
164
    private static final MapContextManager mapContextManager = MapContextLocator
165
            .getMapContextManager();
166
167
    private static final Logger logger = LoggerFactory.getLogger(MapContext.class);
168
169
    /**
170
     * <p>
171
     * Determines the number of frames.</p>
172
     *
173
     * <p>
174
     * Number of updates per second that the timer will invoke repaint this
175
     * component.</p>
176
     */
177 40435 jjdelcerro
    private static int drawFrameRate = 3;
178 42286 jjdelcerro
179 40435 jjdelcerro
    /**
180 42286 jjdelcerro
     * <p>
181
     * Returns the draw frame rate.</p>
182
     *
183
     * <p>
184
     * Draw frame rate is the number of repaints of this <code>MapControl</code>
185
     * instance that timer invokes per second.</p>
186
     *
187
     * @return number of repaints of this <code>MapControl</code> instance that
188
     * timer invokes per second
189
     *
190
     * @see #applyFrameRate()
191
     * @see #setDrawFrameRate(int)
192
     */
193
    public static int getDrawFrameRate() {
194
        return drawFrameRate;
195
    }
196 40435 jjdelcerro
197 42286 jjdelcerro
    /**
198
     * <p>
199
     * Sets the draw frame rate.</p>
200
     *
201
     * <p>
202
     * Draw frame rate is the number of repaints of this <code>MapControl</code>
203
     * instance that timer invokes per second.</p>
204
     *
205
     * @param drawFrameRate number of repaints of this <code>MapControl</code>
206
     * instance that timer invokes per second
207
     *
208
     * @see #applyFrameRate()
209
     * @see #getDrawFrameRate()
210
     */
211
    public static void setDrawFrameRate(int dFR) {
212
        drawFrameRate = dFR;
213
    }
214 40435 jjdelcerro
215 42286 jjdelcerro
    public static void addAreaUnit(String name, String abbr, boolean isLinear, double trans2meter) {
216
        if (!AREANAMES.contains(name)) {
217
            AREANAMES.add(name);
218
            String pow = "";
219
            if (isLinear) {
220
                pow = String.valueOf((char) 178);
221
            }
222
            AREAABBR.add(abbr + pow);
223
            AREATRANS2METER.add(new Double(trans2meter));
224
        }
225
    }
226 40435 jjdelcerro
227 42286 jjdelcerro
    public static String[] getAreaNames() {
228
        return (String[]) AREANAMES.toArray(new String[0]);
229
    }
230
231
    public static String[] getAreaAbbr() {
232
        return (String[]) AREAABBR.toArray(new String[0]);
233
    }
234
235
    public static double[] getAreaTrans2Meter() {
236
        int size = AREATRANS2METER.size();
237
        double[] trans2meters = new double[size];
238
        for (int i = 0; i < size; i++) {
239
            trans2meters[i] = ((Double) AREATRANS2METER.get(i)).doubleValue();
240
        }
241
        return trans2meters;
242
    }
243
244
    public static String getOfLinear(int i) {
245
        if (((String) AREAABBR.get(i)).toLowerCase().endsWith(String.valueOf((char) 178))) {
246
            return String.valueOf((char) 178);
247
        }
248
        return "";
249
    }
250
251
    public static void addDistanceUnit(String name, String abbr, double trans2meter) {
252
        if (!DISTANCENAMES.contains(name)) {
253
            DISTANCENAMES.add(name);
254
            DISTANCEABBR.add(abbr);
255
            DISTANCETRANS2METER.add(new Double(trans2meter));
256
        }
257
    }
258
259
    public static String[] getDistanceNames() {
260
        return (String[]) DISTANCENAMES.toArray(new String[0]);
261
    }
262
263
    public String getDistanceName() {
264
        return (String) DISTANCENAMES.get(this.getViewPort().getDistanceUnits());
265
    }
266
267
    public static String[] getDistanceAbbr() {
268
        return (String[]) DISTANCEABBR.toArray(new String[0]);
269
    }
270
271
    public static double[] getDistanceTrans2Meter() {
272
        int size = DISTANCETRANS2METER.size();
273
        double[] trans2meters = new double[size];
274
        for (int i = 0; i < size; i++) {
275
            trans2meters[i] = ((Double) DISTANCETRANS2METER.get(i)).doubleValue();
276
        }
277
        return trans2meters;
278
    }
279
280
    public static int getDistancePosition(String s) {
281
        for (int i = 0; i < DISTANCENAMES.size(); i++) {
282
            if (DISTANCENAMES.get(i).equals(s)) {
283
                return i;
284
            }
285
        }
286
        return 0;
287
    }
288
289
    /**
290
     * <p>
291
     * Defines the value which a unit of a distance measurement must be divided
292
     * to obtain its equivalent <b>in centimeters</b>.</p>
293
     *
294
     * <p>
295
     * <b><i>Conversion values of distance measurements:</i></b>
296
     * <ul>
297
     * <li><code>MapContext.CHANGE[0]</code>: kilometer
298
     * <li><code>MapContext.CHANGE[1]</code>: meter
299
     * <li><code>MapContext.CHANGE[2]</code>: centimeter
300
     * <li><code>MapContext.CHANGE[3]</code>: millimeter
301
     * <li><code>MapContext.CHANGE[4]</code>: international statute mile
302
     * <li><code>MapContext.CHANGE[5]</code>: yard
303
     * <li><code>MapContext.CHANGE[6]</code>: foot
304
     * <li><code>MapContext.CHANGE[7]</code>: inch
305
     * <li><code>MapContext.CHANGE[8]</code>: grade
306
     * </ul>
307
     *
308
     * <p>
309
     * <h3>Examples:</h3>
310
     * <pre>1 international statute mile / MapContext.CHANGE[4] = X centimeters</pre>
311
     * <pre>1 kilometer / MapContext.CHANGE[0] = X centimeters</pre>
312
     * <pre>1 grade / MapContext.CHANGE[8] = X centimeters</pre>
313
     * </p>
314
     *
315
     * <p>
316
     * <h3>Grade conversion value: <code>MapContext.CHANGE[8]</code></h3>
317
     * The value of <code>MapContext.CHANGE[8]</code> represents the centimeters
318
     * of a straight line between two points on the Earth surface that are 1
319
     * grade far each other of the center of the Earth. This value has been
320
     * calculated using a radius approximated of
321
     * R<sub>Earth</sub>=6.37846082678100774672e6 meters, according these
322
     * equations:
323
     * <pre>D = 2 * (sin (1)) * R<sub>Earth</sub></pre>
324
     * <pre>MapContext.CHANGE[8] = 1 / D</pre>
325
     * <h4>Explanation:</h4>
326
     * We get an isosceles triangle with the center of the Earth and the 2
327
     * points on the surface. This triangle can be divided into two rectangle
328
     * triangles. We know two values, the angle of 1 grade, that will be 0.50
329
     * grades in each triangle, and the Earth radius that is the hypotenuse.
330
     * Then we apply trigonometry and get the distance <i>D</i> between both
331
     * points on the Earth surface.</p>
332
     * <p>
333
     * Now we only must invert that value to obtain
334
     * <code>MapContext.CHANGE[8]</code>.</p>
335
     *
336
     * @deprecated use getDistanceTrans2Meter() * 100
337
     */
338
    public static final double[] CHANGE = {100000, 100, 1, 0.1, 160934.4,
339
        91.44, 30.48, 2.54, 1 / 8.983152841195214E-4};
340
341
    /* Do not alter the order and the values of this array, if you need append values.*/
342
    /**
343
     * <p>
344
     * Gets the name of all distance measurements supported by
345
     * <code>MapContext</code>.</p>
346
     */
347 40435 jjdelcerro
//        public static final String[] NAMES= {
348
//                Messages.getString("Kilometros"),
349
//                Messages.getString("Metros"),
350
//                Messages.getString("Centimetros"),
351
//                Messages.getString("Milimetros"),
352
//                Messages.getString("Millas"),
353
//                Messages.getString("Yardas"),
354
//                Messages.getString("Pies"),
355
//                Messages.getString("Pulgadas"),
356
//                Messages.getString("Grados"),
357
//        };
358 42286 jjdelcerro
    public static final int EQUALS = 0;
359 40435 jjdelcerro
360 42286 jjdelcerro
    public static final int DISJOINT = 1;
361 40435 jjdelcerro
362 42286 jjdelcerro
    public static final int INTERSECTS = 2;
363 40435 jjdelcerro
364 42286 jjdelcerro
    public static final int TOUCHES = 3;
365 40435 jjdelcerro
366 42286 jjdelcerro
    public static final int CROSSES = 4;
367 40435 jjdelcerro
368 42286 jjdelcerro
    public static final int WITHIN = 5;
369 40435 jjdelcerro
370 42286 jjdelcerro
    public static final int CONTAINS = 6;
371 40435 jjdelcerro
372 42286 jjdelcerro
    public static final int OVERLAPS = 7;
373 40435 jjdelcerro
374 42286 jjdelcerro
    /**
375
     * A hierarchy of {@link FLayers FLayers} nodes.
376
     *
377
     * @see #getLayers()
378
     * @see #print(Graphics2D, double, PrintAttributes)
379
     */
380
    protected FLayers layers;
381 40435 jjdelcerro
382 42286 jjdelcerro
    /**
383
     * A layer with graphical items: geometries and symbols.
384
     *
385
     * @see #getGraphicsLayer()
386
     * @see #setGraphicsLayer(GraphicLayer)
387
     * @see #print(Graphics2D, double, PrintAttributes)
388
     */
389 44224 jjdelcerro
//    private GraphicLayer tracLayer = null;
390
    private static final String DEFAULT_TRACTLAYER = "Default";
391 44244 jjdelcerro
    private Map<String, VectorLayer> tracLayers;
392 42286 jjdelcerro
    //MapContextLocator.getMapContextManager().createGraphicsLayer(getProjection());
393 40435 jjdelcerro
394 42286 jjdelcerro
    /**
395
     * Information for draw layers in a view.
396
     *
397
     * @see #getViewPort()
398
     * @see #setViewPort(ViewPort)
399
     */
400
    private ViewPort viewPort;
401 40435 jjdelcerro
402
        // private ArrayList invalidationListeners = new ArrayList();
403 42286 jjdelcerro
    /**
404
     * Array list with all {@link LegendListener LegendListener} registered to
405
     * this map.
406
     *
407
     * @see #addLayerListener(LegendListener)
408
     * @see #removeLayerListener(LegendListener)
409
     * @see #callLegendChanged()
410
     */
411
    private ArrayList legendListeners = new ArrayList();
412 40435 jjdelcerro
413 42286 jjdelcerro
    /**
414
     * Array list with all {@link LayerDrawingListener LayerDrawingListener}
415
     * registered to this map.
416
     *
417
     * @see #addLayerDrawingListener(LayerDrawingListener)
418
     * @see #removeLayerDrawListener(LayerDrawingListener)
419
     * @see #fireLayerDrawingEvent(LayerDrawEvent)
420
     */
421
    private ArrayList layerDrawingListeners = new ArrayList();
422 40435 jjdelcerro
423 42286 jjdelcerro
    /**
424
     * <p>
425
     * Buffer that is used to store and eject events produced on this map:
426
     * <ul>
427
     * <li>Layer collection events.
428
     * <li>View port events.
429
     * <li>Atomic events.
430
     * <li>Layer events.
431
     * <li>Legend events on a {@link Classificable Classificable} layer.
432
     * <li>Selection events on an {@link AlphanumericData AlphanumericData} data
433
     * layer.
434
     * </ul>
435
     * </p>
436
     *
437
     * @see #addAtomicEventListener(AtomicEventListener)
438
     * @see #removeAtomicEventListener(AtomicEventListener)
439
     * @see #beginAtomicEvent()
440
     * @see #endAtomicEvent()
441
     */
442
    private EventBuffer eventBuffer = new EventBuffer();
443 40435 jjdelcerro
444 42286 jjdelcerro
    /**
445
     * Event listener for the collection of layers of this map.
446
     */
447
    private LayerEventListener layerEventListener = null;
448 40435 jjdelcerro
449 42286 jjdelcerro
    /**
450
     * List with information of all errors produced on all layers.
451
     *
452
     * @see #addLayerError(String)
453
     * @see #getLayersError()
454
     * @see #clearErrors()
455
     */
456
    private ArrayList layersError = new ArrayList();
457 40435 jjdelcerro
458 42286 jjdelcerro
    /**
459
     * Array list with all {@link ErrorListener ErrorListener} registered to
460
     * this map.
461
     *
462
     * @see #addErrorListener(ErrorListener)
463
     * @see #removeErrorListener(LegendListener)
464
     * @see #reportDriverExceptions(String, List)
465
     */
466
    private ArrayList errorListeners = new ArrayList();
467 40435 jjdelcerro
468 42286 jjdelcerro
    /**
469
     * Layer order manager decides position of layers added to this map context.
470
     */
471 40713 jldominguez
    private LayerOrderManager orderManager = null;
472 40435 jjdelcerro
473
        // public static ResourceBundle myResourceBundle =
474 42286 jjdelcerro
    // ResourceBundle.getBundle("FMap");
475
    /**
476
     * <p>
477
     * Default <i>zoom in</i> factor.</p>
478
     * <p>
479
     * Doing a <i>zoom in</i> operation, decreases the focal distance and
480
     * increases the eyesight angle to the surface. This allows view an smaller
481
     * area but with the items bigger.</p>
482
     */
483
    public static double ZOOMINFACTOR = 2;
484 40435 jjdelcerro
485 42286 jjdelcerro
    /**
486
     * <p>
487
     * Default <i>zoom out</i> factor.</p>
488
     * <p>
489
     * Doing a <i>zoom out</i> operation, increases the focal distance and
490
     * decreases the eyesight angle to the surface. This allows view a bigger
491
     * area but with the items smaller.</p>
492
     */
493
    public static double ZOOMOUTFACTOR = 0.5;
494 40435 jjdelcerro
495 42286 jjdelcerro
    /**
496
     *          * Draw version of the context. It's used for know when de componend has
497
     * changed any visualization property
498
     *
499
     * @see getDrawVersion
500
     * @see updateDrawVersion
501
     */
502
    private long drawVersion = 0L;
503 40435 jjdelcerro
504 42286 jjdelcerro
    private long layersVersion = 0L;
505
    private long viewPortVersion = 0L;
506
    private long graphicsLayerVersion = 0L;
507 41245 jjdelcerro
508 42286 jjdelcerro
    /**
509
     * Object to Manage Draw of MapContext
510
     */
511
    private MapContextDrawer mapContextDrawer = null;
512 41245 jjdelcerro
513 42286 jjdelcerro
    /**
514
     * Object to Manage Draw of MapContext
515
     */
516
    private Class mapContextDrawerClass = null;
517 41245 jjdelcerro
518 42286 jjdelcerro
    /**
519
     * <p>
520
     * Color used to represent the selections.</p>
521
     */
522
    private static Color selectionColor = Color.YELLOW;
523
    private ArrayList layersToSnap = new ArrayList();
524 40435 jjdelcerro
525 42286 jjdelcerro
    /**
526
     * <p>
527
     * Gets the color used to represent the selections.</p>
528
     *
529
     * @return color used to represent the selections
530
     */
531
    public static Color getSelectionColor() {
532
        return selectionColor;
533
    }
534 40435 jjdelcerro
535 42286 jjdelcerro
    /**
536
     * <p>
537
     * Sets the color used to represent the selections.</p>
538
     *
539
     * @param selectionColor color used to represent the selections
540
     */
541
    public static void setSelectionColor(Color selectionColor) {
542
        MapContext.selectionColor = selectionColor;
543
    }
544 40435 jjdelcerro
545 42286 jjdelcerro
    /**
546
     * <p>
547
     * Creates a new map context with the drawing information defined in the
548
     * view port argument, and without layers.</p>
549
     *
550
     * @param vp information for drawing the layers of this map in the available
551
     * rectangular area according a projection
552
     */
553
    public MapContext(ViewPort vp) {
554 40435 jjdelcerro
        this(new FLayers(), vp);
555 42286 jjdelcerro
    }
556 40435 jjdelcerro
557 42286 jjdelcerro
    public MapContext() {
558 44240 jjdelcerro
        this.tracLayers = new LinkedHashMap<>();
559
        layerEventListener = new LayerEventListener();
560 42286 jjdelcerro
    }
561 40435 jjdelcerro
562 42286 jjdelcerro
    /**
563
     * <p>
564
     * Creates a new map context with the layers and the drawing information
565
     * defined in the view port arguments.</p>
566
     *
567
     * @param fLayers the initial hierarchy of nodes of layers that this map
568
     * will have
569
     * @param vp information for drawing the layers of this map in the available
570
     * rectangular area according a projection
571
     */
572
    public MapContext(FLayers fLayers, ViewPort vp) {
573 44240 jjdelcerro
        this();
574 42286 jjdelcerro
        this.layers = fLayers;
575
        if (layers != null) {
576
            layers.setMapContext(this);
577
            layers.addLayerCollectionListener(layerEventListener);
578
            layers.addLayerCollectionListener(eventBuffer);
579
        }
580
        setViewPort(vp);
581
    }
582 40435 jjdelcerro
583 42286 jjdelcerro
    /**
584
     * <p>
585
     * Reports to all driver error listeners registered of a bundle of driver
586
     * exceptions caused in the same map atomic transaction.</p>
587
     *
588
     * @param introductoryText introductory text specified by developer. If
589
     * <code>null</code>, use ""
590
     * @param driverExceptions list with a bundle of driver exceptions caught
591
     * during an atomic event
592
     *
593
     * @see #addErrorListener(ErrorListener)
594
     * @see #removeErrorListener(LegendListener)
595
     */
596
    public synchronized void reportDriverExceptions(String introductoryText,
597
            List driverExceptions) {
598
        for (int i = 0; i < errorListeners.size(); i++) {
599
            ((ErrorListener) errorListeners.get(i)).
600
                    reportDriverExceptions(introductoryText, driverExceptions);
601
        }
602
    }
603
604
    /**
605
     * <p>
606
     * Adds the specified legend listener (if didn't exist) to receive legend
607
     * events from this map.</p>
608
     *
609
     * @param listener the legend listener
610
     *
611
     * @see #removeLayerListener(LegendListener)
612
     * @see #callLegendChanged()
613
     */
614
    public void addLayerListener(LegendListener listener) {
615
        if (!legendListeners.contains(listener)) {
616
            legendListeners.add(listener);
617
        }
618
    }
619 40435 jjdelcerro
        // SUGERENCIA DE PABLO
620 42286 jjdelcerro
    //        public void addLegendListener(LegendListener listener) {
621
    //                if (!legendListeners.contains(listener))
622
    //                        legendListeners.add(listener);
623
    //        }
624 40435 jjdelcerro
625 42286 jjdelcerro
    /**
626
     * <p>
627
     * Adds the specified layer drawing listener to catch and handle drawing
628
     * events from layers of this map.</p>
629
     *
630
     * @param listener the listener to add
631
     *
632
     * @see #removeLayerDrawListener(LayerDrawingListener)
633
     * @see #fireLayerDrawingEvent(LayerDrawEvent)
634
     */
635
    public void addLayerDrawingListener(LayerDrawingListener listener) {
636
        layerDrawingListeners.add(listener);
637
    }
638 40435 jjdelcerro
639 42286 jjdelcerro
    /**
640
     * <p>
641
     * Removes the specified layer drawing listener from this map.</p>
642
     *
643
     * @param listener the listener to remove
644
     *
645
     * @see #addLayerDrawingListener(LayerDrawingListener)
646
     * @see #fireLayerDrawingEvent(LayerDrawEvent)
647
     */
648
    public void removeLayerDrawListener(LayerDrawingListener listener) {
649
        layerDrawingListeners.remove(listener);
650
    }
651 40435 jjdelcerro
652 42286 jjdelcerro
    /**
653
     * <p>
654
     * Adds the specified error listener to receive error events from this
655
     * map.</p>
656
     *
657
     * @param listener the listener to add
658
     *
659
     * @see #removeErrorListener(LegendListener)
660
     * @see #reportDriverExceptions(String, List)
661
     */
662
    public void addErrorListener(ErrorListener listener) {
663
        errorListeners.add(listener);
664
    }
665 40435 jjdelcerro
666 42286 jjdelcerro
    /**
667
     * <p>
668
     * Removes the specified error listener from this map.</p>
669
     *
670
     * @param listener the listener to remove
671
     *
672
     * @see #addErrorListener(ErrorListener)
673
     * @see #reportDriverExceptions(String, List)
674
     */
675
    public void removeErrorListener(LegendListener listener) {
676
        legendListeners.remove(listener);
677
    }
678 40435 jjdelcerro
679
        // SUGERENCIA DE PABLO:
680 42286 jjdelcerro
    //public void removeErrorListener(ErrorListener listener) {
681
    //        errorListeners.remove(listener);
682
    //}
683
    /**
684
     * <p>
685
     * Notifies to all legend listeners registered, that one legend has
686
     * changed.</p>
687
     * <p>
688
     * This method must be called only if it's wanted to reflect a legend
689
     * change.</p>
690
     *
691
     * @see #addLayerListener(LegendListener)
692
     * @see #removeLayerListener(LegendListener)
693
     */
694
    public synchronized void callLegendChanged() {
695
        for (int i = 0; i < legendListeners.size(); i++) {
696
            ((LegendListener) legendListeners.get(i)).legendChanged(null);
697
        }
698
        // getLayers().moveTo(0,0);
699
    }
700 40435 jjdelcerro
701 42286 jjdelcerro
    /**
702
     * <p>
703
     * Fires a layer drawing event to all
704
     * {@link LayerDrawingListener LayerDrawingListener} listeners registered,
705
     * distinguishing the kind of event.</p>
706
     *
707
     * @param e the event
708
     *
709
     * @see #addLayerDrawingListener(LayerDrawingListener)
710
     * @see #removeLayerDrawListener(LayerDrawingListener)
711
     */
712
    public synchronized void fireLayerDrawingEvent(LayerDrawEvent e) {
713
        for (int i = 0; i < layerDrawingListeners.size(); i++) {
714
            LayerDrawingListener listener = (LayerDrawingListener) layerDrawingListeners.get(i);
715
            switch (e.getEventType()) {
716
                case LayerDrawEvent.LAYER_BEFORE_DRAW:
717
                    listener.beforeLayerDraw(e);
718
                    break;
719
                case LayerDrawEvent.LAYER_AFTER_DRAW:
720
                    listener.afterLayerDraw(e);
721
                    break;
722
                case LayerDrawEvent.GRAPHICLAYER_BEFORE_DRAW:
723
                    listener.beforeGraphicLayerDraw(e);
724
                    break;
725
                case LayerDrawEvent.GRAPHICLAYER_AFTER_DRAW:
726
                    listener.afterLayerGraphicDraw(e);
727
                    break;
728
            }
729
        }
730
        // getLayers().moveTo(0,0);
731
    }
732 40435 jjdelcerro
733 42286 jjdelcerro
    /**
734
     * <p>
735
     * Notifies to all error listeners registered, that one error has been
736
     * produced.</p>
737
     *
738
     * @param e the event with information of the error
739
     *
740
     * @see #addErrorListener(ErrorListener)
741
     * @see #removeErrorListener(LegendListener)
742
     * @see #reportDriverExceptions(String, List)
743
     */
744
    public synchronized void callNewErrorEvent(ErrorEvent e) {
745
        for (int i = 0; i < errorListeners.size(); i++) {
746
            ((ErrorListener) errorListeners.get(i)).errorThrown(e);
747
        }
748
        errorListeners.clear();
749
        // getLayers().moveTo(0,0);
750
    }
751 40435 jjdelcerro
752 42286 jjdelcerro
    /**
753
     * <p>
754
     * Removes the specified layer listener from this map.</p>
755
     *
756
     * @param listener the listener to remove
757
     *
758
     * @see #addLayerListener(LegendListener)
759
     * @see #callLegendChanged()
760
     */
761
    public void removeLayerListener(LegendListener listener) {
762
        legendListeners.remove(listener);
763
    }
764 40435 jjdelcerro
765
        // SUGERENCIA DE PABLO:
766 42286 jjdelcerro
    // public void removeLegendListener(LegendListener listener) {
767
    //         legendListeners.remove(listener);
768
    // }
769
    /**
770
     * <p>
771
     * Returns the hierarchy of {@link FLayers FLayers} nodes stored in this
772
     * map.</p>
773
     *
774
     * @return the hierarchy of nodes of layers stored in this map
775
     */
776
    public FLayers getLayers() {
777
        return layers;
778
    }
779 40435 jjdelcerro
780 42286 jjdelcerro
    /**
781
     * <p>
782
     * Draws the visible layers of this map according its view port, on the
783
     * image parameter.</p>
784
     *
785
     * @param b image with an accessible buffer of image data
786
     */
787
    public void drawLabels(BufferedImage b) {
788
    }
789 40435 jjdelcerro
790 42286 jjdelcerro
    /**
791
     * @see #redraw()
792
     */
793
    public void invalidate() {
794
        updateDrawVersion();
795
        // Small hack to let the MapControl receive an event and repaint
796
        FLayer layer;
797
        if (layers.getLayersCount() > 0) {
798
            layer = layers.getLayer(layers.getLayersCount() - 1);
799
        } else {
800
            layer = getGraphicsLayer();
801
        }
802
        LayerPositionEvent layerMovedEvent = LayerPositionEvent
803
                .createLayerMovedEvent(
804
                        layer, 0, 0);
805
        eventBuffer.layerMoved(layerMovedEvent);
806
    }
807 40435 jjdelcerro
808
    /**
809
     * <p>
810
     * Prints the layers of this map using the {@link Graphics2D Graphics2D}
811
     * argument, that usually is the {@link Graphics Graphics} of the printer.
812
     * </p>
813 42286 jjdelcerro
     *
814
     * @param g for rendering 2-dimensional shapes, text and images on the
815
     * Java(tm) platform
816
     * @param scale the scale of the view. Must be between
817
     * {@linkplain FLayer#getMinScale()} and {@linkplain FLayer#getMaxScale()}.
818
     * @param properties a set with the settings to be applied to a whole print
819
     * job and to all the documents in the print job
820
     * @throws MapContextException if there is an error getting the instance of
821
     * MapContextDrawer
822
     *
823
     * @throws ReadDriverException if fails reading with driver.
824
     *
825 40435 jjdelcerro
     * @see GraphicLayer#draw(BufferedImage, Graphics2D, ViewPort, Cancellable,
826 42286 jjdelcerro
     * double)
827 40435 jjdelcerro
     */
828 42286 jjdelcerro
    public void print(Graphics2D g, double scale,
829
            PrintAttributes properties) throws ReadException,
830 40435 jjdelcerro
            MapContextException {
831
832 42286 jjdelcerro
        CompatLocator.getGraphicsUtils().setRenderingHintsForPrinting(g);
833 40435 jjdelcerro
834 42286 jjdelcerro
        Cancellable cancel = new Cancellable() {
835
            public boolean isCanceled() {
836
                return false;
837
            }
838 40435 jjdelcerro
839 42286 jjdelcerro
            public void setCanceled(boolean canceled) {
840
                // No queremos que se pueda cancelar la impresi?n.
841 40435 jjdelcerro
842 42286 jjdelcerro
            }
843
        };
844
        this.getMapContextDrawer().print(this.layers, g, cancel, scale, properties);
845 44244 jjdelcerro
        for (VectorLayer tracLayer : this.tracLayers.values()) {
846 44224 jjdelcerro
            if (tracLayer != null) {
847
                tracLayer.draw(null, g, viewPort, cancel, scale);
848
            }
849 42286 jjdelcerro
        }
850
    }
851 40435 jjdelcerro
852 42286 jjdelcerro
    /**
853
     * <p>
854
     * Returns a new <code>MapContext</code> instance with the information of
855
     * the <code>vp</code> argument, and the layers of this map.</p>
856
     *
857
     * @param vp information for drawing the layers of this map in the available
858
     * rectangular area according a projection
859
     *
860
     * @return a new <code>MapContext</code> instance projected by
861
     * <code>vp</code>
862
     */
863
    public MapContext createNewFMap(ViewPort vp) {
864
        MapContext ret = new MapContext(vp);
865
        ret.layers = this.layers;
866 40435 jjdelcerro
867 42286 jjdelcerro
        return ret;
868
    }
869
870
    /**
871
     * <p>
872
     * Creates a new independent <code>MapContext</code> instance, that has a
873
     * clone of the layers and the view port of this one.</p>
874
     * <p>
875
     * The new map will have the same data source drivers to avoid waste memory,
876
     * and work faster.</p>
877
     *
878
     * @return the new <code>MapContext</code> instance
879
     *
880
     * @throws XMLException if fails cloning the view port or a layer
881
     *
882
     * @see FLayer#cloneLayer()
883
     * @see ViewPort#cloneViewPort()
884
     */
885
    public MapContext cloneFMap() {
886
        ViewPort vp;
887 40435 jjdelcerro
        try {
888
            vp = (ViewPort) getViewPort().clone();
889
        } catch (CloneNotSupportedException e) {
890
            throw new RuntimeException(e);
891
        }
892 42286 jjdelcerro
        FLayers antLayers = getLayers();
893
        MapContext ret = new MapContext(vp);
894 40713 jldominguez
895 42286 jjdelcerro
        /*
896
         * Cloning order manager
897
         */
898
        LayerOrderManager lom = this.getOrderManager();
899
        try {
900
            lom = (LayerOrderManager) lom.clone();
901
            ret.setOrderManager(lom);
902
        } catch (CloneNotSupportedException e1) {
903
            logger.error("While cloning order manager", e1);
904
        }
905 40435 jjdelcerro
906 42286 jjdelcerro
        FLayers aux = new FLayers();//(ret,null);
907
        aux.setMapContext(ret);
908
        for (int i = 0; i < antLayers.getLayersCount(); i++) {
909
            FLayer lyr = antLayers.getLayer(i);
910
            try {
911
                FLayer auxLayer = lyr.cloneLayer();
912
                aux.addLayer(auxLayer);
913
                auxLayer.dispose();
914
            } catch (Exception e) {
915
                throw new RuntimeException(e);
916
            }
917
        }
918
        ret.layers = aux;
919
        return ret;
920 40435 jjdelcerro
921 42286 jjdelcerro
    }
922 40435 jjdelcerro
923 42286 jjdelcerro
    /**
924
     * Like {@linkplain #cloneFMap()}, but now doesn't clone the layers, rather
925
     * copies them.
926
     *
927
     * @return the new map
928
     */
929
    public MapContext cloneToDraw() {
930
        ViewPort vp;
931 40435 jjdelcerro
        try {
932
            vp = (ViewPort) getViewPort().clone();
933 42286 jjdelcerro
            MapContext mapContext = new MapContext(getLayers(), vp);
934 40435 jjdelcerro
            return mapContext;
935
        } catch (CloneNotSupportedException e) {
936
            throw new RuntimeException(e);
937
        }
938 42286 jjdelcerro
    }
939 40435 jjdelcerro
940 42286 jjdelcerro
    /**
941
     * <p>
942
     * Adds a layer to the group of layers that are at a upper level in the
943
     * tree.</p>
944
     *
945
     * @param vectorial the layer to add
946
     */
947
    public void addToTrackLayer(FLayer vectorial) {
948
    }
949 40435 jjdelcerro
950 42286 jjdelcerro
    /**
951
     * <p>
952
     * Returns the scale of the view in the screen.</p>
953
     *
954
     * @return one of this values:
955
     * <ul>
956
     * <li>the scale of the adjusted extent scale of the view in the screen
957
     * <li><code>-1</code> if there is no image
958
     * <li><code>0</code> if there is no extent defined for the image
959
     * </ul>
960
     *
961
     * @see #setScaleView(long)
962
     * @see ViewPort#getAdjustedExtent()
963
     * @see IProjection#getScale(double, double, double, double)
964
     */
965
    public long getScaleView() {
966
        double dpi = this.getViewPort().getDPI();
967
        IProjection proj = viewPort.getProjection();
968 40435 jjdelcerro
969 42286 jjdelcerro
        if (viewPort.getImageSize() == null) {
970
            return -1;
971
        }
972 40435 jjdelcerro
973 42286 jjdelcerro
        if (viewPort.getAdjustedEnvelope() == null) {
974
            return 0;
975
        }
976
        double[] trans2Meter = getDistanceTrans2Meter();
977
        int mUnits = getViewPort().getMapUnits();
978 40435 jjdelcerro
979 42286 jjdelcerro
        if (proj == null) {
980
            double w = ((viewPort.getImageSize().width / dpi) * 0.0254);
981
            return (long) (viewPort.getAdjustedEnvelope().getLength(0)
982
                    / w * trans2Meter[mUnits]);
983
        }
984 40435 jjdelcerro
985 42286 jjdelcerro
        return Math.round(proj.getScale(
986
                viewPort.getAdjustedEnvelope().getMinimum(0) * trans2Meter[mUnits],
987
                viewPort.getAdjustedEnvelope().getMaximum(0) * trans2Meter[mUnits],
988
                viewPort.getImageSize().width,
989
                dpi));
990 40435 jjdelcerro
991 42286 jjdelcerro
    }
992 40435 jjdelcerro
993 42286 jjdelcerro
    /**
994
     * <p>
995
     * Sets the new extent of the view, calculated using the scale argument.</p>
996
     * <p>
997
     * Doesn't updates the scale if there isn't information about the dimension
998
     * of the image or the adjusted extent.</p>
999
     *
1000
     * @param scale the new scale for the view
1001
     *
1002
     * @see ViewPort#setProjection(IProjection)
1003
     * @see #getScaleView()
1004
     */
1005
    public void setScaleView(long scale) {
1006
        double dpi = this.getViewPort().getDPI();
1007
        if (viewPort.getImageSize() == null) {
1008
            return;
1009
        }
1010
        IProjection proj = viewPort.getProjection();
1011
        if (viewPort.getAdjustedExtent() == null) {
1012
            return;
1013
        }
1014
        double[] trans2Meter = getDistanceTrans2Meter();
1015
        Envelope env = viewPort.getAdjustedExtent();
1016
        Rectangle2D r = new Rectangle2D.Double(env.getMinimum(0), env.getMinimum(1), env.getLength(0), env.getLength(1));
1017
        Rectangle2D rec = proj.getExtent(r, scale, viewPort.getImageWidth(), viewPort.getImageHeight(), 100 * getDistanceTrans2Meter()[getViewPort().getMapUnits()], trans2Meter[getViewPort().getDistanceUnits()], dpi);
1018
        try {
1019
            getViewPort().setEnvelope(geomManager.createEnvelope(rec.getX(), rec.getY(), rec.getMaxX(), rec.getMaxY(), SUBTYPES.GEOM2D));
1020
        } catch (CreateEnvelopeException e) {
1021
            logger.error("Error seting the bounding box");
1022
        }
1023
    }
1024 40435 jjdelcerro
1025 42286 jjdelcerro
    /**
1026
     * <p>
1027
     * Returns the screen resolution (Dots Per Inch) as it was defined by the
1028
     * user's preference, or by default as it is defined in the default
1029
     * Toolkit.</p>
1030
     *
1031
     * Be care, use ViewPort#getDPI to ensure are using the corrects DPI.
1032
     *
1033
     * @return double with the screen's dpi
1034
     */
1035
    public static double getScreenDPI() {
1036
        return CompatLocator.getGraphicsUtils().getScreenDPI();
1037
    }
1038 40435 jjdelcerro
1039 42286 jjdelcerro
    /**
1040
     * @see
1041
     * org.gvsig.fmap.mapcontext.rendering.strategies.Strategy#process(com.iver.cit.gvsig.fmap.FeatureSelectorVisitor)
1042
     */
1043
    public void process(Visitor visitor) {
1044
    }
1045 40435 jjdelcerro
1046 42286 jjdelcerro
    /**
1047
     * @see
1048
     * org.gvsig.fmap.mapcontext.rendering.strategies.Strategy#processSelected(com.iver.cit.gvsig.fmap.FeatureVisitor)
1049
     */
1050
    public void processSelected(Visitor visitor) {
1051
    }
1052 40435 jjdelcerro
1053 42286 jjdelcerro
    /**
1054
     * @see
1055
     * org.gvsig.fmap.mapcontext.rendering.strategies.Strategy#select(com.iver.cit.gvsig.fmap.FeatureSelectorVisitor,
1056
     * VectorialSubSet)
1057
     */
1058
    public void select(Visitor visitor) {
1059
    }
1060 40435 jjdelcerro
1061 42286 jjdelcerro
    /**
1062
     * @see
1063
     * org.gvsig.fmap.mapcontext.rendering.strategies.Strategy#selectFromSelection()
1064
     */
1065
    public void selectFromSelection() {
1066
    }
1067 40435 jjdelcerro
1068 42286 jjdelcerro
    /**
1069
     * @see
1070
     * org.gvsig.fmap.mapcontext.rendering.strategies.Strategy#createIndex()
1071
     */
1072
    public void createIndex() {
1073
    }
1074 40435 jjdelcerro
1075 42286 jjdelcerro
    /**
1076
     * @see org.cresques.geo.Projected#getProjection()
1077
     *
1078
     * @see ViewPort#getProjection()
1079
     * @see #setProjection(IProjection)
1080
     * @see #reProject(ICoordTrans)
1081
     */
1082
    public IProjection getProjection() {
1083
        return getViewPort().getProjection();
1084
    }
1085 40435 jjdelcerro
1086 42286 jjdelcerro
    /**
1087
     * <p>
1088
     * Sets the new projection.</p>
1089
     *
1090
     * @param proj the new projection
1091
     *
1092
     * @see #getProjection()
1093
     * @see ViewPort#setProjection(IProjection)
1094
     * @see #reProject(ICoordTrans)
1095
     */
1096
    public void setProjection(IProjection proj) {
1097
        if (getViewPort() != null) {
1098
            getViewPort().setProjection(proj);
1099
        }
1100
    }
1101 40435 jjdelcerro
1102 42286 jjdelcerro
    /**
1103
     * @see org.cresques.geo.Projected#reProject(org.cresques.cts.ICoordTrans)
1104
     */
1105
    public void reProject(ICoordTrans arg0) {
1106
        // TODO implementar reprojecci?n (lo que sea eso)
1107
    }
1108 40435 jjdelcerro
1109 42286 jjdelcerro
    public Envelope getSelectionBounds() throws BaseException {
1110 40435 jjdelcerro
1111 42286 jjdelcerro
        SelectedEnvelopeVisitor visitor = new SelectedEnvelopeVisitor();
1112 40435 jjdelcerro
1113 42286 jjdelcerro
        layers.accept(visitor);
1114
        Envelope env_in_data_crs = visitor.getSelectioEnvelope();
1115
        return env_in_data_crs;
1116
    }
1117
1118 40435 jjdelcerro
    /**
1119
     * <p>
1120 42286 jjdelcerro
     * Draws this map if its {@link ViewPort ViewPort} has an extent
1121
     * defined:<br>
1122 40435 jjdelcerro
     * <ol>
1123
     * <li>Selects only the layers that have to be drawn:
1124
     * {@linkplain #prepareDrawing(BufferedImage, Graphics2D, double)}.
1125
     * <li>Sets quality: antialiasing by text and images, and quality rendering.
1126
     * <li>Draws the layers.
1127
     * <li>Fires a <code>LayerDrawEvent.GRAPHICLAYER_BEFORE_DRAW</code>.
1128
     * <li>Draws the graphic layer.
1129
     * <li>Fires a <code>LayerDrawEvent.GRAPHICLAYER_AFTER_DRAW</code>.
1130
     * <li>Invokes the garbage collector and memory clean.
1131
     * </ol>
1132
     * </p>
1133 42286 jjdelcerro
     *
1134
     * @param image buffer used sometimes instead <code>g</code> to accelerate
1135
     * the draw. For example, if two points are as closed that can't be
1136
     * distinguished, draws only one.
1137
     * @param g for rendering 2-dimensional shapes, text and images on the
1138
     * Java(tm) platform
1139
     * @param cancel shared object that determines if this layer can continue
1140
     * being drawn
1141
     * @param scale the scale of the view. Must be between
1142
     * {@linkplain FLayer#getMinScale()} and {@linkplain FLayer#getMaxScale()}.
1143
     * @throws MapContextException if there is an error getting the instance of
1144
     * MapContextDrawer
1145
     * @throws ReadDriverException if fails reading with the driver.
1146 40435 jjdelcerro
     */
1147 42286 jjdelcerro
    public void draw(BufferedImage image, Graphics2D g, Cancellable cancel,
1148
            double scale) throws ReadException, MapContextException {
1149
        if (viewPort.getEnvelope() == null) {
1150
            return;
1151
        }
1152 40435 jjdelcerro
1153 42286 jjdelcerro
        CompatLocator.getGraphicsUtils().setRenderingHintsForDrawing(g);
1154 40435 jjdelcerro
1155 42286 jjdelcerro
        this.getMapContextDrawer().draw(this.layers, image, g, cancel, scale);
1156
    }
1157 40435 jjdelcerro
1158 42286 jjdelcerro
    /**
1159
     * <p>
1160
     * Draws only the internal graphic layer using the information of the
1161
     * {@link ViewPort ViewPort} of this map.</p>
1162
     *
1163
     * @param image image used to accelerate the screen draw
1164
     * @param g for rendering 2-dimensional shapes, text and images on the
1165
     * Java(tm) platform
1166
     * @param cancel shared object that determines if this layer can continue
1167
     * being drawn
1168
     * @param scale value that represents the scale
1169
     * @throws ReadDriverException if fails reading with the driver.
1170
     * @deprecated use
1171
     * {@link #draw(BufferedImage, Graphics2D, Cancellable, double)} instead
1172
     * @see GraphicLayer#draw(BufferedImage, Graphics2D, ViewPort, Cancellable,
1173
     * double)
1174
     */
1175
    public void drawGraphics(BufferedImage image, Graphics2D g,
1176
            Cancellable cancel, double scale) throws ReadException {
1177 40435 jjdelcerro
1178
                // From now on the graphics layer is handled by the MapContextDrawer,
1179 42286 jjdelcerro
        // so call the draw method instead.
1180
        try {
1181
            draw(image, g, cancel, scale);
1182
        } catch (MapContextException e) {
1183
            throw new RuntimeException(e);
1184
        }
1185
    }
1186 40435 jjdelcerro
1187
    /**
1188
     * <p>
1189
     * Like
1190
     * {@linkplain MapContext#draw(BufferedImage, Graphics2D, Cancellable, double)}
1191
     * , but creating the task as cancellable.
1192
     * </p>
1193 42286 jjdelcerro
     *
1194
     * @param image buffer used sometimes instead <code>g</code> to accelerate
1195
     * the draw. For example, if two points are as closed that can't be
1196
     * distinguished, draws only one.
1197
     * @param g for rendering 2-dimensional shapes, text and images on the
1198
     * Java(tm) platform
1199
     * @param scale the scale of the view. Must be between
1200
     * {@linkplain FLayer#getMinScale()} and {@linkplain FLayer#getMaxScale()}.
1201
     * @throws MapContextException if there is an error getting the instance of
1202
     * MapContextDrawer
1203
     *
1204
     * @throws ReadDriverException if the driver fails reading.
1205
     *
1206 40435 jjdelcerro
     * @see #draw(BufferedImage, Graphics2D, Cancellable, double)
1207
     */
1208 42286 jjdelcerro
    public void draw(BufferedImage image, Graphics2D g, double scale)
1209
            throws ReadException, MapContextException {
1210
        draw(image, g, new Cancellable() {
1211
            /**
1212
             * @see org.gvsig.utils.swing.threads.Cancellable#isCanceled()
1213
             */
1214
            public boolean isCanceled() {
1215
                return false;
1216
            }
1217 40435 jjdelcerro
1218 42286 jjdelcerro
            public void setCanceled(boolean canceled) {
1219
                // Do nothing
1220
            }
1221
        }, scale);
1222
    }
1223 40435 jjdelcerro
1224 42286 jjdelcerro
    /**
1225
     * <p>
1226
     * Gets the {@link ViewPort ViewPort} associated to this map.</p>
1227
     *
1228
     * @return the view port
1229
     *
1230
     * @see #setViewPort(ViewPort)
1231
     */
1232
    public ViewPort getViewPort() {
1233
        return viewPort;
1234
    }
1235 40435 jjdelcerro
1236 42286 jjdelcerro
    /**
1237
     * <p>
1238
     * Sets a {@link ViewPort ViewPort} with the drawing information of this
1239
     * map.</p>
1240
     * <p>
1241
     * If there was a previous view port, removes its
1242
     * {@link EventBuffer EventBuffer} and adds the new one.</p>
1243
     *
1244
     * @param viewPort the viewPort
1245
     *
1246
     * @see #getViewPort()
1247
     */
1248
    public void setViewPort(ViewPort viewPort) {
1249
        if (this.viewPort != null) {
1250
            this.viewPort.removeViewPortListener(eventBuffer);
1251
        }
1252 40435 jjdelcerro
1253 42286 jjdelcerro
        if (this.mapContextDrawer != null) {
1254
            this.mapContextDrawer.setViewPort(viewPort);
1255
        }
1256 41245 jjdelcerro
1257 42286 jjdelcerro
        this.viewPort = viewPort;
1258
        if (viewPort != null) {
1259
            viewPort.addViewPortListener(eventBuffer);
1260
        }
1261
    }
1262 40435 jjdelcerro
1263 42286 jjdelcerro
    /**
1264
     * <p>
1265
     * Sets the given extent to the {@link ViewPort ViewPort} and updates the
1266
     * view with the new zoom.</p>
1267
     *
1268
     * @param extent the extent of the new zoom
1269
     */
1270
    public void zoomToEnvelope(Envelope extent) {
1271
        if (extent != null && !extent.isEmpty()) {
1272
            getViewPort().setEnvelope(extent);
1273
        }
1274
    }
1275 40435 jjdelcerro
1276 42286 jjdelcerro
    /**
1277
     * <p>
1278
     * Returns the union of all extents of all layers of this map.</p>
1279
     *
1280
     * @return full extent of layers of this map
1281
     * @throws ReadDriverException if the driver fails reading.
1282
     *
1283
     * @see FLayers#getFullEnvelope()
1284
     */
1285
    public Envelope getFullEnvelope() throws ReadException {
1286
        Envelope envelope = layers.getFullEnvelope();
1287 40435 jjdelcerro
1288 44244 jjdelcerro
        for (VectorLayer tracLayer : this.tracLayers.values()) {
1289 44224 jjdelcerro
            if (tracLayer != null) {
1290
                Envelope graphicsEnvelope = tracLayer.getFullEnvelope();
1291
                if( graphicsEnvelope==null ) {
1292
                    continue;
1293
                }
1294
                if (envelope == null) {
1295
                    try {
1296
                        envelope =  (Envelope) graphicsEnvelope.clone();
1297
                    } catch (CloneNotSupportedException ex) {
1298
                    }
1299
                } else if (graphicsEnvelope != null) {
1300
                    envelope.add(graphicsEnvelope);
1301
                }
1302 42286 jjdelcerro
            }
1303
        }
1304
        return envelope;
1305
    }
1306 40435 jjdelcerro
1307 42286 jjdelcerro
    /**
1308
     * <p>
1309
     * Adds a listener of atomic events to the internal
1310
     * {@link EventBuffer EventBuffer}.</p>
1311
     *
1312
     * @param listener the new listener
1313
     *
1314
     * @return <code>true</code> if has added the listener successfully
1315
     *
1316
     * @see #removeAtomicEventListener(AtomicEventListener)
1317
     * @see EventBuffer#addAtomicEventListener(AtomicEventListener)
1318
     */
1319
    public boolean addAtomicEventListener(AtomicEventListener listener) {
1320
        return eventBuffer.addAtomicEventListener(listener);
1321
    }
1322 40435 jjdelcerro
1323 42286 jjdelcerro
    /**
1324
     * <p>
1325
     * Removes a listener of atomic events from the internal
1326
     * {@link EventBuffer EventBuffer}.</p>
1327
     *
1328
     * @param listener the listener to remove
1329
     *
1330 40435 jjdelcerro
     * @return <tt>true</tt> if the list contained the specified element
1331 42286 jjdelcerro
     *
1332
     * @see #addAtomicEventListener(AtomicEventListener)
1333
     * @see EventBuffer#removeAtomicEventListener(AtomicEventListener)
1334
     */
1335
    public boolean removeAtomicEventListener(AtomicEventListener listener) {
1336
        return eventBuffer.removeAtomicEventListener(listener);
1337
    }
1338 40435 jjdelcerro
1339 42286 jjdelcerro
    /**
1340
     * @see EventBuffer#beginAtomicEvent()
1341
     *
1342
     * @see #endAtomicEvent()
1343
     */
1344
    public void beginAtomicEvent() {
1345
        eventBuffer.beginAtomicEvent();
1346
    }
1347 40435 jjdelcerro
1348 42286 jjdelcerro
    /**
1349
     * @see EventBuffer#endAtomicEvent()
1350
     *
1351
     * @see #beginAtomicEvent()
1352
     */
1353
    public void endAtomicEvent() {
1354
        eventBuffer.endAtomicEvent();
1355
    }
1356 40435 jjdelcerro
1357 42286 jjdelcerro
    /**
1358
     * <p>
1359
     * The class <code>LayerEventListener</code> implements the methods of
1360
     * {@link LayerCollectionListener LayerCollectionListener} that handles the
1361
     * "layer added" or "layer removed" events in a map.</p>
1362
     * <p>
1363
     * Is designed as a listener for all layers in a
1364
     * {@link MapContext MapContext}.</p>
1365
     *
1366
     * @author Fernando Gonz?lez Cort?s
1367
     */
1368 43640 jjdelcerro
    public class LayerEventListener extends BaseLayerCollectionListener {
1369 42286 jjdelcerro
1370 43640 jjdelcerro
        @Override
1371 42286 jjdelcerro
        public void layerAdded(LayerCollectionEvent e) {
1372 43640 jjdelcerro
            // Voy a mover todo esto a la vista
1373
//            // Si aun no tenemos envelope, problablemente sera la primera capa,
1374
//            // asi que asignamos el envelope de la capa al mapcontext.
1375
//            if (getViewPort().getEnvelope() == null) {
1376
//                FLayer lyr = e.getAffectedLayer();
1377
//                if (lyr.isAvailable()) {
1378
//                    try {
1379
//                        getViewPort().setEnvelope(lyr.getFullEnvelope());
1380
//                    } catch (Exception ex) {
1381
//                        logger.warn(
1382
//                                MessageFormat.format(
1383
//                                    "Can''t set envelope to view port from layer ''{0}''",
1384
//                                    new Object[]{lyr.getName()}
1385
//                                ),
1386
//                                ex
1387
//                        );
1388
//                    }
1389
//                }
1390
//            }
1391 40435 jjdelcerro
1392 42286 jjdelcerro
            // Registramos al FMap como listener del legend de las capas
1393
            FLayer lyr = e.getAffectedLayer();
1394
            addSelectionListener(lyr);
1395
        }
1396 40435 jjdelcerro
1397 43640 jjdelcerro
        @Override
1398 42286 jjdelcerro
        public void layerRemoved(LayerCollectionEvent e) {
1399
            FLayer lyr = e.getAffectedLayer();
1400 40435 jjdelcerro
1401 42286 jjdelcerro
            lyr.removeLayerListener(eventBuffer);
1402 40435 jjdelcerro
1403 42286 jjdelcerro
            if (lyr instanceof Classifiable) {
1404
                Classifiable c = (Classifiable) lyr;
1405
                c.removeLegendListener(eventBuffer);
1406
            }
1407 40435 jjdelcerro
1408 42286 jjdelcerro
            if (lyr instanceof SingleLayer && ((SingleLayer) lyr).getDataStore() != null) {
1409
                ((SingleLayer) lyr).getDataStore().deleteObserver(
1410
                        MapContext.this);
1411
            }
1412 40435 jjdelcerro
1413 42286 jjdelcerro
        }
1414 40435 jjdelcerro
1415 42286 jjdelcerro
    }
1416 40435 jjdelcerro
1417 42286 jjdelcerro
    /**
1418
     * <p>
1419
     * Adds the {@link LayerEventListener LayerEventListener} of this map to the
1420
     * collection of layers argument.</p>
1421
     *
1422
     * @param a collection of layers
1423
     */
1424
    public void addAsCollectionListener(FLayers layers2) {
1425
        layers2.addLayerCollectionListener(layerEventListener);
1426
    }
1427 40435 jjdelcerro
1428 44244 jjdelcerro
    public VectorLayer getGraphicsLayer(String name) {
1429 44224 jjdelcerro
        return this.tracLayers.get(name);
1430
    }
1431
1432 44245 jjdelcerro
    public Collection<VectorLayer> getGraphicsLayers() {
1433
        return this.tracLayers.values();
1434
    }
1435
1436 44244 jjdelcerro
    public void setGraphicsLayer(String name, FLyrVect layer) {
1437 44224 jjdelcerro
        this.tracLayers.put(name, layer);
1438
    }
1439
1440
    public void removeGraphicsLayer(String name) {
1441
        this.tracLayers.remove(name);
1442
    }
1443
1444 42286 jjdelcerro
    /**
1445
     * <p>
1446
     * Returns the internal {@link GraphicLayer GraphicLayer}.</p>
1447
     *
1448
     * @return the graphic layer of this map
1449
     *
1450
     * @see #setGraphicsLayer(GraphicLayer)
1451
     */
1452
    public GraphicLayer getGraphicsLayer() {
1453 44244 jjdelcerro
        GraphicLayer tracLayer = (GraphicLayer) this.tracLayers.get(DEFAULT_TRACTLAYER);
1454 42286 jjdelcerro
        if (tracLayer == null) {
1455
            if (getViewPort() != null) {
1456 44224 jjdelcerro
                tracLayer
1457 42286 jjdelcerro
                        = MapContextLocator.getMapContextManager()
1458
                        .createGraphicsLayer(
1459
                                getViewPort().getProjection());
1460
            } else {
1461 44224 jjdelcerro
                tracLayer
1462 42286 jjdelcerro
                        = MapContextLocator.getMapContextManager()
1463
                        .createGraphicsLayer(null);
1464
            }
1465 44224 jjdelcerro
            this.tracLayers.put(DEFAULT_TRACTLAYER, tracLayer);
1466 42286 jjdelcerro
        }
1467
        return tracLayer;
1468
    }
1469 40435 jjdelcerro
1470 42286 jjdelcerro
    /**
1471
     * <p>
1472
     * Sets a new {@link GraphicLayer GraphicLayer} to this map.</p>
1473
     *
1474
     * @param graphicLayer the new graphic layer
1475
     *
1476
     * @see #getGraphicsLayer()
1477
     */
1478
    public void setGraphicsLayer(GraphicLayer graphicLayer) {
1479 44224 jjdelcerro
        this.tracLayers.put(DEFAULT_TRACTLAYER, graphicLayer);
1480 42286 jjdelcerro
    }
1481 40435 jjdelcerro
1482 42286 jjdelcerro
    /**
1483
     * <p>
1484
     * Indicates whether some other object is "equal to" this map.</p>
1485
     * <p>
1486
     * Returns <code>true</code> if success one of this options:
1487
     * <ul>
1488
     * <li>Both objects are equal according to
1489
     * {@linkplain Object#equals(Object)}.
1490
     * <li>Both maps have the same layers.
1491
     * <li>Both maps have the same number of layers and with the same name.
1492
     * </ul>
1493
     * </p>
1494
     *
1495
     * @param obj the reference object with which to compare.
1496
     * @return <code>true</code> if this object is the same as the
1497
     * <code>arg0</code> argument; otherwise <code>false</code>.
1498
     *
1499
     * @see Object#equals(Object)
1500
     */
1501
    public boolean equals(Object arg0) {
1502
        if (!(arg0 instanceof MapContext)) {
1503
            return false;
1504
        }
1505
        MapContext map = (MapContext) arg0;
1506
        if (super.equals(arg0)) {
1507
            return true;
1508
        }
1509
        if (getLayers() == map.getLayers()) {
1510
            return true;
1511
        }
1512
        boolean isEqual = true;
1513
        if (map.getLayers().getLayersCount() == getLayers().getLayersCount()) {
1514
            for (int i = 0; i < getLayers().getLayersCount(); i++) {
1515 40435 jjdelcerro
1516 42286 jjdelcerro
                if (!getLayers().getLayer(i).getName().equals(
1517
                        map.getLayers().getLayer(i).getName())) {
1518
                    isEqual = false;
1519
                }
1520 40435 jjdelcerro
1521 42286 jjdelcerro
            }
1522
        } else {
1523
            isEqual = false;
1524
        }
1525
        return isEqual;
1526
    }
1527 40435 jjdelcerro
1528 42286 jjdelcerro
    /**
1529
     * <p>
1530
     * Registers the message of an error associated to this map.</p>
1531
     *
1532
     * @param stringProperty the error message
1533
     *
1534
     * @see #getLayersError()
1535
     * @see #clearErrors()
1536
     */
1537
    public void addLayerError(String stringProperty) {
1538
        layersError.add(stringProperty);
1539
    }
1540 40435 jjdelcerro
1541 42286 jjdelcerro
    /**
1542
     * <p>
1543
     * Gets the list with all error messages registered to this map.</p>
1544
     *
1545
     * @return the list of errors registered to this map
1546
     *
1547
     * @see #addLayerError(String)
1548
     * @see #clearErrors()
1549
     */
1550
    public ArrayList getLayersError() {
1551
        return layersError;
1552
    }
1553 40435 jjdelcerro
1554 42286 jjdelcerro
    /**
1555
     * <p>
1556
     * Removes all error messages associated to this map.</p>
1557
     *
1558
     * @see #addLayerError(String)
1559
     * @see #getLayersError()
1560
     */
1561
    public void clearErrors() {
1562
        layersError.clear();
1563
    }
1564 40435 jjdelcerro
1565 42286 jjdelcerro
    /**
1566
     * <p>
1567
     * Creates and returns a new group of layers that belongs to this
1568
     * <code>MapContext</code>.</p>
1569
     *
1570
     * @param parent layer node in this <code>MapContexte</code> that will be
1571
     * the parent of the new node
1572
     * @return the new layer node
1573
     */
1574
    public FLayers getNewGroupLayer(FLayers parent) {
1575
        FLayers group1 = new FLayers();//(this,parent);
1576
        group1.setMapContext(this);
1577
        group1.setParentLayer(parent);
1578
        return group1;
1579
    }
1580 40435 jjdelcerro
1581 42286 jjdelcerro
    public String getClassName() {
1582
        return null;
1583
    }
1584 40435 jjdelcerro
1585 42286 jjdelcerro
    public ArrayList getLayersToSnap() {
1586
        return layersToSnap;
1587
    }
1588 40435 jjdelcerro
1589 42286 jjdelcerro
    public void setLayersToSnap(ArrayList layersToSnap) {
1590
        this.layersToSnap = layersToSnap;
1591 40435 jjdelcerro
1592 42286 jjdelcerro
    }
1593 40435 jjdelcerro
1594 42286 jjdelcerro
    public void update(Observable observable, Object notification) {
1595
        // TODO REVISAR ESTO!!!
1596
        String ntype = null;
1597
        if (notification instanceof FeatureStoreNotification) {
1598
            FeatureStoreNotification fsNotification = (FeatureStoreNotification) notification;
1599
            ntype = fsNotification.getType();
1600
            if (ntype.equals(FeatureStoreNotification.LOAD_FINISHED)
1601
                    || ntype.equals(FeatureStoreNotification.SELECTION_CHANGE)) {
1602
                getLayers().moveTo(0, 0);
1603
            }
1604
        }
1605
    }
1606 40435 jjdelcerro
1607 42286 jjdelcerro
    public long getDrawVersion() {
1608
        if (getViewPort().getDrawVersion() > this.viewPortVersion
1609
                || getLayers().getDrawVersion() > this.layersVersion
1610
                || getGraphicsLayer().getDrawVersion() > graphicsLayerVersion) {
1611
            updateDrawVersion();
1612
        }
1613
        return this.drawVersion;
1614
    }
1615 40435 jjdelcerro
1616 42286 jjdelcerro
    protected void updateDrawVersion() {
1617
        this.layersVersion = getLayers().getDrawVersion();
1618
        this.viewPortVersion = getViewPort().getDrawVersion();
1619
        this.graphicsLayerVersion = getGraphicsLayer().getDrawVersion();
1620
        this.drawVersion++;
1621
    }
1622 40435 jjdelcerro
1623 42286 jjdelcerro
    public MapContextDrawer getMapContextDrawer() throws ReadException,
1624 40435 jjdelcerro
            MapContextException {
1625 42286 jjdelcerro
        if (this.mapContextDrawer == null) {
1626
            if (mapContextDrawerClass == null) {
1627 40435 jjdelcerro
                this.mapContextDrawer = mapContextManager
1628
                        .createDefaultMapContextDrawerInstance();
1629
            } else {
1630
                this.mapContextDrawer = mapContextManager
1631
                        .createMapContextDrawerInstance(mapContextDrawerClass);
1632
            }
1633 42286 jjdelcerro
            this.mapContextDrawer.setMapContext(this);
1634 40435 jjdelcerro
            this.mapContextDrawer.setViewPort(viewPort);
1635 42286 jjdelcerro
        }
1636 40435 jjdelcerro
1637 42286 jjdelcerro
        return this.mapContextDrawer;
1638
    }
1639
1640
    public void setMapContextDrawerClass(Class mapContextDrawerClass)
1641 40435 jjdelcerro
            throws MapContextException {
1642 42286 jjdelcerro
        mapContextManager.validateMapContextDrawer(mapContextDrawerClass);
1643
        this.mapContextDrawerClass = mapContextDrawerClass;
1644
        if (this.mapContextDrawer != null) {
1645
            this.mapContextDrawer.dispose();
1646
            this.mapContextDrawer = null;
1647
        }
1648
    }
1649 40435 jjdelcerro
1650 42286 jjdelcerro
    public void setMapContextDrawer(MapContextDrawer drawer) {
1651
        if (this.mapContextDrawer != null) {
1652
            this.mapContextDrawer.dispose();
1653
            this.mapContextDrawer = null;
1654
        }
1655
        this.mapContextDrawer = drawer;
1656
        if (this.mapContextDrawer != null) {
1657
            this.mapContextDrawer.setMapContext(this);
1658
            this.mapContextDrawer.setViewPort(viewPort);
1659
        }
1660
    }
1661 40435 jjdelcerro
1662 42286 jjdelcerro
    public void loadFromState(PersistentState state)
1663
            throws PersistenceException {
1664 40435 jjdelcerro
1665 42286 jjdelcerro
        ViewPort vp = (ViewPort) state.get("ViewPort");
1666
        setViewPort(vp);
1667
1668
        layers = (FLayers) state.get("layers");
1669
        layers.setName("root layer");
1670
        loadLayers(layers);
1671
        layers.setMapContext(this);
1672
1673
        layerEventListener = new LayerEventListener();
1674
        layers.addLayerCollectionListener(layerEventListener);
1675
1676
        layers.addLayerCollectionListener(eventBuffer);
1677
        layers.setProjection(vp.getProjection());
1678
1679
        //Add the listener for the selection
1680
        addSelectionListener(layers);
1681
1682
        // ======================
1683
        if (state.hasValue("orderManager")) {
1684
            LayerOrderManager lom = (LayerOrderManager) state.get("orderManager");
1685
            this.setOrderManager(lom);
1686
        }
1687
        DefaultMapContextManager manager = (DefaultMapContextManager) MapContextLocator.getMapContextManager();
1688
        manager.notifyLoadMapContext(this);
1689
    }
1690
1691
    private void loadLayers(FLayers lyrs) {
1692
1693
        int sz = lyrs.getLayersCount();
1694
        for (int i = 0; i < sz; i++) {
1695
            try {
1696
                lyrs.getLayer(i).load();
1697
            } catch (LoadLayerException e) {
1698
                logger.error("While loading layer: " + lyrs.getLayer(i).getName());
1699
            }
1700
        }
1701
    }
1702
1703
    public void saveToState(PersistentState state) throws PersistenceException {
1704
        state.set("ViewPort", viewPort);
1705 42293 jjdelcerro
        state.set("layers", (Persistent)layers);
1706 42286 jjdelcerro
        state.set("orderManager", this.getOrderManager());
1707
    }
1708
1709 41840 jjdelcerro
    public static class RegisterPersistence implements Callable {
1710 40435 jjdelcerro
1711 41840 jjdelcerro
        public Object call() {
1712 42286 jjdelcerro
            PersistenceManager manager = ToolsLocator.getPersistenceManager();
1713
            DynStruct definition = manager.addDefinition(
1714
                    MapContext.class,
1715
                    "MapContext",
1716
                    "MapContext Persistence definition",
1717
                    null,
1718
                    null
1719
            );
1720
            definition.addDynFieldObject("ViewPort")
1721
                    .setClassOfValue(ViewPort.class)
1722
                    .setMandatory(true);
1723 40713 jldominguez
1724 42286 jjdelcerro
            definition.addDynFieldObject("layers")
1725
                    .setClassOfValue(FLayers.class)
1726
                    .setMandatory(true);
1727 40713 jldominguez
1728 42286 jjdelcerro
            definition.addDynFieldObject("orderManager")
1729
                    .setClassOfValue(LayerOrderManager.class)
1730
                    .setMandatory(false);
1731
1732 41840 jjdelcerro
            return Boolean.TRUE;
1733
        }
1734
    }
1735 40435 jjdelcerro
1736 42286 jjdelcerro
    protected void doDispose() throws BaseException {
1737
        dispose(layers);
1738 44244 jjdelcerro
        for (VectorLayer tracLayer : this.tracLayers.values()) {
1739 44224 jjdelcerro
            dispose(tracLayer);
1740
        }
1741 42286 jjdelcerro
    }
1742
1743 40435 jjdelcerro
    /**
1744 42286 jjdelcerro
     * <p>
1745
     * Registers an event buffer as a listener for all layers as argument.</p>
1746 40435 jjdelcerro
     *
1747 42286 jjdelcerro
     * <p>
1748
     * Each {@link FLayer FLayer} of this map must have an event buffer for all
1749
     * kind of specific listeners of that layer. This method distinguish between {@link Classifiable Classifiable},
1750
     * {@link AlphanumericData AlphanumericData}, and {@link FLayers FLayers}
1751
     * layers, and for each one, registers, for their specific listeners, the
1752
     * <code>eventBuffer</code> as a listener.</p>
1753 40435 jjdelcerro
     *
1754
     * @param the layer or layers
1755
     */
1756 42286 jjdelcerro
    private void addSelectionListener(FLayer lyr) {
1757 40435 jjdelcerro
        lyr.addLayerListener(eventBuffer);
1758
1759
        if (lyr instanceof Classifiable) {
1760
            Classifiable c = (Classifiable) lyr;
1761
            c.addLegendListener(eventBuffer);
1762
        }
1763
1764 42286 jjdelcerro
        if (lyr instanceof FLayers) {
1765
            FLayers lyrs = (FLayers) lyr;
1766
            for (int i = 0; i < lyrs.getLayersCount(); i++) {
1767 40435 jjdelcerro
                addSelectionListener(lyrs.getLayer(i));
1768
            }
1769
        }
1770 42286 jjdelcerro
        if (lyr instanceof SingleLayer) {
1771 40435 jjdelcerro
            if (((SingleLayer) lyr).getDataStore() != null) {
1772
                ((SingleLayer) lyr).getDataStore().addObserver(
1773
                        MapContext.this);
1774
            }
1775
        }
1776
    }
1777 40713 jldominguez
1778
    public void setOrderManager(LayerOrderManager lom) {
1779 42286 jjdelcerro
        orderManager = lom;
1780 40713 jldominguez
    }
1781 42286 jjdelcerro
1782 40713 jldominguez
    public LayerOrderManager getOrderManager() {
1783 42286 jjdelcerro
1784
        if (orderManager == null) {
1785
            orderManager = MapContextLocator.getDefaultOrderManager();
1786
        }
1787
        return orderManager;
1788 40713 jldominguez
    }
1789 42286 jjdelcerro
1790 41245 jjdelcerro
    public boolean hasVectorLayers() {
1791
        return this.hasVectorLayers(this.getLayers());
1792
    }
1793 42286 jjdelcerro
1794 41245 jjdelcerro
    public boolean hasActiveVectorLayers() {
1795
        FLayer[] layers = this.getLayers().getActives();
1796 42286 jjdelcerro
        for (int i = 0; i < layers.length; i++) {
1797 41245 jjdelcerro
            FLayer layer = layers[i];
1798
            if (layer.isAvailable() && layer instanceof FLyrVect) {
1799
                return true;
1800
            }
1801
        }
1802
        return false;
1803
    }
1804 42286 jjdelcerro
1805 43147 jjdelcerro
    public boolean hasActiveLayers() {
1806
        FLayer[] layers = this.getLayers().getActives();
1807
        return !ArrayUtils.isEmpty(layers);
1808
    }
1809
1810
    public boolean hasLayers() {
1811
        return !this.getLayers().isEmpty();
1812
    }
1813
1814 41245 jjdelcerro
    private boolean hasVectorLayers(FLayers layers) {
1815 42286 jjdelcerro
        for (int i = 0; i < layers.getLayersCount(); i++) {
1816
            FLayer lyr = layers.getLayer(i);
1817
            if (lyr instanceof FLayers) {
1818
                if (hasVectorLayers((FLayers) lyr)) {
1819
                    return true;
1820
                }
1821
            } else if (lyr instanceof FLyrVect) {
1822
                return true;
1823 41245 jjdelcerro
            }
1824 42286 jjdelcerro
        }
1825
        return false;
1826 41245 jjdelcerro
    }
1827 42293 jjdelcerro
1828 42513 jjdelcerro
    @Override
1829
    public Iterator<FLayer> iterator() {
1830 42293 jjdelcerro
        return this.layers.iterator();
1831
    }
1832
1833
    public Iterator deepiterator() {
1834
        return this.layers.deepiterator();
1835
    }
1836 43618 jjdelcerro
1837
    public MapTimeContext getTimeContext() {
1838
        TimeSupportManager timeSupportManager = TimeSupportLocator.getManager();
1839
        Interval interval = null;
1840
        final List<Instant> times = new ArrayList<>();
1841
        Instant minInstant = null;
1842
        Instant maxInstant = null;
1843
1844
        //TODO Separate absolute and relative time
1845
        FLayers layers = this.getLayers();
1846
        for( Iterator<FLayer> iterator = layers.deepiterator(); iterator.hasNext(); ) {
1847
            FLayer layer = iterator.next();
1848
            if( layer instanceof SingleLayer ) {
1849
                DataStore dataStore = ((SingleLayer) layer).getDataStore();
1850
                if( dataStore.getInterval() != null ) {
1851
                    Instant startInstant = dataStore.getInterval().getStart();
1852
                    Instant endInstant = dataStore.getInterval().getEnd();
1853
                    times.addAll(dataStore.getTimes());
1854
                    if( minInstant == null ) {
1855
                        minInstant = startInstant;
1856
                        maxInstant = endInstant;
1857
                    } else {
1858
                        if( minInstant.isAfter(startInstant) ) {
1859
                            minInstant = startInstant;
1860
                        }
1861
                        if( maxInstant.isBefore(endInstant) ) {
1862
                            maxInstant = endInstant;
1863
                        }
1864
                    }
1865
                }
1866
            }
1867
        }
1868
1869
        if( minInstant != null ) {
1870
            if( minInstant.isAbsolute() ) {
1871
                try {
1872
                    interval = timeSupportManager.createAbsoluteInterval((AbsoluteInstant) minInstant, (AbsoluteInstant) maxInstant);
1873
                } catch (AbsoluteIntervalTypeNotRegisteredException e) {
1874
                    logger.warn("Error creating the time interval", e);
1875
                }
1876
            } else {
1877
                interval = timeSupportManager.createRelativeInterval(((RelativeInstant) minInstant).toMillis(), ((RelativeInstant) maxInstant).toMillis());
1878
            }
1879
        }
1880
        final Interval tmp_interval = interval;
1881
        return new MapTimeContext() {
1882
            @Override
1883
            public Interval getInterval() {
1884
                return tmp_interval;
1885
            }
1886
1887
            @Override
1888
            public List<Instant> getTimes() {
1889
                return times;
1890
            }
1891
        };
1892
    }
1893 44224 jjdelcerro
1894 40435 jjdelcerro
}