diff options
author | John Ahlroos <john@vaadin.com> | 2013-11-06 10:35:03 +0200 |
---|---|---|
committer | Vaadin Code Review <review@vaadin.com> | 2013-11-22 12:59:10 +0000 |
commit | 4caa2f5b6e26ade52a4fba66a0a020b79f9008ea (patch) | |
tree | 4aa4d2b8d4d0566fda4b336d22a1ebbe7ac9d712 /client | |
parent | c2d38fa6c2d67457065fd3dce7e0d939ae0a1278 (diff) | |
download | vaadin-framework-4caa2f5b6e26ade52a4fba66a0a020b79f9008ea.tar.gz vaadin-framework-4caa2f5b6e26ade52a4fba66a0a020b79f9008ea.zip |
Multiple headers and footer rows #3153
Change-Id: Iadb0d8b051d0f0ef1303e0d7d740cf476cd81971
Diffstat (limited to 'client')
-rw-r--r-- | client/src/com/vaadin/client/ui/grid/ColumnGroup.java | 117 | ||||
-rw-r--r-- | client/src/com/vaadin/client/ui/grid/ColumnGroupRow.java | 188 | ||||
-rw-r--r-- | client/src/com/vaadin/client/ui/grid/Grid.java | 482 | ||||
-rw-r--r-- | client/src/com/vaadin/client/ui/grid/GridConnector.java | 92 |
4 files changed, 771 insertions, 108 deletions
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<GridColumn> columns; + + /** + * The grid associated with the column group + */ + private final Grid grid; + + /** + * Constructs a new column group + */ + ColumnGroup(Grid grid, Collection<GridColumn> 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<GridColumn>( + 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<GridColumn> 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<ColumnGroup> groups = new ArrayList<ColumnGroup>(); + + /** + * 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<GridColumn> columns = new HashSet<GridColumn>(); + 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<ColumnGroup> getGroups() { + return Collections.unmodifiableList(groups); + } + + /** + * Is the header visible for the row. + * + * @return <code>true</code> 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 <code>true</code> 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<T> 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<T> extends Composite { private final List<GridColumn<T>> columns = new ArrayList<GridColumn<T>>(); /** - * 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<ColumnGroupRow> columnGroupRows = new ArrayList<ColumnGroupRow>(); + + /** + * 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 <T> * the row type @@ -74,24 +89,24 @@ public class Grid<T> extends Composite { public static abstract class AbstractGridColumn<T> { /** - * Grid associated with the column + * The grid the column is associated with */ private Grid<T> 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<T> 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<T> 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<T> extends Composite { * Sets a column as visible in the grid. * * @param visible - * Set to <code>true</code> to show the column in the grid + * <code>true</code> 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<T> 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); @@ -221,6 +239,122 @@ public class Grid<T> 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 <code>true</code> if the row should be visible + */ + public abstract boolean isRowVisible(ColumnGroupRow row); + + /** + * Should the first row be visible + * + * @return <code>true</code> if the first row should be visible + */ + public abstract boolean firstRowIsVisible(); + + @Override + public void updateCells(Row row, List<Cell> 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. */ public Grid() { @@ -229,6 +363,9 @@ public class Grid<T> extends Composite { escalator.getHeader().setEscalatorUpdater(createHeaderUpdater()); escalator.getBody().setEscalatorUpdater(createBodyUpdater()); escalator.getFooter().setEscalatorUpdater(createFooterUpdater()); + + refreshHeader(); + refreshFooter(); } /** @@ -238,18 +375,26 @@ public class Grid<T> 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<Cell> cellsToUpdate) { - if (isHeaderVisible()) { - for (Cell cell : cellsToUpdate) { - AbstractGridColumn<T> 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<T> 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<Cell> cellsToUpdate) { - if (isFooterVisible()) { - for (Cell cell : cellsToUpdate) { - AbstractGridColumn<T> 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 + * <code>true</code> 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<T> extends Composite { * if the column index does not exist in the grid */ public GridColumn<T> 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. + * + * <p> + * 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. + * </p> + * + * <p> + * 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 <code>false</code>. + * </p> + * + * <p> + * 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. + * </p> + * + * <p> + * The header row is by default visible. + * </p> * * @param visible - * true if header rows should be visible + * <code>true</code> 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 <code>true</code> if the header is visible + * @return <code>true</code> 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. + * + * <p> + * 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. + * </p> + * + * <p> + * 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 <code>false</code>. + * </p> + * + * <p> + * 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. + * </p> + * + * <p> + * The footer row is by default hidden. + * </p> * * @param visible - * true if header rows should be visible + * <code>true</code> 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 <code>true</code> 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. + * + * <p> + * 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. + * </p> + * + * Example usage: + * + * <pre> + * // 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"); + * </pre> + * + * @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 <code>true</code> 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<ColumnGroupRow> getColumnGroupRows() { + return Collections.unmodifiableList(new ArrayList<ColumnGroupRow>( + 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 <code>null</code> if not + * found. + */ + private static ColumnGroup getGroupForColumn(ColumnGroupRow row, + GridColumn column) { + for (ColumnGroup group : row.getGroups()) { + List<GridColumn> 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<String[]> { @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<String, CustomGridColumn> columnIdToColumn = new HashMap<String, CustomGridColumn>(); @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<String[]> 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<String[]> 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<GridColumn> columns = new ArrayList<GridColumn>(); + 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); + } + } + } } |