org.openstreetmap.josm.gui
Class MultiSplitLayout

java.lang.Object
  extended by org.openstreetmap.josm.gui.MultiSplitLayout
All Implemented Interfaces:
java.awt.LayoutManager

public class MultiSplitLayout
extends java.lang.Object
implements java.awt.LayoutManager

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.

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.

All properties in this class are bound: when a properties value is changed, all PropertyChangeListeners are fired.

See Also:
MultiSplitPane

Nested Class Summary
static class MultiSplitLayout.Divider
          Models a single vertical/horiztonal divider.
static class MultiSplitLayout.InvalidLayoutException
          The specified Node is either the wrong type or was configured incorrectly.
static class MultiSplitLayout.Leaf
          Models a java.awt Component child.
static class MultiSplitLayout.Node
          Base class for the nodes that model a MultiSplitLayout.
static class MultiSplitLayout.Split
          Defines a vertical or horizontal subdivision into two or more tiles.
 
Field Summary
private  java.util.Map<java.lang.String,java.awt.Component> childMap
           
private  int dividerSize
           
private  boolean floatingDividers
           
private  MultiSplitLayout.Node model
           
private  java.beans.PropertyChangeSupport pcs
           
 
Constructor Summary
MultiSplitLayout()
          Create a MultiSplitLayout with a default model with a single Leaf node named "default".
MultiSplitLayout(MultiSplitLayout.Node model)
          Create a MultiSplitLayout with the specified model.
 
Method Summary
 void addLayoutComponent(java.lang.String name, java.awt.Component child)
          Add a component to this MultiSplitLayout.
 void addPropertyChangeListener(java.beans.PropertyChangeListener listener)
           
private static void addSplitChild(MultiSplitLayout.Split parent, MultiSplitLayout.Node child)
           
private  java.awt.Rectangle boundsWithXandWidth(java.awt.Rectangle bounds, double x, double width)
           
private  java.awt.Rectangle boundsWithYandHeight(java.awt.Rectangle bounds, double y, double height)
           
private  void checkLayout(MultiSplitLayout.Node root)
           
private  java.awt.Component childForNode(MultiSplitLayout.Node node)
           
 MultiSplitLayout.Divider dividerAt(int x, int y)
          Return the Divider whose bounds contain the specified point, or null if there isn't one.
private  MultiSplitLayout.Divider dividerAt(MultiSplitLayout.Node root, int x, int y)
           
private  java.util.List<MultiSplitLayout.Divider> dividersThatOverlap(MultiSplitLayout.Node root, java.awt.Rectangle r)
           
 java.util.List<MultiSplitLayout.Divider> dividersThatOverlap(java.awt.Rectangle r)
          Return the Dividers whose bounds overlap the specified Rectangle.
private  void firePCS(java.lang.String propertyName, java.lang.Object oldValue, java.lang.Object newValue)
           
 int getDividerSize()
          Returns the width of Dividers in Split rows, and the height of Dividers in Split columns.
 boolean getFloatingDividers()
           
 MultiSplitLayout.Node getModel()
          Return the root of the tree of Split, Leaf, and Divider nodes that define this layout.
 java.beans.PropertyChangeListener[] getPropertyChangeListeners()
           
private  void layout1(MultiSplitLayout.Node root, java.awt.Rectangle bounds)
           
private  void layout2(MultiSplitLayout.Node root, java.awt.Rectangle bounds)
           
 void layoutContainer(java.awt.Container parent)
          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.
private  void layoutGrow(MultiSplitLayout.Split split, java.awt.Rectangle bounds)
           
private  void layoutShrink(MultiSplitLayout.Split split, java.awt.Rectangle bounds)
           
private  void minimizeSplitBounds(MultiSplitLayout.Split split, java.awt.Rectangle bounds)
           
private  java.awt.Dimension minimumComponentSize(MultiSplitLayout.Node node)
           
 java.awt.Dimension minimumLayoutSize(java.awt.Container parent)
           
private  java.awt.Dimension minimumNodeSize(MultiSplitLayout.Node root)
           
private  boolean nodeOverlapsRectangle(MultiSplitLayout.Node node, java.awt.Rectangle r2)
           
private static void parseAttribute(java.lang.String name, java.io.StreamTokenizer st, MultiSplitLayout.Node node)
           
private static void parseLeaf(java.io.StreamTokenizer st, MultiSplitLayout.Split parent)
           
private static MultiSplitLayout.Node parseModel(java.io.Reader r)
           
static MultiSplitLayout.Node parseModel(java.lang.String s)
          A convenience method that converts a string to a MultiSplitLayout model (a tree of Nodes) using a a simple syntax.
private static void parseSplit(java.io.StreamTokenizer st, MultiSplitLayout.Split parent)
           
private  java.awt.Dimension preferredComponentSize(MultiSplitLayout.Node node)
           
 java.awt.Dimension preferredLayoutSize(java.awt.Container parent)
           
