GroupLayout.java
上传用户:haobig99
上传日期:2022-06-15
资源大小:369k
文件大小:130k
源码类别:

J2ME

开发平台:

Java

  1. /*
  2.  * Copyright 2008 Sun Microsystems, Inc.  All Rights Reserved.
  3.  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  4.  *
  5.  * This code is free software; you can redistribute it and/or modify it
  6.  * under the terms of the GNU General Public License version 2 only, as
  7.  * published by the Free Software Foundation.  Sun designates this
  8.  * particular file as subject to the "Classpath" exception as provided
  9.  * by Sun in the LICENSE file that accompanied this code.
  10.  *
  11.  * This code is distributed in the hope that it will be useful, but WITHOUT
  12.  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13.  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14.  * version 2 for more details (a copy is included in the LICENSE file that
  15.  * accompanied this code).
  16.  *
  17.  * You should have received a copy of the GNU General Public License version
  18.  * 2 along with this work; if not, write to the Free Software Foundation,
  19.  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20.  *
  21.  * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
  22.  * CA 95054 USA or visit www.sun.com if you need additional information or
  23.  * have any questions.
  24.  */
  25. package com.sun.lwuit.layouts;
  26. import com.sun.lwuit.Component;
  27. import com.sun.lwuit.Container;
  28. import com.sun.lwuit.Form;
  29. import com.sun.lwuit.geom.Dimension;
  30. import java.util.*;
  31. /**
  32.  * GroupLayout is a LayoutManager that hierarchically groups components to
  33.  * achieve common, and not so common, layouts.  Grouping is done by instances
  34.  * of the Group class.  GroupLayout supports two types of groups:
  35.  * <table>
  36.  *   <tr><td valign=top>Sequential:<td>A sequential group positions its child
  37.  *           elements sequentially, one after another.
  38.  *   <tr><td valign=top>Parallel:<td>A parallel group positions its child 
  39.  *           elements in the same space on top of each other.  Parallel groups 
  40.  *           can also align the child elements along their baseline.
  41.  * </table>
  42.  * Each Group can contain any number of child groups, Components or gaps.
  43.  * GroupLayout treats each axis independently.  That is, there is a group
  44.  * representing the horizontal axis, and a separate group representing the
  45.  * vertical axis.  The horizontal group is responsible for setting the x
  46.  * and width of its contents, where as the vertical group is responsible for
  47.  * setting the y and height of its contents.
  48.  * <p>
  49.  * The following code builds a simple layout consisting of two labels in
  50.  * one column, followed by two textfields in the next column:
  51.  * <pre>
  52.  *   JComponent panel = ...;
  53.  *   GroupLayout layout = new GroupLayout(panel);
  54.  *   panel.setLayout(layout);
  55.  *   layout.setAutocreateGaps(true);
  56.  *   layout.setAutocreateContainerGaps(true);
  57.  *   GroupLayout.SequentialGroup hGroup = layout.createSequentialGroup();
  58.  *   hGroup.add(layout.createParallelGroup().add(label1).add(label2)).
  59.  *          add(layout.createParallelGroup().add(tf1).add(tf2));
  60.  *   layout.setHorizontalGroup(hGroup);
  61.  *   GroupLayout.SequentialGroup vGroup = layout.createSequentialGroup();
  62.  *   vGroup.add(layout.createParallelGroup(GroupLayout.BASELINE).add(label1).add(tf1)).
  63.  *          add(layout.createParallelGroup(GroupLayout.BASELINE).add(label2).add(tf2));
  64.  *   layout.setVerticalGroup(vGroup);
  65.  * </pre>
  66.  * <p>
  67.  * This layout consists of the following:
  68.  * <ul><li>The horizontal axis consists of a sequential group containing two
  69.  *         parallel groups.  The first parallel group consists of the labels,
  70.  *         with the second parallel group consisting of the text fields.
  71.  *     <li>The vertical axis similarly consists of a sequential group
  72.  *         containing two parallel groups.  The parallel groups align their
  73.  *         contents along the baseline.  The first parallel group consists
  74.  *         of the first label and text field, and the second group consists
  75.  *         of the second label and text field.
  76.  * </ul>
  77.  * There are a couple of things to notice in this code:
  78.  * <ul>
  79.  *   <li>You need not explicitly add the components to the container, this
  80.  *       is indirectly done by using one of the <code>add</code> methods.
  81.  *   <li>The various <code>add</code> methods of <code>Groups</code> return
  82.  *       themselves.  This allows for easy chaining of invocations.  For
  83.  *       example, <code>group.add(label1).add(label2);</code> is equivalent to
  84.  *       <code>group.add(label1);group.add(label2);</code>.
  85.  *   <li>There are no public constructors for the Groups, instead
  86.  *       use the create methods of <code>GroupLayout</code>.
  87.  * </ul>
  88.  * GroupLayout offer the ability to automatically insert the appropriate gap
  89.  * between components.  This can be turned on using the
  90.  * <code>setAutocreateGaps()</code> method.  Similarly you can use
  91.  * the <code>setAutocreateContainerGaps()</code> method to insert gaps
  92.  * between the components and the container.
  93.  * 
  94.  * @version $Revision: 1.25 $
  95.  * @author Tomas Pavek
  96.  * @author Jan Stola
  97.  * @author Scott Violet
  98.  * @author Shai Almog
  99.  */
  100. public class GroupLayout extends Layout {
  101.     /** 
  102.      * Compass-direction North (up).
  103.      */
  104.     public static final int NORTH      = 1;
  105.     /** 
  106.      * Compass-direction east (right).
  107.      */
  108.     public static final int EAST       = 3;
  109.     /** 
  110.      * Compass-direction south (down).
  111.      */
  112.     public static final int SOUTH      = 5;
  113.     /** 
  114.      * Compass-direction west (left).
  115.      */
  116.     public static final int WEST       = 7;
  117.     // Used in size calculations
  118.     private static final int MIN_SIZE = 0;
  119.     private static final int PREF_SIZE = 1;
  120.     private static final int MAX_SIZE = 2;
  121.     // Used by prepare, indicates min, pref or max isn't going to be used.
  122.     private static final int SPECIFIC_SIZE = 3;
  123.     
  124.     private static final int UNSET = Integer.MIN_VALUE;
  125.     /**
  126.      * Possible argument when linking sizes of components.  Specifies the
  127.      * the two component should share the same size along the horizontal
  128.      * axis.
  129.      *
  130.      * @see #linkSize(Component[], int)
  131.      */
  132.     public static final int HORIZONTAL = 1;
  133.     /**
  134.      * Possible argument when linking sizes of components.  Specifies the
  135.      * the two component should share the same size along the vertical
  136.      * axis.
  137.      *
  138.      * @see #linkSize(Component[],int)
  139.      */
  140.     public static final int VERTICAL = 2;
  141.     
  142.     private static final int NO_ALIGNMENT = 0;
  143.     /**
  144.      * Possible alignment type.  Indicates the elements should be
  145.      * aligned to the origin.  For the horizontal axis with a left to
  146.      * right orientation this means aligned to the left.
  147.      *
  148.      * @see #createParallelGroup(int)
  149.      */
  150.     public static final int LEADING = 1;
  151.     /**
  152.      * Possible alignment type.  Indicates the elements should be
  153.      * aligned to the end.  For the horizontal axis with a left to
  154.      * right orientation this means aligned to the right.
  155.      *
  156.      * @see #createParallelGroup(int)
  157.      */
  158.     public static final int TRAILING = 2;
  159.     /**
  160.      * Possible alignment type.  Indicates the elements should centered in
  161.      * the spaced provided.
  162.      *
  163.      * @see #createParallelGroup(int)
  164.      */
  165.     public static final int CENTER = 4;
  166.     /**
  167.      * Possible alignment type.  Indicates the elements should aligned along
  168.      * their baseline.
  169.      *
  170.      * @see #createParallelGroup(int)
  171.      */
  172.     public static final int BASELINE = 3;
  173.     
  174.     /**
  175.      * Possible value for the add methods that takes a Component.
  176.      * Indicates the size from the component should be used.
  177.      */
  178.     public static final int DEFAULT_SIZE = -1;
  179.     /**
  180.      * Possible value for the add methods that takes a Component.
  181.      * Indicates the preferred size should be used.
  182.      */
  183.     public static final int PREFERRED_SIZE = -2;
  184.     
  185.     // Whether or not we automatically try and create the preferred
  186.     // padding between components.
  187.     private boolean autocreatePadding;
  188.     
  189.     // Whether or not we automatically try and create the preferred
  190.     // padding between containers
  191.     private boolean autocreateContainerPadding;
  192.     
  193.     /**
  194.      * Group responsible for layout along the horizontal axis.  This is NOT
  195.      * the user specified group, use getHorizontalGroup to dig that out.
  196.      */
  197.     private Group horizontalGroup;
  198.     /**
  199.      * Group responsible for layout along the vertical axis.  This is NOT
  200.      * the user specified group, use getVerticalGroup to dig that out.
  201.      */
  202.     private Group verticalGroup;
  203.     
  204.     // Maps from Component to ComponentInfo.  This is used for tracking
  205.     // information specific to a Component.
  206.     private Hashtable componentInfos;
  207.     
  208.     // Container we're doing layout for.
  209.     private Container host;
  210.     
  211.     // Used by areParallelSiblings, cached to avoid excessive garbage.
  212.     private Vector tmpParallelSet;
  213.     
  214.     // Indicates Springs have changed in some way since last change.
  215.     private boolean springsChanged;
  216.     
  217.     // Indicates invalidateLayout has been invoked.
  218.     private boolean isValid;
  219.     // Whether or not any preferred padding (or container padding) springs exist
  220.     private boolean hasPreferredPaddingSprings;
  221.     
  222.     /**
  223.      * The LayoutStyle instance to use, if null the sharedInstance is used.
  224.      */
  225.     private LayoutStyle layoutStyle;
  226.     /**
  227.      * If true, components that are not visible are treated as though they
  228.      * aren't there.
  229.      */
  230.     private boolean honorsVisibility;
  231.     
  232.     private static void checkSize(int min, int pref, int max,
  233.             boolean isComponentSpring) {
  234.         checkResizeType(min, isComponentSpring);
  235.         if (!isComponentSpring && pref < 0) {
  236.             throw new IllegalArgumentException("Pref must be >= 0");
  237.         } else if (isComponentSpring) {
  238.             checkResizeType(pref, true);
  239.         }
  240.         checkResizeType(max, isComponentSpring);
  241.         checkLessThan(min, pref);
  242.         checkLessThan(pref, max);
  243.     }
  244.     private static void checkResizeType(int type, boolean isComponentSpring) {
  245.         if (type < 0 && ((isComponentSpring && type != DEFAULT_SIZE &&
  246.                                                type != PREFERRED_SIZE) ||
  247.                           (!isComponentSpring && type != PREFERRED_SIZE))) {
  248.             throw new IllegalArgumentException("Invalid size");
  249.         }
  250.     }
  251.     
  252.     private static void checkLessThan(int min, int max) {
  253.         if (min >= 0 && max >= 0 && min > max) {
  254.             throw new IllegalArgumentException(
  255.                              "Following is not met: min<=pref<=max");
  256.         }
  257.     }
  258.     
  259.     /**
  260.      * Creates a GroupLayout for the specified JComponent.
  261.      *
  262.      * @param host the Container to layout
  263.      * @throws IllegalArgumentException if host is null
  264.      */
  265.     public GroupLayout(Container host) {
  266.         if (host == null) {
  267.             throw new IllegalArgumentException("Container must be non-null");
  268.         }
  269.         if(host instanceof Form) {
  270.             host = ((Form)host).getContentPane();
  271.         }
  272.         honorsVisibility = true;
  273.         this.host = host;
  274.         setHorizontalGroup(createParallelGroup(LEADING, true));
  275.         setVerticalGroup(createParallelGroup(LEADING, true));
  276.         componentInfos = new Hashtable();
  277.         tmpParallelSet = new Vector();
  278.     }
  279.     /**
  280.      * Sets whether component visibility is considered when sizing and
  281.      * positioning components. A value of <code>true</code> indicates that
  282.      * non-visible components should not be treated as part of the
  283.      * layout. A value of <code>false</code> indicates that components should be
  284.      * positioned and sized regardless of visibility.
  285.      * <p>
  286.      * A value of <code>false</code> is useful when the visibility of components
  287.      * is dynamically adjusted and you don't want surrounding components and
  288.      * the sizing to change.
  289.      * <p>
  290.      * The specified value is used for components that do not have an
  291.      * explicit visibility specified.
  292.      * <p>
  293.      * The default is <code>true</code>.
  294.      *
  295.      * @param honorsVisibility whether component visibility is considered when
  296.      *                         sizing and positioning components
  297.      * @see #setHonorsVisibility(Component,Boolean)
  298.      */
  299.     public void setHonorsVisibility(boolean honorsVisibility) {
  300.         if (this.honorsVisibility != honorsVisibility) {
  301.             this.honorsVisibility = honorsVisibility;
  302.             springsChanged = true;
  303.             isValid = false;
  304.             invalidateHost();
  305.         }
  306.     }
  307.     
  308.     /**
  309.      * Returns whether component visibility is considered when sizing and
  310.      * positioning components.
  311.      *
  312.      * @return whether component visibility is considered when sizing and
  313.      *         positioning components
  314.      */
  315.     public boolean getHonorsVisibility() {
  316.         return honorsVisibility;
  317.     }
  318.     
  319.     /**
  320.      * Sets whether the component's visibility is considered for
  321.      * sizing and positioning. A value of <code>Boolean.TRUE</code>
  322.      * indicates that if <code>component</code> is not visible it should
  323.      * not be treated as part of the layout. A value of <code>false</code>
  324.      * indicates that <code>component</code> is positioned and sized
  325.      * regardless of it's visibility.  A value of <code>null</code>
  326.      * indicates the value specified by the single argument method <code>
  327.      * setHonorsVisibility</code> should be used.
  328.      * <p>
  329.      * If <code>component</code> is not a child of the <code>Container</code> this
  330.      * <code>GroupLayout</code> is managing, it will be added to the
  331.      * <code>Container</code>.
  332.      *
  333.      * @param component the component
  334.      * @param honorsVisibility whether <code>component</code>'s visibility should be
  335.      *              considered for sizing and positioning
  336.      * @throws IllegalArgumentException if <code>component</code> is <code>null</code>
  337.      * @see #setHonorsVisibility(boolean)
  338.      */
  339.     public void setHonorsVisibility(Component component,
  340.             Boolean honorsVisibility) {
  341.         if (component == null) {
  342.             throw new IllegalArgumentException("Component must be non-null");
  343.         }
  344.         getComponentInfo(component).setHonorsVisibility(honorsVisibility);
  345.         springsChanged = true;
  346.         isValid = false;
  347.         invalidateHost();
  348.     }
  349.     /**
  350.      * Returns a textual description of this GroupLayout.  The return value
  351.      * is intended for debugging purposes only.
  352.      *
  353.      * @return textual description of this GroupLayout
  354.      **/
  355.     public String toString() {
  356.         if (springsChanged) {
  357.             registerComponents(horizontalGroup, HORIZONTAL);
  358.             registerComponents(verticalGroup, VERTICAL);
  359.         }
  360.         StringBuffer buffer = new StringBuffer();
  361.         buffer.append("HORIZONTALn");
  362.         dump(buffer, horizontalGroup, "  ", HORIZONTAL);
  363.         buffer.append("nVERTICALn");
  364.         dump(buffer, verticalGroup, "  ", VERTICAL);
  365.         return buffer.toString();
  366.     }
  367.     
  368.     private void dump(StringBuffer buffer, Spring spring, String indent,
  369.             int axis) {
  370.         String origin = "";
  371.         String padding = "";
  372.         if (spring instanceof ComponentSpring) {
  373.             ComponentSpring cSpring = (ComponentSpring)spring;
  374.             origin = Integer.toString(cSpring.getOrigin()) + " ";
  375.             String name = cSpring.getComponent().toString();
  376.             if (name != null) {
  377.                 origin = "name=" + name + ", ";
  378.             }
  379.         }
  380.         if (spring instanceof AutopaddingSpring) {
  381.             AutopaddingSpring paddingSpring = (AutopaddingSpring)spring;
  382.             padding = ", userCreated=" + paddingSpring.getUserCreated() +
  383.                     ", matches=" + paddingSpring.getMatchDescription();
  384.         }
  385.         buffer.append(indent + spring.getClass().getName() + " " +
  386.                 Integer.toHexString(spring.hashCode()) + " " +
  387.                 origin +
  388.                 ", size=" + spring.getSize() +
  389.                 ", alignment=" + spring.getAlignment() +
  390.                 " prefs=[" + spring.getMinimumSize(axis) +
  391.                 " " + spring.getPreferredSize(axis) +
  392.                 " " + spring.getMaximumSize(axis) + 
  393.                 padding + "]n");
  394.         if (spring instanceof Group) {
  395.             Vector springs = ((Group)spring).springs;
  396.             indent += "  ";
  397.             for (int counter = 0; counter < springs.size(); counter++) {
  398.                 dump(buffer, (Spring)springs.elementAt(counter), indent, axis);
  399.             }
  400.         }
  401.     }
  402.     
  403.     /**
  404.      * Sets whether or not a gap between components 
  405.      * should automatically be created.  For example, if this is true
  406.      * and you add two components to a <code>SequentialGroup</code> a
  407.      * gap between the two will automatically be created.  The default
  408.      * is false.
  409.      *
  410.      * @param autocreatePadding whether or not to automatically created a gap
  411.      *        between components and the container
  412.      */
  413.     public void setAutocreateGaps(boolean autocreatePadding) {
  414.         if (this.autocreatePadding != autocreatePadding) {
  415.             this.autocreatePadding = autocreatePadding;
  416.             invalidateHost();
  417.         }
  418.     }
  419.     
  420.     /**
  421.      * Returns true if gaps between components are automatically be created.
  422.      *
  423.      * @return true if gaps between components should automatically be created
  424.      */
  425.     public boolean getAutocreateGaps() {
  426.         return autocreatePadding;
  427.     }
  428.     /**
  429.      * Sets whether or not gaps between the container and the first/last
  430.      * components should automatically be created. The default
  431.      * is false.
  432.      *
  433.      * @param autocreatePadding whether or not to automatically create
  434.      *        gaps between the container and first/last components.
  435.      */
  436.     public void setAutocreateContainerGaps(boolean autocreatePadding) {
  437.         if (autocreatePadding != autocreateContainerPadding) {
  438.             autocreateContainerPadding = autocreatePadding;
  439.             horizontalGroup = createTopLevelGroup(getHorizontalGroup());
  440.             verticalGroup = createTopLevelGroup(getVerticalGroup());
  441.             invalidateHost();
  442.         }
  443.     }
  444.     
  445.     /**
  446.      * Returns whether or not gaps between the container and the
  447.      * first/last components should automatically be created. The default
  448.      * is false.
  449.      *
  450.      * @return whether or not the gaps between the container and the
  451.      *         first/last components should automatically be created
  452.      */
  453.     public boolean getAutocreateContainerGaps() {
  454.         return autocreateContainerPadding;
  455.     }
  456.     /**
  457.      * Sets the <code>Group</code> that is responsible for
  458.      * layout along the horizontal axis.
  459.      *
  460.      * @param group <code>Group</code> responsible for layout along
  461.      *          the horizontal axis
  462.      * @throws IllegalArgumentException if group is null
  463.      */
  464.     public void setHorizontalGroup(Group group) {
  465.         if (group == null) {
  466.             throw new IllegalArgumentException("Group must be non-null");
  467.         }
  468.         horizontalGroup = createTopLevelGroup(group);
  469.         invalidateHost();
  470.     }
  471.     
  472.     /**
  473.      * Returns the <code>Group</code> that is responsible for
  474.      * layout along the horizontal axis.
  475.      *
  476.      * @return <code>ParallelGroup</code> responsible for layout along
  477.      *          the horizontal axis.
  478.      */
  479.     public Group getHorizontalGroup() {
  480.         int index = 0;
  481.         if (horizontalGroup.springs.size() > 1) {
  482.             index = 1;
  483.         }
  484.         return (Group)horizontalGroup.springs.elementAt(index);
  485.     }
  486.     
  487.     /**
  488.      * Sets the <code>Group</code> that is responsible for
  489.      * layout along the vertical axis.
  490.      *
  491.      * @param group <code>Group</code> responsible for layout along
  492.      *          the vertical axis.
  493.      * @throws IllegalArgumentException if group is null.
  494.      */
  495.     public void setVerticalGroup(Group group) {
  496.         if (group == null) {
  497.             throw new IllegalArgumentException("Group must be non-null");
  498.         }
  499.         verticalGroup = createTopLevelGroup(group);
  500.         invalidateHost();
  501.     }
  502.     
  503.     /**
  504.      * Returns the <code>ParallelGroup</code> that is responsible for
  505.      * layout along the vertical axis.
  506.      *
  507.      * @return <code>ParallelGroup</code> responsible for layout along
  508.      *          the vertical axis.
  509.      */
  510.     public Group getVerticalGroup() {
  511.         int index = 0;
  512.         if (verticalGroup.springs.size() > 1) {
  513.             index = 1;
  514.         }
  515.         return (Group)verticalGroup.springs.elementAt(index);
  516.     }
  517.     /**
  518.      * Wraps the user specified group in a sequential group.  If 
  519.      * container gaps should be generate the necessary springs are
  520.      * added.
  521.      */
  522.     private Group createTopLevelGroup(Group specifiedGroup) {
  523.         SequentialGroup group = createSequentialGroup();
  524.         if (getAutocreateContainerGaps()) {
  525.             group.addSpring(new ContainerAutopaddingSpring());
  526.             group.add(specifiedGroup);
  527.             group.addSpring(new ContainerAutopaddingSpring());
  528.         } else {
  529.             group.add(specifiedGroup);
  530.         }
  531.         return group;
  532.     }
  533.     /**
  534.      * Creates and returns a <code>SequentialGroup</code>.
  535.      *
  536.      * @return a new <code>SequentialGroup</code>
  537.      */
  538.     public SequentialGroup createSequentialGroup() {
  539.         return new SequentialGroup();
  540.     }
  541.     
  542.     /**
  543.      * Creates and returns a <code>ParallelGroup</code> with a
  544.      * <code>LEADING</code> alignment.  This is a cover method for the more
  545.      * general <code>createParallelGroup(int)</code> method.
  546.      *
  547.      * @return a new ParallelGroup
  548.      * @see #createParallelGroup(int)
  549.      */
  550.     public ParallelGroup createParallelGroup() {
  551.         return createParallelGroup(LEADING);
  552.     }
  553.     
  554.     /**
  555.      * Creates and returns an <code>ParallelGroup</code>.  The alignment
  556.      * specifies how children elements should be positioned when the
  557.      * the parallel group is given more space than necessary.  For example,
  558.      * if a ParallelGroup with an alignment of TRAILING is given 100 pixels
  559.      * and a child only needs 50 pixels, the child will be positioned at the
  560.      * position 50.
  561.      *
  562.      * @param alignment alignment for the elements of the Group, one
  563.      *        of <code>LEADING</code>, <code>TRAILING</code>,
  564.      *        <code>CENTER</code> or <code>BASELINE</code>.
  565.      * @throws IllegalArgumentException if alignment is not one of
  566.      *         <code>LEADING</code>, <code>TRAILING</code>,
  567.      *         <code>CENTER</code> or <code>BASELINE</code>
  568.      * @return a new <code>ParallelGroup</code>
  569.      */
  570.     public ParallelGroup createParallelGroup(int alignment) {
  571.         return createParallelGroup(alignment, true);
  572.     }
  573.     
  574.     /**
  575.      * Creates and returns an <code>ParallelGroup</code>.  The alignment
  576.      * specifies how children elements should be positioned when the
  577.      * the parallel group is given more space than necessary.  For example,
  578.      * if a ParallelGroup with an alignment of TRAILING is given 100 pixels
  579.      * and a child only needs 50 pixels, the child will be positioned at the
  580.      * position 50.
  581.      *
  582.      * @param alignment alignment for the elements of the Group, one
  583.      *        of <code>LEADING</code>, <code>TRAILING</code>,
  584.      *        <code>CENTER</code> or <code>BASELINE</code>.
  585.      * @param resizable whether or not the group is resizable.  If the group
  586.      *        is not resizable the min/max size will be the same as the
  587.      *        preferred.
  588.      * @throws IllegalArgumentException if alignment is not one of
  589.      *         <code>LEADING</code>, <code>TRAILING</code>,
  590.      *         <code>CENTER</code> or <code>BASELINE</code>
  591.      * @return a new <code>ParallelGroup</code>
  592.      */
  593.     public ParallelGroup createParallelGroup(int alignment, boolean resizable) {
  594.         if (alignment == BASELINE) {
  595.             return new BaselineGroup(resizable);
  596.         }
  597.         return new ParallelGroup(alignment, resizable);
  598.     }
  599.     
  600.     /**
  601.      * Creates and returns a <code>ParallelGroup</code> that aligns it's
  602.      * elements along the baseline. 
  603.      *
  604.      * @param resizable whether the group is resizable
  605.      * @param anchorBaselineToTop whether the baseline is anchored to
  606.      *        the top or bottom of the group
  607.      * @return parallel group
  608.      * @see #createBaselineGroup
  609.      * @see ParallelGroup
  610.      */
  611.     public ParallelGroup createBaselineGroup(boolean resizable,
  612.             boolean anchorBaselineToTop) {
  613.         return new BaselineGroup(resizable, anchorBaselineToTop);
  614.     }
  615.     
  616.     /**
  617.      * Forces the set of components to have the same size.
  618.      * This can be used multiple times to force
  619.      * any number of components to share the same size.
  620.      * <p>
  621.      * Linked Components are not be resizable.
  622.      *
  623.      * @param components Components to force to have same size.
  624.      * @throws IllegalArgumentException if <code>components</code> is
  625.      *         null, or contains null.
  626.      */
  627.     public void linkSize(Component[] components) {
  628.         linkSize(components, HORIZONTAL | VERTICAL);
  629.     }
  630.     
  631.     /**
  632.      * Forces the set of components to have the same size.
  633.      * This can be used multiple times to force
  634.      * any number of components to share the same size.
  635.      * <p>
  636.      * Linked Components are not be resizable.
  637.      *
  638.      * @param components Components to force to have same size.
  639.      * @param axis Axis to bind size, one of HORIZONTAL, VERTICAL or
  640.      *             HORIZONTAL | VERTICAL
  641.      * @throws IllegalArgumentException if <code>components</code> is
  642.      *         null, or contains null.
  643.      * @throws IllegalArgumentException if <code>axis</code> does not
  644.      *         contain <code>HORIZONTAL</code> or <code>VERTICAL</code>
  645.      */
  646.     public void linkSize(Component[] components, int axis) {
  647.         if (components == null) {
  648.             throw new IllegalArgumentException("Components must be non-null");
  649.         }
  650.         boolean horizontal = ((axis & HORIZONTAL) == HORIZONTAL);
  651.         boolean vertical = ((axis & VERTICAL) == VERTICAL);
  652.         if (!vertical && !horizontal) {
  653.             throw new IllegalArgumentException(
  654.                     "Axis must contain HORIZONTAL or VERTICAL");
  655.         }
  656.         for (int counter = components.length - 1; counter >= 0; counter--) {
  657.             Component c = components[counter];
  658.             if (components[counter] == null) {
  659.                 throw new IllegalArgumentException(
  660.                         "Components must be non-null");
  661.             }
  662.             // Force the component to be added
  663.             getComponentInfo(c);
  664.         }
  665.         if (horizontal) {
  666.             linkSize0(components, HORIZONTAL);
  667.         }
  668.         if (vertical) {
  669.             linkSize0(components, VERTICAL);
  670.         }
  671.         invalidateHost();
  672.     }
  673.     
  674.     private void linkSize0(Component[] components, int axis) {
  675.         LinkInfo master = getComponentInfo(
  676.                 components[components.length - 1]).getLinkInfo(axis);
  677.         for (int counter = components.length - 2; counter >= 0; counter--) {
  678.             master.add(getComponentInfo(components[counter]));
  679.         }
  680.     }
  681.     /**
  682.      * Removes an existing component replacing it with the specified component.
  683.      *
  684.      * @param existingComponent the Component that should be removed and
  685.      *        replaced with newComponent
  686.      * @param newComponent the Component to put in existingComponents place
  687.      * @throws IllegalArgumentException is either of the Components are null or
  688.      *         if existingComponent is not being managed by this layout manager
  689.      */
  690.     public void replace(Component existingComponent, Component newComponent) {
  691.         if (existingComponent == null || newComponent == null) {
  692.             throw new IllegalArgumentException("Components must be non-null");
  693.         }
  694.         // Make sure all the components have been registered, otherwise we may
  695.         // not update the correct Springs.
  696.         if (springsChanged) {
  697.             registerComponents(horizontalGroup, HORIZONTAL);
  698.             registerComponents(verticalGroup, VERTICAL);
  699.         }
  700.         ComponentInfo info = (ComponentInfo)componentInfos.
  701.                 remove(existingComponent);
  702.         if (info == null) {
  703.             throw new IllegalArgumentException("Component must already exist");
  704.         }
  705.         host.removeComponent(existingComponent);
  706.         if (newComponent.getParent() != host) {
  707.             host.addComponent(newComponent);
  708.         }
  709.         info.setComponent(newComponent);
  710.         componentInfos.put(newComponent, info);
  711.         invalidateHost();
  712.     }
  713.     /**
  714.      * Sets the LayoutStyle this GroupLayout is to use. A value of null can
  715.      * be used to indicate the shared instance of LayoutStyle should be used.
  716.      *
  717.      * @param layoutStyle the LayoutStyle to use
  718.      */
  719.     public void setLayoutStyle(LayoutStyle layoutStyle) {
  720.         this.layoutStyle = layoutStyle;
  721.         invalidateHost();
  722.     }
  723.     
  724.     /**
  725.      * Returns the LayoutStyle instance to use
  726.      *
  727.      * @return the LayoutStyle instance to use
  728.      */
  729.     public LayoutStyle getLayoutStyle() {
  730.         return layoutStyle;
  731.     }
  732.     
  733.     private LayoutStyle getLayoutStyle0() {
  734.         LayoutStyle layoutStyle = getLayoutStyle();
  735.         if (layoutStyle == null) {
  736.             layoutStyle = LayoutStyle.getSharedInstance();
  737.         }
  738.         return layoutStyle;
  739.     }
  740.     
  741.     private void invalidateHost() {
  742.         host.invalidate();
  743.         host.repaint();
  744.     }
  745.     /**
  746.      * Notification that a <code>Component</code> has been removed from
  747.      * the parent container.  You should not invoke this method
  748.      * directly, instead invoke <code>removeComponent</code> on the parent
  749.      * <code>Container</code>.
  750.      *
  751.      * @param component the component to be removed
  752.      * @see Container#removeComponent
  753.      */
  754.     public void removeLayoutComponent(Component component) {
  755.         ComponentInfo info = (ComponentInfo)componentInfos.remove(component);
  756.         if (info != null) {
  757.             info.dispose();
  758.             springsChanged = true;
  759.             isValid = false;
  760.         }
  761.     }
  762.     
  763.     /**
  764.      * Returns the preferred size for the specified container.
  765.      *
  766.      * @param parent the container to return size for
  767.      * @throws IllegalArgumentException if <code>parent</code> is not
  768.      *         the same <code>Container</code> that this was created with
  769.      * @throws IllegalStateException if any of the components added to
  770.      *         this layout are not in both a horizontal and vertical group
  771.      * @see Container#getPreferredSize
  772.      */
  773.     public Dimension getPreferredSize(Container parent) {
  774.         checkParent(parent);
  775.         prepare(PREF_SIZE);
  776.         return adjustSize(horizontalGroup.getPreferredSize(HORIZONTAL),
  777.                 verticalGroup.getPreferredSize(VERTICAL));
  778.     }
  779.     
  780.     
  781.     /**
  782.      * Returns the minimum size for the specified container.
  783.      *
  784.      * @param parent the container to return size for
  785.      * @throws IllegalArgumentException if <code>parent</code> is not
  786.      *         the same <code>Container</code> that this was created with
  787.      * @throws IllegalStateException if any of the components added to
  788.      *         this layout are not in both a horizontal and vertical group
  789.      * @see java.awt.Container#getMinimumSize
  790.      */
  791.     /*public Dimension minimumLayoutSize(Container parent) {
  792.         checkParent(parent);
  793.         prepare(MIN_SIZE);
  794.         return adjustSize(horizontalGroup.getMinimumSize(HORIZONTAL),
  795.                 verticalGroup.getMinimumSize(VERTICAL));
  796.     }*/
  797.     
  798.     /**
  799.      * Lays out the specified container.
  800.      *
  801.      * @param parent the container to be laid out
  802.      * @throws IllegalStateException if any of the components added to
  803.      *         this layout are not in both a horizontal and vertical group
  804.      */
  805.     public void layoutContainer(Container parent) {
  806.         // Step 1: Prepare for layout.
  807.         prepare(SPECIFIC_SIZE);
  808.         int insetLeft = parent.getStyle().getMargin(false, Component.LEFT);
  809.         int insetTop = parent.getStyle().getMargin(false, Component.TOP);
  810.         int insetRight = parent.getStyle().getMargin(false, Component.RIGHT);
  811.         int insetBottom = parent.getStyle().getMargin(false, Component.BOTTOM);
  812.         int width = parent.getWidth() - insetLeft - insetRight;
  813.         int height = parent.getHeight() - insetTop - insetBottom;
  814.         boolean ltr = isLeftToRight();
  815.         if (getAutocreateGaps() || getAutocreateContainerGaps() ||
  816.                 hasPreferredPaddingSprings) {
  817.             // Step 2: Calculate autopadding springs
  818.             calculateAutopadding(horizontalGroup, HORIZONTAL, SPECIFIC_SIZE, 0,
  819.                     width);
  820.             calculateAutopadding(verticalGroup, VERTICAL, SPECIFIC_SIZE, 0,
  821.                     height);
  822.         }
  823.         // Step 3: set the size of the groups.
  824.         horizontalGroup.setSize(HORIZONTAL, 0, width);
  825.         verticalGroup.setSize(VERTICAL, 0, height);
  826.         
  827.         // Step 4: apply the size to the components.
  828.         Enumeration componentInfo = componentInfos.elements();
  829.         while (componentInfo.hasMoreElements()) {
  830.             ComponentInfo info = (ComponentInfo)componentInfo.nextElement();
  831.             Component c = info.getComponent();
  832.             info.setBounds(insetLeft, insetTop, width, ltr);
  833.         }
  834.     }
  835.     
  836.     /**
  837.      * Returns the maximum size for the specified container.
  838.      *
  839.      * @param parent the container to return size for
  840.      * @throws IllegalArgumentException if <code>parent</code> is not
  841.      *         the same <code>Container</code> that this was created with
  842.      * @throws IllegalStateException if any of the components added to
  843.      *         this layout are not in both a horizontal and vertical group
  844.      * @see java.awt.Container#getMaximumSize
  845.      */
  846.     /*public Dimension maximumLayoutSize(Container parent) {
  847.         checkParent(parent);
  848.         prepare(MAX_SIZE);
  849.         return adjustSize(horizontalGroup.getMaximumSize(HORIZONTAL),
  850.                 verticalGroup.getMaximumSize(VERTICAL));
  851.     }*/
  852.     
  853.     /**
  854.      * Returns the alignment along the x axis.  This specifies how
  855.      * the component would like to be aligned relative to other
  856.      * components.  The value should be a number between 0 and 1
  857.      * where 0 represents alignment along the origin, 1 is aligned
  858.      * the furthest away from the origin, 0.5 is centered, etc.
  859.      *
  860.      * @param parent Container hosting this LayoutManager
  861.      * @throws IllegalArgumentException if <code>parent</code> is not
  862.      *         the same <code>Container</code> that this was created with
  863.      * @return alignment
  864.      */
  865.     /*public float getLayoutAlignmentX(Container parent) {
  866.         checkParent(parent);
  867.         return .5f;
  868.     }*
  869.     
  870.     /**
  871.      * Returns the alignment along the y axis.  This specifies how
  872.      * the component would like to be aligned relative to other
  873.      * components.  The value should be a number between 0 and 1
  874.      * where 0 represents alignment along the origin, 1 is aligned
  875.      * the furthest away from the origin, 0.5 is centered, etc.
  876.      *
  877.      * @param parent Container hosting this LayoutManager
  878.      * @throws IllegalArgumentException if <code>parent</code> is not
  879.      *         the same <code>Container</code> that this was created with
  880.      * @return alignment
  881.      */
  882.     /*public float getLayoutAlignmentY(Container parent) {
  883.         checkParent(parent);
  884.         return .5f;
  885.     }*/
  886.     
  887.     /**
  888.      * Invalidates the layout, indicating that if the layout manager
  889.      * has cached information it should be discarded.
  890.      *
  891.      * @param parent Container hosting this LayoutManager
  892.      * @throws IllegalArgumentException if <code>parent</code> is not
  893.      *         the same <code>Container</code> that this was created with
  894.      */
  895.     /*public void invalidateLayout(Container parent) {
  896.         checkParent(parent);
  897.         // invalidateLayout is called from Container.invalidate, which
  898.         // does NOT grab the treelock.  All other methods do.  To make sure
  899.         // there aren't any possible threading problems we grab the tree lock
  900.         // here.
  901.         //synchronized(parent.getTreeLock()) {
  902.             isValid = false;
  903.         //}
  904.     }*/
  905.     
  906.     private void prepare(int sizeType) {
  907.         boolean visChanged = false;
  908.         // Step 1: If not-valid, clear springs and update visibility.
  909.         if (!isValid) {
  910.             isValid = true;
  911.             horizontalGroup.setSize(HORIZONTAL, UNSET, UNSET);
  912.             verticalGroup.setSize(VERTICAL, UNSET, UNSET);
  913.             for (Enumeration cis = componentInfos.elements();
  914.                      cis.hasMoreElements();) {
  915.                 ComponentInfo ci = (ComponentInfo)cis.nextElement();
  916.                 if (ci.updateVisibility()) {
  917.                     visChanged = true;
  918.                 }
  919.                 ci.clearCachedSize();
  920.             }
  921.         }
  922.         // Step 2: Make sure components are bound to ComponentInfos
  923.         if (springsChanged) {
  924.             registerComponents(horizontalGroup, HORIZONTAL);
  925.             registerComponents(verticalGroup, VERTICAL);
  926.         }
  927.         // Step 3: Adjust the autopadding. This removes existing
  928.         // autopadding, then recalculates where it should go.
  929.         if (springsChanged || visChanged) {
  930.             checkComponents();
  931.             horizontalGroup.removeAutopadding();
  932.             verticalGroup.removeAutopadding();
  933.             if (getAutocreateGaps()) {
  934.                 insertAutopadding(true);
  935.             } else if (hasPreferredPaddingSprings ||
  936.                     getAutocreateContainerGaps()) {
  937.                 insertAutopadding(false);
  938.             }
  939.             springsChanged = false;
  940.         }
  941.         // Step 4: (for min/pref/max size calculations only) calculate the
  942.         // autopadding. This invokes for unsetting the calculated values, then
  943.         // recalculating them.
  944.         // If sizeType == SPECIFIC_SIZE, it indicates we're doing layout, this
  945.         // step will be done later on.
  946.         if (sizeType != SPECIFIC_SIZE && (getAutocreateGaps() ||
  947.                 getAutocreateContainerGaps() || hasPreferredPaddingSprings)) {
  948.             calculateAutopadding(horizontalGroup, HORIZONTAL, sizeType, 0, 0);
  949.             calculateAutopadding(verticalGroup, VERTICAL, sizeType, 0, 0);
  950.         }
  951.     }
  952.     private void calculateAutopadding(Group group, int axis, int sizeType,
  953.             int origin, int size) {
  954.         group.unsetAutopadding();
  955.         switch(sizeType) {
  956.             case MIN_SIZE:
  957.                 size = group.getMinimumSize(axis);
  958.                 break;
  959.             case PREF_SIZE:
  960.                 size = group.getPreferredSize(axis);
  961.                 break;
  962.             case MAX_SIZE:
  963.                 size = group.getMaximumSize(axis);
  964.                 break;
  965.         }
  966.         group.setSize(axis, origin, size);
  967.         group.calculateAutopadding(axis);
  968.     }
  969.     
  970.     private void checkComponents() {
  971.         Enumeration infos = componentInfos.elements();
  972.         while (infos.hasMoreElements()) {
  973.             ComponentInfo info = (ComponentInfo)infos.nextElement();
  974.             if (info.horizontalSpring == null) {
  975.                 throw new IllegalStateException(info.component +
  976.                         " is not attached to a horizontal group");
  977.             }
  978.             if (info.verticalSpring == null) {
  979.                 throw new IllegalStateException(info.component +
  980.                         " is not attached to a vertical group");
  981.             }
  982.         }
  983.     }
  984.     
  985.     private void registerComponents(Group group, int axis) {
  986.         Vector springs = group.springs;
  987.         for (int counter = springs.size() - 1; counter >= 0; counter--) {
  988.             Spring spring = (Spring)springs.elementAt(counter);
  989.             if (spring instanceof ComponentSpring) {
  990.                 ((ComponentSpring)spring).installIfNecessary(axis);
  991.             } else if (spring instanceof Group) {
  992.                 registerComponents((Group)spring, axis);
  993.             }
  994.         }
  995.     }
  996.     
  997.     private Dimension adjustSize(int width, int height) {
  998.         int insetLeft = host.getStyle().getMargin(false, Component.LEFT);
  999.         int insetTop = host.getStyle().getMargin(false, Component.TOP);
  1000.         int insetRight = host.getStyle().getMargin(false, Component.RIGHT);
  1001.         int insetBottom = host.getStyle().getMargin(false, Component.BOTTOM);
  1002.         return new Dimension(width + insetLeft + insetRight,
  1003.                 height + insetTop + insetBottom);
  1004.     }
  1005.     
  1006.     private void checkParent(Container parent) {
  1007.         if (parent != host) {
  1008.             throw new IllegalArgumentException(
  1009.                     "GroupLayout can only be used with one Container at a time");
  1010.         }
  1011.     }
  1012.     
  1013.     /**
  1014.      * Returns the <code>ComponentInfo</code> for the specified Component.
  1015.      */
  1016.     private ComponentInfo getComponentInfo(Component component) {
  1017.         ComponentInfo info = (ComponentInfo)componentInfos.get(component);
  1018.         if (info == null) {
  1019.             info = new ComponentInfo(component);
  1020.             componentInfos.put(component, info);
  1021.             if (component.getParent() != host) {
  1022.                 host.addComponent(component);
  1023.             }
  1024.         }
  1025.         return info;
  1026.     }
  1027.     
  1028.     /**
  1029.      * Adjusts the autopadding springs for the horizontal and vertical
  1030.      * groups.  If <code>insert</code> is true this will insert auto padding
  1031.      * springs, otherwise this will only adjust the springs that
  1032.      * comprise auto preferred padding springs.
  1033.      */
  1034.     private void insertAutopadding(boolean insert) {
  1035.         horizontalGroup.insertAutopadding(HORIZONTAL, new Vector(1),
  1036.                 new Vector(1), new Vector(1), new Vector(1), insert);
  1037.         verticalGroup.insertAutopadding(VERTICAL, new Vector(1),
  1038.                 new Vector(1), new Vector(1), new Vector(1), insert);
  1039.     }
  1040.     
  1041.     /**
  1042.      * Returns true if the two Components have a common ParallelGroup ancestor
  1043.      * along the particular axis.
  1044.      */
  1045.     private boolean areParallelSiblings(Component source, Component target,
  1046.             int axis) {
  1047.         ComponentInfo sourceInfo = getComponentInfo(source);
  1048.         ComponentInfo targetInfo = getComponentInfo(target);
  1049.         Spring sourceSpring;
  1050.         Spring targetSpring;
  1051.         if (axis == HORIZONTAL) {
  1052.             sourceSpring = sourceInfo.horizontalSpring;
  1053.             targetSpring = targetInfo.horizontalSpring;
  1054.         } else {
  1055.             sourceSpring = sourceInfo.verticalSpring;
  1056.             targetSpring = targetInfo.verticalSpring;
  1057.         }
  1058.         Vector sourcePath = tmpParallelSet;
  1059.         sourcePath.removeAllElements();
  1060.         Spring spring = sourceSpring.getParent();
  1061.         while (spring != null) {
  1062.             sourcePath.addElement(spring);
  1063.             spring = spring.getParent();
  1064.         }
  1065.         spring = targetSpring.getParent();
  1066.         while (spring != null) {
  1067.             if (sourcePath.contains(spring)) {
  1068.                 sourcePath.removeAllElements();
  1069.                 while (spring != null) {
  1070.                     if (spring instanceof ParallelGroup) {
  1071.                         return true;
  1072.                     }
  1073.                     spring = spring.getParent();
  1074.                 }
  1075.                 return false;
  1076.             }
  1077.             spring = spring.getParent();
  1078.         }
  1079.         sourcePath.removeAllElements();
  1080.         return false;
  1081.     }
  1082.     
  1083.     private boolean isLeftToRight() {
  1084.         // Need bidi support...
  1085.         return true;
  1086.         //return host.getComponentOrientation().isLeftToRight();
  1087.     }
  1088.     
  1089.     /**
  1090.      * Spring consists of a range: min, pref and max a value some where in
  1091.      * the middle of that and a location.  Subclasses must override
  1092.      * methods to get the min/max/pref and will likely want to override
  1093.      * the <code>setSize</code> method.  Spring automatically caches the
  1094.      * min/max/pref.  If the min/pref/max has internally changes, or needs
  1095.      * to be updated you must invoked clear.
  1096.      */
  1097.     abstract class Spring {
  1098.         private int size;
  1099.         private int min;
  1100.         private int max;
  1101.         private int pref;
  1102.         private Spring parent;
  1103.         
  1104.         private int alignment;
  1105.         
  1106.         Spring() {
  1107.             min = pref = max = UNSET;
  1108.         }
  1109.         
  1110.         /**
  1111.          * Calculates and returns the minimum size.
  1112.          *
  1113.          * @param axis the axis of layout; one of HORIZONTAL or VERTICAL
  1114.          * @return the minimum size
  1115.          */
  1116.         abstract int calculateMinimumSize(int axis);
  1117.         
  1118.         /**
  1119.          * Calculates and returns the preferred size.
  1120.          *
  1121.          * @param axis the axis of layout; one of HORIZONTAL or VERTICAL
  1122.          * @return the preferred size
  1123.          */
  1124.         abstract int calculatePreferredSize(int axis);
  1125.         
  1126.         /**
  1127.          * Calculates and returns the minimum size.
  1128.          *
  1129.          * @param axis the axis of layout; one of HORIZONTAL or VERTICAL
  1130.          * @return the minimum size
  1131.          */
  1132.         abstract int calculateMaximumSize(int axis);
  1133.         
  1134.         /**
  1135.          * Sets the parent of this Spring.
  1136.          */
  1137.         void setParent(Spring parent) {
  1138.             this.parent = parent;
  1139.         }
  1140.         
  1141.         /**
  1142.          * Returns the parent of this spring.
  1143.          */
  1144.         Spring getParent() {
  1145.             return parent;
  1146.         }
  1147.         
  1148.         // This is here purely as a conveniance for ParallelGroup to avoid
  1149.         // having to track alignment separately.
  1150.         void setAlignment(int alignment) {
  1151.             this.alignment = alignment;
  1152.         }
  1153.         
  1154.         int getAlignment() {
  1155.             return alignment;
  1156.         }
  1157.         
  1158.         /**
  1159.          * Returns the minimum size.
  1160.          */
  1161.         final int getMinimumSize(int axis) {
  1162.             if (min == UNSET) {
  1163.                 min = constrain(calculateMinimumSize(axis));
  1164.             }
  1165.             return min;
  1166.         }
  1167.         
  1168.         /**
  1169.          * Returns the preferred size.
  1170.          */
  1171.         final int getPreferredSize(int axis) {
  1172.             if (pref == UNSET) {
  1173.                 pref = constrain(calculatePreferredSize(axis));
  1174.             }
  1175.             return pref;
  1176.         }
  1177.         
  1178.         /**
  1179.          * Returns the maximum size.
  1180.          */
  1181.         final int getMaximumSize(int axis) {
  1182.             if (max == UNSET) {
  1183.                 max = constrain(calculateMaximumSize(axis));
  1184.             }
  1185.             return max;
  1186.         }
  1187.         
  1188.         /**
  1189.          * Resets the cached min/max/pref.
  1190.          */
  1191.         void unset() {
  1192.             size = min = pref = max = UNSET;
  1193.         }
  1194.         
  1195.         /**
  1196.          * Sets the value and location of the spring.  Subclasses
  1197.          * will want to invoke super, then do any additional sizing.
  1198.          *
  1199.          * @param axis HORIZONTAL or VERTICAL
  1200.          * @param origin of this Spring
  1201.          * @param size of the Spring.  If size is UNSET, this invokes
  1202.          *        clear.
  1203.          */
  1204.         void setSize(int axis, int origin, int size) {
  1205.             this.size = size;
  1206.             if (size == UNSET) {
  1207.                 unset();
  1208.             }
  1209.         }
  1210.         
  1211.         /**
  1212.          * Returns the current size.
  1213.          */
  1214.         int getSize() {
  1215.             return size;
  1216.         }
  1217.         
  1218.         int constrain(int value) {
  1219.             return Math.min(value, Short.MAX_VALUE);
  1220.         }
  1221.         int getBaseline() {
  1222.             return -1;
  1223.         }
  1224.         
  1225.         int getBaselineResizeBehavior() {
  1226.             return Component.BRB_OTHER;
  1227.         }
  1228.         
  1229.         final boolean isResizable(int axis) {
  1230.             int min = getMinimumSize(axis);
  1231.             int pref = getPreferredSize(axis);
  1232.             return (min != pref || pref != getMaximumSize(axis));
  1233.         }
  1234.         
  1235.         /**
  1236.          * Returns true if this Spring will ALWAYS have a zero size. This should 
  1237.          * NOT check the current size, rather it's meant to 
  1238.          * quickly test if this Spring will always have a zero size.
  1239.          */
  1240.         abstract boolean willHaveZeroSize(boolean treatAutopaddingAsZeroSized);
  1241.     }
  1242.     
  1243.     /**
  1244.      * Simple copy constructor for vector
  1245.      */
  1246.     private static Vector create(Vector v) {
  1247.         int size = v.size();
  1248.         Vector vec = new Vector(size);
  1249.         for(int iter = 0 ; iter < size ; iter++) {
  1250.             vec.addElement(v.elementAt(iter));
  1251.         }
  1252.         return vec;
  1253.     }
  1254.     
  1255.     /**
  1256.      * Adds all vector elements from source to dest
  1257.      */
  1258.     private static void addAll(Vector dest, Vector source) {
  1259.         int size = source.size();
  1260.         for(int iter = 0 ; iter < size ; iter++) {
  1261.             dest.addElement(source.elementAt(iter));
  1262.         }
  1263.     }
  1264.     
  1265.     /**
  1266.      * Group provides for commonality between the two types of operations
  1267.      * supported by <code>GroupLayout</code>: laying out components one
  1268.      * after another (<code>SequentialGroup</code>) or layout on top
  1269.      * of each other (<code>ParallelGroup</code>). Use one of
  1270.      * <code>createSequentialGroup</code> or
  1271.      * <code>createParallelGroup</code> to create one.
  1272.      */
  1273.     public abstract class Group extends Spring {
  1274.         // private int origin;
  1275.         // private int size;
  1276.         Vector springs;
  1277.         
  1278.         Group() {
  1279.             springs = new Vector();
  1280.         }
  1281.         
  1282.         int indexOf(Spring spring) {
  1283.             return springs.indexOf(spring);
  1284.         }
  1285.         
  1286.         /**
  1287.          * Adds the Spring to the list of <code>Spring</code>s and returns
  1288.          * the receiver.
  1289.          */
  1290.         Group addSpring(Spring spring) {
  1291.             springs.addElement(spring);
  1292.             spring.setParent(this);
  1293.             if (!(spring instanceof AutopaddingSpring) ||
  1294.                     !((AutopaddingSpring)spring).getUserCreated()) {
  1295.                 springsChanged = true;
  1296.             }
  1297.             return this;
  1298.         }
  1299.         
  1300.         //
  1301.         // Spring methods
  1302.         //
  1303.         
  1304.         void setSize(int axis, int origin, int size) {
  1305.             super.setSize(axis, origin, size);
  1306.             if (size == UNSET) {
  1307.                 for (int counter = springs.size() - 1; counter >= 0;
  1308.                      counter--) {
  1309.                     getSpring(counter).setSize(axis, origin, size);
  1310.                 }
  1311.             } else {
  1312.                 setValidSize(axis, origin, size);
  1313.             }
  1314.         }
  1315.         
  1316.         /**
  1317.          * This is invoked from <code>setSize</code> if passed a value
  1318.          * other than UNSET.
  1319.          */
  1320.         abstract void setValidSize(int axis, int origin, int size);
  1321.         
  1322.         int calculateMinimumSize(int axis) {
  1323.             return calculateSize(axis, MIN_SIZE);
  1324.         }
  1325.         
  1326.         int calculatePreferredSize(int axis) {
  1327.             return calculateSize(axis, PREF_SIZE);
  1328.         }
  1329.         
  1330.         int calculateMaximumSize(int axis) {
  1331.             return calculateSize(axis, MAX_SIZE);
  1332.         }
  1333.         
  1334.         /**
  1335.          * Used to compute how the two values representing two springs
  1336.          * will be combined.  For example, a group that layed things out
  1337.          * one after the next would return <code>a + b</code>.
  1338.          */
  1339.         abstract int operator(int a, int b);
  1340.         
  1341.         /**
  1342.          * Calculates the specified size.  This is called from
  1343.          * one of the <code>getMinimumSize0</code>,
  1344.          * <code>getPreferredSize0</code> or
  1345.          * <code>getMaximumSize0</code> methods.  This will invoke
  1346.          * to <code>operator</code> to combine the values.
  1347.          */
  1348.         int calculateSize(int axis, int type) {
  1349.             int count = springs.size();
  1350.             if (count == 0) {
  1351.                 return 0;
  1352.             }
  1353.             if (count == 1) {
  1354.                 return getSpringSize(getSpring(0), axis, type);
  1355.             }
  1356.             int size = constrain(operator(getSpringSize(getSpring(0), axis, type),
  1357.                     getSpringSize(getSpring(1), axis, type)));
  1358.             for (int counter = 2; counter < count; counter++) {
  1359.                 size = constrain(operator(size, getSpringSize(getSpring(counter),
  1360.                         axis, type)));
  1361.             }
  1362.             return size;
  1363.         }
  1364.         
  1365.         Spring getSpring(int index) {
  1366.             return (Spring)springs.elementAt(index);
  1367.         }
  1368.         
  1369.         int getSpringSize(Spring spring, int axis, int type) {
  1370.             switch(type) {
  1371.                 case MIN_SIZE:
  1372.                     return spring.getMinimumSize(axis);
  1373.                 case PREF_SIZE:
  1374.                     return spring.getPreferredSize(axis);
  1375.                 case MAX_SIZE:
  1376.                     return spring.getMaximumSize(axis);
  1377.             }
  1378.             //assert false;
  1379.             return 0;
  1380.         }
  1381.         
  1382.         // Padding
  1383.         /**
  1384.          * Adjusts the autopadding springs in this group and its children.
  1385.          * If <code>insert</code> is true this will insert auto padding
  1386.          * springs, otherwise this will only adjust the springs that
  1387.          * comprise auto preferred padding springs.
  1388.          *
  1389.          * @param axis the axis of the springs; HORIZONTAL or VERTICAL
  1390.          * @param leadingPadding List of AutopaddingSprings that occur before
  1391.          *                       this Group
  1392.          * @param trailingPadding any trailing autopadding springs are added
  1393.          *                        to this on exit
  1394.          * @param leading List of ComponentSprings that occur before this Group
  1395.          * @param trailing any trailing ComponentSpring are added to this
  1396.          *                 List
  1397.          * @param insert Whether or not to insert AutopaddingSprings or just
  1398.          *               adjust any existing AutopaddingSprings.
  1399.          */
  1400.         abstract void insertAutopadding(int axis, Vector leadingPadding,
  1401.                 Vector trailingPadding, Vector leading, Vector trailing,
  1402.                 boolean insert);
  1403.         
  1404.         /**
  1405.          * Removes any AutopaddingSprings.
  1406.          */
  1407.         void removeAutopadding() {
  1408.             unset();
  1409.             for (int counter = springs.size() - 1; counter >= 0; counter--) {
  1410.                 Spring spring = (Spring)springs.elementAt(counter);
  1411.                 if (spring instanceof AutopaddingSpring) {
  1412.                     if (((AutopaddingSpring)spring).getUserCreated()) {
  1413.                         ((AutopaddingSpring)spring).reset();
  1414.                     } else {
  1415.                         springs.removeElementAt(counter);
  1416.                     }
  1417.                 } else if (spring instanceof Group) {
  1418.                     ((Group)spring).removeAutopadding();
  1419.                 }
  1420.             }
  1421.         }
  1422.         
  1423.         void unsetAutopadding() {
  1424.             // Clear cached pref/min/max.
  1425.             unset();
  1426.             for (int counter = springs.size() - 1; counter >= 0; counter--) {
  1427.                 Spring spring = (Spring)springs.elementAt(counter);
  1428.                 if (spring instanceof AutopaddingSpring) {
  1429.                     ((AutopaddingSpring)spring).unset();
  1430.                 } else if (spring instanceof Group) {
  1431.                     ((Group)spring).unsetAutopadding();
  1432.                 }
  1433.             }
  1434.         }
  1435.         
  1436.         void calculateAutopadding(int axis) {
  1437.             for (int counter = springs.size() - 1; counter >= 0; counter--) {
  1438.                 Spring spring = (Spring)springs.elementAt(counter);
  1439.                 if (spring instanceof AutopaddingSpring) {
  1440.                     // Force size to be reset.
  1441.                     spring.unset();
  1442.                     ((AutopaddingSpring)spring).calculatePadding(axis);
  1443.                 } else if (spring instanceof Group) {
  1444.                     ((Group)spring).calculateAutopadding(axis);
  1445.                 }
  1446.             }
  1447.             // Clear cached pref/min/max.
  1448.             unset();
  1449.         }
  1450.         
  1451.         boolean willHaveZeroSize(boolean treatAutopaddingAsZeroSized) {
  1452.             for (int i = springs.size() -1; i >= 0; i--) {
  1453.                 Spring spring = (Spring)springs.elementAt(i);
  1454.                 if (!spring.willHaveZeroSize(treatAutopaddingAsZeroSized)) {
  1455.                     return false;
  1456.                 }
  1457.             }
  1458.             return true;
  1459.         }
  1460.     }
  1461.     
  1462.     
  1463.     /**
  1464.      * A <code>Group</code> that lays out its elements sequentially, one
  1465.      * after another.  This class has no public constructor, use the
  1466.      * <code>createSequentialGroup</code> method to create one.
  1467.      *
  1468.      * @see #createSequentialGroup()
  1469.      */
  1470.     public class SequentialGroup extends Group {
  1471.         private Spring baselineSpring;
  1472.         
  1473.         SequentialGroup() {
  1474.         }
  1475.         
  1476.         /**
  1477.          * Adds the specified <code>Group</code> to this
  1478.          * <code>SequentialGroup</code>
  1479.          *
  1480.          * @param group the Group to add
  1481.          * @return this Group
  1482.          */
  1483.         public SequentialGroup add(Group group) {
  1484.             return (SequentialGroup)addSpring(group);
  1485.         }
  1486.         
  1487.         /**
  1488.          * Adds a <code>Group</code> to this <code>Group</code>.
  1489.          *
  1490.          * @param group the <code>Group</code> to add
  1491.          * @param useAsBaseline whether the specified <code>Group</code> should
  1492.          *        be used to calculate the baseline for this <code>Group</code>
  1493.          * @return this <code>Group</code>
  1494.          */
  1495.         public SequentialGroup add(boolean useAsBaseline, Group group) {
  1496.             add(group);
  1497.             if (useAsBaseline) {
  1498.                 baselineSpring = group;
  1499.             }
  1500.             return this;
  1501.         }
  1502.         
  1503.         /**
  1504.          * Adds the specified Component.  If the Component's min/max
  1505.          * are different from its pref than the component will be resizable.
  1506.          *
  1507.          * @param component the Component to add
  1508.          * @return this <code>SequentialGroup</code>
  1509.          */
  1510.         public SequentialGroup add(Component component) {
  1511.             return add(component, DEFAULT_SIZE, DEFAULT_SIZE, DEFAULT_SIZE);
  1512.         }
  1513.         
  1514.         /**
  1515.          * Adds a <code>Component</code> to this <code>Group</code>.
  1516.          *
  1517.          * @param useAsBaseline whether the specified <code>Component</code> should
  1518.          *        be used to calculate the baseline for this <code>Group</code>
  1519.          * @param component the <code>Component</code> to add
  1520.          * @return this <code>Group</code>
  1521.          */
  1522.         public SequentialGroup add(boolean useAsBaseline, Component component) {
  1523.             add(component);
  1524.             if (useAsBaseline) {
  1525.                 baselineSpring = getSpring(springs.size() - 1);
  1526.             }
  1527.             return this;
  1528.         }
  1529.         /**
  1530.          * Adds the specified <code>Component</code>.  Min, pref and max
  1531.          * can be absolute values, or they can be one of
  1532.          * <code>DEFAULT_SIZE</code> or <code>PREFERRED_SIZE</code>.  For
  1533.          * example, the following:
  1534.          * <pre>
  1535.          *   add(component, PREFERRED_SIZE, PREFERRED_SIZE, 1000);
  1536.          * </pre>
  1537.          * Forces a max of 1000, with the min and preferred equalling that
  1538.          * of the preferred size of <code>component</code>.
  1539.          *
  1540.          * @param component the Component to add
  1541.          * @param min the minimum size
  1542.          * @param pref the preferred size
  1543.          * @param max the maximum size
  1544.          * @throws IllegalArgumentException if min, pref or max are
  1545.          *         not positive and not one of PREFERRED_SIZE or DEFAULT_SIZE
  1546.          * @return this <code>SequentialGroup</code>
  1547.          */
  1548.         public SequentialGroup add(Component component, int min, int pref,
  1549.                 int max) {
  1550.             return (SequentialGroup)addSpring(new ComponentSpring(
  1551.                     component, min, pref, max));
  1552.         }
  1553.         
  1554.         /**
  1555.          * Adds a <code>Component</code> to this <code>Group</code>
  1556.          * with the specified size.
  1557.          *
  1558.          * @param useAsBaseline whether the specified <code>Component</code> should
  1559.          *        be used to calculate the baseline for this <code>Group</code>
  1560.          * @param component the <code>Component</code> to add
  1561.          * @param min the minimum size or one of <code>DEFAULT_SIZE</code> or
  1562.          *            <code>PREFERRED_SIZE</code>
  1563.          * @param pref the preferred size or one of <code>DEFAULT_SIZE</code> or
  1564.          *            <code>PREFERRED_SIZE</code>
  1565.          * @param max the maximum size or one of <code>DEFAULT_SIZE</code> or
  1566.          *            <code>PREFERRED_SIZE</code>
  1567.          * @return this <code>Group</code>
  1568.          */
  1569.         public SequentialGroup add(boolean useAsBaseline,
  1570.                 Component component, int min, int pref, int max) {
  1571.             add(component, min, pref, max);
  1572.             if (useAsBaseline) {
  1573.                 baselineSpring = getSpring(springs.size() - 1);
  1574.             }
  1575.             return this;
  1576.         }
  1577.         /**
  1578.          * Adds a rigid gap.
  1579.          *
  1580.          * @param pref the size of the gap
  1581.          * @throws IllegalArgumentException if min < 0 or pref < 0 or max < 0
  1582.          *         or the following is not meant min <= pref <= max
  1583.          * @return this <code>SequentialGroup</code>
  1584.          */
  1585.         public SequentialGroup add(int pref) {
  1586.             return add(pref, pref, pref);
  1587.         }
  1588.         
  1589.         /**
  1590.          * Adds a gap with the specified size.
  1591.          *
  1592.          * @param min the minimum size of the gap, or PREFERRED_SIZE
  1593.          * @param pref the preferred size of the gap
  1594.          * @param max the maximum size of the gap, or PREFERRED_SIZE
  1595.          * @throws IllegalArgumentException if min < 0 or pref < 0 or max < 0
  1596.          *         or the following is not meant min <= pref <= max
  1597.          * @return this <code>SequentialGroup</code>
  1598.          */
  1599.         public SequentialGroup add(int min, int pref, int max) {
  1600.             return (SequentialGroup)addSpring(new GapSpring(min, pref, max));
  1601.         }
  1602.         
  1603.         /**
  1604.          * Adds an element representing the preferred gap between the two
  1605.          * components.
  1606.          * 
  1607.          * @param comp1 the first component
  1608.          * @param comp2 the second component
  1609.          * @param type the type of gap; one of the constants defined by
  1610.          *        LayoutStyle
  1611.          * @return this <code>SequentialGroup</code>
  1612.          * @throws IllegalArgumentException if <code>type</code> is not a
  1613.          *         valid LayoutStyle constant
  1614.          * @see LayoutStyle
  1615.          */
  1616.         public SequentialGroup addPreferredGap(Component comp1,
  1617.                 Component comp2,
  1618.                 int type) {
  1619.             return addPreferredGap(comp1, comp2, type, false);
  1620.         }
  1621.         
  1622.         /**
  1623.          * Adds an element representing the preferred gap between the two
  1624.          * components.
  1625.          * 
  1626.          * @param comp1 the first component
  1627.          * @param comp2 the second component
  1628.          * @param type the type of gap; one of the constants defined by
  1629.          *        LayoutStyle
  1630.          * @param canGrow true if the gap can grow if more
  1631.          *                space is available
  1632.          * @return this <code>SequentialGroup</code>
  1633.          * @throws IllegalArgumentException if <code>type</code> is not a
  1634.          *         valid LayoutStyle constant
  1635.          * @see LayoutStyle
  1636.          */
  1637.         public SequentialGroup addPreferredGap(Component comp1,
  1638.                 Component comp2,
  1639.                 int type, boolean canGrow) {
  1640.             if (type != LayoutStyle.RELATED &&
  1641.                     type != LayoutStyle.UNRELATED &&
  1642.                     type != LayoutStyle.INDENT) {
  1643.                 throw new IllegalArgumentException("Invalid type argument");
  1644.             }
  1645.             if (comp1 == null || comp2 == null) {
  1646.                 throw new IllegalArgumentException(
  1647.                         "Components must be non-null");
  1648.             }
  1649.             return (SequentialGroup)addSpring(new PaddingSpring(
  1650.                     comp1, comp2, type, canGrow));
  1651.         }
  1652.         /**
  1653.          * Adds an element representing the preferred gap between the
  1654.          * nearest components.  That is, during layout the neighboring
  1655.          * components are found, and the min, pref and max of this
  1656.          * element is set based on the preferred gap between the
  1657.          * components.  If no neighboring components are found the
  1658.          * min, pref and max are set to 0.
  1659.          * 
  1660.          * @param type the type of gap; one of the LayoutStyle constants
  1661.          * @return this SequentialGroup
  1662.          * @throws IllegalArgumentException if type is not one of
  1663.          *         <code>LayoutStyle.RELATED</code> or
  1664.          *         <code>LayoutStyle.UNRELATED</code>
  1665.          * @see LayoutStyle
  1666.          */
  1667.         public SequentialGroup addPreferredGap(int type) {
  1668.             return addPreferredGap(type, DEFAULT_SIZE, DEFAULT_SIZE);
  1669.         }
  1670.         
  1671.         /**
  1672.          * Adds an element for the preferred gap between the
  1673.          * nearest components.  That is, during layout the neighboring
  1674.          * components are found, and the min of this
  1675.          * element is set based on the preferred gap between the
  1676.          * components.  If no neighboring components are found the
  1677.          * min is set to 0.  This method allows you to specify the
  1678.          * preferred and maximum size by way of the <code>pref</code>
  1679.          * and <code>max</code> arguments.  These can either be a
  1680.          * value &gt;= 0, in which case the preferred or max is the max
  1681.          * of the argument and the preferred gap, of DEFAULT_VALUE in
  1682.          * which case the value is the same as the preferred gap.
  1683.          * 
  1684.          * @param type the type of gap; one of LayoutStyle.RELATED or
  1685.          *        LayoutStyle.UNRELATED
  1686.          * @param pref the preferred size; one of DEFAULT_SIZE or a value > 0
  1687.          * @param max the maximum size; one of DEFAULT_SIZE, PREFERRED_SIZE
  1688.          *        or a value > 0
  1689.          * @return this SequentialGroup
  1690.          * @throws IllegalArgumentException if type is not one of
  1691.          *         <code>LayoutStyle.RELATED</code> or
  1692.          *         <code>LayoutStyle.UNRELATED</code> or pref/max is
  1693.          *         != DEFAULT_SIZE and < 0, or pref > max
  1694.          * @see LayoutStyle
  1695.          */
  1696.         public SequentialGroup addPreferredGap(int type, int pref,
  1697.                                                    int max) {
  1698.             if (type != LayoutStyle.RELATED && type != LayoutStyle.UNRELATED) {
  1699.                 throw new IllegalArgumentException(
  1700.                         "Padding type must be one of Padding.RELATED or Padding.UNRELATED");
  1701.             }
  1702.             if ((pref < 0 && pref != DEFAULT_SIZE && pref != PREFERRED_SIZE) ||
  1703.                     (max < 0 && max != DEFAULT_SIZE && max != PREFERRED_SIZE)||
  1704.                     (pref >= 0 && max >= 0 && pref > max)) {