diff options
author | Johannes Dahlström <johannesd@vaadin.com> | 2015-04-09 17:34:04 +0300 |
---|---|---|
committer | Teemu Suo-Anttila <teemusa@vaadin.com> | 2015-04-13 08:23:36 +0000 |
commit | 68c7963f085fc299ac9ebded9394b638c7392bb1 (patch) | |
tree | 0593ab527b14b0deac8407a9e064d5325fdf416b | |
parent | b3b50eb368a8b6200200b6b1f1324d0fc63f4409 (diff) | |
download | vaadin-framework-68c7963f085fc299ac9ebded9394b638c7392bb1.tar.gz vaadin-framework-68c7963f085fc299ac9ebded9394b638c7392bb1.zip |
Declarative support for Tree inline data (#16321)
<v-tree> elements may now contain a hierarchy of <node> elements.
Change-Id: I6b1703aa4ec598cf0b3a6221f615727efbcbf0ad
-rw-r--r-- | server/src/com/vaadin/ui/AbstractSelect.java | 125 | ||||
-rw-r--r-- | server/src/com/vaadin/ui/Tree.java | 106 | ||||
-rw-r--r-- | server/tests/src/com/vaadin/tests/server/component/tree/TreeDeclarativeTest.java | 59 |
3 files changed, 235 insertions, 55 deletions
diff --git a/server/src/com/vaadin/ui/AbstractSelect.java b/server/src/com/vaadin/ui/AbstractSelect.java index 4c5e6b6ea3..629d2fb504 100644 --- a/server/src/com/vaadin/ui/AbstractSelect.java +++ b/server/src/com/vaadin/ui/AbstractSelect.java @@ -2188,28 +2188,13 @@ public abstract class AbstractSelect extends AbstractField<Object> implements } @Override - public void readDesign(Element design, DesignContext designContext) { + public void readDesign(Element design, DesignContext context) { // handle default attributes - super.readDesign(design, designContext); + super.readDesign(design, context); // handle children specifying selectable items (<option>) Set<String> selected = new HashSet<String>(); for (Element child : design.children()) { - if (!"option".equals(child.nodeName())) { - throw new DesignException( - "Unsupported child element in a select: " - + child.nodeName() + "."); - } - String itemId = child.html(); - addItem(itemId); - if (child.hasAttr("icon")) { - setItemIcon( - itemId, - DesignAttributeHandler.readAttribute("icon", - child.attributes(), Resource.class)); - } - if (child.hasAttr("selected")) { - selected.add(itemId); - } + readItem(child, selected, context); } if (!selected.isEmpty()) { if (isMultiSelect()) { @@ -2223,29 +2208,101 @@ public abstract class AbstractSelect extends AbstractField<Object> implements } } + /** + * Reads an Item from a design and inserts it into the data source. + * Hierarchical select components should override this method to recursively + * recursively read any child items as well. + * + * @since + * @param child + * a child element representing the item + * @param selected + * A set accumulating selected items. If the item that is read is + * marked as selected, its item id should be added to this set. + * @param context + * the DesignContext instance used in parsing + * @return the item id of the new item + * + * @throws DesignException + * if the tag name of the {@code child} element is not + * {@code option}. + */ + protected String readItem(Element child, Set<String> selected, + DesignContext context) { + if (!"option".equals(child.tagName())) { + throw new DesignException("Unrecognized child element in " + + getClass().getSimpleName() + ": " + child.tagName()); + } + String itemId = child.html(); + addItem(itemId); + if (child.hasAttr("icon")) { + setItemIcon( + itemId, + DesignAttributeHandler.readAttribute("icon", + child.attributes(), Resource.class)); + } + if (child.hasAttr("selected")) { + selected.add(itemId); + } + return itemId; + } + @Override - public void writeDesign(Element design, DesignContext designContext) { + public void writeDesign(Element design, DesignContext context) { // Write default attributes - super.writeDesign(design, designContext); + super.writeDesign(design, context); // Write options if warranted - if (designContext.shouldWriteData(this)) { - for (Object itemId : getItemIds()) { - Element optionElement = design.appendElement("option"); + if (context.shouldWriteData(this)) { + writeItems(design, context); + } + } + + /** + * Writes the data source items to a design. Hierarchical select components + * should override this method to only write the root items. + * + * @since + * @param design + * the element into which to insert the items + * @param context + * the DesignContext instance used in writing + */ + protected void writeItems(Element design, DesignContext context) { + for (Object itemId : getItemIds()) { + writeItem(design, itemId, context); + } + } - optionElement.html(getItemCaption(itemId)); + /** + * Writes a data source Item to a design. Hierarchical select components + * should override this method to recursively write any child items as well. + * + * @since + * @param design + * the element into which to insert the item + * @param itemId + * the id of the item to write + * @param context + * the DesignContext instance used in writing + * @return + */ + protected Element writeItem(Element design, Object itemId, + DesignContext context) { + Element element = design.appendElement("option"); - Resource icon = getItemIcon(itemId); - if (icon != null) { - DesignAttributeHandler.writeAttribute("icon", - optionElement.attributes(), icon, null, - Resource.class); - } + element.html(itemId.toString()); - if (isSelected(itemId)) { - optionElement.attr("selected", ""); - } - } + Resource icon = getItemIcon(itemId); + if (icon != null) { + DesignAttributeHandler.writeAttribute("icon", element.attributes(), + icon, null, Resource.class); } + + if (isSelected(itemId)) { + element.attr("selected", ""); + } + + return element; } }
\ No newline at end of file diff --git a/server/src/com/vaadin/ui/Tree.java b/server/src/com/vaadin/ui/Tree.java index 3c5758c1ea..6f5ec96f63 100644 --- a/server/src/com/vaadin/ui/Tree.java +++ b/server/src/com/vaadin/ui/Tree.java @@ -30,6 +30,8 @@ import java.util.Set; import java.util.Stack; import java.util.StringTokenizer; +import org.jsoup.nodes.Element; + import com.vaadin.data.Container; import com.vaadin.data.Item; import com.vaadin.data.util.ContainerHierarchicalWrapper; @@ -57,6 +59,9 @@ import com.vaadin.shared.MouseEventDetails; import com.vaadin.shared.ui.MultiSelectMode; import com.vaadin.shared.ui.dd.VerticalDropLocation; import com.vaadin.shared.ui.tree.TreeConstants; +import com.vaadin.ui.declarative.DesignAttributeHandler; +import com.vaadin.ui.declarative.DesignContext; +import com.vaadin.ui.declarative.DesignException; import com.vaadin.util.ReflectTools; /** @@ -1790,4 +1795,105 @@ public class Tree extends AbstractSelect implements Container.Hierarchical, } expanded.removeAll(removedItemIds); } + + /** + * Reads an Item from a design and inserts it into the data source. + * Recursively handles any children of the item as well. + * + * @since + * @param node + * an element representing the item (tree node). + * @param selected + * A set accumulating selected items. If the item that is read is + * marked as selected, its item id should be added to this set. + * @param context + * the DesignContext instance used in parsing + * @return the item id of the new item + * + * @throws DesignException + * if the tag name of the {@code node} element is not + * {@code node}. + */ + @Override + protected String readItem(Element node, Set<String> selected, + DesignContext context) { + + if (!"node".equals(node.tagName())) { + throw new DesignException("Unrecognized child element in " + + getClass().getSimpleName() + ": " + node.tagName()); + } + + String itemId = node.attr("text"); + addItem(itemId); + if (node.hasAttr("icon")) { + Resource icon = DesignAttributeHandler.readAttribute("icon", + node.attributes(), Resource.class); + setItemIcon(itemId, icon); + } + if (node.hasAttr("selected")) { + selected.add(itemId); + } + + for (Element child : node.children()) { + String childItemId = readItem(child, selected, context); + setParent(childItemId, itemId); + } + return itemId; + } + + /** + * Recursively writes the root items and their children to a design. + * + * @since + * @param design + * the element into which to insert the items + * @param context + * the DesignContext instance used in writing + */ + @Override + protected void writeItems(Element design, DesignContext context) { + for (Object itemId : rootItemIds()) { + writeItem(design, itemId, context); + } + } + + /** + * Recursively writes a data source Item and its children to a design. + * + * @since + * @param design + * the element into which to insert the item + * @param itemId + * the id of the item to write + * @param context + * the DesignContext instance used in writing + * @return + */ + @Override + protected Element writeItem(Element design, Object itemId, + DesignContext context) { + Element element = design.appendElement("node"); + + element.attr("text", itemId.toString()); + + Resource icon = getItemIcon(itemId); + if (icon != null) { + DesignAttributeHandler.writeAttribute("icon", element.attributes(), + icon, null, Resource.class); + } + + if (isSelected(itemId)) { + element.attr("selected", ""); + } + + Collection<?> children = getChildren(itemId); + if (children != null) { + // Yeah... see #5864 + for (Object childItemId : children) { + writeItem(element, childItemId, context); + } + } + + return element; + } } diff --git a/server/tests/src/com/vaadin/tests/server/component/tree/TreeDeclarativeTest.java b/server/tests/src/com/vaadin/tests/server/component/tree/TreeDeclarativeTest.java index b5e86d0835..3fb69a9257 100644 --- a/server/tests/src/com/vaadin/tests/server/component/tree/TreeDeclarativeTest.java +++ b/server/tests/src/com/vaadin/tests/server/component/tree/TreeDeclarativeTest.java @@ -17,7 +17,7 @@ package com.vaadin.tests.server.component.tree; import org.junit.Test; -import com.vaadin.shared.ui.MultiSelectMode; +import com.vaadin.server.ExternalResource; import com.vaadin.tests.design.DeclarativeTestBase; import com.vaadin.ui.Tree; import com.vaadin.ui.Tree.TreeDragMode; @@ -31,34 +31,51 @@ import com.vaadin.ui.Tree.TreeDragMode; public class TreeDeclarativeTest extends DeclarativeTestBase<Tree> { @Test - public void testReadBasic() { - testRead(getBasicDesign(), getBasicExpected()); - } + public void testDragMode() { + String design = "<v-tree drag-mode='node' />"; - @Test - public void testWriteBasic() { - testWrite(getBasicDesign(), getBasicExpected()); - } + Tree tree = new Tree(); + tree.setDragMode(TreeDragMode.NODE); - private String getBasicDesign() { - return "<v-tree selectable='false' drag-mode='node' multiselect-mode='simple' />"; - } - - private Tree getBasicExpected() { - Tree t = new Tree(); - t.setSelectable(false); - t.setDragMode(TreeDragMode.NODE); - t.setMultiselectMode(MultiSelectMode.SIMPLE); - return t; + testRead(design, tree); + testWrite(design, tree); } @Test - public void testReadEmpty() { + public void testEmpty() { testRead("<v-tree />", new Tree()); + testWrite("<v-tree />", new Tree()); } @Test - public void testWriteEmpty() { - testWrite("<v-tree />", new Tree()); + public void testNodes() { + String design = "<v-tree>" // + + " <node text='Node'/>" // + + " <node text='Parent'>" // + + " <node text='Child'>" // + + " <node text='Grandchild'/>" // + + " </node>" // + + " </node>" // + + " <node text='With icon' icon='http://example.com/icon.png'/>" // + + "</v-tree>"; + + Tree tree = new Tree(); + + tree.addItem("Node"); + + tree.addItem("Parent"); + + tree.addItem("Child"); + tree.setParent("Child", "Parent"); + + tree.addItem("Grandchild"); + tree.setParent("Grandchild", "Child"); + + tree.addItem("With icon"); + tree.setItemIcon("With icon", new ExternalResource( + "http://example.com/icon.png")); + + testRead(design, tree); + testWrite(design, tree, true); } } |