Index: trunk/src/org/openstreetmap/josm/actions/ExtensionFileFilter.java
===================================================================
--- trunk/src/org/openstreetmap/josm/actions/ExtensionFileFilter.java	(revision 5458)
+++ trunk/src/org/openstreetmap/josm/actions/ExtensionFileFilter.java	(revision 5459)
@@ -12,4 +12,5 @@
 import javax.swing.filechooser.FileFilter;
 
+import org.openstreetmap.josm.gui.MapView;
 import org.openstreetmap.josm.io.AllFormatsImporter;
 import org.openstreetmap.josm.io.FileExporter;
@@ -51,4 +52,5 @@
                 "org.openstreetmap.josm.io.OsmBzip2Importer",
                 "org.openstreetmap.josm.io.JpgImporter",
+                "org.openstreetmap.josm.io.WMSLayerImporter",
                 "org.openstreetmap.josm.io.AllFormatsImporter"
         };
@@ -56,7 +58,8 @@
         for (String classname : importerNames) {
             try {
-                Class<?> klass = Class.forName(classname);
-                importers.add((FileImporter) klass.newInstance());
-            } catch (Exception e) {}
+                FileImporter importer = (FileImporter) Class.forName(classname).newInstance();
+                importers.add(importer);
+                MapView.addLayerChangeListener(importer);
+            } catch (Throwable t) { }
         }
 
@@ -69,11 +72,13 @@
                 "org.openstreetmap.josm.io.OsmBzip2Exporter",
                 "org.openstreetmap.josm.io.GeoJSONExporter",
+                "org.openstreetmap.josm.io.WMSLayerExporter"
         };
 
         for (String classname : exporterNames) {
             try {
-                Class<?> klass = Class.forName(classname);
-                exporters.add((FileExporter)klass.newInstance());
-            } catch (Exception e) {}
+                FileExporter exporter = (FileExporter)Class.forName(classname).newInstance();
+                exporters.add(exporter);
+                MapView.addLayerChangeListener(exporter);
+            } catch (Throwable t) { }
         }
     }
@@ -134,9 +139,9 @@
 
     /**
-     * Replies an ordered list of {@link ExtensionFileFilter}s for exporting.
+     * Replies an ordered list of enabled {@link ExtensionFileFilter}s for exporting.
      * The list is ordered according to their description, an {@link AllFormatsImporter}
      * is append at the end.
      *
-     * @return an ordered list of {@link ExtensionFileFilter}s for exporting.
+     * @return an ordered list of enabled {@link ExtensionFileFilter}s for exporting.
      * @since 2029
      */
@@ -144,5 +149,5 @@
         LinkedList<ExtensionFileFilter> filters = new LinkedList<ExtensionFileFilter>();
         for (FileExporter exporter : exporters) {
-            if (filters.contains(exporter.filter)) {
+            if (filters.contains(exporter.filter) || !exporter.isEnabled()) {
                 continue;
             }
Index: trunk/src/org/openstreetmap/josm/actions/JosmAction.java
===================================================================
--- trunk/src/org/openstreetmap/josm/actions/JosmAction.java	(revision 5458)
+++ trunk/src/org/openstreetmap/josm/actions/JosmAction.java	(revision 5459)
@@ -128,4 +128,5 @@
     }
 
+    @Override
     public void destroy() {
         if (sc != null) {
Index: trunk/src/org/openstreetmap/josm/actions/SaveAction.java
===================================================================
--- trunk/src/org/openstreetmap/josm/actions/SaveAction.java	(revision 5458)
+++ trunk/src/org/openstreetmap/josm/actions/SaveAction.java	(revision 5459)
@@ -36,5 +36,4 @@
     }
 
-
     @Override public File getFile(Layer layer) {
         File f = layer.getAssociatedFile();
@@ -59,5 +58,5 @@
             }
         }
-        return f == null ? openFileDialog(layer) : f;
+        return f == null ? layer.createAndOpenSaveFileChooser() : f;
     }
 }
Index: trunk/src/org/openstreetmap/josm/actions/SaveActionBase.java
===================================================================
--- trunk/src/org/openstreetmap/josm/actions/SaveActionBase.java	(revision 5458)
+++ trunk/src/org/openstreetmap/josm/actions/SaveActionBase.java	(revision 5459)
@@ -16,12 +16,8 @@
 
 import org.openstreetmap.josm.Main;
-import org.openstreetmap.josm.data.conflict.ConflictCollection;
-import org.openstreetmap.josm.data.osm.OsmPrimitive;
 import org.openstreetmap.josm.gui.ExtendedDialog;
-import org.openstreetmap.josm.gui.layer.GpxLayer;
 import org.openstreetmap.josm.gui.layer.Layer;
 import org.openstreetmap.josm.gui.layer.OsmDataLayer;
 import org.openstreetmap.josm.io.FileExporter;
-import org.openstreetmap.josm.io.GpxImporter;
 import org.openstreetmap.josm.tools.Shortcut;
 
