diff options
author | John Ahlroos <john@vaadin.com> | 2014-07-28 16:26:01 +0300 |
---|---|---|
committer | John Ahlroos <john@vaadin.com> | 2014-07-29 13:23:07 +0300 |
commit | 64caee7afa90ac8b16ba48e768204aa36248ecbe (patch) | |
tree | 726245ba7c945140ea2880b8b47e9510102bbf95 | |
parent | cfad6d54de44fead836ec9355bbc77c06fa26a40 (diff) | |
download | vaadin-framework-64caee7afa90ac8b16ba48e768204aa36248ecbe.tar.gz vaadin-framework-64caee7afa90ac8b16ba48e768204aa36248ecbe.zip |
Allow merging header and footer cells again #13334
This changeset adds the possibility to merge header and footer cells by
using HeaderRow.join().
Note: Currently this does not support hidden columns, support for it
should be added in a later changeset.
Change-Id: I42e089ef2ac6eea304e355423b274159a79baa89
8 files changed, 323 insertions, 18 deletions
diff --git a/client/src/com/vaadin/client/ui/grid/Grid.java b/client/src/com/vaadin/client/ui/grid/Grid.java index ff75417c12..1e310e3ec4 100644 --- a/client/src/com/vaadin/client/ui/grid/Grid.java +++ b/client/src/com/vaadin/client/ui/grid/Grid.java @@ -46,6 +46,7 @@ import com.vaadin.client.data.DataChangeHandler; import com.vaadin.client.data.DataSource; import com.vaadin.client.ui.SubPartAware; import com.vaadin.client.ui.grid.GridHeader.HeaderRow; +import com.vaadin.client.ui.grid.GridStaticSection.StaticCell; import com.vaadin.client.ui.grid.renderers.ComplexRenderer; import com.vaadin.client.ui.grid.renderers.TextRenderer; import com.vaadin.client.ui.grid.renderers.WidgetRenderer; @@ -1436,9 +1437,15 @@ public class Grid<T> extends Composite implements final List<Integer> columnIndices = getVisibleColumnIndices(); for (FlyweightCell cell : cellsToUpdate) { + int index = columnIndices.get(cell.getColumn()); - gridRow.getRenderer().render(cell, - gridRow.getCell(index).getText()); + StaticCell metadata = gridRow.getCell(index); + + // Assign colspan to cell before rendering + cell.setColSpan(metadata.getColspan()); + + // Render + gridRow.getRenderer().render(cell, metadata.getText()); activeCellHandler.updateActiveCellStyle(cell, container); } diff --git a/client/src/com/vaadin/client/ui/grid/GridConnector.java b/client/src/com/vaadin/client/ui/grid/GridConnector.java index 3c7629a60d..458dc7e1d2 100644 --- a/client/src/com/vaadin/client/ui/grid/GridConnector.java +++ b/client/src/com/vaadin/client/ui/grid/GridConnector.java @@ -377,7 +377,7 @@ public class GridConnector extends AbstractComponentConnector { section.setVisible(state.visible); - section.refreshGrid(); + section.refreshSection(); } /** diff --git a/client/src/com/vaadin/client/ui/grid/GridFooter.java b/client/src/com/vaadin/client/ui/grid/GridFooter.java index 7f478f7d29..eba6ad81cb 100644 --- a/client/src/com/vaadin/client/ui/grid/GridFooter.java +++ b/client/src/com/vaadin/client/ui/grid/GridFooter.java @@ -56,7 +56,7 @@ public class GridFooter extends GridStaticSection<GridFooter.FooterRow> { } @Override - protected void refreshGrid() { + protected void refreshSection() { getGrid().refreshFooter(); } } diff --git a/client/src/com/vaadin/client/ui/grid/GridHeader.java b/client/src/com/vaadin/client/ui/grid/GridHeader.java index c5b0febeca..4e046873f4 100644 --- a/client/src/com/vaadin/client/ui/grid/GridHeader.java +++ b/client/src/com/vaadin/client/ui/grid/GridHeader.java @@ -24,7 +24,7 @@ import com.vaadin.client.ui.grid.Grid.AbstractGridColumn.SortableColumnHeaderRen * * TODO Arbitrary number of header rows (zero included, one by default) * - * TODO Merging header cells + * TODO Account for hidden columns when merging header cells * * TODO "Default" row with sorting * @@ -114,7 +114,7 @@ public class GridHeader extends GridStaticSection<GridHeader.HeaderRow> { row.setDefault(true); } defaultRow = row; - refreshGrid(); + refreshSection(); } /** @@ -133,7 +133,7 @@ public class GridHeader extends GridStaticSection<GridHeader.HeaderRow> { } @Override - protected void refreshGrid() { + protected void refreshSection() { getGrid().refreshHeader(); } } diff --git a/client/src/com/vaadin/client/ui/grid/GridStaticSection.java b/client/src/com/vaadin/client/ui/grid/GridStaticSection.java index 4318811ca2..fa4f3e5ea0 100644 --- a/client/src/com/vaadin/client/ui/grid/GridStaticSection.java +++ b/client/src/com/vaadin/client/ui/grid/GridStaticSection.java @@ -16,6 +16,9 @@ package com.vaadin.client.ui.grid; import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.HashSet; import java.util.List; import com.vaadin.client.ui.grid.renderers.TextRenderer; @@ -41,17 +44,19 @@ abstract class GridStaticSection<ROWTYPE extends GridStaticSection.StaticRow<?>> private String text = ""; + private int colspan = 1; + private GridStaticSection<?> section; /** * Sets the text displayed in this cell. - * + * * @param text * a plain text caption */ public void setText(String text) { this.text = text; - section.refreshGrid(); + section.refreshSection(); } /** @@ -72,6 +77,21 @@ abstract class GridStaticSection<ROWTYPE extends GridStaticSection.StaticRow<?>> this.section = section; } + /** + * @return the colspan + */ + public int getColspan() { + return colspan; + } + + /** + * @param colspan + * the colspan to set + */ + public void setColspan(int colspan) { + this.colspan = colspan; + } + } /** @@ -88,6 +108,8 @@ abstract class GridStaticSection<ROWTYPE extends GridStaticSection.StaticRow<?>> private GridStaticSection<?> section; + private Collection<List<CELLTYPE>> cellGroups = new HashSet<List<CELLTYPE>>(); + /** * Returns the cell at the given position in this row. * @@ -101,6 +123,105 @@ abstract class GridStaticSection<ROWTYPE extends GridStaticSection.StaticRow<?>> return cells.get(index); } + /** + * Merges cells in a row + * + * @param cells + * The cells to be merged + * @return The first cell of the merged cells + */ + protected CELLTYPE join(List<CELLTYPE> cells) { + assert cells.size() > 1 : "You cannot merge less than 2 cells together"; + + // Ensure no cell is already grouped + for (CELLTYPE cell : cells) { + if (getCellGroupForCell(cell) != null) { + throw new IllegalStateException("Cell " + cell.getText() + + " is already grouped."); + } + } + + // Ensure continuous range + int firstCellIndex = this.cells.indexOf(cells.get(0)); + for (int i = 0; i < cells.size(); i++) { + if (this.cells.get(firstCellIndex + i) != cells.get(i)) { + throw new IllegalStateException( + "Cell range must be a continous range"); + } + } + + // Create a new group + cellGroups.add(new ArrayList<CELLTYPE>(cells)); + + calculateColspans(); + + getSection().refreshSection(); + + // Returns first cell of group + return cells.get(0); + } + + /** + * Merges columns cells in a row + * + * @param columns + * The columns which header should be merged + * @return The remaining visible cell after the merge + */ + public CELLTYPE join(GridColumn<?, ?>... columns) { + assert columns.length > 1 : "You cannot merge less than 2 columns together"; + + // Convert columns to cells + List<CELLTYPE> cells = new ArrayList<CELLTYPE>(); + for (GridColumn<?, ?> c : columns) { + int index = getSection().getGrid().getColumns().indexOf(c); + cells.add(this.cells.get(index)); + } + + return join(cells); + } + + /** + * Merges columns cells in a row + * + * @param cells + * The cells to merge. Must be from the same row. + * @return The remaining visible cell after the merge + */ + public CELLTYPE join(CELLTYPE... cells) { + return join(Arrays.asList(cells)); + } + + private List<CELLTYPE> getCellGroupForCell(CELLTYPE cell) { + for (List<CELLTYPE> group : cellGroups) { + if (group.contains(cell)) { + return group; + } + } + return null; + } + + private void calculateColspans() { + // Reset all cells + for (CELLTYPE cell : cells) { + cell.setColspan(1); + } + + // Set colspan for grouped cells + for (List<CELLTYPE> group : cellGroups) { + for (int i = 0; i < group.size(); i++) { + CELLTYPE cell = group.get(i); + if (i == 0) { + // Assign full colspan to first cell + cell.setColspan(group.size()); + } else { + // Hide other cells + cell.setColspan(0); + } + } + } + } + protected void addCell(int index) { CELLTYPE cell = createCell(); cell.setSection(getSection()); @@ -146,7 +267,7 @@ abstract class GridStaticSection<ROWTYPE extends GridStaticSection.StaticRow<?>> /** * Informs the grid that this section should be re-rendered. */ - protected abstract void refreshGrid(); + protected abstract void refreshSection(); /** * Sets the visibility of the whole section. @@ -156,7 +277,7 @@ abstract class GridStaticSection<ROWTYPE extends GridStaticSection.StaticRow<?>> */ public void setVisible(boolean visible) { this.visible = visible; - refreshGrid(); + refreshSection(); } /** @@ -185,7 +306,7 @@ abstract class GridStaticSection<ROWTYPE extends GridStaticSection.StaticRow<?>> row.addCell(i); } rows.add(index, row); - refreshGrid(); + refreshSection(); return row; } @@ -218,12 +339,12 @@ abstract class GridStaticSection<ROWTYPE extends GridStaticSection.StaticRow<?>> */ public void removeRow(int index) { rows.remove(index); - refreshGrid(); + refreshSection(); } /** * Removes the given row from the section. - * + * * @param row * the row to be removed * diff --git a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridFooterTest.java b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridFooterTest.java index f7dd85e3c3..e117ed5fbb 100644 --- a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridFooterTest.java +++ b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridFooterTest.java @@ -16,9 +16,13 @@ package com.vaadin.tests.components.grid.basicfeatures; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; import org.junit.Test; +import com.vaadin.tests.components.grid.GridElement.GridCellElement; + public class GridFooterTest extends GridStaticSectionTest { @Test @@ -85,6 +89,57 @@ public class GridFooterTest extends GridStaticSectionTest { assertFooterCount(0); } + @Test + public void joinColumnsByCells() throws Exception { + openTestURL(); + + selectMenuPath("Component", "Footer", "Append row"); + + selectMenuPath("Component", "Footer", "Row 1", "Join column cells 0, 1"); + + GridCellElement spannedCell = getGridElement().getFooterCell(0, 0); + assertTrue(spannedCell.isDisplayed()); + assertEquals("2", spannedCell.getAttribute("colspan")); + + GridCellElement hiddenCell = getGridElement().getFooterCell(0, 1); + assertFalse(hiddenCell.isDisplayed()); + } + + @Test + public void joinColumnsByColumns() throws Exception { + openTestURL(); + + selectMenuPath("Component", "Footer", "Append row"); + + selectMenuPath("Component", "Footer", "Row 1", "Join columns 1, 2"); + + GridCellElement spannedCell = getGridElement().getFooterCell(0, 1); + assertTrue(spannedCell.isDisplayed()); + assertEquals("2", spannedCell.getAttribute("colspan")); + + GridCellElement hiddenCell = getGridElement().getFooterCell(0, 2); + assertFalse(hiddenCell.isDisplayed()); + } + + @Test + public void joinAllColumnsInRow() throws Exception { + openTestURL(); + + selectMenuPath("Component", "Footer", "Append row"); + + selectMenuPath("Component", "Footer", "Row 1", "Join all columns"); + + GridCellElement spannedCell = getGridElement().getFooterCell(0, 0); + assertTrue(spannedCell.isDisplayed()); + assertEquals("11", spannedCell.getAttribute("colspan")); + + for (int columnIndex = 1; columnIndex < 11; columnIndex++) { + GridCellElement hiddenCell = getGridElement().getFooterCell(0, + columnIndex); + assertFalse(hiddenCell.isDisplayed()); + } + } + private void assertFooterCount(int count) { assertEquals("footer count", count, getGridElement().getFooterCount()); } diff --git a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridHeaderTest.java b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridHeaderTest.java index 1b27350f25..771c0da810 100644 --- a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridHeaderTest.java +++ b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridHeaderTest.java @@ -159,6 +159,57 @@ public class GridHeaderTest extends GridStaticSectionTest { assertFalse(hasClassName(headerCell, "sort-desc")); } + @Test + public void joinHeaderColumnsByCells() throws Exception { + openTestURL(); + + selectMenuPath("Component", "Header", "Append row"); + + selectMenuPath("Component", "Header", "Row 2", "Join column cells 0, 1"); + + GridCellElement spannedCell = getGridElement().getHeaderCell(1, 0); + assertTrue(spannedCell.isDisplayed()); + assertEquals("2", spannedCell.getAttribute("colspan")); + + GridCellElement hiddenCell = getGridElement().getHeaderCell(1, 1); + assertFalse(hiddenCell.isDisplayed()); + } + + @Test + public void joinHeaderColumnsByColumns() throws Exception { + openTestURL(); + + selectMenuPath("Component", "Header", "Append row"); + + selectMenuPath("Component", "Header", "Row 2", "Join columns 1, 2"); + + GridCellElement spannedCell = getGridElement().getHeaderCell(1, 1); + assertTrue(spannedCell.isDisplayed()); + assertEquals("2", spannedCell.getAttribute("colspan")); + + GridCellElement hiddenCell = getGridElement().getHeaderCell(1, 2); + assertFalse(hiddenCell.isDisplayed()); + } + + @Test + public void joinAllColumnsInHeaderRow() throws Exception { + openTestURL(); + + selectMenuPath("Component", "Header", "Append row"); + + selectMenuPath("Component", "Header", "Row 2", "Join all columns"); + + GridCellElement spannedCell = getGridElement().getHeaderCell(1, 0); + assertTrue(spannedCell.isDisplayed()); + assertEquals("11", spannedCell.getAttribute("colspan")); + + for (int columnIndex = 1; columnIndex < 11; columnIndex++) { + GridCellElement hiddenCell = getGridElement().getHeaderCell(1, + columnIndex); + assertFalse(hiddenCell.isDisplayed()); + } + } + private void assertHeaderCount(int count) { assertEquals("header count", count, getGridElement().getHeaderCount()); } diff --git a/uitest/src/com/vaadin/tests/widgetset/client/grid/GridBasicClientFeatures.java b/uitest/src/com/vaadin/tests/widgetset/client/grid/GridBasicClientFeatures.java index e013306dc0..b6dfdc8635 100644 --- a/uitest/src/com/vaadin/tests/widgetset/client/grid/GridBasicClientFeatures.java +++ b/uitest/src/com/vaadin/tests/widgetset/client/grid/GridBasicClientFeatures.java @@ -311,13 +311,13 @@ public class GridBasicClientFeatures extends addMenuCommand("Prepend row", new ScheduledCommand() { @Override public void execute() { - setHeaderTexts(header.prependRow()); + configureHeaderRow(header.prependRow()); } }, menuPath); addMenuCommand("Append row", new ScheduledCommand() { @Override public void execute() { - setHeaderTexts(header.appendRow()); + configureHeaderRow(header.appendRow()); } }, menuPath); addMenuCommand("Remove top row", new ScheduledCommand() { @@ -332,6 +332,42 @@ public class GridBasicClientFeatures extends header.removeRow(header.getRowCount() - 1); } }, menuPath); + + } + + private void configureHeaderRow(final HeaderRow row) { + final GridHeader header = grid.getHeader(); + setHeaderTexts(row); + String rowTitle = "Row " + header.getRowCount(); + final String[] menuPath = { "Component", "Header", rowTitle }; + + addMenuCommand("Join column cells 0, 1", new ScheduledCommand() { + + @Override + public void execute() { + row.join(row.getCell(0), row.getCell(1)); + + } + }, menuPath); + + addMenuCommand("Join columns 1, 2", new ScheduledCommand() { + + @Override + public void execute() { + row.join(grid.getColumn(1), grid.getColumn(2)); + + } + }, menuPath); + + addMenuCommand("Join all columns", new ScheduledCommand() { + + @Override + public void execute() { + row.join(grid.getColumns().toArray( + new GridColumn[grid.getColumnCount()])); + + } + }, menuPath); } private void createFooterMenu() { @@ -348,13 +384,13 @@ public class GridBasicClientFeatures extends addMenuCommand("Prepend row", new ScheduledCommand() { @Override public void execute() { - setFooterTexts(footer.prependRow()); + configureFooterRow(footer.prependRow()); } }, menuPath); addMenuCommand("Append row", new ScheduledCommand() { @Override public void execute() { - setFooterTexts(footer.appendRow()); + configureFooterRow(footer.appendRow()); } }, menuPath); addMenuCommand("Remove top row", new ScheduledCommand() { @@ -371,6 +407,41 @@ public class GridBasicClientFeatures extends }, menuPath); } + private void configureFooterRow(final FooterRow row) { + final GridFooter footer = grid.getFooter(); + setFooterTexts(row); + String rowTitle = "Row " + footer.getRowCount(); + final String[] menuPath = { "Component", "Footer", rowTitle }; + + addMenuCommand("Join column cells 0, 1", new ScheduledCommand() { + + @Override + public void execute() { + row.join(row.getCell(0), row.getCell(1)); + + } + }, menuPath); + + addMenuCommand("Join columns 1, 2", new ScheduledCommand() { + + @Override + public void execute() { + row.join(grid.getColumn(1), grid.getColumn(2)); + + } + }, menuPath); + + addMenuCommand("Join all columns", new ScheduledCommand() { + + @Override + public void execute() { + row.join(grid.getColumns().toArray( + new GridColumn[grid.getColumnCount()])); + + } + }, menuPath); + } + /** * Creates a a renderer for a {@link Renderers} */ |