Revision 38283

View differences:

tags/v2_0_0_Build_2047/libraries/libFMap_controls/src-test/org/gvsig/fmap/mapcontrol/tools/AreaListenerTest.java
1
package org.gvsig.fmap.mapcontrol.tools;
2

  
3
import java.awt.geom.Point2D;
4

  
5
import org.cresques.cts.IProjection;
6
import org.gvsig.fmap.crs.CRSFactory;
7
import org.gvsig.fmap.mapcontext.MapContext;
8
import org.gvsig.fmap.mapcontext.ViewPort;
9
import org.gvsig.fmap.mapcontrol.MapControl;
10
import org.gvsig.tools.junit.AbstractLibraryAutoInitTestCase;
11

  
12

  
13
public class AreaListenerTest extends AbstractLibraryAutoInitTestCase {
14
	private IProjection projectionUTM = CRSFactory.getCRS("EPSG:23030");
15
	private IProjection projectionGeo = CRSFactory.getCRS("EPSG:4230");
16
		
17
	@Override
18
	protected void doSetUp() throws Exception {
19
		// Nothing to do	
20
	}
21

  
22
	public void test1() {
23
		AreaListenerImpl areaListenerUTM=new AreaListenerImpl(newMapControlUTM());
24
		AreaListenerImpl areaListenerGeo=new AreaListenerImpl(newMapControlGeo());
25
		Double[] xsUTM=new Double[] {new Double(731292),new Double(731901),new Double(730138)};
26
		Double[] ysUTM=new Double[] {new Double(4351223),new Double(4350768),new Double(4349232)};
27
		double areaUTM=areaListenerUTM.returnCoordsArea(xsUTM,ysUTM,new Point2D.Double(730138,4349232));
28
		Double[] xsGeo=new Double[] {new Double(-0.31888183),new Double(-0.31173131),new Double(-0.33268401)};
29
		Double[] ysGeo=new Double[] {new Double(39.27871741),new Double(39.27464327),new Double(39.26117368)};
30
		double areaGeo=areaListenerGeo.returnGeoCArea(xsGeo,ysGeo,new Point2D.Double(-0.33268401,39.26117368));
31
		assertTrue("Area UTM igual a Geo",areaUTM<(areaGeo+1000)&& areaUTM>(areaGeo-1000));
32
	}
33
	private MapControl newMapControlUTM() {
34
		ViewPort vp = new ViewPort(projectionUTM);
35
		MapControl mc=new MapControl();
36
		mc.setMapContext(new MapContext(vp));
37
		return mc;
38
	}
39
	private MapControl newMapControlGeo() {
40
		ViewPort vp = new ViewPort(projectionGeo);
41
		MapControl mc=new MapControl();
42
		mc.setMapContext(new MapContext(vp));
43
		return mc;
44
	}
45
}
tags/v2_0_0_Build_2047/libraries/libFMap_controls/src/org/gvsig/fmap/mapcontrol/MapControl.java
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 org.gvsig.fmap.mapcontrol;
42

  
43
import java.awt.Color;
44
import java.awt.Cursor;
45
import java.awt.Dimension;
46
import java.awt.Graphics;
47
import java.awt.Graphics2D;
48
import java.awt.Image;
49
import java.awt.Point;
50
import java.awt.Toolkit;
51
import java.awt.event.ActionEvent;
52
import java.awt.event.ActionListener;
53
import java.awt.event.ComponentEvent;
54
import java.awt.event.ComponentListener;
55
import java.awt.event.MouseEvent;
56
import java.awt.event.MouseListener;
57
import java.awt.event.MouseMotionListener;
58
import java.awt.event.MouseWheelEvent;
59
import java.awt.event.MouseWheelListener;
60
import java.awt.geom.Point2D;
61
import java.awt.image.BufferedImage;
62
import java.awt.image.MemoryImageSource;
63
import java.util.ArrayList;
64
import java.util.Comparator;
65
import java.util.HashMap;
66
import java.util.List;
67
import java.util.Set;
68
import java.util.TreeMap;
69
import java.util.prefs.Preferences;
70

  
71
import javax.swing.JComponent;
72
import javax.swing.SwingUtilities;
73
import javax.swing.Timer;
74

  
75
import org.cresques.cts.IProjection;
76
import org.slf4j.Logger;
77
import org.slf4j.LoggerFactory;
78

  
79
import org.gvsig.fmap.crs.CRSFactory;
80
import org.gvsig.fmap.dal.DataStoreNotification;
81
import org.gvsig.fmap.dal.feature.FeatureStoreNotification;
82
import org.gvsig.fmap.geom.Geometry;
83
import org.gvsig.fmap.geom.Geometry.SUBTYPES;
84
import org.gvsig.fmap.geom.GeometryLocator;
85
import org.gvsig.fmap.geom.GeometryManager;
86
import org.gvsig.fmap.geom.exception.CreateEnvelopeException;
87
import org.gvsig.fmap.geom.primitive.Envelope;
88
import org.gvsig.fmap.geom.util.Converter;
89
import org.gvsig.fmap.mapcontext.MapContext;
90
import org.gvsig.fmap.mapcontext.ViewPort;
91
import org.gvsig.fmap.mapcontext.events.AtomicEvent;
92
import org.gvsig.fmap.mapcontext.events.listeners.AtomicEventListener;
93
import org.gvsig.fmap.mapcontext.layers.FLayers;
94
import org.gvsig.fmap.mapcontext.layers.LayerCollectionEvent;
95
import org.gvsig.fmap.mapcontext.layers.LayerEvent;
96
import org.gvsig.fmap.mapcontext.layers.SpatialCache;
97
import org.gvsig.fmap.mapcontext.layers.vectorial.FLyrVect;
98
import org.gvsig.fmap.mapcontext.layers.vectorial.GraphicLayer;
99
import org.gvsig.fmap.mapcontrol.tools.BehaviorException;
100
import org.gvsig.fmap.mapcontrol.tools.CompoundBehavior;
101
import org.gvsig.fmap.mapcontrol.tools.Behavior.Behavior;
102
import org.gvsig.fmap.mapcontrol.tools.Listeners.ToolListener;
103
import org.gvsig.fmap.mapcontrol.tools.grid.Grid;
104
import org.gvsig.fmap.mapcontrol.tools.snapping.snappers.ISnapper;
105
import org.gvsig.fmap.mapcontrol.tools.snapping.snappers.ISnapperGeometriesVectorial;
106
import org.gvsig.fmap.mapcontrol.tools.snapping.snappers.ISnapperRaster;
107
import org.gvsig.fmap.mapcontrol.tools.snapping.snappers.ISnapperVectorial;
108
import org.gvsig.tools.observer.Observable;
109
import org.gvsig.tools.observer.Observer;
110
import org.gvsig.tools.task.Cancellable;
111
import org.gvsig.utils.exceptionHandling.ExceptionHandlingSupport;
112
import org.gvsig.utils.exceptionHandling.ExceptionListener;
113

  
114
/**
115
 * <p>
116
 * A component that includes a {@link MapContext MapContext} with support for
117
 * use it as a particular {@link Behavior Behavior}.
118
 * </p>
119
 * 
120
 * <p>
121
 * A developer can register a set of <code>Behavior</code>, but only one (that
122
 * can be a composition of several) of them can be active. The active one
123
 * defines the way to work and access with its <code>MapContext</code>'s layers.
124
 * The active behavior, in combination with the appropriate {@link ToolListener
125
 * ToolListener} will allow user work with a particular <i>tool</i>.
126
 * </p>
127
 * 
128
 * <p>
129
 * All mouse events produced on this component will be delegated to the current
130
 * active behavior, the <i>currentMapTool</i>.
131
 * </p>
132
 * 
133
 * <p>
134
 * <b>Drawing process:</b>
135
 * </p>
136
 * 
137
 * <p>
138
 * Uses a double buffer for the drawing process of <code>MapContext</code>'s
139
 * information.
140
 * </p>
141
 * 
142
 * <p>
143
 * If the double buffer wasn't created, creates a new one.
144
 * </p>
145
 * 
146
 * <p>
147
 * Paints the component according the following algorithm: <br>
148
 * &nbsp If <i>status</i> is <i>UPDATED</i>:<br>
149
 * &nbsp &nbsp If there is a <i>double buffer</i>:<br>
150
 * &nbsp &nbsp &nbsp If there is a <i>behavior</i> for managing the
151
 * <code>MapControl</code> instance, delegates the drawing process to that
152
 * behavior, calling: <code><i>behavior_instance</i>.paintComponent(g)</code>.<br>
153
 * &nbsp &nbsp &nbsp Else, repaints the current graphical information quickly
154
 * calling: <code>g.drawImage(image,0,0,null)</code>.<br>
155
 * &nbsp Else, (<i>status</i> is <i>OUTDATED</i>, or <i>ONLY_GRAPHICS</i>):
156
 * executes a quickly repaint of the previous information calling
157
 * <code>g.drawImage(image,0,0,null)</code>, and creates a <i>painting
158
 * request</i> to delegate the heavy drawing process to the {@link Drawer2
159
 * Drawer2}'s worker thread, according the <i>SingleWorketThread</i> pattern,
160
 * starting a timer to update (invoking <code>repaint()</code>) the view every
161
 * delay of <code>1000 / drawFrameRate</code> ms. during that heavy drawing
162
 * process, and if its enabled <code>drawAnimationEnabled</code>. The
163
 * <i>painting request</i> once is being attended, invokes
164
 * <code>MapContext</code> to draw the layers:
165
 * <code>mapContext.draw(image, g, cancel,mapContext.getScaleView());</code>
166
 * <br>
167
 * <p>
168
 * Some notes:
169
 * <ul>
170
 * <li>The painting process can be cancelled calling {@link #cancelDrawing()
171
 * #cancelDrawing()}.</li>
172
 * <li>At last resort, the particular implementation of each layer in a
173
 * <code>MapControl</code>'s <code>MapContrext</code> will be that one which
174
 * will draw the graphical information, and, if supports, which could cancel its
175
 * drawing subprocess.</li>
176
 * <li>It's possible to force repaint all layers, calling
177
 * {@link #drawMap(boolean doClear) #drawMap(boolean)}.</li>
178
 * <li>It's possible repaint only the dirty layers, calling
179
 * {@link #rePaintDirtyLayers() #rePaintDirtyLayers()}.</li>
180
 * <li>It's possible repaint only the {@link GraphicLayer GraphicLayer}, calling
181
 * {@link #drawGraphics() #drawGraphics()}.</li>
182
 * </ul>
183
 * </p>
184
 * 
185
 * <p>
186
 * <b>Tools:</b>
187
 * </p>
188
 * 
189
 * <p>
190
 * A developer can:
191
 * <ul>
192
 * <li>Register each tool as:
193
 * <ul>
194
 * <li>A single behavior: {@link #addBehavior(String, Behavior)
195
 * #addMapTool(String, Behavior)}.</li>
196
 * <li>Or, a compound behavior: {@link #addBehavior(String, Behavior)
197
 * #addMapTool(String, Behavior)}.</li>
198
 * </ul>
199
 * </li>
200
 * <li>Get the current active tool: {@link #getCurrentMapTool()
201
 * #getCurrentMapTool()}.</li>
202
 * <li>Get the current active tool name: {@link #getCurrentTool()
203
 * #getCurrentTool()}.</li>
204
 * <li>Get a registered tool: {@link #getMapTool(String) #getMapTool(String)}.</li>
205
 * <li>Get the name of all tools registered: {@link #getMapToolsKeySet()
206
 * #getMapToolsKeySet()}.</li>
207
 * <li>Get all tools registered, including the name they were registered:
208
 * {@link #getNamesMapTools() #getNamesMapTools()}.</li>
209
 * <li>Determine if has a tool registered: {@link #hasTool(String)
210
 * #hasTool(String)}.</li>
211
 * <li>Set as an active tool, one of the registered: {@link #setTool(String)
212
 * #setTool(String)}.</li>
213
 * <li>Set as active tool, the previous used: {@link #setPrevTool()
214
 * #setPrevTool()}.</li>
215
 * <li>Set the current tool: {@link #setCurrentMapTool(Behavior)
216
 * #setCurrentMapTool(Behavior)}.</li>
217
 * <li>Change the draw frame rate: {@link #setDrawFrameRate(int)
218
 * #setDrawFrameRate(int)} and {@link #applyFrameRate() #applyFrameRate()}.</li>
219
 * <li>Get the draw frame rate: {@link #getDrawFrameRate() #getDrawFrameRate()}.
220
 * </li>
221
 * <li>Determine if will repaint this component each time timer finishes:
222
 * {@link #isDrawAnimationEnabled() #isDrawAnimationEnabled()}.</li>
223
 * <li>Change if will repaint this component each time timer finishes:
224
 * {@link #setDrawAnimationEnabled(boolean) #setDrawAnimationEnabled(boolean)}.</li>
225
 * <li>Get the shared object that determines if a drawing process must be
226
 * cancelled or can continue: {@link #getCanceldraw() #getCanceldraw()}.</li>
227
 * <li>Get the combined tool: {@link #getCombinedTool() #getCombinedTool()}.</li>
228
 * <li>Set a combined tool: {@link #setCombinedTool(Behavior)
229
 * #setCombinedTool(Behavior)}.</li>
230
 * <li>Remove the combined tool: {@link #removeCombinedTool()
231
 * #removeCombinedTool()}.</li>
232
 * </ul>
233
 * </p>
234
 * 
235
 * <p>
236
 * <b>Exception listener:</b>
237
 * </p>
238
 * 
239
 * <p>
240
 * Adding an <code>ExceptionListener</code>, can get notification about any
241
 * exception produced:
242
 * <ul>
243
 * <li>Attending a <i>painting request</i>.</li>
244
 * <li>Working with the active tool.</li>
245
 * <li>Applying a <i>zoom in</i> or <i>zoom out</i> operation.</li>
246
 * </ul>
247
 * </p>
248
 * 
249
 * <p>
250
 * <b>Other:</b>
251
 * </p>
252
 * 
253
 * <p>
254
 * Other useful capabilities of <code>MapControl</code>:
255
 * <ul>
256
 * <li>Cancel the current drawing process (notifying it also to the inner
257
 * <code>MapContext</code> instance and its layers): {@link #cancelDrawing()
258
 * #cancelDrawing()}.</li>
259
 * <li>Applying a <i>zoom in</i> operation centered at mouse position (without a
260
 * <code>ToolListener</code>): {@link #zoomIn() #zoomIn()}.</li>
261
 * <li>Applying a <i>zoom out</i> operation centered at mouse position (without
262
 * a <code>ToolListener</code>): {@link #zoomOut() #zoomOut()}.</li>
263
 * </ul>
264
 * </p>
265
 * 
266
 * @see CancelDraw
267
 * @see Drawer
268
 * @see MapContextListener
269
 * @see MapToolListener
270
 * 
271
 * @author Fernando Gonz?lez Cort?s
272
 * @author Pablo Piqueras Bartolom? (pablo.piqueras@iver.es)
273
 */