@@ -44,16 +40,15 @@
 
     public boolean doSave() {
-        Layer layer = null;
-        if (Main.isDisplayingMapView() && (Main.map.mapView.getActiveLayer() instanceof OsmDataLayer
-                || Main.map.mapView.getActiveLayer() instanceof GpxLayer)) {
-            layer = Main.map.mapView.getActiveLayer();
+        if (Main.isDisplayingMapView()) {
+            Layer layer = Main.map.mapView.getActiveLayer();
+            if (layer != null && layer.isSavable()) {
+                return doSave(layer);
+            }
         }
-        if (layer == null)
-            return false;
-        return doSave(layer);
+        return false;
     }
 
     public boolean doSave(Layer layer) {
-        if(!checkSaveConditions(layer))
+        if(!layer.checkSaveConditions())
             return false;
         file = getFile(layer);
@@ -62,5 +57,5 @@
 
     public static boolean doSave(Layer layer, File file) {
-        if(!checkSaveConditions(layer))
+        if(!layer.checkSaveConditions())
             return false;
         return doInternalSave(layer, file);
@@ -101,65 +96,4 @@
 
     /**
-     * Checks whether it is ok to launch a save (whether we have data,
-     * there is no conflict etc.)
-     * @return <code>true</code>, if it is safe to save.
-     */
-    public static boolean checkSaveConditions(Layer layer) {
-        if (layer instanceof GpxLayer)
-            return ((GpxLayer)layer).data != null;
-        else if (layer instanceof OsmDataLayer)  {
-            if (isDataSetEmpty((OsmDataLayer)layer)) {
-                ExtendedDialog dialog = new ExtendedDialog(
-                        Main.parent,
-                        tr("Empty document"),
-                        new String[] {tr("Save anyway"), tr("Cancel")}
-                );
-                dialog.setContent(tr("The document contains no data."));
-                dialog.setButtonIcons(new String[] {"save.png", "cancel.png"});
-                dialog.showDialog();
-                if (dialog.getValue() != 1) return false;
-            }
-
-            ConflictCollection conflicts = ((OsmDataLayer)layer).getConflicts();
-            if (conflicts != null && !conflicts.isEmpty()) {
-                ExtendedDialog dialog = new ExtendedDialog(
-                        Main.parent,
-                        /* I18N: Display title of the window showing conflicts */
-                        tr("Conflicts"),
-                        new String[] {tr("Reject Conflicts and Save"), tr("Cancel")}
-                );
-                dialog.setContent(tr("There are unresolved conflicts. Conflicts will not be saved and handled as if you rejected all. Continue?"));
-                dialog.setButtonIcons(new String[] {"save.png", "cancel.png"});
-                dialog.showDialog();
-                if (dialog.getValue() != 1) return false;
-            }
-            return true;
-        }
-        return false;
-    }
-
-    public static File openFileDialog(Layer layer) {
-        if (layer instanceof OsmDataLayer)
-            return createAndOpenSaveFileChooser(tr("Save OSM file"), "osm");
-        else if (layer instanceof GpxLayer)
-            return createAndOpenSaveFileChooser(tr("Save GPX file"), GpxImporter.FILE_FILTER);
-        return createAndOpenSaveFileChooser(tr("Save Layer"), "lay");
-    }
-
-    /**
-     * Check the data set if it would be empty on save. It is empty, if it contains
-     * no objects (after all objects that are created and deleted without being
-     * transferred to the server have been removed).
-     *
-     * @return <code>true</code>, if a save result in an empty data set.
-     */
-    private static boolean isDataSetEmpty(OsmDataLayer layer) {
-        for (OsmPrimitive osm : layer.data.allNonDeletedPrimitives())
-            if (!osm.isDeleted() || !osm.isNewOrUndeleted())
-                return false;
-        return true;
-    }
-
-    /**
      * Refreshes the enabled state
      *
@@ -179,5 +113,5 @@
         }
         Layer layer = Main.map.mapView.getActiveLayer();
-        setEnabled(layer instanceof OsmDataLayer || layer instanceof GpxLayer);
+        setEnabled(layer != null && layer.isSavable());
     }
 
Index: trunk/src/org/openstreetmap/josm/actions/SaveAsAction.java
===================================================================
--- trunk/src/org/openstreetmap/josm/actions/SaveAsAction.java	(revision 5458)
+++ trunk/src/org/openstreetmap/josm/actions/SaveAsAction.java	(revision 5459)
@@ -21,5 +21,4 @@
     /**
      * Construct the action with "Save" as label.
-     * @param layer Save this layer.
      */
     public SaveAsAction() {
@@ -35,5 +34,5 @@
 
     @Override protected File getFile(Layer layer) {
-        return openFileDialog(layer);
+        return layer.createAndOpenSaveFileChooser();
     }
 }
Index: trunk/src/org/openstreetmap/josm/actions/mapmode/DrawAction.java
===================================================================
--- trunk/src/org/openstreetmap/josm/actions/mapmode/DrawAction.java	(revision 5458)
+++ trunk/src/org/openstreetmap/josm/actions/mapmode/DrawAction.java	(revision 5459)
@@ -2,5 +2,4 @@
 package org.openstreetmap.josm.actions.mapmode;
 
-import java.awt.*;
 import static org.openstreetmap.josm.gui.help.HelpUtil.ht;
 import static org.openstreetmap.josm.tools.I18n.marktr;
@@ -8,4 +7,14 @@
 import static org.openstreetmap.josm.tools.I18n.trn;
 
+import java.awt.AWTEvent;
+import java.awt.BasicStroke;
+import java.awt.Color;
+import java.awt.Component;
+import java.awt.Cursor;
+import java.awt.Graphics2D;
+import java.awt.KeyboardFocusManager;
+import java.awt.Point;
+import java.awt.Stroke;
+import java.awt.Toolkit;
 import java.awt.event.AWTEventListener;
 import java.awt.event.ActionEvent;
@@ -29,5 +38,12 @@
 import java.util.TreeSet;
 
-import javax.swing.*;
+import javax.swing.AbstractAction;
+import javax.swing.JCheckBoxMenuItem;
+import javax.swing.JFrame;
+import javax.swing.JMenuItem;
+import javax.swing.JOptionPane;
+import javax.swing.JPopupMenu;
+import javax.swing.SwingUtilities;
+import javax.swing.Timer;
 
 import org.openstreetmap.josm.Main;
@@ -91,10 +107,11 @@
     private EastNorth currentMouseEastNorth;
 
-    private SnapHelper snapHelper = new SnapHelper();
+    private final SnapHelper snapHelper = new SnapHelper();
 
     private Shortcut backspaceShortcut;
-    private Shortcut snappingShortcut;
-
-    private JCheckBoxMenuItem snapCheckboxMenuItem;
+    private final Shortcut snappingShortcut;
+
+    private final SnapChangeAction snapChangeAction;
+    private final JCheckBoxMenuItem snapCheckboxMenuItem;
     private boolean useRepeatedShortcut;
 
@@ -106,5 +123,6 @@
         snappingShortcut = Shortcut.registerShortcut("mapmode:drawanglesnapping",
             tr("Mode: Draw Angle snapping"), KeyEvent.VK_TAB, Shortcut.DIRECT);
-        addMenuItem();
+        snapChangeAction = new SnapChangeAction();
+        snapCheckboxMenuItem = addMenuItem();
         snapHelper.setMenuCheckBox(snapCheckboxMenuItem);
         cursorJoinNode = ImageProvider.getCursor("crosshair", "joinnode");
@@ -112,5 +130,5 @@
     }
 
-    private void addMenuItem() {
+    private JCheckBoxMenuItem addMenuItem() {
         int n=Main.main.menu.editMenu.getItemCount();
         for (int i=n-1;i>0;i--) {
@@ -120,5 +138,5 @@
             }
         }
-        snapCheckboxMenuItem = MainMenu.addWithCheckbox(Main.main.menu.editMenu, new SnapChangeAction(),  MainMenu.WINDOW_MENU_GROUP.VOLATILE);
+        return MainMenu.addWithCheckbox(Main.main.menu.editMenu, snapChangeAction, MainMenu.WINDOW_MENU_GROUP.VOLATILE);
     }
 
@@ -1207,4 +1225,5 @@
     public void destroy() {
         super.destroy();
+        snapChangeAction.destroy();
     }
 
Index: trunk/src/org/openstreetmap/josm/data/osm/visitor/paint/relations/MultipolygonCache.java
===================================================================
--- trunk/src/org/openstreetmap/josm/data/osm/visitor/paint/relations/MultipolygonCache.java	(revision 5458)
+++ trunk/src/org/openstreetmap/josm/data/osm/visitor/paint/relations/MultipolygonCache.java	(revision 5459)
@@ -27,4 +27,5 @@
 import org.openstreetmap.josm.data.projection.Projection;
 import org.openstreetmap.josm.data.projection.ProjectionChangeListener;
+import org.openstreetmap.josm.gui.MapView;
 import org.openstreetmap.josm.gui.MapView.LayerChangeListener;
 import org.openstreetmap.josm.gui.NavigatableComponent;
@@ -49,4 +50,5 @@
         Main.addProjectionChangeListener(this);
         DataSet.addSelectionListener(this);
+        MapView.addLayerChangeListener(this);
     }
 
Index: trunk/src/org/openstreetmap/josm/gui/ImageryMenu.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/ImageryMenu.java	(revision 5458)
+++ trunk/src/org/openstreetmap/josm/gui/ImageryMenu.java	(revision 5459)
@@ -24,5 +24,4 @@
 import org.openstreetmap.josm.gui.layer.ImageryLayer;
 import org.openstreetmap.josm.gui.layer.Layer;
-import org.openstreetmap.josm.gui.layer.WMSLayer;
 import org.openstreetmap.josm.tools.ImageProvider;
 
@@ -69,17 +68,4 @@
     JMenuItem offsetMenuItem = singleOffset;
     Map_Rectifier_WMSmenuAction rectaction = new Map_Rectifier_WMSmenuAction();
-    JosmAction blankmenu = new JosmAction(
-            tr("Blank Layer"), /* ICON */"blankmenu", tr("Open a blank WMS layer to load data from a file"), null, false) {
-        @Override
-        public void actionPerformed(ActionEvent ev) {
-            if (!isEnabled()) return;
-            Main.main.addLayer(new WMSLayer());
-        }
-
-        @Override
-        protected void updateEnabledState() {
-            setEnabled(Main.map != null && Main.map.mapView != null && !Main.map.mapView.getAllLayers().isEmpty());
-        }
-    };
     int offsPos;
 
@@ -102,6 +88,4 @@
         offsPos = getMenuComponentCount();
         add(offsetMenuItem);
-        addSeparator();
-        add(new JMenuItem(blankmenu));
     }
 
