Class MultiSplitLayout
- java.lang.Object
-
- org.jdesktop.swingx.MultiSplitLayout
-
- All Implemented Interfaces:
java.awt.LayoutManager
,java.io.Serializable
public class MultiSplitLayout extends java.lang.Object implements java.awt.LayoutManager, java.io.Serializable
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:
JXMultiSplitPane
, Serialized Form
-
-
Nested Class Summary
Nested Classes Modifier and Type Class Description static class
MultiSplitLayout.ColSplit
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.RowSplit
static class
MultiSplitLayout.Split
Defines a vertical or horizontal subdivision into two or more tiles.
-
Field Summary
Fields Modifier and Type Field Description private java.util.Map<java.lang.String,java.awt.Component>
childMap
static int
DEFAULT_LAYOUT
private int
dividerSize
private boolean
floatingDividers
private boolean
layoutByWeight
private int
layoutMode
private MultiSplitLayout.Node
model
static int
NO_MIN_SIZE_LAYOUT
private java.beans.PropertyChangeSupport
pcs
private boolean
removeDividers
static int
USER_MIN_SIZE_LAYOUT
private int
userMinSize
-
Constructor Summary
Constructors Constructor Description MultiSplitLayout()
Create a MultiSplitLayout with a default model with a single Leaf node named "default".MultiSplitLayout(boolean layoutByWeight)
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
All Methods Static Methods Instance Methods Concrete Methods Modifier and Type Method Description 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)
void
displayNode(java.lang.String name, boolean visible)
Show/Hide nodes.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)
java.util.List<MultiSplitLayout.Divider>
dividersThatOverlap(java.awt.Rectangle r)
Return the Dividers whose bounds overlap the specified Rectangle.private java.util.List<MultiSplitLayout.Divider>
dividersThatOverlap(MultiSplitLayout.Node root, java.awt.Rectangle r)
private void
doLayoutByWeight(java.awt.Container parent)
Set the size of the child components to match the weights of the children.private void
doLayoutByWeight(MultiSplitLayout.Node node, java.awt.Rectangle bounds)
private void
firePCS(java.lang.String propertyName, java.lang.Object oldValue, java.lang.Object newValue)
java.awt.Component
getComponentForNode(MultiSplitLayout.Node n)
Get the component associated with a MultiSplitLayout.Nodeint
getDividerSize()
Returns the width of Dividers in Split rows, and the height of Dividers in Split columns.boolean
getFloatingDividers()
boolean
getLayoutByWeight()
Get the layoutByWeight falg.int
getLayoutMode()
Get the layout modeMultiSplitLayout.Node
getModel()
Return the root of the tree of Split, Leaf, and Divider nodes that define this layout.java.lang.String
getNameForComponent(java.awt.Component child)
Get the name used to map a componentMultiSplitLayout.Node
getNodeForComponent(java.awt.Component comp)
Get the MultiSplitLayout.Node associated with a componentMultiSplitLayout.Node
getNodeForComponent(MultiSplitLayout.Split split, java.awt.Component comp)
Get the MultiSplitLayout.Node associated with a componentMultiSplitLayout.Node
getNodeForName(java.lang.String name)
Get the MultiSplitLayout.Node associated with a componentMultiSplitLayout.Node
getNodeForName(MultiSplitLayout.Split split, java.lang.String name)
Get the MultiSplitLayout.Node associated with a componentjava.beans.PropertyChangeListener[]
getPropertyChangeListeners()
boolean
getRemoveDividers()
int
getUserMinSize()
Get the minimum node sizeboolean
hasModel()
Is there a valid model for the layout?private boolean
hasMoreVisibleSiblings(MultiSplitLayout.Node splitChild)
Check if the specified node has any following visible siblingsprivate void
layout1(MultiSplitLayout.Node root, java.awt.Rectangle bounds)
private void
layout2(MultiSplitLayout.Node root, java.awt.Rectangle bounds)
void
layoutByWeight(java.awt.Container parent)
Set the size of the child components to match the weights of the children.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)
java.awt.Dimension
maximumNodeSize(MultiSplitLayout.Node root)
Get the maximum size of this node.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)
java.awt.Dimension
minimumNodeSize(MultiSplitLayout.Node root)
Get the minimum size of this node.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)
private static void
printModel(java.lang.String indent, MultiSplitLayout.Node root)
static void
printModel(MultiSplitLayout.Node root)
Print the tree with enough detail for simple debugging.void
removeLayoutComponent(java.awt.Component child)
Removes the specified component from the layout.void
removeLayoutNode(java.lang.String name)
Removes the specified node 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
setLayoutByWeight(boolean state)
Sset the layoutByWeight falg.void
setLayoutMode(int layoutMode)
Set the layout mode.void
setModel(MultiSplitLayout.Node model)
Set the root of the tree of Split, Leaf, and Divider nodes that define this layout.void
setRemoveDividers(boolean removeDividers)
If true, the next divider is removed when a component is removed from the layout.void
setUserMinSize(int minSize)
Set the user defined minimum size support in the USER_MIN_SIZE_LAYOUT layout mode.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)
-
-
-
Field Detail
-
DEFAULT_LAYOUT
public static final int DEFAULT_LAYOUT
- See Also:
- Constant Field Values
-
NO_MIN_SIZE_LAYOUT
public static final int NO_MIN_SIZE_LAYOUT
- See Also:
- Constant Field Values
-
USER_MIN_SIZE_LAYOUT
public static final int USER_MIN_SIZE_LAYOUT
- See Also:
- Constant Field Values
-
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
-
removeDividers
private boolean removeDividers
-
layoutByWeight
private boolean layoutByWeight
-
layoutMode
private int layoutMode
-
userMinSize
private int userMinSize
-
-
Constructor Detail
-
MultiSplitLayout
public MultiSplitLayout()
Create a MultiSplitLayout with a default model with a single Leaf node named "default". #see setModel
-
MultiSplitLayout
public MultiSplitLayout(boolean layoutByWeight)
Create a MultiSplitLayout with a default model with a single Leaf node named "default".- Parameters:
layoutByWeight
- if true the layout is initialized in proportion to the node weights rather than the component preferred sizes. #see setModel
-
MultiSplitLayout
public MultiSplitLayout(MultiSplitLayout.Node model)
Create a MultiSplitLayout with the specified model. #see setModel
-
-
Method Detail
-
layoutByWeight
public void layoutByWeight(java.awt.Container parent)
Set the size of the child components to match the weights of the children. If the components to not all specify a weight then the available layout space is divided equally between the components.
-
doLayoutByWeight
private void doLayoutByWeight(java.awt.Container parent)
Set the size of the child components to match the weights of the children. If the components to not all specify a weight then the available layout space is divided equally between the components.
-
doLayoutByWeight
private void doLayoutByWeight(MultiSplitLayout.Node node, java.awt.Rectangle bounds)
-
getComponentForNode
public java.awt.Component getComponentForNode(MultiSplitLayout.Node n)
Get the component associated with a MultiSplitLayout.Node- Parameters:
n
- the layout node- Returns:
- the component handled by the layout or null if not found
-
getNodeForComponent
public MultiSplitLayout.Node getNodeForComponent(java.awt.Component comp)
Get the MultiSplitLayout.Node associated with a component- Parameters:
comp
- the component being positioned by the layout- Returns:
- the node associated with the component
-
getNodeForName
public MultiSplitLayout.Node getNodeForName(java.lang.String name)
Get the MultiSplitLayout.Node associated with a component- Parameters:
name
- the name used to associate a component with the layout- Returns:
- the node associated with the component
-
getNameForComponent
public java.lang.String getNameForComponent(java.awt.Component child)
Get the name used to map a component- Parameters:
child
- the component- Returns:
- the name used to map the component or null if no mapping is found
-
getNodeForComponent
public MultiSplitLayout.Node getNodeForComponent(MultiSplitLayout.Split split, java.awt.Component comp)
Get the MultiSplitLayout.Node associated with a component- Parameters:
split
- the layout split that owns the requested nodecomp
- the component being positioned by the layout- Returns:
- the node associated with the component
-
getNodeForName
public MultiSplitLayout.Node getNodeForName(MultiSplitLayout.Split split, java.lang.String name)
Get the MultiSplitLayout.Node associated with a component- Parameters:
split
- the layout split that owns the requested nodename
- the name used to associate a component with the layout- Returns:
- the node associated with the component
-
hasModel
public boolean hasModel()
Is there a valid model for the layout?- Returns:
- true if there is a model
-
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.jdesktop.swingx.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()
-
getRemoveDividers
public boolean getRemoveDividers()
- Returns:
- the value of the removeDividers property
- See Also:
setRemoveDividers(boolean)
-
setRemoveDividers
public void setRemoveDividers(boolean removeDividers)
If true, the next divider is removed when a component is removed from the layout. If false, only the node itself is removed. Normally the next divider should be removed from the layout when a component is removed.- Parameters:
removeDividers
- true to removed the next divider whena component is removed from teh layout
-
addLayoutComponent
public void addLayoutComponent(java.lang.String name, java.awt.Component child)
Add a component to this MultiSplitLayout. Thename
should match the name property of the Leaf node that represents the bounds ofchild
. 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 withname
. Note: if a component was already added with the same name, this method does not remove it from its parent.- Specified by:
addLayoutComponent
in interfacejava.awt.LayoutManager
- Parameters:
name
- identifies the Leaf node that defines the child's boundschild
- 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 interfacejava.awt.LayoutManager
- Parameters:
child
- the component to be removed- See Also:
addLayoutComponent(java.lang.String, java.awt.Component)
-
removeLayoutNode
public void removeLayoutNode(java.lang.String name)
Removes the specified node from the layout.- Parameters:
name
- the name of the component to be removed- See Also:
addLayoutComponent(java.lang.String, java.awt.Component)
-
displayNode
public void displayNode(java.lang.String name, boolean visible)
Show/Hide nodes. Any dividers that are no longer required due to one of the nodes being made visible/invisible are also shown/hidden. The visibility of the component managed by the node is also changed by this method- Parameters:
name
- the node namevisible
- the new node visible state
-
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
public java.awt.Dimension minimumNodeSize(MultiSplitLayout.Node root)
Get the minimum size of this node. Sums the minumum sizes of rows or columns to get the overall minimum size for the layout node, including the dividers.- Parameters:
root
- the node whose size is required.- Returns:
- the minimum size.
-
maximumNodeSize
public java.awt.Dimension maximumNodeSize(MultiSplitLayout.Node root)
Get the maximum size of this node. Sums the minumum sizes of rows or columns to get the overall maximum size for the layout node, including the dividers.- Parameters:
root
- the node whose size is required.- Returns:
- the minimum size.
-
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 interfacejava.awt.LayoutManager
-
minimumLayoutSize
public java.awt.Dimension minimumLayoutSize(java.awt.Container parent)
- Specified by:
minimumLayoutSize
in interfacejava.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)
-
hasMoreVisibleSiblings
private boolean hasMoreVisibleSiblings(MultiSplitLayout.Node splitChild)
Check if the specified node has any following visible siblings- Parameters:
splitChild
- the node to checktrue
- if there are visible children following
-
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)
-
getLayoutMode
public int getLayoutMode()
Get the layout mode- Returns:
- current layout mode
-
setLayoutMode
public void setLayoutMode(int layoutMode)
Set the layout mode. By default this layout uses the preferred and minimum sizes of the child components. To ignore the minimum size set the layout mode to MultiSplitLayout.LAYOUT_NO_MIN_SIZE.- Parameters:
layoutMode
- the layout mode- DEFAULT_LAYOUT - use the preferred and minimum sizes when sizing the children
- LAYOUT_NO_MIN_SIZE - ignore the minimum size when sizing the children
-
-
getUserMinSize
public int getUserMinSize()
Get the minimum node size- Returns:
- the minimum size
-
setUserMinSize
public void setUserMinSize(int minSize)
Set the user defined minimum size support in the USER_MIN_SIZE_LAYOUT layout mode.- Parameters:
minSize
- the new minimum size
-
getLayoutByWeight
public boolean getLayoutByWeight()
Get the layoutByWeight falg. If the flag is true the layout initializes itself using the model weights- Returns:
- the layoutByWeight
-
setLayoutByWeight
public void setLayoutByWeight(boolean state)
Sset the layoutByWeight falg. If the flag is true the layout initializes itself using the model weights- Parameters:
state
- the new layoutByWeight to set
-
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 interfacejava.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 coordinatey
- 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.
-