Author: ehillenius
Date: Thu Apr 12 15:59:03 2007
New Revision: 528277

URL: http://svn.apache.org/viewvc?view=rev&rev=528277
Log:
switch trees, part one

Added:
    
incubator/wicket/branches/wicket-1.x/jdk-1.4/wicket-extensions/src/main/java/org/apache/wicket/markup/
    
incubator/wicket/branches/wicket-1.x/jdk-1.4/wicket-extensions/src/main/java/org/apache/wicket/markup/html/
    
incubator/wicket/branches/wicket-1.x/jdk-1.4/wicket-extensions/src/main/java/org/apache/wicket/markup/html/tree/
    
incubator/wicket/branches/wicket-1.x/jdk-1.4/wicket-extensions/src/main/java/org/apache/wicket/markup/html/tree/AbstractTree.java
    
incubator/wicket/branches/wicket-1.x/jdk-1.4/wicket-extensions/src/main/java/org/apache/wicket/markup/html/tree/SelectedPathReplacementModel.java
    
incubator/wicket/branches/wicket-1.x/jdk-1.4/wicket-extensions/src/main/java/org/apache/wicket/markup/html/tree/Tree$DefaultNodePanel.html
    
incubator/wicket/branches/wicket-1.x/jdk-1.4/wicket-extensions/src/main/java/org/apache/wicket/markup/html/tree/Tree.html
    
incubator/wicket/branches/wicket-1.x/jdk-1.4/wicket-extensions/src/main/java/org/apache/wicket/markup/html/tree/Tree.java
    
incubator/wicket/branches/wicket-1.x/jdk-1.4/wicket-extensions/src/main/java/org/apache/wicket/markup/html/tree/TreeState.java
    
incubator/wicket/branches/wicket-1.x/jdk-1.4/wicket-extensions/src/main/java/org/apache/wicket/markup/html/tree/blank.gif
   (with props)
    
incubator/wicket/branches/wicket-1.x/jdk-1.4/wicket-extensions/src/main/java/org/apache/wicket/markup/html/tree/minus.gif
   (with props)
    
incubator/wicket/branches/wicket-1.x/jdk-1.4/wicket-extensions/src/main/java/org/apache/wicket/markup/html/tree/package.html
    
incubator/wicket/branches/wicket-1.x/jdk-1.4/wicket-extensions/src/main/java/org/apache/wicket/markup/html/tree/plus.gif
   (with props)
    
incubator/wicket/branches/wicket-1.x/jdk-1.4/wicket-extensions/src/main/java/org/apache/wicket/markup/html/tree/tree.css
    
incubator/wicket/branches/wicket-1.x/jdk-1.4/wicket-extensions/src/test/java/org/apache/wicket/markup/
    
incubator/wicket/branches/wicket-1.x/jdk-1.4/wicket-extensions/src/test/java/org/apache/wicket/markup/html/
    
incubator/wicket/branches/wicket-1.x/jdk-1.4/wicket-extensions/src/test/java/org/apache/wicket/markup/html/tree/
    
incubator/wicket/branches/wicket-1.x/jdk-1.4/wicket-extensions/src/test/java/org/apache/wicket/markup/html/tree/AbstractTreePage.java
    
incubator/wicket/branches/wicket-1.x/jdk-1.4/wicket-extensions/src/test/java/org/apache/wicket/markup/html/tree/BorderedPage.java
    
incubator/wicket/branches/wicket-1.x/jdk-1.4/wicket-extensions/src/test/java/org/apache/wicket/markup/html/tree/MyTree.java
    
incubator/wicket/branches/wicket-1.x/jdk-1.4/wicket-extensions/src/test/java/org/apache/wicket/markup/html/tree/PageBorder.html
    
incubator/wicket/branches/wicket-1.x/jdk-1.4/wicket-extensions/src/test/java/org/apache/wicket/markup/html/tree/PageBorder.java
    
incubator/wicket/branches/wicket-1.x/jdk-1.4/wicket-extensions/src/test/java/org/apache/wicket/markup/html/tree/TreePage.html
    
incubator/wicket/branches/wicket-1.x/jdk-1.4/wicket-extensions/src/test/java/org/apache/wicket/markup/html/tree/TreePage.java
    
incubator/wicket/branches/wicket-1.x/jdk-1.4/wicket-extensions/src/test/java/org/apache/wicket/markup/html/tree/TreePageExpectedResult_1-1.html
    
incubator/wicket/branches/wicket-1.x/jdk-1.4/wicket-extensions/src/test/java/org/apache/wicket/markup/html/tree/TreePageExpectedResult_1.html
    
incubator/wicket/branches/wicket-1.x/jdk-1.4/wicket-extensions/src/test/java/org/apache/wicket/markup/html/tree/TreePageNoHtmlHead.html
    
incubator/wicket/branches/wicket-1.x/jdk-1.4/wicket-extensions/src/test/java/org/apache/wicket/markup/html/tree/TreePageNoHtmlHead.java
    
incubator/wicket/branches/wicket-1.x/jdk-1.4/wicket-extensions/src/test/java/org/apache/wicket/markup/html/tree/TreePageNoHtmlHeadExpectedResult_1-1.html
    
incubator/wicket/branches/wicket-1.x/jdk-1.4/wicket-extensions/src/test/java/org/apache/wicket/markup/html/tree/TreePageNoHtmlHeadExpectedResult_1.html
    
incubator/wicket/branches/wicket-1.x/jdk-1.4/wicket-extensions/src/test/java/org/apache/wicket/markup/html/tree/TreePageNoWicketHeadTag.html
    
incubator/wicket/branches/wicket-1.x/jdk-1.4/wicket-extensions/src/test/java/org/apache/wicket/markup/html/tree/TreePageNoWicketHeadTag.java
    
incubator/wicket/branches/wicket-1.x/jdk-1.4/wicket-extensions/src/test/java/org/apache/wicket/markup/html/tree/TreePageNoWicketHeadTagExpectedResult_1-1.html
    
incubator/wicket/branches/wicket-1.x/jdk-1.4/wicket-extensions/src/test/java/org/apache/wicket/markup/html/tree/TreePageNoWicketHeadTagExpectedResult_1.html
    
incubator/wicket/branches/wicket-1.x/jdk-1.4/wicket-extensions/src/test/java/org/apache/wicket/markup/html/tree/TreePageWithBorder.html
    
incubator/wicket/branches/wicket-1.x/jdk-1.4/wicket-extensions/src/test/java/org/apache/wicket/markup/html/tree/TreePageWithBorder.java
    
incubator/wicket/branches/wicket-1.x/jdk-1.4/wicket-extensions/src/test/java/org/apache/wicket/markup/html/tree/TreePageWithBorderExpectedResult_1-1.html
    
incubator/wicket/branches/wicket-1.x/jdk-1.4/wicket-extensions/src/test/java/org/apache/wicket/markup/html/tree/TreePageWithBorderExpectedResult_1.html
    
incubator/wicket/branches/wicket-1.x/jdk-1.4/wicket-extensions/src/test/java/org/apache/wicket/markup/html/tree/TreeTest.java
    
