/*
* Concept profile generation tool suite
* Copyright (C) 2015 Biosemantics Group, Erasmus University Medical Center,
* Rotterdam, The Netherlands
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published
* by the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
*/
package org.erasmusmc.tablelayout;
import java.awt.*;
import java.util.*;
/**
* TableLayout is a layout manager that arranges components in rows and columns
* like a spreadsheet. TableLayout allows each row or column to be a different
* size. A row or column can be given an absolute size in pixels, a percentage
* of the available space, or it can grow and shrink to fill the remaining space
* after other rows and columns have been resized.
*
* <p>Using spreadsheet terminology, a cell is the intersection of a row and
* column. Cells have finite, non-negative sizes measured in pixels. The
* dimensions of a cell depend solely upon the dimensions of its row and column.
* </p>
*
* <p>A component occupies a rectangular group of one or more cells. If the
* component occupies more than one cell, the component is resized to fit
* perfectly in the rectangular region of cells. If the component occupies a
* single cell, it can be aligned in four ways within that cell.</p>
*
* <p>A single cell component can be stretched horizontally to fit the cell
* (full justification), or it can be placed in the center of the cell. The
* component could also be left justified or right justified. Similarly, the
* component can be full, center, top, or bottom justified in the vertical.</p>
*
* <pre>
* public static void main (String args[])
* {
* // Create a frame
* Frame frame = new Frame("Example of TableLayout");
* frame.setBounds (100, 100, 300, 300);
* <spc>
* // Create a TableLayout for the frame
* double border = 10;
* double size[][] =
* {{border, 0.10, 20, TableLayout.FILL, 20, 0.20, border}, // Columns
* {border, 0.20, 20, TableLayout.FILL, 20, 0.20, border}}; // Rows
* <spc>
* frame.setLayout (new TableLayout(size));
* <spc>
* // Create some buttons
* String label[] = {"Top", "Bottom", "Left", "Right", "Center", "Overlap"};
* Button button[] = new Button[label.length];
* <spc>
* for (int i = 0; i < label.length; i++)
* button[i] = new Button(label[i]);
* <spc>
* // Add buttons
* frame.add (button[0], "1, 1, 5, 1"); // Top
* frame.add (button[1], "1, 5, 5, 5"); // Bottom
* frame.add (button[2], "1, 3 "); // Left
* frame.add (button[3], "5, 3 "); // Right
* frame.add (button[4], "3, 3, c, c"); // Center
* frame.add (button[5], "3, 3, 3, 5"); // Overlap
* <spc>
* // Allow user to close the window to terminate the program
* frame.addWindowListener
* (new WindowListener()
* {
* public void windowClosing (WindowEvent e)
* {
* System.exit (0);
* }
* <spc>
* public void windowOpened (WindowEvent e) {}
* public void windowClosed (WindowEvent e) {}
* public void windowIconified (WindowEvent e) {}
* public void windowDeiconified (WindowEvent e) {}
* public void windowActivated (WindowEvent e) {}
* public void windowDeactivated (WindowEvent e) {}
* }
* );
* <spc>
* // Show frame
* frame.show();
* }
* </pre>
*
* @author Daniel E. Barbalace
*/
public class TableLayout implements
java.awt.LayoutManager2,
java.io.Serializable,
org.erasmusmc.tablelayout.TableLayoutConstants
{
private static final long serialVersionUID = -5686070153033444350L;
/** Default row/column size */
protected static final double defaultSize[][] = {{}, {}};
/** Widths of columns expressed in absolute and relative terms */
protected double columnSpec[];
/** Heights of rows expressed in absolute and relative terms */
protected double rowSpec[];
/** Widths of columns in pixels */
protected int columnSize[];
/** Heights of rows in pixels */
protected int rowSize[];
/** Offsets of columns in pixels. The left boarder of column n is at
columnOffset[n] and the right boarder is at columnOffset[n + 1] for all
columns including the last one. columnOffset.length = columnSize.length + 1 */
protected int columnOffset[];
/** Offsets of rows in pixels. The left boarder of row n is at
rowOffset[n] and the right boarder is at rowOffset[n + 1] for all
rows including the last one. rowOffset.length = rowSize.length + 1 */
protected int rowOffset[];
/** List of components and their sizes */
protected LinkedList list;
/** Indicates whether or not the size of the cells are known for the last known
size of the container. If dirty is true or the container has been resized,
the cell sizes must be recalculated using calculateSize. */
protected boolean dirty;
/** Previous known width of the container */
protected int oldWidth;
/** Previous known height of the container */
protected int oldHeight;
//******************************************************************************
//** Constructors ***
//******************************************************************************
/**
* Constructs an instance of TableLayout. This TableLayout will have one row
* and one column.
*/
public TableLayout ()
{
this (defaultSize);
}
/**
* Constructs an instance of TableLayout.
*
* @param size widths of columns and heights of rows in the format,
* {{col0, col1, col2, ..., colN}, {row0, row1, row2, ..., rowM}}
* If this parameter is invalid, the TableLayout will have
* exactly one row and one column.
*/
public TableLayout (double size[][])
{
// Make sure rows and columns and nothing else is specified
if ((size != null) && (size.length == 2))
{
// Get the rows and columns
double tempCol[] = size[0];
double tempRow[] = size[1];
// Create new rows and columns
columnSpec = new double[tempCol.length];
rowSpec = new double[tempRow.length];
// Copy rows and columns
System.arraycopy (tempCol, 0, columnSpec, 0, columnSpec.length);
System.arraycopy (tempRow, 0, rowSpec, 0, rowSpec.length);
// Make sure rows and columns are valid
for (int counter = 0; counter < columnSpec.length; counter++)
if ((columnSpec[counter] < 0.0) &&
(columnSpec[counter] != FILL) &&
(columnSpec[counter] != PREFERRED) &&
(columnSpec[counter] != MINIMUM))
{
columnSpec[counter] = 0.0;
}
for (int counter = 0; counter < rowSpec.length; counter++)
if ((rowSpec[counter] < 0.0) &&
(rowSpec[counter] != FILL) &&
(rowSpec[counter] != PREFERRED) &&
(rowSpec[counter] != MINIMUM))
{
rowSpec[counter] = 0.0;
}
}
else
{
double tempCol[] = {FILL};
double tempRow[] = {FILL};
setColumn (tempCol);
setRow (tempRow);
}
// Create an empty list of components
list = new LinkedList();
// Indicate that the cell sizes are not known
dirty = true;
}
//******************************************************************************
//** Get/Set methods ***
//******************************************************************************
/**
* Gets the constraints of a given component.
*
* @param component desired component
*
* @return If the given component is found, the constraints associated with
* that component. If the given component is null or is not found,
* null is returned.
*/
public TableLayoutConstraints getConstraints (Component component)
{
ListIterator iterator = list.listIterator(0);
while (iterator.hasNext())
{
Entry entry = (Entry) iterator.next();
if (entry.component == component)
return new TableLayoutConstraints
(entry.col1, entry.row1, entry.col2, entry.row2,
entry.hAlign, entry.vAlign);
}
return null;
}
/**
* Sets the constraints of a given component.
*
* @param component desired component. This parameter cannot be null.
* @param constraint new set of constraints. This parameter cannot be null.
*
* @return If the given component is found, the constraints associated with
* that component. If the given component is null or is not found,
* null is returned.
*/
public void setConstraints
(Component component, TableLayoutConstraints constraint)
{
// Check parameters
if (component == null)
throw new IllegalArgumentException
("Parameter component cannot be null.");
else if (constraint == null)
throw new IllegalArgumentException
("Parameter constraint cannot be null.");
// Find and update constraints for the given component
ListIterator iterator = list.listIterator(0);
while (iterator.hasNext())
{
Entry entry = (Entry) iterator.next();
if (entry.component == component)
iterator.set (new Entry(component, constraint));
}
}
/**
* Adjusts the number and sizes of rows in this layout. After calling this
* method, the caller should request this layout manager to perform the
* layout. This can be done with the following code:
*
* <pre>
* layout.layoutContainer(container);
* container.repaint();
* </pre>
*
* or
*
* <pre>
* window.pack()
* </pre>
*
* If this is not done, the changes in the layout will not be seen until the
* container is resized.
*
* @param column heights of each of the columns
*
* @see getColumn
*/
public void setColumn (double column[])
{
// Copy columns
columnSpec = new double[column.length];
System.arraycopy (column, 0, columnSpec, 0, columnSpec.length);
// Make sure columns are valid
for (int counter = 0; counter < columnSpec.length; counter++)
if ((columnSpec[counter] < 0.0) &&
(columnSpec[counter] != FILL) &&
(columnSpec[counter] != PREFERRED) &&
(columnSpec[counter] != MINIMUM))
{
columnSpec[counter] = 0.0;
}
// Indicate that the cell sizes are not known
dirty = true;
}
/**
* Adjusts the number and sizes of rows in this layout. After calling this
* method, the caller should request this layout manager to perform the
* layout. This can be done with the following code:
*
* <code>
* layout.layoutContainer(container);
* container.repaint();
* </code>
*
* or
*
* <pre>
* window.pack()
* </pre>
*
* If this is not done, the changes in the layout will not be seen until the
* container is resized.
*
* @param row widths of each of the rows. This parameter cannot be null.
*
* @see getRow
*/
public void setRow (double row[])
{
// Copy rows
rowSpec = new double[row.length];
System.arraycopy (row, 0, rowSpec, 0, rowSpec.length);
// Make sure rows are valid
for (int counter = 0; counter < rowSpec.length; counter++)
if ((rowSpec[counter] < 0.0) &&
(rowSpec[counter] != FILL) &&
(rowSpec[counter] != PREFERRED) &&
(rowSpec[counter] != MINIMUM))
{
rowSpec[counter] = 0.0;
}
// Indicate that the cell sizes are not known
dirty = true;
}
/**
* Adjusts the width of a single column in this layout. After calling this
* method, the caller should request this layout manager to perform the
* layout. This can be done with the following code:
*
* <code>
* layout.layoutContainer(container);
* container.repaint();
* </code>
*
* or
*
* <pre>
* window.pack()
* </pre>
*
* If this is not done, the changes in the layout will not be seen until the
* container is resized.
*
* @param i zero-based index of column to set. If this parameter is not
* valid, an ArrayOutOfBoundsException will be thrown.
* @param size width of the column. This parameter cannot be null.
*
* @see getColumn
*/
public void setColumn (int i, double size)
{
// Make sure size is valid
if ((size < 0.0) &&
(size != FILL) &&
(size != PREFERRED) &&
(size != MINIMUM))
{
size = 0.0;
}
// Copy new size
columnSpec[i] = size;
// Indicate that the cell sizes are not known
dirty = true;
}
/**
* Adjusts the height of a single row in this layout. After calling this
* method, the caller should request this layout manager to perform the
* layout. This can be done with the following code:
*
* <code>
* layout.layoutContainer(container);
* container.repaint();
* </code>
*
* or
*
* <pre>
* window.pack()
* </pre>
*
* If this is not done, the changes in the layout will not be seen until the
* container is resized.
*
* @param i zero-based index of row to set. If this parameter is not
* valid, an ArrayOutOfBoundsException will be thrown.
* @param size height of the row. This parameter cannot be null.
*
* @see getRow
*/
public void setRow (int i, double size)
{
// Make sure size is valid
if ((size < 0.0) &&
(size != FILL) &&
(size != PREFERRED) &&
(size != MINIMUM))
{
size = 0.0;
}
// Copy new size
rowSpec[i] = size;
// Indicate that the cell sizes are not known
dirty = true;
}
/**
* Gets the sizes of columns in this layout.
*
* @return widths of each of the columns
*
* @see setColumn
*/
public double [] getColumn ()
{
// Copy columns
double column[] = new double[columnSpec.length];
System.arraycopy (columnSpec, 0, column, 0, column.length);
return column;
}
/**
* Gets the height of a single row in this layout.
*
* @return height of the requested row
*
* @see setRow
*/
public double [] getRow ()
{
// Copy rows
double row[] = new double[rowSpec.length];
System.arraycopy (rowSpec, 0, row, 0, row.length);
return row;
}
/**
* Gets the width of a single column in this layout.
*
* @param i zero-based index of row to get. If this parameter is not valid,
* an ArrayOutOfBoundsException will be thrown.
*
* @return width of the requested column
*
* @see setRow
*/
public double getColumn (int i)
{
return columnSpec[i];
}
/**
* Gets the sizes of a row in this layout.
*
* @param i zero-based index of row to get. If this parameter is not valid,
* an ArrayOutOfBoundsException will be thrown.
*
* @return height of each of the requested row
*
* @see setRow
*/
public double getRow (int i)
{
return rowSpec[i];
}
/**
* Gets the number of columns in this layout.
*
* @return the number of columns
*/
public int getNumColumn ()
{
return columnSpec.length;
}
/**
* Gets the number of rows in this layout.
*
* @return the number of rows
*/
public int getNumRow ()
{
return rowSpec.length;
}
//******************************************************************************
//** Insertion/Deletion methods ***
//******************************************************************************
/**
* Inserts a column in this layout. All components to the right of the
* insertion point are moved right one column. The container will need to
* be laid out after this method returns. See <code>setColumn</code>.
*
* @param i zero-based index at which to insert the column.
* @param size size of the column to be inserted
*
* @see setColumn
* @see deleteColumn
*/
public void insertColumn (int i, double size)
{
// Make sure position is valid
if ((i < 0) || (i > columnSpec.length))
throw new IllegalArgumentException
("Parameter i is invalid. i = " + i + ". Valid range is [0, " +
columnSpec.length + "].");
// Make sure column size is valid
if ((size < 0.0) &&
(size != FILL) &&
(size != PREFERRED) &&
(size != MINIMUM))
{
size = 0.0;
}
// Copy columns
double column[] = new double[columnSpec.length + 1];
System.arraycopy (columnSpec, 0, column, 0, i);
System.arraycopy (columnSpec, i, column, i + 1, columnSpec.length - i);
// Insert column
column[i] = size;
columnSpec = column;
// Move all components that are to the right of new row
ListIterator iterator = list.listIterator(0);
while (iterator.hasNext())
{
// Get next entry
Entry entry = (Entry) iterator.next();
// Is the first column to the right of the new column
if (entry.col1 >= i)
// Move first column
entry.col1++;
// Is the second column to the right of the new column
if (entry.col2 >= i)
// Move second column
entry.col2++;
}
// Indicate that the cell sizes are not known
dirty = true;
}
/**
* Inserts a row in this layout. All components below the insertion point
* are moved down one row. The container will need to be laid out after this
* method returns. See <code>setRow</code>.
*
* @param i zero-based index at which to insert the column.
* @param size size of the row to be inserted
*
* @see setRow
* @see deleteRow
*/
public void insertRow (int i, double size)
{
// Make sure position is valid
if ((i < 0) || (i > rowSpec.length))
throw new IllegalArgumentException
("Parameter i is invalid. i = " + i + ". Valid range is [0, " +
rowSpec.length + "].");
// Make sure row size is valid
if ((size < 0.0) &&
(size != FILL) &&
(size != PREFERRED) &&
(size != MINIMUM))
{
size = 0.0;
}
// Copy rows
double row[] = new double[rowSpec.length + 1];
System.arraycopy (rowSpec, 0, row, 0, i);
System.arraycopy (rowSpec, i, row, i + 1, rowSpec.length - i);
// Insert row
row[i] = size;
rowSpec = row;
// Move all components that are below the new row
ListIterator iterator = list.listIterator(0);
while (iterator.hasNext())
{
// Get next entry
Entry entry = (Entry) iterator.next();
// Is the first row to the right of the new row
if (entry.row1 >= i)
// Move first row
entry.row1++;
// Is the second row to the right of the new row
if (entry.row2 >= i)
// Move second row
entry.row2++;
}
// Indicate that the cell sizes are not known
dirty = true;
}
/**
* Deletes a column in this layout. All components to the right of the
* deletion point are moved left one column. The container will need to
* be laid out after this method returns. See <code>setColumn</code>.
*
* @param i zero-based index of column to delete
*
* @see setColumn
* @see deleteColumn
*/
public void deleteColumn (int i)
{
// Make sure position is valid
if ((i < 0) || (i >= columnSpec.length))
throw new IllegalArgumentException
("Parameter i is invalid. i = " + i + ". Valid range is [0, " +
(columnSpec.length - 1) + "].");
// Copy columns
double column[] = new double[columnSpec.length - 1];
System.arraycopy (columnSpec, 0, column, 0, i);
System.arraycopy (columnSpec, i + 1, column, i, columnSpec.length - i - 1);
// Delete column
columnSpec = column;
// Move all components that are to the right of row deleted
ListIterator iterator = list.listIterator(0);
while (iterator.hasNext())
{
// Get next entry
Entry entry = (Entry) iterator.next();
// Is the first column to the right of the new column
if (entry.col1 >= i)
// Move first column
entry.col1--;
// Is the second column to the right of the new column
if (entry.col2 >= i)
// Move second column
entry.col2--;
}
// Indicate that the cell sizes are not known
dirty = true;
}
/**
* Deletes a row in this layout. All components below the deletion point are
* moved up one row. The container will need to be laid out after this method
* returns. See <code>setRow</code>. There must be at least two rows in order
* to delete a row.
*
* @param i zero-based index of column to delete
*
* @see setRow
* @see deleteRow
*/
public void deleteRow (int i)
{
// Make sure position is valid
if ((i < 0) || (i >= rowSpec.length))
throw new IllegalArgumentException
("Parameter i is invalid. i = " + i + ". Valid range is [0, " +
(rowSpec.length - 1) + "].");
// Copy rows
double row[] = new double[rowSpec.length - 1];
System.arraycopy (rowSpec, 0, row, 0, i);
System.arraycopy (rowSpec, i + 1, row, i, rowSpec.length - i - 1);
// Delete row
rowSpec = row;
// Move all components that are to below the row deleted
ListIterator iterator = list.listIterator(0);
while (iterator.hasNext())
{
// Get next entry
Entry entry = (Entry) iterator.next();
// Is the first row below the new row
if (entry.row1 >= i)
// Move first row
entry.row1--;
// Is the second row below the new row
if (entry.row2 >= i)
// Move second row
entry.row2--;
}
// Indicate that the cell sizes are not known
dirty = true;
}
//******************************************************************************
//** Misc methods ***
//******************************************************************************
/**
* Converts this TableLayout to a string.
*
* @return a string representing the columns and row sizes in the form
* "{{col0, col1, col2, ..., colN}, {row0, row1, row2, ..., rowM}}"
*/
public String toString ()
{
int counter;
String value = "TableLayout {{";
if (columnSpec.length > 0)
{
for (counter = 0; counter < columnSpec.length - 1; counter++)
value += columnSpec[counter] + ", ";
value += columnSpec[columnSpec.length - 1] + "}, {";
}
else
value += "}, {";
if (rowSpec.length > 0)
{
for (counter = 0; counter < rowSpec.length - 1; counter++)
value += rowSpec[counter] + ", ";
value += rowSpec[rowSpec.length - 1] + "}}";
}
else
value += "}}";
return value;
}
/**
* Draws a grid on the given container. This is useful for seeing where the
* rows and columns go. In the container's paint method, call this method.
*
* @param container container using this TableLayout
* @param g graphics content of container (can be offscreen)
*/
public void drawGrid (Container container, Graphics g)
{
int counter; // Counting variable;
// Calculate the sizes of the rows and columns
Dimension d = container.getSize();
if (dirty || (d.width != oldWidth) || (d.height != oldHeight))
calculateSize (container);
// Initialize y
int y = 0;
for (int row = 0; row < rowSize.length; row++)
{
// Initialize x
int x = 0;
for (int column = 0; column < columnSize.length; column++)
{
// Use a random color to make things easy to see
Color color = new Color((int) (Math.random() * 0xFFFFFFL));
g.setColor (color);
// Draw the cell as a solid rectangle
g.fillRect (x, y, columnSize[column], rowSize[row]);
// Increment x
x += columnSize[column];
}
// Increment y
y += rowSize[row];
}
}
/**
* Determines whether or not there are any hidden components. A hidden
* component is one that will not be shown with this layout's current
* configuration. Such a component is, at least partly, in an invalid row
* or column. For example, on a table with five rows, row -1 and row 5 are both
* invalid. Valid rows are 0 through 4, inclusively.
*
* @return True, if there are any hidden components. False, otherwise.
*
* @see overlapping
*/
public boolean hidden ()
{
// Assume no components are hidden
boolean hidden = false;
// Check all components
ListIterator iterator = list.listIterator(0);
while (iterator.hasNext())
{
// Get next entry
Entry entry = (Entry) iterator.next();
// Is this component valid
if ((entry.row1 < 0) || (entry.col1 < 0) ||
(entry.row2 > rowSpec.length) ||
(entry.col2 > columnSpec.length))
{
hidden = true;
break;
}
}
return hidden;
}
/**
* Determines whether or not there are any overlapping components. Two
* components overlap if they cover at least one common cell.
*
* @return True, if there are any overlapping components. False, otherwise.
*
* @see hidden
*/
public boolean overlapping ()
{
// Count contraints
int numEntry = list.size();
// If there are no components, they can't be overlapping
if (numEntry == 0)
return false;
// Assume no components are overlapping
boolean overlapping = false;
// Put entries in an array
Entry entry[] = (Entry[]) list.toArray(new Entry[numEntry]);
// Check all components
for (int knowUnique = 1; knowUnique < numEntry; knowUnique++)
for (int checking = knowUnique - 1; checking >= 0; checking--)
if
(
(
(entry[checking].col1 >= entry[knowUnique].col1) &&
(entry[checking].col1 <= entry[knowUnique].col2) &&
(entry[checking].row1 >= entry[knowUnique].row1) &&
(entry[checking].row1 <= entry[knowUnique].row2)
)
||
(
(entry[checking].col2 >= entry[knowUnique].col1) &&
(entry[checking].col2 <= entry[knowUnique].col2) &&
(entry[checking].row2 >= entry[knowUnique].row1) &&
(entry[checking].row2 <= entry[knowUnique].row2)
)
)
{
overlapping = true;
break;
}
return overlapping;
}
/**
* Calculates the sizes of the rows and columns based on the absolute and
* relative sizes specified in <code>rowSpec</code> and <code>columnSpec</code>
* and the size of the container. The result is stored in <code>rowSize</code>
* and <code>columnSize</code>.
*
* @param container container using this TableLayout
*/
protected void calculateSize (Container container)
{
int counter; // Counting variable;
// Get number of rows and columns
int numColumn = columnSpec.length;
int numRow = rowSpec.length;
// Create array to hold actual sizes in pixels
columnSize = new int[numColumn];
rowSize = new int[numRow];
// Get the container's insets
Insets inset = container.getInsets();
// Get the size of the container's available space
Dimension d = container.getSize();
int totalWidth = d.width - inset.left - inset.right;
int totalHeight = d.height - inset.top - inset.bottom;
// Initially, the available space is the total space
int availableWidth = totalWidth;
int availableHeight = totalHeight;
// Assign absolute widths; this reduces available width
for (counter = 0; counter < numColumn; counter++)
// Is the current column an absolue size
if ((columnSpec[counter] >= 1.0) || (columnSpec[counter] == 0.0))
{
// Assign absolute width
columnSize[counter] = (int) (columnSpec[counter] + 0.5);
// Reduce available width
availableWidth -= columnSize[counter];
}
// Assign absolute heights; this reduces available height
for (counter = 0; counter < numRow; counter++)
// Is the current column an absolue size
if ((rowSpec[counter] >= 1.0) || (rowSpec[counter] == 0.0))
{
// Assign absolute width
rowSize[counter] = (int) (rowSpec[counter] + 0.5);
// Reduce available width
availableHeight -= rowSize[counter];
}
// Assign preferred and minimum widths; this reduces available width.
// Assignment of preferred/minimum with is like assignment of absolute
// widths except that each column must determine the maximum
// preferred/minimum width of the components that are completely contained
// within the column.
for (counter = 0; counter < numColumn; counter++)
// Is the current column a preferred size
if ((columnSpec[counter] == PREFERRED) ||
(columnSpec[counter] == MINIMUM))
{
// Assume a maximum width of zero
int maxWidth = 0;
// Find maximum preferred width of all components completely
// contained within this column
ListIterator iterator = list.listIterator(0);
while (iterator.hasNext())
{
Entry entry = (Entry) iterator.next();
if ((entry.col1 == counter) && (entry.col2 == counter))
{
Dimension p = (columnSpec[counter] == PREFERRED) ?
entry.component.getPreferredSize() :
entry.component.getMinimumSize();
int width = (p == null) ? 0 : p.width;
if (maxWidth < width)
maxWidth = width;
}
}
// Assign preferred width
columnSize[counter] = maxWidth;
// Reduce available width
availableWidth -= maxWidth;
}
// Assign preferred and minimum heights; this reduces available height.
// Assignment of preferred/minimum with is like assignment of absolute
// heights except that each row must determine the maximum
// preferred/minimum height of the components that are completely contained
// within the row.
for (counter = 0; counter < numRow; counter++)
// Is the current row a preferred size
if ((rowSpec[counter] == PREFERRED) ||
(rowSpec[counter] == MINIMUM))
{
// Assume a maximum height of zero
int maxHeight = 0;
// Find maximum preferred height of all components completely
// contained within this row
ListIterator iterator = list.listIterator(0);
while (iterator.hasNext())
{
Entry entry = (Entry) iterator.next();
if ((entry.row1 == counter) && (entry.row2 == counter))
{
Dimension p = (rowSpec[counter] == PREFERRED) ?
entry.component.getPreferredSize() :
entry.component.getMinimumSize();
int height = (p == null) ? 0 : p.height;
if (maxHeight < height)
maxHeight = height;
}
}
// Assign preferred height
rowSize[counter] = maxHeight;
// Reduce available height
availableHeight -= maxHeight;
}
// Remember how much space is available for relatively sized cells
int relativeWidth = availableWidth;
int relativeHeight = availableHeight;
// Make sure relativeWidth and relativeHeight are non-negative
if (relativeWidth < 0)
relativeWidth = 0;
if (relativeHeight < 0)
relativeHeight = 0;
// Assign relative widths
for (counter = 0; counter < numColumn; counter++)
// Is the current column an relative size
if ((columnSpec[counter] > 0.0) && (columnSpec[counter] < 1.0))
{
// Assign relative width
columnSize[counter] =
(int) (columnSpec[counter] * relativeWidth + 0.5);
// Reduce available width
availableWidth -= columnSize[counter];
}
// Assign relative widths
for (counter = 0; counter < numRow; counter++)
// Is the current column an relative size
if ((rowSpec[counter] > 0.0) && (rowSpec[counter] < 1.0))
{
// Assign relative width
rowSize[counter] = (int) (rowSpec[counter] * relativeHeight + 0.5);
// Reduce available width
availableHeight -= rowSize[counter];
}
// Make sure availableWidth and availableHeight are non-negative
if (availableWidth < 0)
availableWidth = 0;
if (availableHeight < 0)
availableHeight = 0;
// Count the number of "fill" cells
int numFillWidth = 0;
int numFillHeight = 0;
for (counter = 0; counter < numColumn; counter++)
if (columnSpec[counter] == FILL)
numFillWidth++;
for (counter = 0; counter < numRow; counter++)
if (rowSpec[counter] == FILL)
numFillHeight++;
// If numFillWidth (numFillHeight) is zero, the cooresponding if statements
// will always evaluate to false and the division will not occur.
// If there are more than one "fill" cell, slack may occur due to rounding
// errors
int slackWidth = availableWidth;
int slackHeight = availableHeight;
// Assign "fill" cells equal amounts of the remaining space
for (counter = 0; counter < numColumn; counter++)
if (columnSpec[counter] == FILL)
{
columnSize[counter] = availableWidth / numFillWidth;
slackWidth -= columnSize[counter];
}
for (counter = 0; counter < numRow; counter++)
if (rowSpec[counter] == FILL)
{
rowSize[counter] = availableHeight / numFillHeight;
slackHeight -= rowSize[counter];
}
// Add slack to the last "fill" cell
for (counter = numColumn - 1; counter >= 0; counter--)
{
if (columnSpec[counter] == FILL)
{
columnSize[counter] += slackWidth;
break;
}
}
for (counter = numRow - 1; counter >= 0; counter--)
{
if (rowSpec[counter] == FILL)
{
rowSize[counter] += slackHeight;
break;
}
}
// Calculate offsets of each column (done for effeciency)
columnOffset = new int[numColumn + 1];
columnOffset[0] = inset.left;
for (counter = 0; counter < numColumn; counter++)
columnOffset[counter + 1] =
columnOffset[counter] + columnSize[counter];
// Calculate offsets of each row (done for effeciency)
rowOffset = new int[numRow + 1];
rowOffset[0] = inset.top;
for (counter = 0; counter < numRow; counter++)
rowOffset[counter + 1] =
rowOffset[counter] + rowSize[counter];
// Indicate that the size of the cells are known for the container's
// current size
dirty = false;
oldWidth = totalWidth;
oldHeight = totalHeight;
}
//******************************************************************************
//** java.awt.event.LayoutManager methods ***
//******************************************************************************
/**
* To lay out the specified container using this layout. This method reshapes
* the components in the specified target container in order to satisfy the
* constraints of all components.
*
* <p>User code should not have to call this method directly.</p>
*
* @param container container being served by this layout manager
*/
public void layoutContainer (Container container)
{
int x, y; // Coordinates of the currnet component in pixels
int w, h; // Width and height of the current component in pixels
// Calculate sizes if container has changed size or components were added
Dimension d = container.getSize();
if (dirty || (d.width != oldWidth) || (d.height != oldHeight))
calculateSize (container);
// Get components
Component component[] = container.getComponents();
// Layout components
for (int counter = 0; counter < component.length; counter++)
{
try
{
// Get the entry entry for the next component
ListIterator iterator = list.listIterator(0);
Entry entry = null;
while (iterator.hasNext())
{
entry = (Entry) iterator.next();
if (entry.component == component[counter])
break;
else
entry = null;
}
// Skip any components that have not been place in a specific cell
if (entry == null)
break;
// Does the entry occupy a single cell
if (entry.singleCell)
{
// The following block of code has been optimized so that the
// preferred size of the component is only obtained if it is
// needed. There are components in which the getPreferredSize
// method is extremely expensive, such as data driven controls
// with a large amount of data.
// Get the preferred size of the component
int preferredWidth = 0;
int preferredHeight = 0;
if ((entry.hAlign != FULL) || (entry.vAlign != FULL))
{
Dimension preferredSize =
component[counter].getPreferredSize();
preferredWidth = preferredSize.width;
preferredHeight = preferredSize.height;
}
// Determine cell width and height
int cellWidth = columnSize[entry.col1];
int cellHeight = rowSize[entry.row1];
// Determine the width of the component
if ((entry.hAlign == FULL) ||
(cellWidth < preferredWidth))
// Use the width of the cell
w = cellWidth;
else
// Use the prefered width of the component
w = preferredWidth;
// Determine left and right boarders
switch (entry.hAlign)
{
case LEFT :
// Align left side along left edge of cell
x = columnOffset[entry.col1];
break;
case RIGHT :
// Align right side along right edge of cell
x = columnOffset[entry.col1 + 1] - w;
break;
case CENTER :
// Center justify component
x = columnOffset[entry.col1] + ((cellWidth - w) >> 1);
break;
case FULL :
// Align left side along left edge of cell
x = columnOffset[entry.col1];
break;
default :
// This is a never should happen case, but just in case
x = 0;
}
// Determine the height of the component
if ((entry.vAlign == FULL) ||
(cellHeight < preferredHeight))
// Use the height of the cell
h = cellHeight;
else
// Use the prefered height of the component
h = preferredHeight;
// Determine top and bottom boarders
switch (entry.vAlign)
{
case TOP :
// Align top side along top edge of cell
y = rowOffset[entry.row1];
break;
case BOTTOM :
// Align right side along right edge of cell
y = rowOffset[entry.row1 + 1] - h;
break;
case CENTER :
// Center justify component
y = rowOffset[entry.row1] + ((cellHeight - h) >> 1);
break;
case FULL :
// Align right side along right edge of cell
y = rowOffset[entry.row1];
break;
default :
// This is a never should happen case, but just in case
y = 0;
}
}
else
{
// Align left side with left boarder of first column
x = columnOffset[entry.col1];
// Align top side along top edge of first row
y = rowOffset[entry.row1];
// Align right side with right boarder of second column
w = columnOffset[entry.col2 + 1] -
columnOffset[entry.col1];
// Align bottom side with bottom boarder of second row
h = rowOffset[entry.row2 + 1] - rowOffset[entry.row1];
}
// Move and resize component
component[counter].setBounds (x, y, w, h);
}
catch (Exception error)
{
// If any error occurs, skip this component
continue;
}
}
}
/**
* Determines the preferred size of the container argument using this layout.
* The preferred size is the smallest size that, if used for the container's
* size, will ensure that all components are at least as large as their
* preferred size. This method cannot guarantee that all components will be
* their preferred size. For example, if component A and component B are each
* allocate half of the container's width and component A wants to be 10 pixels
* wide while component B wants to be 100 pixels wide, they cannot both be
* accommodated. Since in general components rather be larger than their
* preferred size instead of smaller, component B's request will be fulfilled.
* The preferred size of the container would be 200 pixels.
*
* @param container container being served by this layout manager
*
* @return a dimension indicating the container's preferred size
*/
public Dimension preferredLayoutSize (Container container)
{
Dimension size; // Preferred size of current component
int scaledWidth = 0; // Preferred width of scalled components
int scaledHeight = 0; // Preferred height of scalled components
int temp; // Temporary variable used to compare sizes
int counter; // Counting variable
// Determine percentage of space allocated to fill components. This is
// one minus the sum of all scalable components.
double fillWidthRatio = 1.0;
double fillHeightRatio = 1.0;
int numFillWidth = 0;
int numFillHeight = 0;
for (counter = 0; counter < columnSpec.length; counter++)
if ((columnSpec[counter] > 0.0) && (columnSpec[counter] < 1.0))
fillWidthRatio -= columnSpec[counter];
else if (columnSpec[counter] == FILL)
numFillWidth++;
for (counter = 0; counter < rowSpec.length; counter++)
if ((rowSpec[counter] > 0.0) && (rowSpec[counter] < 1.0))
fillHeightRatio -= rowSpec[counter];
else if (rowSpec[counter] == FILL)
numFillHeight++;
// Adjust fill ratios to reflect number of fill rows/columns
if (numFillWidth > 1)
fillWidthRatio /= numFillWidth;
if (numFillHeight > 1)
fillHeightRatio /= numFillHeight;
// Cap fill ratio bottoms to 0.0
if (fillWidthRatio < 0.0)
fillWidthRatio = 0.0;
if (fillHeightRatio < 0.0)
fillHeightRatio = 0.0;
// Calculate preferred/minimum column widths
int columnPrefMin[] = new int[columnSpec.length];
for (counter = 0; counter < columnSpec.length; counter++)
// Is the current column a preferred/minimum size
if ((columnSpec[counter] == PREFERRED) ||
(columnSpec[counter] == MINIMUM))
{
// Assume a maximum width of zero
int maxWidth = 0;
// Find maximum preferred/minimum width of all components completely
// contained within this column
ListIterator iterator = list.listIterator(0);
while (iterator.hasNext())
{
Entry entry = (Entry) iterator.next();
if ((entry.col1 == counter) && (entry.col2 == counter))
{
Dimension p = (columnSpec[counter] == PREFERRED) ?
entry.component.getPreferredSize() :
entry.component.getMinimumSize();
int width = (p == null) ? 0 : p.width;
if (maxWidth < width)
maxWidth = width;
}
}
// Set column's preferred/minimum width
columnPrefMin[counter] = maxWidth;
}
// Calculate preferred/minimum row heights
int rowPrefMin[] = new int[rowSpec.length];
for (counter = 0; counter < rowSpec.length; counter++)
// Is the current row a preferred/minimum size
if ((rowSpec[counter] == PREFERRED) ||
(rowSpec[counter] == MINIMUM))
{
// Assume a maximum height of zero
int maxHeight = 0;
// Find maximum preferred height of all components completely
// contained within this row
ListIterator iterator = list.listIterator(0);
while (iterator.hasNext())
{
Entry entry = (Entry) iterator.next();
if ((entry.row1 == counter) && (entry.row1 == counter))
{
Dimension p = (rowSpec[counter] == PREFERRED) ?
entry.component.getPreferredSize() :
entry.component.getMinimumSize();
int height = (p == null) ? 0 : p.height;
if (maxHeight < height)
maxHeight = height;
}
}
// Add preferred height
rowPrefMin[counter] += maxHeight;
}
// Find maximum preferred size of all scaled components
ListIterator iterator = list.listIterator(0);
while (iterator.hasNext())
{
// Get next entry
Entry entry = (Entry) iterator.next();
// Make sure entry is in valid rows and columns
if ((entry.col1 < 0) || (entry.col1 >= columnSpec.length) ||
(entry.col2 >= columnSpec.length) ||
(entry.row1 < 0) || (entry.row1 >= rowSpec.length) ||
(entry.row2 >= rowSpec.length))
{
// Skip the bad component
continue;
}
// Get preferred size of current component
size = entry.component.getPreferredSize();
// Calculate portion of component that is not absolutely sized
int scalableWidth = size.width;
int scalableHeight = size.height;
for (counter = entry.col1; counter <= entry.col2; counter++)
if (columnSpec[counter] >= 1.0)
scalableWidth -= columnSpec[counter];
else if ((columnSpec[counter] == PREFERRED) ||
(columnSpec[counter] == MINIMUM))
{
scalableWidth -= columnPrefMin[counter];
}
for (counter = entry.row1; counter <= entry.row2; counter++)
if (rowSpec[counter] >= 1.0)
scalableHeight -= rowSpec[counter];
else if ((rowSpec[counter] == PREFERRED) ||
(rowSpec[counter] == MINIMUM))
{
scalableHeight -= rowPrefMin[counter];
}
//----------------------------------------------------------------------
// Determine total percentage of scalable space that the component
// occupies by adding the relative columns and the fill columns
double relativeWidth = 0.0;
for (counter = entry.col1; counter <= entry.col2; counter++)
{
// Column is scaled
if ((columnSpec[counter] > 0.0) && (columnSpec[counter] < 1.0))
// Add scaled size to relativeWidth
relativeWidth += columnSpec[counter];
// Column is fill
else if ((columnSpec[counter] == FILL) && (fillWidthRatio != 0.0))
// Add fill size to relativeWidth
relativeWidth += fillWidthRatio;
}
// Determine the total scaled width as estimated by this component
if (relativeWidth == 0)
temp = 0;
else
temp = (int) (scalableWidth / relativeWidth + 0.5);
// If the container needs to be bigger, make it so
if (scaledWidth < temp)
scaledWidth = temp;
//----------------------------------------------------------------------
// Determine total percentage of scalable space that the component
// occupies by adding the relative columns and the fill columns
double relativeHeight = 0.0;
for (counter = entry.row1; counter <= entry.row2; counter++)
{
// Row is scaled
if ((rowSpec[counter] > 0.0) && (rowSpec[counter] < 1.0))
// Add scaled size to relativeHeight
relativeHeight += rowSpec[counter];
// Row is fill
else if ((rowSpec[counter] == FILL) && (fillHeightRatio != 0.0))
// Add fill size to relativeHeight
relativeHeight += fillHeightRatio;
}
// Determine the total scaled width as estimated by this component
if (relativeHeight == 0)
temp = 0;
else
temp = (int) (scalableHeight / relativeHeight + 0.5);
// If the container needs to be bigger, make it so
if (scaledHeight < temp)
scaledHeight = temp;
}
// totalWidth is the scaledWidth plus the sum of all absolute widths and all
// preferred widths
int totalWidth = scaledWidth;
for (counter = 0; counter < columnSpec.length; counter++)
// Is the current column an absolute size
if (columnSpec[counter] >= 1.0)
totalWidth += (int) (columnSpec[counter] + 0.5);
// Is the current column a preferred/minimum size
else if ((columnSpec[counter] == PREFERRED) ||
(columnSpec[counter] == MINIMUM))
{
// Add preferred/minimum width
totalWidth += columnPrefMin[counter];
}
// totalHeight is the scaledHeight plus the sum of all absolute heights and
// all preferred widths
int totalHeight = scaledHeight;
for (counter = 0; counter < rowSpec.length; counter++)
// Is the current row an absolute size
if (rowSpec[counter] >= 1.0)
totalHeight += (int) (rowSpec[counter] + 0.5);
// Is the current row a preferred size
else if ((rowSpec[counter] == PREFERRED) ||
(rowSpec[counter] == MINIMUM))
{
// Add preferred/minimum width
totalHeight += rowPrefMin[counter];
}
// Compensate for container's insets
Insets inset = container.getInsets();
totalWidth += inset.left + inset.right;
totalHeight += inset.top + inset.bottom;
return new Dimension(totalWidth, totalHeight);
}
/**
* Determines the minimum size of the container argument using this layout.
* The minimum size is the smallest size that, if used for the container's
* size, will ensure that all components are at least as large as their
* minimum size. This method cannot guarantee that all components will be
* their minimum size. For example, if component A and component B are each
* allocate half of the container's width and component A wants to be 10 pixels
* wide while component B wants to be 100 pixels wide, they cannot both be
* accommodated. Since in general components rather be larger than their
* minimum size instead of smaller, component B's request will be fulfilled.
* The minimum size of the container would be 200 pixels.
*
* @param container container being served by this layout manager
*
* @return a dimension indicating the container's minimum size
*/
public Dimension minimumLayoutSize (Container container)
{
Dimension size; // Minimum size of current component
int scaledWidth = 0; // Minimum width of scalled components
int scaledHeight = 0; // Minimum height of scalled components
int fillWidth = 0; // Minimum width of fill components
int fillHeight = 0; // Minimum height of fill components
int temp; // Temporary variable used to compare sizes
int counter; // Counting variable
// Determine percentage of space allocated to fill components. This is
// one minus the sum of all scalable components.
double fillWidthRatio = 1.0;
double fillHeightRatio = 1.0;
int numFillWidth = 0;
int numFillHeight = 0;
for (counter = 0; counter < columnSpec.length; counter++)
if ((columnSpec[counter] > 0.0) && (columnSpec[counter] < 1.0))
fillWidthRatio -= columnSpec[counter];
else if (columnSpec[counter] == FILL)
numFillWidth++;
for (counter = 0; counter < rowSpec.length; counter++)
if ((rowSpec[counter] > 0.0) && (rowSpec[counter] < 1.0))
fillHeightRatio -= rowSpec[counter];
else if (rowSpec[counter] == FILL)
numFillHeight++;
// Adjust fill ratios to reflect number of fill rows/columns
if (numFillWidth > 1)
fillWidthRatio /= numFillWidth;
if (numFillHeight > 1)
fillHeightRatio /= numFillHeight;
// Cap fill ratio bottoms to 0.0
if (fillWidthRatio < 0.0)
fillWidthRatio = 0.0;
if (fillHeightRatio < 0.0)
fillHeightRatio = 0.0;
// Find maximum minimum size of all scaled components
ListIterator iterator = list.listIterator(0);
while (iterator.hasNext())
{
// Get next entry
Entry entry = (Entry) iterator.next();
// Make sure entry is in valid rows and columns
if ((entry.col1 < 0) || (entry.col1 >= columnSpec.length) ||
(entry.col2 >= columnSpec.length) ||
(entry.row1 < 0) || (entry.row1 >= rowSpec.length) ||
(entry.row2 >= rowSpec.length))
{
// Skip the bad component
continue;
}
// Get minimum size of current component
size = entry.component.getMinimumSize();
// Calculate portion of component that is not absolutely sized
int scalableWidth = size.width;
int scalableHeight = size.height;
for (counter = entry.col1; counter <= entry.col2; counter++)
if (columnSpec[counter] >= 1.0)
scalableWidth -= columnSpec[counter];
for (counter = entry.row1; counter <= entry.row2; counter++)
if (rowSpec[counter] >= 1.0)
scalableHeight -= rowSpec[counter];
//----------------------------------------------------------------------
// Determine total percentage of scalable space that the component
// occupies by adding the relative columns and the fill columns
double relativeWidth = 0.0;
for (counter = entry.col1; counter <= entry.col2; counter++)
{
// Column is scaled
if ((columnSpec[counter] > 0.0) && (columnSpec[counter] < 1.0))
// Add scaled size to relativeWidth
relativeWidth += columnSpec[counter];
// Column is fill
else if ((columnSpec[counter] == FILL) && (fillWidthRatio != 0.0))
// Add fill size to relativeWidth
relativeWidth += fillWidthRatio;
}
// Determine the total scaled width as estimated by this component
if (relativeWidth == 0)
temp = 0;
else
temp = (int) (scalableWidth / relativeWidth + 0.5);
// If the container needs to be bigger, make it so
if (scaledWidth < temp)
scaledWidth = temp;
//----------------------------------------------------------------------
// Determine total percentage of scalable space that the component
// occupies by adding the relative columns and the fill columns
double relativeHeight = 0.0;
for (counter = entry.row1; counter <= entry.row2; counter++)
{
// Row is scaled
if ((rowSpec[counter] > 0.0) && (rowSpec[counter] < 1.0))
// Add scaled size to relativeHeight
relativeHeight += rowSpec[counter];
// Row is fill
else if ((rowSpec[counter] == FILL) && (fillHeightRatio != 0.0))
// Add fill size to relativeHeight
relativeHeight += fillHeightRatio;
}
// Determine the total scaled width as estimated by this component
if (relativeHeight == 0)
temp = 0;
else
temp = (int) (scalableHeight / relativeHeight + 0.5);
// If the container needs to be bigger, make it so
if (scaledHeight < temp)
scaledHeight = temp;
}
// totalWidth is the scaledWidth plus the sum of all absolute widths and all
// preferred widths
int totalWidth = scaledWidth;
for (counter = 0; counter < columnSpec.length; counter++)
// Is the current column an absolute size
if (columnSpec[counter] >= 1.0)
totalWidth += (int) (columnSpec[counter] + 0.5);
// Is the current column a preferred size
else if ((columnSpec[counter] == PREFERRED) ||
(columnSpec[counter] == MINIMUM))
{
// Assume a maximum width of zero
int maxWidth = 0;
// Find maximum preferred width of all components completely
// contained within this column
iterator = list.listIterator(0);
while (iterator.hasNext())
{
Entry entry = (Entry) iterator.next();
if ((entry.col1 == counter) && (entry.col2 == counter))
{
Dimension p = (columnSpec[counter] == PREFERRED) ?
entry.component.getPreferredSize() :
entry.component.getMinimumSize();
int width = (p == null) ? 0 : p.width;
if (maxWidth < width)
maxWidth = width;
}
}
// Add preferred width
totalWidth += maxWidth;
}
// totalHeight is the scaledHeight plus the sum of all absolute heights and
// all preferred widths
int totalHeight = scaledHeight;
for (counter = 0; counter < rowSpec.length; counter++)
// Is the current row an absolute size
if (rowSpec[counter] >= 1.0)
totalHeight += (int) (rowSpec[counter] + 0.5);
// Is the current row a preferred size
else if ((rowSpec[counter] == PREFERRED) ||
(rowSpec[counter] == MINIMUM))
{
// Assume a maximum height of zero
int maxHeight = 0;
// Find maximum preferred height of all components completely
// contained within this row
iterator = list.listIterator(0);
while (iterator.hasNext())
{
Entry entry = (Entry) iterator.next();
if ((entry.row1 == counter) && (entry.row1 == counter))
{
Dimension p = (rowSpec[counter] == PREFERRED) ?
entry.component.getPreferredSize() :
entry.component.getMinimumSize();
int height = (p == null) ? 0 : p.height;
if (maxHeight < height)
maxHeight = height;
}
}
// Add preferred height
totalHeight += maxHeight;
}
// Compensate for container's insets
Insets inset = container.getInsets();
totalWidth += inset.left + inset.right;
totalHeight += inset.top + inset.bottom;
return new Dimension(totalWidth, totalHeight);
}
/**
* Adds the specified component with the specified name to the layout.
*
* @param name indicates entry's position and anchor
* @param component component to add
*/
public void addLayoutComponent (String name, Component component)
{
addLayoutComponent (component, name);
}
//******************************************************************************
//** java.awt.event.LayoutManager2 methods ***
//******************************************************************************
/**
* Adds the specified component with the specified name to the layout.
*
* @param component component to add
* @param constraint indicates entry's position and alignment
*/
public void addLayoutComponent (Component component, Object constraint)
{
if (constraint instanceof String)
{
// Create an entry to associate component with its constraints
constraint = new TableLayoutConstraints((String) constraint);
// Add component and constraints to the list
list.add (new Entry(component, (TableLayoutConstraints) constraint));
}
else if (constraint instanceof TableLayoutConstraints)
{
// Add component and constraints to the list
list.add (new Entry(component, (TableLayoutConstraints) constraint));
}
else if (constraint == null)
throw new IllegalArgumentException("No constraint for the component");
else
throw new IllegalArgumentException
("Cannot accept a constraint of class " + constraint.getClass());
}
/**
* Removes the specified component from the layout.
*
* @param component component being removed
*/
public void removeLayoutComponent (Component component)
{
list.remove (component);
}
/**
* Returns the maximum dimensions for this layout given the components in the
* specified target container.
*
* @param target the component which needs to be laid out
*
* @return unconditionally, a Dimension of Integer.MAX_VALUE by
* Integer.MAX_VALUE since TableLayout does not limit the
* maximum size of a container
*/
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.
*
* @return unconditionally, 0.5
*/
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.
*
* @return unconditionally, 0.5
*/
public float getLayoutAlignmentY (Container parent)
{
return 0.5f;
}
/**
* Invalidates the layout, indicating that if the layout manager has cached
* information it should be discarded.
*/
public void invalidateLayout (Container target)
{
dirty = true;
}
//******************************************************************************
//*** Inner Class ***
//******************************************************************************
// The following inner class is used to bind components to their constraints
protected class Entry extends TableLayoutConstraints
{
/** Component bound by the constraints */
protected Component component;
/** Does the component occupy a single cell */
protected boolean singleCell;
/**
* Constructs an Entry that binds a component to a set of constraints.
*
* @param component component being bound
* @param constranit constraints being applied
*/
public Entry (Component component, TableLayoutConstraints constraint)
{
super (constraint.col1, constraint.row1,
constraint.col2, constraint.row2,
constraint.hAlign, constraint.vAlign);
singleCell = ((row1 == row2) && (col1 == col2));
this.component = component;
}
/**
* Determines whether or not two entries are equal.
*
* @param object object being compared to; must be a Component if it
* is equal to this TableLayoutConstraints.
*
* @return True, if the entries refer to the same component object.
* False, otherwise.
*/
public boolean equals (Object object)
{
boolean equal = false;
if (object instanceof Component)
{
Component component = (Component) object;
equal = (this.component == component);
}
return equal;
}
}
}