Index: trunk/src/org/openstreetmap/josm/gui/MapFrame.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/MapFrame.java	(revision 5458)
+++ trunk/src/org/openstreetmap/josm/gui/MapFrame.java	(revision 5459)
@@ -235,9 +235,9 @@
     }
 
-    public void selectDrawTool(boolean onlyIfModeless) {
+    public boolean selectDrawTool(boolean onlyIfModeless) {
         if(onlyIfModeless && !Main.pref.getBoolean("modeless", false))
-            return;
-
-        selectMapMode(mapModeDraw);
+            return false;
+
+        return selectMapMode(mapModeDraw);
     }
 
Index: trunk/src/org/openstreetmap/josm/gui/MapView.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/MapView.java	(revision 5458)
+++ trunk/src/org/openstreetmap/josm/gui/MapView.java	(revision 5459)
@@ -106,5 +106,5 @@
      * the layer listeners
      */
-    private static final CopyOnWriteArrayList<MapView.LayerChangeListener> layerChangeListeners = new CopyOnWriteArrayList<MapView.LayerChangeListener>();
+    private static final CopyOnWriteArrayList<LayerChangeListener> layerChangeListeners = new CopyOnWriteArrayList<LayerChangeListener>();
     private static final CopyOnWriteArrayList<EditLayerChangeListener> editLayerChangeListeners = new CopyOnWriteArrayList<EditLayerChangeListener>();
 
@@ -114,5 +114,5 @@
      * @param listener the listener. Ignored if null or already registered.
      */
-    public static void removeLayerChangeListener(MapView.LayerChangeListener listener) {
+    public static void removeLayerChangeListener(LayerChangeListener listener) {
         layerChangeListeners.remove(listener);
     }
@@ -127,5 +127,5 @@
      * @param listener the listener. Ignored if null or already registered.
      */
-    public static void addLayerChangeListener(MapView.LayerChangeListener listener) {
+    public static void addLayerChangeListener(LayerChangeListener listener) {
         if (listener != null) {
             layerChangeListeners.addIfAbsent(listener);
@@ -222,9 +222,4 @@
     public MapView(final JPanel contentPane) {
         Main.pref.addPreferenceChangeListener(this);
-
-        //        new MoveAction(MoveAction.Direction.UP);
-        //        new MoveAction(MoveAction.Direction.DOWN);
-        //        new MoveAction(MoveAction.Direction.LEFT);
-        //        new MoveAction(MoveAction.Direction.RIGHT);
 
         addComponentListener(new ComponentAdapter(){
@@ -265,7 +260,4 @@
             }
         });
-
-        // Add Multipolygon cache to layer listeners
-        addLayerChangeListener(MultipolygonCache.getInstance());
     }
 
Index: trunk/src/org/openstreetmap/josm/gui/dialogs/properties/PropertiesDialog.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/dialogs/properties/PropertiesDialog.java	(revision 5458)
+++ trunk/src/org/openstreetmap/josm/gui/dialogs/properties/PropertiesDialog.java	(revision 5459)
@@ -199,14 +199,15 @@
     };
 
-    private DataSetListenerAdapter dataChangedAdapter = new DataSetListenerAdapter(this);
-    private HelpAction helpAction = new HelpAction();
-    private CopyValueAction copyValueAction = new CopyValueAction();
-    private CopyKeyValueAction copyKeyValueAction = new CopyKeyValueAction();
-    private CopyAllKeyValueAction copyAllKeyValueAction = new CopyAllKeyValueAction();
-    private SearchAction searchActionSame = new SearchAction(true);
-    private SearchAction searchActionAny = new SearchAction(false);
-    private AddAction addAction = new AddAction();
-    private EditAction editAction = new EditAction();
-    private DeleteAction deleteAction = new DeleteAction();
+    private final DataSetListenerAdapter dataChangedAdapter = new DataSetListenerAdapter(this);
+    private final HelpAction helpAction = new HelpAction();
+    private final CopyValueAction copyValueAction = new CopyValueAction();
+    private final CopyKeyValueAction copyKeyValueAction = new CopyKeyValueAction();
+    private final CopyAllKeyValueAction copyAllKeyValueAction = new CopyAllKeyValueAction();
+    private final SearchAction searchActionSame = new SearchAction(true);
+    private final SearchAction searchActionAny = new SearchAction(false);
+    private final AddAction addAction = new AddAction();
+    private final EditAction editAction = new EditAction();
+    private final DeleteAction deleteAction = new DeleteAction();
+    private final JosmAction[] josmActions = new JosmAction[]{addAction, editAction, deleteAction};
 
     @Override
@@ -215,7 +216,7 @@
         SelectionEventManager.getInstance().addSelectionListener(this, FireMode.IN_EDT_CONSOLIDATED);
         MapView.addEditLayerChangeListener(this);
-        Main.registerActionShortcut(addAction);
-        Main.registerActionShortcut(editAction);
-        Main.registerActionShortcut(deleteAction);
+        for (JosmAction action : josmActions) {
+            Main.registerActionShortcut(action);
+        }
         updateSelection();
     }
@@ -226,7 +227,7 @@
         SelectionEventManager.getInstance().removeSelectionListener(this);
         MapView.removeEditLayerChangeListener(this);
-        Main.unregisterActionShortcut(addAction);
-        Main.unregisterActionShortcut(editAction);
-        Main.unregisterActionShortcut(deleteAction);
+        for (JosmAction action : josmActions) {
+            Main.unregisterActionShortcut(action);
+        }
     }
 
@@ -1670,3 +1671,11 @@
         }
     }