incubator/wicket/branches/wicket-1.x/jdk-1.4/wicket-extensions/src/test/java/org/apache/wicket/markup/html/tree/folder.gif
   (with props)
    
incubator/wicket/branches/wicket-1.x/jdk-1.4/wicket-extensions/src/test/java/org/apache/wicket/markup/html/tree/folderopen.gif
   (with props)
    
incubator/wicket/branches/wicket-1.x/jdk-1.4/wicket-extensions/src/test/java/org/apache/wicket/markup/html/tree/node.gif
   (with props)
    
incubator/wicket/branches/wicket-1.x/jdk-1.4/wicket/src/main/java/org/apache/wicket/extensions/
    
incubator/wicket/branches/wicket-1.x/jdk-1.4/wicket/src/main/java/org/apache/wicket/extensions/markup/
    
incubator/wicket/branches/wicket-1.x/jdk-1.4/wicket/src/main/java/org/apache/wicket/extensions/markup/html/
    
incubator/wicket/branches/wicket-1.x/jdk-1.4/wicket/src/main/java/org/apache/wicket/extensions/markup/html/tree/
    
incubator/wicket/branches/wicket-1.x/jdk-1.4/wicket/src/main/java/org/apache/wicket/extensions/markup/html/tree/AbstractTree.java
    
incubator/wicket/branches/wicket-1.x/jdk-1.4/wicket/src/main/java/org/apache/wicket/extensions/markup/html/tree/DefaultAbstractTree.java
    
incubator/wicket/branches/wicket-1.x/jdk-1.4/wicket/src/main/java/org/apache/wicket/extensions/markup/html/tree/DefaultTreeState.java
    
incubator/wicket/branches/wicket-1.x/jdk-1.4/wicket/src/main/java/org/apache/wicket/extensions/markup/html/tree/ITreeState.java
    
incubator/wicket/branches/wicket-1.x/jdk-1.4/wicket/src/main/java/org/apache/wicket/extensions/markup/html/tree/ITreeStateListener.java
    
incubator/wicket/branches/wicket-1.x/jdk-1.4/wicket/src/main/java/org/apache/wicket/extensions/markup/html/tree/Tree.html
    
incubator/wicket/branches/wicket-1.x/jdk-1.4/wicket/src/main/java/org/apache/wicket/extensions/markup/html/tree/Tree.java
    
incubator/wicket/branches/wicket-1.x/jdk-1.4/wicket/src/main/java/org/apache/wicket/extensions/markup/html/tree/package.html
    
incubator/wicket/branches/wicket-1.x/jdk-1.4/wicket/src/main/java/org/apache/wicket/extensions/markup/html/tree/res/
    
incubator/wicket/branches/wicket-1.x/jdk-1.4/wicket/src/main/java/org/apache/wicket/extensions/markup/html/tree/res/dotted-line.png
   (with props)
    
incubator/wicket/branches/wicket-1.x/jdk-1.4/wicket/src/main/java/org/apache/wicket/extensions/markup/html/tree/res/folder-closed.gif
   (with props)
    
incubator/wicket/branches/wicket-1.x/jdk-1.4/wicket/src/main/java/org/apache/wicket/extensions/markup/html/tree/res/folder-open.gif
   (with props)
    
incubator/wicket/branches/wicket-1.x/jdk-1.4/wicket/src/main/java/org/apache/wicket/extensions/markup/html/tree/res/item.gif
   (with props)
    
incubator/wicket/branches/wicket-1.x/jdk-1.4/wicket/src/main/java/org/apache/wicket/extensions/markup/html/tree/res/tree-images.png
   (with props)
    
incubator/wicket/branches/wicket-1.x/jdk-1.4/wicket/src/main/java/org/apache/wicket/extensions/markup/html/tree/res/tree-table.css
    
incubator/wicket/branches/wicket-1.x/jdk-1.4/wicket/src/main/java/org/apache/wicket/extensions/markup/html/tree/res/tree.css
    
incubator/wicket/branches/wicket-1.x/jdk-1.4/wicket/src/main/java/org/apache/wicket/extensions/markup/html/tree/res/tree.js
    
incubator/wicket/branches/wicket-1.x/jdk-1.4/wicket/src/main/java/org/apache/wicket/extensions/markup/html/tree/table/
    
incubator/wicket/branches/wicket-1.x/jdk-1.4/wicket/src/main/java/org/apache/wicket/extensions/markup/html/tree/table/AbstractColumn.java
    
incubator/wicket/branches/wicket-1.x/jdk-1.4/wicket/src/main/java/org/apache/wicket/extensions/markup/html/tree/table/AbstractRenderableColumn.java
    
incubator/wicket/branches/wicket-1.x/jdk-1.4/wicket/src/main/java/org/apache/wicket/extensions/markup/html/tree/table/AbstractTreeColumn.java
    
incubator/wicket/branches/wicket-1.x/jdk-1.4/wicket/src/main/java/org/apache/wicket/extensions/markup/html/tree/table/ColumnLocation.java
    
incubator/wicket/branches/wicket-1.x/jdk-1.4/wicket/src/main/java/org/apache/wicket/extensions/markup/html/tree/table/IColumn.java
    
incubator/wicket/branches/wicket-1.x/jdk-1.4/wicket/src/main/java/org/apache/wicket/extensions/markup/html/tree/table/IRenderable.java
    
incubator/wicket/branches/wicket-1.x/jdk-1.4/wicket/src/main/java/org/apache/wicket/extensions/markup/html/tree/table/MiddleColumnsView.java
    
incubator/wicket/branches/wicket-1.x/jdk-1.4/wicket/src/main/java/org/apache/wicket/extensions/markup/html/tree/table/PropertyRenderableColumn.java
    
incubator/wicket/branches/wicket-1.x/jdk-1.4/wicket/src/main/java/org/apache/wicket/extensions/markup/html/tree/table/PropertyTreeColumn.java
    
incubator/wicket/branches/wicket-1.x/jdk-1.4/wicket/src/main/java/org/apache/wicket/extensions/markup/html/tree/table/SideColumnsView.java
    
incubator/wicket/branches/wicket-1.x/jdk-1.4/wicket/src/main/java/org/apache/wicket/extensions/markup/html/tree/table/TreeTable$TreeFragment.html
    
incubator/wicket/branches/wicket-1.x/jdk-1.4/wicket/src/main/java/org/apache/wicket/extensions/markup/html/tree/table/TreeTable.html
    
incubator/wicket/branches/wicket-1.x/jdk-1.4/wicket/src/main/java/org/apache/wicket/extensions/markup/html/tree/table/TreeTable.java
Removed:
    
incubator/wicket/branches/wicket-1.x/jdk-1.4/wicket-extensions/src/main/java/org/apache/wicket/extensions/markup/html/tree/AbstractTree.java
    
incubator/wicket/branches/wicket-1.x/jdk-1.4/wicket-extensions/src/main/java/org/apache/wicket/extensions/markup/html/tree/DefaultAbstractTree.java
    
incubator/wicket/branches/wicket-1.x/jdk-1.4/wicket-extensions/src/main/java/org/apache/wicket/extensions/markup/html/tree/DefaultTreeState.java
    
