/*
* Copyright (c) 1995, 2006, Oracle and/or its affiliates. All rights reserved.
* ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*/
package java.awt;
import java.util.Hashtable;
/**
* A border layout lays out a container, arranging and resizing
* its components to fit in five regions:
* north, south, east, west, and center.
* Each region may contain no more than one component, and
* is identified by a corresponding constant:
* NORTH
, SOUTH
, EAST
,
* WEST
, and CENTER
. When adding a
* component to a container with a border layout, use one of these
* five constants, for example:
*
* Panel p = new Panel(); * p.setLayout(new BorderLayout()); * p.add(new Button("Okay"), BorderLayout.SOUTH); ** As a convenience,
BorderLayout
interprets the
* absence of a string specification the same as the constant
* CENTER
:
* * Panel p2 = new Panel(); * p2.setLayout(new BorderLayout()); * p2.add(new TextArea()); // Same as p.add(new TextArea(), BorderLayout.CENTER); **
* In addition, BorderLayout
supports the relative
* positioning constants, PAGE_START
, PAGE_END
,
* LINE_START
, and LINE_END
.
* In a container whose ComponentOrientation
is set to
* ComponentOrientation.LEFT_TO_RIGHT
, these constants map to
* NORTH
, SOUTH
, WEST
, and
* EAST
, respectively.
*
* For compatibility with previous releases, BorderLayout
* also includes the relative positioning constants BEFORE_FIRST_LINE
,
* AFTER_LAST_LINE
, BEFORE_LINE_BEGINS
and
* AFTER_LINE_ENDS
. These are equivalent to
* PAGE_START
, PAGE_END
, LINE_START
* and LINE_END
respectively. For
* consistency with the relative positioning constants used by other
* components, the latter constants are preferred.
*
* Mixing both absolute and relative positioning constants can lead to
* unpredicable results. If
* you use both types, the relative constants will take precedence.
* For example, if you add components using both the NORTH
* and PAGE_START
constants in a container whose
* orientation is LEFT_TO_RIGHT
, only the
* PAGE_START
will be layed out.
*
* NOTE: Currently (in the Java 2 platform v1.2),
* BorderLayout
does not support vertical
* orientations. The isVertical
setting on the container's
* ComponentOrientation
is not respected.
*
* The components are laid out according to their
* preferred sizes and the constraints of the container's size.
* The NORTH
and SOUTH
components may
* be stretched horizontally; the EAST
and
* WEST
components may be stretched vertically;
* the CENTER
component may stretch both horizontally
* and vertically to fill any space left over.
*
* Here is an example of five buttons in an applet laid out using
* the BorderLayout
layout manager:
*
*
*
* The code for this applet is as follows: *
*
* import java.awt.*; * import java.applet.Applet; * * public class buttonDir extends Applet { * public void init() { * setLayout(new BorderLayout()); * add(new Button("North"), BorderLayout.NORTH); * add(new Button("South"), BorderLayout.SOUTH); * add(new Button("East"), BorderLayout.EAST); * add(new Button("West"), BorderLayout.WEST); * add(new Button("Center"), BorderLayout.CENTER); * } * } *
* @author Arthur van Hoff
* @see java.awt.Container#add(String, Component)
* @see java.awt.ComponentOrientation
* @since JDK1.0
*/
public class BorderLayout implements LayoutManager2,
java.io.Serializable {
/**
* Constructs a border layout with the horizontal gaps
* between components.
* The horizontal gap is specified by hgap
.
*
* @see #getHgap()
* @see #setHgap(int)
*
* @serial
*/
int hgap;
/**
* Constructs a border layout with the vertical gaps
* between components.
* The vertical gap is specified by vgap
.
*
* @see #getVgap()
* @see #setVgap(int)
* @serial
*/
int vgap;
/**
* Constant to specify components location to be the
* north portion of the border layout.
* @serial
* @see #getChild(String, boolean)
* @see #addLayoutComponent
* @see #getLayoutAlignmentX
* @see #getLayoutAlignmentY
* @see #removeLayoutComponent
*/
Component north;
/**
* Constant to specify components location to be the
* west portion of the border layout.
* @serial
* @see #getChild(String, boolean)
* @see #addLayoutComponent
* @see #getLayoutAlignmentX
* @see #getLayoutAlignmentY
* @see #removeLayoutComponent
*/
Component west;
/**
* Constant to specify components location to be the
* east portion of the border layout.
* @serial
* @see #getChild(String, boolean)
* @see #addLayoutComponent
* @see #getLayoutAlignmentX
* @see #getLayoutAlignmentY
* @see #removeLayoutComponent
*/
Component east;
/**
* Constant to specify components location to be the
* south portion of the border layout.
* @serial
* @see #getChild(String, boolean)
* @see #addLayoutComponent
* @see #getLayoutAlignmentX
* @see #getLayoutAlignmentY
* @see #removeLayoutComponent
*/
Component south;
/**
* Constant to specify components location to be the
* center portion of the border layout.
* @serial
* @see #getChild(String, boolean)
* @see #addLayoutComponent
* @see #getLayoutAlignmentX
* @see #getLayoutAlignmentY
* @see #removeLayoutComponent
*/
Component center;
/**
*
* A relative positioning constant, that can be used instead of
* north, south, east, west or center.
* mixing the two types of constants can lead to unpredicable results. If
* you use both types, the relative constants will take precedence.
* For example, if you add components using both the NORTH
* and BEFORE_FIRST_LINE
constants in a container whose
* orientation is LEFT_TO_RIGHT
, only the
* BEFORE_FIRST_LINE
will be layed out.
* This will be the same for lastLine, firstItem, lastItem.
* @serial
*/
Component firstLine;
/**
* A relative positioning constant, that can be used instead of
* north, south, east, west or center.
* Please read Description for firstLine.
* @serial
*/
Component lastLine;
/**
* A relative positioning constant, that can be used instead of
* north, south, east, west or center.
* Please read Description for firstLine.
* @serial
*/
Component firstItem;
/**
* A relative positioning constant, that can be used instead of
* north, south, east, west or center.
* Please read Description for firstLine.
* @serial
*/
Component lastItem;
/**
* The north layout constraint (top of container).
*/
public static final String NORTH = "North";
/**
* The south layout constraint (bottom of container).
*/
public static final String SOUTH = "South";
/**
* The east layout constraint (right side of container).
*/
public static final String EAST = "East";
/**
* The west layout constraint (left side of container).
*/
public static final String WEST = "West";
/**
* The center layout constraint (middle of container).
*/
public static final String CENTER = "Center";
/**
* Synonym for PAGE_START. Exists for compatibility with previous
* versions. PAGE_START is preferred.
*
* @see #PAGE_START
* @since 1.2
*/
public static final String BEFORE_FIRST_LINE = "First";
/**
* Synonym for PAGE_END. Exists for compatibility with previous
* versions. PAGE_END is preferred.
*
* @see #PAGE_END
* @since 1.2
*/
public static final String AFTER_LAST_LINE = "Last";
/**
* Synonym for LINE_START. Exists for compatibility with previous
* versions. LINE_START is preferred.
*
* @see #LINE_START
* @since 1.2
*/
public static final String BEFORE_LINE_BEGINS = "Before";
/**
* Synonym for LINE_END. Exists for compatibility with previous
* versions. LINE_END is preferred.
*
* @see #LINE_END
* @since 1.2
*/
public static final String AFTER_LINE_ENDS = "After";
/**
* The component comes before the first line of the layout's content.
* For Western, left-to-right and top-to-bottom orientations, this is
* equivalent to NORTH.
*
* @see java.awt.Component#getComponentOrientation
* @since 1.4
*/
public static final String PAGE_START = BEFORE_FIRST_LINE;
/**
* The component comes after the last line of the layout's content.
* For Western, left-to-right and top-to-bottom orientations, this is
* equivalent to SOUTH.
*
* @see java.awt.Component#getComponentOrientation
* @since 1.4
*/
public static final String PAGE_END = AFTER_LAST_LINE;
/**
* The component goes at the beginning of the line direction for the
* layout. For Western, left-to-right and top-to-bottom orientations,
* this is equivalent to WEST.
*
* @see java.awt.Component#getComponentOrientation
* @since 1.4
*/
public static final String LINE_START = BEFORE_LINE_BEGINS;
/**
* The component goes at the end of the line direction for the
* layout. For Western, left-to-right and top-to-bottom orientations,
* this is equivalent to EAST.
*
* @see java.awt.Component#getComponentOrientation
* @since 1.4
*/
public static final String LINE_END = AFTER_LINE_ENDS;
/*
* JDK 1.1 serialVersionUID
*/
private static final long serialVersionUID = -8658291919501921765L;
/**
* Constructs a new border layout with
* no gaps between components.
*/
public BorderLayout() {
this(0, 0);
}
/**
* Constructs a border layout with the specified gaps
* between components.
* The horizontal gap is specified by hgap
* and the vertical gap is specified by vgap
.
* @param hgap the horizontal gap.
* @param vgap the vertical gap.
*/
public BorderLayout(int hgap, int vgap) {
this.hgap = hgap;
this.vgap = vgap;
}
/**
* Returns the horizontal gap between components.
* @since JDK1.1
*/
public int getHgap() {
return hgap;
}
/**
* Sets the horizontal gap between components.
* @param hgap the horizontal gap between components
* @since JDK1.1
*/
public void setHgap(int hgap) {
this.hgap = hgap;
}
/**
* Returns the vertical gap between components.
* @since JDK1.1
*/
public int getVgap() {
return vgap;
}
/**
* Sets the vertical gap between components.
* @param vgap the vertical gap between components
* @since JDK1.1
*/
public void setVgap(int vgap) {
this.vgap = vgap;
}
/**
* Adds the specified component to the layout, using the specified
* constraint object. For border layouts, the constraint must be
* one of the following constants: NORTH
,
* SOUTH
, EAST
,
* WEST
, or CENTER
.
*
* Most applications do not call this method directly. This method
* is called when a component is added to a container using the
* Container.add
method with the same argument types.
* @param comp the component to be added.
* @param constraints an object that specifies how and where
* the component is added to the layout.
* @see java.awt.Container#add(java.awt.Component, java.lang.Object)
* @exception IllegalArgumentException if the constraint object is not
* a string, or if it not one of the five specified
* constants.
* @since JDK1.1
*/
public void addLayoutComponent(Component comp, Object constraints) {
synchronized (comp.getTreeLock()) {
if ((constraints == null) || (constraints instanceof String)) {
addLayoutComponent((String)constraints, comp);
} else {
throw new IllegalArgumentException("cannot add to layout: constraint must be a string (or null)");
}
}
}
/**
* @deprecated replaced by addLayoutComponent(Component, Object)
.
*/
@Deprecated
public void addLayoutComponent(String name, Component comp) {
synchronized (comp.getTreeLock()) {
/* Special case: treat null the same as "Center". */
if (name == null) {
name = "Center";
}
/* Assign the component to one of the known regions of the layout.
*/
if ("Center".equals(name)) {
center = comp;
} else if ("North".equals(name)) {
north = comp;
} else if ("South".equals(name)) {
south = comp;
} else if ("East".equals(name)) {
east = comp;
} else if ("West".equals(name)) {
west = comp;
} else if (BEFORE_FIRST_LINE.equals(name)) {
firstLine = comp;
} else if (AFTER_LAST_LINE.equals(name)) {
lastLine = comp;
} else if (BEFORE_LINE_BEGINS.equals(name)) {
firstItem = comp;
} else if (AFTER_LINE_ENDS.equals(name)) {
lastItem = comp;
} else {
throw new IllegalArgumentException("cannot add to layout: unknown constraint: " + name);
}
}
}
/**
* Removes the specified component from this border layout. This
* method is called when a container calls its remove
or
* removeAll
methods. Most applications do not call this
* method directly.
* @param comp the component to be removed.
* @see java.awt.Container#remove(java.awt.Component)
* @see java.awt.Container#removeAll()
*/
public void removeLayoutComponent(Component comp) {
synchronized (comp.getTreeLock()) {
if (comp == center) {
center = null;
} else if (comp == north) {
north = null;
} else if (comp == south) {
south = null;
} else if (comp == east) {
east = null;
} else if (comp == west) {
west = null;
}
if (comp == firstLine) {
firstLine = null;
} else if (comp == lastLine) {
lastLine = null;
} else if (comp == firstItem) {
firstItem = null;
} else if (comp == lastItem) {
lastItem = null;
}
}
}
/**
* Gets the component that was added using the given constraint
*
* @param constraints the desired constraint, one of CENTER
,
* NORTH
, SOUTH
,
* WEST
, EAST
,
* PAGE_START
, PAGE_END
,
* LINE_START
, LINE_END
* @return the component at the given location, or null
if
* the location is empty
* @exception IllegalArgumentException if the constraint object is
* not one of the nine specified constants
* @see #addLayoutComponent(java.awt.Component, java.lang.Object)
* @since 1.5
*/
public Component getLayoutComponent(Object constraints) {
if (CENTER.equals(constraints)) {
return center;
} else if (NORTH.equals(constraints)) {
return north;
} else if (SOUTH.equals(constraints)) {
return south;
} else if (WEST.equals(constraints)) {
return west;
} else if (EAST.equals(constraints)) {
return east;
} else if (PAGE_START.equals(constraints)) {
return firstLine;
} else if (PAGE_END.equals(constraints)) {
return lastLine;
} else if (LINE_START.equals(constraints)) {
return firstItem;
} else if (LINE_END.equals(constraints)) {
return lastItem;
} else {
throw new IllegalArgumentException("cannot get component: unknown constraint: " + constraints);
}
}
/**
* Returns the component that corresponds to the given constraint location
* based on the target Container
's component orientation.
* Components added with the relative constraints PAGE_START
,
* PAGE_END
, LINE_START
, and LINE_END
* take precedence over components added with the explicit constraints
* NORTH
, SOUTH
, WEST
, and EAST
.
* The Container
's component orientation is used to determine the location of components
* added with LINE_START
and LINE_END
.
*
* @param constraints the desired absolute position, one of CENTER
,
* NORTH
, SOUTH
,
* EAST
, WEST
* @param target the {@code Container} used to obtain
* the constraint location based on the target
* {@code Container}'s component orientation.
* @return the component at the given location, or null
if
* the location is empty
* @exception IllegalArgumentException if the constraint object is
* not one of the five specified constants
* @exception NullPointerException if the target parameter is null
* @see #addLayoutComponent(java.awt.Component, java.lang.Object)
* @since 1.5
*/
public Component getLayoutComponent(Container target, Object constraints) {
boolean ltr = target.getComponentOrientation().isLeftToRight();
Component result = null;
if (NORTH.equals(constraints)) {
result = (firstLine != null) ? firstLine : north;
} else if (SOUTH.equals(constraints)) {
result = (lastLine != null) ? lastLine : south;
} else if (WEST.equals(constraints)) {
result = ltr ? firstItem : lastItem;
if (result == null) {
result = west;
}
} else if (EAST.equals(constraints)) {
result = ltr ? lastItem : firstItem;
if (result == null) {
result = east;
}
} else if (CENTER.equals(constraints)) {
result = center;
} else {
throw new IllegalArgumentException("cannot get component: invalid constraint: " + constraints);
}
return result;
}
/**
* Gets the constraints for the specified component
*
* @param comp the component to be queried
* @return the constraint for the specified component,
* or null if component is null or is not present
* in this layout
* @see #addLayoutComponent(java.awt.Component, java.lang.Object)
* @since 1.5
*/
public Object getConstraints(Component comp) {
//fix for 6242148 : API method java.awt.BorderLayout.getConstraints(null) should return null
if (comp == null){
return null;
}
if (comp == center) {
return CENTER;
} else if (comp == north) {
return NORTH;
} else if (comp == south) {
return SOUTH;
} else if (comp == west) {
return WEST;
} else if (comp == east) {
return EAST;
} else if (comp == firstLine) {
return PAGE_START;
} else if (comp == lastLine) {
return PAGE_END;
} else if (comp == firstItem) {
return LINE_START;
} else if (comp == lastItem) {
return LINE_END;
}
return null;
}
/**
* Determines the minimum size of the target
container
* using this layout manager.
*
* This method is called when a container calls its
* getMinimumSize
method. Most applications do not call
* this method directly.
* @param target the container in which to do the layout.
* @return the minimum dimensions needed to lay out the subcomponents
* of the specified container.
* @see java.awt.Container
* @see java.awt.BorderLayout#preferredLayoutSize
* @see java.awt.Container#getMinimumSize()
*/
public Dimension minimumLayoutSize(Container target) {
synchronized (target.getTreeLock()) {
Dimension dim = new Dimension(0, 0);
boolean ltr = target.getComponentOrientation().isLeftToRight();
Component c = null;
if ((c=getChild(EAST,ltr)) != null) {
Dimension d = c.getMinimumSize();
dim.width += d.width + hgap;
dim.height = Math.max(d.height, dim.height);
}
if ((c=getChild(WEST,ltr)) != null) {
Dimension d = c.getMinimumSize();
dim.width += d.width + hgap;
dim.height = Math.max(d.height, dim.height);
}
if ((c=getChild(CENTER,ltr)) != null) {
Dimension d = c.getMinimumSize();
dim.width += d.width;
dim.height = Math.max(d.height, dim.height);
}
if ((c=getChild(NORTH,ltr)) != null) {
Dimension d = c.getMinimumSize();
dim.width = Math.max(d.width, dim.width);
dim.height += d.height + vgap;
}
if ((c=getChild(SOUTH,ltr)) != null) {
Dimension d = c.getMinimumSize();
dim.width = Math.max(d.width, dim.width);
dim.height += d.height + vgap;
}
Insets insets = target.getInsets();
dim.width += insets.left + insets.right;
dim.height += insets.top + insets.bottom;
return dim;
}
}
/**
* Determines the preferred size of the target
* container using this layout manager, based on the components
* in the container.
*
* Most applications do not call this method directly. This method
* is called when a container calls its getPreferredSize
* method.
* @param target the container in which to do the layout.
* @return the preferred dimensions to lay out the subcomponents
* of the specified container.
* @see java.awt.Container
* @see java.awt.BorderLayout#minimumLayoutSize
* @see java.awt.Container#getPreferredSize()
*/
public Dimension preferredLayoutSize(Container target) {
synchronized (target.getTreeLock()) {
Dimension dim = new Dimension(0, 0);
boolean ltr = target.getComponentOrientation().isLeftToRight();
Component c = null;
if ((c=getChild(EAST,ltr)) != null) {
Dimension d = c.getPreferredSize();
dim.width += d.width + hgap;
dim.height = Math.max(d.height, dim.height);
}
if ((c=getChild(WEST,ltr)) != null) {
Dimension d = c.getPreferredSize();
dim.width += d.width + hgap;
dim.height = Math.max(d.height, dim.height);
}
if ((c=getChild(CENTER,ltr)) != null) {
Dimension d = c.getPreferredSize();
dim.width += d.width;
dim.height = Math.max(d.height, dim.height);
}
if ((c=getChild(NORTH,ltr)) != null) {
Dimension d = c.getPreferredSize();
dim.width = Math.max(d.width, dim.width);
dim.height += d.height + vgap;
}
if ((c=getChild(SOUTH,ltr)) != null) {
Dimension d = c.getPreferredSize();
dim.width = Math.max(d.width, dim.width);
dim.height += d.height + vgap;
}
Insets insets = target.getInsets();
dim.width += insets.left + insets.right;
dim.height += insets.top + insets.bottom;
return dim;
}
}
/**
* Returns the maximum dimensions for this layout given the components
* in the specified target container.
* @param target the component which needs to be laid out
* @see Container
* @see #minimumLayoutSize
* @see #preferredLayoutSize
*/
public Dimension maximumLayoutSize(Container target) {
return new Dimension(Integer.MAX_VALUE, Integer.MAX_VALUE);
}
/**
* 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.
*/
public float getLayoutAlignmentX(Container parent) {
return 0.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.
*/
public float getLayoutAlignmentY(Container parent) {
return 0.5f;
}
/**
* Invalidates the layout, indicating that if the layout manager
* has cached information it should be discarded.
*/
public void invalidateLayout(Container target) {
}
/**
* Lays out the container argument using this border layout.
*
* This method actually reshapes the components in the specified
* container in order to satisfy the constraints of this
* BorderLayout
object. The NORTH
* and SOUTH
components, if any, are placed at
* the top and bottom of the container, respectively. The
* WEST
and EAST
components are
* then placed on the left and right, respectively. Finally,
* the CENTER
object is placed in any remaining
* space in the middle.
*
* Most applications do not call this method directly. This method
* is called when a container calls its doLayout
method.
* @param target the container in which to do the layout.
* @see java.awt.Container
* @see java.awt.Container#doLayout()
*/
public void layoutContainer(Container target) {
synchronized (target.getTreeLock()) {
Insets insets = target.getInsets();
int top = insets.top;
int bottom = target.height - insets.bottom;
int left = insets.left;
int right = target.width - insets.right;
boolean ltr = target.getComponentOrientation().isLeftToRight();
Component c = null;
if ((c=getChild(NORTH,ltr)) != null) {
c.setSize(right - left, c.height);
Dimension d = c.getPreferredSize();
c.setBounds(left, top, right - left, d.height);
top += d.height + vgap;
}
if ((c=getChild(SOUTH,ltr)) != null) {
c.setSize(right - left, c.height);
Dimension d = c.getPreferredSize();
c.setBounds(left, bottom - d.height, right - left, d.height);
bottom -= d.height + vgap;
}
if ((c=getChild(EAST,ltr)) != null) {
c.setSize(c.width, bottom - top);
Dimension d = c.getPreferredSize();
c.setBounds(right - d.width, top, d.width, bottom - top);
right -= d.width + hgap;
}
if ((c=getChild(WEST,ltr)) != null) {
c.setSize(c.width, bottom - top);
Dimension d = c.getPreferredSize();
c.setBounds(left, top, d.width, bottom - top);
left += d.width + hgap;
}
if ((c=getChild(CENTER,ltr)) != null) {
c.setBounds(left, top, right - left, bottom - top);
}
}
}
/**
* Get the component that corresponds to the given constraint location
*
* @param key The desired absolute position,
* either NORTH, SOUTH, EAST, or WEST.
* @param ltr Is the component line direction left-to-right?
*/
private Component getChild(String key, boolean ltr) {
Component result = null;
if (key == NORTH) {
result = (firstLine != null) ? firstLine : north;
}
else if (key == SOUTH) {
result = (lastLine != null) ? lastLine : south;
}
else if (key == WEST) {
result = ltr ? firstItem : lastItem;
if (result == null) {
result = west;
}
}
else if (key == EAST) {
result = ltr ? lastItem : firstItem;
if (result == null) {
result = east;
}
}
else if (key == CENTER) {
result = center;
}
if (result != null && !result.visible) {
result = null;
}
return result;
}
/**
* Returns a string representation of the state of this border layout.
* @return a string representation of this border layout.
*/
public String toString() {
return getClass().getName() + "[hgap=" + hgap + ",vgap=" + vgap + "]";
}
}