+
+    @Override
+    public void destroy() {
+        super.destroy();
+        for (JosmAction action : josmActions) {
+            action.destroy();
+        }
+    }
 }
Index: trunk/src/org/openstreetmap/josm/gui/layer/GpxLayer.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/layer/GpxLayer.java	(revision 5458)
+++ trunk/src/org/openstreetmap/josm/gui/layer/GpxLayer.java	(revision 5459)
@@ -63,4 +63,5 @@
 import org.openstreetmap.josm.actions.DiskAccessAction;
 import org.openstreetmap.josm.actions.RenameLayerAction;
+import org.openstreetmap.josm.actions.SaveActionBase;
 import org.openstreetmap.josm.actions.downloadtasks.DownloadOsmTaskList;
 import org.openstreetmap.josm.data.Bounds;
@@ -97,4 +98,5 @@
 import org.openstreetmap.josm.gui.widgets.JFileChooserManager;
 import org.openstreetmap.josm.gui.widgets.JosmComboBox;
+import org.openstreetmap.josm.io.GpxImporter;
 import org.openstreetmap.josm.io.JpgImporter;
 import org.openstreetmap.josm.io.OsmTransferException;
@@ -2042,3 +2044,18 @@
         }
     }
+
+    @Override
+    public boolean isSavable() {
+        return true; // With GpxExporter
+    }
+
+    @Override
+    public boolean checkSaveConditions() {
+        return data != null;
+    }
+
+    @Override
+    public File createAndOpenSaveFileChooser() {
+        return SaveActionBase.createAndOpenSaveFileChooser(tr("Save GPX file"), GpxImporter.FILE_FILTER);
+    }
 }
