0001: /*
0002: * @(#)GridBagLayout.java 1.14 06/10/10
0003: *
0004: * Copyright 1990-2006 Sun Microsystems, Inc. All Rights Reserved.
0005: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
0006: *
0007: * This program is free software; you can redistribute it and/or
0008: * modify it under the terms of the GNU General Public License version
0009: * 2 only, as published by the Free Software Foundation.
0010: *
0011: * This program is distributed in the hope that it will be useful, but
0012: * WITHOUT ANY WARRANTY; without even the implied warranty of
0013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
0014: * General Public License version 2 for more details (a copy is
0015: * included at /legal/license.txt).
0016: *
0017: * You should have received a copy of the GNU General Public License
0018: * version 2 along with this work; if not, write to the Free Software
0019: * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
0020: * 02110-1301 USA
0021: *
0022: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
0023: * Clara, CA 95054 or visit www.sun.com if you need additional
0024: * information or have any questions.
0025: *
0026: */
0027: package java.awt;
0028:
0029: import java.util.Hashtable;
0030: import java.util.Vector;
0031:
0032: class GridBagLayoutInfo implements java.io.Serializable {
0033: int width, height; /* number of cells horizontally, vertically */
0034: int startx, starty; /* starting point for layout */
0035: int minWidth[]; /* largest minWidth in each column */
0036: int minHeight[]; /* largest minHeight in each row */
0037: double weightX[]; /* largest weight in each column */
0038: double weightY[]; /* largest weight in each row */
0039:
0040: GridBagLayoutInfo() {
0041: minWidth = new int[GridBagLayout.MAXGRIDSIZE];
0042: minHeight = new int[GridBagLayout.MAXGRIDSIZE];
0043: weightX = new double[GridBagLayout.MAXGRIDSIZE];
0044: weightY = new double[GridBagLayout.MAXGRIDSIZE];
0045: }
0046: }
0047:
0048: /**
0049: * The <code>GridBagLayout</code> class is a flexible layout
0050: * manager that aligns components vertically and horizontally,
0051: * without requiring that the components be of the same size.
0052: * Each <code>GridBagLayout</code> object maintains a dynamic
0053: * rectangular grid of cells, with each component occupying
0054: * one or more cells, called its <em>display area</em>.
0055: * <p>
0056: * Each component managed by a grid bag layout is associated
0057: * with an instance of
0058: * <a href="java.awt.GridBagConstraints.html"><code>GridBagConstraints</code></a>
0059: * that specifies how the component is laid out within its display area.
0060: * <p>
0061: * How a <code>GridBagLayout</code> object places a set of components
0062: * depends on the <code>GridBagConstraints</code> object associated
0063: * with each component, and on the minimum size
0064: * and the preferred size of the components' containers.
0065: * <p>
0066: * To use a grid bag layout effectively, you must customize one or more
0067: * of the <code>GridBagConstraints</code> objects that are associated
0068: * with its components. You customize a <code>GridBagConstraints</code>
0069: * object by setting one or more of its instance variables:
0070: * <p>
0071: * <dl>
0072: * <dt><a href="java.awt.GridBagConstraints.html#gridx"><code>gridx</code></a>,
0073: * <a href="java.awt.GridBagConstraints.html#gridy"><code>gridy</code></a>
0074: * <dd>Specifies the cell at the upper left of the component's display area,
0075: * where the upper-left-most cell has address
0076: * <code>gridx = 0</code>,
0077: * <code>gridy = 0</code>.
0078: * Use <code>GridBagConstraints.RELATIVE</code> (the default value)
0079: * to specify that the component be just placed
0080: * just to the right of (for <code>gridx</code>)
0081: * or just below (for <code>gridy</code>)
0082: * the component that was added to the container
0083: * just before this component was added.
0084: * <dt><a href="java.awt.GridBagConstraints.html#gridwidth"><code>gridwidth</code></a>,
0085: * <a href="java.awt.GridBagConstraints.html#gridheight"><code>gridheight</code></a>
0086: * <dd>Specifies the number of cells in a row (for <code>gridwidth</code>)
0087: * or column (for <code>gridheight</code>)
0088: * in the component's display area.
0089: * The default value is 1.
0090: * Use <code>GridBagConstraints.REMAINDER</code> to specify
0091: * that the component be the last one in its row (for <code>gridwidth</code>)
0092: * or column (for <code>gridheight</code>).
0093: * Use <code>GridBagConstraints.RELATIVE</code> to specify
0094: * that the component be the next to last one
0095: * in its row (for <code>gridwidth</code>)
0096: * or column (for <code>gridheight</code>).
0097: * <dt><a href="java.awt.GridBagConstraints.html#fill"><code>fill</code></a>
0098: * <dd>Used when the component's display area
0099: * is larger than the component's requested size
0100: * to determine whether (and how) to resize the component.
0101: * Possible values are
0102: * <code>GridBagConstraints.NONE</code> (the default),
0103: * <code>GridBagConstraints.HORIZONTAL</code>
0104: * (make the component wide enough to fill its display area
0105: * horizontally, but don't change its height),
0106: * <code>GridBagConstraints.VERTICAL</code>
0107: * (make the component tall enough to fill its display area
0108: * vertically, but don't change its width), and
0109: * <code>GridBagConstraints.BOTH</code>
0110: * (make the component fill its display area entirely).
0111: * <dt><a href="java.awt.GridBagConstraints.html#ipadx"><code>ipadx</code></a>,
0112: * <a href="java.awt.GridBagConstraints.html#ipady"><code>ipady</code></a>
0113: * <dd>Specifies the component's internal padding within the layout,
0114: * how much to add to the minimum size of the component.
0115: * The width of the component will be at least its minimum width
0116: * plus <code>(ipadx * 2)</code> pixels (since the padding
0117: * applies to both sides of the component). Similarly, the height of
0118: * the component will be at least the minimum height plus
0119: * <code>(ipady * 2)</code> pixels.
0120: * <dt><a href="java.awt.GridBagConstraints.html#insets"><code>insets</code></a>
0121: * <dd>Specifies the component's external padding, the minimum
0122: * amount of space between the component and the edges of its display area.
0123: * <dt><a href="java.awt.GridBagConstraints.html#anchor"><code>anchor</code></a>
0124: * <dd>Used when the component is smaller than its display area
0125: * to determine where (within the display area) to place the component.
0126: * Valid values are
0127: * <code>GridBagConstraints.CENTER</code> (the default),
0128: * <code>GridBagConstraints.NORTH</code>,
0129: * <code>GridBagConstraints.NORTHEAST</code>,
0130: * <code>GridBagConstraints.EAST</code>,
0131: * <code>GridBagConstraints.SOUTHEAST</code>,
0132: * <code>GridBagConstraints.SOUTH</code>,
0133: * <code>GridBagConstraints.SOUTHWEST</code>,
0134: * <code>GridBagConstraints.WEST</code>, and
0135: * <code>GridBagConstraints.NORTHWEST</code>.
0136: * <dt><a href="java.awt.GridBagConstraints.html#weightx"><code>weightx</code></a>,
0137: * <a href="java.awt.GridBagConstraints.html#weighty"><code>weighty</code></a>
0138: * <dd>Used to determine how to distribute space, which is
0139: * important for specifying resizing behavior.
0140: * Unless you specify a weight for at least one component
0141: * in a row (<code>weightx</code>) and column (<code>weighty</code>),
0142: * all the components clump together in the center of their container.
0143: * This is because when the weight is zero (the default),
0144: * the <code>GridBagLayout</code> object puts any extra space
0145: * between its grid of cells and the edges of the container.
0146: * </dl>
0147: * <p>
0148: * The following figure shows ten components (all buttons)
0149: * managed by a grid bag layout:
0150: * <p>
0151: * <img src="images-awt/GridBagLayout-1.gif"
0152: * ALIGN=center HSPACE=10 VSPACE=7>
0153: * <p>
0154: * Each of the ten components has the <code>fill</code> field
0155: * of its associated <code>GridBagConstraints</code> object
0156: * set to <code>GridBagConstraints.BOTH</code>.
0157: * In addition, the components have the following non-default constraints:
0158: * <p>
0159: * <ul>
0160: * <li>Button1, Button2, Button3: <code>weightx = 1.0</code>
0161: * <li>Button4: <code>weightx = 1.0</code>,
0162: * <code>gridwidth = GridBagConstraints.REMAINDER</code>
0163: * <li>Button5: <code>gridwidth = GridBagConstraints.REMAINDER</code>
0164: * <li>Button6: <code>gridwidth = GridBagConstraints.RELATIVE</code>
0165: * <li>Button7: <code>gridwidth = GridBagConstraints.REMAINDER</code>
0166: * <li>Button8: <code>gridheight = 2</code>,
0167: * <code>weighty = 1.0</code>
0168: * <li>Button9, Button 10:
0169: * <code>gridwidth = GridBagConstraints.REMAINDER</code>
0170: * </ul>
0171: * <p>
0172: * Here is the code that implements the example shown above:
0173: * <p>
0174: * <hr><blockquote><pre>
0175: * import java.awt.*;
0176: * import java.util.*;
0177: * import java.applet.Applet;
0178: *
0179: * public class GridBagEx1 extends Applet {
0180: *
0181: * protected void makebutton(String name,
0182: * GridBagLayout gridbag,
0183: * GridBagConstraints c) {
0184: * Button button = new Button(name);
0185: * gridbag.setConstraints(button, c);
0186: * add(button);
0187: * }
0188: *
0189: * public void init() {
0190: * GridBagLayout gridbag = new GridBagLayout();
0191: * GridBagConstraints c = new GridBagConstraints();
0192: *
0193: * setFont(new Font("Helvetica", Font.PLAIN, 14));
0194: * setLayout(gridbag);
0195: *
0196: * c.fill = GridBagConstraints.BOTH;
0197: * c.weightx = 1.0;
0198: * makebutton("Button1", gridbag, c);
0199: * makebutton("Button2", gridbag, c);
0200: * makebutton("Button3", gridbag, c);
0201: *
0202: * c.gridwidth = GridBagConstraints.REMAINDER; //end row
0203: * makebutton("Button4", gridbag, c);
0204: *
0205: * c.weightx = 0.0; //reset to the default
0206: * makebutton("Button5", gridbag, c); //another row
0207: *
0208: * c.gridwidth = GridBagConstraints.RELATIVE; //next-to-last in row
0209: * makebutton("Button6", gridbag, c);
0210: *
0211: * c.gridwidth = GridBagConstraints.REMAINDER; //end row
0212: * makebutton("Button7", gridbag, c);
0213: *
0214: * c.gridwidth = 1; //reset to the default
0215: * c.gridheight = 2;
0216: * c.weighty = 1.0;
0217: * makebutton("Button8", gridbag, c);
0218: *
0219: * c.weighty = 0.0; //reset to the default
0220: * c.gridwidth = GridBagConstraints.REMAINDER; //end row
0221: * c.gridheight = 1; //reset to the default
0222: * makebutton("Button9", gridbag, c);
0223: * makebutton("Button10", gridbag, c);
0224: *
0225: * setSize(300, 100);
0226: * }
0227: *
0228: * public static void main(String args[]) {
0229: * Frame f = new Frame("GridBag Layout Example");
0230: * GridBagEx1 ex1 = new GridBagEx1();
0231: *
0232: * ex1.init();
0233: *
0234: * f.add("Center", ex1);
0235: * f.pack();
0236: * f.setSize(f.getPreferredSize());
0237: * f.show();
0238: * }
0239: * }
0240: * </pre></blockquote><hr>
0241: * <p>
0242: * @version 1.5, 16 Nov 1995
0243: * @author Doug Stein
0244: * @see java.awt.GridBagConstraints
0245: * @since JDK1.0
0246: */
0247: public class GridBagLayout implements LayoutManager2,
0248: java.io.Serializable {
0249: /**
0250: * The maximum number of grid positions (both horizontally and
0251: * vertically) that can be laid out by the grid bag layout.
0252: * @since JDK1.0
0253: */
0254: protected static final int MAXGRIDSIZE = 512;
0255: /**
0256: * The smallest grid that can be laid out by the grid bag layout.
0257: * @since JDK1.0
0258: */
0259: protected static final int MINSIZE = 1;
0260: protected static final int PREFERREDSIZE = 2;
0261: protected Hashtable comptable;
0262: protected GridBagConstraints defaultConstraints;
0263: private GridBagLayoutInfo layoutInfo;
0264: public int columnWidths[];
0265: public int rowHeights[];
0266: public double columnWeights[];
0267: public double rowWeights[];
0268:
0269: /**
0270: * Creates a grid bag layout manager.
0271: * @since JDK1.0
0272: */
0273: public GridBagLayout() {
0274: comptable = new Hashtable();
0275: defaultConstraints = new GridBagConstraints();
0276: }
0277:
0278: /**
0279: * Sets the constraints for the specified component in this layout.
0280: * @param comp the component to be modified.
0281: * @param constraints the constraints to be applied.
0282: * @since JDK1.0
0283: */
0284: public void setConstraints(Component comp,
0285: GridBagConstraints constraints) {
0286: comptable.put(comp, constraints.clone());
0287: }
0288:
0289: /**
0290: * Gets the constraints for the specified component. A copy of
0291: * the actual <code>GridBagConstraints</code> object is returned.
0292: * @param comp the component to be queried.
0293: * @return the constraint for the specified component in this
0294: * grid bag layout; a copy of the actual constraint
0295: * object is returned.
0296: * @since JDK1.0
0297: */
0298: public GridBagConstraints getConstraints(Component comp) {
0299: GridBagConstraints constraints = (GridBagConstraints) comptable
0300: .get(comp);
0301: if (constraints == null) {
0302: setConstraints(comp, defaultConstraints);
0303: constraints = (GridBagConstraints) comptable.get(comp);
0304: }
0305: return (GridBagConstraints) constraints.clone();
0306: }
0307:
0308: /**
0309: * Retrieves the constraints for the specified component.
0310: * The return value is not a copy, but is the actual
0311: * <code>GridBagConstraints</code> object used by the layout mechanism.
0312: * @param comp the component to be queried
0313: * @return the contraints for the specified component.
0314: * @since JDK1.0
0315: */
0316: protected GridBagConstraints lookupConstraints(Component comp) {
0317: GridBagConstraints constraints = (GridBagConstraints) comptable
0318: .get(comp);
0319: if (constraints == null) {
0320: setConstraints(comp, defaultConstraints);
0321: constraints = (GridBagConstraints) comptable.get(comp);
0322: }
0323: return constraints;
0324: }
0325:
0326: /**
0327: * Determines the origin of the layout grid.
0328: * Most applications do not call this method directly.
0329: * @return the origin of the cell in the top-left
0330: * corner of the layout grid.
0331: * @since JDK1.1
0332: */
0333: public Point getLayoutOrigin() {
0334: Point origin = new Point(0, 0);
0335: if (layoutInfo != null) {
0336: origin.x = layoutInfo.startx;
0337: origin.y = layoutInfo.starty;
0338: }
0339: return origin;
0340: }
0341:
0342: /**
0343: * Determines column widths and row heights for the layout grid.
0344: * <p>
0345: * Most applications do not call this method directly.
0346: * @return an array of two arrays, containing the widths
0347: * of the layout columns and
0348: * the heights of the layout rows.
0349: * @since JDK1.1
0350: */
0351: public int[][] getLayoutDimensions() {
0352: if (layoutInfo == null)
0353: return new int[2][0];
0354: int dim[][] = new int[2][];
0355: dim[0] = new int[layoutInfo.width];
0356: dim[1] = new int[layoutInfo.height];
0357: System.arraycopy(layoutInfo.minWidth, 0, dim[0], 0,
0358: layoutInfo.width);
0359: System.arraycopy(layoutInfo.minHeight, 0, dim[1], 0,
0360: layoutInfo.height);
0361: return dim;
0362: }
0363:
0364: /**
0365: * Determines the weights of the layout grid's columns and rows.
0366: * Weights are used to calculate how much a given column or row
0367: * stretches beyond its preferred size, if the layout has extra
0368: * room to fill.
0369: * <p>
0370: * Most applications do not call this method directly.
0371: * @return an array of two arrays, representing the
0372: * horizontal weights of the layout columns
0373: * and the vertical weights of the layout rows.
0374: * @since JDK1.1
0375: */
0376: public double[][] getLayoutWeights() {
0377: if (layoutInfo == null)
0378: return new double[2][0];
0379: double weights[][] = new double[2][];
0380: weights[0] = new double[layoutInfo.width];
0381: weights[1] = new double[layoutInfo.height];
0382: System.arraycopy(layoutInfo.weightX, 0, weights[0], 0,
0383: layoutInfo.width);
0384: System.arraycopy(layoutInfo.weightY, 0, weights[1], 0,
0385: layoutInfo.height);
0386: return weights;
0387: }
0388:
0389: /**
0390: * Determines which cell in the layout grid contains the point
0391: * specified by <code>(x, y)</code>. Each cell is identified
0392: * by its column index (ranging from 0 to the number of columns
0393: * minus 1) and its row index (ranging from 0 to the number of
0394: * rows minus 1).
0395: * <p>
0396: * If the <code>(x, y)</code> point lies
0397: * outside the grid, the following rules are used.
0398: * The column index is returned as zero if <code>x</code> lies to the
0399: * left of the layout, and as the number of columns if <code>x</code> lies
0400: * to the right of the layout. The row index is returned as zero
0401: * if <code>y</code> lies above the layout,
0402: * and as the number of rows if <code>y</code> lies
0403: * below the layout.
0404: * @param x the <i>x</i> coordinate of a point.
0405: * @param y the <i>y</i> coordinate of a point.
0406: * @return an ordered pair of indexes that indicate which cell
0407: * in the layout grid contains the point
0408: * (<i>x</i>, <i>y</i>).
0409: * @since JDK1.1
0410: */
0411: public Point location(int x, int y) {
0412: Point loc = new Point(0, 0);
0413: int i, d;
0414: if (layoutInfo == null)
0415: return loc;
0416: d = layoutInfo.startx;
0417: for (i = 0; i < layoutInfo.width; i++) {
0418: d += layoutInfo.minWidth[i];
0419: if (d > x)
0420: break;
0421: }
0422: loc.x = i;
0423: d = layoutInfo.starty;
0424: for (i = 0; i < layoutInfo.height; i++) {
0425: d += layoutInfo.minHeight[i];
0426: if (d > y)
0427: break;
0428: }
0429: loc.y = i;
0430: return loc;
0431: }
0432:
0433: /**
0434: * Adds the specified component with the specified name to the layout.
0435: * @param name the name of the component.
0436: * @param comp the component to be added.
0437: * @since JDK1.0
0438: */
0439: public void addLayoutComponent(String name, Component comp) {
0440: }
0441:
0442: /**
0443: * Adds the specified component to the layout, using the specified
0444: * constraint object.
0445: * @param comp the component to be added.
0446: * @param constraints an object that determines how
0447: * the component is added to the layout.
0448: * @since JDK1.0
0449: */
0450: public void addLayoutComponent(Component comp, Object constraints) {
0451: if (constraints instanceof GridBagConstraints) {
0452: setConstraints(comp, (GridBagConstraints) constraints);
0453: } else if (constraints instanceof String) {//Netscape : Just Ignore it
0454: } else if (constraints != null) {
0455: throw new IllegalArgumentException(
0456: "cannot add to layout: constraint must be a GridBagConstraint");
0457: }
0458: }
0459:
0460: /**
0461: * Removes the specified component from this layout.
0462: * <p>
0463: * Most applications do not call this method directly.
0464: * @param comp the component to be removed.
0465: * @see java.awt.Container#remove(java.awt.Component)
0466: * @see java.awt.Container#removeAll()
0467: * @since JDK1.0
0468: */
0469: public void removeLayoutComponent(Component comp) {
0470: }
0471:
0472: /**
0473: * Determines the preferred size of the <code>target</code>
0474: * container using this grid bag layout.
0475: * <p>
0476: * Most applications do not call this method directly.
0477: * @param target the container in which to do the layout.
0478: * @see java.awt.Container#getPreferredSize
0479: * @since JDK1.0
0480: */
0481: public Dimension preferredLayoutSize(Container parent) {
0482: GridBagLayoutInfo info = GetLayoutInfo(parent, PREFERREDSIZE);
0483: return GetMinSize(parent, info);
0484: }
0485:
0486: /**
0487: * Determines the minimum size of the <code>target</code> container
0488: * using this grid bag layout.
0489: * <p>
0490: * Most applications do not call this method directly.
0491: * @param target the container in which to do the layout.
0492: * @see java.awt.Container#doLayout
0493: * @since JDK1.0
0494: */
0495: public Dimension minimumLayoutSize(Container parent) {
0496: GridBagLayoutInfo info = GetLayoutInfo(parent, MINSIZE);
0497: return GetMinSize(parent, info);
0498: }
0499:
0500: /**
0501: * Returns the maximum dimensions for this layout given the components
0502: * in the specified target container.
0503: * @param target the component which needs to be laid out
0504: * @see Container
0505: * @see #minimumLayoutSize
0506: * @see #preferredLayoutSize
0507: */
0508: public Dimension maximumLayoutSize(Container target) {
0509: return new Dimension(Integer.MAX_VALUE, Integer.MAX_VALUE);
0510: }
0511:
0512: /**
0513: * Returns the alignment along the x axis. This specifies how
0514: * the component would like to be aligned relative to other
0515: * components. The value should be a number between 0 and 1
0516: * where 0 represents alignment along the origin, 1 is aligned
0517: * the furthest away from the origin, 0.5 is centered, etc.
0518: */
0519: public float getLayoutAlignmentX(Container parent) {
0520: return 0.5f;
0521: }
0522:
0523: /**
0524: * Returns the alignment along the y axis. This specifies how
0525: * the component would like to be aligned relative to other
0526: * components. The value should be a number between 0 and 1
0527: * where 0 represents alignment along the origin, 1 is aligned
0528: * the furthest away from the origin, 0.5 is centered, etc.
0529: */
0530: public float getLayoutAlignmentY(Container parent) {
0531: return 0.5f;
0532: }
0533:
0534: /**
0535: * Invalidates the layout, indicating that if the layout manager
0536: * has cached information it should be discarded.
0537: */
0538: public void invalidateLayout(Container target) {
0539: }
0540:
0541: /**
0542: * Lays out the specified container using this grid bag layout.
0543: * This method reshapes components in the specified container in
0544: * order to satisfy the contraints of this <code>GridBagLayout</code>
0545: * object.
0546: * <p>
0547: * Most applications do not call this method directly.
0548: * @param parent the container in which to do the layout.
0549: * @see java.awt.Container
0550: * @see java.awt.Container#doLayout
0551: * @since JDK1.0
0552: */
0553: public void layoutContainer(Container parent) {
0554: ArrangeGrid(parent);
0555: }
0556:
0557: /**
0558: * Returns a string representation of this grid bag layout's values.
0559: * @return a string representation of this grid bag layout.
0560: * @since JDK1.0
0561: */
0562: public String toString() {
0563: return getClass().getName();
0564: }
0565:
0566: /**
0567: * Print the layout information. Useful for debugging.
0568: */
0569:
0570: /* DEBUG
0571: *
0572: * protected void DumpLayoutInfo(GridBagLayoutInfo s) {
0573: * int x;
0574: *
0575: * System.out.println("Col\tWidth\tWeight");
0576: * for (x=0; x<s.width; x++) {
0577: * System.out.println(x + "\t" +
0578: * s.minWidth[x] + "\t" +
0579: * s.weightX[x]);
0580: * }
0581: * System.out.println("Row\tHeight\tWeight");
0582: * for (x=0; x<s.height; x++) {
0583: * System.out.println(x + "\t" +
0584: * s.minHeight[x] + "\t" +
0585: * s.weightY[x]);
0586: * }
0587: * }
0588: */
0589:
0590: /**
0591: * Print the layout constraints. Useful for debugging.
0592: */
0593:
0594: /* DEBUG
0595: *
0596: * protected void DumpConstraints(GridBagConstraints constraints) {
0597: * System.out.println(
0598: * "wt " +
0599: * constraints.weightx +
0600: * " " +
0601: * constraints.weighty +
0602: * ", " +
0603: *
0604: * "box " +
0605: * constraints.gridx +
0606: * " " +
0607: * constraints.gridy +
0608: * " " +
0609: * constraints.gridwidth +
0610: * " " +
0611: * constraints.gridheight +
0612: * ", " +
0613: *
0614: * "min " +
0615: * constraints.minWidth +
0616: * " " +
0617: * constraints.minHeight +
0618: * ", " +
0619: *
0620: * "pad " +
0621: * constraints.insets.bottom +
0622: * " " +
0623: * constraints.insets.left +
0624: * " " +
0625: * constraints.insets.right +
0626: * " " +
0627: * constraints.insets.top +
0628: * " " +
0629: * constraints.ipadx +
0630: * " " +
0631: * constraints.ipady);
0632: * }
0633: */
0634:
0635: /*
0636: * Fill in an instance of the above structure for the current set
0637: * of managed children. This requires three passes through the
0638: * set of children:
0639: *
0640: * 1) Figure out the dimensions of the layout grid
0641: * 2) Determine which cells the components occupy
0642: * 3) Distribute the weights and min sizes amoung the rows/columns.
0643: *
0644: * This also caches the minsizes for all the children when they are
0645: * first encountered (so subsequent loops don't need to ask again).
0646: */
0647:
0648: private GridBagLayoutInfo GetLayoutInfo(Container parent,
0649: int sizeflag) {
0650: synchronized (parent.getTreeLock()) {
0651: GridBagLayoutInfo r = new GridBagLayoutInfo();
0652: Component comp;
0653: GridBagConstraints constraints;
0654: Dimension d;
0655: Component components[] = parent.getComponents();
0656: int compindex, i, j, k, px, py, pixels_diff, nextSize;
0657: int curX, curY, curWidth, curHeight, curRow, curCol;
0658: double weight_diff, weight, start, size;
0659: int xMax[], yMax[];
0660: /*
0661: * Pass #1
0662: *
0663: * Figure out the dimensions of the layout grid (use a value of 1 for
0664: * zero or negative widths and heights).
0665: */
0666:
0667: r.width = r.height = 0;
0668: curRow = curCol = -1;
0669: xMax = new int[MAXGRIDSIZE];
0670: yMax = new int[MAXGRIDSIZE];
0671: for (compindex = 0; compindex < components.length; compindex++) {
0672: comp = components[compindex];
0673: if (!comp.isVisible())
0674: continue;
0675: constraints = lookupConstraints(comp);
0676: curX = constraints.gridx;
0677: curY = constraints.gridy;
0678: curWidth = constraints.gridwidth;
0679: if (curWidth <= 0)
0680: curWidth = 1;
0681: curHeight = constraints.gridheight;
0682: if (curHeight <= 0)
0683: curHeight = 1;
0684: /* If x or y is negative, then use relative positioning: */
0685: if (curX < 0 && curY < 0) {
0686: if (curRow >= 0)
0687: curY = curRow;
0688: else if (curCol >= 0)
0689: curX = curCol;
0690: else
0691: curY = 0;
0692: }
0693: if (curX < 0) {
0694: px = 0;
0695: for (i = curY; i < (curY + curHeight); i++)
0696: px = Math.max(px, xMax[i]);
0697: curX = px - curX - 1;
0698: if (curX < 0)
0699: curX = 0;
0700: } else if (curY < 0) {
0701: py = 0;
0702: for (i = curX; i < (curX + curWidth); i++)
0703: py = Math.max(py, yMax[i]);
0704: curY = py - curY - 1;
0705: if (curY < 0)
0706: curY = 0;
0707: }
0708: /* Adjust the grid width and height */
0709:
0710: px = curX + curWidth;
0711: r.width = Math.max(r.width, px);
0712: py = curY + curHeight;
0713: r.height = Math.max(r.height, py);
0714: /* Adjust the xMax and yMax arrays */
0715: for (i = curX; i < (curX + curWidth); i++) {
0716: yMax[i] = py;
0717: }
0718: for (i = curY; i < (curY + curHeight); i++) {
0719: xMax[i] = px;
0720: }
0721: /* Cache the current slave's size. */
0722: if (sizeflag == PREFERREDSIZE)
0723: d = comp.getPreferredSize();
0724: else
0725: d = comp.getMinimumSize();
0726: constraints.minWidth = d.width;
0727: constraints.minHeight = d.height;
0728: /* Zero width and height must mean that this is the last item (or
0729: * else something is wrong). */
0730: if (constraints.gridheight == 0
0731: && constraints.gridwidth == 0)
0732: curRow = curCol = -1;
0733: /* Zero width starts a new row */
0734: if (constraints.gridheight == 0 && curRow < 0)
0735: curCol = curX + curWidth;
0736: /* Zero height starts a new column */
0737: else if (constraints.gridwidth == 0 && curCol < 0)
0738: curRow = curY + curHeight;
0739: }
0740: /*
0741: * Apply minimum row/column dimensions
0742: */
0743: if (columnWidths != null && r.width < columnWidths.length)
0744: r.width = columnWidths.length;
0745: if (rowHeights != null && r.height < rowHeights.length)
0746: r.height = rowHeights.length;
0747: /*
0748: * Pass #2
0749: *
0750: * Negative values for gridX are filled in with the current x value.
0751: * Negative values for gridY are filled in with the current y value.
0752: * Negative or zero values for gridWidth and gridHeight end the current
0753: * row or column, respectively.
0754: */
0755:
0756: curRow = curCol = -1;
0757: xMax = new int[MAXGRIDSIZE];
0758: yMax = new int[MAXGRIDSIZE];
0759: for (compindex = 0; compindex < components.length; compindex++) {
0760: comp = components[compindex];
0761: if (!comp.isVisible())
0762: continue;
0763: constraints = lookupConstraints(comp);
0764: curX = constraints.gridx;
0765: curY = constraints.gridy;
0766: curWidth = constraints.gridwidth;
0767: curHeight = constraints.gridheight;
0768: /* If x or y is negative, then use relative positioning: */
0769: if (curX < 0 && curY < 0) {
0770: if (curRow >= 0)
0771: curY = curRow;
0772: else if (curCol >= 0)
0773: curX = curCol;
0774: else
0775: curY = 0;
0776: }
0777: if (curX < 0) {
0778: if (curHeight <= 0) {
0779: curHeight += r.height - curY;
0780: if (curHeight < 1)
0781: curHeight = 1;
0782: }
0783: px = 0;
0784: for (i = curY; i < (curY + curHeight); i++)
0785: px = Math.max(px, xMax[i]);
0786: curX = px - curX - 1;
0787: if (curX < 0)
0788: curX = 0;
0789: } else if (curY < 0) {
0790: if (curWidth <= 0) {
0791: curWidth += r.width - curX;
0792: if (curWidth < 1)
0793: curWidth = 1;
0794: }
0795: py = 0;
0796: for (i = curX; i < (curX + curWidth); i++)
0797: py = Math.max(py, yMax[i]);
0798: curY = py - curY - 1;
0799: if (curY < 0)
0800: curY = 0;
0801: }
0802: if (curWidth <= 0) {
0803: curWidth += r.width - curX;
0804: if (curWidth < 1)
0805: curWidth = 1;
0806: }
0807: if (curHeight <= 0) {
0808: curHeight += r.height - curY;
0809: if (curHeight < 1)
0810: curHeight = 1;
0811: }
0812: px = curX + curWidth;
0813: py = curY + curHeight;
0814: for (i = curX; i < (curX + curWidth); i++) {
0815: yMax[i] = py;
0816: }
0817: for (i = curY; i < (curY + curHeight); i++) {
0818: xMax[i] = px;
0819: }
0820: /* Make negative sizes start a new row/column */
0821: if (constraints.gridheight == 0
0822: && constraints.gridwidth == 0)
0823: curRow = curCol = -1;
0824: if (constraints.gridheight == 0 && curRow < 0)
0825: curCol = curX + curWidth;
0826: else if (constraints.gridwidth == 0 && curCol < 0)
0827: curRow = curY + curHeight;
0828: /* Assign the new values to the gridbag slave */
0829: constraints.tempX = curX;
0830: constraints.tempY = curY;
0831: constraints.tempWidth = curWidth;
0832: constraints.tempHeight = curHeight;
0833: }
0834: /*
0835: * Apply minimum row/column dimensions and weights
0836: */
0837: if (columnWidths != null)
0838: System.arraycopy(columnWidths, 0, r.minWidth, 0,
0839: columnWidths.length);
0840: if (rowHeights != null)
0841: System.arraycopy(rowHeights, 0, r.minHeight, 0,
0842: rowHeights.length);
0843: if (columnWeights != null)
0844: System.arraycopy(columnWeights, 0, r.weightX, 0,
0845: columnWeights.length);
0846: if (rowWeights != null)
0847: System.arraycopy(rowWeights, 0, r.weightY, 0,
0848: rowWeights.length);
0849: /*
0850: * Pass #3
0851: *
0852: * Distribute the minimun widths and weights:
0853: */
0854:
0855: nextSize = Integer.MAX_VALUE;
0856: for (i = 1; i != Integer.MAX_VALUE; i = nextSize, nextSize = Integer.MAX_VALUE) {
0857: for (compindex = 0; compindex < components.length; compindex++) {
0858: comp = components[compindex];
0859: if (!comp.isVisible())
0860: continue;
0861: constraints = lookupConstraints(comp);
0862: if (constraints.tempWidth == i) {
0863: px = constraints.tempX + constraints.tempWidth; /* right column */
0864: /*
0865: * Figure out if we should use this slave\'s weight. If the weight
0866: * is less than the total weight spanned by the width of the cell,
0867: * then discard the weight. Otherwise split the difference
0868: * according to the existing weights.
0869: */
0870:
0871: weight_diff = constraints.weightx;
0872: for (k = constraints.tempX; k < px; k++)
0873: weight_diff -= r.weightX[k];
0874: if (weight_diff > 0.0) {
0875: weight = 0.0;
0876: for (k = constraints.tempX; k < px; k++)
0877: weight += r.weightX[k];
0878: for (k = constraints.tempX; weight > 0.0
0879: && k < px; k++) {
0880: double wt = r.weightX[k];
0881: double dx = (wt * weight_diff) / weight;
0882: r.weightX[k] += dx;
0883: weight_diff -= dx;
0884: weight -= wt;
0885: }
0886: /* Assign the remainder to the rightmost cell */
0887: r.weightX[px - 1] += weight_diff;
0888: }
0889: /*
0890: * Calculate the minWidth array values.
0891: * First, figure out how wide the current slave needs to be.
0892: * Then, see if it will fit within the current minWidth values.
0893: * If it will not fit, add the difference according to the
0894: * weightX array.
0895: */
0896:
0897: pixels_diff = constraints.minWidth
0898: + constraints.ipadx
0899: + constraints.insets.left
0900: + constraints.insets.right;
0901: for (k = constraints.tempX; k < px; k++)
0902: pixels_diff -= r.minWidth[k];
0903: if (pixels_diff > 0) {
0904: weight = 0.0;
0905: for (k = constraints.tempX; k < px; k++)
0906: weight += r.weightX[k];
0907: for (k = constraints.tempX; weight > 0.0
0908: && k < px; k++) {
0909: double wt = r.weightX[k];
0910: int dx = (int) ((wt * ((double) pixels_diff)) / weight);
0911: r.minWidth[k] += dx;
0912: pixels_diff -= dx;
0913: weight -= wt;
0914: }
0915: /* Any leftovers go into the rightmost cell */
0916: r.minWidth[px - 1] += pixels_diff;
0917: }
0918: } else if (constraints.tempWidth > i
0919: && constraints.tempWidth < nextSize)
0920: nextSize = constraints.tempWidth;
0921: if (constraints.tempHeight == i) {
0922: py = constraints.tempY + constraints.tempHeight; /* bottom row */
0923: /*
0924: * Figure out if we should use this slave\'s weight. If the weight
0925: * is less than the total weight spanned by the height of the cell,
0926: * then discard the weight. Otherwise split it the difference
0927: * according to the existing weights.
0928: */
0929:
0930: weight_diff = constraints.weighty;
0931: for (k = constraints.tempY; k < py; k++)
0932: weight_diff -= r.weightY[k];
0933: if (weight_diff > 0.0) {
0934: weight = 0.0;
0935: for (k = constraints.tempY; k < py; k++)
0936: weight += r.weightY[k];
0937: for (k = constraints.tempY; weight > 0.0
0938: && k < py; k++) {
0939: double wt = r.weightY[k];
0940: double dy = (wt * weight_diff) / weight;
0941: r.weightY[k] += dy;
0942: weight_diff -= dy;
0943: weight -= wt;
0944: }
0945: /* Assign the remainder to the bottom cell */
0946: r.weightY[py - 1] += weight_diff;
0947: }
0948: /*
0949: * Calculate the minHeight array values.
0950: * First, figure out how tall the current slave needs to be.
0951: * Then, see if it will fit within the current minHeight values.
0952: * If it will not fit, add the difference according to the
0953: * weightY array.
0954: */
0955:
0956: pixels_diff = constraints.minHeight
0957: + constraints.ipady
0958: + constraints.insets.top
0959: + constraints.insets.bottom;
0960: for (k = constraints.tempY; k < py; k++)
0961: pixels_diff -= r.minHeight[k];
0962: if (pixels_diff > 0) {
0963: weight = 0.0;
0964: for (k = constraints.tempY; k < py; k++)
0965: weight += r.weightY[k];
0966: for (k = constraints.tempY; weight > 0.0
0967: && k < py; k++) {
0968: double wt = r.weightY[k];
0969: int dy = (int) ((wt * ((double) pixels_diff)) / weight);
0970: r.minHeight[k] += dy;
0971: pixels_diff -= dy;
0972: weight -= wt;
0973: }
0974: /* Any leftovers go into the bottom cell */
0975: r.minHeight[py - 1] += pixels_diff;
0976: }
0977: } else if (constraints.tempHeight > i
0978: && constraints.tempHeight < nextSize)
0979: nextSize = constraints.tempHeight;
0980: }
0981: }
0982: return r;
0983: }
0984: }
0985:
0986: /**
0987: * Adjusts the x, y, width, and height fields to the correct
0988: * values depending on the constraint geometry and pads.
0989: * @param constraints the constraints to be applied
0990: * @param r the <code>Rectangle</code> to be adjusted
0991: * @since 1.4
0992: */
0993: protected void adjustForGravity(GridBagConstraints constraints,
0994: Rectangle r) {
0995: AdjustForGravity(constraints, r);
0996: }
0997:
0998: /*
0999: * Adjusts the x, y, width, and height fields to the correct
1000: * values depending on the constraint geometry and pads.
1001: */
1002: protected void AdjustForGravity(GridBagConstraints constraints,
1003: Rectangle r) {
1004: int diffx, diffy;
1005: r.x += constraints.insets.left;
1006: r.width -= (constraints.insets.left + constraints.insets.right);
1007: r.y += constraints.insets.top;
1008: r.height -= (constraints.insets.top + constraints.insets.bottom);
1009: diffx = 0;
1010: if ((constraints.fill != GridBagConstraints.HORIZONTAL && constraints.fill != GridBagConstraints.BOTH)
1011: && (r.width > (constraints.minWidth + constraints.ipadx))) {
1012: diffx = r.width
1013: - (constraints.minWidth + constraints.ipadx);
1014: r.width = constraints.minWidth + constraints.ipadx;
1015: }
1016: diffy = 0;
1017: if ((constraints.fill != GridBagConstraints.VERTICAL && constraints.fill != GridBagConstraints.BOTH)
1018: && (r.height > (constraints.minHeight + constraints.ipady))) {
1019: diffy = r.height
1020: - (constraints.minHeight + constraints.ipady);
1021: r.height = constraints.minHeight + constraints.ipady;
1022: }
1023: switch (constraints.anchor) {
1024: case GridBagConstraints.CENTER:
1025: r.x += diffx / 2;
1026: r.y += diffy / 2;
1027: break;
1028:
1029: case GridBagConstraints.NORTH:
1030: r.x += diffx / 2;
1031: break;
1032:
1033: case GridBagConstraints.NORTHEAST:
1034: r.x += diffx;
1035: break;
1036:
1037: case GridBagConstraints.EAST:
1038: r.x += diffx;
1039: r.y += diffy / 2;
1040: break;
1041:
1042: case GridBagConstraints.SOUTHEAST:
1043: r.x += diffx;
1044: r.y += diffy;
1045: break;
1046:
1047: case GridBagConstraints.SOUTH:
1048: r.x += diffx / 2;
1049: r.y += diffy;
1050: break;
1051:
1052: case GridBagConstraints.SOUTHWEST:
1053: r.y += diffy;
1054: break;
1055:
1056: case GridBagConstraints.WEST:
1057: r.y += diffy / 2;
1058: break;
1059:
1060: case GridBagConstraints.NORTHWEST:
1061: break;
1062:
1063: default:
1064: throw new IllegalArgumentException("illegal anchor value");
1065: }
1066: }
1067:
1068: /*
1069: * Figure out the minimum size of the
1070: * master based on the information from GetLayoutInfo()
1071: */
1072: private Dimension GetMinSize(Container parent,
1073: GridBagLayoutInfo info) {
1074: Dimension d = new Dimension();
1075: int i, t;
1076: Insets insets = parent.getInsets();
1077: t = 0;
1078: for (i = 0; i < info.width; i++)
1079: t += info.minWidth[i];
1080: d.width = t + insets.left + insets.right;
1081: t = 0;
1082: for (i = 0; i < info.height; i++)
1083: t += info.minHeight[i];
1084: d.height = t + insets.top + insets.bottom;
1085: return d;
1086: }
1087:
1088: /**
1089: * Lays out the grid.
1090: * @param parent the layout container
1091: * @since 1.4
1092: */
1093: protected void arrangeGrid(Container parent) {
1094: ArrangeGrid(parent);
1095: }
1096:
1097: /*
1098: * Lay out the grid
1099: */
1100: protected void ArrangeGrid(Container parent) {
1101: Component comp;
1102: int compindex;
1103: GridBagConstraints constraints;
1104: Insets insets = parent.getInsets();
1105: Component components[] = parent.getComponents();
1106: Dimension d;
1107: Rectangle r = new Rectangle();
1108: int i, diffw, diffh;
1109: double weight;
1110: GridBagLayoutInfo info;
1111: /*
1112: * If the parent has no slaves anymore, then don't do anything
1113: * at all: just leave the parent's size as-is.
1114: */
1115: if (components.length == 0
1116: && (columnWidths == null || columnWidths.length == 0)
1117: && (rowHeights == null || rowHeights.length == 0)) {
1118: return;
1119: }
1120: /*
1121: * Pass #1: scan all the slaves to figure out the total amount
1122: * of space needed.
1123: */
1124:
1125: info = GetLayoutInfo(parent, PREFERREDSIZE);
1126: d = GetMinSize(parent, info);
1127: if (parent.width < d.width || parent.height < d.height) {
1128: info = GetLayoutInfo(parent, MINSIZE);
1129: d = GetMinSize(parent, info);
1130: }
1131: layoutInfo = info;
1132: r.width = d.width;
1133: r.height = d.height;
1134: /*
1135: * DEBUG
1136: *
1137: * DumpLayoutInfo(info);
1138: * for (compindex = 0 ; compindex < components.length ; compindex++) {
1139: * comp = components[compindex];
1140: * if (!comp.isVisible())
1141: * continue;
1142: * constraints = lookupConstraints(comp);
1143: * DumpConstraints(constraints);
1144: * }
1145: * System.out.println("minSize " + r.width + " " + r.height);
1146: */
1147:
1148: /*
1149: * If the current dimensions of the window don't match the desired
1150: * dimensions, then adjust the minWidth and minHeight arrays
1151: * according to the weights.
1152: */
1153:
1154: diffw = parent.width - r.width;
1155: if (diffw != 0) {
1156: weight = 0.0;
1157: for (i = 0; i < info.width; i++)
1158: weight += info.weightX[i];
1159: if (weight > 0.0) {
1160: for (i = 0; i < info.width; i++) {
1161: int dx = (int) ((((double) diffw) * info.weightX[i]) / weight);
1162: info.minWidth[i] += dx;
1163: r.width += dx;
1164: if (info.minWidth[i] < 0) {
1165: r.width -= info.minWidth[i];
1166: info.minWidth[i] = 0;
1167: }
1168: }
1169: }
1170: diffw = parent.width - r.width;
1171: } else {
1172: diffw = 0;
1173: }
1174: diffh = parent.height - r.height;
1175: if (diffh != 0) {
1176: weight = 0.0;
1177: for (i = 0; i < info.height; i++)
1178: weight += info.weightY[i];
1179: if (weight > 0.0) {
1180: for (i = 0; i < info.height; i++) {
1181: int dy = (int) ((((double) diffh) * info.weightY[i]) / weight);
1182: info.minHeight[i] += dy;
1183: r.height += dy;
1184: if (info.minHeight[i] < 0) {
1185: r.height -= info.minHeight[i];
1186: info.minHeight[i] = 0;
1187: }
1188: }
1189: }
1190: diffh = parent.height - r.height;
1191: } else {
1192: diffh = 0;
1193: }
1194: /*
1195: * DEBUG
1196: *
1197: * System.out.println("Re-adjusted:");
1198: * DumpLayoutInfo(info);
1199: */
1200:
1201: /*
1202: * Now do the actual layout of the slaves using the layout information
1203: * that has been collected.
1204: */
1205:
1206: info.startx = diffw / 2 + insets.left;
1207: info.starty = diffh / 2 + insets.top;
1208: for (compindex = 0; compindex < components.length; compindex++) {
1209: comp = components[compindex];
1210: if (!comp.isVisible())
1211: continue;
1212: constraints = lookupConstraints(comp);
1213: r.x = info.startx;
1214: for (i = 0; i < constraints.tempX; i++)
1215: r.x += info.minWidth[i];
1216: r.y = info.starty;
1217: for (i = 0; i < constraints.tempY; i++)
1218: r.y += info.minHeight[i];
1219: r.width = 0;
1220: for (i = constraints.tempX; i < (constraints.tempX + constraints.tempWidth); i++) {
1221: r.width += info.minWidth[i];
1222: }
1223: r.height = 0;
1224: for (i = constraints.tempY; i < (constraints.tempY + constraints.tempHeight); i++) {
1225: r.height += info.minHeight[i];
1226: }
1227: AdjustForGravity(constraints, r);
1228: /*
1229: * If the window is too small to be interesting then
1230: * unmap it. Otherwise configure it and then make sure
1231: * it's mapped.
1232: */
1233:
1234: if ((r.width <= 0) || (r.height <= 0)) {
1235: comp.setBounds(0, 0, 0, 0);
1236: } else {
1237: if (comp.x != r.x || comp.y != r.y
1238: || comp.width != r.width
1239: || comp.height != r.height) {
1240: comp.setBounds(r.x, r.y, r.width, r.height);
1241: }
1242: }
1243: }
1244: }
1245:
1246: // Added for serial backwards compatability (4348425)
1247: static final long serialVersionUID = 8838754796412211005L;
1248: }
|