aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJohn Ahlroos <john@vaadin.com>2014-07-28 16:26:01 +0300
committerJohn Ahlroos <john@vaadin.com>2014-07-29 13:23:07 +0300
commit64caee7afa90ac8b16ba48e768204aa36248ecbe (patch)
tree726245ba7c945140ea2880b8b47e9510102bbf95
parentcfad6d54de44fead836ec9355bbc77c06fa26a40 (diff)
downloadvaadin-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
-rw-r--r--client/src/com/vaadin/client/ui/grid/Grid.java11
-rw-r--r--client/src/com/vaadin/client/ui/grid/GridConnector.java2
-rw-r--r--client/src/com/vaadin/client/ui/grid/GridFooter.java2
-rw-r--r--client/src/com/vaadin/client/ui/grid/GridHeader.java6
-rw-r--r--client/src/com/vaadin/client/ui/grid/GridStaticSection.java135
-rw-r--r--uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridFooterTest.java55
-rw-r--r--uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridHeaderTest.java51
-rw-r--r--uitest/src/com/vaadin/tests/widgetset/client/grid/GridBasicClientFeatures.java79
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}
*/