Index: trunk/src/org/openstreetmap/josm/gui/layer/ImageryLayer.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/layer/ImageryLayer.java	(revision 5458)
+++ trunk/src/org/openstreetmap/josm/gui/layer/ImageryLayer.java	(revision 5459)
@@ -72,4 +72,12 @@
     protected OffsetServerThread offsetServerThread;
 
+    private final ImageryAdjustAction adjustAction = new ImageryAdjustAction(this);
+    private final AbstractAction useServerOffsetAction = new AbstractAction(tr("(use server offset)")) {
+        @Override
+        public void actionPerformed(ActionEvent e) {
+            enableOffsetServer(true);
+        }
+    };
+
     protected OffsetServerThread createoffsetServerThread() {
         return new OffsetServerThread(new OsmosnimkiOffsetServer(
@@ -179,12 +187,4 @@
         }
     }
-
-    ImageryAdjustAction adjustAction = new ImageryAdjustAction(this);
-    AbstractAction useServerOffsetAction = new AbstractAction(tr("(use server offset)")) {
-        @Override
-        public void actionPerformed(ActionEvent e) {
-            enableOffsetServer(true);
-        }
-    };
 
     public void enableOffsetServer(boolean enable) {
@@ -311,3 +311,11 @@
         }
     }
+
+    /* (non-Javadoc)
+     * @see org.openstreetmap.josm.gui.layer.Layer#destroy()
+     */
+    @Override
+    public void destroy() {
+        adjustAction.destroy();
+    }
 }
Index: trunk/src/org/openstreetmap/josm/gui/layer/Layer.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/layer/Layer.java	(revision 5458)
+++ trunk/src/org/openstreetmap/josm/gui/layer/Layer.java	(revision 5459)
@@ -23,4 +23,5 @@
 import org.openstreetmap.josm.actions.GpxExportAction;
 import org.openstreetmap.josm.actions.SaveAction;
+import org.openstreetmap.josm.actions.SaveActionBase;
 import org.openstreetmap.josm.actions.SaveAsAction;
 import org.openstreetmap.josm.data.Bounds;
@@ -427,3 +428,40 @@
         }
     }
+
+    /**
+     * Initializes the layer after a successful load of data from a file
+     * @since 5459
+     */
+    public void onPostLoadFromFile() {
+        // To be overriden if needed
+    }
+    
+    /**
+     * Replies the savable state of this layer (i.e if it can be saved through a "File->Save" dialog).
+     * @return true if this layer can be saved to a file
+     * @since 5459
+     */
+    public boolean isSavable() {
+        return false;
+    }
+    
+    /**
+     * Checks whether it is ok to launch a save (whether we have data, there is no conflict etc.)
+     * @return <code>true</code>, if it is safe to save.
+     * @since 5459
+     */
+    public boolean checkSaveConditions() {
+        return true;
+    }
+    
+    /**
+     * Creates a new "Save" dialog for this layer and makes it visible.<br/>
+     * When the user has chosen a file, checks the file extension, and confirms overwrite if needed.
+     * @return The output {@code File}
+     * @since 5459
+     * @see SaveActionBase#createAndOpenSaveFileChooser
+     */
+    public File createAndOpenSaveFileChooser() {
+        return SaveActionBase.createAndOpenSaveFileChooser(tr("Save Layer"), "lay");
+    }
 }
Index: trunk/src/org/openstreetmap/josm/gui/layer/OsmDataLayer.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/layer/OsmDataLayer.java	(revision 5458)
+++ trunk/src/org/openstreetmap/josm/gui/layer/OsmDataLayer.java	(revision 5459)
@@ -42,4 +42,5 @@
 import org.openstreetmap.josm.actions.ExpertToggleAction;
 import org.openstreetmap.josm.actions.RenameLayerAction;
+import org.openstreetmap.josm.actions.SaveActionBase;
 import org.openstreetmap.josm.actions.ToggleUploadDiscouragedLayerAction;
 import org.openstreetmap.josm.data.Bounds;
@@ -71,4 +72,5 @@
 import org.openstreetmap.josm.data.projection.Projection;
 import org.openstreetmap.josm.data.validation.TestError;
+import org.openstreetmap.josm.gui.ExtendedDialog;
 import org.openstreetmap.josm.gui.HelpAwareOptionPane;
 import org.openstreetmap.josm.gui.HelpAwareOptionPane.ButtonSpec;