incubator/wicket/branches/wicket-1.x/jdk-1.4/wicket-extensions/src/main/java/org/apache/wicket/extensions/markup/html/tree/ITreeState.java
    
incubator/wicket/branches/wicket-1.x/jdk-1.4/wicket-extensions/src/main/java/org/apache/wicket/extensions/markup/html/tree/ITreeStateListener.java
    
incubator/wicket/branches/wicket-1.x/jdk-1.4/wicket-extensions/src/main/java/org/apache/wicket/extensions/markup/html/tree/Tree.html
    
incubator/wicket/branches/wicket-1.x/jdk-1.4/wicket-extensions/src/main/java/org/apache/wicket/extensions/markup/html/tree/Tree.java
    
incubator/wicket/branches/wicket-1.x/jdk-1.4/wicket-extensions/src/main/java/org/apache/wicket/extensions/markup/html/tree/package.html
    
incubator/wicket/branches/wicket-1.x/jdk-1.4/wicket-extensions/src/main/java/org/apache/wicket/extensions/markup/html/tree/res/
    
incubator/wicket/branches/wicket-1.x/jdk-1.4/wicket-extensions/src/main/java/org/apache/wicket/extensions/markup/html/tree/table/
    
incubator/wicket/branches/wicket-1.x/jdk-1.4/wicket/src/main/java/org/apache/wicket/markup/html/tree/
    
incubator/wicket/branches/wicket-1.x/jdk-1.4/wicket/src/test/java/org/apache/wicket/markup/html/tree/

Added: 
incubator/wicket/branches/wicket-1.x/jdk-1.4/wicket-extensions/src/main/java/org/apache/wicket/markup/html/tree/AbstractTree.java
URL: 
http://svn.apache.org/viewvc/incubator/wicket/branches/wicket-1.x/jdk-1.4/wicket-extensions/src/main/java/org/apache/wicket/markup/html/tree/AbstractTree.java?view=auto&rev=528277
==============================================================================
--- 
incubator/wicket/branches/wicket-1.x/jdk-1.4/wicket-extensions/src/main/java/org/apache/wicket/markup/html/tree/AbstractTree.java
 (added)
+++ 
incubator/wicket/branches/wicket-1.x/jdk-1.4/wicket-extensions/src/main/java/org/apache/wicket/markup/html/tree/AbstractTree.java
 Thu Apr 12 15:59:03 2007
