Index: /trunk/src/org/openstreetmap/josm/Main.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/Main.java	(revision 10431)
+++ /trunk/src/org/openstreetmap/josm/Main.java	(revision 10432)
@@ -62,5 +62,4 @@
 import org.openstreetmap.josm.actions.downloadtasks.PostDownloadHandler;
 import org.openstreetmap.josm.actions.mapmode.DrawAction;
-import org.openstreetmap.josm.actions.mapmode.MapMode;
 import org.openstreetmap.josm.actions.search.SearchAction;
 import org.openstreetmap.josm.data.Bounds;
@@ -80,17 +79,13 @@
 import org.openstreetmap.josm.gui.GettingStarted;
 import org.openstreetmap.josm.gui.MainApplication.Option;
+import org.openstreetmap.josm.gui.MainFrame;
 import org.openstreetmap.josm.gui.MainMenu;
+import org.openstreetmap.josm.gui.MainPanel;
 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;
 import org.openstreetmap.josm.gui.io.SaveLayersDialog;
 import org.openstreetmap.josm.gui.layer.AbstractModifiableLayer;
 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.MainLayerManager;
 import org.openstreetmap.josm.gui.layer.OsmDataLayer;
@@ -195,4 +190,6 @@
      * <p>
      * There should be no need to access this to access any map data. Use {@link #layerManager} instead.
+     *
+     * @see MainPanel
      */
     public static MapFrame map;
@@ -236,8 +233,8 @@
     /**
      * The MOTD Layer.
-     */
-    public final GettingStarted gettingStarted = new GettingStarted();
-
-    private static final Collection<MapFrameListener> mapFrameListeners = new ArrayList<>();
+     * @deprecated Do not access this. It will be removed soon. You should not need to access the GettingStarted panel.
+     */
+    @Deprecated
+    public final GettingStarted gettingStarted = mainPanel.getGettingStarted();
 
     protected static final Map<String, Throwable> NETWORK_ERRORS = new HashMap<>();
@@ -253,4 +250,10 @@
      */
     public static int logLevel = 3;
+
+    /**
+     * The real main panel. This field may be removed any time and made private to {@link MainFrame}
+     * @see #panel
+     */
+    protected static final MainPanel mainPanel = new MainPanel(getLayerManager());
 
     private static void rememberWarnErrorMsg(String msg) {
@@ -548,33 +551,12 @@
     /**
      * Set or clear (if passed <code>null</code>) the map.
+     * <p>
+     * To be removed any time
      * @param map The map to set {@link Main#map} to. Can be null.
-     */
+     * @deprecated This is done automatically by {@link MainPanel}
+     */
+    @Deprecated
     public final void setMapFrame(final MapFrame map) {
-        MapFrame old = Main.map;
-        panel.setVisible(false);
-        panel.removeAll();
-        if (map != null) {
-            map.fillPanel(panel);
-        } else {
-            old.destroy();
-            panel.add(gettingStarted, BorderLayout.CENTER);
-        }
-        panel.setVisible(true);
-        redoUndoListener.commandChanged(0, 0);
-
-        Main.map = map;
-
-        // Notify map frame listeners, mostly plugins.
-        if ((map == null) == (old == null)) {
-            Main.warn("Replacing the map frame. This is not expected by some plugins and should not happen.");
-        }
-        for (MapFrameListener listener : mapFrameListeners) {
-            MapView.fireDeprecatedListenerOnAdd = true;
-            listener.mapFrameInitialized(old, map);
-            MapView.fireDeprecatedListenerOnAdd = false;
-        }
-        if (map == null && currentProgressMonitor != null) {
-            currentProgressMonitor.showForegroundDialog();
-        }
+        Main.warn("setMapFrame call was ignored.");
     }
 
@@ -582,12 +564,13 @@
      * Remove the specified layer from the map. If it is the last layer,
      * remove the map as well.
+     * <p>
+     * To be removed end of 2016
      * @param layer The layer to remove
-     */
+     * @deprecated You can remove the layer using {@link #getLayerManager()}
+     */
+    @Deprecated
     public final synchronized void removeLayer(final Layer layer) {
         if (map != null) {
             getLayerManager().removeLayer(layer);
-            if (isDisplayingMapView() && getLayerManager().getLayers().isEmpty()) {
-                setMapFrame(null);
-            }
         }
     }
@@ -613,28 +596,9 @@
     public Main() {
         main = this;
-        getLayerManager().addLayerChangeListener(new LayerChangeListener() {
+        mainPanel.addAndFireMapFrameListener(new MapFrameListener() {
             @Override
-            public void layerAdded(LayerAddEvent e) {
-                Layer layer = e.getAddedLayer();
-                if (map == null) {
-                    Main.main.createMapFrame(layer, null);
-                    Main.map.setVisible(true);
-                }
-                ProjectionBounds viewProjectionBounds = layer.getViewProjectionBounds();
-                if (viewProjectionBounds != null) {
-                    Main.map.mapView.scheduleZoomTo(new ViewportData(viewProjectionBounds));
-                }
-            }
-
-            @Override
-            public void layerRemoving(LayerRemoveEvent e) {
-                // empty
-            }
-
-            @Override
-            public void layerOrderChanged(LayerOrderChangeEvent e) {
-                //empty
-            }
-
+            public void mapFrameInitialized(MapFrame oldFrame, MapFrame newFrame) {
+                redoUndoListener.commandChanged(0, 0);
+            }
         });
     }
@@ -836,4 +800,6 @@
      *
      * If no map exists, create one.
+     * <p>
+     * To be removed end of 2016
      *
      * @param layer the layer
@@ -841,7 +807,9 @@
      * @see #addLayer(Layer, ProjectionBounds)
      * @see #addLayer(Layer, ViewportData)
-     */
+     * @deprecated You can add the layer to the layer manager: {@link #getLayerManager()}
+     */
+    @Deprecated
     public final void addLayer(final Layer layer) {
-        addLayer(layer, layer.getViewProjectionBounds());
+        addLayer(layer, (ViewportData) null);
     }
 
@@ -869,5 +837,6 @@
     public final void addLayer(Layer layer, ViewportData viewport) {
         getLayerManager().addLayer(layer);
-        if (viewport != null) {
+        if (viewport != null && Main.map.mapView != null) {
+            // MapView may be null in headless mode here.
             Main.map.mapView.scheduleZoomTo(viewport);
         }
@@ -876,28 +845,25 @@
     /**
      * Creates the map frame. Call only in EDT Thread.
+     * <p>
+     * To be removed any time
      * @param firstLayer The first layer that was added.
      * @param viewportData The initial viewport. Can be <code>null</code> to be automatically computed.
-     */
+     * @deprecated Not supported. MainPanel does this automatically.
+     */
+    @Deprecated
     public synchronized void createMapFrame(Layer firstLayer, ViewportData viewportData) {
         GuiHelper.assertCallFromEdt();
-        MapFrame mapFrame = new MapFrame(contentPanePrivate, viewportData);
-        setMapFrame(mapFrame);
-        if (firstLayer != null) {
-            mapFrame.selectMapMode((MapMode) mapFrame.getDefaultButtonAction(), firstLayer);
-        }
-        mapFrame.initializeDialogsPane();
-        // bootstrapping problem: make sure the layer list dialog is going to
-        // listen to change events of the very first layer
-        //
-        if (firstLayer != null) {
-            firstLayer.addPropertyChangeListener(LayerListDialog.getInstance().getModel());
-        }
+        Main.error("createMapFrame() not supported any more.");
     }
 
     /**
      * Replies <code>true</code> if there is an edit layer
+     * <p>
+     * To be removed end of 2016
      *
      * @return <code>true</code> if there is an edit layer
-     */
+     * @deprecated You can get the edit layer using the layer manager and then check if it is not null: {@link #getLayerManager()}
+     */
+    @Deprecated
     public boolean hasEditLayer() {
         if (getEditLayer() == null) return false;
@@ -907,9 +873,12 @@
     /**
      * Replies the current edit layer
+     * <p>
+     * To be removed end of 2016
      *
      * @return the current edit layer. <code>null</code>, if no current edit layer exists
-     */
+     * @deprecated You can get the edit layer using the layer manager: {@link #getLayerManager()}
+     */
+    @Deprecated
     public OsmDataLayer getEditLayer() {
-        if (!isDisplayingMapView()) return null;
         return getLayerManager().getEditLayer();
     }
@@ -917,10 +886,13 @@
     /**
      * Replies the current data set.
+     * <p>
+     * To be removed end of 2016
      *
      * @return the current data set. <code>null</code>, if no current data set exists
-     */
+     * @deprecated You can get the data set using the layer manager: {@link #getLayerManager()}
+     */
+    @Deprecated
     public DataSet getCurrentDataSet() {
-        if (!hasEditLayer()) return null;
-        return getEditLayer().data;
+        return getLayerManager().getEditDataSet();
     }
 
@@ -946,9 +918,12 @@
     /**
      * Returns the currently active  layer
+     * <p>
+     * To be removed end of 2016
      *
      * @return the currently active layer. <code>null</code>, if currently no active layer exists
-     */
+     * @deprecated You can get the layer using the layer manager: {@link #getLayerManager()}
+     */
+    @Deprecated
     public Layer getActiveLayer() {
-        if (!isDisplayingMapView()) return null;
         return getLayerManager().getActiveLayer();
     }
@@ -1015,5 +990,5 @@
      * Global panel.
      */
-    public static final JPanel panel = new JPanel(new BorderLayout());
+    public static final JPanel panel = mainPanel;
 
     private final CommandQueueListener redoUndoListener = new CommandQueueListener() {
@@ -1201,10 +1176,5 @@
         }
         // Remove all layers because somebody may rely on layerRemoved events (like AutosaveTask)
-        if (Main.isDisplayingMapView()) {
-            Collection<Layer> layers = new ArrayList<>(getLayerManager().getLayers());
-            for (Layer l: layers) {
-                Main.main.removeLayer(l);
-            }
-        }
+        getLayerManager().resetState();
         try {
             pref.saveDefaults();
@@ -1692,9 +1662,9 @@
      */
     public static boolean addMapFrameListener(MapFrameListener listener, boolean fireWhenMapViewPresent) {
-        boolean changed = listener != null && mapFrameListeners.add(listener);
-        if (fireWhenMapViewPresent && changed && map != null) {
-            listener.mapFrameInitialized(null, map);
-        }
-        return changed;
+        if (fireWhenMapViewPresent) {
+            return mainPanel.addAndFireMapFrameListener(listener);
+        } else {
+            return mainPanel.addMapFrameListener(listener);
+        }
     }
 
@@ -1706,5 +1676,5 @@
      */
     public static boolean addMapFrameListener(MapFrameListener listener) {
-        return addMapFrameListener(listener, false);
+        return mainPanel.addMapFrameListener(listener);
     }
 
@@ -1716,5 +1686,5 @@
      */
     public static boolean removeMapFrameListener(MapFrameListener listener) {
-        return listener != null && mapFrameListeners.remove(listener);
+        return mainPanel.removeMapFrameListener(listener);
     }
 
Index: /trunk/src/org/openstreetmap/josm/actions/SessionLoadAction.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/actions/SessionLoadAction.java	(revision 10431)
+++ /trunk/src/org/openstreetmap/josm/actions/SessionLoadAction.java	(revision 10432)
@@ -125,13 +125,9 @@
         private void addLayers() {
             if (layers != null && !layers.isEmpty()) {
-                Layer firstLayer = layers.get(0);
                 boolean noMap = Main.map == null;
-                if (noMap) {
-                    Main.main.createMapFrame(firstLayer, viewport);
-                }
                 for (Layer l : layers) {
                     if (canceled)
                         return;
-                    Main.main.addLayer(l, (ViewportData) null);
+                    Main.getLayerManager().addLayer(l);
                 }
                 if (active != null) {
@@ -139,5 +135,5 @@
                 }
                 if (noMap) {
-                    Main.map.setVisible(true);
+                    Main.map.mapView.scheduleZoomTo(viewport);
                 }
             }
Index: /trunk/src/org/openstreetmap/josm/actions/downloadtasks/DownloadGpsTask.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/actions/downloadtasks/DownloadGpsTask.java	(revision 10431)
+++ /trunk/src/org/openstreetmap/josm/actions/downloadtasks/DownloadGpsTask.java	(revision 10432)
@@ -13,4 +13,5 @@
 import org.openstreetmap.josm.data.Bounds;
 import org.openstreetmap.josm.data.Bounds.ParseMethod;
+import org.openstreetmap.josm.data.ViewportData;
 import org.openstreetmap.josm.data.gpx.GpxData;
 import org.openstreetmap.josm.gui.PleaseWaitRunnable;
@@ -141,12 +142,11 @@
             if (layer == null) return null;
             if (newLayer || mergeLayer == null) {
-                if (Main.main != null) {
-                    Main.main.addLayer(layer);
-                }
+                Main.getLayerManager().addLayer(layer);
                 return layer;
             } else {
                 mergeLayer.mergeFrom(layer);
+                mergeLayer.invalidate();
                 if (Main.map != null) {
-                    Main.map.repaint();
+                    Main.map.mapView.scheduleZoomTo(new ViewportData(layer.getViewProjectionBounds()));
                 }
                 return mergeLayer;
Index: /trunk/src/org/openstreetmap/josm/gui/MainApplication.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/MainApplication.java	(revision 10431)
+++ /trunk/src/org/openstreetmap/josm/gui/MainApplication.java	(revision 10432)
@@ -317,4 +317,13 @@
         initApplicationPreferences();
 
+        // Can only be called after preferences are initialized.
+        // We can move this to MainPanel constructor as soon as noone depends on Main#panel any more.
+        GuiHelper.runInEDTAndWait(new Runnable() {
+            @Override
+            public void run() {
+                mainPanel.updateContent();
+            }
+        });
+
         Policy.setPolicy(new Policy() {
             // Permissions for plug-ins loaded when josm is started via webstart
@@ -399,5 +408,5 @@
                 args.containsKey(Option.GEOMETRY) ? args.get(Option.GEOMETRY).iterator().next() : null,
                 !args.containsKey(Option.NO_MAXIMIZE) && Main.pref.getBoolean("gui.maximized", false));
-        final MainFrame mainFrame = new MainFrame(contentPanePrivate, geometry);
+        final MainFrame mainFrame = new MainFrame(contentPanePrivate, mainPanel, geometry);
         Main.parent = mainFrame;
 
Index: /trunk/src/org/openstreetmap/josm/gui/MainFrame.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/MainFrame.java	(revision 10431)
+++ /trunk/src/org/openstreetmap/josm/gui/MainFrame.java	(revision 10432)
@@ -40,8 +40,4 @@
  */
 public class MainFrame extends JFrame {
-    protected transient WindowGeometry geometry;
-    protected int windowState = JFrame.NORMAL;
-    private MainMenu menu;
-
     private final transient LayerStateChangeListener updateTitleOnLayerStateChange = new LayerStateChangeListener() {
         @Override
@@ -52,5 +48,4 @@
 
     private final transient PropertyChangeListener updateTitleOnSaveChange = new PropertyChangeListener() {
-
         @Override
         public void propertyChange(PropertyChangeEvent evt) {
@@ -63,17 +58,22 @@
     };
 
+    protected transient WindowGeometry geometry;
+    protected int windowState = JFrame.NORMAL;
+    private MainMenu menu;
+
     /**
      * Create a new main window.
      */
     public MainFrame() {
-        this(new JPanel(), new WindowGeometry(new Rectangle(10, 10, 500, 500)));
-    }
-
-    /**
-     * Create a new main window.
+        this(new JPanel(), new MainPanel(Main.getLayerManager()), new WindowGeometry(new Rectangle(10, 10, 500, 500)));
+    }
+
+    /**
+     * Create a new main window. The parameters will be removed in the future.
      * @param contentPanePrivate The content
+     * @param mainPanel The main panel.
      * @param geometry The inital geometry to use.
      */
-    public MainFrame(Container contentPanePrivate, WindowGeometry geometry) {
+    public MainFrame(Container contentPanePrivate, MainPanel mainPanel, WindowGeometry geometry) {
         super();
         this.geometry = geometry;
@@ -120,5 +120,4 @@
 
         getContentPane().add(Main.panel, BorderLayout.CENTER);
-        Main.panel.add(Main.main.gettingStarted, BorderLayout.CENTER);
         menu.initialize();
     }
Index: /trunk/src/org/openstreetmap/josm/gui/MainPanel.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/MainPanel.java	(revision 10432)
+++ /trunk/src/org/openstreetmap/josm/gui/MainPanel.java	(revision 10432)
@@ -0,0 +1,182 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.gui;
+
+import java.awt.BorderLayout;
+import java.util.List;
+import java.util.concurrent.CopyOnWriteArrayList;
+
+import javax.swing.JPanel;
+import javax.swing.SwingUtilities;
+
+import org.openstreetmap.josm.Main;
+import org.openstreetmap.josm.actions.mapmode.MapMode;
+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.MainLayerManager;
+import org.openstreetmap.josm.gui.util.GuiHelper;
+
+/**
+ * This is the content panel inside the {@link MainFrame}. It displays the content the user is working with.
+ * <p>
+ * If there is no active layer, there is no content displayed. As soon as there are active layers, the {@link MapFrame} is displayed.
+ *
+ * @author Michael Zangl
+ * @since 10432
+ */
+public class MainPanel extends JPanel {
+    private MapFrame map;
+    // Needs to be lazy because we need to wait for preferences to set up.
+    private GettingStarted gettingStarted;
+    private final CopyOnWriteArrayList<MapFrameListener> mapFrameListeners = new CopyOnWriteArrayList<>();
+    private final transient MainLayerManager layerManager;
+
+    /**
+     * Create a new main panel
+     * @param layerManager The layer manager to use to display the content.
+     */
+    public MainPanel(MainLayerManager layerManager) {
+        super(new BorderLayout());
+        this.layerManager = layerManager;
+        reAddListeners();
+    }
+
+    /**
+     * Update the content of this {@link MainFrame} to either display the map or display the welcome screen.
+     */
+    protected void updateContent() {
+        GuiHelper.assertCallFromEdt();
+        MapFrame old = map;
+        boolean showMap = !layerManager.getLayers().isEmpty();
+        if (old != null && showMap) {
+            // no state change
+            return;
+        }
+
+        // remove old content
+        setVisible(false);
+        removeAll();
+        if (old != null) {
+            old.destroy();
+        }
+
+        // create new content
+        if (showMap) {
+            map = createNewMapFrame();
+        } else {
+            map = null;
+            Main.map = map;
+            add(getGettingStarted(), BorderLayout.CENTER);
+        }
+        setVisible(true);
+
+        if (old == null && !showMap) {
+            // listeners may not be able to handle this...
+            return;
+        }
+
+        // Notify map frame listeners, mostly plugins.
+        for (MapFrameListener listener : mapFrameListeners) {
+            MapView.fireDeprecatedListenerOnAdd = true;
+            listener.mapFrameInitialized(old, map);
+            MapView.fireDeprecatedListenerOnAdd = false;
+        }
+        if (map == null && Main.currentProgressMonitor != null) {
+            Main.currentProgressMonitor.showForegroundDialog();
+        }
+    }
+
+    private MapFrame createNewMapFrame() {
+        MapFrame mapFrame = new MapFrame(null, null);
+        // Required by many components.
+        Main.map = mapFrame;
+
+        mapFrame.fillPanel(this);
+
+        //TODO: Move this to some better place
+        List<Layer> layers = Main.getLayerManager().getLayers();
+        if (!layers.isEmpty()) {
+            mapFrame.selectMapMode((MapMode) mapFrame.getDefaultButtonAction(), layers.get(0));
+        }
+        mapFrame.initializeDialogsPane();
+        mapFrame.setVisible(true);
+        return mapFrame;
+    }
+
+    /**
+     * Registers a new {@code MapFrameListener} that will be notified of MapFrame changes.
+     * <p>
+     * It will fire an initial mapFrameInitialized event
+     * when the MapFrame is present. Otherwise will only fire when the MapFrame is created
+     * or destroyed.
+     * @param listener The MapFrameListener
+     * @return {@code true} if the listeners collection changed as a result of the call.
+     */
+    public boolean addAndFireMapFrameListener(MapFrameListener listener) {
+        boolean changed = addMapFrameListener(listener);
+        if (changed && map != null) {
+            listener.mapFrameInitialized(null, map);
+        }
+        return changed;
+    }
+
+    /**
+     * Registers a new {@code MapFrameListener} that will be notified of MapFrame changes
+     * @param listener The MapFrameListener
+     * @return {@code true} if the listeners collection changed as a result of the call
+     */
+    public boolean addMapFrameListener(MapFrameListener listener) {
+        return listener != null && mapFrameListeners.add(listener);
+    }
+
+    /**
+     * Unregisters the given {@code MapFrameListener} from MapFrame changes
+     * @param listener The MapFrameListener
+     * @return {@code true} if the listeners collection changed as a result of the call
+     */
+    public boolean removeMapFrameListener(MapFrameListener listener) {
+        return listener != null && mapFrameListeners.remove(listener);
+    }
+
+    /**
+     * Gets the {@link GettingStarted} panel.
+     * @return The panel.
+     */
+    public GettingStarted getGettingStarted() {
+        if (gettingStarted == null) {
+            gettingStarted = new GettingStarted();
+        }
+        return gettingStarted;
+    }
+
+    /**
+     * Re-adds the layer listeners. Never call this in production, only needed for testing.
+     */
+    public void reAddListeners() {
+        layerManager.addLayerChangeListener(new LayerChangeListener() {
+            @Override
+            public void layerAdded(LayerAddEvent e) {
+                updateContent();
+            }
+
+            @Override
+            public void layerRemoving(final LayerRemoveEvent e) {
+                // Delay main.map removal until after all listeners are finished.
+                // Some components rely on this and e.g. get the MapView that way.
+                SwingUtilities.invokeLater(new Runnable() {
+                    @Override
+                    public void run() {
+                        updateContent();
+                    }
+                });
+            }
+
+            @Override
+            public void layerOrderChanged(LayerOrderChangeEvent e) {
+                // ignored
+            }
+        });
+    }
+}
Index: /trunk/src/org/openstreetmap/josm/gui/MapFrame.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/MapFrame.java	(revision 10431)
+++ /trunk/src/org/openstreetmap/josm/gui/MapFrame.java	(revision 10432)
@@ -188,6 +188,5 @@
     /**
      * Constructs a new {@code MapFrame}.
-     * @param contentPane The content pane used to register shortcuts in its
-     * {@link javax.swing.InputMap} and {@link javax.swing.ActionMap}
+     * @param contentPane Ignored. Main content pane is used.
      * @param viewportData the initial viewport of the map. Can be null, then
      * the viewport is derived from the layer data.
Index: /trunk/src/org/openstreetmap/josm/gui/MapMover.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/MapMover.java	(revision 10431)
+++ /trunk/src/org/openstreetmap/josm/gui/MapMover.java	(revision 10432)
@@ -11,11 +11,8 @@
 import java.awt.event.MouseEvent;
 import java.awt.event.MouseWheelEvent;
+import java.util.ArrayList;
 
 import javax.swing.AbstractAction;
-import javax.swing.ActionMap;
-import javax.swing.InputMap;
-import javax.swing.JComponent;
 import javax.swing.JPanel;
-import javax.swing.KeyStroke;
 
 import org.openstreetmap.gui.jmapviewer.JMapViewer;
@@ -27,4 +24,5 @@
 import org.openstreetmap.josm.data.preferences.BooleanProperty;
 import org.openstreetmap.josm.tools.Destroyable;
+import org.openstreetmap.josm.tools.Pair;
 import org.openstreetmap.josm.tools.Shortcut;
 
@@ -64,5 +62,16 @@
 
         ZoomerAction(String action) {
+            this(action, "MapMover.Zoomer." + action);
+        }
+
+        /**
+         * Constructs a new {@code ZoomerAction}.
+         * @param action action
+         * @param name name
+         * @since 10432
+         */
+        public ZoomerAction(String action, String name) {
             this.action = action;
+            putValue(NAME, name);
         }
 
@@ -107,58 +116,44 @@
      */
     private final NavigatableComponent nc;
-    private final JPanel contentPane;
 
     private boolean movementInPlace;
+
+    private final ArrayList<Pair<ZoomerAction, Shortcut>> registeredShortcuts = new ArrayList<>();
 
     /**
      * Constructs a new {@code MapMover}.
      * @param navComp the navigatable component
-     * @param contentPane the content pane
+     * @param contentPane Ignored. The main action map is used.
      */
     public MapMover(NavigatableComponent navComp, JPanel contentPane) {
         this.nc = navComp;
-        this.contentPane = contentPane;
         nc.addMouseListener(this);
         nc.addMouseMotionListener(this);
         nc.addMouseWheelListener(this);
 
-        if (contentPane != null) {
-            // CHECKSTYLE.OFF: LineLength
-            contentPane.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(
-                Shortcut.registerShortcut("system:movefocusright", tr("Map: {0}", tr("Move right")), KeyEvent.VK_RIGHT, Shortcut.CTRL).getKeyStroke(),
-                "MapMover.Zoomer.right");
-            contentPane.getActionMap().put("MapMover.Zoomer.right", new ZoomerAction("right"));
-
-            contentPane.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(
-                Shortcut.registerShortcut("system:movefocusleft", tr("Map: {0}", tr("Move left")), KeyEvent.VK_LEFT, Shortcut.CTRL).getKeyStroke(),
-                "MapMover.Zoomer.left");
-            contentPane.getActionMap().put("MapMover.Zoomer.left", new ZoomerAction("left"));
-
-            contentPane.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(
-                Shortcut.registerShortcut("system:movefocusup", tr("Map: {0}", tr("Move up")), KeyEvent.VK_UP, Shortcut.CTRL).getKeyStroke(),
-                "MapMover.Zoomer.up");
-            contentPane.getActionMap().put("MapMover.Zoomer.up", new ZoomerAction("up"));
-
-            contentPane.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(
-                Shortcut.registerShortcut("system:movefocusdown", tr("Map: {0}", tr("Move down")), KeyEvent.VK_DOWN, Shortcut.CTRL).getKeyStroke(),
-                "MapMover.Zoomer.down");
-            contentPane.getActionMap().put("MapMover.Zoomer.down", new ZoomerAction("down"));
-            // CHECKSTYLE.ON: LineLength
-
-            // see #10592 - Disable these alternate shortcuts on OS X because of conflict with system shortcut
-            if (!Main.isPlatformOsx()) {
-                contentPane.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(
-                    Shortcut.registerShortcut("view:zoominalternate",
-                            tr("Map: {0}", tr("Zoom in")), KeyEvent.VK_COMMA, Shortcut.CTRL).getKeyStroke(),
-                    "MapMover.Zoomer.in");
-                contentPane.getActionMap().put("MapMover.Zoomer.in", new ZoomerAction(","));
-
-                contentPane.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(
-                    Shortcut.registerShortcut("view:zoomoutalternate",
-                            tr("Map: {0}", tr("Zoom out")), KeyEvent.VK_PERIOD, Shortcut.CTRL).getKeyStroke(),
-                    "MapMover.Zoomer.out");
-                contentPane.getActionMap().put("MapMover.Zoomer.out", new ZoomerAction("."));
-            }
-        }
+        registerActionShortcut(new ZoomerAction("right"),
+                Shortcut.registerShortcut("system:movefocusright", tr("Map: {0}", tr("Move right")), KeyEvent.VK_RIGHT, Shortcut.CTRL));
+
+        registerActionShortcut(new ZoomerAction("left"),
+                Shortcut.registerShortcut("system:movefocusleft", tr("Map: {0}", tr("Move left")), KeyEvent.VK_LEFT, Shortcut.CTRL));
+
+        registerActionShortcut(new ZoomerAction("up"),
+                Shortcut.registerShortcut("system:movefocusup", tr("Map: {0}", tr("Move up")), KeyEvent.VK_UP, Shortcut.CTRL));
+        registerActionShortcut(new ZoomerAction("down"),
+                Shortcut.registerShortcut("system:movefocusdown", tr("Map: {0}", tr("Move down")), KeyEvent.VK_DOWN, Shortcut.CTRL));
+
+        // see #10592 - Disable these alternate shortcuts on OS X because of conflict with system shortcut
+        if (!Main.isPlatformOsx()) {
+            registerActionShortcut(new ZoomerAction(",", "MapMover.Zoomer.in"),
+                    Shortcut.registerShortcut("view:zoominalternate", tr("Map: {0}", tr("Zoom in")), KeyEvent.VK_COMMA, Shortcut.CTRL));
+
+            registerActionShortcut(new ZoomerAction(".", "MapMover.Zoomer.out"),
+                    Shortcut.registerShortcut("view:zoomoutalternate", tr("Map: {0}", tr("Zoom out")), KeyEvent.VK_PERIOD, Shortcut.CTRL));
+        }
+    }
+
+    private void registerActionShortcut(ZoomerAction action, Shortcut shortcut) {
+        Main.registerActionShortcut(action, shortcut);
+        registeredShortcuts.add(new Pair<>(action, shortcut));
     }
 
@@ -270,24 +265,6 @@
     @Override
     public void destroy() {
-        if (this.contentPane != null) {
-            InputMap inputMap = contentPane.getInputMap();
-            KeyStroke[] inputKeys = inputMap.keys();
-            if (inputKeys != null) {
-                for (KeyStroke key : inputKeys) {
-                    Object binding = inputMap.get(key);
-                    if (binding instanceof String && ((String) binding).startsWith("MapMover.")) {
-                        inputMap.remove(key);
-                    }
-                }
-            }
-            ActionMap actionMap = contentPane.getActionMap();
-            Object[] actionsKeys = actionMap.keys();
-            if (actionsKeys != null) {
-                for (Object key : actionsKeys) {
-                    if (key instanceof String && ((String) key).startsWith("MapMover.")) {
-                        actionMap.remove(key);
-                    }
-                }
-            }
+        for (Pair<ZoomerAction, Shortcut> shortcut : registeredShortcuts) {
+            Main.unregisterActionShortcut(shortcut.a, shortcut.b);
         }
     }
Index: /trunk/src/org/openstreetmap/josm/gui/MapView.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/MapView.java	(revision 10431)
+++ /trunk/src/org/openstreetmap/josm/gui/MapView.java	(revision 10432)
@@ -32,6 +32,4 @@
 
 import javax.swing.AbstractButton;
-import javax.swing.ActionMap;
-import javax.swing.InputMap;
 import javax.swing.JComponent;
 import javax.swing.JPanel;
@@ -42,4 +40,5 @@
 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;
@@ -495,6 +494,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}
+     * @param contentPane Ignored. Main content pane is used.
      * @param viewportData the initial viewport of the map. Can be null, then
      * the viewport is derived from the layer data.
@@ -598,4 +596,9 @@
         if (layer instanceof MarkerLayer && playHeadMarker == null) {
             playHeadMarker = PlayHeadMarker.create();
+        }
+
+        ProjectionBounds viewProjectionBounds = layer.getViewProjectionBounds();
+        if (viewProjectionBounds != null) {
+            scheduleZoomTo(new ViewportData(viewProjectionBounds));
         }
 
Index: /trunk/src/org/openstreetmap/josm/gui/dialogs/LayerListDialog.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/dialogs/LayerListDialog.java	(revision 10431)
+++ /trunk/src/org/openstreetmap/josm/gui/dialogs/LayerListDialog.java	(revision 10432)
@@ -331,5 +331,5 @@
     public void showNotify() {
         layerManager.addActiveLayerChangeListener(activateLayerAction);
-        layerManager.addLayerChangeListener(model);
+        layerManager.addLayerChangeListener(model, true);
         layerManager.addAndFireActiveLayerChangeListener(model);
         model.populate();
@@ -338,5 +338,5 @@
     @Override
     public void hideNotify() {
-        layerManager.removeLayerChangeListener(model);
+        layerManager.removeLayerChangeListener(model, true);
         layerManager.removeActiveLayerChangeListener(model);
         layerManager.removeActiveLayerChangeListener(activateLayerAction);
Index: /trunk/src/org/openstreetmap/josm/gui/layer/LayerManager.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/layer/LayerManager.java	(revision 10431)
+++ /trunk/src/org/openstreetmap/josm/gui/layer/LayerManager.java	(revision 10432)
@@ -90,8 +90,10 @@
     public static class LayerRemoveEvent extends LayerManagerEvent {
         private final Layer removedLayer;
+        private final boolean lastLayer;
 
         LayerRemoveEvent(LayerManager source, Layer removedLayer) {
             super(source);
             this.removedLayer = removedLayer;
+            this.lastLayer = source.getLayers().size() == 1;
         }
 
@@ -102,4 +104,13 @@
         public Layer getRemovedLayer() {
             return removedLayer;
+        }
+
+        /**
+         * Check if the layer that was removed is the last layer in the list.
+         * @return <code>true</code> if this was the last layer.
+         * @since 10432
+         */
+        public boolean isLastLayer() {
+            return lastLayer;
         }
     }
@@ -347,3 +358,16 @@
         }
     }
+
+    /**
+     * Reset all layer manager state. This includes removing all layers and then unregistering all listeners
+     * @since 10432
+     */
+    public void resetState() {
+        // some layer remove listeners remove other layers.
+        while (!getLayers().isEmpty()) {
+            removeLayer(getLayers().get(0));
+        }
+
+        layerChangeListeners.clear();
+    }
 }
Index: /trunk/src/org/openstreetmap/josm/gui/layer/MainLayerManager.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/layer/MainLayerManager.java	(revision 10431)
+++ /trunk/src/org/openstreetmap/josm/gui/layer/MainLayerManager.java	(revision 10432)
@@ -313,3 +313,11 @@
         return ret;
     }
+
+    @Override
+    public void resetState() {
+        // active and edit layer are unset automatically
+        super.resetState();
+
+        activeLayerChangeListeners.clear();
+    }
 }
Index: /trunk/src/org/openstreetmap/josm/io/NoteImporter.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/io/NoteImporter.java	(revision 10431)
+++ /trunk/src/org/openstreetmap/josm/io/NoteImporter.java	(revision 10432)
@@ -14,5 +14,4 @@
 import org.openstreetmap.josm.gui.layer.NoteLayer;
 import org.openstreetmap.josm.gui.progress.ProgressMonitor;
-import org.openstreetmap.josm.gui.util.GuiHelper;
 import org.xml.sax.SAXException;
 
@@ -38,11 +37,6 @@
         try (InputStream is = Compression.getUncompressedFileInputStream(file)) {
             final NoteLayer layer = loadLayer(is, file, file.getName(), progressMonitor);
-            if (Main.map == null || !Main.getLayerManager().containsLayer(layer)) {
-                GuiHelper.runInEDT(new Runnable() {
-                    @Override
-                    public void run() {
-                        Main.main.addLayer(layer);
-                    }
-                });
+            if (!Main.getLayerManager().containsLayer(layer)) {
+                Main.getLayerManager().addLayer(layer);
             }
         } catch (SAXException e) {
Index: /trunk/test/unit/org/openstreetmap/josm/io/NoteImporterTest.java
===================================================================
--- /trunk/test/unit/org/openstreetmap/josm/io/NoteImporterTest.java	(revision 10431)
+++ /trunk/test/unit/org/openstreetmap/josm/io/NoteImporterTest.java	(revision 10432)
@@ -7,8 +7,9 @@
 import java.io.File;
 
+import org.junit.Rule;
 import org.junit.Test;
 import org.openstreetmap.josm.Main;
 import org.openstreetmap.josm.TestUtils;
-import org.openstreetmap.josm.gui.layer.Layer;
+import org.openstreetmap.josm.testutils.JOSMTestRules;
 
 /**
@@ -18,14 +19,15 @@
 
     /**
+     * Use the test rules to remove any layers and reset state.
+     */
+    @Rule
+    public final JOSMTestRules rules = new JOSMTestRules();
+
+    /**
      * Non-regression test for <a href="https://josm.openstreetmap.de/ticket/12531">Bug #12531</a>.
      */
     @Test
     public void testTicket12531() {
-        if (Main.map != null) {
-            for (Layer l: Main.getLayerManager().getLayers()) {
-                Main.getLayerManager().removeLayer(l);
-            }
-            Main.main.setMapFrame(null);
-        }
+        Main.getLayerManager().resetState();
         assertNull(Main.map);
         assertTrue(new NoteImporter().importDataHandleExceptions(
Index: /trunk/test/unit/org/openstreetmap/josm/testutils/JOSMTestRules.java
===================================================================
--- /trunk/test/unit/org/openstreetmap/josm/testutils/JOSMTestRules.java	(revision 10431)
+++ /trunk/test/unit/org/openstreetmap/josm/testutils/JOSMTestRules.java	(revision 10432)
@@ -13,5 +13,4 @@
 import org.openstreetmap.josm.Main;
 import org.openstreetmap.josm.data.projection.Projections;
-import org.openstreetmap.josm.gui.layer.MainLayerManager;
 import org.openstreetmap.josm.gui.util.GuiHelper;
 import org.openstreetmap.josm.io.OsmApi;
@@ -223,8 +222,5 @@
         });
         // Remove all layers
-        MainLayerManager lm = Main.getLayerManager();
-        while (!lm.getLayers().isEmpty()) {
-            lm.removeLayer(lm.getLayers().get(0));
-        }
+        Main.getLayerManager().resetState();
 
         // TODO: Remove global listeners and other global state.
