| /* GridBagLayout - Layout manager for components according to GridBagConstraints | |
| Copyright (C) 2002, 2003, 2004, 2005, 2006 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., 51 Franklin Street, Fifth Floor, Boston, MA | |
| 02110-1301 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 java.awt; | |
| import java.io.Serializable; | |
| import java.util.ArrayList; | |
| import java.util.HashMap; | |
| import java.util.Hashtable; | |
| /** | |
| * @author Michael Koch (konqueror@gmx.de) | |
| * @author Jeroen Frijters (jeroen@frijters.net) | |
| */ | |
| public class GridBagLayout | |
| implements Serializable, LayoutManager2 | |
| { | |
| private static final long serialVersionUID = 8838754796412211005L; | |
| protected static final int MINSIZE = 1; | |
| protected static final int PREFERREDSIZE = 2; | |
| protected static final int MAXGRIDSIZE = 512; | |
| // comptable remembers the original contraints given to us. | |
| // internalcomptable is used to keep track of modified constraint values | |
| // that we calculate, particularly when we are given RELATIVE and | |
| // REMAINDER constraints. | |
| // Constraints kept in comptable are never modified, and constraints | |
| // kept in internalcomptable can be modified internally only. | |
| protected Hashtable comptable; | |
| private Hashtable internalcomptable; | |
| protected GridBagLayoutInfo layoutInfo; | |
| protected GridBagConstraints defaultConstraints; | |
| public double[] columnWeights; | |
| public int[] columnWidths; | |
| public double[] rowWeights; | |
| public int[] rowHeights; | |
| public GridBagLayout () | |
| { | |
| this.comptable = new Hashtable(); | |
| this.internalcomptable = new Hashtable(); | |
| this.defaultConstraints= new GridBagConstraints(); | |
| } | |
| /** | |
| * Helper method to calc the sum of a range of elements in an int array. | |
| */ | |
| private int sumIntArray (int[] array, int upto) | |
| { | |
| int result = 0; | |
| for (int i = 0; i < upto; i++) | |
| result += array [i]; | |
| return result; | |
| } | |
| /** | |
| * Helper method to calc the sum of all elements in an int array. | |
| */ | |
| private int sumIntArray (int[] array) | |
| { | |
| return sumIntArray(array, array.length); | |
| } | |
| /** | |
| * Helper method to calc the sum of all elements in an double array. | |
| */ | |
| private double sumDoubleArray (double[] array) | |
| { | |
| double result = 0; | |
| for (int i = 0; i < array.length; i++) | |
| result += array [i]; | |
| return result; | |
| } | |
| public void addLayoutComponent (String name, Component component) | |
| { | |
| // do nothing here. | |
| } | |
| public void removeLayoutComponent (Component component) | |
| { | |
| // do nothing here | |
| } | |
| public void addLayoutComponent (Component component, Object constraints) | |
| { | |
| if (constraints == null) | |
| return; | |
| if (!(constraints instanceof GridBagConstraints)) | |
| throw new IllegalArgumentException("constraints " | |
| + constraints | |
| + " are not an instance of GridBagConstraints"); | |
| setConstraints (component, (GridBagConstraints) constraints); | |
| } | |
| public Dimension preferredLayoutSize (Container parent) | |
| { | |
| if (parent == null) | |
| return new Dimension (0, 0); | |
| GridBagLayoutInfo li = getLayoutInfo (parent, PREFERREDSIZE); | |
| return getMinSize (parent, li); | |
| } | |
| public Dimension minimumLayoutSize (Container parent) | |
| { | |
| if (parent == null) | |
| return new Dimension (0, 0); | |
| GridBagLayoutInfo li = getLayoutInfo (parent, MINSIZE); | |
| return getMinSize (parent, li); | |
| } | |
| public Dimension maximumLayoutSize (Container target) | |
| { | |
| return new Dimension (Integer.MAX_VALUE, Integer.MAX_VALUE); | |
| } | |
| public void layoutContainer (Container parent) | |
| { | |
| arrangeGrid (parent); | |
| } | |
| public float getLayoutAlignmentX (Container target) | |
| { | |
| return Component.CENTER_ALIGNMENT; | |
| } | |
| public float getLayoutAlignmentY (Container target) | |
| { | |
| return Component.CENTER_ALIGNMENT; | |
| } | |
| public void invalidateLayout (Container target) | |
| { | |
| this.layoutInfo = null; | |
| } | |
| public void setConstraints (Component component, | |
| GridBagConstraints constraints) | |
| { | |
| GridBagConstraints clone = (GridBagConstraints) constraints.clone(); | |
| if (clone.gridx < 0) | |
| clone.gridx = GridBagConstraints.RELATIVE; | |
| if (clone.gridy < 0) | |
| clone.gridy = GridBagConstraints.RELATIVE; | |
| if (clone.gridwidth == 0) | |
| clone.gridwidth = GridBagConstraints.REMAINDER; | |
| else if (clone.gridwidth < 0) | |
| clone.gridwidth = 1; | |
| if (clone.gridheight == 0) | |
| clone.gridheight = GridBagConstraints.REMAINDER; | |
| else if (clone.gridheight < 0) | |
| clone.gridheight = 1; | |
| comptable.put (component, clone); | |
| } | |
| public GridBagConstraints getConstraints (Component component) | |
| { | |
| return (GridBagConstraints) (lookupConstraints (component).clone()); | |
| } | |
| protected GridBagConstraints lookupConstraints (Component component) | |
| { | |
| GridBagConstraints result = (GridBagConstraints) comptable.get (component); | |
| if (result == null) | |
| { | |
| setConstraints (component, defaultConstraints); | |
| result = (GridBagConstraints) comptable.get (component); | |
| } | |
| return result; | |
| } | |
| private GridBagConstraints lookupInternalConstraints (Component component) | |
| { | |
| GridBagConstraints result = | |
| (GridBagConstraints) internalcomptable.get (component); | |
| if (result == null) | |
| { | |
| result = (GridBagConstraints) lookupConstraints(component).clone(); | |
| internalcomptable.put (component, result); | |
| } | |
| return result; | |
| } | |
| /** | |
| * @since 1.1 | |
| */ | |
| public Point getLayoutOrigin () | |
| { | |
| if (layoutInfo == null) | |
| return new Point (0, 0); | |
| return new Point (layoutInfo.pos_x, layoutInfo.pos_y); | |
| } | |
| /** | |
| * @since 1.1 | |
| */ | |
| public int[][] getLayoutDimensions () | |
| { | |
| int[][] result = new int [2][]; | |
| if (layoutInfo == null) | |
| { | |
| result[0] = new int[0]; | |
| result[1] = new int[0]; | |
| return result; | |
| } | |
| result [0] = new int [layoutInfo.cols]; | |
| System.arraycopy (layoutInfo.colWidths, 0, result [0], 0, layoutInfo.cols); | |
| result [1] = new int [layoutInfo.rows]; | |
| System.arraycopy (layoutInfo.rowHeights, 0, result [1], 0, layoutInfo.rows); | |
| return result; | |
| } | |
| public double[][] getLayoutWeights () | |
| { | |
| double[][] result = new double [2][]; | |
| if (layoutInfo == null) | |
| { | |
| result[0] = new double[0]; | |
| result[1] = new double[0]; | |
| return result; | |
| } | |
| result [0] = new double [layoutInfo.cols]; | |
| System.arraycopy (layoutInfo.colWeights, 0, result [0], 0, layoutInfo.cols); | |
| result [1] = new double [layoutInfo.rows]; | |
| System.arraycopy (layoutInfo.rowWeights, 0, result [1], 0, layoutInfo.rows); | |
| return result; | |
| } | |
| /** | |
| * @since 1.1 | |
| */ | |
| public Point location (int x, int y) | |
| { | |
| if (layoutInfo == null) | |
| return new Point (0, 0); | |
| int col; | |
| int row; | |
| int pixel_x = layoutInfo.pos_x; | |
| int pixel_y = layoutInfo.pos_y; | |
| for (col = 0; col < layoutInfo.cols; col++) | |
| { | |
| int w = layoutInfo.colWidths [col]; | |
| if (x < pixel_x + w) | |
| break; | |
| pixel_x += w; | |
| } | |
| for (row = 0; row < layoutInfo.rows; row++) | |
| { | |
| int h = layoutInfo.rowHeights [row]; | |
| if (y < pixel_y + h) | |
| break; | |
| pixel_y += h; | |
| } | |
| return new Point (col, row); | |
| } | |
| /** | |
| * Move and resize a rectangle according to a set of grid bag | |
| * constraints. The x, y, width and height fields of the | |
| * rectangle argument are adjusted to the new values. | |
| * | |
| * @param constraints position and size constraints | |
| * @param r rectangle to be moved and resized | |
| */ | |
| protected void AdjustForGravity (GridBagConstraints constraints, | |
| Rectangle r) | |
| { | |
| Insets insets = constraints.insets; | |
| if (insets != null) | |
| { | |
| r.x += insets.left; | |
| r.y += insets.top; | |
| r.width -= insets.left + insets.right; | |
| r.height -= insets.top + insets.bottom; | |
| } | |
| } | |
| /** | |
| * Obsolete. | |
| */ | |
| protected void ArrangeGrid (Container parent) | |
| { | |
| Component[] components = parent.getComponents(); | |
| if (components.length == 0) | |
| return; | |
| GridBagLayoutInfo info = getLayoutInfo (parent, PREFERREDSIZE); | |
| if (info.cols == 0 && info.rows == 0) | |
| return; | |
| // DEBUG | |
| //dumpLayoutInfo (info); | |
| // Calling setBounds on these components causes this layout to | |
| // be invalidated, clearing the layout information cache, | |
| // layoutInfo. So we wait until after this for loop to set | |
| // layoutInfo. | |
| Component lastComp = null; | |
| Rectangle cell = new Rectangle(); | |
| for (int i = 0; i < components.length; i++) | |
| { | |
| Component component = components[i]; | |
| // If component is not visible we dont have to care about it. | |
| if (! component.isVisible()) | |
| continue; | |
| Dimension dim = component.getPreferredSize(); | |
| GridBagConstraints constraints = lookupInternalConstraints(component); | |
| if (lastComp != null | |
| && constraints.gridheight == GridBagConstraints.REMAINDER) | |
| cell.y += cell.height; | |
| else | |
| cell.y = sumIntArray(info.rowHeights, constraints.gridy); | |
| if (lastComp != null | |
| && constraints.gridwidth == GridBagConstraints.REMAINDER) | |
| cell.x += cell.width; | |
| else | |
| cell.x = sumIntArray(info.colWidths, constraints.gridx); | |
| cell.width = sumIntArray(info.colWidths, constraints.gridx | |
| + constraints.gridwidth) - cell.x; | |
| cell.height = sumIntArray(info.rowHeights, constraints.gridy | |
| + constraints.gridheight) - cell.y; | |
| // Adjust for insets. | |
| AdjustForGravity( constraints, cell ); | |
| // Note: Documentation says that padding is added on both sides, but | |
| // visual inspection shows that the Sun implementation only adds it | |
| // once, so we do the same. | |
| dim.width += constraints.ipadx; | |
| dim.height += constraints.ipady; | |
| switch (constraints.fill) | |
| { | |
| case GridBagConstraints.HORIZONTAL: | |
| dim.width = cell.width; | |
| break; | |
| case GridBagConstraints.VERTICAL: | |
| dim.height = cell.height; | |
| break; | |
| case GridBagConstraints.BOTH: | |
| dim.width = cell.width; | |
| dim.height = cell.height; | |
| break; | |
| } | |
| int x = 0; | |
| int y = 0; | |
| switch (constraints.anchor) | |
| { | |
| case GridBagConstraints.NORTH: | |
| x = cell.x + (cell.width - dim.width) / 2; | |
| y = cell.y; | |
| break; | |
| case GridBagConstraints.SOUTH: | |
| x = cell.x + (cell.width - dim.width) / 2; | |
| y = cell.y + cell.height - dim.height; | |
| break; | |
| case GridBagConstraints.WEST: | |
| x = cell.x; | |
| y = cell.y + (cell.height - dim.height) / 2; | |
| break; | |
| case GridBagConstraints.EAST: | |
| x = cell.x + cell.width - dim.width; | |
| y = cell.y + (cell.height - dim.height) / 2; | |
| break; | |
| case GridBagConstraints.NORTHEAST: | |
| x = cell.x + cell.width - dim.width; | |
| y = cell.y; | |
| break; | |
| case GridBagConstraints.NORTHWEST: | |
| x = cell.x; | |
| y = cell.y; | |
| break; | |
| case GridBagConstraints.SOUTHEAST: | |
| x = cell.x + cell.width - dim.width; | |
| y = cell.y + cell.height - dim.height; | |
| break; | |
| case GridBagConstraints.SOUTHWEST: | |
| x = cell.x; | |
| y = cell.y + cell.height - dim.height; | |
| break; | |
| default: | |
| x = cell.x + (cell.width - dim.width) / 2; | |
| y = cell.y + (cell.height - dim.height) / 2; | |
| break; | |
| } | |
| component.setBounds(info.pos_x + x, info.pos_y + y, dim.width, | |
| dim.height); | |
| lastComp = component; | |
| } | |
| // DEBUG | |
| //dumpLayoutInfo(info); | |
| // Cache layout information. | |
| layoutInfo = getLayoutInfo(parent, PREFERREDSIZE); | |
| } | |
| /** | |
| * Obsolete. | |
| */ | |
| protected GridBagLayoutInfo GetLayoutInfo (Container parent, int sizeflag) | |
| { | |
| if (sizeflag != MINSIZE && sizeflag != PREFERREDSIZE) | |
| throw new IllegalArgumentException(); | |
| Dimension parentDim = parent.getSize (); | |
| Insets parentInsets = parent.getInsets (); | |
| parentDim.width -= parentInsets.left + parentInsets.right; | |
| parentDim.height -= parentInsets.top + parentInsets.bottom; | |
| int current_y = 0; | |
| int max_x = 0; | |
| int max_y = 0; | |
| // Guaranteed to contain the last component added to the given row | |
| // or column, whose gridwidth/height is not REMAINDER. | |
| HashMap lastInRow = new HashMap(); | |
| HashMap lastInCol = new HashMap(); | |
| Component[] components = parent.getComponents(); | |
| // Components sorted by gridwidths/heights, | |
| // smallest to largest, with REMAINDER and RELATIVE at the end. | |
| // These are useful when determining sizes and weights. | |
| ArrayList sortedByWidth = new ArrayList(components.length); | |
| ArrayList sortedByHeight = new ArrayList(components.length); | |
| // STEP 1: first we figure out how many rows/columns | |
| for (int i = 0; i < components.length; i++) | |
| { | |
| Component component = components [i]; | |
| // If component is not visible we dont have to care about it. | |
| if (!component.isVisible()) | |
| continue; | |
| // When looking up the constraint for the first time, check the | |
| // original unmodified constraint. After the first time, always | |
| // refer to the internal modified constraint. | |
| GridBagConstraints originalConstraints = lookupConstraints (component); | |
| GridBagConstraints constraints = (GridBagConstraints) originalConstraints.clone(); | |
| internalcomptable.put(component, constraints); | |
| // Cases: | |
| // | |
| // 1. gridy == RELATIVE, gridx == RELATIVE | |
| // | |
| // use y as the row number; check for the next | |
| // available slot at row y | |
| // | |
| // 2. only gridx == RELATIVE | |
| // | |
| // check for the next available slot at row gridy | |
| // | |
| // 3. only gridy == RELATIVE | |
| // | |
| // check for the next available slot at column gridx | |
| // | |
| // 4. neither gridx or gridy == RELATIVE | |
| // | |
| // nothing to check; just add it | |
| // cases 1 and 2 | |
| if(constraints.gridx == GridBagConstraints.RELATIVE) | |
| { | |
| if (constraints.gridy == GridBagConstraints.RELATIVE) | |
| constraints.gridy = current_y; | |
| int x; | |
| // Check the component that occupies the right-most spot in this | |
| // row. We want to add this component after it. | |
| // If this row is empty, add to the 0 position. | |
| if (!lastInRow.containsKey(new Integer(constraints.gridy))) | |
| x = 0; | |
| else | |
| { | |
| Component lastComponent = (Component) lastInRow.get(new Integer(constraints.gridy)); | |
| GridBagConstraints lastConstraints = lookupInternalConstraints(lastComponent); | |
| x = lastConstraints.gridx + Math.max(1, lastConstraints.gridwidth); | |
| } | |
| // Determine if this component will fit in the slot vertically. | |
| // If not, bump it over to where it does fit. | |
| for (int y = constraints.gridy + 1; y < constraints.gridy + Math.max(1, constraints.gridheight); y++) | |
| { | |
| if (lastInRow.containsKey(new Integer(y))) | |
| { | |
| Component lastComponent = (Component) lastInRow.get(new Integer(y)); | |
| GridBagConstraints lastConstraints = lookupInternalConstraints(lastComponent); | |
| x = Math.max (x, | |
| lastConstraints.gridx + Math.max(1, lastConstraints.gridwidth)); | |
| } | |
| } | |
| constraints.gridx = x; | |
| } | |
| // case 3 | |
| else if(constraints.gridy == GridBagConstraints.RELATIVE) | |
| { | |
| int y; | |
| // Check the component that occupies the bottom-most spot in | |
| // this column. We want to add this component below it. | |
| // If this column is empty, add to the 0 position. | |
| if (!lastInCol.containsKey(new Integer(constraints.gridx))) | |
| { | |
| y = current_y; | |
| } | |
| else | |
| { | |
| Component lastComponent = (Component)lastInCol.get(new Integer(constraints.gridx)); | |
| GridBagConstraints lastConstraints = lookupInternalConstraints(lastComponent); | |
| y = lastConstraints.gridy + Math.max(1, lastConstraints.gridheight); | |
| } | |
| // Determine if this component will fit in the slot horizontally. | |
| // If not, bump it down to where it does fit. | |
| for (int x = constraints.gridx + 1; x < constraints.gridx + Math.max(1, constraints.gridwidth); x++) | |
| { | |
| if (lastInCol.containsKey(new Integer(x))) | |
| { | |
| Component lastComponent = (Component) lastInCol.get(new Integer(x)); | |
| GridBagConstraints lastConstraints = lookupInternalConstraints(lastComponent); | |
| y = Math.max (y, | |
| lastConstraints.gridy + Math.max(1, lastConstraints.gridheight)); | |
| } | |
| } | |
| constraints.gridy = y; | |
| } | |
| // case 4: do nothing | |
| max_x = Math.max(max_x, | |
| constraints.gridx + Math.max(1, constraints.gridwidth)); | |
| max_y = Math.max(max_y, | |
| constraints.gridy + Math.max(1, constraints.gridheight)); | |
| sortBySpan(component, constraints.gridwidth, sortedByWidth, true); | |
| sortBySpan(component, constraints.gridheight, sortedByHeight, false); | |
| // Update our reference points for RELATIVE gridx and gridy. | |
| if(constraints.gridwidth == GridBagConstraints.REMAINDER) | |
| { | |
| current_y = constraints.gridy + Math.max(1, constraints.gridheight); | |
| } | |
| else if (constraints.gridwidth != GridBagConstraints.REMAINDER) | |
| { | |
| for (int y = constraints.gridy; y < constraints.gridy + Math.max(1, constraints.gridheight); y++) | |
| { | |
| if(lastInRow.containsKey(new Integer(y))) | |
| { | |
| Component lastComponent = (Component) lastInRow.get(new Integer(y)); | |
| GridBagConstraints lastConstraints = lookupInternalConstraints(lastComponent); | |
| if (constraints.gridx > lastConstraints.gridx) | |
| { | |
| lastInRow.put(new Integer(y), component); | |
| } | |
| } | |
| else | |
| { | |
| lastInRow.put(new Integer(y), component); | |
| } | |
| } | |
| for (int x = constraints.gridx; x < constraints.gridx + Math.max(1, constraints.gridwidth); x++) | |
| { | |
| if(lastInCol.containsKey(new Integer(x))) | |
| { | |
| Component lastComponent = (Component) lastInCol.get(new Integer(x)); | |
| GridBagConstraints lastConstraints = lookupInternalConstraints(lastComponent); | |
| if (constraints.gridy > lastConstraints.gridy) | |
| { | |
| lastInCol.put(new Integer(x), component); | |
| } | |
| } | |
| else | |
| { | |
| lastInCol.put(new Integer(x), component); | |
| } | |
| } | |
| } | |
| } // end of STEP 1 | |
| GridBagLayoutInfo info = new GridBagLayoutInfo(max_x, max_y); | |
| // Check if column widths and row heights are overridden. | |
| for (int x = 0; x < max_x; x++) | |
| { | |
| if(columnWidths != null && columnWidths.length > x) | |
| info.colWidths[x] = columnWidths[x]; | |
| if(columnWeights != null && columnWeights.length > x) | |
| info.colWeights[x] = columnWeights[x]; | |
| } | |
| for (int y = 0; y < max_y; y++) | |
| { | |
| if(rowHeights != null && rowHeights.length > y) | |
| info.rowHeights[y] = rowHeights[y]; | |
| if(rowWeights != null && rowWeights.length > y) | |
| info.rowWeights[y] = rowWeights[y]; | |
| } | |
| // STEP 2: Fix up any cells with width/height as REMAINDER/RELATIVE. | |
| for (int i = 0; i < components.length; i++) | |
| { | |
| Component component = components [i]; | |
| // If component is not visible we dont have to care about it. | |
| if (!component.isVisible()) | |
| continue; | |
| GridBagConstraints constraints = lookupInternalConstraints (component); | |
| if(constraints.gridwidth == GridBagConstraints.REMAINDER || constraints.gridwidth == GridBagConstraints.RELATIVE) | |
| { | |
| if(constraints.gridwidth == GridBagConstraints.REMAINDER) | |
| { | |
| for (int y = constraints.gridy; y < constraints.gridy + Math.max(1, constraints.gridheight); y++) | |
| { | |
| if (lastInRow.containsKey(new Integer(y))) | |
| { | |
| Component lastComponent = (Component) lastInRow.get(new Integer(y)); | |
| GridBagConstraints lastConstraints = lookupInternalConstraints(lastComponent); | |
| if (lastConstraints.gridwidth == GridBagConstraints.RELATIVE) | |
| { | |
| constraints.gridx = max_x - 1; | |
| break; | |
| } | |
| else | |
| { | |
| constraints.gridx = Math.max (constraints.gridx, | |
| lastConstraints.gridx + Math.max (1, lastConstraints.gridwidth)); | |
| } | |
| } | |
| } | |
| constraints.gridwidth = max_x - constraints.gridx; | |
| } | |
| else if (constraints.gridwidth == GridBagConstraints.RELATIVE) | |
| { | |
| constraints.gridwidth = max_x - constraints.gridx - 1; | |
| } | |
| // Re-sort | |
| sortedByWidth.remove(sortedByWidth.indexOf(component)); | |
| sortBySpan(component, constraints.gridwidth, sortedByWidth, true); | |
| } | |
| if(constraints.gridheight == GridBagConstraints.REMAINDER || constraints.gridheight == GridBagConstraints.RELATIVE) | |
| { | |
| if(constraints.gridheight == GridBagConstraints.REMAINDER) | |
| { | |
| for (int x = constraints.gridx; x < constraints.gridx + Math.max(1, constraints.gridwidth); x++) | |
| { | |
| if (lastInCol.containsKey(new Integer(x))) | |
| { | |
| Component lastComponent = (Component) lastInRow.get(new Integer(x)); | |
| if (lastComponent != null) | |
| { | |
| GridBagConstraints lastConstraints = lookupInternalConstraints(lastComponent); | |
| if (lastConstraints.gridheight == GridBagConstraints.RELATIVE) | |
| { | |
| constraints.gridy = max_y - 1; | |
| break; | |
| } | |
| else | |
| { | |
| constraints.gridy = Math.max (constraints.gridy, | |
| lastConstraints.gridy + Math.max (1, lastConstraints.gridheight)); | |
| } | |
| } | |
| } | |
| } | |
| constraints.gridheight = max_y - constraints.gridy; | |
| } | |
| else if (constraints.gridheight == GridBagConstraints.RELATIVE) | |
| { | |
| constraints.gridheight = max_y - constraints.gridy - 1; | |
| } | |
| // Re-sort | |
| sortedByHeight.remove(sortedByHeight.indexOf(component)); | |
| sortBySpan(component, constraints.gridheight, sortedByHeight, false); | |
| } | |
| } // end of STEP 2 | |
| // STEP 3: Determine sizes and weights for columns. | |
| for (int i = 0; i < sortedByWidth.size(); i++) | |
| { | |
| Component component = (Component) sortedByWidth.get(i); | |
| // If component is not visible we dont have to care about it. | |
| if (!component.isVisible()) | |
| continue; | |
| GridBagConstraints constraints = lookupInternalConstraints (component); | |
| int width = (sizeflag == PREFERREDSIZE) ? | |
| component.getPreferredSize().width : | |
| component.getMinimumSize().width; | |
| if(constraints.insets != null) | |
| width += constraints.insets.left + constraints.insets.right; | |
| width += constraints.ipadx; | |
| distributeSizeAndWeight(width, | |
| constraints.weightx, | |
| constraints.gridx, | |
| constraints.gridwidth, | |
| info.colWidths, | |
| info.colWeights); | |
| } // end of STEP 3 | |
| // STEP 4: Determine sizes and weights for rows. | |
| for (int i = 0; i < sortedByHeight.size(); i++) | |
| { | |
| Component component = (Component) sortedByHeight.get(i); | |
| // If component is not visible we dont have to care about it. | |
| if (!component.isVisible()) | |
| continue; | |
| GridBagConstraints constraints = lookupInternalConstraints (component); | |
| int height = (sizeflag == PREFERREDSIZE) ? | |
| component.getPreferredSize().height : | |
| component.getMinimumSize().height; | |
| if(constraints.insets != null) | |
| height += constraints.insets.top + constraints.insets.bottom; | |
| height += constraints.ipady; | |
| distributeSizeAndWeight(height, | |
| constraints.weighty, | |
| constraints.gridy, | |
| constraints.gridheight, | |
| info.rowHeights, | |
| info.rowWeights); | |
| } // end of STEP 4 | |
| // Adjust cell sizes iff parent size not zero. | |
| if (parentDim.width > 0 && parentDim.height > 0) | |
| { | |
| calcCellSizes (info.colWidths, info.colWeights, parentDim.width); | |
| calcCellSizes (info.rowHeights, info.rowWeights, parentDim.height); | |
| } | |
| int totalWidth = sumIntArray(info.colWidths); | |
| int totalHeight = sumIntArray(info.rowHeights); | |
| // Make sure pos_x and pos_y are never negative. | |
| if (totalWidth >= parentDim.width) | |
| info.pos_x = parentInsets.left; | |
| else | |
| info.pos_x = parentInsets.left + (parentDim.width - totalWidth) / 2; | |
| if (totalHeight >= parentDim.height) | |
| info.pos_y = parentInsets.top; | |
| else | |
| info.pos_y = parentInsets.top + (parentDim.height - totalHeight) / 2; | |
| // DEBUG | |
| //dumpLayoutInfo (info); | |
| return info; | |
| } | |
| /** | |
| * Obsolete. | |
| */ | |
| protected Dimension GetMinSize (Container parent, GridBagLayoutInfo info) | |
| { | |
| if (parent == null || info == null) | |
| return new Dimension (0, 0); | |
| Insets insets = parent.getInsets(); | |
| int width = sumIntArray (info.colWidths) + insets.left + insets.right; | |
| int height = sumIntArray (info.rowHeights) + insets.top + insets.bottom; | |
| return new Dimension (width, height); | |
| } | |
| /** | |
| * @since 1.4 | |
| */ | |
| protected Dimension getMinSize (Container parent, GridBagLayoutInfo info) | |
| { | |
| return GetMinSize (parent, info); | |
| } | |
| /** | |
| * Helper method used by GetLayoutInfo to keep components sorted, either | |
| * by gridwidth or gridheight. | |
| * | |
| * @param component Component to add to the sorted list. | |
| * @param span Either the component's gridwidth or gridheight. | |
| * @param list <code>ArrayList</code> of components, sorted by | |
| * their span. | |
| * @param sortByWidth Flag indicating sorting index. If true, sort by | |
| * width. Otherwise, sort by height. | |
| * FIXME: Use a better sorting algorithm. | |
| */ | |
| private void sortBySpan (Component component, int span, ArrayList list, boolean sortByWidth) | |
| { | |
| if (span == GridBagConstraints.REMAINDER | |
| || span == GridBagConstraints.RELATIVE) | |
| { | |
| // Put all RELATIVE and REMAINDER components at the end. | |
| list.add(component); | |
| } | |
| else | |
| { | |
| int i = 0; | |
| if (list.size() > 0) | |
| { | |
| GridBagConstraints gbc = lookupInternalConstraints((Component) list.get(i)); | |
| int otherspan = sortByWidth ? | |
| gbc.gridwidth : | |
| gbc.gridheight; | |
| while (otherspan != GridBagConstraints.REMAINDER | |
| && otherspan != GridBagConstraints.RELATIVE | |
| && span >= otherspan) | |
| { | |
| i++; | |
| if (i < list.size()) | |
| { | |
| gbc = lookupInternalConstraints((Component) list.get(i)); | |
| otherspan = sortByWidth ? | |
| gbc.gridwidth : | |
| gbc.gridheight; | |
| } | |
| else | |
| break; | |
| } | |
| } | |
| list.add(i, component); | |
| } | |
| } | |
| /** | |
| * Helper method used by GetLayoutInfo to distribute a component's size | |
| * and weight. | |
| * | |
| * @param size Preferred size of component, with inset and padding | |
| * already added. | |
| * @param weight Weight of component. | |
| * @param start Starting position of component. Either | |
| * constraints.gridx or gridy. | |
| * @param span Span of component. either contraints.gridwidth or | |
| * gridheight. | |
| * @param sizes Sizes of rows or columns. | |
| * @param weights Weights of rows or columns. | |
| */ | |
| private void distributeSizeAndWeight (int size, double weight, | |
| int start, int span, | |
| int[] sizes, double[] weights) | |
| { | |
| if (span == 1) | |
| { | |
| sizes[start] = Math.max(sizes[start], size); | |
| weights[start] = Math.max(weights[start], weight); | |
| } | |
| else | |
| { | |
| int numOccupied = span; | |
| int lastOccupied = -1; | |
| for(int i = start; i < start + span; i++) | |
| { | |
| if (sizes[i] == 0.0) | |
| numOccupied--; | |
| else | |
| { | |
| size -= sizes[i]; | |
| lastOccupied = i; | |
| } | |
| } | |
| // A component needs to occupy at least one row. | |
| if(numOccupied == 0) | |
| sizes[start + span - 1] = size; | |
| else if (size > 0) | |
| sizes[lastOccupied] += size; | |
| calcCellWeights(weight, weights, start, span); | |
| } | |
| } | |
| /** | |
| * Helper method used by GetLayoutInfo to calculate weight distribution. | |
| * @param weight Weight of component. | |
| * @param weights Weights of rows/columns. | |
| * @param start Starting position of component in grid (gridx/gridy). | |
| * @param span Span of component (gridwidth/gridheight). | |
| */ | |
| private void calcCellWeights (double weight, double[] weights, int start, int span) | |
| { | |
| double totalWeight = 0.0; | |
| for(int k = start; k < start + span; k++) | |
| totalWeight += weights[k]; | |
| if(weight > totalWeight) | |
| { | |
| if (totalWeight == 0.0) | |
| { | |
| weights[start + span - 1] += weight; | |
| } | |
| else | |
| { | |
| double diff = weight - totalWeight ; | |
| double remaining = diff; | |
| for(int k = start; k < start + span; k++) | |
| { | |
| double extraWeight = diff * weights[k] / totalWeight; | |
| weights[k] += extraWeight; | |
| remaining -= extraWeight; | |
| } | |
| if (remaining > 0.0 && weights[start + span - 1] != 0.0) | |
| { | |
| weights[start + span - 1] += remaining; | |
| } | |
| } | |
| } | |
| } | |
| /** | |
| * Helper method used by GetLayoutInfo to distribute extra space | |
| * based on weight distribution. | |
| * | |
| * @param sizes Sizes of rows/columns. | |
| * @param weights Weights of rows/columns. | |
| * @param range Dimension of container. | |
| */ | |
| private void calcCellSizes (int[] sizes, double[] weights, int range) | |
| { | |
| int totalSize = sumIntArray (sizes); | |
| double totalWeight = sumDoubleArray (weights); | |
| int diff = range - totalSize; | |
| if (diff == 0) | |
| return; | |
| for (int i = 0; i < sizes.length; i++) | |
| { | |
| int newsize = (int) (sizes[i] + (((double) diff) * weights [i] / totalWeight )); | |
| if (newsize > 0) | |
| sizes[i] = newsize; | |
| } | |
| } | |
| private void dumpLayoutInfo (GridBagLayoutInfo info) | |
| { | |
| System.out.println ("GridBagLayoutInfo:"); | |
| System.out.println ("cols: " + info.cols + ", rows: " + info.rows); | |
| System.out.print ("colWidths: "); | |
| dumpArray(info.colWidths); | |
| System.out.print ("rowHeights: "); | |
| dumpArray(info.rowHeights); | |
| System.out.print ("colWeights: "); | |
| dumpArray(info.colWeights); | |
| System.out.print ("rowWeights: "); | |
| dumpArray(info.rowWeights); | |
| } | |
| private void dumpArray(int[] array) | |
| { | |
| String sep = ""; | |
| for(int i = 0; i < array.length; i++) | |
| { | |
| System.out.print(sep); | |
| System.out.print(array[i]); | |
| sep = ", "; | |
| } | |
| System.out.println(); | |
| } | |
| private void dumpArray(double[] array) | |
| { | |
| String sep = ""; | |
| for(int i = 0; i < array.length; i++) | |
| { | |
| System.out.print(sep); | |
| System.out.print(array[i]); | |
| sep = ", "; | |
| } | |
| System.out.println(); | |
| } | |
| /** | |
| * @since 1.4 | |
| */ | |
| protected void arrangeGrid (Container parent) | |
| { | |
| ArrangeGrid (parent); | |
| } | |
| /** | |
| * @since 1.4 | |
| */ | |
| protected GridBagLayoutInfo getLayoutInfo (Container parent, int sizeflag) | |
| { | |
| return GetLayoutInfo (parent, sizeflag); | |
| } | |
| /** | |
| * Move and resize a rectangle according to a set of grid bag | |
| * constraints. The x, y, width and height fields of the | |
| * rectangle argument are adjusted to the new values. | |
| * | |
| * @param constraints position and size constraints | |
| * @param r rectangle to be moved and resized | |
| * | |
| * @since 1.4 | |
| */ | |
| protected void adjustForGravity (GridBagConstraints constraints, | |
| Rectangle r) | |
| { | |
| AdjustForGravity (constraints, r); | |
| } | |
| } |