From 4caa2f5b6e26ade52a4fba66a0a020b79f9008ea Mon Sep 17 00:00:00 2001
From: John Ahlroos
Date: Wed, 6 Nov 2013 10:35:03 +0200
Subject: [PATCH] Multiple headers and footer rows #3153
Change-Id: Iadb0d8b051d0f0ef1303e0d7d740cf476cd81971
---
.../vaadin/client/ui/grid/ColumnGroup.java | 117 +++++
.../vaadin/client/ui/grid/ColumnGroupRow.java | 188 +++++++
.../src/com/vaadin/client/ui/grid/Grid.java | 482 +++++++++++++++---
.../vaadin/client/ui/grid/GridConnector.java | 92 +++-
.../ui/components/grid/ColumnGroup.java | 141 +++++
.../ui/components/grid/ColumnGroupRow.java | 255 +++++++++
.../com/vaadin/ui/components/grid/Grid.java | 134 ++++-
.../vaadin/ui/components/grid/GridColumn.java | 15 +-
.../server/component/grid/GridColumns.java | 92 +++-
.../shared/ui/grid/ColumnGroupRowState.java | 46 ++
.../shared/ui/grid/ColumnGroupState.java | 45 ++
.../shared/ui/grid/GridColumnState.java | 6 -
.../com/vaadin/shared/ui/grid/GridState.java | 12 +-
.../components/grid/GridBasicFeatures.java | 149 ++++--
.../components/grid/GridColumnGroups.java | 111 ++++
15 files changed, 1679 insertions(+), 206 deletions(-)
create mode 100644 client/src/com/vaadin/client/ui/grid/ColumnGroup.java
create mode 100644 client/src/com/vaadin/client/ui/grid/ColumnGroupRow.java
create mode 100644 server/src/com/vaadin/ui/components/grid/ColumnGroup.java
create mode 100644 server/src/com/vaadin/ui/components/grid/ColumnGroupRow.java
create mode 100644 shared/src/com/vaadin/shared/ui/grid/ColumnGroupRowState.java
create mode 100644 shared/src/com/vaadin/shared/ui/grid/ColumnGroupState.java
create mode 100644 uitest/src/com/vaadin/tests/components/grid/GridColumnGroups.java
diff --git a/client/src/com/vaadin/client/ui/grid/ColumnGroup.java b/client/src/com/vaadin/client/ui/grid/ColumnGroup.java
new file mode 100644
index 0000000000..c37068def7
--- /dev/null
+++ b/client/src/com/vaadin/client/ui/grid/ColumnGroup.java
@@ -0,0 +1,117 @@
+/*
+ * Copyright 2000-2013 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.Collection;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * Column groups are used to group columns together for adding common auxiliary
+ * headers and footers. Columns groups are added to {@link ColumnGroupRow
+ * ColumnGroupRows}.
+ *
+ * @since 7.2
+ * @author Vaadin Ltd
+ */
+public class ColumnGroup {
+
+ /**
+ * The text shown in the header
+ */
+ private String header;
+
+ /**
+ * The text shown in the footer
+ */
+ private String footer;
+
+ /**
+ * The columns included in the group when also accounting for subgroup
+ * columns
+ */
+ private final List columns;
+
+ /**
+ * The grid associated with the column group
+ */
+ private final Grid grid;
+
+ /**
+ * Constructs a new column group
+ */
+ ColumnGroup(Grid grid, Collection columns) {
+ if (columns == null) {
+ throw new IllegalArgumentException(
+ "columns cannot be null. Pass an empty list instead.");
+ }
+ this.grid = grid;
+ this.columns = Collections.unmodifiableList(new ArrayList(
+ columns));
+ }
+
+ /**
+ * Gets the header text.
+ *
+ * @return the header text
+ */
+ public String getHeaderCaption() {
+ return header;
+ }
+
+ /**
+ * Sets the text shown in the header.
+ *
+ * @param header
+ * the header to set
+ */
+ public void setHeaderCaption(String header) {
+ this.header = header;
+ grid.refreshHeader();
+ }
+
+ /**
+ * Gets the text shown in the footer.
+ *
+ * @return the text in the footer
+ */
+ public String getFooterCaption() {
+ return footer;
+ }
+
+ /**
+ * Sets the text displayed in the footer.
+ *
+ * @param footer
+ * the footer to set
+ */
+ public void setFooterCaption(String footer) {
+ this.footer = footer;
+ grid.refreshFooter();
+ }
+
+ /**
+ * Returns all column in this group. It includes the subgroups columns as
+ * well.
+ *
+ * @return unmodifiable list of columns
+ */
+ public List getColumns() {
+ return columns;
+ }
+}
diff --git a/client/src/com/vaadin/client/ui/grid/ColumnGroupRow.java b/client/src/com/vaadin/client/ui/grid/ColumnGroupRow.java
new file mode 100644
index 0000000000..6bbc9bc9eb
--- /dev/null
+++ b/client/src/com/vaadin/client/ui/grid/ColumnGroupRow.java
@@ -0,0 +1,188 @@
+/*
+ * Copyright 2000-2013 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.Arrays;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * A column group row represents an auxiliary header or footer row added to the
+ * grid. A column group row includes column groups that group columns together.
+ *
+ * @since 7.2
+ * @author Vaadin Ltd
+ */
+public class ColumnGroupRow {
+
+ /**
+ * The column groups in this row
+ */
+ private List groups = new ArrayList();
+
+ /**
+ * The grid associated with the column row
+ */
+ private final Grid grid;
+
+ /**
+ * Is the header shown
+ */
+ public boolean headerVisible = true;
+
+ /**
+ * Is the footer shown
+ */
+ public boolean footerVisible = false;
+
+ /**
+ * Constructs a new column group row
+ *
+ * @param grid
+ * Grid associated with this column
+ *
+ */
+ ColumnGroupRow(Grid grid) {
+ this.grid = grid;
+ }
+
+ /**
+ * Add a new group to the row by using column instances.
+ *
+ * @param columns
+ * The columns that should belong to the group
+ * @return a column group representing the collection of columns added to
+ * the group.
+ */
+ public ColumnGroup addGroup(GridColumn... columns) {
+
+ for (GridColumn column : columns) {
+ if (isColumnGrouped(column)) {
+ throw new IllegalArgumentException("Column "
+ + String.valueOf(column.getHeaderCaption())
+ + " already belongs to another group.");
+ }
+ }
+
+ ColumnGroup group = new ColumnGroup(grid, Arrays.asList(columns));
+ groups.add(group);
+ grid.refreshHeader();
+ grid.refreshFooter();
+ return group;
+ }
+
+ /**
+ * Add a new group to the row by using other already greated groups
+ *
+ * @param groups
+ * The subgroups of the group.
+ * @return a column group representing the collection of columns added to
+ * the group.
+ *
+ */
+ public ColumnGroup addGroup(ColumnGroup... groups) {
+ assert groups != null : "groups cannot be null";
+
+ Set columns = new HashSet();
+ for (ColumnGroup group : groups) {
+ columns.addAll(group.getColumns());
+ }
+
+ ColumnGroup group = new ColumnGroup(grid, columns);
+ this.groups.add(group);
+ grid.refreshHeader();
+ grid.refreshFooter();
+ return group;
+ }
+
+ /**
+ * Removes a group from the row.
+ *
+ * @param group
+ * The group to remove
+ */
+ public void removeGroup(ColumnGroup group) {
+ groups.remove(group);
+ grid.refreshHeader();
+ grid.refreshFooter();
+ }
+
+ /**
+ * Get the groups in the row
+ *
+ * @return unmodifiable list of groups in this row
+ */
+ public List getGroups() {
+ return Collections.unmodifiableList(groups);
+ }
+
+ /**
+ * Is the header visible for the row.
+ *
+ * @return true if header is visible
+ */
+ public boolean isHeaderVisible() {
+ return headerVisible;
+ }
+
+ /**
+ * Sets the header visible for the row.
+ *
+ * @param visible
+ * should the header be shown
+ */
+ public void setHeaderVisible(boolean visible) {
+ headerVisible = visible;
+ grid.refreshHeader();
+ }
+
+ /**
+ * Is the footer visible for the row.
+ *
+ * @return true if footer is visible
+ */
+ public boolean isFooterVisible() {
+ return footerVisible;
+ }
+
+ /**
+ * Sets the footer visible for the row.
+ *
+ * @param visible
+ * should the footer be shown
+ */
+ public void setFooterVisible(boolean visible) {
+ footerVisible = visible;
+ grid.refreshFooter();
+ }
+
+ /**
+ * Iterates all the column groups and checks if the columns alread has been
+ * added to a group.
+ */
+ private boolean isColumnGrouped(GridColumn column) {
+ for (ColumnGroup group : groups) {
+ if (group.getColumns().contains(column)) {
+ return true;
+ }
+ }
+ return false;
+ }
+}
diff --git a/client/src/com/vaadin/client/ui/grid/Grid.java b/client/src/com/vaadin/client/ui/grid/Grid.java
index 3c4e2d6e13..67f14301f0 100644
--- a/client/src/com/vaadin/client/ui/grid/Grid.java
+++ b/client/src/com/vaadin/client/ui/grid/Grid.java
@@ -55,7 +55,7 @@ import com.vaadin.shared.util.SharedUtil;
public class Grid extends Composite {
/**
- * Escalator used internally by the grid to render the rows
+ * Escalator used internally by grid to render the rows
*/
private Escalator escalator = GWT.create(Escalator.class);
@@ -65,8 +65,23 @@ public class Grid extends Composite {
private final List> columns = new ArrayList>();
/**
- * Base class for grid columns internally used by the Grid. You should use
- * {@link GridColumn} when creating new columns.
+ * The column groups rows added to the grid
+ */
+ private final List columnGroupRows = new ArrayList();
+
+ /**
+ * Are the headers for the columns visible
+ */
+ private boolean columnHeadersVisible = false;
+
+ /**
+ * Are the footers for the columns visible
+ */
+ private boolean columnFootersVisible = false;
+
+ /**
+ * Base class for grid columns internally used by the Grid. The user should
+ * use {@link GridColumn} when creating new columns.
*
* @param
* the row type
@@ -74,24 +89,24 @@ public class Grid extends Composite {
public static abstract class AbstractGridColumn {
/**
- * Grid associated with the column
+ * The grid the column is associated with
*/
private Grid grid;
/**
- * Text displayed in the column header
+ * Should the column be visible in the grid
*/
- private String header;
+ private boolean visible;
/**
- * Text displayed in the column footer
+ * The text displayed in the header of the column
*/
- private String footer;
+ private String header;
/**
- * Is the column visible
+ * Text displayed in the column footer
*/
- private boolean visible;
+ private String footer;
/**
* Internally used by the grid to set itself
@@ -125,14 +140,15 @@ public class Grid extends Composite {
* the text displayed in the column header
*/
public void setHeaderCaption(String caption) {
- if (SharedUtil.equals(caption, this.header)) {
+ if (SharedUtil.equals(caption, header)) {
return;
}
- this.header = caption;
+ header = caption;
if (grid != null) {
grid.refreshHeader();
+
}
}
@@ -153,11 +169,11 @@ public class Grid extends Composite {
* the text displayed in the footer of the column
*/
public void setFooterCaption(String caption) {
- if (SharedUtil.equals(caption, this.footer)) {
+ if (SharedUtil.equals(caption, footer)) {
return;
}
- this.footer = caption;
+ footer = caption;
if (grid != null) {
grid.refreshFooter();
@@ -177,7 +193,8 @@ public class Grid extends Composite {
* Sets a column as visible in the grid.
*
* @param visible
- * Set to true to show the column in the grid
+ * true if the column should be displayed in the
+ * grid
*/
public void setVisible(boolean visible) {
if (this.visible == visible) {
@@ -206,8 +223,9 @@ public class Grid extends Composite {
* Returns the text that should be displayed in the cell.
*
* @param row
- * the row object that provides the cell content
- * @return The cell content of the row
+ * The row object that provides the cell content.
+ *
+ * @return The cell content
*/
public abstract String getValue(T row);
@@ -220,6 +238,122 @@ public class Grid extends Composite {
}
}
+ /**
+ * Base class for header / footer escalator updater
+ */
+ protected abstract class HeaderFooterEscalatorUpdater implements
+ EscalatorUpdater {
+
+ /**
+ * The row container which contains the header or footer rows
+ */
+ private RowContainer rows;
+
+ /**
+ * Should the index be counted from 0-> or 0<-
+ */
+ private boolean inverted;
+
+ /**
+ * Constructs an updater for updating a header / footer
+ *
+ * @param rows
+ * The row container
+ * @param inverted
+ * Should index counting be inverted
+ */
+ public HeaderFooterEscalatorUpdater(RowContainer rows, boolean inverted) {
+ this.rows = rows;
+ this.inverted = inverted;
+ }
+
+ /**
+ * Gets the header/footer caption value
+ *
+ * @return The value that should be rendered for the column caption
+ */
+ public abstract String getColumnValue(GridColumn column);
+
+ /**
+ * Gets the group caption value
+ *
+ * @param group
+ * The group for with the caption value should be returned
+ * @return The value that should be rendered for the column caption
+ */
+ public abstract String getGroupValue(ColumnGroup group);
+
+ /**
+ * Is the row visible in the header/footer
+ *
+ * @return true if the row should be visible
+ */
+ public abstract boolean isRowVisible(ColumnGroupRow row);
+
+ /**
+ * Should the first row be visible
+ *
+ * @return true if the first row should be visible
+ */
+ public abstract boolean firstRowIsVisible();
+
+ @Override
+ public void updateCells(Row row, List cellsToUpdate) {
+
+ int rowIndex;
+ if (inverted) {
+ rowIndex = rows.getRowCount() - row.getRow() - 1;
+ } else {
+ rowIndex = row.getRow();
+ }
+
+ if (firstRowIsVisible() && rowIndex == 0) {
+ // column headers
+ for (Cell cell : cellsToUpdate) {
+ int columnIndex = cell.getColumn();
+ GridColumn column = columns.get(columnIndex);
+ cell.getElement().setInnerText(getColumnValue(column));
+ }
+
+ } else if (columnGroupRows.size() > 0) {
+ // Adjust for headers
+ if (firstRowIsVisible()) {
+ rowIndex--;
+ }
+
+ // Adjust for previous invisible header rows
+ ColumnGroupRow groupRow = null;
+ for (int i = 0, realIndex = 0; i < columnGroupRows.size(); i++) {
+ groupRow = columnGroupRows.get(i);
+ if (isRowVisible(groupRow)) {
+ if (realIndex == rowIndex) {
+ rowIndex = realIndex;
+ break;
+ }
+ realIndex++;
+ }
+ }
+
+ assert groupRow != null;
+
+ for (Cell cell : cellsToUpdate) {
+ int columnIndex = cell.getColumn();
+ GridColumn column = columns.get(columnIndex);
+ ColumnGroup group = getGroupForColumn(groupRow, column);
+
+ if (group != null) {
+ // FIXME Should merge the group cells when escalator
+ // supports it
+ cell.getElement().setInnerText(getGroupValue(group));
+ } else {
+ // Cells are reused
+ cell.getElement().setInnerHTML(null);
+ }
+ }
+ }
+ }
+ }
+
/**
* Creates a new instance.
*/
@@ -229,6 +363,9 @@ public class Grid extends Composite {
escalator.getHeader().setEscalatorUpdater(createHeaderUpdater());
escalator.getBody().setEscalatorUpdater(createBodyUpdater());
escalator.getFooter().setEscalatorUpdater(createFooterUpdater());
+
+ refreshHeader();
+ refreshFooter();
}
/**
@@ -238,18 +375,26 @@ public class Grid extends Composite {
* @return the updater that updates the data in the escalator.
*/
private EscalatorUpdater createHeaderUpdater() {
- return new EscalatorUpdater() {
+ return new HeaderFooterEscalatorUpdater(escalator.getHeader(), true) {
@Override
- public void updateCells(Row row, List cellsToUpdate) {
- if (isHeaderVisible()) {
- for (Cell cell : cellsToUpdate) {
- AbstractGridColumn column = columns.get(cell
- .getColumn());
- cell.getElement().setInnerText(
- column.getHeaderCaption());
- }
- }
+ public boolean isRowVisible(ColumnGroupRow row) {
+ return row.isHeaderVisible();
+ }
+
+ @Override
+ public String getGroupValue(ColumnGroup group) {
+ return group.getHeaderCaption();
+ }
+
+ @Override
+ public String getColumnValue(GridColumn column) {
+ return column.getHeaderCaption();
+ }
+
+ @Override
+ public boolean firstRowIsVisible() {
+ return isColumnHeadersVisible();
}
};
}
@@ -275,40 +420,80 @@ public class Grid extends Composite {
* @return the updater that updates the data in the escalator.
*/
private EscalatorUpdater createFooterUpdater() {
- return new EscalatorUpdater() {
+ return new HeaderFooterEscalatorUpdater(escalator.getFooter(), false) {
@Override
- public void updateCells(Row row, List cellsToUpdate) {
- if (isFooterVisible()) {
- for (Cell cell : cellsToUpdate) {
- AbstractGridColumn column = columns.get(cell
- .getColumn());
- cell.getElement().setInnerText(
- column.getFooterCaption());
- }
- }
+ public boolean isRowVisible(ColumnGroupRow row) {
+ return row.isFooterVisible();
+ }
+
+ @Override
+ public String getGroupValue(ColumnGroup group) {
+ return group.getFooterCaption();
+ }
+
+ @Override
+ public String getColumnValue(GridColumn column) {
+ return column.getFooterCaption();
+ }
+
+ @Override
+ public boolean firstRowIsVisible() {
+ return isColumnFootersVisible();
}
};
}
/**
- * Refreshes all header rows.
+ * Refreshes header or footer rows on demand
+ *
+ * @param rows
+ * The row container
+ * @param firstRowIsVisible
+ * is the first row visible
+ * @param isHeader
+ * true if we refreshing the header, else assumed
+ * the footer
*/
- private void refreshHeader() {
- RowContainer header = escalator.getHeader();
- if (isHeaderVisible() && header.getRowCount() > 0) {
- header.refreshRows(0, header.getRowCount());
+ private void refreshRowContainer(RowContainer rows,
+ boolean firstRowIsVisible, boolean isHeader) {
+
+ // Count needed rows
+ int totalRows = firstRowIsVisible ? 1 : 0;
+ for (ColumnGroupRow row : columnGroupRows) {
+ if (isHeader ? row.isHeaderVisible() : row.isFooterVisible()) {
+ totalRows++;
+ }
+ }
+
+ // Add or Remove rows on demand
+ int rowDiff = totalRows - rows.getRowCount();
+ if (rowDiff > 0) {
+ rows.insertRows(0, rowDiff);
+ } else if (rowDiff < 0) {
+ rows.removeRows(0, -rowDiff);
+ }
+
+ // Refresh all the rows
+ if (rows.getRowCount() > 0) {
+ rows.refreshRows(0, rows.getRowCount());
}
}
/**
- * Refreshes all footer rows.
+ * Refreshes all header rows
*/
- private void refreshFooter() {
- RowContainer footer = escalator.getFooter();
- if (isFooterVisible() && footer.getRowCount() > 0) {
- footer.refreshRows(0, footer.getRowCount());
- }
+ void refreshHeader() {
+ refreshRowContainer(escalator.getHeader(), isColumnHeadersVisible(),
+ true);
+ }
+
+ /**
+ * Refreshes all footer rows
+ */
+ void refreshFooter() {
+ refreshRowContainer(escalator.getFooter(), isColumnFootersVisible(),
+ false);
}
/**
@@ -388,71 +573,200 @@ public class Grid extends Composite {
* if the column index does not exist in the grid
*/
public GridColumn getColumn(int index) throws IllegalArgumentException {
- try {
- return columns.get(index);
- } catch (ArrayIndexOutOfBoundsException aioobe) {
- throw new IllegalStateException("Column not found.", aioobe);
+ if (index < 0 || index >= columns.size()) {
+ throw new IllegalStateException("Column not found.");
}
+ return columns.get(index);
}
/**
- * Sets the header row visible.
+ * Set the column headers visible.
+ *
+ *
+ * A column header is a single cell header on top of each column reserved
+ * for a specific header for that column. The column header can be set by
+ * {@link GridColumn#setHeaderCaption(String)} and column headers cannot be
+ * merged with other column headers.
+ *
+ *
+ *
+ * All column headers occupy the first header row of the grid. If you do not
+ * wish to show the column headers in the grid you should hide the row by
+ * setting visibility of the header row to false.
+ *
+ *
+ *
+ * If you want to merge the column headers into groups you can use
+ * {@link ColumnGroupRow}s to group columns together and give them a common
+ * header. See {@link #addColumnGroupRow()} for details.
+ *
+ *
+ *
+ * The header row is by default visible.
+ *
*
* @param visible
- * true if header rows should be visible
+ * true if header rows should be visible
*/
- public void setHeaderVisible(boolean visible) {
- if (visible == isHeaderVisible()) {
+ public void setColumnHeadersVisible(boolean visible) {
+ if (visible == isColumnHeadersVisible()) {
return;
}
-
- RowContainer header = escalator.getHeader();
-
- // TODO Should support multiple headers
- if (visible) {
- header.insertRows(0, 1);
- } else {
- header.removeRows(0, 1);
- }
+ columnHeadersVisible = visible;
+ refreshHeader();
}
/**
- * Are the header row(s) visible?
+ * Are the column headers visible
*
- * @return true if the header is visible
+ * @return true if they are visible
*/
- public boolean isHeaderVisible() {
- return escalator.getHeader().getRowCount() > 0;
+ public boolean isColumnHeadersVisible() {
+ return columnHeadersVisible;
}
/**
- * Sets the footer row(s) visible.
+ * Set the column footers visible.
+ *
+ *
+ * A column footer is a single cell footer below of each column reserved for
+ * a specific footer for that column. The column footer can be set by
+ * {@link GridColumn#setFooterCaption(String)} and column footers cannot be
+ * merged with other column footers.
+ *
+ *
+ *
+ * All column footers occupy the first footer row of the grid. If you do not
+ * wish to show the column footers in the grid you should hide the row by
+ * setting visibility of the footer row to false.
+ *
+ *
+ *
+ * If you want to merge the column footers into groups you can use
+ * {@link ColumnGroupRow}s to group columns together and give them a common
+ * footer. See {@link #addColumnGroupRow()} for details.
+ *
+ *
+ *
+ * The footer row is by default hidden.
+ *
*
* @param visible
- * true if header rows should be visible
+ * true if the footer row should be visible
*/
- public void setFooterVisible(boolean visible) {
- if (visible == isFooterVisible()) {
+ public void setColumnFootersVisible(boolean visible) {
+ if (visible == isColumnFootersVisible()) {
return;
}
+ this.columnFootersVisible = visible;
+ refreshFooter();
+ }
- RowContainer footer = escalator.getFooter();
+ /**
+ * Are the column footers visible
+ *
+ * @return true if they are visible
+ *
+ */
+ public boolean isColumnFootersVisible() {
+ return columnFootersVisible;
+ }
- // TODO Should support multiple footers
- if (visible) {
- footer.insertRows(0, 1);
- } else {
- footer.removeRows(0, 1);
- }
+ /**
+ * Adds a new column group row to the grid.
+ *
+ *
+ * Column group rows are rendered in the header and footer of the grid.
+ * Column group rows are made up of column groups which groups together
+ * columns for adding a common auxiliary header or footer for the columns.
+ *
+ *
+ * Example usage:
+ *
+ *
+ * // Add a new column group row to the grid
+ * ColumnGroupRow row = grid.addColumnGroupRow();
+ *
+ * // Group "Column1" and "Column2" together to form a header in the row
+ * ColumnGroup column12 = row.addGroup("Column1", "Column2");
+ *
+ * // Set a common header for "Column1" and "Column2"
+ * column12.setHeader("Column 1&2");
+ *
+ * // Set a common footer for "Column1" and "Column2"
+ * column12.setFooter("Column 1&2");
+ *
+ *
+ * @return a column group row instance you can use to add column groups
+ */
+ public ColumnGroupRow addColumnGroupRow() {
+ ColumnGroupRow row = new ColumnGroupRow(this);
+ columnGroupRows.add(row);
+ refreshHeader();
+ refreshFooter();
+ return row;
+ }
+
+ /**
+ * Adds a new column group row to the grid at a specific index.
+ *
+ * @see #addColumnGroupRow() {@link Grid#addColumnGroupRow()} for example
+ * usage
+ *
+ * @param rowIndex
+ * the index where the column group row should be added
+ * @return a column group row instance you can use to add column groups
+ */
+ public ColumnGroupRow addColumnGroupRow(int rowIndex) {
+ ColumnGroupRow row = new ColumnGroupRow(this);
+ columnGroupRows.add(rowIndex, row);
+ refreshHeader();
+ refreshFooter();
+ return row;
}
/**
- * Are the footer row(s) visible?
+ * Removes a column group row
*
- * @return true if the footer is visible
+ * @param row
+ * The row to remove
*/
- public boolean isFooterVisible() {
- return escalator.getFooter().getRowCount() > 0;
+ public void removeColumnGroupRow(ColumnGroupRow row) {
+ columnGroupRows.remove(row);
+ refreshHeader();
+ refreshFooter();
+ }
+
+ /**
+ * Get the column group rows
+ *
+ * @return a unmodifiable list of column group rows
+ *
+ */
+ public List getColumnGroupRows() {
+ return Collections.unmodifiableList(new ArrayList(
+ columnGroupRows));
+ }
+
+ /**
+ * Returns the column group for a row and column
+ *
+ * @param row
+ * The row of the column
+ * @param column
+ * the column to get the group for
+ * @return A column group for the row and column or null if not
+ * found.
+ */
+ private static ColumnGroup getGroupForColumn(ColumnGroupRow row,
+ GridColumn column) {
+ for (ColumnGroup group : row.getGroups()) {
+ List columns = group.getColumns();
+ if (columns.contains(column)) {
+ return group;
+ }
+ }
+ return null;
}
@Override
diff --git a/client/src/com/vaadin/client/ui/grid/GridConnector.java b/client/src/com/vaadin/client/ui/grid/GridConnector.java
index c48c9936bc..32907e1e29 100644
--- a/client/src/com/vaadin/client/ui/grid/GridConnector.java
+++ b/client/src/com/vaadin/client/ui/grid/GridConnector.java
@@ -16,15 +16,19 @@
package com.vaadin.client.ui.grid;
+import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
+import java.util.List;
import java.util.Map;
import java.util.Set;
import com.vaadin.client.communication.StateChangeEvent;
import com.vaadin.client.ui.AbstractComponentConnector;
import com.vaadin.shared.ui.Connect;
+import com.vaadin.shared.ui.grid.ColumnGroupRowState;
+import com.vaadin.shared.ui.grid.ColumnGroupState;
import com.vaadin.shared.ui.grid.GridColumnState;
import com.vaadin.shared.ui.grid.GridState;
@@ -38,6 +42,10 @@ import com.vaadin.shared.ui.grid.GridState;
@Connect(com.vaadin.ui.components.grid.Grid.class)
public class GridConnector extends AbstractComponentConnector {
+ /**
+ * Custom implementation of the custom grid column using a String[]Â to
+ * represent the cell value
+ */
private class CustomGridColumn extends GridColumn {
@Override
@@ -47,7 +55,9 @@ public class GridConnector extends AbstractComponentConnector {
}
}
- // Maps a generated column id -> A grid column instance
+ /**
+ * Maps a generated column id to a grid column instance
+ */
private Map columnIdToColumn = new HashMap();
@Override
@@ -71,16 +81,6 @@ public class GridConnector extends AbstractComponentConnector {
public void onStateChanged(StateChangeEvent stateChangeEvent) {
super.onStateChanged(stateChangeEvent);
- // Header
- if (stateChangeEvent.hasPropertyChanged("headerVisible")) {
- getWidget().setHeaderVisible(getState().headerVisible);
- }
-
- // Footer
- if (stateChangeEvent.hasPropertyChanged("footerVisible")) {
- getWidget().setFooterVisible(getState().footerVisible);
- }
-
// Column updates
if (stateChangeEvent.hasPropertyChanged("columns")) {
@@ -92,7 +92,7 @@ public class GridConnector extends AbstractComponentConnector {
// Add new columns
for (int columnIndex = currentColumns; columnIndex < totalColumns; columnIndex++) {
- addColumnFromStateChangeEvent(columnIndex, stateChangeEvent);
+ addColumnFromStateChangeEvent(columnIndex);
}
// Update old columns
@@ -100,9 +100,26 @@ public class GridConnector extends AbstractComponentConnector {
// FIXME Currently updating all column header / footers when a
// change in made in one column. When the framework supports
// quering a specific item in a list then it should do so here.
- updateColumnFromStateChangeEvent(columnIndex, stateChangeEvent);
+ updateColumnFromStateChangeEvent(columnIndex);
}
}
+
+ // Header
+ if (stateChangeEvent.hasPropertyChanged("columnHeadersVisible")) {
+ getWidget()
+ .setColumnHeadersVisible(getState().columnHeadersVisible);
+ }
+
+ // Footer
+ if (stateChangeEvent.hasPropertyChanged("columnFootersVisible")) {
+ getWidget()
+ .setColumnFootersVisible(getState().columnFootersVisible);
+ }
+
+ // Column row groups
+ if (stateChangeEvent.hasPropertyChanged("columnGroupRows")) {
+ updateColumnGroupsFromStateChangeEvent();
+ }
}
/**
@@ -110,12 +127,8 @@ public class GridConnector extends AbstractComponentConnector {
*
* @param columnIndex
* The index of the column to update
- * @param stateChangeEvent
- * The state change event that contains the changes for the
- * column
*/
- private void updateColumnFromStateChangeEvent(int columnIndex,
- StateChangeEvent stateChangeEvent) {
+ private void updateColumnFromStateChangeEvent(int columnIndex) {
GridColumn column = getWidget().getColumn(columnIndex);
GridColumnState columnState = getState().columns.get(columnIndex);
updateColumnFromState(column, columnState);
@@ -126,30 +139,30 @@ public class GridConnector extends AbstractComponentConnector {
*
* @param columnIndex
* The index of the column, according to how it
- * @param stateChangeEvent
*/
- private void addColumnFromStateChangeEvent(int columnIndex,
- StateChangeEvent stateChangeEvent) {
+ private void addColumnFromStateChangeEvent(int columnIndex) {
GridColumnState state = getState().columns.get(columnIndex);
CustomGridColumn column = new CustomGridColumn();
updateColumnFromState(column, state);
+
columnIdToColumn.put(state.id, column);
+
getWidget().addColumn(column, columnIndex);
}
/**
- * Updates fields in column from a {@link GridColumnState} DTO
+ * Updates the column values from a state
*
* @param column
* The column to update
* @param state
- * The state to update from
+ * The state to get the data from
*/
private static void updateColumnFromState(GridColumn column,
GridColumnState state) {
+ column.setVisible(state.visible);
column.setHeaderCaption(state.header);
column.setFooterCaption(state.footer);
- column.setVisible(state.visible);
}
/**
@@ -176,4 +189,35 @@ public class GridConnector extends AbstractComponentConnector {
}
}
}
+
+ /**
+ * Updates the column groups from a state change
+ */
+ private void updateColumnGroupsFromStateChangeEvent() {
+
+ // FIXME When something changes the header/footer rows will be
+ // re-created. At some point we should optimize this so partial updates
+ // can be made on the header/footer.
+ for (ColumnGroupRow row : getWidget().getColumnGroupRows()) {
+ getWidget().removeColumnGroupRow(row);
+ }
+
+ for (ColumnGroupRowState rowState : getState().columnGroupRows) {
+ ColumnGroupRow row = getWidget().addColumnGroupRow();
+ row.setFooterVisible(rowState.footerVisible);
+ row.setHeaderVisible(rowState.headerVisible);
+
+ for (ColumnGroupState groupState : rowState.groups) {
+ List columns = new ArrayList();
+ for (String columnId : groupState.columns) {
+ CustomGridColumn column = columnIdToColumn.get(columnId);
+ columns.add(column);
+ }
+ ColumnGroup group = row.addGroup(columns
+ .toArray(new GridColumn[columns.size()]));
+ group.setFooterCaption(groupState.footer);
+ group.setHeaderCaption(groupState.header);
+ }
+ }
+ }
}
diff --git a/server/src/com/vaadin/ui/components/grid/ColumnGroup.java b/server/src/com/vaadin/ui/components/grid/ColumnGroup.java
new file mode 100644
index 0000000000..0ab1f61a46
--- /dev/null
+++ b/server/src/com/vaadin/ui/components/grid/ColumnGroup.java
@@ -0,0 +1,141 @@
+/*
+ * Copyright 2000-2013 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.ui.components.grid;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import com.vaadin.shared.ui.grid.ColumnGroupState;
+
+/**
+ * Column groups are used to group columns together for adding common auxiliary
+ * headers and footers. Columns groups are added to {@link ColumnGroupRow}'s.
+ *
+ * @since 7.2
+ * @author Vaadin Ltd
+ */
+public class ColumnGroup implements Serializable {
+
+ /**
+ * List of property ids belonging to this group
+ */
+ private List
+ *
+ *
+ * Example usage:
+ *
+ *
+ * // Add a new column group row to the grid
+ * ColumnGroupRow row = grid.addColumnGroupRow();
+ *
+ * // Group "Column1" and "Column2" together to form a header in the row
+ * ColumnGroup column12 = row.addGroup("Column1", "Column2");
+ *
+ * // Set a common header for "Column1" and "Column2"
+ * column12.setHeader("Column 1&2");
+ *
+ *
+ *
+ *
+ * @return a column group instance you can use to add column groups
+ */
+ public ColumnGroupRow addColumnGroupRow() {
+ ColumnGroupRowState state = new ColumnGroupRowState();
+ ColumnGroupRow row = new ColumnGroupRow(this, state, columnKeys);
+ columnGroupRows.add(row);
+ getState().columnGroupRows.add(state);
+ return row;
+ }
+
+ /**
+ * Adds a new column group to the grid at a specific index
+ *
+ * @param rowIndex
+ * the index of the row
+ * @return a column group instance you can use to add column groups
+ */
+ public ColumnGroupRow addColumnGroupRow(int rowIndex) {
+ ColumnGroupRowState state = new ColumnGroupRowState();
+ ColumnGroupRow row = new ColumnGroupRow(this, state, columnKeys);
+ columnGroupRows.add(rowIndex, row);
+ getState().columnGroupRows.add(rowIndex, state);
+ return row;
+ }
+
+ /**
+ * Removes a column group.
+ *
+ * @param row
+ * the row to remove
+ */
+ public void removeColumnGroupRow(ColumnGroupRow row) {
+ columnGroupRows.remove(row);
+ getState().columnGroupRows.remove(row.getState());
+ }
+
+ /**
+ * Gets the column group rows.
+ *
+ * @return an unmodifiable list of column group rows
+ */
+ public List getColumnGroupRows() {
+ return Collections.unmodifiableList(new ArrayList(
+ columnGroupRows));
}
/**
* Used internally by the {@link Grid} to get a {@link GridColumn} by
* referencing its generated state id. Also used by {@link GridColumn} to
- * verify if it has been detached from the {@link Grid}
+ * verify if it has been detached from the {@link Grid}.
*
* @param columnId
- * The client id generated for the column when the column is
+ * the client id generated for the column when the column is
* added to the grid
- * @return The column with the id or null if not found
+ * @return the column with the id or null if not found
*/
GridColumn getColumnByColumnId(String columnId) {
- Object propertyId = columnKeys.get(columnId);
+ Object propertyId = getPropertyIdByColumnId(columnId);
return getColumn(propertyId);
}
+ /**
+ * Used internally by the {@link Grid} to get a property id by referencing
+ * the columns generated state id.
+ *
+ * @param columnId
+ * The state id of the column
+ * @return The column instance or null if not found
+ */
+ Object getPropertyIdByColumnId(String columnId) {
+ return columnKeys.get(columnId);
+ }
+
@Override
protected GridState getState() {
return (GridState) super.getState();
@@ -241,7 +337,7 @@ public class Grid extends AbstractComponent {
* @param datasourcePropertyId
* The property id of a property in the datasource
*/
- protected GridColumn appendColumn(Object datasourcePropertyId) {
+ private GridColumn appendColumn(Object datasourcePropertyId) {
if (datasourcePropertyId == null) {
throw new IllegalArgumentException("Property id cannot be null");
}
diff --git a/server/src/com/vaadin/ui/components/grid/GridColumn.java b/server/src/com/vaadin/ui/components/grid/GridColumn.java
index 505919b3cf..dde0669238 100644
--- a/server/src/com/vaadin/ui/components/grid/GridColumn.java
+++ b/server/src/com/vaadin/ui/components/grid/GridColumn.java
@@ -16,6 +16,8 @@
package com.vaadin.ui.components.grid;
+import java.io.Serializable;
+
import com.vaadin.shared.ui.grid.GridColumnState;
/**
@@ -25,10 +27,10 @@ import com.vaadin.shared.ui.grid.GridColumnState;
* @since 7.2
* @author Vaadin Ltd
*/
-public class GridColumn {
+public class GridColumn implements Serializable {
/**
- * The shared state of the column
+ * The state of the column shared to the client
*/
private final GridColumnState state;
@@ -138,9 +140,16 @@ public class GridColumn {
* the new pixel width of the column
* @throws IllegalStateException
* if the column is no longer attached to any grid
+ * @throws IllegalArgumentException
+ * thrown if pixel width is less than zero
*/
- public void setWidth(int pixelWidth) throws IllegalStateException {
+ public void setWidth(int pixelWidth) throws IllegalStateException,
+ IllegalArgumentException {
checkColumnIsAttached();
+ if (pixelWidth < 0) {
+ throw new IllegalArgumentException(
+ "Pixel width should be greated than 0");
+ }
state.width = pixelWidth;
grid.markAsDirty();
}
diff --git a/server/tests/src/com/vaadin/tests/server/component/grid/GridColumns.java b/server/tests/src/com/vaadin/tests/server/component/grid/GridColumns.java
index 5989d537b4..85864160a8 100644
--- a/server/tests/src/com/vaadin/tests/server/component/grid/GridColumns.java
+++ b/server/tests/src/com/vaadin/tests/server/component/grid/GridColumns.java
@@ -32,6 +32,8 @@ import com.vaadin.data.util.IndexedContainer;
import com.vaadin.server.KeyMapper;
import com.vaadin.shared.ui.grid.GridColumnState;
import com.vaadin.shared.ui.grid.GridState;
+import com.vaadin.ui.components.grid.ColumnGroup;
+import com.vaadin.ui.components.grid.ColumnGroupRow;
import com.vaadin.ui.components.grid.Grid;
import com.vaadin.ui.components.grid.GridColumn;
@@ -110,9 +112,15 @@ public class GridColumns {
assertEquals(100, column.getWidth());
assertEquals(column.getWidth(), getColumnState("column1").width);
- column.setWidth(-1);
- assertEquals(-1, column.getWidth());
- assertEquals(-1, getColumnState("column1").width);
+ try {
+ column.setWidth(-1);
+ fail("Setting width to -1 should throw exception");
+ } catch (IllegalArgumentException iae) {
+
+ }
+
+ assertEquals(100, column.getWidth());
+ assertEquals(100, getColumnState("column1").width);
}
@Test
@@ -126,6 +134,7 @@ public class GridColumns {
try {
column.setHeaderCaption("asd");
+
fail("Succeeded in modifying a detached column");
} catch (IllegalStateException ise) {
// Detached state should throw exception
@@ -157,7 +166,7 @@ public class GridColumns {
}
@Test
- public void testAddingColumn() {
+ public void testAddingColumn() throws Exception {
grid.getContainerDatasource().addContainerProperty("columnX",
String.class, "");
GridColumn column = grid.getColumn("columnX");
@@ -165,33 +174,72 @@ public class GridColumns {
}
@Test
- public void testHeaderVisiblility() {
+ public void testHeaderVisiblility() throws Exception {
- assertTrue(grid.isHeaderVisible());
- assertTrue(state.headerVisible);
+ assertTrue(grid.isColumnHeadersVisible());
+ assertTrue(state.columnHeadersVisible);
- grid.setHeaderVisible(false);
- assertFalse(grid.isHeaderVisible());
- assertFalse(state.headerVisible);
+ grid.setColumnHeadersVisible(false);
+ assertFalse(grid.isColumnHeadersVisible());
+ assertFalse(state.columnHeadersVisible);
- grid.setHeaderVisible(true);
- assertTrue(grid.isHeaderVisible());
- assertTrue(state.headerVisible);
+ grid.setColumnHeadersVisible(true);
+ assertTrue(grid.isColumnHeadersVisible());
+ assertTrue(state.columnHeadersVisible);
}
@Test
- public void testFooterVisibility() {
+ public void testFooterVisibility() throws Exception {
+
+ assertFalse(grid.isColumnFootersVisible());
+ assertFalse(state.columnFootersVisible);
- assertTrue(grid.isFooterVisible());
- assertTrue(state.footerVisible);
+ grid.setColumnFootersVisible(false);
+ assertFalse(grid.isColumnFootersVisible());
+ assertFalse(state.columnFootersVisible);
- grid.setFooterVisible(false);
- assertFalse(grid.isFooterVisible());
- assertFalse(state.footerVisible);
+ grid.setColumnFootersVisible(true);
+ assertTrue(grid.isColumnFootersVisible());
+ assertTrue(state.columnFootersVisible);
+ }
- grid.setFooterVisible(true);
- assertTrue(grid.isFooterVisible());
- assertTrue(state.footerVisible);
+ @Test
+ public void testColumnGroups() throws Exception {
+
+ // Add a new row
+ ColumnGroupRow row = grid.addColumnGroupRow();
+ assertTrue(state.columnGroupRows.size() == 1);
+
+ // Add a group by property id
+ ColumnGroup columns12 = row.addGroup("column1", "column2");
+ assertTrue(state.columnGroupRows.get(0).groups.size() == 1);
+
+ // Set header of column
+ columns12.setHeaderCaption("Column12");
+ assertEquals("Column12",
+ state.columnGroupRows.get(0).groups.get(0).header);
+
+ // Set footer of column
+ columns12.setFooterCaption("Footer12");
+ assertEquals("Footer12",
+ state.columnGroupRows.get(0).groups.get(0).footer);
+
+ // Add another group by column instance
+ ColumnGroup columns34 = row.addGroup(grid.getColumn("column3"),
+ grid.getColumn("column4"));
+ assertTrue(state.columnGroupRows.get(0).groups.size() == 2);
+
+ // add another group row
+ ColumnGroupRow row2 = grid.addColumnGroupRow();
+ assertTrue(state.columnGroupRows.size() == 2);
+
+ // add a group by combining the two previous groups
+ ColumnGroup columns1234 = row2.addGroup(columns12, columns34);
+ assertTrue(columns1234.getColumns().size() == 4);
+
+ // Insert a group as the second group
+ ColumnGroupRow newRow2 = grid.addColumnGroupRow(1);
+ assertTrue(state.columnGroupRows.size() == 3);
}
private GridColumnState getColumnState(Object propertyId) {
diff --git a/shared/src/com/vaadin/shared/ui/grid/ColumnGroupRowState.java b/shared/src/com/vaadin/shared/ui/grid/ColumnGroupRowState.java
new file mode 100644
index 0000000000..a8e0f87457
--- /dev/null
+++ b/shared/src/com/vaadin/shared/ui/grid/ColumnGroupRowState.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2000-2013 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.shared.ui.grid;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * The column group row data shared between the server and client
+ *
+ * @since 7.2
+ * @author Vaadin Ltd
+ */
+public class ColumnGroupRowState implements Serializable {
+
+ /**
+ * The groups that has been added to the row
+ */
+ public List groups = new ArrayList();
+
+ /**
+ * Is the header shown
+ */
+ public boolean headerVisible = true;
+
+ /**
+ * Is the footer shown
+ */
+ public boolean footerVisible = false;
+
+}
diff --git a/shared/src/com/vaadin/shared/ui/grid/ColumnGroupState.java b/shared/src/com/vaadin/shared/ui/grid/ColumnGroupState.java
new file mode 100644
index 0000000000..3992b6611f
--- /dev/null
+++ b/shared/src/com/vaadin/shared/ui/grid/ColumnGroupState.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2000-2013 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.shared.ui.grid;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * The column group data shared between the server and the client
+ *
+ * @since 7.2
+ * @author Vaadin Ltd
+ */
+public class ColumnGroupState implements Serializable {
+
+ /**
+ * The columns that is included in the group
+ */
+ public List columns = new ArrayList();
+
+ /**
+ * The header text of the group
+ */
+ public String header;
+
+ /**
+ * The footer text of the group
+ */
+ public String footer;
+}
diff --git a/shared/src/com/vaadin/shared/ui/grid/GridColumnState.java b/shared/src/com/vaadin/shared/ui/grid/GridColumnState.java
index 391eb2a65c..0301c5ead2 100644
--- a/shared/src/com/vaadin/shared/ui/grid/GridColumnState.java
+++ b/shared/src/com/vaadin/shared/ui/grid/GridColumnState.java
@@ -34,17 +34,11 @@ public class GridColumnState implements Serializable {
/**
* Header caption for the column
- *
- * FIXME Only single header currently supported. Should support many
- * headers.
*/
public String header;
/**
* Footer caption for the column
- *
- * FIXME Only single footer currently supported. Should support many
- * footers.
*/
public String footer;
diff --git a/shared/src/com/vaadin/shared/ui/grid/GridState.java b/shared/src/com/vaadin/shared/ui/grid/GridState.java
index e1e0fff354..d1167f3d4f 100644
--- a/shared/src/com/vaadin/shared/ui/grid/GridState.java
+++ b/shared/src/com/vaadin/shared/ui/grid/GridState.java
@@ -40,13 +40,17 @@ public class GridState extends AbstractComponentState {
public List columns = new ArrayList();
/**
- * Are the header row(s) visible. By default they are visible.
+ * Is the column header row visible
*/
- public boolean headerVisible = true;
+ public boolean columnHeadersVisible = true;
/**
- * Are the footer row(s) visible. By default they are visible.
+ * Is the column footer row visible
*/
- public boolean footerVisible = true;
+ public boolean columnFootersVisible = false;
+ /**
+ * The column groups added to the grid
+ */
+ public List columnGroupRows = new ArrayList();
}
diff --git a/uitest/src/com/vaadin/tests/components/grid/GridBasicFeatures.java b/uitest/src/com/vaadin/tests/components/grid/GridBasicFeatures.java
index 5b3d742f19..bd3e96f84a 100644
--- a/uitest/src/com/vaadin/tests/components/grid/GridBasicFeatures.java
+++ b/uitest/src/com/vaadin/tests/components/grid/GridBasicFeatures.java
@@ -19,6 +19,8 @@ import java.util.ArrayList;
import com.vaadin.data.util.IndexedContainer;
import com.vaadin.tests.components.AbstractComponentTest;
+import com.vaadin.ui.components.grid.ColumnGroup;
+import com.vaadin.ui.components.grid.ColumnGroupRow;
import com.vaadin.ui.components.grid.Grid;
import com.vaadin.ui.components.grid.GridColumn;
@@ -32,6 +34,8 @@ public class GridBasicFeatures extends AbstractComponentTest {
private final int COLUMNS = 10;
+ private int columnGroupRows = 0;
+
@Override
protected Grid constructComponent() {
@@ -42,20 +46,51 @@ public class GridBasicFeatures extends AbstractComponentTest {
ds.addContainerProperty("Column" + col, String.class, "");
}
+ // Create grid
Grid grid = new Grid(ds);
- // Headers and footers
+ // Add footer values (header values are automatically created)
for (int col = 0; col < COLUMNS; col++) {
- GridColumn column = grid.getColumn("Column" + col);
- column.setHeaderCaption("Column " + col);
- column.setFooterCaption("Footer " + col);
+ grid.getColumn("Column" + col).setFooterCaption("Footer " + col);
}
createColumnActions();
+ createHeaderActions();
+
+ createFooterActions();
+
+ createColumnGroupActions();
+
return grid;
}
+ protected void createHeaderActions() {
+ createCategory("Headers", null);
+
+ createBooleanAction("Visible", "Headers", true,
+ new Command() {
+
+ @Override
+ public void execute(Grid grid, Boolean value, Object data) {
+ grid.setColumnHeadersVisible(value);
+ }
+ });
+ }
+
+ protected void createFooterActions() {
+ createCategory("Footers", null);
+
+ createBooleanAction("Visible", "Footers", false,
+ new Command() {
+
+ @Override
+ public void execute(Grid grid, Boolean value, Object data) {
+ grid.setColumnFootersVisible(value);
+ }
+ });
+ }
+
protected void createColumnActions() {
createCategory("Columns", null);
@@ -77,46 +112,6 @@ public class GridBasicFeatures extends AbstractComponentTest {
}
}, c);
- createBooleanAction("Footer", "Column" + c, true,
- new Command() {
-
- @Override
- public void execute(Grid grid, Boolean value,
- Object columnIndex) {
- Object propertyId = (new ArrayList(grid
- .getContainerDatasource()
- .getContainerPropertyIds())
- .get((Integer) columnIndex));
- GridColumn column = grid.getColumn(propertyId);
- String footer = column.getFooterCaption();
- if (footer == null) {
- column.setFooterCaption("Footer " + columnIndex);
- } else {
- column.setFooterCaption(null);
- }
- }
- }, c);
-
- createBooleanAction("Header", "Column" + c, true,
- new Command() {
-
- @Override
- public void execute(Grid grid, Boolean value,
- Object columnIndex) {
- Object propertyId = (new ArrayList(grid
- .getContainerDatasource()
- .getContainerPropertyIds())
- .get((Integer) columnIndex));
- GridColumn column = grid.getColumn(propertyId);
- String header = column.getHeaderCaption();
- if (header == null) {
- column.setHeaderCaption("Column " + columnIndex);
- } else {
- column.setHeaderCaption(null);
- }
- }
- }, c);
-
createClickAction("Remove", "Column" + c,
new Command() {
@@ -131,6 +126,72 @@ public class GridBasicFeatures extends AbstractComponentTest {
}
+ protected void createColumnGroupActions() {
+ createCategory("Column groups", null);
+
+ createClickAction("Add group row", "Column groups",
+ new Command() {
+
+ @Override
+ public void execute(Grid grid, String value, Object data) {
+ final ColumnGroupRow row = grid.addColumnGroupRow();
+ columnGroupRows++;
+ createCategory("Column group row " + columnGroupRows,
+ "Column groups");
+
+ createBooleanAction("Header Visible",
+ "Column group row " + columnGroupRows, true,
+ new Command() {
+
+ @Override
+ public void execute(Grid grid,
+ Boolean value, Object columnIndex) {
+ row.setHeaderVisible(value);
+ }
+ }, row);
+
+ createBooleanAction("Footer Visible",
+ "Column group row " + columnGroupRows, false,
+ new Command() {
+
+ @Override
+ public void execute(Grid grid,
+ Boolean value, Object columnIndex) {
+ row.setFooterVisible(value);
+ }
+ }, row);
+
+ for (int i = 0; i < COLUMNS; i += 2) {
+ final int columnIndex = i;
+ createClickAction("Group Column " + columnIndex
+ + " & " + (columnIndex + 1),
+ "Column group row " + columnGroupRows,
+ new Command() {
+
+ @Override
+ public void execute(Grid c,
+ Integer value, Object data) {
+ final ColumnGroup group = row
+ .addGroup(
+ "Column" + value,
+ "Column"
+ + (value + 1));
+
+ group.setHeaderCaption("Column "
+ + value + " & "
+ + (value + 1));
+
+ group.setFooterCaption("Column "
+ + value + " & "
+ + (value + 1));
+ }
+ }, i, row);
+ }
+ }
+ }, null, null);
+
+ }
+
@Override
protected Integer getTicketNumber() {
return 12829;
diff --git a/uitest/src/com/vaadin/tests/components/grid/GridColumnGroups.java b/uitest/src/com/vaadin/tests/components/grid/GridColumnGroups.java
new file mode 100644
index 0000000000..66e7651f76
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/components/grid/GridColumnGroups.java
@@ -0,0 +1,111 @@
+/*
+ * Copyright 2000-2013 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.tests.components.grid;
+
+import com.vaadin.data.util.IndexedContainer;
+import com.vaadin.server.VaadinRequest;
+import com.vaadin.tests.components.AbstractTestUI;
+import com.vaadin.ui.components.grid.ColumnGroup;
+import com.vaadin.ui.components.grid.ColumnGroupRow;
+import com.vaadin.ui.components.grid.Grid;
+import com.vaadin.ui.components.grid.GridColumn;
+
+/**
+ *
+ * @since
+ * @author Vaadin Ltd
+ */
+public class GridColumnGroups extends AbstractTestUI {
+
+ private final int COLUMNS = 4;
+
+ @Override
+ protected void setup(VaadinRequest request) {
+
+ // Setup grid
+ IndexedContainer ds = new IndexedContainer();
+ for (int col = 0; col < COLUMNS; col++) {
+ ds.addContainerProperty("Column" + col, String.class, "");
+ }
+ Grid grid = new Grid(ds);
+ addComponent(grid);
+
+ /*-
+ * ---------------------------------------------
+ * | Header 1 | <- Auxiliary row 2
+ * |-------------------------------------------|
+ * | Header 2 | Header 3 | <- Auxiliary row 1
+ * |-------------------------------------------|
+ * | Column 1 | Column 2 | Column 3 | Column 4 | <- Column headers
+ * --------------------------------------------|
+ * | ... | ... | ... | ... |
+ * | ... | ... | ... | ... |
+ * --------------------------------------------|
+ * | Column 1 | Column 2 | Column 3 | Column 4 | <- Column footers
+ * --------------------------------------------|
+ * | Footer 2 | Footer 3 | <- Auxiliary row 1
+ * --------------------------------------------|
+ * | Footer 1 | <- Auxiliary row 2
+ * ---------------------------------------------
+ -*/
+
+ // Set column footers (headers are generated automatically)
+ grid.setColumnFootersVisible(true);
+ for (Object propertyId : ds.getContainerPropertyIds()) {
+ GridColumn column = grid.getColumn(propertyId);
+ column.setFooterCaption(String.valueOf(propertyId));
+ }
+
+ // First auxiliary row
+ ColumnGroupRow auxRow1 = grid.addColumnGroupRow();
+
+ // Using property id to create a column group
+ ColumnGroup columns12 = auxRow1.addGroup("Column0", "Column1");
+ columns12.setHeaderCaption("Header 2");
+ columns12.setFooterCaption("Footer 2");
+
+ // Using grid columns to create a column group
+ GridColumn column3 = grid.getColumn("Column2");
+ GridColumn column4 = grid.getColumn("Column3");
+ ColumnGroup columns34 = auxRow1.addGroup(column3, column4);
+ columns34.setHeaderCaption("Header 3");
+ columns34.setFooterCaption("Footer 3");
+
+ // Second auxiliary row
+ ColumnGroupRow auxRow2 = grid.addColumnGroupRow();
+
+ // Using previous groups to create a column group
+ ColumnGroup columns1234 = auxRow2.addGroup(columns12, columns34);
+ columns1234.setHeaderCaption("Header 1");
+ columns1234.setFooterCaption("Footer 1");
+
+ }
+
+ @Override
+ protected String getTestDescription() {
+ return "Grid should support headers and footer groups";
+ }
+
+ @Override
+ protected Integer getTicketNumber() {
+ return 12894;
+ }
+
+}
--
2.39.5