Change-Id: I2327af18b2e1e4d31a057b110eee9495f16d9633tags/7.5.0.beta1
@@ -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); |
@@ -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()); |
@@ -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); | |||
} | |||
} |
@@ -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)); | |||
} | |||
} | |||
} |