aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJohannes Dahlström <johannesd@vaadin.com>2015-04-09 17:34:04 +0300
committerTeemu Suo-Anttila <teemusa@vaadin.com>2015-04-13 08:23:36 +0000
commit68c7963f085fc299ac9ebded9394b638c7392bb1 (patch)
tree0593ab527b14b0deac8407a9e064d5325fdf416b
parentb3b50eb368a8b6200200b6b1f1324d0fc63f4409 (diff)
downloadvaadin-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.java125
-rw-r--r--server/src/com/vaadin/ui/Tree.java106
-rw-r--r--server/tests/src/com/vaadin/tests/server/component/tree/TreeDeclarativeTest.java59
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);
}
}