@@ -655,8 +657,5 @@
     }
 
-    /**
-     * Initializes the layer after a successful load of OSM data from a file
-     *
-     */
+    @Override
     public void onPostLoadFromFile() {
         setRequiresSaveToFile(false);
@@ -745,3 +744,59 @@
         data.setUploadDiscouraged(uploadDiscouraged);
     }
+
+    @Override
+    public boolean isSavable() {
+        return true; // With OsmExporter
+    }
+
+    @Override
+    public boolean checkSaveConditions() {
+        if (isDataSetEmpty()) {
+            ExtendedDialog dialog = new ExtendedDialog(
+                    Main.parent,
+                    tr("Empty document"),
+                    new String[] {tr("Save anyway"), tr("Cancel")}
+            );
+            dialog.setContent(tr("The document contains no data."));
+            dialog.setButtonIcons(new String[] {"save.png", "cancel.png"});
+            dialog.showDialog();
+            if (dialog.getValue() != 1) return false;
+        }
+
+        ConflictCollection conflicts = getConflicts();
+        if (conflicts != null && !conflicts.isEmpty()) {
+            ExtendedDialog dialog = new ExtendedDialog(
+                    Main.parent,
+                    /* I18N: Display title of the window showing conflicts */
+                    tr("Conflicts"),
+                    new String[] {tr("Reject Conflicts and Save"), tr("Cancel")}
+            );
+            dialog.setContent(tr("There are unresolved conflicts. Conflicts will not be saved and handled as if you rejected all. Continue?"));
+            dialog.setButtonIcons(new String[] {"save.png", "cancel.png"});
+            dialog.showDialog();
+            if (dialog.getValue() != 1) return false;
+        }
+        return true;
+    }
+    
+    /**
+     * Check the data set if it would be empty on save. It is empty, if it contains
+     * no objects (after all objects that are created and deleted without being
+     * transferred to the server have been removed).
+     *
+     * @return <code>true</code>, if a save result in an empty data set.
+     */
+    private boolean isDataSetEmpty() {
+        if (data != null) {
+            for (OsmPrimitive osm : data.allNonDeletedPrimitives())
+                if (!osm.isDeleted() || !osm.isNewOrUndeleted())
+                    return false;
+        }
+        return true;
+    }
+
+    @Override
+    public File createAndOpenSaveFileChooser() {
+        return SaveActionBase.createAndOpenSaveFileChooser(tr("Save OSM file"), "osm");
+    }
 }
Index: trunk/src/org/openstreetmap/josm/gui/layer/WMSLayer.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/layer/WMSLayer.java	(revision 5458)
+++ trunk/src/org/openstreetmap/josm/gui/layer/WMSLayer.java	(revision 5459)
@@ -33,5 +33,4 @@
 import javax.swing.Action;
 import javax.swing.JCheckBoxMenuItem;
-import javax.swing.JFileChooser;
 import javax.swing.JMenuItem;
 import javax.swing.JOptionPane;
@@ -39,5 +38,4 @@
 import org.openstreetmap.gui.jmapviewer.AttributionSupport;
 import org.openstreetmap.josm.Main;
-import org.openstreetmap.josm.actions.DiskAccessAction;
 import org.openstreetmap.josm.actions.SaveActionBase;
 import org.openstreetmap.josm.data.Bounds;
@@ -62,7 +60,5 @@
 import org.openstreetmap.josm.gui.dialogs.LayerListDialog;
 import org.openstreetmap.josm.gui.dialogs.LayerListPopup;
-import org.openstreetmap.josm.gui.progress.NullProgressMonitor;
 import org.openstreetmap.josm.gui.progress.ProgressMonitor;
-import org.openstreetmap.josm.io.WMSLayerExporter;
 import org.openstreetmap.josm.io.WMSLayerImporter;
 import org.openstreetmap.josm.io.imagery.Grabber;
@@ -70,5 +66,4 @@
 import org.openstreetmap.josm.io.imagery.WMSGrabber;
 import org.openstreetmap.josm.io.imagery.WMSRequest;
-import org.openstreetmap.josm.tools.ImageProvider;
 
 
@@ -124,5 +119,4 @@
     protected boolean settingsChanged;
     protected ImageryInfo info;
-    protected MapView mv;
     public WmsCache cache;
     private AttributionSupport attribution = new AttributionSupport();
@@ -178,5 +172,4 @@
     @Override
     public void hookUpMapView() {
-        mv = Main.map.mapView;
         if (info.getUrl() != null) {
             for (WMSLayer layer: Main.map.mapView.getLayersOfType(WMSLayer.class)) {
@@ -194,5 +187,5 @@
             this.info.setPixelPerDegree(getPPD());
         }
-        resolution = mv.getDist100PixelText();
+        resolution = Main.map.mapView.getDist100PixelText();
 
         final MouseAdapter adapter = new MouseAdapter() {
@@ -484,6 +477,6 @@
                 SeparatorLayerAction.INSTANCE,
                 new OffsetAction(),
-                new LoadWmsAction(),
-                new SaveWmsAction(),
+                new LayerSaveAction(this),
+                new LayerSaveAsAction(this),
                 new BookmarkWmsAction(),
                 SeparatorLayerAction.INSTANCE,
@@ -523,5 +516,6 @@
             return -1;
 
-        EastNorth cursorEastNorth = mv.getEastNorth(mv.lastMEvent.getX(), mv.lastMEvent.getY());
+        MouseEvent lastMEvent = Main.map.mapView.lastMEvent;
+        EastNorth cursorEastNorth = Main.map.mapView.getEastNorth(lastMEvent.getX(), lastMEvent.getY());
         int mouseX = getImageXIndex(cursorEastNorth.east());
         int mouseY = getImageYIndex(cursorEastNorth.north());
@@ -605,5 +599,5 @@
             if (request.getState() != null && !request.isPrecacheOnly()) {
                 finishedRequests.add(request);
-                mv.repaint();
+                Main.map.mapView.repaint();
             }
         } finally {
@@ -669,5 +663,5 @@
                         );
             } else {
-                downloadAndPaintVisible(mv.getGraphics(), mv, true);
+                downloadAndPaintVisible(Main.map.mapView.getGraphics(), Main.map.mapView, true);
             }
         }
