/Users/richardallenbair/Documents/Source/Projects/nonsense/swingx/src/beaninfo/MultiSplitLayout_API.java |
/* * $Id: MultiSplitLayout_API.html 1352 2006-08-22 22:52:00Z rbair $ * * 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; 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 JXMultiSplitPane. JXMultiSplitPane * 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 JXMultiSplitPane */ public class MultiSplitLayout extends JavaBean implements LayoutManager { /** * Create a MultiSplitLayout with a default model with a single * Leaf node named "default". * * #see setModel */ public MultiSplitLayout(); /** * Create a MultiSplitLayout with the specified model. * * #see setModel */ public MultiSplitLayout(Node model); /** * 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(); /** * 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); /** * 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(); /** * 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); /** * @return the value of the floatingDividers property * @see #setFloatingDividers */ public boolean getFloatingDividers(); /** * 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); /** * 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); /** * Removes the specified component from the layout. * * @param child the component to be removed * @see #addLayoutComponent */ public void removeLayoutComponent(Component child); public Dimension preferredLayoutSize(Container parent); public Dimension minimumLayoutSize(Container parent); /** * The specified Node is either the wrong type or was configured * incorrectly. */ public static class InvalidLayoutException extends RuntimeException { public InvalidLayoutException (String msg, Node node); /** * @return the invalid Node. */ public Node getNode(); } /** * 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); /** * 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 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); /** * Base class for the nodes that model a MultiSplitLayout. */ public static abstract class Node { /** * Returns the Split parent of this Node, or null. * * @return the value of the parent property. * @see #setParent */ public Split getParent(); /** * 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); /** * Returns the bounding Rectangle for this Node. * * @return the value of the bounds property. * @see #setBounds */ public Rectangle getBounds(); /** * 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); /** * 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(); /** * 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); /** * 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 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(); } /** * Defines a vertical or horizontal subdivision into two or more * tiles. */ public static class Split extends Node { /** * 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(); /** * 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); /** * 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(); /** * 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); /** * 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(); } /** * Models a java.awt Component child. */ public static class Leaf extends Node { /** * 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); /** * Return the Leaf's name. * * @return the value of the name property. * @see #setName */ public String getName(); /** * 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); } /** * 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(); /** * Dividers can't have a weight, they don't grow or shrink. * @throws UnsupportedOperationException */ public void setWeight(double weight); } /** * 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); /** * Print the tree with enough detail for simple debugging. */ public static void printModel(Node root); }