@@ -0,0 +1,398 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 org.apache.wicket.markup.html.tree;
+
+import java.util.Enumeration;
+
+import javax.swing.tree.DefaultMutableTreeNode;
+import javax.swing.tree.DefaultTreeSelectionModel;
+import javax.swing.tree.TreeModel;
+import javax.swing.tree.TreeNode;
+import javax.swing.tree.TreePath;
+import javax.swing.tree.TreeSelectionModel;
+
+import org.apache.wicket.markup.html.panel.Panel;
+
+
+/**
+ * Base component for trees. The trees from this package work with the Swing
+ * tree models and [EMAIL PROTECTED] 
javax.swing.tree.DefaultMutableTreeNode}s. Hence,
+ * users can re-use their Swing tree models.
+ * 
+ * @author Eelco Hillenius
+ */
+public abstract class AbstractTree extends Panel
+{
+       /** AbstractTree state for this component. */
+       private TreeState treeState;
+
+       /**
+        * Construct using the given model as the tree model to use. A new tree
+        * state will be constructed by calling newTreeState.
+        * 
+        * @param id
+        *            The id of this component
+        * @param model
+        *            the underlying tree model
+        */
+       public AbstractTree(final String id, final TreeModel model)
+       {
+               super(id);
+               this.treeState = newTreeState(model);
+       }
+
+       /**
+        * Construct using the given tree state that holds the model to be used 
as
+        * the tree model.
+        * 
+        * @param id
+        *            The id of this component
+        * @param treeState
+        *            treeState that holds the underlying tree model
+        */
+       public AbstractTree(final String id, final TreeState treeState)
+       {
+               super(id);
+               this.treeState = treeState;
+       }
+
+       /**
+        * Ensures that the node identified by the specified path is collapsed 
and
+        * viewable.
+        * 
+        * @param path
+        *            the <code>TreePath</code> identifying a node
+        */
+       public void collapsePath(TreePath path)
+       {
+               setExpandedState(path, false);
+       }
+
+       /**
+        * Collapses all the siblings of a given node.
+        * 
+        * @param node
+        *            The node of which to collapse the siblings.
+        */
+       public void collapseSiblings(final DefaultMutableTreeNode node)
+       {
+               // Collapse all previous siblings
+               DefaultMutableTreeNode previousNode = node.getPreviousSibling();
+               while (null != previousNode)
+               {
+                       final TreePath siblingSelection = new 
TreePath(previousNode.getPath());
+                       setExpandedState(siblingSelection, false); // inverse
+                       previousNode = previousNode.getPreviousSibling();
+               }
+               // Collapse all following siblings
+               DefaultMutableTreeNode nextNode = node.getNextSibling();
+               while (null != nextNode)
+               {
+                       final TreePath siblingSelection = new 
TreePath(nextNode.getPath());
+                       setExpandedState(siblingSelection, false); // inverse
+                       // ToDo: Check if previousNode can be null? If so, 
needs trapping - Gwyn
+                       nextNode = previousNode.getNextSibling();
+               }
+       }
+
+       /**
+        * Expand or collapse all nodes.
+        * 
+        * @param expand
+        *            If true, expand all nodes in the tree. Else collapse all 
nodes
+        *            in the tree.
+        */
+       public void expandAll(boolean expand)
+       {
+               TreeNode root = (TreeNode)getTreeState().getModel().getRoot();
+               expandAll(new TreePath(root), expand);
+       }
+
+       /**
+        * Ensures that the node identified by the specified path is expanded 
and
+        * viewable. If the last item in the path is a leaf, this will have no
+        * effect.
+        * 
+        * @param path
+        *            the <code>TreePath</code> identifying a node
+        */
+       public void expandPath(TreePath path)
+       {
+               // Only expand if not leaf!
+               TreeModel model = getTreeState().getModel();
+
+               if (path != null && model != null && 
!model.isLeaf(path.getLastPathComponent()))
+               {
+                       setExpandedState(path, true);
+               }
+       }
+
+       /**
+        * Gets the current tree state.
+        * 
+        * @return the tree current tree state
+        */
+       public final TreeState getTreeState()
+       {
+               return treeState;
+       }
+
+       /**
+        * Convenience method that determines whether the path of the given tree
+        * node is expanded in this tree's state.
+        * 
+        * @param node
+        *            the tree node
+        * @return whether the path of the given tree node is expanded
+        */
+       public final boolean isExpanded(DefaultMutableTreeNode node)
+       {
+               return isExpanded(new TreePath(node.getPath()));
+       }
+
+       /**
+        * Convenience method that determines whether the given path is 
expanded in
+        * this tree's state.
+        * 
+        * @param path
+        *            the tree path
+        * @return whether the given path is expanded
+        */
+       public final boolean isExpanded(TreePath path)
+       {
+               return treeState.isExpanded(path);
+       }
+
+       /**
+        * Gets whether the tree root node should be displayed.
+        * 
+        * @return whether the tree root node should be displayed
+        */
+       public final boolean isRootVisible()
+       {
+               return treeState.isRootVisible();
+       }
+
+       /**
+        * Returns true if the value identified by path is currently viewable, 
which
+        * means it is either the root or all of its parents are expanded.
+        * Otherwise, this method returns false.
+        * 
+        * @param path
+        *            The path
+        * 
+        * @return true if the node is viewable, otherwise false
+        */
+       public final boolean isVisible(TreePath path)
+       {
+               if (path != null)
+               {
+                       TreePath parentPath = path.getParentPath();
+
+                       if (parentPath != null)
+                               return isExpanded(parentPath);
+                       // Root.
+                       return true;
+               }
+               return false;
+       }
+
+       /**
+        * Creates a new tree state by creating a new [EMAIL PROTECTED] 
TreeState}object,
+        * which is then set as the current tree state, creating a new
+        * [EMAIL PROTECTED] TreeSelectionModel}and then calling setTreeModel 
with this
+        * 
+        * @param model
+        *            the model that the new tree state applies to
+        * @return the tree state
+        */
+       public TreeState newTreeState(final TreeModel model)
+       {
+               return newTreeState(model, true);
+       }
+
+       /**
+        * Sets the new expanded state, based on the given node
+        * 
+        * @param node
+        *            the tree node model
+        */
+       public void setExpandedState(final DefaultMutableTreeNode node)
+       {
+               final TreePath selection = new TreePath(node.getPath());
+               setExpandedState(selection, 
(!treeState.isExpanded(selection))); // inverse
+
+               // If set to SINGLE_TREE_SELECTION, collapse all sibling nodes
+               final int selectionType = 
getTreeState().getSelectionModel().getSelectionMode();
+               if (TreeSelectionModel.SINGLE_TREE_SELECTION == selectionType)
+               {
+                       collapseSiblings(node);
+               }
+       }
+
+       /**
+        * Sets the expanded property in the stree state for selection.
+        * 
+        * @param selection
+        *            the selection to set the expanded property for
+        * @param expanded
+        *            true if the selection is expanded, false otherwise
+        */
+       public void setExpandedState(final TreePath selection, final boolean 
expanded)
+       {
+               treeState.setExpandedState(selection, expanded);
+       }
+
+       /**
+        * Sets whether the tree root node should be displayed.
+        * 
+        * @param rootVisible
+        *            whether the tree node should be displayed
+        */
+       public void setRootVisible(final boolean rootVisible)
+       {
+               treeState.setRootVisible(rootVisible);
+       }
+
+       /**
+        * Sets the new expanded state (to true), based on the given user node 
and
+        * set the tree path to the currently selected.
+        * 
+        * @param node
+        *            the tree node model
+        */
+       public void setSelected(final DefaultMutableTreeNode node)
+       {
+               final TreePath selection = new TreePath(node.getPath());
+               treeState.setSelectedPath(selection);
+               setExpandedState(selection, true);
+       }
+
+       /**
+        * Sets the current tree model.
+        * 
+        * @param treeModel
+        *            the tree model to set as the current one
+        */
+       public void setTreeModel(final TreeModel treeModel)
+       {
+               this.treeState = newTreeState(treeModel);
+       }
+
+       /**
+        * Sets the current tree state to the given tree state.
+        * 
+        * @param treeState
+        *            the tree state to set as the current one
+        */
+       public void setTreeState(final TreeState treeState)
+       {
+               this.treeState = treeState;
+       }
+
+       /**
+        * Gives the current tree model as a string.
+        * 
+        * @return the current tree model as a string
+        */
+       public String toString()
+       {
+               StringBuffer b = new StringBuffer("-- TREE MODEL --\n");
+               TreeState state = getTreeState();
+               TreeModel treeModel = null;
+               if (state != null)
+               {
+                       treeModel = state.getModel();
+               }
+               if (treeModel != null)
+               {
+                       StringBuffer tabs = new StringBuffer();
+                       DefaultMutableTreeNode rootNode = 
(DefaultMutableTreeNode)treeModel.getRoot();
+                       Enumeration e = rootNode.preorderEnumeration();
+                       while (e.hasMoreElements())
+                       {
+                               DefaultMutableTreeNode node = 
(DefaultMutableTreeNode)e.nextElement();
+                               tabs.delete(0, tabs.length());
+                               tabs.append("|");
+                               for (int i = 0; i < node.getLevel(); i++)
+                               {
+                                       tabs.append("-");
+                               }
+                               b.append(tabs).append(node).append("\n");
+                       }
+               }
+               else
+               {
+                       b.append("<EMPTY>");
+               }
+               return b.toString();
+       }
+
+       /**
+        * Creates a new tree state by creating a new [EMAIL PROTECTED] 
TreeState}object,
+        * which is then set as the current tree state, creating a new
+        * [EMAIL PROTECTED] TreeSelectionModel}and then calling setTreeModel 
with this
+        * 
+        * @param treeModel
+        *            the model that the new tree state applies to
+        * @param rootVisible
+        *            whether the tree node should be displayed
+        * @return the tree state
+        */
+       protected final TreeState newTreeState(final TreeModel treeModel, final 
boolean rootVisible)
+       {
+               final TreeState treeState = new TreeState();
+               final TreeSelectionModel treeSelectionModel = new 
DefaultTreeSelectionModel();
+               
treeSelectionModel.setSelectionMode(TreeSelectionModel.DISCONTIGUOUS_TREE_SELECTION);
+               treeState.setModel(treeModel);
+               treeState.setSelectionModel(treeSelectionModel);
+               treeState.setRootVisible(rootVisible);
+               treeModel.addTreeModelListener(treeState);
+               return treeState;
+       }
+
+       /**
+        * Expand recursively.
+        * 
+        * @param parent
+        *            The current parent node
+        * @param expand
+        *            Whether to expand or to collapse
+        */
+       private final void expandAll(TreePath parent, boolean expand)
+       {
+               TreeNode node = (TreeNode)parent.getLastPathComponent();
+               if (node.getChildCount() >= 0)
+               {
+                       for (Enumeration e = node.children(); 
e.hasMoreElements();)
+                       {
+                               TreeNode n = (TreeNode)e.nextElement();
+                               TreePath path = parent.pathByAddingChild(n);
+                               expandAll(path, expand);
+                       }
+               }
+
+               if (expand)
+               {
+                       expandPath(parent);
+               }
+               else
+               {
+                       collapsePath(parent);
+               }
+       }
+}

Added: 
incubator/wicket/branches/wicket-1.x/jdk-1.4/wicket-extensions/src/main/java/org/apache/wicket/markup/html/tree/SelectedPathReplacementModel.java
URL: 
http://svn.apache.org/viewvc/incubator/wicket/branches/wicket-1.x/jdk-1.4/wicket-extensions/src/main/java/org/apache/wicket/markup/html/tree/SelectedPathReplacementModel.java?view=auto&rev=528277
==============================================================================
--- 
incubator/wicket/branches/wicket-1.x/jdk-1.4/wicket-extensions/src/main/java/org/apache/wicket/markup/html/tree/SelectedPathReplacementModel.java
 (added)
