0N/A/*
2362N/A * Copyright (c) 1997, 2007, Oracle and/or its affiliates. All rights reserved.
0N/A * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
0N/A *
0N/A * This code is free software; you can redistribute it and/or modify it
0N/A * under the terms of the GNU General Public License version 2 only, as
2362N/A * published by the Free Software Foundation. Oracle designates this
0N/A * particular file as subject to the "Classpath" exception as provided
2362N/A * by Oracle in the LICENSE file that accompanied this code.
0N/A *
0N/A * This code is distributed in the hope that it will be useful, but WITHOUT
0N/A * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
0N/A * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
0N/A * version 2 for more details (a copy is included in the LICENSE file that
0N/A * accompanied this code).
0N/A *
0N/A * You should have received a copy of the GNU General Public License version
0N/A * 2 along with this work; if not, write to the Free Software Foundation,
0N/A * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
0N/A *
2362N/A * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
2362N/A * or visit www.oracle.com if you need additional information or have any
2362N/A * questions.
0N/A */
0N/A
0N/A
0N/Apackage javax.swing;
0N/A
0N/Aimport java.awt.*;
0N/Aimport java.beans.ConstructorProperties;
0N/Aimport java.io.Serializable;
0N/Aimport java.io.PrintStream;
0N/A
0N/A/**
0N/A * A layout manager that allows multiple components to be laid out either
0N/A * vertically or horizontally. The components will not wrap so, for
0N/A * example, a vertical arrangement of components will stay vertically
0N/A * arranged when the frame is resized.
0N/A * <TABLE ALIGN="RIGHT" BORDER="0" SUMMARY="layout">
0N/A * <TR>
0N/A * <TD ALIGN="CENTER">
0N/A * <P ALIGN="CENTER"><IMG SRC="doc-files/BoxLayout-1.gif"
0N/A * alt="The following text describes this graphic."
0N/A * WIDTH="191" HEIGHT="201" ALIGN="BOTTOM" BORDER="0">
0N/A * </TD>
0N/A * </TR>
0N/A * </TABLE>
0N/A * <p>
0N/A * Nesting multiple panels with different combinations of horizontal and
0N/A * vertical gives an effect similar to GridBagLayout, without the
0N/A * complexity. The diagram shows two panels arranged horizontally, each
0N/A * of which contains 3 components arranged vertically.
0N/A *
0N/A * <p> The BoxLayout manager is constructed with an axis parameter that
0N/A * specifies the type of layout that will be done. There are four choices:
0N/A *
0N/A * <blockquote><b><tt>X_AXIS</tt></b> - Components are laid out horizontally
0N/A * from left to right.</blockquote>
0N/A *
0N/A * <blockquote><b><tt>Y_AXIS</tt></b> - Components are laid out vertically
0N/A * from top to bottom.</blockquote>
0N/A *
0N/A * <blockquote><b><tt>LINE_AXIS</tt></b> - Components are laid out the way
0N/A * words are laid out in a line, based on the container's
0N/A * <tt>ComponentOrientation</tt> property. If the container's
0N/A * <tt>ComponentOrientation</tt> is horizontal then components are laid out
0N/A * horizontally, otherwise they are laid out vertically. For horizontal
0N/A * orientations, if the container's <tt>ComponentOrientation</tt> is left to
0N/A * right then components are laid out left to right, otherwise they are laid
0N/A * out right to left. For vertical orientations components are always laid out
0N/A * from top to bottom.</blockquote>
0N/A *
0N/A * <blockquote><b><tt>PAGE_AXIS</tt></b> - Components are laid out the way
0N/A * text lines are laid out on a page, based on the container's
0N/A * <tt>ComponentOrientation</tt> property. If the container's
0N/A * <tt>ComponentOrientation</tt> is horizontal then components are laid out
0N/A * vertically, otherwise they are laid out horizontally. For horizontal
0N/A * orientations, if the container's <tt>ComponentOrientation</tt> is left to
0N/A * right then components are laid out left to right, otherwise they are laid
0N/A * out right to left.&nbsp; For vertical orientations components are always
0N/A * laid out from top to bottom.</blockquote>
0N/A * <p>
0N/A * For all directions, components are arranged in the same order as they were
0N/A * added to the container.
0N/A * <p>
0N/A * BoxLayout attempts to arrange components
0N/A * at their preferred widths (for horizontal layout)
0N/A * or heights (for vertical layout).
0N/A * For a horizontal layout,
0N/A * if not all the components are the same height,
0N/A * BoxLayout attempts to make all the components
0N/A * as high as the highest component.
0N/A * If that's not possible for a particular component,
0N/A * then BoxLayout aligns that component vertically,
0N/A * according to the component's Y alignment.
0N/A * By default, a component has a Y alignment of 0.5,
0N/A * which means that the vertical center of the component
0N/A * should have the same Y coordinate as
0N/A * the vertical centers of other components with 0.5 Y alignment.
0N/A * <p>
0N/A * Similarly, for a vertical layout,
0N/A * BoxLayout attempts to make all components in the column
0N/A * as wide as the widest component.
0N/A * If that fails, it aligns them horizontally
0N/A * according to their X alignments. For <code>PAGE_AXIS</code> layout,
0N/A * horizontal alignment is done based on the leading edge of the component.
0N/A * In other words, an X alignment value of 0.0 means the left edge of a
0N/A * component if the container's <code>ComponentOrientation</code> is left to
0N/A * right and it means the right edge of the component otherwise.
0N/A * <p>
0N/A * Instead of using BoxLayout directly, many programs use the Box class.
0N/A * The Box class is a lightweight container that uses a BoxLayout.
0N/A * It also provides handy methods to help you use BoxLayout well.
0N/A * Adding components to multiple nested boxes is a powerful way to get
0N/A * the arrangement you want.
0N/A * <p>
0N/A * For further information and examples see
0N/A * <a
0N/A href="http://java.sun.com/docs/books/tutorial/uiswing/layout/box.html">How to Use BoxLayout</a>,
0N/A * a section in <em>The Java Tutorial.</em>
0N/A * <p>
0N/A * <strong>Warning:</strong>
0N/A * Serialized objects of this class will not be compatible with
0N/A * future Swing releases. The current serialization support is
0N/A * appropriate for short term storage or RMI between applications running
0N/A * the same version of Swing. As of 1.4, support for long term storage
0N/A * of all JavaBeans<sup><font size="-2">TM</font></sup>
0N/A * has been added to the <code>java.beans</code> package.
0N/A * Please see {@link java.beans.XMLEncoder}.
0N/A *
0N/A * @see Box
0N/A * @see java.awt.ComponentOrientation
0N/A * @see JComponent#getAlignmentX
0N/A * @see JComponent#getAlignmentY
0N/A *
0N/A * @author Timothy Prinzing
0N/A */
0N/Apublic class BoxLayout implements LayoutManager2, Serializable {
0N/A
0N/A /**
0N/A * Specifies that components should be laid out left to right.
0N/A */
0N/A public static final int X_AXIS = 0;
0N/A
0N/A /**
0N/A * Specifies that components should be laid out top to bottom.
0N/A */
0N/A public static final int Y_AXIS = 1;
0N/A
0N/A /**
0N/A * Specifies that components should be laid out in the direction of
0N/A * a line of text as determined by the target container's
0N/A * <code>ComponentOrientation</code> property.
0N/A */
0N/A public static final int LINE_AXIS = 2;
0N/A
0N/A /**
0N/A * Specifies that components should be laid out in the direction that
0N/A * lines flow across a page as determined by the target container's
0N/A * <code>ComponentOrientation</code> property.
0N/A */
0N/A public static final int PAGE_AXIS = 3;
0N/A
0N/A /**
0N/A * Creates a layout manager that will lay out components along the
0N/A * given axis.
0N/A *
0N/A * @param target the container that needs to be laid out
0N/A * @param axis the axis to lay out components along. Can be one of:
0N/A * <code>BoxLayout.X_AXIS</code>,
0N/A * <code>BoxLayout.Y_AXIS</code>,
0N/A * <code>BoxLayout.LINE_AXIS</code> or
0N/A * <code>BoxLayout.PAGE_AXIS</code>
0N/A *
0N/A * @exception AWTError if the value of <code>axis</code> is invalid
0N/A */
0N/A @ConstructorProperties({"target", "axis"})
0N/A public BoxLayout(Container target, int axis) {
0N/A if (axis != X_AXIS && axis != Y_AXIS &&
0N/A axis != LINE_AXIS && axis != PAGE_AXIS) {
0N/A throw new AWTError("Invalid axis");
0N/A }
0N/A this.axis = axis;
0N/A this.target = target;
0N/A }
0N/A
0N/A /**
0N/A * Constructs a BoxLayout that
0N/A * produces debugging messages.
0N/A *
0N/A * @param target the container that needs to be laid out
0N/A * @param axis the axis to lay out components along. Can be one of:
0N/A * <code>BoxLayout.X_AXIS</code>,
0N/A * <code>BoxLayout.Y_AXIS</code>,
0N/A * <code>BoxLayout.LINE_AXIS</code> or
0N/A * <code>BoxLayout.PAGE_AXIS</code>
0N/A *
0N/A * @param dbg the stream to which debugging messages should be sent,
0N/A * null if none
0N/A */
0N/A BoxLayout(Container target, int axis, PrintStream dbg) {
0N/A this(target, axis);
0N/A this.dbg = dbg;
0N/A }
0N/A
0N/A /**
0N/A * Returns the container that uses this layout manager.
0N/A *
0N/A * @return the container that uses this layout manager
0N/A *
0N/A * @since 1.6
0N/A */
0N/A public final Container getTarget() {
0N/A return this.target;
0N/A }
0N/A
0N/A /**
0N/A * Returns the axis that was used to lay out components.
0N/A * Returns one of:
0N/A * <code>BoxLayout.X_AXIS</code>,
0N/A * <code>BoxLayout.Y_AXIS</code>,
0N/A * <code>BoxLayout.LINE_AXIS</code> or
0N/A * <code>BoxLayout.PAGE_AXIS</code>
0N/A *
0N/A * @return the axis that was used to lay out components
0N/A *
0N/A * @since 1.6
0N/A */
0N/A public final int getAxis() {
0N/A return this.axis;
0N/A }
0N/A
0N/A /**
0N/A * Indicates that a child has changed its layout related information,
0N/A * and thus any cached calculations should be flushed.
0N/A * <p>
0N/A * This method is called by AWT when the invalidate method is called
0N/A * on the Container. Since the invalidate method may be called
0N/A * asynchronously to the event thread, this method may be called
0N/A * asynchronously.
0N/A *
0N/A * @param target the affected container
0N/A *
0N/A * @exception AWTError if the target isn't the container specified to the
0N/A * BoxLayout constructor
0N/A */
0N/A public synchronized void invalidateLayout(Container target) {
0N/A checkContainer(target);
0N/A xChildren = null;
0N/A yChildren = null;
0N/A xTotal = null;
0N/A yTotal = null;
0N/A }
0N/A
0N/A /**
0N/A * Not used by this class.
0N/A *
0N/A * @param name the name of the component
0N/A * @param comp the component
0N/A */
0N/A public void addLayoutComponent(String name, Component comp) {
0N/A invalidateLayout(comp.getParent());
0N/A }
0N/A
0N/A /**
0N/A * Not used by this class.
0N/A *
0N/A * @param comp the component
0N/A */
0N/A public void removeLayoutComponent(Component comp) {
0N/A invalidateLayout(comp.getParent());
0N/A }
0N/A
0N/A /**
0N/A * Not used by this class.
0N/A *
0N/A * @param comp the component
0N/A * @param constraints constraints
0N/A */
0N/A public void addLayoutComponent(Component comp, Object constraints) {
0N/A invalidateLayout(comp.getParent());
0N/A }
0N/A
0N/A /**
0N/A * Returns the preferred dimensions for this layout, given the components
0N/A * in the specified target container.
0N/A *
0N/A * @param target the container that needs to be laid out
0N/A * @return the dimensions >= 0 && <= Integer.MAX_VALUE
0N/A * @exception AWTError if the target isn't the container specified to the
0N/A * BoxLayout constructor
0N/A * @see Container
0N/A * @see #minimumLayoutSize
0N/A * @see #maximumLayoutSize
0N/A */
0N/A public Dimension preferredLayoutSize(Container target) {
0N/A Dimension size;
0N/A synchronized(this) {
0N/A checkContainer(target);
0N/A checkRequests();
0N/A size = new Dimension(xTotal.preferred, yTotal.preferred);
0N/A }
0N/A
0N/A Insets insets = target.getInsets();
0N/A size.width = (int) Math.min((long) size.width + (long) insets.left + (long) insets.right, Integer.MAX_VALUE);
0N/A size.height = (int) Math.min((long) size.height + (long) insets.top + (long) insets.bottom, Integer.MAX_VALUE);
0N/A return size;
0N/A }
0N/A
0N/A /**
0N/A * Returns the minimum dimensions needed to lay out the components
0N/A * contained in the specified target container.
0N/A *
0N/A * @param target the container that needs to be laid out
0N/A * @return the dimensions >= 0 && <= Integer.MAX_VALUE
0N/A * @exception AWTError if the target isn't the container specified to the
0N/A * BoxLayout constructor
0N/A * @see #preferredLayoutSize
0N/A * @see #maximumLayoutSize
0N/A */
0N/A public Dimension minimumLayoutSize(Container target) {
0N/A Dimension size;
0N/A synchronized(this) {
0N/A checkContainer(target);
0N/A checkRequests();
0N/A size = new Dimension(xTotal.minimum, yTotal.minimum);
0N/A }
0N/A
0N/A Insets insets = target.getInsets();
0N/A size.width = (int) Math.min((long) size.width + (long) insets.left + (long) insets.right, Integer.MAX_VALUE);
0N/A size.height = (int) Math.min((long) size.height + (long) insets.top + (long) insets.bottom, Integer.MAX_VALUE);
0N/A return size;
0N/A }
0N/A
0N/A /**
0N/A * Returns the maximum dimensions the target container can use
0N/A * to lay out the components it contains.
0N/A *
0N/A * @param target the container that needs to be laid out
0N/A * @return the dimenions >= 0 && <= Integer.MAX_VALUE
0N/A * @exception AWTError if the target isn't the container specified to the
0N/A * BoxLayout constructor
0N/A * @see #preferredLayoutSize
0N/A * @see #minimumLayoutSize
0N/A */
0N/A public Dimension maximumLayoutSize(Container target) {
0N/A Dimension size;
0N/A synchronized(this) {
0N/A checkContainer(target);
0N/A checkRequests();
0N/A size = new Dimension(xTotal.maximum, yTotal.maximum);
0N/A }
0N/A
0N/A Insets insets = target.getInsets();
0N/A size.width = (int) Math.min((long) size.width + (long) insets.left + (long) insets.right, Integer.MAX_VALUE);
0N/A size.height = (int) Math.min((long) size.height + (long) insets.top + (long) insets.bottom, Integer.MAX_VALUE);
0N/A return size;
0N/A }
0N/A
0N/A /**
0N/A * Returns the alignment along the X axis for the container.
0N/A * If the box is horizontal, the default
0N/A * alignment will be returned. Otherwise, the alignment needed
0N/A * to place the children along the X axis will be returned.
0N/A *
0N/A * @param target the container
0N/A * @return the alignment >= 0.0f && <= 1.0f
0N/A * @exception AWTError if the target isn't the container specified to the
0N/A * BoxLayout constructor
0N/A */
0N/A public synchronized float getLayoutAlignmentX(Container target) {
0N/A checkContainer(target);
0N/A checkRequests();
0N/A return xTotal.alignment;
0N/A }
0N/A
0N/A /**
0N/A * Returns the alignment along the Y axis for the container.
0N/A * If the box is vertical, the default
0N/A * alignment will be returned. Otherwise, the alignment needed
0N/A * to place the children along the Y axis will be returned.
0N/A *
0N/A * @param target the container
0N/A * @return the alignment >= 0.0f && <= 1.0f
0N/A * @exception AWTError if the target isn't the container specified to the
0N/A * BoxLayout constructor
0N/A */
0N/A public synchronized float getLayoutAlignmentY(Container target) {
0N/A checkContainer(target);
0N/A checkRequests();
0N/A return yTotal.alignment;
0N/A }
0N/A
0N/A /**
0N/A * Called by the AWT <!-- XXX CHECK! --> when the specified container
0N/A * needs to be laid out.
0N/A *
0N/A * @param target the container to lay out
0N/A *
0N/A * @exception AWTError if the target isn't the container specified to the
0N/A * BoxLayout constructor
0N/A */
0N/A public void layoutContainer(Container target) {
0N/A checkContainer(target);
0N/A int nChildren = target.getComponentCount();
0N/A int[] xOffsets = new int[nChildren];
0N/A int[] xSpans = new int[nChildren];
0N/A int[] yOffsets = new int[nChildren];
0N/A int[] ySpans = new int[nChildren];
0N/A
0N/A Dimension alloc = target.getSize();
0N/A Insets in = target.getInsets();
0N/A alloc.width -= in.left + in.right;
0N/A alloc.height -= in.top + in.bottom;
0N/A
0N/A // Resolve axis to an absolute value (either X_AXIS or Y_AXIS)
0N/A ComponentOrientation o = target.getComponentOrientation();
0N/A int absoluteAxis = resolveAxis( axis, o );
0N/A boolean ltr = (absoluteAxis != axis) ? o.isLeftToRight() : true;
0N/A
0N/A
0N/A // determine the child placements
0N/A synchronized(this) {
0N/A checkRequests();
0N/A
0N/A if (absoluteAxis == X_AXIS) {
0N/A SizeRequirements.calculateTiledPositions(alloc.width, xTotal,
0N/A xChildren, xOffsets,
0N/A xSpans, ltr);
0N/A SizeRequirements.calculateAlignedPositions(alloc.height, yTotal,
0N/A yChildren, yOffsets,
0N/A ySpans);
0N/A } else {
0N/A SizeRequirements.calculateAlignedPositions(alloc.width, xTotal,
0N/A xChildren, xOffsets,
0N/A xSpans, ltr);
0N/A SizeRequirements.calculateTiledPositions(alloc.height, yTotal,
0N/A yChildren, yOffsets,
0N/A ySpans);
0N/A }
0N/A }
0N/A
0N/A // flush changes to the container
0N/A for (int i = 0; i < nChildren; i++) {
0N/A Component c = target.getComponent(i);
0N/A c.setBounds((int) Math.min((long) in.left + (long) xOffsets[i], Integer.MAX_VALUE),
0N/A (int) Math.min((long) in.top + (long) yOffsets[i], Integer.MAX_VALUE),
0N/A xSpans[i], ySpans[i]);
0N/A
0N/A }
0N/A if (dbg != null) {
0N/A for (int i = 0; i < nChildren; i++) {
0N/A Component c = target.getComponent(i);
0N/A dbg.println(c.toString());
0N/A dbg.println("X: " + xChildren[i]);
0N/A dbg.println("Y: " + yChildren[i]);
0N/A }
0N/A }
0N/A
0N/A }
0N/A
0N/A void checkContainer(Container target) {
0N/A if (this.target != target) {
0N/A throw new AWTError("BoxLayout can't be shared");
0N/A }
0N/A }
0N/A
0N/A void checkRequests() {
0N/A if (xChildren == null || yChildren == null) {
0N/A // The requests have been invalidated... recalculate
0N/A // the request information.
0N/A int n = target.getComponentCount();
0N/A xChildren = new SizeRequirements[n];
0N/A yChildren = new SizeRequirements[n];
0N/A for (int i = 0; i < n; i++) {
0N/A Component c = target.getComponent(i);
0N/A if (!c.isVisible()) {
0N/A xChildren[i] = new SizeRequirements(0,0,0, c.getAlignmentX());
0N/A yChildren[i] = new SizeRequirements(0,0,0, c.getAlignmentY());
0N/A continue;
0N/A }
0N/A Dimension min = c.getMinimumSize();
0N/A Dimension typ = c.getPreferredSize();
0N/A Dimension max = c.getMaximumSize();
0N/A xChildren[i] = new SizeRequirements(min.width, typ.width,
0N/A max.width,
0N/A c.getAlignmentX());
0N/A yChildren[i] = new SizeRequirements(min.height, typ.height,
0N/A max.height,
0N/A c.getAlignmentY());
0N/A }
0N/A
0N/A // Resolve axis to an absolute value (either X_AXIS or Y_AXIS)
0N/A int absoluteAxis = resolveAxis(axis,target.getComponentOrientation());
0N/A
0N/A if (absoluteAxis == X_AXIS) {
0N/A xTotal = SizeRequirements.getTiledSizeRequirements(xChildren);
0N/A yTotal = SizeRequirements.getAlignedSizeRequirements(yChildren);
0N/A } else {
0N/A xTotal = SizeRequirements.getAlignedSizeRequirements(xChildren);
0N/A yTotal = SizeRequirements.getTiledSizeRequirements(yChildren);
0N/A }
0N/A }
0N/A }
0N/A
0N/A /**
0N/A * Given one of the 4 axis values, resolve it to an absolute axis.
0N/A * The relative axis values, PAGE_AXIS and LINE_AXIS are converted
0N/A * to their absolute couterpart given the target's ComponentOrientation
0N/A * value. The absolute axes, X_AXIS and Y_AXIS are returned unmodified.
0N/A *
0N/A * @param axis the axis to resolve
0N/A * @param o the ComponentOrientation to resolve against
0N/A * @return the resolved axis
0N/A */
0N/A private int resolveAxis( int axis, ComponentOrientation o ) {
0N/A int absoluteAxis;
0N/A if( axis == LINE_AXIS ) {
0N/A absoluteAxis = o.isHorizontal() ? X_AXIS : Y_AXIS;
0N/A } else if( axis == PAGE_AXIS ) {
0N/A absoluteAxis = o.isHorizontal() ? Y_AXIS : X_AXIS;
0N/A } else {
0N/A absoluteAxis = axis;
0N/A }
0N/A return absoluteAxis;
0N/A }
0N/A
0N/A
0N/A private int axis;
0N/A private Container target;
0N/A
0N/A private transient SizeRequirements[] xChildren;
0N/A private transient SizeRequirements[] yChildren;
0N/A private transient SizeRequirements xTotal;
0N/A private transient SizeRequirements yTotal;
0N/A
0N/A private transient PrintStream dbg;
0N/A}