Index: trunk/src/org/openstreetmap/josm/Main.java
===================================================================
--- trunk/src/org/openstreetmap/josm/Main.java	(revision 2222)
+++ trunk/src/org/openstreetmap/josm/Main.java	(revision 2224)
@@ -220,5 +220,5 @@
             mapFrame.selectMapMode((MapMode)mapFrame.getDefaultButtonAction());
             mapFrame.setVisible(true);
-            mapFrame.setVisibleDialogs();
+            mapFrame.initializeDialogsPane();
             // bootstrapping problem: make sure the layer list dialog is going to
             // listen to change events of the very first layer
@@ -243,5 +243,5 @@
     /**
      * Replies the current edit layer
-     * 
+     *
      * @return the current edit layer. null, if no current edit layer exists
      */
@@ -549,5 +549,5 @@
                 newGeometry = width + "x" + height + "+" + x + "+" + y;
             }
-            
+
             if (map  != null) {
                 newToggleDlgWidth = Integer.toString(map.getToggleDlgWidth());
Index: trunk/src/org/openstreetmap/josm/data/Preferences.java
===================================================================
--- trunk/src/org/openstreetmap/josm/data/Preferences.java	(revision 2222)
+++ trunk/src/org/openstreetmap/josm/data/Preferences.java	(revision 2224)
@@ -442,8 +442,4 @@
     public final void resetToDefault(){
         properties.clear();
-        put("layerlist.visible", true);
-        put("propertiesdialog.visible", true);
-        put("selectionlist.visible", true);
-        put("commandstack.visible", true);
         if (System.getProperty("os.name").toUpperCase().indexOf("WINDOWS") == -1) {
             put("laf", "javax.swing.plaf.metal.MetalLookAndFeel");
Index: trunk/src/org/openstreetmap/josm/gui/MapFrame.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/MapFrame.java	(revision 2222)
+++ trunk/src/org/openstreetmap/josm/gui/MapFrame.java	(revision 2224)
@@ -8,4 +8,5 @@
 import java.awt.Dimension;
 import java.util.ArrayList;
+import java.util.List;
 
 import javax.swing.AbstractButton;
@@ -29,4 +30,5 @@
 import org.openstreetmap.josm.gui.dialogs.CommandStackDialog;
 import org.openstreetmap.josm.gui.dialogs.ConflictDialog;
+import org.openstreetmap.josm.gui.dialogs.DialogsPanel;
 import org.openstreetmap.josm.gui.dialogs.FilterDialog;
 import org.openstreetmap.josm.gui.dialogs.HistoryDialog;
@@ -75,9 +77,9 @@
      * instead of adding directly to this list.
      */
-    private JPanel toggleDialogs = new JPanel();
-    private ArrayList<ToggleDialog> allDialogs = new ArrayList<ToggleDialog>();
+    private List<ToggleDialog> allDialogs = new ArrayList<ToggleDialog>();
+    private DialogsPanel dialogsPanel = new DialogsPanel();
 
     public final ButtonGroup toolGroup = new ButtonGroup();
-    
+
     /**
      * Default width of the toggle dialog area.
@@ -107,5 +109,5 @@
 
         JSplitPane splitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, true,
-                             mapView, toggleDialogs); 
+                             mapView, dialogsPanel);
 
         /**
@@ -113,5 +115,5 @@
          */
         splitPane.setResizeWeight(1.0);
-        
+
         /**
          * Some beautifications.
@@ -127,11 +129,11 @@
             }
         });
-        
+
         add(splitPane, BorderLayout.CENTER);
 
-        toggleDialogs.setLayout(new BoxLayout(toggleDialogs, BoxLayout.Y_AXIS));
-        toggleDialogs.setPreferredSize(new Dimension(Main.pref.getInteger("toggleDialogs.width",DEF_TOGGLE_DLG_WIDTH), 0));
-                                                                        
-        toggleDialogs.setMinimumSize(new Dimension(24, 0));
+        dialogsPanel.setLayout(new BoxLayout(dialogsPanel, BoxLayout.Y_AXIS));
+        dialogsPanel.setPreferredSize(new Dimension(Main.pref.getInteger("toggleDialogs.width",DEF_TOGGLE_DLG_WIDTH), 0));
+
+        dialogsPanel.setMinimumSize(new Dimension(24, 0));
         mapView.setMinimumSize(new Dimension(10,0));
 
@@ -173,7 +175,5 @@
      */
     public void destroy() {
-        for (ToggleDialog t : allDialogs) {
-            t.closeDetachedDialog();
-        }
+        dialogsPanel.destroy();
         for (int i = 0; i < toolBarActions.getComponentCount(); ++i)
             if (toolBarActions.getComponent(i) instanceof Destroyable) {
@@ -203,16 +203,6 @@
      * Open all ToggleDialogs that have their preferences property set. Close all others.
      */
-    public void setVisibleDialogs() {
-        toggleDialogs.removeAll();
-        for (ToggleDialog dialog: allDialogs) {
-            dialog.setVisible(false);
-            toggleDialogs.add(dialog);
-            dialog.setParent(toggleDialogs);
-            if (Main.pref.getBoolean(dialog.getPreferencePrefix()+".visible")) {
-                dialog.showDialog();
-            } else {
-                dialog.hideDialog();
-            }
-        }
+    public void initializeDialogsPane() {
+        dialogsPanel.initialize(allDialogs);
     }
 
@@ -243,6 +233,4 @@
         }
     }
-
-
 
     /**
@@ -299,9 +287,5 @@
      */
     public <T> T getToggleDialog(Class<T> type) {
-        for (ToggleDialog td : allDialogs) {
-            if (type.isInstance(td))
-                return type.cast(td);
-        }
-        return null;
+        return dialogsPanel.getToggleDialog(type);
     }
 
@@ -310,5 +294,5 @@
      */
     public int getToggleDlgWidth() {
-        return toggleDialogs.getWidth();
+        return dialogsPanel.getWidth();
     }
 }
Index: trunk/src/org/openstreetmap/josm/gui/MultiSplitLayout.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/MultiSplitLayout.java	(revision 2224)
+++ trunk/src/org/openstreetmap/josm/gui/MultiSplitLayout.java	(revision 2224)
@@ -0,0 +1,1351 @@
+/*
+ * $Id: MultiSplitLayout.java,v 1.15 2005/10/26 14:29:54 hansmuller Exp $
+ *
+ * Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle,
+ * Santa Clara, California 95054, U.S.A. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+//package org.jdesktop.swingx;
+package org.openstreetmap.josm.gui;
+
+import java.awt.Component;
+import java.awt.Container;
+import java.awt.Dimension;
+import java.awt.Insets;
+import java.awt.LayoutManager;
+import java.awt.Rectangle;
+import java.beans.PropertyChangeListener;
+import java.beans.PropertyChangeSupport;
+import java.io.IOException;
+import java.io.Reader;
+import java.io.StreamTokenizer;
+import java.io.StringReader;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.ListIterator;
+import java.util.Map;
+import javax.swing.UIManager;
+
+/**
+ * The MultiSplitLayout layout manager recursively arranges its
+ * components in row and column groups called "Splits".  Elements of
+ * the layout are separated by gaps called "Dividers".  The overall
+ * layout is defined with a simple tree model whose nodes are
+ * instances of MultiSplitLayout.Split, MultiSplitLayout.Divider,
+ * and MultiSplitLayout.Leaf. Named Leaf nodes represent the space
+ * allocated to a component that was added with a constraint that
+ * matches the Leaf's name.  Extra space is distributed
+ * among row/column siblings according to their 0.0 to 1.0 weight.
+ * If no weights are specified then the last sibling always gets
+ * all of the extra space, or space reduction.
+ *
+ * <p>
+ * Although MultiSplitLayout can be used with any Container, it's
+ * the default layout manager for MultiSplitPane.  MultiSplitPane
+ * supports interactively dragging the Dividers, accessibility,
+ * and other features associated with split panes.
+ *
+ * <p>
+ * All properties in this class are bound: when a properties value
+ * is changed, all PropertyChangeListeners are fired.
+ *
+ * @author Hans Muller
+ * @see MultiSplitPane
+ */
+
+public class MultiSplitLayout implements LayoutManager {
+    private final Map<String, Component> childMap = new HashMap<String, Component>();
+    private final PropertyChangeSupport pcs = new PropertyChangeSupport(this);
+    private Node model;
+    private int dividerSize;
+    private boolean floatingDividers = true;
+
+    /**
+     * Create a MultiSplitLayout with a default model with a single
+     * Leaf node named "default".
+     *
+     * #see setModel
+     */
+    public MultiSplitLayout() {
+        this(new Leaf("default"));
+    }
+
+    /**
+     * Create a MultiSplitLayout with the specified model.
+     *
+     * #see setModel
+     */
+    public MultiSplitLayout(Node model) {
+        this.model = model;
+        this.dividerSize = UIManager.getInt("SplitPane.dividerSize");
+        if (this.dividerSize == 0) {
+            this.dividerSize = 7;
+        }
+    }
+
+    public void addPropertyChangeListener(PropertyChangeListener listener) {
+        if (listener != null) {
+            pcs.addPropertyChangeListener(listener);
+        }
+    }
+    public void removePropertyChangeListener(PropertyChangeListener listener) {
+        if (listener != null) {
+            pcs.removePropertyChangeListener(listener);
+        }
+    }
+    public PropertyChangeListener[] getPropertyChangeListeners() {
+        return pcs.getPropertyChangeListeners();
+    }
+
+    private void firePCS(String propertyName, Object oldValue, Object newValue) {
+        if (!(oldValue != null && newValue != null && oldValue.equals(newValue))) {
+            pcs.firePropertyChange(propertyName, oldValue, newValue);
+        }
+    }
+
+    /**
+     * Return the root of the tree of Split, Leaf, and Divider nodes
+     * that define this layout.
+     *
+     * @return the value of the model property
+     * @see #setModel
+     */
+    public Node getModel() { return model; }
+
+    /**
+     * Set the root of the tree of Split, Leaf, and Divider nodes
+     * that define this layout.  The model can be a Split node
+     * (the typical case) or a Leaf.  The default value of this
+     * property is a Leaf named "default".
+     *
+     * @param model the root of the tree of Split, Leaf, and Divider node
+     * @throws IllegalArgumentException if model is a Divider or null
+     * @see #getModel
+     */
+    public void setModel(Node model) {
+        if ((model == null) || (model instanceof Divider)) {
+            throw new IllegalArgumentException("invalid model");
+        }
+        Node oldModel = model;
+        this.model = model;
+        firePCS("model", oldModel, model);
+    }
+
+    /**
+     * Returns the width of Dividers in Split rows, and the height of
+     * Dividers in Split columns.
+     *
+     * @return the value of the dividerSize property
+     * @see #setDividerSize
+     */
+    public int getDividerSize() { return dividerSize; }
+
+    /**
+     * Sets the width of Dividers in Split rows, and the height of
+     * Dividers in Split columns.  The default value of this property
+     * is the same as for JSplitPane Dividers.
+     *
+     * @param dividerSize the size of dividers (pixels)
+     * @throws IllegalArgumentException if dividerSize < 0
+     * @see #getDividerSize
+     */
+    public void setDividerSize(int dividerSize) {
+        if (dividerSize < 0) {
+            throw new IllegalArgumentException("invalid dividerSize");
+        }
+        int oldDividerSize = this.dividerSize;
+        this.dividerSize = dividerSize;
+        firePCS("dividerSize", oldDividerSize, dividerSize);
+    }
+
+    /**
+     * @return the value of the floatingDividers property
+     * @see #setFloatingDividers
+     */
+    public boolean getFloatingDividers() { return floatingDividers; }
+
+
+    /**
+     * If true, Leaf node bounds match the corresponding component's
+     * preferred size and Splits/Dividers are resized accordingly.
+     * If false then the Dividers define the bounds of the adjacent
+     * Split and Leaf nodes.  Typically this property is set to false
+     * after the (MultiSplitPane) user has dragged a Divider.
+     *
+     * @see #getFloatingDividers
+     */
+    public void setFloatingDividers(boolean floatingDividers) {
+        boolean oldFloatingDividers = this.floatingDividers;
+        this.floatingDividers = floatingDividers;
+        firePCS("floatingDividers", oldFloatingDividers, floatingDividers);
+    }
+
+
+    /**
+     * Add a component to this MultiSplitLayout.  The
+     * <code>name</code> should match the name property of the Leaf
+     * node that represents the bounds of <code>child</code>.  After
+     * layoutContainer() recomputes the bounds of all of the nodes in
+     * the model, it will set this child's bounds to the bounds of the
+     * Leaf node with <code>name</code>.  Note: if a component was already
+     * added with the same name, this method does not remove it from
+     * its parent.
+     *
+     * @param name identifies the Leaf node that defines the child's bounds
+     * @param child the component to be added
+     * @see #removeLayoutComponent
+     */
+    public void addLayoutComponent(String name, Component child) {
+        if (name == null) {
+            throw new IllegalArgumentException("name not specified");
+        }
+        childMap.put(name, child);
+    }
+
+    /**
+     * Removes the specified component from the layout.
+     *
+     * @param child the component to be removed
+     * @see #addLayoutComponent
+     */
+    public void removeLayoutComponent(Component child) {
+        String name = child.getName();
+        if (name != null) {
+            childMap.remove(name);
+        }
+    }
+
+    private Component childForNode(Node node) {
+        if (node instanceof Leaf) {
+            Leaf leaf = (Leaf)node;
+            String name = leaf.getName();
+            return (name != null) ? childMap.get(name) : null;
+        }
+        return null;
+    }
+
+
+    private Dimension preferredComponentSize(Node node) {
+        Component child = childForNode(node);
+        return (child != null) ? child.getPreferredSize() : new Dimension(0, 0);
+
+    }
+
+    private Dimension minimumComponentSize(Node node) {
+        Component child = childForNode(node);
+        return (child != null) ? child.getMinimumSize() : new Dimension(0, 0);
+
+    }
+
+    private Dimension preferredNodeSize(Node root) {
+        if (root instanceof Leaf) {
+            return preferredComponentSize(root);
+        }
+        else if (root instanceof Divider) {
+            int dividerSize = getDividerSize();
+            return new Dimension(dividerSize, dividerSize);
+        }
+        else {
+            Split split = (Split)root;
+            List<Node> splitChildren = split.getChildren();
+            int width = 0;
+            int height = 0;
+            if (split.isRowLayout()) {
+                for(Node splitChild : splitChildren) {
+                    Dimension size = preferredNodeSize(splitChild);
+                    width += size.width;
+                    height = Math.max(height, size.height);
+                }
+            }
+            else {
+                for(Node splitChild : splitChildren) {
+                    Dimension size = preferredNodeSize(splitChild);
+                    width = Math.max(width, size.width);
+                    height += size.height;
+                }
+            }
+            return new Dimension(width, height);
+        }
+    }
+
+    private Dimension minimumNodeSize(Node root) {
+        if (root instanceof Leaf) {
+            Component child = childForNode(root);
+            return (child != null) ? child.getMinimumSize() : new Dimension(0, 0);
+        }
+        else if (root instanceof Divider) {
+            int dividerSize = getDividerSize();
+            return new Dimension(dividerSize, dividerSize);
+        }
+        else {
+            Split split = (Split)root;
+            List<Node> splitChildren = split.getChildren();
+            int width = 0;
+            int height = 0;
+            if (split.isRowLayout()) {
+                for(Node splitChild : splitChildren) {
+                    Dimension size = minimumNodeSize(splitChild);
+                    width += size.width;
+                    height = Math.max(height, size.height);
+                }
+            }
+            else {
+                for(Node splitChild : splitChildren) {
+                    Dimension size = minimumNodeSize(splitChild);
+                    width = Math.max(width, size.width);
+                    height += size.height;
+                }
+            }
+            return new Dimension(width, height);
+        }
+    }
+
+    private Dimension sizeWithInsets(Container parent, Dimension size) {
+        Insets insets = parent.getInsets();
+        int width = size.width + insets.left + insets.right;
+        int height = size.height + insets.top + insets.bottom;
+        return new Dimension(width, height);
+    }
+
+    public Dimension preferredLayoutSize(Container parent) {
+        Dimension size = preferredNodeSize(getModel());
+        return sizeWithInsets(parent, size);
+    }
+
+    public Dimension minimumLayoutSize(Container parent) {
+        Dimension size = minimumNodeSize(getModel());
+        return sizeWithInsets(parent, size);
+    }
+
+
+    private Rectangle boundsWithYandHeight(Rectangle bounds, double y, double height) {
+        Rectangle r = new Rectangle();
+        r.setBounds((int)(bounds.getX()), (int)y, (int)(bounds.getWidth()), (int)height);
+        return r;
+    }
+
+    private Rectangle boundsWithXandWidth(Rectangle bounds, double x, double width) {
+        Rectangle r = new Rectangle();
+        r.setBounds((int)x, (int)(bounds.getY()), (int)width, (int)(bounds.getHeight()));
+        return r;
+    }
+
+
+    private void minimizeSplitBounds(Split split, Rectangle bounds) {
+        Rectangle splitBounds = new Rectangle(bounds.x, bounds.y, 0, 0);
+        List<Node> splitChildren = split.getChildren();
+        Node lastChild = splitChildren.get(splitChildren.size() - 1);
+        Rectangle lastChildBounds = lastChild.getBounds();
+        if (split.isRowLayout()) {
+            int lastChildMaxX = lastChildBounds.x + lastChildBounds.width;
+            splitBounds.add(lastChildMaxX, bounds.y + bounds.height);
+        }
+        else {
+            int lastChildMaxY = lastChildBounds.y + lastChildBounds.height;
+            splitBounds.add(bounds.x + bounds.width, lastChildMaxY);
+        }
+        split.setBounds(splitBounds);
+    }
+
+
+    private void layoutShrink(Split split, Rectangle bounds) {
+        Rectangle splitBounds = split.getBounds();
+        ListIterator<Node> splitChildren = split.getChildren().listIterator();
+        Node lastWeightedChild = split.lastWeightedChild();
+
+        if (split.isRowLayout()) {
+            int totalWidth = 0;          // sum of the children's widths
+            int minWeightedWidth = 0;    // sum of the weighted childrens' min widths
+            int totalWeightedWidth = 0;  // sum of the weighted childrens' widths
+            for(Node splitChild : split.getChildren()) {
+                int nodeWidth = splitChild.getBounds().width;
+                int nodeMinWidth = Math.min(nodeWidth, minimumNodeSize(splitChild).width);
+                totalWidth += nodeWidth;
+                if (splitChild.getWeight() > 0.0) {
+                    minWeightedWidth += nodeMinWidth;
+                    totalWeightedWidth += nodeWidth;
+                }
+            }
+
+            double x = bounds.getX();
+            double extraWidth = splitBounds.getWidth() - bounds.getWidth();
+            double availableWidth = extraWidth;
+            boolean onlyShrinkWeightedComponents =
+                (totalWeightedWidth - minWeightedWidth) > extraWidth;
+
+            while(splitChildren.hasNext()) {
+                Node splitChild = splitChildren.next();
+                Rectangle splitChildBounds = splitChild.getBounds();
+                double minSplitChildWidth = minimumNodeSize(splitChild).getWidth();
+                double splitChildWeight = (onlyShrinkWeightedComponents)
+                    ? splitChild.getWeight()
+                    : (splitChildBounds.getWidth() / (double)totalWidth);
+
+                if (!splitChildren.hasNext()) {
+                    double newWidth =  Math.max(minSplitChildWidth, bounds.getMaxX() - x);
+                    Rectangle newSplitChildBounds = boundsWithXandWidth(bounds, x, newWidth);
+                    layout2(splitChild, newSplitChildBounds);
+                }
+                else if ((availableWidth > 0.0) && (splitChildWeight > 0.0)) {
+                    double allocatedWidth = Math.rint(splitChildWeight * extraWidth);
+                    double oldWidth = splitChildBounds.getWidth();
+                    double newWidth = Math.max(minSplitChildWidth, oldWidth - allocatedWidth);
+                    Rectangle newSplitChildBounds = boundsWithXandWidth(bounds, x, newWidth);
+                    layout2(splitChild, newSplitChildBounds);
+                    availableWidth -= (oldWidth - splitChild.getBounds().getWidth());
+                }
+                else {
+                    double existingWidth = splitChildBounds.getWidth();
+                    Rectangle newSplitChildBounds = boundsWithXandWidth(bounds, x, existingWidth);
+                    layout2(splitChild, newSplitChildBounds);
+                }
+                x = splitChild.getBounds().getMaxX();
+            }
+        }
+
+        else {
+            int totalHeight = 0;          // sum of the children's heights
+            int minWeightedHeight = 0;    // sum of the weighted childrens' min heights
+            int totalWeightedHeight = 0;  // sum of the weighted childrens' heights
+            for(Node splitChild : split.getChildren()) {
+                int nodeHeight = splitChild.getBounds().height;
+                int nodeMinHeight = Math.min(nodeHeight, minimumNodeSize(splitChild).height);
+                totalHeight += nodeHeight;
+                if (splitChild.getWeight() > 0.0) {
+                    minWeightedHeight += nodeMinHeight;
+                    totalWeightedHeight += nodeHeight;
+                }
+            }
+
+            double y = bounds.getY();
+            double extraHeight = splitBounds.getHeight() - bounds.getHeight();
+            double availableHeight = extraHeight;
+            boolean onlyShrinkWeightedComponents =
+                (totalWeightedHeight - minWeightedHeight) > extraHeight;
+
+            while(splitChildren.hasNext()) {
+                Node splitChild = splitChildren.next();
+                Rectangle splitChildBounds = splitChild.getBounds();
+                double minSplitChildHeight = minimumNodeSize(splitChild).getHeight();
+                double splitChildWeight = (onlyShrinkWeightedComponents)
+                    ? splitChild.getWeight()
+                    : (splitChildBounds.getHeight() / (double)totalHeight);
+
+                if (!splitChildren.hasNext()) {
+                    double oldHeight = splitChildBounds.getHeight();
+                    double newHeight =  Math.max(minSplitChildHeight, bounds.getMaxY() - y);
+                    Rectangle newSplitChildBounds = boundsWithYandHeight(bounds, y, newHeight);
+                    layout2(splitChild, newSplitChildBounds);
+                    availableHeight -= (oldHeight - splitChild.getBounds().getHeight());
+                }
+                else if ((availableHeight > 0.0) && (splitChildWeight > 0.0)) {
+                    double allocatedHeight = Math.rint(splitChildWeight * extraHeight);
+                    double oldHeight = splitChildBounds.getHeight();
+                    double newHeight = Math.max(minSplitChildHeight, oldHeight - allocatedHeight);
+                    Rectangle newSplitChildBounds = boundsWithYandHeight(bounds, y, newHeight);
+                    layout2(splitChild, newSplitChildBounds);
+                    availableHeight -= (oldHeight - splitChild.getBounds().getHeight());
+                }
+                else {
+                    double existingHeight = splitChildBounds.getHeight();
+                    Rectangle newSplitChildBounds = boundsWithYandHeight(bounds, y, existingHeight);
+                    layout2(splitChild, newSplitChildBounds);
+                }
+                y = splitChild.getBounds().getMaxY();
+            }
+        }
+
+        /* The bounds of the Split node root are set to be
+         * big enough to contain all of its children. Since
+         * Leaf children can't be reduced below their
+         * (corresponding java.awt.Component) minimum sizes,
+         * the size of the Split's bounds maybe be larger than
+         * the bounds we were asked to fit within.
+         */
+        minimizeSplitBounds(split, bounds);
+    }
+
+
+    private void layoutGrow(Split split, Rectangle bounds) {
+        Rectangle splitBounds = split.getBounds();
+        ListIterator<Node> splitChildren = split.getChildren().listIterator();
+        Node lastWeightedChild = split.lastWeightedChild();
+
+        /* Layout the Split's child Nodes' along the X axis.  The bounds
+         * of each child will have the same y coordinate and height as the
+         * layoutGrow() bounds argument.  Extra width is allocated to the
+         * to each child with a non-zero weight:
+         *     newWidth = currentWidth + (extraWidth * splitChild.getWeight())
+         * Any extraWidth "left over" (that's availableWidth in the loop
+         * below) is given to the last child.  Note that Dividers always
+         * have a weight of zero, and they're never the last child.
+         */
+        if (split.isRowLayout()) {
+            double x = bounds.getX();
+            double extraWidth = bounds.getWidth() - splitBounds.getWidth();
+            double availableWidth = extraWidth;
+
+            while(splitChildren.hasNext()) {
+                Node splitChild = splitChildren.next();
+                Rectangle splitChildBounds = splitChild.getBounds();
+                double splitChildWeight = splitChild.getWeight();
+
+                if (!splitChildren.hasNext()) {
+                    double newWidth = bounds.getMaxX() - x;
+                    Rectangle newSplitChildBounds = boundsWithXandWidth(bounds, x, newWidth);
+                    layout2(splitChild, newSplitChildBounds);
+                }
+                else if ((availableWidth > 0.0) && (splitChildWeight > 0.0)) {
+                    double allocatedWidth = (splitChild.equals(lastWeightedChild))
+                        ? availableWidth
+                        : Math.rint(splitChildWeight * extraWidth);
+                    double newWidth = splitChildBounds.getWidth() + allocatedWidth;
+                    Rectangle newSplitChildBounds = boundsWithXandWidth(bounds, x, newWidth);
+                    layout2(splitChild, newSplitChildBounds);
+                    availableWidth -= allocatedWidth;
+                }
+                else {
+                    double existingWidth = splitChildBounds.getWidth();
+                    Rectangle newSplitChildBounds = boundsWithXandWidth(bounds, x, existingWidth);
+                    layout2(splitChild, newSplitChildBounds);
+                }
+                x = splitChild.getBounds().getMaxX();
+            }
+        }
+
+        /* Layout the Split's child Nodes' along the Y axis.  The bounds
+         * of each child will have the same x coordinate and width as the
+         * layoutGrow() bounds argument.  Extra height is allocated to the
+         * to each child with a non-zero weight:
+         *     newHeight = currentHeight + (extraHeight * splitChild.getWeight())
+         * Any extraHeight "left over" (that's availableHeight in the loop
+         * below) is given to the last child.  Note that Dividers always
+         * have a weight of zero, and they're never the last child.
+         */
+        else {
+            double y = bounds.getY();
+            double extraHeight = bounds.getMaxY() - splitBounds.getHeight();
+            double availableHeight = extraHeight;
+
+            while(splitChildren.hasNext()) {
+                Node splitChild = splitChildren.next();
+                Rectangle splitChildBounds = splitChild.getBounds();
+                double splitChildWeight = splitChild.getWeight();
+
+                if (!splitChildren.hasNext()) {
+                    double newHeight = bounds.getMaxY() - y;
+                    Rectangle newSplitChildBounds = boundsWithYandHeight(bounds, y, newHeight);
+                    layout2(splitChild, newSplitChildBounds);
+                }
+                else if ((availableHeight > 0.0) && (splitChildWeight > 0.0)) {
+                    double allocatedHeight = (splitChild.equals(lastWeightedChild))
+                        ? availableHeight
+                        : Math.rint(splitChildWeight * extraHeight);
+                    double newHeight = splitChildBounds.getHeight() + allocatedHeight;
+                    Rectangle newSplitChildBounds = boundsWithYandHeight(bounds, y, newHeight);
+                    layout2(splitChild, newSplitChildBounds);
+                    availableHeight -= allocatedHeight;
+                }
+                else {
+                    double existingHeight = splitChildBounds.getHeight();
+                    Rectangle newSplitChildBounds = boundsWithYandHeight(bounds, y, existingHeight);
+                    layout2(splitChild, newSplitChildBounds);
+                }
+                y = splitChild.getBounds().getMaxY();
+            }
+        }
+    }
+
+
+    /* Second pass of the layout algorithm: branch to layoutGrow/Shrink
+     * as needed.
+     */
+   private void layout2(Node root, Rectangle bounds) {
+        if (root instanceof Leaf) {
+            Component child = childForNode(root);
+            if (child != null) {
+                child.setBounds(bounds);
+            }
+            root.setBounds(bounds);
+        }
+        else if (root instanceof Divider) {
+            root.setBounds(bounds);
+        }
+        else if (root instanceof Split) {
+            Split split = (Split)root;
+            boolean grow = split.isRowLayout()
+                ? (split.getBounds().width <= bounds.width)
+                : (split.getBounds().height <= bounds.height);
+            if (grow) {
+                layoutGrow(split, bounds);
+                root.setBounds(bounds);
+            }
+            else {
+                layoutShrink(split, bounds);
+                // split.setBounds() called in layoutShrink()
+            }
+        }
+    }
+
+
+    /* First pass of the layout algorithm.
+     *
+     * If the Dividers are "floating" then set the bounds of each
+     * node to accomodate the preferred size of all of the
+     * Leaf's java.awt.Components.  Otherwise, just set the bounds
+     * of each Leaf/Split node so that it's to the left of (for
+     * Split.isRowLayout() Split children) or directly above
+     * the Divider that follows.
+     *
+     * This pass sets the bounds of each Node in the layout model.  It
+     * does not resize any of the parent Container's
+     * (java.awt.Component) children.  That's done in the second pass,
+     * see layoutGrow() and layoutShrink().
+     */
+    private void layout1(Node root, Rectangle bounds) {
+        if (root instanceof Leaf) {
+            root.setBounds(bounds);
+        }
+        else if (root instanceof Split) {
+            Split split = (Split)root;
+            Iterator<Node> splitChildren = split.getChildren().iterator();
+            Rectangle childBounds = null;
+            int dividerSize = getDividerSize();
+
+            /* Layout the Split's child Nodes' along the X axis.  The bounds
+             * of each child will have the same y coordinate and height as the
+             * layout1() bounds argument.
+             *
+             * Note: the column layout code - that's the "else" clause below
+             * this if, is identical to the X axis (rowLayout) code below.
+             */
+            if (split.isRowLayout()) {
+                double x = bounds.getX();
+                while(splitChildren.hasNext()) {
+                    Node splitChild = splitChildren.next();
+                    Divider dividerChild =
+                        (splitChildren.hasNext()) ? (Divider)(splitChildren.next()) : null;
+
+                    double childWidth = 0.0;
+                    if (getFloatingDividers()) {
+                        childWidth = preferredNodeSize(splitChild).getWidth();
+                    }
+                    else {
+                        if (dividerChild != null) {
+                            childWidth = dividerChild.getBounds().getX() - x;
+                        }
+                        else {
+                            childWidth = split.getBounds().getMaxX() - x;
+                        }
+                    }
+                    childBounds = boundsWithXandWidth(bounds, x, childWidth);
+                    layout1(splitChild, childBounds);
+
+                    if (getFloatingDividers() && (dividerChild != null)) {
+                        double dividerX = childBounds.getMaxX();
+                        Rectangle dividerBounds = boundsWithXandWidth(bounds, dividerX, dividerSize);
+                        dividerChild.setBounds(dividerBounds);
+                    }
+                    if (dividerChild != null) {
+                        x = dividerChild.getBounds().getMaxX();
+                    }
+                }
+            }
+
+            /* Layout the Split's child Nodes' along the Y axis.  The bounds
+             * of each child will have the same x coordinate and width as the
+             * layout1() bounds argument.  The algorithm is identical to what's
+             * explained above, for the X axis case.
+             */
+            else {
+                double y = bounds.getY();
+                while(splitChildren.hasNext()) {
+                    Node splitChild = splitChildren.next();
+                    Divider dividerChild =
+                        (splitChildren.hasNext()) ? (Divider)(splitChildren.next()) : null;
+
+                    double childHeight = 0.0;
+                    if (getFloatingDividers()) {
+                        childHeight = preferredNodeSize(splitChild).getHeight();
+                    }
+                    else {
+                        if (dividerChild != null) {
+                            childHeight = dividerChild.getBounds().getY() - y;
+                        }
+                        else {
+                            childHeight = split.getBounds().getMaxY() - y;
+                        }
+                    }
+                    childBounds = boundsWithYandHeight(bounds, y, childHeight);
+                    layout1(splitChild, childBounds);
+
+                    if (getFloatingDividers() && (dividerChild != null)) {
+                        double dividerY = childBounds.getMaxY();
+                        Rectangle dividerBounds = boundsWithYandHeight(bounds, dividerY, dividerSize);
+                        dividerChild.setBounds(dividerBounds);
+                    }
+                    if (dividerChild != null) {
+                        y = dividerChild.getBounds().getMaxY();
+                    }
+                }
+            }
+            /* The bounds of the Split node root are set to be just
+             * big enough to contain all of its children, but only
+             * along the axis it's allocating space on.  That's
+             * X for rows, Y for columns.  The second pass of the
+             * layout algorithm - see layoutShrink()/layoutGrow()
+             * allocates extra space.
+             */
+            minimizeSplitBounds(split, bounds);
+        }
+    }
+
+    /**
+     * The specified Node is either the wrong type or was configured
+     * incorrectly.
+     */
+    public static class InvalidLayoutException extends RuntimeException {
+        private final Node node;
+        public InvalidLayoutException (String msg, Node node) {
+            super(msg);
+            this.node = node;
+        }
+        /**
+         * @return the invalid Node.
+         */
+        public Node getNode() { return node; }
+    }
+
+    private void throwInvalidLayout(String msg, Node node) {
+        throw new InvalidLayoutException(msg, node);
+    }
+
+    private void checkLayout(Node root) {
+        if (root instanceof Split) {
+            Split split = (Split)root;
+            if (split.getChildren().size() <= 2) {
+                throwInvalidLayout("Split must have > 2 children", root);
+            }
+            Iterator<Node> splitChildren = split.getChildren().iterator();
+            double weight = 0.0;
+            while(splitChildren.hasNext()) {
+                Node splitChild = splitChildren.next();
+                if (splitChild instanceof Divider) {
+                    throwInvalidLayout("expected a Split or Leaf Node", splitChild);
+                }
+                if (splitChildren.hasNext()) {
+                    Node dividerChild = splitChildren.next();
+                    if (!(dividerChild instanceof Divider)) {
+                        throwInvalidLayout("expected a Divider Node", dividerChild);
+                    }
+                }
+                weight += splitChild.getWeight();
+                checkLayout(splitChild);
+            }
+            if (weight > 1.0) {
+                throwInvalidLayout("Split children's total weight > 1.0", root);
+            }
+        }
+    }
+
+    /**
+     * Compute the bounds of all of the Split/Divider/Leaf Nodes in
+     * the layout model, and then set the bounds of each child component
+     * with a matching Leaf Node.
+     */
+    public void layoutContainer(Container parent) {
+        checkLayout(getModel());
+        Insets insets = parent.getInsets();
+        Dimension size = parent.getSize();
+        int width = size.width - (insets.left + insets.right);
+        int height = size.height - (insets.top + insets.bottom);
+        Rectangle bounds = new Rectangle(insets.left, insets.top, width, height);
+        layout1(getModel(), bounds);
+        layout2(getModel(), bounds);
+    }
+
+
+    private Divider dividerAt(Node root, int x, int y) {
+        if (root instanceof Divider) {
+            Divider divider = (Divider)root;
+            return (divider.getBounds().contains(x, y)) ? divider : null;
+        }
+        else if (root instanceof Split) {
+            Split split = (Split)root;
+            for(Node child : split.getChildren()) {
+                if (child.getBounds().contains(x, y)) {
+                    return dividerAt(child, x, y);
+                }
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Return the Divider whose bounds contain the specified
+     * point, or null if there isn't one.
+     *
+     * @param x x coordinate
+     * @param y y coordinate
+     * @return the Divider at x,y
+     */
+    public Divider dividerAt(int x, int y) {
+        return dividerAt(getModel(), x, y);
+    }
+
+    private boolean nodeOverlapsRectangle(Node node, Rectangle r2) {
+        Rectangle r1 = node.getBounds();
+        return
+            (r1.x <= (r2.x + r2.width)) && ((r1.x + r1.width) >= r2.x) &&
+            (r1.y <= (r2.y + r2.height)) && ((r1.y + r1.height) >= r2.y);
+    }
+
+    private List<Divider> dividersThatOverlap(Node root, Rectangle r) {
+        if (nodeOverlapsRectangle(root, r) && (root instanceof Split)) {
+            List<Divider> dividers = new ArrayList<Divider>();
+            for(Node child : ((Split)root).getChildren()) {
+                if (child instanceof Divider) {
+                    if (nodeOverlapsRectangle(child, r)) {
+                        dividers.add((Divider)child);
+                    }
+                }
+                else if (child instanceof Split) {
+                    dividers.addAll(dividersThatOverlap(child, r));
+                }
+            }
+            return dividers;
+        }
+        else {
+            return Collections.emptyList();
+        }
+    }
+
+    /**
+     * Return the Dividers whose bounds overlap the specified
+     * Rectangle.
+     *
+     * @param r target Rectangle
+     * @return the Dividers that overlap r
+     * @throws IllegalArgumentException if the Rectangle is null
+     */
+    public List<Divider> dividersThatOverlap(Rectangle r) {
+        if (r == null) {
+            throw new IllegalArgumentException("null Rectangle");
+        }
+        return dividersThatOverlap(getModel(), r);
+    }
+
+
+    /**
+     * Base class for the nodes that model a MultiSplitLayout.
+     */
+    public static abstract class Node {
+        private Split parent = null;
+        private Rectangle bounds = new Rectangle();
+        private double weight = 0.0;
+
+        /**
+         * Returns the Split parent of this Node, or null.
+         *
+         * @return the value of the parent property.
+         * @see #setParent
+         */
+        public Split getParent() { return parent; }
+
+        /**
+         * Set the value of this Node's parent property.  The default
+         * value of this property is null.
+         *
+         * @param parent a Split or null
+         * @see #getParent
+         */
+        public void setParent(Split parent) {
+            this.parent = parent;
+        }
+
+        /**
+         * Returns the bounding Rectangle for this Node.
+         *
+         * @return the value of the bounds property.
+         * @see #setBounds
+         */
+        public Rectangle getBounds() {
+            return new Rectangle(this.bounds);
+        }
+
+        /**
+         * Set the bounding Rectangle for this node.  The value of
+         * bounds may not be null.  The default value of bounds
+         * is equal to <code>new Rectangle(0,0,0,0)</code>.
+         *
+         * @param bounds the new value of the bounds property
+         * @throws IllegalArgumentException if bounds is null
+         * @see #getBounds
+         */
+        public void setBounds(Rectangle bounds) {
+            if (bounds == null) {
+                throw new IllegalArgumentException("null bounds");
+            }
+            this.bounds = new Rectangle(bounds);
+        }
+
+        /**
+         * Value between 0.0 and 1.0 used to compute how much space
+         * to add to this sibling when the layout grows or how
+         * much to reduce when the layout shrinks.
+         *
+         * @return the value of the weight property
+         * @see #setWeight
+         */
+        public double getWeight() { return weight; }
+
+        /**
+         * The weight property is a between 0.0 and 1.0 used to
+         * compute how much space to add to this sibling when the
+         * layout grows or how much to reduce when the layout shrinks.
+         * If rowLayout is true then this node's width grows
+         * or shrinks by (extraSpace * weight).  If rowLayout is false,
+         * then the node's height is changed.  The default value
+         * of weight is 0.0.
+         *
+         * @param weight a double between 0.0 and 1.0
+         * @see #getWeight
+         * @see MultiSplitLayout#layoutContainer
+         * @throws IllegalArgumentException if weight is not between 0.0 and 1.0
+         */
+        public void setWeight(double weight) {
+            if ((weight < 0.0)|| (weight > 1.0)) {
+                throw new IllegalArgumentException("invalid weight");
+            }
+            this.weight = weight;
+        }
+
+        private Node siblingAtOffset(int offset) {
+            Split parent = getParent();
+            if (parent == null) { return null; }
+            List<Node> siblings = parent.getChildren();
+            int index = siblings.indexOf(this);
+            if (index == -1) { return null; }
+            index += offset;
+            return ((index > -1) && (index < siblings.size())) ? siblings.get(index) : null;
+        }
+
+        /**
+         * Return the Node that comes after this one in the parent's
+         * list of children, or null.  If this node's parent is null,
+         * or if it's the last child, then return null.
+         *
+         * @return the Node that comes after this one in the parent's list of children.
+         * @see #previousSibling
+         * @see #getParent
+         */
+        public Node nextSibling() {
+            return siblingAtOffset(+1);
+        }
+
+        /**
+         * Return the Node that comes before this one in the parent's
+         * list of children, or null.  If this node's parent is null,
+         * or if it's the last child, then return null.
+         *
+         * @return the Node that comes before this one in the parent's list of children.
+         * @see #nextSibling
+         * @see #getParent
+         */
+        public Node previousSibling() {
+            return siblingAtOffset(-1);
+        }
+    }
+
+    /**
+     * Defines a vertical or horizontal subdivision into two or more
+     * tiles.
+     */
+    public static class Split extends Node {
+        private List<Node> children = Collections.emptyList();
+        private boolean rowLayout = true;
+
+        /**
+         * Returns true if the this Split's children are to be
+         * laid out in a row: all the same height, left edge
+         * equal to the previous Node's right edge.  If false,
+         * children are laid on in a column.
+         *
+         * @return the value of the rowLayout property.
+         * @see #setRowLayout
+         */
+        public boolean isRowLayout() { return rowLayout; }
+
+        /**
+         * Set the rowLayout property.  If true, all of this Split's
+         * children are to be laid out in a row: all the same height,
+         * each node's left edge equal to the previous Node's right
+         * edge.  If false, children are laid on in a column.  Default
+         * value is true.
+         *
+         * @param rowLayout true for horizontal row layout, false for column
+         * @see #isRowLayout
+         */
+        public void setRowLayout(boolean rowLayout) {
+            this.rowLayout = rowLayout;
+        }
+
+        /**
+         * Returns this Split node's children.  The returned value
+         * is not a reference to the Split's internal list of children
+         *
+         * @return the value of the children property.
+         * @see #setChildren
+         */
+        public List<Node> getChildren() {
+            return new ArrayList<Node>(children);
+        }
+
+        /**
+         * Set's the children property of this Split node.  The parent
+         * of each new child is set to this Split node, and the parent
+         * of each old child (if any) is set to null.  This method
+         * defensively copies the incoming List.  Default value is
+         * an empty List.
+         *
+         * @param children List of children
+         * @see #getChildren
+         * @throws IllegalArgumentException if children is null
+         */
+        public void setChildren(List<Node> children) {
+            if (children == null) {
+                throw new IllegalArgumentException("children must be a non-null List");
+            }
+            for(Node child : this.children) {
+                child.setParent(null);
+            }
+            this.children = new ArrayList<Node>(children);
+            for(Node child : this.children) {
+                child.setParent(this);
+            }
+        }
+
+        /**
+         * Convenience method that returns the last child whose weight
+         * is > 0.0.
+         *
+         * @return the last child whose weight is > 0.0.
+         * @see #getChildren
+         * @see Node#getWeight
+         */
+        public final Node lastWeightedChild() {
+            List<Node> children = getChildren();
+            Node weightedChild = null;
+            for(Node child : children) {
+                if (child.getWeight() > 0.0) {
+                    weightedChild = child;
+                }
+            }
+            return weightedChild;
+        }
+
+        public String toString() {
+            int nChildren = getChildren().size();
+            StringBuffer sb = new StringBuffer("MultiSplitLayout.Split");
+            sb.append(isRowLayout() ? " ROW [" : " COLUMN [");
+            sb.append(nChildren + ((nChildren == 1) ? " child" : " children"));
+            sb.append("] ");
+            sb.append(getBounds());
+            return sb.toString();
+        }
+    }
+
+
+    /**
+     * Models a java.awt Component child.
+     */
+    public static class Leaf extends Node {
+        private String name = "";
+
+        /**
+         * Create a Leaf node.  The default value of name is "".
+         */
+        public Leaf() { }
+
+        /**
+         * Create a Leaf node with the specified name.  Name can not
+         * be null.
+         *
+         * @param name value of the Leaf's name property
+         * @throws IllegalArgumentException if name is null
+         */
+        public Leaf(String name) {
+            if (name == null) {
+                throw new IllegalArgumentException("name is null");
+            }
+            this.name = name;
+        }
+
+        /**
+         * Return the Leaf's name.
+         *
+         * @return the value of the name property.
+         * @see #setName
+         */
+        public String getName() { return name; }
+
+        /**
+         * Set the value of the name property.  Name may not be null.
+         *
+         * @param name value of the name property
+         * @throws IllegalArgumentException if name is null
+         */
+        public void setName(String name) {
+            if (name == null) {
+                throw new IllegalArgumentException("name is null");
+            }
+            this.name = name;
+        }
+
+        public String toString() {
+            StringBuffer sb = new StringBuffer("MultiSplitLayout.Leaf");
+            sb.append(" \"");
+            sb.append(getName());
+            sb.append("\"");
+            sb.append(" weight=");
+            sb.append(getWeight());
+            sb.append(" ");
+            sb.append(getBounds());
+            return sb.toString();
+        }
+    }
+
+
+    /**
+     * Models a single vertical/horiztonal divider.
+     */
+    public static class Divider extends Node {
+        /**
+         * Convenience method, returns true if the Divider's parent
+         * is a Split row (a Split with isRowLayout() true), false
+         * otherwise. In other words if this Divider's major axis
+         * is vertical, return true.
+         *
+         * @return true if this Divider is part of a Split row.
+         */
+        public final boolean isVertical() {
+            Split parent = getParent();
+            return (parent != null) ? parent.isRowLayout() : false;
+        }
+
+        /**
+         * Dividers can't have a weight, they don't grow or shrink.
+         * @throws UnsupportedOperationException
+         */
+        public void setWeight(double weight) {
+            throw new UnsupportedOperationException();
+        }
+
+        public String toString() {
+            return "MultiSplitLayout.Divider " + getBounds().toString();
+        }
+    }
+
+
+    private static void throwParseException(StreamTokenizer st, String msg) throws Exception {
+        throw new Exception("MultiSplitLayout.parseModel Error: " + msg);
+    }
+
+    private static void parseAttribute(String name, StreamTokenizer st, Node node) throws Exception {
+        if ((st.nextToken() != '=')) {
+            throwParseException(st, "expected '=' after " + name);
+        }
+        if (name.equalsIgnoreCase("WEIGHT")) {
+            if (st.nextToken() == StreamTokenizer.TT_NUMBER) {
+                node.setWeight(st.nval);
+            }
+            else {
+                throwParseException(st, "invalid weight");
+            }
+        }
+        else if (name.equalsIgnoreCase("NAME")) {
+            if (st.nextToken() == StreamTokenizer.TT_WORD) {
+                if (node instanceof Leaf) {
+                    ((Leaf)node).setName(st.sval);
+                }
+                else {
+                    throwParseException(st, "can't specify name for " + node);
+                }
+            }
+            else {
+                throwParseException(st, "invalid name");
+            }
+        }
+        else {
+            throwParseException(st, "unrecognized attribute \"" + name + "\"");
+        }
+    }
+
+    private static void addSplitChild(Split parent, Node child) {
+        List<Node> children = new ArrayList<Node>(parent.getChildren());
+        if (children.size() == 0) {
+            children.add(child);
+        }
+        else {
+            children.add(new Divider());
+            children.add(child);
+        }
+        parent.setChildren(children);
+    }
+
+    private static void parseLeaf(StreamTokenizer st, Split parent) throws Exception {
+        Leaf leaf = new Leaf();
+        int token;
+        while ((token = st.nextToken()) != StreamTokenizer.TT_EOF) {
+            if (token == ')') {
+                break;
+            }
+            if (token == StreamTokenizer.TT_WORD) {
+                parseAttribute(st.sval, st, leaf);
+            }
+            else {
+                throwParseException(st, "Bad Leaf: " + leaf);
+            }
+        }
+        addSplitChild(parent, leaf);
+    }
+
+    private static void parseSplit(StreamTokenizer st, Split parent) throws Exception {
+        int token;
+        while ((token = st.nextToken()) != StreamTokenizer.TT_EOF) {
+            if (token == ')') {
+                break;
+            }
+            else if (token == StreamTokenizer.TT_WORD) {
+                if (st.sval.equalsIgnoreCase("WEIGHT")) {
+                    parseAttribute(st.sval, st, parent);
+                }
+                else {
+                    addSplitChild(parent, new Leaf(st.sval));
+                }
+            }
+            else if (token == '(') {
+                if ((token = st.nextToken()) != StreamTokenizer.TT_WORD) {
+                    throwParseException(st, "invalid node type");
+                }
+                String nodeType = st.sval.toUpperCase();
+                if (nodeType.equals("LEAF")) {
+                    parseLeaf(st, parent);
+                }
+                else if (nodeType.equals("ROW") || nodeType.equals("COLUMN")) {
+                    Split split = new Split();
+                    split.setRowLayout(nodeType.equals("ROW"));
+                    addSplitChild(parent, split);
+                    parseSplit(st, split);
+                }
+                else {
+                    throwParseException(st, "unrecognized node type '" + nodeType + "'");
+                }
+            }
+        }
+    }
+
+    private static Node parseModel (Reader r) {
+        StreamTokenizer st = new StreamTokenizer(r);
+        try {
+            Split root = new Split();
+            parseSplit(st, root);
+            return root.getChildren().get(0);
+        }
+        catch (Exception e) {
+            System.err.println(e);
+        }
+        finally {
+            try { r.close(); } catch (IOException ignore) {}
+        }
+        return null;
+    }
+
+    /**
+     * A convenience method that converts a string to a
+     * MultiSplitLayout model (a tree of Nodes) using a
+     * a simple syntax.  Nodes are represented by
+     * parenthetical expressions whose first token
+     * is one of ROW/COLUMN/LEAF.  ROW and COLUMN specify
+     * horizontal and vertical Split nodes respectively,
+     * LEAF specifies a Leaf node.  A Leaf's name and
+     * weight can be specified with attributes,
+     * name=<i>myLeafName</i> weight=<i>myLeafWeight</i>.
+     * Similarly, a Split's weight can be specified with
+     * weight=<i>mySplitWeight</i>.
+     *
+     * <p> For example, the following expression generates
+     * a horizontal Split node with three children:
+     * the Leafs named left and right, and a Divider in
+     * between:
+     * <pre>
+     * (ROW (LEAF name=left) (LEAF name=right weight=1.0))
+     * </pre>
+     *
+     * <p> Dividers should not be included in the string,
+     * they're added automatcially as needed.  Because
+     * Leaf nodes often only need to specify a name, one
+     * can specify a Leaf by just providing the name.
+     * The previous example can be written like this:
+     * <pre>
+     * (ROW left (LEAF name=right weight=1.0))
+     * </pre>
+     *
+     * <p>Here's a more complex example.  One row with
+     * three elements, the first and last of which are columns
+     * with two leaves each:
+     * <pre>
+     * (ROW (COLUMN weight=0.5 left.top left.bottom)
+     *      (LEAF name=middle)
+     *      (COLUMN weight=0.5 right.top right.bottom))
+     * </pre>
+     *
+     *
+     * <p> This syntax is not intended for archiving or
+     * configuration files .  It's just a convenience for
+     * examples and tests.
+     *
+     * @return the Node root of a tree based on s.
+     */
+    public static Node parseModel(String s) {
+        return parseModel(new StringReader(s));
+    }
+
+
+    private static void printModel(String indent, Node root) {
+        if (root instanceof Split) {
+            Split split = (Split)root;
+            System.out.println(indent + split);
+            for(Node child : split.getChildren()) {
+                printModel(indent + "  ", child);
+            }
+        }
+        else {
+            System.out.println(indent + root);
+        }
+    }
+
+    /**
+     * Print the tree with enough detail for simple debugging.
+     */
+    public static void printModel(Node root) {
+        printModel("", root);
+    }
+}
Index: trunk/src/org/openstreetmap/josm/gui/MultiSplitPane.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/MultiSplitPane.java	(revision 2224)
+++ trunk/src/org/openstreetmap/josm/gui/MultiSplitPane.java	(revision 2224)
@@ -0,0 +1,398 @@
+/*
+ * $Id: MultiSplitPane.java,v 1.15 2005/10/26 14:29:54 hansmuller Exp $
+ *
+ * Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle,
+ * Santa Clara, California 95054, U.S.A. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+//package org.jdesktop.swingx;
+package org.openstreetmap.josm.gui;
+
+import java.awt.Color;
+import java.awt.Cursor;
+import java.awt.Graphics;
+import java.awt.Graphics2D;
+import java.awt.Rectangle;
+import java.awt.event.KeyEvent;
+import java.awt.event.KeyListener;
+import java.awt.event.MouseEvent;
+import javax.accessibility.AccessibleContext;
+import javax.accessibility.AccessibleRole;
+import javax.swing.JPanel;
+import javax.swing.event.MouseInputAdapter;
+
+import org.openstreetmap.josm.gui.MultiSplitLayout.Divider;
+import org.openstreetmap.josm.gui.MultiSplitLayout.Node;
+
+/**
+ *
+ * <p>
+ * All properties in this class are bound: when a properties value
+ * is changed, all PropertyChangeListeners are fired.
+ *
+ * @author Hans Muller
+ */
+public class MultiSplitPane extends JPanel {
+    private AccessibleContext accessibleContext = null;
+    private boolean continuousLayout = true;
+    private DividerPainter dividerPainter = new DefaultDividerPainter();
+
+    /**
+     * Creates a MultiSplitPane with it's LayoutManager set to
+     * to an empty MultiSplitLayout.
+     */
+    public MultiSplitPane() {
+        super(new MultiSplitLayout());
+        InputHandler inputHandler = new InputHandler();
+        addMouseListener(inputHandler);
+        addMouseMotionListener(inputHandler);
+        addKeyListener(inputHandler);
+        setFocusable(true);
+    }
+
+    /**
+     * A convenience method that returns the layout manager cast
+     * to MutliSplitLayout.
+     *
+     * @return this MultiSplitPane's layout manager
+     * @see java.awt.Container#getLayout
+     * @see #setModel
+     */
+    public final MultiSplitLayout getMultiSplitLayout() {
+        return (MultiSplitLayout)getLayout();
+    }
+
+    /**
+     * A convenience method that sets the MultiSplitLayout model.
+     * Equivalent to <code>getMultiSplitLayout.setModel(model)</code>
+     *
+     * @param model the root of the MultiSplitLayout model
+     * @see #getMultiSplitLayout
+     * @see MultiSplitLayout#setModel
+     */
+    public final void setModel(Node model) {
+        getMultiSplitLayout().setModel(model);
+    }
+
+    /**
+     * A convenience method that sets the MultiSplitLayout dividerSize
+     * property. Equivalent to
+     * <code>getMultiSplitLayout().setDividerSize(newDividerSize)</code>.
+     *
+     * @param dividerSize the value of the dividerSize property
+     * @see #getMultiSplitLayout
+     * @see MultiSplitLayout#setDividerSize
+     */
+    public final void setDividerSize(int dividerSize) {
+        getMultiSplitLayout().setDividerSize(dividerSize);
+    }
+
+    /**
+     * Sets the value of the <code>continuousLayout</code> property.
+     * If true, then the layout is revalidated continuously while
+     * a divider is being moved.  The default value of this property
+     * is true.
+     *
+     * @param continuousLayout value of the continuousLayout property
+     * @see #isContinuousLayout
+     */
+    public void setContinuousLayout(boolean continuousLayout) {
+        boolean oldContinuousLayout = continuousLayout;
+        this.continuousLayout = continuousLayout;
+        firePropertyChange("continuousLayout", oldContinuousLayout, continuousLayout);
+    }
+
+    /**
+     * Returns true if dragging a divider only updates
+     * the layout when the drag gesture ends (typically, when the
+     * mouse button is released).
+     *
+     * @return the value of the <code>continuousLayout</code> property
+     * @see #setContinuousLayout
+     */
+    public boolean isContinuousLayout() {
+        return continuousLayout;
+    }
+
+    /**
+     * Returns the Divider that's currently being moved, typically
+     * because the user is dragging it, or null.
+     *
+     * @return the Divider that's being moved or null.
+     */
+    public Divider activeDivider() {
+        return dragDivider;
+    }
+
+    /**
+     * Draws a single Divider.  Typically used to specialize the
+     * way the active Divider is painted.
+     *
+     * @see #getDividerPainter
+     * @see #setDividerPainter
+     */
+    public static abstract class DividerPainter {
+        /**
+         * Paint a single Divider.
+         *
+         * @param g the Graphics object to paint with
+         * @param divider the Divider to paint
+         */
+        public abstract void paint(Graphics g, Divider divider);
+    }
+
+    private class DefaultDividerPainter extends DividerPainter {
+        public void paint(Graphics g, Divider divider) {
+            if ((divider == activeDivider()) && !isContinuousLayout()) {
+                Graphics2D g2d = (Graphics2D)g;
+                g2d.setColor(Color.black);
+                g2d.fill(divider.getBounds());
+            }
+        }
+    }
+
+    /**
+     * The DividerPainter that's used to paint Dividers on this MultiSplitPane.
+     * This property may be null.
+     *
+     * @return the value of the dividerPainter Property
+     * @see #setDividerPainter
+     */
+    public DividerPainter getDividerPainter() {
+        return dividerPainter;
+    }
+
+    /**
+     * Sets the DividerPainter that's used to paint Dividers on this
+     * MultiSplitPane.  The default DividerPainter only draws
+     * the activeDivider (if there is one) and then, only if
+     * continuousLayout is false.  The value of this property is
+     * used by the paintChildren method: Dividers are painted after
+     * the MultiSplitPane's children have been rendered so that
+     * the activeDivider can appear "on top of" the children.
+     *
+     * @param dividerPainter the value of the dividerPainter property, can be null
+     * @see #paintChildren
+     * @see #activeDivider
+     */
+    public void setDividerPainter(DividerPainter dividerPainter) {
+        this.dividerPainter = dividerPainter;
+    }
+
+    /**
+     * Uses the DividerPainter (if any) to paint each Divider that
+     * overlaps the clip Rectangle.  This is done after the call to
+     * <code>super.paintChildren()</code> so that Dividers can be
+     * rendered "on top of" the children.
+     * <p>
+     * {@inheritDoc}
+     */
+    protected void paintChildren(Graphics g) {
+        super.paintChildren(g);
+        DividerPainter dp = getDividerPainter();
+        Rectangle clipR = g.getClipBounds();
+        if ((dp != null) && (clipR != null)) {
+            Graphics dpg = g.create();
+            try {
+                MultiSplitLayout msl = getMultiSplitLayout();
+                for(Divider divider : msl.dividersThatOverlap(clipR)) {
+                    dp.paint(dpg, divider);
+                }
+            }
+            finally {
+                dpg.dispose();
+            }
+        }
+    }
+
+    private boolean dragUnderway = false;
+    private MultiSplitLayout.Divider dragDivider = null;
+    private Rectangle initialDividerBounds = null;
+    private boolean oldFloatingDividers = true;
+    private int dragOffsetX = 0;
+    private int dragOffsetY = 0;
+    private int dragMin = -1;
+    private int dragMax = -1;
+
+    private void startDrag(int mx, int my) {
+        requestFocusInWindow();
+        MultiSplitLayout msl = getMultiSplitLayout();
+        MultiSplitLayout.Divider divider = msl.dividerAt(mx, my);
+        if (divider != null) {
+            MultiSplitLayout.Node prevNode = divider.previousSibling();
+            MultiSplitLayout.Node nextNode = divider.nextSibling();
+            if ((prevNode == null) || (nextNode == null)) {
+                dragUnderway = false;
+            }
+            else {
+                initialDividerBounds = divider.getBounds();
+                dragOffsetX = mx - initialDividerBounds.x;
+                dragOffsetY = my - initialDividerBounds.y;
+                dragDivider  = divider;
+                Rectangle prevNodeBounds = prevNode.getBounds();
+                Rectangle nextNodeBounds = nextNode.getBounds();
+                if (dragDivider.isVertical()) {
+                    dragMin = prevNodeBounds.x;
+                    dragMax = nextNodeBounds.x + nextNodeBounds.width;
+                    dragMax -= dragDivider.getBounds().width;
+                }
+                else {
+                    dragMin = prevNodeBounds.y;
+                    dragMax = nextNodeBounds.y + nextNodeBounds.height;
+                    dragMax -= dragDivider.getBounds().height;
+                }
+                oldFloatingDividers = getMultiSplitLayout().getFloatingDividers();
+                getMultiSplitLayout().setFloatingDividers(false);
+                dragUnderway = true;
+            }
+        }
+        else {
+            dragUnderway = false;
+        }
+    }
+
+    private void repaintDragLimits() {
+        Rectangle damageR = dragDivider.getBounds();
+        if (dragDivider.isVertical()) {
+            damageR.x = dragMin;
+            damageR.width = dragMax - dragMin;
+        }
+        else {
+            damageR.y = dragMin;
+            damageR.height = dragMax - dragMin;
+        }
+        repaint(damageR);
+    }
+
+    private void updateDrag(int mx, int my) {
+        if (!dragUnderway) {
+            return;
+        }
+        Rectangle oldBounds = dragDivider.getBounds();
+        Rectangle bounds = new Rectangle(oldBounds);
+        if (dragDivider.isVertical()) {
+            bounds.x = mx - dragOffsetX;
+            bounds.x = Math.max(bounds.x, dragMin);
+            bounds.x = Math.min(bounds.x, dragMax);
+        }
+        else {
+            bounds.y = my - dragOffsetY;
+            bounds.y = Math.max(bounds.y, dragMin);
+            bounds.y = Math.min(bounds.y, dragMax);
+        }
+        dragDivider.setBounds(bounds);
+        if (isContinuousLayout()) {
+            revalidate();
+            repaintDragLimits();
+        }
+        else {
+            repaint(oldBounds.union(bounds));
+        }
+    }
+
+    private void clearDragState() {
+        dragDivider = null;
+        initialDividerBounds = null;
+        oldFloatingDividers = true;
+        dragOffsetX = dragOffsetY = 0;
+        dragMin = dragMax = -1;
+        dragUnderway = false;
+    }
+
+    private void finishDrag(int x, int y) {
+        if (dragUnderway) {
+            clearDragState();
+            if (!isContinuousLayout()) {
+                revalidate();
+                repaint();
+            }
+        }
+    }
+
+    private void cancelDrag() {
+        if (dragUnderway) {
+            dragDivider.setBounds(initialDividerBounds);
+            getMultiSplitLayout().setFloatingDividers(oldFloatingDividers);
+            setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
+            repaint();
+            revalidate();
+            clearDragState();
+        }
+    }
+
+    private void updateCursor(int x, int y, boolean show) {
+        if (dragUnderway) {
+            return;
+        }
+        int cursorID = Cursor.DEFAULT_CURSOR;
+        if (show) {
+            MultiSplitLayout.Divider divider = getMultiSplitLayout().dividerAt(x, y);
+            if (divider != null) {
+                cursorID  = (divider.isVertical()) ?
+                    Cursor.E_RESIZE_CURSOR :
+                    Cursor.N_RESIZE_CURSOR;
+            }
+        }
+        setCursor(Cursor.getPredefinedCursor(cursorID));
+    }
+
+
+    private class InputHandler extends MouseInputAdapter implements KeyListener {
+
+        public void mouseEntered(MouseEvent e) {
+            updateCursor(e.getX(), e.getY(), true);
+        }
+
+        public void mouseMoved(MouseEvent e) {
+            updateCursor(e.getX(), e.getY(), true);
+        }
+
+        public void mouseExited(MouseEvent e) {
+            updateCursor(e.getX(), e.getY(), false);
+        }
+
+        public void mousePressed(MouseEvent e) {
+            startDrag(e.getX(), e.getY());
+        }
+        public void mouseReleased(MouseEvent e) {
+            finishDrag(e.getX(), e.getY());
+        }
+        public void mouseDragged(MouseEvent e) {
+            updateDrag(e.getX(), e.getY());
+        }
+        public void keyPressed(KeyEvent e) {
+            if (e.getKeyCode() == KeyEvent.VK_ESCAPE) {
+                cancelDrag();
+            }
+        }
+        public void keyReleased(KeyEvent e) { }
+        public void keyTyped(KeyEvent e) { }
+    }
+
+    public AccessibleContext getAccessibleContext() {
+        if( accessibleContext == null ) {
+            accessibleContext = new AccessibleMultiSplitPane();
+        }
+        return accessibleContext;
+    }
+
+    protected class AccessibleMultiSplitPane extends AccessibleJPanel {
+        public AccessibleRole getAccessibleRole() {
+            return AccessibleRole.SPLIT_PANE;
+        }
+    }
+}
Index: trunk/src/org/openstreetmap/josm/gui/dialogs/CommandStackDialog.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/dialogs/CommandStackDialog.java	(revision 2222)
+++ trunk/src/org/openstreetmap/josm/gui/dialogs/CommandStackDialog.java	(revision 2224)
@@ -29,5 +29,5 @@
     public CommandStackDialog(final MapFrame mapFrame) {
         super(tr("Command Stack"), "commandstack", tr("Open a list of all commands (undo buffer)."),
-                Shortcut.registerShortcut("subwindow:commandstack", tr("Toggle: {0}", tr("Command Stack")), KeyEvent.VK_O, Shortcut.GROUP_LAYER, Shortcut.SHIFT_DEFAULT), 100);
+                Shortcut.registerShortcut("subwindow:commandstack", tr("Toggle: {0}", tr("Command Stack")), KeyEvent.VK_O, Shortcut.GROUP_LAYER, Shortcut.SHIFT_DEFAULT), 100, true);
         Main.main.undoRedo.listenerCommands.add(this);
 
Index: trunk/src/org/openstreetmap/josm/gui/dialogs/DialogsPanel.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/dialogs/DialogsPanel.java	(revision 2224)
+++ trunk/src/org/openstreetmap/josm/gui/dialogs/DialogsPanel.java	(revision 2224)
@@ -0,0 +1,286 @@
+// License: GPL. See LICENSE file for details.
+
+package org.openstreetmap.josm.gui.dialogs;
+
+import static org.openstreetmap.josm.tools.I18n.tr;
+
+import java.awt.Dimension;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.swing.BoxLayout;
+import javax.swing.JPanel;
+
+import org.openstreetmap.josm.gui.MultiSplitLayout;
+import org.openstreetmap.josm.gui.MultiSplitLayout.Node;
+import org.openstreetmap.josm.gui.MultiSplitLayout.Leaf;
+import org.openstreetmap.josm.gui.MultiSplitLayout.Divider;
+import org.openstreetmap.josm.gui.MultiSplitLayout.Split;
+import org.openstreetmap.josm.gui.MultiSplitPane;
+import org.openstreetmap.josm.Main;
+
+public class DialogsPanel extends JPanel {
+    protected List<ToggleDialog> allDialogs = new ArrayList<ToggleDialog>();
+    protected MultiSplitPane mSpltPane = new MultiSplitPane();
+    final protected int DIVIDER_SIZE = 5;
+
+    /**
+     * Panels that are added to the multisplitpane.
+     */
+    private List<JPanel> panels = new ArrayList<JPanel>();
+
+    private boolean initialized = false;
+    public void initialize(List<ToggleDialog> allDialogs) {
+        if (initialized) {
+            throw new IllegalStateException();
+        }
+        initialized = true;
+        this.allDialogs = allDialogs;
+
+        for (Integer i=0; i < allDialogs.size(); ++i) {
+            final ToggleDialog dlg = allDialogs.get(i);
+            dlg.setDialogsPanel(this);
+            dlg.setVisible(false);
+        }
+        for (int i=0; i < allDialogs.size() + 1; ++i) {
+            final JPanel p = new JPanel() {
+                /**
+                 * Honoured by the MultiSplitPaneLayout when the
+                 * entire Window is resized.
+                 */
+                public Dimension getMinimumSize() {
+                    return new Dimension(0, 40);
+                }
+            };
+            p.setLayout(new BoxLayout(p, BoxLayout.Y_AXIS));
+            p.setVisible(false);
+
+            mSpltPane.add(p, "L"+i);
+            panels.add(p);
+        }
+
+        for (Integer i=0; i < allDialogs.size(); ++i) {
+            final ToggleDialog dlg = allDialogs.get(i);
+            if (dlg.isDialogShowing()) {
+                dlg.showDialog();
+                if (dlg.isDialogInCollapsedView()) {
+                    dlg.collapse();
+                }
+            } else {
+                dlg.hideDialog();
+            }
+        }
+        this.add(mSpltPane);
+        reconstruct(Action.ELEMENT_SHRINKS, null);
+    }
+
+    /**
+     * What action was performed to trigger the reconstruction
+     */
+    public enum Action {
+        INVISIBLE_TO_DEFAULT,
+        COLLAPSED_TO_DEFAULT,
+    /*  INVISIBLE_TO_COLLAPSED,    does not happen */
+        ELEMENT_SHRINKS         /* else. (Remaining elements have more space.) */
+    };
+    /**
+     * Reconstruct the view, if the configurations of dialogs has changed.
+     * @param action what happened, so the reconstruction is necessary
+     * @param triggeredBy the dialog that caused the reconstruction
+     */
+    public void reconstruct(Action action, ToggleDialog triggeredBy) {
+
+        final int N = allDialogs.size();
+
+        /**
+         * reset the panels
+         */
+        for (int i=0; i < N; ++i) {
+            final JPanel p = panels.get(i);
+            p.removeAll();
+            p.setVisible(false);
+        }
+
+        /**
+         * Add the elements to their respective panel.
+         *
+         * Each panel contains one dialog in default view and zero or more
+         * collapsed dialogs on top of it. The last panel is an exception
+         * as it can have collapsed dialogs at the bottom as well.
+         * If there are no dialogs in default view, show the collapsed ones
+         * in the last panel anyway.
+         */
+        int k = N-1;                // index of the current Panel (start with last one)
+        JPanel p = panels.get(k);   // current Panel
+        k = -1;                     // indicates that the current Panel index is N-1, but no default-view-Dialog was added to this Panel yet.
+        for (int i=N-1; i >= 0 ; --i) {
+            final ToggleDialog dlg = allDialogs.get(i);
+            if (dlg.isDialogInDefaultView()) {
+                if (k == -1) {
+                    k = N-1;
+                } else {
+                    --k;
+                    p = panels.get(k);
+                }
+                p.add(dlg, 0);
+                p.setVisible(true);
+            }
+            else if (dlg.isDialogInCollapsedView()) {
+                p.add(dlg, 0);
+                p.setVisible(true);
+            }
+        }
+
+        if (k == -1) {
+            k = N-1;
+        }
+        final int numPanels = N - k;
+
+        /**
+         * Determine the panel geometry
+         */
+        if (action == Action.ELEMENT_SHRINKS) {
+            for (int i=0; i<N; ++i) {
+                final ToggleDialog dlg = allDialogs.get(i);
+                if (dlg.isDialogInDefaultView()) {
+                    final int ph = dlg.getPreferredHeight();
+                    final int ah = dlg.getSize().height;
+                    dlg.setPreferredSize(new Dimension(Integer.MAX_VALUE, (ah < 20 ? ph : ah)));
+                }
+            }
+        } else {
+            if (triggeredBy == null) {
+                throw new IllegalArgumentException();
+            }
+
+            int sumP = 0;   // sum of preferred heights of dialogs in default view (without the triggering dialog)
+            int sumA = 0;   // sum of actual heights of dialogs in default view (without the triggering dialog)
+            int sumC = 0;   // sum of heights of all collapsed dialogs (triggering dialog is never collapsed)
+
+            for (int i=0; i<N; ++i) {
+                final ToggleDialog dlg = allDialogs.get(i);
+                if (dlg.isDialogInDefaultView()) {
+                    if (dlg != triggeredBy) {
+                        final int ph = dlg.getPreferredHeight();
+                        final int ah = dlg.getSize().height;
+                        sumP += ph;
+                        sumA += ah;
+                    }
+                }
+                else if (dlg.isDialogInCollapsedView()) {
+                    sumC += dlg.getSize().height;
+                }
+            }
+
+            /** total Height */
+            final int H = mSpltPane.getMultiSplitLayout().getModel().getBounds().getSize().height;
+
+            /** space, that is available for dialogs in default view (after the reconfiguration) */
+            final int s2 = H - (numPanels - 1) * DIVIDER_SIZE - sumC;
+
+            final int hp_trig = triggeredBy.getPreferredHeight();
+            if (hp_trig <= 0) throw new IllegalStateException(); // Must be positive
+
+            /** The new dialog gets a fair share */
+            final int hn_trig = hp_trig * s2 / (hp_trig + sumP);
+            triggeredBy.setPreferredSize(new Dimension(Integer.MAX_VALUE, hn_trig));
+
+            /** This is remainig for the other default view dialogs */
+            final int R = s2 - hn_trig;
+
+            /**
+             * Take space only from dialogs that are relatively large
+             */
+            int D_m = 0;        // additional space needed by the small dialogs
+            int D_p = 0;        // available space from the large dialogs
+            for (int i=0; i<N; ++i) {
+                final ToggleDialog dlg = allDialogs.get(i);
+                if (dlg.isDialogInDefaultView() && dlg != triggeredBy) {
+                    final int ha = dlg.getSize().height;                              // current
+                    final int h0 = ha * R / sumA;                                     // proportional shrinking
+                    final int he = dlg.getPreferredHeight() * s2 / (sumP + hp_trig);  // fair share
+                    if (h0 < he) {                  // dialog is relatively small
+                        int hn = Math.min(ha, he);  // shrink less, but do not grow
+                        D_m += hn - h0;
+                    } else {                        // dialog is relatively large
+                        D_p += h0 - he;
+                    }
+                }
+            }
+            /** adjust, without changing the sum */
+            for (int i=0; i<N; ++i) {
+                final ToggleDialog dlg = allDialogs.get(i);
+                if (dlg.isDialogInDefaultView() && dlg != triggeredBy) {
+                    final int ha = dlg.getSize().height;
+                    final int h0 = ha * R / sumA;
+                    final int he = dlg.getPreferredHeight() * s2 / (sumP + hp_trig);
+                    if (h0 < he) {
+                        int hn = Math.min(ha, he);
+                        dlg.setPreferredSize(new Dimension(Integer.MAX_VALUE, hn));
+                    } else {
+                        int d;
+                        try {
+                            d = (h0-he) * D_m / D_p;
+                        } catch (ArithmeticException e) { /* D_p may be zero - nothing wrong with that. */
+                            d = 0;
+                        };
+                        dlg.setPreferredSize(new Dimension(Integer.MAX_VALUE, h0 - d));
+                    }
+                }
+            }
+        }
+
+        /**
+         * create Layout
+         */
+        final List<Node> ch = new ArrayList<Node>();
+
+        for (int i = k; i <= N-1; ++i) {
+            if (i != k) {
+                ch.add(new Divider());
+            }
+            Leaf l = new Leaf("L"+i);
+            l.setWeight(1.0 / numPanels);
+            ch.add(l);
+        }
+
+        if (numPanels == 1) {
+            Node model = ch.get(0);
+            mSpltPane.getMultiSplitLayout().setModel(model);
+        } else {
+            Split model = new Split();
+            model.setRowLayout(false);
+            model.setChildren(ch);
+            mSpltPane.getMultiSplitLayout().setModel(model);
+        }
+
+        mSpltPane.getMultiSplitLayout().setDividerSize(DIVIDER_SIZE);
+        mSpltPane.getMultiSplitLayout().setFloatingDividers(true);
+        mSpltPane.revalidate();
+    }
+
+    public void destroy() {
+        for (ToggleDialog t : allDialogs) {
+            t.closeDetachedDialog();
+        }
+    }
+
+    /**
+     * Replies the instance of a toggle dialog of type <code>type</code> managed by this
+     * map frame
+     *
+     * @param <T>
+     * @param type the class of the toggle dialog, i.e. UserListDialog.class
+     * @return the instance of a toggle dialog of type <code>type</code> managed by this
+     * map frame; null, if no such dialog exists
+     *
+     */
+    public <T> T getToggleDialog(Class<T> type) {
+        for (ToggleDialog td : allDialogs) {
+            if (type.isInstance(td))
+                return type.cast(td);
+        }
+        return null;
+    }
+}
Index: trunk/src/org/openstreetmap/josm/gui/dialogs/LayerListDialog.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/dialogs/LayerListDialog.java	(revision 2222)
+++ trunk/src/org/openstreetmap/josm/gui/dialogs/LayerListDialog.java	(revision 2224)
@@ -56,5 +56,5 @@
  * change the ordering of the layers, to hide/show layers, to activate layers,
  * and to delete layers.
- * 
+ *
  */
 public class LayerListDialog extends ToggleDialog {
@@ -66,5 +66,5 @@
     /**
      * Creates the instance of the dialog. It's connected to the map frame <code>mapFrame</code>
-     * 
+     *
      * @param mapFrame the map frame
      */
@@ -75,5 +75,5 @@
     /**
      * Replies the instance of the dialog
-     * 
+     *
      * @return the instance of the dialog
      * @throws IllegalStateException thrown, if the dialog is not created yet
@@ -144,5 +144,5 @@
     protected LayerListDialog(MapFrame mapFrame) {
         super(tr("Layers"), "layerlist", tr("Open a list of all loaded layers."),
-                Shortcut.registerShortcut("subwindow:layers", tr("Toggle: {0}", tr("Layers")), KeyEvent.VK_L, Shortcut.GROUP_LAYER), 100);
+                Shortcut.registerShortcut("subwindow:layers", tr("Toggle: {0}", tr("Layers")), KeyEvent.VK_L, Shortcut.GROUP_LAYER), 100, true);
 
         // create the models
@@ -194,5 +194,5 @@
      * <code>listener</code> receives a {@see IEnabledStateUpdating#updateEnabledState()}
      * on every {@see ListSelectionEvent}.
-     * 
+     *
      * @param listener  the listener
      * @param listSelectionModel  the source emitting {@see ListSelectionEvent}s
@@ -212,5 +212,5 @@
      * <code>listener</code> receives a {@see IEnabledStateUpdating#updateEnabledState()}
      * on every {@see ListDataEvent}.
-     * 
+     *
      * @param listener  the listener
      * @param listSelectionModel  the source emitting {@see ListDataEvent}s
@@ -237,5 +237,5 @@
      * <code>listener</code> receives a {@see IEnabledStateUpdating#updateEnabledState()}
      * on every {@see LayerChangeListener}-event emitted by {@see MapView}.
-     * 
+     *
      * @param listener  the listener
      */
@@ -272,5 +272,5 @@
         /**
          * Creates a {@see DeleteLayerAction} for a specific layer.
-         * 
+         *
          * @param layer the layer. Must not be null.
          * @exception IllegalArgumentException thrown, if layer is null
@@ -288,5 +288,5 @@
          * Creates a {@see DeleteLayerAction} which will delete the currently
          * selected layers in the layer dialog.
-         * 
+         *
          */
         public DeleteLayerAction() {
@@ -353,5 +353,5 @@
          * Creates a {@see ShowHideLayerAction} which toggle the visibility of
          * a specific layer.
-         * 
+         *
          * @param layer  the layer. Must not be null.
          * @exception IllegalArgumentException thrown, if layer is null
@@ -369,5 +369,5 @@
          * Creates a {@see ShowHideLayerAction} which will toggle the visibility of
          * the currently selected layers
-         * 
+         *
          */
         public ShowHideLayerAction() {
@@ -620,12 +620,12 @@
      * The layer list model. The model manages a list of layers and provides methods for
      * moving layers up and down, for toggling their visibility, and for activating a layer.
-     * 
+     *
      * The model is a {@see ListModel} and it provides a {@see ListSelectionModel}. It expectes
      * to be configured with a {@see DefaultListSelectionModel}. The selection model is used
      * to update the selection state of views depending on messages sent to the model.
-     * 
+     *
      * The model manages a list of {@see LayerListModelListener} which are mainly notified if
      * the model requires views to make a specific list entry visible.
-     * 
+     *
      * It also listens to {@see PropertyChangeEvent}s of every {@see Layer} it manages, in particular to
      * the properties {@see Layer#VISIBLE_PROP} and {@see Layer#NAME_PROP}.
@@ -639,5 +639,5 @@
         /**
          * constructor
-         * 
+         *
          * @param selectionModel the list selection model
          */
@@ -649,5 +649,5 @@
         /**
          * Adds a listener to this model
-         * 
+         *
          * @param listener the listener
          */
@@ -663,5 +663,5 @@
          * removes a listener from  this model
          * @param listener the listener
-         * 
+         *
          */
         public void removeLayerListModelListener(LayerListModelListener listener) {
@@ -675,5 +675,5 @@
         /**
          * Fires a make visible event to listeners
-         * 
+         *
          * @param index the index of the row to make visible
          * @param layer the layer at this index
@@ -688,5 +688,5 @@
         /**
          * Fires a refresh event to listeners of this model
-         * 
+         *
          * @see LayerListModelListener#refresh()
          */
@@ -700,5 +700,5 @@
          * Populates the model with the current layers managed by
          * {@see MapView}.
-         * 
+         *
          */
         public void populate() {
@@ -715,5 +715,5 @@
          * Marks <code>layer</code> as selected layer. Ignored, if
          * layer is null.
-         * 
+         *
          * @param layer the layer.
          */
@@ -732,5 +732,5 @@
          * Replies the list of currently selected layers. Never null, but may
          * be empty.
-         * 
+         *
          * @return the list of currently selected layers. Never null, but may
          * be empty.
@@ -749,5 +749,5 @@
          * Replies a the list of indices of the selected rows. Never null,
          * but may be empty.
-         * 
+         *
          * @return  the list of indices of the selected rows. Never null,
          * but may be empty.
@@ -765,5 +765,5 @@
         /**
          * Invoked if a layer managed by {@see MapView} is removed
-         * 
+         *
          * @param layer the layer which is removed
          */
@@ -783,5 +783,5 @@
         /**
          * Invoked when a layer managed by {@see MapView} is added
-         * 
+         *
          * @param layer the layer
          */
@@ -797,5 +797,5 @@
         /**
          * Replies the first layer. Null if no layers are present
-         * 
+         *
          * @return the first layer. Null if no layers are present
          */
@@ -807,5 +807,5 @@
         /**
          * Replies the layer at position <code>index</code>
-         * 
+         *
          * @param index the index
          * @return the layer at position <code>index</code>. Null,
@@ -821,5 +821,5 @@
          * Replies true if the the currently selected layers can move up
          * by one position
-         * 
+         *
          * @return true if the the currently selected layers can move up
          * by one position
@@ -832,5 +832,5 @@
         /**
          * Move up the currently selected layers by one position
-         * 
+         *
          */
         public void moveUp() {
@@ -854,5 +854,5 @@
          * Replies true if the currently selected layers can move down
          * by one position
-         * 
+         *
          * @return true if the currently selected layers can move down
          * by one position
@@ -865,5 +865,5 @@
         /**
          * Move down the currently selected layers by one position
-         * 
+         *
          */
         public void moveDown() {
@@ -888,5 +888,5 @@
          * Make sure the first of the selected layers is visible in the
          * views of this model.
-         * 
+         *
          */
         protected void ensureSelectedIsVisible() {
@@ -901,5 +901,5 @@
          * Replies a list of layers which are possible merge targets
          * for <code>source</code>
-         * 
+         *
          * @param source the source layer
          * @return a list of layers which are possible merge targets
@@ -924,5 +924,5 @@
          * Replies the list of layers currently managed by {@see MapView}.
          * Never null, but can be empty.
-         * 
+         *
          * @return the list of layers currently managed by {@see MapView}.
          * Never null, but can be empty.
@@ -936,5 +936,5 @@
         /**
          * Ensures that at least one layer is selected in the layer dialog
-         * 
+         *
          */
         protected void ensureActiveSelected() {
@@ -956,5 +956,5 @@
         /**
          * Replies the active layer. null, if no active layer is available
-         * 
+         *
          * @return the active layer. null, if no active layer is available
          */
@@ -1043,5 +1043,5 @@
      * Creates a {@see ShowHideLayerAction} for <code>layer</code> in the
      * context of this {@see LayerListDialog}.
-     * 
+     *
      * @param layer the layer
      * @return the action
@@ -1054,5 +1054,5 @@
      * Creates a {@see DeleteLayerAction} for <code>layer</code> in the
      * context of this {@see LayerListDialog}.
-     * 
+     *
      * @param layer the layer
      * @return the action
@@ -1065,5 +1065,5 @@
      * Creates a {@see ActivateLayerAction} for <code>layer</code> in the
      * context of this {@see LayerListDialog}.
-     * 
+     *
      * @param layer the layer
      * @return the action
@@ -1076,5 +1076,5 @@
      * Creates a {@see MergeLayerAction} for <code>layer</code> in the
      * context of this {@see LayerListDialog}.
-     * 
+     *
      * @param layer the layer
      * @return the action
Index: trunk/src/org/openstreetmap/josm/gui/dialogs/PropertiesDialog.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/dialogs/PropertiesDialog.java	(revision 2222)
+++ trunk/src/org/openstreetmap/josm/gui/dialogs/PropertiesDialog.java	(revision 2224)
@@ -453,5 +453,5 @@
         super(tr("Properties/Memberships"), "propertiesdialog", tr("Properties for selected objects."),
                 Shortcut.registerShortcut("subwindow:properties", tr("Toggle: {0}", tr("Properties/Memberships")), KeyEvent.VK_P,
-                        Shortcut.GROUP_LAYER, Shortcut.SHIFT_DEFAULT), 150);
+                        Shortcut.GROUP_LAYER, Shortcut.SHIFT_DEFAULT), 150, true);
 
         // setting up the properties table
Index: trunk/src/org/openstreetmap/josm/gui/dialogs/SelectionListDialog.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/dialogs/SelectionListDialog.java	(revision 2222)
+++ trunk/src/org/openstreetmap/josm/gui/dialogs/SelectionListDialog.java	(revision 2224)
@@ -85,5 +85,5 @@
     public SelectionListDialog() {
         super(tr("Current Selection"), "selectionlist", tr("Open a selection list window."),
-                Shortcut.registerShortcut("subwindow:selection", tr("Toggle: {0}", tr("Current Selection")), KeyEvent.VK_T, Shortcut.GROUP_LAYER, Shortcut.SHIFT_DEFAULT), 150);
+                Shortcut.registerShortcut("subwindow:selection", tr("Toggle: {0}", tr("Current Selection")), KeyEvent.VK_T, Shortcut.GROUP_LAYER, Shortcut.SHIFT_DEFAULT), 150, true);
 
         selectionHistory = new LinkedList<Collection<? extends OsmPrimitive>>();
Index: trunk/src/org/openstreetmap/josm/gui/dialogs/ToggleDialog.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/dialogs/ToggleDialog.java	(revision 2222)
+++ trunk/src/org/openstreetmap/josm/gui/dialogs/ToggleDialog.java	(revision 2224)
@@ -34,4 +34,5 @@
 import org.openstreetmap.josm.actions.JosmAction;
 import org.openstreetmap.josm.actions.HelpAction.Helpful;
+import org.openstreetmap.josm.gui.dialogs.DialogsPanel.Action;
 import org.openstreetmap.josm.tools.GBC;
 import org.openstreetmap.josm.tools.ImageProvider;
@@ -40,59 +41,29 @@
 /**
  * This class is a toggle dialog that can be turned on and off.
- * 
+ *
  *
  */
 public class ToggleDialog extends JPanel implements Helpful {
-//    private static final Logger logger = Logger.getLogger(ToggleDialog.class.getName());
-
-    /**
-     * The action to toggle the visibility state of this toggle dialog.
-     * 
-     * Emits {@see PropertyChangeEvent}s for the property <tt>selected</tt>:
-     * <ul>
-     *   <li>true, if the dialog is currently visible</li>
-     *   <li>false, if the dialog is currently invisible</li>
-     * </ul>
-     *
-     */
-    public final class ToggleDialogAction extends JosmAction {
-        private ToggleDialogAction(String name, String iconName, String tooltip, Shortcut shortcut, String prefname) {
-            super(name, iconName, tooltip, shortcut, false);
-        }
-
-        public void actionPerformed(ActionEvent e) {
-            toggleVisibility();
-        }
-
-        public void toggleVisibility() {
-            if (isShowing) {
-                hideDialog();
-            } else {
-                showDialog();
-            }
-        }
-    }
-
-    /**
-     * The action to toggle this dialog.
-     */
+    /** The action to toggle this dialog */
     private ToggleDialogAction toggleAction;
     private String preferencePrefix;
 
-    private JPanel parent;
+    /** DialogsPanel that manages all ToggleDialogs */
+    private DialogsPanel dialogsPanel;
+
     private  TitleBar titleBar;
     private String title;
 
-    /** 
+    /**
      * Indicates whether the dialog is showing or not.
      */
     private boolean isShowing;
-    /** 
+    /**
      * If isShowing is true, indicates whether the dialog is docked or not, e. g.
      * shown as part of the main window or as a seperate dialog window.
      */
     private boolean isDocked;
-    /** 
-     * If isShowing and isDocked are true, indicates whether the dialog is 
+    /**
+     * If isShowing and isDocked are true, indicates whether the dialog is
      * currently minimized or not.
      */
@@ -101,6 +72,8 @@
     /** the preferred height if the toggle dialog is expanded */
     private int preferredHeight;
+
     /** the label in the title bar which shows whether the toggle dialog is expanded or collapsed */
     private JLabel lblMinimized;
+
     /** the JDialog displaying the toggle dialog as undocked dialog */
     private JDialog detachedDialog;
@@ -108,5 +81,12 @@
     /**
      * Constructor
-     * 
+     * (see below)
+     */
+    public ToggleDialog(String name, String iconName, String tooltip, Shortcut shortcut, int preferredHeight) {
+        this(name, iconName, tooltip, shortcut, preferredHeight, false);
+    }
+    /**
+     * Constructor
+     *
      * @param name  the name of the dialog
      * @param iconName the name of the icon to be displayed
@@ -114,21 +94,10 @@
      * @param shortcut  the shortcut
      * @param preferredHeight the preferred height for the dialog
-     */
-    public ToggleDialog(String name, String iconName, String tooltip, Shortcut shortcut, int preferredHeight) {
+     * @param defShow if the dialog should be shown by default, if there is no preference
+     */
+    public ToggleDialog(String name, String iconName, String tooltip, Shortcut shortcut, int preferredHeight, boolean defShow) {
         super(new BorderLayout());
         this.preferencePrefix = iconName;
-        init(name, iconName, tooltip, shortcut, preferredHeight);
-    }
-
-    /**
-     * Initializes the toggle dialog
-     * 
-     * @param name
-     * @param iconName
-     * @param tooltip
-     * @param shortcut
-     * @param preferredHeight
-     */
-    private void init(String name, String iconName, String tooltip, Shortcut shortcut, final int preferredHeight) {
+
         /** Use the full width of the parent element */
         setPreferredSize(new Dimension(0, preferredHeight));
@@ -147,7 +116,7 @@
         add(titleBar, BorderLayout.NORTH);
 
-        setVisible(false);
         setBorder(BorderFactory.createEtchedBorder());
 
+        isShowing = Main.pref.getBoolean(preferencePrefix+".visible", defShow);
         isDocked = Main.pref.getBoolean(preferencePrefix+".docked", true);
         isCollapsed = Main.pref.getBoolean(preferencePrefix+".minimized", false);
@@ -155,6 +124,108 @@
 
     /**
+     * The action to toggle the visibility state of this toggle dialog.
+     *
+     * Emits {@see PropertyChangeEvent}s for the property <tt>selected</tt>:
+     * <ul>
+     *   <li>true, if the dialog is currently visible</li>
+     *   <li>false, if the dialog is currently invisible</li>
+     * </ul>
+     *
+     */
+    public final class ToggleDialogAction extends JosmAction {
+        private ToggleDialogAction(String name, String iconName, String tooltip, Shortcut shortcut, String prefname) {
+            super(name, iconName, tooltip, shortcut, false);
+        }
+
+        public void actionPerformed(ActionEvent e) {
+            if (isShowing) {
+                hideDialog();
+                dialogsPanel.reconstruct(Action.ELEMENT_SHRINKS, null);
+            } else {
+                showDialog();
+                expand();
+                dialogsPanel.reconstruct(Action.INVISIBLE_TO_DEFAULT, ToggleDialog.this);
+            }
+        }
+    }
+
+    /**
+     * Shows the dialog
+     */
+    public void showDialog() {
+        setIsShowing(true);
+        if (!isDocked) {
+            detach();
+        } else {
+            dock();
+            this.setVisible(true);
+        }
+        // toggling the selected value in order to enforce PropertyChangeEvents
+        setIsShowing(true);
+        toggleAction.putValue("selected", false);
+        toggleAction.putValue("selected", true);
+    }
+
+    /**
+     * Hides the dialog
+     */
+    public void hideDialog() {
+        closeDetachedDialog();
+        this.setVisible(false);
+        setIsShowing(false);
+        toggleAction.putValue("selected", false);
+    }
+
+    /**
+     * Displays the toggle dialog in the toggle dialog view on the right
+     * of the main map window.
+     *
+     */
+    protected void dock() {
+        detachedDialog = null;
+        titleBar.setVisible(true);
+        setIsDocked(true);
+    }
+
+    /**
+     * Display the dialog in a detached window.
+     *
+     */
+    protected void detach() {
+        setContentVisible(true);
+        this.setVisible(true);
+        titleBar.setVisible(false);
+        detachedDialog = new DetachedDialog();
+        detachedDialog.setVisible(true);
+        setIsDocked(false);
+    }
+
+    /**
+     * Collapses the toggle dialog to the title bar only
+     *
+     */
+    public void collapse() {
+        setContentVisible(false);
+        setIsCollapsed(true);
+        setPreferredSize(new Dimension(0,20));
+        setMaximumSize(new Dimension(Integer.MAX_VALUE,20));
+        setMinimumSize(new Dimension(Integer.MAX_VALUE,20));
+        lblMinimized.setIcon(ImageProvider.get("misc", "minimized"));
+    }
+
+    /**
+     * Expands the toggle dialog
+     */
+    protected void expand() {
+        setContentVisible(true);
+        setIsCollapsed(false);
+        setPreferredSize(new Dimension(0,preferredHeight));
+        setMaximumSize(new Dimension(Integer.MAX_VALUE, Integer.MAX_VALUE));
+        lblMinimized.setIcon(ImageProvider.get("misc", "normal"));
+    }
+
+    /**
      * Sets the visibility of all components in this toggle dialog, except the title bar
-     * 
+     *
      * @param visible true, if the components should be visible; false otherwise
      */
@@ -169,187 +240,7 @@
 
     /**
-     * Toggles between collapsed and expanded state
-     * 
-     */
-    protected void toggleExpandedState() {
-        if (isCollapsed) {
-            expand();
-        } else {
-            collapse();
-        }
-    }
-
-    /**
-     * Collapses the toggle dialog to the title bar only
-     * 
-     */
-    protected void collapse() {
-        setContentVisible(false);
-        isCollapsed = true;
-        Main.pref.put(preferencePrefix+".minimized", true);
-        setPreferredSize(new Dimension(0,20));
-        setMaximumSize(new Dimension(Integer.MAX_VALUE,20));
-        lblMinimized.setIcon(ImageProvider.get("misc", "minimized"));
-        refreshToggleDialogsView();
-    }
-
-    /**
-     * Expands the toggle dialog
-     */
-    protected void expand() {
-        setContentVisible(true);
-        isCollapsed = false;
-        Main.pref.put(preferencePrefix+".minimized", false);
-        setPreferredSize(new Dimension(0,preferredHeight));
-        setMaximumSize(new Dimension(Integer.MAX_VALUE, Integer.MAX_VALUE));
-        lblMinimized.setIcon(ImageProvider.get("misc", "normal"));
-        refreshToggleDialogsView();
-    }
-
-    /**
-     * Replies the index of this toggle dialog in the view of
-     * toggle dialog.
-     * 
-     * @return
-     */
-    protected int getDialogPosition() {
-        if (parent == null) return -1;
-        for (int i=0; i< parent.getComponentCount(); i++) {
-            String name = parent.getComponent(i).getName();
-            if (name != null && name.equals(this.getName()))
-                return i;
-        }
-        return -1;
-    }
-
-    /**
-     * Displays the toggle dialog in the toggle dialog view on the right
-     * of the main map window.
-     * 
-     */
-    protected void dock() {
-        detachedDialog = null;
-        if (parent == null) return;
-
-        // check whether the toggle dialog view contains a placeholder
-        // for this toggle dialog. If so, replace it with this dialog.
-        //
-        int idx = getDialogPosition();
-        if (idx > -1) {
-            parent.remove(idx);
-            if (idx >= parent.getComponentCount()) {
-                parent.add(ToggleDialog.this);
-            } else {
-                parent.add(ToggleDialog.this,idx);
-            }
-        } else {
-            parent.add(ToggleDialog.this);
-        }
-        parent.validate();
-
-        if(Main.pref.getBoolean(preferencePrefix+".visible")) {
-            setVisible(true);
-        } else {
-            setVisible(false);
-        }
-        titleBar.setVisible(true);
-        isCollapsed = Main.pref.getBoolean(preferencePrefix+".minimized", false);
-        if (isCollapsed) {
-            collapse();
-        } else {
-            expand();
-        }
-        isDocked = true;
-        Main.pref.put(preferencePrefix+".docked", isDocked);
-    }
-
-    /**
-     * Display the dialog in a detached window.
-     * 
-     */
-    protected void detach() {
-        setContentVisible(true);
-        setVisible(true);
-        // replace the toggle dialog by an invisible place holder. Makes sure
-        // we can place the toggle dialog where it was when it becomes docked
-        // again.
-        //
-        if (parent != null) {
-            int idx = getDialogPosition();
-            if (idx > -1) {
-                JPanel placeHolder = new JPanel();
-                placeHolder.setName(this.getName());
-                placeHolder.setVisible(false);
-                parent.add(placeHolder,idx);
-            }
-            parent.remove(ToggleDialog.this);
-        }
-        
-
-        titleBar.setVisible(false);
-        detachedDialog = new DetachedDialog();
-        detachedDialog.setVisible(true);
-        refreshToggleDialogsView();
-        isDocked = false;
-        Main.pref.put(preferencePrefix+".docked", isDocked);
-    }
-
-    /**
-     * Hides the dialog
-     */
-    public void hideDialog() {
-        closeDetachedDialog();
-        setVisible(false);
-        isShowing = false;
-        Main.pref.put(preferencePrefix+".visible", false);
-        refreshToggleDialogsView();
-        toggleAction.putValue("selected", false);
-    }
-
-    /**
-     * Replies true if this dialog is showing either as docked or as detached dialog
-     */
-    public boolean isDialogShowing() {
-        return this.isShowing;
-    }
-
-    /**
-     * Shows the dialog
-     */
-    public void showDialog() {
-        if (!isDocked) {
-            detach();
-        } else {
-            dock();
-            if (!isCollapsed) {
-                expand();
-                setVisible(true);
-                refreshToggleDialogsView();
-            } else {
-                setVisible(true);
-                refreshToggleDialogsView();
-            }
-        }
-        isShowing = true;
-        // toggling the selected value in order to enforce PropertyChangeEvents
-        toggleAction.putValue("selected", false);
-        toggleAction.putValue("selected", true);
-        Main.pref.put(preferencePrefix+".visible", true);
-    }
-
-    /**
-     * Refreshes the layout of the parent toggle dialog view
-     * 
-     */
-    protected void refreshToggleDialogsView() {
-        if(parent != null){
-            parent.validate();
-        }
-    }
-
-    /**
      * Closes the the detached dialog if this toggle dialog is currently displayed
      * in a detached dialog.
-     * 
+     *
      */
     public void closeDetachedDialog() {
@@ -361,58 +252,8 @@
     }
 
-    public String helpTopic() {
-        String help = getClass().getName();
-        help = help.substring(help.lastIndexOf('.')+1, help.length()-6);
-        return "Dialog/"+help;
-    }
-
-    /**
-     * Replies the action to toggle the visible state of this toggle dialog
-     * 
-     * @return the action to toggle the visible state of this toggle dialog
-     */
-    public AbstractAction getToggleAction() {
-        return toggleAction;
-    }
-
-    /**
-     * Replies the prefix for the preference settings of this dialog.
-     * 
-     * @return the prefix for the preference settings of this dialog.
-     */
-    public String getPreferencePrefix() {
-        return preferencePrefix;
-    }
-
-    /**
-     * Sets the parent displaying all toggle dialogs
-     * 
-     * @param parent the parent
-     */
-    public void setParent(JPanel parent) {
-        this.parent = parent;
-    }
-
-    /**
-     * Replies the name of this toggle dialog
-     *
-     */
-    @Override
-    public String getName() {
-        return "toggleDialog." + preferencePrefix;
-    }
-
-    /**
-     * Sets the title
-     * 
-     * @param title the title
-     */
-    public void setTitle(String title) {
-        titleBar.setTitle(title);
-    }
 
     /**
      * The title bar displayed in docked mode
-     * 
+     *
      */
     private class TitleBar extends JPanel {
@@ -429,10 +270,10 @@
             lblTitle = new JLabel("",smallIcon, JLabel.TRAILING);
             lblTitle.setIconTextGap(8);
-            
+
             JPanel conceal = new JPanel();
             conceal.add(lblTitle);
             conceal.setVisible(false);
             add(conceal, GBC.std());
-            
+
             // Cannot add the label directly since it would displace other elements on resize
             JComponent lblTitle_weak = new JComponent() {
@@ -450,5 +291,12 @@
                         @Override
                         public void mouseClicked(MouseEvent e) {
-                            toggleExpandedState();
+//                            toggleExpandedState();
+                            if (isCollapsed) {
+                                expand();
+                                dialogsPanel.reconstruct(Action.COLLAPSED_TO_DEFAULT, ToggleDialog.this);
+                            } else {
+                                collapse();
+                                dialogsPanel.reconstruct(Action.ELEMENT_SHRINKS, null);
+                            }
                         }
                     }
@@ -463,4 +311,5 @@
                         public void actionPerformed(ActionEvent e) {
                             detach();
+                            dialogsPanel.reconstruct(Action.ELEMENT_SHRINKS, null);
                         }
                     }
@@ -476,4 +325,5 @@
                         public void actionPerformed(ActionEvent e) {
                             hideDialog();
+                            dialogsPanel.reconstruct(Action.ELEMENT_SHRINKS, null);
                         }
                     }
@@ -495,5 +345,5 @@
     /**
      * The dialog class used to display toggle dialogs in a detached window.
-     * 
+     *
      */
     private class DetachedDialog extends JDialog {
@@ -507,4 +357,6 @@
                     dispose();
                     dock();
+                    expand();
+                    dialogsPanel.reconstruct(Action.INVISIBLE_TO_DEFAULT, ToggleDialog.this);
                 }
             });
@@ -534,5 +386,5 @@
         return last;
     }
-    
+
     /**
      * Default size of the detached dialog.
@@ -542,3 +394,89 @@
         return new Dimension(Main.map.DEF_TOGGLE_DLG_WIDTH, preferredHeight);
     }
+
+    /**
+     * Replies the action to toggle the visible state of this toggle dialog
+     *
+     * @return the action to toggle the visible state of this toggle dialog
+     */
+    public AbstractAction getToggleAction() {
+        return toggleAction;
+    }
+
+    /**
+     * Replies the prefix for the preference settings of this dialog.
+     *
+     * @return the prefix for the preference settings of this dialog.
+     */
+    public String getPreferencePrefix() {
+        return preferencePrefix;
+    }
+
+    /**
+     * Sets the dialogsPanel managing all toggle dialogs
+     */
+    public void setDialogsPanel(DialogsPanel dialogsPanel) {
+        this.dialogsPanel = dialogsPanel;
+    }
+
+    /**
+     * Replies the name of this toggle dialog
+     */
+    @Override
+    public String getName() {
+        return "toggleDialog." + preferencePrefix;
+    }
+
+    /**
+     * Sets the title
+     */
+    public void setTitle(String title) {
+        titleBar.setTitle(title);
+    }
+
+    private void setIsShowing(boolean val) {
+        isShowing = val;
+        Main.pref.put(preferencePrefix+".visible", val);
+    }
+
+    private void setIsDocked(boolean val) {
+        isDocked = val;
+        Main.pref.put(preferencePrefix+".docked", val);
+    }
+
+    private void setIsCollapsed(boolean val) {
+        isCollapsed = val;
+        Main.pref.put(preferencePrefix+".minimized", val);
+    }
+
+    public int getPreferredHeight() {
+        return preferredHeight;
+    }
+
+    /**
+     * Replies true if this dialog is showing either as docked or as detached dialog
+     */
+    public boolean isDialogShowing() {
+        return isShowing;
+    }
+
+    /**
+     * Replies true if this dialog is docked and expanded
+     */
+    public boolean isDialogInDefaultView() {
+        return isShowing && isDocked && (! isCollapsed);
+    }
+
+    /**
+     * Replies true if this dialog is docked and collapsed
+     */
+    public boolean isDialogInCollapsedView() {
+        return isShowing && isDocked && isCollapsed;
+    }
+
+    public String helpTopic() {
+        String help = getClass().getName();
+        help = help.substring(help.lastIndexOf('.')+1, help.length()-6);
+        return "Dialog/"+help;
+    }
 }
