You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tapestry.apache.org by hl...@apache.org on 2011/09/05 23:30:23 UTC

svn commit: r1165419 - in /tapestry/tapestry5/trunk/tapestry-core/src: main/java/org/apache/tapestry5/corelib/components/ main/java/org/apache/tapestry5/tree/ main/resources/org/apache/tapestry5/ test/groovy/org/apache/tapestry5/integration/app1/ test/...

Author: hlship
Date: Mon Sep  5 21:30:22 2011
New Revision: 1165419

URL: http://svn.apache.org/viewvc?rev=1165419&view=rev
Log:
TAP5-1629: A Tree component that does not have a selection model bound should not track selections on the client or server

Added:
    tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/StuffValueEncoder.java
    tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/TreeSelectionDemo.java
    tapestry/tapestry5/trunk/tapestry-core/src/test/resources/org/apache/tapestry5/integration/app1/pages/TreeSelectionDemo.tml
Modified:
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/corelib/components/Tree.java
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/tree/DefaultTreeSelectionModel.java
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/tree/TreeSelectionModel.java
    tapestry/tapestry5/trunk/tapestry-core/src/main/resources/org/apache/tapestry5/tree.css
    tapestry/tapestry5/trunk/tapestry-core/src/main/resources/org/apache/tapestry5/tree.js
    tapestry/tapestry5/trunk/tapestry-core/src/test/groovy/org/apache/tapestry5/integration/app1/TreeTests.groovy
    tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/Stuff.java
    tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/Index.java
    tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/TreeDemo.java

Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/corelib/components/Tree.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/corelib/components/Tree.java?rev=1165419&r1=1165418&r2=1165419&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/corelib/components/Tree.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/corelib/components/Tree.java Mon Sep  5 21:30:22 2011
@@ -14,12 +14,8 @@
 
 package org.apache.tapestry5.corelib.components;
 
-import java.util.Arrays;
-import java.util.List;
-
 import org.apache.tapestry5.*;
 import org.apache.tapestry5.annotations.*;
-import org.apache.tapestry5.corelib.internal.InternalFormSupport;
 import org.apache.tapestry5.dom.Element;
 import org.apache.tapestry5.func.F;
 import org.apache.tapestry5.func.Flow;
@@ -31,17 +27,22 @@ import org.apache.tapestry5.runtime.Rend
 import org.apache.tapestry5.runtime.RenderQueue;
 import org.apache.tapestry5.services.javascript.JavaScriptSupport;
 import org.apache.tapestry5.tree.*;
