// License: GPL. For details, see LICENSE file.
package org.openstreetmap.josm.gui;
import static org.openstreetmap.josm.tools.I18n.tr;
import java.awt.AlphaComposite;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.awt.event.KeyEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionListener;
import java.awt.geom.Area;
import java.awt.geom.GeneralPath;
import java.awt.image.BufferedImage;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
import java.util.TreeSet;
import java.util.concurrent.CopyOnWriteArrayList;
import javax.swing.AbstractButton;
import javax.swing.JComponent;
import javax.swing.JPanel;
import org.openstreetmap.josm.Main;
import org.openstreetmap.josm.actions.mapmode.MapMode;
import org.openstreetmap.josm.data.Bounds;
import org.openstreetmap.josm.data.Preferences.PreferenceChangeEvent;
import org.openstreetmap.josm.data.Preferences.PreferenceChangedListener;
import org.openstreetmap.josm.data.ProjectionBounds;
import org.openstreetmap.josm.data.SelectionChangedListener;
import org.openstreetmap.josm.data.ViewportData;
import org.openstreetmap.josm.data.coor.EastNorth;
import org.openstreetmap.josm.data.coor.LatLon;
import org.openstreetmap.josm.data.imagery.ImageryInfo;
import org.openstreetmap.josm.data.osm.DataSet;
import org.openstreetmap.josm.data.osm.visitor.paint.PaintColors;
import org.openstreetmap.josm.data.osm.visitor.paint.Rendering;
import org.openstreetmap.josm.data.osm.visitor.paint.relations.MultipolygonCache;
import org.openstreetmap.josm.gui.MapViewState.MapViewRectangle;
import org.openstreetmap.josm.gui.datatransfer.OsmTransferHandler;
import org.openstreetmap.josm.gui.layer.AbstractMapViewPaintable;
import org.openstreetmap.josm.gui.layer.GpxLayer;
import org.openstreetmap.josm.gui.layer.ImageryLayer;
import org.openstreetmap.josm.gui.layer.Layer;
import org.openstreetmap.josm.gui.layer.LayerManager;
import org.openstreetmap.josm.gui.layer.LayerManager.LayerAddEvent;
import org.openstreetmap.josm.gui.layer.LayerManager.LayerOrderChangeEvent;
import org.openstreetmap.josm.gui.layer.LayerManager.LayerRemoveEvent;
import org.openstreetmap.josm.gui.layer.MainLayerManager;
import org.openstreetmap.josm.gui.layer.MainLayerManager.ActiveLayerChangeEvent;
import org.openstreetmap.josm.gui.layer.MainLayerManager.ActiveLayerChangeListener;
import org.openstreetmap.josm.gui.layer.MapViewGraphics;
import org.openstreetmap.josm.gui.layer.MapViewPaintable;
import org.openstreetmap.josm.gui.layer.MapViewPaintable.LayerPainter;
import org.openstreetmap.josm.gui.layer.MapViewPaintable.MapViewEvent;
import org.openstreetmap.josm.gui.layer.MapViewPaintable.PaintableInvalidationEvent;
import org.openstreetmap.josm.gui.layer.MapViewPaintable.PaintableInvalidationListener;
import org.openstreetmap.josm.gui.layer.OsmDataLayer;
import org.openstreetmap.josm.gui.layer.geoimage.GeoImageLayer;
import org.openstreetmap.josm.gui.layer.markerlayer.PlayHeadMarker;
import org.openstreetmap.josm.tools.AudioPlayer;
import org.openstreetmap.josm.tools.Shortcut;
import org.openstreetmap.josm.tools.Utils;
import org.openstreetmap.josm.tools.bugreport.BugReport;
import org.openstreetmap.josm.tools.bugreport.BugReportExceptionHandler;
/**
* This is a component used in the {@link MapFrame} for browsing the map. It use is to
* provide the MapMode's enough capabilities to operate.
*
* {@code MapView} holds meta-data about the data set currently displayed, as scale level,
* center point viewed, what scrolling mode or editing mode is selected or with
* what projection the map is viewed etc..
*
* {@code MapView} is able to administrate several layers.
*
* @author imi
*/
public class MapView extends NavigatableComponent
implements PropertyChangeListener, PreferenceChangedListener,
LayerManager.LayerChangeListener, MainLayerManager.ActiveLayerChangeListener {
/**
* Interface to notify listeners of a layer change.
*
* To be removed: end of 2016. * @deprecated Use {@link org.openstreetmap.josm.gui.layer.LayerManager.LayerChangeListener} instead. * @author imi */ @Deprecated public interface LayerChangeListener { /** * Notifies this listener that the active layer has changed. * @param oldLayer The previous active layer * @param newLayer The new activer layer */ void activeLayerChange(Layer oldLayer, Layer newLayer); /** * Notifies this listener that a layer has been added. * @param newLayer The new added layer */ void layerAdded(Layer newLayer); /** * Notifies this listener that a layer has been removed. * @param oldLayer The old removed layer */ void layerRemoved(Layer oldLayer); } /** * An interface that needs to be implemented in order to listen for changes to the active edit layer. *
* To be removed: end of 2016. * @deprecated Use {@link ActiveLayerChangeListener} instead. */ @Deprecated @FunctionalInterface public interface EditLayerChangeListener { /** * Called after the active edit layer was changed. * @param oldLayer The old edit layer * @param newLayer The current (new) edit layer */ void editLayerChanged(OsmDataLayer oldLayer, OsmDataLayer newLayer); } /** * An invalidation listener that simply calls repaint() for now. * @author Michael Zangl * @since 10271 */ private class LayerInvalidatedListener implements PaintableInvalidationListener { private boolean ignoreRepaint; @Override public void paintableInvalidated(PaintableInvalidationEvent event) { ignoreRepaint = true; repaint(); } /** * Temporary until all {@link MapViewPaintable}s support this. * @param p The paintable. */ public void addTo(MapViewPaintable p) { if (p instanceof AbstractMapViewPaintable) { ((AbstractMapViewPaintable) p).addInvalidationListener(this); } } /** * Temporary until all {@link MapViewPaintable}s support this. * @param p The paintable. */ public void removeFrom(MapViewPaintable p) { if (p instanceof AbstractMapViewPaintable) { ((AbstractMapViewPaintable) p).removeInvalidationListener(this); } } /** * Attempts to trace repaints that did not originate from this listener. Good to find missed {@link MapView#repaint()}s in code. */ protected synchronized void traceRandomRepaint() { if (!ignoreRepaint) { System.err.println("Repaint:"); Thread.dumpStack(); } ignoreRepaint = false; } } /** * This class is an adapter for the old layer change interface. * @author Michael Zangl * @since 10271 * @deprecated New implementations should use {@link org.openstreetmap.josm.gui.layer.LayerManager.LayerChangeListener} */ @Deprecated protected static class LayerChangeAdapter implements ActiveLayerChangeListener, LayerManager.LayerChangeListener { private final LayerChangeListener wrapped; private boolean receiveOneInitialFire; public LayerChangeAdapter(LayerChangeListener wrapped) { this.wrapped = wrapped; } public LayerChangeAdapter(LayerChangeListener wrapped, boolean initialFire) { this(wrapped); this.receiveOneInitialFire = initialFire; } @Override public void layerAdded(LayerAddEvent e) { wrapped.layerAdded(e.getAddedLayer()); } @Override public void layerRemoving(LayerRemoveEvent e) { wrapped.layerRemoved(e.getRemovedLayer()); } @Override public void layerOrderChanged(LayerOrderChangeEvent e) { // not in old API } @Override public void activeOrEditLayerChanged(ActiveLayerChangeEvent e) { Layer oldActive = receiveOneInitialFire ? null : e.getPreviousActiveLayer(); Layer newActive = e.getSource().getActiveLayer(); if (oldActive != newActive) { wrapped.activeLayerChange(oldActive, newActive); } receiveOneInitialFire = false; } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + ((wrapped == null) ? 0 : wrapped.hashCode()); return result; } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; LayerChangeAdapter other = (LayerChangeAdapter) obj; if (wrapped == null) { if (other.wrapped != null) return false; } else if (!wrapped.equals(other.wrapped)) return false; return true; } @Override public String toString() { return "LayerChangeAdapter [wrapped=" + wrapped + ']'; } } /** * This class is an adapter for the old layer change interface. * @author Michael Zangl * @since 10271 * @deprecated New implementations should use {@link org.openstreetmap.josm.gui.layer.MainLayerManager.ActiveLayerChangeListener} */ @Deprecated protected static class EditLayerChangeAdapter implements ActiveLayerChangeListener { private final EditLayerChangeListener wrapped; public EditLayerChangeAdapter(EditLayerChangeListener wrapped) { this.wrapped = wrapped; } @Override public void activeOrEditLayerChanged(ActiveLayerChangeEvent e) { OsmDataLayer oldLayer = e.getPreviousEditLayer(); OsmDataLayer newLayer = e.getSource().getEditLayer(); if (oldLayer != newLayer) { wrapped.editLayerChanged(oldLayer, newLayer); } } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + ((wrapped == null) ? 0 : wrapped.hashCode()); return result; } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; EditLayerChangeAdapter other = (EditLayerChangeAdapter) obj; if (wrapped == null) { if (other.wrapped != null) return false; } else if (!wrapped.equals(other.wrapped)) return false; return true; } @Override public String toString() { return "EditLayerChangeAdapter [wrapped=" + wrapped + ']'; } } /** * A layer painter that issues a warning when being called. * @author Michael Zangl * @since 10474 */ private static class WarningLayerPainter implements LayerPainter { boolean warningPrinted; private final Layer layer; WarningLayerPainter(Layer layer) { this.layer = layer; } @Override public void paint(MapViewGraphics graphics) { if (!warningPrinted) { Main.debug("A layer triggered a repaint while being added: " + layer); warningPrinted = true; } } @Override public void detachFromMapView(MapViewEvent event) { // ignored } } /** * Removes a layer change listener *
* To be removed: end of 2016. * * @param listener the listener. Ignored if null or not registered. * @deprecated You should register the listener on {@link Main#getLayerManager()} instead. */ @Deprecated public static void removeLayerChangeListener(LayerChangeListener listener) { LayerChangeAdapter adapter = new LayerChangeAdapter(listener); try { Main.getLayerManager().removeLayerChangeListener(adapter); } catch (IllegalArgumentException e) { // Ignored in old implementation Main.debug(e); } try { Main.getLayerManager().removeActiveLayerChangeListener(adapter); } catch (IllegalArgumentException e) { // Ignored in old implementation Main.debug(e); } } /** * Removes an edit layer change listener *
* To be removed: end of 2016. * * @param listener the listener. Ignored if null or not registered. * @deprecated You should register the listener on {@link Main#getLayerManager()} instead. */ @Deprecated public static void removeEditLayerChangeListener(EditLayerChangeListener listener) { try { Main.getLayerManager().removeActiveLayerChangeListener(new EditLayerChangeAdapter(listener)); } catch (IllegalArgumentException e) { // Ignored in old implementation Main.debug(e); } } /** * Adds a layer change listener *
* To be removed: end of 2016. * * @param listener the listener. Ignored if null or already registered. * @deprecated You should register the listener on {@link Main#getLayerManager()} instead. */ @Deprecated public static void addLayerChangeListener(LayerChangeListener listener) { if (fireDeprecatedListenerOnAdd) { Main.warn("Plugin seems to be adding listener during mapFrameInitialized(): " + BugReport.getCallingMethod(2) + ". Layer listeners should be set on plugin load."); } addLayerChangeListener(listener, fireDeprecatedListenerOnAdd); } /** * Adds a layer change listener *
* To be removed: end of 2016. * * @param listener the listener. Ignored if null or already registered. * @param initialFire fire an active-layer-changed-event right after adding * the listener in case there is a layer present (should be) * @deprecated You should register the listener on {@link Main#getLayerManager()} instead. */ @Deprecated public static void addLayerChangeListener(LayerChangeListener listener, boolean initialFire) { if (listener != null) { initialFire = initialFire && (Main.isDisplayingMapView() || fireDeprecatedListenerOnAdd); LayerChangeAdapter adapter = new LayerChangeAdapter(listener, initialFire); Main.getLayerManager().addLayerChangeListener(adapter, initialFire); if (initialFire) { Main.getLayerManager().addAndFireActiveLayerChangeListener(adapter); } else { Main.getLayerManager().addActiveLayerChangeListener(adapter); } adapter.receiveOneInitialFire = false; } } /** * Adds an edit layer change listener *
* To be removed: end of 2016. * * @param listener the listener. Ignored if null or already registered. * @param initialFire fire an edit-layer-changed-event right after adding * the listener in case there is an edit layer present * @deprecated You should register the listener on {@link Main#getLayerManager()} instead. */ @Deprecated public static void addEditLayerChangeListener(EditLayerChangeListener listener, boolean initialFire) { if (listener != null) { boolean doFire = initialFire && Main.isDisplayingMapView() && Main.getLayerManager().getEditLayer() != null; if (doFire) { Main.getLayerManager().addAndFireActiveLayerChangeListener(new EditLayerChangeAdapter(listener)); } else { Main.getLayerManager().addActiveLayerChangeListener(new EditLayerChangeAdapter(listener)); } } } /** * Adds an edit layer change listener *
* To be removed: end of 2016. * * @param listener the listener. Ignored if null or already registered. * @deprecated You should register the listener on {@link Main#getLayerManager()} instead. */ @Deprecated public static void addEditLayerChangeListener(EditLayerChangeListener listener) { addEditLayerChangeListener(listener, false); } /** * Temporary. To be removed as soon as the {@link LayerChangeListener}s are removed. *
* Some plugins add their listeners in {@link Main#setMapFrame(MapFrame)}. This method is now called just after the first layer was added to
* 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
* to that listener when it is added to immitate the old behaviour. You should not access it from anywhere else.
*/
public static boolean fireDeprecatedListenerOnAdd;
public boolean viewportFollowing;
/**
* A list of all layers currently loaded. If we support multiple map views, this list may be different for each of them.
*/
private final MainLayerManager layerManager;
/**
* The play head marker: there is only one of these so it isn't in any specific layer
*/
public transient PlayHeadMarker playHeadMarker;
/**
* The last event performed by mouse.
*/
public MouseEvent lastMEvent = new MouseEvent(this, 0, 0, 0, 0, 0, 0, false); // In case somebody reads it before first mouse move
/**
* Temporary layers (selection rectangle, etc.) that are never cached and
* drawn on top of regular layers.
* Access must be synchronized.
*/
private final transient Set
* To be removed: end of 2016.
* @param layer The layer to add
* @deprecated Use {@link Main#getLayerManager()}.addLayer() instead.
*/
@Deprecated
public void addLayer(Layer layer) {
layerManager.addLayer(layer);
}
@Override
public void layerAdded(LayerAddEvent e) {
try {
Layer layer = e.getAddedLayer();
registeredLayers.put(layer, new WarningLayerPainter(layer));
// Layers may trigger a redraw during this call if they open dialogs.
LayerPainter painter = layer.attachToMapView(new MapViewEvent(this, false));
if (!registeredLayers.containsKey(layer)) {
// The layer may have removed itself during attachToMapView()
Main.warn("Layer was removed during attachToMapView()");
} else {
registeredLayers.put(layer, painter);
ProjectionBounds viewProjectionBounds = layer.getViewProjectionBounds();
if (viewProjectionBounds != null) {
scheduleZoomTo(new ViewportData(viewProjectionBounds));
}
layer.addPropertyChangeListener(this);
Main.addProjectionChangeListener(layer);
invalidatedListener.addTo(layer);
AudioPlayer.reset();
repaint();
}
} catch (RuntimeException t) {
throw BugReport.intercept(t).put("layer", e.getAddedLayer());
}
}
/**
* Returns current data set. To be removed: end of 2016.
* @deprecated Use {@link #getLayerManager()}.getEditDataSet() instead.
*/
@Override
@Deprecated
protected DataSet getCurrentDataSet() {
return layerManager.getEditDataSet();
}
/**
* Replies true if the active data layer (edit layer) is drawable.
*
* @return true if the active data layer (edit layer) is drawable, false otherwise
*/
public boolean isActiveLayerDrawable() {
return layerManager.getEditLayer() != null;
}
/**
* Replies true if the active data layer (edit layer) is visible.
*
* @return true if the active data layer (edit layer) is visible, false otherwise
*/
public boolean isActiveLayerVisible() {
OsmDataLayer e = layerManager.getEditLayer();
return e != null && e.isVisible();
}
/**
* Determines the next active data layer according to the following rules:
*
* To be removed: end of 2016.
* @param layer The layer to remove
* @deprecated Use {@link Main#getLayerManager()}.removeLayer() instead.
*/
@Deprecated
public void removeLayer(Layer layer) {
layerManager.removeLayer(layer);
}
@Override
public void layerRemoving(LayerRemoveEvent e) {
Layer layer = e.getRemovedLayer();
LayerPainter painter = registeredLayers.remove(layer);
if (painter == null) {
Main.error("The painter for layer " + layer + " was not registered.");
return;
}
painter.detachFromMapView(new MapViewEvent(this, false));
Main.removeProjectionChangeListener(layer);
layer.removePropertyChangeListener(this);
invalidatedListener.removeFrom(layer);
layer.destroy();
AudioPlayer.reset();
repaint();
}
private boolean virtualNodesEnabled;
public void setVirtualNodesEnabled(boolean enabled) {
if (virtualNodesEnabled != enabled) {
virtualNodesEnabled = enabled;
repaint();
}
}
/**
* Checks if virtual nodes should be drawn. Default is
* To be removed: end of 2016.
* @param layer The layer to search for.
* @return The index in the list.
* @throws IllegalArgumentException if that layer does not belong to this view.
* @deprecated Access the layer list using {@link Main#getLayerManager()} instead.
*/
@Deprecated
public int getLayerPos(Layer layer) {
int curLayerPos = layerManager.getLayers().indexOf(layer);
if (curLayerPos == -1)
throw new IllegalArgumentException(tr("Layer not in list."));
return curLayerPos;
}
/**
* Creates a list of the visible layers in Z-Order, the layer with the lowest Z-Order
* first, layer with the highest Z-Order last.
*
* The active data layer is pulled above all adjacent data layers.
*
* To be removed: end of 2016.
*
* @return a list of the visible in Z-Order, the layer with the lowest Z-Order
* first, layer with the highest Z-Order last.
* @deprecated Access the layer list using {@link Main#getLayerManager()} instead.
*/
@Deprecated
public List
*
* @return the number of layers managed by this map view
* @deprecated Use {@link Main#getLayerManager()}.getLayers().size() instead.
*/
@Deprecated
public int getNumLayers() {
return getAllLayers().size();
}
/**
* Replies true if there is at least one layer in this map view
*
*
* @return true if there is at least one layer in this map view
* @deprecated Use !{@link Main#getLayerManager()}.getLayers().isEmpty() instead.
*/
@Deprecated
public boolean hasLayers() {
return getNumLayers() > 0;
}
/**
* Sets the active layer to
*
* @param layer the layer to be activate; must be one of the layers in the list of layers
* @throws IllegalArgumentException if layer is not in the list of layers
* @deprecated Use !{@link Main#getLayerManager()}.setActiveLayer() instead.
*/
@Deprecated
public void setActiveLayer(Layer layer) {
layerManager.setActiveLayer(layer);
}
/**
* Replies the currently active layer
*
*
* @return the currently active layer (may be null)
* @deprecated Use !{@link Main#getLayerManager()}.getActiveLayer() instead.
*/
@Deprecated
public Layer getActiveLayer() {
return layerManager.getActiveLayer();
}
@Override
public void activeOrEditLayerChanged(ActiveLayerChangeEvent e) {
if (Main.map != null) {
/* This only makes the buttons look disabled. Disabling the actions as well requires
* the user to re-select the tool after i.e. moving a layer. While testing I found
* that I switch layers and actions at the same time and it was annoying to mind the
* order. This way it works as visual clue for new users */
// FIXME: This does not belong here.
for (final AbstractButton b: Main.map.allMapModeButtons) {
MapMode mode = (MapMode) b.getAction();
final boolean activeLayerSupported = mode.layerIsSupported(layerManager.getActiveLayer());
if (activeLayerSupported) {
Main.registerActionShortcut(mode, mode.getShortcut()); //fix #6876
} else {
Main.unregisterShortcut(mode.getShortcut());
}
b.setEnabled(activeLayerSupported);
}
}
AudioPlayer.reset();
repaint();
}
/**
* Replies the current edit layer, if any
*
*
* @return the current edit layer. May be null.
* @deprecated Use !{@link Main#getLayerManager()}.getEditLayer() instead. To be made private: end of 2016.
*/
@Deprecated
public OsmDataLayer getEditLayer() {
return layerManager.getEditLayer();
}
/**
* replies true if the list of layers managed by this map view contain layer
*
*
* @param layer the layer
* @return true if the list of layers managed by this map view contain layer
* @deprecated Use !{@link Main#getLayerManager()}.containsLayer() instead.
*/
@Deprecated
public boolean hasLayer(Layer layer) {
return layerManager.containsLayer(layer);
}
/**
* Adds a new temporary layer.
*
* A temporary layer is a layer that is painted above all normal layers. Layers are painted in the order they are added.
*
* @param mvp The layer to paint.
* @return
* This is the only safe method to find changes to the map view, since many components call MapView.repaint() directly.
* @author Michael Zangl
* @since 10600 (functional interface)
*/
@FunctionalInterface
public interface RepaintListener {
/**
* Called when any repaint method is called (using default arguments if required).
* @param tm see {@link JComponent#repaint(long, int, int, int, int)}
* @param x see {@link JComponent#repaint(long, int, int, int, int)}
* @param y see {@link JComponent#repaint(long, int, int, int, int)}
* @param width see {@link JComponent#repaint(long, int, int, int, int)}
* @param height see {@link JComponent#repaint(long, int, int, int, int)}
*/
void repaint(long tm, int x, int y, int width, int height);
}
private final transient CopyOnWriteArrayList
*
* To be removed: end of 2016.
* @param layersList lit of layers
*
* @return the next active data layer
* @deprecated now handled by {@link MainLayerManager}
*/
@Deprecated
protected Layer determineNextActiveLayer(Listfalse
* @return The virtual nodes property.
* @see Rendering#render(DataSet, boolean, Bounds)
*/
public boolean isVirtualNodesEnabled() {
return virtualNodesEnabled;
}
/**
* Moves the layer to the given new position. No event is fired, but repaints
* according to the new Z-Order of the layers.
*
* @param layer The layer to move
* @param pos The new position of the layer
*/
public void moveLayer(Layer layer, int pos) {
layerManager.moveLayer(layer, pos);
}
@Override
public void layerOrderChanged(LayerOrderChangeEvent e) {
AudioPlayer.reset();
repaint();
}
/**
* Gets the index of the layer in the layer list.
* true
if the view can be drawn, false
otherwise.
*/
public boolean prepareToDraw() {
updateLocationState();
if (initialViewport != null) {
zoomTo(initialViewport);
initialViewport = null;
}
if (BugReportExceptionHandler.exceptionHandlingInProgress())
return false;
if (getCenter() == null)
return false; // no data loaded yet.
// if the position was remembered, we need to adjust center once before repainting
if (oldLoc != null && oldSize != null) {
Point l1 = getLocationOnScreen();
final EastNorth newCenter = new EastNorth(
getCenter().getX()+ (l1.x-oldLoc.x - (oldSize.width-getWidth())/2.0)*getScale(),
getCenter().getY()+ (oldLoc.y-l1.y + (oldSize.height-getHeight())/2.0)*getScale()
);
oldLoc = null; oldSize = null;
zoomTo(newCenter);
}
return true;
}
/**
* Returns all layers. To be removed: end of 2016.
*
* @return An unmodifiable collection of all layers
* @deprecated Use {@link LayerManager#getLayers()} instead.
*/
@Deprecated
public Collection
* List<WMSLayer> wmsLayers = getLayersOfType(WMSLayer.class);
*
*
* @param layer
. If layer
is an instance
* of {@link OsmDataLayer} also sets editLayer to layer
.
* true
if the layer was added.
*/
public boolean addTemporaryLayer(MapViewPaintable mvp) {
synchronized (temporaryLayers) {
boolean added = temporaryLayers.add(mvp);
if (added) {
invalidatedListener.addTo(mvp);
}
return added;
}
}
/**
* Removes a layer previously added as temporary layer.
* @param mvp The layer to remove.
* @return true
if that layer was removed.
*/
public boolean removeTemporaryLayer(MapViewPaintable mvp) {
synchronized (temporaryLayers) {
boolean removed = temporaryLayers.remove(mvp);
if (removed) {
invalidatedListener.removeFrom(mvp);
}
return removed;
}
}
/**
* Gets a list of temporary layers.
* @return The layers in the order they are added.
*/
public List