Index: trunk/src/org/openstreetmap/josm/Main.java
===================================================================
--- trunk/src/org/openstreetmap/josm/Main.java	(revision 10268)
+++ trunk/src/org/openstreetmap/josm/Main.java	(revision 10271)
@@ -87,5 +87,4 @@
 import org.openstreetmap.josm.gui.MapFrame;
 import org.openstreetmap.josm.gui.MapFrameListener;
-import org.openstreetmap.josm.gui.MapView;
 import org.openstreetmap.josm.gui.dialogs.LayerListDialog;
 import org.openstreetmap.josm.gui.help.HelpUtil;
@@ -93,4 +92,5 @@
 import org.openstreetmap.josm.gui.layer.AbstractModifiableLayer;
 import org.openstreetmap.josm.gui.layer.Layer;
+import org.openstreetmap.josm.gui.layer.LayerManagerWithActive;
 import org.openstreetmap.josm.gui.layer.OsmDataLayer;
 import org.openstreetmap.josm.gui.layer.OsmDataLayer.CommandQueueListener;
@@ -190,6 +190,14 @@
     /**
      * The MapFrame. Use {@link Main#setMapFrame} to set or clear it.
+     * <p>
+     * There should be no need to access this to access any map data. Use {@link #layerManager} instead.
      */
     public static MapFrame map;
+
+    /**
+     * Provides access to the layers displayed in the main view.
+     * @since 10271
+     */
+    private static final LayerManagerWithActive layerManager = new LayerManagerWithActive();
 
     /**
@@ -531,6 +539,6 @@
     public final synchronized void removeLayer(final Layer layer) {
         if (map != null) {
-            map.mapView.removeLayer(layer);
-            if (isDisplayingMapView() && map.mapView.getAllLayers().isEmpty()) {
+            getLayerManager().removeLayer(layer);
+            if (isDisplayingMapView() && getLayerManager().getLayers().isEmpty()) {
                 setMapFrame(null);
             }
@@ -608,5 +616,5 @@
             public void initialize() {
                 validator = new OsmValidator();
-                MapView.addLayerChangeListener(validator);
+                getLayerManager().addLayerChangeListener(validator);
             }
         });
@@ -730,4 +738,13 @@
 
     /**
+     * Returns the main layer manager that is used by the map view.
+     * @return The layer manager. The value returned will never change.
+     * @since 10271
+     */
+    public static LayerManagerWithActive getLayerManager() {
+        return layerManager;
+    }
+
+    /**
      * Add a new layer to the map.
      *
@@ -773,5 +790,5 @@
         }
         layer.hookUpMapView();
-        map.mapView.addLayer(layer);
+        getLayerManager().addLayer(layer);
         if (noMap) {
             Main.map.setVisible(true);
@@ -813,5 +830,5 @@
     public OsmDataLayer getEditLayer() {
         if (!isDisplayingMapView()) return null;
-        return map.mapView.getEditLayer();
+        return getLayerManager().getEditLayer();
     }
 
@@ -852,5 +869,5 @@
     public Layer getActiveLayer() {
         if (!isDisplayingMapView()) return null;
-        return map.mapView.getActiveLayer();
+        return getLayerManager().getActiveLayer();
     }
 
@@ -1033,5 +1050,5 @@
     public static boolean saveUnsavedModifications() {
         if (!isDisplayingMapView()) return true;
-        return saveUnsavedModifications(map.mapView.getLayersOfType(AbstractModifiableLayer.class), true);
+        return saveUnsavedModifications(getLayerManager().getLayersOfType(AbstractModifiableLayer.class), true);
     }
 
@@ -1100,5 +1117,5 @@
             // Remove all layers because somebody may rely on layerRemoved events (like AutosaveTask)
             if (Main.isDisplayingMapView()) {
-                Collection<Layer> layers = new ArrayList<>(Main.map.mapView.getAllLayers());
+                Collection<Layer> layers = new ArrayList<>(getLayerManager().getLayers());
                 for (Layer l: layers) {
                     Main.main.removeLayer(l);
Index: trunk/src/org/openstreetmap/josm/data/validation/OsmValidator.java
===================================================================
--- trunk/src/org/openstreetmap/josm/data/validation/OsmValidator.java	(revision 10268)
+++ trunk/src/org/openstreetmap/josm/data/validation/OsmValidator.java	(revision 10271)
@@ -59,6 +59,8 @@
 import org.openstreetmap.josm.data.validation.tests.WayConnectedToArea;
 import org.openstreetmap.josm.data.validation.tests.WronglyOrderedWays;
-import org.openstreetmap.josm.gui.MapView.LayerChangeListener;
-import org.openstreetmap.josm.gui.layer.Layer;
+import org.openstreetmap.josm.gui.layer.LayerManager.LayerAddEvent;
+import org.openstreetmap.josm.gui.layer.LayerManager.LayerChangeListener;
+import org.openstreetmap.josm.gui.layer.LayerManager.LayerOrderChangeEvent;
+import org.openstreetmap.josm.gui.layer.LayerManager.LayerRemoveEvent;
 import org.openstreetmap.josm.gui.layer.OsmDataLayer;
 import org.openstreetmap.josm.gui.layer.ValidatorLayer;
@@ -339,20 +341,20 @@
     /* -------------------------------------------------------------------------- */
     @Override
