summaryrefslogtreecommitdiffstats
path: root/server/src/com/vaadin/ui/GridLayout.java
diff options
context:
space:
mode:
Diffstat (limited to 'server/src/com/vaadin/ui/GridLayout.java')
-rw-r--r--server/src/com/vaadin/ui/GridLayout.java429
1 files changed, 110 insertions, 319 deletions
diff --git a/server/src/com/vaadin/ui/GridLayout.java b/server/src/com/vaadin/ui/GridLayout.java
index 36f4c40a52..be961964e6 100644
--- a/server/src/com/vaadin/ui/GridLayout.java
+++ b/server/src/com/vaadin/ui/GridLayout.java
@@ -27,7 +27,6 @@ import java.util.Map.Entry;
import com.vaadin.event.LayoutEvents.LayoutClickEvent;
import com.vaadin.event.LayoutEvents.LayoutClickListener;
import com.vaadin.event.LayoutEvents.LayoutClickNotifier;
-import com.vaadin.server.LegacyPaint;
import com.vaadin.server.PaintException;
import com.vaadin.server.PaintTarget;
import com.vaadin.shared.Connector;
@@ -36,6 +35,7 @@ import com.vaadin.shared.MouseEventDetails;
import com.vaadin.shared.ui.MarginInfo;
import com.vaadin.shared.ui.gridlayout.GridLayoutServerRpc;
import com.vaadin.shared.ui.gridlayout.GridLayoutState;
+import com.vaadin.shared.ui.gridlayout.GridLayoutState.ChildComponentData;
/**
* A layout where the components are laid out on a grid using cell coordinates.
@@ -88,30 +88,8 @@ public class GridLayout extends AbstractLayout implements
*/
private int cursorY = 0;
- /**
- * Contains all items that are placed on the grid. These are components with
- * grid area definition.
- */
- private final LinkedList<Area> areas = new LinkedList<Area>();
-
- /**
- * Mapping from components to their respective areas.
- */
private final LinkedList<Component> components = new LinkedList<Component>();
- /**
- * Mapping from components to alignments (horizontal + vertical).
- */
- private Map<Component, Alignment> componentToAlignment = new HashMap<Component, Alignment>();
-
- private static final Alignment ALIGNMENT_DEFAULT = Alignment.TOP_LEFT;
-
- /**
- * Has there been rows inserted or deleted in the middle of the layout since
- * the last paint operation.
- */
- private boolean structuralChange = false;
-
private Map<Integer, Float> columnExpandRatio = new HashMap<Integer, Float>();
private Map<Integer, Float> rowExpandRatio = new HashMap<Integer, Float>();
@@ -176,7 +154,7 @@ public class GridLayout extends AbstractLayout implements
* </p>
*
* @param component
- * the component to be added.
+ * the component to be added, not <code>null</code>.
* @param column1
* the column of the upper left corner of the area <code>c</code>
* is supposed to occupy. The leftmost column has index 0.
@@ -228,29 +206,30 @@ public class GridLayout extends AbstractLayout implements
// Inserts the component to right place at the list
// Respect top-down, left-right ordering
// component.setParent(this);
- final Iterator<Area> i = areas.iterator();
+ final Iterator<Component> i = components.iterator();
+ final Map<Connector, ChildComponentData> childDataMap = getState().childData;
int index = 0;
boolean done = false;
while (!done && i.hasNext()) {
- final Area existingArea = i.next();
+ final ChildComponentData existingArea = childDataMap.get(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);
}
+ childDataMap.put(component, area.childData);
+
// Attempt to add to super
try {
super.addComponent(component);
} catch (IllegalArgumentException e) {
- areas.remove(area);
+ childDataMap.remove(component);
components.remove(component);
throw e;
}
@@ -284,11 +263,12 @@ public class GridLayout extends AbstractLayout implements
* if <code>area</code> overlaps with any existing area.
*/
private void checkExistingOverlaps(Area area) throws OverlapsException {
- for (final Iterator<Area> i = areas.iterator(); i.hasNext();) {
- final Area existingArea = i.next();
- if (existingArea.overlaps(area)) {
+ for (Entry<Connector, ChildComponentData> entry : getState().childData
+ .entrySet()) {
+ if (componentsOverlap(entry.getValue(), area.childData)) {
// Component not added, overlaps with existing component
- throw new OverlapsException(existingArea);
+ throw new OverlapsException(new Area(entry.getValue(),
+ (Component) entry.getKey()));
}
}
}
@@ -300,7 +280,7 @@ public class GridLayout extends AbstractLayout implements
* is 1.
*
* @param component
- * the component to be added.
+ * the component to be added, not <code>null</code>.
* @param column
* the column index, starting from 0.
* @param row
@@ -356,10 +336,13 @@ public class GridLayout extends AbstractLayout implements
* grid is automatically extended.
*
* @param component
- * the component to be added.
+ * the component to be added, not <code>null</code>.
*/
@Override
public void addComponent(Component component) {
+ if (component == null) {
+ throw new IllegalArgumentException("Component must not be null");
+ }
// Finds first available place from the grid
Area area;
@@ -399,25 +382,10 @@ public class GridLayout extends AbstractLayout implements
return;
}
- Area area = null;
- for (final Iterator<Area> i = areas.iterator(); area == null
- && i.hasNext();) {
- final Area a = i.next();
- if (a.getComponent() == component) {
- area = a;
- }
- }
-
+ getState().childData.remove(component);
components.remove(component);
- if (area != null) {
- areas.remove(area);
- }
-
- componentToAlignment.remove(component);
super.removeComponent(component);
-
- markAsDirty();
}
/**
@@ -431,10 +399,12 @@ public class GridLayout extends AbstractLayout implements
public void removeComponent(int column, int row) {
// Finds the area
- for (final Iterator<Area> i = areas.iterator(); i.hasNext();) {
- final Area area = i.next();
- if (area.getColumn1() == column && area.getRow1() == row) {
- removeComponent(area.getComponent());
+ for (final Iterator<Component> i = components.iterator(); i.hasNext();) {
+ final Component component = i.next();
+ final ChildComponentData childData = getState().childData
+ .get(component);
+ if (childData.column1 == column && childData.row1 == row) {
+ removeComponent(component);
return;
}
}
@@ -477,23 +447,6 @@ public class GridLayout extends AbstractLayout implements
*/
@Override
public void paintContent(PaintTarget target) throws PaintException {
- // TODO refactor attribute names in future release.
- target.addAttribute("structuralChange", structuralChange);
- structuralChange = false;
-
- // Area iterator
- final Iterator<Area> areaiterator = areas.iterator();
-
- // Current item to be processed (fetch first item)
- Area area = areaiterator.hasNext() ? (Area) areaiterator.next() : null;
-
- // Collects rowspan related information here
- final HashMap<Integer, Integer> cellUsed = new HashMap<Integer, Integer>();
-
- // Empty cell collector
- int emptyCells = 0;
-
- final String[] alignmentsArray = new String[components.size()];
final Integer[] columnExpandRatioArray = new Integer[getColumns()];
final Integer[] rowExpandRatioArray = new Integer[getRows()];
@@ -517,158 +470,24 @@ public class GridLayout extends AbstractLayout implements
}
}
- boolean equallyDividedRows = false;
int realRowExpandRatioSum = 0;
float rowSum = getExpandRatioSum(rowExpandRatio);
if (rowSum == 0) {
// no rows have been expanded
- equallyDividedRows = true;
float equalSize = 1 / (float) getRows();
int myRatio = Math.round(equalSize * 1000);
for (int i = 0; i < getRows(); i++) {
rowExpandRatioArray[i] = myRatio;
}
realRowExpandRatioSum = myRatio * getRows();
- }
-
- int index = 0;
-
- // Iterates every applicable row
- for (int cury = 0; cury < getRows(); cury++) {
- target.startTag("gr");
-
- if (!equallyDividedRows) {
+ } else {
+ for (int cury = 0; cury < getRows(); cury++) {
int myRatio = Math
.round((getRowExpandRatio(cury) / rowSum) * 1000);
rowExpandRatioArray[cury] = myRatio;
realRowExpandRatioSum += myRatio;
-
}
- // Iterates every applicable column
- for (int curx = 0; curx < getColumns(); 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
- final int cols = (area.column2 - area.column1) + 1;
- final 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);
- }
- LegacyPaint.paint(area.getComponent(), target);
-
- alignmentsArray[index++] = String
- .valueOf(getComponentAlignment(area.getComponent())
- .getBitMask());
-
- target.endTag("gc");
-
- // Fetch next item
- if (areaiterator.hasNext()) {
- 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
- final int rowspanDepth = 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(Integer.valueOf(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", getColumns() - 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
+ }
// correct possible rounding error
if (rowExpandRatioArray.length > 0) {
@@ -681,9 +500,6 @@ public class GridLayout extends AbstractLayout implements
target.addAttribute("colExpand", columnExpandRatioArray);
target.addAttribute("rowExpand", rowExpandRatioArray);
- // Add child component alignment info to layout tag
- target.addAttribute("alignments", alignmentsArray);
-
}
private float getExpandRatioSum(Map<Integer, Float> ratioMap) {
@@ -703,11 +519,13 @@ public class GridLayout extends AbstractLayout implements
*/
@Override
public Alignment getComponentAlignment(Component childComponent) {
- Alignment alignment = componentToAlignment.get(childComponent);
- if (alignment == null) {
- return ALIGNMENT_DEFAULT;
+ ChildComponentData childComponentData = getState().childData
+ .get(childComponent);
+ if (childComponentData == null) {
+ throw new IllegalArgumentException(
+ "The given component is not a child of this layout");
} else {
- return alignment;
+ return new Alignment(childComponentData.alignment);
}
}
@@ -728,31 +546,8 @@ public class GridLayout extends AbstractLayout implements
* @since 3.0
*/
public class Area implements Serializable {
-
- /**
- * The column of the upper left corner cell of the area.
- */
- private final 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 final int column2;
-
- /**
- * The row of the lower right corner cell of the area.
- */
- private int row2;
-
- /**
- * Component painted in the area.
- */
- private Component component;
+ private final ChildComponentData childData;
+ private final Component component;
/**
* <p>
@@ -776,10 +571,16 @@ public class GridLayout extends AbstractLayout implements
*/
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;
+ childData = new ChildComponentData();
+ childData.column1 = column1;
+ childData.row1 = row1;
+ childData.column2 = column2;
+ childData.row2 = row2;
+ }
+
+ public Area(ChildComponentData childData, Component component) {
+ this.childData = childData;
this.component = component;
}
@@ -793,9 +594,7 @@ public class GridLayout extends AbstractLayout implements
* this on, <code>false</code> if it does not.
*/
public boolean overlaps(Area other) {
- return column1 <= other.getColumn2() && row1 <= other.getRow2()
- && column2 >= other.getColumn1() && row2 >= other.getRow1();
-
+ return componentsOverlap(childData, other.childData);
}
/**
@@ -808,27 +607,12 @@ public class GridLayout extends AbstractLayout implements
}
/**
- * Sets the component connected to the area.
- *
- * <p>
- * This function only sets the value in the data structure 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;
- }
-
- /**
* Gets the column of the top-left corner cell.
*
* @return the column of the top-left corner cell.
*/
public int getColumn1() {
- return column1;
+ return childData.column1;
}
/**
@@ -837,7 +621,7 @@ public class GridLayout extends AbstractLayout implements
* @return the column of the bottom-right corner cell.
*/
public int getColumn2() {
- return column2;
+ return childData.column2;
}
/**
@@ -846,7 +630,7 @@ public class GridLayout extends AbstractLayout implements
* @return the row of the top-left corner cell.
*/
public int getRow1() {
- return row1;
+ return childData.row1;
}
/**
@@ -855,11 +639,17 @@ public class GridLayout extends AbstractLayout implements
* @return the row of the bottom-right corner cell.
*/
public int getRow2() {
- return row2;
+ return childData.row2;
}
}
+ private static boolean componentsOverlap(ChildComponentData a,
+ ChildComponentData b) {
+ return a.column1 <= b.column2 && a.row1 <= b.row2
+ && a.column2 >= b.column1 && a.row2 >= b.row1;
+ }
+
/**
* Gridlayout does not support laying components on top of each other. An
* <code>OverlapsException</code> is thrown when a component already exists
@@ -895,13 +685,13 @@ public class GridLayout extends AbstractLayout implements
}
sb.append(")");
sb.append(" is already added to ");
- sb.append(existingArea.column1);
+ sb.append(existingArea.childData.column1);
sb.append(",");
- sb.append(existingArea.column1);
+ sb.append(existingArea.childData.column1);
sb.append(",");
- sb.append(existingArea.row1);
+ sb.append(existingArea.childData.row1);
sb.append(",");
- sb.append(existingArea.row2);
+ sb.append(existingArea.childData.row2);
sb.append("(column1, column2, row1, row2).");
return sb.toString();
@@ -970,13 +760,15 @@ public class GridLayout extends AbstractLayout implements
// Checks for overlaps
if (getColumns() > columns) {
- for (final Iterator<Area> i = areas.iterator(); i.hasNext();) {
- final Area area = i.next();
- if (area.column2 >= columns) {
- throw new OutOfBoundsException(area);
+ for (Entry<Connector, ChildComponentData> entry : getState().childData
+ .entrySet()) {
+ if (entry.getValue().column2 >= columns) {
+ throw new OutOfBoundsException(new Area(entry.getValue(),
+ (Component) entry.getKey()));
}
}
}
+ // TODO forget expands for removed columns
getState().columns = columns;
}
@@ -1012,13 +804,15 @@ public class GridLayout extends AbstractLayout implements
// Checks for overlaps
if (getRows() > rows) {
- for (final Iterator<Area> i = areas.iterator(); i.hasNext();) {
- final Area area = i.next();
- if (area.row2 >= rows) {
- throw new OutOfBoundsException(area);
+ for (Entry<Connector, ChildComponentData> entry : getState().childData
+ .entrySet()) {
+ if (entry.getValue().row2 >= rows) {
+ throw new OutOfBoundsException(new Area(entry.getValue(),
+ (Component) entry.getKey()));
}
}
}
+ // TODO forget expands for removed rows
getState().rows = rows;
}
@@ -1090,30 +884,22 @@ public class GridLayout extends AbstractLayout implements
public void replaceComponent(Component oldComponent, Component newComponent) {
// Gets the locations
- Area oldLocation = null;
- Area newLocation = null;
- for (final Iterator<Area> i = areas.iterator(); i.hasNext();) {
- final Area location = i.next();
- final Component component = location.getComponent();
- if (component == oldComponent) {
- oldLocation = location;
- }
- if (component == newComponent) {
- newLocation = location;
- }
- }
+ ChildComponentData oldLocation = getState().childData.get(oldComponent);
+ ChildComponentData newLocation = getState().childData.get(newComponent);
if (oldLocation == null) {
addComponent(newComponent);
} else if (newLocation == null) {
removeComponent(oldComponent);
- addComponent(newComponent, oldLocation.getColumn1(),
- oldLocation.getRow1(), oldLocation.getColumn2(),
- oldLocation.getRow2());
+ addComponent(newComponent, oldLocation.column1, oldLocation.row1,
+ oldLocation.column2, oldLocation.row2);
} else {
- oldLocation.setComponent(newComponent);
- newLocation.setComponent(oldComponent);
- markAsDirty();
+ int oldAlignment = oldLocation.alignment;
+ oldLocation.alignment = newLocation.alignment;
+ newLocation.alignment = oldAlignment;
+
+ getState().childData.put(newComponent, oldLocation);
+ getState().childData.put(oldComponent, newLocation);
}
}
@@ -1125,7 +911,6 @@ public class GridLayout extends AbstractLayout implements
@Override
public void removeAllComponents() {
super.removeAllComponents();
- componentToAlignment = new HashMap<Component, Alignment>();
cursorX = 0;
cursorY = 0;
}
@@ -1133,8 +918,19 @@ public class GridLayout extends AbstractLayout implements
@Override
public void setComponentAlignment(Component childComponent,
Alignment alignment) {
- componentToAlignment.put(childComponent, alignment);
- markAsDirty();
+ ChildComponentData childComponentData = getState().childData
+ .get(childComponent);
+ if (childComponentData == null) {
+ throw new IllegalArgumentException(
+ "Component must be added to layout before using setComponentAlignment()");
+ } else {
+ if (alignment == null) {
+ childComponentData.alignment = GridLayoutState.ALIGNMENT_DEFAULT
+ .getBitMask();
+ } else {
+ childComponentData.alignment = alignment.getBitMask();
+ }
+ }
}
/*
@@ -1170,8 +966,7 @@ public class GridLayout extends AbstractLayout implements
+ " in a gridlayout with height " + getRows());
}
- for (Iterator<Area> i = areas.iterator(); i.hasNext();) {
- Area existingArea = i.next();
+ for (ChildComponentData existingArea : getState().childData.values()) {
// Areas ending below the row needs to be moved down or stretched
if (existingArea.row2 >= row) {
existingArea.row2++;
@@ -1189,7 +984,6 @@ public class GridLayout extends AbstractLayout implements
}
setRows(getRows() + 1);
- structuralChange = true;
markAsDirty();
}
@@ -1222,8 +1016,7 @@ public class GridLayout extends AbstractLayout implements
}
// Shrink or remove areas in the selected row
- for (Iterator<Area> i = areas.iterator(); i.hasNext();) {
- Area existingArea = i.next();
+ for (ChildComponentData existingArea : getState().childData.values()) {
if (existingArea.row2 >= row) {
existingArea.row2--;
@@ -1248,7 +1041,6 @@ public class GridLayout extends AbstractLayout implements
}
}
- structuralChange = true;
markAsDirty();
}
@@ -1339,12 +1131,12 @@ public class GridLayout extends AbstractLayout implements
* @return Component in given cell or null if empty
*/
public Component getComponent(int x, int y) {
- for (final Iterator<Area> iterator = areas.iterator(); iterator
- .hasNext();) {
- final Area area = iterator.next();
- if (area.getColumn1() <= x && x <= area.getColumn2()
- && area.getRow1() <= y && y <= area.getRow2()) {
- return area.getComponent();
+ for (Entry<Connector, ChildComponentData> entry : getState().childData
+ .entrySet()) {
+ ChildComponentData childData = entry.getValue();
+ if (childData.column1 <= x && x <= childData.column2
+ && childData.row1 <= y && y <= childData.row2) {
+ return (Component) entry.getKey();
}
}
return null;
@@ -1360,14 +1152,13 @@ public class GridLayout extends AbstractLayout implements
* the grid
*/
public Area getComponentArea(Component component) {
- for (final Iterator<Area> iterator = areas.iterator(); iterator
- .hasNext();) {
- final Area area = iterator.next();
- if (area.getComponent() == component) {
- return area;
- }
+ ChildComponentData childComponentData = getState().childData
+ .get(component);
+ if (childComponentData == null) {
+ return null;
+ } else {
+ return new Area(childComponentData, component);
}
- return null;
}
@Override