Statistics
| Revision:

root / trunk / libraries / libFMap / src / com / iver / cit / gvsig / fmap / MapContext.java @ 35778

History | View | Annotate | Download (57.5 KB)

1
/* 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 com.iver.cit.gvsig.fmap;
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.Point2D;
49
import java.awt.geom.Rectangle2D;
50
import java.awt.image.BufferedImage;
51
import java.lang.reflect.InvocationTargetException;
52
import java.util.ArrayList;
53
import java.util.List;
54
import java.util.prefs.Preferences;
55

    
56
import javax.print.attribute.PrintRequestAttributeSet;
57

    
58
import org.cresques.cts.ICoordTrans;
59
import org.cresques.cts.IProjection;
60
import org.cresques.geo.Projected;
61

    
62
import com.hardcode.gdbms.driver.exceptions.ReadDriverException;
63
import com.iver.cit.gvsig.exceptions.visitors.VisitorException;
64
import com.iver.cit.gvsig.fmap.core.IGeometry;
65
import com.iver.cit.gvsig.fmap.layers.CancelationException;
66
import com.iver.cit.gvsig.fmap.layers.FLayer;
67
import com.iver.cit.gvsig.fmap.layers.FLayers;
68
import com.iver.cit.gvsig.fmap.layers.GraphicLayer;
69
import com.iver.cit.gvsig.fmap.layers.LayerCollectionEvent;
70
import com.iver.cit.gvsig.fmap.layers.LayerCollectionListener;
71
import com.iver.cit.gvsig.fmap.layers.LayerDrawEvent;
72
import com.iver.cit.gvsig.fmap.layers.LayerDrawingListener;
73
import com.iver.cit.gvsig.fmap.layers.LayerPositionEvent;
74
import com.iver.cit.gvsig.fmap.layers.VectorialAdapter;
75
import com.iver.cit.gvsig.fmap.layers.XMLException;
76
import com.iver.cit.gvsig.fmap.layers.layerOperations.AlphanumericData;
77
import com.iver.cit.gvsig.fmap.layers.layerOperations.Classifiable;
78
import com.iver.cit.gvsig.fmap.layers.layerOperations.Selectable;
79
import com.iver.cit.gvsig.fmap.layers.order.DefaultOrderManager;
80
import com.iver.cit.gvsig.fmap.layers.order.OrderManager;
81
import com.iver.cit.gvsig.fmap.operations.selection.Record;
82
import com.iver.cit.gvsig.fmap.operations.strategies.FeatureVisitor;
83
import com.iver.cit.gvsig.fmap.operations.strategies.SelectedZoomVisitor;
84
import com.iver.cit.gvsig.fmap.rendering.LegendListener;
85
import com.iver.utiles.XMLEntity;
86
import com.iver.utiles.swing.threads.Cancellable;
87

    
88
/**
89
 * <p>The <code>MapContext</code> class represents the model and a part of the control and view around graphical layers
90
 * used by {@link MapControl MapControl}.</p>
91
 *
92
 * <p>An instance of <code>MapContext</code> is made up with:
93
 * <ul>
94
 * <li>a hierarchy of {@link FLayers FLayers} nodes
95
 * <li>a {@link GraphicLayer GraphicLayer} layer
96
 * <li>a {@link ViewPort ViewPort}
97
 * <li>an {@link EventBuffer EventButter}
98
 * <li>some {@link com.iver.cit.gvsig.fmap.layers.LegendListener LegendListener}s
99
 * <li>some {@link LayerDrawingListener LayerDrawingListener}s
100
 * <li>some {@link LayerEventListener LayerEventListener}s
101
 * <li>some {@link ErrorListener ErrorListener}s
102
 * </ul>
103
 * </p>
104
 *
105
 * @author Fernando Gonz?lez Cort?s
106
 */