-    public void activeLayerChange(Layer oldLayer, Layer newLayer) {
-        // Do nothing
+    public void layerAdded(LayerAddEvent e) {
+        // do nothing
     }
 
     @Override
-    public void layerAdded(Layer newLayer) {
-        // Do nothing
+    public void layerOrderChanged(LayerOrderChangeEvent e) {
+        // do nothing
     }
 
     @Override
-    public void layerRemoved(Layer oldLayer) {
-        if (oldLayer == errorLayer) {
+    public void layerRemoving(LayerRemoveEvent e) {
+        if (e.getRemovedLayer() == errorLayer) {
             errorLayer = null;
             return;
         }
-        if (Main.map.mapView.getLayersOfType(OsmDataLayer.class).isEmpty()) {
+        if (e.getSource().getLayersOfType(OsmDataLayer.class).isEmpty()) {
             if (errorLayer != null) {
                 Main.main.removeLayer(errorLayer);
Index: trunk/src/org/openstreetmap/josm/gui/MapFrame.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/MapFrame.java	(revision 10268)
+++ trunk/src/org/openstreetmap/josm/gui/MapFrame.java	(revision 10271)
@@ -76,4 +76,5 @@
 import org.openstreetmap.josm.gui.dialogs.properties.PropertiesDialog;
 import org.openstreetmap.josm.gui.layer.Layer;
+import org.openstreetmap.josm.gui.layer.LayerManager;
 import org.openstreetmap.josm.gui.util.AdvancedKeyPressDetector;
 import org.openstreetmap.josm.tools.Destroyable;
@@ -98,4 +99,6 @@
     /**
      * The view control displayed.
+     * <p>
+     * Accessing this is discouraged. Use the {@link LayerManager} to access map data.
      */
     public final MapView mapView;
@@ -190,5 +193,5 @@
         setLayout(new BorderLayout());
 
-        mapView = new MapView(contentPane, viewportData);
+        mapView = new MapView(Main.getLayerManager(), contentPane, viewportData);
         if (!GraphicsEnvironment.isHeadless()) {
             new FileDrop(mapView);
@@ -775,5 +778,5 @@
             }
             // invalidate repaint cache
-            Main.map.mapView.preferenceChanged(null);
+            mapView.preferenceChanged(null);
         }
 
Index: trunk/src/org/openstreetmap/josm/gui/MapView.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/MapView.java	(revision 10268)
+++ trunk/src/org/openstreetmap/josm/gui/MapView.java	(revision 10271)
@@ -26,8 +26,6 @@
 import java.util.Collection;
 import java.util.Collections;
-import java.util.EnumSet;
 import java.util.LinkedHashSet;
 import java.util.List;
-import java.util.ListIterator;
 import java.util.Set;
 import java.util.concurrent.CopyOnWriteArrayList;
@@ -59,9 +57,14 @@
 import org.openstreetmap.josm.gui.layer.ImageryLayer;
 import org.openstreetmap.josm.gui.layer.Layer;
-import org.openstreetmap.josm.gui.layer.LayerPositionStrategy;
+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.LayerManagerWithActive;
+import org.openstreetmap.josm.gui.layer.LayerManagerWithActive.ActiveLayerChangeEvent;
+import org.openstreetmap.josm.gui.layer.LayerManagerWithActive.ActiveLayerChangeListener;
 import org.openstreetmap.josm.gui.layer.MapViewPaintable;
 import org.openstreetmap.josm.gui.layer.MapViewPaintable.PaintableInvalidationEvent;
 import org.openstreetmap.josm.gui.layer.MapViewPaintable.PaintableInvalidationListener;
-import org.openstreetmap.josm.gui.layer.NativeScaleLayer;
 import org.openstreetmap.josm.gui.layer.OsmDataLayer;
 import org.openstreetmap.josm.gui.layer.geoimage.GeoImageLayer;
@@ -87,10 +90,13 @@
  */
 public class MapView extends NavigatableComponent
-implements PropertyChangeListener, PreferenceChangedListener, OsmDataLayer.LayerStateChangeListener {
-
+implements PropertyChangeListener, PreferenceChangedListener, OsmDataLayer.LayerStateChangeListener,
+LayerManager.LayerChangeListener, LayerManagerWithActive.ActiveLayerChangeListener {
     /**
      * Interface to notify listeners of a layer change.
+     * <p>
+     * To be removed: end of 2016. Use {@link org.openstreetmap.josm.gui.layer.LayerManager.LayerChangeListener} instead.
      * @author imi
      */
+    @Deprecated
     public interface LayerChangeListener {
 
@@ -117,5 +123,8 @@
     /**
      * An interface that needs to be implemented in order to listen for changes to the active edit layer.
-     */
+     * <p>
+     * To be removed: end of 2016. Use {@link ActiveLayerChangeListener} instead.
+     */
+    @Deprecated
     public interface EditLayerChangeListener {
 
@@ -131,4 +140,5 @@
      * An invalidation listener that simply calls repaint() for now.
      * @author Michael Zangl
+     * @since 10271
      */
     private class LayerInvalidatedListener implements PaintableInvalidationListener {
@@ -172,38 +182,192 @@
     }
 
-    public boolean viewportFollowing;
-
-    /**
-     * the layer listeners
-     */
-    private static final CopyOnWriteArrayList<LayerChangeListener> layerChangeListeners = new CopyOnWriteArrayList<>();
-    private static final CopyOnWriteArrayList<EditLayerChangeListener> editLayerChangeListeners = new CopyOnWriteArrayList<>();
+    /**
+     * This class is an adapter for the old layer change interface.
+     * <p>
+     * New implementations should use {@link org.openstreetmap.josm.gui.layer.LayerManager.LayerChangeListener}
+     * @author Michael Zangl
+     * @since 10271
+     */
+    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.
+     * <p>
+     * New implementations should use {@link org.openstreetmap.josm.gui.layer.LayerManagerWithActive.ActiveLayerChangeListener}
+     * @author Michael Zangl
+     * @since 10271
+     */
+    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 + "]";
+        }
+
+    }
 
     /**
      * Removes a layer change listener
+     * <p>
+     * You should register the listener on {@link Main#getLayerManager()} instead. To be removed: end of 2016.
+     *
+     * @param listener the listener. Ignored if null or not registered.
+     */
+    @Deprecated
+    public static void removeLayerChangeListener(LayerChangeListener listener) {
+        LayerChangeAdapter adapter = new LayerChangeAdapter(listener);
+        try {
+            Main.getLayerManager().removeLayerChangeListener(adapter);
+        } catch (IllegalArgumentException e) {
+            // Ignored in old implementation
+        }
+        try {
+            Main.getLayerManager().removeActiveLayerChangeListener(adapter);
+        } catch (IllegalArgumentException e) {
+            // Ignored in old implementation
+        }
+    }
+
+    /**
+     * Removes an edit layer change listener
+     * <p>
+     * You should register the listener on {@link Main#getLayerManager()} instead. To be removed: end of 2016.
+     *
+     * @param listener the listener. Ignored if null or not registered.
+     */
+    @Deprecated
+    public static void removeEditLayerChangeListener(EditLayerChangeListener listener) {
+        try {
+            Main.getLayerManager().removeActiveLayerChangeListener(new EditLayerChangeAdapter(listener));
+        } catch (IllegalArgumentException e) {
+            // Ignored in old implementation
+        }
+    }
+
+    /**
+     * Adds a layer change listener
+     * <p>
+     * You should register the listener on {@link Main#getLayerManager()} instead. To be removed: end of 2016.
      *
      * @param listener the listener. Ignored if null or already registered.
      */
-    public static void removeLayerChangeListener(LayerChangeListener listener) {
-        layerChangeListeners.remove(listener);
-    }
-
-    public static void removeEditLayerChangeListener(EditLayerChangeListener listener) {
-        editLayerChangeListeners.remove(listener);
+    @Deprecated
+    public static void addLayerChangeListener(LayerChangeListener listener) {
+        addLayerChangeListener(listener, false);
     }
 
     /**
      * Adds a layer change listener
-     *
-     * @param listener the listener. Ignored if null or already registered.
-     */
-    public static void addLayerChangeListener(LayerChangeListener listener) {
-        if (listener != null) {
-            layerChangeListeners.addIfAbsent(listener);
-        }
-    }
-
-    /**
-     * Adds a layer change listener
+     * <p>
+     * You should register the listener on {@link Main#getLayerManager()} instead. To be removed: end of 2016.
      *
      * @param listener the listener. Ignored if null or already registered.
@@ -211,8 +375,13 @@
      * the listener in case there is a layer present (should be)
      */
+    @Deprecated
     public static void addLayerChangeListener(LayerChangeListener listener, boolean initialFire) {
-        addLayerChangeListener(listener);
-        if (initialFire && Main.isDisplayingMapView()) {
-            listener.activeLayerChange(null, Main.map.mapView.getActiveLayer());
+        if (listener != null) {
+            initialFire = initialFire && Main.isDisplayingMapView();
+
+            LayerChangeAdapter adapter = new LayerChangeAdapter(listener, initialFire);
+            Main.getLayerManager().addLayerChangeListener(adapter, false);
+            Main.getLayerManager().addActiveLayerChangeListener(adapter, initialFire);
+            adapter.receiveOneInitialFire = false;
         }
     }
@@ -220,4 +389,6 @@
     /**
      * Adds an edit layer change listener
+     * <p>
+     * You should register the listener on {@link Main#getLayerManager()} instead. To be removed: end of 2016.
      *
      * @param listener the listener. Ignored if null or already registered.
@@ -225,8 +396,8 @@
      * the listener in case there is an edit layer present
      */
+    @Deprecated
     public static void addEditLayerChangeListener(EditLayerChangeListener listener, boolean initialFire) {
-        addEditLayerChangeListener(listener);
-        if (initialFire && Main.isDisplayingMapView() && Main.map.mapView.getEditLayer() != null) {
-            listener.editLayerChanged(null, Main.map.mapView.getEditLayer());
+        if (listener != null) {
+            Main.getLayerManager().addActiveLayerChangeListener(new EditLayerChangeAdapter(listener), initialFire && Main.isDisplayingMapView() && Main.map.mapView.getEditLayer() != null);
         }
     }
@@ -234,47 +405,20 @@
     /**
      * Adds an edit layer change listener
+     * <p>
+     * You should register the listener on {@link Main#getLayerManager()} instead. To be removed: end of 2016.
      *
      * @param listener the listener. Ignored if null or already registered.
      */
+    @Deprecated
     public static void addEditLayerChangeListener(EditLayerChangeListener listener) {
-        if (listener != null) {
-            editLayerChangeListeners.addIfAbsent(listener);
-        }
-    }
-
-    /**
-     * Calls the {@link LayerChangeListener#activeLayerChange(Layer, Layer)} method of all listeners.
-     *
-     * @param oldLayer The old layer
-     * @param newLayer The new active layer.
-     */
-    protected void fireActiveLayerChanged(Layer oldLayer, Layer newLayer) {
-        for (LayerChangeListener l : layerChangeListeners) {
-            l.activeLayerChange(oldLayer, newLayer);
-        }
-    }
-
-    protected void fireLayerAdded(Layer newLayer) {
-        for (MapView.LayerChangeListener l : MapView.layerChangeListeners) {
-            l.layerAdded(newLayer);
-        }
-    }
-
-    protected void fireLayerRemoved(Layer layer) {
-        for (MapView.LayerChangeListener l : MapView.layerChangeListeners) {
-            l.layerRemoved(layer);
-        }
-    }
-
-    protected void fireEditLayerChanged(OsmDataLayer oldLayer, OsmDataLayer newLayer) {
-        for (EditLayerChangeListener l : editLayerChangeListeners) {
-            l.editLayerChanged(oldLayer, newLayer);
-        }
-    }
-
-    /**
-     * A list of all layers currently loaded.
-     */
-    private final transient List<Layer> layers = new ArrayList<>();
+        addEditLayerChangeListener(listener, false);
+    }
+
+    public boolean viewportFollowing = false;
+
+    /**
+     * A list of all layers currently loaded. If we support multiple map views, this list may be different for each of them.
+     */
+    private final LayerManagerWithActive layerManager;
 
     /**
@@ -282,14 +426,4 @@
      */
     public transient PlayHeadMarker playHeadMarker;
-
-    /**
-     * The layer from the layers list that is currently active.
-     */
-    private transient Layer activeLayer;
-
-    /**
-     * The edit layer is the current active data layer.
-     */
-    private transient OsmDataLayer editLayer;
 
     /**
@@ -322,4 +456,5 @@
     /**
      * Constructs a new {@code MapView}.
+     * @param layerManager The layers to display.
      * @param contentPane The content pane used to register shortcuts in its
      * {@link InputMap} and {@link ActionMap}
@@ -327,6 +462,9 @@
      * the viewport is derived from the layer data.
      */
-    public MapView(final JPanel contentPane, final ViewportData viewportData) {
+    public MapView(LayerManagerWithActive layerManager, final JPanel contentPane, final ViewportData viewportData) {
+        this.layerManager = layerManager;
         initialViewport = viewportData;
+        layerManager.addLayerChangeListener(this);
+        layerManager.addActiveLayerChangeListener(this, false);
         Main.pref.addPreferenceChangeListener(this);
 
@@ -405,82 +543,41 @@
 
     /**
-     * Add a layer to the current MapView. The layer will be added at topmost
-     * position.
+     * Add a layer to the current MapView.
+     * <p>
+     * Use {@link Main#getLayerManager()}.addLayer() instead. To be removed: end of 2016.
      * @param layer The layer to add
      */
+    @Deprecated
     public void addLayer(Layer layer) {
+        layerManager.addLayer(layer);
+    }
+
+    @Override
+    public void layerAdded(LayerAddEvent e) {
+        Layer layer = e.getAddedLayer();
+        if (layer instanceof MarkerLayer && playHeadMarker == null) {
+            playHeadMarker = PlayHeadMarker.create();
+        }
+
         boolean isOsmDataLayer = layer instanceof OsmDataLayer;
-        EnumSet<LayerListenerType> listenersToFire = EnumSet.noneOf(LayerListenerType.class);
-        Layer oldActiveLayer = activeLayer;
-        OsmDataLayer oldEditLayer = editLayer;
-
-        synchronized (layers) {
-            if (layer instanceof MarkerLayer && playHeadMarker == null) {
-                playHeadMarker = PlayHeadMarker.create();
-            }
-
-            LayerPositionStrategy positionStrategy = layer.getDefaultLayerPosition();
-            int position = positionStrategy.getPosition(this);
-            checkPosition(position);
-            insertLayerAt(layer, position);
-
-            if (isOsmDataLayer || oldActiveLayer == null) {
-                // autoselect the new layer
-                listenersToFire.addAll(setActiveLayer(layer, true));
-            }
-
-            if (isOsmDataLayer) {
-                ((OsmDataLayer) layer).addLayerStateChangeListener(this);
-            }
-
-            if (layer instanceof NativeScaleLayer) {
-                Main.map.mapView.setNativeScaleLayer((NativeScaleLayer) layer);
-            }
-
-            layer.addPropertyChangeListener(this);
-            invalidatedListener.addTo(layer);
-            Main.addProjectionChangeListener(layer);
-            AudioPlayer.reset();
-        }
-        fireLayerAdded(layer);
-        onActiveEditLayerChanged(oldActiveLayer, oldEditLayer, listenersToFire);
-
-        if (!listenersToFire.isEmpty()) {
-            repaint();
-        }
-    }
-
-    /**
-     * Check if the (new) position is valid
-     * @param position The position index
-     * @throws IndexOutOfBoundsException if it is not.
-     */
-    private void checkPosition(int position) {
-        if (position < 0 || position > layers.size()) {
-            throw new IndexOutOfBoundsException("Position " + position + " out of range.");
-        }
-    }
-
-    /**
-     * Insert a layer at a given position.
-     * @param layer The layer to add.
-     * @param position The position on which we should add it.
-     */
-    private void insertLayerAt(Layer layer, int position) {
-        if (position == layers.size()) {
-            layers.add(layer);
-        } else {
-            layers.add(position, layer);
-        }
-    }
-
+        if (isOsmDataLayer) {
+            ((OsmDataLayer) layer).addLayerStateChangeListener(this);
+        }
+
+        layer.addPropertyChangeListener(this);
+        Main.addProjectionChangeListener(layer);
+        invalidatedListener.addTo(layer);
+        AudioPlayer.reset();
+
+        repaint();
+    }
+
+    /**
+     * Use {@link Main#getLayerManager()} instead. To be removed: end of 2016.
+     */
     @Override
+    @Deprecated
     protected DataSet getCurrentDataSet() {
-        synchronized (layers) {
-            if (editLayer != null)
-                return editLayer.data;
-            else
-                return null;
-        }
+        return layerManager.getEditDataSet();
     }
 
@@ -491,7 +588,5 @@
      */
     public boolean isActiveLayerDrawable() {
-        synchronized (layers) {
-            return editLayer != null;
-        }
+         return getEditLayer() != null;
     }
 
@@ -502,7 +597,6 @@
      */
     public boolean isActiveLayerVisible() {
-        synchronized (layers) {
-            return isActiveLayerDrawable() && editLayer.isVisible();
-        }
+        OsmDataLayer e = getEditLayer();
+        return e != null && e.isVisible();
     }
 
@@ -515,8 +609,10 @@
      *   <li>otherwise, the top most layer of any type becomes active</li>
      * </ul>
+     * To be removed: end of 2016 (now handled by {@link LayerManagerWithActive}
      * @param layersList lit of layers
      *
      * @return the next active data layer
      */
+    @Deprecated
     protected Layer determineNextActiveLayer(List<Layer> layersList) {
         // First look for data layer
@@ -532,5 +628,4 @@
         // and then give up
         return null;
-
     }
 
@@ -538,43 +633,27 @@
      * Remove the layer from the mapview. If the layer was in the list before,
      * an LayerChange event is fired.
+     * <p>
+     * Use {@link Main#getLayerManager()}.removeLayer() instead. To be removed: end of 2016.
      * @param layer The layer to remove
      */
+    @Deprecated
     public void removeLayer(Layer layer) {
-        EnumSet<LayerListenerType> listenersToFire = EnumSet.noneOf(LayerListenerType.class);
-        Layer oldActiveLayer = activeLayer;
-        OsmDataLayer oldEditLayer = editLayer;
-
-        synchronized (layers) {
-            List<Layer> layersList = new ArrayList<>(layers);
-
-            if (!layersList.remove(layer))
-                return;
-
-            listenersToFire = setEditLayer(layersList);
-
-            if (layer == activeLayer) {
-                listenersToFire.addAll(setActiveLayer(determineNextActiveLayer(layersList), false));
-            }
-
-            if (layer instanceof OsmDataLayer) {
-                ((OsmDataLayer) layer).removeLayerPropertyChangeListener(this);
-            }
-
-            layers.remove(layer);
-            Main.removeProjectionChangeListener(layer);
-            layer.removePropertyChangeListener(this);
-            invalidatedListener.removeFrom(layer);
-            layer.destroy();
-            AudioPlayer.reset();
-        }
-        onActiveEditLayerChanged(oldActiveLayer, oldEditLayer, listenersToFire);
-        fireLayerRemoved(layer);
+        layerManager.removeLayer(layer);
+    }
+
+    @Override
+    public void layerRemoving(LayerRemoveEvent e) {
+        Layer layer = e.getRemovedLayer();
+        if (layer instanceof OsmDataLayer) {
+            ((OsmDataLayer) layer).removeLayerPropertyChangeListener(this);
+        }
+
+        Main.removeProjectionChangeListener(layer);
+        layer.removePropertyChangeListener(this);
+        invalidatedListener.removeFrom(layer);
+        layer.destroy();
+        AudioPlayer.reset();
 
         repaint();
-    }
-
-    private void onEditLayerChanged(OsmDataLayer oldEditLayer) {
-        fireEditLayerChanged(oldEditLayer, editLayer);
-        refreshTitle();
     }
 
@@ -605,25 +684,10 @@
      */
     public void moveLayer(Layer layer, int pos) {
-        EnumSet<LayerListenerType> listenersToFire;
-        Layer oldActiveLayer = activeLayer;
-        OsmDataLayer oldEditLayer = editLayer;
-
-        synchronized (layers) {
-            int curLayerPos = layers.indexOf(layer);
-            if (curLayerPos == -1)
-                throw new IllegalArgumentException(tr("Layer not in list."));
-            if (pos == curLayerPos)
-                return; // already in place.
-            layers.remove(curLayerPos);
-            if (pos >= layers.size()) {
-                layers.add(layer);
-            } else {
-                layers.add(pos, layer);
-            }
-            listenersToFire = setEditLayer(layers);
-            AudioPlayer.reset();
-        }
-        onActiveEditLayerChanged(oldActiveLayer, oldEditLayer, listenersToFire);
-
+        layerManager.moveLayer(layer, pos);
+    }
+
+    @Override
+    public void layerOrderChanged(LayerOrderChangeEvent e) {
+        AudioPlayer.reset();
         repaint();
     }
@@ -631,54 +695,16 @@
     /**
      * Gets the index of the layer in the layer list.
+     * <p>
+     * Access the layer list using {@link Main#getLayerManager()} instead. 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
     public int getLayerPos(Layer layer) {
-        int curLayerPos;
-        synchronized (layers) {
-            curLayerPos = layers.indexOf(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.
-     * <p>
-     * The active data layer is pulled above all adjacent data layers.
-     *
-     * @return a list of the visible in Z-Order, the layer with the lowest Z-Order
-     * first, layer with the highest Z-Order last.
-     */
-    public List<Layer> getVisibleLayersInZOrder() {
-        synchronized (layers) {
-            List<Layer> ret = new ArrayList<>();
-            // This is set while we delay the addition of the active layer.
-            boolean activeLayerDelayed = false;
-            for (ListIterator<Layer> iterator = layers.listIterator(layers.size()); iterator.hasPrevious();) {
-                Layer l = iterator.previous();
-                if (!l.isVisible()) {
-                    // ignored
-                } else if (l == activeLayer && l instanceof OsmDataLayer) {
-                    // delay and add after the current block of OsmDataLayer
-                    activeLayerDelayed = true;
-                } else {
-                    if (activeLayerDelayed && !(l instanceof OsmDataLayer)) {
-                        // add active layer before the current one.
-                        ret.add(activeLayer);
-                        activeLayerDelayed = false;
-                    }
-                    // Add this layer now
-                    ret.add(l);
-                }
-            }
-            if (activeLayerDelayed) {
-                ret.add(activeLayer);
-            }
-            return ret;
-        }
     }
 
@@ -700,5 +726,5 @@
         }
 
-        List<Layer> visibleLayers = getVisibleLayersInZOrder();
+        List<Layer> visibleLayers = layerManager.getVisibleLayersInZOrder();
 
         int nonChangedLayersCount = 0;
@@ -893,23 +919,25 @@
 
     /**
+     * Use {@link LayerManager#getLayers()} instead. To be removed: end of 2016.
+     *
      * @return An unmodifiable collection of all layers
      */
+    @Deprecated
     public Collection<Layer> getAllLayers() {
-        synchronized (layers) {
-            return Collections.unmodifiableCollection(new ArrayList<>(layers));
-        }
-    }
-
-    /**
+        return layerManager.getLayers();
+    }
+
+    /**
+     * Use {@link LayerManager#getLayers()} instead. To be removed: end of 2016.
+     *
      * @return An unmodifiable ordered list of all layers
      */
+    @Deprecated
     public List<Layer> getAllLayersAsList() {
-        synchronized (layers) {
-            return Collections.unmodifiableList(new ArrayList<>(layers));
-        }
-    }
-
-    /**
-     * Replies an unmodifiable list of layers of a certain type.
+        return layerManager.getLayers();
+    }
+
+    /**
+     * Replies an unmodifiable list of layers of a certain type. To be removed: end of 2016.
      *
      * Example:
@@ -917,4 +945,6 @@
      *     List&lt;WMSLayer&gt; wmsLayers = getLayersOfType(WMSLayer.class);
      * </pre>
+     * Use {@link LayerManager#getLayersOfType(Class)} instead.
+     *
      * @param <T> layer type
      *
@@ -922,24 +952,29 @@
      * @return an unmodifiable list of layers of a certain type.
      */
+    @Deprecated
     public <T extends Layer> List<T> getLayersOfType(Class<T> ofType) {
-        return new ArrayList<>(Utils.filteredCollection(getAllLayers(), ofType));
-    }
-
-    /**
-     * Replies the number of layers managed by this map view
+        return layerManager.getLayersOfType(ofType);
+    }
+
+    /**
+     * Replies the number of layers managed by this map view. To be removed: end of 2016.
+     * <p>
+     * You can use {@link Main#getLayerManager()}.getLayers().size() instead.
      *
      * @return the number of layers managed by this map view
      */
+    @Deprecated
     public int getNumLayers() {
-        synchronized (layers) {
-            return layers.size();
-        }
+        return getAllLayers().size();
     }
 
     /**
      * Replies true if there is at least one layer in this map view
+     * <p>
+     * You can use !{@link Main#getLayerManager()}.getLayers().isEmpty() instead.
      *
      * @return true if there is at least one layer in this map view
      */
+    @Deprecated
     public boolean hasLayers() {
         return getNumLayers() > 0;
@@ -947,123 +982,30 @@
 
     /**
-     * Sets the active edit layer.
-     * <p>
-     * @param layersList A list to select that layer from.
-     * @return A list of change listeners that should be fired using {@link #onActiveEditLayerChanged(Layer, OsmDataLayer, EnumSet)}
-     */
-    private EnumSet<LayerListenerType> setEditLayer(List<Layer> layersList) {
-        final OsmDataLayer newEditLayer = findNewEditLayer(layersList);
-
-        // Set new edit layer
-        if (newEditLayer != editLayer) {
-            if (newEditLayer == null) {
-                // Note: Unsafe to call while layer write lock is held.
-                getCurrentDataSet().setSelected();
-            }
-
-            editLayer = newEditLayer;
-            return EnumSet.of(LayerListenerType.EDIT_LAYER_CHANGE);
-        } else {
-            return EnumSet.noneOf(LayerListenerType.class);
-        }
-
-    }
-
-    private OsmDataLayer findNewEditLayer(List<Layer> layersList) {
-        OsmDataLayer newEditLayer = layersList.contains(editLayer) ? editLayer : null;
-        // Find new edit layer
-        if (activeLayer != editLayer || !layersList.contains(editLayer)) {
-            if (activeLayer instanceof OsmDataLayer && layersList.contains(activeLayer)) {
-                newEditLayer = (OsmDataLayer) activeLayer;
-            } else {
-                for (Layer layer:layersList) {
-                    if (layer instanceof OsmDataLayer) {
-                        newEditLayer = (OsmDataLayer) layer;
-                        break;
-                    }
-                }
-            }
-        }
-        return newEditLayer;
-    }
-
-    /**
      * Sets the active layer to <code>layer</code>. If <code>layer</code> is an instance
-     * of {@link OsmDataLayer} also sets {@link #editLayer} to <code>layer</code>.
+     * of {@link OsmDataLayer} also sets editLayer to <code>layer</code>.
+     * <p>
+     * You can use !{@link Main#getLayerManager()}.setActiveLayer() instead.
      *
      * @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
     public void setActiveLayer(Layer layer) {
-        EnumSet<LayerListenerType> listenersToFire;
-        Layer oldActiveLayer;
-        OsmDataLayer oldEditLayer;
-
-        synchronized (layers) {
-            oldActiveLayer = activeLayer;
-            oldEditLayer = editLayer;
-            listenersToFire = setActiveLayer(layer, true);
-        }
-        onActiveEditLayerChanged(oldActiveLayer, oldEditLayer, listenersToFire);
-
-        repaint();
-    }
-
-    /**
-     * Sets the active layer. Propagates this change to all map buttons.
-     * @param layer The layer to be active.
-     * @param setEditLayer if this is <code>true</code>, the edit layer is also set.
-     * @return A list of change listeners that should be fired using {@link #onActiveEditLayerChanged(Layer, OsmDataLayer, EnumSet)}
-     */
-    private EnumSet<LayerListenerType> setActiveLayer(final Layer layer, boolean setEditLayer) {
-        if (layer != null && !layers.contains(layer))
-            throw new IllegalArgumentException(tr("Layer ''{0}'' must be in list of layers", layer.toString()));
-
-        if (layer == activeLayer)
-            return EnumSet.noneOf(LayerListenerType.class);
-
-        activeLayer = layer;
-        EnumSet<LayerListenerType> listenersToFire = EnumSet.of(LayerListenerType.ACTIVE_LAYER_CHANGE);
-        if (setEditLayer) {
-            listenersToFire.addAll(setEditLayer(layers));
-        }
-
-        return listenersToFire;
-    }
-
+    	layerManager.setActiveLayer(layer);
+    }
     /**
      * Replies the currently active layer
+     * <p>
+     * You can use !{@link Main#getLayerManager()}.getActiveLayer() instead.
      *
      * @return the currently active layer (may be null)
      */
+    @Deprecated
     public Layer getActiveLayer() {
-        synchronized (layers) {
-            return activeLayer;
-        }
-    }
-
-    private enum LayerListenerType {
-        ACTIVE_LAYER_CHANGE,
-        EDIT_LAYER_CHANGE
-    }
-
-    /**
-     * This is called whenever one of active layer/edit layer or both may have been changed,
-     * @param oldActive The old active layer
-     * @param oldEdit The old edit layer.
-     * @param listenersToFire A mask of listeners to fire using {@link LayerListenerType}s
-     */
-    private void onActiveEditLayerChanged(final Layer oldActive, final OsmDataLayer oldEdit, EnumSet<LayerListenerType> listenersToFire) {
-        if (listenersToFire.contains(LayerListenerType.EDIT_LAYER_CHANGE)) {
-            onEditLayerChanged(oldEdit);
-        }
-        if (listenersToFire.contains(LayerListenerType.ACTIVE_LAYER_CHANGE)) {
-            onActiveLayerChanged(oldActive);
-        }
-    }
-
-    private void onActiveLayerChanged(final Layer old) {
-        fireActiveLayerChanged(old, activeLayer);
-
+        return layerManager.getActiveLayer();
+    }
+
+    @Override
+    public void activeOrEditLayerChanged(ActiveLayerChangeEvent e) {
         /* 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
@@ -1072,5 +1014,5 @@
         for (final AbstractButton b: Main.map.allMapModeButtons) {
             MapMode mode = (MapMode) b.getAction();
-            final boolean activeLayerSupported = mode.layerIsSupported(activeLayer);
+            final boolean activeLayerSupported = mode.layerIsSupported(layerManager.getActiveLayer());
             if (activeLayerSupported) {
                 Main.registerActionShortcut(mode, mode.getShortcut()); //fix #6876
@@ -1085,4 +1027,5 @@
         }
         AudioPlayer.reset();
+        refreshTitle();
         repaint();
     }
@@ -1090,23 +1033,25 @@
     /**
      * Replies the current edit layer, if any
+     * <p>
+     * You can use !{@link Main#getLayerManager()}.getEditLayer() instead. To be made private: end of 2016.
      *
      * @return the current edit layer. May be null.
      */
+    @Deprecated
     public OsmDataLayer getEditLayer() {
-        synchronized (layers) {
-            return editLayer;
-        }
+        return layerManager.getEditLayer();
     }
 
     /**
      * replies true if the list of layers managed by this map view contain layer
+     * <p>
+     * You can use !{@link Main#getLayerManager()}.containsLayer() instead.
      *
      * @param layer the layer
      * @return true if the list of layers managed by this map view contain layer
      */
+    @Deprecated
     public boolean hasLayer(Layer layer) {
-        synchronized (layers) {
-            return layers.contains(layer);
-        }
+        return layerManager.containsLayer(layer);
     }
 
@@ -1180,10 +1125,9 @@
     protected void refreshTitle() {
         if (Main.parent != null) {
-            synchronized (layers) {
-                boolean dirty = editLayer != null &&
-                        (editLayer.requiresSaveToFile() || (editLayer.requiresUploadToServer() && !editLayer.isUploadDiscouraged()));
-                ((JFrame) Main.parent).setTitle((dirty ? "* " : "") + tr("Java OpenStreetMap Editor"));
-                ((JFrame) Main.parent).getRootPane().putClientProperty("Window.documentModified", dirty);
-            }
+            OsmDataLayer editLayer = layerManager.getEditLayer();
+            boolean dirty = editLayer != null &&
+                    (editLayer.requiresSaveToFile() || (editLayer.requiresUploadToServer() && !editLayer.isUploadDiscouraged()));
+            ((JFrame) Main.parent).setTitle((dirty ? "* " : "") + tr("Java OpenStreetMap Editor"));
+            ((JFrame) Main.parent).getRootPane().putClientProperty("Window.documentModified", dirty);
         }
     }
@@ -1204,4 +1148,6 @@
 
     public void destroy() {
+        layerManager.removeLayerChangeListener(this);
+        layerManager.removeActiveLayerChangeListener(this);
         Main.pref.removePreferenceChangeListener(this);
         DataSet.removeSelectionListener(repaintSelectionChangedListener);
@@ -1210,11 +1156,5 @@
             mapMover.destroy();
         }
-        synchronized (layers) {
-            activeLayer = null;
-            changedLayer = null;
-            editLayer = null;
-            layers.clear();
-            nonChangedLayers.clear();
-        }
+        nonChangedLayers.clear();
         synchronized (temporaryLayers) {
             temporaryLayers.clear();
@@ -1224,5 +1164,5 @@
     @Override
     public void uploadDiscouragedChanged(OsmDataLayer layer, boolean newValue) {
-        if (layer == getEditLayer()) {
+        if (layer == layerManager.getEditLayer()) {
             refreshTitle();
         }
Index: trunk/src/org/openstreetmap/josm/gui/layer/LayerManagerWithActive.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/layer/LayerManagerWithActive.java	(revision 10271)
+++ trunk/src/org/openstreetmap/josm/gui/layer/LayerManagerWithActive.java	(revision 10271)
@@ -0,0 +1,282 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.gui.layer;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.ListIterator;
+import java.util.concurrent.CopyOnWriteArrayList;
+
+import org.openstreetmap.josm.data.osm.DataSet;
+import org.openstreetmap.josm.gui.util.GuiHelper;
+
+/**
+ * This class extends the layer manager by adding an active and an edit layer.
+ * <p>
+ * The active layer is the layer the user is currently working on.
+ * <p>
+ * The edit layer is an data layer that we currently work with.
+ * @author Michael Zangl
+ * @since 10271
+ */
+public class LayerManagerWithActive extends LayerManager {
+    /**
+     * This listener listens to changes of the active or the edit layer.
+     * @author Michael Zangl
+     *
+     */
+    public interface ActiveLayerChangeListener {
+        /**
+         * Called whenever the active or edit layer changed.
+         * <p>
+         * You can be sure that this layer is still contained in this set.
+         * <p>
+         * Listeners are called in the EDT thread and you can manipulate the layer manager in the current thread.
+         * @param e The change event.
+         */
+        public void activeOrEditLayerChanged(ActiveLayerChangeEvent e);
+    }
+
+    /**
+     * This event is fired whenever the active or the edit layer changes.
+     * @author Michael Zangl
+     */
+    public class ActiveLayerChangeEvent extends LayerManagerEvent {
+
+        private final OsmDataLayer previousEditLayer;
+
+        private final Layer previousActiveLayer;
+
+        /**
+         * Create a new {@link ActiveLayerChangeEvent}
+         * @param source The source
+         * @param previousEditLayer the previous edit layer
+         * @param previousActiveLayer the previous active layer
+         */
+        ActiveLayerChangeEvent(LayerManagerWithActive source, OsmDataLayer previousEditLayer,
+                Layer previousActiveLayer) {
+            super(source);
+            this.previousEditLayer = previousEditLayer;
+            this.previousActiveLayer = previousActiveLayer;
+        }
+
+        /**
+         * Gets the edit layer that was previously used.
+         * @return The old edit layer, <code>null</code> if there is none.
+         */
+        public OsmDataLayer getPreviousEditLayer() {
+            return previousEditLayer;
+        }
+
+        /**
+         * Gets the active layer that was previously used.
+         * @return The old active layer, <code>null</code> if there is none.
+         */
+        public Layer getPreviousActiveLayer() {
+            return previousActiveLayer;
+        }
+
+        @Override
+        public LayerManagerWithActive getSource() {
+            return (LayerManagerWithActive) super.getSource();
+        }
+    }
+
+    /**
+     * The layer from the layers list that is currently active.
+     */
+    private Layer activeLayer;
+
+    /**
+     * The edit layer is the current active data layer.
+     */
+    private OsmDataLayer editLayer;
+
+    private final List<ActiveLayerChangeListener> activeLayerChangeListeners = new CopyOnWriteArrayList<>();
+
+    /**
+     * Adds a active/edit layer change listener
+     *
+     * @param listener the listener.
+     * @param initialFire fire a fake active-layer-changed-event right after adding
+     * the listener. The previous layers will be null. The listener is notified in the current thread.
+     */
+    public synchronized void addActiveLayerChangeListener(ActiveLayerChangeListener listener, boolean initialFire) {
+        if (activeLayerChangeListeners.contains(listener)) {
+            throw new IllegalArgumentException("Attempted to add listener that was already in list: " + listener);
+        }
+        activeLayerChangeListeners.add(listener);
+        if (initialFire) {
+            listener.activeOrEditLayerChanged(new ActiveLayerChangeEvent(this, null, null));
+        }
+    }
+
+    /**
+     * Removes an active/edit layer change listener.
+     * @param listener the listener.
+     */
+    public synchronized void removeActiveLayerChangeListener(ActiveLayerChangeListener listener) {
+        if (!activeLayerChangeListeners.contains(listener)) {
+            throw new IllegalArgumentException("Attempted to remove listener that was not in list: " + listener);
+        }
+        activeLayerChangeListeners.remove(listener);
+    }
+
+    /**
+     * Set the active layer. If the layer is an OsmDataLayer, the edit layer is also changed.
+     * @param layer The active layer.
+     */
+    public void setActiveLayer(final Layer layer) {
+        // we force this on to the EDT Thread to make events fire from there.
+        // The synchronization lock needs to be held by the EDT.
+        GuiHelper.runInEDTAndWaitWithException(new Runnable() {
+            @Override
+            public void run() {
+                realSetActiveLayer(layer);
+            }
+        });
+    }
+
+    protected synchronized void realSetActiveLayer(final Layer layer) {
+        // to be called in EDT thread
+        checkContainsLayer(layer);
+        setActiveLayer(layer, false);
+    }
+
+    private void setActiveLayer(Layer layer, boolean forceEditLayerUpdate) {
+        ActiveLayerChangeEvent event = new ActiveLayerChangeEvent(this, editLayer, activeLayer);
+        activeLayer = layer;
+        if (activeLayer instanceof OsmDataLayer) {
+            editLayer = (OsmDataLayer) activeLayer;
+        } else if (forceEditLayerUpdate) {
+            editLayer = null;
+        }
+        fireActiveLayerChange(event);
+    }
+
+    private void fireActiveLayerChange(ActiveLayerChangeEvent event) {
+        GuiHelper.assertCallFromEdt();
+        if (event.getPreviousActiveLayer() != activeLayer || event.getPreviousEditLayer() != editLayer) {
+            for (ActiveLayerChangeListener l : activeLayerChangeListeners) {
+                l.activeOrEditLayerChanged(event);
+            }
+        }
+    }
+
+    @Override
+    protected synchronized void realAddLayer(Layer layer) {
+        super.realAddLayer(layer);
+
+        // update the active layer automatically.
+        if (layer instanceof OsmDataLayer || activeLayer == null) {
+            setActiveLayer(layer);
+        }
+    }
+
+    @Override
+    protected synchronized void realRemoveLayer(Layer layer) {
+        if (layer == activeLayer || layer == editLayer) {
+            Layer nextActive = suggestNextActiveLayer(layer);
+            setActiveLayer(nextActive, true);
+        }
+
+        super.realRemoveLayer(layer);
+    }
+
+    /**
+     * Determines the next active data layer according to the following
+     * rules:
+     * <ul>
+     *   <li>if there is at least one {@link OsmDataLayer} the first one
+     *     becomes active</li>
+     *   <li>otherwise, the top most layer of any type becomes active</li>
+     * </ul>
+     *
+     * @param except A layer to ignore.
+     * @return the next active data layer
+     */
+    private Layer suggestNextActiveLayer(Layer except) {
+        List<Layer> layersList = new ArrayList<>(getLayers());
+        layersList.remove(except);
+        // First look for data layer
+        for (Layer layer : layersList) {
+            if (layer instanceof OsmDataLayer) {
+                return layer;
+            }
+        }
+
+        // Then any layer
+        if (!layersList.isEmpty())
+            return layersList.get(0);
+
+        // and then give up
+        return null;
+    }
+
+    /**
+     * Replies the currently active layer
+     *
+     * @return the currently active layer (may be null)
+     */
+    public synchronized Layer getActiveLayer() {
+        return activeLayer;
+    }
+
+    /**
+     * Replies the current edit layer, if any
+     *
+     * @return the current edit layer. May be null.
+     */
+    public synchronized OsmDataLayer getEditLayer() {
+        return editLayer;
+    }
+
+    /**
+     * Gets the data set of the active edit layer.
+     * @return That data set, <code>null</code> if there is no edit layer.
+     */
+    public synchronized DataSet getEditDataSet() {
+        if (editLayer != null) {
+            return editLayer.data;
+        } else {
+            return null;
+        }
+    }
+
+
+    /**
+     * 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.
+     * <p>
+     * The active data layer is pulled above all adjacent data layers.
+     *
+     * @return a list of the visible in Z-Order, the layer with the lowest Z-Order
+     * first, layer with the highest Z-Order last.
+     */
+    public synchronized List<Layer> getVisibleLayersInZOrder() {
+        List<Layer> ret = new ArrayList<>();
+        // This is set while we delay the addition of the active layer.
+        boolean activeLayerDelayed = false;
+        List<Layer> layers = getLayers();
+        for (ListIterator<Layer> iterator = layers.listIterator(layers.size()); iterator.hasPrevious();) {
+            Layer l = iterator.previous();
+            if (!l.isVisible()) {
+                // ignored
+            } else if (l == activeLayer && l instanceof OsmDataLayer) {
+                // delay and add after the current block of OsmDataLayer
+                activeLayerDelayed = true;
+            } else {
+                if (activeLayerDelayed && !(l instanceof OsmDataLayer)) {
+                    // add active layer before the current one.
+                    ret.add(activeLayer);
+                    activeLayerDelayed = false;
+                }
+                // Add this layer now
+                ret.add(l);
+            }
+        }
+        if (activeLayerDelayed) {
+            ret.add(activeLayer);
+        }
+        return ret;
+    }
+}
Index: trunk/src/org/openstreetmap/josm/gui/layer/LayerPositionStrategy.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/layer/LayerPositionStrategy.java	(revision 10268)
+++ trunk/src/org/openstreetmap/josm/gui/layer/LayerPositionStrategy.java	(revision 10271)
@@ -4,5 +4,4 @@
 import java.util.List;
 
-import org.openstreetmap.josm.gui.MapView;
 import org.openstreetmap.josm.tools.Predicate;
 import org.openstreetmap.josm.tools.Predicates;
@@ -20,5 +19,5 @@
     public static final LayerPositionStrategy IN_FRONT = new LayerPositionStrategy() {
         @Override
-        public int getPosition(MapView manager) {
+        public int getPosition(LayerManager manager) {
             return 0;
         }
@@ -73,6 +72,6 @@
         return new LayerPositionStrategy() {
             @Override
-            public int getPosition(MapView manager) {
-                List<Layer> layers = manager.getAllLayersAsList();
+            public int getPosition(LayerManager manager) {
+                List<Layer> layers = manager.getLayers();
                 for (int i = 0; i < layers.size(); i++) {
                     if (what.evaluate(layers.get(i))) {
@@ -93,6 +92,6 @@
         return new LayerPositionStrategy() {
             @Override
-            public int getPosition(MapView manager) {
-                List<Layer> layers = manager.getAllLayersAsList();
+            public int getPosition(LayerManager manager) {
+                List<Layer> layers = manager.getLayers();
                 for (int i = layers.size() - 1; i >= 0; i--) {
                     if (what.evaluate(layers.get(i))) {
@@ -110,4 +109,4 @@
      * @return The position in the range 0...layers.size
      */
-    public abstract int getPosition(MapView manager);
+    public abstract int getPosition(LayerManager manager);
 }
Index: trunk/src/org/openstreetmap/josm/gui/util/GuiHelper.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/util/GuiHelper.java	(revision 10268)
+++ trunk/src/org/openstreetmap/josm/gui/util/GuiHelper.java	(revision 10271)
@@ -131,4 +131,31 @@
 
     /**
+     * Executes synchronously a runnable in
+     * <a href="http://docs.oracle.com/javase/tutorial/uiswing/concurrency/dispatch.html">Event Dispatch Thread</a>.
+     * <p>
+     * Passes on the exception that was thrown to the thread calling this. The exception is wrapped in a {@link RuntimeException} if it was a normal {@link Throwable}.
+     * @param task The runnable to execute
+     * @see SwingUtilities#invokeAndWait
+     * @since 10271
+     */
+    public static void runInEDTAndWaitWithException(Runnable task) {
+        if (SwingUtilities.isEventDispatchThread()) {
+            task.run();
+        } else {
+            try {
+                SwingUtilities.invokeAndWait(task);
+            } catch (InterruptedException e) {
+                Main.error(e);
+            } catch (InvocationTargetException e) {
+                if (e.getCause() instanceof RuntimeException) {
+                    throw (RuntimeException) e.getCause();
+                } else {
+                    throw new RuntimeException("Exception while clling " + task, e.getCause());
+                }
+            }
+        }
+    }
+
+    /**
      * Executes synchronously a callable in
      * <a href="http://docs.oracle.com/javase/tutorial/uiswing/concurrency/dispatch.html">Event Dispatch Thread</a>
@@ -156,4 +183,16 @@
                 return null;
             }
+        }
+    }
+
+    /**
+     * This function fails if it was not called from the EDT thread.
+     * @throws IllegalStateException if called from wrong thread.
+     * @since 10271
+     */
+    public static void assertCallFromEdt() {
+        if (!SwingUtilities.isEventDispatchThread()) {
+            throw new IllegalStateException(
+                    "Needs to be called from the EDT thread, not from " + Thread.currentThread().getName());
         }
     }