@@ -680,5 +674,5 @@
 
         private void changeResolution(WMSLayer layer) {
-            layer.resolution = layer.mv.getDist100PixelText();
+            layer.resolution = Main.map.mapView.getDist100PixelText();
             layer.info.setPixelPerDegree(layer.getPPD());
             layer.settingsChanged = true;
@@ -761,5 +755,5 @@
                 }
             }
-            mv.repaint();
+            Main.map.mapView.repaint();
         }
         @Override
@@ -775,44 +769,4 @@
     }
 
-    public class SaveWmsAction extends AbstractAction {
-        public SaveWmsAction() {
-            super(tr("Save WMS layer to file"), ImageProvider.get("save"));
-        }
-        @Override
-        public void actionPerformed(ActionEvent ev) {
-            File f = SaveActionBase.createAndOpenSaveFileChooser(
-                    tr("Save WMS layer"), WMSLayerImporter.FILE_FILTER);
-            try {
-                new WMSLayerExporter().exportData(f, WMSLayer.this);
-            } catch (Exception ex) {
-                ex.printStackTrace(System.out);
-            }
-        }
-    }
-
-    public class LoadWmsAction extends AbstractAction {
-        public LoadWmsAction() {
-            super(tr("Load WMS layer from file"), ImageProvider.get("open"));
-        }
-        @Override
-        public void actionPerformed(ActionEvent ev) {
-            JFileChooser fc = DiskAccessAction.createAndOpenFileChooser(true,
-                    false, tr("Load WMS layer"), WMSLayerImporter.FILE_FILTER, JFileChooser.FILES_ONLY, null);
-            if (fc == null) return;
-            File f = fc.getSelectedFile();
-            if (f == null) return;
-            try {
-                new WMSLayerImporter(WMSLayer.this).importData(f, NullProgressMonitor.INSTANCE);
-            } catch (InvalidClassException ex) {
-                JOptionPane.showMessageDialog(Main.parent, ex.getMessage(), tr("File Format Error"), JOptionPane.ERROR_MESSAGE);
-                return;
-            } catch (Exception ex) {
-                ex.printStackTrace();
-                JOptionPane.showMessageDialog(Main.parent, ex.getMessage(), tr("Error loading file"), JOptionPane.ERROR_MESSAGE);
-                return;
-            }
-        }
-    }
-    
     /**
      * This action will add a WMS layer menu entry with the current WMS layer
@@ -860,5 +814,5 @@
                     }
                 }
-                mv.repaint();
+                Main.map.mapView.repaint();
             }
         }
@@ -952,9 +906,9 @@
     }
 
-    protected Grabber getGrabber(boolean localOnly){
-        if(getInfo().getImageryType() == ImageryType.HTML)
-            return new HTMLGrabber(mv, this, localOnly);
-        else if(getInfo().getImageryType() == ImageryType.WMS)
-            return new WMSGrabber(mv, this, localOnly);
+    protected Grabber getGrabber(boolean localOnly) {
+        if (getInfo().getImageryType() == ImageryType.HTML)
+            return new HTMLGrabber(Main.map.mapView, this, localOnly);
+        else if (getInfo().getImageryType() == ImageryType.WMS)
+            return new WMSGrabber(Main.map.mapView, this, localOnly);
         else throw new IllegalStateException("getGrabber() called for non-WMS layer type");
     }
@@ -1042,9 +996,15 @@
         
         settingsChanged = true;
-        mv.repaint();
+        if (Main.isDisplayingMapView()) {
+            Main.map.mapView.repaint();
+        }
         if (cache != null) {
             cache.saveIndex();
             cache = null;
         }
+    }
+
+    @Override
+    public void onPostLoadFromFile() {
         if (info.getUrl() != null) {
             cache = new WmsCache(info.getUrl(), imageSize);
@@ -1052,3 +1012,13 @@
         }
     }
+
+    @Override
+    public boolean isSavable() {
+        return true; // With WMSLayerExporter
+    }
+
+    @Override
+    public File createAndOpenSaveFileChooser() {
+        return SaveActionBase.createAndOpenSaveFileChooser(tr("Save WMS file"), WMSLayerImporter.FILE_FILTER);
+    }
 }
Index: trunk/src/org/openstreetmap/josm/io/FileExporter.java
===================================================================
--- trunk/src/org/openstreetmap/josm/io/FileExporter.java	(revision 5458)
+++ trunk/src/org/openstreetmap/josm/io/FileExporter.java	(revision 5459)
@@ -8,11 +8,16 @@
 
 import org.openstreetmap.josm.actions.ExtensionFileFilter;
+import org.openstreetmap.josm.gui.MapView.LayerChangeListener;
 import org.openstreetmap.josm.gui.layer.Layer;
 
-public abstract class FileExporter {
-    public ExtensionFileFilter filter;
+public abstract class FileExporter implements LayerChangeListener {
+    
+    public final ExtensionFileFilter filter;
+
+    private boolean enabled;
 
     public FileExporter(ExtensionFileFilter filter) {
         this.filter = filter;
+        this.enabled = true;
     }
 
@@ -24,3 +29,36 @@
         throw new IOException(tr("Could not export ''{0}''.", file.getName()));
     }
+
+    /**
+     * Returns the enabled state of this {@code FileExporter}. When enabled, it is listed and usable in "File->Save" dialogs. 
+     * @return true if this {@code FileExporter} is enabled
+     * @since 5459
+     */
+    public final boolean isEnabled() {
+        return enabled;
+    }
+
+    /**
+     * Sets the enabled state of the {@code FileExporter}. When enabled, it is listed and usable in "File->Save" dialogs.
+     * @param enabled true to enable this {@code FileExporter}, false to disable it
+     * @since 5459
+     */
+    public final void setEnabled(boolean enabled) {
+        this.enabled = enabled;
+    }
+
+    @Override
+    public void activeLayerChange(Layer oldLayer, Layer newLayer) {
+        // To be overriden by subclasses if their enabled state depends of the active layer nature
+    }
+
+    @Override
+    public void layerAdded(Layer newLayer) {
+        // To be overriden by subclasses if needed
+    }
+
+    @Override
+    public void layerRemoved(Layer oldLayer) {
+        // To be overriden by subclasses if needed
+    }
 }
