Browse Source

Declarative read support for Table (#16367)

Change-Id: I2327af18b2e1e4d31a057b110eee9495f16d9633
tags/7.5.0.beta1
Johannes Dahlström 9 years ago
parent
commit
ed4bec15a1

+ 4
- 0
server/src/com/vaadin/ui/AbstractSelect.java View File

@@ -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);

+ 162
- 1
server/src/com/vaadin/ui/Table.java View File

@@ -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());

+ 165
- 0
server/tests/src/com/vaadin/tests/server/component/table/TableDeclarativeTest.java View File

@@ -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);

}
}

+ 52
- 0
server/tests/src/com/vaadin/tests/server/component/table/TableDeclarativeTestBase.java View File

@@ -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));
}
}
}

Loading…
Cancel
Save