/*
* (c) Copyright 2010-2011 AgileBirds
*
* This file is part of OpenFlexo.
*
* OpenFlexo 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 3 of the License, or
* (at your option) any later version.
*
* OpenFlexo 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 OpenFlexo. If not, see <http://www.gnu.org/licenses/>.
*
*/
package org.openflexo.ie.view.widget;
import java.awt.Component;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.Insets;
import java.awt.LayoutManager2;
import java.awt.Point;
import java.awt.Rectangle;
import java.util.Hashtable;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JComponent;
import org.openflexo.foundation.ie.IEObject;
import org.openflexo.foundation.ie.SingleWidgetComponentInstance;
import org.openflexo.foundation.ie.widget.IEHTMLTableConstraints;
import org.openflexo.foundation.ie.widget.IEHTMLTableWidget;
import org.openflexo.foundation.ie.widget.IEReusableWidget;
import org.openflexo.foundation.ie.widget.IESequenceTR;
import org.openflexo.foundation.ie.widget.IESequenceWidget;
import org.openflexo.foundation.ie.widget.IETDWidget;
import org.openflexo.foundation.ie.widget.IEWidget;
import org.openflexo.foundation.ie.widget.ITableRow;
import org.openflexo.foundation.ie.widget.ITableRowReusableWidget;
import org.openflexo.logging.FlexoLogger;
class GridBagLayoutInfo implements java.io.Serializable {
int width, height; /* number of cells horizontally, vertically */
int startx, starty; /* starting point for layout */
int minWidth[]; /* largest minWidth in each column */
int minHeight[]; /* largest minHeight in each row */
double weightX[]; /* largest weight in each column */
double weightY[]; /* largest weight in each row */
GridBagLayoutInfo() {
minWidth = new int[IEHTMLTableLayout.MAXGRIDSIZE];
minHeight = new int[IEHTMLTableLayout.MAXGRIDSIZE];
weightX = new double[IEHTMLTableLayout.MAXGRIDSIZE];
weightY = new double[IEHTMLTableLayout.MAXGRIDSIZE];
}
}
public class IEHTMLTableLayout implements LayoutManager2 {
private IEHTMLTableWidget _table;
private Container _parent;
private static final Logger logger = FlexoLogger.getLogger(IEHTMLTableLayout.class.getPackage().getName());
public static final int BORDER_SIZE = 3;
public IEHTMLTableLayout(IEHTMLTableWidget htmlTable, JComponent parent) {
this();
_table = htmlTable;
_parent = parent;
}
public IEObject getModel(Component comp) {
IEObject w = null;
if (comp instanceof IEWidgetView) {
w = ((IEWidgetView) comp).getModel();
}
if (w instanceof IESequenceWidget) {
IETDWidget td = ((IESequenceWidget) w).td();
if (td == null) {
if (logger.isLoggable(Level.WARNING)) {
logger.warning("I could not find the parent TD of sequence. This is no good.");
}
return null;
} else {
return td;
}
} else if (w instanceof IESequenceTR) {
return w;
} else if (w instanceof ITableRowReusableWidget) {
return ((ITableRowReusableWidget) w).getReusableComponentInstance();
} else {
if (logger.isLoggable(Level.SEVERE)) {
logger.severe("Model is nor an ITableRow nor a sequence." + comp.getClass());
}
return null;
}
}
/**
* Returns the total width percentage from the cell <code>from</code> to the cell <code>to</code> (included). If you want to know the
* width percentage of a cell, <code>from</code> and <code>to</code> are equal to the xLocation of that cell.
*
* @param from
* - the starting cell
* @param to
* - the ending cell
* @return the total width percentage between these two cells (both included)
*/
private double sum(int from, int to) {
if (to < from) {
return 0.0d;
}
return _table.getPourcentage(from, to - from + 1);
}
private int getParentWidth() {
int parentWidth = _parent.getWidth() == 0 && _parent.getParent() != null ? _parent.getParent().getWidth() : _parent.getWidth();
return parentWidth - 2 * BORDER_SIZE;
}
private int getWidth(IEObject widget) {
int parentWidth = getParentWidth();
if (widget instanceof IEWidget) {
if (widget instanceof IESequenceTR) {
int retval = new Double(sum(0, ((ITableRow) widget).getColCount() - 1) * parentWidth).intValue();
if (((IESequenceTR) widget).isSubsequence()) {
retval -= 2 * ((IESequenceTR) widget).getSequenceDepth();
}
return retval;
} else if (widget instanceof IETDWidget) {
IETDWidget td = (IETDWidget) widget;
int retval = new Double(sum(td.getXLocation(), td.getXLocation() + td.getColSpan() - 1) * parentWidth).intValue();
if (td.getXLocation() == 0 || td.getXLocation() + td.getColSpan() == td.tr().getColCount()) {
retval -= td.tr().getSequenceTR().getSequenceDepth() * 2;
}
return retval;
} else {
if (logger.isLoggable(Level.SEVERE)) {
logger.severe("Trying to layout something else than authorized : " + widget.getClass().getName());
}
return 0;
}
} else if (widget instanceof SingleWidgetComponentInstance) {
SingleWidgetComponentInstance ci = (SingleWidgetComponentInstance) widget;
IEReusableWidget reusable = ci.getReusableWidget();
ITableRow iTableRow = (ITableRow) ((ITableRowReusableWidget) reusable).getRootObject();
int retval = new Double(sum(0, iTableRow.getColCount() - 1) * parentWidth).intValue();
retval -= 2 * iTableRow.getSequenceDepth();
return retval;
}
if (logger.isLoggable(Level.SEVERE)) {
logger.severe("Trying to layout something else than authorized : " + widget.getClass().getName());
}
return 0;
}
private int getX(IEObject model) {
if (model instanceof IEWidget) {
if (model instanceof IESequenceTR) {
return ((IESequenceTR) model).getSequenceDepth() + BORDER_SIZE;// One
// pixel
// for
// each border
} else if (model instanceof IETDWidget) {
Insets i = _parent.getInsets();
int retval = new Double(sum(0, ((IETDWidget) model).getXLocation() - 1) * getParentWidth()).intValue();
if (retval == 0 && i != null) {
return i.left + BORDER_SIZE;
}
return retval + BORDER_SIZE;
} else {
if (logger.isLoggable(Level.SEVERE)) {
logger.severe("Trying to layout something else than authorized");
}
return 0;
}
} else if (model instanceof SingleWidgetComponentInstance) {
SingleWidgetComponentInstance ci = (SingleWidgetComponentInstance) model;
IEReusableWidget reusable = ci.getReusableWidget();
return ((IESequenceTR) reusable.getParent()).getSequenceDepth() + BORDER_SIZE;
}
if (logger.isLoggable(Level.SEVERE)) {
logger.severe("Trying to layout something else than authorized : " + model.getClass());
}
return 0;
}
@Override
public void layoutContainer(Container parent) {
Component comp;
int compindex;
IEHTMLTableConstraints constraints;
Insets insets = parent.getInsets();
insets.top += BORDER_SIZE;
insets.bottom += BORDER_SIZE;
Component components[] = parent.getComponents();
Dimension d;
Rectangle r = new Rectangle();
int i, diffw, diffh;
double weight;
GridBagLayoutInfo info;
_parent = parent;
/*
* If the parent has no slaves anymore, then don't do anything at all:
* just leave the parent's size as-is.
*/
if (components.length == 0 && (columnWidths == null || columnWidths.length == 0) && (rowHeights == null || rowHeights.length == 0)) {
return;
}
/*
* Pass #1: scan all the slaves to figure out the total amount of space
* needed.
*/
info = getLayoutInfo(parent, PREFERREDSIZE);
d = getMinSize(parent, info);
if (parent.getWidth() < d.width || parent.getHeight() < d.height) {
info = getLayoutInfo(parent, MINSIZE);
d = getMinSize(parent, info);
}
layoutInfo = info;
r.width = d.width;
r.height = d.height;
/*
* If the current dimensions of the window don't match the desired
* dimensions, then adjust the minWidth and minHeight arrays according
* to the weights.
*/
diffw = parent.getWidth() - r.width;
if (diffw != 0) {
weight = 0.0;
for (i = 0; i < info.width; i++) {
weight += info.weightX[i];
}
if (weight > 0.0) {
for (i = 0; i < info.width; i++) {
int dx = (int) (diffw * info.weightX[i] / weight);
info.minWidth[i] += dx;
r.width += dx;
if (info.minWidth[i] < 0) {
r.width -= info.minWidth[i];
info.minWidth[i] = 0;
}
}
}
diffw = parent.getWidth() - r.width;
} else {
diffw = 0;
}
diffh = parent.getHeight() - r.height;
if (diffh != 0) {
weight = 0.0;
for (i = 0; i < info.height; i++) {
weight += info.weightY[i];
}
if (weight > 0.0) {
for (i = 0; i < info.height; i++) {
int dy = (int) (diffh * info.weightY[i] / weight);
info.minHeight[i] += dy;
r.height += dy;
if (info.minHeight[i] < 0) {
r.height -= info.minHeight[i];
info.minHeight[i] = 0;
}
}
}
diffh = parent.getHeight() - r.height;
} else {
diffh = 0;
}
/*
* Now do the actual layout of the slaves using the layout information
* that has been collected.
*/
info.startx = diffw / 2 + insets.left;
info.starty = diffh / 2 + insets.top;
IEObject model = null;
for (compindex = 0; compindex < components.length; compindex++) {
comp = components[compindex];
if (!comp.isVisible()) {
continue;
}
constraints = lookupConstraints(comp);
model = getModel(comp);
r.x = getX(model);
// for (i = 0; i < constraints.tempX; i++)
// r.x += info.minWidth[i];
r.y = info.starty;
for (i = 0; i < constraints.tempY; i++) {
r.y += info.minHeight[i];
}
r.width = getWidth(model);
// for (i = constraints.tempX; i < (constraints.tempX +
// constraints.tempWidth); i++) {
// r.width += info.minWidth[i];
// }
r.height = 0;
for (i = constraints.tempY; i < constraints.tempY + constraints.tempHeight; i++) {
r.height += info.minHeight[i];
}
adjustForGravity(constraints, r);
/*
* fix for 4408108 - components were being created outside of the
* container
*/
if (r.x < 0) {
r.width -= r.x;
r.x = 0;
}
if (r.y < 0) {
r.height -= r.y;
r.y = BORDER_SIZE;
}
/*
* If the window is too small to be interesting then unmap it.
* Otherwise configure it and then make sure it's mapped.
*/
if (r.width <= 0 || r.height <= 0) {
comp.setBounds(0, 0, 0, 0);
} else {
if (comp.getX() != r.x || comp.getY() != r.y || comp.getWidth() != r.width || comp.getHeight() != r.height) {
comp.setBounds(r.x, r.y, r.width, r.height);
}
}
}
}
/**
* The maximum number of grid positions (both horizontally and vertically) that can be laid out by the grid bag layout.
*/
protected static final int MAXGRIDSIZE = 512;
/**
* The smallest grid that can be laid out by the grid bag layout.
*/
protected static final int MINSIZE = 1;
/**
* The preferred grid size that can be laid out by the grid bag layout.
*/
protected static final int PREFERREDSIZE = 2;
/**
* This hashtable maintains the association between a component and its gridbag constraints. The Keys in <code>comptable</code> are the
* components and the values are the instances of <code>IEHTMLTableConstraints</code>.
*
* @serial
* @see java.awt.IEHTMLTableConstraints
*/
protected Hashtable<Component, IEHTMLTableConstraints> comptable;
/**
* This field holds a gridbag constraints instance containing the default values, so if a component does not have gridbag constraints
* associated with it, then the component will be assigned a copy of the <code>defaultConstraints</code>.
*
* @serial
* @see #getConstraints(Component)
* @see #setConstraints(Component, IEHTMLTableConstraints)
* @see #lookupConstraints(Component)
*/
protected IEHTMLTableConstraints defaultConstraints;
/**
* This field holds the layout information for the gridbag. The information in this field is based on the most recent validation of the
* gridbag. If <code>layoutInfo</code> is <code>null</code> this indicates that there are no components in the gridbag or if there are
* components, they have not yet been validated.
*
* @serial
* @see #getLayoutInfo(Container, int)
*/
protected GridBagLayoutInfo layoutInfo;
/**
* This field holds the overrides to the column minimum width. If this field is non-<code>null</code> the values are applied to the
* gridbag after all of the minimum columns widths have been calculated. If columnWidths has more elements than the number of columns,
* columns are added to the gridbag to match the number of elements in columnWidth.
*
* @serial
* @see #getLayoutDimensions()
*/
public int columnWidths[];
/**
* This field holds the overrides to the row minimum heights. If this field is non-</code>null</code> the values are applied to the
* gridbag after all of the minimum row heights have been calculated. If <code>rowHeights</code> has more elements than the number of
* rows, rowa are added to the gridbag to match the number of elements in <code>rowHeights</code>.
*
* @serial
* @see #getLayoutDimensions()
*/
public int rowHeights[];
/**
* This field holds the overrides to the column weights. If this field is non-<code>null</code> the values are applied to the gridbag
* after all of the columns weights have been calculated. If <code>columnWeights[i]</code> > weight for column i, then column i is
* assigned the weight in <code>columnWeights[i]</code>. If <code>columnWeights</code> has more elements than the number of columns, the
* excess elements are ignored - they do not cause more columns to be created.
*
* @serial
*/
public double columnWeights[];
/**
* This field holds the overrides to the row weights. If this field is non-</code>null</code> the values are applied to the gridbag
* after all of the rows weights have been calculated. If <code>rowWeights[i]</code> > weight for row i, then row i is assigned the
* weight in <code>rowWeights[i]</code>. If <code>rowWeights</code> has more elements than the number of rows, the excess elements are
* ignored - they do not cause more rows to be created.
*
* @serial
*/
public double rowWeights[];
/**
* Creates a grid bag layout manager.
*/
private IEHTMLTableLayout() {
comptable = new Hashtable<Component, IEHTMLTableConstraints>();
defaultConstraints = new IEHTMLTableConstraints();
}
/**
* Sets the constraints for the specified component in this layout.
*
* @param comp
* the component to be modified
* @param constraints
* the constraints to be applied
*/
public void setConstraints(Component comp, IEHTMLTableConstraints constraints) {
comptable.put(comp, constraints.clone());
}
/**
* Gets the constraints for the specified component. A copy of the actual <code>IEHTMLTableConstraints</code> object is returned.
*
* @param comp
* the component to be queried
* @return the constraint for the specified component in this grid bag layout; a copy of the actual constraint object is returned
*/
public IEHTMLTableConstraints getConstraints(Component comp) {
IEHTMLTableConstraints constraints = comptable.get(comp);
if (constraints == null) {
constraints = defaultConstraints.clone();
comptable.put(comp, constraints.clone());
}
return constraints.clone();
}
/**
* Retrieves the constraints for the specified component. The return value is not a copy, but is the actual
* <code>IEHTMLTableConstraints</code> object used by the layout mechanism.
*
* @param comp
* the component to be queried
* @return the contraints for the specified component
*/
protected IEHTMLTableConstraints lookupConstraints(Component comp) {
IEHTMLTableConstraints constraints = comptable.get(comp);
if (constraints == null) {
constraints = defaultConstraints.clone();
comptable.put(comp, constraints.clone());
}
return constraints;
}
/**
* Removes the constraints for the specified component in this layout
*
* @param comp
* the component to be modified
*/
private void removeConstraints(Component comp) {
comptable.remove(comp);
}
/**
* Determines the origin of the layout area, in the graphics coordinate space of the target container. This value represents the pixel
* coordinates of the top-left corner of the layout area regardless of the <code>ComponentOrientation</code> value of the container.
* This is distinct from the grid origin given by the cell coordinates (0,0). Most applications do not call this method directly.
*
* @return the graphics origin of the cell in the top-left corner of the layout grid
* @see java.awt.ComponentOrientation
* @since JDK1.1
*/
public Point getLayoutOrigin() {
Point origin = new Point(0, 0);
if (layoutInfo != null) {
origin.x = layoutInfo.startx;
origin.y = layoutInfo.starty;
}
return origin;
}
/**
* Determines column widths and row heights for the layout grid.
* <p>
* Most applications do not call this method directly.
*
* @return an array of two arrays, containing the widths of the layout columns and the heights of the layout rows
* @since JDK1.1
*/
public int[][] getLayoutDimensions() {
if (layoutInfo == null) {
return new int[2][0];
}
int dim[][] = new int[2][];
dim[0] = new int[layoutInfo.width];
dim[1] = new int[layoutInfo.height];
System.arraycopy(layoutInfo.minWidth, 0, dim[0], 0, layoutInfo.width);
System.arraycopy(layoutInfo.minHeight, 0, dim[1], 0, layoutInfo.height);
return dim;
}
/**
* Determines the weights of the layout grid's columns and rows. Weights are used to calculate how much a given column or row stretches
* beyond its preferred size, if the layout has extra room to fill.
* <p>
* Most applications do not call this method directly.
*
* @return an array of two arrays, representing the horizontal weights of the layout columns and the vertical weights of the layout rows
* @since JDK1.1
*/
public double[][] getLayoutWeights() {
if (layoutInfo == null) {
return new double[2][0];
}
double weights[][] = new double[2][];
weights[0] = new double[layoutInfo.width];
weights[1] = new double[layoutInfo.height];
System.arraycopy(layoutInfo.weightX, 0, weights[0], 0, layoutInfo.width);
System.arraycopy(layoutInfo.weightY, 0, weights[1], 0, layoutInfo.height);
return weights;
}
/**
* Determines which cell in the layout grid contains the point specified by <code>(x, y)</code>. Each cell is identified by its
* column index (ranging from 0 to the number of columns minus 1) and its row index (ranging from 0 to the number of rows minus 1).
* <p>
* If the <code>(x, y)</code> point lies outside the grid, the following rules are used. The column index is returned as zero if
* <code>x</code> lies to the left of the layout for a left-to-right container or to the right of the layout for a right-to-left
* container. The column index is returned as the number of columns if <code>x</code> lies to the right of the layout in a left-to-right
* container or to the left in a right-to-left container. The row index is returned as zero if <code>y</code> lies above the layout, and
* as the number of rows if <code>y</code> lies below the layout. The orientation of a container is determined by its
* <code>ComponentOrientation</code> property.
*
* @param x
* the <i>x</i> coordinate of a point
* @param y
* the <i>y</i> coordinate of a point
* @return an ordered pair of indexes that indicate which cell in the layout grid contains the point (<i>x</i>, <i>y</i>).
* @see java.awt.ComponentOrientation
* @since JDK1.1
*/
public Point location(int x, int y) {
Point loc = new Point(0, 0);
int i, d;
if (layoutInfo == null) {
return loc;
}
d = layoutInfo.startx;
if (!rightToLeft) {
for (i = 0; i < layoutInfo.width; i++) {
d += layoutInfo.minWidth[i];
if (d > x) {
break;
}
}
} else {
for (i = layoutInfo.width - 1; i >= 0; i--) {
if (d > x) {
break;
}
d += layoutInfo.minWidth[i];
}
i++;
}
loc.x = i;
d = layoutInfo.starty;
for (i = 0; i < layoutInfo.height; i++) {
d += layoutInfo.minHeight[i];
if (d > y) {
break;
}
}
loc.y = i;
return loc;
}
/**
* Adds the specified component with the specified name to the layout.
*
* @param name
* the name of the component
* @param comp
* the component to be added
*/
@Override
public void addLayoutComponent(String name, Component comp) {
}
/**
* Adds the specified component to the layout, using the specified <code>constraints</code> object. Note that constraints are mutable
* and are, therefore, cloned when cached.
*
* @param comp
* the component to be added
* @param constraints
* an object that determines how the component is added to the layout
* @exception IllegalArgumentException
* if <code>constraints</code> is not a <code>GridBagConstraint</code>
*/
@Override
public void addLayoutComponent(Component comp, Object constraints) {
if (constraints instanceof IEHTMLTableConstraints) {
setConstraints(comp, (IEHTMLTableConstraints) constraints);
} else if (constraints != null) {
throw new IllegalArgumentException("cannot add to layout: constraints must be a GridBagConstraint");
}
}
/**
* Removes the specified component from this layout.
* <p>
* Most applications do not call this method directly.
*
* @param comp
* the component to be removed.
* @see java.awt.Container#remove(java.awt.Component)
* @see java.awt.Container#removeAll()
*/
@Override
public void removeLayoutComponent(Component comp) {
removeConstraints(comp);
}
/**
* Determines the preferred size of the <code>parent</code> container using this grid bag layout.
* <p>
* Most applications do not call this method directly.
*
* @param parent
* the container in which to do the layout
* @see java.awt.Container#getPreferredSize
* @return the preferred size of the <code>parent</code> container
*/
@Override
public Dimension preferredLayoutSize(Container parent) {
GridBagLayoutInfo info = getLayoutInfo(parent, PREFERREDSIZE);
return getMinSize(parent, info);
}
/**
* Determines the minimum size of the <code>parent</code> container using this grid bag layout.
* <p>
* Most applications do not call this method directly.
*
* @param parent
* the container in which to do the layout
* @see java.awt.Container#doLayout
* @return the minimum size of the <code>parent</code> container
*/
@Override
public Dimension minimumLayoutSize(Container parent) {
GridBagLayoutInfo info = getLayoutInfo(parent, MINSIZE);
return getMinSize(parent, info);
}
/**
* Returns the maximum dimensions for this layout given the components in the specified target container.
*
* @param target
* the container which needs to be laid out
* @see Container
* @see #minimumLayoutSize(Container)
* @see #preferredLayoutSize(Container)
* @return the maximum dimensions for this layout
*/
@Override
public Dimension maximumLayoutSize(Container target) {
return new Dimension(Integer.MAX_VALUE, Integer.MAX_VALUE);
}
/**
* Returns the alignment along the x axis. This specifies how the component would like to be aligned relative to other components. The
* value should be a number between 0 and 1 where 0 represents alignment along the origin, 1 is aligned the furthest away from the
* origin, 0.5 is centered, etc.
* <p>
*
* @return the value <code>0.5f</code> to indicate centered
*/
@Override
public float getLayoutAlignmentX(Container parent) {
return 0.5f;
}
/**
* Returns the alignment along the y axis. This specifies how the component would like to be aligned relative to other components. The
* value should be a number between 0 and 1 where 0 represents alignment along the origin, 1 is aligned the furthest away from the
* origin, 0.5 is centered, etc.
* <p>
*
* @return the value <code>0.5f</code> to indicate centered
*/
@Override
public float getLayoutAlignmentY(Container parent) {
return 0.5f;
}
/**
* Invalidates the layout, indicating that if the layout manager has cached information it should be discarded.
*/
@Override
public void invalidateLayout(Container target) {
}
/**
* Returns a string representation of this grid bag layout's values.
*
* @return a string representation of this grid bag layout.
*/
@Override
public String toString() {
return getClass().getName();
}
/**
* Fills in an instance of <code>GridBagLayoutInfo</code> for the current set of managed children. This requires three passes through
* the set of children:
*
* <ol>
* <li>Figure out the dimensions of the layout grid.
* <li>Determine which cells the components occupy.
* <li>Distribute the weights and min sizes amoung the rows/columns.
* </ol>
*
* This also caches the minsizes for all the children when they are first encountered (so subsequent loops don't need to ask again).
*
* @param parent
* the layout container
* @param sizeflag
* either <code>PREFERREDSIZE</code> or <code>MINSIZE</code>
* @return the <code>GridBagLayoutInfo</code> for the set of children
* @since 1.4
*/
protected GridBagLayoutInfo getLayoutInfo(Container parent, int sizeflag) {
return GetLayoutInfo(parent, sizeflag);
}
/**
* This method is obsolete and supplied for backwards compatability only; new code should call {@link #getLayoutInfo(Container, int)
* getLayoutInfo} instead.
*/
protected GridBagLayoutInfo GetLayoutInfo(Container parent, int sizeflag) {
synchronized (parent.getTreeLock()) {
GridBagLayoutInfo r = new GridBagLayoutInfo();
Component comp;
IEHTMLTableConstraints constraints;
Dimension d;
Component components[] = parent.getComponents();
int compindex, i, k, px, py, pixels_diff, nextSize;
int curX, curY, curWidth, curHeight, curRow, curCol;
double weight_diff, weight;
int xMax[], yMax[];
/*
* Pass #1
*
* Figure out the dimensions of the layout grid (use a value of 1
* for zero or negative widths and heights).
*/
r.width = r.height = 0;
curRow = curCol = -1;
xMax = new int[MAXGRIDSIZE];
yMax = new int[MAXGRIDSIZE];
IEObject model = null;
for (compindex = 0; compindex < components.length; compindex++) {
comp = components[compindex];
if (!comp.isVisible()) {
continue;
}
constraints = lookupConstraints(comp);
model = getModel(comp);
curX = getGridX(model);
curY = getGridY(model);
curWidth = getColSpan(model);
if (curWidth <= 0) {
curWidth = 1;
}
curHeight = getRowSpan(model);
if (curHeight <= 0) {
curHeight = 1;
}
/* If x or y is negative, then use relative positioning: */
if (curX < 0 && curY < 0) {
if (curRow >= 0) {
curY = curRow;
} else if (curCol >= 0) {
curX = curCol;
} else {
curY = 0;
}
}
if (curX < 0) {
px = 0;
for (i = curY; i < curY + curHeight; i++) {
if (xMax[i] > px) {
px = xMax[i];
}
}
curX = px - curX - 1;
if (curX < 0) {
curX = 0;
}
} else if (curY < 0) {
py = 0;
for (i = curX; i < curX + curWidth; i++) {
if (yMax[i] > py) {
py = yMax[i];
}
}
curY = py - curY - 1;
if (curY < 0) {
curY = 0;
}
}
/* Adjust the grid width and height */
// for (px = curX + curWidth; r.width < px; r.width++);
px = curX + curWidth;
if (px > r.width) {
r.width = px;
}
// for (py = curY + curHeight; r.height < py; r.height++);
py = curY + curHeight;
if (py > r.height) {
r.height = py;
}
/* Adjust the xMax and yMax arrays */
for (i = curX; i < curX + curWidth; i++) {
yMax[i] = py;
}
for (i = curY; i < curY + curHeight; i++) {
xMax[i] = px;
}
/* Cache the current slave's size. */
if (sizeflag == PREFERREDSIZE) {
d = comp.getPreferredSize();
} else {
d = comp.getMinimumSize();
}
constraints.minWidth = d.width;
constraints.minHeight = d.height;
/*
* Zero width and height must mean that this is the last item
* (or else something is wrong).
*/
if (constraints.gridheight == 0 && constraints.gridwidth == 0) {
curRow = curCol = -1;
}
/* Zero width starts a new row */
if (constraints.gridheight == 0 && curRow < 0) {
curCol = curX + curWidth;
} else if (constraints.gridwidth == 0 && curCol < 0) {
curRow = curY + curHeight;
}
}
/*
* Apply minimum row/column dimensions
*/
if (columnWidths != null && r.width < columnWidths.length) {
r.width = columnWidths.length;
}
if (rowHeights != null && r.height < rowHeights.length) {
r.height = rowHeights.length;
}
/*
* Pass #2
*
* Negative values for gridX are filled in with the current x value.
* Negative values for gridY are filled in with the current y value.
* Negative or zero values for gridWidth and gridHeight end the
* current row or column, respectively.
*/
curRow = curCol = -1;
xMax = new int[MAXGRIDSIZE];
yMax = new int[MAXGRIDSIZE];
for (compindex = 0; compindex < components.length; compindex++) {
comp = components[compindex];
if (!comp.isVisible()) {
continue;
}
constraints = lookupConstraints(comp);
model = getModel(comp);
curX = getGridX(model);
curY = getGridY(model);
curWidth = getColSpan(model);
curHeight = getRowSpan(model);
/* If x or y is negative, then use relative positioning: */
if (curX < 0 && curY < 0) {
if (curRow >= 0) {
curY = curRow;
} else if (curCol >= 0) {
curX = curCol;
} else {
curY = 0;
}
}
if (curX < 0) {
if (curHeight <= 0) {
curHeight += r.height - curY;
if (curHeight < 1) {
curHeight = 1;
}
}
px = 0;
for (i = curY; i < curY + curHeight; i++) {
if (xMax[i] > px) {
px = xMax[i];
}
}
curX = px - curX - 1;
if (curX < 0) {
curX = 0;
}
} else if (curY < 0) {
if (curWidth <= 0) {
curWidth += r.width - curX;
if (curWidth < 1) {
curWidth = 1;
}
}
py = 0;
for (i = curX; i < curX + curWidth; i++) {
if (yMax[i] > py) {
py = yMax[i];
}
}
curY = py - curY - 1;
if (curY < 0) {
curY = 0;
}
}
if (curWidth <= 0) {
curWidth += r.width - curX;
if (curWidth < 1) {
curWidth = 1;
}
}
if (curHeight <= 0) {
curHeight += r.height - curY;
if (curHeight < 1) {
curHeight = 1;
}
}
px = curX + curWidth;
py = curY + curHeight;
for (i = curX; i < curX + curWidth; i++) {
yMax[i] = py;
}
for (i = curY; i < curY + curHeight; i++) {
xMax[i] = px;
}
/* Make negative sizes start a new row/column */
if (constraints.gridheight == 0 && constraints.gridwidth == 0) {
curRow = curCol = -1;
}
if (constraints.gridheight == 0 && curRow < 0) {
curCol = curX + curWidth;
} else if (constraints.gridwidth == 0 && curCol < 0) {
curRow = curY + curHeight;
}
/* Assign the new values to the gridbag slave */
constraints.tempX = curX;
constraints.tempY = curY;
constraints.tempWidth = curWidth;
constraints.tempHeight = curHeight;
}
/*
* Apply minimum row/column dimensions and weights
*/
if (columnWidths != null) {
System.arraycopy(columnWidths, 0, r.minWidth, 0, columnWidths.length);
}
if (rowHeights != null) {
System.arraycopy(rowHeights, 0, r.minHeight, 0, rowHeights.length);
}
if (columnWeights != null) {
System.arraycopy(columnWeights, 0, r.weightX, 0, columnWeights.length);
}
if (rowWeights != null) {
System.arraycopy(rowWeights, 0, r.weightY, 0, rowWeights.length);
}
/*
* Pass #3
*
* Distribute the minimun widths and weights:
*/
nextSize = Integer.MAX_VALUE;
for (i = 1; i != Integer.MAX_VALUE; i = nextSize, nextSize = Integer.MAX_VALUE) {
for (compindex = 0; compindex < components.length; compindex++) {
comp = components[compindex];
if (!comp.isVisible()) {
continue;
}
constraints = lookupConstraints(comp);
if (constraints.tempWidth == i) {
px = constraints.tempX + constraints.tempWidth; /*
* right
* column
*/
/*
* Figure out if we should use this slave\'s weight. If
* the weight is less than the total weight spanned by
* the width of the cell, then discard the weight.
* Otherwise split the difference according to the
* existing weights.
*/
weight_diff = constraints.weightx;
for (k = constraints.tempX; k < px; k++) {
weight_diff -= r.weightX[k];
}
if (weight_diff > 0.0) {
weight = 0.0;
for (k = constraints.tempX; k < px; k++) {
weight += r.weightX[k];
}
for (k = constraints.tempX; weight > 0.0 && k < px; k++) {
double wt = r.weightX[k];
double dx = wt * weight_diff / weight;
r.weightX[k] += dx;
weight_diff -= dx;
weight -= wt;
}
/* Assign the remainder to the rightmost cell */
r.weightX[px - 1] += weight_diff;
}
/*
* Calculate the minWidth array values. First, figure
* out how wide the current slave needs to be. Then, see
* if it will fit within the current minWidth values. If
* it will not fit, add the difference according to the
* weightX array.
*/
pixels_diff = constraints.minWidth + constraints.ipadx + constraints.insets.left + constraints.insets.right;
for (k = constraints.tempX; k < px; k++) {
pixels_diff -= r.minWidth[k];
}
if (pixels_diff > 0) {
weight = 0.0;
for (k = constraints.tempX; k < px; k++) {
weight += r.weightX[k];
}
for (k = constraints.tempX; weight > 0.0 && k < px; k++) {
double wt = r.weightX[k];
int dx = (int) (wt * pixels_diff / weight);
r.minWidth[k] += dx;
pixels_diff -= dx;
weight -= wt;
}
/* Any leftovers go into the rightmost cell */
r.minWidth[px - 1] += pixels_diff;
}
} else if (constraints.tempWidth > i && constraints.tempWidth < nextSize) {
nextSize = constraints.tempWidth;
}
if (constraints.tempHeight == i) {
py = constraints.tempY + constraints.tempHeight; /*
* bottom
* row
*/
/*
* Figure out if we should use this slave's weight. If
* the weight is less than the total weight spanned by
* the height of the cell, then discard the weight.
* Otherwise split it the difference according to the
* existing weights.
*/
weight_diff = constraints.weighty;
for (k = constraints.tempY; k < py; k++) {
weight_diff -= r.weightY[k];
}
if (weight_diff > 0.0) {
weight = 0.0;
for (k = constraints.tempY; k < py; k++) {
weight += r.weightY[k];
}
for (k = constraints.tempY; weight > 0.0 && k < py; k++) {
double wt = r.weightY[k];
double dy = wt * weight_diff / weight;
r.weightY[k] += dy;
weight_diff -= dy;
weight -= wt;
}
/* Assign the remainder to the bottom cell */
r.weightY[py - 1] += weight_diff;
}
/*
* Calculate the minHeight array values. First, figure
* out how tall the current slave needs to be. Then, see
* if it will fit within the current minHeight values.
* If it will not fit, add the difference according to
* the weightY array.
*/
pixels_diff = constraints.minHeight + constraints.ipady + constraints.insets.top + constraints.insets.bottom;
for (k = constraints.tempY; k < py; k++) {
pixels_diff -= r.minHeight[k];
}
if (pixels_diff > 0) {
weight = 0.0;
for (k = constraints.tempY; k < py; k++) {
weight += r.weightY[k];
}
for (k = constraints.tempY; weight > 0.0 && k < py; k++) {
double wt = r.weightY[k];
int dy = (int) (wt * pixels_diff / weight);
r.minHeight[k] += dy;
pixels_diff -= dy;
weight -= wt;
}
/* Any leftovers go into the bottom cell */
r.minHeight[py - 1] += pixels_diff;
}
} else if (constraints.tempHeight > i && constraints.tempHeight < nextSize) {
nextSize = constraints.tempHeight;
}
}
}
return r;
}
}
/**
* @param model
* @return
*/
private int getRowSpan(IEObject model) {
if (model instanceof IESequenceTR) {
return 1;
} else if (model instanceof SingleWidgetComponentInstance) {
return 1;
} else if (model instanceof ITableRowReusableWidget) {
return 1;
} else if (model instanceof IETDWidget) {
return ((IETDWidget) model).getRowSpan();
} else {
if (logger.isLoggable(Level.WARNING)) {
logger.warning("Trying to layout an unknown component.");
}
return 0;
}
}
/**
* @param model
* @return
*/
private int getColSpan(IEObject model) {
if (model instanceof IESequenceTR) {
return ((IESequenceTR) model).getColCount();
} else if (model instanceof SingleWidgetComponentInstance) {
return ((IESequenceTR) ((SingleWidgetComponentInstance) model).getReusableWidget().getRootObject()).getColCount();
} else if (model instanceof ITableRowReusableWidget) {
return ((ITableRowReusableWidget) model).getColCount();
} else if (model instanceof IETDWidget) {
return ((IETDWidget) model).getColSpan();
} else {
if (logger.isLoggable(Level.WARNING)) {
logger.warning("Trying to layout an unknown component.");
}
return 0;
}
}
/**
* @param model
* @return
*/
private int getGridY(IEObject model) {
if (model instanceof IESequenceTR) {
return ((IESequenceTR) model).getIndex();
} else if (model instanceof IETDWidget) {
return ((IETDWidget) model).tr().getIndex();
} else if (model instanceof SingleWidgetComponentInstance) {
return ((ITableRowReusableWidget) ((SingleWidgetComponentInstance) model).getReusableWidget()).getRowIndex();
} else if (model instanceof ITableRowReusableWidget) {
return ((ITableRowReusableWidget) model).getRowIndex();
}
if (logger.isLoggable(Level.WARNING)) {
logger.warning("Trying to layout an unknown component:" + model.getClass());
}
return 0;
}
/**
* @param model
* @return
*/
private int getGridX(IEObject model) {
if (model instanceof IESequenceTR) {
return 0;
} else if (model instanceof SingleWidgetComponentInstance) {
return 0;
} else if (model instanceof IETDWidget) {
return ((IETDWidget) model).getXLocation();
} else if (model instanceof ITableRowReusableWidget) {
return 0;
} else {
if (logger.isLoggable(Level.WARNING)) {
logger.warning("Trying to layout an unknown component.");
}
return 0;
}
}
/**
* Adjusts the x, y, width, and height fields to the correct values depending on the constraint geometry and pads.
*
* @param constraints
* the constraints to be applied
* @param r
* the <code>Rectangle</code> to be adjusted
* @since 1.4
*/
protected void adjustForGravity(IEHTMLTableConstraints constraints, Rectangle r) {
int diffx, diffy;
if (!rightToLeft) {
r.x += constraints.insets.left;
} else {
r.x -= r.width - constraints.insets.right;
}
r.width -= constraints.insets.left + constraints.insets.right;
r.y += constraints.insets.top;
r.height -= constraints.insets.top + constraints.insets.bottom;
diffx = 0;
if (constraints.fill != IEHTMLTableConstraints.HORIZONTAL && constraints.fill != IEHTMLTableConstraints.BOTH
&& r.width > constraints.minWidth + constraints.ipadx) {
diffx = r.width - (constraints.minWidth + constraints.ipadx);
r.width = constraints.minWidth + constraints.ipadx;
}
diffy = 0;
if (constraints.fill != IEHTMLTableConstraints.VERTICAL && constraints.fill != IEHTMLTableConstraints.BOTH
&& r.height > constraints.minHeight + constraints.ipady) {
diffy = r.height - (constraints.minHeight + constraints.ipady);
r.height = constraints.minHeight + constraints.ipady;
}
switch (constraints.anchor) {
case IEHTMLTableConstraints.CENTER:
r.x += diffx / 2;
r.y += diffy / 2;
break;
case IEHTMLTableConstraints.PAGE_START:
case IEHTMLTableConstraints.NORTH:
r.x += diffx / 2;
break;
case IEHTMLTableConstraints.NORTHEAST:
r.x += diffx;
break;
case IEHTMLTableConstraints.EAST:
r.x += diffx;
r.y += diffy / 2;
break;
case IEHTMLTableConstraints.SOUTHEAST:
r.x += diffx;
r.y += diffy;
break;
case IEHTMLTableConstraints.PAGE_END:
case IEHTMLTableConstraints.SOUTH:
r.x += diffx / 2;
r.y += diffy;
break;
case IEHTMLTableConstraints.SOUTHWEST:
r.y += diffy;
break;
case IEHTMLTableConstraints.WEST:
r.y += diffy / 2;
break;
case IEHTMLTableConstraints.NORTHWEST:
break;
case IEHTMLTableConstraints.LINE_START:
if (rightToLeft) {
r.x += diffx;
}
r.y += diffy / 2;
break;
case IEHTMLTableConstraints.LINE_END:
if (!rightToLeft) {
r.x += diffx;
}
r.y += diffy / 2;
break;
case IEHTMLTableConstraints.FIRST_LINE_START:
if (rightToLeft) {
r.x += diffx;
}
break;
case IEHTMLTableConstraints.FIRST_LINE_END:
if (!rightToLeft) {
r.x += diffx;
}
break;
case IEHTMLTableConstraints.LAST_LINE_START:
if (rightToLeft) {
r.x += diffx;
}
r.y += diffy;
break;
case IEHTMLTableConstraints.LAST_LINE_END:
if (!rightToLeft) {
r.x += diffx;
}
r.y += diffy;
break;
default:
throw new IllegalArgumentException("illegal anchor value");
}
}
/**
* Figures out the minimum size of the master based on the information from getLayoutInfo().
*
* @param parent
* the layout container
* @param info
* the layout info for this parent
* @return a <code>Dimension</code> object containing the minimum size
* @since 1.4
*/
protected Dimension getMinSize(Container parent, GridBagLayoutInfo info) {
return GetMinSize(parent, info);
}
/**
* This method is obsolete and supplied for backwards compatability only; new code should call
* {@link #getMinSize(Container, GridBagLayoutInfo) getMinSize} instead.
*/
protected Dimension GetMinSize(Container parent, GridBagLayoutInfo info) {
Dimension d = new Dimension();
int i, t;
Insets insets = parent.getInsets();
insets.bottom += BORDER_SIZE;
insets.top += BORDER_SIZE;
t = 0;
for (i = 0; i < info.width; i++) {
t += info.minWidth[i];
}
d.width = t + insets.left + insets.right;
t = 0;
for (i = 0; i < info.height; i++) {
t += info.minHeight[i];
}
d.height = t + insets.top + insets.bottom;
return d;
}
transient boolean rightToLeft = false;
}