Statistics
| Revision:

svn-gvsig-desktop / branches / v2_0_0_prep / libraries / libFMap_mapcontext / src / org / gvsig / fmap / mapcontext / MapContext.java @ 28665

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