+++ 
incubator/wicket/branches/wicket-1.x/jdk-1.4/wicket-extensions/src/main/java/org/apache/wicket/markup/html/tree/SelectedPathReplacementModel.java
 Thu Apr 12 15:59:03 2007
@@ -0,0 +1,73 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 org.apache.wicket.markup.html.tree;
+
+import javax.swing.tree.DefaultMutableTreeNode;
+import javax.swing.tree.TreePath;
+
+import org.apache.wicket.model.AbstractReadOnlyModel;
+
+
+/**
+ * Replacement model that looks up whether the current row is the active one.
+ * 
+ * @author Eelco Hillenius
+ */
+public final class SelectedPathReplacementModel extends AbstractReadOnlyModel
+{
+       private static final long serialVersionUID = 1L;
+
+       /** the tree node. */
+       private final DefaultMutableTreeNode node;
+
+       /** The tree. */
+       private final Tree tree;
+
+       /**
+        * Construct.
+        * 
+        * @param tree
+        *            The tree
+        * 
+        * @param node
+        *            The tree node
+        */
+       public SelectedPathReplacementModel(Tree tree, DefaultMutableTreeNode 
node)
+       {
+               this.node = node;
+               this.tree = tree;
+       }
+
+       /**
+        * @see org.apache.wicket.model.IModel#getObject()
+        */
+       public Object getObject()
+       {
+               TreePath path = new TreePath(node.getPath());
+               TreePath selectedPath = tree.getTreeState().getSelectedPath();
+               if (selectedPath != null)
+               {
+                       boolean equals = tree.equals(path, selectedPath);
+
+                       if (equals)
+                       {
+                               return "treerow-selected";
+                       }
+               }
+               return "treerow";
+       }
+}
\ No newline at end of file

Added: 
incubator/wicket/branches/wicket-1.x/jdk-1.4/wicket-extensions/src/main/java/org/apache/wicket/markup/html/tree/Tree$DefaultNodePanel.html
URL: 
http://svn.apache.org/viewvc/incubator/wicket/branches/wicket-1.x/jdk-1.4/wicket-extensions/src/main/java/org/apache/wicket/markup/html/tree/Tree%24DefaultNodePanel.html?view=auto&rev=528277
==============================================================================
--- 
incubator/wicket/branches/wicket-1.x/jdk-1.4/wicket-extensions/src/main/java/org/apache/wicket/markup/html/tree/Tree$DefaultNodePanel.html
 (added)
+++ 
incubator/wicket/branches/wicket-1.x/jdk-1.4/wicket-extensions/src/main/java/org/apache/wicket/markup/html/tree/Tree$DefaultNodePanel.html
 Thu Apr 12 15:59:03 2007
@@ -0,0 +1,23 @@
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You 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.
+-->
+<wicket:panel>
+<a href="#" wicket:id="junctionLink" class="wicket-indent-tree-junctionlink"
+       ><img wicket:id="junctionImage" 
class="wicket-indent-tree-junctionimage"/></a>
+<a href="#" wicket:id="nodeLink" class="wicket-indent-tree-nodelink"
+       ><img wicket:id="nodeImage" class="wicket-indent-tree-nodeimage"/><span
+               wicket:id="label" 
class="wicket-indent-tree-nodelabel">label</span></a>
+</wicket:panel>

Added: 
incubator/wicket/branches/wicket-1.x/jdk-1.4/wicket-extensions/src/main/java/org/apache/wicket/markup/html/tree/Tree.html
URL: 
http://svn.apache.org/viewvc/incubator/wicket/branches/wicket-1.x/jdk-1.4/wicket-extensions/src/main/java/org/apache/wicket/markup/html/tree/Tree.html?view=auto&rev=528277
==============================================================================
--- 
incubator/wicket/branches/wicket-1.x/jdk-1.4/wicket-extensions/src/main/java/org/apache/wicket/markup/html/tree/Tree.html
 (added)
+++ 
incubator/wicket/branches/wicket-1.x/jdk-1.4/wicket-extensions/src/main/java/org/apache/wicket/markup/html/tree/Tree.html
 Thu Apr 12 15:59:03 2007
@@ -0,0 +1,24 @@
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You 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.
+-->
+<wicket:panel>
+<span class="wicket-indent-tree">
+<span wicket:id="tree"  class="wicket-indent-tree-row">
+ <span wicket:id="spacers" class="wicket-indent-tree-spacer"></span>
+  <span wicket:id="node" class="wicket-indent-tree-node"></span>
+ </span>
+</span>
+</wicket:panel>

Added: 
incubator/wicket/branches/wicket-1.x/jdk-1.4/wicket-extensions/src/main/java/org/apache/wicket/markup/html/tree/Tree.java
URL: 
http://svn.apache.org/viewvc/incubator/wicket/branches/wicket-1.x/jdk-1.4/wicket-extensions/src/main/java/org/apache/wicket/markup/html/tree/Tree.java?view=auto&rev=528277
==============================================================================
--- 
incubator/wicket/branches/wicket-1.x/jdk-1.4/wicket-extensions/src/main/java/org/apache/wicket/markup/html/tree/Tree.java
 (added)
+++ 
incubator/wicket/branches/wicket-1.x/jdk-1.4/wicket-extensions/src/main/java/org/apache/wicket/markup/html/tree/Tree.java
 Thu Apr 12 15:59:03 2007
