diff options
author | elmot <elmot@vaadin.com> | 2016-11-23 12:30:54 +0200 |
---|---|---|
committer | Ilia Motornyi <elmot@vaadin.com> | 2016-11-29 12:09:55 +0000 |
commit | 5eaac7ac6e18f9eda7e083617cf07dd631924e0c (patch) | |
tree | 46a8cfadbaa75bbf567556f773f809ea2e89d164 | |
parent | 5ab990325f370d767a5ad76b016a852fb2b5330c (diff) | |
download | vaadin-framework-5eaac7ac6e18f9eda7e083617cf07dd631924e0c.tar.gz vaadin-framework-5eaac7ac6e18f9eda7e083617cf07dd631924e0c.zip |
Grid merging footer cells
Change-Id: I24895c7ae602ffc9a7812dcc441e99ac670356e2
6 files changed, 217 insertions, 59 deletions
diff --git a/client/src/main/java/com/vaadin/client/connectors/grid/GridConnector.java b/client/src/main/java/com/vaadin/client/connectors/grid/GridConnector.java index 617a0480ba..bcae476cf3 100644 --- a/client/src/main/java/com/vaadin/client/connectors/grid/GridConnector.java +++ b/client/src/main/java/com/vaadin/client/connectors/grid/GridConnector.java @@ -232,22 +232,26 @@ public class GridConnector extends AbstractListingConnector grid.setDefaultHeaderRow(row); } - rowState.cells.forEach((columnId, cellState) -> { - updateHeaderCellFromState(row.getCell(getColumn(columnId)), - cellState); - }); - for (Map.Entry<CellState, Set<String>> cellGroupEntry : rowState.cellGroups.entrySet()) { - Set<String> group = cellGroupEntry.getValue(); - - Grid.Column<?, ?>[] columns = - group.stream().map(idToColumn::get).toArray(size->new Grid.Column<?, ?>[size]); - // Set state to be the same as first in group. - updateHeaderCellFromState(row.join(columns), cellGroupEntry.getKey()); - } + updateStaticRow(rowState, row); + } + } + + private void updateStaticRow(RowState rowState, Grid.StaticSection.StaticRow row) { + rowState.cells.forEach((columnId, cellState) -> { + updateStaticCellFromState(row.getCell(getColumn(columnId)), + cellState); + }); + for (Map.Entry<CellState, Set<String>> cellGroupEntry : rowState.cellGroups.entrySet()) { + Set<String> group = cellGroupEntry.getValue(); + + Grid.Column<?, ?>[] columns = + group.stream().map(idToColumn::get).toArray(size->new Grid.Column<?, ?>[size]); + // Set state to be the same as first in group. + updateStaticCellFromState(row.join(columns), cellGroupEntry.getKey()); } } - private void updateHeaderCellFromState(HeaderCell cell, + private void updateStaticCellFromState(Grid.StaticSection.StaticCell cell, CellState cellState) { switch (cellState.type) { case TEXT: @@ -288,39 +292,10 @@ public class GridConnector extends AbstractListingConnector for (RowState rowState : state.rows) { FooterRow row = grid.appendFooterRow(); - rowState.cells.forEach((columnId, cellState) -> { - updateFooterCellFromState(row.getCell(getColumn(columnId)), - cellState); - }); + updateStaticRow(rowState, row); } } - private void updateFooterCellFromState(FooterCell 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; - if (connector != null) { - cell.setWidget(connector.getWidget()); - } else { - // This happens if you do setVisible(false) on the component on - // the server side - cell.setWidget(null); - } - break; - default: - throw new IllegalStateException( - "unexpected cell type: " + cellState.type); - } - cell.setStyleName(cellState.styleName); - } - @Override public void setDataSource(DataSource<JsonObject> dataSource) { super.setDataSource(dataSource); diff --git a/server/src/main/java/com/vaadin/ui/Grid.java b/server/src/main/java/com/vaadin/ui/Grid.java index 5010387377..7e38e7028d 100644 --- a/server/src/main/java/com/vaadin/ui/Grid.java +++ b/server/src/main/java/com/vaadin/ui/Grid.java @@ -1672,20 +1672,30 @@ public class Grid<T> extends AbstractListing<T> } /** - * Merges columns cells in a row + * Merges column cells in the row. Original cells are hidden, and new merged cell is shown instead. + * The cell has a width of all merged cells together, inherits styles of the first merged cell + * but has empty caption. * - * @param cells - * The cells to merge. Must be from the same row. - * @return The remaining visible cell after the merge + * @param cellsToMerge + * the cells which should be merged. The cells should not be merged to any other cell set. + * @return the remaining visible cell after the merge + * + * @see #join(Grid.HeaderCell...) + * @see com.vaadin.ui.AbstractComponent#setCaption(String) setCaption */ HeaderCell join(Set<HeaderCell> cellsToMerge); /** - * Merges columns cells in a row + * Merges column cells in the row. Original cells are hidden, and new merged cell is shown instead. + * The cell has a width of all merged cells together, inherits styles of the first merged cell + * but has empty caption. + * + * @param cellsToMerge + * the cells which should be merged. The cells should not be merged to any other cell set. + * @return the remaining visible cell after the merge * - * @param cells - * The cells to merge. Must be from the same row. - * @return The remaining visible cell after the merge + * @see #join(Set) + * @see com.vaadin.ui.AbstractComponent#setCaption(String) setCaption */ HeaderCell join(HeaderCell... cellsToMerge); @@ -1785,6 +1795,34 @@ public class Grid<T> extends AbstractListing<T> public default FooterCell getCell(Column<?, ?> column) { return getCell(column.getId()); } + + /** + * Merges column cells in the row. Original cells are hidden, and new merged cell is shown instead. + * The cell has a width of all merged cells together, inherits styles of the first merged cell + * but has empty caption. + * + * @param cellsToMerge + * the cells which should be merged. The cells should not be merged to any other cell set. + * @return the remaining visible cell after the merge + * + * @see #join(Grid.FooterCell...) + * @see com.vaadin.ui.AbstractComponent#setCaption(String) setCaption + */ + FooterCell join(Set<FooterCell> cellsToMerge); + + /** + * Merges column cells in the row. Original cells are hidden, and new merged cell is shown instead. + * The cell has a width of all merged cells together, inherits styles of the first merged cell + * but has empty caption. + * + * @param cellsToMerge + * the cells which should be merged. The cells should not be merged to any other cell set. + * @return the remaining visible cell after the merge + * + * @see #join(Set) + * @see com.vaadin.ui.AbstractComponent#setCaption(String) setCaption + */ + FooterCell join(FooterCell ... cellsToMerge); } /** @@ -1844,6 +1882,13 @@ public class Grid<T> extends AbstractListing<T> * @return cell content type */ public GridStaticCellType getCellType(); + + /** + * Gets the column id where this cell is. + * + * @return column id for this cell + */ + public String getColumnId(); } /** diff --git a/server/src/main/java/com/vaadin/ui/components/grid/Footer.java b/server/src/main/java/com/vaadin/ui/components/grid/Footer.java index 9423e2d842..0da179a2c0 100644 --- a/server/src/main/java/com/vaadin/ui/components/grid/Footer.java +++ b/server/src/main/java/com/vaadin/ui/components/grid/Footer.java @@ -17,6 +17,10 @@ package com.vaadin.ui.components.grid; import com.vaadin.ui.Grid; +import java.util.Arrays; +import java.util.HashSet; +import java.util.Set; + /** * Represents the footer section of a Grid. * @@ -61,6 +65,56 @@ public abstract class Footer extends StaticSection<Footer.Row> { protected String getCellTagName() { return "td"; } + + /** + * Merges column cells in the row. Original cells are hidden, and new merged cell is shown instead. + * The cell has a width of all merged cells together, inherits styles of the first merged cell + * but has empty caption. + * + * @param cellsToMerge + * the cells which should be merged. The cells should not be merged to any other cell set. + * @return the remaining visible cell after the merge + * + * @see #join(Grid.FooterCell...) + * @see com.vaadin.ui.AbstractComponent#setCaption(String) setCaption + */ + @Override + public Grid.FooterCell join(Set<Grid.FooterCell> cellsToMerge) { + for (Grid.FooterCell cell : cellsToMerge) { + checkIfAlreadyMerged(cell.getColumnId()); + } + + // Create new cell data for the group + Cell newCell = createCell(); + + Set<String> columnGroup = new HashSet<>(); + for (Grid.FooterCell cell : cellsToMerge) { + columnGroup.add(cell.getColumnId()); + } + addMergedCell(newCell, columnGroup); + markAsDirty(); + return newCell; + } + + /** + * Merges column cells in the row. Original cells are hidden, and new merged cell is shown instead. + * The cell has a width of all merged cells together, inherits styles of the first merged cell + * but has empty caption. + * + * @param cellsToMerge + * the cells which should be merged. The cells should not be merged to any other cell set. + * @return the remaining visible cell after the merge + * + * @see #join(Set) + * @see com.vaadin.ui.AbstractComponent#setCaption(String) setCaption + */ + @Override + public Grid.FooterCell join(Grid.FooterCell... cellsToMerge) { + Set<Grid.FooterCell> footerCells = new HashSet<>(Arrays.asList(cellsToMerge)); + return join(footerCells); + } + + } @Override diff --git a/server/src/main/java/com/vaadin/ui/components/grid/Header.java b/server/src/main/java/com/vaadin/ui/components/grid/Header.java index 6a4b72c5f9..5236a200fa 100644 --- a/server/src/main/java/com/vaadin/ui/components/grid/Header.java +++ b/server/src/main/java/com/vaadin/ui/components/grid/Header.java @@ -87,11 +87,16 @@ public abstract class Header extends StaticSection<Header.Row> { } /** - * Merges columns cells in a row + * Merges column cells in the row. Original cells are hidden, and new merged cell is shown instead. + * The cell has a width of all merged cells together, inherits styles of the first merged cell + * but has empty caption. * * @param cellsToMerge - * the cells which should be merged + * the cells which should be merged. The cells should not be merged to any other cell set. * @return the remaining visible cell after the merge + * + * @see #join(Grid.HeaderCell...) + * @see com.vaadin.ui.AbstractComponent#setCaption(String) setCaption */ @Override public Grid.HeaderCell join(Set<Grid.HeaderCell> cellsToMerge) { @@ -112,11 +117,16 @@ public abstract class Header extends StaticSection<Header.Row> { } /** - * Merges columns cells in a row + * Merges column cells in the row. Original cells are hidden, and new merged cell is shown instead. + * The cell has a width of all merged cells together, inherits styles of the first merged cell + * but has empty caption. * * @param cellsToMerge - * the cells which should be merged + * the cells which should be merged. The cells should not be merged to any other cell set. * @return the remaining visible cell after the merge + * + * @see #join(Set) + * @see com.vaadin.ui.AbstractComponent#setCaption(String) setCaption */ @Override public Grid.HeaderCell join(Grid.HeaderCell... cellsToMerge) { diff --git a/uitest/src/main/java/com/vaadin/tests/components/grid/basics/GridBasics.java b/uitest/src/main/java/com/vaadin/tests/components/grid/basics/GridBasics.java index 4f36eb6207..a39ff27e88 100644 --- a/uitest/src/main/java/com/vaadin/tests/components/grid/basics/GridBasics.java +++ b/uitest/src/main/java/com/vaadin/tests/components/grid/basics/GridBasics.java @@ -547,6 +547,16 @@ public class GridBasics extends AbstractTestUIWithLog { headerRow.join(toMerge).setText(jointCellText); } + private void mergeFooterСells(int rowIndex, String jointCellText, int... columnIndexes) { + FooterRow footerRow = grid.getFooterRow(rowIndex); + List<Column<DataObject, ?>> columns = grid.getColumns(); + Set<Grid.FooterCell> toMerge = new HashSet<>(); + for (int columnIndex : columnIndexes) { + toMerge.add(footerRow.getCell(columns.get(columnIndex))); + } + footerRow.join(toMerge).setText(jointCellText); + } + private void createFooterMenu(MenuItem footerMenu) { footerMenu.addItem("Add default footer row", menuItem -> { FooterRow defaultFooter = grid.appendFooterRow(); @@ -574,6 +584,15 @@ public class GridBasics extends AbstractTestUIWithLog { footerMenu.addItem("Remove first footer row", menuItem -> { grid.removeFooterRow(0); }); + footerMenu.addItem("Merge Footer Cells [0,0..1]", menuItem -> { + mergeFooterСells(0, "0+1", 0, 1); + }); + footerMenu.addItem("Merge Footer Cells [1,1..3]", menuItem -> { + mergeFooterСells(1, "1+2+3", 1, 2, 3); + }); + footerMenu.addItem("Merge Footer Cells [0,6..7]", menuItem -> { + mergeFooterСells(0, "6+7", 6, 7); + }); } /* DetailsGenerator related things */ diff --git a/uitest/src/test/java/com/vaadin/tests/components/grid/basics/GridHeaderFooterTest.java b/uitest/src/test/java/com/vaadin/tests/components/grid/basics/GridHeaderFooterTest.java index 94f30fe279..5e2b0eb9f7 100644 --- a/uitest/src/test/java/com/vaadin/tests/components/grid/basics/GridHeaderFooterTest.java +++ b/uitest/src/test/java/com/vaadin/tests/components/grid/basics/GridHeaderFooterTest.java @@ -265,16 +265,25 @@ public class GridHeaderFooterTest extends GridBasicsTest { selectMenuPath("Component", "Header", "Append header row"); selectMenuPath("Component", "Header", "Merge Header Cells [0,0..1]"); - GridCellElement c00 = getGridElement().getHeaderCell(0, 0); - assertEquals("0+1", c00.getText()); - assertEquals("Colspan of cell [0,0]", "2", c00.getAttribute("colspan")); + selectMenuPath("Component", "Footer", "Append footer row"); + selectMenuPath("Component", "Footer", "Merge Footer Cells [0,0..1]"); + + checkMergedHeaderFooter(); selectMenuPath("Component", "Columns", "Column 1", "Remove"); selectMenuPath("Component", "Header", "Append header row"); + selectMenuPath("Component", "Footer", "Append footer row"); + + checkHeaderAfterDelete(); + checkFooterAfterDelete(); + + } + private void checkHeaderAfterDelete() { + GridCellElement c00; c00 = getGridElement().getHeaderCell(0, 0); assertEquals("Column 0", c00.getText()); - assertEquals("Colspan of cell [0,0]", "1", c00.getAttribute("colspan")); + assertEquals("Colspan of header cell [0,0]", "1", c00.getAttribute("colspan")); GridCellElement c01 = getGridElement().getHeaderCell(0, 1); assertEquals("Column 2", c01.getText()); @@ -290,8 +299,33 @@ public class GridHeaderFooterTest extends GridBasicsTest { GridCellElement c21 = getGridElement().getHeaderCell(2, 1); assertEquals("Header cell 1", c21.getText()); + } + + private void checkFooterAfterDelete() { + GridCellElement c10; + //footer has an invisible first row + c10 = getGridElement().getFooterCell(1, 0); + assertEquals("Footer cell 0", c10.getText()); + assertEquals("Colspan of footer cell [0,0]", "1", c10.getAttribute("colspan")); + GridCellElement c11 = getGridElement().getFooterCell(1, 1); + assertEquals("Footer cell 2", c11.getText()); + GridCellElement c20 = getGridElement().getFooterCell(2, 0); + assertEquals("Footer cell 0", c20.getText()); + + GridCellElement c21 = getGridElement().getFooterCell(2, 1); + assertEquals("Footer cell 1", c21.getText()); + } + + private void checkMergedHeaderFooter() { + GridCellElement c00 = getGridElement().getHeaderCell(0, 0); + assertEquals("0+1", c00.getText()); + assertEquals("Colspan of header cell [0,0]", "2", c00.getAttribute("colspan")); + + c00 = getGridElement().getFooterCell(0, 0); + assertEquals("0+1", c00.getText()); + assertEquals("Colspan of footer cell [0,0]", "2", c00.getAttribute("colspan")); } @Test @@ -315,6 +349,27 @@ public class GridHeaderFooterTest extends GridBasicsTest { } + @Test + public void testFooterMerge() { + selectMenuPath("Component", "Footer", "Append footer row"); + selectMenuPath("Component", "Footer", "Merge Footer Cells [0,0..1]"); + selectMenuPath("Component", "Footer", "Merge Footer Cells [1,1..3]"); + selectMenuPath("Component", "Footer", "Merge Footer Cells [0,6..7]"); + + GridCellElement mergedCell1 = getGridElement().getFooterCell(0, 0); + assertEquals("0+1", mergedCell1.getText()); + assertEquals("Colspan, cell [0,0]", "2", mergedCell1.getAttribute("colspan")); + + GridCellElement mergedCell2 = getGridElement().getFooterCell(1, 1); + assertEquals("1+2+3", mergedCell2.getText()); + assertEquals("Colspan of cell [1,1]", "3", mergedCell2.getAttribute("colspan")); + + GridCellElement mergedCell3 = getGridElement().getFooterCell(0, 6); + assertEquals("6+7", mergedCell3.getText()); + assertEquals("Colspan of cell [0,6]", "2", mergedCell3.getAttribute("colspan")); + + } + private void toggleColumnHidable(int index) { selectMenuPath("Component", "Columns", "Column " + index, "Hidable"); } |