/*
 * Copyright (c) 2006, Oracle and/or its affiliates. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.  Oracle designates this
 * particular file as subject to the "Classpath" exception as provided
 * by Oracle in the LICENSE file that accompanied this code.
 *
 * This code 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 General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
 */
package javax.swing;

import java.awt.Component;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.Insets;
import java.awt.LayoutManager2;
import java.util.*;
import static java.awt.Component.BaselineResizeBehavior;
import static javax.swing.LayoutStyle.ComponentPlacement;
import static javax.swing.SwingConstants.HORIZONTAL;
import static javax.swing.SwingConstants.VERTICAL;

GroupLayout is a LayoutManager that hierarchically groups components in order to position them in a Container. GroupLayout is intended for use by builders, but may be hand-coded as well. Grouping is done by instances of the Group class. GroupLayout supports two types of groups. A sequential group positions its child elements sequentially, one after another. A parallel group aligns its child elements in one of four ways.

Each group may contain any number of elements, where an element is a Group, Component, or gap. A gap can be thought of as an invisible component with a minimum, preferred and maximum size. In addition GroupLayout supports a preferred gap, whose value comes from LayoutStyle.

Elements are similar to a spring. Each element has a range as specified by a minimum, preferred and maximum. Gaps have either a developer-specified range, or a range determined by LayoutStyle. The range for Components is determined from the Component's getMinimumSize, getPreferredSize and getMaximumSize methods. In addition, when adding Components you may specify a particular range to use instead of that from the component. The range for a Group is determined by the type of group. A ParallelGroup's range is the maximum of the ranges of its elements. A SequentialGroup's range is the sum of the ranges of its elements.

GroupLayout treats each axis independently. That is, there is a group representing the horizontal axis, and a group representing the vertical axis. The horizontal group is responsible for determining the minimum, preferred and maximum size along the horizontal axis as well as setting the x and width of the components contained in it. The vertical group is responsible for determining the minimum, preferred and maximum size along the vertical axis as well as setting the y and height of the components contained in it. Each Component must exist in both a horizontal and vertical group, otherwise an IllegalStateException is thrown during layout, or when the minimum, preferred or maximum size is requested.

The following diagram shows a sequential group along the horizontal axis. The sequential group contains three components. A parallel group was used along the vertical axis.

To reinforce that each axis is treated independently the diagram shows the range of each group and element along each axis. The range of each component has been projected onto the axes, and the groups are rendered in blue (horizontal) and red (vertical). For readability there is a gap between each of the elements in the sequential group.

The sequential group along the horizontal axis is rendered as a solid blue line. Notice the sequential group is the sum of the children elements it contains.

Along the vertical axis the parallel group is the maximum of the height of each of the components. As all three components have the same height, the parallel group has the same height.

The following diagram shows the same three components, but with the parallel group along the horizontal axis and the sequential group along the vertical axis.

As c1 is the largest of the three components, the parallel group is sized to c1. As c2 and c3 are smaller than c1 they are aligned based on the alignment specified for the component (if specified) or the default alignment of the parallel group. In the diagram c2 and c3 were created with an alignment of LEADING. If the component orientation were right-to-left then c2 and c3 would be positioned on the opposite side.

The following diagram shows a sequential group along both the horizontal and vertical axis.

GroupLayout provides the ability to insert gaps between Components. The size of the gap is determined by an instance of LayoutStyle. This may be turned on using the setAutoCreateGaps method. Similarly, you may use the setAutoCreateContainerGaps method to insert gaps between components that touch the edge of the parent container and the container.

The following builds a panel consisting of two labels in one column, followed by two textfields in the next column:

  JComponent panel = ...;
  GroupLayout layout = new GroupLayout(panel);
  panel.setLayout(layout);
  // Turn on automatically adding gaps between components
  layout.setAutoCreateGaps(true);
  // Turn on automatically creating gaps between components that touch
  // the edge of the container and the container.
  layout.setAutoCreateContainerGaps(true);
  // Create a sequential group for the horizontal axis.
  GroupLayout.SequentialGroup hGroup = layout.createSequentialGroup();
  // The sequential group in turn contains two parallel groups.
  // One parallel group contains the labels, the other the text fields.
  // Putting the labels in a parallel group along the horizontal axis
  // positions them at the same x location.
  //
  // Variable indentation is used to reinforce the level of grouping.
  hGroup.addGroup(layout.createParallelGroup().
           addComponent(label1).addComponent(label2));
  hGroup.addGroup(layout.createParallelGroup().
           addComponent(tf1).addComponent(tf2));
  layout.setHorizontalGroup(hGroup);
  // Create a sequential group for the vertical axis.
  GroupLayout.SequentialGroup vGroup = layout.createSequentialGroup();
  // The sequential group contains two parallel groups that align
  // the contents along the baseline. The first parallel group contains
  // the first label and text field, and the second parallel group contains
  // the second label and text field. By using a sequential group
  // the labels and text fields are positioned vertically after one another.
  vGroup.addGroup(layout.createParallelGroup(Alignment.BASELINE).
           addComponent(label1).addComponent(tf1));
  vGroup.addGroup(layout.createParallelGroup(Alignment.BASELINE).
           addComponent(label2).addComponent(tf2));
  layout.setVerticalGroup(vGroup);

When run the following is produced.

This layout consists of the following.

  • The horizontal axis consists of a sequential group containing two parallel groups. The first parallel group contains the labels, and the second parallel group contains the text fields.
  • The vertical axis consists of a sequential group containing two parallel groups. The parallel groups are configured to align their components along the baseline. The first parallel group contains the first label and first text field, and the second group consists of the second label and second text field.
There are a couple of things to notice in this code:
  • You need not explicitly add the components to the container; this is indirectly done by using one of the add methods of Group.
  • The various add methods return the caller. This allows for easy chaining of invocations. For example, group.addComponent(label1).addComponent(label2); is equivalent to group.addComponent(label1); group.addComponent(label2);.
  • There are no public constructors for Groups; instead use the create methods of GroupLayout.
