aboutsummaryrefslogtreecommitdiffstats
path: root/src/com/itmill/toolkit/ui/GridLayout.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/com/itmill/toolkit/ui/GridLayout.java')
-rw-r--r--src/com/itmill/toolkit/ui/GridLayout.java1993
1 files changed, 1006 insertions, 987 deletions
diff --git a/src/com/itmill/toolkit/ui/GridLayout.java b/src/com/itmill/toolkit/ui/GridLayout.java
index 901842bed7..0e0d80172e 100644
--- a/src/com/itmill/toolkit/ui/GridLayout.java
+++ b/src/com/itmill/toolkit/ui/GridLayout.java
@@ -61,992 +61,1011 @@ import com.itmill.toolkit.terminal.gwt.client.ui.AlignmentInfo;
*/
public class GridLayout extends AbstractLayout {
- /**
- * Initial grid columns.
- */
- private int cols = 0;
-
- /**
- * Initial grid rows.
- */
- private int rows = 0;
-
- /**
- * Cursor X position: this is where the next component with unspecified x,y
- * is inserted
- */
- private int cursorX = 0;
-
- /**
- * Cursor Y position: this is where the next component with unspecified x,y
- * is inserted
- */
- private int cursorY = 0;
-
- /**
- * Contains all items that are placed on the grid. These are components with
- * grid area definition.
- */
- private LinkedList areas = new LinkedList();
-
- /**
- * Mapping from components to their respective areas.
- */
- private LinkedList components = new LinkedList();
-
- /**
- * Mapping from components to alignments (horizontal + vertical).
- */
- private Map componentToAlignment = new HashMap();
-
- /**
- * Contained component should be aligned horizontally to the left.
- */
- public static final int ALIGNMENT_LEFT = AlignmentInfo.ALIGNMENT_LEFT;
-
- /**
- * Contained component should be aligned horizontally to the right.
- */
- public static final int ALIGNMENT_RIGHT = AlignmentInfo.ALIGNMENT_RIGHT;
-
- /**
- * Contained component should be aligned vertically to the top.
- */
- public static final int ALIGNMENT_TOP = AlignmentInfo.ALIGNMENT_TOP;
-
- /**
- * Contained component should be aligned vertically to the bottom.
- */
- public static final int ALIGNMENT_BOTTOM = AlignmentInfo.ALIGNMENT_BOTTOM;
-
- /**
- * Contained component should be horizontally aligned to center.
- */
- public static final int ALIGNMENT_HORIZONTAL_CENTER = AlignmentInfo.ALIGNMENT_HORIZONTAL_CENTER;
-
- /**
- * Contained component should be vertically aligned to center.
- */
- public static final int ALIGNMENT_VERTICAL_CENTER = AlignmentInfo.ALIGNMENT_VERTICAL_CENTER;
-
- /**
- * Is spacing between contained components enabled. Defaults to false.
- */
- private boolean spacing = false;
-
- /**
- * Constructor for grid of given size (number of cells). Note that grid's
- * final size depends on the items that are added into the grid. Grid grows
- * if you add components outside the grid's area.
- *
- * @param columns
- * Number of columns in the grid.
- * @param rows
- * Number of rows in the grid.
- */
- public GridLayout(int columns, int rows) {
- setColumns(columns);
- setRows(rows);
- }
-
- /**
- * Constructs an empty grid layout that is extended as needed.
- */
- public GridLayout() {
- this(1, 1);
- }
-
- /**
- * <p>
- * Adds a component with a specified area to the grid. The area the new
- * component should take is defined by specifying the upper left corner
- * (column1, row1) and the lower right corner (column2, row2) of the area.
- * </p>
- *
- * <p>
- * If the new component overlaps with any of the existing components already
- * present in the grid the operation will fail and an
- * {@link OverlapsException} is thrown.
- * </p>
- *
- * @param c
- * the component to be added.
- * @param column1
- * the column of the upper left corner of the area <code>c</code>
- * is supposed to occupy.
- * @param row1
- * the row of the upper left corner of the area <code>c</code>
- * is supposed to occupy.
- * @param column2
- * the column of the lower right corner of the area
- * <code>c</code> is supposed to occupy.
- * @param row2
- * the row of the lower right corner of the area <code>c</code>
- * is supposed to occupy.
- * @throws OverlapsException
- * if the new component overlaps with any of the components
- * already in the grid.
- * @throws OutOfBoundsException
- * if the cells are outside of the grid area.
- */
- public void addComponent(Component component, int column1, int row1,
- int column2, int row2) throws OverlapsException,
- OutOfBoundsException {
-
- if (component == null)
- throw new NullPointerException("Component must not be null");
-
- // Checks that the component does not already exist in the container
- if (components.contains(component))
- throw new IllegalArgumentException(
- "Component is already in the container");
-
- // Creates the area
- Area area = new Area(component, column1, row1, column2, row2);
-
- // Checks the validity of the coordinates
- if (column2 < column1 || row2 < row1)
- throw new IllegalArgumentException(
- "Illegal coordinates for the component");
- if (column1 < 0 || row1 < 0 || column2 >= cols || row2 >= rows)
- throw new OutOfBoundsException(area);
-
- // Checks that newItem does not overlap with existing items
- checkExistingOverlaps(area);
-
- // Inserts the component to right place at the list
- // Respect top-down, left-right ordering
- component.setParent(this);
- Iterator i = areas.iterator();
- int index = 0;
- boolean done = false;
- while (!done && i.hasNext()) {
- Area existingArea = (Area) i.next();
- if ((existingArea.row1 >= row1 && existingArea.column1 > column1)
- || existingArea.row1 > row1) {
- areas.add(index, area);
- components.add(index, component);
- done = true;
- }
- index++;
- }
- if (!done) {
- areas.addLast(area);
- components.addLast(component);
- }
-
- super.addComponent(component);
- requestRepaint();
- }
-
- /**
- * Tests if the given area overlaps with any of the items already on the
- * grid.
- *
- * @param area
- * the Area to be checked for overlapping.
- * @throws OverlapsException
- * if <code>area</code> overlaps with any existing area.
- */
- private void checkExistingOverlaps(Area area) throws OverlapsException {
- for (Iterator i = areas.iterator(); i.hasNext();) {
- Area existingArea = (Area) i.next();
- if (existingArea.overlaps(area))
-
- // Component not added, overlaps with existing component
- throw new OverlapsException(existingArea);
- }
- }
-
- /**
- * Adds the component into this container to cells column1,row1 (NortWest
- * corner of the area.) End coordinates (SouthEast corner of the area) are
- * the same as column1,row1. Component width and height is 1.
- *
- * @param c
- * the component to be added.
- * @param column
- * the column index.
- * @param row
- * the row index.
- */
- public void addComponent(Component c, int column, int row) {
- this.addComponent(c, column, row, column, row);
- }
-
- /**
- * Force the next component to be added to the beginning of the next line.
- * By calling this function user can ensure that no more components are
- * added to the right of the previous component.
- *
- * @see #space()
- */
- public void newLine() {
- cursorX = 0;
- cursorY++;
- }
-
- /**
- * Moves the cursor forwards by one. If the cursor goes out of the right
- * grid border, move it to next line.
- *
- * @see #newLine()
- */
- public void space() {
- cursorX++;
- if (cursorX >= cols) {
- cursorX = 0;
- cursorY++;
- }
- }
-
- /**
- * Adds the component into this container to the cursor position. If the
- * cursor position is already occupied, the cursor is moved forwards to find
- * free position. If the cursor goes out from the bottom of the grid, the
- * grid is automatically extended.
- *
- * @param c
- * the component to be added.
- */
- public void addComponent(Component component) {
-
- // Finds first available place from the grid
- Area area;
- boolean done = false;
- while (!done)
- try {
- area = new Area(component, cursorX, cursorY, cursorX, cursorY);
- checkExistingOverlaps(area);
- done = true;
- } catch (OverlapsException ignored) {
- space();
- }
-
- // Extends the grid if needed
- cols = cursorX >= cols ? cursorX + 1 : cols;
- rows = cursorY >= rows ? cursorY + 1 : rows;
-
- addComponent(component, cursorX, cursorY);
- }
-
- /**
- * Removes the given component from this container.
- *
- * @param c
- * the component to be removed.
- */
- public void removeComponent(Component component) {
-
- // Check that the component is contained in the container
- if (component == null || !components.contains(component))
- return;
-
- super.removeComponent(component);
-
- Area area = null;
- for (Iterator i = areas.iterator(); area == null && i.hasNext();) {
- Area a = (Area) i.next();
- if (a.getComponent() == component)
- area = a;
- }
-
- components.remove(component);
- if (area != null)
- areas.remove(area);
-
- componentToAlignment.remove(component);
-
- requestRepaint();
- }
-
- /**
- * Removes the component specified with it's cell index.
- *
- * @param column
- * the Component's column.
- * @param row
- * the Component's row.
- */
- public void removeComponent(int column, int row) {
-
- // Finds the area
- for (Iterator i = areas.iterator(); i.hasNext();) {
- Area area = (Area) i.next();
- if (area.getColumn1() == column && area.getRow1() == row) {
- removeComponent(area.getComponent());
- return;
- }
- }
- }
-
- /**
- * Gets an Iterator to the component container contents. Using the Iterator
- * it's possible to step through the contents of the container.
- *
- * @return the Iterator of the components inside the container.
- */
- public Iterator getComponentIterator() {
- return Collections.unmodifiableCollection(components).iterator();
- }
-
- /**
- * Paints the contents of this component.
- *
- * @param target
- * the Paint Event.
- * @throws PaintException
- * if the paint operation failed.
- */
- public void paintContent(PaintTarget target) throws PaintException {
-
- super.paintContent(target);
-
- // TODO refactor attribute names in future release.
- target.addAttribute("h", rows);
- target.addAttribute("w", cols);
-
- if (this.spacing)
- target.addAttribute("spacing", this.spacing);
-
- // Area iterator
- Iterator areaiterator = areas.iterator();
-
- // Current item to be processed (fetch first item)
- Area area = areaiterator.hasNext() ? (Area) areaiterator.next() : null;
-
- // Collects rowspan related information here
- HashMap cellUsed = new HashMap();
-
- // Empty cell collector
- int emptyCells = 0;
-
- // Iterates every applicable row
- for (int cury = 0; cury < rows; cury++) {
- target.startTag("gr");
-
- // Iterates every applicable column
- for (int curx = 0; curx < cols; curx++) {
-
- // Checks if current item is located at curx,cury
- if (area != null && (area.row1 == cury)
- && (area.column1 == curx)) {
-
- // First check if empty cell needs to be rendered
- if (emptyCells > 0) {
- target.startTag("gc");
- target.addAttribute("x", curx - emptyCells);
- target.addAttribute("y", cury);
- if (emptyCells > 1) {
- target.addAttribute("w", emptyCells);
- }
- target.endTag("gc");
- emptyCells = 0;
- }
-
- // Now proceed rendering current item
- int cols = (area.column2 - area.column1) + 1;
- int rows = (area.row2 - area.row1) + 1;
- target.startTag("gc");
-
- target.addAttribute("x", curx);
- target.addAttribute("y", cury);
-
- if (cols > 1) {
- target.addAttribute("w", cols);
- }
- if (rows > 1) {
- target.addAttribute("h", rows);
- }
- area.getComponent().paint(target);
-
- target.endTag("gc");
-
- // Fetch next item
- if (areaiterator.hasNext()) {
- area = (Area) areaiterator.next();
- } else {
- area = null;
- }
-
- // Updates the cellUsed if rowspan needed
- if (rows > 1) {
- int spannedx = curx;
- for (int j = 1; j <= cols; j++) {
- cellUsed.put(new Integer(spannedx), new Integer(
- cury + rows - 1));
- spannedx++;
- }
- }
-
- // Skips the current item's spanned columns
- if (cols > 1) {
- curx += cols - 1;
- }
-
- } else {
-
- // Checks against cellUsed, render space or ignore cell
- if (cellUsed.containsKey(new Integer(curx))) {
-
- // Current column contains already an item,
- // check if rowspan affects at current x,y position
- int rowspanDepth = ((Integer) cellUsed.get(new Integer(
- curx))).intValue();
-
- if (rowspanDepth >= cury) {
-
- // ignore cell
- // Check if empty cell needs to be rendered
- if (emptyCells > 0) {
- target.startTag("gc");
- target.addAttribute("x", curx - emptyCells);
- target.addAttribute("y", cury);
- if (emptyCells > 1) {
- target.addAttribute("w", emptyCells);
- }
- target.endTag("gc");
-
- emptyCells = 0;
- }
- } else {
-
- // empty cell is needed
- emptyCells++;
-
- // Removes the cellUsed key as it has become
- // obsolete
- cellUsed.remove(new Integer(curx));
- }
- } else {
-
- // empty cell is needed
- emptyCells++;
- }
- }
-
- } // iterates every column
-
- // Last column handled of current row
-
- // Checks if empty cell needs to be rendered
- if (emptyCells > 0) {
- target.startTag("gc");
- target.addAttribute("x", cols - emptyCells);
- target.addAttribute("y", cury);
- if (emptyCells > 1) {
- target.addAttribute("w", emptyCells);
- }
- target.endTag("gc");
-
- emptyCells = 0;
- }
-
- target.endTag("gr");
- } // iterates every row
-
- // Last row handled
- }
-
- /**
- * Gets the components UIDL tag.
- *
- * @return the Component UIDL tag as string.
- * @see com.itmill.toolkit.ui.AbstractComponent#getTag()
- */
- public String getTag() {
- return "gridlayout";
- }
-
- /**
- * This class defines an area on a grid. An Area is defined by the cells of
- * its upper left corner (column1,row1) and lower right corner
- * (column2,row2).
- *
- * @author IT Mill Ltd.
- * @version
- * @VERSION@
- * @since 3.0
- */
- public class Area {
-
- /**
- * The column of the upper left corner cell of the area.
- */
- private int column1;
-
- /**
- * The row of the upper left corner cell of the area.
- */
- private int row1;
-
- /**
- * The column of the lower right corner cell of the area.
- */
- private int column2;
-
- /**
- * The row of the lower right corner cell of the area.
- */
- private int row2;
-
- /**
- * Component painted on the area.
- */
- private Component component;
-
- /**
- * <p>
- * Construct a new area on a grid.
- * </p>
- *
- * @param component
- * the component connected to the area.
- * @param column1
- * The column of the upper left corner cell of the area
- * <code>c</code> is supposed to occupy.
- * @param row1
- * The row of the upper left corner cell of the area
- * <code>c</code> is supposed to occupy.
- * @param column2
- * The column of the lower right corner cell of the area
- * <code>c</code> is supposed to occupy.
- * @param row2
- * The row of the lower right corner cell of the area
- * <code>c</code> is supposed to occupy.
- * @throws OverlapsException
- * if the new component overlaps with any of the components
- * already in the grid
- */
- public Area(Component component, int column1, int row1, int column2,
- int row2) {
- this.column1 = column1;
- this.row1 = row1;
- this.column2 = column2;
- this.row2 = row2;
- this.component = component;
- }
-
- /**
- * Tests if the given Area overlaps with an another Area.
- *
- * @param other
- * the Another Area that's to be tested for overlap with this
- * area.
- * @return <code>true</code> if <code>other</code> overlaps with
- * this area, <code>false</code> if it doesn't.
- */
- public boolean overlaps(Area other) {
- return column1 <= other.getColumn2() && row1 <= other.getRow2()
- && column2 >= other.getColumn1() && row2 >= other.getRow1();
-
- }
-
- /**
- * Gets the component connected to the area.
- *
- * @return the Component.
- */
- public Component getComponent() {
- return component;
- }
-
- /**
- * Sets the component connected to the area.
- *
- * <p>
- * This function only sets the value in the datastructure and does not
- * send any events or set parents.
- * </p>
- *
- * @param newComponent
- * the new connected overriding the existing one.
- */
- protected void setComponent(Component newComponent) {
- component = newComponent;
- }
-
- /**
- * @deprecated Use getColumn1() instead.
- *
- * @see com.itmill.toolkit.ui.GridLayout#getColumn1()
- */
- public int getX1() {
- return getColumn1();
- }
-
- /**
- * Gets the column of the top-left corner cell.
- *
- * @return the column of the top-left corner cell.
- */
- public int getColumn1() {
- return column1;
- }
-
- /**
- * @deprecated Use getColumn2() instead.
- *
- * @see com.itmill.toolkit.ui.GridLayout#getColumn2()
- */
- public int getX2() {
- return getColumn2();
- }
-
- /**
- * Gets the column of the bottom-right corner cell.
- *
- * @return the column of the bottom-right corner cell.
- */
- public int getColumn2() {
- return column2;
- }
-
- /**
- * @deprecated Use getRow1() instead.
- *
- * @see com.itmill.toolkit.ui.GridLayout#getRow1()
- */
- public int getY1() {
- return getRow1();
- }
-
- /**
- * Gets the row of the top-left corner cell.
- *
- * @return the row of the top-left corner cell.
- */
- public int getRow1() {
- return row1;
- }
-
- /**
- * @deprecated Use getRow2() instead.
- *
- * @see com.itmill.toolkit.ui.GridLayout#getRow2()
- */
- public int getY2() {
- return getRow2();
- }
-
- /**
- * Gets the row of the bottom-right corner cell.
- *
- * @return the row of the bottom-right corner cell.
- */
- public int getRow2() {
- return row2;
- }
-
- }
-
- /**
- * An <code>Exception</code> object which is thrown when two Items occupy
- * the same space on a grid.
- *
- * @author IT Mill Ltd.
- * @version
- * @VERSION@
- * @since 3.0
- */
- public class OverlapsException extends java.lang.RuntimeException {
-
- /**
- * Serial generated by eclipse.
- */
- private static final long serialVersionUID = 3978144339870101561L;
-
- private Area existingArea;
-
- /**
- * Constructs an <code>OverlapsException</code>.
- *
- * @param existingArea
- */
- public OverlapsException(Area existingArea) {
- this.existingArea = existingArea;
- }
-
- /**
- * Gets the area .
- *
- * @return the existing area.
- */
- public Area getArea() {
- return existingArea;
- }
- }
-
- /**
- * An <code>Exception</code> object which is thrown when an area exceeds
- * the bounds of the grid.
- *
- * @author IT Mill Ltd.
- * @version
- * @VERSION@
- * @since 3.0
- */
- public class OutOfBoundsException extends java.lang.RuntimeException {
-
- /**
- * Serial generated by eclipse.
- */
- private static final long serialVersionUID = 3618985589664592694L;
-
- private Area areaOutOfBounds;
-
- /**
- * Constructs an <code>OoutOfBoundsException</code> with the specified
- * detail message.
- *
- * @param areaOutOfBounds
- */
- public OutOfBoundsException(Area areaOutOfBounds) {
- this.areaOutOfBounds = areaOutOfBounds;
- }
-
- /**
- * Gets the area that is out of bounds.
- *
- * @return the area out of Bound.
- */
- public Area getArea() {
- return areaOutOfBounds;
- }
- }
-
- /**
- * Sets the width of the layout.
- * <p>
- * <strong>NOTE:</strong> The behaviour of this methdod has changed in
- * version 5.0. Now this method won't set the number of columns in the grid
- * like it used to (use {@link #setColumns()} for that). Instead, it sets
- * the actual visual width of the layout in pixels or in another unit
- * specified in {@link Sizeable}.UNIT_SYMBOLS.
- * </p>
- */
- public void setWidth(int width) {
- super.setWidth(width);
- }
-
- /**
- * Gets the width of the layout.
- * <p>
- * <strong>NOTE:</strong> The behaviour of this methdod has changed in
- * version 5.0. Now this method won't return the number of columns in the
- * grid like it used to (use {@link #getColumns()} for that). Instead, it
- * returns the actual visual width of the layout in pixels or in another
- * unit specified in {@link Sizeable}.UNIT_SYMBOLS.
- * </p>
- */
- public int getWidth() {
- return super.getWidth();
- }
-
- /**
- * Sets the number of columns in the grid. The column count can not be
- * reduced if there are any areas that would be outside of the shrunk grid.
- *
- * @param columns
- * the new number of columns in the grid.
- */
- public void setColumns(int columns) {
-
- // The the param
- if (columns < 1)
- throw new IllegalArgumentException(
- "The number of columns and rows in the grid must be at least 1");
-
- // In case of no change
- if (this.cols == columns)
- return;
-
- // Checks for overlaps
- if (this.cols > columns)
- for (Iterator i = areas.iterator(); i.hasNext();) {
- Area area = (Area) i.next();
- if (area.column2 >= columns)
- throw new OutOfBoundsException(area);
- }
-
- this.cols = columns;
-
- requestRepaint();
- }
-
- /**
- * Get the number of columns in the grid.
- *
- * @return the number of columns in the grid.
- */
- public final int getColumns() {
- return this.cols;
- }
-
- /**
- * Set the height of the layout.
- * <p>
- * <strong>NOTE:</strong> The behaviour of this methdod has changed in
- * version 5.0. Now this method won't set the number of rows in the grid
- * like it used to (use {@link #setRows()} for that). Instead, it sets the
- * actual visual height of the layout in pixels or in another unit specified
- * in {@link Sizeable}.UNIT_SYMBOLS.
- * </p>
- */
- public void setHeight(int height) {
- super.setHeight(height);
- }
-
- /**
- * Gets the height of the layout.
- * <p>
- * <strong>NOTE:</strong> The behaviour of this methdod has changed in
- * version 5.0. Now this method won't return the number of rows in the grid
- * like it used to (use {@link #getRows()} for that). Instead, it returns
- * the actual visual height of the layout in pixels or in another unit
- * specified in {@link Sizeable}.UNIT_SYMBOLS.
- * </p>
- */
- public int getHeight() {
- return super.getHeight();
- }
-
- /**
- * Sets the number of rows in the grid. The number of rows can not be
- * reduced if there are any areas that would be outside of the shrunk grid.
- *
- * @param rows
- * the new number of rows in the grid.
- */
- public void setRows(int rows) {
-
- // The the param
- if (rows < 1)
- throw new IllegalArgumentException(
- "The number of columns and rows in the grid must be at least 1");
-
- // In case of no change
- if (this.rows == rows)
- return;
-
- // Checks for overlaps
- if (this.rows > rows)
- for (Iterator i = areas.iterator(); i.hasNext();) {
- Area area = (Area) i.next();
- if (area.row2 >= rows)
- throw new OutOfBoundsException(area);
- }
-
- this.rows = rows;
-
- requestRepaint();
- }
-
- /**
- * Get the number of rows in the grid.
- *
- * @return the number of rows in the grid.
- */
- public final int getRows() {
- return this.rows;
- }
-
- /**
- * Gets the current cursor x-position. The cursor position points the
- * position for the next component that is added without specifying its
- * coordinates (grid cell). When the cursor position is occupied, the next
- * component will be added to first free position after the cursor.
- *
- * @return the grid column the Cursor is on.
- */
- public int getCursorX() {
- return cursorX;
- }
-
- /**
- * Gets the current cursor y-position. The cursor position points the
- * position for the next component that is added without specifying its
- * coordinates (grid cell). When the cursor position is occupied, the next
- * component will be added to first free position after the cursor.
- *
- * @return the grid row the Cursor is on.
- */
- public int getCursorY() {
- return cursorY;
- }
-
- /* Documented in superclass */
- public void replaceComponent(Component oldComponent, Component newComponent) {
-
- // Gets the locations
- Area oldLocation = null;
- Area newLocation = null;
- for (Iterator i = areas.iterator(); i.hasNext();) {
- Area location = (Area) i.next();
- Component component = (Component) location.getComponent();
- if (component == oldComponent)
- oldLocation = location;
- if (component == newComponent)
- newLocation = location;
- }
-
- if (oldLocation == null)
- addComponent(newComponent);
- else if (newLocation == null) {
- removeComponent(oldComponent);
- addComponent(newComponent, oldLocation.getColumn1(), oldLocation
- .getRow1(), oldLocation.getColumn2(), oldLocation.getRow2());
- } else {
- oldLocation.setComponent(newComponent);
- newLocation.setComponent(oldComponent);
- requestRepaint();
- }
- }
-
- /*
- * Removes all components from this container.
- *
- * @see com.itmill.toolkit.ui.ComponentContainer#removeAllComponents()
- */
- public void removeAllComponents() {
- super.removeAllComponents();
- this.componentToAlignment = new HashMap();
- this.cursorX = 0;
- this.cursorY = 0;
- }
-
- /**
- * Set alignment for one contained component in this layout.
- *
- * @param childComponent
- * the component to align within it's layout cell.
- * @param horizontalAlignment
- * the horizontal alignment for the child component (left,
- * center, right).
- * @param verticalAlignment
- * the vertical alignment for the child component (top, center,
- * bottom).
- */
- public void setComponentAlignment(Component childComponent,
- int horizontalAlignment, int verticalAlignment) {
- componentToAlignment.put(childComponent, new Integer(
- horizontalAlignment + verticalAlignment));
- }
-
- /**
- * Enable spacing between child components within this layout.
- *
- * <p>
- * <strong>NOTE:</strong> This will only affect spaces between components,
- * not also all around spacing of the layout (i.e. do not mix this with HTML
- * Table elements cellspacing-attribute). Use {@link #setMargin(boolean)} to
- * add extra space around the layout.
- * </p>
- *
- * @param enabled
- */
- public void setSpacing(boolean enabled) {
- this.spacing = enabled;
- }
+ /**
+ * Initial grid columns.
+ */
+ private int cols = 0;
+
+ /**
+ * Initial grid rows.
+ */
+ private int rows = 0;
+
+ /**
+ * Cursor X position: this is where the next component with unspecified x,y
+ * is inserted
+ */
+ private int cursorX = 0;
+
+ /**
+ * Cursor Y position: this is where the next component with unspecified x,y
+ * is inserted
+ */
+ private int cursorY = 0;
+
+ /**
+ * Contains all items that are placed on the grid. These are components with
+ * grid area definition.
+ */
+ private LinkedList areas = new LinkedList();
+
+ /**
+ * Mapping from components to their respective areas.
+ */
+ private LinkedList components = new LinkedList();
+
+ /**
+ * Mapping from components to alignments (horizontal + vertical).
+ */
+ private Map componentToAlignment = new HashMap();
+
+ /**
+ * Contained component should be aligned horizontally to the left.
+ */
+ public static final int ALIGNMENT_LEFT = AlignmentInfo.ALIGNMENT_LEFT;
+
+ /**
+ * Contained component should be aligned horizontally to the right.
+ */
+ public static final int ALIGNMENT_RIGHT = AlignmentInfo.ALIGNMENT_RIGHT;
+
+ /**
+ * Contained component should be aligned vertically to the top.
+ */
+ public static final int ALIGNMENT_TOP = AlignmentInfo.ALIGNMENT_TOP;
+
+ /**
+ * Contained component should be aligned vertically to the bottom.
+ */
+ public static final int ALIGNMENT_BOTTOM = AlignmentInfo.ALIGNMENT_BOTTOM;
+
+ /**
+ * Contained component should be horizontally aligned to center.
+ */
+ public static final int ALIGNMENT_HORIZONTAL_CENTER = AlignmentInfo.ALIGNMENT_HORIZONTAL_CENTER;
+
+ /**
+ * Contained component should be vertically aligned to center.
+ */
+ public static final int ALIGNMENT_VERTICAL_CENTER = AlignmentInfo.ALIGNMENT_VERTICAL_CENTER;
+
+ /**
+ * Is spacing between contained components enabled. Defaults to false.
+ */
+ private boolean spacing = false;
+
+ /**
+ * Constructor for grid of given size (number of cells). Note that grid's
+ * final size depends on the items that are added into the grid. Grid grows
+ * if you add components outside the grid's area.
+ *
+ * @param columns
+ * Number of columns in the grid.
+ * @param rows
+ * Number of rows in the grid.
+ */
+ public GridLayout(int columns, int rows) {
+ setColumns(columns);
+ setRows(rows);
+ }
+
+ /**
+ * Constructs an empty grid layout that is extended as needed.
+ */
+ public GridLayout() {
+ this(1, 1);
+ }
+
+ /**
+ * <p>
+ * Adds a component with a specified area to the grid. The area the new
+ * component should take is defined by specifying the upper left corner
+ * (column1, row1) and the lower right corner (column2, row2) of the area.
+ * </p>
+ *
+ * <p>
+ * If the new component overlaps with any of the existing components already
+ * present in the grid the operation will fail and an
+ * {@link OverlapsException} is thrown.
+ * </p>
+ *
+ * @param c
+ * the component to be added.
+ * @param column1
+ * the column of the upper left corner of the area
+ * <code>c</code> is supposed to occupy.
+ * @param row1
+ * the row of the upper left corner of the area
+ * <code>c</code> is supposed to occupy.
+ * @param column2
+ * the column of the lower right corner of the area
+ * <code>c</code> is supposed to occupy.
+ * @param row2
+ * the row of the lower right corner of the area
+ * <code>c</code> is supposed to occupy.
+ * @throws OverlapsException
+ * if the new component overlaps with any of the components
+ * already in the grid.
+ * @throws OutOfBoundsException
+ * if the cells are outside of the grid area.
+ */
+ public void addComponent(Component component, int column1, int row1,
+ int column2, int row2) throws OverlapsException,
+ OutOfBoundsException {
+
+ if (component == null) {
+ throw new NullPointerException("Component must not be null");
+ }
+
+ // Checks that the component does not already exist in the container
+ if (components.contains(component)) {
+ throw new IllegalArgumentException(
+ "Component is already in the container");
+ }
+
+ // Creates the area
+ Area area = new Area(component, column1, row1, column2, row2);
+
+ // Checks the validity of the coordinates
+ if (column2 < column1 || row2 < row1) {
+ throw new IllegalArgumentException(
+ "Illegal coordinates for the component");
+ }
+ if (column1 < 0 || row1 < 0 || column2 >= cols || row2 >= rows) {
+ throw new OutOfBoundsException(area);
+ }
+
+ // Checks that newItem does not overlap with existing items
+ checkExistingOverlaps(area);
+
+ // Inserts the component to right place at the list
+ // Respect top-down, left-right ordering
+ component.setParent(this);
+ Iterator i = areas.iterator();
+ int index = 0;
+ boolean done = false;
+ while (!done && i.hasNext()) {
+ Area existingArea = (Area) i.next();
+ if ((existingArea.row1 >= row1 && existingArea.column1 > column1)
+ || existingArea.row1 > row1) {
+ areas.add(index, area);
+ components.add(index, component);
+ done = true;
+ }
+ index++;
+ }
+ if (!done) {
+ areas.addLast(area);
+ components.addLast(component);
+ }
+
+ super.addComponent(component);
+ requestRepaint();
+ }
+
+ /**
+ * Tests if the given area overlaps with any of the items already on the
+ * grid.
+ *
+ * @param area
+ * the Area to be checked for overlapping.
+ * @throws OverlapsException
+ * if <code>area</code> overlaps with any existing area.
+ */
+ private void checkExistingOverlaps(Area area) throws OverlapsException {
+ for (Iterator i = areas.iterator(); i.hasNext();) {
+ Area existingArea = (Area) i.next();
+ if (existingArea.overlaps(area)) {
+ // Component not added, overlaps with existing component
+ throw new OverlapsException(existingArea);
+ }
+ }
+ }
+
+ /**
+ * Adds the component into this container to cells column1,row1 (NortWest
+ * corner of the area.) End coordinates (SouthEast corner of the area) are
+ * the same as column1,row1. Component width and height is 1.
+ *
+ * @param c
+ * the component to be added.
+ * @param column
+ * the column index.
+ * @param row
+ * the row index.
+ */
+ public void addComponent(Component c, int column, int row) {
+ this.addComponent(c, column, row, column, row);
+ }
+
+ /**
+ * Force the next component to be added to the beginning of the next line.
+ * By calling this function user can ensure that no more components are
+ * added to the right of the previous component.
+ *
+ * @see #space()
+ */
+ public void newLine() {
+ cursorX = 0;
+ cursorY++;
+ }
+
+ /**
+ * Moves the cursor forwards by one. If the cursor goes out of the right
+ * grid border, move it to next line.
+ *
+ * @see #newLine()
+ */
+ public void space() {
+ cursorX++;
+ if (cursorX >= cols) {
+ cursorX = 0;
+ cursorY++;
+ }
+ }
+
+ /**
+ * Adds the component into this container to the cursor position. If the
+ * cursor position is already occupied, the cursor is moved forwards to find
+ * free position. If the cursor goes out from the bottom of the grid, the
+ * grid is automatically extended.
+ *
+ * @param c
+ * the component to be added.
+ */
+ public void addComponent(Component component) {
+
+ // Finds first available place from the grid
+ Area area;
+ boolean done = false;
+ while (!done) {
+ try {
+ area = new Area(component, cursorX, cursorY, cursorX, cursorY);
+ checkExistingOverlaps(area);
+ done = true;
+ } catch (OverlapsException ignored) {
+ space();
+ }
+ }
+
+ // Extends the grid if needed
+ cols = cursorX >= cols ? cursorX + 1 : cols;
+ rows = cursorY >= rows ? cursorY + 1 : rows;
+
+ addComponent(component, cursorX, cursorY);
+ }
+
+ /**
+ * Removes the given component from this container.
+ *
+ * @param c
+ * the component to be removed.
+ */
+ public void removeComponent(Component component) {
+
+ // Check that the component is contained in the container
+ if (component == null || !components.contains(component)) {
+ return;
+ }
+
+ super.removeComponent(component);
+
+ Area area = null;
+ for (Iterator i = areas.iterator(); area == null && i.hasNext();) {
+ Area a = (Area) i.next();
+ if (a.getComponent() == component) {
+ area = a;
+ }
+ }
+
+ components.remove(component);
+ if (area != null) {
+ areas.remove(area);
+ }
+
+ componentToAlignment.remove(component);
+
+ requestRepaint();
+ }
+
+ /**
+ * Removes the component specified with it's cell index.
+ *
+ * @param column
+ * the Component's column.
+ * @param row
+ * the Component's row.
+ */
+ public void removeComponent(int column, int row) {
+
+ // Finds the area
+ for (Iterator i = areas.iterator(); i.hasNext();) {
+ Area area = (Area) i.next();
+ if (area.getColumn1() == column && area.getRow1() == row) {
+ removeComponent(area.getComponent());
+ return;
+ }
+ }
+ }
+
+ /**
+ * Gets an Iterator to the component container contents. Using the Iterator
+ * it's possible to step through the contents of the container.
+ *
+ * @return the Iterator of the components inside the container.
+ */
+ public Iterator getComponentIterator() {
+ return Collections.unmodifiableCollection(components).iterator();
+ }
+
+ /**
+ * Paints the contents of this component.
+ *
+ * @param target
+ * the Paint Event.
+ * @throws PaintException
+ * if the paint operation failed.
+ */
+ public void paintContent(PaintTarget target) throws PaintException {
+
+ super.paintContent(target);
+
+ // TODO refactor attribute names in future release.
+ target.addAttribute("h", rows);
+ target.addAttribute("w", cols);
+
+ if (spacing) {
+ target.addAttribute("spacing", spacing);
+ }
+
+ // Area iterator
+ Iterator areaiterator = areas.iterator();
+
+ // Current item to be processed (fetch first item)
+ Area area = areaiterator.hasNext() ? (Area) areaiterator.next() : null;
+
+ // Collects rowspan related information here
+ HashMap cellUsed = new HashMap();
+
+ // Empty cell collector
+ int emptyCells = 0;
+
+ // Iterates every applicable row
+ for (int cury = 0; cury < rows; cury++) {
+ target.startTag("gr");
+
+ // Iterates every applicable column
+ for (int curx = 0; curx < cols; curx++) {
+
+ // Checks if current item is located at curx,cury
+ if (area != null && (area.row1 == cury)
+ && (area.column1 == curx)) {
+
+ // First check if empty cell needs to be rendered
+ if (emptyCells > 0) {
+ target.startTag("gc");
+ target.addAttribute("x", curx - emptyCells);
+ target.addAttribute("y", cury);
+ if (emptyCells > 1) {
+ target.addAttribute("w", emptyCells);
+ }
+ target.endTag("gc");
+ emptyCells = 0;
+ }
+
+ // Now proceed rendering current item
+ int cols = (area.column2 - area.column1) + 1;
+ int rows = (area.row2 - area.row1) + 1;
+ target.startTag("gc");
+
+ target.addAttribute("x", curx);
+ target.addAttribute("y", cury);
+
+ if (cols > 1) {
+ target.addAttribute("w", cols);
+ }
+ if (rows > 1) {
+ target.addAttribute("h", rows);
+ }
+ area.getComponent().paint(target);
+
+ target.endTag("gc");
+
+ // Fetch next item
+ if (areaiterator.hasNext()) {
+ area = (Area) areaiterator.next();
+ } else {
+ area = null;
+ }
+
+ // Updates the cellUsed if rowspan needed
+ if (rows > 1) {
+ int spannedx = curx;
+ for (int j = 1; j <= cols; j++) {
+ cellUsed.put(new Integer(spannedx), new Integer(
+ cury + rows - 1));
+ spannedx++;
+ }
+ }
+
+ // Skips the current item's spanned columns
+ if (cols > 1) {
+ curx += cols - 1;
+ }
+
+ } else {
+
+ // Checks against cellUsed, render space or ignore cell
+ if (cellUsed.containsKey(new Integer(curx))) {
+
+ // Current column contains already an item,
+ // check if rowspan affects at current x,y position
+ int rowspanDepth = ((Integer) cellUsed.get(new Integer(
+ curx))).intValue();
+
+ if (rowspanDepth >= cury) {
+
+ // ignore cell
+ // Check if empty cell needs to be rendered
+ if (emptyCells > 0) {
+ target.startTag("gc");
+ target.addAttribute("x", curx - emptyCells);
+ target.addAttribute("y", cury);
+ if (emptyCells > 1) {
+ target.addAttribute("w", emptyCells);
+ }
+ target.endTag("gc");
+
+ emptyCells = 0;
+ }
+ } else {
+
+ // empty cell is needed
+ emptyCells++;
+
+ // Removes the cellUsed key as it has become
+ // obsolete
+ cellUsed.remove(new Integer(curx));
+ }
+ } else {
+
+ // empty cell is needed
+ emptyCells++;
+ }
+ }
+
+ } // iterates every column
+
+ // Last column handled of current row
+
+ // Checks if empty cell needs to be rendered
+ if (emptyCells > 0) {
+ target.startTag("gc");
+ target.addAttribute("x", cols - emptyCells);
+ target.addAttribute("y", cury);
+ if (emptyCells > 1) {
+ target.addAttribute("w", emptyCells);
+ }
+ target.endTag("gc");
+
+ emptyCells = 0;
+ }
+
+ target.endTag("gr");
+ } // iterates every row
+
+ // Last row handled
+ }
+
+ /**
+ * Gets the components UIDL tag.
+ *
+ * @return the Component UIDL tag as string.
+ * @see com.itmill.toolkit.ui.AbstractComponent#getTag()
+ */
+ public String getTag() {
+ return "gridlayout";
+ }
+
+ /**
+ * This class defines an area on a grid. An Area is defined by the cells of
+ * its upper left corner (column1,row1) and lower right corner
+ * (column2,row2).
+ *
+ * @author IT Mill Ltd.
+ * @version
+ * @VERSION@
+ * @since 3.0
+ */
+ public class Area {
+
+ /**
+ * The column of the upper left corner cell of the area.
+ */
+ private int column1;
+
+ /**
+ * The row of the upper left corner cell of the area.
+ */
+ private int row1;
+
+ /**
+ * The column of the lower right corner cell of the area.
+ */
+ private int column2;
+
+ /**
+ * The row of the lower right corner cell of the area.
+ */
+ private int row2;
+
+ /**
+ * Component painted on the area.
+ */
+ private Component component;
+
+ /**
+ * <p>
+ * Construct a new area on a grid.
+ * </p>
+ *
+ * @param component
+ * the component connected to the area.
+ * @param column1
+ * The column of the upper left corner cell of the area
+ * <code>c</code> is supposed to occupy.
+ * @param row1
+ * The row of the upper left corner cell of the area
+ * <code>c</code> is supposed to occupy.
+ * @param column2
+ * The column of the lower right corner cell of the area
+ * <code>c</code> is supposed to occupy.
+ * @param row2
+ * The row of the lower right corner cell of the area
+ * <code>c</code> is supposed to occupy.
+ * @throws OverlapsException
+ * if the new component overlaps with any of the
+ * components already in the grid
+ */
+ public Area(Component component, int column1, int row1, int column2,
+ int row2) {
+ this.column1 = column1;
+ this.row1 = row1;
+ this.column2 = column2;
+ this.row2 = row2;
+ this.component = component;
+ }
+
+ /**
+ * Tests if the given Area overlaps with an another Area.
+ *
+ * @param other
+ * the Another Area that's to be tested for overlap with
+ * this area.
+ * @return <code>true</code> if <code>other</code> overlaps with
+ * this area, <code>false</code> if it doesn't.
+ */
+ public boolean overlaps(Area other) {
+ return column1 <= other.getColumn2() && row1 <= other.getRow2()
+ && column2 >= other.getColumn1() && row2 >= other.getRow1();
+
+ }
+
+ /**
+ * Gets the component connected to the area.
+ *
+ * @return the Component.
+ */
+ public Component getComponent() {
+ return component;
+ }
+
+ /**
+ * Sets the component connected to the area.
+ *
+ * <p>
+ * This function only sets the value in the datastructure and does not
+ * send any events or set parents.
+ * </p>
+ *
+ * @param newComponent
+ * the new connected overriding the existing one.
+ */
+ protected void setComponent(Component newComponent) {
+ component = newComponent;
+ }
+
+ /**
+ * @deprecated Use getColumn1() instead.
+ *
+ * @see com.itmill.toolkit.ui.GridLayout#getColumn1()
+ */
+ public int getX1() {
+ return getColumn1();
+ }
+
+ /**
+ * Gets the column of the top-left corner cell.
+ *
+ * @return the column of the top-left corner cell.
+ */
+ public int getColumn1() {
+ return column1;
+ }
+
+ /**
+ * @deprecated Use getColumn2() instead.
+ *
+ * @see com.itmill.toolkit.ui.GridLayout#getColumn2()
+ */
+ public int getX2() {
+ return getColumn2();
+ }
+
+ /**
+ * Gets the column of the bottom-right corner cell.
+ *
+ * @return the column of the bottom-right corner cell.
+ */
+ public int getColumn2() {
+ return column2;
+ }
+
+ /**
+ * @deprecated Use getRow1() instead.
+ *
+ * @see com.itmill.toolkit.ui.GridLayout#getRow1()
+ */
+ public int getY1() {
+ return getRow1();
+ }
+
+ /**
+ * Gets the row of the top-left corner cell.
+ *
+ * @return the row of the top-left corner cell.
+ */
+ public int getRow1() {
+ return row1;
+ }
+
+ /**
+ * @deprecated Use getRow2() instead.
+ *
+ * @see com.itmill.toolkit.ui.GridLayout#getRow2()
+ */
+ public int getY2() {
+ return getRow2();
+ }
+
+ /**
+ * Gets the row of the bottom-right corner cell.
+ *
+ * @return the row of the bottom-right corner cell.
+ */
+ public int getRow2() {
+ return row2;
+ }
+
+ }
+
+ /**
+ * An <code>Exception</code> object which is thrown when two Items occupy
+ * the same space on a grid.
+ *
+ * @author IT Mill Ltd.
+ * @version
+ * @VERSION@
+ * @since 3.0
+ */
+ public class OverlapsException extends java.lang.RuntimeException {
+
+ /**
+ * Serial generated by eclipse.
+ */
+ private static final long serialVersionUID = 3978144339870101561L;
+
+ private Area existingArea;
+
+ /**
+ * Constructs an <code>OverlapsException</code>.
+ *
+ * @param existingArea
+ */
+ public OverlapsException(Area existingArea) {
+ this.existingArea = existingArea;
+ }
+
+ /**
+ * Gets the area .
+ *
+ * @return the existing area.
+ */
+ public Area getArea() {
+ return existingArea;
+ }
+ }
+
+ /**
+ * An <code>Exception</code> object which is thrown when an area exceeds
+ * the bounds of the grid.
+ *
+ * @author IT Mill Ltd.
+ * @version
+ * @VERSION@
+ * @since 3.0
+ */
+ public class OutOfBoundsException extends java.lang.RuntimeException {
+
+ /**
+ * Serial generated by eclipse.
+ */
+ private static final long serialVersionUID = 3618985589664592694L;
+
+ private Area areaOutOfBounds;
+
+ /**
+ * Constructs an <code>OoutOfBoundsException</code> with the specified
+ * detail message.
+ *
+ * @param areaOutOfBounds
+ */
+ public OutOfBoundsException(Area areaOutOfBounds) {
+ this.areaOutOfBounds = areaOutOfBounds;
+ }
+
+ /**
+ * Gets the area that is out of bounds.
+ *
+ * @return the area out of Bound.
+ */
+ public Area getArea() {
+ return areaOutOfBounds;
+ }
+ }
+
+ /**
+ * Sets the width of the layout.
+ * <p>
+ * <strong>NOTE:</strong> The behaviour of this methdod has changed in
+ * version 5.0. Now this method won't set the number of columns in the grid
+ * like it used to (use {@link #setColumns()} for that). Instead, it sets
+ * the actual visual width of the layout in pixels or in another unit
+ * specified in {@link Sizeable}.UNIT_SYMBOLS.
+ * </p>
+ */
+ public void setWidth(int width) {
+ super.setWidth(width);
+ }
+
+ /**
+ * Gets the width of the layout.
+ * <p>
+ * <strong>NOTE:</strong> The behaviour of this methdod has changed in
+ * version 5.0. Now this method won't return the number of columns in the
+ * grid like it used to (use {@link #getColumns()} for that). Instead, it
+ * returns the actual visual width of the layout in pixels or in another
+ * unit specified in {@link Sizeable}.UNIT_SYMBOLS.
+ * </p>
+ */
+ public int getWidth() {
+ return super.getWidth();
+ }
+
+ /**
+ * Sets the number of columns in the grid. The column count can not be
+ * reduced if there are any areas that would be outside of the shrunk grid.
+ *
+ * @param columns
+ * the new number of columns in the grid.
+ */
+ public void setColumns(int columns) {
+
+ // The the param
+ if (columns < 1) {
+ throw new IllegalArgumentException(
+ "The number of columns and rows in the grid must be at least 1");
+ }
+
+ // In case of no change
+ if (cols == columns) {
+ return;
+ }
+
+ // Checks for overlaps
+ if (cols > columns) {
+ for (Iterator i = areas.iterator(); i.hasNext();) {
+ Area area = (Area) i.next();
+ if (area.column2 >= columns) {
+ throw new OutOfBoundsException(area);
+ }
+ }
+ }
+
+ cols = columns;
+
+ requestRepaint();
+ }
+
+ /**
+ * Get the number of columns in the grid.
+ *
+ * @return the number of columns in the grid.
+ */
+ public final int getColumns() {
+ return cols;
+ }
+
+ /**
+ * Set the height of the layout.
+ * <p>
+ * <strong>NOTE:</strong> The behaviour of this methdod has changed in
+ * version 5.0. Now this method won't set the number of rows in the grid
+ * like it used to (use {@link #setRows()} for that). Instead, it sets the
+ * actual visual height of the layout in pixels or in another unit specified
+ * in {@link Sizeable}.UNIT_SYMBOLS.
+ * </p>
+ */
+ public void setHeight(int height) {
+ super.setHeight(height);
+ }
+
+ /**
+ * Gets the height of the layout.
+ * <p>
+ * <strong>NOTE:</strong> The behaviour of this methdod has changed in
+ * version 5.0. Now this method won't return the number of rows in the grid
+ * like it used to (use {@link #getRows()} for that). Instead, it returns
+ * the actual visual height of the layout in pixels or in another unit
+ * specified in {@link Sizeable}.UNIT_SYMBOLS.
+ * </p>
+ */
+ public int getHeight() {
+ return super.getHeight();
+ }
+
+ /**
+ * Sets the number of rows in the grid. The number of rows can not be
+ * reduced if there are any areas that would be outside of the shrunk grid.
+ *
+ * @param rows
+ * the new number of rows in the grid.
+ */
+ public void setRows(int rows) {
+
+ // The the param
+ if (rows < 1) {
+ throw new IllegalArgumentException(
+ "The number of columns and rows in the grid must be at least 1");
+ }
+
+ // In case of no change
+ if (this.rows == rows) {
+ return;
+ }
+
+ // Checks for overlaps
+ if (this.rows > rows) {
+ for (Iterator i = areas.iterator(); i.hasNext();) {
+ Area area = (Area) i.next();
+ if (area.row2 >= rows) {
+ throw new OutOfBoundsException(area);
+ }
+ }
+ }
+
+ this.rows = rows;
+
+ requestRepaint();
+ }
+
+ /**
+ * Get the number of rows in the grid.
+ *
+ * @return the number of rows in the grid.
+ */
+ public final int getRows() {
+ return rows;
+ }
+
+ /**
+ * Gets the current cursor x-position. The cursor position points the
+ * position for the next component that is added without specifying its
+ * coordinates (grid cell). When the cursor position is occupied, the next
+ * component will be added to first free position after the cursor.
+ *
+ * @return the grid column the Cursor is on.
+ */
+ public int getCursorX() {
+ return cursorX;
+ }
+
+ /**
+ * Gets the current cursor y-position. The cursor position points the
+ * position for the next component that is added without specifying its
+ * coordinates (grid cell). When the cursor position is occupied, the next
+ * component will be added to first free position after the cursor.
+ *
+ * @return the grid row the Cursor is on.
+ */
+ public int getCursorY() {
+ return cursorY;
+ }
+
+ /* Documented in superclass */
+ public void replaceComponent(Component oldComponent, Component newComponent) {
+
+ // Gets the locations
+ Area oldLocation = null;
+ Area newLocation = null;
+ for (Iterator i = areas.iterator(); i.hasNext();) {
+ Area location = (Area) i.next();
+ Component component = location.getComponent();
+ if (component == oldComponent) {
+ oldLocation = location;
+ }
+ if (component == newComponent) {
+ newLocation = location;
+ }
+ }
+
+ if (oldLocation == null) {
+ addComponent(newComponent);
+ } else if (newLocation == null) {
+ removeComponent(oldComponent);
+ addComponent(newComponent, oldLocation.getColumn1(), oldLocation
+ .getRow1(), oldLocation.getColumn2(), oldLocation.getRow2());
+ } else {
+ oldLocation.setComponent(newComponent);
+ newLocation.setComponent(oldComponent);
+ requestRepaint();
+ }
+ }
+
+ /*
+ * Removes all components from this container.
+ *
+ * @see com.itmill.toolkit.ui.ComponentContainer#removeAllComponents()
+ */
+ public void removeAllComponents() {
+ super.removeAllComponents();
+ componentToAlignment = new HashMap();
+ cursorX = 0;
+ cursorY = 0;
+ }
+
+ /**
+ * Set alignment for one contained component in this layout.
+ *
+ * @param childComponent
+ * the component to align within it's layout cell.
+ * @param horizontalAlignment
+ * the horizontal alignment for the child component (left,
+ * center, right).
+ * @param verticalAlignment
+ * the vertical alignment for the child component (top,
+ * center, bottom).
+ */
+ public void setComponentAlignment(Component childComponent,
+ int horizontalAlignment, int verticalAlignment) {
+ componentToAlignment.put(childComponent, new Integer(
+ horizontalAlignment + verticalAlignment));
+ }
+
+ /**
+ * Enable spacing between child components within this layout.
+ *
+ * <p>
+ * <strong>NOTE:</strong> This will only affect spaces between components,
+ * not also all around spacing of the layout (i.e. do not mix this with HTML
+ * Table elements cellspacing-attribute). Use {@link #setMargin(boolean)} to
+ * add extra space around the layout.
+ * </p>
+ *
+ * @param enabled
+ */
+ public void setSpacing(boolean enabled) {
+ spacing = enabled;
+ }
}