@@ -0,0 +1,756 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 org.apache.wicket.markup.html.tree;
+
+import java.util.ArrayList;
+import java.util.Enumeration;
+import java.util.List;
+
+import javax.swing.event.TreeModelEvent;
+import javax.swing.event.TreeModelListener;
+import javax.swing.tree.DefaultMutableTreeNode;
+import javax.swing.tree.TreeModel;
+import javax.swing.tree.TreePath;
+
+import org.apache.wicket.AttributeModifier;
+import org.apache.wicket.Component;
+import org.apache.wicket.ResourceReference;
+import org.apache.wicket.WicketRuntimeException;
+import org.apache.wicket.behavior.HeaderContributor;
+import org.apache.wicket.markup.html.basic.Label;
+import org.apache.wicket.markup.html.image.Image;
+import org.apache.wicket.markup.html.link.Link;
+import org.apache.wicket.markup.html.list.ListItem;
+import org.apache.wicket.markup.html.list.ListView;
+import org.apache.wicket.markup.html.list.Loop;
+import org.apache.wicket.markup.html.panel.Panel;
+import org.apache.wicket.markup.html.resources.CompressedResourceReference;
+import org.apache.wicket.model.IModel;
+
+
+/**
+ * An tree that renders as a flat (not-nested) list, using spacers for
+ * indentation and nodes at the end of one row.
+ * <p>
+ * The visible tree rows are put in one flat list. For each row, a list is
+ * constructed with fillers, that can be used to create indentation. After the
+ * fillers, the actual node content is put.
+ * </p>
+ * <p>
+ * </p>
+ * 
+ * @author Eelco Hillenius
+ */
+public class Tree extends AbstractTree implements TreeModelListener
+{
+       /**
+        * The default node panel. If you provide your own panel by overriding
+        * Tree.newNodePanel, but only want to override the markup, not the
+        * components that are added, you <i>may</i> extend this class. If you 
want
+        * to use other components than the default, provide a panel or fragment
+        * instead (and that's probably what you want as the look and feel of 
what
+        * this panel renders may be adjusted by overriding
+        * [EMAIL PROTECTED] Tree#createJunctionLink(DefaultMutableTreeNode)} 
and
+        * [EMAIL PROTECTED] Tree#createNodeLink(DefaultMutableTreeNode)}.
+        */
+       public static class DefaultNodePanel extends Panel
+       {
+               private static final long serialVersionUID = 1L;
+
+               /**
+                * Construct.
+                * 
+                * @param panelId
+                *            The component id
+                * @param tree
+                *            The containing tree component
+                * @param node
+                *            The tree node for this panel
+                */
+               public DefaultNodePanel(String panelId, Tree tree, 
DefaultMutableTreeNode node)
+               {
+                       super(panelId);
+                       // create a link for expanding and collapsing the node
+                       Link expandCollapsLink = tree.createJunctionLink(node);
+                       add(expandCollapsLink);
+                       // create a link for selecting a node
+                       Link selectLink = tree.createNodeLink(node);
+                       add(selectLink);
+               }
+       }
+
+       /**
+        * Renders spacer items.
+        */
+       private static final class SpacerList extends Loop
+       {
+               private static final long serialVersionUID = 1L;
+
+               /**
+                * Construct.
+                * 
+                * @param id
+                *            component id
+                * @param size
+                *            size of loop
+                */
+               public SpacerList(String id, int size)
+               {
+                       super(id, size);
+               }
+
+               /**
+                * @see 
org.apache.wicket.markup.html.list.Loop#populateItem(LoopItem)
+                */
+               protected void populateItem(final Loop.LoopItem loopItem)
+               {
+                       // nothing needed; we just render the tags and use CSS 
to indent
+               }
+       }
+
+       /**
+        * List view for tree paths.
+        */
+       private final class TreePathsListView extends ListView
+       {
+               private static final long serialVersionUID = 1L;
+
+               /**
+                * Construct.
+                * 
+                * @param name
+                *            name of the component
+                */
+               public TreePathsListView(String name)
+               {
+                       super(name, treePathsModel);
+               }
+
+               /**
+                * @see 
org.apache.wicket.markup.html.list.ListView#getReuseItems()
+                */
+               public boolean getReuseItems()
+               {
+                       return Tree.this.getOptimizeItemRemoval();
+               }
+
+               /**
+                * @see org.apache.wicket.markup.html.list.ListView#newItem(int)
+                */
+               protected ListItem newItem(final int index)
+               {
+                       IModel listItemModel = getListItemModel(getModel(), 
index);
+
+                       // create a list item that is smart enough to determine 
whether
+                       // it should be displayed or not
+                       return new ListItem(index, listItemModel)
+                       {
+                               private static final long serialVersionUID = 1L;
+
+                               public boolean isVisible()
+                               {
+                                       TreeState treeState = getTreeState();
+                                       DefaultMutableTreeNode node = 
(DefaultMutableTreeNode)getModelObject();
+                                       final TreePath path = new 
TreePath(node.getPath());
+                                       final int row = 
treeState.getRowForPath(path);
+
+                                       // if the row is -1, it is not visible, 
otherwise it is
+                                       return (row != -1);
+                               }
+                       };
+               }
+
+               /**
+                * @see 
org.apache.wicket.markup.html.list.ListView#populateItem(org.apache.wicket.markup.html.list.ListItem)
+                */
+               protected void populateItem(ListItem listItem)
+               {
+                       // get the model object which is a tree node
+                       DefaultMutableTreeNode node = 
(DefaultMutableTreeNode)listItem.getModelObject();
+
+                       // add spacers
+                       int level = node.getLevel();
+                       listItem.add(new SpacerList("spacers", level));
+
+                       // add node panel
+                       Component nodePanel = newNodePanel("node", node);
+                       if (nodePanel == null)
+                       {
+                               throw new WicketRuntimeException("node panel 
must be not-null");
+                       }
+                       if (!"node".equals(nodePanel.getId()))
+                       {
+                               throw new WicketRuntimeException("panel must 
have id 'node' assigned");
+                       }
+
+                       listItem.add(nodePanel);
+
+                       // add attr modifier for highlighting the selection
+                       listItem.add(new AttributeModifier("class", true, new 
SelectedPathReplacementModel(
+                                       Tree.this, node)));
+               }
+       }
+
+       /**
+        * Model for the paths of the tree.
+        */
+       private final class TreePathsModel implements IModel
+       {
+               private static final long serialVersionUID = 1L;
+
+               /** whether this model is dirty. */
+               boolean dirty = true;
+
+               /** tree paths. */
+               private List paths = new ArrayList();
+
+               private transient boolean attached = false;
+
+               /**
+                * Inserts the given node in the path list with the given index.
+                * 
+                * @param index
+                *            the index where the node should be inserted in
+                * @param node
+                *            node to insert
+                */
+               void add(int index, DefaultMutableTreeNode node)
+               {
+                       paths.add(index, node);
+               }
+
+               /**
+                * Gives the index of the given node withing this tree.
+                * 
+                * @param node
+                *            node to look for
+                * @return the index of the given node withing this tree
+                */
+               int indexOf(DefaultMutableTreeNode node)
+               {
+                       return paths.indexOf(node);
+               }
+
+               /**
+                * Removes the given node from the path list.
+                * 
+                * @param node
+                *            the node to remove
+                */
+               void remove(DefaultMutableTreeNode node)
+               {
+                       paths.remove(node);
+               }
+
+
+               public Object getObject()
+               {
+                       if (dirty && !attached)
+                       {
+                               paths.clear();
+                               TreeModel model = getTreeState().getModel();
+                               DefaultMutableTreeNode rootNode = 
(DefaultMutableTreeNode)model.getRoot();
+                               Enumeration e = rootNode.preorderEnumeration();
+                               while (e.hasMoreElements())
+                               {
+                                       DefaultMutableTreeNode treeNode = 
(DefaultMutableTreeNode)e.nextElement();
+                                       // TreePath path = new 
TreePath(treeNode.getPath());
+                                       paths.add(treeNode);
+                               }
+                               dirty = false;
+                       }
+                       attached = true;
+                       return paths;
+               }
+
+               public void setObject(Object object)
+               {
+                       throw new UnsupportedOperationException("This is a 
read-only model");
+               }
+
+               public void detach()
+               {
+                       attached = false;
+               }
+       }
+
+       /** Name of the junction image component; value = 'junctionImage'. */
+       public static final String JUNCTION_IMAGE_NAME = "junctionImage";
+
+       /** Name of the node image component; value = 'nodeImage'. */
+       public static final String NODE_IMAGE_NAME = "nodeImage";
+
+       /** Blank image. */
+       private static final ResourceReference BLANK = new 
ResourceReference(Tree.class, "blank.gif");
+
+       /**
+        * Reference to the css file.
+        */
+       private static final ResourceReference CSS = new 
CompressedResourceReference(Tree.class,
+                       "tree.css");
+
+       /** Minus sign image. */
+       private static final ResourceReference MINUS = new 
ResourceReference(Tree.class, "minus.gif");
+
+       /** Plus sign image. */
+       private static final ResourceReference PLUS = new 
ResourceReference(Tree.class, "plus.gif");
+
+       private static final long serialVersionUID = 1L;
+
+       /**
+        * If true, re-rendering the tree is more efficient if the tree model
+        * doesn't get changed. However, if this is true, you need to push 
changes
+        * to this tree. This can easility be done by registering this tree as 
the
+        * listener for tree model events (TreeModelListener), but you should 
<b>be
+        * carefull</b> not to create a memory leak by doing this (e.g. when you
+        * store the tree model in your session, the tree you registered cannot 
be
+        * GC-ed). TRUE by default.
+        */
+       private boolean reuseItems = true;
+
+       /** List view for tree paths. */
+       private TreePathsListView treePathsListView;
+
+       /** Model for the paths of the tree. */
+       private TreePathsModel treePathsModel;
+
+       /**
+        * Constructor.
+        * 
+        * @param id
+        *            The id of this container
+        * @param model
+        *            the underlying tree model
+        */
+       public Tree(final String id, final TreeModel model)
+       {
+               super(id, model);
+               this.treePathsModel = new TreePathsModel();
+               add(treePathsListView = createTreePathsListView());
+
+               ResourceReference css = getCss();
+               add(HeaderContributor.forCss(css.getScope(), css.getName()));
+       }
+
+       /**
+        * Construct using the given tree state that holds the model to be used 
as
+        * the tree model.
+        * 
+        * @param id
+        *            The id of this container
+        * @param treeState
+        *            treeState that holds the underlying tree model
+        */
+       public Tree(String id, TreeState treeState)
+       {
+               super(id, treeState);
+               this.treePathsModel = new TreePathsModel();
+               add(treePathsListView = createTreePathsListView());
+
+               ResourceReference css = getCss();
+               add(HeaderContributor.forCss(css.getScope(), css.getName()));
+       }
+
+       /**
+        * Gets whether item removal should be optimized. If true, re-rendering 
the
+        * tree is more efficient if the tree model doesn't get changed. 
However, if
+        * this is true, you need to push changes to this tree. This can 
easility be
+        * done by registering this tree as the listener for tree model events
+        * (TreeModelListener), but you should <b>be carefull</b> not to create 
a
+        * memory leak by doing this (e.g. when you store the tree model in your
+        * session, the tree you registered cannot be GC-ed). TRUE by default.
+        * 
+        * @return whether item removal should be optimized
+        * @deprecated Will be replaced by [EMAIL PROTECTED] #getReuseItems()}
+        */
+       // TODO Post 1.2: Remove
+       public boolean getOptimizeItemRemoval()
+       {
+               return getReuseItems();
+       }
+
+       /**
+        * Gets whether items should be reused. If true, re-rendering the tree 
is
+        * more efficient if the tree model doesn't get changed. However, if 
this is
+        * true, you need to push changes to this tree. This can easility be 
done by
+        * registering this tree as the listener for tree model events
+        * (TreeModelListener), but you should <b>be carefull</b> not to create 
a
+        * memory leak by doing this (e.g. when you store the tree model in your
+        * session, the tree you registered cannot be GC-ed). TRUE by default.
+        * 
+        * @return whether items should be reused
+        */
+       public boolean getReuseItems()
+       {
+               return reuseItems;
+       }
+
+       /**
+        * Sets whether items should be reused. If true, re-rendering the tree 
is
+        * more efficient if the tree model doesn't get changed. However, if 
this is
+        * true, you need to push changes to this tree. This can easility be 
done by
+        * registering this tree as the listener for tree model events
+        * (TreeModelListener), but you should <b>be carefull</b> not to create 
a
+        * memory leak by doing this (e.g. when you store the tree model in your
+        * session, the tree you registered cannot be GC-ed). TRUE by default.
+        * 
+        * @param optimizeItemRemoval
+        *            whether the child items should be reused
+        * @deprecated Will be replaced by [EMAIL PROTECTED] 
#setReuseItems(boolean)}
+        */
+       // TODO Post 1.2: Remove
+       public void setOptimizeItemRemoval(boolean optimizeItemRemoval)
+       {
+               setReuseItems(optimizeItemRemoval);
+       }
+
+       /**
+        * Sets whether item removal should be optimized. If true, re-rendering 
the
+        * tree is more efficient if the tree model doesn't get changed. 
However, if
+        * this is true, you need to push changes to this tree. This can 
easility be
+        * done by registering this tree as the listener for tree model events
+        * (TreeModelListener), but you should <b>be carefull</b> not to create 
a
+        * memory leak by doing this (e.g. when you store the tree model in your
+        * session, the tree you registered cannot be GC-ed). TRUE by default.
+        * 
+        * @param reuseItems
+        *            whether the child items should be reused
+        * @return This
+        */
+       public Tree setReuseItems(boolean reuseItems)
+       {
+               this.reuseItems = reuseItems;
+               return this;
+       }
+
+       /**
+        * Sets the current tree model.
+        * 
+        * @param treeModel
+        *            the tree model to set as the current one
+        */
+       public void setTreeModel(final TreeModel treeModel)
+       {
+               super.setTreeModel(treeModel);
+               this.treePathsModel = new TreePathsModel();
+               treePathsListView = createTreePathsListView();
+               replace(treePathsListView);
+       }
+
+       /**
+        * Sets the current tree state to the given tree state.
+        * 
+        * @param treeState
+        *            the tree state to set as the current one
+        */
+       public void setTreeState(final TreeState treeState)
+       {
+               super.setTreeState(treeState);
+               this.treePathsModel = new TreePathsModel();
+               treePathsListView = createTreePathsListView();
+               replace(treePathsListView);
+       }
+
+       /**
+        * @see 
javax.swing.event.TreeModelListener#treeNodesChanged(javax.swing.event.TreeModelEvent)
+        */
+       public void treeNodesChanged(TreeModelEvent e)
+       {
+               // nothing to do here
+       }
+
+       /**
+        * @see 
javax.swing.event.TreeModelListener#treeNodesInserted(javax.swing.event.TreeModelEvent)
+        */
+       public void treeNodesInserted(TreeModelEvent e)
+       {
+               modelChanging();
+               Object[] newNodes = e.getChildren();
+               int len = newNodes.length;
+               for (int i = 0; i < len; i++)
+               {
+                       DefaultMutableTreeNode newNode = 
(DefaultMutableTreeNode)newNodes[i];
+                       DefaultMutableTreeNode previousNode = 
newNode.getPreviousSibling();
+                       int insertRow;
+                       if (previousNode == null)
+                       {
+                               previousNode = 
(DefaultMutableTreeNode)newNode.getParent();
+                       }
+                       if (previousNode != null)
+                       {
+                               insertRow = 
treePathsModel.indexOf(previousNode) + 1;
+                               if (insertRow == -1)
+                               {
+                                       throw new IllegalStateException("node " 
+ previousNode
+                                                       + " not found in 
backing list");
+                               }
+                       }
+                       else
+                       {
+                               insertRow = 0;
+                       }
+                       treePathsModel.add(insertRow, newNode);
+               }
+               modelChanged();
+       }
+
+       /**
+        * @see 
javax.swing.event.TreeModelListener#treeNodesRemoved(javax.swing.event.TreeModelEvent)
+        */
+       public void treeNodesRemoved(TreeModelEvent e)
+       {
+               modelChanging();
+               Object[] deletedNodes = e.getChildren();
+               int len = deletedNodes.length;
+               for (int i = 0; i < len; i++)
+               {
+                       DefaultMutableTreeNode deletedNode = 
(DefaultMutableTreeNode)deletedNodes[i];
+                       treePathsModel.remove(deletedNode);
+               }
+               modelChanged();
+       }
+
+       /**
+        * @see 
javax.swing.event.TreeModelListener#treeStructureChanged(javax.swing.event.TreeModelEvent)
+        */
+       public void treeStructureChanged(TreeModelEvent e)
+       {
+               treePathsModel.dirty = true;
+               modelChanged();
+       }
+
+       /**
+        * Creates a junction link.
+        * 
+        * @param node
+        *            the node
+        * @return link for expanding/ collapsing the tree
+        */
+       protected Link createJunctionLink(final DefaultMutableTreeNode node)
+       {
+               final Link junctionLink = new Link("junctionLink")
+               {
+                       private static final long serialVersionUID = 1L;
+
+                       public void onClick()
+                       {
+                               junctionLinkClicked(node);
+                       }
+               };
+               junctionLink.add(getJunctionImage(node));
+               return junctionLink;
+       }
+
+       /**
+        * Creates a node link.
+        * 
+        * @param node
+        *            the model of the node
+        * @return link for selection
+        */
+       protected Link createNodeLink(final DefaultMutableTreeNode node)
+       {
+               final Link nodeLink = new Link("nodeLink")
+               {
+                       private static final long serialVersionUID = 1L;
+
+                       public void onClick()
+                       {
+                               nodeLinkClicked(node);
+                       }
+               };
+               nodeLink.add(getNodeImage(node));
+               nodeLink.add(new Label("label", getNodeLabel(node)));
+               return nodeLink;
+       }
+
+       /**
+        * Creates the tree paths list view.
+        * 
+        * @return the tree paths list view
+        */
+       protected final TreePathsListView createTreePathsListView()
+       {
+               final TreePathsListView treePaths = new 
TreePathsListView("tree");
+               return treePaths;
+       }
+
+       /**
+        * Returns whether the path and the selected path are equal. This 
method is
+        * used by the [EMAIL PROTECTED] AttributeModifier}that is used for 
setting the CSS
+        * class for the selected row.
+        * 
+        * @param path
+        *            the path
+        * @param selectedPath
+        *            the selected path
+        * @return true if the path and the selected are equal, false otherwise
+        */
+       protected boolean equals(final TreePath path, final TreePath 
selectedPath)
+       {
+               Object pathNode = path.getLastPathComponent();
+               Object selectedPathNode = selectedPath.getLastPathComponent();
+               return (pathNode != null && selectedPathNode != null && 
pathNode.equals(selectedPathNode));
+       }
+
+       /**
+        * Gets the stylesheet.
+        * 
+        * @return the stylesheet
+        */
+       protected ResourceReference getCss()
+       {
+               return CSS;
+       }
+
+       /**
+        * Get image for a junction; used by method createExpandCollapseLink. 
If you
+        * use the packaged panel (Tree.html), you must name the component using
+        * JUNCTION_IMAGE_NAME.
+        * 
+        * @param node
+        *            the tree node
+        * @return the image for the junction
+        */
+       protected Image getJunctionImage(final DefaultMutableTreeNode node)
+       {
+               if (!node.isLeaf())
+               {
+                       // we want the image to be dynamically, yet resolving 
to a static
+                       // image.
+                       return new Image(JUNCTION_IMAGE_NAME)
+                       {
+                               private static final long serialVersionUID = 1L;
+
+                               protected ResourceReference 
getImageResourceReference()
+                               {
+                                       if (isExpanded(node))
+                                       {
+                                               return MINUS;
+                                       }
+                                       else
+                                       {
+                                               return PLUS;
+                                       }
+                               }
+                       };
+               }
+               else
+               {
+                       return new Image(JUNCTION_IMAGE_NAME, BLANK);
+               }
+       }
+
+       /**
+        * Get image for a node; used by method createNodeLink. If you use the
+        * packaged panel (Tree.html), you must name the component using
+        * NODE_IMAGE_NAME.
+        * 
+        * @param node
+        *            the tree node
+        * @return the image for the node
+        */
+       protected Image getNodeImage(final DefaultMutableTreeNode node)
+       {
+               return new Image(NODE_IMAGE_NAME, BLANK);
+       }
+
+       /**
+        * Gets the label of the node that is used for the node link. Defaults 
to
+        * treeNodeModel.getUserObject().toString(); override to provide a 
custom
+        * label
+        * 
+        * @param node
+        *            the tree node
+        * @return the label of the node that is used for the node link
+        */
+       protected String getNodeLabel(final DefaultMutableTreeNode node)
+       {
+               return String.valueOf(node.getUserObject());
+       }
+
+       /**
+        * @see org.apache.wicket.Component#onAttach()
+        */
+       protected void onAttach()
+       {
+               super.onAttach();
+               // if we don't optimize, rebuild the paths on every request
+               if (!getOptimizeItemRemoval())
+               {
+                       treePathsModel.dirty = true;
+               }
+       }
+
+       /**
+        * Handler that is called when a junction link is clicked; this
+        * implementation sets the expanded state to one that corresponds with 
the
+        * node selection.
+        * 
+        * @param node
+        *            the tree node
+        */
+       protected void junctionLinkClicked(final DefaultMutableTreeNode node)
+       {
+               setExpandedState(node);
+       }
+
+       /**
+        * Create a new panel for a tree node. This method can be overriden to
+        * provide a custom panel. This way, you can effectively nest anything 
you
+        * want in the tree, like input fields, images, etc.
+        * <p>
+        * <strong> you must use the provide panelId as the id of your custom 
panel
+        * </strong><br>
+        * for example, do:
+        * 
+        * <pre>
+        * return new MyNodePanel(panelId, node);
+        * </pre>
+        * 
+        * </p>
+        * <p>
+        * You can choose to either let your own panel extend from 
DefaultNodePanel
+        * when you just want to provide different markup but want to reuse the
+        * default components on this panel, or extend from NodePanel directly, 
and
+        * provide any component structure you like.
+        * </p>
+        * 
+        * @param panelId
+        *            the id that the panel MUST use
+        * @param node
+        *            the tree node for the panel
+        * @return a new Panel
+        */
+       protected Component newNodePanel(String panelId, DefaultMutableTreeNode 
node)
+       {
+               return new DefaultNodePanel(panelId, this, node);
+       }
+
+       /**
+        * Handler that is called when a node link is clicked; this 
implementation
+        * sets the expanded state just as a click on a junction would do. 
Override
+        * this for custom behavior.
+        * 
+        * @param node
+        *            the tree node model
+        */
+       protected void nodeLinkClicked(final DefaultMutableTreeNode node)
+       {
+               setSelected(node);
+       }
+}


Reply via email to