private  java.awt.Dimension preferredNodeSize(MultiSplitLayout.Node root)
           
static void printModel(MultiSplitLayout.Node root)
          Print the tree with enough detail for simple debugging.
private static void printModel(java.lang.String indent, MultiSplitLayout.Node root)
           
 void removeLayoutComponent(java.awt.Component child)
          Removes the specified component from the layout.
 void removePropertyChangeListener(java.beans.PropertyChangeListener listener)
           
 void setDividerSize(int dividerSize)
          Sets the width of Dividers in Split rows, and the height of Dividers in Split columns.
 void setFloatingDividers(boolean floatingDividers)
          If true, Leaf node bounds match the corresponding component's preferred size and Splits/Dividers are resized accordingly.
 void setModel(MultiSplitLayout.Node model)
          Set the root of the tree of Split, Leaf, and Divider nodes that define this layout.
private  java.awt.Dimension sizeWithInsets(java.awt.Container parent, java.awt.Dimension size)
           
private  void throwInvalidLayout(java.lang.String msg, MultiSplitLayout.Node node)
           
private static void throwParseException(java.io.StreamTokenizer st, java.lang.String msg)
           
 
Methods inherited from class java.lang.Object
clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
 

Field Detail

childMap

private final java.util.Map<java.lang.String,java.awt.Component> childMap

pcs

private final java.beans.PropertyChangeSupport pcs

model

private MultiSplitLayout.Node model

dividerSize

private int dividerSize

floatingDividers

private boolean floatingDividers
Constructor Detail

MultiSplitLayout

public MultiSplitLayout()
Create a MultiSplitLayout with a default model with a single Leaf node named "default". #see setModel


MultiSplitLayout

public MultiSplitLayout(MultiSplitLayout.Node model)
Create a MultiSplitLayout with the specified model. #see setModel

Method Detail

addPropertyChangeListener

public void addPropertyChangeListener(java.beans.PropertyChangeListener listener)

removePropertyChangeListener

public void removePropertyChangeListener(java.beans.PropertyChangeListener listener)

getPropertyChangeListeners

public java.beans.PropertyChangeListener[] getPropertyChangeListeners()

firePCS

private void firePCS(java.lang.String propertyName,
                     java.lang.Object oldValue,
                     java.lang.Object newValue)

getModel

public MultiSplitLayout.Node getModel()
Return the root of the tree of Split, Leaf, and Divider nodes that define this layout.

Returns:
the value of the model property
See Also:
setModel(org.openstreetmap.josm.gui.MultiSplitLayout.Node)

setModel