+import org.slf4j.Logger;
+
+import java.util.List;
 
 /**
  * A component used to render a recursive tree structure, with expandable/collapsable/selectable nodes. The data that is displayed
  * by the component is provided as a {@link TreeModel}. A secondary model, the {@link TreeExpansionModel}, is used
- * to track which nodes have been expanded. The {@link TreeSelectionModel} is used to track node selections.
+ * to track which nodes have been expanded. The optional {@link TreeSelectionModel} is used to track node selections (as currently
+ * implemented, only leaf nodes may be selected).
+ * <p/>
  * The Tree component uses special tricks to support recursive rendering of the Tree as necessary.
- * 
+ *
  * @since 5.3
  */
 @SuppressWarnings(
-{ "rawtypes", "unchecked", "unused" })
+        {"rawtypes", "unchecked", "unused"})
 @Events({EventConstants.NODE_SELECTED, EventConstants.NODE_UNSELECTED})
 public class Tree
 {
@@ -78,12 +79,13 @@ public class Tree
     private TreeExpansionModel expansionModel;
 
     /**
-     * Used to control the Tree's selections. By default, a persistent field inside the Tree
-     * component stores a {@link DefaultTreeSelectionModel}. This parameter may be bound when more
-     * control over the implementation of the selection model, or how it is stored, is
-     * required.
+     * Used to control the Tree's selections. When this parameter is bound, then the client-side Tree
+     * will track what is selected or not selected, and communicate this (via Ajax requests) up to
+     * the server, where it will be recorded into the model. On the client-side, the Tree component will
+     * add or remove the {@code t-selected-leaf-node-label} CSS class from {@code span.t-tree-label}
+     * for the node.
      */
-    @Parameter(allowNull = false, value = "defaultTreeSelectionModel")
+    @Parameter
     private TreeSelectionModel selectionModel;
 
     /**
@@ -111,9 +113,6 @@ public class Tree
     @Persist
     private TreeExpansionModel defaultTreeExpansionModel;
 
-    @Persist
-    private TreeSelectionModel defaultTreeSelectionModel;
-
     private static RenderCommand RENDER_CLOSE_TAG = new RenderCommand()
     {
         public void render(MarkupWriter writer, RenderQueue queue)
@@ -130,15 +129,16 @@ public class Tree
         }
     };
 
+    @Inject
+    private Logger logger;
+
     /**
      * Renders a single node (which may be the last within its containing node).
      * This is a mix of immediate rendering, and queuing up various Blocks and Render commands
      * to do the rest. May recursively render child nodes of the active node.
-     * 
-     * @param node
-     *            to render
-     * @param isLast
-     *            if true, add "t-last" attribute to the LI element
+     *
+     * @param node   to render
+     * @param isLast if true, add "t-last" attribute to the LI element
      * @return command to render the node
      */
     private RenderCommand toRenderCommand(final TreeNode node, final boolean isLast)
@@ -170,10 +170,16 @@ public class Tree
 
                 String clientId = jss.allocateClientId(resources);
 
-                 JSONObject spec = new JSONObject("clientId", clientId);
+                JSONObject spec = new JSONObject("clientId", clientId);
 
                 e.attribute("id", clientId);
 
+                logger.info(String.format("Selection model for %s is %s.",
+                        resources.getCompleteId(),
+                        selectionModel));
+
+                spec.put("leaf", node.isLeaf());
+
                 if (hasChildren)
                 {
                     Link expandChildren = resources.createEventLink("expandChildren", node.getId());
@@ -181,17 +187,31 @@ public class Tree
                     Link markCollapsed = resources.createEventLink("markCollapsed", node.getId());
 
                     spec.put("expandChildrenURL", expandChildren.toString())
-                            .put( "markExpandedURL", markExpanded.toString())
+                            .put("markExpandedURL", markExpanded.toString())
                             .put("markCollapsedURL", markCollapsed.toString());
 
                     if (expanded)
                         spec.put("expanded", true);
-                }
-                else
+                } else
                 {
-                    Link toggleLeaf = resources.createEventLink("toggleLeaf", node.getId());
-
-                    spec.put("toggleLeafURL", toggleLeaf.toString());
+                    if (selectionModel != null)
+                    {
+                        // May need to address this in the future; in other tree implementations I've constructed,
+                        // folders are selectable, and selections even propagate up and down the tree.
+
+                        Link selectLeaf = resources.createEventLink("select", node.getId());
+
+                        spec.put("selectURL", selectLeaf.toString());
+                        if (selectionModel.isSelected(node))
+                        {
+                            spec.put("selected", true);
+                        }
+
+                        logger.info(String.format("%s rendered node %s as selectable", resources.getCompleteId(), node.getId()));
+                    } else
+                    {
+                        logger.info(String.format("%s rendered node %s as NOT selectable", resources.getCompleteId(), node.getId()));
+                    }
                 }
 
                 jss.addInitializerCall("treeNode", spec);
@@ -204,6 +224,7 @@ public class Tree
                 queue.push(RENDER_CLOSE_TAG); // li
 
                 if (expanded)
+
                 {
                     queue.push(new RenderNodes(node.getChildren()));
                 }
@@ -213,10 +234,14 @@ public class Tree
                 queue.push(RENDER_LABEL_SPAN);
 
             }
-        };
+        }
+
+                ;
     }
 
-    /** Renders an &lt;ul&gt; element and renders each node recursively inside the element. */
+    /**
+     * Renders an &lt;ul&gt; element and renders each node recursively inside the element.
+     */
     private class RenderNodes implements RenderCommand
     {
         private final Flow<TreeNode> nodes;
@@ -243,6 +268,7 @@ public class Tree
                 }
             });
         }
+
     }
 
     public String getContainerClass()
@@ -273,32 +299,31 @@ public class Tree
         return new JSONObject();
     }
 
