summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTeemu Suo-Anttila <teemusa@vaadin.com>2014-12-04 11:35:14 +0200
committerTeemu Suo-Anttila <teemusa@vaadin.com>2014-12-08 14:06:55 +0200
commite1d1673422cd31ac2fa9e7476ca7f695a0143868 (patch)
tree9cc4bb4cbc4cb1539e7de6194e7b46f5835a95a8
parentaaba0aca69d0093f30d6fa04f2695d8272b7314a (diff)
downloadvaadin-framework-e1d1673422cd31ac2fa9e7476ca7f695a0143868.tar.gz
vaadin-framework-e1d1673422cd31ac2fa9e7476ca7f695a0143868.zip
Flatten Header and Footer API into client-side Grid (#13334)
Change-Id: I70d6d79efbf8d6b14d89d836779cbf16173887fc
-rw-r--r--client/src/com/vaadin/client/ui/grid/Grid.java1060
-rw-r--r--client/src/com/vaadin/client/ui/grid/GridConnector.java86
-rw-r--r--client/src/com/vaadin/client/ui/grid/GridFooter.java74
-rw-r--r--client/src/com/vaadin/client/ui/grid/GridHeader.java150
-rw-r--r--client/src/com/vaadin/client/ui/grid/GridStaticSection.java598
-rw-r--r--uitest/src/com/vaadin/tests/widgetset/client/grid/GridBasicClientFeaturesWidget.java58
-rw-r--r--uitest/src/com/vaadin/tests/widgetset/client/grid/GridClientColumnRendererConnector.java12
7 files changed, 1135 insertions, 903 deletions
diff --git a/client/src/com/vaadin/client/ui/grid/Grid.java b/client/src/com/vaadin/client/ui/grid/Grid.java
index fe14ddef30..ad970b3af1 100644
--- a/client/src/com/vaadin/client/ui/grid/Grid.java
+++ b/client/src/com/vaadin/client/ui/grid/Grid.java
@@ -19,8 +19,10 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
+import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
+import java.util.Map;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;
@@ -49,9 +51,6 @@ import com.vaadin.client.data.DataChangeHandler;
import com.vaadin.client.data.DataSource;
import com.vaadin.client.ui.SubPartAware;
import com.vaadin.client.ui.grid.EditorRow.State;
-import com.vaadin.client.ui.grid.GridFooter.FooterRow;
-import com.vaadin.client.ui.grid.GridHeader.HeaderRow;
-import com.vaadin.client.ui.grid.GridStaticSection.StaticCell;
import com.vaadin.client.ui.grid.events.AbstractGridKeyEventHandler;
import com.vaadin.client.ui.grid.events.BodyKeyDownHandler;
import com.vaadin.client.ui.grid.events.BodyKeyPressHandler;
@@ -159,6 +158,757 @@ public class Grid<T> extends ResizeComposite implements
GridColumn<?, T> column, int columnIndex);
}
+ /**
+ * Abstract base class for Grid header and footer sections.
+ *
+ * @param <ROWTYPE>
+ * the type of the rows in the section
+ */
+ protected abstract static class StaticSection<ROWTYPE extends StaticSection.StaticRow<?>> {
+
+ /**
+ * A header or footer cell. Has a simple textual caption.
+ *
+ */
+ static class StaticCell {
+
+ private Object content = null;
+
+ private int colspan = 1;
+
+ private StaticSection<?> section;
+
+ private GridStaticCellType type = GridStaticCellType.TEXT;
+
+ private String styleName = null;
+
+ /**
+ * Sets the text displayed in this cell.
+ *
+ * @param text
+ * a plain text caption
+ */
+ public void setText(String text) {
+ this.content = text;
+ this.type = GridStaticCellType.TEXT;
+ section.requestSectionRefresh();
+ }
+
+ /**
+ * Returns the text displayed in this cell.
+ *
+ * @return the plain text caption
+ */
+ public String getText() {
+ if (type != GridStaticCellType.TEXT) {
+ throw new IllegalStateException(
+ "Cannot fetch Text from a cell with type " + type);
+ }
+ return (String) content;
+ }
+
+ protected StaticSection<?> getSection() {
+ assert section != null;
+ return section;
+ }
+
+ protected void setSection(StaticSection<?> section) {
+ this.section = section;
+ }
+
+ /**
+ * Returns the amount of columns the cell spans. By default is 1.
+ *
+ * @return The amount of columns the cell spans.
+ */
+ public int getColspan() {
+ return colspan;
+ }
+
+ /**
+ * Sets the amount of columns the cell spans. Must be more or equal
+ * to 1. By default is 1.
+ *
+ * @param colspan
+ * the colspan to set
+ */
+ public void setColspan(int colspan) {
+ if (colspan < 1) {
+ throw new IllegalArgumentException(
+ "Colspan cannot be less than 1");
+ }
+
+ this.colspan = colspan;
+ section.requestSectionRefresh();
+ }
+
+ /**
+ * Returns the html inside the cell.
+ *
+ * @throws IllegalStateException
+ * if trying to retrive HTML from a cell with a type
+ * other than {@link GridStaticCellType#HTML}.
+ * @return the html content of the cell.
+ */
+ public String getHtml() {
+ if (type != GridStaticCellType.HTML) {
+ throw new IllegalStateException(
+ "Cannot fetch HTML from a cell with type " + type);
+ }
+ return (String) content;
+ }
+
+ /**
+ * Sets the content of the cell to the provided html. All previous
+ * content is discarded and the cell type is set to
+ * {@link GridStaticCellType#HTML}.
+ *
+ * @param html
+ * The html content of the cell
+ */
+ public void setHtml(String html) {
+ this.content = html;
+ this.type = GridStaticCellType.HTML;
+ section.requestSectionRefresh();
+ }
+
+ /**
+ * Returns the widget in the cell.
+ *
+ * @throws IllegalStateException
+ * if the cell is not {@link GridStaticCellType#WIDGET}
+ *
+ * @return the widget in the cell
+ */
+ public Widget getWidget() {
+ if (type != GridStaticCellType.WIDGET) {
+ throw new IllegalStateException(
+ "Cannot fetch Widget from a cell with type " + type);
+ }
+ return (Widget) content;
+ }
+
+ /**
+ * Set widget as the content of the cell. The type of the cell
+ * becomes {@link GridStaticCellType#WIDGET}. All previous content
+ * is discarded.
+ *
+ * @param widget
+ * The widget to add to the cell. Should not be
+ * previously attached anywhere (widget.getParent ==
+ * null).
+ */
+ public void setWidget(Widget widget) {
+ this.content = widget;
+ this.type = GridStaticCellType.WIDGET;
+ section.requestSectionRefresh();
+ }
+
+ /**
+ * Returns the type of the cell.
+ *
+ * @return the type of content the cell contains.
+ */
+ public GridStaticCellType getType() {
+ return type;
+ }
+
+ /**
+ * Returns the custom style name for this cell.
+ *
+ * @return the style name or null if no style name has been set
+ */
+ public String getStyleName() {
+ return styleName;
+ }
+
+ /**
+ * Sets a custom style name for this cell.
+ *
+ * @param styleName
+ * the style name to set or null to not use any style
+ * name
+ */
+ public void setStyleName(String styleName) {
+ this.styleName = styleName;
+ section.requestSectionRefresh();
+
+ }
+
+ }
+
+ /**
+ * Abstract base class for Grid header and footer rows.
+ *
+ * @param <CELLTYPE>
+ * the type of the cells in the row
+ */
+ abstract static class StaticRow<CELLTYPE extends StaticCell> {
+
+ private Map<GridColumn<?, ?>, CELLTYPE> cells = new HashMap<GridColumn<?, ?>, CELLTYPE>();
+
+ private StaticSection<?> section;
+
+ /**
+ * Map from set of spanned columns to cell meta data.
+ */
+ private Map<Set<GridColumn<?, ?>>, CELLTYPE> cellGroups = new HashMap<Set<GridColumn<?, ?>>, CELLTYPE>();
+
+ /**
+ * A custom style name for the row or null if none is set.
+ */
+ private String styleName = null;
+
+ /**
+ * Returns the cell on given GridColumn. If the column is merged
+ * returned cell is the cell for the whole group.
+ *
+ * @param column
+ * the column in grid
+ * @return the cell on given column, merged cell for merged columns,
+ * null if not found
+ */
+ public CELLTYPE getCell(GridColumn<?, ?> column) {
+ Set<GridColumn<?, ?>> cellGroup = getCellGroupForColumn(column);
+ if (cellGroup != null) {
+ return cellGroups.get(cellGroup);
+ }
+ return cells.get(column);
+ }
+
+ /**
+ * Merges columns cells in a row
+ *
+ * @param columns
+ * the columns which header should be merged
+ * @return the remaining visible cell after the merge, or the cell
+ * on first column if all are hidden
+ */
+ public CELLTYPE join(GridColumn<?, ?>... columns) {
+ if (columns.length <= 1) {
+ throw new IllegalArgumentException(
+ "You can't merge less than 2 columns together.");
+ }
+
+ HashSet<GridColumn<?, ?>> columnGroup = new HashSet<GridColumn<?, ?>>();
+ for (GridColumn<?, ?> column : columns) {
+ if (!cells.containsKey(column)) {
+ throw new IllegalArgumentException(
+ "Given column does not exists on row " + column);
+ } else if (getCellGroupForColumn(column) != null) {
+ throw new IllegalStateException(
+ "Column is already in a group.");
+ }
+ columnGroup.add(column);
+ }
+
+ CELLTYPE joinedCell = createCell();
+ cellGroups.put(columnGroup, joinedCell);
+ joinedCell.setSection(getSection());
+
+ calculateColspans();
+
+ return joinedCell;
+ }
+
+ /**
+ * Merges columns cells in a row
+ *
+ * @param cells
+ * The cells to merge. Must be from the same row.
+ * @return The remaining visible cell after the merge, or the first
+ * cell if all columns are hidden
+ */
+ public CELLTYPE join(CELLTYPE... cells) {
+ if (cells.length <= 1) {
+ throw new IllegalArgumentException(
+ "You can't merge less than 2 cells together.");
+ }
+
+ GridColumn<?, ?>[] columns = new GridColumn<?, ?>[cells.length];
+
+ int j = 0;
+ for (GridColumn<?, ?> column : this.cells.keySet()) {
+ CELLTYPE cell = this.cells.get(column);
+ if (!this.cells.containsValue(cells[j])) {
+ throw new IllegalArgumentException(
+ "Given cell does not exists on row");
+ } else if (cell.equals(cells[j])) {
+ columns[j++] = column;
+ if (j == cells.length) {
+ break;
+ }
+ }
+ }
+
+ return join(columns);
+ }
+
+ private Set<GridColumn<?, ?>> getCellGroupForColumn(
+ GridColumn<?, ?> column) {
+ for (Set<GridColumn<?, ?>> group : cellGroups.keySet()) {
+ if (group.contains(column)) {
+ return group;
+ }
+ }
+ return null;
+ }
+
+ void calculateColspans() {
+
+ // Reset all cells
+ for (CELLTYPE cell : this.cells.values()) {
+ cell.setColspan(1);
+ }
+
+ List<GridColumn<?, ?>> columnOrder = new ArrayList<GridColumn<?, ?>>(
+ section.grid.getColumns());
+ // Set colspan for grouped cells
+ for (Set<GridColumn<?, ?>> group : cellGroups.keySet()) {
+ if (!checkCellGroupAndOrder(columnOrder, group)) {
+ cellGroups.get(group).setColspan(1);
+ } else {
+ int colSpan = group.size();
+ cellGroups.get(group).setColspan(colSpan);
+ }
+ }
+
+ }
+
+ private boolean checkCellGroupAndOrder(
+ List<GridColumn<?, ?>> columnOrder,
+ Set<GridColumn<?, ?>> cellGroup) {
+ if (!columnOrder.containsAll(cellGroup)) {
+ return false;
+ }
+
+ for (int i = 0; i < columnOrder.size(); ++i) {
+ if (!cellGroup.contains(columnOrder.get(i))) {
+ continue;
+ }
+
+ for (int j = 1; j < cellGroup.size(); ++j) {
+ if (!cellGroup.contains(columnOrder.get(i + j))) {
+ return false;
+ }
+ }
+ return true;
+ }
+ return false;
+ }
+
+ protected void addCell(GridColumn<?, ?> column) {
+ CELLTYPE cell = createCell();
+ cell.setSection(getSection());
+ cells.put(column, cell);
+ }
+
+ protected void removeCell(GridColumn<?, ?> column) {
+ cells.remove(column);
+ }
+
+ protected abstract CELLTYPE createCell();
+
+ protected StaticSection<?> getSection() {
+ return section;
+ }
+
+ protected void setSection(StaticSection<?> section) {
+ this.section = section;
+ }
+
+ /**
+ * Returns the custom style name for this row.
+ *
+ * @return the style name or null if no style name has been set
+ */
+ public String getStyleName() {
+ return styleName;
+ }
+
+ /**
+ * Sets a custom style name for this row.
+ *
+ * @param styleName
+ * the style name to set or null to not use any style
+ * name
+ */
+ public void setStyleName(String styleName) {
+ this.styleName = styleName;
+ section.requestSectionRefresh();
+ }
+ }
+
+ private Grid<?> grid;
+
+ private List<ROWTYPE> rows = new ArrayList<ROWTYPE>();
+
+ private boolean visible = true;
+
+ /**
+ * Creates and returns a new instance of the row type.
+ *
+ * @return the created row
+ */
+ protected abstract ROWTYPE createRow();
+
+ /**
+ * Informs the grid that this section should be re-rendered.
+ * <p>
+ * <b>Note</b> that re-render means calling update() on each cell,
+ * preAttach()/postAttach()/preDetach()/postDetach() is not called as
+ * the cells are not removed from the DOM.
+ */
+ protected abstract void requestSectionRefresh();
+
+ /**
+ * Sets the visibility of the whole section.
+ *
+ * @param visible
+ * true to show this section, false to hide
+ */
+ public void setVisible(boolean visible) {
+ this.visible = visible;
+ requestSectionRefresh();
+ }
+
+ /**
+ * Returns the visibility of this section.
+ *
+ * @return true if visible, false otherwise.
+ */
+ public boolean isVisible() {
+ return visible;
+ }
+
+ /**
+ * Inserts a new row at the given position. Shifts the row currently at
+ * that position and any subsequent rows down (adds one to their
+ * indices).
+ *
+ * @param index
+ * the position at which to insert the row
+ * @return the new row
+ *
+ * @throws IndexOutOfBoundsException
+ * if the index is out of bounds
+ * @see #appendRow()
+ * @see #prependRow()
+ * @see #removeRow(int)
+ * @see #removeRow(StaticRow)
+ */
+ public ROWTYPE addRowAt(int index) {
+ ROWTYPE row = createRow();
+ row.setSection(this);
+ for (int i = 0; i < getGrid().getColumnCount(); ++i) {
+ row.addCell(grid.getColumn(i));
+ }
+ rows.add(index, row);
+
+ requestSectionRefresh();
+ return row;
+ }
+
+ /**
+ * Adds a new row at the top of this section.
+ *
+ * @return the new row
+ * @see #appendRow()
+ * @see #addRowAt(int)
+ * @see #removeRow(int)
+ * @see #removeRow(StaticRow)
+ */
+ public ROWTYPE prependRow() {
+ return addRowAt(0);
+ }
+
+ /**
+ * Adds a new row at the bottom of this section.
+ *
+ * @return the new row
+ * @see #prependRow()
+ * @see #addRowAt(int)
+ * @see #removeRow(int)
+ * @see #removeRow(StaticRow)
+ */
+ public ROWTYPE appendRow() {
+ return addRowAt(rows.size());
+ }
+
+ /**
+ * Removes the row at the given position.
+ *
+ * @param index
+ * the position of the row
+ *
+ * @throws IndexOutOfBoundsException
+ * if the index is out of bounds
+ * @see #addRowAt(int)
+ * @see #appendRow()
+ * @see #prependRow()
+ * @see #removeRow(StaticRow)
+ */
+ public void removeRow(int index) {
+ rows.remove(index);
+ requestSectionRefresh();
+ }
+
+ /**
+ * Removes the given row from the section.
+ *
+ * @param row
+ * the row to be removed
+ *
+ * @throws IllegalArgumentException
+ * if the row does not exist in this section
+ * @see #addRowAt(int)
+ * @see #appendRow()
+ * @see #prependRow()
+ * @see #removeRow(int)
+ */
+ public void removeRow(ROWTYPE row) {
+ try {
+ removeRow(rows.indexOf(row));
+ } catch (IndexOutOfBoundsException e) {
+ throw new IllegalArgumentException(
+ "Section does not contain the given row");
+ }
+ }
+
+ /**
+ * Returns the row at the given position.
+ *
+ * @param index
+ * the position of the row
+ * @return the row with the given index
+ *
+ * @throws IndexOutOfBoundsException
+ * if the index is out of bounds
+ */
+ public ROWTYPE getRow(int index) {
+ try {
+ return rows.get(index);
+ } catch (IndexOutOfBoundsException e) {
+ throw new IllegalArgumentException("Row with index " + index
+ + " does not exist");
+ }
+ }
+
+ /**
+ * Returns the number of rows in this section.
+ *
+ * @return the number of rows
+ */
+ public int getRowCount() {
+ return rows.size();
+ }
+
+ protected List<ROWTYPE> getRows() {
+ return rows;
+ }
+
+ protected int getVisibleRowCount() {
+ return isVisible() ? getRowCount() : 0;
+ }
+
+ protected void addColumn(GridColumn<?, ?> column) {
+ for (ROWTYPE row : rows) {
+ row.addCell(column);
+ }
+ }
+
+ protected void removeColumn(GridColumn<?, ?> column) {
+ for (ROWTYPE row : rows) {
+ row.removeCell(column);
+ }
+ }
+
+ protected void setGrid(Grid<?> grid) {
+ this.grid = grid;
+ }
+
+ protected Grid<?> getGrid() {
+ assert grid != null;
+ return grid;
+ }
+ }
+
+ /**
+ * Represents the header section of a Grid. A header consists of a single
+ * header row containing a header cell for each column. Each cell has a
+ * simple textual caption.
+ */
+ protected static class Header extends StaticSection<HeaderRow> {
+ private HeaderRow defaultRow;
+
+ private boolean markAsDirty = false;
+
+ @Override
+ public void removeRow(int index) {
+ HeaderRow removedRow = getRow(index);
+ super.removeRow(index);
+ if (removedRow == defaultRow) {
+ setDefaultRow(null);
+ }
+ }
+
+ /**
+ * Sets the default row of this header. The default row is a special
+ * header row providing a user interface for sorting columns.
+ *
+ * @param row
+ * the new default row, or null for no default row
+ *
+ * @throws IllegalArgumentException
+ * this header does not contain the row
+ */
+ public void setDefaultRow(HeaderRow row) {
+ if (row == defaultRow) {
+ return;
+ }
+ if (row != null && !getRows().contains(row)) {
+ throw new IllegalArgumentException(
+ "Cannot set a default row that does not exist in the container");
+ }
+ if (defaultRow != null) {
+ defaultRow.setDefault(false);
+ }
+ if (row != null) {
+ row.setDefault(true);
+ }
+ defaultRow = row;
+ requestSectionRefresh();
+ }
+
+ /**
+ * Returns the current default row of this header. The default row is a
+ * special header row providing a user interface for sorting columns.
+ *
+ * @return the default row or null if no default row set
+ */
+ public HeaderRow getDefaultRow() {
+ return defaultRow;
+ }
+
+ @Override
+ protected HeaderRow createRow() {
+ return new HeaderRow();
+ }
+
+ @Override
+ protected void requestSectionRefresh() {
+ markAsDirty = true;
+
+ /*
+ * Defer the refresh so if we multiple times call refreshSection()
+ * (for example when updating cell values) we only get one actual
+ * refresh in the end.
+ */
+ Scheduler.get().scheduleFinally(new Scheduler.ScheduledCommand() {
+
+ @Override
+ public void execute() {
+ if (markAsDirty) {
+ markAsDirty = false;
+ getGrid().refreshHeader();
+ }
+ }
+ });
+ }
+
+ /**
+ * Returns the events consumed by the header
+ *
+ * @return a collection of BrowserEvents
+ */
+ public Collection<String> getConsumedEvents() {
+ return Arrays.asList(BrowserEvents.TOUCHSTART,
+ BrowserEvents.TOUCHMOVE, BrowserEvents.TOUCHEND,
+ BrowserEvents.TOUCHCANCEL, BrowserEvents.CLICK);
+ }
+ }
+
+ /**
+ * A single row in a grid header section.
+ *
+ */
+ public static class HeaderRow extends StaticSection.StaticRow<HeaderCell> {
+
+ private boolean isDefault = false;
+
+ protected void setDefault(boolean isDefault) {
+ this.isDefault = isDefault;
+ }
+
+ public boolean isDefault() {
+ return isDefault;
+ }
+
+ @Override
+ protected HeaderCell createCell() {
+ return new HeaderCell();
+ }
+ }
+
+ /**
+ * A single cell in a grid header row. Has a textual caption.
+ *
+ */
+ public static class HeaderCell extends StaticSection.StaticCell {
+ }
+
+ /**
+ * Represents the footer section of a Grid. The footer is always empty.
+ */
+ protected static class Footer extends StaticSection<FooterRow> {
+ private boolean markAsDirty = false;
+
+ @Override
+ protected FooterRow createRow() {
+ return new FooterRow();
+ }
+
+ @Override
+ protected void requestSectionRefresh() {
+ markAsDirty = true;
+
+ /*
+ * Defer the refresh so if we multiple times call refreshSection()
+ * (for example when updating cell values) we only get one actual
+ * refresh in the end.
+ */
+ Scheduler.get().scheduleFinally(new Scheduler.ScheduledCommand() {
+
+ @Override
+ public void execute() {
+ if (markAsDirty) {
+ markAsDirty = false;
+ getGrid().refreshFooter();
+ }
+ }
+ });
+ }
+ }
+
+ /**
+ * A single cell in a grid Footer row. Has a textual caption.
+ *
+ */
+ public static class FooterCell extends StaticSection.StaticCell {
+ }
+
+ /**
+ * A single row in a grid Footer section.
+ *
+ */
+ public static class FooterRow extends StaticSection.StaticRow<FooterCell> {
+
+ @Override
+ protected FooterCell createCell() {
+ return new FooterCell();
+ }
+ }
+
public static abstract class AbstractGridKeyEvent<HANDLER extends AbstractGridKeyEventHandler>
extends KeyEvent<HANDLER> {
@@ -753,9 +1503,9 @@ public class Grid<T> extends ResizeComposite implements
*/
private Escalator escalator = GWT.create(Escalator.class);
- private final GridHeader header = GWT.create(GridHeader.class);
+ private final Header header = GWT.create(Header.class);
- private final GridFooter footer = GWT.create(GridFooter.class);
+ private final Footer footer = GWT.create(Footer.class);
/**
* List of columns in the grid. Order defines the visible order.
@@ -1320,10 +2070,10 @@ public class Grid<T> extends ResizeComposite implements
protected class StaticSectionUpdater implements EscalatorUpdater {
- private GridStaticSection<?> section;
+ private StaticSection<?> section;
private RowContainer container;
- public StaticSectionUpdater(GridStaticSection<?> section,
+ public StaticSectionUpdater(StaticSection<?> section,
RowContainer container) {
super();
this.section = section;
@@ -1332,15 +2082,14 @@ public class Grid<T> extends ResizeComposite implements
@Override
public void update(Row row, Iterable<FlyweightCell> cellsToUpdate) {
- GridStaticSection.StaticRow<?> staticRow = section.getRow(row
- .getRow());
+ StaticSection.StaticRow<?> staticRow = section.getRow(row.getRow());
final List<GridColumn<?, T>> columns = getColumns();
setCustomStyleName(row.getElement(), staticRow.getStyleName());
for (FlyweightCell cell : cellsToUpdate) {
- final StaticCell metadata = staticRow.getCell(columns.get(cell
- .getColumn()));
+ final StaticSection.StaticCell metadata = staticRow
+ .getCell(columns.get(cell.getColumn()));
// Decorate default row with sorting indicators
if (staticRow instanceof HeaderRow) {
@@ -1426,13 +2175,12 @@ public class Grid<T> extends ResizeComposite implements
@Override
public void postAttach(Row row, Iterable<FlyweightCell> attachedCells) {
- GridStaticSection.StaticRow<?> gridRow = section.getRow(row
- .getRow());
+ StaticSection.StaticRow<?> gridRow = section.getRow(row.getRow());
List<GridColumn<?, T>> columns = getColumns();
for (FlyweightCell cell : attachedCells) {
- StaticCell metadata = gridRow.getCell(columns.get(cell
- .getColumn()));
+ StaticSection.StaticCell metadata = gridRow.getCell(columns
+ .get(cell.getColumn()));
/*
* If the cell contains widgets that are not currently attach
* then attach them now.
@@ -1456,12 +2204,12 @@ public class Grid<T> extends ResizeComposite implements
@Override
public void preDetach(Row row, Iterable<FlyweightCell> cellsToDetach) {
if (section.getRowCount() > row.getRow()) {
- GridStaticSection.StaticRow<?> gridRow = section.getRow(row
+ StaticSection.StaticRow<?> gridRow = section.getRow(row
.getRow());
List<GridColumn<?, T>> columns = getColumns();
for (FlyweightCell cell : cellsToDetach) {
- StaticCell metadata = gridRow.getCell(columns.get(cell
- .getColumn()));
+ StaticSection.StaticCell metadata = gridRow.getCell(columns
+ .get(cell.getColumn()));
if (GridStaticCellType.WIDGET.equals(metadata.getType())
&& metadata.getWidget().isAttached()) {
@@ -1642,8 +2390,7 @@ public class Grid<T> extends ResizeComposite implements
* <code>true</code> if we refreshing the header, else assumed
* the footer
*/
- private void refreshRowContainer(RowContainer rows,
- GridStaticSection<?> section) {
+ private void refreshRowContainer(RowContainer rows, StaticSection<?> section) {
// Add or Remove rows on demand
int rowDiff = section.getVisibleRowCount() - rows.getRowCount();
@@ -1861,19 +2608,288 @@ public class Grid<T> extends ResizeComposite implements
*
* @return the header
*/
- public GridHeader getHeader() {
+ protected Header getHeader() {
return header;
}
/**
+ * Gets the header row at given index.
+ *
+ * @param rowIndex
+ * 0 based index for row. Counted from top to bottom
+ * @return header row at given index
+ * @throws IllegalArgumentException
+ * if no row exists at given index
+ */
+ public HeaderRow getHeaderRow(int rowIndex) {
+ return header.getRow(rowIndex);
+ }
+
+ /**
+ * Inserts a new row at the given position to the header section. Shifts the
+ * row currently at that position and any subsequent rows down (adds one to
+ * their indices).
+ *
+ * @param index
+ * the position at which to insert the row
+ * @return the new row
+ *
+ * @throws IllegalArgumentException
+ * if the index is less than 0 or greater than row count
+ * @see #appendHeaderRow()
+ * @see #prependHeaderRow()
+ * @see #removeHeaderRow(HeaderRow)
+ * @see #removeHeaderRow(int)
+ */
+ public HeaderRow addHeaderRowAt(int index) {
+ return header.addRowAt(index);
+ }
+
+ /**
+ * Adds a new row at the bottom of the header section.
+ *
+ * @return the new row
+ * @see #prependHeaderRow()
+ * @see #addHeaderRowAt(int)
+ * @see #removeHeaderRow(HeaderRow)
+ * @see #removeHeaderRow(int)
+ */
+ public HeaderRow appendHeaderRow() {
+ return header.appendRow();
+ }
+
+ /**
+ * Returns the current default row of the header section. The default row is
+ * a special header row providing a user interface for sorting columns.
+ * Setting a header text for column updates cells in the default header.
+ *
+ * @return the default row or null if no default row set
+ */
+ public HeaderRow getDefaultHeaderRow() {
+ return header.getDefaultRow();
+ }
+
+ /**
+ * Gets the row count for the header section.
+ *
+ * @return row count
+ */
+ public int getHeaderRowCount() {
+ return header.getRowCount();
+ }
+
+ /**
+ * Adds a new row at the top of the header section.
+ *
+ * @return the new row
+ * @see #appendHeaderRow()
+ * @see #addHeaderRowAt(int)
+ * @see #removeHeaderRow(HeaderRow)
+ * @see #removeHeaderRow(int)
+ */
+ public HeaderRow prependHeaderRow() {
+ return header.prependRow();
+ }
+
+ /**
+ * Removes the given row from the header section.
+ *
+ * @param row
+ * the row to be removed
+ *
+ * @throws IllegalArgumentException
+ * if the row does not exist in this section
+ * @see #removeHeaderRow(int)
+ * @see #addHeaderRowAt(int)
+ * @see #appendHeaderRow()
+ * @see #prependHeaderRow()
+ */
+ public void removeHeaderRow(HeaderRow row) {
+ header.removeRow(row);
+ }
+
+ /**
+ * Removes the row at the given position from the header section.
+ *
+ * @param index
+ * the position of the row
+ *
+ * @throws IllegalArgumentException
+ * if no row exists at given index
+ * @see #removeHeaderRow(HeaderRow)
+ * @see #addHeaderRowAt(int)
+ * @see #appendHeaderRow()
+ * @see #prependHeaderRow()
+ */
+ public void removeHeaderRow(int rowIndex) {
+ header.removeRow(rowIndex);
+ }
+
+ /**
+ * Sets the default row of the header. The default row is a special header
+ * row providing a user interface for sorting columns.
+ *
+ * @param row
+ * the new default row, or null for no default row
+ *
+ * @throws IllegalArgumentException
+ * header does not contain the row
+ */
+ public void setDefaultHeaderRow(HeaderRow row) {
+ header.setDefaultRow(row);
+ }
+
+ /**
+ * Sets the visibility of the header section.
+ *
+ * @param visible
+ * true to show header section, false to hide
+ */
+ public void setHeaderVisible(boolean visible) {
+ header.setVisible(visible);
+ }
+
+ /**
+ * Returns the visibility of the header section.
+ *
+ * @return true if visible, false otherwise.
+ */
+ public boolean isHeaderVisible() {
+ return header.isVisible();
+ }
+
+ /* Grid Footers */
+
+ /**
* Returns the footer section of this grid. The default footer is empty.
*
* @return the footer
*/
- public GridFooter getFooter() {
+ protected Footer getFooter() {
return footer;
}
+ /**
+ * Gets the footer row at given index.
+ *
+ * @param rowIndex
+ * 0 based index for row. Counted from top to bottom
+ * @return footer row at given index
+ * @throws IllegalArgumentException
+ * if no row exists at given index
+ */
+ public FooterRow getFooterRow(int rowIndex) {
+ return footer.getRow(rowIndex);
+ }
+
+ /**
+ * Inserts a new row at the given position to the footer section. Shifts the
+ * row currently at that position and any subsequent rows down (adds one to
+ * their indices).
+ *
+ * @param index
+ * the position at which to insert the row
+ * @return the new row
+ *
+ * @throws IllegalArgumentException
+ * if the index is less than 0 or greater than row count
+ * @see #appendFooterRow()
+ * @see #prependFooterRow()
+ * @see #removeFooterRow(FooterRow)
+ * @see #removeFooterRow(int)
+ */
+ public FooterRow addFooterRowAt(int index) {
+ return footer.addRowAt(index);
+ }
+
+ /**
+ * Adds a new row at the bottom of the footer section.
+ *
+ * @return the new row
+ * @see #prependFooterRow()
+ * @see #addFooterRowAt(int)
+ * @see #removeFooterRow(FooterRow)
+ * @see #removeFooterRow(int)
+ */
+ public FooterRow appendFooterRow() {
+ return footer.appendRow();
+ }
+
+ /**
+ * Gets the row count for the footer.
+ *
+ * @return row count
+ */
+ public int getFooterRowCount() {
+ return footer.getRowCount();
+ }
+
+ /**
+ * Adds a new row at the top of the footer section.
+ *
+ * @return the new row
+ * @see #appendFooterRow()
+ * @see #addFooterRowAt(int)
+ * @see #removeFooterRow(FooterRow)
+ * @see #removeFooterRow(int)
+ */
+ public FooterRow prependFooterRow() {
+ return footer.prependRow();
+ }
+
+ /**
+ * Removes the given row from the footer section.
+ *
+ * @param row
+ * the row to be removed
+ *
+ * @throws IllegalArgumentException
+ * if the row does not exist in this section
+ * @see #removeFooterRow(int)
+ * @see #addFooterRowAt(int)
+ * @see #appendFooterRow()
+ * @see #prependFooterRow()
+ */
+ public void removeFooterRow(FooterRow row) {
+ footer.removeRow(row);
+ }
+
+ /**
+ * Removes the row at the given position from the footer section.
+ *
+ * @param index
+ * the position of the row
+ *
+ * @throws IllegalArgumentException
+ * if no row exists at given index
+ * @see #removeFooterRow(FooterRow)
+ * @see #addFooterRowAt(int)
+ * @see #appendFooterRow()
+ * @see #prependFooterRow()
+ */
+ public void removeFooterRow(int rowIndex) {
+ footer.removeRow(rowIndex);
+ }
+
+ /**
+ * Sets the visibility of the footer section.
+ *
+ * @param visible
+ * true to show footer section, false to hide
+ */
+ public void setFooterVisible(boolean visible) {
+ footer.setVisible(visible);
+ }
+
+ /**
+ * Returns the visibility of the footer section.
+ *
+ * @return true if visible, false otherwise.
+ */
+ public boolean isFooterVisible() {
+ return footer.isVisible();
+ }
+
public EditorRow<T> getEditorRow() {
return editorRow;
}
diff --git a/client/src/com/vaadin/client/ui/grid/GridConnector.java b/client/src/com/vaadin/client/ui/grid/GridConnector.java
index ae78860d79..ff55106175 100644
--- a/client/src/com/vaadin/client/ui/grid/GridConnector.java
+++ b/client/src/com/vaadin/client/ui/grid/GridConnector.java
@@ -42,7 +42,10 @@ import com.vaadin.client.ui.AbstractFieldConnector;
import com.vaadin.client.ui.AbstractHasComponentsConnector;
import com.vaadin.client.ui.SimpleManagedLayout;
import com.vaadin.client.ui.grid.Grid.CellStyleGenerator;
-import com.vaadin.client.ui.grid.GridHeader.HeaderRow;
+import com.vaadin.client.ui.grid.Grid.FooterCell;
+import com.vaadin.client.ui.grid.Grid.FooterRow;
+import com.vaadin.client.ui.grid.Grid.HeaderCell;
+import com.vaadin.client.ui.grid.Grid.HeaderRow;
import com.vaadin.client.ui.grid.renderers.AbstractRendererConnector;
import com.vaadin.client.ui.grid.selection.AbstractRowHandleSelectionModel;
import com.vaadin.client.ui.grid.selection.SelectionChangeEvent;
@@ -442,13 +445,11 @@ public class GridConnector extends AbstractHasComponentsConnector implements
}
if (stateChangeEvent.hasPropertyChanged("header")) {
- updateSectionFromState(getWidget().getHeader(),
- getState().header);
+ updateHeaderFromState(getState().header);
}
if (stateChangeEvent.hasPropertyChanged("footer")) {
- updateSectionFromState(getWidget().getFooter(),
- getState().footer);
+ updateFooterFromState(getState().footer);
}
if (stateChangeEvent.hasPropertyChanged("editorRowEnabled")) {
@@ -485,21 +486,20 @@ public class GridConnector extends AbstractHasComponentsConnector implements
return true;
}
- private void updateSectionFromState(GridStaticSection<?> section,
- GridStaticSectionState state) {
+ private void updateHeaderFromState(GridStaticSectionState state) {
+ getWidget().setHeaderVisible(state.visible);
- while (section.getRowCount() != 0) {
- section.removeRow(0);
+ while (getWidget().getHeaderRowCount() > 0) {
+ getWidget().removeHeaderRow(0);
}
for (RowState rowState : state.rows) {
- GridStaticSection.StaticRow<?> row = section.appendRow();
+ HeaderRow row = getWidget().appendHeaderRow();
for (CellState cellState : rowState.cells) {
CustomGridColumn column = columnIdToColumn
.get(cellState.columnId);
- GridStaticSection.StaticCell cell = row.getCell(column);
- updateStaticCellFromState(cell, cellState);
+ updateHeaderCellFromState(row.getCell(column), cellState);
}
for (Set<String> group : rowState.cellGroups.keySet()) {
@@ -513,23 +513,71 @@ public class GridConnector extends AbstractHasComponentsConnector implements
}
// Set state to be the same as first in group.
- updateStaticCellFromState(row.join(columns), cellState);
+ updateHeaderCellFromState(row.join(columns), cellState);
}
- if (section instanceof GridHeader && rowState.defaultRow) {
- ((GridHeader) section).setDefaultRow((HeaderRow) row);
+ if (rowState.defaultRow) {
+ getWidget().setDefaultHeaderRow(row);
}
row.setStyleName(rowState.styleName);
}
+ }
+
+ private void updateHeaderCellFromState(HeaderCell cell, CellState cellState) {
+ switch (cellState.type) {
+ case TEXT:
+ cell.setText(cellState.text);
+ break;
+ case HTML:
+ cell.setHtml(cellState.html);
+ break;
+ case WIDGET:
+ ComponentConnector connector = (ComponentConnector) cellState.connector;
+ cell.setWidget(connector.getWidget());
+ break;
+ default:
+ throw new IllegalStateException("unexpected cell type: "
+ + cellState.type);
+ }
+ cell.setStyleName(cellState.styleName);
+ }
- section.setVisible(state.visible);
+ private void updateFooterFromState(GridStaticSectionState state) {
+ getWidget().setFooterVisible(state.visible);
- section.requestSectionRefresh();
+ while (getWidget().getFooterRowCount() > 0) {
+ getWidget().removeFooterRow(0);
+ }
+
+ for (RowState rowState : state.rows) {
+ FooterRow row = getWidget().appendFooterRow();
+
+ for (CellState cellState : rowState.cells) {
+ CustomGridColumn column = columnIdToColumn
+ .get(cellState.columnId);
+ updateFooterCellFromState(row.getCell(column), cellState);
+ }
+
+ for (Set<String> group : rowState.cellGroups.keySet()) {
+ GridColumn<?, ?>[] columns = new GridColumn<?, ?>[group.size()];
+ CellState cellState = rowState.cellGroups.get(group);
+
+ int i = 0;
+ for (String columnId : group) {
+ columns[i] = columnIdToColumn.get(columnId);
+ i++;
+ }
+
+ // Set state to be the same as first in group.
+ updateFooterCellFromState(row.join(columns), cellState);
+ }
+
+ row.setStyleName(rowState.styleName);
+ }
}
- private void updateStaticCellFromState(GridStaticSection.StaticCell cell,
- CellState cellState) {
+ private void updateFooterCellFromState(FooterCell cell, CellState cellState) {
switch (cellState.type) {
case TEXT:
cell.setText(cellState.text);
diff --git a/client/src/com/vaadin/client/ui/grid/GridFooter.java b/client/src/com/vaadin/client/ui/grid/GridFooter.java
deleted file mode 100644
index e798139b9a..0000000000
--- a/client/src/com/vaadin/client/ui/grid/GridFooter.java
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * Copyright 2000-2014 Vaadin Ltd.
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not
- * use this file except in compliance with the License. You may obtain a copy of
- * the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations under
- * the License.
- */
-package com.vaadin.client.ui.grid;
-
-import com.google.gwt.core.client.Scheduler;
-
-/**
- * Represents the footer section of a Grid. The footer is always empty.
- *
- * @since
- * @author Vaadin Ltd
- */
-public class GridFooter extends GridStaticSection<GridFooter.FooterRow> {
-
- /**
- * A single row in a grid Footer section.
- *
- */
- public class FooterRow extends GridStaticSection.StaticRow<FooterCell> {
-
- @Override
- protected FooterCell createCell() {
- return new FooterCell();
- }
- }
-
- /**
- * A single cell in a grid Footer row. Has a textual caption.
- *
- */
- public class FooterCell extends GridStaticSection.StaticCell {
- }
-
- private boolean markAsDirty = false;
-
- @Override
- protected FooterRow createRow() {
- return new FooterRow();
- }
-
- @Override
- protected void requestSectionRefresh() {
- markAsDirty = true;
-
- /*
- * Defer the refresh so if we multiple times call refreshSection() (for
- * example when updating cell values) we only get one actual refresh in
- * the end.
- */
- Scheduler.get().scheduleFinally(new Scheduler.ScheduledCommand() {
-
- @Override
- public void execute() {
- if (markAsDirty) {
- markAsDirty = false;
- getGrid().refreshFooter();
- }
- }
- });
- }
-}
diff --git a/client/src/com/vaadin/client/ui/grid/GridHeader.java b/client/src/com/vaadin/client/ui/grid/GridHeader.java
deleted file mode 100644
index 2867ae4d1c..0000000000
--- a/client/src/com/vaadin/client/ui/grid/GridHeader.java
+++ /dev/null
@@ -1,150 +0,0 @@
-/*
- * Copyright 2000-2014 Vaadin Ltd.
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not
- * use this file except in compliance with the License. You may obtain a copy of
- * the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations under
- * the License.
- */
-package com.vaadin.client.ui.grid;
-
-import java.util.Arrays;
-import java.util.Collection;
-
-import com.google.gwt.core.client.Scheduler;
-import com.google.gwt.dom.client.BrowserEvents;
-
-/**
- * Represents the header section of a Grid. A header consists of a single header
- * row containing a header cell for each column. Each cell has a simple textual
- * caption.
- *
- * @since
- * @author Vaadin Ltd
- */
-public class GridHeader extends GridStaticSection<GridHeader.HeaderRow> {
-
- /**
- * A single row in a grid header section.
- *
- */
- public class HeaderRow extends GridStaticSection.StaticRow<HeaderCell> {
-
- private boolean isDefault = false;
-
- protected void setDefault(boolean isDefault) {
- this.isDefault = isDefault;
- }
-
- public boolean isDefault() {
- return isDefault;
- }
-
- @Override
- protected HeaderCell createCell() {
- return new HeaderCell();
- }
- }
-
- /**
- * A single cell in a grid header row. Has a textual caption.
- *
- */
- public class HeaderCell extends GridStaticSection.StaticCell {
- }
-
- private HeaderRow defaultRow;
-
- private boolean markAsDirty = false;
-
- @Override
- public void removeRow(int index) {
- HeaderRow removedRow = getRow(index);
- super.removeRow(index);
- if (removedRow == defaultRow) {
- setDefaultRow(null);
- }
- }
-
- /**
- * Sets the default row of this header. The default row is a special header
- * row providing a user interface for sorting columns.
- *
- * @param row
- * the new default row, or null for no default row
- *
- * @throws IllegalArgumentException
- * this header does not contain the row
- */
- public void setDefaultRow(HeaderRow row) {
- if (row == defaultRow) {
- return;
- }
- if (row != null && !getRows().contains(row)) {
- throw new IllegalArgumentException(
- "Cannot set a default row that does not exist in the container");
- }
- if (defaultRow != null) {
- defaultRow.setDefault(false);
- }
- if (row != null) {
- row.setDefault(true);
- }
- defaultRow = row;
- requestSectionRefresh();
- }
-
- /**
- * Returns the current default row of this header. The default row is a
- * special header row providing a user interface for sorting columns.
- *
- * @return the default row or null if no default row set
- */
- public HeaderRow getDefaultRow() {
- return defaultRow;
- }
-
- @Override
- protected HeaderRow createRow() {
- return new HeaderRow();
- }
-
- @Override
- protected void requestSectionRefresh() {
- markAsDirty = true;
-
- /*
- * Defer the refresh so if we multiple times call refreshSection() (for
- * example when updating cell values) we only get one actual refresh in
- * the end.
- */
- Scheduler.get().scheduleFinally(new Scheduler.ScheduledCommand() {
-
- @Override
- public void execute() {
- if (markAsDirty) {
- markAsDirty = false;
- getGrid().refreshHeader();
- }
- }
- });
- }
-
- /**
- * Returns the events consumed by the header
- *
- * @return a collection of BrowserEvents
- */
- public Collection<String> getConsumedEvents() {
- return Arrays.asList(BrowserEvents.TOUCHSTART, BrowserEvents.TOUCHMOVE,
- BrowserEvents.TOUCHEND, BrowserEvents.TOUCHCANCEL,
- BrowserEvents.CLICK);
- }
-}
diff --git a/client/src/com/vaadin/client/ui/grid/GridStaticSection.java b/client/src/com/vaadin/client/ui/grid/GridStaticSection.java
deleted file mode 100644
index 228ff73894..0000000000
--- a/client/src/com/vaadin/client/ui/grid/GridStaticSection.java
+++ /dev/null
@@ -1,598 +0,0 @@
-/*
- * Copyright 2000-2014 Vaadin Ltd.
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not
- * use this file except in compliance with the License. You may obtain a copy of
- * the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations under
- * the License.
- */
-package com.vaadin.client.ui.grid;
-
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-import com.google.gwt.user.client.ui.Widget;
-import com.vaadin.shared.ui.grid.GridStaticCellType;
-
-/**
- * Abstract base class for Grid header and footer sections.
- *
- * @since
- * @author Vaadin Ltd
- * @param <ROWTYPE>
- * the type of the rows in the section
- */
-abstract class GridStaticSection<ROWTYPE extends GridStaticSection.StaticRow<?>> {
-
- /**
- * A header or footer cell. Has a simple textual caption.
- *
- */
- static class StaticCell {
-
- private Object content = null;
-
- private int colspan = 1;
-
- private GridStaticSection<?> section;
-
- private GridStaticCellType type = GridStaticCellType.TEXT;
-
- private String styleName = null;
-
- /**
- * Sets the text displayed in this cell.
- *
- * @param text
- * a plain text caption
- */
- public void setText(String text) {
- this.content = text;
- this.type = GridStaticCellType.TEXT;
- section.requestSectionRefresh();
- }
-
- /**
- * Returns the text displayed in this cell.
- *
- * @return the plain text caption
- */
- public String getText() {
- if (type != GridStaticCellType.TEXT) {
- throw new IllegalStateException(
- "Cannot fetch Text from a cell with type " + type);
- }
- return (String) content;
- }
-
- protected GridStaticSection<?> getSection() {
- assert section != null;
- return section;
- }
-
- protected void setSection(GridStaticSection<?> section) {
- this.section = section;
- }
-
- /**
- * Returns the amount of columns the cell spans. By default is 1.
- *
- * @return The amount of columns the cell spans.
- */
- public int getColspan() {
- return colspan;
- }
-
- /**
- * Sets the amount of columns the cell spans. Must be more or equal to
- * 1. By default is 1.
- *
- * @param colspan
- * the colspan to set
- */
- public void setColspan(int colspan) {
- if (colspan < 1) {
- throw new IllegalArgumentException(
- "Colspan cannot be less than 1");
- }
-
- this.colspan = colspan;
- section.requestSectionRefresh();
- }
-
- /**
- * Returns the html inside the cell.
- *
- * @throws IllegalStateException
- * if trying to retrive HTML from a cell with a type other
- * than {@link Type#HTML}.
- * @return the html content of the cell.
- */
- public String getHtml() {
- if (type != GridStaticCellType.HTML) {
- throw new IllegalStateException(
- "Cannot fetch HTML from a cell with type " + type);
- }
- return (String) content;
- }
-
- /**
- * Sets the content of the cell to the provided html. All previous
- * content is discarded and the cell type is set to {@link Type#HTML}.
- *
- * @param html
- * The html content of the cell
- */
- public void setHtml(String html) {
- this.content = html;
- this.type = GridStaticCellType.HTML;
- section.requestSectionRefresh();
- }
-
- /**
- * Returns the widget in the cell.
- *
- * @throws IllegalStateException
- * if the cell is not {@link Type#WIDGET}
- *
- * @return the widget in the cell
- */
- public Widget getWidget() {
- if (type != GridStaticCellType.WIDGET) {
- throw new IllegalStateException(
- "Cannot fetch Widget from a cell with type " + type);
- }
- return (Widget) content;
- }
-
- /**
- * Set widget as the content of the cell. The type of the cell becomes
- * {@link Type#WIDGET}. All previous content is discarded.
- *
- * @param widget
- * The widget to add to the cell. Should not be previously
- * attached anywhere (widget.getParent == null).
- */
- public void setWidget(Widget widget) {
- this.content = widget;
- this.type = GridStaticCellType.WIDGET;
- section.requestSectionRefresh();
- }
-
- /**
- * Returns the type of the cell.
- *
- * @return the type of content the cell contains.
- */
- public GridStaticCellType getType() {
- return type;
- }
-
- /**
- * Returns the custom style name for this cell.
- *
- * @return the style name or null if no style name has been set
- */
- public String getStyleName() {
- return styleName;
- }
-
- /**
- * Sets a custom style name for this cell.
- *
- * @param styleName
- * the style name to set or null to not use any style name
- */
- public void setStyleName(String styleName) {
- this.styleName = styleName;
- section.requestSectionRefresh();
-
- }
-
- }
-
- /**
- * Abstract base class for Grid header and footer rows.
- *
- * @param <CELLTYPE>
- * the type of the cells in the row
- */
- abstract static class StaticRow<CELLTYPE extends StaticCell> {
-
- private Map<GridColumn<?, ?>, CELLTYPE> cells = new HashMap<GridColumn<?, ?>, CELLTYPE>();
-
- private GridStaticSection<?> section;
-
- /**
- * Map from set of spanned columns to cell meta data.
- */
- private Map<Set<GridColumn<?, ?>>, CELLTYPE> cellGroups = new HashMap<Set<GridColumn<?, ?>>, CELLTYPE>();
-
- /**
- * A custom style name for the row or null if none is set.
- */
- private String styleName = null;
-
- /**
- * Returns the cell on given GridColumn. If the column is merged
- * returned cell is the cell for the whole group.
- *
- * @param column
- * the column in grid
- * @return the cell on given column, merged cell for merged columns,
- * null if not found
- */
- public CELLTYPE getCell(GridColumn<?, ?> column) {
- Set<GridColumn<?, ?>> cellGroup = getCellGroupForColumn(column);
- if (cellGroup != null) {
- return cellGroups.get(cellGroup);
- }
- return cells.get(column);
- }
-
- /**
- * Merges columns cells in a row
- *
- * @param columns
- * the columns which header should be merged
- * @return the remaining visible cell after the merge, or the cell on
- * first column if all are hidden
- */
- public CELLTYPE join(GridColumn<?, ?>... columns) {
- if (columns.length <= 1) {
- throw new IllegalArgumentException(
- "You can't merge less than 2 columns together.");
- }
-
- HashSet<GridColumn<?, ?>> columnGroup = new HashSet<GridColumn<?, ?>>();
- for (GridColumn<?, ?> column : columns) {
- if (!cells.containsKey(column)) {
- throw new IllegalArgumentException(
- "Given column does not exists on row " + column);
- } else if (getCellGroupForColumn(column) != null) {
- throw new IllegalStateException(
- "Column is already in a group.");
- }
- columnGroup.add(column);
- }
-
- CELLTYPE joinedCell = createCell();
- cellGroups.put(columnGroup, joinedCell);
- joinedCell.setSection(getSection());
-
- calculateColspans();
-
- return joinedCell;
- }
-
- /**
- * Merges columns cells in a row
- *
- * @param cells
- * The cells to merge. Must be from the same row.
- * @return The remaining visible cell after the merge, or the first cell
- * if all columns are hidden
- */
- public CELLTYPE join(CELLTYPE... cells) {
- if (cells.length <= 1) {
- throw new IllegalArgumentException(
- "You can't merge less than 2 cells together.");
- }
-
- GridColumn<?, ?>[] columns = new GridColumn<?, ?>[cells.length];
-
- int j = 0;
- for (GridColumn<?, ?> column : this.cells.keySet()) {
- CELLTYPE cell = this.cells.get(column);
- if (!this.cells.containsValue(cells[j])) {
- throw new IllegalArgumentException(
- "Given cell does not exists on row");
- } else if (cell.equals(cells[j])) {
- columns[j++] = column;
- if (j == cells.length) {
- break;
- }
- }
- }
-
- return join(columns);
- }
-
- private Set<GridColumn<?, ?>> getCellGroupForColumn(
- GridColumn<?, ?> column) {
- for (Set<GridColumn<?, ?>> group : cellGroups.keySet()) {
- if (group.contains(column)) {
- return group;
- }
- }
- return null;
- }
-
- void calculateColspans() {
-
- // Reset all cells
- for (CELLTYPE cell : this.cells.values()) {
- cell.setColspan(1);
- }
-
- List<GridColumn<?, ?>> columnOrder = new ArrayList<GridColumn<?, ?>>(
- section.grid.getColumns());
- // Set colspan for grouped cells
- for (Set<GridColumn<?, ?>> group : cellGroups.keySet()) {
- if (!checkCellGroupAndOrder(columnOrder, group)) {
- cellGroups.get(group).setColspan(1);
- } else {
- int colSpan = group.size();
- cellGroups.get(group).setColspan(colSpan);
- }
- }
-
- }
-
- private boolean checkCellGroupAndOrder(
- List<GridColumn<?, ?>> columnOrder,
- Set<GridColumn<?, ?>> cellGroup) {
- if (!columnOrder.containsAll(cellGroup)) {
- return false;
- }
-
- for (int i = 0; i < columnOrder.size(); ++i) {
- if (!cellGroup.contains(columnOrder.get(i))) {
- continue;
- }
-
- for (int j = 1; j < cellGroup.size(); ++j) {
- if (!cellGroup.contains(columnOrder.get(i + j))) {
- return false;
- }
- }
- return true;
- }
- return false;
- }
-
- protected void addCell(GridColumn<?, ?> column) {
- CELLTYPE cell = createCell();
- cell.setSection(getSection());
- cells.put(column, cell);
- }
-
- protected void removeCell(GridColumn<?, ?> column) {
- cells.remove(column);
- }
-
- protected abstract CELLTYPE createCell();
-
- protected GridStaticSection<?> getSection() {
- return section;
- }
-
- protected void setSection(GridStaticSection<?> section) {
- this.section = section;
- }
-
- /**
- * Returns the custom style name for this row.
- *
- * @return the style name or null if no style name has been set
- */
- public String getStyleName() {
- return styleName;
- }
-
- /**
- * Sets a custom style name for this row.
- *
- * @param styleName
- * the style name to set or null to not use any style name
- */
- public void setStyleName(String styleName) {
- this.styleName = styleName;
- section.requestSectionRefresh();
- }
-
- }
-
- private Grid<?> grid;
-
- private List<ROWTYPE> rows = new ArrayList<ROWTYPE>();
-
- private boolean visible = true;
-
- /**
- * Creates and returns a new instance of the row type.
- *
- * @return the created row
- */
- protected abstract ROWTYPE createRow();
-
- /**
- * Informs the grid that this section should be re-rendered.
- * <p>
- * <b>Note</b> that re-render means calling update() on each cell,
- * preAttach()/postAttach()/preDetach()/postDetach() is not called as the
- * cells are not removed from the DOM.
- */
- protected abstract void requestSectionRefresh();
-
- /**
- * Sets the visibility of the whole section.
- *
- * @param visible
- * true to show this section, false to hide
- */
- public void setVisible(boolean visible) {
- this.visible = visible;
- requestSectionRefresh();
- }
-
- /**
- * Returns the visibility of this section.
- *
- * @return true if visible, false otherwise.
- */
- public boolean isVisible() {
- return visible;
- }
-
- /**
- * Inserts a new row at the given position. Shifts the row currently at that
- * position and any subsequent rows down (adds one to their indices).
- *
- * @param index
- * the position at which to insert the row
- * @return the new row
- *
- * @throws IndexOutOfBoundsException
- * if the index is out of bounds
- * @see #appendRow()
- * @see #prependRow()
- * @see #removeRow(int)
- * @see #removeRow(StaticRow)
- */
- public ROWTYPE addRow(int index) {
- ROWTYPE row = createRow();
- row.setSection(this);
- for (int i = 0; i < getGrid().getColumnCount(); ++i) {
- row.addCell(grid.getColumn(i));
- }
- rows.add(index, row);
-
- requestSectionRefresh();
- return row;
- }
-
- /**
- * Adds a new row at the top of this section.
- *
- * @return the new row
- * @see #appendRow()
- * @see #addRow(int)
- * @see #removeRow(int)
- * @see #removeRow(StaticRow)
- */
- public ROWTYPE prependRow() {
- return addRow(0);
- }
-
- /**
- * Adds a new row at the bottom of this section.
- *
- * @return the new row
- * @see #prependRow()
- * @see #addRow(int)
- * @see #removeRow(int)
- * @see #removeRow(StaticRow)
- */
- public ROWTYPE appendRow() {
- return addRow(rows.size());
- }
-
- /**
- * Removes the row at the given position.
- *
- * @param index
- * the position of the row
- *
- * @throws IndexOutOfBoundsException
- * if the index is out of bounds
- * @see #addRow(int)
- * @see #appendRow()
- * @see #prependRow()
- * @see #removeRow(StaticRow)
- */
- public void removeRow(int index) {
- rows.remove(index);
- requestSectionRefresh();
- }
-
- /**
- * Removes the given row from the section.
- *
- * @param row
- * the row to be removed
- *
- * @throws IllegalArgumentException
- * if the row does not exist in this section
- * @see #addRow(int)
- * @see #appendRow()
- * @see #prependRow()
- * @see #removeRow(int)
- */
- public void removeRow(ROWTYPE row) {
- try {
- removeRow(rows.indexOf(row));
- } catch (IndexOutOfBoundsException e) {
- throw new IllegalArgumentException(
- "Section does not contain the given row");
- }
- }
-
- /**
- * Returns the row at the given position.
- *
- * @param index
- * the position of the row
- * @return the row with the given index
- *
- * @throws IndexOutOfBoundsException
- * if the index is out of bounds
- */
- public ROWTYPE getRow(int index) {
- try {
- return rows.get(index);
- } catch (IndexOutOfBoundsException e) {
- throw new IllegalArgumentException("Row with index " + index
- + " does not exist");
- }
- }
-
- /**
- * Returns the number of rows in this section.
- *
- * @return the number of rows
- */
- public int getRowCount() {
- return rows.size();
- }
-
- protected List<ROWTYPE> getRows() {
- return rows;
- }
-
- protected int getVisibleRowCount() {
- return isVisible() ? getRowCount() : 0;
- }
-
- protected void addColumn(GridColumn<?, ?> column) {
- for (ROWTYPE row : rows) {
- row.addCell(column);
- }
- }
-
- protected void removeColumn(GridColumn<?, ?> column) {
- for (ROWTYPE row : rows) {
- row.removeCell(column);
- }
- }
-
- protected void setGrid(Grid<?> grid) {
- this.grid = grid;
- }
-
- protected Grid<?> getGrid() {
- assert grid != null;
- return grid;
- }
-}
diff --git a/uitest/src/com/vaadin/tests/widgetset/client/grid/GridBasicClientFeaturesWidget.java b/uitest/src/com/vaadin/tests/widgetset/client/grid/GridBasicClientFeaturesWidget.java
index ce899be8f9..cdf674e570 100644
--- a/uitest/src/com/vaadin/tests/widgetset/client/grid/GridBasicClientFeaturesWidget.java
+++ b/uitest/src/com/vaadin/tests/widgetset/client/grid/GridBasicClientFeaturesWidget.java
@@ -42,12 +42,10 @@ import com.vaadin.client.ui.grid.EditorRowHandler;
import com.vaadin.client.ui.grid.FlyweightCell;
import com.vaadin.client.ui.grid.Grid;
import com.vaadin.client.ui.grid.Grid.CellStyleGenerator;
+import com.vaadin.client.ui.grid.Grid.FooterRow;
+import com.vaadin.client.ui.grid.Grid.HeaderRow;
import com.vaadin.client.ui.grid.Grid.SelectionMode;
import com.vaadin.client.ui.grid.GridColumn;
-import com.vaadin.client.ui.grid.GridFooter;
-import com.vaadin.client.ui.grid.GridFooter.FooterRow;
-import com.vaadin.client.ui.grid.GridHeader;
-import com.vaadin.client.ui.grid.GridHeader.HeaderRow;
import com.vaadin.client.ui.grid.Renderer;
import com.vaadin.client.ui.grid.datasources.ListDataSource;
import com.vaadin.client.ui.grid.datasources.ListSorter;
@@ -343,7 +341,7 @@ public class GridBasicClientFeaturesWidget extends
column.setHeaderText("Header (0," + c + ")");
}
- HeaderRow row = grid.getHeader().getDefaultRow();
+ HeaderRow row = grid.getDefaultHeaderRow();
for (int i = 0; i < col; ++i) {
String caption = "Header (0," + i + ")";
GridColumn<?, ?> column = grid.getColumn(i);
@@ -628,7 +626,7 @@ public class GridBasicClientFeaturesWidget extends
addMenuCommand("HTML Header", new ScheduledCommand() {
@Override
public void execute() {
- grid.getHeader().getRow(0).getCell(column)
+ grid.getHeaderRow(0).getCell(column)
.setHtml("<b>HTML Header</b>");
}
}, "Component", "Columns", "Column " + i, "Header Type");
@@ -643,8 +641,7 @@ public class GridBasicClientFeaturesWidget extends
button.setText("Clicked");
}
});
- grid.getHeader().getRow(0).getCell(column)
- .setWidget(button);
+ grid.getHeaderRow(0).getCell(column).setWidget(button);
}
}, "Component", "Columns", "Column " + i, "Header Type");
@@ -652,14 +649,13 @@ public class GridBasicClientFeaturesWidget extends
addMenuCommand("Text Footer", new ScheduledCommand() {
@Override
public void execute() {
- grid.getFooter().getRow(0).getCell(column)
- .setText("Text Footer");
+ grid.getFooterRow(0).getCell(column).setText("Text Footer");
}
}, "Component", "Columns", "Column " + i, "Footer Type");
addMenuCommand("HTML Footer", new ScheduledCommand() {
@Override
public void execute() {
- grid.getFooter().getRow(0).getCell(column)
+ grid.getFooterRow(0).getCell(column)
.setHtml("<b>HTML Footer</b>");
}
}, "Component", "Columns", "Column " + i, "Footer Type");
@@ -674,8 +670,7 @@ public class GridBasicClientFeaturesWidget extends
button.setText("Clicked");
}
});
- grid.getFooter().getRow(0).getCell(column)
- .setWidget(button);
+ grid.getFooterRow(0).getCell(column).setWidget(button);
}
}, "Component", "Columns", "Column " + i, "Footer Type");
}
@@ -719,66 +714,65 @@ public class GridBasicClientFeaturesWidget extends
}
private void createHeaderMenu() {
- final GridHeader header = grid.getHeader();
final String[] menuPath = { "Component", "Header" };
addMenuCommand("Visible", new ScheduledCommand() {
@Override
public void execute() {
- header.setVisible(!header.isVisible());
+ grid.setHeaderVisible(!grid.isHeaderVisible());
}
}, menuPath);
addMenuCommand("Top", new ScheduledCommand() {
@Override
public void execute() {
- header.setDefaultRow(header.getRow(0));
+ grid.setDefaultHeaderRow(grid.getHeaderRow(0));
}
}, "Component", "Header", "Default row");
addMenuCommand("Bottom", new ScheduledCommand() {
@Override
public void execute() {
- header.setDefaultRow(header.getRow(header.getRowCount() - 1));
+ grid.setDefaultHeaderRow(grid.getHeaderRow(grid
+ .getHeaderRowCount() - 1));
}
}, "Component", "Header", "Default row");
addMenuCommand("Unset", new ScheduledCommand() {
@Override
public void execute() {
- header.setDefaultRow(null);
+ grid.setDefaultHeaderRow(null);
}
}, "Component", "Header", "Default row");
addMenuCommand("Prepend row", new ScheduledCommand() {
@Override
public void execute() {
- configureHeaderRow(header.prependRow());
+ configureHeaderRow(grid.prependHeaderRow());
}
}, menuPath);
addMenuCommand("Append row", new ScheduledCommand() {
@Override
public void execute() {
- configureHeaderRow(header.appendRow());
+ configureHeaderRow(grid.appendHeaderRow());
}
}, menuPath);
addMenuCommand("Remove top row", new ScheduledCommand() {
@Override
public void execute() {
- header.removeRow(0);
+ grid.removeHeaderRow(0);
}
}, menuPath);
addMenuCommand("Remove bottom row", new ScheduledCommand() {
@Override
public void execute() {
- header.removeRow(header.getRowCount() - 1);
+ grid.removeHeaderRow(grid.getHeaderRowCount() - 1);
}
}, menuPath);
}
private void configureHeaderRow(final HeaderRow row) {
- final GridHeader header = grid.getHeader();
setHeaderTexts(row);
- String rowTitle = "Row " + header.getRowCount();
+ String rowTitle = "Row " + grid.getHeaderRowCount();
final String[] menuPath = { "Component", "Header", rowTitle };
addMenuCommand("Join column cells 0, 1", new ScheduledCommand() {
@@ -828,39 +822,38 @@ public class GridBasicClientFeaturesWidget extends
}
private void createFooterMenu() {
- final GridFooter footer = grid.getFooter();
final String[] menuPath = { "Component", "Footer" };
addMenuCommand("Visible", new ScheduledCommand() {
@Override
public void execute() {
- footer.setVisible(!footer.isVisible());
+ grid.setFooterVisible(!grid.isFooterVisible());
}
}, menuPath);
addMenuCommand("Prepend row", new ScheduledCommand() {
@Override
public void execute() {
- configureFooterRow(footer.prependRow());
+ configureFooterRow(grid.prependFooterRow());
}
}, menuPath);
addMenuCommand("Append row", new ScheduledCommand() {
@Override
public void execute() {
- configureFooterRow(footer.appendRow());
+ configureFooterRow(grid.appendFooterRow());
}
}, menuPath);
addMenuCommand("Remove top row", new ScheduledCommand() {
@Override
public void execute() {
- footer.removeRow(0);
+ grid.removeFooterRow(0);
}
}, menuPath);
addMenuCommand("Remove bottom row", new ScheduledCommand() {
@Override
public void execute() {
- assert footer.getRowCount() > 0;
- footer.removeRow(footer.getRowCount() - 1);
+ assert grid.getFooterRowCount() > 0;
+ grid.removeFooterRow(grid.getFooterRowCount() - 1);
}
}, menuPath);
}
@@ -912,9 +905,8 @@ public class GridBasicClientFeaturesWidget extends
}
private void configureFooterRow(final FooterRow row) {
- final GridFooter footer = grid.getFooter();
setFooterTexts(row);
- String rowTitle = "Row " + footer.getRowCount();
+ String rowTitle = "Row " + grid.getFooterRowCount();
final String[] menuPath = { "Component", "Footer", rowTitle };
addMenuCommand("Join column cells 0, 1", new ScheduledCommand() {
diff --git a/uitest/src/com/vaadin/tests/widgetset/client/grid/GridClientColumnRendererConnector.java b/uitest/src/com/vaadin/tests/widgetset/client/grid/GridClientColumnRendererConnector.java
index bde16b817e..3290c67467 100644
--- a/uitest/src/com/vaadin/tests/widgetset/client/grid/GridClientColumnRendererConnector.java
+++ b/uitest/src/com/vaadin/tests/widgetset/client/grid/GridClientColumnRendererConnector.java
@@ -145,12 +145,12 @@ public class GridClientColumnRendererConnector extends
// Add a column to display the data in
GridColumn<String, String> c = createColumnWithRenderer(Renderers.TEXT_RENDERER);
grid.addColumn(c);
- grid.getHeader().getDefaultRow().getCell(c).setText("Column 1");
+ grid.getDefaultHeaderRow().getCell(c).setText("Column 1");
// Add another column with a custom complex renderer
c = createColumnWithRenderer(Renderers.CPLX_RENDERER);
grid.addColumn(c);
- grid.getHeader().getDefaultRow().getCell(c).setText("Column 2");
+ grid.getDefaultHeaderRow().getCell(c).setText("Column 2");
// Add method for testing sort event firing
grid.addSortHandler(new SortHandler<String>() {
@@ -161,9 +161,8 @@ public class GridClientColumnRendererConnector extends
String text = "Client-side sort event received<br>"
+ "Columns: " + event.getOrder().size() + ", order: ";
for (SortOrder order : event.getOrder()) {
- String columnHeader = getWidget().getHeader()
- .getDefaultRow().getCell(order.getColumn())
- .getText();
+ String columnHeader = getWidget().getDefaultHeaderRow()
+ .getCell(order.getColumn()).getText();
text += columnHeader + ": "
+ order.getDirection().toString();
}
@@ -189,8 +188,7 @@ public class GridClientColumnRendererConnector extends
getWidget().addColumn(column);
getWidget()
- .getHeader()
- .getDefaultRow()
+ .getDefaultHeaderRow()
.getCell(column)
.setText(
"Column "