Statistics
| Revision:

root / branches / v2_0_0_prep / libraries / libFMap_mapcontext / src / org / gvsig / fmap / mapcontext / MapContext.java @ 38581

History | View | Annotate | Download (53.8 KB)

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