aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTeemu Suo-Anttila <teemusa@vaadin.com>2015-04-10 14:55:31 +0300
committerTeemu Suo-Anttila <teemusa@vaadin.com>2015-04-14 16:19:30 +0300
commitcda732dd1f5110ef60cdc9f1848e83cea6ebd830 (patch)
tree6cd91a280d5dc7fbe0b45127b3ce71ded01620ae
parent9298d87e5c0c2fd14278e96af3d49a7a7a092dd2 (diff)
downloadvaadin-framework-cda732dd1f5110ef60cdc9f1848e83cea6ebd830.tar.gz
vaadin-framework-cda732dd1f5110ef60cdc9f1848e83cea6ebd830.zip
Fix Grid Header/Footer declarative support (#16596)
Change-Id: Iedd02738840b4d1a82681cf090c744f07166fdd4
-rw-r--r--server/src/com/vaadin/ui/Grid.java251
-rw-r--r--server/tests/src/com/vaadin/tests/server/component/grid/declarative/GridColumnDeclarativeTest.java4
-rw-r--r--server/tests/src/com/vaadin/tests/server/component/grid/declarative/GridDeclarativeTestBase.java85
-rw-r--r--server/tests/src/com/vaadin/tests/server/component/grid/declarative/GridHeaderFooterDeclarativeTest.java267
4 files changed, 602 insertions, 5 deletions
diff --git a/server/src/com/vaadin/ui/Grid.java b/server/src/com/vaadin/ui/Grid.java
index d3578d8f98..3b602abf1a 100644
--- a/server/src/com/vaadin/ui/Grid.java
+++ b/server/src/com/vaadin/ui/Grid.java
@@ -31,6 +31,7 @@ import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
+import java.util.Map.Entry;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;
@@ -1286,7 +1287,7 @@ public class Grid extends AbstractComponent implements SelectionNotifier,
* @param <ROWTYPE>
* the type of the rows in the section
*/
- protected static abstract class StaticSection<ROWTYPE extends StaticSection.StaticRow<?>>
+ abstract static class StaticSection<ROWTYPE extends StaticSection.StaticRow<?>>
implements Serializable {
/**
@@ -1458,6 +1459,86 @@ public class Grid extends AbstractComponent implements SelectionNotifier,
getRowState().styleName = styleName;
}
+ /**
+ * Writes the declarative design to the given table row element.
+ *
+ * @since
+ * @param trElement
+ * Element to write design to
+ * @param designContext
+ * the design context
+ */
+ protected void writeDesign(Element trElement,
+ DesignContext designContext) {
+ Set<CELLTYPE> visited = new HashSet<CELLTYPE>();
+ for (Grid.Column column : section.grid.getColumns()) {
+ CELLTYPE cell = getCell(column.getPropertyId());
+ if (visited.contains(cell)) {
+ continue;
+ }
+ visited.add(cell);
+
+ Element cellElement = trElement
+ .appendElement(getCellTagName());
+ cell.writeDesign(cellElement, designContext);
+
+ for (Entry<Set<CELLTYPE>, CELLTYPE> entry : cellGroups
+ .entrySet()) {
+ if (entry.getValue() == cell) {
+ cellElement.attr("colspan", ""
+ + entry.getKey().size());
+ break;
+ }
+ }
+ }
+ }
+
+ /**
+ * Reads the declarative design from the given table row element.
+ *
+ * @since
+ * @param trElement
+ * Element to read design from
+ * @param designContext
+ * the design context
+ * @throws DesignException
+ * if the given table row contains unexpected children
+ */
+ protected void readDesign(Element trElement,
+ DesignContext designContext) throws DesignException {
+ Elements cellElements = trElement.children();
+ int totalColSpans = 0;
+ for (int i = 0; i < cellElements.size(); ++i) {
+ Element element = cellElements.get(i);
+ if (!element.tagName().equals(getCellTagName())) {
+ throw new DesignException(
+ "Unexpected element in tr while expecting "
+ + getCellTagName() + ": "
+ + element.tagName());
+ }
+
+ int columnIndex = i + totalColSpans;
+
+ int colspan = DesignAttributeHandler.readAttribute(
+ "colspan", element.attributes(), 1, int.class);
+
+ Set<CELLTYPE> cells = new HashSet<CELLTYPE>();
+ for (int c = 0; c < colspan; ++c) {
+ cells.add(getCell(section.grid.getColumns()
+ .get(columnIndex + c).getPropertyId()));
+ }
+
+ if (colspan > 1) {
+ totalColSpans += colspan - 1;
+ join(cells).readDesign(element, designContext);
+ } else {
+ cells.iterator().next()
+ .readDesign(element, designContext);
+ }
+ }
+ }
+
+ abstract protected String getCellTagName();
}
/**
@@ -1577,6 +1658,15 @@ public class Grid extends AbstractComponent implements SelectionNotifier,
}
/**
+ * Returns the type of content stored in this cell.
+ *
+ * @return cell content type
+ */
+ public GridStaticCellType getCellType() {
+ return cellState.type;
+ }
+
+ /**
* Returns the custom style name for this cell.
*
* @return the style name or null if no style name has been set
@@ -1604,6 +1694,57 @@ public class Grid extends AbstractComponent implements SelectionNotifier,
cellState.connector = null;
}
}
+
+ /**
+ * Writes the declarative design to the given table cell element.
+ *
+ * @since
+ * @param cellElement
+ * Element to write design to
+ * @param designContext
+ * the design context
+ */
+ protected void writeDesign(Element cellElement,
+ DesignContext designContext) {
+ switch (cellState.type) {
+ case TEXT:
+ DesignAttributeHandler.writeAttribute("plain-text",
+ cellElement.attributes(), "", null, String.class);
+ cellElement.appendText(getText());
+ break;
+ case HTML:
+ cellElement.append(getHtml());
+ break;
+ case WIDGET:
+ cellElement.appendChild(designContext
+ .createElement(getComponent()));
+ break;
+ }
+ }
+
+ /**
+ * Reads the declarative design from the given table cell element.
+ *
+ * @since
+ * @param cellElement
+ * Element to read design from
+ * @param designContext
+ * the design context
+ */
+ protected void readDesign(Element cellElement,
+ DesignContext designContext) {
+ if (!cellElement.hasAttr("plain-text")) {
+ if (cellElement.children().size() > 0
+ && cellElement.child(0).tagName().contains("-")) {
+ setComponent(designContext.readDesign(cellElement
+ .child(0)));
+ } else {
+ setHtml(cellElement.html());
+ }
+ } else {
+ setText(cellElement.html());
+ }
+ }
}
protected Grid grid;
@@ -1833,6 +1974,50 @@ public class Grid extends AbstractComponent implements SelectionNotifier,
}
return false;
}
+
+ /**
+ * Writes the declarative design to the given table section element.
+ *
+ * @since
+ * @param tableSectionElement
+ * Element to write design to
+ * @param designContext
+ * the design context
+ */
+ protected void writeDesign(Element tableSectionElement,
+ DesignContext designContext) {
+ for (ROWTYPE row : rows) {
+ row.writeDesign(tableSectionElement.appendElement("tr"),
+ designContext);
+ }
+ }
+
+ /**
+ * Writes the declarative design from the given table section element.
+ *
+ * @since
+ * @param tableSectionElement
+ * Element to read design from
+ * @param designContext
+ * the design context
+ * @throws DesignException
+ * if the table section contains unexpected children
+ */
+ protected void readDesign(Element tableSectionElement,
+ DesignContext designContext) throws DesignException {
+ while (rows.size() > 0) {
+ removeRow(0);
+ }
+
+ for (Element row : tableSectionElement.children()) {
+ if (!row.tagName().equals("tr")) {
+ throw new DesignException("Unexpected element in "
+ + tableSectionElement.tagName() + ": "
+ + row.tagName());
+ }
+ appendRow().readDesign(row, designContext);
+ }
+ }
}
/**
@@ -1930,6 +2115,16 @@ public class Grid extends AbstractComponent implements SelectionNotifier,
}
}
}
+
+ @Override
+ protected void readDesign(Element tableSectionElement,
+ DesignContext designContext) {
+ super.readDesign(tableSectionElement, designContext);
+
+ if (defaultRow == null && !rows.isEmpty()) {
+ grid.setDefaultHeaderRow(rows.get(0));
+ }
+ }
}
/**
@@ -1945,10 +2140,41 @@ public class Grid extends AbstractComponent implements SelectionNotifier,
getRowState().defaultRow = value;
}
+ private boolean isDefaultRow() {
+ return getRowState().defaultRow;
+ }
+
@Override
protected HeaderCell createCell() {
return new HeaderCell(this);
}
+
+ @Override
+ protected String getCellTagName() {
+ return "th";
+ }
+
+ @Override
+ protected void writeDesign(Element trElement,
+ DesignContext designContext) {
+ super.writeDesign(trElement, designContext);
+
+ if (section.grid.getDefaultHeaderRow() == this) {
+ DesignAttributeHandler.writeAttribute("default",
+ trElement.attributes(), true, null, boolean.class);
+ }
+ }
+
+ @Override
+ protected void readDesign(Element trElement, DesignContext designContext) {
+ super.readDesign(trElement, designContext);
+
+ boolean defaultRow = DesignAttributeHandler.readAttribute(
+ "default", trElement.attributes(), false, boolean.class);
+ if (defaultRow) {
+ section.grid.setDefaultHeaderRow(this);
+ }
+ }
}
/**
@@ -2005,6 +2231,11 @@ public class Grid extends AbstractComponent implements SelectionNotifier,
return new FooterCell(this);
}
+ @Override
+ protected String getCellTagName() {
+ return "td";
+ }
+
}
/**
@@ -5232,6 +5463,16 @@ public class Grid extends AbstractComponent implements SelectionNotifier,
addColumn(propertyId, String.class).readDesign(col, context);
++i;
}
+
+ for (Element child : table.children()) {
+ if (child.tagName().equals("thead")) {
+ header.readDesign(child, context);
+ } else if (child.tagName().equals("tbody")) {
+ // TODO: Inline data
+ } else if (child.tagName().equals("tfoot")) {
+ footer.readDesign(child, context);
+ }
+ }
}
}
@@ -5285,6 +5526,14 @@ public class Grid extends AbstractComponent implements SelectionNotifier,
column.writeDesign(colElement, context);
}
+ // Always write thead. Reads correctly when there no header rows
+ header.writeDesign(tableElement.appendElement("thead"), context);
+
+ // TODO: Body
+
+ if (footer.getRowCount() > 0) {
+ footer.writeDesign(tableElement.appendElement("tfoot"), context);
+ }
}
@Override
diff --git a/server/tests/src/com/vaadin/tests/server/component/grid/declarative/GridColumnDeclarativeTest.java b/server/tests/src/com/vaadin/tests/server/component/grid/declarative/GridColumnDeclarativeTest.java
index 735a1ab502..1c22a69571 100644
--- a/server/tests/src/com/vaadin/tests/server/component/grid/declarative/GridColumnDeclarativeTest.java
+++ b/server/tests/src/com/vaadin/tests/server/component/grid/declarative/GridColumnDeclarativeTest.java
@@ -29,6 +29,7 @@ public class GridColumnDeclarativeTest extends GridDeclarativeTestBase {
+ " <col sortable=false max-width='200' expand='2' property-id='Column2'>"
+ " <col sortable=true editable=false min-width='15' expand='1' property-id='Column3'>"
+ "</colgroup>" //
+ + "<thead />" //
+ "</table></v-grid>";
Grid grid = new Grid();
grid.addColumn("Column1", String.class).setWidth(100);
@@ -37,6 +38,9 @@ public class GridColumnDeclarativeTest extends GridDeclarativeTestBase {
grid.addColumn("Column3", String.class).setMinimumWidth(15)
.setExpandRatio(1).setEditable(false);
+ // Remove the default header
+ grid.removeHeaderRow(grid.getDefaultHeaderRow());
+
// Use the read grid component to do another pass on write.
testRead(design, grid, true);
testWrite(design, grid);
diff --git a/server/tests/src/com/vaadin/tests/server/component/grid/declarative/GridDeclarativeTestBase.java b/server/tests/src/com/vaadin/tests/server/component/grid/declarative/GridDeclarativeTestBase.java
index 56f4647e90..0a32ec1734 100644
--- a/server/tests/src/com/vaadin/tests/server/component/grid/declarative/GridDeclarativeTestBase.java
+++ b/server/tests/src/com/vaadin/tests/server/component/grid/declarative/GridDeclarativeTestBase.java
@@ -22,6 +22,10 @@ import org.junit.Assert;
import com.vaadin.tests.design.DeclarativeTestBase;
import com.vaadin.ui.Grid;
import com.vaadin.ui.Grid.Column;
+import com.vaadin.ui.Grid.FooterCell;
+import com.vaadin.ui.Grid.FooterRow;
+import com.vaadin.ui.Grid.HeaderCell;
+import com.vaadin.ui.Grid.HeaderRow;
public class GridDeclarativeTestBase extends DeclarativeTestBase<Grid> {
@@ -31,15 +35,88 @@ public class GridDeclarativeTestBase extends DeclarativeTestBase<Grid> {
}
public Grid testRead(String design, Grid expected, boolean retestWrite) {
- Grid readGrid = super.testRead(design, expected);
+ Grid actual = super.testRead(design, expected);
- compareGridColumns(expected, readGrid);
+ compareGridColumns(expected, actual);
+ compareHeaders(expected, actual);
+ compareFooters(expected, actual);
if (retestWrite) {
- testWrite(design, readGrid);
+ testWrite(design, actual);
}
- return readGrid;
+ return actual;
+ }
+
+ private void compareHeaders(Grid expected, Grid actual) {
+ Assert.assertEquals("Different header row count",
+ expected.getHeaderRowCount(), actual.getHeaderRowCount());
+ for (int i = 0; i < expected.getHeaderRowCount(); ++i) {
+ HeaderRow expectedRow = expected.getHeaderRow(i);
+ HeaderRow actualRow = actual.getHeaderRow(i);
+
+ if (expectedRow.equals(expected.getDefaultHeaderRow())) {
+ Assert.assertEquals("Different index for default header row",
+ actual.getDefaultHeaderRow(), actualRow);
+ }
+
+ for (Column c : expected.getColumns()) {
+ String baseError = "Difference when comparing cell for "
+ + c.toString() + " on header row " + i + ": ";
+ Object propertyId = c.getPropertyId();
+ HeaderCell expectedCell = expectedRow.getCell(propertyId);
+ HeaderCell actualCell = actualRow.getCell(propertyId);
+
+ switch (expectedCell.getCellType()) {
+ case TEXT:
+ Assert.assertEquals(baseError + "Text content",
+ expectedCell.getText(), actualCell.getText());
+ break;
+ case HTML:
+ Assert.assertEquals(baseError + "HTML content",
+ expectedCell.getHtml(), actualCell.getHtml());
+ break;
+ case WIDGET:
+ assertEquals(baseError + "Component content",
+ expectedCell.getComponent(),
+ actualCell.getComponent());
+ break;
+ }
+ }
+ }
+ }
+
+ private void compareFooters(Grid expected, Grid actual) {
+ Assert.assertEquals("Different footer row count",
+ expected.getFooterRowCount(), actual.getFooterRowCount());
+ for (int i = 0; i < expected.getFooterRowCount(); ++i) {
+ FooterRow expectedRow = expected.getFooterRow(i);
+ FooterRow actualRow = actual.getFooterRow(i);
+
+ for (Column c : expected.getColumns()) {
+ String baseError = "Difference when comparing cell for "
+ + c.toString() + " on footer row " + i + ": ";
+ Object propertyId = c.getPropertyId();
+ FooterCell expectedCell = expectedRow.getCell(propertyId);
+ FooterCell actualCell = actualRow.getCell(propertyId);
+
+ switch (expectedCell.getCellType()) {
+ case TEXT:
+ Assert.assertEquals(baseError + "Text content",
+ expectedCell.getText(), actualCell.getText());
+ break;
+ case HTML:
+ Assert.assertEquals(baseError + "HTML content",
+ expectedCell.getHtml(), actualCell.getHtml());
+ break;
+ case WIDGET:
+ assertEquals(baseError + "Component content",
+ expectedCell.getComponent(),
+ actualCell.getComponent());
+ break;
+ }
+ }
+ }
}
private void compareGridColumns(Grid expected, Grid actual) {
diff --git a/server/tests/src/com/vaadin/tests/server/component/grid/declarative/GridHeaderFooterDeclarativeTest.java b/server/tests/src/com/vaadin/tests/server/component/grid/declarative/GridHeaderFooterDeclarativeTest.java
new file mode 100644
index 0000000000..b4e82950cb
--- /dev/null
+++ b/server/tests/src/com/vaadin/tests/server/component/grid/declarative/GridHeaderFooterDeclarativeTest.java
@@ -0,0 +1,267 @@
+/*
+ * Copyright 2000-2014 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.server.component.grid.declarative;
+
+import org.junit.Test;
+
+import com.vaadin.shared.ui.label.ContentMode;
+import com.vaadin.ui.Grid;
+import com.vaadin.ui.Grid.Column;
+import com.vaadin.ui.Grid.FooterRow;
+import com.vaadin.ui.Grid.HeaderRow;
+import com.vaadin.ui.Label;
+
+public class GridHeaderFooterDeclarativeTest extends GridDeclarativeTestBase {
+
+ @Test
+ public void testSingleDefaultHeader() {
+ String design = "<v-grid><table>"//
+ + "<colgroup>"
+ + " <col sortable=true property-id='Column1'>"
+ + " <col sortable=true property-id='Column2'>"
+ + " <col sortable=true property-id='Column3'>"
+ + "</colgroup>" //
+ + "<thead>" //
+ + " <tr default='true'><th plain-text=''>Column1<th plain-text=''>Column2<th plain-text=''>Column3</tr>" //
+ + "</thead>" //
+ + "</table></v-grid>";
+ Grid grid = new Grid();
+ grid.addColumn("Column1", String.class);
+ grid.addColumn("Column2", String.class);
+ grid.addColumn("Column3", String.class);
+
+ testWrite(design, grid);
+ testRead(design, grid, true);
+ }
+
+ @Test
+ public void testSingleDefaultHTMLHeader() {
+ String design = "<v-grid><table>"//
+ + "<colgroup>"
+ + " <col sortable=true property-id='Column1'>"
+ + " <col sortable=true property-id='Column2'>"
+ + " <col sortable=true property-id='Column3'>"
+ + "</colgroup>" //
+ + "<thead>" //
+ + " <tr default='true'><th>Column1<th>Column2<th>Column3</tr>" //
+ + "</thead>" //
+ + "</table></v-grid>";
+ Grid grid = new Grid();
+ grid.addColumn("Column1", String.class);
+ grid.addColumn("Column2", String.class);
+ grid.addColumn("Column3", String.class);
+
+ HeaderRow row = grid.getDefaultHeaderRow();
+ for (Column c : grid.getColumns()) {
+ row.getCell(c.getPropertyId()).setHtml(c.getHeaderCaption());
+ }
+
+ testWrite(design, grid);
+ testRead(design, grid, true);
+ }
+
+ @Test
+ public void testNoHeaderRows() {
+ String design = "<v-grid><table>"//
+ + "<colgroup>"
+ + " <col sortable=true property-id='Column1'>"
+ + "</colgroup>" //
+ + "<thead />" //
+ + "</table></v-grid>";
+
+ Grid grid = new Grid();
+ grid.addColumn("Column1", String.class);
+ grid.removeHeaderRow(grid.getDefaultHeaderRow());
+
+ testWrite(design, grid);
+ testRead(design, grid, true);
+ }
+
+ @Test
+ public void testMultipleHeadersWithColSpans() {
+ String design = "<v-grid><table>"//
+ + "<colgroup>"
+ + " <col sortable=true property-id='Column1'>"
+ + " <col sortable=true property-id='Column2'>"
+ + " <col sortable=true property-id='Column3'>"
+ + "</colgroup>" //
+ + "<thead>" //
+ + " <tr><th colspan=3>Baz</tr>"
+ + " <tr default='true'><th>Column1<th>Column2<th>Column3</tr>" //
+ + " <tr><th>Foo<th colspan=2>Bar</tr>" //
+ + "</thead>" //
+ + "</table></v-grid>";
+ Grid grid = new Grid();
+ grid.addColumn("Column1", String.class);
+ grid.addColumn("Column2", String.class);
+ grid.addColumn("Column3", String.class);
+
+ HeaderRow row = grid.getDefaultHeaderRow();
+ for (Column c : grid.getColumns()) {
+ row.getCell(c.getPropertyId()).setHtml(c.getHeaderCaption());
+ }
+
+ grid.prependHeaderRow().join("Column1", "Column2", "Column3")
+ .setHtml("Baz");
+ row = grid.appendHeaderRow();
+ row.getCell("Column1").setHtml("Foo");
+ row.join("Column2", "Column3").setHtml("Bar");
+
+ testWrite(design, grid);
+ testRead(design, grid, true);
+ }
+
+ @Test
+ public void testSingleDefaultFooter() {
+ String design = "<v-grid><table>"//
+ + "<colgroup>"
+ + " <col sortable=true property-id='Column1'>"
+ + " <col sortable=true property-id='Column2'>"
+ + " <col sortable=true property-id='Column3'>"
+ + "</colgroup>" //
+ + "<thead />" // No headers read or written
+ + "<tfoot>" //
+ + " <tr><td plain-text=''>Column1<td plain-text=''>Column2<td plain-text=''>Column3</tr>" //
+ + "</tfoot>" //
+ + "</table></v-grid>";
+ Grid grid = new Grid();
+ grid.addColumn("Column1", String.class);
+ grid.addColumn("Column2", String.class);
+ grid.addColumn("Column3", String.class);
+
+ FooterRow row = grid.appendFooterRow();
+ for (Column c : grid.getColumns()) {
+ row.getCell(c.getPropertyId()).setText(c.getHeaderCaption());
+ }
+
+ grid.removeHeaderRow(grid.getDefaultHeaderRow());
+
+ testWrite(design, grid);
+ testRead(design, grid, true);
+ }
+
+ @Test
+ public void testSingleDefaultHTMLFooter() {
+ String design = "<v-grid><table>"//
+ + "<colgroup>"
+ + " <col sortable=true property-id='Column1'>"
+ + " <col sortable=true property-id='Column2'>"
+ + " <col sortable=true property-id='Column3'>"
+ + "</colgroup>" //
+ + "<thead />" // No headers read or written
+ + "<tfoot>" //
+ + " <tr><td>Column1<td>Column2<td>Column3</tr>" //
+ + "</tfoot>" //
+ + "</table></v-grid>";
+ Grid grid = new Grid();
+ grid.addColumn("Column1", String.class);
+ grid.addColumn("Column2", String.class);
+ grid.addColumn("Column3", String.class);
+
+ FooterRow row = grid.appendFooterRow();
+ for (Column c : grid.getColumns()) {
+ row.getCell(c.getPropertyId()).setHtml(c.getHeaderCaption());
+ }
+
+ grid.removeHeaderRow(grid.getDefaultHeaderRow());
+
+ testWrite(design, grid);
+ testRead(design, grid, true);
+ }
+
+ @Test
+ public void testMultipleFootersWithColSpans() {
+ String design = "<v-grid><table>"//
+ + "<colgroup>"
+ + " <col sortable=true property-id='Column1'>"
+ + " <col sortable=true property-id='Column2'>"
+ + " <col sortable=true property-id='Column3'>"
+ + "</colgroup>" //
+ + "<thead />" // No headers read or written.
+ + "<tfoot>" //
+ + " <tr><td colspan=3>Baz</tr>"
+ + " <tr><td>Column1<td>Column2<td>Column3</tr>" //
+ + " <tr><td>Foo<td colspan=2>Bar</tr>" //
+ + "</tfoot>" //
+ + "</table></v-grid>";
+ Grid grid = new Grid();
+ grid.addColumn("Column1", String.class);
+ grid.addColumn("Column2", String.class);
+ grid.addColumn("Column3", String.class);
+
+ FooterRow row = grid.appendFooterRow();
+ for (Column c : grid.getColumns()) {
+ row.getCell(c.getPropertyId()).setHtml(c.getHeaderCaption());
+ }
+
+ grid.prependFooterRow().join("Column1", "Column2", "Column3")
+ .setHtml("Baz");
+ row = grid.appendFooterRow();
+ row.getCell("Column1").setHtml("Foo");
+ row.join("Column2", "Column3").setHtml("Bar");
+
+ grid.removeHeaderRow(grid.getDefaultHeaderRow());
+
+ testWrite(design, grid);
+ testRead(design, grid, true);
+ }
+
+ @Test
+ public void testComponentInGridHeader() {
+ String design = "<v-grid><table>"//
+ + "<colgroup>"
+ + " <col sortable=true property-id='Column1'>"
+ + "</colgroup>" //
+ + "<thead>" //
+ + "<tr default=true><th><v-label><b>Foo</b></v-label></tr>"
+ + "</thead>"//
+ + "</table></v-grid>";
+
+ Label component = new Label("<b>Foo</b>");
+ component.setContentMode(ContentMode.HTML);
+
+ Grid grid = new Grid();
+ grid.addColumn("Column1", String.class);
+ grid.getDefaultHeaderRow().getCell("Column1").setComponent(component);
+
+ testRead(design, grid, true);
+ testWrite(design, grid);
+ }
+
+ @Test
+ public void testComponentInGridFooter() {
+ String design = "<v-grid><table>"//
+ + "<colgroup>"
+ + " <col sortable=true property-id='Column1'>"
+ + "</colgroup>" //
+ + "<thead />" // No headers read or written
+ + "<tfoot>" //
+ + "<tr><td><v-label><b>Foo</b></v-label></tr>"//
+ + "</tfoot>" //
+ + "</table></v-grid>";
+
+ Label component = new Label("<b>Foo</b>");
+ component.setContentMode(ContentMode.HTML);
+
+ Grid grid = new Grid();
+ grid.addColumn("Column1", String.class);
+ grid.prependFooterRow().getCell("Column1").setComponent(component);
+ grid.removeHeaderRow(grid.getDefaultHeaderRow());
+
+ testRead(design, grid, true);
+ testWrite(design, grid);
+ }
+}