Index: trunk/src/org/openstreetmap/josm/io/FileImporter.java
===================================================================
--- trunk/src/org/openstreetmap/josm/io/FileImporter.java	(revision 5458)
+++ trunk/src/org/openstreetmap/josm/io/FileImporter.java	(revision 5459)
@@ -17,12 +17,17 @@
 import org.openstreetmap.josm.actions.ExtensionFileFilter;
 import org.openstreetmap.josm.gui.HelpAwareOptionPane;
+import org.openstreetmap.josm.gui.MapView.LayerChangeListener;
+import org.openstreetmap.josm.gui.layer.Layer;
 import org.openstreetmap.josm.gui.progress.ProgressMonitor;
 
-public abstract class FileImporter implements Comparable<FileImporter> {
+public abstract class FileImporter implements Comparable<FileImporter>, LayerChangeListener {
 
     public final ExtensionFileFilter filter;
+    
+    private boolean enabled;
 
     public FileImporter(ExtensionFileFilter filter) {
         this.filter = filter;
+        this.enabled = true;
     }
 
@@ -122,3 +127,36 @@
         return new GZIPInputStream(in);
     }
+
+    /**
+     * Returns the enabled state of this {@code FileImporter}. When enabled, it is listed and usable in "File->Open" dialog. 
+     * @return true if this {@code FileImporter} is enabled
+     * @since 5459
+     */
+    public final boolean isEnabled() {
+        return enabled;
+    }
+
+    /**
+     * Sets the enabled state of the {@code FileImporter}. When enabled, it is listed and usable in "File->Open" dialog.
+     * @param enabled true to enable this {@code FileImporter}, false to disable it
+     * @since 5459
+     */
+    public final void setEnabled(boolean enabled) {
+        this.enabled = enabled;
+    }
+
+    @Override
+    public void activeLayerChange(Layer oldLayer, Layer newLayer) {
+        // To be overriden by subclasses if their enabled state depends of the active layer nature
+    }
+
+    @Override
+    public void layerAdded(Layer newLayer) {
+        // To be overriden by subclasses if needed
+    }
+
+    @Override
+    public void layerRemoved(Layer oldLayer) {
+        // To be overriden by subclasses if needed
+    }
 }
Index: trunk/src/org/openstreetmap/josm/io/WMSLayerExporter.java
===================================================================
--- trunk/src/org/openstreetmap/josm/io/WMSLayerExporter.java	(revision 5458)
+++ trunk/src/org/openstreetmap/josm/io/WMSLayerExporter.java	(revision 5459)
@@ -38,3 +38,8 @@
         }
     }
+
+    @Override
+    public void activeLayerChange(Layer oldLayer, Layer newLayer) {
+        setEnabled(newLayer instanceof WMSLayer);
+    }
 }
Index: trunk/src/org/openstreetmap/josm/io/WMSLayerImporter.java
===================================================================
--- trunk/src/org/openstreetmap/josm/io/WMSLayerImporter.java	(revision 5458)
+++ trunk/src/org/openstreetmap/josm/io/WMSLayerImporter.java	(revision 5459)
@@ -9,7 +9,9 @@
 import java.io.ObjectInputStream;
 
+import org.openstreetmap.josm.Main;
 import org.openstreetmap.josm.actions.ExtensionFileFilter;
 import org.openstreetmap.josm.gui.layer.WMSLayer;
 import org.openstreetmap.josm.gui.progress.ProgressMonitor;
+import org.openstreetmap.josm.gui.util.GuiHelper;
 import org.openstreetmap.josm.tools.CheckParameterUtil;
 
@@ -55,4 +57,13 @@
             ois.close();
         }
+        
+        // FIXME: remove UI stuff from IO subsystem
+        GuiHelper.runInEDT(new Runnable() {
+            @Override
+            public void run() {
+                Main.main.addLayer(wmsLayer);
+                wmsLayer.onPostLoadFromFile();
+            }
+        });
     }
 
