Index: src/org/openstreetmap/josm/actions/ChangesetManagerToggleAction.java
===================================================================
--- src/org/openstreetmap/josm/actions/ChangesetManagerToggleAction.java	(revision 4348)
+++ src/org/openstreetmap/josm/actions/ChangesetManagerToggleAction.java	(working copy)
@@ -33,7 +33,7 @@
                 "dialogs/changeset/changesetmanager",
                 tr("Toggle visibility of Changeset Manager window"),
                 Shortcut.registerShortcut(
-                        "menu:view:changesetdialog",
+                        "menu:windows:changesetdialog",
                         tr("Toggle visibility of Changeset Manager window"),
                         KeyEvent.VK_C,
                         Shortcut.GROUPS_ALT2 + Shortcut.GROUP_HOTKEY
Index: src/org/openstreetmap/josm/plugins/PluginProxy.java
===================================================================
--- src/org/openstreetmap/josm/plugins/PluginProxy.java	(revision 4348)
+++ src/org/openstreetmap/josm/plugins/PluginProxy.java	(working copy)
@@ -24,6 +24,12 @@
         this.plugin = plugin;
     }
 
+    /**
+     * Not required anymore since the MapFrame is initialized only once now, so
+     * plugins may assume it exists and it won't change. Will be removed after
+     * 2012-01-01.
+     */
+    @Deprecated
     @Override public void mapFrameInitialized(MapFrame oldFrame, MapFrame newFrame) {
         try {
             plugin.getClass().getMethod("mapFrameInitialized", MapFrame.class, MapFrame.class).invoke(plugin, oldFrame, newFrame);
Index: src/org/openstreetmap/josm/plugins/PluginHandler.java
===================================================================
--- src/org/openstreetmap/josm/plugins/PluginHandler.java	(revision 4348)
+++ src/org/openstreetmap/josm/plugins/PluginHandler.java	(working copy)
@@ -26,9 +26,9 @@
 import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
-import java.util.Map.Entry;
 import java.util.Set;
 import java.util.TreeSet;
+import java.util.Map.Entry;
 import java.util.concurrent.ExecutionException;
 import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Executors;
@@ -49,15 +49,14 @@
 import org.openstreetmap.josm.Main;
 import org.openstreetmap.josm.data.Version;
 import org.openstreetmap.josm.gui.HelpAwareOptionPane;
-import org.openstreetmap.josm.gui.HelpAwareOptionPane.ButtonSpec;
 import org.openstreetmap.josm.gui.JMultilineLabel;
 import org.openstreetmap.josm.gui.MapFrame;
+import org.openstreetmap.josm.gui.HelpAwareOptionPane.ButtonSpec;
 import org.openstreetmap.josm.gui.download.DownloadSelection;
 import org.openstreetmap.josm.gui.help.HelpUtil;
 import org.openstreetmap.josm.gui.preferences.PreferenceSettingFactory;
 import org.openstreetmap.josm.gui.progress.NullProgressMonitor;
 import org.openstreetmap.josm.gui.progress.ProgressMonitor;
-import org.openstreetmap.josm.io.remotecontrol.RemoteControl;
 import org.openstreetmap.josm.tools.CheckParameterUtil;
 import org.openstreetmap.josm.tools.GBC;
 import org.openstreetmap.josm.tools.I18n;
@@ -824,11 +823,11 @@
     }
 
     /**
-     * Notified loaded plugins about a new map frame
-     *
-     * @param old the old map frame
-     * @param map the new map frame
+     * Not required anymore since the MapFrame is initialized only once now, so
+     * plugins may assume it exists and it won't change. Will be removed after
+     * 2012-01-01.
      */
+    @Deprecated
     public static void notifyMapFrameChanged(MapFrame old, MapFrame map) {
         for (PluginProxy plugin : pluginList) {
             plugin.mapFrameInitialized(old, map);
Index: src/org/openstreetmap/josm/plugins/Plugin.java
===================================================================
--- src/org/openstreetmap/josm/plugins/Plugin.java	(revision 4348)
+++ src/org/openstreetmap/josm/plugins/Plugin.java	(working copy)
@@ -80,10 +80,11 @@
     }
 
     /**
-     * Called after Main.mapFrame is initalized. (After the first data is loaded).
-     * You can use this callback to tweak the newFrame to your needs, as example install
-     * an alternative Painter.
+     * Not required anymore since the MapFrame is initialized only once now, so
+     * plugins may assume it exists and it won't change. Will be removed after
+     * 2012-01-01.
      */
+    @Deprecated
     public void mapFrameInitialized(MapFrame oldFrame, MapFrame newFrame) {}
 
     /**
Index: src/org/openstreetmap/josm/Main.java
===================================================================
--- src/org/openstreetmap/josm/Main.java	(revision 4348)
+++ src/org/openstreetmap/josm/Main.java	(working copy)
@@ -1,5 +1,6 @@
 // License: GPL. Copyright 2007 by Immanuel Scholz and others
 package org.openstreetmap.josm;
+
 import static org.openstreetmap.josm.tools.I18n.tr;
 
 import java.awt.BorderLayout;
@@ -87,7 +88,6 @@
 import org.openstreetmap.josm.tools.Utils;
 
 abstract public class Main {
-
     /**
      * Replies true if JOSM currently displays a map view. False, if it doesn't, i.e. if
      * it only shows the MOTD panel.
@@ -95,10 +95,13 @@
      * @return true if JOSM currently displays a map view
      */
     static public boolean isDisplayingMapView() {
-        if (map == null) return false;
-        if (map.mapView == null) return false;
+        if (map == null)
+            return false;
+        if (map.mapView == null)
+            return false;
         return true;
     }
+
     /**
      * Global parent component for all dialogs and message boxes
      */
@@ -124,10 +127,13 @@
     public static PrimitiveDeepCopy pasteBuffer = new PrimitiveDeepCopy();
     public static Layer pasteSource;
 
+    protected static JPanel contentPanePrivate = new JPanel(new BorderLayout());
+
     /**
      * The MapFrame. Use setMapFrame to set or clear it.
      */
     public static MapFrame map;
+
     /**
      * True, when in applet mode
      */
@@ -155,16 +161,19 @@
      * Print a message if logging is on.
      */
     static public int log_level = 2;
+
     static public void warn(String msg) {
         if (log_level < 1)
             return;
         System.out.println(msg);
     }
+
     static public void info(String msg) {
         if (log_level < 2)
             return;
         System.out.println(msg);
     }
+
     static public void debug(String msg) {
         if (log_level < 3)
             return;
@@ -186,24 +195,26 @@
     public static boolean isOpenjdk;
 
     /**
-     * Set or clear (if passed <code>null</code>) the map.
+     * MapFrame is now created only once and only shown/hidden. Use show/hideMapFrame instead.
+     * This function has no use any longer. Will be removed on or after 2012-01-01. FIXME
      */
+    @Deprecated
     public final void setMapFrame(final MapFrame map) {
-        MapFrame old = Main.map;
-        panel.setVisible(false);
+    }
+
+    public final void showMapFrame() {
         panel.removeAll();
-        if (map != null) {
             map.fillPanel(panel);
-        } else {
-            old.destroy();
-            panel.add(gettingStarted, BorderLayout.CENTER);
-        }
-        panel.setVisible(true);
+        map.setVisible(true);
         redoUndoListener.commandChanged(0,0);
+    }
 
-        Main.map = map;
-
-        PluginHandler.notifyMapFrameChanged(old, map);
+    public final void hideMapFrame() {
+        panel.removeAll();
+        map.setVisible(false);
+        panel.add(gettingStarted, BorderLayout.CENTER);
+        redoUndoListener.commandChanged(0, 0);
+        panel.repaint();
     }
 
     /**
@@ -214,7 +225,7 @@
         if (map != null) {
             map.mapView.removeLayer(layer);
             if (map.mapView.getAllLayers().isEmpty()) {
-                setMapFrame(null);
+                hideMapFrame();
             }
         }
     }
@@ -242,8 +253,8 @@
         // creating toolbar
         contentPanePrivate.add(toolbar.control, BorderLayout.NORTH);
 
-        registerActionShortcut(menu.help, Shortcut.registerShortcut("system:help", tr("Help"),
-                KeyEvent.VK_F1, Shortcut.GROUP_DIRECT));
+        registerActionShortcut(menu.help, Shortcut.registerShortcut("system:help", tr("Help"), KeyEvent.VK_F1,
+                Shortcut.GROUP_DIRECT));
 
         TaggingPresetPreference.initialize();
         MapPaintPreference.initialize();
@@ -252,23 +263,26 @@
         validator = new OsmValidator();
         MapView.addLayerChangeListener(validator);
 
+        map = new MapFrame(contentPanePrivate);
+        map.initializeDialogsPane();
+
         toolbar.refreshToolbarControl();
 
         toolbar.control.updateUI();
         contentPanePrivate.updateUI();
 
+        // remove call after 2012-01-01 FIXME
+        PluginHandler.notifyMapFrameChanged(null, map);
     }
 
     /**
      * Add a new layer to the map. If no map exists, create one.
      */
     public final void addLayer(final Layer layer) {
-        if (map == null) {
-            final MapFrame mapFrame = new MapFrame(contentPanePrivate);
-            setMapFrame(mapFrame);
-            mapFrame.selectMapMode((MapMode)mapFrame.getDefaultButtonAction());
-            mapFrame.setVisible(true);
-            mapFrame.initializeDialogsPane();
+        if (!map.isVisible()) {
+            Main.map.selectMapMode((MapMode) Main.map.getDefaultButtonAction());
+            showMapFrame();
+
             // bootstrapping problem: make sure the layer list dialog is going to
             // listen to change events of the very first layer
             //
@@ -283,7 +297,8 @@
      * @return true if there is an edit layer
      */
     public boolean hasEditLayer() {
-        if (getEditLayer() == null) return false;
+        if (getEditLayer() == null)
+            return false;
         return true;
     }
 
@@ -293,8 +308,10 @@
      * @return the current edit layer. null, if no current edit layer exists
      */
     public OsmDataLayer getEditLayer() {
-        if (map == null) return null;
-        if (map.mapView == null) return null;
+        if (map == null)
+            return null;
+        if (map.mapView == null)
+            return null;
         return map.mapView.getEditLayer();
     }
 
@@ -304,7 +321,8 @@
      * @return the current data set. null, if no current data set exists
      */
     public DataSet getCurrentDataSet() {
-        if (!hasEditLayer()) return null;
+        if (!hasEditLayer())
+            return null;
         return getEditLayer().data;
     }
 
@@ -314,13 +332,13 @@
      * @return the currently active layer. null, if currently no active layer exists
      */
     public Layer getActiveLayer() {
-        if (map == null) return null;
-        if (map.mapView == null) return null;
+        if (map == null)
+            return null;
+        if (map.mapView == null)
+            return null;
         return map.mapView.getActiveLayer();
     }
 
-    protected static JPanel contentPanePrivate = new JPanel(new BorderLayout());
-
     /**
      * @deprecated If you just need to register shortcut for action, use registerActionShortcut instead of accessing InputMap directly
      */
@@ -338,7 +356,8 @@
         InputMap inputMap = contentPanePrivate.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);
         Object existing = inputMap.get(keyStroke);
         if (existing != null && !existing.equals(action)) {
-            System.out.println(String.format("Keystroke %s is already assigned to %s, will be overridden by %s", keyStroke, existing, action));
+            System.out.println(String.format("Keystroke %s is already assigned to %s, will be overridden by %s",
+                    keyStroke, existing, action));
         }
         inputMap.put(keyStroke, action);
 
@@ -358,7 +377,6 @@
         contentPanePrivate.getActionMap().remove(action);
     }
 
-
     ///////////////////////////////////////////////////////////////////////////
     //  Implementation part
     ///////////////////////////////////////////////////////////////////////////
@@ -375,6 +393,50 @@
         }
     };
 
+    /*    private final List<ToggleDialog> toggleDialogs = new ArrayList<ToggleDialog>();
+    public IconToggleButton addToggleDialog(final ToggleDialog dlg) {
+        toggleDialogs.add(tg);
+        final IconToggleButton button = new IconToggleButton(dlg.getToggleAction());
+        button.addMouseListener(new PopupMenuLauncher(new JPopupMenu() {
+            {
+                add(new AbstractAction() {
+                    {
+                        putValue(NAME, tr("Hide this button"));
+                        putValue(SHORT_DESCRIPTION, tr("Click the arrow at the bottom to show it again."));
+                    }
+
+                    @Override
+                    public void actionPerformed(ActionEvent e) {
+                        dlg.hideButton();
+                        validateToolBarToggle();
+                    }
+                });
+            }
+        }));
+        dlg.setButton(button);
+        if (button.isVisible()) {
+            toolBarToggle.add(button);
+        }
+        allDialogs.add(dlg);
+        if (dialogsPanel.initialized) {
+            dialogsPanel.add(dlg);
+        }
+        return button;
+    }
+
+    public List<ToggleDialog> getToggleDialogs() {
+        return toggleDialogs;
+    }
+
+    public void validateToolBarToggle() {
+        toolBarToggle.removeAll();
+        for (ToggleDialog dlg : allDialogs) {
+            if (dlg.getButton().isVisible()) {
+                toolBarToggle.add(dlg.getButton());
+            }
+        }
+    }*/
+
     /**
      * Should be called before the main constructor to setup some parameter stuff
      * @param args The parsed argument list.
@@ -387,12 +449,10 @@
             String laf = Main.pref.get("laf", defaultlaf);
             try {
                 UIManager.setLookAndFeel(laf);
-            }
-            catch (final java.lang.ClassNotFoundException e) {
+            } catch (final java.lang.ClassNotFoundException e) {
                 System.out.println("Look and Feel not found: " + laf);
                 Main.pref.put("laf", defaultlaf);
-            }
-            catch (final javax.swing.UnsupportedLookAndFeelException e) {
+            } catch (final javax.swing.UnsupportedLookAndFeelException e) {
                 System.out.println("Look and Feel not supported: " + laf);
                 Main.pref.put("laf", defaultlaf);
             }
@@ -458,7 +518,8 @@
             }
         }
         if (bounds == null) {
-            bounds = !args.containsKey("no-maximize") ? new Rectangle(0,0,screenDimension.width,screenDimension.height) : new Rectangle(1000,740);
+            bounds = !args.containsKey("no-maximize") ? new Rectangle(0, 0, screenDimension.width,
+                    screenDimension.height) : new Rectangle(1000, 740);
         }
     }
 
@@ -478,12 +539,8 @@
                     try {
                         f = new File(new URI(s));
                     } catch (URISyntaxException e) {
-                        JOptionPane.showMessageDialog(
-                                Main.parent,
-                                tr("Ignoring malformed file URL: \"{0}\"", s),
-                                tr("Warning"),
-                                JOptionPane.WARNING_MESSAGE
-                        );
+                        JOptionPane.showMessageDialog(Main.parent, tr("Ignoring malformed file URL: \"{0}\"", s),
+                                tr("Warning"), JOptionPane.WARNING_MESSAGE);
                     }
                     if (f!=null) {
                         fileList.add(f);
@@ -495,8 +552,7 @@
                     break;
                 }
             }
-            if(!fileList.isEmpty())
-            {
+            if (!fileList.isEmpty()) {
                 OpenFileAction.openFiles(fileList, true);
             }
         }
@@ -511,12 +567,9 @@
                     break;
                 case fileUrl:
                 case fileName:
-                    JOptionPane.showMessageDialog(
-                            Main.parent,
-                            tr("Parameter \"downloadgps\" does not accept file names or file URLs"),
-                            tr("Warning"),
-                            JOptionPane.WARNING_MESSAGE
-                    );
+                    JOptionPane.showMessageDialog(Main.parent,
+                            tr("Parameter \"downloadgps\" does not accept file names or file URLs"), tr("Warning"),
+                            JOptionPane.WARNING_MESSAGE);
                 }
             }
         }
@@ -528,7 +581,8 @@
     }
 
     public static boolean saveUnsavedModifications() {
-        if (map == null) return true;
+        if (map == null)
+            return true;
         SaveLayersDialog dialog = new SaveLayersDialog(Main.parent);
         List<OsmDataLayer> layersWithUnmodifiedChanges = new ArrayList<OsmDataLayer>();
         for (OsmDataLayer l: Main.map.mapView.getLayersOfType(OsmDataLayer.class)) {
@@ -541,9 +595,12 @@
             dialog.getModel().populate(layersWithUnmodifiedChanges);
             dialog.setVisible(true);
             switch(dialog.getUserAction()) {
-            case CANCEL: return false;
-            case PROCEED: return true;
-            default: return false;
+            case CANCEL:
+                return false;
+            case PROCEED:
+                return true;
+            default:
+                return false;
             }
         }
 
@@ -573,7 +630,9 @@
      * The type of a command line parameter, to be used in switch statements.
      * @see paramType
      */
-    private enum DownloadParamType { httpUrl, fileUrl, bounds, fileName }
+    private enum DownloadParamType {
+        httpUrl, fileUrl, bounds, fileName
+    }
 
     /**
      * Guess the type of a parameter string specified on the command line with --download= or --downloadgps.
@@ -581,11 +640,14 @@
      * @return The guessed parameter type
      */
     private DownloadParamType paramType(String s) {
-        if(s.startsWith("http:")) return DownloadParamType.httpUrl;
-        if(s.startsWith("file:")) return DownloadParamType.fileUrl;
+        if (s.startsWith("http:"))
+            return DownloadParamType.httpUrl;
+        if (s.startsWith("file:"))
+            return DownloadParamType.fileUrl;
         final StringTokenizer st = new StringTokenizer(s, ",");
         // we assume a string with exactly 3 commas is a bounds parameter
-        if (st.countTokens() == 4) return DownloadParamType.bounds;
+        if (st.countTokens() == 4)
+            return DownloadParamType.bounds;
         // everything else must be a file name
         return DownloadParamType.fileName;
     }
@@ -598,12 +660,8 @@
     private static void downloadFromParamHttp(final boolean rawGps, String s) {
         final Bounds b = OsmUrlToBounds.parse(s);
         if (b == null) {
-            JOptionPane.showMessageDialog(
-                    Main.parent,
-                    tr("Ignoring malformed URL: \"{0}\"", s),
-                    tr("Warning"),
-                    JOptionPane.WARNING_MESSAGE
-            );
+            JOptionPane.showMessageDialog(Main.parent, tr("Ignoring malformed URL: \"{0}\"", s), tr("Warning"),
+                    JOptionPane.WARNING_MESSAGE);
         } else {
             downloadFromParamBounds(rawGps, b);
         }
@@ -617,10 +675,8 @@
     private static void downloadFromParamBounds(final boolean rawGps, String s) {
         final StringTokenizer st = new StringTokenizer(s, ",");
         if (st.countTokens() == 4) {
-            Bounds b = new Bounds(
-                    new LatLon(Double.parseDouble(st.nextToken()),Double.parseDouble(st.nextToken())),
-                    new LatLon(Double.parseDouble(st.nextToken()),Double.parseDouble(st.nextToken()))
-            );
+            Bounds b = new Bounds(new LatLon(Double.parseDouble(st.nextToken()), Double.parseDouble(st.nextToken())),
+                    new LatLon(Double.parseDouble(st.nextToken()), Double.parseDouble(st.nextToken())));
             downloadFromParamBounds(rawGps, b);
         }
     }
@@ -647,14 +703,14 @@
             platform = new PlatformHookUnixoid();
         } else if (os.toLowerCase().startsWith("windows")) {
             platform = new PlatformHookWindows();
-        } else if (os.equals("Linux") || os.equals("Solaris") ||
-                os.equals("SunOS") || os.equals("AIX") ||
-                os.equals("FreeBSD") || os.equals("NetBSD") || os.equals("OpenBSD")) {
+        } else if (os.equals("Linux") || os.equals("Solaris") || os.equals("SunOS") || os.equals("AIX")
+                || os.equals("FreeBSD") || os.equals("NetBSD") || os.equals("OpenBSD")) {
             platform = new PlatformHookUnixoid();
         } else if (os.toLowerCase().startsWith("mac os x")) {
             platform = new PlatformHookOsx();
         } else {
-            System.err.println("I don't know your operating system '"+os+"', so I'm guessing its some kind of *nix.");
+            System.err.println("I don't know your operating system '" + os
+                    + "', so I'm guessing its some kind of *nix.");
             platform = new PlatformHookUnixoid();
         }
     }
@@ -689,8 +745,7 @@
                     newToggleDlgWidth = "";
                 }
             }