public void setModel(MultiSplitLayout.Node 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".

Parameters:
model - the root of the tree of Split, Leaf, and Divider node
Throws:
java.lang.IllegalArgumentException - if model is a Divider or null
See Also:
getModel()

getDividerSize

public int getDividerSize()
Returns the width of Dividers in Split rows, and the height of Dividers in Split columns.

Returns:
the value of the dividerSize property
See Also:
setDividerSize(int)

setDividerSize

public void setDividerSize(int 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.

Parameters:
dividerSize - the size of dividers (pixels)
Throws:
java.lang.IllegalArgumentException - if dividerSize < 0
See Also:
getDividerSize()

getFloatingDividers

public boolean getFloatingDividers()
Returns:
the value of the floatingDividers property
See Also:
setFloatingDividers(boolean)

setFloatingDividers

public void setFloatingDividers(boolean 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 Also:
getFloatingDividers()

addLayoutComponent

public void addLayoutComponent(java.lang.String name,
                               java.awt.Component child)
Add a component to this MultiSplitLayout. The name should match the name property of the Leaf node that represents the bounds of child. 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 name. Note: if a component was already added with the same name, this method does not remove it from its parent.

Specified by:
addLayoutComponent in interface java.awt.LayoutManager
Parameters:
name - identifies the Leaf node that defines the child's bounds
child - the component to be added
See Also:
removeLayoutComponent(java.awt.Component)

removeLayoutComponent

public void removeLayoutComponent(java.awt.Component child)
Removes the specified component from the layout.

Specified by:
removeLayoutComponent in interface java.awt.LayoutManager
Parameters:
child - the component to be removed
See Also:
addLayoutComponent(java.lang.String, java.awt.Component)

childForNode

private java.awt.Component childForNode(MultiSplitLayout.Node node)

preferredComponentSize

private java.awt.Dimension preferredComponentSize(MultiSplitLayout.Node node)

minimumComponentSize

private java.awt.Dimension minimumComponentSize(MultiSplitLayout.Node node)

preferredNodeSize

private java.awt.Dimension preferredNodeSize(MultiSplitLayout.Node root)

minimumNodeSize

private java.awt.Dimension minimumNodeSize(MultiSplitLayout.Node root)

sizeWithInsets

private java.awt.Dimension sizeWithInsets(java.awt.Container parent,
                                          java.awt.Dimension size)

preferredLayoutSize

public java.awt.Dimension preferredLayoutSize(java.awt.Container parent)
Specified by:
preferredLayoutSize in interface java.awt.LayoutManager

minimumLayoutSize

public java.awt.Dimension minimumLayoutSize(java.awt.Container parent)
Specified by:
minimumLayoutSize in interface java.awt.LayoutManager

boundsWithYandHeight

private java.awt.Rectangle boundsWithYandHeight(java.awt.Rectangle bounds,
                                                double y,
                                                double height)

boundsWithXandWidth

private java.awt.Rectangle boundsWithXandWidth(java.awt.Rectangle bounds,
                                               double x,
                                               double width)

minimizeSplitBounds

private void minimizeSplitBounds(MultiSplitLayout.Split split,
                                 java.awt.Rectangle bounds)

layoutShrink

private void layoutShrink(MultiSplitLayout.Split split,
                          java.awt.Rectangle bounds)

layoutGrow

private void layoutGrow(MultiSplitLayout.Split split,
                        java.awt.Rectangle bounds)

layout2

private void layout2(MultiSplitLayout.Node root,
                     java.awt.Rectangle bounds)

layout1

private void layout1(MultiSplitLayout.Node root,
                     java.awt.Rectangle bounds)

throwInvalidLayout

private void throwInvalidLayout(java.lang.String msg,
                                MultiSplitLayout.Node node)

checkLayout

private void checkLayout(MultiSplitLayout.Node root)

layoutContainer

public void layoutContainer(java.awt.Container parent)
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.

Specified by:
layoutContainer in interface java.awt.LayoutManager

dividerAt

private MultiSplitLayout.Divider dividerAt(MultiSplitLayout.Node root,
                                           int x,
                                           int y)

dividerAt

public MultiSplitLayout.Divider dividerAt(int x,
                                          int y)
Return the Divider whose bounds contain the specified point, or null if there isn't one.

Parameters:
x - x coordinate
y - y coordinate
Returns:
the Divider at x,y

nodeOverlapsRectangle

private boolean nodeOverlapsRectangle(MultiSplitLayout.Node node,
                                      java.awt.Rectangle r2)

dividersThatOverlap

private java.util.List<MultiSplitLayout.Divider> dividersThatOverlap(MultiSplitLayout.Node root,
                                                                     java.awt.Rectangle r)

dividersThatOverlap

public java.util.List<MultiSplitLayout.Divider> dividersThatOverlap(java.awt.Rectangle r)
Return the Dividers whose bounds overlap the specified Rectangle.

Parameters:
r - target Rectangle
Returns:
the Dividers that overlap r
Throws:
java.lang.IllegalArgumentException - if the Rectangle is null

throwParseException

private static void throwParseException(java.io.StreamTokenizer st,
                                        java.lang.String msg)
                                 throws java.lang.Exception
Throws:
java.lang.Exception

parseAttribute

private static void parseAttribute(java.lang.String name,
                                   java.io.StreamTokenizer st,
                                   MultiSplitLayout.Node node)
                            throws java.lang.Exception
Throws:
java.lang.Exception

addSplitChild

private static void addSplitChild(MultiSplitLayout.Split parent,
                                  MultiSplitLayout.Node child)

parseLeaf

private static void parseLeaf(java.io.StreamTokenizer st,
                              MultiSplitLayout.Split parent)
                       throws java.lang.Exception
Throws:
java.lang.Exception

parseSplit

private static void parseSplit(java.io.StreamTokenizer st,
                               MultiSplitLayout.Split parent)
                        throws java.lang.Exception
Throws:
java.lang.Exception

parseModel

private static MultiSplitLayout.Node parseModel(java.io.Reader r)

parseModel

public static MultiSplitLayout.Node parseModel(java.lang.String s)
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=myLeafName weight=myLeafWeight. Similarly, a Split's weight can be specified with weight=mySplitWeight.

For example, the following expression generates a horizontal Split node with three children: the Leafs named left and right, and a Divider in between:

 (ROW (LEAF name=left) (LEAF name=right weight=1.0))
 

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:

 (ROW left (LEAF name=right weight=1.0))
 

Here's a more complex example. One row with three elements, the first and last of which are columns with two leaves each:

 (ROW (COLUMN weight=0.5 left.top left.bottom)
      (LEAF name=middle)
      (COLUMN weight=0.5 right.top right.bottom))
 

This syntax is not intended for archiving or configuration files . It's just a convenience for examples and tests.

Returns:
the Node root of a tree based on s.

printModel

private static void printModel(java.lang.String indent,
                               MultiSplitLayout.Node root)

printModel

public static void printModel(MultiSplitLayout.Node root)
Print the tree with enough detail for simple debugging.



JOSM