summaryrefslogtreecommitdiff
path: root/javax/swing/SpringLayout.java
diff options
context:
space:
mode:
Diffstat (limited to 'javax/swing/SpringLayout.java')
-rw-r--r--javax/swing/SpringLayout.java660
1 files changed, 660 insertions, 0 deletions
diff --git a/javax/swing/SpringLayout.java b/javax/swing/SpringLayout.java
new file mode 100644
index 000000000..60a50525f
--- /dev/null
+++ b/javax/swing/SpringLayout.java
@@ -0,0 +1,660 @@
+/* SpringLayout.java --
+ Copyright (C) 2004 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath 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 for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package javax.swing;
+
+import java.awt.Component;
+import java.awt.Container;
+import java.awt.Dimension;
+import java.awt.LayoutManager2;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.swing.Spring;
+
+/**
+ * A very flexible layout manager. Components are laid out by defining the
+ * relationships between them. The relationships are expressed as
+ * {@link Spring}s. You can attach a Spring for each edge of a component and
+ * link it to an edge of a different component. For example, you can say,
+ * the northern edge of component A should be attached to the southern edge
+ * of component B, and the space between them should be something between
+ * x and y pixels, and preferably z pixels.
+ * <p>While quite simple, this layout manager can be used to emulate most other
+ * layout managers, and can also be used to solve some layout problems, which
+ * would be hard to solve with other layout managers.</p>
+ *
+ * @author Roman Kennke (roman@ontographics.com)
+ */
+public class SpringLayout implements LayoutManager2
+{
+
+ /** The right edge of a component. */
+ public static final String EAST = "East";
+
+ /** The top edge of a component. */
+ public static final String NORTH = "North";
+
+ /** The bottom edge of a component. */
+ public static final String SOUTH = "South";
+
+ /** The left edge of a component. */
+ public static final String WEST = "West";
+
+ /** maps components to their constraints. */
+ private Map constraintsMap;
+
+ /**
+ * The constraints that define the relationships between components.
+ * Each Constraints object can hold 4 Springs: one for each edge of the
+ * component. Additionally it can hold Springs for the components width
+ * and the components height. Since the height and width constraints are
+ * dependend on the other constraints, a component can be over-constraint.
+ * In this case (like when all of NORTH, SOUTH and HEIGHT are constraint),
+ * the values are adjusted, so that the mathematics still hold true.
+ *
+ * @author Roman Kennke (roman@ontographics.com)
+ */
+ public final static class Constraints
+ {
+
+ // The constraints for each edge, and width and height.
+ /** The Spring for the left edge. */
+ private Spring x;
+
+ /** The Spring for the upper edge. */
+ private Spring y;
+
+ /** The Spring for the height. */
+ private Spring height;
+
+ /** The Spring for the width. */
+ private Spring width;
+
+ /** The Spring for the right edge. */
+ private Spring east;
+
+ /** The Spring for the bottom edge. */
+ private Spring south;
+
+ /**
+ * Creates a new Constraints object.
+ * There is no constraint set.
+ */
+ public Constraints()
+ {
+ x = y = height = width = east = south = null;
+ }
+
+ /**
+ * Creates a new Constraints object.
+ *
+ * @param x the constraint for the left edge of the component.
+ * @param y the constraint for the upper edge of the component.
+ */
+ public Constraints(Spring x, Spring y)
+ {
+ this.x = x;
+ this.y = y;
+ width = height = east = south = null;
+ }
+
+ /**
+ * Creates a new Constraints object.
+ *
+ * @param x the constraint for the left edge of the component.
+ * @param y the constraint for the upper edge of the component.
+ * @param width the constraint for the width of the component.
+ * @param height the constraint for the height of the component.
+ */
+ public Constraints(Spring x, Spring y, Spring width, Spring height)
+ {
+ this.x = x;
+ this.y = y;
+ this.width = width;
+ this.height = height;
+ east = south = null;
+ }
+
+ /**
+ * Returns the constraint for the edge with the <code>edgeName</code>.
+ * This is expected to be one of
+ * {@link #EAST}, {@link #WEST}, {@link NORTH} or {@link SOUTH}.
+ *
+ * @param edgeName the name of the edge.
+ * @return the constraint for the specified edge.
+ */
+ public Spring getConstraint(String edgeName)
+ {
+ Spring retVal = null;
+ if (edgeName.equals(SpringLayout.NORTH))
+ retVal = y;
+ else if (edgeName.equals(SpringLayout.WEST))
+ retVal = x;
+ else if (edgeName.equals(SpringLayout.SOUTH))
+ {
+ retVal = south;
+ if ((retVal == null) && (y != null) && (height != null))
+ retVal = Spring.sum(y, height);
+ }
+ else if (edgeName.equals(SpringLayout.EAST))
+ {
+ retVal = east;
+ if ((retVal == null) && (x != null) && (width != null))
+ retVal = Spring.sum(x, width);
+ }
+
+ return retVal;
+ }
+
+ /**
+ * Returns the constraint for the height of the component.
+ *
+ * @return the height constraint.
+ */
+ public Spring getHeight()
+ {
+ Spring retVal = height;
+ if ((retVal == null) && (y != null) && (south != null))
+ {
+ retVal = Spring.sum(south, Spring.minus(y));
+ }
+ return retVal;
+ }
+
+ /**
+ * Returns the constraint for the width of the component.
+ *
+ * @return the width constraint.
+ */
+ public Spring getWidth()
+ {
+ Spring retVal = width;
+ if ((retVal == null) && (x != null) && (east != null))
+ {
+ retVal = Spring.sum(east, Spring.minus(x));
+ }
+ return retVal;
+ }
+
+ /**
+ * Returns the constraint for the left edge of the component.
+ *
+ * @return the left-edge constraint (== WEST).
+ */
+ public Spring getX()
+ {
+ Spring retVal = x;
+ if ((retVal == null) && (width != null) && (east != null))
+ {
+ retVal = Spring.sum(east, Spring.minus(width));
+ }
+ return retVal;
+ }
+
+ /**
+ * Returns the constraint for the upper edge of the component.
+ *
+ * @return the upper-edge constraint (== NORTH).
+ */
+ public Spring getY()
+ {
+ Spring retVal = y;
+ if ((retVal == null) && (height != null) && (south != null))
+ {
+ retVal = Spring.sum(south, Spring.minus(height));
+ }
+ return retVal;
+ }
+
+ /**
+ * Sets a constraint for the specified edge. If this leads to an
+ * over-constrained situation, the constraints get adjusted, so that
+ * the mathematics still hold true.
+ *
+ * @param edgeName the name of the edge, one of {@link #EAST},
+ * {@link #WEST}, {@link NORTH} or {@link SOUTH}.
+ * @param s the constraint to be set.
+ */
+ public void setConstraint(String edgeName, Spring s)
+ {
+
+ if (edgeName.equals(SpringLayout.WEST))
+ {
+ x = s;
+ if ((width != null) && (east != null))
+ width = Spring.sum(east, Spring.minus(x));
+ }
+ else if (edgeName.equals(SpringLayout.NORTH))
+ {
+ y = s;
+ if ((height != null) && (south != null))
+ height = Spring.sum(south, Spring.minus(y));
+ }
+ else if (edgeName.equals(SpringLayout.EAST))
+ {
+ east = s;
+ if ((x != null) && (width != null))
+ x = Spring.sum(east, Spring.minus(width));
+ }
+ else if (edgeName.equals(SpringLayout.SOUTH))
+ {
+ south = s;
+ if ((height != null) && (y != null))
+ y = Spring.sum(south, Spring.minus(height));
+ }
+
+ }
+
+ /**
+ * Sets the height-constraint.
+ *
+ * @param s the constraint to be set.
+ */
+ public void setHeight(Spring s)
+ {
+ height = s;
+ if ((south != null) && (y != null))
+ south = Spring.sum(y, height);
+
+ }
+
+ /**
+ * Sets the width-constraint.
+ *
+ * @param s the constraint to be set.
+ */
+ public void setWidth(Spring s)
+ {
+ width = s;
+ if ((east != null) && (x != null))
+ east = Spring.sum(x, width);
+
+ }
+
+ /**
+ * Sets the WEST-constraint.
+ *
+ * @param s the constraint to be set.
+ */
+ public void setX(Spring s)
+ {
+ x = s;
+ if ((width != null) && (east != null))
+ width = Spring.sum(east, Spring.minus(x));
+
+ }
+
+ /**
+ * Sets the NORTH-constraint.
+ *
+ * @param s the constraint to be set.
+ */
+ public void setY(Spring s)
+ {
+ y = s;
+ if ((height != null) && (south != null))
+ height = Spring.sum(south, Spring.minus(y));
+
+ }
+ }
+
+ /**
+ * Creates a new SpringLayout.
+ */
+ public SpringLayout()
+ {
+
+ constraintsMap = new HashMap();
+ }
+
+ /**
+ * Adds a layout component and a constraint object to this layout.
+ * This method is usually only called by a {@java.awt.Container}s add
+ * Method.
+ *
+ * @param component the component to be added.
+ * @param constraint the constraint to be set.
+ */
+ public void addLayoutComponent(Component component, Object constraint)
+ {
+ constraintsMap.put(component, constraint);
+ }
+
+
+ /**
+ * Adds a layout component and a constraint object to this layout.
+ * This method is usually only called by a {@java.awt.Container}s add
+ * Method. This method does nothing, since SpringLayout does not manage
+ * String-indexed components.
+ *
+ * @param component the component to be added.
+ * @param constraint the constraint to be set.
+ */
+ public void addLayoutComponent(String name, Component c)
+ {
+ // do nothing here.
+ }
+
+ /**
+ * Returns the constraint of the edge named by <code>edgeName</code>.
+ *
+ * @param c the component from which to get the constraint.
+ * @param edgeName the name of the edge, one of {@link #EAST},
+ * {@link #WEST}, {@link NORTH} or {@link SOUTH}.
+ * @return the constraint of the edge <code>edgeName</code> of the
+ * component c.
+ */
+ public Spring getConstraint(String edgeName, Component c)
+ {
+ Constraints constraints = getConstraints(c);
+ return constraints.getConstraint(edgeName);
+ }
+
+ /**
+ * Returns the {@link Constraints} object associated with the specified
+ * component.
+ *
+ * @param c the component for which to determine the constraint.
+ * @return the {@link Constraints} object associated with the specified
+ * component.
+ */
+ public SpringLayout.Constraints getConstraints(Component c)
+ {
+ Constraints constraints = (Constraints) constraintsMap.get(c);
+ if (constraints == null)
+ {
+ Container parent = c.getParent();
+ constraints = new Constraints();
+ if (parent != null)
+ {
+ constraints.setX
+ (Spring.constant(parent.getInsets().left));
+ constraints.setY
+ (Spring.constant(parent.getInsets().top));
+ }
+ else
+ {
+ constraints.setX
+ (Spring.constant(0));
+ constraints.setY
+ (Spring.constant(0));
+
+ }
+ constraints.setWidth
+ (Spring.constant(c.getMinimumSize().width,
+ c.getPreferredSize().width,
+ c.getMaximumSize().width));
+ constraints.setHeight
+ (Spring.constant(c.getMinimumSize().height,
+ c.getPreferredSize().height,
+ c.getMaximumSize().height));
+
+ constraintsMap.put(c, constraints);
+
+ }
+
+ return constraints;
+ }
+
+ /**
+ * Returns the X alignment of the Container <code>p</code>.
+ *
+ * @param p the {@link java.awt.Container} for which to determine the X
+ * alignment.
+ * @return always 0.0
+ */
+ public float getLayoutAlignmentX(Container p)
+ {
+ return 0.0F;
+ }
+
+ /**
+ * Returns the Y alignment of the Container <code>p</code>.
+ *
+ * @param p the {@link java.awt.Container} for which to determine the Y
+ * alignment.
+ * @return always 0.0
+ */
+ public float getLayoutAlignmentY(Container p)
+ {
+ return 0.0F;
+ }
+
+ /**
+ * Recalculate a possibly cached layout.
+ */
+ public void invalidateLayout(Container p)
+ {
+ // nothing to do here yet
+ }
+
+ /**
+ * Lays out the container <code>p</code>.
+ *
+ * @param p the container to be laid out.
+ */
+ public void layoutContainer(Container p)
+ {
+
+ addLayoutComponent(p, new Constraints(Spring.constant(0),
+ Spring.constant(0)));
+
+ int offsetX = p.getInsets().left;
+ int offsetY = p.getInsets().right;
+
+ Component[] components = p.getComponents();
+ for (int index = 0; index < components.length; index++)
+ {
+ Component c = components[index];
+ Constraints constraints = getConstraints(c);
+ int x = constraints.getX().getValue();
+ int y = constraints.getY().getValue();
+ int width = constraints.getWidth().getValue();
+ int height = constraints.getHeight().getValue();
+
+ c.setLocation(x + offsetX, y + offsetY);
+ c.setSize(width, height);
+ }
+
+ }
+
+ /**
+ * Calculates the maximum size of the layed out container. This
+ * respects the maximum sizes of all contained components.
+ *
+ * @param p the container to be laid out.
+ * @return the maximum size of the container.
+ */
+ public Dimension maximumLayoutSize(Container p)
+ {
+ int maxX = 0;
+ int maxY = 0;
+
+ int offsetX = p.getInsets().left;
+ int offsetY = p.getInsets().right;
+
+ Component[] components = p.getComponents();
+ for (int index = 0; index < components.length; index++)
+ {
+ Component c = components[index];
+ Constraints constraints = getConstraints(c);
+ int x = constraints.getX().getMaximumValue();
+ int y = constraints.getY().getMaximumValue();
+ int width = constraints.getWidth().getMaximumValue();
+ int height = constraints.getHeight().getMaximumValue();
+
+ int rightEdge = offsetX + x + width;
+ if (rightEdge > maxX)
+ maxX = rightEdge;
+ int bottomEdge = offsetY + y + height;
+ if (bottomEdge > maxY)
+ maxY = bottomEdge;
+ }
+
+ return new Dimension(maxX, maxY);
+ }
+
+
+ /**
+ * Calculates the minimum size of the layed out container. This
+ * respects the minimum sizes of all contained components.
+ *
+ * @param p the container to be laid out.
+ * @return the minimum size of the container.
+ */
+ public Dimension minimumLayoutSize(Container p)
+ {
+ int maxX = 0;
+ int maxY = 0;
+
+ int offsetX = p.getInsets().left;
+ int offsetY = p.getInsets().right;
+
+ Component[] components = p.getComponents();
+ for (int index = 0; index < components.length; index++)
+ {
+ Component c = components[index];
+ Constraints constraints = getConstraints(c);
+ int x = constraints.getX().getMinimumValue();
+ int y = constraints.getY().getMinimumValue();
+ int width = constraints.getWidth().getMinimumValue();
+ int height = constraints.getHeight().getMinimumValue();
+
+ int rightEdge = offsetX + x + width;
+ if (rightEdge > maxX)
+ maxX = rightEdge;
+ int bottomEdge = offsetY + y + height;
+ if (bottomEdge > maxY)
+ maxY = bottomEdge;
+ }
+
+ return new Dimension(maxX, maxY);
+ }
+
+ /**
+ * Calculates the preferred size of the layed out container. This
+ * respects the preferred sizes of all contained components.
+ *
+ * @param p the container to be laid out.
+ * @return the preferred size of the container.
+ */
+ public Dimension preferredLayoutSize(Container p)
+ {
+ int maxX = 0;
+ int maxY = 0;
+
+ int offsetX = p.getInsets().left;
+ int offsetY = p.getInsets().right;
+
+ Component[] components = p.getComponents();
+ for (int index = 0; index < components.length; index++)
+ {
+ Component c = components[index];
+ Constraints constraints = getConstraints(c);
+ int x = constraints.getX().getPreferredValue();
+ int y = constraints.getY().getPreferredValue();
+ int width = constraints.getWidth().getPreferredValue();
+ int height = constraints.getHeight().getPreferredValue();
+
+ int rightEdge = offsetX + x + width;
+ if (rightEdge > maxX)
+ maxX = rightEdge;
+ int bottomEdge = offsetY + y + height;
+ if (bottomEdge > maxY)
+ maxY = bottomEdge;
+ }
+
+ return new Dimension(maxX, maxY);
+ }
+
+ /**
+ * Attaches the edge <code>e1</code> of component <code>c1</code> to
+ * the edge <code>e2</code> of component <code>c2</code> width the
+ * fixed strut <code>pad</code>.
+ *
+ * @param e1 the edge of component 1.
+ * @param c1 the component 1.
+ * @param pad the space between the components in pixels.
+ * @param e2 the edge of component 2.
+ * @param c2 the component 2.
+ */
+ public void putConstraint(String e1, Component c1, int pad, String e2,
+ Component c2)
+ {
+ Constraints constraints1 = getConstraints(c1);
+ Constraints constraints2 = getConstraints(c2);
+
+ Spring strut = Spring.constant(pad);
+ Spring otherEdge = constraints2.getConstraint(e2);
+ constraints1.setConstraint(e1, Spring.sum(strut, otherEdge));
+
+ }
+
+ /**
+ * Attaches the edge <code>e1</code> of component <code>c1</code> to
+ * the edge <code>e2</code> of component <code>c2</code> width the
+ * {@link Spring} <code>s</code>.
+ *
+ * @param e1 the edge of component 1.
+ * @param c1 the component 1.
+ * @param s the space between the components as a {@link Spring} object.
+ * @param e2 the edge of component 2.
+ * @param c2 the component 2.
+ */
+ public void putConstraint(String e1, Component c1, Spring s, String e2,
+ Component c2)
+ {
+ Constraints constraints1 = getConstraints(c1);
+ Constraints constraints2 = getConstraints(c2);
+
+ Spring otherEdge = constraints2.getConstraint(e2);
+ constraints1.setConstraint(e1, Spring.sum(s, otherEdge));
+
+ }
+
+ /**
+ * Removes a layout component.
+ * @param c the layout component to remove.
+ */
+ public void removeLayoutComponent(Component c)
+ {
+ // do nothing here
+ }
+}