You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@wicket.apache.org by eh...@apache.org on 2007/04/13 00:59:06 UTC

svn commit: r528277 [1/5] - in /incubator/wicket/branches/wicket-1.x/jdk-1.4: wicket-extensions/src/main/java/org/apache/wicket/extensions/markup/html/tree/ wicket-extensions/src/main/java/org/apache/wicket/extensions/markup/html/tree/res/ wicket-exten...

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 {@link 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 {@link TreeState}object,
+	 * which is then set as the current tree state, creating a new
+	 * {@link 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 {@link TreeState}object,
+	 * which is then set as the current tree state, creating a new
+	 * {@link 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
+	 * {@link Tree#createJunctionLink(DefaultMutableTreeNode)} and
+	 * {@link 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 {@link #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 {@link #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 {@link 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);
+	}
+}