Author:Tomas Pavek, Jan Stola, Scott Violet
Since:1.6
/** * {@code GroupLayout} is a {@code LayoutManager} that hierarchically * groups components in order to position them in a {@code Container}. * {@code GroupLayout} is intended for use by builders, but may be * hand-coded as well. * Grouping is done by instances of the {@link Group Group} class. {@code * GroupLayout} supports two types of groups. A sequential group * positions its child elements sequentially, one after another. A * parallel group aligns its child elements in one of four ways. * <p> * Each group may contain any number of elements, where an element is * a {@code Group}, {@code Component}, or gap. A gap can be thought * of as an invisible component with a minimum, preferred and maximum * size. In addition {@code GroupLayout} supports a preferred gap, * whose value comes from {@code LayoutStyle}. * <p> * Elements are similar to a spring. Each element has a range as * specified by a minimum, preferred and maximum. Gaps have either a * developer-specified range, or a range determined by {@code * LayoutStyle}. The range for {@code Component}s is determined from * the {@code Component}'s {@code getMinimumSize}, {@code * getPreferredSize} and {@code getMaximumSize} methods. In addition, * when adding {@code Component}s you may specify a particular range * to use instead of that from the component. The range for a {@code * Group} is determined by the type of group. A {@code ParallelGroup}'s * range is the maximum of the ranges of its elements. A {@code * SequentialGroup}'s range is the sum of the ranges of its elements. * <p> * {@code GroupLayout} treats each axis independently. That is, there * is a group representing the horizontal axis, and a group * representing the vertical axis. The horizontal group is * responsible for determining the minimum, preferred and maximum size * along the horizontal axis as well as setting the x and width of the * components contained in it. The vertical group is responsible for * determining the minimum, preferred and maximum size along the * vertical axis as well as setting the y and height of the * components contained in it. Each {@code Component} must exist in both * a horizontal and vertical group, otherwise an {@code IllegalStateException} * is thrown during layout, or when the minimum, preferred or * maximum size is requested. * <p> * The following diagram shows a sequential group along the horizontal * axis. The sequential group contains three components. A parallel group * was used along the vertical axis. * <p align="center"> * <img src="doc-files/groupLayout.1.gif"> * <p> * To reinforce that each axis is treated independently the diagram shows * the range of each group and element along each axis. The * range of each component has been projected onto the axes, * and the groups are rendered in blue (horizontal) and red (vertical). * For readability there is a gap between each of the elements in the * sequential group. * <p> * The sequential group along the horizontal axis is rendered as a solid * blue line. Notice the sequential group is the sum of the children elements * it contains. * <p> * Along the vertical axis the parallel group is the maximum of the height * of each of the components. As all three components have the same height, * the parallel group has the same height. * <p> * The following diagram shows the same three components, but with the * parallel group along the horizontal axis and the sequential group along * the vertical axis. * <p> * <p align="center"> * <img src="doc-files/groupLayout.2.gif"> * <p> * As {@code c1} is the largest of the three components, the parallel * group is sized to {@code c1}. As {@code c2} and {@code c3} are smaller * than {@code c1} they are aligned based on the alignment specified * for the component (if specified) or the default alignment of the * parallel group. In the diagram {@code c2} and {@code c3} were created * with an alignment of {@code LEADING}. If the component orientation were * right-to-left then {@code c2} and {@code c3} would be positioned on * the opposite side. * <p> * The following diagram shows a sequential group along both the horizontal * and vertical axis. * <p align="center"> * <img src="doc-files/groupLayout.3.gif"> * <p> * {@code GroupLayout} provides the ability to insert gaps between * {@code Component}s. The size of the gap is determined by an * instance of {@code LayoutStyle}. This may be turned on using the * {@code setAutoCreateGaps} method. Similarly, you may use * the {@code setAutoCreateContainerGaps} method to insert gaps * between components that touch the edge of the parent container and the * container. * <p> * The following builds a panel consisting of two labels in * one column, followed by two textfields in the next column: * <pre> * JComponent panel = ...; * GroupLayout layout = new GroupLayout(panel); * panel.setLayout(layout); * * // Turn on automatically adding gaps between components * layout.setAutoCreateGaps(true); * * // Turn on automatically creating gaps between components that touch * // the edge of the container and the container. * layout.setAutoCreateContainerGaps(true); * * // Create a sequential group for the horizontal axis. * * GroupLayout.SequentialGroup hGroup = layout.createSequentialGroup(); * * // The sequential group in turn contains two parallel groups. * // One parallel group contains the labels, the other the text fields. * // Putting the labels in a parallel group along the horizontal axis * // positions them at the same x location. * // * // Variable indentation is used to reinforce the level of grouping. * hGroup.addGroup(layout.createParallelGroup(). * addComponent(label1).addComponent(label2)); * hGroup.addGroup(layout.createParallelGroup(). * addComponent(tf1).addComponent(tf2)); * layout.setHorizontalGroup(hGroup); * * // Create a sequential group for the vertical axis. * GroupLayout.SequentialGroup vGroup = layout.createSequentialGroup(); * * // The sequential group contains two parallel groups that align * // the contents along the baseline. The first parallel group contains * // the first label and text field, and the second parallel group contains * // the second label and text field. By using a sequential group * // the labels and text fields are positioned vertically after one another. * vGroup.addGroup(layout.createParallelGroup(Alignment.BASELINE). * addComponent(label1).addComponent(tf1)); * vGroup.addGroup(layout.createParallelGroup(Alignment.BASELINE). * addComponent(label2).addComponent(tf2)); * layout.setVerticalGroup(vGroup); * </pre> * <p> * When run the following is produced. * <p align="center"> * <img src="doc-files/groupLayout.example.png"> * <p> * This layout consists of the following. * <ul><li>The horizontal axis consists of a sequential group containing two * parallel groups. The first parallel group contains the labels, * and the second parallel group contains the text fields. * <li>The vertical axis consists of a sequential group * containing two parallel groups. The parallel groups are configured * to align their components along the baseline. The first parallel * group contains the first label and first text field, and * the second group consists of the second label and second * text field. * </ul> * There are a couple of things to notice in this code: * <ul> * <li>You need not explicitly add the components to the container; this * is indirectly done by using one of the {@code add} methods of * {@code Group}. * <li>The various {@code add} methods return * the caller. This allows for easy chaining of invocations. For * example, {@code group.addComponent(label1).addComponent(label2);} is * equivalent to * {@code group.addComponent(label1); group.addComponent(label2);}. * <li>There are no public constructors for {@code Group}s; instead * use the create methods of {@code GroupLayout}. * </ul> * * @author Tomas Pavek * @author Jan Stola * @author Scott Violet * @since 1.6 */
public class GroupLayout implements LayoutManager2 { // Used in size calculations private static final int MIN_SIZE = 0; private static final int PREF_SIZE = 1; private static final int MAX_SIZE = 2; // Used by prepare, indicates min, pref or max isn't going to be used. private static final int SPECIFIC_SIZE = 3; private static final int UNSET = Integer.MIN_VALUE;
Indicates the size from the component or gap should be used for a particular range value.
See Also:
  • Group
/** * Indicates the size from the component or gap should be used for a * particular range value. * * @see Group */
public static final int DEFAULT_SIZE = -1;
Indicates the preferred size from the component or gap should be used for a particular range value.
See Also:
  • Group
/** * Indicates the preferred size from the component or gap should * be used for a particular range value. * * @see Group */
public static final int PREFERRED_SIZE = -2; // Whether or not we automatically try and create the preferred // padding between components. private boolean autocreatePadding; // Whether or not we automatically try and create the preferred // padding between components the touch the edge of the container and // the container. private boolean autocreateContainerPadding;
Group responsible for layout along the horizontal axis. This is NOT the user specified group, use getHorizontalGroup to dig that out.
/** * Group responsible for layout along the horizontal axis. This is NOT * the user specified group, use getHorizontalGroup to dig that out. */
private Group horizontalGroup;
Group responsible for layout along the vertical axis. This is NOT the user specified group, use getVerticalGroup to dig that out.
/** * Group responsible for layout along the vertical axis. This is NOT * the user specified group, use getVerticalGroup to dig that out. */
private Group verticalGroup; // Maps from Component to ComponentInfo. This is used for tracking // information specific to a Component. private Map<Component,ComponentInfo> componentInfos; // Container we're doing layout for. private Container host; // Used by areParallelSiblings, cached to avoid excessive garbage. private Set<Spring> tmpParallelSet; // Indicates Springs have changed in some way since last change. private boolean springsChanged; // Indicates invalidateLayout has been invoked. private boolean isValid; // Whether or not any preferred padding (or container padding) springs // exist private boolean hasPreferredPaddingSprings;
The LayoutStyle instance to use, if null the sharedInstance is used.
/** * The LayoutStyle instance to use, if null the sharedInstance is used. */
private LayoutStyle layoutStyle;
If true, components that are not visible are treated as though they aren't there.
/** * If true, components that are not visible are treated as though they * aren't there. */
private boolean honorsVisibility;
Enumeration of the possible ways ParallelGroup can align its children.
See Also:
Since:1.6
/** * Enumeration of the possible ways {@code ParallelGroup} can align * its children. * * @see #createParallelGroup(Alignment) * @since 1.6 */
public enum Alignment {
Indicates the elements should be aligned to the origin. For the horizontal axis with a left to right orientation this means aligned to the left edge. For the vertical axis leading means aligned to the top edge.
See Also:
  • createParallelGroup(Alignment)
/** * Indicates the elements should be * aligned to the origin. For the horizontal axis with a left to * right orientation this means aligned to the left edge. For the * vertical axis leading means aligned to the top edge. * * @see #createParallelGroup(Alignment) */
LEADING,
Indicates the elements should be aligned to the end of the region. For the horizontal axis with a left to right orientation this means aligned to the right edge. For the vertical axis trailing means aligned to the bottom edge.
See Also:
  • createParallelGroup(Alignment)
/** * Indicates the elements should be aligned to the end of the * region. For the horizontal axis with a left to right * orientation this means aligned to the right edge. For the * vertical axis trailing means aligned to the bottom edge. * * @see #createParallelGroup(Alignment) */
TRAILING,
Indicates the elements should be centered in the region.
See Also:
  • createParallelGroup(Alignment)
/** * Indicates the elements should be centered in * the region. * * @see #createParallelGroup(Alignment) */
CENTER,
Indicates the elements should be aligned along their baseline.
See Also:
/** * Indicates the elements should be aligned along * their baseline. * * @see #createParallelGroup(Alignment) * @see #createBaselineGroup(boolean,boolean) */
BASELINE } private static void checkSize(int min, int pref, int max, boolean isComponentSpring) { checkResizeType(min, isComponentSpring); if (!isComponentSpring && pref < 0) { throw new IllegalArgumentException("Pref must be >= 0"); } else if (isComponentSpring) { checkResizeType(pref, true); } checkResizeType(max, isComponentSpring); checkLessThan(min, pref); checkLessThan(pref, max); } private static void checkResizeType(int type, boolean isComponentSpring) { if (type < 0 && ((isComponentSpring && type != DEFAULT_SIZE && type != PREFERRED_SIZE) || (!isComponentSpring && type != PREFERRED_SIZE))) { throw new IllegalArgumentException("Invalid size"); } } private static void checkLessThan(int min, int max) { if (min >= 0 && max >= 0 && min > max) { throw new IllegalArgumentException( "Following is not met: min<=pref<=max"); } }
Creates a GroupLayout for the specified Container.
Params:
  • host – the Container the GroupLayout is the LayoutManager for
Throws:
/** * Creates a {@code GroupLayout} for the specified {@code Container}. * * @param host the {@code Container} the {@code GroupLayout} is * the {@code LayoutManager} for * @throws IllegalArgumentException if host is {@code null} */
public GroupLayout(Container host) { if (host == null) { throw new IllegalArgumentException("Container must be non-null"); } honorsVisibility = true; this.host = host; setHorizontalGroup(createParallelGroup(Alignment.LEADING, true)); setVerticalGroup(createParallelGroup(Alignment.LEADING, true)); componentInfos = new HashMap<Component,ComponentInfo>(); tmpParallelSet = new HashSet<Spring>(); }
Sets whether component visiblity is considered when sizing and positioning components. A value of true indicates that non-visible components should not be treated as part of the layout. A value of false indicates that components should be positioned and sized regardless of visibility.

A value of false is useful when the visibility of components is dynamically adjusted and you don't want surrounding components and the sizing to change.

The specified value is used for components that do not have an explicit visibility specified.

The default is true.

Params:
  • honorsVisibility – whether component visiblity is considered when sizing and positioning components
See Also:
/** * Sets whether component visiblity is considered when sizing and * positioning components. A value of {@code true} indicates that * non-visible components should not be treated as part of the * layout. A value of {@code false} indicates that components should be * positioned and sized regardless of visibility. * <p> * A value of {@code false} is useful when the visibility of components * is dynamically adjusted and you don't want surrounding components and * the sizing to change. * <p> * The specified value is used for components that do not have an * explicit visibility specified. * <p> * The default is {@code true}. * * @param honorsVisibility whether component visiblity is considered when * sizing and positioning components * @see #setHonorsVisibility(Component,Boolean) */
public void setHonorsVisibility(boolean honorsVisibility) { if (this.honorsVisibility != honorsVisibility) { this.honorsVisibility = honorsVisibility; springsChanged = true; isValid = false; invalidateHost(); } }
Returns whether component visiblity is considered when sizing and positioning components.
Returns:whether component visiblity is considered when sizing and positioning components
/** * Returns whether component visiblity is considered when sizing and * positioning components. * * @return whether component visiblity is considered when sizing and * positioning components */
public boolean getHonorsVisibility() { return honorsVisibility; }
Sets whether the component's visiblity is considered for sizing and positioning. A value of Boolean.TRUE indicates that if component is not visible it should not be treated as part of the layout. A value of false indicates that component is positioned and sized regardless of it's visibility. A value of null indicates the value specified by the single argument method setHonorsVisibility should be used.

If component is not a child of the Container this GroupLayout is managine, it will be added to the Container.

Params:
  • component – the component
  • honorsVisibility – whether component's visiblity should be considered for sizing and positioning
Throws:
See Also:
/** * Sets whether the component's visiblity is considered for * sizing and positioning. A value of {@code Boolean.TRUE} * indicates that if {@code component} is not visible it should * not be treated as part of the layout. A value of {@code false} * indicates that {@code component} is positioned and sized * regardless of it's visibility. A value of {@code null} * indicates the value specified by the single argument method {@code * setHonorsVisibility} should be used. * <p> * If {@code component} is not a child of the {@code Container} this * {@code GroupLayout} is managine, it will be added to the * {@code Container}. * * @param component the component * @param honorsVisibility whether {@code component}'s visiblity should be * considered for sizing and positioning * @throws IllegalArgumentException if {@code component} is {@code null} * @see #setHonorsVisibility(Component,Boolean) */
public void setHonorsVisibility(Component component, Boolean honorsVisibility) { if (component == null) { throw new IllegalArgumentException("Component must be non-null"); } getComponentInfo(component).setHonorsVisibility(honorsVisibility); springsChanged = true; isValid = false; invalidateHost(); }
Sets whether a gap between components should automatically be created. For example, if this is true and you add two components to a SequentialGroup a gap between the two components is automatically be created. The default is false.
Params:
  • autoCreatePadding – whether a gap between components is automatically created
/** * Sets whether a gap between components should automatically be * created. For example, if this is {@code true} and you add two * components to a {@code SequentialGroup} a gap between the * two components is automatically be created. The default is * {@code false}. * * @param autoCreatePadding whether a gap between components is * automatically created */
public void setAutoCreateGaps(boolean autoCreatePadding) { if (this.autocreatePadding != autoCreatePadding) { this.autocreatePadding = autoCreatePadding; invalidateHost(); } }
Returns true if gaps between components are automatically created.
Returns:true if gaps between components are automatically created
/** * Returns {@code true} if gaps between components are automatically * created. * * @return {@code true} if gaps between components are automatically * created */
public boolean getAutoCreateGaps() { return autocreatePadding; }
Sets whether a gap between the container and components that touch the border of the container should automatically be created. The default is false.
Params:
  • autoCreateContainerPadding – whether a gap between the container and components that touch the border of the container should automatically be created
/** * Sets whether a gap between the container and components that * touch the border of the container should automatically be * created. The default is {@code false}. * * @param autoCreateContainerPadding whether a gap between the container and * components that touch the border of the container should * automatically be created */
public void setAutoCreateContainerGaps(boolean autoCreateContainerPadding){ if (this.autocreateContainerPadding != autoCreateContainerPadding) { this.autocreateContainerPadding = autoCreateContainerPadding; horizontalGroup = createTopLevelGroup(getHorizontalGroup()); verticalGroup = createTopLevelGroup(getVerticalGroup()); invalidateHost(); } }
Returns true if gaps between the container and components that border the container are automatically created.
Returns:true if gaps between the container and components that border the container are automatically created
/** * Returns {@code true} if gaps between the container and components that * border the container are automatically created. * * @return {@code true} if gaps between the container and components that * border the container are automatically created */
public boolean getAutoCreateContainerGaps() { return autocreateContainerPadding; }
Sets the Group that positions and sizes components along the horizontal axis.
Params:
  • group – the Group that positions and sizes components along the horizontal axis
Throws:
/** * Sets the {@code Group} that positions and sizes * components along the horizontal axis. * * @param group the {@code Group} that positions and sizes * components along the horizontal axis * @throws IllegalArgumentException if group is {@code null} */
public void setHorizontalGroup(Group group) { if (group == null) { throw new IllegalArgumentException("Group must be non-null"); } horizontalGroup = createTopLevelGroup(group); invalidateHost(); }
Returns the Group that positions and sizes components along the horizontal axis.
Returns:the Group responsible for positioning and sizing component along the horizontal axis
/** * Returns the {@code Group} that positions and sizes components * along the horizontal axis. * * @return the {@code Group} responsible for positioning and * sizing component along the horizontal axis */
private Group getHorizontalGroup() { int index = 0; if (horizontalGroup.springs.size() > 1) { index = 1; } return (Group)horizontalGroup.springs.get(index); }
Sets the Group that positions and sizes components along the vertical axis.
Params:
  • group – the Group that positions and sizes components along the vertical axis
Throws:
/** * Sets the {@code Group} that positions and sizes * components along the vertical axis. * * @param group the {@code Group} that positions and sizes * components along the vertical axis * @throws IllegalArgumentException if group is {@code null} */
public void setVerticalGroup(Group group) { if (group == null) { throw new IllegalArgumentException("Group must be non-null"); } verticalGroup = createTopLevelGroup(group); invalidateHost(); }
Returns the Group that positions and sizes components along the vertical axis.
Returns:the Group responsible for positioning and sizing component along the vertical axis
/** * Returns the {@code Group} that positions and sizes components * along the vertical axis. * * @return the {@code Group} responsible for positioning and * sizing component along the vertical axis */
private Group getVerticalGroup() { int index = 0; if (verticalGroup.springs.size() > 1) { index = 1; } return (Group)verticalGroup.springs.get(index); }
Wraps the user specified group in a sequential group. If container gaps should be generated the necessary springs are added.
/** * Wraps the user specified group in a sequential group. If * container gaps should be generated the necessary springs are * added. */
private Group createTopLevelGroup(Group specifiedGroup) { SequentialGroup group = createSequentialGroup(); if (getAutoCreateContainerGaps()) { group.addSpring(new ContainerAutoPreferredGapSpring()); group.addGroup(specifiedGroup); group.addSpring(new ContainerAutoPreferredGapSpring()); } else { group.addGroup(specifiedGroup); } return group; }
Creates and returns a SequentialGroup.
Returns:a new SequentialGroup
/** * Creates and returns a {@code SequentialGroup}. * * @return a new {@code SequentialGroup} */
public SequentialGroup createSequentialGroup() { return new SequentialGroup(); }
Creates and returns a ParallelGroup with an alignment of Alignment.LEADING. This is a cover method for the more general createParallelGroup(Alignment) method.
See Also:
Returns:a new ParallelGroup
/** * Creates and returns a {@code ParallelGroup} with an alignment of * {@code Alignment.LEADING}. This is a cover method for the more * general {@code createParallelGroup(Alignment)} method. * * @return a new {@code ParallelGroup} * @see #createParallelGroup(Alignment) */
public ParallelGroup createParallelGroup() { return createParallelGroup(Alignment.LEADING); }
Creates and returns a ParallelGroup with the specified alignment. This is a cover method for the more general createParallelGroup(Alignment,boolean) method with true supplied for the second argument.
Params:
  • alignment – the alignment for the elements of the group
Throws:
See Also:
Returns:a new ParallelGroup
/** * Creates and returns a {@code ParallelGroup} with the specified * alignment. This is a cover method for the more general {@code * createParallelGroup(Alignment,boolean)} method with {@code true} * supplied for the second argument. * * @param alignment the alignment for the elements of the group * @throws IllegalArgumentException if {@code alignment} is {@code null} * @return a new {@code ParallelGroup} * @see #createBaselineGroup * @see ParallelGroup */
public ParallelGroup createParallelGroup(Alignment alignment) { return createParallelGroup(alignment, true); }
Creates and returns a ParallelGroup with the specified alignment and resize behavior. The alignment argument specifies how children elements are positioned that do not fill the group. For example, if a ParallelGroup with an alignment of TRAILING is given 100 and a child only needs 50, the child is positioned at the position 50 (with a component orientation of left-to-right).

Baseline alignment is only useful when used along the vertical axis. A ParallelGroup created with a baseline alignment along the horizontal axis is treated as LEADING.

Refer to ParallelGroup for details on the behavior of baseline groups.

Params:
  • alignment – the alignment for the elements of the group
  • resizable – true if the group is resizable; if the group is not resizable the preferred size is used for the minimum and maximum size of the group
Throws:
See Also:
Returns:a new ParallelGroup
/** * Creates and returns a {@code ParallelGroup} with the specified * alignment and resize behavior. The {@code * alignment} argument specifies how children elements are * positioned that do not fill the group. For example, if a {@code * ParallelGroup} with an alignment of {@code TRAILING} is given * 100 and a child only needs 50, the child is * positioned at the position 50 (with a component orientation of * left-to-right). * <p> * Baseline alignment is only useful when used along the vertical * axis. A {@code ParallelGroup} created with a baseline alignment * along the horizontal axis is treated as {@code LEADING}. * <p> * Refer to {@link GroupLayout.ParallelGroup ParallelGroup} for details on * the behavior of baseline groups. * * @param alignment the alignment for the elements of the group * @param resizable {@code true} if the group is resizable; if the group * is not resizable the preferred size is used for the * minimum and maximum size of the group * @throws IllegalArgumentException if {@code alignment} is {@code null} * @return a new {@code ParallelGroup} * @see #createBaselineGroup * @see GroupLayout.ParallelGroup */
public ParallelGroup createParallelGroup(Alignment alignment, boolean resizable){ if (alignment == Alignment.BASELINE) { return new BaselineGroup(resizable); } return new ParallelGroup(alignment, resizable); }
Creates and returns a ParallelGroup that aligns it's elements along the baseline.
Params:
  • resizable – whether the group is resizable
  • anchorBaselineToTop – whether the baseline is anchored to the top or bottom of the group
See Also:
/** * Creates and returns a {@code ParallelGroup} that aligns it's * elements along the baseline. * * @param resizable whether the group is resizable * @param anchorBaselineToTop whether the baseline is anchored to * the top or bottom of the group * @see #createBaselineGroup * @see ParallelGroup */
public ParallelGroup createBaselineGroup(boolean resizable, boolean anchorBaselineToTop) { return new BaselineGroup(resizable, anchorBaselineToTop); }
Forces the specified components to have the same size regardless of their preferred, minimum or maximum sizes. Components that are linked are given the maximum of the preferred size of each of the linked components. For example, if you link two components with a preferred width of 10 and 20, both components are given a width of 20.

This can be used multiple times to force any number of components to share the same size.

Linked Components are not be resizable.

Params:
  • components – the Components that are to have the same size
Throws:
See Also:
/** * Forces the specified components to have the same size * regardless of their preferred, minimum or maximum sizes. Components that * are linked are given the maximum of the preferred size of each of * the linked components. For example, if you link two components with * a preferred width of 10 and 20, both components are given a width of 20. * <p> * This can be used multiple times to force any number of * components to share the same size. * <p> * Linked Components are not be resizable. * * @param components the {@code Component}s that are to have the same size * @throws IllegalArgumentException if {@code components} is * {@code null}, or contains {@code null} * @see #linkSize(int,Component[]) */
public void linkSize(Component... components) { linkSize(SwingConstants.HORIZONTAL, components); linkSize(SwingConstants.VERTICAL, components); }
Forces the specified components to have the same size along the specified axis regardless of their preferred, minimum or maximum sizes. Components that are linked are given the maximum of the preferred size of each of the linked components. For example, if you link two components along the horizontal axis and the preferred width is 10 and 20, both components are given a width of 20.

This can be used multiple times to force any number of components to share the same size.

Linked Components are not be resizable.

Params:
  • components – the Components that are to have the same size
  • axis – the axis to link the size along; one of SwingConstants.HORIZONTAL or SwingConstans.VERTICAL
Throws:
  • IllegalArgumentException – if components is null, or contains null; or axis is not SwingConstants.HORIZONTAL or SwingConstants.VERTICAL
/** * Forces the specified components to have the same size along the * specified axis regardless of their preferred, minimum or * maximum sizes. Components that are linked are given the maximum * of the preferred size of each of the linked components. For * example, if you link two components along the horizontal axis * and the preferred width is 10 and 20, both components are given * a width of 20. * <p> * This can be used multiple times to force any number of * components to share the same size. * <p> * Linked {@code Component}s are not be resizable. * * @param components the {@code Component}s that are to have the same size * @param axis the axis to link the size along; one of * {@code SwingConstants.HORIZONTAL} or * {@code SwingConstans.VERTICAL} * @throws IllegalArgumentException if {@code components} is * {@code null}, or contains {@code null}; or {@code axis} * is not {@code SwingConstants.HORIZONTAL} or * {@code SwingConstants.VERTICAL} */
public void linkSize(int axis, Component... components) { if (components == null) { throw new IllegalArgumentException("Components must be non-null"); } for (int counter = components.length - 1; counter >= 0; counter--) { Component c = components[counter]; if (components[counter] == null) { throw new IllegalArgumentException( "Components must be non-null"); } // Force the component to be added getComponentInfo(c); } int glAxis; if (axis == SwingConstants.HORIZONTAL) { glAxis = HORIZONTAL; } else if (axis == SwingConstants.VERTICAL) { glAxis = VERTICAL; } else { throw new IllegalArgumentException("Axis must be one of " + "SwingConstants.HORIZONTAL or SwingConstants.VERTICAL"); } LinkInfo master = getComponentInfo( components[components.length - 1]).getLinkInfo(glAxis); for (int counter = components.length - 2; counter >= 0; counter--) { master.add(getComponentInfo(components[counter])); } invalidateHost(); }
Replaces an existing component with a new one.
Params:
  • existingComponent – the component that should be removed and replaced with newComponent
  • newComponent – the component to put in existingComponent's place
Throws:
  • IllegalArgumentException – if either of the components are null or existingComponent is not being managed by this layout manager
/** * Replaces an existing component with a new one. * * @param existingComponent the component that should be removed * and replaced with {@code newComponent} * @param newComponent the component to put in * {@code existingComponent}'s place * @throws IllegalArgumentException if either of the components are * {@code null} or {@code existingComponent} is not being managed * by this layout manager */
public void replace(Component existingComponent, Component newComponent) { if (existingComponent == null || newComponent == null) { throw new IllegalArgumentException("Components must be non-null"); } // Make sure all the components have been registered, otherwise we may // not update the correct Springs. if (springsChanged) { registerComponents(horizontalGroup, HORIZONTAL); registerComponents(verticalGroup, VERTICAL); } ComponentInfo info = componentInfos.remove(existingComponent); if (info == null) { throw new IllegalArgumentException("Component must already exist"); } host.remove(existingComponent); if (newComponent.getParent() != host) { host.add(newComponent); } info.setComponent(newComponent); componentInfos.put(newComponent, info); invalidateHost(); }
Sets the LayoutStyle used to calculate the preferred gaps between components. A value of null indicates the shared instance of LayoutStyle should be used.
Params:
  • layoutStyle – the LayoutStyle to use
See Also:
/** * Sets the {@code LayoutStyle} used to calculate the preferred * gaps between components. A value of {@code null} indicates the * shared instance of {@code LayoutStyle} should be used. * * @param layoutStyle the {@code LayoutStyle} to use * @see LayoutStyle */
public void setLayoutStyle(LayoutStyle layoutStyle) { this.layoutStyle = layoutStyle; invalidateHost(); }
Returns the LayoutStyle used for calculating the preferred gap between components. This returns the value specified to setLayoutStyle, which may be null.
Returns:the LayoutStyle used for calculating the preferred gap between components
/** * Returns the {@code LayoutStyle} used for calculating the preferred * gap between components. This returns the value specified to * {@code setLayoutStyle}, which may be {@code null}. * * @return the {@code LayoutStyle} used for calculating the preferred * gap between components */
public LayoutStyle getLayoutStyle() { return layoutStyle; } private LayoutStyle getLayoutStyle0() { LayoutStyle layoutStyle = getLayoutStyle(); if (layoutStyle == null) { layoutStyle = LayoutStyle.getInstance(); } return layoutStyle; } private void invalidateHost() { if (host instanceof JComponent) { ((JComponent)host).revalidate(); } else { host.invalidate(); } host.repaint(); } // // LayoutManager //
Notification that a Component has been added to the parent container. You should not invoke this method directly, instead you should use one of the Group methods to add a Component.
Params:
  • name – the string to be associated with the component
  • component – the Component to be added
/** * Notification that a {@code Component} has been added to * the parent container. You should not invoke this method * directly, instead you should use one of the {@code Group} * methods to add a {@code Component}. * * @param name the string to be associated with the component * @param component the {@code Component} to be added */
public void addLayoutComponent(String name, Component component) { }
Notification that a Component has been removed from the parent container. You should not invoke this method directly, instead invoke remove on the parent Container.
Params:
  • component – the component to be removed
See Also:
/** * Notification that a {@code Component} has been removed from * the parent container. You should not invoke this method * directly, instead invoke {@code remove} on the parent * {@code Container}. * * @param component the component to be removed * @see java.awt.Component#remove */
public void removeLayoutComponent(Component component) { ComponentInfo info = componentInfos.remove(component); if (info != null) { info.dispose(); springsChanged = true; isValid = false; } }
Returns the preferred size for the specified container.
Params:
  • parent – the container to return the preferred size for
Throws:
See Also:
Returns:the preferred size for parent
/** * Returns the preferred size for the specified container. * * @param parent the container to return the preferred size for * @return the preferred size for {@code parent} * @throws IllegalArgumentException if {@code parent} is not * the same {@code Container} this was created with * @throws IllegalStateException if any of the components added to * this layout are not in both a horizontal and vertical group * @see java.awt.Container#getPreferredSize */
public Dimension preferredLayoutSize(Container parent) { checkParent(parent); prepare(PREF_SIZE); return adjustSize(horizontalGroup.getPreferredSize(HORIZONTAL), verticalGroup.getPreferredSize(VERTICAL)); }
Returns the minimum size for the specified container.
Params:
  • parent – the container to return the size for
Throws:
See Also:
Returns:the minimum size for parent
/** * Returns the minimum size for the specified container. * * @param parent the container to return the size for * @return the minimum size for {@code parent} * @throws IllegalArgumentException if {@code parent} is not * the same {@code Container} that this was created with * @throws IllegalStateException if any of the components added to * this layout are not in both a horizontal and vertical group * @see java.awt.Container#getMinimumSize */
public Dimension minimumLayoutSize(Container parent) { checkParent(parent); prepare(MIN_SIZE); return adjustSize(horizontalGroup.getMinimumSize(HORIZONTAL), verticalGroup.getMinimumSize(VERTICAL)); }
Lays out the specified container.
Params:
  • parent – the container to be laid out
Throws:
  • IllegalStateException – if any of the components added to this layout are not in both a horizontal and vertical group
/** * Lays out the specified container. * * @param parent the container to be laid out * @throws IllegalStateException if any of the components added to * this layout are not in both a horizontal and vertical group */
public void layoutContainer(Container parent) { // Step 1: Prepare for layout. prepare(SPECIFIC_SIZE); Insets insets = parent.getInsets(); int width = parent.getWidth() - insets.left - insets.right; int height = parent.getHeight() - insets.top - insets.bottom; boolean ltr = isLeftToRight(); if (getAutoCreateGaps() || getAutoCreateContainerGaps() || hasPreferredPaddingSprings) { // Step 2: Calculate autopadding springs calculateAutopadding(horizontalGroup, HORIZONTAL, SPECIFIC_SIZE, 0, width); calculateAutopadding(verticalGroup, VERTICAL, SPECIFIC_SIZE, 0, height); } // Step 3: set the size of the groups. horizontalGroup.setSize(HORIZONTAL, 0, width); verticalGroup.setSize(VERTICAL, 0, height); // Step 4: apply the size to the components. for (ComponentInfo info : componentInfos.values()) { info.setBounds(insets, width, ltr); } } // // LayoutManager2 //
Notification that a Component has been added to the parent container. You should not invoke this method directly, instead you should use one of the Group methods to add a Component.
Params:
  • component – the component added
  • constraints – description of where to place the component
/** * Notification that a {@code Component} has been added to * the parent container. You should not invoke this method * directly, instead you should use one of the {@code Group} * methods to add a {@code Component}. * * @param component the component added * @param constraints description of where to place the component */
public void addLayoutComponent(Component component, Object constraints) { }
Returns the maximum size for the specified container.
Params:
  • parent – the container to return the size for
Throws:
See Also:
Returns:the maximum size for parent
/** * Returns the maximum size for the specified container. * * @param parent the container to return the size for * @return the maximum size for {@code parent} * @throws IllegalArgumentException if {@code parent} is not * the same {@code Container} that this was created with * @throws IllegalStateException if any of the components added to * this layout are not in both a horizontal and vertical group * @see java.awt.Container#getMaximumSize */
public Dimension maximumLayoutSize(Container parent) { checkParent(parent); prepare(MAX_SIZE); return adjustSize(horizontalGroup.getMaximumSize(HORIZONTAL), verticalGroup.getMaximumSize(VERTICAL)); }
Returns the alignment along the x axis. This specifies how the component would like to be aligned relative to other components. The value should be a number between 0 and 1 where 0 represents alignment along the origin, 1 is aligned the furthest away from the origin, 0.5 is centered, etc.
Params:
  • parent – the Container hosting this LayoutManager
Throws:
Returns:the alignment; this implementation returns .5
/** * Returns the alignment along the x axis. This specifies how * the component would like to be aligned relative to other * components. The value should be a number between 0 and 1 * where 0 represents alignment along the origin, 1 is aligned * the furthest away from the origin, 0.5 is centered, etc. * * @param parent the {@code Container} hosting this {@code LayoutManager} * @throws IllegalArgumentException if {@code parent} is not * the same {@code Container} that this was created with * @return the alignment; this implementation returns {@code .5} */
public float getLayoutAlignmentX(Container parent) { checkParent(parent); return .5f; }
Returns the alignment along the y axis. This specifies how the component would like to be aligned relative to other components. The value should be a number between 0 and 1 where 0 represents alignment along the origin, 1 is aligned the furthest away from the origin, 0.5 is centered, etc.
Params:
  • parent – the Container hosting this LayoutManager
Throws:
Returns:alignment; this implementation returns .5
/** * Returns the alignment along the y axis. This specifies how * the component would like to be aligned relative to other * components. The value should be a number between 0 and 1 * where 0 represents alignment along the origin, 1 is aligned * the furthest away from the origin, 0.5 is centered, etc. * * @param parent the {@code Container} hosting this {@code LayoutManager} * @throws IllegalArgumentException if {@code parent} is not * the same {@code Container} that this was created with * @return alignment; this implementation returns {@code .5} */
public float getLayoutAlignmentY(Container parent) { checkParent(parent); return .5f; }
Invalidates the layout, indicating that if the layout manager has cached information it should be discarded.
Params:
  • parent – the Container hosting this LayoutManager
Throws:
/** * Invalidates the layout, indicating that if the layout manager * has cached information it should be discarded. * * @param parent the {@code Container} hosting this LayoutManager * @throws IllegalArgumentException if {@code parent} is not * the same {@code Container} that this was created with */
public void invalidateLayout(Container parent) { checkParent(parent); // invalidateLayout is called from Container.invalidate, which // does NOT grab the treelock. All other methods do. To make sure // there aren't any possible threading problems we grab the tree lock // here. synchronized(parent.getTreeLock()) { isValid = false; } } private void prepare(int sizeType) { boolean visChanged = false; // Step 1: If not-valid, clear springs and update visibility. if (!isValid) { isValid = true; horizontalGroup.setSize(HORIZONTAL, UNSET, UNSET); verticalGroup.setSize(VERTICAL, UNSET, UNSET); for (ComponentInfo ci : componentInfos.values()) { if (ci.updateVisibility()) { visChanged = true; } ci.clearCachedSize(); } } // Step 2: Make sure components are bound to ComponentInfos if (springsChanged) { registerComponents(horizontalGroup, HORIZONTAL); registerComponents(verticalGroup, VERTICAL); } // Step 3: Adjust the autopadding. This removes existing // autopadding, then recalculates where it should go. if (springsChanged || visChanged) { checkComponents(); horizontalGroup.removeAutopadding(); verticalGroup.removeAutopadding(); if (getAutoCreateGaps()) { insertAutopadding(true); } else if (hasPreferredPaddingSprings || getAutoCreateContainerGaps()) { insertAutopadding(false); } springsChanged = false; } // Step 4: (for min/pref/max size calculations only) calculate the // autopadding. This invokes for unsetting the calculated values, then // recalculating them. // If sizeType == SPECIFIC_SIZE, it indicates we're doing layout, this // step will be done later on. if (sizeType != SPECIFIC_SIZE && (getAutoCreateGaps() || getAutoCreateContainerGaps() || hasPreferredPaddingSprings)) { calculateAutopadding(horizontalGroup, HORIZONTAL, sizeType, 0, 0); calculateAutopadding(verticalGroup, VERTICAL, sizeType, 0, 0); } } private void calculateAutopadding(Group group, int axis, int sizeType, int origin, int size) { group.unsetAutopadding(); switch(sizeType) { case MIN_SIZE: size = group.getMinimumSize(axis); break; case PREF_SIZE: size = group.getPreferredSize(axis); break; case MAX_SIZE: size = group.getMaximumSize(axis); break; default: break; } group.setSize(axis, origin, size); group.calculateAutopadding(axis); } private void checkComponents() { for (ComponentInfo info : componentInfos.values()) { if (info.horizontalSpring == null) { throw new IllegalStateException(info.component + " is not attached to a horizontal group"); } if (info.verticalSpring == null) { throw new IllegalStateException(info.component + " is not attached to a vertical group"); } } } private void registerComponents(Group group, int axis) { List<Spring> springs = group.springs; for (int counter = springs.size() - 1; counter >= 0; counter--) { Spring spring = springs.get(counter); if (spring instanceof ComponentSpring) { ((ComponentSpring)spring).installIfNecessary(axis); } else if (spring instanceof Group) { registerComponents((Group)spring, axis); } } } private Dimension adjustSize(int width, int height) { Insets insets = host.getInsets(); return new Dimension(width + insets.left + insets.right, height + insets.top + insets.bottom); } private void checkParent(Container parent) { if (parent != host) { throw new IllegalArgumentException( "GroupLayout can only be used with one Container at a time"); } }
Returns the ComponentInfo for the specified Component, creating one if necessary.
/** * Returns the {@code ComponentInfo} for the specified Component, * creating one if necessary. */
private ComponentInfo getComponentInfo(Component component) { ComponentInfo info = componentInfos.get(component); if (info == null) { info = new ComponentInfo(component); componentInfos.put(component, info); if (component.getParent() != host) { host.add(component); } } return info; }
Adjusts the autopadding springs for the horizontal and vertical groups. If insert is true this will insert auto padding springs, otherwise this will only adjust the springs that comprise auto preferred padding springs.
/** * Adjusts the autopadding springs for the horizontal and vertical * groups. If {@code insert} is {@code true} this will insert auto padding * springs, otherwise this will only adjust the springs that * comprise auto preferred padding springs. */
private void insertAutopadding(boolean insert) { horizontalGroup.insertAutopadding(HORIZONTAL, new ArrayList<AutoPreferredGapSpring>(1), new ArrayList<AutoPreferredGapSpring>(1), new ArrayList<ComponentSpring>(1), new ArrayList<ComponentSpring>(1), insert); verticalGroup.insertAutopadding(VERTICAL, new ArrayList<AutoPreferredGapSpring>(1), new ArrayList<AutoPreferredGapSpring>(1), new ArrayList<ComponentSpring>(1), new ArrayList<ComponentSpring>(1), insert); }
Returns true if the two Components have a common ParallelGroup ancestor along the particular axis.
/** * Returns {@code true} if the two Components have a common ParallelGroup * ancestor along the particular axis. */
private boolean areParallelSiblings(Component source, Component target, int axis) { ComponentInfo sourceInfo = getComponentInfo(source); ComponentInfo targetInfo = getComponentInfo(target); Spring sourceSpring; Spring targetSpring; if (axis == HORIZONTAL) { sourceSpring = sourceInfo.horizontalSpring; targetSpring = targetInfo.horizontalSpring; } else { sourceSpring = sourceInfo.verticalSpring; targetSpring = targetInfo.verticalSpring; } Set<Spring> sourcePath = tmpParallelSet; sourcePath.clear(); Spring spring = sourceSpring.getParent(); while (spring != null) { sourcePath.add(spring); spring = spring.getParent(); } spring = targetSpring.getParent(); while (spring != null) { if (sourcePath.contains(spring)) { sourcePath.clear(); while (spring != null) { if (spring instanceof ParallelGroup) { return true; } spring = spring.getParent(); } return false; } spring = spring.getParent(); } sourcePath.clear(); return false; } private boolean isLeftToRight() { return host.getComponentOrientation().isLeftToRight(); }
Returns a string representation of this GroupLayout. This method is intended to be used for debugging purposes, and the content and format of the returned string may vary between implementations.
Returns:a string representation of this GroupLayout
/** * Returns a string representation of this {@code GroupLayout}. * This method is intended to be used for debugging purposes, * and the content and format of the returned string may vary * between implementations. * * @return a string representation of this {@code GroupLayout} **/
public String toString() { if (springsChanged) { registerComponents(horizontalGroup, HORIZONTAL); registerComponents(verticalGroup, VERTICAL); } StringBuffer buffer = new StringBuffer(); buffer.append("HORIZONTAL\n"); createSpringDescription(buffer, horizontalGroup, " ", HORIZONTAL); buffer.append("\nVERTICAL\n"); createSpringDescription(buffer, verticalGroup, " ", VERTICAL); return buffer.toString(); } private void createSpringDescription(StringBuffer buffer, Spring spring, String indent, int axis) { String origin = ""; String padding = ""; if (spring instanceof ComponentSpring) { ComponentSpring cSpring = (ComponentSpring)spring; origin = Integer.toString(cSpring.getOrigin()) + " "; String name = cSpring.getComponent().getName(); if (name != null) { origin = "name=" + name + ", "; } } if (spring instanceof AutoPreferredGapSpring) { AutoPreferredGapSpring paddingSpring = (AutoPreferredGapSpring)spring; padding = ", userCreated=" + paddingSpring.getUserCreated() + ", matches=" + paddingSpring.getMatchDescription(); } buffer.append(indent + spring.getClass().getName() + " " + Integer.toHexString(spring.hashCode()) + " " + origin + ", size=" + spring.getSize() + ", alignment=" + spring.getAlignment() + " prefs=[" + spring.getMinimumSize(axis) + " " + spring.getPreferredSize(axis) + " " + spring.getMaximumSize(axis) + padding + "]\n"); if (spring instanceof Group) { List<Spring> springs = ((Group)spring).springs; indent += " "; for (int counter = 0; counter < springs.size(); counter++) { createSpringDescription(buffer, springs.get(counter), indent, axis); } } }
Spring consists of a range: min, pref and max, a value some where in the middle of that, and a location. Spring caches the min/max/pref. If the min/pref/max has internally changes, or needs to be updated you must invoke clear.
/** * Spring consists of a range: min, pref and max, a value some where in * the middle of that, and a location. Spring caches the * min/max/pref. If the min/pref/max has internally changes, or needs * to be updated you must invoke clear. */
private abstract class Spring { private int size; private int min; private int max; private int pref; private Spring parent; private Alignment alignment; Spring() { min = pref = max = UNSET; }
Calculates and returns the minimum size.
Params:
  • axis – the axis of layout; one of HORIZONTAL or VERTICAL
Returns:the minimum size
/** * Calculates and returns the minimum size. * * @param axis the axis of layout; one of HORIZONTAL or VERTICAL * @return the minimum size */
abstract int calculateMinimumSize(int axis);
Calculates and returns the preferred size.
Params:
  • axis – the axis of layout; one of HORIZONTAL or VERTICAL
Returns:the preferred size
/** * Calculates and returns the preferred size. * * @param axis the axis of layout; one of HORIZONTAL or VERTICAL * @return the preferred size */
abstract int calculatePreferredSize(int axis);
Calculates and returns the minimum size.
Params:
  • axis – the axis of layout; one of HORIZONTAL or VERTICAL
Returns:the minimum size
/** * Calculates and returns the minimum size. * * @param axis the axis of layout; one of HORIZONTAL or VERTICAL * @return the minimum size */
abstract int calculateMaximumSize(int axis);
Sets the parent of this Spring.
/** * Sets the parent of this Spring. */
void setParent(Spring parent) { this.parent = parent; }
Returns the parent of this spring.
/** * Returns the parent of this spring. */
Spring getParent() { return parent; } // This is here purely as a conveniance for ParallelGroup to avoid // having to track alignment separately. void setAlignment(Alignment alignment) { this.alignment = alignment; }
Alignment for this Spring, this may be null.
/** * Alignment for this Spring, this may be null. */
Alignment getAlignment() { return alignment; }
Returns the minimum size.
/** * Returns the minimum size. */
final int getMinimumSize(int axis) { if (min == UNSET) { min = constrain(calculateMinimumSize(axis)); } return min; }
Returns the preferred size.
/** * Returns the preferred size. */
final int getPreferredSize(int axis) { if (pref == UNSET) { pref = constrain(calculatePreferredSize(axis)); } return pref; }
Returns the maximum size.
/** * Returns the maximum size. */
final int getMaximumSize(int axis) { if (max == UNSET) { max = constrain(calculateMaximumSize(axis)); } return max; }
Sets the value and location of the spring. Subclasses will want to invoke super, then do any additional sizing.
Params:
  • axis – HORIZONTAL or VERTICAL
  • origin – of this Spring
  • size – of the Spring. If size is UNSET, this invokes clear.
/** * Sets the value and location of the spring. Subclasses * will want to invoke super, then do any additional sizing. * * @param axis HORIZONTAL or VERTICAL * @param origin of this Spring * @param size of the Spring. If size is UNSET, this invokes * clear. */
void setSize(int axis, int origin, int size) { this.size = size; if (size == UNSET) { unset(); } }
Resets the cached min/max/pref.
/** * Resets the cached min/max/pref. */
void unset() { size = min = pref = max = UNSET; }
Returns the current size.
/** * Returns the current size. */
int getSize() { return size; } int constrain(int value) { return Math.min(value, Short.MAX_VALUE); } int getBaseline() { return -1; } BaselineResizeBehavior getBaselineResizeBehavior() { return BaselineResizeBehavior.OTHER; } final boolean isResizable(int axis) { int min = getMinimumSize(axis); int pref = getPreferredSize(axis); return (min != pref || pref != getMaximumSize(axis)); }
Returns true if this spring will ALWAYS have a zero size. This should NOT check the current size, rather it's meant to quickly test if this Spring will always have a zero size.
Params:
  • treatAutopaddingAsZeroSized – if true, auto padding springs should be treated as having a size of 0
Returns:true if this spring will have a zero size, false otherwise
/** * Returns {@code true} if this spring will ALWAYS have a zero * size. This should NOT check the current size, rather it's * meant to quickly test if this Spring will always have a * zero size. * * @param treatAutopaddingAsZeroSized if {@code true}, auto padding * springs should be treated as having a size of {@code 0} * @return {@code true} if this spring will have a zero size, * {@code false} otherwise */
abstract boolean willHaveZeroSize(boolean treatAutopaddingAsZeroSized); }
Group provides the basis for the two types of operations supported by GroupLayout: laying out components one after another (SequentialGroup) or aligned (ParallelGroup). Group and its subclasses have no public constructor; to create one use one of createSequentialGroup or createParallelGroup. Additionally, taking a Group created from one GroupLayout and using it with another will produce undefined results.

Various methods in Group and its subclasses allow you to explicitly specify the range. The arguments to these methods can take two forms, either a value greater than or equal to 0, or one of DEFAULT_SIZE or PREFERRED_SIZE. A value greater than or equal to 0 indicates a specific size. DEFAULT_SIZE indicates the corresponding size from the component should be used. For example, if DEFAULT_SIZE is passed as the minimum size argument, the minimum size is obtained from invoking getMinimumSize on the component. Likewise, PREFERRED_SIZE indicates the value from getPreferredSize should be used. The following example adds myComponent to group with specific values for the range. That is, the minimum is explicitly specified as 100, preferred as 200, and maximum as 300.

  group.addComponent(myComponent, 100, 200, 300);
The following example adds myComponent to group using a combination of the forms. The minimum size is forced to be the same as the preferred size, the preferred size is determined by using myComponent.getPreferredSize and the maximum is determined by invoking getMaximumSize on the component.
  group.addComponent(myComponent, GroupLayout.PREFERRED_SIZE,
            GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE);

Unless otherwise specified all the methods of Group and its subclasses that allow you to specify a range throw an IllegalArgumentException if passed an invalid range. An invalid range is one in which any of the values are < 0 and not one of PREFERRED_SIZE or DEFAULT_SIZE, or the following is not met (for specific values): min <= pref <= max.

Similarly any methods that take a Component throw a NullPointerException if passed null and any methods that take a Group throw an IllegalArgumentException if passed null.

See Also:
Since:1.6
/** * {@code Group} provides the basis for the two types of * operations supported by {@code GroupLayout}: laying out * components one after another ({@link SequentialGroup SequentialGroup}) * or aligned ({@link ParallelGroup ParallelGroup}). {@code Group} and * its subclasses have no public constructor; to create one use * one of {@code createSequentialGroup} or * {@code createParallelGroup}. Additionally, taking a {@code Group} * created from one {@code GroupLayout} and using it with another * will produce undefined results. * <p> * Various methods in {@code Group} and its subclasses allow you * to explicitly specify the range. The arguments to these methods * can take two forms, either a value greater than or equal to 0, * or one of {@code DEFAULT_SIZE} or {@code PREFERRED_SIZE}. A * value greater than or equal to {@code 0} indicates a specific * size. {@code DEFAULT_SIZE} indicates the corresponding size * from the component should be used. For example, if {@code * DEFAULT_SIZE} is passed as the minimum size argument, the * minimum size is obtained from invoking {@code getMinimumSize} * on the component. Likewise, {@code PREFERRED_SIZE} indicates * the value from {@code getPreferredSize} should be used. * The following example adds {@code myComponent} to {@code group} * with specific values for the range. That is, the minimum is * explicitly specified as 100, preferred as 200, and maximum as * 300. * <pre> * group.addComponent(myComponent, 100, 200, 300); * </pre> * The following example adds {@code myComponent} to {@code group} using * a combination of the forms. The minimum size is forced to be the * same as the preferred size, the preferred size is determined by * using {@code myComponent.getPreferredSize} and the maximum is * determined by invoking {@code getMaximumSize} on the component. * <pre> * group.addComponent(myComponent, GroupLayout.PREFERRED_SIZE, * GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE); * </pre> * <p> * Unless otherwise specified all the methods of {@code Group} and * its subclasses that allow you to specify a range throw an * {@code IllegalArgumentException} if passed an invalid range. An * invalid range is one in which any of the values are &lt; 0 and * not one of {@code PREFERRED_SIZE} or {@code DEFAULT_SIZE}, or * the following is not met (for specific values): {@code min} * &lt;= {@code pref} &lt;= {@code max}. * <p> * Similarly any methods that take a {@code Component} throw a * {@code NullPointerException} if passed {@code null} and any methods * that take a {@code Group} throw an {@code IllegalArgumentException} if * passed {@code null}. * * @see #createSequentialGroup * @see #createParallelGroup * @since 1.6 */
public abstract class Group extends Spring { // private int origin; // private int size; List<Spring> springs; Group() { springs = new ArrayList<Spring>(); }
Adds a Group to this Group.
Params:
  • group – the Group to add
Returns:this Group
/** * Adds a {@code Group} to this {@code Group}. * * @param group the {@code Group} to add * @return this {@code Group} */
public Group addGroup(Group group) { return addSpring(group); }
Adds a Component to this Group.
Params:
  • component – the Component to add
Returns:this Group
/** * Adds a {@code Component} to this {@code Group}. * * @param component the {@code Component} to add * @return this {@code Group} */
public Group addComponent(Component component) { return addComponent(component, DEFAULT_SIZE, DEFAULT_SIZE, DEFAULT_SIZE); }
Adds a Component to this Group with the specified size.
Params:
  • component – the Component to add
  • min – the minimum size or one of DEFAULT_SIZE or PREFERRED_SIZE
  • pref – the preferred size or one of DEFAULT_SIZE or PREFERRED_SIZE
  • max – the maximum size or one of DEFAULT_SIZE or PREFERRED_SIZE
Returns:this Group
/** * Adds a {@code Component} to this {@code Group} * with the specified size. * * @param component the {@code Component} to add * @param min the minimum size or one of {@code DEFAULT_SIZE} or * {@code PREFERRED_SIZE} * @param pref the preferred size or one of {@code DEFAULT_SIZE} or * {@code PREFERRED_SIZE} * @param max the maximum size or one of {@code DEFAULT_SIZE} or * {@code PREFERRED_SIZE} * @return this {@code Group} */
public Group addComponent(Component component, int min, int pref, int max) { return addSpring(new ComponentSpring(component, min, pref, max)); }
Adds a rigid gap to this Group.
Params:
  • size – the size of the gap
Throws:
Returns:this Group
/** * Adds a rigid gap to this {@code Group}. * * @param size the size of the gap * @return this {@code Group} * @throws IllegalArgumentException if {@code size} is less than * {@code 0} */
public Group addGap(int size) { return addGap(size, size, size); }
Adds a gap to this Group with the specified size.
Params:
  • min – the minimum size of the gap
  • pref – the preferred size of the gap
  • max – the maximum size of the gap
Throws:
Returns:this Group
/** * Adds a gap to this {@code Group} with the specified size. * * @param min the minimum size of the gap * @param pref the preferred size of the gap * @param max the maximum size of the gap * @throws IllegalArgumentException if any of the values are * less than {@code 0} * @return this {@code Group} */
public Group addGap(int min, int pref, int max) { return addSpring(new GapSpring(min, pref, max)); } Spring getSpring(int index) { return springs.get(index); } int indexOf(Spring spring) { return springs.indexOf(spring); }
Adds the Spring to the list of Springs and returns the receiver.
/** * Adds the Spring to the list of {@code Spring}s and returns * the receiver. */
Group addSpring(Spring spring) { springs.add(spring); spring.setParent(this); if (!(spring instanceof AutoPreferredGapSpring) || !((AutoPreferredGapSpring)spring).getUserCreated()) { springsChanged = true; } return this; } // // Spring methods // void setSize(int axis, int origin, int size) { super.setSize(axis, origin, size); if (size == UNSET) { for (int counter = springs.size() - 1; counter >= 0; counter--) { getSpring(counter).setSize(axis, origin, size); } } else { setValidSize(axis, origin, size); } }
This is invoked from setSize if passed a value other than UNSET.
/** * This is invoked from {@code setSize} if passed a value * other than UNSET. */
abstract void setValidSize(int axis, int origin, int size); int calculateMinimumSize(int axis) { return calculateSize(axis, MIN_SIZE); } int calculatePreferredSize(int axis) { return calculateSize(axis, PREF_SIZE); } int calculateMaximumSize(int axis) { return calculateSize(axis, MAX_SIZE); }
Calculates the specified size. This is called from one of the getMinimumSize0, getPreferredSize0 or getMaximumSize0 methods. This will invoke to operator to combine the values.
/** * Calculates the specified size. This is called from * one of the {@code getMinimumSize0}, * {@code getPreferredSize0} or * {@code getMaximumSize0} methods. This will invoke * to {@code operator} to combine the values. */
int calculateSize(int axis, int type) { int count = springs.size(); if (count == 0) { return 0; } if (count == 1) { return getSpringSize(getSpring(0), axis, type); } int size = constrain(operator(getSpringSize(getSpring(0), axis, type), getSpringSize(getSpring(1), axis, type))); for (int counter = 2; counter < count; counter++) { size = constrain(operator(size, getSpringSize( getSpring(counter), axis, type))); } return size; } int getSpringSize(Spring spring, int axis, int type) { switch(type) { case MIN_SIZE: return spring.getMinimumSize(axis); case PREF_SIZE: return spring.getPreferredSize(axis); case MAX_SIZE: return spring.getMaximumSize(axis); } assert false; return 0; }
Used to compute how the two values representing two springs will be combined. For example, a group that layed things out one after the next would return a + b.
/** * Used to compute how the two values representing two springs * will be combined. For example, a group that layed things out * one after the next would return {@code a + b}. */
abstract int operator(int a, int b); // // Padding //
Adjusts the autopadding springs in this group and its children. If insert is true this will insert auto padding springs, otherwise this will only adjust the springs that comprise auto preferred padding springs.
Params:
  • axis – the axis of the springs; HORIZONTAL or VERTICAL
  • leadingPadding – List of AutopaddingSprings that occur before this Group
  • trailingPadding – any trailing autopadding springs are added to this on exit
  • leading – List of ComponentSprings that occur before this Group
  • trailing – any trailing ComponentSpring are added to this List
  • insert – Whether or not to insert AutopaddingSprings or just adjust any existing AutopaddingSprings.
/** * Adjusts the autopadding springs in this group and its children. * If {@code insert} is true this will insert auto padding * springs, otherwise this will only adjust the springs that * comprise auto preferred padding springs. * * @param axis the axis of the springs; HORIZONTAL or VERTICAL * @param leadingPadding List of AutopaddingSprings that occur before * this Group * @param trailingPadding any trailing autopadding springs are added * to this on exit * @param leading List of ComponentSprings that occur before this Group * @param trailing any trailing ComponentSpring are added to this * List * @param insert Whether or not to insert AutopaddingSprings or just * adjust any existing AutopaddingSprings. */
abstract void insertAutopadding(int axis, List<AutoPreferredGapSpring> leadingPadding, List<AutoPreferredGapSpring> trailingPadding, List<ComponentSpring> leading, List<ComponentSpring> trailing, boolean insert);
Removes any AutopaddingSprings for this Group and its children.
/** * Removes any AutopaddingSprings for this Group and its children. */
void removeAutopadding() { unset(); for (int counter = springs.size() - 1; counter >= 0; counter--) { Spring spring = springs.get(counter); if (spring instanceof AutoPreferredGapSpring) { if (((AutoPreferredGapSpring)spring).getUserCreated()) { ((AutoPreferredGapSpring)spring).reset(); } else { springs.remove(counter); } } else if (spring instanceof Group) { ((Group)spring).removeAutopadding(); } } } void unsetAutopadding() { // Clear cached pref/min/max. unset(); for (int counter = springs.size() - 1; counter >= 0; counter--) { Spring spring = springs.get(counter); if (spring instanceof AutoPreferredGapSpring) { spring.unset(); } else if (spring instanceof Group) { ((Group)spring).unsetAutopadding(); } } } void calculateAutopadding(int axis) { for (int counter = springs.size() - 1; counter >= 0; counter--) { Spring spring = springs.get(counter); if (spring instanceof AutoPreferredGapSpring) { // Force size to be reset. spring.unset(); ((AutoPreferredGapSpring)spring).calculatePadding(axis); } else if (spring instanceof Group) { ((Group)spring).calculateAutopadding(axis); } } // Clear cached pref/min/max. unset(); } @Override boolean willHaveZeroSize(boolean treatAutopaddingAsZeroSized) { for (int i = springs.size() - 1; i >= 0; i--) { Spring spring = springs.get(i); if (!spring.willHaveZeroSize(treatAutopaddingAsZeroSized)) { return false; } } return true; } }
A Group that positions and sizes its elements sequentially, one after another. This class has no public constructor, use the createSequentialGroup method to create one.

In order to align a SequentialGroup along the baseline of a baseline aligned ParallelGroup you need to specify which of the elements of the SequentialGroup is used to determine the baseline. The element used to calculate the baseline is specified using one of the add methods that take a boolean. The last element added with a value of true for useAsBaseline is used to calculate the baseline.

See Also:
Since:1.6
/** * A {@code Group} that positions and sizes its elements * sequentially, one after another. This class has no public * constructor, use the {@code createSequentialGroup} method * to create one. * <p> * In order to align a {@code SequentialGroup} along the baseline * of a baseline aligned {@code ParallelGroup} you need to specify * which of the elements of the {@code SequentialGroup} is used to * determine the baseline. The element used to calculate the * baseline is specified using one of the {@code add} methods that * take a {@code boolean}. The last element added with a value of * {@code true} for {@code useAsBaseline} is used to calculate the * baseline. * * @see #createSequentialGroup * @since 1.6 */
public class SequentialGroup extends Group { private Spring baselineSpring; SequentialGroup() { }
{@inheritDoc}
/** * {@inheritDoc} */
public SequentialGroup addGroup(Group group) { return (SequentialGroup)super.addGroup(group); }
Adds a Group to this Group.
Params:
  • group – the Group to add
  • useAsBaseline – whether the specified Group should be used to calculate the baseline for this Group
Returns:this Group
/** * Adds a {@code Group} to this {@code Group}. * * @param group the {@code Group} to add * @param useAsBaseline whether the specified {@code Group} should * be used to calculate the baseline for this {@code Group} * @return this {@code Group} */
public SequentialGroup addGroup(boolean useAsBaseline, Group group) { super.addGroup(group); if (useAsBaseline) { baselineSpring = group; } return this; }
{@inheritDoc}
/** * {@inheritDoc} */
public SequentialGroup addComponent(Component component) { return (SequentialGroup)super.addComponent(component); }
Adds a Component to this Group.
Params:
  • useAsBaseline – whether the specified Component should be used to calculate the baseline for this Group
  • component – the Component to add
Returns:this Group
/** * Adds a {@code Component} to this {@code Group}. * * @param useAsBaseline whether the specified {@code Component} should * be used to calculate the baseline for this {@code Group} * @param component the {@code Component} to add * @return this {@code Group} */
public SequentialGroup addComponent(boolean useAsBaseline, Component component) { super.addComponent(component); if (useAsBaseline) { baselineSpring = springs.get(springs.size() - 1); } return this; }
{@inheritDoc}
/** * {@inheritDoc} */
public SequentialGroup addComponent(Component component, int min, int pref, int max) { return (SequentialGroup)super.addComponent( component, min, pref, max); }
Adds a Component to this Group with the specified size.
Params:
  • useAsBaseline – whether the specified Component should be used to calculate the baseline for this Group
  • component – the Component to add
  • min – the minimum size or one of DEFAULT_SIZE or PREFERRED_SIZE
  • pref – the preferred size or one of DEFAULT_SIZE or PREFERRED_SIZE
  • max – the maximum size or one of DEFAULT_SIZE or PREFERRED_SIZE
Returns:this Group
/** * Adds a {@code Component} to this {@code Group} * with the specified size. * * @param useAsBaseline whether the specified {@code Component} should * be used to calculate the baseline for this {@code Group} * @param component the {@code Component} to add * @param min the minimum size or one of {@code DEFAULT_SIZE} or * {@code PREFERRED_SIZE} * @param pref the preferred size or one of {@code DEFAULT_SIZE} or * {@code PREFERRED_SIZE} * @param max the maximum size or one of {@code DEFAULT_SIZE} or * {@code PREFERRED_SIZE} * @return this {@code Group} */
public SequentialGroup addComponent(boolean useAsBaseline, Component component, int min, int pref, int max) { super.addComponent(component, min, pref, max); if (useAsBaseline) { baselineSpring = springs.get(springs.size() - 1); } return this; }
{@inheritDoc}
/** * {@inheritDoc} */
public SequentialGroup addGap(int size) { return (SequentialGroup)super.addGap(size); }
{@inheritDoc}
/** * {@inheritDoc} */
public SequentialGroup addGap(int min, int pref, int max) { return (SequentialGroup)super.addGap(min, pref, max); }
Adds an element representing the preferred gap between two components. The element created to represent the gap is not resizable.
Params:
  • comp1 – the first component
  • comp2 – the second component
  • type – the type of gap; one of the constants defined by LayoutStyle
Throws:
See Also:
Returns:this SequentialGroup
/** * Adds an element representing the preferred gap between two * components. The element created to represent the gap is not * resizable. * * @param comp1 the first component * @param comp2 the second component * @param type the type of gap; one of the constants defined by * {@code LayoutStyle} * @return this {@code SequentialGroup} * @throws IllegalArgumentException if {@code type}, {@code comp1} or * {@code comp2} is {@code null} * @see LayoutStyle */
public SequentialGroup addPreferredGap(JComponent comp1, JComponent comp2, ComponentPlacement type) { return addPreferredGap(comp1, comp2, type, DEFAULT_SIZE, PREFERRED_SIZE); }
Adds an element representing the preferred gap between two components.
Params:
  • comp1 – the first component
  • comp2 – the second component
  • type – the type of gap
  • pref – the preferred size of the grap; one of DEFAULT_SIZE or a value >= 0
  • max – the maximum size of the gap; one of DEFAULT_SIZE, PREFERRED_SIZE or a value >= 0
Throws:
See Also:
Returns:this SequentialGroup
/** * Adds an element representing the preferred gap between two * components. * * @param comp1 the first component * @param comp2 the second component * @param type the type of gap * @param pref the preferred size of the grap; one of * {@code DEFAULT_SIZE} or a value &gt;= 0 * @param max the maximum size of the gap; one of * {@code DEFAULT_SIZE}, {@code PREFERRED_SIZE} * or a value &gt;= 0 * @return this {@code SequentialGroup} * @throws IllegalArgumentException if {@code type}, {@code comp1} or * {@code comp2} is {@code null} * @see LayoutStyle */
public SequentialGroup addPreferredGap(JComponent comp1, JComponent comp2, ComponentPlacement type, int pref, int max) { if (type == null) { throw new IllegalArgumentException("Type must be non-null"); } if (comp1 == null || comp2 == null) { throw new IllegalArgumentException( "Components must be non-null"); } checkPreferredGapValues(pref, max); return (SequentialGroup)addSpring(new PreferredGapSpring( comp1, comp2, type, pref, max)); }
Adds an element representing the preferred gap between the nearest components. During layout, neighboring components are found, and the size of the added gap is set based on the preferred gap between the components. If no neighboring components are found the gap has a size of 0.

The element created to represent the gap is not resizable.

Params:
  • type – the type of gap; one of LayoutStyle.ComponentPlacement.RELATED or LayoutStyle.ComponentPlacement.UNRELATED
Throws:
  • IllegalArgumentException – if type is not one of LayoutStyle.ComponentPlacement.RELATED or LayoutStyle.ComponentPlacement.UNRELATED
See Also:
Returns:this SequentialGroup
/** * Adds an element representing the preferred gap between the * nearest components. During layout, neighboring * components are found, and the size of the added gap is set * based on the preferred gap between the components. If no * neighboring components are found the gap has a size of {@code 0}. * <p> * The element created to represent the gap is not * resizable. * * @param type the type of gap; one of * {@code LayoutStyle.ComponentPlacement.RELATED} or * {@code LayoutStyle.ComponentPlacement.UNRELATED} * @return this {@code SequentialGroup} * @see LayoutStyle * @throws IllegalArgumentException if {@code type} is not one of * {@code LayoutStyle.ComponentPlacement.RELATED} or * {@code LayoutStyle.ComponentPlacement.UNRELATED} */
public SequentialGroup addPreferredGap(ComponentPlacement type) { return addPreferredGap(type, DEFAULT_SIZE, DEFAULT_SIZE); }
Adds an element representing the preferred gap between the nearest components. During layout, neighboring components are found, and the minimum of this gap is set based on the size of the preferred gap between the neighboring components. If no neighboring components are found the minimum size is set to 0.
Params:
  • type – the type of gap; one of LayoutStyle.ComponentPlacement.RELATED or LayoutStyle.ComponentPlacement.UNRELATED
  • pref – the preferred size of the grap; one of DEFAULT_SIZE or a value >= 0
  • max – the maximum size of the gap; one of DEFAULT_SIZE, PREFERRED_SIZE or a value >= 0
Throws:
  • IllegalArgumentException – if type is not one of LayoutStyle.ComponentPlacement.RELATED or LayoutStyle.ComponentPlacement.UNRELATED
See Also:
Returns:this SequentialGroup
/** * Adds an element representing the preferred gap between the * nearest components. During layout, neighboring * components are found, and the minimum of this * gap is set based on the size of the preferred gap between the * neighboring components. If no neighboring components are found the * minimum size is set to 0. * * @param type the type of gap; one of * {@code LayoutStyle.ComponentPlacement.RELATED} or * {@code LayoutStyle.ComponentPlacement.UNRELATED} * @param pref the preferred size of the grap; one of * {@code DEFAULT_SIZE} or a value &gt;= 0 * @param max the maximum size of the gap; one of * {@code DEFAULT_SIZE}, {@code PREFERRED_SIZE} * or a value &gt;= 0 * @return this {@code SequentialGroup} * @throws IllegalArgumentException if {@code type} is not one of * {@code LayoutStyle.ComponentPlacement.RELATED} or * {@code LayoutStyle.ComponentPlacement.UNRELATED} * @see LayoutStyle */
public SequentialGroup addPreferredGap(ComponentPlacement type, int pref, int max) { if (type != ComponentPlacement.RELATED && type != ComponentPlacement.UNRELATED) { throw new IllegalArgumentException( "Type must be one of " + "LayoutStyle.ComponentPlacement.RELATED or " + "LayoutStyle.ComponentPlacement.UNRELATED"); } checkPreferredGapValues(pref, max); hasPreferredPaddingSprings = true; return (SequentialGroup)addSpring(new AutoPreferredGapSpring( type, pref, max)); }
Adds an element representing the preferred gap between an edge the container and components that touch the border of the container. This has no effect if the added gap does not touch an edge of the parent container.

The element created to represent the gap is not resizable.

Returns:this SequentialGroup
/** * Adds an element representing the preferred gap between an edge * the container and components that touch the border of the * container. This has no effect if the added gap does not * touch an edge of the parent container. * <p> * The element created to represent the gap is not * resizable. * * @return this {@code SequentialGroup} */
public SequentialGroup addContainerGap() { return addContainerGap(DEFAULT_SIZE, DEFAULT_SIZE); }
Adds an element representing the preferred gap between one edge of the container and the next or previous Component with the specified size. This has no effect if the next or previous element is not a Component and does not touch one edge of the parent container.
Params:
  • pref – the preferred size; one of DEFAULT_SIZE or a value >= 0
  • max – the maximum size; one of DEFAULT_SIZE, PREFERRED_SIZE or a value >= 0
Returns:this SequentialGroup
/** * Adds an element representing the preferred gap between one * edge of the container and the next or previous {@code * Component} with the specified size. This has no * effect if the next or previous element is not a {@code * Component} and does not touch one edge of the parent * container. * * @param pref the preferred size; one of {@code DEFAULT_SIZE} or a * value &gt;= 0 * @param max the maximum size; one of {@code DEFAULT_SIZE}, * {@code PREFERRED_SIZE} or a value &gt;= 0 * @return this {@code SequentialGroup} */
public SequentialGroup addContainerGap(int pref, int max) { if ((pref < 0 && pref != DEFAULT_SIZE) || (max < 0 && max != DEFAULT_SIZE && max != PREFERRED_SIZE)|| (pref >= 0 && max >= 0 && pref > max)) { throw new IllegalArgumentException( "Pref and max must be either DEFAULT_VALUE " + "or >= 0 and pref <= max"); } hasPreferredPaddingSprings = true; return (SequentialGroup)addSpring( new ContainerAutoPreferredGapSpring(pref, max)); } int operator(int a, int b) { return constrain(a) + constrain(b); } void setValidSize(int axis, int origin, int size) { int pref = getPreferredSize(axis); if (size == pref) { // Layout at preferred size for (Spring spring : springs) { int springPref = spring.getPreferredSize(axis); spring.setSize(axis, origin, springPref); origin += springPref; } } else if (springs.size() == 1) { Spring spring = getSpring(0); spring.setSize(axis, origin, Math.min( Math.max(size, spring.getMinimumSize(axis)), spring.getMaximumSize(axis))); } else if (springs.size() > 1) { // Adjust between min/pref setValidSizeNotPreferred(axis, origin, size); } } private void setValidSizeNotPreferred(int axis, int origin, int size) { int delta = size - getPreferredSize(axis); assert delta != 0; boolean useMin = (delta < 0); int springCount = springs.size(); if (useMin) { delta *= -1; } // The following algorithm if used for resizing springs: // 1. Calculate the resizability of each spring (pref - min or // max - pref) into a list. // 2. Sort the list in ascending order // 3. Iterate through each of the resizable Springs, attempting // to give them (pref - size) / resizeCount // 4. For any Springs that can not accomodate that much space // add the remainder back to the amount to distribute and // recalculate how must space the remaining springs will get. // 5. Set the size of the springs. // First pass, sort the resizable springs into the List resizable List<SpringDelta> resizable = buildResizableList(axis, useMin); int resizableCount = resizable.size(); if (resizableCount > 0) { // How much we would like to give each Spring. int sDelta = delta / resizableCount; // Remaining space. int slop = delta - sDelta * resizableCount; int[] sizes = new int[springCount]; int sign = useMin ? -1 : 1; // Second pass, accumulate the resulting deltas (relative to // preferred) into sizes. for (int counter = 0; counter < resizableCount; counter++) { SpringDelta springDelta = resizable.get(counter); if ((counter + 1) == resizableCount) { sDelta += slop; } springDelta.delta = Math.min(sDelta, springDelta.delta); delta -= springDelta.delta; if (springDelta.delta != sDelta && counter + 1 < resizableCount) { // Spring didn't take all the space, reset how much // each spring will get. sDelta = delta / (resizableCount - counter - 1); slop = delta - sDelta * (resizableCount - counter - 1); } sizes[springDelta.index] = sign * springDelta.delta; } // And finally set the size of each spring for (int counter = 0; counter < springCount; counter++) { Spring spring = getSpring(counter); int sSize = spring.getPreferredSize(axis) + sizes[counter]; spring.setSize(axis, origin, sSize); origin += sSize; } } else { // Nothing resizable, use the min or max of each of the // springs. for (int counter = 0; counter < springCount; counter++) { Spring spring = getSpring(counter); int sSize; if (useMin) { sSize = spring.getMinimumSize(axis); } else { sSize = spring.getMaximumSize(axis); } spring.setSize(axis, origin, sSize); origin += sSize; } } }
Returns the sorted list of SpringDelta's for the current set of Springs. The list is ordered based on the amount of flexibility of the springs.
/** * Returns the sorted list of SpringDelta's for the current set of * Springs. The list is ordered based on the amount of flexibility of * the springs. */
private List<SpringDelta> buildResizableList(int axis, boolean useMin) { // First pass, figure out what is resizable int size = springs.size(); List<SpringDelta> sorted = new ArrayList<SpringDelta>(size); for (int counter = 0; counter < size; counter++) { Spring spring = getSpring(counter); int sDelta; if (useMin) { sDelta = spring.getPreferredSize(axis) - spring.getMinimumSize(axis); } else { sDelta = spring.getMaximumSize(axis) - spring.getPreferredSize(axis); } if (sDelta > 0) { sorted.add(new SpringDelta(counter, sDelta)); } } Collections.sort(sorted); return sorted; } private int indexOfNextNonZeroSpring( int index, boolean treatAutopaddingAsZeroSized) { while (index < springs.size()) { Spring spring = springs.get(index); if (!spring.willHaveZeroSize(treatAutopaddingAsZeroSized)) { return index; } index++; } return index; } @Override void insertAutopadding(int axis, List<AutoPreferredGapSpring> leadingPadding, List<AutoPreferredGapSpring> trailingPadding, List<ComponentSpring> leading, List<ComponentSpring> trailing, boolean insert) { List<AutoPreferredGapSpring> newLeadingPadding = new ArrayList<AutoPreferredGapSpring>(leadingPadding); List<AutoPreferredGapSpring> newTrailingPadding = new ArrayList<AutoPreferredGapSpring>(1); List<ComponentSpring> newLeading = new ArrayList<ComponentSpring>(leading); List<ComponentSpring> newTrailing = null; int counter = 0; // Warning, this must use springs.size, as it may change during the // loop. while (counter < springs.size()) { Spring spring = getSpring(counter); if (spring instanceof AutoPreferredGapSpring) { if (newLeadingPadding.size() == 0) { // Autopadding spring. Set the sources of the // autopadding spring based on newLeading. AutoPreferredGapSpring padding = (AutoPreferredGapSpring)spring; padding.setSources(newLeading); newLeading.clear(); counter = indexOfNextNonZeroSpring(counter + 1, true); if (counter == springs.size()) { // Last spring in the list, add it to // trailingPadding. if (!(padding instanceof ContainerAutoPreferredGapSpring)) { trailingPadding.add(padding); } } else { newLeadingPadding.clear(); newLeadingPadding.add(padding); } } else { counter = indexOfNextNonZeroSpring(counter + 1, true); } } else { // Not a padding spring if (newLeading.size() > 0 && insert) { // There's leading ComponentSprings, create an // autopadding spring. AutoPreferredGapSpring padding = new AutoPreferredGapSpring(); // Force the newly created spring to be considered // by NOT incrementing counter springs.add(counter, padding); continue; } if (spring instanceof ComponentSpring) { // Spring is a Component, make it the target of any // leading AutopaddingSpring. ComponentSpring cSpring = (ComponentSpring)spring; if (!cSpring.isVisible()) { counter++; continue; } for (AutoPreferredGapSpring gapSpring : newLeadingPadding) { gapSpring.addTarget(cSpring, axis); } newLeading.clear(); newLeadingPadding.clear(); counter = indexOfNextNonZeroSpring(counter + 1, false); if (counter == springs.size()) { // Last Spring, add it to trailing trailing.add(cSpring); } else { // Not that last Spring, add it to leading newLeading.add(cSpring); } } else if (spring instanceof Group) { // Forward call to child Group if (newTrailing == null) { newTrailing = new ArrayList<ComponentSpring>(1); } else { newTrailing.clear(); } newTrailingPadding.clear(); ((Group)spring).insertAutopadding(axis, newLeadingPadding, newTrailingPadding, newLeading, newTrailing, insert); newLeading.clear(); newLeadingPadding.clear(); counter = indexOfNextNonZeroSpring( counter + 1, (newTrailing.size() == 0)); if (counter == springs.size()) { trailing.addAll(newTrailing); trailingPadding.addAll(newTrailingPadding); } else { newLeading.addAll(newTrailing); newLeadingPadding.addAll(newTrailingPadding); } } else { // Gap newLeadingPadding.clear(); newLeading.clear(); counter++; } } } } int getBaseline() { if (baselineSpring != null) { int baseline = baselineSpring.getBaseline(); if (baseline >= 0) { int size = 0; for (Spring spring : springs) { if (spring == baselineSpring) { return size + baseline; } else { size += spring.getPreferredSize(VERTICAL); } } } } return -1; } BaselineResizeBehavior getBaselineResizeBehavior() { if (isResizable(VERTICAL)) { if (!baselineSpring.isResizable(VERTICAL)) { // Spring to use for baseline isn't resizable. In this case // baseline resize behavior can be determined based on how // preceeding springs resize. boolean leadingResizable = false; for (Spring spring : springs) { if (spring == baselineSpring) { break; } else if (spring.isResizable(VERTICAL)) { leadingResizable = true; break; } } boolean trailingResizable = false; for (int i = springs.size() - 1; i >= 0; i--) { Spring spring = springs.get(i); if (spring == baselineSpring) { break; } if (spring.isResizable(VERTICAL)) { trailingResizable = true; break; } } if (leadingResizable && !trailingResizable) { return BaselineResizeBehavior.CONSTANT_DESCENT; } else if (!leadingResizable && trailingResizable) { return BaselineResizeBehavior.CONSTANT_ASCENT; } // If we get here, both leading and trailing springs are // resizable. Fall through to OTHER. } else { BaselineResizeBehavior brb = baselineSpring.getBaselineResizeBehavior(); if (brb == BaselineResizeBehavior.CONSTANT_ASCENT) { for (Spring spring : springs) { if (spring == baselineSpring) { return BaselineResizeBehavior.CONSTANT_ASCENT; } if (spring.isResizable(VERTICAL)) { return BaselineResizeBehavior.OTHER; } } } else if (brb == BaselineResizeBehavior.CONSTANT_DESCENT) { for (int i = springs.size() - 1; i >= 0; i--) { Spring spring = springs.get(i); if (spring == baselineSpring) { return BaselineResizeBehavior.CONSTANT_DESCENT; } if (spring.isResizable(VERTICAL)) { return BaselineResizeBehavior.OTHER; } } } } return BaselineResizeBehavior.OTHER; } // Not resizable, treat as constant_ascent return BaselineResizeBehavior.CONSTANT_ASCENT; } private void checkPreferredGapValues(int pref, int max) { if ((pref < 0 && pref != DEFAULT_SIZE && pref != PREFERRED_SIZE) || (max < 0 && max != DEFAULT_SIZE && max != PREFERRED_SIZE)|| (pref >= 0 && max >= 0 && pref > max)) { throw new IllegalArgumentException( "Pref and max must be either DEFAULT_SIZE, " + "PREFERRED_SIZE, or >= 0 and pref <= max"); } } }
Used by SequentialGroup in calculating resizability of springs.
/** * Used by SequentialGroup in calculating resizability of springs. */
private static final class SpringDelta implements Comparable<SpringDelta> { // Original index. public final int index; // Delta, one of pref - min or max - pref. public int delta; public SpringDelta(int index, int delta) { this.index = index; this.delta = delta; } public int compareTo(SpringDelta o) { return delta - o.delta; } public String toString() { return super.toString() + "[index=" + index + ", delta=" + delta + "]"; } }
A Group that aligns and sizes it's children. ParallelGroup aligns it's children in four possible ways: along the baseline, centered, anchored to the leading edge, or anchored to the trailing edge.

Baseline

A ParallelGroup that aligns it's children along the baseline must first decide where the baseline is anchored. The baseline can either be anchored to the top, or anchored to the bottom of the group. That is, the distance between the baseline and the beginning of the group can be a constant distance, or the distance between the end of the group and the baseline can be a constant distance. The possible choices correspond to the BaselineResizeBehavior constants CONSTANT_ASCENT and CONSTANT_DESCENT.

The baseline anchor may be explicitly specified by the createBaselineGroup method, or determined based on the elements. If not explicitly specified, the baseline will be anchored to the bottom if all the elements with a baseline, and that are aligned to the baseline, have a baseline resize behavior of CONSTANT_DESCENT; otherwise the baseline is anchored to the top of the group.

Elements aligned to the baseline are resizable if they have have a baseline resize behavior of CONSTANT_ASCENT or CONSTANT_DESCENT. Elements with a baseline resize behavior of OTHER or CENTER_OFFSET are not resizable.

The baseline is calculated based on the preferred height of each of the elements that have a baseline. The baseline is calculated using the following algorithm: max(maxNonBaselineHeight, maxAscent + maxDescent), where the maxNonBaselineHeight is the maximum height of all elements that do not have a baseline, or are not aligned along the baseline. maxAscent is the maximum ascent (baseline) of all elements that have a baseline and are aligned along the baseline. maxDescent is the maximum descent (preferred height - baseline) of all elements that have a baseline and are aligned along the baseline.

A ParallelGroup that aligns it's elements along the baseline is only useful along the vertical axis. If you create a baseline group and use it along the horizontal axis an IllegalStateException is thrown when you ask GroupLayout for the minimum, preferred or maximum size or attempt to layout the components.

Elements that are not aligned to the baseline and smaller than the size of the ParallelGroup are positioned in one of three ways: centered, anchored to the leading edge, or anchored to the trailing edge.

Non-baseline ParallelGroup

ParallelGroups created with an alignment other than BASELINE align elements that are smaller than the size of the group in one of three ways: centered, anchored to the leading edge, or anchored to the trailing edge.

The leading edge is based on the axis and ComponentOrientation. For the vertical axis the top edge is always the leading edge, and the bottom edge is always the trailing edge. When the ComponentOrientation is LEFT_TO_RIGHT, the leading edge is the left edge and the trailing edge the right edge. A ComponentOrientation of RIGHT_TO_LEFT flips the left and right edges. Child elements are aligned based on the specified alignment the element was added with. If you do not specify an alignment, the alignment specified for the ParallelGroup is used.

To align elements along the baseline you createBaselineGroup, or createParallelGroup with an alignment of BASELINE. If the group was not created with a baseline alignment, and you attempt to add an element specifying a baseline alignment, an IllegalArgumentException is thrown.

See Also:
Since:1.6
/** * A {@code Group} that aligns and sizes it's children. * {@code ParallelGroup} aligns it's children in * four possible ways: along the baseline, centered, anchored to the * leading edge, or anchored to the trailing edge. * <h3>Baseline</h3> * A {@code ParallelGroup} that aligns it's children along the * baseline must first decide where the baseline is * anchored. The baseline can either be anchored to the top, or * anchored to the bottom of the group. That is, the distance between the * baseline and the beginning of the group can be a constant * distance, or the distance between the end of the group and the * baseline can be a constant distance. The possible choices * correspond to the {@code BaselineResizeBehavior} constants * {@link * java.awt.Component.BaselineResizeBehavior#CONSTANT_ASCENT CONSTANT_ASCENT} and * {@link * java.awt.Component.BaselineResizeBehavior#CONSTANT_DESCENT CONSTANT_DESCENT}. * <p> * The baseline anchor may be explicitly specified by the * {@code createBaselineGroup} method, or determined based on the elements. * If not explicitly specified, the baseline will be anchored to * the bottom if all the elements with a baseline, and that are * aligned to the baseline, have a baseline resize behavior of * {@code CONSTANT_DESCENT}; otherwise the baseline is anchored to the top * of the group. * <p> * Elements aligned to the baseline are resizable if they have have * a baseline resize behavior of {@code CONSTANT_ASCENT} or * {@code CONSTANT_DESCENT}. Elements with a baseline resize * behavior of {@code OTHER} or {@code CENTER_OFFSET} are not resizable. * <p> * The baseline is calculated based on the preferred height of each * of the elements that have a baseline. The baseline is * calculated using the following algorithm: * {@code max(maxNonBaselineHeight, maxAscent + maxDescent)}, where the * {@code maxNonBaselineHeight} is the maximum height of all elements * that do not have a baseline, or are not aligned along the baseline. * {@code maxAscent} is the maximum ascent (baseline) of all elements that * have a baseline and are aligned along the baseline. * {@code maxDescent} is the maximum descent (preferred height - baseline) * of all elements that have a baseline and are aligned along the baseline. * <p> * A {@code ParallelGroup} that aligns it's elements along the baseline * is only useful along the vertical axis. If you create a * baseline group and use it along the horizontal axis an * {@code IllegalStateException} is thrown when you ask * {@code GroupLayout} for the minimum, preferred or maximum size or * attempt to layout the components. * <p> * Elements that are not aligned to the baseline and smaller than the size * of the {@code ParallelGroup} are positioned in one of three * ways: centered, anchored to the leading edge, or anchored to the * trailing edge. * * <h3>Non-baseline {@code ParallelGroup}</h3> * {@code ParallelGroup}s created with an alignment other than * {@code BASELINE} align elements that are smaller than the size * of the group in one of three ways: centered, anchored to the * leading edge, or anchored to the trailing edge. * <p> * The leading edge is based on the axis and {@code * ComponentOrientation}. For the vertical axis the top edge is * always the leading edge, and the bottom edge is always the * trailing edge. When the {@code ComponentOrientation} is {@code * LEFT_TO_RIGHT}, the leading edge is the left edge and the * trailing edge the right edge. A {@code ComponentOrientation} of * {@code RIGHT_TO_LEFT} flips the left and right edges. Child * elements are aligned based on the specified alignment the * element was added with. If you do not specify an alignment, the * alignment specified for the {@code ParallelGroup} is used. * <p> * To align elements along the baseline you {@code createBaselineGroup}, * or {@code createParallelGroup} with an alignment of {@code BASELINE}. * If the group was not created with a baseline alignment, and you attempt * to add an element specifying a baseline alignment, an * {@code IllegalArgumentException} is thrown. * * @see #createParallelGroup() * @see #createBaselineGroup(boolean,boolean) * @since 1.6 */
public class ParallelGroup extends Group { // How children are layed out. private final Alignment childAlignment; // Whether or not we're resizable. private final boolean resizable; ParallelGroup(Alignment childAlignment, boolean resizable) { this.childAlignment = childAlignment; this.resizable = resizable; }
{@inheritDoc}
/** * {@inheritDoc} */
public ParallelGroup addGroup(Group group) { return (ParallelGroup)super.addGroup(group); }
{@inheritDoc}
/** * {@inheritDoc} */
public ParallelGroup addComponent(Component component) { return (ParallelGroup)super.addComponent(component); }
{@inheritDoc}
/** * {@inheritDoc} */
public ParallelGroup addComponent(Component component, int min, int pref, int max) { return (ParallelGroup)super.addComponent(component, min, pref, max); }
{@inheritDoc}
/** * {@inheritDoc} */
public ParallelGroup addGap(int pref) { return (ParallelGroup)super.addGap(pref); }
{@inheritDoc}
/** * {@inheritDoc} */
public ParallelGroup addGap(int min, int pref, int max) { return (ParallelGroup)super.addGap(min, pref, max); }
Adds a Group to this ParallelGroup with the specified alignment. If the child is smaller than the Group it is aligned based on the specified alignment.
Params:
  • alignment – the alignment
  • group – the Group to add
Throws:
Returns:this ParallelGroup
/** * Adds a {@code Group} to this {@code ParallelGroup} with the * specified alignment. If the child is smaller than the * {@code Group} it is aligned based on the specified * alignment. * * @param alignment the alignment * @param group the {@code Group} to add * @return this {@code ParallelGroup} * @throws IllegalArgumentException if {@code alignment} is * {@code null} */
public ParallelGroup addGroup(Alignment alignment, Group group) { checkChildAlignment(alignment); group.setAlignment(alignment); return (ParallelGroup)addSpring(group); }
Adds a Component to this ParallelGroup with the specified alignment.
Params:
  • alignment – the alignment
  • component – the Component to add
Throws:
Returns:this Group
/** * Adds a {@code Component} to this {@code ParallelGroup} with * the specified alignment. * * @param alignment the alignment * @param component the {@code Component} to add * @return this {@code Group} * @throws IllegalArgumentException if {@code alignment} is * {@code null} */
public ParallelGroup addComponent(Component component, Alignment alignment) { return addComponent(component, alignment, DEFAULT_SIZE, DEFAULT_SIZE, DEFAULT_SIZE); }
Adds a Component to this ParallelGroup with the specified alignment and size.
Params:
  • alignment – the alignment
  • component – the Component to add
  • min – the minimum size
  • pref – the preferred size
  • max – the maximum size
Throws:
Returns:this Group
/** * Adds a {@code Component} to this {@code ParallelGroup} with the * specified alignment and size. * * @param alignment the alignment * @param component the {@code Component} to add * @param min the minimum size * @param pref the preferred size * @param max the maximum size * @throws IllegalArgumentException if {@code alignment} is * {@code null} * @return this {@code Group} */
public ParallelGroup addComponent(Component component, Alignment alignment, int min, int pref, int max) { checkChildAlignment(alignment); ComponentSpring spring = new ComponentSpring(component, min, pref, max); spring.setAlignment(alignment); return (ParallelGroup)addSpring(spring); } boolean isResizable() { return resizable; } int operator(int a, int b) { return Math.max(a, b); } int calculateMinimumSize(int axis) { if (!isResizable()) { return getPreferredSize(axis); } return super.calculateMinimumSize(axis); } int calculateMaximumSize(int axis) { if (!isResizable()) { return getPreferredSize(axis); } return super.calculateMaximumSize(axis); } void setValidSize(int axis, int origin, int size) { for (Spring spring : springs) { setChildSize(spring, axis, origin, size); } } void setChildSize(Spring spring, int axis, int origin, int size) { Alignment alignment = spring.getAlignment(); int springSize = Math.min( Math.max(spring.getMinimumSize(axis), size), spring.getMaximumSize(axis)); if (alignment == null) { alignment = childAlignment; } switch (alignment) { case TRAILING: spring.setSize(axis, origin + size - springSize, springSize); break; case CENTER: spring.setSize(axis, origin + (size - springSize) / 2,springSize); break; default: // LEADING, or BASELINE spring.setSize(axis, origin, springSize); break; } } @Override void insertAutopadding(int axis, List<AutoPreferredGapSpring> leadingPadding, List<AutoPreferredGapSpring> trailingPadding, List<ComponentSpring> leading, List<ComponentSpring> trailing, boolean insert) { for (Spring spring : springs) { if (spring instanceof ComponentSpring) { if (((ComponentSpring)spring).isVisible()) { for (AutoPreferredGapSpring gapSpring : leadingPadding) { gapSpring.addTarget((ComponentSpring)spring, axis); } trailing.add((ComponentSpring)spring); } } else if (spring instanceof Group) { ((Group)spring).insertAutopadding(axis, leadingPadding, trailingPadding, leading, trailing, insert); } else if (spring instanceof AutoPreferredGapSpring) { ((AutoPreferredGapSpring)spring).setSources(leading); trailingPadding.add((AutoPreferredGapSpring)spring); } } } private void checkChildAlignment(Alignment alignment) { checkChildAlignment(alignment, (this instanceof BaselineGroup)); } private void checkChildAlignment(Alignment alignment, boolean allowsBaseline) { if (alignment == null) { throw new IllegalArgumentException("Alignment must be non-null"); } if (!allowsBaseline && alignment == Alignment.BASELINE) { throw new IllegalArgumentException("Alignment must be one of:" + "LEADING, TRAILING or CENTER"); } } }
An extension of ParallelGroup that aligns its constituent Springs along the baseline.
/** * An extension of {@code ParallelGroup} that aligns its * constituent {@code Spring}s along the baseline. */
private class BaselineGroup extends ParallelGroup { // Whether or not all child springs have a baseline private boolean allSpringsHaveBaseline; // max(spring.getBaseline()) of all springs aligned along the baseline // that have a baseline private int prefAscent; // max(spring.getPreferredSize().height - spring.getBaseline()) of all // springs aligned along the baseline that have a baseline private int prefDescent; // Whether baselineAnchoredToTop was explicitly set private boolean baselineAnchorSet; // Whether the baseline is anchored to the top or the bottom. // If anchored to the top the baseline is always at prefAscent, // otherwise the baseline is at (height - prefDescent) private boolean baselineAnchoredToTop; // Whether or not the baseline has been calculated. private boolean calcedBaseline; BaselineGroup(boolean resizable) { super(Alignment.LEADING, resizable); prefAscent = prefDescent = -1; calcedBaseline = false; } BaselineGroup(boolean resizable, boolean baselineAnchoredToTop) { this(resizable); this.baselineAnchoredToTop = baselineAnchoredToTop; baselineAnchorSet = true; } void unset() { super.unset(); prefAscent = prefDescent = -1; calcedBaseline = false; } void setValidSize(int axis, int origin, int size) { checkAxis(axis); if (prefAscent == -1) { super.setValidSize(axis, origin, size); } else { // do baseline layout baselineLayout(origin, size); } } int calculateSize(int axis, int type) { checkAxis(axis); if (!calcedBaseline) { calculateBaselineAndResizeBehavior(); } if (type == MIN_SIZE) { return calculateMinSize(); } if (type == MAX_SIZE) { return calculateMaxSize(); } if (allSpringsHaveBaseline) { return prefAscent + prefDescent; } return Math.max(prefAscent + prefDescent, super.calculateSize(axis, type)); } private void calculateBaselineAndResizeBehavior() { // calculate baseline prefAscent = 0; prefDescent = 0; int baselineSpringCount = 0; BaselineResizeBehavior resizeBehavior = null; for (Spring spring : springs) { if (spring.getAlignment() == null || spring.getAlignment() == Alignment.BASELINE) { int baseline = spring.getBaseline(); if (baseline >= 0) { if (spring.isResizable(VERTICAL)) { BaselineResizeBehavior brb = spring. getBaselineResizeBehavior(); if (resizeBehavior == null) { resizeBehavior = brb; } else if (brb != resizeBehavior) { resizeBehavior = BaselineResizeBehavior. CONSTANT_ASCENT; } } prefAscent = Math.max(prefAscent, baseline); prefDescent = Math.max(prefDescent, spring. getPreferredSize(VERTICAL) - baseline); baselineSpringCount++; } } } if (!baselineAnchorSet) { if (resizeBehavior == BaselineResizeBehavior.CONSTANT_DESCENT){ this.baselineAnchoredToTop = false; } else { this.baselineAnchoredToTop = true; } } allSpringsHaveBaseline = (baselineSpringCount == springs.size()); calcedBaseline = true; } private int calculateMaxSize() { int maxAscent = prefAscent; int maxDescent = prefDescent; int nonBaselineMax = 0; for (Spring spring : springs) { int baseline; int springMax = spring.getMaximumSize(VERTICAL); if ((spring.getAlignment() == null || spring.getAlignment() == Alignment.BASELINE) && (baseline = spring.getBaseline()) >= 0) { int springPref = spring.getPreferredSize(VERTICAL); if (springPref != springMax) { switch (spring.getBaselineResizeBehavior()) { case CONSTANT_ASCENT: if (baselineAnchoredToTop) { maxDescent = Math.max(maxDescent, springMax - baseline); } break; case CONSTANT_DESCENT: if (!baselineAnchoredToTop) { maxAscent = Math.max(maxAscent, springMax - springPref + baseline); } break; default: // CENTER_OFFSET and OTHER, not resizable break; } } } else { // Not aligned along the baseline, or no baseline. nonBaselineMax = Math.max(nonBaselineMax, springMax); } } return Math.max(nonBaselineMax, maxAscent + maxDescent); } private int calculateMinSize() { int minAscent = 0; int minDescent = 0; int nonBaselineMin = 0; if (baselineAnchoredToTop) { minAscent = prefAscent; } else { minDescent = prefDescent; } for (Spring spring : springs) { int springMin = spring.getMinimumSize(VERTICAL); int baseline; if ((spring.getAlignment() == null || spring.getAlignment() == Alignment.BASELINE) && (baseline = spring.getBaseline()) >= 0) { int springPref = spring.getPreferredSize(VERTICAL); BaselineResizeBehavior brb = spring. getBaselineResizeBehavior(); switch (brb) { case CONSTANT_ASCENT: if (baselineAnchoredToTop) { minDescent = Math.max(springMin - baseline, minDescent); } else { minAscent = Math.max(baseline, minAscent); } break; case CONSTANT_DESCENT: if (!baselineAnchoredToTop) { minAscent = Math.max( baseline - (springPref - springMin), minAscent); } else { minDescent = Math.max(springPref - baseline, minDescent); } break; default: // CENTER_OFFSET and OTHER are !resizable, use // the preferred size. minAscent = Math.max(baseline, minAscent); minDescent = Math.max(springPref - baseline, minDescent); break; } } else { // Not aligned along the baseline, or no baseline. nonBaselineMin = Math.max(nonBaselineMin, springMin); } } return Math.max(nonBaselineMin, minAscent + minDescent); }
Lays out springs that have a baseline along the baseline. All others are centered.
/** * Lays out springs that have a baseline along the baseline. All * others are centered. */
private void baselineLayout(int origin, int size) { int ascent; int descent; if (baselineAnchoredToTop) { ascent = prefAscent; descent = size - ascent; } else { ascent = size - prefDescent; descent = prefDescent; } for (Spring spring : springs) { Alignment alignment = spring.getAlignment(); if (alignment == null || alignment == Alignment.BASELINE) { int baseline = spring.getBaseline(); if (baseline >= 0) { int springMax = spring.getMaximumSize(VERTICAL); int springPref = spring.getPreferredSize(VERTICAL); int height = springPref; int y; switch(spring.getBaselineResizeBehavior()) { case CONSTANT_ASCENT: y = origin + ascent - baseline; height = Math.min(descent, springMax - baseline) + baseline; break; case CONSTANT_DESCENT: height = Math.min(ascent, springMax - springPref + baseline) + (springPref - baseline); y = origin + ascent + (springPref - baseline) - height; break; default: // CENTER_OFFSET & OTHER, not resizable y = origin + ascent - baseline; break; } spring.setSize(VERTICAL, y, height); } else { setChildSize(spring, VERTICAL, origin, size); } } else { setChildSize(spring, VERTICAL, origin, size); } } } int getBaseline() { if (springs.size() > 1) { // Force the baseline to be calculated getPreferredSize(VERTICAL); return prefAscent; } else if (springs.size() == 1) { return springs.get(0).getBaseline(); } return -1; } BaselineResizeBehavior getBaselineResizeBehavior() { if (springs.size() == 1) { return springs.get(0).getBaselineResizeBehavior(); } if (baselineAnchoredToTop) { return BaselineResizeBehavior.CONSTANT_ASCENT; } return BaselineResizeBehavior.CONSTANT_DESCENT; } // If the axis is VERTICAL, throws an IllegalStateException private void checkAxis(int axis) { if (axis == HORIZONTAL) { throw new IllegalStateException( "Baseline must be used along vertical axis"); } } } private final class ComponentSpring extends Spring { private Component component; private int origin; // min/pref/max are either a value >= 0 or one of // DEFAULT_SIZE or PREFERRED_SIZE private final int min; private final int pref; private final int max; // Baseline for the component, computed as necessary. private int baseline = -1; // Whether or not the size has been requested yet. private boolean installed; private ComponentSpring(Component component, int min, int pref, int max) { this.component = component; if (component == null) { throw new IllegalArgumentException( "Component must be non-null"); } checkSize(min, pref, max, true); this.min = min; this.max = max; this.pref = pref; // getComponentInfo makes sure component is a child of the // Container GroupLayout is the LayoutManager for. getComponentInfo(component); } int calculateMinimumSize(int axis) { if (isLinked(axis)) { return getLinkSize(axis, MIN_SIZE); } return calculateNonlinkedMinimumSize(axis); } int calculatePreferredSize(int axis) { if (isLinked(axis)) { return getLinkSize(axis, PREF_SIZE); } int min = getMinimumSize(axis); int pref = calculateNonlinkedPreferredSize(axis); int max = getMaximumSize(axis); return Math.min(max, Math.max(min, pref)); } int calculateMaximumSize(int axis) { if (isLinked(axis)) { return getLinkSize(axis, MAX_SIZE); } return Math.max(getMinimumSize(axis), calculateNonlinkedMaximumSize(axis)); } boolean isVisible() { return getComponentInfo(getComponent()).isVisible(); } int calculateNonlinkedMinimumSize(int axis) { if (!isVisible()) { return 0; } if (min >= 0) { return min; } if (min == PREFERRED_SIZE) { return calculateNonlinkedPreferredSize(axis); } assert (min == DEFAULT_SIZE); return getSizeAlongAxis(axis, component.getMinimumSize()); } int calculateNonlinkedPreferredSize(int axis) { if (!isVisible()) { return 0; } if (pref >= 0) { return pref; } assert (pref == DEFAULT_SIZE || pref == PREFERRED_SIZE); return getSizeAlongAxis(axis, component.getPreferredSize()); } int calculateNonlinkedMaximumSize(int axis) { if (!isVisible()) { return 0; } if (max >= 0) { return max; } if (max == PREFERRED_SIZE) { return calculateNonlinkedPreferredSize(axis); } assert (max == DEFAULT_SIZE); return getSizeAlongAxis(axis, component.getMaximumSize()); } private int getSizeAlongAxis(int axis, Dimension size) { return (axis == HORIZONTAL) ? size.width : size.height; } private int getLinkSize(int axis, int type) { if (!isVisible()) { return 0; } ComponentInfo ci = getComponentInfo(component); return ci.getLinkSize(axis, type); } void setSize(int axis, int origin, int size) { super.setSize(axis, origin, size); this.origin = origin; if (size == UNSET) { baseline = -1; } } int getOrigin() { return origin; } void setComponent(Component component) { this.component = component; } Component getComponent() { return component; } int getBaseline() { if (baseline == -1) { Spring horizontalSpring = getComponentInfo(component). horizontalSpring; int width = horizontalSpring.getPreferredSize(HORIZONTAL); int height = getPreferredSize(VERTICAL); if (width > 0 && height > 0) { baseline = component.getBaseline(width, height); } } return baseline; } BaselineResizeBehavior getBaselineResizeBehavior() { return getComponent().getBaselineResizeBehavior(); } private boolean isLinked(int axis) { return getComponentInfo(component).isLinked(axis); } void installIfNecessary(int axis) { if (!installed) { installed = true; if (axis == HORIZONTAL) { getComponentInfo(component).horizontalSpring = this; } else { getComponentInfo(component).verticalSpring = this; } } } @Override boolean willHaveZeroSize(boolean treatAutopaddingAsZeroSized) { return !isVisible(); } }
Spring representing the preferred distance between two components.
/** * Spring representing the preferred distance between two components. */
private class PreferredGapSpring extends Spring { private final JComponent source; private final JComponent target; private final ComponentPlacement type; private final int pref; private final int max; PreferredGapSpring(JComponent source, JComponent target, ComponentPlacement type, int pref, int max) { this.source = source; this.target = target; this.type = type; this.pref = pref; this.max = max; } int calculateMinimumSize(int axis) { return getPadding(axis); } int calculatePreferredSize(int axis) { if (pref == DEFAULT_SIZE || pref == PREFERRED_SIZE) { return getMinimumSize(axis); } int min = getMinimumSize(axis); int max = getMaximumSize(axis); return Math.min(max, Math.max(min, pref)); } int calculateMaximumSize(int axis) { if (max == PREFERRED_SIZE || max == DEFAULT_SIZE) { return getPadding(axis); } return Math.max(getMinimumSize(axis), max); } private int getPadding(int axis) { int position; if (axis == HORIZONTAL) { position = SwingConstants.EAST; } else { position = SwingConstants.SOUTH; } return getLayoutStyle0().getPreferredGap(source, target, type, position, host); } @Override boolean willHaveZeroSize(boolean treatAutopaddingAsZeroSized) { return false; } }
Spring represented a certain amount of space.
/** * Spring represented a certain amount of space. */
private class GapSpring extends Spring { private final int min; private final int pref; private final int max; GapSpring(int min, int pref, int max) { checkSize(min, pref, max, false); this.min = min; this.pref = pref; this.max = max; } int calculateMinimumSize(int axis) { if (min == PREFERRED_SIZE) { return getPreferredSize(axis); } return min; } int calculatePreferredSize(int axis) { return pref; } int calculateMaximumSize(int axis) { if (max == PREFERRED_SIZE) { return getPreferredSize(axis); } return max; } @Override boolean willHaveZeroSize(boolean treatAutopaddingAsZeroSized) { return false; } }
Spring reprensenting the distance between any number of sources and targets. The targets and sources are computed during layout. An instance of this can either be dynamically created when autocreatePadding is true, or explicitly created by the developer.
/** * Spring reprensenting the distance between any number of sources and * targets. The targets and sources are computed during layout. An * instance of this can either be dynamically created when * autocreatePadding is true, or explicitly created by the developer. */
private class AutoPreferredGapSpring extends Spring { List<ComponentSpring> sources; ComponentSpring source; private List<AutoPreferredGapMatch> matches; int size; int lastSize; private final int pref; private final int max; // Type of gap private ComponentPlacement type; private boolean userCreated; private AutoPreferredGapSpring() { this.pref = PREFERRED_SIZE; this.max = PREFERRED_SIZE; this.type = ComponentPlacement.RELATED; } AutoPreferredGapSpring(int pref, int max) { this.pref = pref; this.max = max; } AutoPreferredGapSpring(ComponentPlacement type, int pref, int max) { this.type = type; this.pref = pref; this.max = max; this.userCreated = true; } public void setSource(ComponentSpring source) { this.source = source; } public void setSources(List<ComponentSpring> sources) { this.sources = new ArrayList<ComponentSpring>(sources); } public void setUserCreated(boolean userCreated) { this.userCreated = userCreated; } public boolean getUserCreated() { return userCreated; } void unset() { lastSize = getSize(); super.unset(); size = 0; } public void reset() { size = 0; sources = null; source = null; matches = null; } public void calculatePadding(int axis) { size = UNSET; int maxPadding = UNSET; if (matches != null) { LayoutStyle p = getLayoutStyle0(); int position; if (axis == HORIZONTAL) { if (isLeftToRight()) { position = SwingConstants.EAST; } else { position = SwingConstants.WEST; } } else { position = SwingConstants.SOUTH; } for (int i = matches.size() - 1; i >= 0; i--) { AutoPreferredGapMatch match = matches.get(i); maxPadding = Math.max(maxPadding, calculatePadding(p, position, match.source, match.target)); } } if (size == UNSET) { size = 0; } if (maxPadding == UNSET) { maxPadding = 0; } if (lastSize != UNSET) { size += Math.min(maxPadding, lastSize); } } private int calculatePadding(LayoutStyle p, int position, ComponentSpring source, ComponentSpring target) { int delta = target.getOrigin() - (source.getOrigin() + source.getSize()); if (delta >= 0) { int padding; if ((source.getComponent() instanceof JComponent) && (target.getComponent() instanceof JComponent)) { padding = p.getPreferredGap( (JComponent)source.getComponent(), (JComponent)target.getComponent(), type, position, host); } else { padding = 10; } if (padding > delta) { size = Math.max(size, padding - delta); } return padding; } return 0; } public void addTarget(ComponentSpring spring, int axis) { int oAxis = (axis == HORIZONTAL) ? VERTICAL : HORIZONTAL; if (source != null) { if (areParallelSiblings(source.getComponent(), spring.getComponent(), oAxis)) { addValidTarget(source, spring); } } else { Component component = spring.getComponent(); for (int counter = sources.size() - 1; counter >= 0; counter--){ ComponentSpring source = sources.get(counter); if (areParallelSiblings(source.getComponent(), component, oAxis)) { addValidTarget(source, spring); } } } } private void addValidTarget(ComponentSpring source, ComponentSpring target) { if (matches == null) { matches = new ArrayList<AutoPreferredGapMatch>(1); } matches.add(new AutoPreferredGapMatch(source, target)); } int calculateMinimumSize(int axis) { return size; } int calculatePreferredSize(int axis) { if (pref == PREFERRED_SIZE || pref == DEFAULT_SIZE) { return size; } return Math.max(size, pref); } int calculateMaximumSize(int axis) { if (max >= 0) { return Math.max(getPreferredSize(axis), max); } return size; } String getMatchDescription() { return (matches == null) ? "" : matches.toString(); } public String toString() { return super.toString() + getMatchDescription(); } @Override boolean willHaveZeroSize(boolean treatAutopaddingAsZeroSized) { return treatAutopaddingAsZeroSized; } }
Represents two springs that should have autopadding inserted between them.
/** * Represents two springs that should have autopadding inserted between * them. */
private final static class AutoPreferredGapMatch { public final ComponentSpring source; public final ComponentSpring target; AutoPreferredGapMatch(ComponentSpring source, ComponentSpring target) { this.source = source; this.target = target; } private String toString(ComponentSpring spring) { return spring.getComponent().getName(); } public String toString() { return "[" + toString(source) + "-" + toString(target) + "]"; } }
An extension of AutopaddingSpring used for container level padding.
/** * An extension of AutopaddingSpring used for container level padding. */
private class ContainerAutoPreferredGapSpring extends AutoPreferredGapSpring { private List<ComponentSpring> targets; ContainerAutoPreferredGapSpring() { super(); setUserCreated(true); } ContainerAutoPreferredGapSpring(int pref, int max) { super(pref, max); setUserCreated(true); } public void addTarget(ComponentSpring spring, int axis) { if (targets == null) { targets = new ArrayList<ComponentSpring>(1); } targets.add(spring); } public void calculatePadding(int axis) { LayoutStyle p = getLayoutStyle0(); int maxPadding = 0; int position; size = 0; if (targets != null) { // Leading if (axis == HORIZONTAL) { if (isLeftToRight()) { position = SwingConstants.WEST; } else { position = SwingConstants.EAST; } } else { position = SwingConstants.SOUTH; } for (int i = targets.size() - 1; i >= 0; i--) { ComponentSpring targetSpring = targets.get(i); int padding = 10; if (targetSpring.getComponent() instanceof JComponent) { padding = p.getContainerGap( (JComponent)targetSpring.getComponent(), position, host); maxPadding = Math.max(padding, maxPadding); padding -= targetSpring.getOrigin(); } else { maxPadding = Math.max(padding, maxPadding); } size = Math.max(size, padding); } } else { // Trailing if (axis == HORIZONTAL) { if (isLeftToRight()) { position = SwingConstants.EAST; } else { position = SwingConstants.WEST; } } else { position = SwingConstants.SOUTH; } if (sources != null) { for (int i = sources.size() - 1; i >= 0; i--) { ComponentSpring sourceSpring = sources.get(i); maxPadding = Math.max(maxPadding, updateSize(p, sourceSpring, position)); } } else if (source != null) { maxPadding = updateSize(p, source, position); } } if (lastSize != UNSET) { size += Math.min(maxPadding, lastSize); } } private int updateSize(LayoutStyle p, ComponentSpring sourceSpring, int position) { int padding = 10; if (sourceSpring.getComponent() instanceof JComponent) { padding = p.getContainerGap( (JComponent)sourceSpring.getComponent(), position, host); } int delta = Math.max(0, getParent().getSize() - sourceSpring.getSize() - sourceSpring.getOrigin()); size = Math.max(size, padding - delta); return padding; } String getMatchDescription() { if (targets != null) { return "leading: " + targets.toString(); } if (sources != null) { return "trailing: " + sources.toString(); } return "--"; } } // LinkInfo contains the set of ComponentInfosthat are linked along a // particular axis. private static class LinkInfo { private final int axis; private final List<ComponentInfo> linked; private int size; LinkInfo(int axis) { linked = new ArrayList<ComponentInfo>(); size = UNSET; this.axis = axis; } public void add(ComponentInfo child) { LinkInfo childMaster = child.getLinkInfo(axis, false); if (childMaster == null) { linked.add(child); child.setLinkInfo(axis, this); } else if (childMaster != this) { linked.addAll(childMaster.linked); for (ComponentInfo childInfo : childMaster.linked) { childInfo.setLinkInfo(axis, this); } } clearCachedSize(); } public void remove(ComponentInfo info) { linked.remove(info); info.setLinkInfo(axis, null); if (linked.size() == 1) { linked.get(0).setLinkInfo(axis, null); } clearCachedSize(); } public void clearCachedSize() { size = UNSET; } public int getSize(int axis) { if (size == UNSET) { size = calculateLinkedSize(axis); } return size; } private int calculateLinkedSize(int axis) { int size = 0; for (ComponentInfo info : linked) { ComponentSpring spring; if (axis == HORIZONTAL) { spring = info.horizontalSpring; } else { assert (axis == VERTICAL); spring = info.verticalSpring; } size = Math.max(size, spring.calculateNonlinkedPreferredSize(axis)); } return size; } }
Tracks the horizontal/vertical Springs for a Component. This class is also used to handle Springs that have their sizes linked.
/** * Tracks the horizontal/vertical Springs for a Component. * This class is also used to handle Springs that have their sizes * linked. */
private class ComponentInfo { // Component being layed out private Component component; ComponentSpring horizontalSpring; ComponentSpring verticalSpring; // If the component's size is linked to other components, the // horizontalMaster and/or verticalMaster reference the group of // linked components. private LinkInfo horizontalMaster; private LinkInfo verticalMaster; private boolean visible; private Boolean honorsVisibility; ComponentInfo(Component component) { this.component = component; updateVisibility(); } public void dispose() { // Remove horizontal/vertical springs removeSpring(horizontalSpring); horizontalSpring = null; removeSpring(verticalSpring); verticalSpring = null; // Clean up links if (horizontalMaster != null) { horizontalMaster.remove(this); } if (verticalMaster != null) { verticalMaster.remove(this); } } void setHonorsVisibility(Boolean honorsVisibility) { this.honorsVisibility = honorsVisibility; } private void removeSpring(Spring spring) { if (spring != null) { ((Group)spring.getParent()).springs.remove(spring); } } public boolean isVisible() { return visible; }
Updates the cached visibility.
Returns:true if the visibility changed
/** * Updates the cached visibility. * * @return true if the visibility changed */
boolean updateVisibility() { boolean honorsVisibility; if (this.honorsVisibility == null) { honorsVisibility = GroupLayout.this.getHonorsVisibility(); } else { honorsVisibility = this.honorsVisibility; } boolean newVisible = (honorsVisibility) ? component.isVisible() : true; if (visible != newVisible) { visible = newVisible; return true; } return false; } public void setBounds(Insets insets, int parentWidth, boolean ltr) { int x = horizontalSpring.getOrigin(); int w = horizontalSpring.getSize(); int y = verticalSpring.getOrigin(); int h = verticalSpring.getSize(); if (!ltr) { x = parentWidth - x - w; } component.setBounds(x + insets.left, y + insets.top, w, h); } public void setComponent(Component component) { this.component = component; if (horizontalSpring != null) { horizontalSpring.setComponent(component); } if (verticalSpring != null) { verticalSpring.setComponent(component); } } public Component getComponent() { return component; }
Returns true if this component has its size linked to other components.
/** * Returns true if this component has its size linked to * other components. */
public boolean isLinked(int axis) { if (axis == HORIZONTAL) { return horizontalMaster != null; } assert (axis == VERTICAL); return (verticalMaster != null); } private void setLinkInfo(int axis, LinkInfo linkInfo) { if (axis == HORIZONTAL) { horizontalMaster = linkInfo; } else { assert (axis == VERTICAL); verticalMaster = linkInfo; } } public LinkInfo getLinkInfo(int axis) { return getLinkInfo(axis, true); } private LinkInfo getLinkInfo(int axis, boolean create) { if (axis == HORIZONTAL) { if (horizontalMaster == null && create) { // horizontalMaster field is directly set by adding // us to the LinkInfo. new LinkInfo(HORIZONTAL).add(this); } return horizontalMaster; } else { assert (axis == VERTICAL); if (verticalMaster == null && create) { // verticalMaster field is directly set by adding // us to the LinkInfo. new LinkInfo(VERTICAL).add(this); } return verticalMaster; } } public void clearCachedSize() { if (horizontalMaster != null) { horizontalMaster.clearCachedSize(); } if (verticalMaster != null) { verticalMaster.clearCachedSize(); } } int getLinkSize(int axis, int type) { if (axis == HORIZONTAL) { return horizontalMaster.getSize(axis); } else { assert (axis == VERTICAL); return verticalMaster.getSize(axis); } } } }