-        }
-        catch (Exception e) {
+        } catch (Exception e) {
             System.out.println("Failed to get GUI geometry: " + e);
             e.printStackTrace();
         }
@@ -702,8 +757,8 @@
             pref.put("toggleDialogs.width", newToggleDlgWidth);
         }
     }
-    private static class WindowPositionSizeListener extends WindowAdapter implements
-    ComponentListener {
+
+    private static class WindowPositionSizeListener extends WindowAdapter implements ComponentListener {
 
         @Override
         public void windowStateChanged(WindowEvent e) {
@@ -738,6 +793,7 @@
         }
 
     }
+
     public static void addListener() {
         parent.addComponentListener(new WindowPositionSizeListener());
         ((JFrame)parent).addWindowStateListener(new WindowPositionSizeListener());
@@ -746,16 +802,15 @@
     public static void checkJava6() {
         String version = System.getProperty("java.version");
         if (version != null) {
-            if (version.startsWith("1.6") || version.startsWith("6") ||
-                    version.startsWith("1.7") || version.startsWith("7"))
+            if (version.startsWith("1.6") || version.startsWith("6") || version.startsWith("1.7")
+                    || version.startsWith("7"))
                 return;
             if (version.startsWith("1.5") || version.startsWith("5")) {
-                JLabel ho = new JLabel("<html>"+
-                        tr("<h2>JOSM requires Java version 6.</h2>"+
-                                "Detected Java version: {0}.<br>"+
-                                "You can <ul><li>update your Java (JRE) or</li>"+
-                                "<li>use an earlier (Java 5 compatible) version of JOSM.</li></ul>"+
-                                "More Info:", version)+"</html>");
+                JLabel ho = new JLabel("<html>"
+                        + tr("<h2>JOSM requires Java version 6.</h2>" + "Detected Java version: {0}.<br>"
+                                + "You can <ul><li>update your Java (JRE) or</li>"
+                                + "<li>use an earlier (Java 5 compatible) version of JOSM.</li></ul>" + "More Info:",
+                                version) + "</html>");
                 JTextArea link = new JTextArea("http://josm.openstreetmap.de/wiki/Help/SystemRequirements");
                 link.setEditable(false);
                 link.setBackground(panel.getBackground());
@@ -768,7 +823,8 @@
                 panel.add(link, gbc);
                 final String EXIT = tr("Exit JOSM");
                 final String CONTINUE = tr("Continue, try anyway");
-                int ret = JOptionPane.showOptionDialog(null, panel, tr("Error"), JOptionPane.YES_NO_OPTION, JOptionPane.ERROR_MESSAGE, null, new String[] {EXIT, CONTINUE}, EXIT);
+                int ret = JOptionPane.showOptionDialog(null, panel, tr("Error"), JOptionPane.YES_NO_OPTION,
+                        JOptionPane.ERROR_MESSAGE, null, new String[] { EXIT, CONTINUE }, EXIT);
                 if (ret == 0) {
                     System.exit(0);
                 }
@@ -852,11 +908,13 @@
      * @param listener the listener. Ignored if null.
      */
     public static void addProjectionChangeListener(ProjectionChangeListener listener) {
-        if (listener == null) return;
+        if (listener == null)
+            return;
         synchronized (Main.class) {
             for (WeakReference<ProjectionChangeListener> wr : listeners) {
                 // already registered ? => abort
-                if (wr.get() == listener) return;
+                if (wr.get() == listener)
+                    return;
             }
         }
         listeners.add(new WeakReference<ProjectionChangeListener>(listener));
@@ -868,7 +926,8 @@
      * @param listener the listener. Ignored if null.
      */
     public static void removeProjectionChangeListener(ProjectionChangeListener listener) {
-        if (listener == null) return;
+        if (listener == null)
+            return;
         synchronized(Main.class){
             Iterator<WeakReference<ProjectionChangeListener>> it = listeners.iterator();
             while(it.hasNext()){
Index: src/org/openstreetmap/josm/gui/MainMenu.java
===================================================================
--- src/org/openstreetmap/josm/gui/MainMenu.java	(revision 4348)
+++ src/org/openstreetmap/josm/gui/MainMenu.java	(working copy)
@@ -11,7 +11,11 @@
 import javax.swing.JMenu;
 import javax.swing.JMenuBar;
 import javax.swing.JMenuItem;
+import javax.swing.JPopupMenu;
+import javax.swing.JSeparator;
 import javax.swing.KeyStroke;
+import javax.swing.event.MenuEvent;
+import javax.swing.event.MenuListener;
 
 import org.openstreetmap.josm.Main;
 import org.openstreetmap.josm.actions.AboutAction;
@@ -52,7 +56,6 @@
 import org.openstreetmap.josm.actions.OpenFileAction;
 import org.openstreetmap.josm.actions.OpenLocationAction;
 import org.openstreetmap.josm.actions.OrthogonalizeAction;
-import org.openstreetmap.josm.actions.OrthogonalizeAction.Undo;
 import org.openstreetmap.josm.actions.PasteAction;
 import org.openstreetmap.josm.actions.PasteTagsAction;
 import org.openstreetmap.josm.actions.PreferencesAction;
@@ -78,6 +81,7 @@
 import org.openstreetmap.josm.actions.WireframeToggleAction;
 import org.openstreetmap.josm.actions.ZoomInAction;
 import org.openstreetmap.josm.actions.ZoomOutAction;
+import org.openstreetmap.josm.actions.OrthogonalizeAction.Undo;
 import org.openstreetmap.josm.actions.audio.AudioBackAction;
 import org.openstreetmap.josm.actions.audio.AudioFasterAction;
 import org.openstreetmap.josm.actions.audio.AudioFwdAction;
@@ -184,9 +188,17 @@
     public final JMenu presetsMenu = addMenu(marktr("Presets"), KeyEvent.VK_P, 4, ht("/Menu/Presets"));
     public final ImageryMenu imageryMenu =
         (ImageryMenu)addMenu(new ImageryMenu(), marktr("Imagery"), KeyEvent.VK_I, 5, ht("/Menu/Imagery"));
+    /** the window menu is split into several groups. The first is for windows that can be opened from
+     * this menu any time, e.g. the changeset editor. The second group is for toggle dialogs and the third
+     * group is for currently open windows that cannot be toggled, e.g. relation editors. It's recommended
+     * to use WINDOW_MENU_GROUP to determine the group integer.
+     */
+    public final JMenu windowMenu = addMenu(marktr("Windows"), KeyEvent.VK_W, 6, ht("/Menu/Windows"));
+    public static enum WINDOW_MENU_GROUP { ALWAYS, TOGGLE_DIALOG, VOLATILE }
+
     public JMenu audioMenu = null;
-    public final JMenu helpMenu = addMenu(marktr("Help"), KeyEvent.VK_H, 6, ht("/Menu/Help"));
-    public final int defaultMenuPos = 6;
+    public final JMenu helpMenu = addMenu(marktr("Help"), KeyEvent.VK_H, 7, ht("/Menu/Help"));
+    public final int defaultMenuPos = 7;
 
     public final JosmAction moveUpAction = new MoveAction(MoveAction.Direction.UP);
     public final JosmAction moveDownAction = new MoveAction(MoveAction.Direction.DOWN);
@@ -196,24 +208,121 @@
 
     public final TaggingPresetSearchAction presetSearchAction = new TaggingPresetSearchAction();
     public FullscreenToggleAction fullscreenToggleAction = null;
+
+    /** this menu listener hides unnecessary JSeparators in a menu list but does not remove them.
+     * If at a later time the separators are required, they will be made visible again. Intended
+     * usage is make menus not look broken if separators are used to group the menu and some of
+     * these groups are empty.
+     */
+    public final static MenuListener menuSeparatorHandler = new MenuListener() {
+        @Override
+        public void menuCanceled(MenuEvent arg0) {}
+        @Override
+        public void menuDeselected(MenuEvent arg0) {}
+        @Override
+        public void menuSelected(MenuEvent a) {
+            if(!(a.getSource() instanceof JMenu))
+                return;
+            final JPopupMenu m = ((JMenu) a.getSource()).getPopupMenu();
+            for(int i=0; i < m.getComponentCount()-1; i++) {
+                if(!(m.getComponent(i) instanceof JSeparator)) {
+                    continue;
+                }
+                // hide separator if the next menu item is one as well
+                ((JSeparator) m.getComponent(i)).setVisible(!(m.getComponent(i+1) instanceof JSeparator));
+            }
+            // hide separator at the end of the menu
+            if(m.getComponent(m.getComponentCount()-1) instanceof JSeparator) {
+                ((JSeparator) m.getComponent(m.getComponentCount()-1)).setVisible(false);
+            }
+        }
+    };
+
     /**
      * Add a JosmAction to a menu.
      *
      * This method handles all the shortcut handling. It also makes sure that actions that are
-     * handled by the OS are not duplicated on the menu.
+     * handled by the OS are not duplicated on the menu. Menu item will be added at the end of
+     * the menu.
+     * @param menu to add the action to
+     * @param the action that should get a menu item
      */
     public static JMenuItem add(JMenu menu, JosmAction action) {
-        JMenuItem menuitem = null;
-        if (!action.getShortcut().getAutomatic()) {
-            menuitem = menu.add(action);
+        if (action.getShortcut().getAutomatic())
+            return null;
+        JMenuItem menuitem = menu.add(action);
             KeyStroke ks = action.getShortcut().getKeyStroke();
             if (ks != null) {
                 menuitem.setAccelerator(ks);
             }
+        return menuitem;
+    }
+
+    /**
+     * Add a JosmAction to a menu.
+     *
+     * This method handles all the shortcut handling. It also makes sure that actions that are
+     * handled by the OS are not duplicated on the menu.
+     * @param menu to add the action to
+     * @param the action that should get a menu item
+     * @param group the item should be added to. Groups are split by a separator.
+     *        0 is the first group, -1 will add the item to the end.
+     */
+    public static <E extends Enum<E>> JMenuItem add(JMenu menu, JosmAction action, Enum<E> group) {
+        if (action.getShortcut().getAutomatic())
+            return null;
+        int i = getInsertionIndexForGroup(menu, group.ordinal());
+        JMenuItem menuitem = (JMenuItem) menu.add(new JMenuItem(action), i);
+        KeyStroke ks = action.getShortcut().getKeyStroke();
+        if (ks != null) {
+            menuitem.setAccelerator(ks);
         }
         return menuitem;
     }
 
+    /**
+     * Add a JosmAction to a menu and automatically prints accelerator if available.
+     * Also adds a checkbox that may be toggled.
+     * @param menu to add the action to
+     * @param the action that should get a menu item
+     * @param group the item should be added to. Groups are split by a separator. Use
+     *        one of the enums that are defined for some of the menus to tell in which
+     *        group the item should go.
+     */
+    public static <E extends Enum<E>> JCheckBoxMenuItem addWithCheckbox(JMenu menu, JosmAction action, Enum<E> group) {
+        int i = getInsertionIndexForGroup(menu, group.ordinal());
+        final JCheckBoxMenuItem mi = (JCheckBoxMenuItem) menu.add(new JCheckBoxMenuItem(action), i);
+        final KeyStroke ks = action.getShortcut().getKeyStroke();
+        if (ks != null) {
+            mi.setAccelerator(ks);
+        }
+        return mi;
+    }
+
+    /** finds the correct insertion index for a given group and adds separators if necessary */
+    private static int getInsertionIndexForGroup(JMenu menu, int group) {
+        if(group < 0)
+            return -1;
+        // look for separator that *ends* the group (or stop at end of menu)
+        int i;
+        for(i=0; i < menu.getItemCount() && group >= 0; i++) {
+            if(menu.getItem(i) == null) {
+                group--;
+            }
+        }
+        // insert before separator that ends the group
+        if(group < 0) {
+            i--;
+        }
+        // not enough separators have been found, add them
+        while(group > 0) {
+            menu.addSeparator();
+            group--;
+            i++;
+        }
+        return i;
+    }
+
     public JMenu addMenu(String name, int mnemonicKey, int position, String relativeHelpTopic) {
         return addMenu(new JMenu(tr(name)), name, mnemonicKey, position, relativeHelpTopic);
     }
@@ -294,14 +403,6 @@
         vft.setAccelerator(viewportFollowToggleAction.getShortcut().getKeyStroke());
         viewportFollowToggleAction.addButtonModel(vft.getModel());
 
-        // -- changeset manager toggle action
-        ChangesetManagerToggleAction changesetManagerToggleAction = new ChangesetManagerToggleAction();
-        final JCheckBoxMenuItem mi = new JCheckBoxMenuItem(changesetManagerToggleAction);
-        viewMenu.addSeparator();
-        viewMenu.add(mi);
-        mi.setAccelerator(changesetManagerToggleAction.getShortcut().getKeyStroke());
-        changesetManagerToggleAction.addButtonModel(mi.getModel());
-
         if(!Main.applet && Main.platform.canFullscreen()) {
             // -- fullscreen toggle action
             fullscreenToggleAction = new FullscreenToggleAction();
@@ -341,6 +442,13 @@
         add(toolsMenu, joinAreas);
         add(toolsMenu, createMultipolygon);
 
+        // -- changeset manager toggle action
+        ChangesetManagerToggleAction changesetManagerToggleAction = new ChangesetManagerToggleAction();
+        final JCheckBoxMenuItem mi = MainMenu.addWithCheckbox(windowMenu, changesetManagerToggleAction,
+                MainMenu.WINDOW_MENU_GROUP.ALWAYS);
+        changesetManagerToggleAction.addButtonModel(mi.getModel());
+
+
         if (!Main.pref.getBoolean("audio.menuinvisible", false)) {
             audioMenu = addMenu(marktr("Audio"), KeyEvent.VK_A, defaultMenuPos, ht("/Menu/Audio"));
             add(audioMenu, audioPlayPause);
@@ -359,6 +467,9 @@
                 Shortcut.GROUP_DIRECT).getKeyStroke());
         add(helpMenu, about);
 
+
+        windowMenu.addMenuListener(menuSeparatorHandler);
+
         new PresetsMenuEnabler(presetsMenu).refreshEnabled();
     }
 
Index: src/org/openstreetmap/josm/gui/dialogs/ToggleDialog.java
===================================================================
--- src/org/openstreetmap/josm/gui/dialogs/ToggleDialog.java	(revision 4348)
+++ src/org/openstreetmap/josm/gui/dialogs/ToggleDialog.java	(working copy)
@@ -25,6 +25,7 @@
 import javax.swing.BorderFactory;
 import javax.swing.ImageIcon;
 import javax.swing.JButton;
+import javax.swing.JCheckBoxMenuItem;
 import javax.swing.JComponent;
 import javax.swing.JDialog;
 import javax.swing.JLabel;
@@ -34,6 +35,7 @@
 
 import org.openstreetmap.josm.Main;
 import org.openstreetmap.josm.actions.JosmAction;
+import org.openstreetmap.josm.gui.MainMenu;
 import org.openstreetmap.josm.gui.dialogs.DialogsPanel.Action;
 import org.openstreetmap.josm.gui.help.HelpUtil;
 import org.openstreetmap.josm.gui.help.Helpful;
@@ -47,7 +49,6 @@
  *
  */
 public class ToggleDialog extends JPanel implements Helpful {
-
     /** The action to toggle this dialog */
     protected ToggleDialogAction toggleAction;
     protected String preferencePrefix;
@@ -85,6 +86,11 @@
     protected JToggleButton button;
     protected boolean buttonHidden;
 
+    /** holds the menu entry in the windows menu. Required to properly
+     * toggle the checkbox on show/hide
+     */
+    protected JCheckBoxMenuItem windowMenuItem;
+
     /**
      * Constructor
      * (see below)
@@ -132,6 +138,10 @@
         buttonHidden = Main.pref.getBoolean(preferencePrefix+".button_hidden", false);
 
         RedirectInputMap.redirectToMainContentPane(this);
+
+        windowMenuItem = MainMenu.addWithCheckbox(Main.main.menu.windowMenu,
+                (JosmAction) getToggleAction(),
+                MainMenu.WINDOW_MENU_GROUP.TOGGLE_DIALOG);
     }
 
     /**
@@ -152,6 +162,9 @@
 
         public void actionPerformed(ActionEvent e) {
             toggleButtonHook();
+            if(getValue("toolbarbutton") != null && getValue("toolbarbutton") instanceof JButton) {
+                ((JButton) getValue("toolbarbutton")).setSelected(!isShowing);
+            }
             if (isShowing) {
                 hideDialog();
                 dialogsPanel.reconstruct(Action.ELEMENT_SHRINKS, null);
@@ -187,6 +200,7 @@
         }
         // toggling the selected value in order to enforce PropertyChangeEvents
         setIsShowing(true);
+        windowMenuItem.setState(true);
         toggleAction.putValue("selected", false);
         toggleAction.putValue("selected", true);
     }
@@ -244,6 +258,7 @@
     public void hideDialog() {
         closeDetachedDialog();
         this.setVisible(false);
+        windowMenuItem.setState(false);
         setIsShowing(false);
         toggleAction.putValue("selected", false);
     }
@@ -322,6 +337,7 @@
     public void destroy() {
         closeDetachedDialog();
         hideNotify();
+        Main.main.menu.windowMenu.remove(windowMenuItem);
     }
 
     /**
Index: src/org/openstreetmap/josm/gui/dialogs/relation/GenericRelationEditor.java
===================================================================
--- src/org/openstreetmap/josm/gui/dialogs/relation/GenericRelationEditor.java	(revision 4348)
+++ src/org/openstreetmap/josm/gui/dialogs/relation/GenericRelationEditor.java	(working copy)
@@ -34,6 +34,8 @@
 import javax.swing.BorderFactory;
 import javax.swing.JComponent;
 import javax.swing.JLabel;
+import javax.swing.JMenu;
+import javax.swing.JMenuItem;
 import javax.swing.JOptionPane;
 import javax.swing.JPanel;
 import javax.swing.JScrollPane;
@@ -53,6 +55,7 @@
 
 import org.openstreetmap.josm.Main;
 import org.openstreetmap.josm.actions.CopyAction;
+import org.openstreetmap.josm.actions.JosmAction;
 import org.openstreetmap.josm.actions.PasteTagsAction.TagPaster;
 import org.openstreetmap.josm.command.AddCommand;
 import org.openstreetmap.josm.command.ChangeCommand;
@@ -67,8 +70,9 @@
 import org.openstreetmap.josm.gui.ConditionalOptionPaneUtil;
 import org.openstreetmap.josm.gui.DefaultNameFormatter;
 import org.openstreetmap.josm.gui.HelpAwareOptionPane;
-import org.openstreetmap.josm.gui.HelpAwareOptionPane.ButtonSpec;
+import org.openstreetmap.josm.gui.MainMenu;
 import org.openstreetmap.josm.gui.SideButton;
+import org.openstreetmap.josm.gui.HelpAwareOptionPane.ButtonSpec;
 import org.openstreetmap.josm.gui.dialogs.properties.PresetListPanel.PresetHandler;
 import org.openstreetmap.josm.gui.help.ContextSensitiveHelpAction;
 import org.openstreetmap.josm.gui.help.HelpUtil;
@@ -101,6 +105,11 @@
 
     private AutoCompletingTextField tfRole;
 
+    /** the menu item in the windows menu. Required to properly
+     * hide on dialog close.
+     */
+    private JMenuItem windowMenuItem;
+
     /**
      * Creates a new relation editor for the given relation. The relation will be saved if the user
      * selects "ok" in the editor.
@@ -574,16 +583,41 @@
         super.setVisible(visible);
         if (visible) {
             RelationDialogManager.getRelationDialogManager().positionOnScreen(this);
+            if(windowMenuItem == null) {
+                addToWindowMenu();
+            }
         } else {
             // make sure all registered listeners are unregistered
             //
             selectionTableModel.unregister();
             memberTableModel.unregister();
             memberTable.unlinkAsListener();
+            if(windowMenuItem != null) {
+                Main.main.menu.windowMenu.remove(windowMenuItem);
+                windowMenuItem = null;
+            }
             dispose();
         }
     }
 
+    /** adds current relation editor to the windows menu (in the "volatile" group) o*/
+    protected void addToWindowMenu() {
+        String name = getRelation() == null ? tr("New Relation") : getRelation().getLocalName();
+        final String tt = tr("Focus Relation Editor with relation ''{0}'' in layer ''{1}''",
+                name, getLayer().getName());
+        name = tr("Relation Editor: {0}", name == null ? getRelation().getId() : name);
+        final JMenu wm = Main.main.menu.windowMenu;
+        final JosmAction focusAction = new JosmAction(name, "dialogs/relationlist", tt, null, false, false) {
+            @Override
+            public void actionPerformed(ActionEvent e) {
+                final RelationEditor r = (RelationEditor) getValue("relationEditor");
+                r.setVisible(true);
+            }
+        };
+        focusAction.putValue("relationEditor", this);
+        windowMenuItem = MainMenu.add(wm, focusAction, MainMenu.WINDOW_MENU_GROUP.VOLATILE);
+    }
+
     /**
      * checks whether the current relation has members referring to itself. If so,
      * warns the users and provides an option for removing these members.
Index: src/org/openstreetmap/josm/gui/help/HelpBrowser.java
===================================================================
--- src/org/openstreetmap/josm/gui/help/HelpBrowser.java	(revision 4348)
+++ src/org/openstreetmap/josm/gui/help/HelpBrowser.java	(working copy)
@@ -24,6 +24,7 @@
 import javax.swing.JComponent;
 import javax.swing.JDialog;
 import javax.swing.JEditorPane;
+import javax.swing.JMenuItem;
 import javax.swing.JOptionPane;
 import javax.swing.JPanel;
 import javax.swing.JScrollPane;
@@ -44,7 +45,9 @@
 import javax.swing.text.html.HTML.Tag;
 
 import org.openstreetmap.josm.Main;
+import org.openstreetmap.josm.actions.JosmAction;
 import org.openstreetmap.josm.gui.HelpAwareOptionPane;
+import org.openstreetmap.josm.gui.MainMenu;
 import org.openstreetmap.josm.tools.ImageProvider;
 import org.openstreetmap.josm.tools.OpenBrowser;
 import org.openstreetmap.josm.tools.WindowGeometry;
@@ -53,6 +56,11 @@
     /** the unique instance */
     private static HelpBrowser instance;
 
+    /** the menu item in the windows menu. Required to properly
+     * hide on dialog close.
+     */
+    private JMenuItem windowMenuItem;
+
     /**
      * Replies the unique instance of the help browser
      *
@@ -106,6 +114,13 @@
 
     private HelpContentReader reader;
 
+    private static final JosmAction focusAction = new JosmAction(tr("JOSM Help Browser"), "help", "", null, false, false) {
+        @Override
+        public void actionPerformed(ActionEvent e) {
+            HelpBrowser.getInstance().setVisible(true);
+        }
+    };
+
     /**
      * Builds the style sheet used in the internal help browser
      *
@@ -193,6 +208,13 @@
         } else if (!visible && isShowing()){
             new WindowGeometry(this).remember(getClass().getName() + ".geometry");
         }
+        if(windowMenuItem != null && !visible) {
+            Main.main.menu.windowMenu.remove(windowMenuItem);
+            windowMenuItem = null;
+        }
+        if(windowMenuItem == null && visible) {
+            windowMenuItem = MainMenu.add(Main.main.menu.windowMenu, focusAction, MainMenu.WINDOW_MENU_GROUP.VOLATILE);
+        }
         super.setVisible(visible);
     }
 
Index: src/org/openstreetmap/josm/gui/preferences/ToolbarPreferences.java
===================================================================
--- src/org/openstreetmap/josm/gui/preferences/ToolbarPreferences.java	(revision 4348)
+++ src/org/openstreetmap/josm/gui/preferences/ToolbarPreferences.java	(working copy)
@@ -26,7 +26,6 @@
 import java.util.List;
 import java.util.Map;
 
-import javax.swing.AbstractAction;
 import javax.swing.Action;
 import javax.swing.DefaultListCellRenderer;
 import javax.swing.DefaultListModel;
@@ -214,10 +213,11 @@
                     String paramName = readTillChar('=', '=');
                     skip('=');
                     String paramValue = readTillChar(',','}');
-                    if ("icon".equals(paramName) && paramValue.length() > 0)
+                    if ("icon".equals(paramName) && paramValue.length() > 0) {
                         result.setIcon(paramValue);
-                    else if("name".equals(paramName) && paramValue.length() > 0)
+                    } else if("name".equals(paramName) && paramValue.length() > 0) {
                         result.setName(paramValue);
+                    }
                     skip(',');
                 }
                 skip('}');
@@ -280,9 +280,10 @@
                     escape(tmp);
                     first = false;
                 }
-                if(!first)
+                if(!first) {
                     result.append('}');
             }
+            }
 
             return result.toString();
         }
@@ -322,9 +323,10 @@
                     default:
                         return null;
                     }
-                } else
+                } else {
                     rowIndex -= 2;
             }
+            }
             ActionParameter<Object> param = getParam(rowIndex);
             switch (columnIndex) {
             case 0:
@@ -351,9 +353,10 @@
                 } else if (rowIndex == 1) {
                      currentAction.setIcon((String)aValue);
                      return;
-                } else
+                } else {
                     rowIndex -= 2;
             }
+            }
             ActionParameter<Object> param = getParam(rowIndex);
             currentAction.getParameters().put(param.getName(), param.readFromString((String)aValue));
         }
@@ -756,10 +759,11 @@
                     t.add("|");
                 } else {
                     String res = parser.saveAction(action);
-                    if(res != null)
+                    if(res != null) {
                         t.add(res);
                 }
             }
+            }
             if (t.isEmpty()) {
                 t = Collections.singletonList(EMPTY_TOOLBAR_MARKER);
             }
@@ -901,7 +905,7 @@
     }
 
     /**
-     * Parse the toolbar preference setting and construct the toolbar GUI control.
+     * Parse the toolbar preference setting and construct the c GUI control.
      *
      * Call this, if anything has changed in the toolbar settings and you want to refresh
      * the toolbar content (e.g. after registering actions in a plugin)
@@ -915,13 +919,15 @@
             } else {
                 JButton b = control.add(action.getParametrizedAction());
                 String tt = action.getDisplayTooltip();
-                if (tt != null && !tt.isEmpty())
+                if (tt != null && !tt.isEmpty()) {
                     b.setToolTipText(tt);
+                }
                 Icon i = action.getDisplayIcon();
-                if (i != null)
+                if (i != null) {
                     b.setIcon(i);
             }
         }
+        }
         control.setVisible(control.getComponentCount() != 0);
     }
 
Index: src/org/openstreetmap/josm/gui/MapFrame.java
===================================================================
--- src/org/openstreetmap/josm/gui/MapFrame.java	(revision 4348)
+++ src/org/openstreetmap/josm/gui/MapFrame.java	(working copy)
@@ -115,6 +115,9 @@
     private final Map<Layer, MapMode> lastMapMode = new HashMap<Layer, MapMode>();
 
     public MapFrame(JPanel contentPane) {
+        // don't show right now because it is initialized before there are any layers
+        setVisible(false);
+
         setSize(400,400);
         setLayout(new BorderLayout());
 
@@ -122,9 +125,6 @@
 
         new FileDrop(mapView);
 
-        // show menu entry
-        Main.main.menu.viewMenu.setVisible(true);
-
         // toolbar
         toolBarActions.setFloatable(false);
         addMapMode(new IconToggleButton(new SelectAction(this)));
@@ -311,6 +311,8 @@
         boolean old = isVisible();
         super.setVisible(aFlag);
         if (old != aFlag) {
+            // show or hide menu entry
+            Main.main.menu.viewMenu.setVisible(aFlag);
             firePropertyChange("visible", old, aFlag);
         }
     }
