source: josm/trunk/src/org/openstreetmap/josm/gui/MapView.java@ 10627

Last change on this file since 10627 was 10627, checked in by Don-vip, 8 years ago

sonar - squid:S1166 - Exception handlers should preserve the original exceptions

  • Property svn:eol-style set to native
File size: 48.9 KB
Line 
1// License: GPL. For details, see LICENSE file.
2package org.openstreetmap.josm.gui;
3
4import static org.openstreetmap.josm.tools.I18n.tr;
5
6import java.awt.AlphaComposite;
7import java.awt.Color;
8import java.awt.Dimension;
9import java.awt.Graphics;
10import java.awt.Graphics2D;
11import java.awt.Point;
12import java.awt.Rectangle;
13import java.awt.event.ComponentAdapter;
14import java.awt.event.ComponentEvent;
15import java.awt.event.KeyEvent;
16import java.awt.event.MouseAdapter;
17import java.awt.event.MouseEvent;
18import java.awt.event.MouseMotionListener;
19import java.awt.geom.Area;
20import java.awt.geom.GeneralPath;
21import java.awt.image.BufferedImage;
22import java.beans.PropertyChangeEvent;
23import java.beans.PropertyChangeListener;
24import java.util.ArrayList;
25import java.util.Arrays;
26import java.util.Collection;
27import java.util.Collections;
28import java.util.HashMap;
29import java.util.LinkedHashSet;
30import java.util.List;
31import java.util.Set;
32import java.util.concurrent.CopyOnWriteArrayList;
33
34import javax.swing.AbstractButton;
35import javax.swing.JComponent;
36import javax.swing.JPanel;
37
38import org.openstreetmap.josm.Main;
39import org.openstreetmap.josm.actions.mapmode.MapMode;
40import org.openstreetmap.josm.data.Bounds;
41import org.openstreetmap.josm.data.Preferences.PreferenceChangeEvent;
42import org.openstreetmap.josm.data.Preferences.PreferenceChangedListener;
43import org.openstreetmap.josm.data.ProjectionBounds;
44import org.openstreetmap.josm.data.SelectionChangedListener;
45import org.openstreetmap.josm.data.ViewportData;
46import org.openstreetmap.josm.data.coor.EastNorth;
47import org.openstreetmap.josm.data.coor.LatLon;
48import org.openstreetmap.josm.data.imagery.ImageryInfo;
49import org.openstreetmap.josm.data.osm.DataSet;
50import org.openstreetmap.josm.data.osm.visitor.paint.PaintColors;
51import org.openstreetmap.josm.data.osm.visitor.paint.Rendering;
52import org.openstreetmap.josm.data.osm.visitor.paint.relations.MultipolygonCache;
53import org.openstreetmap.josm.gui.MapViewState.MapViewRectangle;
54import org.openstreetmap.josm.gui.datatransfer.OsmTransferHandler;
55import org.openstreetmap.josm.gui.layer.AbstractMapViewPaintable;
56import org.openstreetmap.josm.gui.layer.GpxLayer;
57import org.openstreetmap.josm.gui.layer.ImageryLayer;
58import org.openstreetmap.josm.gui.layer.Layer;
59import org.openstreetmap.josm.gui.layer.LayerManager;
60import org.openstreetmap.josm.gui.layer.LayerManager.LayerAddEvent;
61import org.openstreetmap.josm.gui.layer.LayerManager.LayerOrderChangeEvent;
62import org.openstreetmap.josm.gui.layer.LayerManager.LayerRemoveEvent;
63import org.openstreetmap.josm.gui.layer.MainLayerManager;
64import org.openstreetmap.josm.gui.layer.MainLayerManager.ActiveLayerChangeEvent;
65import org.openstreetmap.josm.gui.layer.MainLayerManager.ActiveLayerChangeListener;
66import org.openstreetmap.josm.gui.layer.MapViewGraphics;
67import org.openstreetmap.josm.gui.layer.MapViewPaintable;
68import org.openstreetmap.josm.gui.layer.MapViewPaintable.LayerPainter;
69import org.openstreetmap.josm.gui.layer.MapViewPaintable.MapViewEvent;
70import org.openstreetmap.josm.gui.layer.MapViewPaintable.PaintableInvalidationEvent;
71import org.openstreetmap.josm.gui.layer.MapViewPaintable.PaintableInvalidationListener;
72import org.openstreetmap.josm.gui.layer.OsmDataLayer;
73import org.openstreetmap.josm.gui.layer.geoimage.GeoImageLayer;
74import org.openstreetmap.josm.gui.layer.markerlayer.PlayHeadMarker;
75import org.openstreetmap.josm.tools.AudioPlayer;
76import org.openstreetmap.josm.tools.Shortcut;
77import org.openstreetmap.josm.tools.Utils;
78import org.openstreetmap.josm.tools.bugreport.BugReport;
79import org.openstreetmap.josm.tools.bugreport.BugReportExceptionHandler;
80
81/**
82 * This is a component used in the {@link MapFrame} for browsing the map. It use is to
83 * provide the MapMode's enough capabilities to operate.<br><br>
84 *
85 * {@code MapView} holds meta-data about the data set currently displayed, as scale level,
86 * center point viewed, what scrolling mode or editing mode is selected or with
87 * what projection the map is viewed etc..<br><br>
88 *
89 * {@code MapView} is able to administrate several layers.
90 *
91 * @author imi
92 */
93public class MapView extends NavigatableComponent
94implements PropertyChangeListener, PreferenceChangedListener,
95LayerManager.LayerChangeListener, MainLayerManager.ActiveLayerChangeListener {
96 /**
97 * Interface to notify listeners of a layer change.
98 * <p>
99 * To be removed: end of 2016.
100 * @deprecated Use {@link org.openstreetmap.josm.gui.layer.LayerManager.LayerChangeListener} instead.
101 * @author imi
102 */
103 @Deprecated
104 public interface LayerChangeListener {
105
106 /**
107 * Notifies this listener that the active layer has changed.
108 * @param oldLayer The previous active layer
109 * @param newLayer The new activer layer
110 */
111 void activeLayerChange(Layer oldLayer, Layer newLayer);
112
113 /**
114 * Notifies this listener that a layer has been added.
115 * @param newLayer The new added layer
116 */
117 void layerAdded(Layer newLayer);
118
119 /**
120 * Notifies this listener that a layer has been removed.
121 * @param oldLayer The old removed layer
122 */
123 void layerRemoved(Layer oldLayer);
124 }
125
126 /**
127 * An interface that needs to be implemented in order to listen for changes to the active edit layer.
128 * <p>
129 * To be removed: end of 2016.
130 * @deprecated Use {@link ActiveLayerChangeListener} instead.
131 */
132 @Deprecated
133 @FunctionalInterface
134 public interface EditLayerChangeListener {
135
136 /**
137 * Called after the active edit layer was changed.
138 * @param oldLayer The old edit layer
139 * @param newLayer The current (new) edit layer
140 */
141 void editLayerChanged(OsmDataLayer oldLayer, OsmDataLayer newLayer);
142 }
143
144 /**
145 * An invalidation listener that simply calls repaint() for now.
146 * @author Michael Zangl
147 * @since 10271
148 */
149 private class LayerInvalidatedListener implements PaintableInvalidationListener {
150 private boolean ignoreRepaint;
151 @Override
152 public void paintableInvalidated(PaintableInvalidationEvent event) {
153 ignoreRepaint = true;
154 repaint();
155 }
156
157 /**
158 * Temporary until all {@link MapViewPaintable}s support this.
159 * @param p The paintable.
160 */
161 public void addTo(MapViewPaintable p) {
162 if (p instanceof AbstractMapViewPaintable) {
163 ((AbstractMapViewPaintable) p).addInvalidationListener(this);
164 }
165 }
166
167 /**
168 * Temporary until all {@link MapViewPaintable}s support this.
169 * @param p The paintable.
170 */
171 public void removeFrom(MapViewPaintable p) {
172 if (p instanceof AbstractMapViewPaintable) {
173 ((AbstractMapViewPaintable) p).removeInvalidationListener(this);
174 }
175 }
176
177 /**
178 * Attempts to trace repaints that did not originate from this listener. Good to find missed {@link MapView#repaint()}s in code.
179 */
180 protected synchronized void traceRandomRepaint() {
181 if (!ignoreRepaint) {
182 System.err.println("Repaint:");
183 Thread.dumpStack();
184 }
185 ignoreRepaint = false;
186 }
187 }
188
189 /**
190 * This class is an adapter for the old layer change interface.
191 * <p>
192 * New implementations should use {@link org.openstreetmap.josm.gui.layer.LayerManager.LayerChangeListener}
193 * @author Michael Zangl
194 * @since 10271
195 */
196 protected static class LayerChangeAdapter implements ActiveLayerChangeListener, LayerManager.LayerChangeListener {
197
198 private final LayerChangeListener wrapped;
199 private boolean receiveOneInitialFire;
200
201 public LayerChangeAdapter(LayerChangeListener wrapped) {
202 this.wrapped = wrapped;
203 }
204
205 public LayerChangeAdapter(LayerChangeListener wrapped, boolean initialFire) {
206 this(wrapped);
207 this.receiveOneInitialFire = initialFire;
208 }
209
210 @Override
211 public void layerAdded(LayerAddEvent e) {
212 wrapped.layerAdded(e.getAddedLayer());
213 }
214
215 @Override
216 public void layerRemoving(LayerRemoveEvent e) {
217 wrapped.layerRemoved(e.getRemovedLayer());
218 }
219
220 @Override
221 public void layerOrderChanged(LayerOrderChangeEvent e) {
222 // not in old API
223 }
224
225 @Override
226 public void activeOrEditLayerChanged(ActiveLayerChangeEvent e) {
227 Layer oldActive = receiveOneInitialFire ? null : e.getPreviousActiveLayer();
228 Layer newActive = e.getSource().getActiveLayer();
229 if (oldActive != newActive) {
230 wrapped.activeLayerChange(oldActive, newActive);
231 }
232 receiveOneInitialFire = false;
233 }
234
235 @Override
236 public int hashCode() {
237 final int prime = 31;
238 int result = 1;
239 result = prime * result + ((wrapped == null) ? 0 : wrapped.hashCode());
240 return result;
241 }
242
243 @Override
244 public boolean equals(Object obj) {
245 if (this == obj)
246 return true;
247 if (obj == null)
248 return false;
249 if (getClass() != obj.getClass())
250 return false;
251 LayerChangeAdapter other = (LayerChangeAdapter) obj;
252 if (wrapped == null) {
253 if (other.wrapped != null)
254 return false;
255 } else if (!wrapped.equals(other.wrapped))
256 return false;
257 return true;
258 }
259
260 @Override
261 public String toString() {
262 return "LayerChangeAdapter [wrapped=" + wrapped + ']';
263 }
264 }
265
266 /**
267 * This class is an adapter for the old layer change interface.
268 * <p>
269 * New implementations should use {@link org.openstreetmap.josm.gui.layer.MainLayerManager.ActiveLayerChangeListener}
270 * @author Michael Zangl
271 * @since 10271
272 */
273 protected static class EditLayerChangeAdapter implements ActiveLayerChangeListener {
274
275 private final EditLayerChangeListener wrapped;
276
277 public EditLayerChangeAdapter(EditLayerChangeListener wrapped) {
278 this.wrapped = wrapped;
279 }
280
281 @Override
282 public void activeOrEditLayerChanged(ActiveLayerChangeEvent e) {
283 OsmDataLayer oldLayer = e.getPreviousEditLayer();
284 OsmDataLayer newLayer = e.getSource().getEditLayer();
285 if (oldLayer != newLayer) {
286 wrapped.editLayerChanged(oldLayer, newLayer);
287 }
288 }
289
290 @Override
291 public int hashCode() {
292 final int prime = 31;
293 int result = 1;
294 result = prime * result + ((wrapped == null) ? 0 : wrapped.hashCode());
295 return result;
296 }
297
298 @Override
299 public boolean equals(Object obj) {
300 if (this == obj)
301 return true;
302 if (obj == null)
303 return false;
304 if (getClass() != obj.getClass())
305 return false;
306 EditLayerChangeAdapter other = (EditLayerChangeAdapter) obj;
307 if (wrapped == null) {
308 if (other.wrapped != null)
309 return false;
310 } else if (!wrapped.equals(other.wrapped))
311 return false;
312 return true;
313 }
314
315 @Override
316 public String toString() {
317 return "EditLayerChangeAdapter [wrapped=" + wrapped + ']';
318 }
319 }
320
321 /**
322 * A layer painter that issues a warning when being called.
323 * @author Michael Zangl
324 * @since 10474
325 */
326 private static class WarningLayerPainter implements LayerPainter {
327 boolean warningPrinted = false;
328 private final Layer layer;
329
330 WarningLayerPainter(Layer layer) {
331 this.layer = layer;
332 }
333
334 @Override
335 public void paint(MapViewGraphics graphics) {
336 if (!warningPrinted) {
337 Main.debug("A layer triggered a repaint while being added: " + layer);
338 warningPrinted = true;
339 }
340 }
341
342 @Override
343 public void detachFromMapView(MapViewEvent event) {
344 // ignored
345 }
346 }
347
348 /**
349 * Removes a layer change listener
350 * <p>
351 * To be removed: end of 2016.
352 *
353 * @param listener the listener. Ignored if null or not registered.
354 * @deprecated You should register the listener on {@link Main#getLayerManager()} instead.
355 */
356 @Deprecated
357 public static void removeLayerChangeListener(LayerChangeListener listener) {
358 LayerChangeAdapter adapter = new LayerChangeAdapter(listener);
359 try {
360 Main.getLayerManager().removeLayerChangeListener(adapter);
361 } catch (IllegalArgumentException e) {
362 // Ignored in old implementation
363 Main.debug(e);
364 }
365 try {
366 Main.getLayerManager().removeActiveLayerChangeListener(adapter);
367 } catch (IllegalArgumentException e) {
368 // Ignored in old implementation
369 Main.debug(e);
370 }
371 }
372
373 /**
374 * Removes an edit layer change listener
375 * <p>
376 * To be removed: end of 2016.
377 *
378 * @param listener the listener. Ignored if null or not registered.
379 * @deprecated You should register the listener on {@link Main#getLayerManager()} instead.
380 */
381 @Deprecated
382 public static void removeEditLayerChangeListener(EditLayerChangeListener listener) {
383 try {
384 Main.getLayerManager().removeActiveLayerChangeListener(new EditLayerChangeAdapter(listener));
385 } catch (IllegalArgumentException e) {
386 // Ignored in old implementation
387 Main.debug(e);
388 }
389 }
390
391 /**
392 * Adds a layer change listener
393 * <p>
394 * To be removed: end of 2016.
395 *
396 * @param listener the listener. Ignored if null or already registered.
397 * @deprecated You should register the listener on {@link Main#getLayerManager()} instead.
398 */
399 @Deprecated
400 public static void addLayerChangeListener(LayerChangeListener listener) {
401 if (fireDeprecatedListenerOnAdd) {
402 Main.warn("Plugin seems to be adding listener during mapFrameInitialized(): " + BugReport.getCallingMethod(2)
403 + ". Layer listeners should be set on plugin load.");
404 }
405 addLayerChangeListener(listener, fireDeprecatedListenerOnAdd);
406 }
407
408 /**
409 * Adds a layer change listener
410 * <p>
411 * To be removed: end of 2016.
412 *
413 * @param listener the listener. Ignored if null or already registered.
414 * @param initialFire fire an active-layer-changed-event right after adding
415 * the listener in case there is a layer present (should be)
416 * @deprecated You should register the listener on {@link Main#getLayerManager()} instead.
417 */
418 @Deprecated
419 public static void addLayerChangeListener(LayerChangeListener listener, boolean initialFire) {
420 if (listener != null) {
421 initialFire = initialFire && (Main.isDisplayingMapView() || fireDeprecatedListenerOnAdd);
422
423 LayerChangeAdapter adapter = new LayerChangeAdapter(listener, initialFire);
424 Main.getLayerManager().addLayerChangeListener(adapter, initialFire);
425 if (initialFire) {
426 Main.getLayerManager().addAndFireActiveLayerChangeListener(adapter);
427 } else {
428 Main.getLayerManager().addActiveLayerChangeListener(adapter);
429 }
430 adapter.receiveOneInitialFire = false;
431 }
432 }
433
434 /**
435 * Adds an edit layer change listener
436 * <p>
437 * To be removed: end of 2016.
438 *
439 * @param listener the listener. Ignored if null or already registered.
440 * @param initialFire fire an edit-layer-changed-event right after adding
441 * the listener in case there is an edit layer present
442 * @deprecated You should register the listener on {@link Main#getLayerManager()} instead.
443 */
444 @Deprecated
445 public static void addEditLayerChangeListener(EditLayerChangeListener listener, boolean initialFire) {
446 if (listener != null) {
447 boolean doFire = initialFire && Main.isDisplayingMapView() && Main.getLayerManager().getEditLayer() != null;
448 if (doFire) {
449 Main.getLayerManager().addAndFireActiveLayerChangeListener(new EditLayerChangeAdapter(listener));
450 } else {
451 Main.getLayerManager().addActiveLayerChangeListener(new EditLayerChangeAdapter(listener));
452 }
453 }
454 }
455
456 /**
457 * Adds an edit layer change listener
458 * <p>
459 * To be removed: end of 2016.
460 *
461 * @param listener the listener. Ignored if null or already registered.
462 * @deprecated You should register the listener on {@link Main#getLayerManager()} instead.
463 */
464 @Deprecated
465 public static void addEditLayerChangeListener(EditLayerChangeListener listener) {
466 addEditLayerChangeListener(listener, false);
467 }
468
469
470 /**
471 * Temporary. To be removed as soon as the {@link LayerChangeListener}s are removed.
472 * <p>
473 * Some plugins add their listeners in {@link Main#setMapFrame(MapFrame)}. This method is now called just after the first layer was added to
474 * the layer manager. So that listener would not receive the addition of the first layer. As long as this field is set, we fake an add call
475 * to that listener when it is added to immitate the old behaviour. You should not access it from anywhere else.
476 */
477 public static boolean fireDeprecatedListenerOnAdd;
478
479 public boolean viewportFollowing;
480
481 /**
482 * A list of all layers currently loaded. If we support multiple map views, this list may be different for each of them.
483 */
484 private final MainLayerManager layerManager;
485
486 /**
487 * The play head marker: there is only one of these so it isn't in any specific layer
488 */
489 public transient PlayHeadMarker playHeadMarker;
490
491 /**
492 * The last event performed by mouse.
493 */
494 public MouseEvent lastMEvent = new MouseEvent(this, 0, 0, 0, 0, 0, 0, false); // In case somebody reads it before first mouse move
495
496 /**
497 * Temporary layers (selection rectangle, etc.) that are never cached and
498 * drawn on top of regular layers.
499 * Access must be synchronized.
500 */
501 private final transient Set<MapViewPaintable> temporaryLayers = new LinkedHashSet<>();
502
503 private transient BufferedImage nonChangedLayersBuffer;
504 private transient BufferedImage offscreenBuffer;
505 // Layers that wasn't changed since last paint
506 private final transient List<Layer> nonChangedLayers = new ArrayList<>();
507 private transient Layer changedLayer;
508 private int lastViewID;
509 private boolean paintPreferencesChanged = true;
510 private Rectangle lastClipBounds = new Rectangle();
511 private transient MapMover mapMover;
512
513 /**
514 * The listener that listens to invalidations of all layers.
515 */
516 private final LayerInvalidatedListener invalidatedListener = new LayerInvalidatedListener();
517
518 /**
519 * This is a map of all Layers that have been added to this view.
520 */
521 private final HashMap<Layer, LayerPainter> registeredLayers = new HashMap<>();
522
523 /**
524 * Constructs a new {@code MapView}.
525 * @param layerManager The layers to display.
526 * @param contentPane Ignored. Main content pane is used.
527 * @param viewportData the initial viewport of the map. Can be null, then
528 * the viewport is derived from the layer data.
529 * @since 10279
530 */
531 public MapView(MainLayerManager layerManager, final JPanel contentPane, final ViewportData viewportData) {
532 this.layerManager = layerManager;
533 initialViewport = viewportData;
534 layerManager.addLayerChangeListener(this, true);
535 layerManager.addActiveLayerChangeListener(this);
536 Main.pref.addPreferenceChangeListener(this);
537
538 addComponentListener(new ComponentAdapter() {
539 @Override
540 public void componentResized(ComponentEvent e) {
541 removeComponentListener(this);
542
543 mapMover = new MapMover(MapView.this, contentPane);
544 }
545 });
546
547 // listend to selection changes to redraw the map
548 DataSet.addSelectionListener(repaintSelectionChangedListener);
549
550 //store the last mouse action
551 this.addMouseMotionListener(new MouseMotionListener() {
552 @Override
553 public void mouseDragged(MouseEvent e) {
554 mouseMoved(e);
555 }
556
557 @Override
558 public void mouseMoved(MouseEvent e) {
559 lastMEvent = e;
560 }
561 });
562 this.addMouseListener(new MouseAdapter() {
563 @Override
564 public void mousePressed(MouseEvent me) {
565 // focus the MapView component when mouse is pressed inside it
566 requestFocus();
567 }
568 });
569
570 if (Shortcut.findShortcut(KeyEvent.VK_TAB, 0) != null) {
571 setFocusTraversalKeysEnabled(false);
572 }
573
574 for (JComponent c : getMapNavigationComponents(MapView.this)) {
575 add(c);
576 }
577 setTransferHandler(new OsmTransferHandler());
578 }
579
580 /**
581 * Adds the map navigation components to a
582 * @param forMapView The map view to get the components for.
583 * @return A list containing the correctly positioned map navigation components.
584 */
585 public static List<? extends JComponent> getMapNavigationComponents(MapView forMapView) {
586 MapSlider zoomSlider = new MapSlider(forMapView);
587 Dimension size = zoomSlider.getPreferredSize();
588 zoomSlider.setSize(size);
589 zoomSlider.setLocation(3, 0);
590 zoomSlider.setFocusTraversalKeysEnabled(Shortcut.findShortcut(KeyEvent.VK_TAB, 0) == null);
591
592 MapScaler scaler = new MapScaler(forMapView);
593 scaler.setPreferredLineLength(size.width - 10);
594 scaler.setSize(scaler.getPreferredSize());
595 scaler.setLocation(3, size.height);
596
597 return Arrays.asList(zoomSlider, scaler);
598 }
599
600 // remebered geometry of the component
601 private Dimension oldSize;
602 private Point oldLoc;
603
604 /**
605 * Call this method to keep map position on screen during next repaint
606 */
607 public void rememberLastPositionOnScreen() {
608 oldSize = getSize();
609 oldLoc = getLocationOnScreen();
610 }
611
612 /**
613 * Add a layer to the current MapView.
614 * <p>
615 * To be removed: end of 2016.
616 * @param layer The layer to add
617 * @deprecated Use {@link Main#getLayerManager()}.addLayer() instead.
618 */
619 @Deprecated
620 public void addLayer(Layer layer) {
621 layerManager.addLayer(layer);
622 }
623
624 @Override
625 public void layerAdded(LayerAddEvent e) {
626 try {
627 Layer layer = e.getAddedLayer();
628 registeredLayers.put(layer, new WarningLayerPainter(layer));
629 // Layers may trigger a redraw during this call if they open dialogs.
630 LayerPainter painter = layer.attachToMapView(new MapViewEvent(this, false));
631 if (!registeredLayers.containsKey(layer)) {
632 // The layer may have removed itself during attachToMapView()
633 Main.warn("Layer was removed during attachToMapView()");
634 } else {
635 registeredLayers.put(layer, painter);
636
637 ProjectionBounds viewProjectionBounds = layer.getViewProjectionBounds();
638 if (viewProjectionBounds != null) {
639 scheduleZoomTo(new ViewportData(viewProjectionBounds));
640 }
641
642 layer.addPropertyChangeListener(this);
643 Main.addProjectionChangeListener(layer);
644 invalidatedListener.addTo(layer);
645 AudioPlayer.reset();
646
647 repaint();
648 }
649 } catch (RuntimeException t) {
650 throw BugReport.intercept(t).put("layer", e.getAddedLayer());
651 }
652 }
653
654 /**
655 * Returns current data set. To be removed: end of 2016.
656 * @deprecated Use {@link #getLayerManager()}.getEditDataSet() instead.
657 */
658 @Override
659 @Deprecated
660 protected DataSet getCurrentDataSet() {
661 return layerManager.getEditDataSet();
662 }
663
664 /**
665 * Replies true if the active data layer (edit layer) is drawable.
666 *
667 * @return true if the active data layer (edit layer) is drawable, false otherwise
668 */
669 public boolean isActiveLayerDrawable() {
670 return getEditLayer() != null;
671 }
672
673 /**
674 * Replies true if the active data layer (edit layer) is visible.
675 *
676 * @return true if the active data layer (edit layer) is visible, false otherwise
677 */
678 public boolean isActiveLayerVisible() {
679 OsmDataLayer e = getEditLayer();
680 return e != null && e.isVisible();
681 }
682
683 /**
684 * Determines the next active data layer according to the following rules:
685 * <ul>
686 * <li>if there is at least one {@link OsmDataLayer} the first one
687 * becomes active</li>
688 * <li>otherwise, the top most layer of any type becomes active</li>
689 * </ul>
690 * To be removed: end of 2016.
691 * @param layersList lit of layers
692 *
693 * @return the next active data layer
694 * @deprecated now handled by {@link MainLayerManager}
695 */
696 @Deprecated
697 protected Layer determineNextActiveLayer(List<Layer> layersList) {
698 // First look for data layer
699 for (Layer layer:layersList) {
700 if (layer instanceof OsmDataLayer)
701 return layer;
702 }
703
704 // Then any layer
705 if (!layersList.isEmpty())
706 return layersList.get(0);
707
708 // and then give up
709 return null;
710 }
711
712 /**
713 * Remove the layer from the mapview. If the layer was in the list before,
714 * an LayerChange event is fired.
715 * <p>
716 * To be removed: end of 2016.
717 * @param layer The layer to remove
718 * @deprecated Use {@link Main#getLayerManager()}.removeLayer() instead.
719 */
720 @Deprecated
721 public void removeLayer(Layer layer) {
722 layerManager.removeLayer(layer);
723 }
724
725 @Override
726 public void layerRemoving(LayerRemoveEvent e) {
727 Layer layer = e.getRemovedLayer();
728
729 LayerPainter painter = registeredLayers.remove(layer);
730 if (painter == null) {
731 Main.error("The painter for layer " + layer + " was not registered.");
732 return;
733 }
734 painter.detachFromMapView(new MapViewEvent(this, false));
735 Main.removeProjectionChangeListener(layer);
736 layer.removePropertyChangeListener(this);
737 invalidatedListener.removeFrom(layer);
738 layer.destroy();
739 AudioPlayer.reset();
740
741 repaint();
742 }
743
744 private boolean virtualNodesEnabled;
745
746 public void setVirtualNodesEnabled(boolean enabled) {
747 if (virtualNodesEnabled != enabled) {
748 virtualNodesEnabled = enabled;
749 repaint();
750 }
751 }
752
753 /**
754 * Checks if virtual nodes should be drawn. Default is <code>false</code>
755 * @return The virtual nodes property.
756 * @see Rendering#render(DataSet, boolean, Bounds)
757 */
758 public boolean isVirtualNodesEnabled() {
759 return virtualNodesEnabled;
760 }
761
762 /**
763 * Moves the layer to the given new position. No event is fired, but repaints
764 * according to the new Z-Order of the layers.
765 *
766 * @param layer The layer to move
767 * @param pos The new position of the layer
768 */
769 public void moveLayer(Layer layer, int pos) {
770 layerManager.moveLayer(layer, pos);
771 }
772
773 @Override
774 public void layerOrderChanged(LayerOrderChangeEvent e) {
775 AudioPlayer.reset();
776 repaint();
777 }
778
779 /**
780 * Gets the index of the layer in the layer list.
781 * <p>
782 * To be removed: end of 2016.
783 * @param layer The layer to search for.
784 * @return The index in the list.
785 * @throws IllegalArgumentException if that layer does not belong to this view.
786 * @deprecated Access the layer list using {@link Main#getLayerManager()} instead.
787 */
788 @Deprecated
789 public int getLayerPos(Layer layer) {
790 int curLayerPos = layerManager.getLayers().indexOf(layer);
791 if (curLayerPos == -1)
792 throw new IllegalArgumentException(tr("Layer not in list."));
793 return curLayerPos;
794 }
795
796 /**
797 * Creates a list of the visible layers in Z-Order, the layer with the lowest Z-Order
798 * first, layer with the highest Z-Order last.
799 * <p>
800 * The active data layer is pulled above all adjacent data layers.
801 * <p>
802 * To be removed: end of 2016.
803 *
804 * @return a list of the visible in Z-Order, the layer with the lowest Z-Order
805 * first, layer with the highest Z-Order last.
806 * @deprecated Access the layer list using {@link Main#getLayerManager()} instead.
807 */
808 @Deprecated
809 public List<Layer> getVisibleLayersInZOrder() {
810 return layerManager.getVisibleLayersInZOrder();
811 }
812
813 private void paintLayer(Layer layer, Graphics2D g, Bounds box) {
814 try {
815 LayerPainter painter = registeredLayers.get(layer);
816 if (painter == null) {
817 throw new IllegalArgumentException("Cannot paint layer, it is not registered.");
818 }
819 MapViewRectangle clipBounds = getState().getViewArea(g.getClipBounds());
820 MapViewGraphics paintGraphics = new MapViewGraphics(this, g, clipBounds);
821
822 if (layer.getOpacity() < 1) {
823 g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, (float) layer.getOpacity()));
824 }
825 painter.paint(paintGraphics);
826 g.setPaintMode();
827 } catch (RuntimeException t) {
828 //TODO: only display.
829 throw BugReport.intercept(t).put("layer", layer).put("bounds", box);
830 }
831 }
832
833 /**
834 * Draw the component.
835 */
836 @Override
837 public void paint(Graphics g) {
838 if (!prepareToDraw()) {
839 return;
840 }
841
842 List<Layer> visibleLayers = layerManager.getVisibleLayersInZOrder();
843
844 int nonChangedLayersCount = 0;
845 for (Layer l: visibleLayers) {
846 if (l.isChanged() || l == changedLayer) {
847 break;
848 } else {
849 nonChangedLayersCount++;
850 }
851 }
852
853 boolean canUseBuffer;
854
855 synchronized (this) {
856 canUseBuffer = !paintPreferencesChanged;
857 paintPreferencesChanged = false;
858 }
859 canUseBuffer = canUseBuffer && nonChangedLayers.size() <= nonChangedLayersCount &&
860 lastViewID == getViewID() && lastClipBounds.contains(g.getClipBounds());
861 if (canUseBuffer) {
862 for (int i = 0; i < nonChangedLayers.size(); i++) {
863 if (visibleLayers.get(i) != nonChangedLayers.get(i)) {
864 canUseBuffer = false;
865 break;
866 }
867 }
868 }
869
870 if (null == offscreenBuffer || offscreenBuffer.getWidth() != getWidth() || offscreenBuffer.getHeight() != getHeight()) {
871 offscreenBuffer = new BufferedImage(getWidth(), getHeight(), BufferedImage.TYPE_3BYTE_BGR);
872 }
873
874 Graphics2D tempG = offscreenBuffer.createGraphics();
875 tempG.setClip(g.getClip());
876 Bounds box = getLatLonBounds(g.getClipBounds());
877
878 if (!canUseBuffer || nonChangedLayersBuffer == null) {
879 if (null == nonChangedLayersBuffer
880 || nonChangedLayersBuffer.getWidth() != getWidth() || nonChangedLayersBuffer.getHeight() != getHeight()) {
881 nonChangedLayersBuffer = new BufferedImage(getWidth(), getHeight(), BufferedImage.TYPE_3BYTE_BGR);
882 }
883 Graphics2D g2 = nonChangedLayersBuffer.createGraphics();
884 g2.setClip(g.getClip());
885 g2.setColor(PaintColors.getBackgroundColor());
886 g2.fillRect(0, 0, getWidth(), getHeight());
887
888 for (int i = 0; i < nonChangedLayersCount; i++) {
889 paintLayer(visibleLayers.get(i), g2, box);
890 }
891 } else {
892 // Maybe there were more unchanged layers then last time - draw them to buffer
893 if (nonChangedLayers.size() != nonChangedLayersCount) {
894 Graphics2D g2 = nonChangedLayersBuffer.createGraphics();
895 g2.setClip(g.getClip());
896 for (int i = nonChangedLayers.size(); i < nonChangedLayersCount; i++) {
897 paintLayer(visibleLayers.get(i), g2, box);
898 }
899 }
900 }
901
902 nonChangedLayers.clear();
903 changedLayer = null;
904 for (int i = 0; i < nonChangedLayersCount; i++) {
905 nonChangedLayers.add(visibleLayers.get(i));
906 }
907 lastViewID = getViewID();
908 lastClipBounds = g.getClipBounds();
909
910 tempG.drawImage(nonChangedLayersBuffer, 0, 0, null);
911
912 for (int i = nonChangedLayersCount; i < visibleLayers.size(); i++) {
913 paintLayer(visibleLayers.get(i), tempG, box);
914 }
915
916 synchronized (temporaryLayers) {
917 for (MapViewPaintable mvp : temporaryLayers) {
918 try {
919 mvp.paint(tempG, this, box);
920 } catch (RuntimeException e) {
921 throw BugReport.intercept(e).put("mvp", mvp);
922 }
923 }
924 }
925
926 // draw world borders
927 try {
928 drawWorldBorders(tempG);
929 } catch (RuntimeException e) {
930 throw BugReport.intercept(e).put("bounds", getProjection()::getWorldBoundsLatLon);
931 }
932
933 if (Main.isDisplayingMapView() && Main.map.filterDialog != null) {
934 Main.map.filterDialog.drawOSDText(tempG);
935 }
936
937 if (playHeadMarker != null) {
938 playHeadMarker.paint(tempG, this);
939 }
940
941 try {
942 g.drawImage(offscreenBuffer, 0, 0, null);
943 } catch (ClassCastException e) {
944 // See #11002 and duplicate tickets. On Linux with Java >= 8 Many users face this error here:
945 //
946 // java.lang.ClassCastException: sun.awt.image.BufImgSurfaceData cannot be cast to sun.java2d.xr.XRSurfaceData
947 // at sun.java2d.xr.XRPMBlitLoops.cacheToTmpSurface(XRPMBlitLoops.java:145)
948 // at sun.java2d.xr.XrSwToPMBlit.Blit(XRPMBlitLoops.java:353)
949 // at sun.java2d.pipe.DrawImage.blitSurfaceData(DrawImage.java:959)
950 // at sun.java2d.pipe.DrawImage.renderImageCopy(DrawImage.java:577)
951 // at sun.java2d.pipe.DrawImage.copyImage(DrawImage.java:67)
952 // at sun.java2d.pipe.DrawImage.copyImage(DrawImage.java:1014)
953 // at sun.java2d.pipe.ValidatePipe.copyImage(ValidatePipe.java:186)
954 // at sun.java2d.SunGraphics2D.drawImage(SunGraphics2D.java:3318)
955 // at sun.java2d.SunGraphics2D.drawImage(SunGraphics2D.java:3296)
956 // at org.openstreetmap.josm.gui.MapView.paint(MapView.java:834)
957 //
958 // It seems to be this JDK bug, but Oracle does not seem to be fixing it:
959 // https://bugs.openjdk.java.net/browse/JDK-7172749
960 //
961 // According to bug reports it can happen for a variety of reasons such as:
962 // - long period of time
963 // - change of screen resolution
964 // - addition/removal of a secondary monitor
965 //
966 // But the application seems to work fine after, so let's just log the error
967 Main.error(e);
968 }
969 super.paint(g);
970 }
971
972 private void drawWorldBorders(Graphics2D tempG) {
973 tempG.setColor(Color.WHITE);
974 Bounds b = getProjection().getWorldBoundsLatLon();
975 double lat = b.getMinLat();
976 double lon = b.getMinLon();
977
978 Point p = getPoint(b.getMin());
979
980 GeneralPath path = new GeneralPath();
981
982 double d = 1.0;
983 path.moveTo(p.x, p.y);
984 double max = b.getMax().lat();
985 for (; lat <= max; lat += d) {
986 p = getPoint(new LatLon(lat >= max ? max : lat, lon));
987 path.lineTo(p.x, p.y);
988 }
989 lat = max; max = b.getMax().lon();
990 for (; lon <= max; lon += d) {
991 p = getPoint(new LatLon(lat, lon >= max ? max : lon));
992 path.lineTo(p.x, p.y);
993 }
994 lon = max; max = b.getMinLat();
995 for (; lat >= max; lat -= d) {
996 p = getPoint(new LatLon(lat <= max ? max : lat, lon));
997 path.lineTo(p.x, p.y);
998 }
999 lat = max; max = b.getMinLon();
1000 for (; lon >= max; lon -= d) {
1001 p = getPoint(new LatLon(lat, lon <= max ? max : lon));
1002 path.lineTo(p.x, p.y);
1003 }
1004
1005 int w = getWidth();
1006 int h = getHeight();
1007
1008 // Work around OpenJDK having problems when drawing out of bounds
1009 final Area border = new Area(path);
1010 // Make the viewport 1px larger in every direction to prevent an
1011 // additional 1px border when zooming in
1012 final Area viewport = new Area(new Rectangle(-1, -1, w + 2, h + 2));
1013 border.intersect(viewport);
1014 tempG.draw(border);
1015 }
1016
1017 /**
1018 * Sets up the viewport to prepare for drawing the view.
1019 * @return <code>true</code> if the view can be drawn, <code>false</code> otherwise.
1020 */
1021 public boolean prepareToDraw() {
1022 updateLocationState();
1023 if (initialViewport != null) {
1024 zoomTo(initialViewport);
1025 initialViewport = null;
1026 }
1027 if (BugReportExceptionHandler.exceptionHandlingInProgress())
1028 return false;
1029
1030 if (getCenter() == null)
1031 return false; // no data loaded yet.
1032
1033 // if the position was remembered, we need to adjust center once before repainting
1034 if (oldLoc != null && oldSize != null) {
1035 Point l1 = getLocationOnScreen();
1036 final EastNorth newCenter = new EastNorth(
1037 getCenter().getX()+ (l1.x-oldLoc.x - (oldSize.width-getWidth())/2.0)*getScale(),
1038 getCenter().getY()+ (oldLoc.y-l1.y + (oldSize.height-getHeight())/2.0)*getScale()
1039 );
1040 oldLoc = null; oldSize = null;
1041 zoomTo(newCenter);
1042 }
1043
1044 return true;
1045 }
1046
1047 /**
1048 * Returns all layers. To be removed: end of 2016.
1049 *
1050 * @return An unmodifiable collection of all layers
1051 * @deprecated Use {@link LayerManager#getLayers()} instead.
1052 */
1053 @Deprecated
1054 public Collection<Layer> getAllLayers() {
1055 return layerManager.getLayers();
1056 }
1057
1058 /**
1059 * Returns all layers as list. To be removed: end of 2016.
1060 *
1061 * @return An unmodifiable ordered list of all layers
1062 * @deprecated Use {@link LayerManager#getLayers()} instead.
1063 */
1064 @Deprecated
1065 public List<Layer> getAllLayersAsList() {
1066 return layerManager.getLayers();
1067 }
1068
1069 /**
1070 * Replies an unmodifiable list of layers of a certain type. To be removed: end of 2016.
1071 *
1072 * Example:
1073 * <pre>
1074 * List&lt;WMSLayer&gt; wmsLayers = getLayersOfType(WMSLayer.class);
1075 * </pre>
1076 *
1077 * @param <T> layer type
1078 *
1079 * @param ofType The layer type.
1080 * @return an unmodifiable list of layers of a certain type.
1081 * @deprecated Use {@link LayerManager#getLayersOfType(Class)} instead.
1082 */
1083 @Deprecated
1084 public <T extends Layer> List<T> getLayersOfType(Class<T> ofType) {
1085 return layerManager.getLayersOfType(ofType);
1086 }
1087
1088 /**
1089 * Replies the number of layers managed by this map view. To be removed: end of 2016.
1090 * <p>
1091 *
1092 * @return the number of layers managed by this map view
1093 * @deprecated Use {@link Main#getLayerManager()}.getLayers().size() instead.
1094 */
1095 @Deprecated
1096 public int getNumLayers() {
1097 return getAllLayers().size();
1098 }
1099
1100 /**
1101 * Replies true if there is at least one layer in this map view
1102 * <p>
1103 *
1104 * @return true if there is at least one layer in this map view
1105 * @deprecated Use !{@link Main#getLayerManager()}.getLayers().isEmpty() instead.
1106 */
1107 @Deprecated
1108 public boolean hasLayers() {
1109 return getNumLayers() > 0;
1110 }
1111
1112 /**
1113 * Sets the active layer to <code>layer</code>. If <code>layer</code> is an instance
1114 * of {@link OsmDataLayer} also sets editLayer to <code>layer</code>.
1115 * <p>
1116 *
1117 * @param layer the layer to be activate; must be one of the layers in the list of layers
1118 * @throws IllegalArgumentException if layer is not in the list of layers
1119 * @deprecated Use !{@link Main#getLayerManager()}.setActiveLayer() instead.
1120 */
1121 @Deprecated
1122 public void setActiveLayer(Layer layer) {
1123 layerManager.setActiveLayer(layer);
1124 }
1125
1126 /**
1127 * Replies the currently active layer
1128 * <p>
1129 *
1130 * @return the currently active layer (may be null)
1131 * @deprecated Use !{@link Main#getLayerManager()}.getActiveLayer() instead.
1132 */
1133 @Deprecated
1134 public Layer getActiveLayer() {
1135 return layerManager.getActiveLayer();
1136 }
1137
1138 @Override
1139 public void activeOrEditLayerChanged(ActiveLayerChangeEvent e) {
1140 if (Main.map != null) {
1141 /* This only makes the buttons look disabled. Disabling the actions as well requires
1142 * the user to re-select the tool after i.e. moving a layer. While testing I found
1143 * that I switch layers and actions at the same time and it was annoying to mind the
1144 * order. This way it works as visual clue for new users */
1145 // FIXME: This does not belong here.
1146 for (final AbstractButton b: Main.map.allMapModeButtons) {
1147 MapMode mode = (MapMode) b.getAction();
1148 final boolean activeLayerSupported = mode.layerIsSupported(layerManager.getActiveLayer());
1149 if (activeLayerSupported) {
1150 Main.registerActionShortcut(mode, mode.getShortcut()); //fix #6876
1151 } else {
1152 Main.unregisterShortcut(mode.getShortcut());
1153 }
1154 b.setEnabled(activeLayerSupported);
1155 }
1156 }
1157 AudioPlayer.reset();
1158 repaint();
1159 }
1160
1161 /**
1162 * Replies the current edit layer, if any
1163 * <p>
1164 *
1165 * @return the current edit layer. May be null.
1166 * @deprecated Use !{@link Main#getLayerManager()}.getEditLayer() instead. To be made private: end of 2016.
1167 */
1168 @Deprecated
1169 public OsmDataLayer getEditLayer() {
1170 return layerManager.getEditLayer();
1171 }
1172
1173 /**
1174 * replies true if the list of layers managed by this map view contain layer
1175 * <p>
1176 *
1177 * @param layer the layer
1178 * @return true if the list of layers managed by this map view contain layer
1179 * @deprecated Use !{@link Main#getLayerManager()}.containsLayer() instead.
1180 */
1181 @Deprecated
1182 public boolean hasLayer(Layer layer) {
1183 return layerManager.containsLayer(layer);
1184 }
1185
1186 /**
1187 * Adds a new temporary layer.
1188 * <p>
1189 * A temporary layer is a layer that is painted above all normal layers. Layers are painted in the order they are added.
1190 *
1191 * @param mvp The layer to paint.
1192 * @return <code>true</code> if the layer was added.
1193 */
1194 public boolean addTemporaryLayer(MapViewPaintable mvp) {
1195 synchronized (temporaryLayers) {
1196 boolean added = temporaryLayers.add(mvp);
1197 if (added) {
1198 invalidatedListener.addTo(mvp);
1199 }
1200 return added;
1201 }
1202 }
1203
1204 /**
1205 * Removes a layer previously added as temporary layer.
1206 * @param mvp The layer to remove.
1207 * @return <code>true</code> if that layer was removed.
1208 */
1209 public boolean removeTemporaryLayer(MapViewPaintable mvp) {
1210 synchronized (temporaryLayers) {
1211 boolean removed = temporaryLayers.remove(mvp);
1212 if (removed) {
1213 invalidatedListener.removeFrom(mvp);
1214 }
1215 return removed;
1216 }
1217 }
1218
1219 /**
1220 * Gets a list of temporary layers.
1221 * @return The layers in the order they are added.
1222 */
1223 public List<MapViewPaintable> getTemporaryLayers() {
1224 synchronized (temporaryLayers) {
1225 return Collections.unmodifiableList(new ArrayList<>(temporaryLayers));
1226 }
1227 }
1228
1229 @Override
1230 public void propertyChange(PropertyChangeEvent evt) {
1231 if (evt.getPropertyName().equals(Layer.VISIBLE_PROP)) {
1232 repaint();
1233 } else if (evt.getPropertyName().equals(Layer.OPACITY_PROP) ||
1234 evt.getPropertyName().equals(Layer.FILTER_STATE_PROP)) {
1235 Layer l = (Layer) evt.getSource();
1236 if (l.isVisible()) {
1237 changedLayer = l;
1238 repaint();
1239 }
1240 }
1241 }
1242
1243 /**
1244 * Sets the title of the JOSM main window, adding a star if there are dirty layers.
1245 * @see Main#parent
1246 * @deprecated Replaced by {@link MainFrame#refreshTitle()}. The {@link MainFrame} should handle this by itself.
1247 */
1248 @Deprecated
1249 protected void refreshTitle() {
1250 if (Main.parent != null) {
1251 ((MainFrame) Main.parent).refreshTitle();
1252 }
1253 }
1254
1255 @Override
1256 public void preferenceChanged(PreferenceChangeEvent e) {
1257 synchronized (this) {
1258 paintPreferencesChanged = true;
1259 }
1260 }
1261
1262 private final transient SelectionChangedListener repaintSelectionChangedListener = newSelection -> repaint();
1263
1264 /**
1265 * Destroy this map view panel. Should be called once when it is not needed any more.
1266 */
1267 public void destroy() {
1268 layerManager.removeLayerChangeListener(this, true);
1269 layerManager.removeActiveLayerChangeListener(this);
1270 Main.pref.removePreferenceChangeListener(this);
1271 DataSet.removeSelectionListener(repaintSelectionChangedListener);
1272 MultipolygonCache.getInstance().clear(this);
1273 if (mapMover != null) {
1274 mapMover.destroy();
1275 }
1276 nonChangedLayers.clear();
1277 synchronized (temporaryLayers) {
1278 temporaryLayers.clear();
1279 }
1280 nonChangedLayersBuffer = null;
1281 }
1282
1283 /**
1284 * Get a string representation of all layers suitable for the {@code source} changeset tag.
1285 * @return A String of sources separated by ';'
1286 */
1287 public String getLayerInformationForSourceTag() {
1288 final Collection<String> layerInfo = new ArrayList<>();
1289 if (!getLayersOfType(GpxLayer.class).isEmpty()) {
1290 // no i18n for international values
1291 layerInfo.add("survey");
1292 }
1293 for (final GeoImageLayer i : getLayersOfType(GeoImageLayer.class)) {
1294 if (i.isVisible()) {
1295 layerInfo.add(i.getName());
1296 }
1297 }
1298 for (final ImageryLayer i : getLayersOfType(ImageryLayer.class)) {
1299 if (i.isVisible()) {
1300 layerInfo.add(ImageryInfo.ImageryType.BING.equals(i.getInfo().getImageryType()) ? "Bing" : i.getName());
1301 }
1302 }
1303 return Utils.join("; ", layerInfo);
1304 }
1305
1306 /**
1307 * This is a listener that gets informed whenever repaint is called for this MapView.
1308 * <p>
1309 * This is the only safe method to find changes to the map view, since many components call MapView.repaint() directly.
1310 * @author Michael Zangl
1311 * @since 10600 (functional interface)
1312 */
1313 @FunctionalInterface
1314 public interface RepaintListener {
1315 /**
1316 * Called when any repaint method is called (using default arguments if required).
1317 * @param tm see {@link JComponent#repaint(long, int, int, int, int)}
1318 * @param x see {@link JComponent#repaint(long, int, int, int, int)}
1319 * @param y see {@link JComponent#repaint(long, int, int, int, int)}
1320 * @param width see {@link JComponent#repaint(long, int, int, int, int)}
1321 * @param height see {@link JComponent#repaint(long, int, int, int, int)}
1322 */
1323 void repaint(long tm, int x, int y, int width, int height);
1324 }
1325
1326 private final transient CopyOnWriteArrayList<RepaintListener> repaintListeners = new CopyOnWriteArrayList<>();
1327
1328 /**
1329 * Adds a listener that gets informed whenever repaint() is called for this class.
1330 * @param l The listener.
1331 */
1332 public void addRepaintListener(RepaintListener l) {
1333 repaintListeners.add(l);
1334 }
1335
1336 /**
1337 * Removes a registered repaint listener.
1338 * @param l The listener.
1339 */
1340 public void removeRepaintListener(RepaintListener l) {
1341 repaintListeners.remove(l);
1342 }
1343
1344 @Override
1345 public void repaint(long tm, int x, int y, int width, int height) {
1346 // This is the main repaint method, all other methods are convenience methods and simply call this method.
1347 // This is just an observation, not a must, but seems to be true for all implementations I found so far.
1348 if (repaintListeners != null) {
1349 // Might get called early in super constructor
1350 for (RepaintListener l : repaintListeners) {
1351 l.repaint(tm, x, y, width, height);
1352 }
1353 }
1354 super.repaint(tm, x, y, width, height);
1355 }
1356
1357 @Override
1358 public void repaint() {
1359 if (Main.isTraceEnabled()) {
1360 invalidatedListener.traceRandomRepaint();
1361 }
1362 super.repaint();
1363 }
1364
1365 /**
1366 * Returns the layer manager.
1367 * @return the layer manager
1368 * @since 10282
1369 */
1370 public final MainLayerManager getLayerManager() {
1371 return layerManager;
1372 }
1373
1374 /**
1375 * Schedule a zoom to the given position on the next redraw.
1376 * Temporary, may be removed without warning.
1377 * @param viewportData the viewport to zoom to
1378 * @since 10394
1379 */
1380 public void scheduleZoomTo(ViewportData viewportData) {
1381 initialViewport = viewportData;
1382 }
1383}
Note: See TracBrowser for help on using the repository browser.