107
public class MapContext implements Projected {
108
        /**
109
         * <p>Defines the value which a unit of a distance measurement must be divided to obtain its equivalent <b>in meters</b>.</p>
110
         *
111
         * <p><b><i>Conversion values of distance measurements:</i></b>
112
         * <ul>
113
         *  <li><code>MapContext.CHANGEM[0]</code>: kilometer
114
         *  <li><code>MapContext.CHANGEM[1]</code>: meter
115
         *  <li><code>MapContext.CHANGEM[2]</code>: centimeter
116
         *  <li><code>MapContext.CHANGEM[3]</code>: millimeter
117
         *  <li><code>MapContext.CHANGEM[4]</code>: international statute mile
118
         *  <li><code>MapContext.CHANGEM[5]</code>: yard
119
         *  <li><code>MapContext.CHANGEM[6]</code>: foot
120
         *  <li><code>MapContext.CHANGEM[7]</code>: inch
121
         *  <li><code>MapContext.CHANGEM[8]</code>: grade
122
         * </ul>
123
         *
124
         * <p><h3>Examples:</h3>
125
         * <pre>1 international statute mile / MapContext.CHANGEM[4] = X meters</pre>
126
         * <pre>1 kilometer / MapContext.CHANGEM[0] = X meters</pre>
127
         * <pre>1 grade / MapContext.CHANGEM[8] = X meters</pre>
128
         * </p>
129
         *
130
         * <p><h3>Grade conversion value: <code>MapContext.CHANGEM[8]</code></h3>
131
         * The value of <code>MapContext.CHANGEM[8]</code> represents the meters of a straight line between two
132
         *  points on the Earth surface that are 1 grade far each other of the center of the Earth. This value has been calculated using
133
         *  a radius approximated of R<sub>Earth</sub>=6.37846082678100774672e6 meters, according these equations:
134
         * <pre>D = 2 * (sin (1)) * R<sub>Earth</sub></pre>
135
         * <pre>MapContext.CHANGEM[8] = 1 / D</pre>
136
         * <h4>Explanation:</h4>
137
         * We get an isosceles triangle with the center of the Earth and the 2 points on the surface. This triangle can be divided into
138
         * 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
139
         * is the hypotenuse. Then we apply trigonometry and get the distance <i>D</i> between both points on the Earth surface.</p>
140
         * <p>Now we only must invert that value to obtain <code>MapContext.CHANGEM[8]</code>.</p>
141
         *@deprecated use getDistanceTrans2Meter()
142
         */
143
        public static final double[] CHANGEM = { 1000, 1, 0.01, 0.001, 1609.344,
144
                        0.9144, 0.3048, 0.0254, 1/8.983152841195214E-6 };
145

    
146

    
147
        public static ArrayList AREANAMES=new ArrayList();
148
        public static ArrayList AREAABBR=new ArrayList();
149
        public static ArrayList AREATRANS2METER=new ArrayList();
150

    
151
        public static ArrayList DISTANCENAMES=new ArrayList();
152
        public static ArrayList DISTANCEABBR=new ArrayList();
153
        public static ArrayList DISTANCETRANS2METER=new ArrayList();
154

    
155
        static{
156
                MapContext.addDistanceUnit("Kilometros","Km",1000);
157
            MapContext.addDistanceUnit("Metros","m",1);
158
            MapContext.addDistanceUnit("Centimetros","cm",0.01);
159
            MapContext.addDistanceUnit("Milimetros","mm",0.001);
160
            MapContext.addDistanceUnit("Millas","mi",1609.344);
161
            MapContext.addDistanceUnit("Yardas","Ya",0.9144);
162
            MapContext.addDistanceUnit("Pies","ft",0.3048);
163
            MapContext.addDistanceUnit("Pulgadas","inche",0.0254);
164
            MapContext.addDistanceUnit("Grados","?",1/8.983152841195214E-6);
165

    
166
            MapContext.addAreaUnit("Kilometros","Km",true,1000);
167
            MapContext.addAreaUnit("Metros","m",true,1);
168
            MapContext.addAreaUnit("Centimetros","cm",true,0.01);
169
            MapContext.addAreaUnit("Milimetros","mm",true,0.001);
170
            MapContext.addAreaUnit("Millas","mi",true,1609.344);
171
            MapContext.addAreaUnit("Yardas","Ya",true,0.9144);
172
            MapContext.addAreaUnit("Pies","ft",true,0.3048);
173
            MapContext.addAreaUnit("Pulgadas","inche",true,0.0254);
174
            MapContext.addAreaUnit("Grados","?",true,1/8.983152841195214E-6);
175

    
176

    
177
    }
178

    
179

    
180

    
181
        public static void addAreaUnit(String name, String abbr,boolean isLinear,double trans2meter){
182
                if (!AREANAMES.contains(name)){
183
                        AREANAMES.add(name);
184
                        String pow="";
185
                        if (isLinear)
186
                                pow=String.valueOf((char)178);
187
                        AREAABBR.add(abbr+pow);
188
                        AREATRANS2METER.add(new Double(trans2meter));
189
                }
190
        }
191
        public static String[] getAreaNames(){
192
                return (String[])AREANAMES.toArray(new String[0]);
193
        }
194
        public static String[] getAreaAbbr(){
195
                return (String[])AREAABBR.toArray(new String[0]);
196
        }
197
        public static double[] getAreaTrans2Meter(){
198
                int size=AREATRANS2METER.size();
199
                double[] trans2meters=new double[size];
200
                for (int i = 0; i < size; i++) {
201
                        trans2meters[i]=((Double)AREATRANS2METER.get(i)).doubleValue();
202
                }
203
                return trans2meters;
204
        }
205
        public static String getOfLinear(int i) {
206
                if (((String)AREAABBR.get(i)).toLowerCase().endsWith(String.valueOf((char)178))){
207
                        return String.valueOf((char)178);
208
                }
209
                return "";
210
        }
211
        public static void addDistanceUnit(String name, String abbr,double trans2meter){
212
                if (!DISTANCENAMES.contains(name)){
213
                        DISTANCENAMES.add(name);
214
                        DISTANCEABBR.add(abbr);
215
                        DISTANCETRANS2METER.add(new Double(trans2meter));
216
                }
217
        }
218
        public static String[] getDistanceNames(){
219
                return (String[])DISTANCENAMES.toArray(new String[0]);
220
        }
221
        public static String[] getDistanceAbbr(){
222
                return (String[])DISTANCEABBR.toArray(new String[0]);
223
        }
224
        public static double[] getDistanceTrans2Meter(){
225
                int size=DISTANCETRANS2METER.size();
226
                double[] trans2meters=new double[size];
227
                for (int i = 0; i < size; i++) {
228
                        trans2meters[i]=((Double)DISTANCETRANS2METER.get(i)).doubleValue();
229
                }
230
                return trans2meters;
231
        }
232
        public static int getDistancePosition(String s){
233
                for (int i = 0; i < DISTANCENAMES.size(); i++) {
234
                        if (DISTANCENAMES.get(i).equals(s)){
235
                                return i;
236
                        }
237
                }
238
                return 0;
239
        }
240

    
241
        /**
242
         * <p>Defines the value which a unit of a distance measurement must be divided to obtain its equivalent <b>in centimeters</b>.</p>
243
         *
244
         * <p><b><i>Conversion values of distance measurements:</i></b>
245
         * <ul>
246
         *  <li><code>MapContext.CHANGE[0]</code>: kilometer
247
         *  <li><code>MapContext.CHANGE[1]</code>: meter
248
         *  <li><code>MapContext.CHANGE[2]</code>: centimeter
249
         *  <li><code>MapContext.CHANGE[3]</code>: millimeter
250
         *  <li><code>MapContext.CHANGE[4]</code>: international statute mile
251
         *  <li><code>MapContext.CHANGE[5]</code>: yard
252
         *  <li><code>MapContext.CHANGE[6]</code>: foot
253
         *  <li><code>MapContext.CHANGE[7]</code>: inch
254
         *  <li><code>MapContext.CHANGE[8]</code>: grade
255
         * </ul>
256
         *
257
         * <p><h3>Examples:</h3>
258
         * <pre>1 international statute mile / MapContext.CHANGE[4] = X centimeters</pre>
259
         * <pre>1 kilometer / MapContext.CHANGE[0] = X centimeters</pre>
260
         * <pre>1 grade / MapContext.CHANGE[8] = X centimeters</pre>
261
         * </p>
262
         *
263
         * <p><h3>Grade conversion value: <code>MapContext.CHANGE[8]</code></h3>
264
         * The value of <code>MapContext.CHANGE[8]</code> represents the centimeters of a straight line between two
265
         *  points on the Earth surface that are 1 grade far each other of the center of the Earth. This value has been calculated using
266
         *  a radius approximated of R<sub>Earth</sub>=6.37846082678100774672e6 meters, according these equations:
267
         * <pre>D = 2 * (sin (1)) * R<sub>Earth</sub></pre>
268
         * <pre>MapContext.CHANGE[8] = 1 / D</pre>
269
         * <h4>Explanation:</h4>
270
         * We get an isosceles triangle with the center of the Earth and the 2 points on the surface. This triangle can be divided into
271
         * 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
272
         * is the hypotenuse. Then we apply trigonometry and get the distance <i>D</i> between both points on the Earth surface.</p>
273
         * <p>Now we only must invert that value to obtain <code>MapContext.CHANGE[8]</code>.</p>
274
         * @deprecated use getDistanceTrans2Meter() * 100
275
         */
276
        public static final double[] CHANGE = { 100000, 100, 1, 0.1, 160934.4,
277
                        91.44, 30.48, 2.54, 1/8.983152841195214E-4 };
278

    
279
        /* Do not alter the order and the values of this array, if you need append values.*/
280
        /**
281
         * <p>Gets the name of all distance measurements supported by <code>MapContext</code>.</p>
282
         */
283
//        public static final String[] NAMES= {
284
//                Messages.getString("Kilometros"),
285
//                Messages.getString("Metros"),
286
//                Messages.getString("Centimetros"),
287
//                Messages.getString("Milimetros"),
288
//                Messages.getString("Millas"),
289
//                Messages.getString("Yardas"),
290
//                Messages.getString("Pies"),
291
//                Messages.getString("Pulgadas"),
292
//                Messages.getString("Grados"),
293
//        };
294

    
295
        public static final int EQUALS = 0;
296

    
297
        public static final int DISJOINT = 1;
298

    
299
        public static final int INTERSECTS = 2;
300

    
301
        public static final int TOUCHES = 3;
302

    
303
        public static final int CROSSES = 4;
304

    
305
        public static final int WITHIN = 5;
306

    
307
        public static final int CONTAINS = 6;
308

    
309
        public static final int OVERLAPS = 7;
310

    
311
        /**
312
         * A hierarchy of {@link FLayers FLayers} nodes.
313
         *
314
         * @see #getLayers()
315
         * @see #print(Graphics2D, double, PrintRequestAttributeSet)
316
         */
317
        protected FLayers layers;
318

    
319
        /**
320
         * A layer with graphical items: geometries and symbols.
321
         *
322
         * @see #getGraphicsLayer()
323
         * @see #setGraphicsLayer(GraphicLayer)
324
         * @see #drawGraphics(BufferedImage, Graphics2D, Cancellable, double)
325
         * @see #print(Graphics2D, double, PrintRequestAttributeSet)
326
         */
327
        private GraphicLayer tracLayer = new GraphicLayer();
328

    
329
        /**
330
         * Information for draw layers in a view.
331
         *
332
         * @see #getViewPort()
333
         * @see #setViewPort(ViewPort)
334
         */
335
        private ViewPort viewPort;
336

    
337
        // private ArrayList invalidationListeners = new ArrayList();
338

    
339
        /**
340
         * Array list with all {@link LegendListener LegendListener} registered to this map.
341
         *
342
         * @see #addLayerListener(LegendListener)
343
         * @see #removeLayerListener(LegendListener)
344
         * @see #callLegendChanged()
345
         */
346
        private ArrayList legendListeners = new ArrayList();
347

    
348
        /**
349
         * Array list with all {@link LayerDrawingListener LayerDrawingListener} registered to this map.
350
         *
351
         * @see #addLayerDrawingListener(LayerDrawingListener)
352
         * @see #removeLayerDrawListener(LayerDrawingListener)
353
         * @see #fireLayerDrawingEvent(LayerDrawEvent)
354
         */
355
        private ArrayList layerDrawingListeners = new ArrayList();
356

    
357
        /**
358
         * <p>Buffer that is used to store and eject events produced on this map:
359
         * <ul>
360
         *  <li>Layer collection events.
361
         *  <li>View port events.
362
         *  <li>Atomic events.
363
         *  <li>Layer events.
364
         *  <li>Legend events on a {@link Classificable Classificable} layer.
365
         *  <li>Selection events on an {@link AlphanumericData AlphanumericData} data layer.
366
         * </ul>
367
         * </p>
368
         *
369
         * @see #addAtomicEventListener(AtomicEventListener)
370
         * @see #removeAtomicEventListener(AtomicEventListener)
371
         * @see #beginAtomicEvent()
372
         * @see #endAtomicEvent()
373
         */
374
        private EventBuffer eventBuffer = new EventBuffer();
375

    
376
        /**
377
         * Event listener for the collection of layers of this map.
378
         */
379
        private LayerEventListener layerEventListener = null;
380

    
381
        /**
382
         * List with information of all errors produced on all layers.
383
         *
384
         * @see #addLayerError(String)
385
         * @see #getLayersError()
386
         * @see #clearErrors()
387
         */
388
        private ArrayList layersError = new ArrayList();
389

    
390
        /**
391
         * Array list with all {@link ErrorListener ErrorListener} registered to this map.
392
         *
393
         * @see #addErrorListener(ErrorListener)
394
         * @see #removeErrorListener(LegendListener)
395
         * @see #callNewErrorEvent(ErrorEvent)
396
         * @see #reportDriverExceptions(String, List)
397
         */
398
        private ArrayList errorListeners = new ArrayList();
399

    
400

    
401

    
402
        // public static ResourceBundle myResourceBundle =
403
        // ResourceBundle.getBundle("FMap");
404

    
405
        /**
406
         * <p>Default <i>zoom in</i> factor.</p>
407
         * <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
408
         * area but with the items bigger.</p>
409
         */
410
        public static double ZOOMINFACTOR=2;
411

    
412
        /**
413
         * <p>Default <i>zoom out</i> factor.</p>
414
         * <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
415
         * area but with the items smaller.</p>
416
         */
417
        public static double ZOOMOUTFACTOR=0.5;
418

    
419
        /**
420
         *          * Draw version of the context. It's used for know when de componend has
421
         * changed any visualization property
422
         *
423
         *  @see getDrawVersion
424
         *  @see updateDrawVersion
425
         */
426
        private long drawVersion= 0L;
427

    
428
        /**
429
         * Object to Manage Draw of MapContext
430
         */
431
        private MapContextDrawer mapContextDrawer= null;
432

    
433
        /**
434
         * Object to Manage Draw of MapContext
435
         */
436
        private Class mapContextDrawerClass = DefaultMapContextDrawer.class;
437
        private Class defaultMapContextDrawerClass = DefaultMapContextDrawer.class;
438

    
439
        /**
440
         * <p>Color used to represent the selections.</p>
441
         */
442
        private static Color selectionColor = Color.YELLOW;
443

    
444

    
445
        /**
446
         * <p>Gets the color used to represent the selections.</p>
447
         *
448
         * @return color used to represent the selections
449
         */
450
        public static Color getSelectionColor() {
451
                return selectionColor;
452
        }
453

    
454
        /**
455
         * <p>Sets the color used to represent the selections.</p>
456
         *
457
         * @param selectionColor color used to represent the selections
458
         */
459
        public static void setSelectionColor(Color selectionColor) {
460
                MapContext.selectionColor = selectionColor;
461
        }
462

    
463
        /**
464
         * <p>Creates a new map context with the drawing information defined in the view port argument, and
465
         *  without layers.</p>
466
         *
467
         * @param vp information for drawing the layers of this map in the available rectangular area according a projection
468
         */
469
        public MapContext(ViewPort vp) {
470
                this.layers = new FLayers();//(this,null);
471
                this.layers.setMapContext(this);
472

    
473
                layerEventListener = new LayerEventListener();
474
                layers.addLayerCollectionListener(layerEventListener);
475
                layers.addLayerCollectionListener(eventBuffer);
476

    
477
                setViewPort(vp);
478

    
479
        }
480

    
481
        /**
482
         * <p>Creates a new map context with the layers and the drawing information defined in the view port arguments.</p>
483
         *
484
         * @param fLayers the initial hierarchy of nodes of layers that this map will have
485
         * @param vp information for drawing the layers of this map in the available rectangular area according a projection
486
         */
487
        public MapContext(FLayers fLayers, ViewPort vp) {
488
                this.layers = fLayers;
489

    
490
                layerEventListener = new LayerEventListener();
491
                layers.addLayerCollectionListener(layerEventListener);
492
                layers.addLayerCollectionListener(eventBuffer);
493

    
494
                setViewPort(vp);
495
        }
496

    
497
        /**
498
         * <p>Reports to all driver error listeners registered of a bundle of driver exceptions caused in the same map atomic transaction.</p>
499
         *
500
         * @param introductoryText introductory text specified by developer. If <code>null</code>, use ""
501
         * @param driverExceptions list with a bundle of driver exceptions caught during an atomic event
502
         *
503
         * @see #addErrorListener(ErrorListener)
504
         * @see #removeErrorListener(LegendListener)
505
         * @see #callNewErrorEvent(ErrorEvent)
506
         */
507
        public synchronized void reportDriverExceptions(String introductoryText,
508
                                                                                                        List driverExceptions){
509
                for (int i = 0; i < errorListeners.size(); i++) {
510
                        ((ErrorListener) errorListeners.get(i)).
511
                                reportDriverExceptions(introductoryText, driverExceptions);
512
                }
513
        }
514

    
515
        /**
516
         * <p>Adds the specified legend listener (if didn't exist) to receive legend events from this map.</p>
517
         *
518
         * @param listener the legend listener
519
         *
520
         * @see #removeLayerListener(LegendListener)
521
         * @see #callLegendChanged()
522
         */
523
        public void addLayerListener(LegendListener listener) {
524
                if (!legendListeners.contains(listener))
525
                        legendListeners.add(listener);
526
        }
527
        // SUGERENCIA DE PABLO
528
        //        public void addLegendListener(LegendListener listener) {
529
        //                if (!legendListeners.contains(listener))
530
        //                        legendListeners.add(listener);
531
        //        }
532

    
533
        /**
534
         * <p>Adds the specified layer drawing listener to catch and handle drawing events from layers of this map.</p>
535
         *
536
         * @param listener the listener to add
537
         *
538
         * @see #removeLayerDrawListener(LayerDrawingListener)
539
         * @see #fireLayerDrawingEvent(LayerDrawEvent)
540
         */
541
        public void addLayerDrawingListener(LayerDrawingListener listener) {
542
                layerDrawingListeners.add(listener);
543
        }
544

    
545
        /**
546
         * <p>Removes the specified layer drawing listener from this map.</p>
547
         *
548
         * @param listener the listener to remove
549
         *
550
         * @see #addLayerDrawingListener(LayerDrawingListener)
551
         * @see #fireLayerDrawingEvent(LayerDrawEvent)
552
         */
553
        public void removeLayerDrawListener(LayerDrawingListener listener) {
554
                layerDrawingListeners.remove(listener);
555
        }
556

    
557
        /**
558
         * <p>Adds the specified error listener to receive error events from this map.</p>
559
         *
560
         * @param listener the listener to add
561
         *
562
         * @see #removeErrorListener(LegendListener)
563
         * @see #callNewErrorEvent(ErrorEvent)
564
         * @see #reportDriverExceptions(String, List)
565
         */
566
        public void addErrorListener(ErrorListener listener) {
567
                errorListeners.add(listener);
568
        }
569

    
570
        /**
571
         * <p>Removes the specified error listener from this map.</p>
572
         *
573
         * @param listener the listener to remove
574
         *
575
         * @see #addErrorListener(ErrorListener)
576
         * @see #callNewErrorEvent(ErrorEvent)
577
         * @see #reportDriverExceptions(String, List)
578
         */
579
        public void removeErrorListener(LegendListener listener) {
580
                legendListeners.remove(listener);
581
        }
582

    
583
        // SUGERENCIA DE PABLO:
584
        //public void removeErrorListener(ErrorListener listener) {
585
        //        errorListeners.remove(listener);
586
        //}
587

    
588
        /**
589
         * <p>Notifies to all legend listeners registered, that one legend has changed.</p>
590
         * <p>This method must be called only if it's wanted to reflect a legend change.</p>
591
         *
592
         * @see #addLayerListener(LegendListener)
593
         * @see #removeLayerListener(LegendListener)
594
         */
595
        public synchronized void callLegendChanged() {
596
                for (int i = 0; i < legendListeners.size(); i++) {
597
                        ((LegendListener) legendListeners.get(i)).legendChanged(null);
598
                }
599
                // getLayers().moveTo(0,0);
600
        }
601

    
602
        /**
603
         * <p>Fires a layer drawing event to all {@link LayerDrawingListener LayerDrawingListener} listeners registered,
604
         *  distinguishing the kind of event.</p>
605
         *
606
         * @param e the event
607
         *
608
         * @see #addLayerDrawingListener(LayerDrawingListener)
609
         * @see #removeLayerDrawListener(LayerDrawingListener)
610
         */
611
        public synchronized void fireLayerDrawingEvent(LayerDrawEvent e) {
612
                for (int i = 0; i < layerDrawingListeners.size(); i++)
613
                {
614
                        LayerDrawingListener listener = (LayerDrawingListener) layerDrawingListeners.get(i);
615
                        switch (e.getEventType())
616
                        {
617
                                case LayerDrawEvent.LAYER_BEFORE_DRAW:
618
                                        listener.beforeLayerDraw(e);
619
                                        break;
620
                                case LayerDrawEvent.LAYER_AFTER_DRAW:
621
                                        listener.afterLayerDraw(e);
622
                                        break;
623
                                case LayerDrawEvent.GRAPHICLAYER_BEFORE_DRAW:
624
                                        listener.beforeGraphicLayerDraw(e);
625
                                        break;
626
                                case LayerDrawEvent.GRAPHICLAYER_AFTER_DRAW:
627
                                        listener.afterLayerGraphicDraw(e);
628
                                        break;
629
                        }
630
                }
631
                // getLayers().moveTo(0,0);
632
        }
633

    
634
        /**
635
         * <p>Notifies to all error listeners registered, that one error has been produced.</p>
636
         *
637
         * @param e the event with information of the error
638
         *
639
         * @see #addErrorListener(ErrorListener)
640
         * @see #removeErrorListener(LegendListener)
641
         * @see #reportDriverExceptions(String, List)
642
         */
643
        public synchronized void callNewErrorEvent(ErrorEvent e) {
644
                for (int i = 0; i < errorListeners.size(); i++) {
645
                        ((ErrorListener) errorListeners.get(i)).errorThrown(e);
646
                }
647
                errorListeners.clear();
648
                // getLayers().moveTo(0,0);
649
        }
650

    
651
        /**
652
         * <p>Removes the specified layer listener from this map.</p>
653
         *
654
         * @param listener the listener to remove
655
         *
656
         * @see #addLayerListener(LegendListener)
657
         * @see #callLegendChanged()
658
         */
659
        public void removeLayerListener(LegendListener listener) {
660
                legendListeners.remove(listener);
661
        }
662

    
663
        // SUGERENCIA DE PABLO:
664
        // public void removeLegendListener(LegendListener listener) {
665
        //         legendListeners.remove(listener);
666
        // }
667

    
668
        /**
669
         * <p>Returns the hierarchy of {@link FLayers FLayers} nodes stored in this map.</p>
670
         *
671
         * @return the hierarchy of nodes of layers stored in this map
672
         */
673
        public FLayers getLayers() {
674
                return layers;
675
        }
676

    
677
        /**
678
         * <p>Draws the visible layers of this map according its view port, on the image parameter.</p>
679
         *
680
         * @param b image with an accessible buffer of image data
681
         */
682
        public void drawLabels(BufferedImage b) {
683
        }
684

    
685
        /**
686
         * @see #redraw()
687
         */
688
        public void invalidate() {
689
                if (getLayers().getLayersCount() > 0)
690
                        getLayers().moveTo(0, 0);
691
        }
692

    
693
        /**
694
         * <p>Prints the layers of this map using the {@link Graphics2D Graphics2D} argument, that usually is
695
         * the {@link Graphics Graphics} of the printer.</p>
696
         *
697
         * @param g for rendering 2-dimensional shapes, text and images on the Java(tm) platform
698
         * @param scale the scale of the view. Must be between {@linkplain FLayer#getMinScale()} and {@linkplain FLayer#getMaxScale()}.
699
         * @param properties a set with the settings to be applied to a whole print job and to all the documents in the print job
700
         *
701
         * @throws ReadDriverException if fails reading with driver.
702
         *
703
         * @see FLayers#print(Graphics2D, ViewPort, Cancellable, double, PrintRequestAttributeSet)
704
         * @see GraphicLayer#draw(BufferedImage, Graphics2D, ViewPort, Cancellable, double)
705
         */
706
        public void print(Graphics2D g, double scale, PrintRequestAttributeSet properties) throws ReadDriverException {
707
                RenderingHints renderHints = new RenderingHints(
708
                                RenderingHints.KEY_ANTIALIASING,
709
                                RenderingHints.VALUE_ANTIALIAS_ON);
710
                renderHints.put(RenderingHints.KEY_RENDERING,
711
                                RenderingHints.VALUE_RENDER_QUALITY);
712
                g.setRenderingHints(renderHints);
713

    
714
                Cancellable cancel = new Cancellable() {
715
                        public boolean isCanceled() {
716
                                return false;
717
                        }
718

    
719
                        public void setCanceled(boolean canceled) {
720
                                // No queremos que se pueda cancelar la impresi?n.
721

    
722
                        }
723
                };
724
                this.getMapContextDrawer().print(this.layers, g, cancel, scale,properties);
725
                tracLayer.draw(null, g, viewPort, cancel, scale);
726
        }
727

    
728
        /**
729
         * <p>Returns a new <code>MapContext</code> instance with the information of the <code>vp</code> argument, and the layers of this map.</p>
730
         *
731
         * @param vp information for drawing the layers of this map in the available rectangular area according a projection
732
         *
733
         * @return a new <code>MapContext</code> instance projected by <code>vp</code>
734
         */
735
        public MapContext createNewFMap(ViewPort vp) {
736
                MapContext ret = new MapContext(vp);
737
                ret.layers = this.layers;
738

    
739
                return ret;
740
        }
741

    
742
        /**
743
         * <p>Creates a new independent <code>MapContext</code> instance, that has a clone of the layers and the view port of this one.</p>
744
         * <p>The new map will have the same data source drivers to avoid waste memory, and work faster.</p>
745
         *
746
         * @return the new <code>MapContext</code> instance
747
         *
748
         * @throws XMLException if fails cloning the view port or a layer
749
         *
750
         * @see FLayer#cloneLayer()
751
         * @see ViewPort#cloneViewPort()
752
         */
753
        public MapContext cloneFMap() throws XMLException {
754
                ViewPort vp = getViewPort().cloneViewPort();
755
                FLayers antLayers = getLayers();
756
                MapContext ret = new MapContext(vp);
757
                FLayers aux = new FLayers();//(ret,null);
758
                aux.setMapContext(ret);
759
                for (int i=0; i < antLayers.getLayersCount(); i++)
760
                {
761
                        FLayer lyr = antLayers.getLayer(i);
762
                        try {
763
                                aux.addLayer(lyr.cloneLayer());
764
                        } catch (Exception e) {
765

    
766
                                // TODO Auto-generated catch block
767
                                e.printStackTrace();
768
                                throw new XMLException(e);
769
                        }
770
                }
771
                ret.layers = aux;
772
        // FJP: Nuevo para que se vean los graficos                
773
                ret.setGraphicsLayer(this.getGraphicsLayer());
774
        // FJP: Fin nuevo
775

    
776
                
777
                return ret;
778

    
779
//                return createFromXML(getXMLEntity());
780

    
781
        }
782

    
783
        /**
784
         * Like {@linkplain #cloneFMap()}, but now doesn't clone the layers, rather copies them.
785
         *
786
         * @return the new map
787
         */
788
        public MapContext cloneToDraw() {
789
                ViewPort vp = getViewPort().cloneViewPort();
790
                MapContext mapContext=new MapContext(getLayers(),vp);
791
                return mapContext;
792
        }
793

    
794
        /**
795
         * A?ade la capa que se pasa como par?metro al nodo que se pasa como
796
         * parametro y lanza ProjectionMismatchException si no est?n todas las capas
797
         * de este FMap en la misma proyecci?n. Lanza un ChildNotAllowedException si
798
         * la capa no es un FLayers y no permite hijos
799
         *
800
         * @param vectorial
801
         *            DOCUMENT ME!
802
         */
803

    
804
        /*
805
         * public void addLayer(LayerPath parent, FLayer layer) throws
806
         * ProjectionMismatchException, ChildrenNotAllowedException {
807
         * layers.addLayer(parent, layer); } public void removeLayer(LayerPath
808
         * parent)throws ChildrenNotAllowedException{ layers.removeLayer(parent); }
809
         */
810

    
811
        /**
812
         * <p>Adds a layer to the group of layers that are at a upper level in the tree.</p>
813
         *
814
         * @param vectorial the layer to add
815
         */
816
        public void addToTrackLayer(FLayer vectorial) {
817
        }
818

    
819
        /**
820
         * <p>Returns the scale of the view in the screen.</p>
821
         *
822
         * @return one of this values:
823
         * <ul>
824
         * <li>the scale of the adjusted extent scale of the view in the screen
825
         * <li><code>-1</code> if there is no image
826
         * <li><code>0</code> if there is no extent defined for the image
827
         * </ul>
828
         *
829
         * @see #setScaleView(long)
830
         * @see ViewPort#getAdjustedExtent()
831
         * @see IProjection#getScale(double, double, double, double)
832
         */
833
        public long getScaleView() {
834
                double dpi = getScreenDPI();
835
                IProjection proj = viewPort.getProjection();
836

    
837
                if (viewPort.getImageSize() == null)
838
                        return -1;
839

    
840
                if (viewPort.getAdjustedExtent() == null) {
841
                        return 0;
842
                }
843
                double[] trans2Meter=getDistanceTrans2Meter();
844
                if (proj == null) {
845
                        double w = ((viewPort.getImageSize().getWidth() / dpi) * 2.54);
846
                        return (long) (viewPort.getAdjustedExtent().getWidth() / w * trans2Meter[getViewPort()
847
                                        .getMapUnits()]);
848
                }
849

    
850
                return Math.round(proj.getScale((viewPort.getAdjustedExtent().getMinX()*trans2Meter[getViewPort().getMapUnits()]),
851
                                (viewPort.getAdjustedExtent().getMaxX()*trans2Meter[getViewPort().getMapUnits()]), viewPort.getImageSize()
852
                                                .getWidth(), dpi));
853

    
854

    
855
        }
856

    
857
        /**
858
         * <p>Sets the new extent of the view, calculated using the scale argument.</p>
859
         * <p>Doesn't updates the scale if there isn't information about the dimension of the image or the
860
         *  adjusted extent.</p>
861
         *
862
         * @param scale the new scale for the view
863
         *
864
         * @see ViewPort#setProjection(IProjection)
865
         * @see #getScaleView()
866
         */
867
        public void setScaleView(long scale) {
868
                //clearAllCachingImageDrawnLayers();
869
                double dpi = getScreenDPI();
870
                if (viewPort.getImageSize() == null)
871
                        return;
872
                IProjection proj = viewPort.getProjection();
873
                if (viewPort.getAdjustedExtent() == null) {
874
                        return;
875
                }
876
                double[] trans2Meter=getDistanceTrans2Meter();
877
                Rectangle2D rec=proj.getExtent(viewPort.getAdjustedExtent(), //extent
878
                                scale, //scale
879
                                viewPort.getImageWidth(), //wImage
880
                                viewPort.getImageHeight(), //hImage
881
                                100*trans2Meter[getViewPort().getMapUnits()], //mapUnits
882
                                trans2Meter[getViewPort().getDistanceUnits()], //distanceUnits
883
                                dpi); //dpi
884
                getViewPort().setExtent(rec);
885
        }
886

    
887
        /**
888
         * <p>Returns the screen resolution (Dots Per Inch) as it was defined by the user's preference, or
889
         * by default as it is defined in the default Toolkit.</p>
890
         *
891
         * @return double with the screen's dpi
892
         */
893
        public static double getScreenDPI() {
894
                Preferences prefsResolution = Preferences.userRoot().node( "gvsig.configuration.screen" );
895
                Toolkit kit = Toolkit.getDefaultToolkit();
896
                double dpi = prefsResolution.getInt("dpi",kit.getScreenResolution());
897
                return dpi;
898
        }
899

    
900
        /**
901
         * @see com.iver.cit.gvsig.fmap.operations.strategies.Strategy#setVectorial(com.iver.cit.gvsig.fmap.VectorialAdapter)
902
         */
903
        public void setVectorial(VectorialAdapter v) {
904
        }
905

    
906
        /**
907
         * @see com.iver.cit.gvsig.fmap.operations.strategies.Strategy#process(com.iver.cit.gvsig.fmap.FeatureSelectorVisitor)
908
         */
909
        public void process(FeatureVisitor visitor) {
910
        }
911

    
912
        /**
913
         * @see com.iver.cit.gvsig.fmap.operations.strategies.Strategy#processSelected(com.iver.cit.gvsig.fmap.FeatureVisitor)
914
         */
915
        public void processSelected(FeatureVisitor visitor) {
916
        }
917

    
918
        /**
919
         * @see com.iver.cit.gvsig.fmap.operations.strategies.Strategy#select(com.iver.cit.gvsig.fmap.FeatureSelectorVisitor,
920
         *      VectorialSubSet)
921
         */
922
        public void select(FeatureVisitor visitor) {
923
        }
924

    
925
        /**
926
         * @see com.iver.cit.gvsig.fmap.operations.strategies.Strategy#selectFromSelection()
927
         */
928
        public void selectFromSelection() {
929
        }
930

    
931
        /**
932
         * @see com.iver.cit.gvsig.fmap.operations.strategies.Strategy#createIndex()
933
         */
934
        public void createIndex() {
935
        }
936

    
937
        /**
938
         * @see org.cresques.geo.Projected#getProjection()
939
         *
940
         * @see ViewPort#getProjection()
941
         * @see #setProjection(IProjection)
942
         * @see #reProject(ICoordTrans)
943
         */
944
        public IProjection getProjection() {
945
                return getViewPort().getProjection();
946
        }
947

    
948
        /**
949
         * <p>Sets the new projection.</p>
950
         *
951
         * @param proj the new projection
952
         *
953
         * @see #getProjection()
954
         * @see ViewPort#setProjection(IProjection)
955
         * @see #reProject(ICoordTrans)
956
         */
957
        public void setProjection(IProjection proj) {
958
                if (getViewPort() != null) {
959
                        getViewPort().setProjection(proj);
960
                }
961
        }
962

    
963
        /**
964
         * @see org.cresques.geo.Projected#reProject(org.cresques.cts.ICoordTrans)
965
         */
966
        public void reProject(ICoordTrans arg0) {
967
                // TODO implementar reprojecci?n (lo que sea eso)
968
        }
969

    
970
        /**
971
         * @see com.iver.cit.gvsig.fmap.operations.strategies.Strategy#selectByPoint(java.awt.geom.Point2D,
972
         *      double)
973
         */
974
        /*
975
         * public void selectByPoint(Point2D p, double tolerance) throws
976
         * DriverException { Point2D mapPoint = viewPort.toMapPoint((int) p.getX(),
977
         * (int) p.getY()); SelectByPointVisitor visitor = new
978
         * SelectByPointVisitor(); visitor.setQueriedPoint(mapPoint);
979
         * visitor.setTolerance(getViewPort().toMapDistance(3));
980
         *
981
         * try { layers.process(visitor); } catch (VisitException e) { throw new
982
         * RuntimeException("No se espera que SelectByPointVisitor lance esta
983
         * excepci?n", e); } }
984
         */
985

    
986
        /**
987
         * @see com.iver.cit.gvsig.fmap.operations.strategies.Strategy#selectByRect(java.awt.geom.Rectangle2D)
988
         */
989
        /*
990
         * public void selectByRect(Rectangle2D rect) throws DriverException {
991
         * FLayer[] actives = layers.getActives(); for (int i=0; i < actives.length;
992
         * i++) { if (actives[i] instanceof FLyrVect) { FLyrVect lyrVect =
993
         * (FLyrVect) actives[i]; FBitSet oldBitSet = lyrVect.getSelection();
994
         * FBitSet newBitSet = lyrVect.queryByRect(rect); newBitSet.xor(oldBitSet);
995
         * lyrVect.setSelection(newBitSet); } }
996
         *  }
997
         */
998

    
999
        /**
1000
         * @see com.iver.cit.gvsig.fmap.operations.strategies.Strategy#selectByShape(com.iver.cit.gvsig.fmap.fshape.IGeometry,
1001
         *      int)
1002
         */
1003
        public void selectByShape(IGeometry g, int relationship) {
1004
        }
1005

    
1006
        /**
1007
         * @see com.iver.cit.gvsig.fmap.operations.strategies.Strategy#queryByPoint(Point2D,
1008
         *      double)
1009
         */
1010
        public Record[] queryByPoint(Point2D p, double tolerance) {
1011
                return null;
1012
        }
1013

    
1014
        /**
1015
         * @see com.iver.cit.gvsig.fmap.operations.strategies.Strategy#queryByRect(java.awt.geom.Rectangle2D)
1016
         */
1017
        public Record[] queryByRect(Rectangle2D rect) {
1018
                return null;
1019
        }
1020

    
1021
        /**
1022
         * @see com.iver.cit.gvsig.fmap.operations.strategies.Strategy#queryByShape(com.iver.cit.gvsig.fmap.fshape.IGeometry,
1023
         *      int)
1024
         */
1025
        public Record[] queryByShape(IGeometry g, int relationship) {
1026
                return null;
1027
        }
1028

    
1029
        /**
1030
         * @see com.iver.cit.gvsig.fmap.operations.strategies.Strategy#getSelectionBounds()
1031
         *
1032
         * @see SelectedZoomVisitor#getSelectBound()
1033
         */
1034
        public Rectangle2D getSelectionBounds() {
1035
                SelectedZoomVisitor visitor = new SelectedZoomVisitor();
1036

    
1037
                try {
1038
                        layers.process(visitor);
1039
                } catch (ReadDriverException e1) {
1040
                        throw new RuntimeException(
1041
                                        "No se espera que SelectByPointVisitor lance esta excepci?n",
1042
                                        e1);
1043
                } catch (VisitorException e) {
1044
                        throw new RuntimeException(
1045
                                        "No se espera que SelectByPointVisitor lance esta excepci?n",
1046
                                        e);
1047
                }
1048

    
1049
                return visitor.getSelectBound();
1050
        }
1051

    
1052
        /**
1053
         * <p>Draws this map if its {@link ViewPort ViewPort} has an extent defined:<br>
1054
         * <ol>
1055
         * <li>Selects only the layers that have to be drawn: {@linkplain #prepareDrawing(BufferedImage, Graphics2D, double)}.
1056
         * <li>Sets quality: antialiasing by text and images, and quality rendering.
1057
         * <li>Draws the layers.
1058
         * <li>Fires a <code>LayerDrawEvent.GRAPHICLAYER_BEFORE_DRAW</code>.
1059
         * <li>Draws the graphic layer.
1060
         * <li>Fires a <code>LayerDrawEvent.GRAPHICLAYER_AFTER_DRAW</code>.
1061
         * <li>Invokes the garbage collector and memory clean.
1062
         * </ol></p>
1063
         *
1064
         * @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.
1065
         * @param g for rendering 2-dimensional shapes, text and images on the Java(tm) platform
1066
         * @param cancel shared object that determines if this layer can continue being drawn
1067
         * @param scale the scale of the view. Must be between {@linkplain FLayer#getMinScale()} and {@linkplain FLayer#getMaxScale()}.
1068
         * @throws ReadDriverException if fails reading with the driver.
1069
         */
1070
        public void draw(BufferedImage image, Graphics2D g, Cancellable cancel,
1071
                        double scale) throws ReadDriverException {
1072
                if (viewPort.getExtent() == null) {
1073
                        // System.err.println("viewPort.getExtent() = null");
1074
                        return;
1075
                }
1076
                System.out.println("Viewport despues: " + viewPort.toString());
1077
                /*
1078
                 * if ((viewPort.getImageWidth() <=0) || (viewPort.getImageHeight() <=
1079
                 * 0)) { return; }
1080
                 */
1081

    
1082
//                prepareDrawing(image, g, scale);
1083

    
1084
                // M?s c?lidad al texto
1085
                RenderingHints renderHints = new RenderingHints(
1086
                                RenderingHints.KEY_ANTIALIASING,
1087
                                RenderingHints.VALUE_ANTIALIAS_ON);
1088
                renderHints.put(RenderingHints.KEY_RENDERING,
1089
                                RenderingHints.VALUE_RENDER_QUALITY);
1090
                renderHints.put(RenderingHints.KEY_TEXT_ANTIALIASING,
1091
                                RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
1092
                g.setRenderingHints(renderHints);
1093

    
1094
                long t1 = System.currentTimeMillis();
1095
//                layers.draw(image, g, viewPort, cancel, scale);
1096

    
1097
                this.getMapContextDrawer().draw(this.layers, image, g, cancel, scale);
1098

    
1099
                LayerDrawEvent beforeTracLayerEvent = new LayerDrawEvent(tracLayer,
1100
                                g, viewPort, LayerDrawEvent.GRAPHICLAYER_BEFORE_DRAW);
1101
                fireLayerDrawingEvent(beforeTracLayerEvent);
1102
                tracLayer.draw(image, g, viewPort, cancel, scale);
1103
                LayerDrawEvent afterTracLayerEvent = new LayerDrawEvent(tracLayer,
1104
                                g, viewPort, LayerDrawEvent.GRAPHICLAYER_AFTER_DRAW);
1105
                fireLayerDrawingEvent(afterTracLayerEvent);
1106

    
1107
                //layers.setDirty(false);
1108
                long t2 = System.currentTimeMillis();
1109
                System.err.println("Tiempo de dibujado:" + (t2 - t1) +
1110
                                " mseg. Memoria libre:" + Runtime.getRuntime().freeMemory() / 1024  + " KB");
1111
                /*
1112
                 * g.setColor(Color.BLUE); GeneralPath shpR = new
1113
                 * GeneralPath(viewPort.getExtent());
1114
                 * shpR.transform(viewPort.getAffineTransform()); g.draw(shpR);
1115
                 */
1116
                System.gc();
1117
        }
1118
        
1119
        
1120
        
1121
        /**
1122
         * <p>Draws this map if its {@link ViewPort ViewPort} has an extent defined:<br>
1123
         * <ol>
1124
         * <li>Selects only the layers that have to be drawn: {@linkplain #prepareDrawing(BufferedImage, Graphics2D, double)}.
1125
         * <li>Sets quality: antialiasing by text and images, and quality rendering.
1126
         * <li>Draws the layers.
1127
         * <li>Fires a <code>LayerDrawEvent.GRAPHICLAYER_BEFORE_DRAW</code>.
1128
         * <li>Draws the graphic layer.
1129
         * <li>Fires a <code>LayerDrawEvent.GRAPHICLAYER_AFTER_DRAW</code>.
1130
         * <li>Invokes the garbage collector and memory clean.
1131
         * </ol></p>
1132
         *
1133
         * @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.
1134
         * @param g for rendering 2-dimensional shapes, text and images on the Java(tm) platform
1135
         * @param cancel shared object that determines if this layer can continue being drawn
1136
         * @param scale the scale of the view. Must be between {@linkplain FLayer#getMinScale()} and {@linkplain FLayer#getMaxScale()}.
1137
         * @throws ReadDriverException if fails reading with the driver.
1138
         */
1139
        public void draw(BufferedImage image, Graphics2D g, Cancellable cancel,
1140
                        double scale, double _dpi) throws ReadDriverException {
1141
                if (viewPort.getExtent() == null) {
1142
                        // System.err.println("viewPort.getExtent() = null");
1143
                        return;
1144
                }
1145
                System.out.println("Viewport despues: " + viewPort.toString());
1146
                /*
1147
                 * if ((viewPort.getImageWidth() <=0) || (viewPort.getImageHeight() <=
1148
                 * 0)) { return; }
1149
                 */
1150

    
1151
//                prepareDrawing(image, g, scale);
1152

    
1153
                // M?s c?lidad al texto
1154
                RenderingHints renderHints = new RenderingHints(
1155
                                RenderingHints.KEY_ANTIALIASING,
1156
                                RenderingHints.VALUE_ANTIALIAS_ON);
1157
                renderHints.put(RenderingHints.KEY_RENDERING,
1158
                                RenderingHints.VALUE_RENDER_QUALITY);
1159
                renderHints.put(RenderingHints.KEY_TEXT_ANTIALIASING,
1160
                                RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
1161
                g.setRenderingHints(renderHints);
1162

    
1163
                long t1 = System.currentTimeMillis();
1164
//                layers.draw(image, g, viewPort, cancel, scale);
1165

    
1166
                this.getMapContextDrawer().draw(this.layers, image, g, cancel, scale, _dpi);
1167

    
1168
                LayerDrawEvent beforeTracLayerEvent = new LayerDrawEvent(tracLayer,
1169
                                g, viewPort, LayerDrawEvent.GRAPHICLAYER_BEFORE_DRAW);
1170
                fireLayerDrawingEvent(beforeTracLayerEvent);
1171
                tracLayer.draw(image, g, viewPort, cancel, scale);
1172
                LayerDrawEvent afterTracLayerEvent = new LayerDrawEvent(tracLayer,
1173
                                g, viewPort, LayerDrawEvent.GRAPHICLAYER_AFTER_DRAW);
1174
                fireLayerDrawingEvent(afterTracLayerEvent);
1175

    
1176
                //layers.setDirty(false);
1177
                long t2 = System.currentTimeMillis();
1178
                System.err.println("Tiempo de dibujado:" + (t2 - t1) +
1179
                                " mseg. Memoria libre:" + Runtime.getRuntime().freeMemory() / 1024  + " KB");
1180
                /*
1181
                 * g.setColor(Color.BLUE); GeneralPath shpR = new
1182
                 * GeneralPath(viewPort.getExtent());
1183
                 * shpR.transform(viewPort.getAffineTransform()); g.draw(shpR);
1184
                 */
1185
                System.gc();
1186
        }
1187

    
1188
        /**
1189
         * <p>Draws only the internal graphic layer using the information of the {@link ViewPort ViewPort} of this map.</p>
1190
         *
1191
         * @param image image used to accelerate the screen draw
1192
         * @param g for rendering 2-dimensional shapes, text and images on the Java(tm) platform
1193
         * @param cancel shared object that determines if this layer can continue being drawn
1194
         * @param scale value that represents the scale
1195
         * @throws ReadDriverException if fails reading with the driver.
1196
         *
1197
         * @see GraphicLayer#draw(BufferedImage, Graphics2D, ViewPort, Cancellable, double)
1198
         */
1199
        public void drawGraphics(BufferedImage image, Graphics2D g,
1200
                        Cancellable cancel, double scale) throws ReadDriverException {
1201
                if (viewPort == null)
1202
                        return;
1203
                tracLayer.draw(image, g, viewPort, cancel, scale);
1204
        }
1205

    
1206
        /**
1207
         * <p>Like {@linkplain MapContext#draw(BufferedImage, Graphics2D, Cancellable, double)}, but creating
1208
         *  the task as cancellable.</p>
1209
         *
1210
         * @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.
1211
         * @param g for rendering 2-dimensional shapes, text and images on the Java(tm) platform
1212
         * @param scale the scale of the view. Must be between {@linkplain FLayer#getMinScale()} and {@linkplain FLayer#getMaxScale()}.
1213
         *
1214
         * @throws ReadDriverException if the driver fails reading.
1215
         *
1216
         * @see #draw(BufferedImage, Graphics2D, Cancellable, double)
1217
         */
1218
        public void draw(BufferedImage image, Graphics2D g, double scale)
1219
                        throws ReadDriverException {
1220
//                layers.setDirty(true);
1221
                draw(image, g, new Cancellable() {
1222
                        /**
1223
                         * @see com.iver.utiles.swing.threads.Cancellable#isCanceled()
1224
                         */
1225
                        public boolean isCanceled() {
1226
                                return false;
1227
                        }
1228

    
1229
                        public void setCanceled(boolean canceled) {
1230
                                // TODO Auto-generated method stub
1231

    
1232
                        }
1233
                }, scale);
1234
        }
1235

    
1236
        
1237
        /**
1238
         * <p>Like {@linkplain MapContext#draw(BufferedImage, Graphics2D, Cancellable, double)}, but creating
1239
         *  the task as cancellable.</p>
1240
         *
1241
         * @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.
1242
         * @param g for rendering 2-dimensional shapes, text and images on the Java(tm) platform
1243
         * @param scale the scale of the view. Must be between {@linkplain FLayer#getMinScale()} and {@linkplain FLayer#getMaxScale()}.
1244
         *
1245
         * @throws ReadDriverException if the driver fails reading.
1246
         *
1247
         * @see #draw(BufferedImage, Graphics2D, Cancellable, double)
1248
         */
1249
        public void draw(BufferedImage image, Graphics2D g, double scale, double _dpi)
1250
                        throws ReadDriverException {
1251
//                layers.setDirty(true);
1252
                draw(image, g, new Cancellable() {
1253
                        /**
1254
                         * @see com.iver.utiles.swing.threads.Cancellable#isCanceled()
1255
                         */
1256
                        public boolean isCanceled() {
1257
                                return false;
1258
                        }
1259

    
1260
                        public void setCanceled(boolean canceled) {
1261
                                // TODO Auto-generated method stub
1262

    
1263
                        }
1264
                }, scale, _dpi);
1265
        }
1266
        
1267
        
1268
        /**
1269
         * <p>Gets the {@link ViewPort ViewPort} associated to this map.</p>
1270
         *
1271
         * @return the view port
1272
         *
1273
         * @see #setViewPort(ViewPort)
1274
         */
1275
        public ViewPort getViewPort() {
1276
                return viewPort;
1277
        }
1278

    
1279
        /**
1280
         * <p>Sets a {@link ViewPort ViewPort} with the drawing information
1281
         *  of this map.</p>
1282
         * <p>If there was a previous view port, removes its {@link EventBuffer EventBuffer} and
1283
         *  adds the new one.</p>
1284
         *
1285
         * @param viewPort the viewPort
1286
         *
1287
         * @see #getViewPort()
1288
         */
1289
        public void setViewPort(ViewPort viewPort) {
1290
                if (this.viewPort != null) {
1291
                        this.viewPort.removeViewPortListener(eventBuffer);
1292
                }
1293

    
1294
                if (this.mapContextDrawer != null){
1295
                        this.mapContextDrawer.setViewPort(viewPort);
1296
                }
1297

    
1298
                this.viewPort = viewPort;
1299
                if (viewPort != null)
1300
                        viewPort.addViewPortListener(eventBuffer);
1301
        }
1302

    
1303
        /**
1304
         * <p>Sets the given extent to the {@link ViewPort ViewPort} and updates the view with the new zoom.</p>
1305
         *
1306
         * @param extent the extent of the new zoom
1307
         */
1308
        public void zoomToExtent(Rectangle2D extent) {
1309
                if (extent!=null)
1310
                        getViewPort().setExtent(extent);
1311
        }
1312

    
1313
        /**
1314
         * <p>Returns the union of all extents of all layers of this map.</p>
1315
         *
1316
         * @return full extent of layers of this map
1317
         * @throws ReadDriverException if the driver fails reading.
1318
         *
1319
         * @see FLayers#getFullExtent()
1320
         */
1321
        public Rectangle2D getFullExtent() throws ReadDriverException {
1322
                return layers.getFullExtent();
1323
        }
1324

    
1325
        /**
1326
         * <p>Returns an XML entity with the name of this class as a property, and two children branches:<br>
1327
         * <ul>
1328
         * <li>XML entity of the internal {@link ViewPort ViewPort}.
1329
         * <li>XML entity of the internal {@link FLayers FLayers}.
1330
         * </ul>
1331
         *
1332
         * @return XMLEntity the XML entity
1333
         * @throws XMLException if there is any error creating the XML from the map.
1334
         *
1335
         * @see #createFromXML(XMLEntity)
1336
         * @see #createFromXML03(XMLEntity)
1337
         * @see ViewPort#getXMLEntity()
1338
         * @see FLayers#getXMLEntity()
1339
         */
1340
        public XMLEntity getXMLEntity() throws XMLException {
1341
                XMLEntity xml = new XMLEntity();
1342
                xml.putProperty("className", this.getClass().getName());
1343
                xml.addChild(viewPort.getXMLEntity());
1344
                xml.addChild(layers.getXMLEntity());
1345

    
1346
                return xml;
1347
        }
1348

    
1349
        /**
1350
         * <p>Creates a new <code>MapContext</code> instance from an XML entity, with
1351
         *  the data of the {@link ViewPort ViewPort} and
1352
         *  {@link FLayers FLayers}.</p>
1353
         *
1354
         * @param xml an XML entity
1355
         *
1356
         * @return the new <code>MapContext</code> instance
1357
         *
1358
         * @throws XMLException if there is any error creating the map from the XML.
1359
         *
1360
         * @see #getXMLEntity()
1361
         * @see #createFromXML(XMLEntity)
1362
         * @see ViewPort#createFromXML03(XMLEntity)
1363
         * @see FLayers#setXMLEntity03(XMLEntity)
1364
         */
1365
        public static MapContext createFromXML03(XMLEntity xml) throws XMLException {
1366
                ViewPort vp = ViewPort.createFromXML03(xml.getChild(0));
1367
                MapContext fmap = new MapContext(vp);
1368
                fmap.layers.setXMLEntity03(xml.getChild(1));
1369

    
1370
                return fmap;
1371
        }
1372

    
1373
        /**
1374
         * <p>Creates a new <code>MapContext</code> instance from an XML entity, with
1375
         *  with the data of the {@link ViewPort ViewPort} and
1376
         *  {@link FLayers FLayers}.</p>
1377
         *
1378
         * @param xml an XML entity
1379
         *
1380
         * @return the new <code>MapContext</code> instance
1381
         *
1382
         * @throws XMLException if there is any error creating the map from the XML.
1383
         *
1384
         * @see #getXMLEntity()
1385
         * @see #createFromXML03(XMLEntity)
1386
         * @see ViewPort#createFromXML(XMLEntity)
1387
         * @see FLayers#setXMLEntity(XMLEntity)
1388
         */
1389
        public static MapContext createFromXML(XMLEntity xml) throws XMLException {
1390
                ViewPort vp = ViewPort.createFromXML(xml.getChild(0));
1391
                MapContext fmap = new MapContext(vp);
1392
                fmap.layers.setXMLEntity(xml.getChild(1));
1393
                fmap.layers.setName("root layer");
1394
                return fmap;
1395
        }
1396

    
1397
        /**
1398
         * <p>Adds a listener of atomic events to the internal {@link EventBuffer EventBuffer}.</p>
1399
         *
1400
         * @param listener the new listener
1401
         *
1402
         * @return <code>true</code> if has added the listener successfully
1403
         *
1404
         * @see #removeAtomicEventListener(AtomicEventListener)
1405
         * @see EventBuffer#addAtomicEventListener(AtomicEventListener)
1406
         */
1407
        public boolean addAtomicEventListener(AtomicEventListener listener) {
1408
                return eventBuffer.addAtomicEventListener(listener);
1409
        }
1410

    
1411
        /**
1412
         * <p>Removes a listener of atomic events from the internal {@link EventBuffer EventBuffer}.</p>
1413
         *
1414
         * @param listener the listener to remove
1415
         *
1416
     * @return <tt>true</tt> if the list contained the specified element
1417
         *
1418
         * @see #addAtomicEventListener(AtomicEventListener)
1419
         * @see EventBuffer#removeAtomicEventListener(AtomicEventListener)
1420
         */
1421
        public boolean removeAtomicEventListener(AtomicEventListener listener) {
1422
                return eventBuffer.removeAtomicEventListener(listener);
1423
        }
1424

    
1425
        /**
1426
         * @see EventBuffer#beginAtomicEvent()
1427
         *
1428
         * @see #endAtomicEvent()
1429
         */
1430
        public void beginAtomicEvent() {
1431
                eventBuffer.beginAtomicEvent();
1432
        }
1433

    
1434
        /**
1435
         * @see EventBuffer#endAtomicEvent()
1436
         *
1437
         * @see #beginAtomicEvent()
1438
         */
1439
        public void endAtomicEvent() {
1440
                eventBuffer.endAtomicEvent();
1441
        }
1442

    
1443
        /**
1444
         * <p>The class <code>LayerEventListener</code> implements the methods of {@link LayerCollectionListener LayerCollectionListener}
1445
         *  that handles the "layer added" or "layer removed" events in a map.</p>
1446
         * <p>Is designed as a listener for all layers in a {@link MapContext MapContext}.</p>
1447
         *
1448
         * @author Fernando Gonz?lez Cort?s
1449
         */
1450
        public class LayerEventListener implements LayerCollectionListener {
1451
                /*
1452
                 * @see com.iver.cit.gvsig.fmap.layers.LayerCollectionListener#layerAdded(com.iver.cit.gvsig.fmap.layers.LayerCollectionEvent)
1453
                 */
1454
                public void layerAdded(LayerCollectionEvent e) {
1455
                        // Si es la primera capa, fijamos su extent al ViewPort
1456
                        // if (getLayers().getLayersCount() == 1) {
1457
                        if (getViewPort().getExtent() == null) {
1458
                                FLayer lyr = e.getAffectedLayer();
1459
                                if (lyr.isAvailable()) {
1460
                                        try {
1461
                                                getViewPort().setExtent(lyr.getFullExtent());
1462
                                        } catch (ReadDriverException e1) {
1463
                                                e1.printStackTrace();
1464
                                        }
1465
                                }
1466
                        }
1467

    
1468
                        // Registramos al FMap como listener del legend de las capas
1469
                        FLayer lyr = e.getAffectedLayer();
1470
                        selectionListener(lyr);
1471
                }
1472

    
1473
                /**
1474
                 * <p>Registers an event buffer as a listener for all layers as argument.</p>
1475
                 *
1476
                 * <p>Each {@link FLayer FLayer} of this map must have an event buffer for all kind
1477
                 * of specific listeners of that layer. This method distinguish between {@link Classifiable Classifiable},
1478
                 * {@link AlphanumericData AlphanumericData}, and {@link FLayers FLayers} layers, and for each one,
1479
                 * registers, for their specific listeners, the <code>eventBuffer</code> as a listener.</p>
1480
                 *
1481
                 * @param the layer or layers
1482
                 */
1483
                private void selectionListener(FLayer lyr){
1484
                        lyr.addLayerListener(eventBuffer);
1485

    
1486
                        if (lyr instanceof Classifiable) {
1487
                                Classifiable c = (Classifiable) lyr;
1488
                                c.addLegendListener(eventBuffer);
1489
                        }
1490

    
1491
                        if (lyr instanceof AlphanumericData) {
1492
                                Selectable s=null;
1493
                                try {
1494
                                        s = ((AlphanumericData) lyr).getRecordset();
1495
                                        if (s!=null) {
1496
                                                s.addSelectionListener(eventBuffer);
1497
                                        }
1498
                                } catch (ReadDriverException e1) {
1499
                                        e1.printStackTrace();
1500
                                }
1501

    
1502
                        }
1503
                        if (lyr instanceof FLayers){
1504
                                FLayers lyrs=(FLayers)lyr;
1505
                                for(int i=0;i<lyrs.getLayersCount();i++){
1506
                                        selectionListener(lyrs.getLayer(i));
1507
                                }
1508
                        }
1509

    
1510
                }
1511
                /*
1512
                 * @see com.iver.cit.gvsig.fmap.layers.LayerCollectionListener#layerMoved(com.iver.cit.gvsig.fmap.layers.LayerPositionEvent)
1513
                 */
1514
                public void layerMoved(LayerPositionEvent e) {
1515
                }
1516

    
1517
                /*
1518
                 * @see com.iver.cit.gvsig.fmap.layers.LayerCollectionListener#layerRemoved(com.iver.cit.gvsig.fmap.layers.LayerCollectionEvent)
1519
                 */
1520
                public void layerRemoved(LayerCollectionEvent e) {
1521
                        FLayer lyr = e.getAffectedLayer();
1522

    
1523
                        lyr.removeLayerListener(eventBuffer);
1524

    
1525
                        if (lyr instanceof Classifiable) {
1526
                                Classifiable c = (Classifiable) lyr;
1527
                                c.removeLegendListener(eventBuffer);
1528
                        }
1529

    
1530
                        if (lyr instanceof Selectable) {
1531
                                Selectable s = (Selectable) lyr;
1532
                                s.addSelectionListener(eventBuffer);
1533
                        }
1534
                }
1535

    
1536
                /*
1537
                 * @see com.iver.cit.gvsig.fmap.layers.LayerCollectionListener#layerAdding(com.iver.cit.gvsig.fmap.layers.LayerCollectionEvent)
1538
                 */
1539
                public void layerAdding(LayerCollectionEvent e)
1540
                                throws CancelationException {
1541
                }
1542

    
1543
                /*
1544
                 * @see com.iver.cit.gvsig.fmap.layers.LayerCollectionListener#layerMoving(com.iver.cit.gvsig.fmap.layers.LayerPositionEvent)
1545
                 */
1546
                public void layerMoving(LayerPositionEvent e)
1547
                                throws CancelationException {
1548
                }
1549

    
1550
                /*
1551
                 * @see com.iver.cit.gvsig.fmap.layers.LayerCollectionListener#layerRemoving(com.iver.cit.gvsig.fmap.layers.LayerCollectionEvent)
1552
                 */
1553
                public void layerRemoving(LayerCollectionEvent e)
1554
                                throws CancelationException {
1555
                }
1556

    
1557

    
1558
                /*
1559
                 * @see com.iver.cit.gvsig.fmap.layers.LayerCollectionListener#visibilityChanged(com.iver.cit.gvsig.fmap.layers.LayerCollectionEvent)
1560
                 */
1561
                public void visibilityChanged(LayerCollectionEvent e)
1562
                                throws CancelationException {
1563
                }
1564
        }
1565

    
1566
        /**
1567
         * <p>Adds the {@link LayerEventListener LayerEventListener} of this map to the
1568
         *  collection of layers argument.</p>
1569
         *
1570
         * @param a collection of layers
1571
         */
1572
        public void addAsCollectionListener(FLayers layers2) {
1573
                layers2.addLayerCollectionListener(layerEventListener);
1574
        }
1575

    
1576
        /**
1577
         * <p>Returns the internal {@link GraphicLayer GraphicLayer}.</p>
1578
         *
1579
         * @return the graphic layer of this map
1580
         *
1581
         * @see #setGraphicsLayer(GraphicLayer)
1582
         */
1583
        public GraphicLayer getGraphicsLayer() {
1584
                return tracLayer;
1585
        }
1586

    
1587
        /**
1588
         * <p>Sets a new {@link GraphicLayer GraphicLayer} to this map.</p>
1589
         *
1590
         * @param graphicLayer the new graphic layer
1591
         *
1592
         * @see #getGraphicsLayer()
1593
         */
1594
        public void setGraphicsLayer(GraphicLayer graphicLayer) {
1595
                tracLayer = graphicLayer;
1596
        }
1597

    
1598
        /**
1599
         * <p>Indicates whether some other object is "equal to" this map.</p>
1600
         * <p>Returns <code>true</code> if success one of this options:
1601
         * <ul>
1602
         * <li>Both objects are equal according to {@linkplain Object#equals(Object)}.
1603
         * <li>Both maps have the same layers.
1604
         * <li>Both maps have the same number of layers and with the same name.
1605
         * </ul>
1606
         * </p>
1607
         *
1608
         * @param obj the reference object with which to compare.
1609
     * @return <code>true</code> if this object is the same as the <code>arg0</code> argument;  otherwise <code>false</code>.
1610
         *
1611
         * @see Object#equals(Object)
1612
         */
1613
        public boolean equals(Object arg0) {
1614
                if (!(arg0 instanceof MapContext)){
1615
                        return false;
1616
                }
1617
                MapContext map = (MapContext) arg0;
1618
                if (super.equals(arg0))
1619
                        return true;
1620
                if (getLayers() == map.getLayers())
1621
                        return true;
1622
                boolean isEqual = true;
1623
                if (map.getLayers().getLayersCount() == getLayers().getLayersCount()) {
1624
                        for (int i = 0; i < getLayers().getLayersCount(); i++) {
1625

    
1626
                                if (!getLayers().getLayer(i).getName().equals(
1627
                                                map.getLayers().getLayer(i).getName())) {
1628
                                        isEqual = false;
1629
                                }
1630

    
1631
                        }
1632
                } else {
1633
                        isEqual = false;
1634
                }
1635
                return isEqual;
1636
        }
1637

    
1638
        /**
1639
         * <p>Registers the message of an error associated to this map.</p>
1640
         *
1641
         * @param stringProperty the error message
1642
         *
1643
         * @see #getLayersError()
1644
         * @see #clearErrors()
1645
         */
1646
        public void addLayerError(String stringProperty) {
1647
                layersError.add(stringProperty);
1648
        }
1649

    
1650
        /**
1651
         * <p>Gets the list with all error messages registered to this map.</p>
1652
         *
1653
         * @return the list of errors registered to this map
1654
         *
1655
         * @see #addLayerError(String)
1656
         * @see #clearErrors()
1657
         */
1658
        public ArrayList getLayersError() {
1659
                return layersError;
1660
        }
1661

    
1662
        /**
1663
         * <p>Removes all error messages associated to this map.</p>
1664
         *
1665
         * @see #addLayerError(String)
1666
         * @see #getLayersError()
1667
         */
1668
        public void clearErrors() {
1669
                layersError.clear();
1670
        }
1671

    
1672
        /**
1673
         * <p>Creates and returns a new group of layers that belongs to this <code>MapContext</code>.</p>
1674
         *
1675
         * @param parent layer node in this <code>MapContexte</code> that will be the parent of the new node
1676
         * @return the new layer node
1677
         */
1678
        public FLayers getNewGroupLayer(FLayers parent) {
1679
                FLayers group1 = new FLayers();//(this,parent);
1680
                group1.setMapContext(this);
1681
                group1.setParentLayer(parent);
1682
            return group1;
1683
        }
1684

    
1685

    
1686
        public long getDrawVersion() {
1687
                return this.drawVersion;
1688
        }
1689

    
1690
        protected void updateDrawVersion(){
1691
                this.drawVersion++;
1692
        }
1693

    
1694
        public MapContextDrawer getMapContextDrawer() throws ReadDriverException{
1695
                if (this.mapContextDrawer == null){
1696
                        try {
1697
                                this.mapContextDrawer = (MapContextDrawer) this.mapContextDrawerClass.getConstructor(null).newInstance(null);
1698
                                this.mapContextDrawer.setMapContext(this);
1699
                                this.mapContextDrawer.setViewPort(viewPort);
1700

    
1701
                        } catch (IllegalArgumentException e) {
1702
                                throw new ReadDriverException("Can't create MapContextDraver",e);
1703
                        } catch (SecurityException e) {
1704
                                throw new ReadDriverException("Can't create MapContextDraver",e);
1705
                        } catch (InstantiationException e) {
1706
                                throw new ReadDriverException("Can't create MapContextDraver",e);
1707
                        } catch (IllegalAccessException e) {
1708
                                throw new ReadDriverException("Can't create MapContextDraver",e);
1709
                        } catch (InvocationTargetException e) {
1710
                                throw new ReadDriverException("Can't create MapContextDraver",e);
1711
                        } catch (NoSuchMethodException e) {
1712
                                throw new ReadDriverException("Can't create MapContextDraver",e);
1713
                        }
1714
                }
1715

    
1716
                return this.mapContextDrawer;
1717
        }
1718

    
1719
        public boolean setMapContextDrawerClass(Class mapContextDrawerClass){
1720
                if (mapContextDrawerClass == null){
1721
                        mapContextDrawerClass = this.defaultMapContextDrawerClass;
1722
                }
1723
                if (! MapContextDrawer.class.isAssignableFrom(mapContextDrawerClass)){
1724
                        return false;
1725
                }
1726
                this.mapContextDrawerClass = mapContextDrawerClass;
1727
                if (this.mapContextDrawer != null){
1728
                        this.mapContextDrawer.dispose();
1729
                        this.mapContextDrawer = null;
1730
                }
1731
                return true;
1732

    
1733
        }
1734

    
1735
        public void setMapContextDrawer(MapContextDrawer drawer){
1736
                if (this.mapContextDrawer != null){
1737
                        this.mapContextDrawer.dispose();
1738
                        this.mapContextDrawer = null;
1739
                }
1740
                this.mapContextDrawer = drawer;
1741
                if (this.mapContextDrawer != null){
1742
                        this.mapContextDrawer.setMapContext(this);
1743
                        this.mapContextDrawer.setViewPort(viewPort);
1744
                }
1745
        }
1746

    
1747
        /**
1748
         * <p>Returns the OrderManager. When a new layer is added to this MapContext,
1749
         * the order manager will decide the right position for the
1750
         * layer.</p> <p>The orderManager will only be used when adding a layer,
1751
         * so it will not affect to the collection order when the user modifies the
1752
         * order.</p>
1753
         *
1754
         * @return The configured order manager, or DefaultOrderManager in no
1755
         * order manager was configured
1756
         */
1757
        public OrderManager getOrderManager() {
1758
                /**
1759
                 * Don't keep an order manager, always use a system-wide manager.
1760
                 *
1761
                 * In an idea scenario, we'd like to be able to configure an order
1762
                 * manager at different levels (system-wide, project-wide,
1763
                 * mapcontext-wide).
1764
                 *
1765
                 * However, gvSIG 1.9 does not provide the necessary infraestructure
1766
                 * to support this behaviour in a clean-way, so we don't offer this
1767
                 * behaviour at this time.
1768
                 */
1769
                return DefaultOrderManager.getDefaultOrderManager();
1770
        }
1771
}