GridBagLayout.java [plain text]
package java.awt;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Hashtable;
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;
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();
}
private int sumIntArray (int[] array, int upto)
{
int result = 0;
for (int i = 0; i < upto; i++)
result += array [i];
return result;
}
private int sumIntArray (int[] array)
{
return sumIntArray(array, array.length);
}
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)
{
}
public void removeLayoutComponent (Component component)
{
}
public void addLayoutComponent (Component component, Object constraints)
{
if (constraints == null)
return;
if (!(constraints instanceof GridBagConstraints))
throw new IllegalArgumentException();
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 != GridBagConstraints.REMAINDER
&& clone.gridwidth != GridBagConstraints.RELATIVE)
clone.gridwidth = 1;
if (clone.gridheight == 0)
clone.gridheight = GridBagConstraints.REMAINDER;
else if (clone.gridheight < 0
&& clone.gridheight != GridBagConstraints.REMAINDER
&& clone.gridheight != GridBagConstraints.RELATIVE)
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;
}
public Point getLayoutOrigin ()
{
if (layoutInfo == null)
return new Point (0, 0);
return new Point (layoutInfo.pos_x, layoutInfo.pos_y);
}
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;
}
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);
}
protected void AdjustForGravity (GridBagConstraints gbc, Rectangle rect)
{
throw new Error ("Not implemented");
}
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;
layoutInfo = info;
for(int i = 0; i < components.length; i++)
{
Component component = components [i];
if (!component.isVisible())
continue;
GridBagConstraints constraints =
lookupInternalConstraints(component);
int cellx = sumIntArray(layoutInfo.colWidths, constraints.gridx);
int celly = sumIntArray(layoutInfo.rowHeights, constraints.gridy);
int cellw = sumIntArray(layoutInfo.colWidths,
constraints.gridx + constraints.gridwidth) - cellx;
int cellh = sumIntArray(layoutInfo.rowHeights,
constraints.gridy + constraints.gridheight) - celly;
Insets insets = constraints.insets;
if (insets != null)
{
cellx += insets.left;
celly += insets.top;
cellw -= insets.left + insets.right;
cellh -= insets.top + insets.bottom;
}
Dimension dim = component.getPreferredSize();
dim.width += constraints.ipadx;
dim.height += constraints.ipady;
switch(constraints.fill)
{
case GridBagConstraints.HORIZONTAL:
dim.width = cellw;
break;
case GridBagConstraints.VERTICAL:
dim.height = cellh;
break;
case GridBagConstraints.BOTH:
dim.width = cellw;
dim.height = cellh;
break;
}
int x;
int y;
switch(constraints.anchor)
{
case GridBagConstraints.NORTH:
x = cellx + (cellw - dim.width) / 2;
y = celly;
break;
case GridBagConstraints.SOUTH:
x = cellx + (cellw - dim.width) / 2;
y = celly + cellh - dim.height;
break;
case GridBagConstraints.WEST:
x = cellx;
y = celly + (cellh - dim.height) / 2;
break;
case GridBagConstraints.EAST:
x = cellx + cellw - dim.width;
y = celly + (cellh - dim.height) / 2;
break;
case GridBagConstraints.NORTHEAST:
x = cellx + cellw - dim.width;
y = celly;
break;
case GridBagConstraints.NORTHWEST:
x = cellx;
y = celly;
break;
case GridBagConstraints.SOUTHEAST:
x = cellx + cellw - dim.width;
y = celly + cellh - dim.height;
break;
case GridBagConstraints.SOUTHWEST:
x = cellx;
y = celly + cellh - dim.height;
break;
default:
x = cellx + (cellw - dim.width) / 2;
y = celly + (cellh - dim.height) / 2;
break;
}
component.setBounds(layoutInfo.pos_x + x, layoutInfo.pos_y + y, dim.width, dim.height);
}
}
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;
HashMap lastInRow = new HashMap();
HashMap lastInCol = new HashMap();
Component[] components = parent.getComponents();
ArrayList sortedByWidth = new ArrayList(components.length);
ArrayList sortedByHeight = new ArrayList(components.length);
for (int i = 0; i < components.length; i++)
{
Component component = components [i];
if (!component.isVisible())
continue;
GridBagConstraints originalConstraints = lookupConstraints (component);
GridBagConstraints constraints = (GridBagConstraints) originalConstraints.clone();
internalcomptable.put(component, constraints);
if(constraints.gridx == GridBagConstraints.RELATIVE)
{
if (constraints.gridy == GridBagConstraints.RELATIVE)
constraints.gridy = current_y;
int x;
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);
}
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;
}
else if(constraints.gridy == GridBagConstraints.RELATIVE)
{
int y;
if (!lastInCol.containsKey(new Integer(constraints.gridx)))
y = 0;
else
{
Component lastComponent = (Component)lastInCol.get(new Integer(constraints.gridx));
GridBagConstraints lastConstraints = lookupInternalConstraints(lastComponent);
y = lastConstraints.gridy + Math.max(1, lastConstraints.gridheight);
}
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;
}
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);
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);
}
}
}
}
GridBagLayoutInfo info = new GridBagLayoutInfo(max_x, max_y);
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];
}
for (int i = 0; i < components.length; i++)
{
Component component = components [i];
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;
}
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));
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;
}
sortedByHeight.remove(sortedByHeight.indexOf(component));
sortBySpan(component, constraints.gridheight, sortedByHeight, false);
}
}
for (int i = 0; i < sortedByWidth.size(); i++)
{
Component component = (Component) sortedByWidth.get(i);
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);
}
for (int i = 0; i < sortedByHeight.size(); i++)
{
Component component = (Component) sortedByHeight.get(i);
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);
}
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);
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;
return info;
}
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);
}
protected Dimension getMinSize (Container parent, GridBagLayoutInfo info)
{
return GetMinSize (parent, info);
}
private void sortBySpan (Component component, int span, ArrayList list, boolean sortByWidth)
{
if (span == GridBagConstraints.REMAINDER
|| span == GridBagConstraints.RELATIVE)
{
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);
}
}
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;
}
}
if(numOccupied == 0)
sizes[start + span - 1] = size;
else if (size > 0)
sizes[lastOccupied] += size;
calcCellWeights(weight, weights, start, span);
}
}
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;
}
}
}
}
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();
}
protected void arrangeGrid (Container parent)
{
ArrangeGrid (parent);
}
protected GridBagLayoutInfo getLayoutInfo (Container parent, int sizeflag)
{
return GetLayoutInfo (parent, sizeflag);
}
protected void adjustForGravity (GridBagConstraints gbc, Rectangle rect)
{
AdjustForGravity (gbc, rect);
}
}