diff options
author | Johannes Dahlström <johannesd@vaadin.com> | 2015-04-15 13:36:18 +0300 |
---|---|---|
committer | Vaadin Code Review <review@vaadin.com> | 2015-04-17 14:31:32 +0000 |
commit | ed4bec15a1fbc53a1818192644cdb86e0e2e30ee (patch) | |
tree | ccb65d62e45ef155bfdfcc25908c76ff546bd99c | |
parent | 2d3ed921065acd7761df07b9b403d111bedf33d9 (diff) | |
download | vaadin-framework-ed4bec15a1fbc53a1818192644cdb86e0e2e30ee.tar.gz vaadin-framework-ed4bec15a1fbc53a1818192644cdb86e0e2e30ee.zip |
Declarative read support for Table (#16367)
Change-Id: I2327af18b2e1e4d31a057b110eee9495f16d9633
4 files changed, 383 insertions, 1 deletions
diff --git a/server/src/com/vaadin/ui/AbstractSelect.java b/server/src/com/vaadin/ui/AbstractSelect.java index 6ac0dad5e4..0e3cfef4ce 100644 --- a/server/src/com/vaadin/ui/AbstractSelect.java +++ b/server/src/com/vaadin/ui/AbstractSelect.java @@ -2192,6 +2192,10 @@ public abstract class AbstractSelect extends AbstractField<Object> implements // handle default attributes super.readDesign(design, context); // handle children specifying selectable items (<option>) + readItems(design, context); + } + + protected void readItems(Element design, DesignContext context) { Set<String> selected = new HashSet<String>(); for (Element child : design.children()) { readItem(child, selected, context); diff --git a/server/src/com/vaadin/ui/Table.java b/server/src/com/vaadin/ui/Table.java index 347bb8fbff..202e58f0c9 100644 --- a/server/src/com/vaadin/ui/Table.java +++ b/server/src/com/vaadin/ui/Table.java @@ -34,6 +34,9 @@ import java.util.StringTokenizer; import java.util.logging.Level; import java.util.logging.Logger; +import org.jsoup.nodes.Element; +import org.jsoup.select.Elements; + import com.vaadin.data.Container; import com.vaadin.data.Item; import com.vaadin.data.Property; @@ -63,6 +66,9 @@ import com.vaadin.shared.MouseEventDetails; import com.vaadin.shared.ui.MultiSelectMode; import com.vaadin.shared.ui.table.TableConstants; import com.vaadin.shared.util.SharedUtil; +import com.vaadin.ui.declarative.DesignAttributeHandler; +import com.vaadin.ui.declarative.DesignContext; +import com.vaadin.ui.declarative.DesignException; /** * <p> @@ -3863,7 +3869,7 @@ public class Table extends AbstractSelect implements Action.Container, /** * Checks whether row headers are visible. - * + * * @return {@code false} if row headers are hidden, {@code true} otherwise * @since 7.3.9 */ @@ -6025,6 +6031,161 @@ public class Table extends AbstractSelect implements Action.Container, return iterator(); } + @Override + public void readDesign(Element design, DesignContext context) { + super.readDesign(design, context); + + if (design.hasAttr("sortable")) { + setSortEnabled(DesignAttributeHandler.readAttribute("sortable", + design.attributes(), boolean.class)); + } + + readColumns(design); + readHeader(design); + readBody(design); + readFooter(design); + } + + private void readColumns(Element design) { + Element colgroup = design.select("> table > colgroup").first(); + + if (colgroup != null) { + int i = 0; + List<Object> pIds = new ArrayList<Object>(); + for (Element col : colgroup.children()) { + if (!col.tagName().equals("col")) { + throw new DesignException("invalid column"); + } + + String id = DesignAttributeHandler.readAttribute("property-id", + col.attributes(), "property-" + i++, String.class); + pIds.add(id); + + addContainerProperty(id, String.class, null); + + if (col.hasAttr("width")) { + setColumnWidth( + id, + DesignAttributeHandler.readAttribute("width", + col.attributes(), Integer.class)); + } + if (col.hasAttr("center")) { + setColumnAlignment(id, Align.CENTER); + } else if (col.hasAttr("right")) { + setColumnAlignment(id, Align.RIGHT); + } + if (col.hasAttr("expand")) { + if (col.attr("expand").isEmpty()) { + setColumnExpandRatio(id, 1); + } else { + setColumnExpandRatio(id, + DesignAttributeHandler.readAttribute("expand", + col.attributes(), float.class)); + } + } + if (col.hasAttr("collapsible")) { + setColumnCollapsible(id, + DesignAttributeHandler.readAttribute("collapsible", + col.attributes(), boolean.class)); + } + if (col.hasAttr("collapsed")) { + setColumnCollapsed(id, + DesignAttributeHandler.readAttribute("collapsed", + col.attributes(), boolean.class)); + } + } + setVisibleColumns(pIds.toArray()); + } + } + + private void readFooter(Element design) { + readHeaderOrFooter(design, false); + } + + private void readHeader(Element design) { + readHeaderOrFooter(design, true); + } + + @Override + protected void readItems(Element design, DesignContext context) { + // Do nothing - header/footer and inline data must be handled after + // colgroup. + } + + private void readHeaderOrFooter(Element design, boolean header) { + String selector = header ? "> table > thead" : "> table > tfoot"; + Element elem = design.select(selector).first(); + if (elem != null) { + if (!header) { + setFooterVisible(true); + } + if (elem.children().size() != 1) { + throw new DesignException( + "Table header and footer should contain exactly one <tr> element"); + } + Element tr = elem.child(0); + Elements elems = tr.children(); + Collection<?> propertyIds = visibleColumns; + if (elems.size() != propertyIds.size()) { + throw new DesignException( + "Table header and footer should contain as many items as there" + + " are columns in the Table."); + } + Iterator<?> propertyIt = propertyIds.iterator(); + for (Element e : elems) { + String columnValue = e.html(); + Object propertyId = propertyIt.next(); + if (header) { + setColumnHeader(propertyId, columnValue); + if (e.hasAttr("icon")) { + setColumnIcon( + propertyId, + DesignAttributeHandler.readAttribute("icon", + e.attributes(), Resource.class)); + } + } else { + setColumnFooter(propertyId, columnValue); + } + } + } + } + + private void readBody(Element design) { + Element tbody = design.select("> table > tbody").first(); + if (tbody != null) { + for (Element row : tbody.children()) { + Elements cells = row.children(); + if (visibleColumns.size() != cells.size()) { + throw new DesignException( + "Wrong number of columns in a row of a Table. Expected " + + visibleColumns.size() + ", was " + + cells.size() + "."); + } + Object[] data = new String[cells.size()]; + for (int c = 0; c < cells.size(); ++c) { + data[c] = cells.get(c).html(); + } + Object itemId = addItem(data, null); + if (itemId == null) { + throw new DesignException( + "A row of a Table could not be read"); + } + } + } + } + + @Override + protected Collection<String> getCustomAttributes() { + Collection<String> result = super.getCustomAttributes(); + result.add("sortable"); + result.add("sort-enabled"); + result.add("sort-disabled"); + result.add("footer-visible"); + result.add("current-page-first-item-id"); + result.add("current-page-first-item-index"); + return result; + } + private final Logger getLogger() { if (logger == null) { logger = Logger.getLogger(Table.class.getName()); diff --git a/server/tests/src/com/vaadin/tests/server/component/table/TableDeclarativeTest.java b/server/tests/src/com/vaadin/tests/server/component/table/TableDeclarativeTest.java new file mode 100644 index 0000000000..27888dee14 --- /dev/null +++ b/server/tests/src/com/vaadin/tests/server/component/table/TableDeclarativeTest.java @@ -0,0 +1,165 @@ +/* + * 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.table; + +import java.io.UnsupportedEncodingException; + +import org.junit.Test; + +import com.vaadin.server.ExternalResource; +import com.vaadin.shared.ui.MultiSelectMode; +import com.vaadin.ui.Table; +import com.vaadin.ui.Table.Align; +import com.vaadin.ui.Table.ColumnHeaderMode; +import com.vaadin.ui.Table.RowHeaderMode; +import com.vaadin.ui.Table.TableDragMode; + +/** + * Test declarative support for {@link Table}. + * + * @since + * @author Vaadin Ltd + */ +public class TableDeclarativeTest extends TableDeclarativeTestBase { + + @Test + public void testBasicAttributes() { + + String design = "<v-table page-length=30 cache-rate=3 selectable editable sortable=false " + + "drag-mode=row multi-select-mode=simple column-header-mode=id " + + "column-reordering-allowed column-collapsing-allowed sort-ascending=false " + + "row-header-mode=id sort-container-property-id=foo />"; + + Table table = new Table(); + table.setPageLength(30); + table.setCacheRate(3); + table.setSelectable(true); + table.setEditable(true); + table.setSortEnabled(false); + table.setDragMode(TableDragMode.ROW); + table.setMultiSelectMode(MultiSelectMode.SIMPLE); + table.setColumnHeaderMode(ColumnHeaderMode.ID); + table.setRowHeaderMode(RowHeaderMode.ID); + table.setColumnReorderingAllowed(true); + table.setColumnCollapsingAllowed(true); + table.setSortAscending(false); + table.setSortContainerPropertyId("foo"); + + testRead(design, table); + // testWrite(design, table); + } + + @Test + public void testColumns() { + String design = "<v-table column-collapsing-allowed=true>" // + + " <table>" // + + " <colgroup>" + + " <col property-id='foo'>" + + " <col property-id='bar' center expand=1 collapsible=false>" + + " <col property-id='baz' right expand=2 collapsed=true>" + + " </colgroup>" // + + " </table>" // + + "</v-table>"; + + Table table = new Table(); + table.setColumnCollapsingAllowed(true); + + table.addContainerProperty("foo", String.class, null); + table.setColumnAlignment("foo", Align.LEFT); + table.setColumnExpandRatio("foo", 0); + + table.addContainerProperty("bar", String.class, null); + table.setColumnAlignment("bar", Align.CENTER); + table.setColumnExpandRatio("bar", 1); + table.setColumnCollapsible("bar", false); + + table.addContainerProperty("baz", String.class, null); + table.setColumnAlignment("baz", Align.RIGHT); + table.setColumnExpandRatio("baz", 2); + table.setColumnCollapsed("baz", true); + + testRead(design, table); + // testWrite(design, table); + } + + @Test + public void testHeadersFooters() { + String design = "<v-table>" // + + " <table>" // + + " <colgroup><col property-id=foo><col property-id=bar></colgroup>" // + + " <thead>" // + + " <tr><th icon='http://example.com/icon.png'>FOO<th>BAR" // + + " </thead>" // + + " <tfoot>" // + + " <tr><td>foo<td>bar" // + + " </tfoot>" // + + " </table>" // + + "</v-table>"; + + Table table = new Table(); + table.setFooterVisible(true); + + table.addContainerProperty("foo", String.class, null); + table.setColumnHeader("foo", "FOO"); + table.setColumnIcon("foo", new ExternalResource( + "http://example.com/icon.png")); + table.setColumnFooter("foo", "foo"); + + table.addContainerProperty("bar", String.class, null); + table.setColumnHeader("bar", "BAR"); + table.setColumnFooter("bar", "bar"); + + testRead(design, table); + // testWrite(design, table); + } + + @Test + public void testInlineData() throws UnsupportedEncodingException { + String design = "<v-table footer-visible=true> "// + + " <table>" // + + " <colgroup>" + + " <col property-id='foo' width=150 />" + + " <col property-id='bar' />" + + " <col property-id='baz' />" // + + " </colgroup>" + + " <thead>" + + " <tr><th>Description<th>Milestone<th>Status</tr>" + + " </thead>" + + " <tbody>" + + " <tr><td>r1c1</td><td>r1c2</td><td>r1c3</td>" // + + " <tr><td>r2c1</td><td>r2c2</td><td>r2c3</td>" // + + " </tbody>" // + + " <tfoot>" // + + " <tr><td>F1<td>F2<td>F3</tr>" // + + " </tfoot>" // + + " </table>" // + + "</v-table>"; + Table table = new Table(); + table.addContainerProperty("foo", String.class, null); + table.addContainerProperty("bar", String.class, null); + table.addContainerProperty("baz", String.class, null); + table.setColumnHeaders("Description", "Milestone", "Status"); + table.setColumnFooter("foo", "F1"); + table.setColumnFooter("bar", "F2"); + table.setColumnFooter("baz", "F3"); + table.addItem(new Object[] { "r1c1", "r1c2", "r1c3" }, null); + table.addItem(new Object[] { "r2c1", "r2c2", "r2c3" }, null); + table.setFooterVisible(true); + testRead(design, table); + // testWrite(design, table); + + } +} diff --git a/server/tests/src/com/vaadin/tests/server/component/table/TableDeclarativeTestBase.java b/server/tests/src/com/vaadin/tests/server/component/table/TableDeclarativeTestBase.java new file mode 100644 index 0000000000..7f803c7f8b --- /dev/null +++ b/server/tests/src/com/vaadin/tests/server/component/table/TableDeclarativeTestBase.java @@ -0,0 +1,52 @@ +/* + * 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.table; + +import static org.junit.Assert.assertTrue; + +import com.vaadin.tests.design.DeclarativeTestBase; +import com.vaadin.ui.Table; + +public class TableDeclarativeTestBase extends DeclarativeTestBase<Table> { + + @Override + public Table testRead(String design, Table expected) { + Table read = super.testRead(design, expected); + compareFooter(read, expected); + compareBody(read, expected); + return read; + } + + private void compareBody(Table read, Table expected) { + assertEquals(expected.getItemIds().size(), read.getItemIds().size()); + for (Object rowId : expected.getItemIds()) { + assertTrue(read.containsId(rowId)); + for (Object propertyId : read.getVisibleColumns()) { + Object expectedItem = expected.getContainerProperty(rowId, + propertyId); + Object readItem = read.getContainerProperty(rowId, propertyId); + assertEquals(expectedItem, readItem); + } + } + } + + private void compareFooter(Table read, Table expected) { + for (Object pid : expected.getVisibleColumns()) { + assertEquals(expected.getColumnFooter(pid), + read.getColumnFooter(pid)); + } + } +} |