-    Object onToggleLeaf(String nodeId)
+    Object onSelect(String nodeId, @RequestParameter("t:selected") boolean selected)
     {
         TreeNode node = model.getById(nodeId);
 
         String event;
 
-        if(selectionModel.isSelected(node))
-        {
-            selectionModel.unselect(node);
-
-            event = EventConstants.NODE_UNSELECTED;
-        }
-        else
+        if (selected)
         {
             selectionModel.select(node);
 
             event = EventConstants.NODE_SELECTED;
+        } else
+        {
+            selectionModel.unselect(node);
+
+            event = EventConstants.NODE_UNSELECTED;
         }
 
         CaptureResultCallback<Object> callback = CaptureResultCallback.create();
 
-        resources.triggerEvent(event, new Object [] { nodeId }, callback);
+        resources.triggerEvent(event, new Object[]{nodeId}, callback);
 
         final Object result = callback.getResult();
 
-        if(result != null)
+        if (result != null)
             return result;
 
         return new JSONObject();
@@ -312,14 +337,6 @@ public class Tree
         return defaultTreeExpansionModel;
     }
 
-    public TreeSelectionModel getDefaultTreeSelectionModel()
-    {
-        if(defaultTreeSelectionModel == null)
-            defaultTreeSelectionModel = new DefaultTreeSelectionModel();
-
-        return defaultTreeSelectionModel;
-    }
-
     /**
      * Returns the actual {@link TreeExpansionModel} in use for this Tree component,
      * as per the expansionModel parameter. This is often, but not always, the same
@@ -345,7 +362,9 @@ public class Tree
         return new RenderNodes(model.getRootNodes());
     }
 
-    /** Clears the tree's {@link TreeExpansionModel}. */
+    /**
+     * Clears the tree's {@link TreeExpansionModel}.
+     */
     public void clearExpansions()
     {
         expansionModel.clear();

Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/tree/DefaultTreeSelectionModel.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/tree/DefaultTreeSelectionModel.java?rev=1165419&r1=1165418&r2=1165419&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/tree/DefaultTreeSelectionModel.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/tree/DefaultTreeSelectionModel.java Mon Sep  5 21:30:22 2011
@@ -20,7 +20,7 @@ import org.apache.tapestry5.ioc.internal
 import java.util.Set;
 
 /**
- * Default implementation of {@link TreeSelectionModel}.
+ * Default implementation of {@link TreeSelectionModel}. This is simply a wrapper around a set of node ids.
  *
  * @param <T> type of node
  */

Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/tree/TreeSelectionModel.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/tree/TreeSelectionModel.java?rev=1165419&r1=1165418&r2=1165419&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/tree/TreeSelectionModel.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/tree/TreeSelectionModel.java Mon Sep  5 21:30:22 2011
@@ -15,15 +15,16 @@
 package org.apache.tapestry5.tree;
 
 /**
- * Tracks which nodes of a {@link TreeModel} are currently selected. The {@linkplain DefaultTreeExpansionModel default
+ * Tracks which <em>leaf</em> nodes of a {@link TreeModel} are currently selected. The {@linkplain DefaultTreeSelectionModel default
  * implementation} simply stores a set of {@linkplain TreeNode#getId() unique node
- * ids} to identify expanded nodes. The expansion model is updated whenever folders are expanded or
- * collapsed on the client side.
+ * ids} to identify selected nodes. The selection model is updated whenever the user clicks on the label for a leaf node.
+ * <p/>
+ * In the future, new methods may be added that will support selection of folders as well as leafs, and define the rules for
+ * how selections and de-selections propagate down to children or up to parents.
  *
  * @param <T> type of node
- *
- * @since 5.3
  * @see org.apache.tapestry5.corelib.components.Tree
+ * @since 5.3
  */
 public interface TreeSelectionModel<T>
 {
@@ -49,6 +50,8 @@ public interface TreeSelectionModel<T>
      */
     void unselect(TreeNode<T> node);
 
-    /** Clears the selection. */
+    /**
+     * Clears the selection.
+     */
     void clear();
 }

Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/resources/org/apache/tapestry5/tree.css
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/resources/org/apache/tapestry5/tree.css?rev=1165419&r1=1165418&r2=1165419&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/resources/org/apache/tapestry5/tree.css (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/resources/org/apache/tapestry5/tree.css Mon Sep  5 21:30:22 2011
@@ -51,6 +51,10 @@ SPAN.t-tree-icon.t-leaf-node {
   background-position: -32px -16px;
 }
 
+SPAN.t-tree-label.t-selectable {
+    cursor: pointer;
+}
+
 SPAN.t-tree-label.t-selected-leaf-node-label {
   font-weight: bold;
 }

Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/resources/org/apache/tapestry5/tree.js
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/resources/org/apache/tapestry5/tree.js?rev=1165419&r1=1165418&r2=1165419&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/resources/org/apache/tapestry5/tree.js (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/resources/org/apache/tapestry5/tree.js Mon Sep  5 21:30:22 2011
@@ -76,14 +76,14 @@ T5.extendInitializers(function() {
     }
 
     function initializer(spec) {
-        var loaded = spec.expanded;
+        var loaded = spec.expanded || spec.leaf;
         var expanded = spec.expanded;
-        var selected = false;
+        var loading = false;
 
         if (expanded) {
             $(spec.clientId).addClassName("t-tree-expanded")
         }
-        var loading = false;
+
 
         function successHandler(reply) {
             // Remove the Ajax load indicator
@@ -112,67 +112,29 @@ T5.extendInitializers(function() {
 
         }
 
-        function toggleLeafHandler(reply) {
-            var response = reply.responseJSON;
-
-            $(spec.clientId).update("");
-
-            Tapestry.loadScriptsInReply(response, function() {
-                loading = false;
-                loaded = true;
-                expanded = true;
-                selected = !selected;
-            });
-        }
-
         function doLoad() {
             if (loading)
                 return;
 
             loading = true;
 
-            if (spec.expandChildrenURL) {
-                $(spec.clientId).addClassName("t-empty-node");
-            }
-            else {
-                $(spec.clientId).next("span.t-tree-label").addClassName("t-selected-leaf-node-label");
-            }
-            $(spec.clientId).update("<span class='t-ajax-wait'/>");
-
-            var requestURL = spec.expandChildrenURL ? spec.expandChildrenURL : spec.toggleLeafURL;
+            $(spec.clientId).addClassName("t-empty-node");
 
-            var handler = spec.expandChildrenURL ? successHandler : toggleLeafHandler;
-
-            Tapestry.ajaxRequest(requestURL, handler);
+            $(spec.clientId).update("<span class='t-ajax-wait'/>");
 
+            Tapestry.ajaxRequest(spec.expandChildrenURL, successHandler);
         }
 
         $(spec.clientId).observe("click", function(event) {
             event.stop();
 
-            if (!loaded) {
+            if (!loaded && spec.expandChildrenURL) {
 
                 doLoad();
 
                 return;
             }
 
-            if (spec.toggleLeafURL) {
-                var label = $(spec.clientId).next("span.t-tree-label");
-
-                if (selected) {
-                    label.removeClassName("t-selected-leaf-node-label");
-                }
-                else {
-                    label.addClassName("t-selected-leaf-node-label");
-                }
-                selected = !selected;
-
-                Tapestry.ajaxRequest(spec.toggleLeafURL, {});
-
-                return;
-            }
-
             // Children have been loaded, just a matter of toggling
             // between showing or hiding the children.
 
@@ -182,10 +144,48 @@ T5.extendInitializers(function() {
 
             var url = expanded ? spec.markCollapsedURL : spec.markExpandedURL;
 
+            // Send request, ignore response.
+
             Tapestry.ajaxRequest(url, {});
 
             expanded = !expanded;
         });
+
+
+        if (spec.selectURL) {
+
+            var selected = spec.selected;
+
+            var label = $(spec.clientId).next("span.t-tree-label");
+
+            label.addClassName("t-selectable");
+
+            if (selected) {
+                label.addClassName("t-selected-leaf-node-label");
+            }
+
+            label.observe("click", function(event) {
+                event.stop();
+
+
+                selected = ! selected;
+
+
+                if (selected) {
+                    label.addClassName("t-selected-leaf-node-label");
+                }
+                else {
+                    label.removeClassName("t-selected-leaf-node-label");
+                }
+
+                // TODO: In the future, we may want to select children when a parent is selected,
+                // or vice-versa. There's a lot of use cases. These will be directed from new methods
+                // on the TreeSelectionModel interface and encoded into the response. For now,
+                // the response is empty and ignored.
+
+                Tapestry.ajaxRequest(spec.selectURL, { parameters: { "t:selected": selected } });
+            });
+        }
     }
 
     return {

Modified: tapestry/tapestry5/trunk/tapestry-core/src/test/groovy/org/apache/tapestry5/integration/app1/TreeTests.groovy
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/test/groovy/org/apache/tapestry5/integration/app1/TreeTests.groovy?rev=1165419&r1=1165418&r2=1165419&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/test/groovy/org/apache/tapestry5/integration/app1/TreeTests.groovy (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/test/groovy/org/apache/tapestry5/integration/app1/TreeTests.groovy Mon Sep  5 21:30:22 2011
@@ -20,7 +20,8 @@ import org.testng.annotations.Test
 class TreeTests extends SeleniumTestCase
 {
     @Test
-    void basics() {
+    void basics()
+    {
 
         openBaseURL()
 
@@ -33,7 +34,7 @@ class TreeTests extends SeleniumTestCase
 
         sleep 25 // See if that helps with the intermittent test suite failures on the CI server
 
-        waitForAjaxRequestsToComplete  PAGE_LOAD_TIMEOUT
+        waitForAjaxRequestsToComplete PAGE_LOAD_TIMEOUT
 
         assertTextPresent "Board Games"
 
@@ -41,7 +42,7 @@ class TreeTests extends SeleniumTestCase
         click "//div[@class='t-tree-container test-hook']/ul/li[2]/ul/li/span[@class='t-tree-icon']"
 
         //Assert the leafs are displayed
-        waitForAjaxRequestsToComplete  PAGE_LOAD_TIMEOUT
+        waitForAjaxRequestsToComplete PAGE_LOAD_TIMEOUT
 
         clickAndWait "link=Redraw"
 
@@ -49,13 +50,14 @@ class TreeTests extends SeleniumTestCase
     }
 
     @Test
-    void selectLeaf() {
+    void select_node()
+    {
 
         openBaseURL()
 
-        clickAndWait "link=Tree Component Demo"
+        clickAndWait "link=Tree Component Selection Demo"
 
-        clickAndWait "link=clear expansions"
+        clickAndWait "link=clear all"
 
         click "//span[@class='t-tree-icon']"
 
@@ -63,7 +65,14 @@ class TreeTests extends SeleniumTestCase
 
         assertTextPresent "Oscar", "Gromit", "Max", "Roger", "Cooper"
 
-        click "//span[@class='t-tree-icon t-leaf-node']"
+        // Click the first selectable node, probably Oscar
+        click "css=span.t-selectable"
+
+        waitForCSSSelectedElementToAppear "span.t-selected-leaf-node-label"
+
+        clickAndWait "link=Redraw"
+
+        // Make sure it is still there after a redraw
 
         waitForCSSSelectedElementToAppear "span.t-selected-leaf-node-label"
     }

Modified: tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/Stuff.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/Stuff.java?rev=1165419&r1=1165418&r2=1165419&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/Stuff.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/Stuff.java Mon Sep  5 21:30:22 2011
@@ -14,11 +14,14 @@
 
 package org.apache.tapestry5.integration.app1;
 
+import org.apache.tapestry5.ValueEncoder;
+import org.apache.tapestry5.ioc.internal.util.CollectionFactory;
+import org.apache.tapestry5.tree.DefaultTreeModel;
+import org.apache.tapestry5.tree.TreeModel;
+
 import java.util.List;
 import java.util.UUID;
 
-import org.apache.tapestry5.ioc.internal.util.CollectionFactory;
-
 public class Stuff
 {
     public final String uuid = UUID.randomUUID().toString();
@@ -64,4 +67,29 @@ public class Stuff
 
         return null;
     }
+
+    public static final Stuff ROOT = new Stuff("<root>");
+
+    static
+    {
+        ROOT.addChild(new Stuff("Pets").addChildrenNamed("Oscar", "Gromit", "Max", "Roger", "Cooper"));
+        ROOT.addChild(new Stuff("Games").addChild(
+                new Stuff("Board Games").addChildrenNamed("Settlers of Catan", "Agricola", "Ra", "Risk", "Dvonn"))
+                .addChild(new Stuff("Card Games").addChildrenNamed("Magic the Gathering", "Dominion", "Mu")));
+
+        Stuff numbers = new Stuff("Numbers");
+
+        for (int i = 0; i < 10000; i++)
+        {
+            numbers.addChild(new Stuff(Integer.toString(i)));
+        }
+
+        ROOT.addChild(numbers);
+    }
+
+    public static TreeModel<Stuff> createTreeModel() {
+        ValueEncoder<Stuff> encoder = new StuffValueEncoder();
+
+        return new DefaultTreeModel<Stuff>(encoder, new StuffTreeModelAdapter(), Stuff.ROOT.children);
+    }
 }

Added: tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/StuffValueEncoder.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/StuffValueEncoder.java?rev=1165419&view=auto
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/StuffValueEncoder.java (added)
+++ tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/StuffValueEncoder.java Mon Sep  5 21:30:22 2011
@@ -0,0 +1,16 @@
+package org.apache.tapestry5.integration.app1;
+
+import org.apache.tapestry5.ValueEncoder;
+
+public class StuffValueEncoder implements ValueEncoder<Stuff>
+{
+    public String toClient(Stuff value)
+    {
+        return value.uuid;
+    }
+
+    public Stuff toValue(String clientValue)
+    {
+        return Stuff.ROOT.seek(clientValue);
+    }
+}

Modified: tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/Index.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/Index.java?rev=1165419&r1=1165418&r2=1165419&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/Index.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/Index.java Mon Sep  5 21:30:22 2011
@@ -70,6 +70,8 @@ public class Index
 
                     new Item("TreeDemo", "Tree Component Demo", "Demo of Tree Component"),
 
+                    new Item("TreeSelectionDemo", "Tree Component Selection Demo", "Demo of Selection with Tree Component"),
+
                     new Item("InvalidExpressionInDynamicTemplate", "Invalid Dynamic Expression",
                             "Invalid expression in a Dynamic Template"),
 

Modified: tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/TreeDemo.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/TreeDemo.java?rev=1165419&r1=1165418&r2=1165419&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/TreeDemo.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/TreeDemo.java Mon Sep  5 21:30:22 2011
@@ -14,12 +14,9 @@
 
 package org.apache.tapestry5.integration.app1.pages;
 
-import org.apache.tapestry5.ValueEncoder;
 import org.apache.tapestry5.annotations.InjectComponent;
 import org.apache.tapestry5.corelib.components.Tree;
 import org.apache.tapestry5.integration.app1.Stuff;
-import org.apache.tapestry5.integration.app1.StuffTreeModelAdapter;
-import org.apache.tapestry5.tree.DefaultTreeModel;
 import org.apache.tapestry5.tree.TreeModel;
 
 public class TreeDemo
@@ -27,45 +24,14 @@ public class TreeDemo
     @InjectComponent
     private Tree tree;
 
-    private static final Stuff rootStuff = new Stuff("<root>");
-
-    static
-    {
-        rootStuff.addChild(new Stuff("Pets").addChildrenNamed("Oscar", "Gromit", "Max", "Roger", "Cooper"));
-        rootStuff.addChild(new Stuff("Games").addChild(
-                new Stuff("Board Games").addChildrenNamed("Settlers of Catan", "Agricola", "Ra", "Risk", "Dvonn"))
-                .addChild(new Stuff("Card Games").addChildrenNamed("Magic the Gathering", "Dominion", "Mu")));
-
-        Stuff numbers = new Stuff("Numbers");
-
-        for (int i = 0; i < 10000; i++)
-        {
-            numbers.addChild(new Stuff(Integer.toString(i)));
-        }
-
-        rootStuff.addChild(numbers);
-    }
-
     public TreeModel<Stuff> getStuffModel()
     {
-        ValueEncoder<Stuff> encoder = new ValueEncoder<Stuff>()
-        {
-            public String toClient(Stuff value)
-            {
-                return value.uuid;
-            }
-
-            public Stuff toValue(String clientValue)
-            {
-                return rootStuff.seek(clientValue);
-            }
-        };
-
-        return new DefaultTreeModel<Stuff>(encoder, new StuffTreeModelAdapter(), rootStuff.children);
+        return Stuff.createTreeModel();
     }
 
     void onActionFromClear()
     {
         tree.clearExpansions();
     }
+
 }

Added: tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/TreeSelectionDemo.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/TreeSelectionDemo.java?rev=1165419&view=auto
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/TreeSelectionDemo.java (added)
+++ tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/TreeSelectionDemo.java Mon Sep  5 21:30:22 2011
@@ -0,0 +1,88 @@
+package org.apache.tapestry5.integration.app1.pages;
+
+import org.apache.tapestry5.annotations.InjectComponent;
+import org.apache.tapestry5.annotations.Log;
+import org.apache.tapestry5.annotations.Persist;
+import org.apache.tapestry5.annotations.Property;
+import org.apache.tapestry5.corelib.components.Tree;
+import org.apache.tapestry5.integration.app1.Stuff;
+import org.apache.tapestry5.ioc.internal.util.CollectionFactory;
+import org.apache.tapestry5.ioc.util.Stack;
+import org.apache.tapestry5.tree.DefaultTreeSelectionModel;
+import org.apache.tapestry5.tree.TreeModel;
+import org.apache.tapestry5.tree.TreeNode;
+import org.apache.tapestry5.tree.TreeSelectionModel;
+
+import java.util.List;
+
+/**
+ *
+ */
+public class TreeSelectionDemo
+{
+    @Persist
+    private TreeSelectionModel selectionModel;
+
+    @InjectComponent
+    private Tree tree;
+
+    @Property
+    private Stuff selectedObject;
+
+    void onActionFromClearAll()
+    {
+        tree.getExpansionModel().clear();
+        tree.getSelectionModel().clear();
+    }
+
+    public TreeModel<Stuff> getStuffModel()
+    {
+        return Stuff.createTreeModel();
+    }
+
+    @Log
+    public TreeSelectionModel<Stuff> getSelectionModel()
+    {
+        if (selectionModel == null)
+        {
+            selectionModel = new DefaultTreeSelectionModel();
+        }
+
+        return selectionModel;
+    }
+
+    public List<Stuff> getSelectedObjects()
+    {
+
+        List<Stuff> result = CollectionFactory.newList();
+        Stack<TreeNode<Stuff>> queue = CollectionFactory.newStack();
+
+        TreeModel<Stuff> model = getStuffModel();
+        TreeSelectionModel<Stuff> selectionModel = getSelectionModel();
+
+        for (TreeNode<Stuff> root : model.getRootNodes())
+        {
+            queue.push(root);
+        }
+
+
+        while (!queue.isEmpty())
+        {
+            TreeNode<Stuff> current = queue.pop();
+
+            if (selectionModel.isSelected(current))
+            {
+                result.add(current.getValue());
+            }
+
+            for (TreeNode<Stuff> child : current.getChildren())
+            {
+                queue.push(child);
+            }
+        }
+
+
+        return result;
+    }
+
+}

Added: tapestry/tapestry5/trunk/tapestry-core/src/test/resources/org/apache/tapestry5/integration/app1/pages/TreeSelectionDemo.tml
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/test/resources/org/apache/tapestry5/integration/app1/pages/TreeSelectionDemo.tml?rev=1165419&view=auto
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/test/resources/org/apache/tapestry5/integration/app1/pages/TreeSelectionDemo.tml (added)
+++ tapestry/tapestry5/trunk/tapestry-core/src/test/resources/org/apache/tapestry5/integration/app1/pages/TreeSelectionDemo.tml Mon Sep  5 21:30:22 2011
@@ -0,0 +1,28 @@
+<t:border xmlns:t="http://tapestry.apache.org/schema/tapestry_5_3.xsd" xmlns:p="tapestry:parameter">
+
+    <h1>Tree Selection Demo</h1>
+
+    <t:tree class="test-hook" t:id="tree" model="stuffModel" selectionModel="selectionModel"/>
+
+    <p>
+        [
+        <t:pagelink page="treeSelectionDemo">Redraw</t:pagelink>
+        ]
+        [
+        <t:actionlink t:id="clearAll">clear all</t:actionlink>
+        ]
+    </p>
+
+    <h2>Selections</h2>
+
+    <ul>
+
+        <t:loop source="selectedObjects" value="selectedObject">
+
+            <li>${selectedObject.name}</li>
+        </t:loop>
+
+    </ul>
+
+
+</t:border>
\ No newline at end of file