diff options
Diffstat (limited to 'libjava/classpath/javax/swing/BoxLayout.java')
-rw-r--r-- | libjava/classpath/javax/swing/BoxLayout.java | 693 |
1 files changed, 194 insertions, 499 deletions
diff --git a/libjava/classpath/javax/swing/BoxLayout.java b/libjava/classpath/javax/swing/BoxLayout.java index 28bb53928ef..ebc0b4c211c 100644 --- a/libjava/classpath/javax/swing/BoxLayout.java +++ b/libjava/classpath/javax/swing/BoxLayout.java @@ -45,12 +45,6 @@ import java.awt.Dimension; import java.awt.Insets; import java.awt.LayoutManager2; import java.io.Serializable; -import java.util.Collection; -import java.util.Iterator; -import java.util.List; -import java.util.Vector; - -import gnu.java.awt.AWTUtilities; /** * A layout that stacks the children of a container in a Box, either @@ -63,248 +57,6 @@ public class BoxLayout implements LayoutManager2, Serializable { /** - * This is an abstraction that allows the BoxLayout algorithm to - * be applied to both direction (X and Y) without duplicating the - * algorithm. It defines several methods that access properties of - * a component for a specific direction. - */ - static interface Direction - { - /** - * Returns the correct part of <code>d</code> for this direction. This will - * be <code>d.width</code> for horizontal and <code>d.height</code> for - * vertical direction. - * - * @param d the size as Dimension object - * - * @return the correct part of <code>d</code> for this direction - */ - int size(Dimension d); - - /** - * Returns the lower bounds of the {@link Insets} object according to this - * direction. This will be <code>insets.top</code> for vertical direction - * and <code>insets.left</code> for horizontal direction. - * - * @param the {@link Insets} object from which to return the lower bounds - * - * @return the lower bounds of the {@link Insets} object according to this - * direction - */ - int lower(Insets insets); - - /** - * Returns the alignment property according to this direction. - * - * @param comp the Component for which to return the alignment property - * - * @return the alignment property according to this direction - */ - float alignment(Component comp); - - /** - * Sets the location for Component <code>c</code>. <code>coord1</code> - * specifies the coordinate of the location in this direction, - * <code>coord2</code> the coordinate of the location in the opposite - * direction. - * - * @param c the Component for which to set the location - * @param coord1 the coordinate in this direction - * @param coord2 the coordinate in the opposite direction - */ - void setLocation(Component c, int coord1, int coord2); - - /** - * Sets the size for Component <code>c</code>. <code>coord1</code> - * specifies the size in this direction, - * <code>coord2</code> the size in the opposite - * direction. - * - * @param c the Component for which to set the size - * @param size1 the size in this direction - * @param size2 the size in the opposite direction - */ - void setSize(Component c, int size1, int size2); - } - - /** - * The horizontal direction. - */ - static class Horizontal implements Direction - { - /** - * Returns the correct part of <code>d</code> for this direction. This will - * be <code>d.width</code> for horizontal and <code>d.height</code> for - * vertical direction. - * - * @param d the size as Dimension object - * - * @return the correct part of <code>d</code> for this direction - */ - public int size(Dimension d) - { - return d.width; - } - - /** - * Returns the lower bounds of the {@link Insets} object according to this - * direction. This will be <code>insets.top</code> for vertical direction - * and <code>insets.left</code> for horizontal direction. - * - * @param insets the {@link Insets} object from which to return the lower - * bounds - * - * @return the lower bounds of the {@link Insets} object according to this - * direction - */ - public int lower(Insets insets) - { - return insets.left; - } - - /** - * Returns the alignment property according to this direction. - * - * @param comp the Component for which to return the alignment property - * - * @return the alignment property according to this direction - */ - public float alignment(Component comp) - { - return comp.getAlignmentX(); - } - - /** - * Sets the location for Component <code>c</code>. <code>coord1</code> - * specifies the coordinate of the location in this direction, - * <code>coord2</code> the coordinate of the location in the opposite - * direction. - * - * @param c the Component for which to set the location - * @param coord1 the coordinate in this direction - * @param coord2 the coordinate in the opposite direction - */ - public void setLocation(Component c, int coord1, int coord2) - { - c.setLocation(coord1, coord2); - } - - /** - * Sets the size for Component <code>c</code>. <code>coord1</code> - * specifies the size in this direction, - * <code>coord2</code> the size in the opposite - * direction. - * - * @param c the Component for which to set the size - * @param size1 the size in this direction - * @param size2 the size in the opposite direction - */ - public void setSize(Component c, int size1, int size2) - { - c.setSize(size1, size2); - } - } - /** - * The vertical direction. - */ - static class Vertical implements Direction - { - /** - * Returns the correct part of <code>d</code> for this direction. This will - * be <code>d.width</code> for horizontal and <code>d.height</code> for - * vertical direction. - * - * @param d the size as Dimension object - * - * @return the correct part of <code>d</code> for this direction - */ - public int size(Dimension d) - { - return d.height; - } - - /** - * Returns the lower bounds of the {@link Insets} object according to this - * direction. This will be <code>insets.top</code> for vertical direction - * and <code>insets.left</code> for horizontal direction. - * - * @param insets the {@link Insets} object from which to return the lower - * bounds - * - * @return the lower bounds of the {@link Insets} object according to this - * direction - */ - public int lower(Insets insets) - { - return insets.top; - } - - /** - * Returns the alignment property according to this direction. - * - * @param comp the Component for which to return the alignment property - * - * @return the alignment property according to this direction - */ - public float alignment(Component comp) - { - return comp.getAlignmentY(); - } - - /** - * Sets the location for Component <code>c</code>. <code>coord1</code> - * specifies the coordinate of the location in this direction, - * <code>coord2</code> the coordinate of the location in the opposite - * direction. - * - * @param c the Component for which to set the location - * @param coord1 the coordinate in this direction - * @param coord2 the coordinate in the opposite direction - */ - public void setLocation(Component c, int coord1, int coord2) - { - c.setLocation(coord2, coord1); - } - - /** - * Sets the size for Component <code>c</code>. <code>coord1</code> - * specifies the size in this direction, - * <code>coord2</code> the size in the opposite - * direction. - * - * @param c the Component for which to set the size - * @param size1 the size in this direction - * @param size2 the size in the opposite direction - */ - public void setSize(Component c, int size1, int size2) - { - c.setSize(size2, size1); - } - } - - /** - * A helper class that temporarily stores the size specs of a component. - */ - static class SizeReq - { - int size; - int min; - int pref; - int max; - float align; - Component comp; - SizeReq(Component comp, Direction dir) - { - this.min = dir.size(comp.getMinimumSize()); - this.pref = dir.size(comp.getPreferredSize()); - this.max = dir.size(comp.getMaximumSize()); - this.size = dir.size(comp.getSize()); - this.align = dir.alignment(comp); - this.comp = comp; - } - } - - /** * Specifies that components are laid out left to right. */ public static final int X_AXIS = 0; @@ -334,16 +86,50 @@ public class BoxLayout implements LayoutManager2, Serializable */ private Container container; - /* + /** * Current type of component layouting. Defaults to X_AXIS. */ private int way = X_AXIS; - /** Constant for the horizontal direction. */ - private static final Direction HORIZONTAL = new Horizontal(); + /** + * The size requirements of the containers children for the X direction. + */ + private SizeRequirements[] xChildren; + + /** + * The size requirements of the containers children for the Y direction. + */ + private SizeRequirements[] yChildren; + + /** + * The size requirements of the container to be laid out for the X direction. + */ + private SizeRequirements xTotal; + + /** + * The size requirements of the container to be laid out for the Y direction. + */ + private SizeRequirements yTotal; + + /** + * The offsets of the child components in the X direction. + */ + private int[] offsetsX; + + /** + * The offsets of the child components in the Y direction. + */ + private int[] offsetsY; + + /** + * The spans of the child components in the X direction. + */ + private int[] spansX; - /** Constant for the vertical direction. */ - private static final Direction VERTICAL = new Vertical(); + /** + * The spans of the child components in the Y direction. + */ + private int[] spansY; /** * Constructs a <code>BoxLayout</code> object. @@ -355,6 +141,9 @@ public class BoxLayout implements LayoutManager2, Serializable */ public BoxLayout(Container container, int way) { + if (way != X_AXIS && way != Y_AXIS && way != LINE_AXIS && way != PAGE_AXIS) + throw new AWTError("Invalid axis"); + int width = 0; int height = 0; this.container = container; @@ -369,6 +158,7 @@ public class BoxLayout implements LayoutManager2, Serializable */ public void addLayoutComponent(String name, Component component) { + // Nothing to do here. } /** @@ -378,6 +168,7 @@ public class BoxLayout implements LayoutManager2, Serializable */ public void removeLayoutComponent(Component component) { + // Nothing to do here. } private boolean isHorizontalIn(Container parent) @@ -401,45 +192,16 @@ public class BoxLayout implements LayoutManager2, Serializable */ public Dimension preferredLayoutSize(Container parent) { - if (parent != container) - throw new AWTError("invalid parent"); - - Insets insets = parent.getInsets(); - int x = 0; - int y = 0; - - List children = AWTUtilities.getVisibleChildren(parent); + synchronized (container.getTreeLock()) + { + if (container != parent) + throw new AWTError("BoxLayout can't be shared"); - if (isHorizontalIn(parent)) - { - x = insets.left + insets.right; - // sum up preferred widths of components, find maximum of preferred - // heights - for (Iterator i = children.iterator(); i.hasNext();) - { - Component comp = (Component) i.next(); - Dimension sz = comp.getPreferredSize(); - x += sz.width; - y = Math.max(y, sz.height); - } - y += insets.bottom + insets.top; - } - else - { - y = insets.top + insets.bottom; - // sum up preferred heights of components, find maximum of - // preferred widths - for (Iterator i = children.iterator(); i.hasNext();) - { - Component comp = (Component) i.next(); - Dimension sz = comp.getPreferredSize(); - y += sz.height; - x = Math.max(x, sz.width); - } - x += insets.left + insets.right; + checkTotalRequirements(); + Insets i = container.getInsets(); + return new Dimension(xTotal.preferred + i.left + i.right, + yTotal.preferred + i.top + i.bottom); } - - return new Dimension(x, y); } /** @@ -451,41 +213,16 @@ public class BoxLayout implements LayoutManager2, Serializable */ public Dimension minimumLayoutSize(Container parent) { - if (parent != container) - throw new AWTError("invalid parent"); - - Insets insets = parent.getInsets(); - int x = insets.left + insets.right; - int y = insets.bottom + insets.top; - - List children = AWTUtilities.getVisibleChildren(parent); - - if (isHorizontalIn(parent)) + synchronized (container.getTreeLock()) { - // sum up preferred widths of components, find maximum of preferred - // heights - for (Iterator i = children.iterator(); i.hasNext();) - { - Component comp = (Component) i.next(); - Dimension sz = comp.getMinimumSize(); - x += sz.width; - y = Math.max(y, sz.height); - } - } - else - { - // sum up preferred heights of components, find maximum of - // preferred widths - for (Iterator i = children.iterator(); i.hasNext();) - { - Component comp = (Component) i.next(); - Dimension sz = comp.getMinimumSize(); - y += sz.height; - x = Math.max(x, sz.width); - } + if (container != parent) + throw new AWTError("BoxLayout can't be shared"); + + checkTotalRequirements(); + Insets i = container.getInsets(); + return new Dimension(xTotal.minimum + i.left + i.right, + yTotal.minimum + i.top + i.bottom); } - - return new Dimension(x, y); } /** @@ -495,12 +232,20 @@ public class BoxLayout implements LayoutManager2, Serializable */ public void layoutContainer(Container parent) { - if (isHorizontalIn(parent)) - layoutAlgorithm(parent, HORIZONTAL, VERTICAL); - else - layoutAlgorithm(parent, VERTICAL, HORIZONTAL); + synchronized (container.getTreeLock()) + { + if (container != parent) + throw new AWTError("BoxLayout can't be shared"); + + checkLayout(); + Component[] children = container.getComponents(); + Insets in = container.getInsets(); + for (int i = 0; i < children.length; i++) + children[i].setBounds(offsetsX[i] + in.left, offsetsY[i] + in.top, + spansX[i], spansY[i]); + } } - + /** * Adds a component to the layout. Not used in BoxLayout * @@ -509,6 +254,7 @@ public class BoxLayout implements LayoutManager2, Serializable */ public void addLayoutComponent(Component child, Object constraints) { + // Nothing to do here. } /** @@ -520,10 +266,14 @@ public class BoxLayout implements LayoutManager2, Serializable */ public float getLayoutAlignmentX(Container parent) { - if (parent != container) - throw new AWTError("invalid parent"); - - return 0; + synchronized (container.getTreeLock()) + { + if (container != parent) + throw new AWTError("BoxLayout can't be shared"); + + checkTotalRequirements(); + return xTotal.alignment; + } } /** @@ -535,10 +285,14 @@ public class BoxLayout implements LayoutManager2, Serializable */ public float getLayoutAlignmentY(Container parent) { - if (parent != container) - throw new AWTError("invalid parent"); - - return 0; + synchronized (container.getTreeLock()) + { + if (container != parent) + throw new AWTError("BoxLayout can't be shared"); + + checkTotalRequirements(); + return yTotal.alignment; + } } /** @@ -548,8 +302,20 @@ public class BoxLayout implements LayoutManager2, Serializable */ public void invalidateLayout(Container parent) { - if (parent != container) - throw new AWTError("invalid parent"); + if (container != parent) + throw new AWTError("BoxLayout can't be shared"); + + synchronized (container.getTreeLock()) + { + xChildren = null; + yChildren = null; + xTotal = null; + yTotal = null; + offsetsX = null; + offsetsY = null; + spansX = null; + spansY = null; + } } /** @@ -562,188 +328,117 @@ public class BoxLayout implements LayoutManager2, Serializable */ public Dimension maximumLayoutSize(Container parent) { - if (parent != container) - throw new AWTError("invalid parent"); - - Insets insets = parent.getInsets(); - int x = insets.left + insets.right; - int y = insets.top + insets.bottom; + synchronized (container.getTreeLock()) + { + if (container != parent) + throw new AWTError("BoxLayout can't be shared"); - List children = AWTUtilities.getVisibleChildren(parent); + checkTotalRequirements(); + Insets i = container.getInsets(); + return new Dimension(xTotal.maximum + i.left + i.right, + yTotal.maximum + i.top + i.bottom); + } + } - if (isHorizontalIn(parent)) + /** + * Makes sure that the xTotal and yTotal fields are set up correctly. A call + * to {@link #invalidateLayout} sets these fields to null and they have to be + * recomputed. + */ + private void checkTotalRequirements() + { + if (xTotal == null || yTotal == null) { - - // sum up preferred widths of components, find maximum of preferred - // heights - for (Iterator i = children.iterator(); i.hasNext();) + checkRequirements(); + if (isHorizontalIn(container)) { - Component comp = (Component) i.next(); - Dimension sz = comp.getMaximumSize(); - x += sz.width; - // Check for overflow. - if (x < 0) - x = Integer.MAX_VALUE; - y = Math.max(y, sz.height); + xTotal = SizeRequirements.getTiledSizeRequirements(xChildren); + yTotal = SizeRequirements.getAlignedSizeRequirements(yChildren); } - } - else - { - // sum up preferred heights of components, find maximum of - // preferred widths - for (Iterator i = children.iterator(); i.hasNext();) + else { - Component comp = (Component) i.next(); - Dimension sz = comp.getMaximumSize(); - y += sz.height; - // Check for overflow - if (y < 0) - y = Integer.MAX_VALUE; - x = Math.max(x, sz.width); + xTotal = SizeRequirements.getAlignedSizeRequirements(xChildren); + yTotal = SizeRequirements.getTiledSizeRequirements(yChildren); } - } - return new Dimension(x, y); + } } /** - * Lays out the Container <code>c</code> in the layout direction - * <code>layoutDir</code>. The direction that is crossing the layout - * direction is specified in <code>crossDir</code>. - * - * @param parent - * @param layoutDir - * @param crossDir + * Makes sure that the xChildren and yChildren fields are correctly set up. + * A call to {@link #invalidateLayout(Container)} sets these fields to null, + * so they have to be set up again. */ - void layoutAlgorithm(Container parent, Direction layoutDir, Direction crossDir) + private void checkRequirements() { - if (parent != container) - throw new AWTError("invalid parent"); - - Dimension parentSize = parent.getSize(); - Insets insets = parent.getInsets(); - Dimension innerSize = new Dimension(parentSize.width - insets.left - - insets.right, parentSize.height - - insets.bottom - insets.top); - - // Set all components to their preferredSizes and sum up the allocated - // space. Create SizeReqs for each component and store them in - // sizeReqs. Find the maximum size in the crossing direction. - List children = AWTUtilities.getVisibleChildren(parent); - Vector sizeReqs = new Vector(); - int allocated = 0; - for (Iterator i = children.iterator(); i.hasNext();) - { - Component c = (Component) i.next(); - SizeReq sizeReq = new SizeReq(c, layoutDir); - int preferred = layoutDir.size(c.getPreferredSize()); - sizeReq.size = preferred; - allocated += preferred; - sizeReqs.add(sizeReq); - } - - // Distribute remaining space (may be positive or negative) over components - int remainder = layoutDir.size(innerSize) - allocated; - distributeSpace(sizeReqs, remainder, layoutDir); - - // Resize and relocate components. If the component can be sized to - // take the full space in the crossing direction, then do so, otherwise - // align according to its alingnmentX or alignmentY property. - int loc = 0; - int offset1 = layoutDir.lower(insets); - int offset2 = crossDir.lower(insets); - for (Iterator i = sizeReqs.iterator(); i.hasNext();) + if (xChildren == null || yChildren == null) { - SizeReq sizeReq = (SizeReq) i.next(); - Component c = sizeReq.comp; - int availCrossSize = crossDir.size(innerSize); - int maxCross = crossDir.size(c.getMaximumSize()); - int crossSize = Math.min(availCrossSize, maxCross); - int crossRemainder = availCrossSize - crossSize; - int crossLoc = (int) (crossDir.alignment(c) * crossRemainder); - layoutDir.setSize(c, sizeReq.size, crossSize); - layoutDir.setLocation(c, offset1 + loc, offset2 + crossLoc); - loc += sizeReq.size; + Component[] children = container.getComponents(); + xChildren = new SizeRequirements[children.length]; + yChildren = new SizeRequirements[children.length]; + for (int i = 0; i < children.length; i++) + { + if (! children[i].isVisible()) + { + xChildren[i] = new SizeRequirements(); + yChildren[i] = new SizeRequirements(); + } + else + { + xChildren[i] = + new SizeRequirements(children[i].getMinimumSize().width, + children[i].getPreferredSize().width, + children[i].getMaximumSize().width, + children[i].getAlignmentX()); + yChildren[i] = + new SizeRequirements(children[i].getMinimumSize().height, + children[i].getPreferredSize().height, + children[i].getMaximumSize().height, + children[i].getAlignmentY()); + } + } } } /** - * Distributes some space over a set of components. This implementation - * tries to set the components as close as possible to their - * <code>preferredSize</code>s, and respects the components - * <code>minimumSize</code> and <code>maximumSize</code>. - * - * The algorithm is implemented as follows: - * - * <ul> - * <li>The <code>remainder</code> is divided by the number of components - * in <code>freeComponents</code>.</li> - * <li>The result is added to (or substracted from) the size of each - * component.</li> - * <li>If the <code>minimumSize</code> or <code>maximumSize</code> of a - * component is exceeded, then this component is set to its - * <code>minimumSize</code> or <code>maximumSize</code>, it is removed from - * <code>freeComponents</code> and the difference is added to a new - * remainder.</li> - * <li>Finally, if there is a new remainer != 0 and the - * <code>freeComponents.size() != 0</code>, then this method is called - * recursivly to distribute the newly allocated remaining space.</li> - * </ul> - * - * @param freeComponents a SizeReq collection for components that have space - * left so that they can be moved freely - * @param remainder the space that should be distributed between the - * components - * @param dir the direction in which we operate + * Makes sure that the offsetsX, offsetsY, spansX and spansY fields are set + * up correctly. A call to {@link #invalidateLayout} sets these fields + * to null and they have to be recomputed. */ - void distributeSpace(Collection freeComponents, int remainder, Direction dir) + private void checkLayout() { - // Sum up total available space in components. If the remainder is negative - // then we sum up the difference between minSize and size. If remainder - // is positive we sum up the difference between maxSize and size. - double totalAvailable = 0; - for (Iterator i = freeComponents.iterator(); i.hasNext();) - { - SizeReq sizeReq = (SizeReq) i.next(); - if (remainder >= 0) - totalAvailable += sizeReq.max - sizeReq.size; - else - totalAvailable += sizeReq.min - sizeReq.size; - } - if (totalAvailable == 0) - if (remainder >= 0) - totalAvailable = 1; - else - totalAvailable = -1; - - int newRemainder = 0; - Vector stillFree = new Vector(); - for (Iterator i = freeComponents.iterator(); i.hasNext();) + if (offsetsX == null || offsetsY == null || spansX == null + || spansY == null) { - // Add/substract share to component. - SizeReq sizeReq = (SizeReq) i.next(); - double available = 0; - if (remainder >= 0) - available = sizeReq.max - sizeReq.size; + checkRequirements(); + checkTotalRequirements(); + int len = container.getComponents().length; + offsetsX = new int[len]; + offsetsY = new int[len]; + spansX = new int[len]; + spansY = new int[len]; + + Insets in = container.getInsets(); + int width = container.getWidth() - in.left - in.right; + int height = container.getHeight() - in.top -in.bottom; + + if (isHorizontalIn(container)) + { + SizeRequirements.calculateTiledPositions(width, + xTotal, xChildren, + offsetsX, spansX); + SizeRequirements.calculateAlignedPositions(height, + yTotal, yChildren, + offsetsY, spansY); + } else - available = sizeReq.min - sizeReq.size; - int share = (int) ((available / totalAvailable) * remainder); - sizeReq.size += share; - // check for min/maximumSize - if (sizeReq.size < sizeReq.min) - { - newRemainder += sizeReq.size - sizeReq.min; - sizeReq.size = sizeReq.min; - } - else if (sizeReq.size > sizeReq.max) - { - newRemainder += sizeReq.size - sizeReq.max; - sizeReq.size = sizeReq.max; - } - else - stillFree.add(sizeReq); + { + SizeRequirements.calculateAlignedPositions(width, + xTotal, xChildren, + offsetsX, spansX); + SizeRequirements.calculateTiledPositions(height, + yTotal, yChildren, + offsetsY, spansY); + } } - // recursivly call this method if necessary - if (newRemainder != 0 && stillFree.size() > 0) - distributeSpace(stillFree, newRemainder, dir); } } |