274
public class MapControl extends JComponent implements ComponentListener,
275
    Observer {
276

  
277
    protected static final GeometryManager geomManager =
278
        GeometryLocator.getGeometryManager();
279
    protected static final Logger logger =
280
        LoggerFactory.getLogger(GeometryManager.class);
281

  
282
    /**
283
     * <p>
284
     * One of the possible status of <code>MapControl</code>. Determines that
285
     * all visible information has been drawn and its updated.
286
     * </p>
287
     */
288
    public static final int ACTUALIZADO = 0;
289

  
290
    /**
291
     * <p>
292
     * One of the possible status of <code>MapControl</code>. Determines that
293
     * not all visible information has been drawn or isn't updated.
294
     * </p>
295
     */
296
    public static final int DESACTUALIZADO = 1;
297

  
298
    /**
299
     * <p>
300
     * Determines if the drawer can update this <code>MapControl</code> instance
301
     * when the timer launches an event.
302
     * </p>
303
     */
304
    private static boolean drawAnimationEnabled = true;
305

  
306
    /**
307
     * <p>
308
     * Inner model with the layers, event support for drawing them, and the
309
     * <code>ViewPort</code> with information to adapt to the bounds available
310
     * in <i>image coordinates</i>.
311
     * </p>
312
     * 
313
     * @see #getMapContext()
314
     * @see #setMapContext(MapContext)
315
     */
316
    private MapContext mapContext = null;
317

  
318
    /**
319
     * <p>
320
     * All registered <code>Behavior</code> that can define a way to work with
321
     * this <code>MapControl</code>.
322
     * </p>
323
     * 
324
     * <p>
325
     * Only one of them can be active at a given moment.
326
     * </p>
327
     * 
328
     * @see #addBehavior(String, Behavior)
329
     * @see #addBehavior(String, Behavior[])
330
     * @see #getMapTool(String)
331
     * @see #getMapToolsKeySet()
332
     * @see #getNamesMapTools()
333
     */
334
    protected HashMap namesMapTools = new HashMap();
335

  
336
    /**
337
     * <p>
338
     * Active {@link Behavior Behavior} that will generate events according a
339
     * criterion, and then, with a {@link ToolListener ToolListener} associated,
340
     * will simulate to user that works with this component as a particular
341
     * tool.
342
     * </p>
343
     * 
344
     * @see #getCurrentMapTool()
345
     * @see #getCurrentTool()
346
     * @see #setTool(String)
347
     */
348
    protected Behavior currentMapTool = null;
349

  
350
    /**
351
     * <p>
352
     * Determines which's the current drawn status of this component:
353
     * <ul>
354
     * <li><b>OUTDATED</b>: all visible information has been drawn or isn't
355
     * updated.</li>
356
     * <li><b>UTDATED</b>: all visible information has been drawn and its
357
     * updated.</li>
358
     * <li><b>ONLY_GRAPHICS</b>: only the graphical layer must be drawn /
359
     * updated.</li>
360
     * </ul>
361
     * </p>
362
     * 
363
     * <p>
364
     * The <code>MapControl</code> drawing process will consider the value of
365
     * this parameter to decide which elements will be updated or drawn.
366
     * </p>
367
     */
368
    private int status = DESACTUALIZADO;
369

  
370
    /**
371
     * <p>
372
     * Image with a buffer to accelerate the draw the changes of the graphical
373
     * items in this component.
374
     * </p>
375
     * 
376
     * <p>
377
     * Firstly, information will be drawn in the buffer, and, when is outright
378
     * drawn, that information will be displayed. Meanwhile, the previous image
379
     * can be kept showed.
380
     * </p>
381
     * 
382
     * @see BufferedImage
383
     * 
384
     * @see #getImage()
385
     */
386
    private BufferedImage image = null;
387

  
388
    /**
389
     * <p>
390
     * Name of the tool used currently to interact with this component.
391
     * </p>
392
     * 
393
     * @see #getCurrentTool()
394
     * @see #setTool(String)
395
     */
396
    protected String currentTool;
397

  
398
    /**
399
     * <p>
400
     * Object to store the flag that notifies a drawing thread task and
401
     * <code>MapContext</code>'s layers, that must be canceled or can continue
402
     * with the process.
403
     * </p>
404
     * 
405
     * @see #cancelDrawing()
406
     */
407
    private CancelDraw canceldraw;
408

  
409
    // private boolean isCancelled = true;
410

  
411
    /**
412
     * <p>
413
     * Fires an action events after a specified delay.
414
     * </p>
415
     * 
416
     * <p>
417
     * <code>MapControl</code> will use the timer to update its visible
418
     * graphical information during a drawing process, or allowing to cancel
419
     * that process.
420
     * </p>
421
     * 
422
     * <p>
423
     * This is very useful to pretend faster interactivity to user when
424
     * <code>MapControl</code> has lots of layers, and / or layers with heavy
425
     * graphical elements, that need a long time to finish drawing all its data.
426
     * </p>
427
     */
428
    private Timer timer;
429

  
430
    /**
431
     * <p>
432
     * Reference to the {@link ViewPort ViewPort} of the {@link MapContext
433
     * MapContext} of this component.
434
     * </p>
435
     * 
436
     * <p>
437
     * The view port once is created an instance of <code>MapControl</code>, is
438
     * obtained from the <i>EPSG:23030</i> projection, that's the default
439
     * projection for this component.
440
     * </p>
441
     * 
442
     * <p>
443
     * After, the view port will change adapting itself according the current
444
     * projection and the extent.
445
     * </p>
446
     * 
447
     * @see #getViewPort()
448
     * 
449
     * @see ViewPort
450
     */
451
    protected ViewPort vp;
452

  
453
    /**
454
     * <p>
455
     * Manager of all <code>MapControl</code> painting requests.
456
     * </p>
457
     */
458
    private Drawer drawer;
459

  
460
    /**
461
     * <p>
462
     * Listener of all kind of mouse events produced in this component.
463
     * </p>
464
     * 
465
     * <p>
466
     * Delegates each mouse event to the current map tool.
467
     * </p>
468
     * 
469
     * @see #addBehavior(String, Behavior)
470
     * @see #addBehavior(String, Behavior[])
471
     * @see #getMapTool(String)
472
     * @see #getMapToolsKeySet()
473
     * @see #getNamesMapTools()
474
     * @see #setTool(String)
475
     */
476
    protected MapToolListener mapToolListener = new MapToolListener();
477

  
478
    /**
479
     * <p>
480
     * Listener of all events produced in a this component's
481
     * <code>MapContext</code> object during an atomic period of time.
482
     * </p>
483
     */
484
    private MapContextListener mapContextListener = new MapContextListener();
485

  
486
    /**
487
     * <p>
488
     * Group of <code>ExceptionListener</code> that, in whatever moment could be
489
     * notified a Throwable Java error or exception.
490
     * </p>
491
     * 
492
     * @see #addExceptionListener(ExceptionListener)
493
     * @see #removeExceptionListener(ExceptionListener)
494
     */
495
    private ExceptionHandlingSupport exceptionHandlingSupport =
496
        new ExceptionHandlingSupport();
497

  
498
    /**
499
     * <p>
500
     * Name of the previous tool used.
501
     * </p>
502
     */
503
    protected String prevTool;
504

  
505
    /**
506
     * <p>
507
     * Tool that will be used combined with the current tool of this
508
     * <code>MapControl</code>.
509
     * </p>
510
     */
511
    private Behavior combinedTool = null;
512

  
513
    /**
514
     * Optional grid that could be applied on the <code>MapControl</code>'s view
515
     * port.
516
     * 
517
     * @see #getGrid()
518
     * @see #setAdjustGrid(boolean)
519
     */
520
    private Grid cadgrid = new Grid();
521
    /**
522
     * Represents the cursor's point selected in <i>screen coordinates</i>.
523
     * 
524
     * @see ViewPort#fromMapPoint(Point2D)
525
     */
526
    private Point2D adjustedPoint;
527
    /**
528
     * <p>
529
     * Determines if the position of the snap of the mouse's cursor on the
530
     * <code>MapControl</code> is within the area around a control point of a
531
     * geometry.
532
     * </p>
533
     * 
534
     * <p>
535
     * The area is calculated as a circle centered at the control point and with
536
     * radius the pixels tolerance defined in the preferences.
537
     * </p>
538
     */
539
    private boolean bForceCoord = false;
540

  
541
    /**
542
     * Kind of geometry drawn to identify the kind of control point selected by
543
     * the cursor's mouse.
544
     */
545
    private ISnapper usedSnap = null;
546

  
547
    /**
548
     * Determines if the snap tools are enabled or disabled.
549
     * 
550
     * @see #isRefentEnabled()
551
     * @see #setRefentEnabled(boolean)
552
     */
553
    private boolean bRefent = true;
554

  
555
    /**
556
     * Stores the 2D map coordinates of the last point added.
557
     */
558
    private double[] previousPoint = null;
559

  
560
    protected static MapControlManager mapControlManager =
561
        MapControlLocator.getMapControlManager();
562

  
563
    private static TreeMap selected = new TreeMap(new Comparator() {
564

  
565
        public int compare(Object o1, Object o2) {
566
            if (o1.getClass().equals(o2.getClass()))
567
                return 0;
568
            if (((ISnapper) o1).getPriority() > ((ISnapper) o2).getPriority())
569
                return 1;
570
            else
571
                return -1;
572
        }
573

  
574
    });
575

  
576
    /**
577
     * Represents the cursor's point selected in <i>map coordinates</i>.
578
     * 
579
     * @see MapControl#toMapPoint
580
     */
581
    private Point2D mapAdjustedPoint;
582

  
583
    /**
584
     * Renderer used to draw the layers.
585
     */
586
    private MapControlDrawer mapControlDrawer = null;
587
	private Cursor transparentCursor;
588

  
589
    /**
590
     * <p>
591
     * Creates a new <code>MapControl</code> instance with the following
592
     * characteristics:
593
     * <ul>
594
     * <li><i>Name</i>: MapControl .</li>
595
     * <li>Disables the double buffer of <code>JComponent</code> .</li>
596
     * <li>Sets opaque <i>(see {@link JComponent#setOpaque(boolean)} )</i>.</li>
597
     * <li>Sets its status to <code>OUTDATED</code> .</li>
598
     * <li>Creates a new {@link CancelDraw CancelDraw} object to notify
599
     * <code>MapContext</code>'s layers if can continue processing the drawn or
600
     * must cancel it.</li>
601
     * <li>Creates a new {@link MapContext MapContext} with a new
602
     * {@link ViewPort ViewPort} in the projection <i>"EPSG:23030"</i> .</li>
603
     * <li>Creates a new {@link CommandListener CommandListener} for edition
604
     * operations.</li>
605
     * <li>Creates a new {@link MapToolListener MapToolListener}, and associates
606
     * it as a listener of whatever kind of mouse events produced in this
607
     * component.</li>
608
     * <li>Creates a new {@link Drawer2 Drawer2} for managing the painting
609
     * requests.</li>
610
     * <li>Creates a new timer that will invoke refresh this component
611
     * <code>drawFrameRate</code> per second, when is running a drawing process,
612
     * and its enabled <code>drawAnimationEnabled</code>.</li>
613
     * </ul>
614
     * </p>
615
     */
616
    public MapControl() {
617
        this.setName("MapControl");
618
        Toolkit toolkit = Toolkit.getDefaultToolkit();
619
        Image imageTransparentCursor = toolkit.createImage(new MemoryImageSource(16, 16, new int[16 * 16], 0,16));
620
        transparentCursor =
621
            toolkit.createCustomCursor(imageTransparentCursor, new Point(0, 0), "invisiblecursor");
622

  
623
        setDoubleBuffered(false);
624
        setOpaque(true);
625
        status = DESACTUALIZADO;
626

  
627
        // Clase usada para cancelar el dibujado
628
        canceldraw = new CancelDraw();
629

  
630
        // Modelo de datos y ventana del mismo
631
        // TODO: Cuando creamos un mapControl, deber?amos asignar
632
        // la projecci?n por defecto con la que vayamos a trabajar.
633
        // 23030 es el c?digo EPSG del UTM30 elipsoide ED50
634
        vp = new ViewPort(CRSFactory.getCRS("EPSG:23030"));
635
        setMapContext(new MapContext(vp));
636

  
637
        // eventos
638
        this.addComponentListener(this);
639
        this.addMouseListener(mapToolListener);
640
        this.addMouseMotionListener(mapToolListener);
641
        this.addMouseWheelListener(mapToolListener);
642

  
643
        this.drawer = new Drawer();
644
        // Timer para mostrar el redibujado mientras se dibuja
645
        timer =
646
            new Timer(1000 / MapContext.getDrawFrameRate(),
647
                new ActionListener() {
648

  
649
                    public void actionPerformed(ActionEvent e) {
650

  
651
                        if (drawAnimationEnabled) {
652
                            MapControl.this.repaint();
653
                        }
654
                    }
655
                });
656
        initializeGrid();
657
    }
658

  
659
    /**
660
     * <p>
661
     * Sets a <code>MapContext</code> to this component.
662
     * </p>
663
     * 
664
     * <p>
665
     * The <code>MapContext</code> has the <i>model</i>, and most of the
666
     * <i>view</i>, and <i>control</i> logic of the layers of this component,
667
     * including a {@link ViewPort ViewPort} to adapt the information to the
668
     * projection, and to display it in the available area.
669
     * </p>
670
     * 
671
     * <p>
672
     * If <code>model</code> hadn't a <code>ViewPort</code>, assigns the current
673
     * one to it, otherwise, use its <code>ViewPort</code>.
674
     * </p>
675
     * 
676
     * <p>
677
     * After assigning the <code>MapContext</code> and <code>ViewPort</code>,
678
     * sets the same {@link MapContextListener MapContextListener} that was
679
     * using, and changes the <i>status</i> to <code>OUTDATED</code>.
680
     * </p>
681
     * 
682
     * @param model
683
     *            this component's <code>MapContext</code>, that includes the
684
     *            <code>ViewPort</code>.
685
     * 
686
     * @see MapContext
687
     * 
688
     * @see #getMapContext()
689
     */
690
    public void setMapContext(MapContext model) {
691
        if (mapContext != null) {
692
            mapContext.removeAtomicEventListener(mapContextListener);
693
            mapContext.dispose();
694
        }
695

  
696
        mapContext = model;
697

  
698
        if (mapContext.getViewPort() == null) {
699
            mapContext.setViewPort(vp);
700
        } else {
701
            vp = mapContext.getViewPort();
702
            cadgrid.setViewPort(vp);
703
        }
704

  
705
        mapContext.addAtomicEventListener(mapContextListener);
706

  
707
        status = DESACTUALIZADO;
708
    }
709

  
710
    /**
711
     * @return the mapControlDrawer
712
     */
713
    public MapControlDrawer getMapControlDrawer() {
714
        return mapControlDrawer;
715
    }
716

  
717
    /**
718
     * @param mapControlDrawer
719
     *            the mapControlDrawer to set
720
     */
721
    public void setMapControlDrawer(MapControlDrawer mapControlDrawer) {
722
        this.mapControlDrawer = mapControlDrawer;
723
        this.mapControlDrawer.setViewPort(vp);
724
    }
725

  
726
    /**
727
     * <p>
728
     * Gets this component's {@link MapContext MapContext} projection.
729
     * </p>
730
     * 
731
     * @return this component's {@link MapContext MapContext} projection
732
     * 
733
     * @see MapContext#getProjection()
734
     * @see MapControl#setProjection(IProjection)
735
     */
736
    public IProjection getProjection() {
737
        return getMapContext().getProjection();
738
    }
739

  
740
    /**
741
     * <p>
742
     * Sets the projection to this component's {@link MapContext MapContext}.
743
     * </p>
744
     * 
745
     * @param proj
746
     *            the kind of projection to this component's {@link MapContext
747
     *            MapContext}
748
     * 
749
     * @see MapContext#setProjection(IProjection)
750
     * @see MapControl#getProjection()
751
     */
752
    public void setProjection(IProjection proj) {
753
        getMapContext().setProjection(proj);
754
    }
755

  
756
    /**
757
     * <p>
758
     * Gets this component's <code>MapContext</code>, with the <i>model</i>, and
759
     * most of the <i>view</i>, and <i>control</i> logic of the layers of this
760
     * component, including a {@link ViewPort ViewPort} to adapt the information
761
     * to the projection, and display it in the available area.
762
     * </p>
763
     * 
764
     * @return this component's <code>MapContext</code>, that includes the
765
     *         <code>ViewPort</code> used to project the
766
     *         graphical information, and display it in the available area
767
     * 
768
     * @see MapContext
769
     * 
770
     * @see MapControl#setMapContext(MapContext)
771
     */
772
    public MapContext getMapContext() {
773
        return mapContext;
774
    }
775

  
776
    /**
777
     * <p>
778
     * Registers a new behavior to this component.
779
     * </p>
780
     * 
781
     * <p>
782
     * According the nature of the {@link Behavior Behavior}, different events
783
     * will be generated. Those events can be caught by a particular
784
     * {@link ToolListener ToolListener}, allowing user to interact with this
785
     * <code>MapControl</code> object as a <i>tool</i>.
786
     * </p>
787
     * 
788
     * @param name
789
     *            name to identify the behavior to add
790
     * @param tool
791
     *            the behavior to add
792
     * 
793
     * @see #addBehavior(String, Behavior[])
794
     * @see #getNamesMapTools()
795
     * @see #getMapToolsKeySet()
796
     * @see #hasTool(String)
797
     */
798
    public void addBehavior(String name, Behavior tool) {
799
        namesMapTools.put(name, tool);
800
        tool.setMapControl(this);
801
    }
802

  
803
    /**
804
     * <p>
805
     * Registers a new behavior to this component as a {@link CompoundBehavior
806
     * CompoundBehavior} made up of <code>tools</code>.
807
     * </p>
808
     * 
809
     * <p>
810
     * According the nature of the behaviors registered, different events will
811
     * be generated. Those events can be caught by a particular
812
     * {@link ToolListener ToolListener}, allowing user to interact with this
813
     * <code>MapControl</code> object as a <i>tool</i>.
814
     * </p>
815
     * 
816
     * @param name
817
     *            name to identify the compound behavior to add
818
     * @param tools
819
     *            the compound behavior to add
820
     * 
821
     * @see #addBehavior(String, Behavior)
822
     * @see #getNamesMapTools()
823
     * @see #getMapToolsKeySet()
824
     * @see #hasTool(String)
825
     */
826
    public void addBehavior(String name, Behavior[] tools) {
827
        CompoundBehavior tool = new CompoundBehavior(tools);
828
        addBehavior(name, tool);
829
    }
830

  
831
    /**
832
     * <p>
833
     * Gets the <code>Behavior</code> registered in this component, identified
834
     * by <code>name</code>.
835
     * </p>
836
     * 
837
     * @param name
838
     *            name of a registered behavior
839
     * 
840
     * @return tool the registered behavior in this component as
841
     *         <code>name</code>, or <code>null</code> if
842
     *         no one has that identifier
843
     * 
844
     * @see #addBehavior(String, Behavior)
845
     * @see #addBehavior(String, Behavior[])
846
     * @see #hasTool(String)
847
     */
848
    public Behavior getMapTool(String name) {
849
        return (Behavior) namesMapTools.get(name);
850
    }
851

  
852
    /**
853
     * <p>
854
     * Returns a set view of the keys that identified the tools registered.
855
     * </p>
856
     * 
857
     * @return a set view of the keys that identified the tools registered
858
     * 
859
     * @see HashMap#keySet()
860
     * 
861
     * @see #getNamesMapTools()
862
     * @see #addBehavior(String, Behavior)
863
     * @see #addBehavior(String, Behavior[])
864
     */
865
    public Set getMapToolsKeySet() {
866
        return namesMapTools.keySet();
867
    }
868

  
869
    /**
870
     * <p>
871
     * Returns <code>true</code> if this component contains a tool identified by
872
     * <code>toolName</code>.
873
     * </p>
874
     * 
875
     * @param toolName
876
     *            identifier of the tool
877
     * 
878
     * @return <code>true</code> if this component contains a tool identified by
879
     *         <code>toolName</code>; otherwise <code>false</code>
880
     * 
881
     * @see #addBehavior(String, Behavior)
882
     * @see #addBehavior(String, Behavior[])
883
     */
884
    public boolean hasTool(String toolName) {
885
        return namesMapTools.containsKey(toolName);
886
    }
887

  
888
    /**
889
     * <p>
890
     * Sets as current active <code>Behavior</code> associated to this
891
     * component, that one which is registered and identified by
892
     * <code>toolName</code>.
893
     * </p>
894
     * 
895
     * <p>
896
     * Changing the current active behavior for this <code>MapControl</code>,
897
     * implies also updating the previous <i>behavior</i> tool, and the current
898
     * cursor.
899
     * </p>
900
     * 
901
     * @param toolName
902
     *            name of a registered behavior
903
     * 
904
     * @see #getCurrentMapTool()
905
     * @see #getCurrentTool()
906
     */
907
    public void setTool(String toolName) {
908
        prevTool = getCurrentTool();
909
        Behavior mapTool = (Behavior) namesMapTools.get(toolName);
910
        currentMapTool = mapTool;
911
        currentTool = toolName;
912

  
913
        if (combinedTool != null) {
914
            if (mapTool instanceof CompoundBehavior) {
915
                ((CompoundBehavior) mapTool).addMapBehavior(combinedTool, true);
916
            } else {
917
                currentMapTool =
918
                    new CompoundBehavior(new Behavior[] { currentMapTool });
919
                ((CompoundBehavior) currentMapTool).addMapBehavior(
920
                    combinedTool, true);
921
            }
922
        }
923

  
924
        // this.setCursor(mapTool.getCursor());
925
    }
926

  
927
    /**
928
     * <p>
929
     * Gets as current active <code>Behavior</code> associated to this
930
     * component, that one which is registered and identified by
931
     * <code>toolName</code>.
932
     * </p>
933
     * 
934
     * <p>
935
     * Changing the current active behavior for this <code>MapControl</code>,
936
     * implies also updating the previous <i>behavior</i> tool, and the current
937
     * cursor.
938
     * </p>
939
     * 
940
     * @param toolName
941
     *            name of a registered behavior
942
     * 
943
     * @see #getCurrentTool()
944
     * @see #setTool(String)
945
     */
946
    public Behavior getCurrentMapTool() {
947
        return currentMapTool;
948
    }
949

  
950
    /**
951
     * <p>
952
     * Returns the name of the current selected tool on this MapControl
953
     * </p>
954
     * 
955
     * @return the name of the current's behavior tool associated to this
956
     *         component
957
     * 
958
     * @see #getCurrentMapTool()
959
     * @see #setTool(String)
960
     */
961
    public String getCurrentTool() {
962
        return currentTool;
963
    }
964

  
965
    /**
966
     * <p>
967
     * Determines that current drawing process of <code>MapControl</code>'s
968
     * <code>MapContext</code>'s data must be canceled.
969
     * </p>
970
     * 
971
     * <p>
972
     * It has no effects if now isn't drawing that graphical information.
973
     * </p>
974
     * 
975
     * <p>
976
     * At last resort, the particular implementation of each layer in this
977
     * <code>MapControl</code>'s <code>MapContrext</code> will be that one which
978
     * will draw the graphical information, and, if supports, which could cancel
979
     * its drawing subprocess.
980
     * </p>
981
     */
982
    public void cancelDrawing() {
983
        /*
984
         * if (drawer != null) {
985
         * if (!drawer.isAlive()) {
986
         * return;
987
         * }
988
         * }
989
         */
990
        canceldraw.setCanceled(true);
991

  
992
        /*
993
         * while (!isCancelled) {
994
         * if (!drawer.isAlive()) {
995
         * // Si hemos llegado aqu? con un thread vivo, seguramente
996
         * // no estamos actualizados.
997
         * 
998
         * break;
999
         * }
1000
         * 
1001
         * }
1002
         * canceldraw.setCancel(false);
1003
         * isCancelled = false;
1004
         * drawerAlive = false;
1005
         */
1006
    }
1007

  
1008
    /**
1009
     * <p>
1010
     * Creates a {@link BufferedImage BufferedImage} image if there was no
1011
     * buffered image, or if its viewport's image height or width is different
1012
     * from this component's size. Once has created a double-buffer, fills it
1013
     * with the vieport's background color, or with <i>white</i> if it had no
1014
     * background color.
1015
     * </p>
1016
     * 
1017
     * <p>
1018
     * If no double-buffered existed, creates a {@link BufferedImage
1019
     * BufferedImage} with the size of this component, and as an image with
1020
     * 8-bit RGBA color components packed into integer pixels. That image has a
1021
     * <code>DirectColorModel</code> with alpha. The color data in that image is
1022
     * considered not to be premultiplied with alpha.
1023
     * </p>
1024
     * 
1025
     * <p>
1026
     * Once has created and filled the new inner <code>MapControl</code>'s
1027
     * double-buffer, changes the status to <code>OUTDATED</code>.
1028
     * </p>
1029
     * 
1030
     * @return <code>true</code> if has created and filled a new double-buffer
1031
     *         for this <code>MapControl</code> instance; otherwise
1032
     *         <code>false</code>
1033
     */
1034
    private boolean adaptToImageSize() {
1035
        if ((image == null) || (vp.getImageWidth() != this.getWidth())
1036
            || (vp.getImageHeight() != this.getHeight())) {
1037
            image =
1038
                new BufferedImage(this.getWidth(), this.getHeight(),
1039
                    BufferedImage.TYPE_INT_ARGB);
1040
            // ESTILO MAC
1041
            // image = GraphicsEnvironment.getLocalGraphicsEnvironment()
1042
            // .getDefaultScreenDevice().getDefaultConfiguration()
1043
            // .createCompatibleImage(this.getWidth(), this.getHeight());
1044
            vp.setImageSize(new Dimension(getWidth(), getHeight()));
1045
            getMapContext().getViewPort().refreshExtent();
1046

  
1047
            Graphics gTemp = image.createGraphics();
1048
            Color theBackColor = vp.getBackColor();
1049
            if (theBackColor == null) {
1050
                gTemp.setColor(Color.WHITE);
1051
            } else {
1052
                gTemp.setColor(theBackColor);
1053
            }
1054

  
1055
            gTemp.fillRect(0, 0, getWidth(), getHeight());
1056
            gTemp.dispose();
1057
            status = DESACTUALIZADO;
1058
            // g.drawImage(image,0,0,null);
1059
            return true;
1060
        }
1061
        return false;
1062
    }
1063

  
1064
    /**
1065
     * <p>
1066
     * Paints the graphical information of this component using a double buffer.
1067
     * </p>
1068
     * 
1069
     * <p>
1070
     * If the double buffer wasn't created, creates a new one.
1071
     * </p>
1072
     * 
1073
     * <p>
1074
     * Paints the component according the following algorithm: <br>
1075
     * &nbsp If <i>status</i> is <i>UPDATED</i>:<br>
1076
     * &nbsp &nbsp If there is no <i>double buffer</i>:<br>
1077
     * &nbsp &nbsp &nbsp If there is a <i>behavior</i> for managing the
1078
     * <code>MapControl</code> instance, delegates the drawing process to that
1079
     * behavior, calling:
1080
     * <code><i>behavior_instance</i>.paintComponent(g)</code> &nbsp .<br>
1081
     * &nbsp &nbsp &nbsp Else, repaints the current graphical information
1082
     * quickly calling: <code>g.drawImage(image,0,0,null)</code> &nbsp .<br>
1083
     * &nbsp Else, (<i>status</i> is <i>OUTDATED</i>, or <i>ONLY_GRAPHICS</i>):
1084
     * executes a quickly repaint of the previous information calling
1085
     * <code>g.drawImage(image,0,0,null)</code>, and creates a <i>painting
1086
     * request</i> to delegate the heavy drawing process to the {@link Drawer2
1087
     * Drawer2}'s worker thread, according the <i>SingleWorketThread</i>
1088
     * pattern, starting a timer to update (invoking <code>repaint()</code> that
1089
     * comprises invoke this method) the view every delay of 360 ms. during the
1090
     * the process drawing.
1091
     * </p>
1092
     * 
1093
     * @see javax.swing.JComponent#paintComponent(java.awt.Graphics)
1094
     * @see Drawer2
1095
     */
1096
    protected void paintComponent(Graphics g) {
1097
        adaptToImageSize();
1098

  
1099
        try {
1100
            mapControlDrawer.startDrawing(this);
1101
        } catch (InterruptedException e) {
1102
            logger.error("Error locking the MapControlDrawer", e);
1103
        }
1104
        mapControlDrawer.setGraphics(g);
1105
        mapControlDrawer.stopDrawing(this);
1106
        mapControlDrawer.setViewPort(getMapContext().getViewPort());
1107

  
1108
        if (status == ACTUALIZADO) {
1109
            /*
1110
             * Si hay un behaviour y la imagen es distinta de null se delega el
1111
             * dibujado
1112
             * en dicho behaviour
1113
             */
1114
            if (image != null) {
1115
                if (currentMapTool != null) {
1116
                    currentMapTool.paintComponent(mapControlDrawer);
1117
                } else {
1118
                    mapControlDrawer.drawImage(image, 0, 0);
1119
                }
1120
            }
1121
		} else if ((status == DESACTUALIZADO)) {
1122

  
1123
			mapControlDrawer.drawImage(image, 0, 0);
1124

  
1125
			drawer.put(new PaintingRequest());
1126
			timer.start();
1127
		}
1128
        cadgrid.drawGrid(mapControlDrawer);
1129
        drawCursor();
1130
    }
1131

  
1132
    /**
1133
     * <p>
1134
     * Gets the {@link BufferedImage BufferedImage} used to accelerate the draw
1135
     * of new ''frames'' with changes, or new graphical items in this component.
1136
     * </p>
1137
     * 
1138
     * @return double buffered image used by this component to accelerate the
1139
     *         draw of its graphical information, or <code>null</code> if isn't
1140
     *         already created
1141
     * 
1142
     * @see BufferedImage
1143
     */
1144
    public BufferedImage getImage() {
1145
        return image;
1146
    }
1147

  
1148
    /**
1149
     * <p>
1150
     * Forces repaint all visible graphical information in this component.
1151
     * </p>
1152
     * 
1153
     * <p>
1154
     * If <code>doClear == true</code>, before repainting, clears the background
1155
     * color, with the inner viewport's background color.
1156
     * </p>
1157
     * 
1158
     * @param doClear
1159
     *            <code>true</code> if needs clearing the background color
1160
     *            before drawing the map
1161
     * 
1162
     * @see #cancelDrawing()
1163
     * @see FLayers#setDirty(boolean)
1164
     */
1165
    public void drawMap(boolean doClear) {
1166
        cancelDrawing();
1167
        // System.out.println("drawMap con doClear=" + doClear);
1168
        status = DESACTUALIZADO;
1169
        if (doClear) {
1170
            // image = null; // Se usa para el PAN
1171
            if (image != null) {
1172
                Graphics2D g = image.createGraphics();
1173
                Color theBackColor = vp.getBackColor();
1174
                if (theBackColor == null) {
1175
                    g.setColor(Color.WHITE);
1176
                } else {
1177
                    g.setColor(theBackColor);
1178
                }
1179
                g.fillRect(0, 0, vp.getImageWidth(), vp.getImageHeight());
1180
                g.dispose();
1181
            }
1182
        }
1183
        repaint();
1184
    }
1185

  
1186
    /**
1187
     * <p>
1188
     * Cancels any current drawing process, changing the status to
1189
     * <code>OUTDATED</code>, and forcing repaint only the layers dirty.
1190
     * </p>
1191
     * 
1192
     * @see #cancelDrawing()
1193
     */
1194
    public void rePaintDirtyLayers() {
1195
        cancelDrawing();
1196
        status = DESACTUALIZADO;
1197
        repaint();
1198
    }
1199

  
1200
    /**
1201
     * @deprecated use {@link #drawMap(boolean)} instead, or even
1202
     * better {@link #getMapContext()}.invalidate().
1203
     */
1204
    public void drawGraphics() {
1205
        drawMap(false);
1206
    }
1207

  
1208
    /**
1209
     * @see java.awt.event.ComponentListener#componentHidden(java.awt.event.ComponentEvent)
1210
     */
1211
    public void componentHidden(ComponentEvent e) {
1212
    }
1213

  
1214
    /**
1215
     * @see java.awt.event.ComponentListener#componentMoved(java.awt.event.ComponentEvent)
1216
     */
1217
    public void componentMoved(ComponentEvent e) {
1218
    }
1219

  
1220
    /**
1221
     * @see java.awt.event.ComponentListener#componentResized(java.awt.event.ComponentEvent)
1222
     */
1223
    public void componentResized(ComponentEvent e) {
1224
        /*
1225
         * image = new BufferedImage(this.getWidth(), this.getHeight(),
1226
         * BufferedImage.TYPE_INT_ARGB);
1227
         * Graphics gTemp = image.createGraphics();
1228
         * gTemp.setColor(vp.getBackColor());
1229
         * gTemp.fillRect(0,0,getWidth(), getHeight());
1230
         * System.out.println("MapControl resized");
1231
         * // image = null;
1232
         * vp.setImageSize(new Dimension(getWidth(), getHeight()));
1233
         * getMapContext().getViewPort().setScale();
1234
         */
1235
        // drawMap(true);
1236
    }
1237

  
1238
    /**
1239
     * @see java.awt.event.ComponentListener#componentShown(java.awt.event.ComponentEvent)
1240
     */
1241
    public void componentShown(ComponentEvent e) {
1242
    }
1243

  
1244
    /**
1245
     * @see ExceptionHandlingSupport#addExceptionListener(ExceptionListener)
1246
     */
1247
    public void addExceptionListener(ExceptionListener o) {
1248
        exceptionHandlingSupport.addExceptionListener(o);
1249
    }
1250

  
1251
    /**
1252
     * @see ExceptionHandlingSupport#removeExceptionListener(ExceptionListener)
1253
     */
1254
    public boolean removeExceptionListener(ExceptionListener o) {
1255
        return exceptionHandlingSupport.removeExceptionListener(o);
1256
    }
1257

  
1258
    /**
1259
     * @see ExceptionHandlingSupport#throwException(Throwable)
1260
     */
1261
    protected void throwException(Throwable t) {
1262
        exceptionHandlingSupport.throwException(t);
1263
    }
1264

  
1265
    /**
1266
     * <p>
1267
     * Represents each <code>MapControl</code>'s data painting request.
1268
     * </p>
1269
     * 
1270
     * <p>
1271
     * The request will be attended by a <code>Drawer2</code>, which will hold
1272
     * it since the <code>Drawer2</code>'s worker takes it, or arrives a new
1273
     * painting request, which will replace it.
1274
     * </p>
1275
     */
1276
    private class PaintingRequest {
1277

  
1278
        /**
1279
         * <p>
1280
         * Creates a new <code>PaintingRequest
1281
         * </p>
1282
         * instance.</p>
1283
         */
1284
        public PaintingRequest() {
1285
        }
1286

  
1287
        /**
1288
         * <p>
1289
         * <code>MapControl</code> paint process:
1290
         * </p>
1291
         * 
1292
         * <p>
1293
         * <ul>
1294
         * <li><i>1.- </i>Cancels all previous <code>MapControl</code>'s drawing
1295
         * processes.</li>
1296
         * <li><i>2.- </i>If <i>status</i> was OUTDATED:
1297
         * <ul>
1298
         * <li><i>2.1.- </i>Fills the background color with viewport's
1299
         * background color, or <i>white</i> if it was undefined.</li>
1300
         * <li><i>2.2.- </i>Notifies <i>MapContext</i> to be drawn invoking: <code>mapContext.draw(double-buffer, double-buffer's buffer, shared cancel-draw object, mapContext.getScaleView());</code>
1301
         * .</li>
1302
         * <li><i>2.3.- </i>If <code>canceldraw.isCanceled()</code>
1303
         * <ul>
1304
         * <li><i>2.3.1.- </i>Sets <i>status</i> to OUTDATED.</li>
1305
         * <li><i>2.3.2.- </i>Sets <i>dirty</i> all layers stored in
1306
         * <i>MapContext</i>.</li>
1307
         * </ul>
1308
         * </li>
1309
         * <li><i>2.4.- </i>Else, sets <i>status</i> to UPDATED.</li>
1310
         * </ul>
1311
         * </li>
1312
         * <li><i>3.- </i>Stops the <i>timer</i>.</li>
1313
         * <li><i>4.- </i>Repaints this component invoking:
1314
         * <code>repaint();</code></li>
1315
         * </ul>
1316
         * </p>
1317
         * 
1318
         * @see #cancelDrawing()
1319
         * @see MapContext#draw(BufferedImage, Graphics2D, Cancellable, double)
1320
         * @see MapContext#drawGraphics(BufferedImage, Graphics2D, Cancellable,
1321
         *      double)
1322
         * 
1323
         * @see ViewPort
1324
         */
1325
        public void paint() {
1326
            try {
1327
                canceldraw.setCanceled(false);
1328
                Graphics2D g = image.createGraphics();
1329

  
1330
                ViewPort viewPort = mapContext.getViewPort();
1331

  
1332
                if (status == DESACTUALIZADO) {
1333
                    Graphics2D gTemp = image.createGraphics();
1334
                    Color theBackColor = viewPort.getBackColor();
1335
                    if (theBackColor == null) {
1336
                        gTemp.setColor(Color.WHITE);
1337
                    } else {
1338
                        gTemp.setColor(theBackColor);
1339
                    }
1340
                    gTemp.fillRect(0, 0, viewPort.getImageWidth(), viewPort
1341
                        .getImageHeight());
1342
                    mapContext.draw(image, g, canceldraw, mapContext
1343
                        .getScaleView());
1344
                    if (!canceldraw.isCanceled()) {
1345
                        status = ACTUALIZADO;
1346
                    }
1347
				}
1348

  
1349
                timer.stop();
1350
                repaint();
1351

  
1352
            } catch (Throwable e) {
1353
                timer.stop();
1354
                e.printStackTrace();
1355
                throwException(e);
1356
            } 
1357
        }
1358
    }
1359

  
1360
    /**
1361
     * <p>
1362
     * An instance of <code>Drawer2</code> could manage all
1363
     * <code>MapControl</code> painting requests.
1364
     * </p>
1365
     * 
1366
     * <p>
1367
     * Based on the <i>WorkerThread</i> software pattern, creates a worker
1368
     * thread that will attend sequentially the current waiting painting
1369
     * request, after finishing the previous (that could be by a cancel action).
1370
     * </p>
1371
     * 
1372
     * <p>
1373
     * All new {@link PaintingRequest PaintingRequest} generated will be stored
1374
     * as <i>waiting requests</i> since the worker attends it.
1375
     * </p>
1376
     * 
1377
     * <p>
1378
     * If a worker finished and there was no <i>painting request</i>, the worker
1379
     * would be set to wait until any <i>painting request</i> would be put.
1380
     * </p>
1381
     * 
1382
     * @author fjp
1383
     */
1384
    public class Drawer {
1385

  
1386
        // Una mini cola de 2. No acumulamos peticiones de dibujado
1387
        // dibujamos solo lo ?ltimo que nos han pedido.
1388

  
1389
        /**
1390
         * <p>
1391
         * Painting request that's been attended by the <code>Drawer2</code>'s
1392
         * worker.
1393
         * </p>
1394
         * 
1395
         * @see #put(org.gvsig.fmap.mapcontrol.MapControl.PaintingRequest)
1396
         * @see #take()
1397
         */
1398
        private PaintingRequest paintingRequest;
1399

  
1400
        /**
1401
         * <p>
1402
         * Painting request waiting to be attended by the <code>Drawer2</code>'s
1403
         * worker.
1404
         * </p>
1405
         * 
1406
         * @see #put(org.gvsig.fmap.mapcontrol.MapControl.PaintingRequest)
1407
         * @see #take()
1408
         */
1409
        private PaintingRequest waitingRequest;
1410

  
1411
        /**
1412
         * <p>
1413
         * Determines that the <code>Drawer2</code>'s worker is busy attending a
1414
         * painting request.
1415
         * </p>
1416
         * 
1417
         * @see #put(org.gvsig.fmap.mapcontrol.MapControl.PaintingRequest)
1418
         * @see #take()
1419
         */
1420
        private boolean waiting;
1421

  
1422
        /**
1423
         * <p>
1424
         * Notifies the <code>Drawer2</code>'s worker to finish or continue with
1425
         * its process.
1426
         * </p>
1427
         * 
1428
         * @see #setShutdown(boolean)
1429
         */
1430
        private boolean shutdown;
1431

  
1432
        /**
1433
         * <p>
1434
         * Sets this <code>Drawer2</code>'s worker to finish or continue with
1435
         * its process.
1436
         * </p>
1437
         * 
1438
         * @param isShutdown
1439
         *            a boolean value
1440
         */
1441
        public void setShutdown(boolean isShutdown) {
1442
            shutdown = isShutdown;
1443
        }
1444

  
1445
        /**
1446
         * <p>
... This diff was truncated because it exceeds the maximum size that can be displayed.

Also available in: Unified diff