You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@wicket.apache.org by sv...@apache.org on 2012/02/05 23:02:55 UTC
[4/9] moving old tree examples away,
merged recursive panel example into panel compref
http://git-wip-us.apache.org/repos/asf/wicket/blob/05840d1c/wicket-examples/src/main/java/org/apache/wicket/examples/tree/content/SelectableFolderContent.java
----------------------------------------------------------------------
diff --cc wicket-examples/src/main/java/org/apache/wicket/examples/tree/content/SelectableFolderContent.java
index 0000000,0000000..b2605d5
new file mode 100644
--- /dev/null
+++ b/wicket-examples/src/main/java/org/apache/wicket/examples/tree/content/SelectableFolderContent.java
@@@ -1,0 -1,0 +1,111 @@@
++/*
++ * 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.examples.tree.content;
++
++import org.apache.wicket.Component;
++import org.apache.wicket.ajax.AjaxRequestTarget;
++import org.apache.wicket.examples.tree.Foo;
++import org.apache.wicket.extensions.markup.html.repeater.tree.AbstractTree;
++import org.apache.wicket.extensions.markup.html.repeater.tree.ITreeProvider;
++import org.apache.wicket.extensions.markup.html.repeater.tree.content.Folder;
++import org.apache.wicket.model.IModel;
++
++/**
++ * @author Sven Meier
++ */
++public class SelectableFolderContent extends Content
++{
++
++ private static final long serialVersionUID = 1L;
++
++ private ITreeProvider<Foo> provider;
++
++ private IModel<Foo> selected;
++
++ public SelectableFolderContent(ITreeProvider<Foo> provider)
++ {
++ this.provider = provider;
++ }
++
++ @Override
++ public void detach()
++ {
++ if (selected != null)
++ {
++ selected.detach();
++ }
++ }
++
++ protected boolean isSelected(Foo foo)
++ {
++ IModel<Foo> model = provider.model(foo);
++
++ try
++ {
++ return selected != null && selected.equals(model);
++ }
++ finally
++ {
++ model.detach();
++ }
++ }
++
++ protected void select(Foo foo, AbstractTree<Foo> tree, final AjaxRequestTarget target)
++ {
++ if (selected != null)
++ {
++ tree.updateNode(selected.getObject(), target);
++
++ selected.detach();
++ selected = null;
++ }
++
++ selected = provider.model(foo);
++
++ tree.updateNode(foo, target);
++ }
++
++ @Override
++ public Component newContentComponent(String id, final AbstractTree<Foo> tree, IModel<Foo> model)
++ {
++ return new Folder<Foo>(id, tree, model)
++ {
++ private static final long serialVersionUID = 1L;
++
++ /**
++ * Always clickable.
++ */
++ @Override
++ protected boolean isClickable()
++ {
++ return true;
++ }
++
++ @Override
++ protected void onClick(AjaxRequestTarget target)
++ {
++ SelectableFolderContent.this.select(getModelObject(), tree, target);
++ }
++
++ @Override
++ protected boolean isSelected()
++ {
++ return SelectableFolderContent.this.isSelected(getModelObject());
++ }
++ };
++ }
++}
http://git-wip-us.apache.org/repos/asf/wicket/blob/05840d1c/wicket-examples/src/main/resources/org/apache/wicket/examples/homepage/HomePage.html
----------------------------------------------------------------------
diff --cc wicket-examples/src/main/resources/org/apache/wicket/examples/homepage/HomePage.html
index 5cc23cc,5cc23cc..165389f
--- a/wicket-examples/src/main/resources/org/apache/wicket/examples/homepage/HomePage.html
+++ b/wicket-examples/src/main/resources/org/apache/wicket/examples/homepage/HomePage.html
@@@ -30,8 -30,8 +30,8 @@@
<tr><td align="right"><a href="unicodeconverter">unicode converter</a></td><td> - Converts input using some model magic.</td></tr>
<tr><td align="right"><a href="niceurl">niceurl</a></td><td> - Demonstrates the use of "nice" URLs.</td></tr>
<tr><td align="right"><a href="ajax">ajax</a></td><td> - Examples using wicket's built-in AJAX.</td></tr>
-- <tr><td align="right"><a href="nested">nested</a></td><td> - Trees and nested lists.</td></tr>
<tr><td align="right"><a href="repeater">repeaters</a></td><td> - DataView, DataTable, GridView component examples.</td></tr>
++ <tr><td align="right"><a href="tree">tree</a></td><td> - Trees.</td></tr>
<tr><td align="right"><a href="authentication1">authentication-1</a></td><td> - A very simple authentication example.</td></tr>
<tr><td align="right"><a href="authentication2">authentication-2</a></td><td> - A little bit more advanced authentication example (using cookies).</td></tr>
<tr><td align="right"><a href="authentication3">authentication-3</a></td><td> - Demonstrates authentication for pages.</td></tr>
http://git-wip-us.apache.org/repos/asf/wicket/blob/05840d1c/wicket-examples/src/main/webapp/WEB-INF/web.xml
----------------------------------------------------------------------
diff --cc wicket-examples/src/main/webapp/WEB-INF/web.xml
index 3b9c848,3b9c848..f52ca6a
--- a/wicket-examples/src/main/webapp/WEB-INF/web.xml
+++ b/wicket-examples/src/main/webapp/WEB-INF/web.xml
@@@ -144,15 -144,15 +144,6 @@@
</filter>
<filter>
-- <filter-name>NestedApplication</filter-name>
-- <filter-class>org.apache.wicket.protocol.http.WicketFilter</filter-class>
-- <init-param>
-- <param-name>applicationClassName</param-name>
-- <param-value>org.apache.wicket.examples.nested.NestedApplication</param-value>
-- </init-param>
-- </filter>
--
-- <filter>
<filter-name>GuestBookApplication</filter-name>
<filter-class>org.apache.wicket.protocol.http.WicketFilter</filter-class>
<init-param>
@@@ -261,6 -261,6 +252,15 @@@
</filter>
<filter>
++ <filter-name>TreeApplication</filter-name>
++ <filter-class>org.apache.wicket.protocol.http.WicketFilter</filter-class>
++ <init-param>
++ <param-name>applicationClassName</param-name>
++ <param-value>org.apache.wicket.examples.tree.TreeApplication</param-value>
++ </init-param>
++ </filter>
++
++ <filter>
<filter-name>NiceUrlApplication</filter-name>
<filter-class>org.apache.wicket.protocol.http.WicketFilter</filter-class>
<init-param>
@@@ -474,6 -474,6 +474,13 @@@
</filter-mapping>
<filter-mapping>
++ <filter-name>TreeApplication</filter-name>
++ <url-pattern>/tree/*</url-pattern>
++ <dispatcher>REQUEST</dispatcher>
++ <dispatcher>INCLUDE</dispatcher>
++ </filter-mapping>
++
++ <filter-mapping>
<filter-name>NiceUrlApplication</filter-name>
<url-pattern>/niceurl/*</url-pattern>
<dispatcher>REQUEST</dispatcher>
@@@ -495,13 -495,13 +502,6 @@@
</filter-mapping>
<filter-mapping>
-- <filter-name>NestedApplication</filter-name>
-- <url-pattern>/nested/*</url-pattern>
-- <dispatcher>REQUEST</dispatcher>
-- <dispatcher>INCLUDE</dispatcher>
-- </filter-mapping>
--
-- <filter-mapping>
<filter-name>PubApplication</filter-name>
<url-pattern>/pub/*</url-pattern>
<dispatcher>REQUEST</dispatcher>
http://git-wip-us.apache.org/repos/asf/wicket/blob/05840d1c/wicket-examples/src/main/webapp/style.css
----------------------------------------------------------------------
diff --cc wicket-examples/src/main/webapp/style.css
index 5e48de1,5e48de1..ea81568
--- a/wicket-examples/src/main/webapp/style.css
+++ b/wicket-examples/src/main/webapp/style.css
@@@ -43,6 -43,6 +43,11 @@@ h1,h2
padding: 10px 10px 10px 10px;
}
++.panel {
++ border: 2px dotted #fc0;
++ padding: 5px;
++}
++
.mark {
background-color: yellow;
margin: 5px;
http://git-wip-us.apache.org/repos/asf/wicket/blob/05840d1c/wicket-extensions/src/main/java/org/apache/wicket/extensions/markup/html/repeater/data/table/DataTable.java
----------------------------------------------------------------------
diff --cc wicket-extensions/src/main/java/org/apache/wicket/extensions/markup/html/repeater/data/table/DataTable.java
index 53753e0,53753e0..8843090
--- a/wicket-extensions/src/main/java/org/apache/wicket/extensions/markup/html/repeater/data/table/DataTable.java
+++ b/wicket-extensions/src/main/java/org/apache/wicket/extensions/markup/html/repeater/data/table/DataTable.java
@@@ -92,15 -92,15 +92,7 @@@ public class DataTable<T> extends Pane
String className = getCssClass();
if (!Strings.isEmpty(className))
{
-- CharSequence oldClassName = tag.getAttribute("class");
-- if (Strings.isEmpty(oldClassName))
-- {
-- tag.put("class", className);
-- }
-- else
-- {
-- tag.put("class", oldClassName + " " + className);
-- }
++ tag.append("class", className, " ");
}
}
}
@@@ -155,7 -155,7 +147,7 @@@
final IColumn<T> column = DataTable.this.columns.get(index);
if (column instanceof IStyledColumn)
{
-- item.add(new DataTable.CssAttributeBehavior()
++ item.add(new CssAttributeBehavior()
{
private static final long serialVersionUID = 1L;
http://git-wip-us.apache.org/repos/asf/wicket/blob/05840d1c/wicket-extensions/src/main/java/org/apache/wicket/extensions/markup/html/repeater/tree/AbstractTree.java
----------------------------------------------------------------------
diff --cc wicket-extensions/src/main/java/org/apache/wicket/extensions/markup/html/repeater/tree/AbstractTree.java
index 0000000,0000000..2dd8425
new file mode 100644
--- /dev/null
+++ b/wicket-extensions/src/main/java/org/apache/wicket/extensions/markup/html/repeater/tree/AbstractTree.java
@@@ -1,0 -1,0 +1,343 @@@
++/*
++ * 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.extensions.markup.html.repeater.tree;
++
++import java.util.Set;
++
++import org.apache.wicket.Component;
++import org.apache.wicket.ajax.AjaxRequestTarget;
++import org.apache.wicket.extensions.markup.html.repeater.tree.util.ProviderSubset;
++import org.apache.wicket.markup.html.panel.Panel;
++import org.apache.wicket.markup.repeater.DefaultItemReuseStrategy;
++import org.apache.wicket.markup.repeater.IItemReuseStrategy;
++import org.apache.wicket.markup.repeater.Item;
++import org.apache.wicket.model.IModel;
++import org.apache.wicket.util.visit.IVisit;
++import org.apache.wicket.util.visit.IVisitor;
++
++/**
++ * Abstract base class for {@link NestedTree} and {@link TableTree}. Uses its model for storing the
++ * {@link State} of its nodes.
++ *
++ * Note that a tree has no notion of a <em>selection</em>. Handling state of nodes besides
++ * expanse/collapse is irrelevant to a tree implementation.
++ *
++ * @see #newContentComponent(String, IModel)
++ *
++ * @author svenmeier
++ * @param <T>
++ * the model object type
++ */
++public abstract class AbstractTree<T> extends Panel
++{
++ private static final long serialVersionUID = 1L;
++
++ private ITreeProvider<T> provider;
++
++ private IItemReuseStrategy itemReuseStrategy;
++
++ protected AbstractTree(String id, ITreeProvider<T> provider)
++ {
++ this(id, provider, null);
++ }
++
++ protected AbstractTree(String id, ITreeProvider<T> provider, IModel<Set<T>> state)
++ {
++ super(id, state);
++
++ if (provider == null)
++ {
++ throw new IllegalArgumentException("argument [provider] cannot be null");
++ }
++ this.provider = provider;
++
++ // see #updateBranch(Object, AjaxRequestTarget)
++ setOutputMarkupId(true);
++ }
++
++ /**
++ * Sets the item reuse strategy. This strategy controls the creation of {@link Item}s.
++ *
++ * @see IItemReuseStrategy
++ *
++ * @param strategy
++ * item reuse strategy
++ * @return this for chaining
++ */
++ public AbstractTree<T> setItemReuseStrategy(IItemReuseStrategy strategy)
++ {
++ this.itemReuseStrategy = strategy;
++
++ return this;
++ }
++
++ /**
++ * @return currently set item reuse strategy. Defaults to <code>DefaultItemReuseStrategy</code>
++ * if none was set.
++ *
++ * @see DefaultItemReuseStrategy
++ */
++ public IItemReuseStrategy getItemReuseStrategy()
++ {
++ if (itemReuseStrategy == null)
++ {
++ return DefaultItemReuseStrategy.getInstance();
++ }
++ return itemReuseStrategy;
++ }
++
++ /**
++ * Get the provider of the tree nodes.
++ *
++ * @return provider
++ */
++ public ITreeProvider<T> getProvider()
++ {
++ return provider;
++ }
++
++ /**
++ * Delegate to {@link #newModel()} if none is inited in super implementation.
++ */
++ @Override
++ protected IModel<?> initModel()
++ {
++ IModel<?> model = super.initModel();
++
++ if (model == null)
++ {
++ model = newModel();
++ }
++
++ return model;
++ }
++
++ /**
++ * Factory method for a model, by default creates a model containing a {@link ProviderSubset}.
++ *
++ * @return model for this tree
++ */
++ protected IModel<Set<T>> newModel()
++ {
++ return new ProviderSubset<T>(provider).createModel();
++ }
++
++ /**
++ * Get the model of this tree.
++ *
++ * @return model
++ */
++ @SuppressWarnings("unchecked")
++ public IModel<Set<T>> getModel()
++ {
++ return (IModel<Set<T>>)getDefaultModel();
++ }
++
++ /**
++ * Get the model object of this tree.
++ *
++ * @return the model object
++ */
++ public Set<T> getModelObject()
++ {
++ return getModel().getObject();
++ }
++
++ /**
++ * Set the model.
++ *
++ * @param model
++ * the model
++ */
++ public void setModel(IModel<Set<T>> model)
++ {
++ setDefaultModel(model);
++ }
++
++ /**
++ * Set the model object.
++ *
++ * @param state
++ * the model object
++ */
++ public void setModelObject(Set<T> state)
++ {
++ setDefaultModelObject(state);
++ }
++
++ /**
++ * Expand the given node, tries to update the affected branch if the change happens on an
++ * {@link AjaxRequestTarget}.
++ *
++ * @param t
++ * the node to expand
++ *
++ * @see #getModelObject()
++ * @see Set#add(Object)
++ * @see #updateBranch(Object, AjaxRequestTarget)
++ */
++ public void expand(T t)
++ {
++ getModelObject().add(t);
++
++ updateBranch(t, AjaxRequestTarget.get());
++ }
++
++ /**
++ * Collapse the given node, tries to update the affected branch if the change happens on an
++ * {@link AjaxRequestTarget}.
++ *
++ * @param t
++ * the object to collapse
++ *
++ * @see #getModelObject()
++ * @see Set#remove(Object)
++ * @see #updateBranch(Object, AjaxRequestTarget)
++ */
++ public void collapse(T t)
++ {
++ getModelObject().remove(t);
++
++ updateBranch(t, AjaxRequestTarget.get());
++ }
++
++ /**
++ * Get the given node's {@link State}.
++ *
++ * @param t
++ * the node to get state for
++ * @return state
++ *
++ * @see #getModelObject()
++ * @see Set#contains(Object)
++ */
++ public State getState(T t)
++ {
++ if (getModelObject().contains(t))
++ {
++ return State.EXPANDED;
++ }
++ else
++ {
++ return State.COLLAPSED;
++ }
++ }
++
++ /**
++ * Overriden to detach the {@link ITreeProvider}.
++ */
++ @Override
++ protected void onDetach()
++ {
++ provider.detach();
++
++ super.onDetach();
++ }
++
++ /**
++ * Create a new component for a node.
++ *
++ * @param id
++ * the component id
++ * @param model
++ * the model containing the node
++ * @return created component
++ */
++ public Component newNodeComponent(String id, final IModel<T> model)
++ {
++ return new Node<T>(id, this, model)
++ {
++ private static final long serialVersionUID = 1L;
++
++ @Override
++ protected Component createContent(String id, IModel<T> model)
++ {
++ return AbstractTree.this.newContentComponent(id, model);
++ }
++ };
++ }
++
++ /**
++ * Create a new component for the content of a node.
++ *
++ * @param id
++ * the component id
++ * @param model
++ * the model containing the node
++ * @return created component
++ */
++ protected abstract Component newContentComponent(String id, IModel<T> model);
++
++ /**
++ * Convenience method to update a single branch on an {@link AjaxRequestTarget}. Does nothing if
++ * the given node is currently not visible or target is <code>null</code>.
++ *
++ * This default implementation adds this whole component for rendering.
++ *
++ * @param t
++ * @param target
++ */
++ public void updateBranch(T t, final AjaxRequestTarget target)
++ {
++ if (target != null)
++ {
++ target.add(this);
++ }
++ }
++
++ /**
++ * Convenience method to update a single node on an {@link AjaxRequestTarget}. Does nothing if
++ * the given node is currently not visible or target is <code>null</code>.
++ *
++ * @param t
++ * @param target
++ */
++ public void updateNode(T t, final AjaxRequestTarget target)
++ {
++ if (target != null)
++ {
++ final IModel<T> model = getProvider().model(t);
++ visitChildren(Node.class, new IVisitor<Node<T>, Void>()
++ {
++ public void component(Node<T> node, IVisit<Void> visit)
++ {
++ if (model.equals(node.getModel()))
++ {
++ target.add(node);
++ visit.stop();
++ }
++ visit.dontGoDeeper();
++ }
++ });
++ model.detach();
++ }
++ }
++
++ /**
++ * The state of a node.
++ */
++ public static enum State {
++ /**
++ * The node is collapsed, i.e. its children are not iterated.
++ */
++ COLLAPSED,
++ /**
++ * The node is expanded, i.e. its children are iterated.
++ */
++ EXPANDED
++ }
++}
http://git-wip-us.apache.org/repos/asf/wicket/blob/05840d1c/wicket-extensions/src/main/java/org/apache/wicket/extensions/markup/html/repeater/tree/DefaultNestedTree.java
----------------------------------------------------------------------
diff --cc wicket-extensions/src/main/java/org/apache/wicket/extensions/markup/html/repeater/tree/DefaultNestedTree.java
index 0000000,0000000..f2d04ba
new file mode 100644
--- /dev/null
+++ b/wicket-extensions/src/main/java/org/apache/wicket/extensions/markup/html/repeater/tree/DefaultNestedTree.java
@@@ -1,0 -1,0 +1,55 @@@
++/*
++ * 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.extensions.markup.html.repeater.tree;
++
++import java.util.Set;
++
++import org.apache.wicket.Component;
++import org.apache.wicket.extensions.markup.html.repeater.tree.content.Folder;
++import org.apache.wicket.extensions.markup.html.repeater.tree.theme.WindowsTheme;
++import org.apache.wicket.model.IModel;
++
++/**
++ * An implementation of the NestedTree that aims to solve the 90% usecase by using {@link Folder}s
++ * on a standard {@link NestedTree}.
++ *
++ * @param <T>
++ * The model object type
++ * @author svenmeier
++ */
++public class DefaultNestedTree<T> extends NestedTree<T>
++{
++ private static final long serialVersionUID = 1L;
++
++ public DefaultNestedTree(String id, ITreeProvider<T> provider)
++ {
++ this(id, provider, null);
++ }
++
++ public DefaultNestedTree(String id, ITreeProvider<T> provider, IModel<Set<T>> state)
++ {
++ super(id, provider, state);
++
++ add(new WindowsTheme());
++ }
++
++ @Override
++ protected Component newContentComponent(String id, IModel<T> model)
++ {
++ return new Folder<T>(id, this, model);
++ }
++}
http://git-wip-us.apache.org/repos/asf/wicket/blob/05840d1c/wicket-extensions/src/main/java/org/apache/wicket/extensions/markup/html/repeater/tree/DefaultTableTree.java
----------------------------------------------------------------------
diff --cc wicket-extensions/src/main/java/org/apache/wicket/extensions/markup/html/repeater/tree/DefaultTableTree.java
index 0000000,0000000..838d2b6
new file mode 100644
--- /dev/null
+++ b/wicket-extensions/src/main/java/org/apache/wicket/extensions/markup/html/repeater/tree/DefaultTableTree.java
@@@ -1,0 -1,0 +1,75 @@@
++/*
++ * 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.extensions.markup.html.repeater.tree;
++
++import java.util.List;
++import java.util.Set;
++
++import org.apache.wicket.Component;
++import org.apache.wicket.extensions.markup.html.repeater.data.table.HeadersToolbar;
++import org.apache.wicket.extensions.markup.html.repeater.data.table.IColumn;
++import org.apache.wicket.extensions.markup.html.repeater.data.table.NavigationToolbar;
++import org.apache.wicket.extensions.markup.html.repeater.data.table.NoRecordsToolbar;
++import org.apache.wicket.extensions.markup.html.repeater.tree.content.Folder;
++import org.apache.wicket.extensions.markup.html.repeater.tree.theme.WindowsTheme;
++import org.apache.wicket.markup.repeater.Item;
++import org.apache.wicket.markup.repeater.OddEvenItem;
++import org.apache.wicket.model.IModel;
++
++/**
++ * An implementation of the TableTree that aims to solve the 90% usecase by using {@link Folder}s
++ * and by adding navigation, headers and no-records-found toolbars to a standard {@link TableTree}.
++ *
++ * @param <T>
++ * The model object type
++ * @author svenmeier
++ */
++public class DefaultTableTree<T> extends TableTree<T>
++{
++
++ private static final long serialVersionUID = 1L;
++
++ public DefaultTableTree(String id, List<IColumn<T>> columns, ISortableTreeProvider<T> provider,
++ int rowsPerPage)
++ {
++ this(id, columns, provider, rowsPerPage, null);
++ }
++
++ public DefaultTableTree(String id, List<IColumn<T>> columns, ISortableTreeProvider<T> provider,
++ int rowsPerPage, IModel<Set<T>> state)
++ {
++ super(id, columns, provider, rowsPerPage, state);
++
++ getTable().addTopToolbar(new NavigationToolbar(getTable()));
++ getTable().addTopToolbar(new HeadersToolbar(getTable(), provider));
++ getTable().addBottomToolbar(new NoRecordsToolbar(getTable()));
++
++ add(new WindowsTheme());
++ }
++
++ @Override
++ protected Component newContentComponent(String id, IModel<T> model)
++ {
++ return new Folder<T>(id, this, model);
++ }
++
++ @Override
++ protected Item<T> newRowItem(String id, int index, IModel<T> model)
++ {
++ return new OddEvenItem<T>(id, index, model);
++ }
++}
http://git-wip-us.apache.org/repos/asf/wicket/blob/05840d1c/wicket-extensions/src/main/java/org/apache/wicket/extensions/markup/html/repeater/tree/ISortableTreeProvider.java
----------------------------------------------------------------------
diff --cc wicket-extensions/src/main/java/org/apache/wicket/extensions/markup/html/repeater/tree/ISortableTreeProvider.java
index 0000000,0000000..e0b5095
new file mode 100644
--- /dev/null
+++ b/wicket-extensions/src/main/java/org/apache/wicket/extensions/markup/html/repeater/tree/ISortableTreeProvider.java
@@@ -1,0 -1,0 +1,30 @@@
++/*
++ * 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.extensions.markup.html.repeater.tree;
++
++import org.apache.wicket.extensions.markup.html.repeater.data.sort.ISortStateLocator;
++
++/**
++ * Tree provider that can hold sort state
++ *
++ * @author svenmeier
++ * @param <T>
++ * node type
++ */
++public interface ISortableTreeProvider<T> extends ITreeProvider<T>, ISortStateLocator
++{
++}
http://git-wip-us.apache.org/repos/asf/wicket/blob/05840d1c/wicket-extensions/src/main/java/org/apache/wicket/extensions/markup/html/repeater/tree/ITreeProvider.java
----------------------------------------------------------------------
diff --cc wicket-extensions/src/main/java/org/apache/wicket/extensions/markup/html/repeater/tree/ITreeProvider.java
index 0000000,0000000..a86098a
new file mode 100644
--- /dev/null
+++ b/wicket-extensions/src/main/java/org/apache/wicket/extensions/markup/html/repeater/tree/ITreeProvider.java
@@@ -1,0 -1,0 +1,78 @@@
++/*
++ * 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.extensions.markup.html.repeater.tree;
++
++import java.util.Iterator;
++
++import org.apache.wicket.model.IDetachable;
++import org.apache.wicket.model.IModel;
++
++/**
++ * Provider of a tree.
++ *
++ * You can use the {@link IDetachable#detach()} method for cleaning up your ITreeProvider instance.
++ *
++ * @see IDetachable
++ * @see AbstractTree
++ *
++ * @author svenmeier
++ * @param <T>
++ * the node type
++ */
++public interface ITreeProvider<T> extends IDetachable
++{
++
++ /**
++ * Get the roots of the tree.
++ *
++ * @return roots
++ */
++ Iterator<? extends T> getRoots();
++
++ /**
++ * Does the given object have children - note that this method may return <code>true</code> even
++ * if {@link #getChildren(Object)} returns an empty iterator.
++ *
++ * @param node
++ * the node to check for children
++ * @return {@code true} if node has children
++ */
++ boolean hasChildren(T node);
++
++ /**
++ * Get the children of the given node.
++ *
++ * @param node
++ * node to get children for
++ * @return children of node
++ */
++ Iterator<? extends T> getChildren(T node);
++
++ /**
++ * Callback used by the consumer of this tree provider to wrap objects retrieved from
++ * {@link #getRoots()} or {@link #getChildren(Object)} with a model (usually a detachable one).
++ * <p>
++ * Important note: The model must implement {@link Object#equals(Object)} and
++ * {@link Object#hashCode()} !
++ *
++ * @param object
++ * the object that needs to be wrapped
++ *
++ * @return the model representation of the object
++ */
++ IModel<T> model(T object);
++}
http://git-wip-us.apache.org/repos/asf/wicket/blob/05840d1c/wicket-extensions/src/main/java/org/apache/wicket/extensions/markup/html/repeater/tree/NestedTree.html
----------------------------------------------------------------------
diff --cc wicket-extensions/src/main/java/org/apache/wicket/extensions/markup/html/repeater/tree/NestedTree.html
index 0000000,0000000..5bb6b64
new file mode 100644
--- /dev/null
+++ b/wicket-extensions/src/main/java/org/apache/wicket/extensions/markup/html/repeater/tree/NestedTree.html
@@@ -1,0 -1,0 +1,20 @@@
++<?xml version="1.0" encoding="UTF-8" ?>
++<!--
++ 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 xmlns:wicket="http://wicket.apache.org">
++ <div wicket:id="subtree">[subtree]</div>
++</wicket:panel>
http://git-wip-us.apache.org/repos/asf/wicket/blob/05840d1c/wicket-extensions/src/main/java/org/apache/wicket/extensions/markup/html/repeater/tree/NestedTree.java
----------------------------------------------------------------------
diff --cc wicket-extensions/src/main/java/org/apache/wicket/extensions/markup/html/repeater/tree/NestedTree.java
index 0000000,0000000..c0b1974
new file mode 100644
--- /dev/null
+++ b/wicket-extensions/src/main/java/org/apache/wicket/extensions/markup/html/repeater/tree/NestedTree.java
@@@ -1,0 -1,0 +1,122 @@@
++/*
++ * 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.extensions.markup.html.repeater.tree;
++
++import java.util.Set;
++
++import org.apache.wicket.Component;
++import org.apache.wicket.ajax.AjaxRequestTarget;
++import org.apache.wicket.extensions.markup.html.repeater.tree.nested.BranchItem;
++import org.apache.wicket.extensions.markup.html.repeater.tree.nested.Subtree;
++import org.apache.wicket.model.AbstractReadOnlyModel;
++import org.apache.wicket.model.IModel;
++import org.apache.wicket.util.visit.IVisit;
++import org.apache.wicket.util.visit.IVisitor;
++
++/**
++ * A tree with nested markup.
++ *
++ * @author svenmeier
++ * @param <T>
++ * the model object type
++ */
++public abstract class NestedTree<T> extends AbstractTree<T>
++{
++
++ private static final long serialVersionUID = 1L;
++
++ /**
++ * Construct.
++ *
++ * @param id
++ * the component id
++ * @param provider
++ * the provider of the tree
++ */
++ public NestedTree(String id, ITreeProvider<T> provider)
++ {
++ this(id, provider, null);
++ }
++
++ /**
++ * Construct.
++ *
++ * @param id
++ * the component id
++ * @param provider
++ * the provider of the tree
++ * @param state
++ * the expansion state
++ *
++ * @see State
++ */
++ public NestedTree(String id, ITreeProvider<T> provider, IModel<Set<T>> state)
++ {
++ super(id, provider, state);
++
++ add(newSubtree("subtree", new RootsModel()));
++ }
++
++ /**
++ * Create a new subtree.
++ *
++ * @param id
++ * component id
++ * @param model
++ * the model of the new subtree
++ * @return the created component
++ */
++ public Component newSubtree(String id, IModel<T> model)
++ {
++ return new Subtree<T>(id, this, model);
++ }
++
++ /**
++ * Overriden to update the affected {@link BranchItem} only.
++ */
++ @Override
++ public void updateBranch(T t, final AjaxRequestTarget target)
++ {
++ if (target != null)
++ {
++ final IModel<T> model = getProvider().model(t);
++ visitChildren(BranchItem.class, new IVisitor<BranchItem<T>, Void>()
++ {
++ public void component(BranchItem<T> branch, IVisit<Void> visit)
++ {
++ if (model.equals(branch.getModel()))
++ {
++ target.add(branch);
++ visit.stop();
++ }
++ }
++ });
++ model.detach();
++ }
++ }
++
++ private class RootsModel extends AbstractReadOnlyModel<T>
++ {
++ private static final long serialVersionUID = 1L;
++
++ @Override
++ public T getObject()
++ {
++ return null;
++ }
++ }
++}
http://git-wip-us.apache.org/repos/asf/wicket/blob/05840d1c/wicket-extensions/src/main/java/org/apache/wicket/extensions/markup/html/repeater/tree/Node.html
----------------------------------------------------------------------
diff --cc wicket-extensions/src/main/java/org/apache/wicket/extensions/markup/html/repeater/tree/Node.html
index 0000000,0000000..7c30dcd
new file mode 100644
--- /dev/null
+++ b/wicket-extensions/src/main/java/org/apache/wicket/extensions/markup/html/repeater/tree/Node.html
@@@ -1,0 -1,0 +1,27 @@@
++<?xml version="1.0" encoding="UTF-8" ?>
++<!--
++ 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.
++-->
++<html>
++<body>
++
++<wicket:panel xmlns:wicket="http://wicket.apache.org">
++ <a wicket:id="junction"> </a>
++ <span wicket:id="content" class="tree-content">[content]</span>
++</wicket:panel>
++
++</body>
++</html>
http://git-wip-us.apache.org/repos/asf/wicket/blob/05840d1c/wicket-extensions/src/main/java/org/apache/wicket/extensions/markup/html/repeater/tree/Node.java
----------------------------------------------------------------------
diff --cc wicket-extensions/src/main/java/org/apache/wicket/extensions/markup/html/repeater/tree/Node.java
index 0000000,0000000..79c7eb7
new file mode 100644
--- /dev/null
+++ b/wicket-extensions/src/main/java/org/apache/wicket/extensions/markup/html/repeater/tree/Node.java
@@@ -1,0 -1,0 +1,213 @@@
++/*
++ * 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.extensions.markup.html.repeater.tree;
++
++import org.apache.wicket.Component;
++import org.apache.wicket.MarkupContainer;
++import org.apache.wicket.ajax.AjaxRequestTarget;
++import org.apache.wicket.ajax.markup.html.AjaxFallbackLink;
++import org.apache.wicket.behavior.Behavior;
++import org.apache.wicket.extensions.markup.html.repeater.tree.AbstractTree.State;
++import org.apache.wicket.markup.ComponentTag;
++import org.apache.wicket.markup.html.panel.Panel;
++import org.apache.wicket.model.IModel;
++
++/**
++ * Representation of a single node in the tree. By default uses an {@link AjaxFallbackLink} for its
++ * junction component.
++ *
++ * @see #createJunctionComponent(String)
++ *
++ * @author svenmeier
++ * @param <T>
++ * The model object type
++ */
++public abstract class Node<T> extends Panel
++{
++
++ private static final long serialVersionUID = 1L;
++
++ /**
++ * The component id for the content component.
++ */
++ public static final String CONTENT_ID = "content";
++
++ private AbstractTree<T> tree;
++
++ /**
++ * Constructor.
++ *
++ * @param id
++ * component id
++ * @param tree
++ * the owning tree
++ * @param model
++ * the model for this node
++ */
++ public Node(String id, AbstractTree<T> tree, IModel<T> model)
++ {
++ super(id, model);
++
++ this.tree = tree;
++
++ setOutputMarkupId(true);
++
++ MarkupContainer junction = createJunctionComponent("junction");
++ junction.add(new StyleBehavior());
++ add(junction);
++
++ Component content = createContent(CONTENT_ID, model);
++ if (!content.getId().equals(CONTENT_ID))
++ {
++ throw new IllegalArgumentException(
++ "content must have component id equal to Node.CONTENT_ID");
++ }
++ add(content);
++ }
++
++ /**
++ * @return the model
++ */
++ @SuppressWarnings("unchecked")
++ public IModel<T> getModel()
++ {
++ return (IModel<T>)getDefaultModel();
++ }
++
++ /**
++ * @return the model object
++ */
++ public T getModelObject()
++ {
++ return getModel().getObject();
++ }
++
++ /**
++ * The junction component expands and collapses this node.
++ *
++ * @param id
++ * the component id
++ * @return component representing the junction
++ */
++ protected MarkupContainer createJunctionComponent(String id)
++ {
++ return new AjaxFallbackLink<Void>(id)
++ {
++ private static final long serialVersionUID = 1L;
++
++ @Override
++ public void onClick(AjaxRequestTarget target)
++ {
++ toggle();
++ }
++
++ @Override
++ public boolean isEnabled()
++ {
++ return tree.getProvider().hasChildren(Node.this.getModelObject());
++ }
++ };
++ }
++
++ private void toggle()
++ {
++ T t = getModelObject();
++
++ if (tree.getState(t) == State.EXPANDED)
++ {
++ tree.collapse(t);
++ }
++ else
++ {
++ tree.expand(t);
++ }
++ }
++
++ /**
++ * Create the component to display the actual node's content.
++ *
++ * @param id
++ * the component id
++ * @param model
++ * the node's model
++ * @return the component representing the content
++ */
++ protected abstract Component createContent(String id, IModel<T> model);
++
++ /**
++ * Get the style class depending on the current {@link State} of this node.
++ *
++ * @see #getExpandedStyleClass(Object)
++ * @see #getCollapsedStyleClass()
++ * @see #getOtherStyleClass()
++ * @return the style class
++ */
++ protected String getStyleClass()
++ {
++ T t = getModelObject();
++
++ if (tree.getProvider().hasChildren(t))
++ {
++ if (tree.getState(t) == State.EXPANDED)
++ {
++ return getExpandedStyleClass(t);
++ }
++ else
++ {
++ return getCollapsedStyleClass();
++ }
++ }
++ return getOtherStyleClass();
++ }
++
++ protected String getExpandedStyleClass(T t)
++ {
++ return "tree-junction-expanded";
++ }
++
++ protected String getCollapsedStyleClass()
++ {
++ return "tree-junction-collapsed";
++ }
++
++ protected String getOtherStyleClass()
++ {
++ return "tree-junction";
++ }
++
++ /**
++ * Behavior to add the style class attribute.
++ *
++ * @see Node#getStyleClass()
++ */
++ private static class StyleBehavior extends Behavior
++ {
++ private static final long serialVersionUID = 1L;
++
++ @Override
++ public void onComponentTag(Component component, ComponentTag tag)
++ {
++ Node<?> node = (Node<?>)component.getParent();
++
++ String styleClass = node.getStyleClass();
++ if (styleClass != null)
++ {
++ tag.put("class", styleClass);
++ }
++ }
++ }
++}
http://git-wip-us.apache.org/repos/asf/wicket/blob/05840d1c/wicket-extensions/src/main/java/org/apache/wicket/extensions/markup/html/repeater/tree/TableTree.html
----------------------------------------------------------------------
diff --cc wicket-extensions/src/main/java/org/apache/wicket/extensions/markup/html/repeater/tree/TableTree.html
index 0000000,0000000..9609da0
new file mode 100644
--- /dev/null
+++ b/wicket-extensions/src/main/java/org/apache/wicket/extensions/markup/html/repeater/tree/TableTree.html
@@@ -1,0 -1,0 +1,20 @@@
++<?xml version="1.0" encoding="UTF-8" ?>
++<!--
++ 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 xmlns:wicket="http://wicket.apache.org">
++ <table wicket:id="table">[table]</table>
++</wicket:panel>
http://git-wip-us.apache.org/repos/asf/wicket/blob/05840d1c/wicket-extensions/src/main/java/org/apache/wicket/extensions/markup/html/repeater/tree/TableTree.java
----------------------------------------------------------------------
diff --cc wicket-extensions/src/main/java/org/apache/wicket/extensions/markup/html/repeater/tree/TableTree.java
index 0000000,0000000..d37630e
new file mode 100644
--- /dev/null
+++ b/wicket-extensions/src/main/java/org/apache/wicket/extensions/markup/html/repeater/tree/TableTree.java
@@@ -1,0 -1,0 +1,226 @@@
++/*
++ * 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.extensions.markup.html.repeater.tree;
++
++import java.util.List;
++import java.util.Set;
++
++import org.apache.wicket.ajax.AjaxRequestTarget;
++import org.apache.wicket.extensions.markup.html.repeater.data.table.DataTable;
++import org.apache.wicket.extensions.markup.html.repeater.data.table.IColumn;
++import org.apache.wicket.extensions.markup.html.repeater.tree.table.ITreeColumn;
++import org.apache.wicket.extensions.markup.html.repeater.tree.table.ITreeDataProvider;
++import org.apache.wicket.extensions.markup.html.repeater.tree.table.NodeModel;
++import org.apache.wicket.extensions.markup.html.repeater.tree.table.TreeDataProvider;
++import org.apache.wicket.markup.repeater.IItemReuseStrategy;
++import org.apache.wicket.markup.repeater.Item;
++import org.apache.wicket.markup.repeater.RefreshingView;
++import org.apache.wicket.markup.repeater.data.IDataProvider;
++import org.apache.wicket.model.IModel;
++import org.apache.wicket.util.lang.Args;
++import org.apache.wicket.util.visit.IVisit;
++import org.apache.wicket.util.visit.IVisitor;
++
++/**
++ * A tree with tabular markup.
++ *
++ * @author svenmeier
++ *
++ * @param <T>
++ * The model object type
++ */
++public abstract class TableTree<T> extends AbstractTree<T>
++{
++ private static final long serialVersionUID = 1L;
++
++ private final DataTable<T> table;
++
++ /**
++ * Constructor
++ *
++ * @param id
++ * component id
++ * @param columns
++ * list of IColumn objects
++ * @param dataProvider
++ * imodel for data provider
++ * @param rowsPerPage
++ * number of rows per page
++ */
++ public TableTree(final String id, final List<IColumn<T>> columns,
++ final ITreeProvider<T> dataProvider, final long rowsPerPage)
++ {
++ this(id, columns, dataProvider, rowsPerPage, null);
++ }
++
++ /**
++ * Constructor
++ *
++ * @param id
++ * component id
++ * @param columns
++ * list of IColumn objects
++ * @param provider
++ * provider of the tree
++ * @param rowsPerPage
++ * number of rows per page
++ * @param state
++ * the expansion state
++ */
++ public TableTree(final String id, final List<IColumn<T>> columns,
++ final ITreeProvider<T> provider, final long rowsPerPage, IModel<Set<T>> state)
++ {
++ super(id, provider, state);
++
++ Args.notEmpty(columns, "columns");
++ for (IColumn<T> column : columns)
++ {
++ if (column instanceof ITreeColumn<?>)
++ {
++ ((ITreeColumn<T>)column).setTree(this);
++ }
++ }
++
++ this.table = newDataTable("table", columns, newDataProvider(provider), rowsPerPage);
++ add(table);
++ }
++
++ /**
++ * Factory method for the wrapped {@link DataTable}.
++ *
++ * @param id
++ * @param columns
++ * @param dataProvider
++ * @param rowsPerPage
++ * @return nested data table
++ */
++ protected DataTable<T> newDataTable(String id, List<IColumn<T>> columns,
++ IDataProvider<T> dataProvider, long rowsPerPage)
++ {
++ return new DataTable<T>(id, columns, dataProvider, rowsPerPage)
++ {
++ private static final long serialVersionUID = 1L;
++
++ @Override
++ protected Item<T> newRowItem(String id, int index, IModel<T> model)
++ {
++ Item<T> item = TableTree.this.newRowItem(id, index, model);
++
++ // see #update(Node);
++ item.setOutputMarkupId(true);
++
++ return item;
++ }
++ };
++ }
++
++ /**
++ * Get the nested table.
++ *
++ * @return the nested table
++ */
++ public DataTable<T> getTable()
++ {
++ return table;
++ }
++
++ /**
++ * Sets the item reuse strategy. This strategy controls the creation of {@link Item}s.
++ *
++ * @see RefreshingView#setItemReuseStrategy(IItemReuseStrategy)
++ * @see IItemReuseStrategy
++ *
++ * @param strategy
++ * item reuse strategy
++ * @return this for chaining
++ */
++ @Override
++ public final TableTree<T> setItemReuseStrategy(final IItemReuseStrategy strategy)
++ {
++ table.setItemReuseStrategy(strategy);
++
++ super.setItemReuseStrategy(strategy);
++
++ return this;
++ }
++
++ /**
++ * Overriden to update the complete row item of the node.
++ */
++ @Override
++ public void updateNode(T t, final AjaxRequestTarget target)
++ {
++ if (target != null)
++ {
++ final IModel<T> model = getProvider().model(t);
++ visitChildren(Item.class, new IVisitor<Item<T>, Void>()
++ {
++ public void component(Item<T> item, IVisit<Void> visit)
++ {
++ NodeModel<T> nodeModel = (NodeModel<T>)item.getModel();
++
++ if (model.equals(nodeModel.getWrappedModel()))
++ {
++ target.add(item);
++ visit.stop();
++ }
++ visit.dontGoDeeper();
++ }
++ });
++ model.detach();
++ }
++ }
++
++ /**
++ * Hook method to create an {@link ITreeDataProvider}.
++ *
++ * @param provider
++ * the tree provider
++ * @return the data provider
++ */
++ protected ITreeDataProvider<T> newDataProvider(ITreeProvider<T> provider)
++ {
++ return new TreeDataProvider<T>(provider)
++ {
++ private static final long serialVersionUID = 1L;
++
++ @Override
++ protected boolean iterateChildren(T object)
++ {
++ return TableTree.this.getState(object) == State.EXPANDED;
++ }
++ };
++ }
++
++ /**
++ * Create a row item for the nested {@link DataTable}.
++ *
++ * @param id
++ * component id
++ * @param index
++ * index of row
++ * @param model
++ * model for row
++ * @return row item
++ */
++ protected Item<T> newRowItem(String id, int index, IModel<T> model)
++ {
++ Item<T> item = new Item<T>(id, index, model);
++
++ return item;
++ }
++}
http://git-wip-us.apache.org/repos/asf/wicket/blob/05840d1c/wicket-extensions/src/main/java/org/apache/wicket/extensions/markup/html/repeater/tree/content/CheckFolder.html
----------------------------------------------------------------------
diff --cc wicket-extensions/src/main/java/org/apache/wicket/extensions/markup/html/repeater/tree/content/CheckFolder.html
index 0000000,0000000..e55210f
new file mode 100644
--- /dev/null
+++ b/wicket-extensions/src/main/java/org/apache/wicket/extensions/markup/html/repeater/tree/content/CheckFolder.html
@@@ -1,0 -1,0 +1,35 @@@
++<?xml version="1.0" encoding="UTF-8" ?>
++<!--
++ 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.
++-->
++<html>
++
++<head>
++</head>
++
++<body>
++
++<wicket:panel xmlns:wicket="http://wicket.apache.org">
++ <input type="checkbox" wicket:id="check" />
++
++ <a wicket:id="link">
++ <span class="tree-label" wicket:id="label">[label]</span>
++ </a>
++</wicket:panel>
++
++</body>
++
++</html>
http://git-wip-us.apache.org/repos/asf/wicket/blob/05840d1c/wicket-extensions/src/main/java/org/apache/wicket/extensions/markup/html/repeater/tree/content/CheckFolder.java
----------------------------------------------------------------------
diff --cc wicket-extensions/src/main/java/org/apache/wicket/extensions/markup/html/repeater/tree/content/CheckFolder.java
index 0000000,0000000..6a61593
new file mode 100644
--- /dev/null
+++ b/wicket-extensions/src/main/java/org/apache/wicket/extensions/markup/html/repeater/tree/content/CheckFolder.java
@@@ -1,0 -1,0 +1,40 @@@
++/*
++ * 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.extensions.markup.html.repeater.tree.content;
++
++import org.apache.wicket.extensions.markup.html.repeater.tree.AbstractTree;
++import org.apache.wicket.markup.html.form.Check;
++import org.apache.wicket.markup.html.form.CheckGroup;
++import org.apache.wicket.model.IModel;
++
++/**
++ * This class adds a {@link Check} to a {@link Folder}. Remeber to wrap your tree in a
++ * {@link CheckGroup} for all checks to work correctly.
++ *
++ * @author svenmeier
++ */
++public class CheckFolder<T> extends Folder<T>
++{
++ private static final long serialVersionUID = 1L;
++
++ public CheckFolder(String id, AbstractTree<T> tree, IModel<T> model)
++ {
++ super(id, tree, model);
++
++ add(new Check<T>("check", model));
++ }
++}
http://git-wip-us.apache.org/repos/asf/wicket/blob/05840d1c/wicket-extensions/src/main/java/org/apache/wicket/extensions/markup/html/repeater/tree/content/CheckedFolder.html
----------------------------------------------------------------------
diff --cc wicket-extensions/src/main/java/org/apache/wicket/extensions/markup/html/repeater/tree/content/CheckedFolder.html
index 0000000,0000000..48433b6
new file mode 100644
--- /dev/null
+++ b/wicket-extensions/src/main/java/org/apache/wicket/extensions/markup/html/repeater/tree/content/CheckedFolder.html
@@@ -1,0 -1,0 +1,35 @@@
++<?xml version="1.0" encoding="UTF-8" ?>
++<!--
++ 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.
++-->
++<html>
++
++<head>
++</head>
++
++<body>
++
++<wicket:panel xmlns:wicket="http://wicket.apache.org">
++ <input type="checkbox" wicket:id="checkbox" />
++
++ <a wicket:id="link">
++ <span class="tree-label" wicket:id="label">[label]</span>
++ </a>
++</wicket:panel>
++
++</body>
++
++</html>
http://git-wip-us.apache.org/repos/asf/wicket/blob/05840d1c/wicket-extensions/src/main/java/org/apache/wicket/extensions/markup/html/repeater/tree/content/CheckedFolder.java
----------------------------------------------------------------------
diff --cc wicket-extensions/src/main/java/org/apache/wicket/extensions/markup/html/repeater/tree/content/CheckedFolder.java
index 0000000,0000000..cf0f1ed
new file mode 100644
--- /dev/null
+++ b/wicket-extensions/src/main/java/org/apache/wicket/extensions/markup/html/repeater/tree/content/CheckedFolder.java
@@@ -1,0 -1,0 +1,92 @@@
++/*
++ * 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.extensions.markup.html.repeater.tree.content;
++
++import org.apache.wicket.Component;
++import org.apache.wicket.ajax.AjaxRequestTarget;
++import org.apache.wicket.ajax.markup.html.form.AjaxCheckBox;
++import org.apache.wicket.extensions.markup.html.repeater.tree.AbstractTree;
++import org.apache.wicket.markup.html.form.CheckBox;
++import org.apache.wicket.model.IModel;
++import org.apache.wicket.model.Model;
++
++/**
++ * This class adds a {@link CheckBox} to a {@link Folder}. Subclasses have to override
++ * {@link #newCheckBoxModel(IModel)} to do anything useful with the checkbox state.
++ *
++ * @see #newCheckBoxModel(IModel)
++ *
++ * @author svenmeier
++ */
++public class CheckedFolder<T> extends Folder<T>
++{
++
++ private static final long serialVersionUID = 1L;
++
++ public CheckedFolder(String id, AbstractTree<T> tree, IModel<T> model)
++ {
++ super(id, tree, model);
++
++ add(newCheckBox("checkbox", model));
++ }
++
++ /**
++ * Hook method to create a new checkbox component. This default implementation uses an
++ * {@link AjaxCheckBox}.
++ *
++ * @param id
++ * @param model
++ * @return created component
++ *
++ * @see #newCheckBoxModel(IModel)
++ * @see #onUpdate(AjaxRequestTarget)
++ */
++ protected Component newCheckBox(String id, IModel<T> model)
++ {
++ return new AjaxCheckBox(id, newCheckBoxModel(model))
++ {
++ private static final long serialVersionUID = 1L;
++
++ @Override
++ protected void onUpdate(AjaxRequestTarget target)
++ {
++ CheckedFolder.this.onUpdate(target);
++ }
++ };
++ }
++
++ /**
++ * Create the model for the checkbox, defaults to {@link Boolean#FALSE}.
++ *
++ * @param model
++ * @return wrapping model
++ */
++ protected IModel<Boolean> newCheckBoxModel(IModel<T> model)
++ {
++ return Model.of(Boolean.FALSE);
++ }
++
++ /**
++ * Hook method to be notified of an update of the checkbox.
++ *
++ * @param target
++ * @see #newCheckBox(String, IModel)
++ */
++ protected void onUpdate(AjaxRequestTarget target)
++ {
++ }
++}
http://git-wip-us.apache.org/repos/asf/wicket/blob/05840d1c/wicket-extensions/src/main/java/org/apache/wicket/extensions/markup/html/repeater/tree/content/Folder.java
----------------------------------------------------------------------
diff --cc wicket-extensions/src/main/java/org/apache/wicket/extensions/markup/html/repeater/tree/content/Folder.java
index 0000000,0000000..bfba16e
new file mode 100644
--- /dev/null
+++ b/wicket-extensions/src/main/java/org/apache/wicket/extensions/markup/html/repeater/tree/content/Folder.java
@@@ -1,0 -1,0 +1,157 @@@
++/*
++ * 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.extensions.markup.html.repeater.tree.content;
++
++import org.apache.wicket.ajax.AjaxRequestTarget;
++import org.apache.wicket.extensions.markup.html.repeater.tree.AbstractTree;
++import org.apache.wicket.extensions.markup.html.repeater.tree.AbstractTree.State;
++import org.apache.wicket.extensions.markup.html.repeater.tree.ITreeProvider;
++import org.apache.wicket.model.IModel;
++
++/**
++ * A typical folder representation of nodes in a tree.
++ *
++ * The link is used to expand/collapse the tree depending on the {@link State} of the current node.
++ * Nodes without children are not clickable. Subclasses may change this behavior by overriding
++ * {@link #isClickable()} and {@link #onClick(AjaxRequestTarget)}.
++ *
++ * @author svenmeier
++ */
++public class Folder<T> extends StyledLinkLabel<T>
++{
++
++ private static final long serialVersionUID = 1L;
++
++ private AbstractTree<T> tree;
++
++ public Folder(String id, AbstractTree<T> tree, IModel<T> model)
++ {
++ super(id, model);
++
++ this.tree = tree;
++ }
++
++ /**
++ * Clickable if node can be expanded/collapsed, i.e. has children.
++ *
++ * @see ITreeProvider#hasChildren(Object)
++ */
++ @Override
++ protected boolean isClickable()
++ {
++ T t = getModelObject();
++
++ return tree.getProvider().hasChildren(t);
++ }
++
++ /**
++ * Toggle the node's {@link State} on click.
++ */
++ @Override
++ protected void onClick(AjaxRequestTarget target)
++ {
++ T t = getModelObject();
++ if (tree.getState(t) == State.EXPANDED)
++ {
++ tree.collapse(t);
++ }
++ else
++ {
++ tree.expand(t);
++ }
++ }
++
++ /**
++ * Delegates to others methods depending wether the given model is a folder, expanded, collapsed
++ * or selected.
++ *
++ * @see ITreeProvider#hasChildren(Object)
++ * @see AbstractTree#getState(Object)
++ * @see #isSelected()
++ * @see #getOpenStyleClass()
++ * @see #getClosedStyleClass()
++ * @see #getOtherStyleClass(Object)
++ * @see #getSelectedStyleClass()
++ */
++ @Override
++ protected String getStyleClass()
++ {
++ T t = getModelObject();
++
++ String styleClass;
++ if (tree.getProvider().hasChildren(t))
++ {
++ if (tree.getState(t) == State.EXPANDED)
++ {
++ styleClass = getOpenStyleClass();
++ }
++ else
++ {
++ styleClass = getClosedStyleClass();
++ }
++ }
++ else
++ {
++ styleClass = getOtherStyleClass(t);
++ }
++
++ if (isSelected())
++ {
++ styleClass += " " + getSelectedStyleClass();
++ }
++
++ return styleClass;
++ }
++
++ /**
++ * Optional attribute which decides if an additional "selected" style class should be rendered.
++ *
++ * @return defaults to <code>false</code>
++ */
++ protected boolean isSelected()
++ {
++ return false;
++ }
++
++ /**
++ * Get a style class for anything other than closed or open folders.
++ */
++ protected String getOtherStyleClass(T t)
++ {
++ return "tree-folder-other";
++ }
++
++ protected String getClosedStyleClass()
++ {
++ return "tree-folder-closed";
++ }
++
++ protected String getOpenStyleClass()
++ {
++ return "tree-folder-open";
++ }
++
++ /**
++ * Get a style class to render for a selected folder.
++ *
++ * @see #isSelected()
++ */
++ protected String getSelectedStyleClass()
++ {
++ return "selected";
++ }
++}
http://git-wip-us.apache.org/repos/asf/wicket/blob/05840d1c/wicket-extensions/src/main/java/org/apache/wicket/extensions/markup/html/repeater/tree/content/StyledLinkLabel.html
----------------------------------------------------------------------
diff --cc wicket-extensions/src/main/java/org/apache/wicket/extensions/markup/html/repeater/tree/content/StyledLinkLabel.html
index 0000000,0000000..efe3a32
new file mode 100644
--- /dev/null
+++ b/wicket-extensions/src/main/java/org/apache/wicket/extensions/markup/html/repeater/tree/content/StyledLinkLabel.html
@@@ -1,0 -1,0 +1,33 @@@
++<?xml version="1.0" encoding="UTF-8" ?>
++<!--
++ 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.
++-->
++<html>
++
++<head>
++</head>
++
++<body>
++
++<wicket:panel xmlns:wicket="http://wicket.apache.org">
++ <a wicket:id="link">
++ <span class="tree-label" wicket:id="label">[label]</span>
++ </a>
++</wicket:panel>
++
++</body>
++
++</html>
http://git-wip-us.apache.org/repos/asf/wicket/blob/05840d1c/wicket-extensions/src/main/java/org/apache/wicket/extensions/markup/html/repeater/tree/content/StyledLinkLabel.java
----------------------------------------------------------------------
diff --cc wicket-extensions/src/main/java/org/apache/wicket/extensions/markup/html/repeater/tree/content/StyledLinkLabel.java
index 0000000,0000000..a26c6d3
new file mode 100644
--- /dev/null
+++ b/wicket-extensions/src/main/java/org/apache/wicket/extensions/markup/html/repeater/tree/content/StyledLinkLabel.java
@@@ -1,0 -1,0 +1,166 @@@
++/*
++ * 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.extensions.markup.html.repeater.tree.content;
++
++import org.apache.wicket.Component;
++import org.apache.wicket.MarkupContainer;
++import org.apache.wicket.ajax.AjaxRequestTarget;
++import org.apache.wicket.ajax.markup.html.AjaxFallbackLink;
++import org.apache.wicket.behavior.Behavior;
++import org.apache.wicket.markup.ComponentTag;
++import org.apache.wicket.markup.html.basic.Label;
++import org.apache.wicket.markup.html.panel.Panel;
++import org.apache.wicket.model.IModel;
++
++/**
++ * A styled link with a label.
++ *
++ * @see #newLinkComponent(String, IModel)
++ * @see #getStyleClass()
++ *
++ * @author svenmeier
++ */
++public abstract class StyledLinkLabel<T> extends Panel
++{
++ private static final StyleBehavior STYLE_CLASS = new StyleBehavior();
++
++ private static final long serialVersionUID = 1L;
++
++ public StyledLinkLabel(String id, IModel<T> model)
++ {
++ super(id, model);
++
++ MarkupContainer link = newLinkComponent("link", model);
++ link.add(STYLE_CLASS);
++ add(link);
++
++ link.add(newLabelComponent("label", model));
++ }
++
++ @SuppressWarnings("unchecked")
++ public IModel<T> getModel()
++ {
++ return (IModel<T>)getDefaultModel();
++ }
++
++ public T getModelObject()
++ {
++ return getModel().getObject();
++ }
++
++ /**
++ * Hook method to create a new link component.
++ *
++ * This default implementation returns an {@link AjaxFallbackLink} which invokes
++ * {@link #onClick(AjaxRequestTarget)} only if {@link #isClickable()} returns <code>true</code>.
++ *
++ * @see #isClickable()
++ * @see #onClick(AjaxRequestTarget)
++ */
++ protected MarkupContainer newLinkComponent(String id, IModel<T> model)
++ {
++ return new AjaxFallbackLink<Void>(id)
++ {
++ private static final long serialVersionUID = 1L;
++
++ @Override
++ public boolean isEnabled()
++ {
++ return StyledLinkLabel.this.isClickable();
++ }
++
++ @Override
++ public void onClick(AjaxRequestTarget target)
++ {
++ StyledLinkLabel.this.onClick(target);
++ }
++ };
++ }
++
++ /**
++ * Hook method to create a new label component.
++ *
++ * @param id
++ * @param model
++ * @return created component
++ *
++ * @see #newLabelModel(IModel)
++ */
++ protected Component newLabelComponent(String id, IModel<T> model)
++ {
++ return new Label(id, newLabelModel(model));
++ }
++
++ /**
++ * Create the model for the label, defaults to the model itself.
++ *
++ * @param model
++ * @return wrapping model
++ */
++ protected IModel<?> newLabelModel(IModel<T> model)
++ {
++ return model;
++ }
++
++ /**
++ * Get a style class for the link.
++ */
++ protected abstract String getStyleClass();
++
++ /**
++ * Clicking is disabled by default, override this method if you want your link to be enabled.
++ *
++ * @see #newLinkComponent(String, IModel)
++ * @see #isClickable()
++ */
++ protected boolean isClickable()
++ {
++ return false;
++ }
++
++ /**
++ * Hook method to be notified of a click on the link.
++ *
++ * @param target
++ *
++ * @see #newLinkComponent(String, IModel)
++ * @see #isClickable()
++ */
++ protected void onClick(AjaxRequestTarget target)
++ {
++ }
++
++ /**
++ * Behavior to add a style class attribute to a contained link.
++ */
++ private static class StyleBehavior extends Behavior
++ {
++ private static final long serialVersionUID = 1L;
++
++ @Override
++ public void onComponentTag(Component component, ComponentTag tag)
++ {
++ StyledLinkLabel<?> parent = (StyledLinkLabel<?>)component.getParent();
++
++ String styleClass = parent.getStyleClass();
++ if (styleClass != null)
++ {
++ tag.put("class", styleClass);
++ }
++ }
++ }
++}
http://git-wip-us.apache.org/repos/asf/wicket/blob/05840d1c/wicket-extensions/src/main/java/org/apache/wicket/extensions/markup/html/repeater/tree/nested/BranchItem.java
----------------------------------------------------------------------
diff --cc wicket-extensions/src/main/java/org/apache/wicket/extensions/markup/html/repeater/tree/nested/BranchItem.java
index 0000000,0000000..d82f1df
new file mode 100644
--- /dev/null
+++ b/wicket-extensions/src/main/java/org/apache/wicket/extensions/markup/html/repeater/tree/nested/BranchItem.java
@@@ -1,0 -1,0 +1,61 @@@
++/*
++ * 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.extensions.markup.html.repeater.tree.nested;
++
++import org.apache.wicket.markup.ComponentTag;
++import org.apache.wicket.markup.repeater.Item;
++import org.apache.wicket.model.IModel;
++
++/**
++ * A branch is a container for a single node and its children inside a {@link Subtree}.
++ *
++ * @see Subtree#newBranchItem(String, int, IModel)
++ *
++ * @author svenmeier
++ */
++public final class BranchItem<T> extends Item<T>
++{
++
++ private static final long serialVersionUID = 1L;
++
++ public BranchItem(String id, int index, IModel<T> model)
++ {
++ super(id, index, model);
++
++ setOutputMarkupId(true);
++ }
++
++ @Override
++ protected void onComponentTag(ComponentTag tag)
++ {
++ super.onComponentTag(tag);
++
++ if (isLast())
++ {
++ tag.put("class", "tree-branch tree-branch-last");
++ }
++ else
++ {
++ tag.put("class", "tree-branch tree-branch-mid");
++ }
++ }
++
++ private boolean isLast()
++ {
++ return getIndex() == getParent().size() - 1;
++ }
++}
http://git-wip-us.apache.org/repos/asf/wicket/blob/05840d1c/wicket-extensions/src/main/java/org/apache/wicket/extensions/markup/html/repeater/tree/nested/Subtree.html
----------------------------------------------------------------------
diff --cc wicket-extensions/src/main/java/org/apache/wicket/extensions/markup/html/repeater/tree/nested/Subtree.html
index 0000000,0000000..e3d8986
new file mode 100644
--- /dev/null
+++ b/wicket-extensions/src/main/java/org/apache/wicket/extensions/markup/html/repeater/tree/nested/Subtree.html
@@@ -1,0 -1,0 +1,34 @@@
++<?xml version="1.0" encoding="UTF-8" ?>
++<!--
++ 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.
++-->
++<html>
++
++<head>
++</head>
++
++<body>
++
++<wicket:panel xmlns:wicket="http://wicket.apache.org">
++ <div wicket:id="branches">
++ <div wicket:id="node" class="tree-node">[node]</div>
++ <div wicket:id="subtree" class="tree-subtree">[subtree]</div>
++ </div>
++</wicket:panel>
++
++</body>
++
++</html>
http://git-wip-us.apache.org/repos/asf/wicket/blob/05840d1c/wicket-extensions/src/main/java/org/apache/wicket/extensions/markup/html/repeater/tree/nested/Subtree.java
----------------------------------------------------------------------
diff --cc wicket-extensions/src/main/java/org/apache/wicket/extensions/markup/html/repeater/tree/nested/Subtree.java
index 0000000,0000000..0152ccd
new file mode 100644
--- /dev/null
+++ b/wicket-extensions/src/main/java/org/apache/wicket/extensions/markup/html/repeater/tree/nested/Subtree.java
@@@ -1,0 -1,0 +1,171 @@@
++/*
++ * 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.extensions.markup.html.repeater.tree.nested;
++
++import java.util.Iterator;
++
++import org.apache.wicket.Component;
++import org.apache.wicket.extensions.markup.html.repeater.tree.AbstractTree.State;
++import org.apache.wicket.extensions.markup.html.repeater.tree.ITreeProvider;
++import org.apache.wicket.extensions.markup.html.repeater.tree.NestedTree;
++import org.apache.wicket.markup.html.panel.Panel;
++import org.apache.wicket.markup.repeater.IItemFactory;
++import org.apache.wicket.markup.repeater.IItemReuseStrategy;
++import org.apache.wicket.markup.repeater.Item;
++import org.apache.wicket.markup.repeater.RefreshingView;
++import org.apache.wicket.model.IModel;
++
++/**
++ * A subtree handles all children of a single node (or the root nodes if a <code>null</code> node
++ * was given to the constructor).
++ *
++ * @see ITreeProvider#getChildren(Object)
++ * @see ITreeProvider#getRoots()
++ *
++ * @author svenmeier
++ */
++public class Subtree<T> extends Panel
++{
++
++ private static final long serialVersionUID = 1L;
++
++ private NestedTree<T> tree;
++
++ /**
++ * Create a subtree for the children of the node contained in the given model or the root nodes
++ * if the model contains <code>null</code>.
++ *
++ * @param id
++ * component id
++ * @param tree
++ * the containing tree
++ * @param model
++ */
++ public Subtree(String id, final NestedTree<T> tree, final IModel<T> model)
++ {
++ super(id, model);
++
++ if (tree == null)
++ {
++ throw new IllegalArgumentException("argument [tree] cannot be null");
++ }
++ this.tree = tree;
++
++ RefreshingView<T> branches = new RefreshingView<T>("branches")
++ {
++ private static final long serialVersionUID = 1L;
++
++ @Override
++ protected Iterator<IModel<T>> getItemModels()
++ {
++ return new ModelIterator();
++ }
++
++ @Override
++ protected Item<T> newItem(String id, int index, IModel<T> model)
++ {
++ return newBranchItem(id, index, model);
++ }
++
++ @Override
++ protected void populateItem(Item<T> item)
++ {
++ IModel<T> model = item.getModel();
++
++ Component node = tree.newNodeComponent("node", model);
++ item.add(node);
++
++ item.add(tree.newSubtree("subtree", model));
++ }
++ };
++ branches.setItemReuseStrategy(new IItemReuseStrategy()
++ {
++ private static final long serialVersionUID = 1L;
++
++ public <S> Iterator<Item<S>> getItems(IItemFactory<S> factory,
++ Iterator<IModel<S>> newModels, Iterator<Item<S>> existingItems)
++ {
++ return tree.getItemReuseStrategy().getItems(factory, newModels, existingItems);
++ }
++ });
++ add(branches);
++ }
++
++ @SuppressWarnings("unchecked")
++ public IModel<T> getModel()
++ {
++ return (IModel<T>)getDefaultModel();
++ }
++
++ public T getModelObject()
++ {
++ return getModel().getObject();
++ }
++
++ protected BranchItem<T> newBranchItem(String id, int index, IModel<T> model)
++ {
++ return new BranchItem<T>(id, index, model);
++ }
++
++ @Override
++ public boolean isVisible()
++ {
++ T t = getModel().getObject();
++ if (t == null)
++ {
++ // roots always visible
++ return true;
++ }
++ else
++ {
++ return tree.getState(t) == State.EXPANDED;
++ }
++ }
++
++ private final class ModelIterator implements Iterator<IModel<T>>
++ {
++ private Iterator<? extends T> children;
++
++ public ModelIterator()
++ {
++ T t = getModel().getObject();
++ if (t == null)
++ {
++ children = tree.getProvider().getRoots();
++ }
++ else
++ {
++ children = tree.getProvider().getChildren(t);
++ }
++ }
++
++ public void remove()
++ {
++ throw new UnsupportedOperationException();
++ }
++
++ public boolean hasNext()
++ {
++ return children.hasNext();
++ }
++
++ public IModel<T> next()
++ {
++ return tree.getProvider().model(children.next());
++ }
++ }
++}
http://git-wip-us.apache.org/repos/asf/wicket/blob/05840d1c/wicket-extensions/src/main/java/org/apache/wicket/extensions/markup/html/repeater/tree/table/AbstractTreeColumn.java
----------------------------------------------------------------------
diff --cc wicket-extensions/src/main/java/org/apache/wicket/extensions/markup/html/repeater/tree/table/AbstractTreeColumn.java
index 0000000,0000000..fd1fa8b
new file mode 100644
--- /dev/null
+++ b/wicket-extensions/src/main/java/org/apache/wicket/extensions/markup/html/repeater/tree/table/AbstractTreeColumn.java
@@@ -1,0 -1,0 +1,50 @@@
++/*
++ * 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.extensions.markup.html.repeater.tree.table;
++
++import org.apache.wicket.extensions.markup.html.repeater.data.table.AbstractColumn;
++import org.apache.wicket.extensions.markup.html.repeater.tree.TableTree;
++import org.apache.wicket.model.IModel;
++
++/**
++ * @author svenmeier
++ */
++public abstract class AbstractTreeColumn<T> extends AbstractColumn<T> implements ITreeColumn<T>
++{
++
++ private TableTree<T> tree;
++
++ public AbstractTreeColumn(IModel<String> displayModel)
++ {
++ super(displayModel);
++ }
++
++ public AbstractTreeColumn(IModel<String> displayModel, String sortProperty)
++ {
++ super(displayModel, sortProperty);
++ }
++
++ public void setTree(TableTree<T> tree)
++ {
++ this.tree = tree;
++ }
++
++ public TableTree<T> getTree()
++ {
++ return tree;
++ }
++}
http://git-wip-us.apache.org/repos/asf/wicket/blob/05840d1c/wicket-extensions/src/main/java/org/apache/wicket/extensions/markup/html/repeater/tree/table/ITreeColumn.java
----------------------------------------------------------------------
diff --cc wicket-extensions/src/main/java/org/apache/wicket/extensions/markup/html/repeater/tree/table/ITreeColumn.java
index 0000000,0000000..856c93c
new file mode 100644
--- /dev/null
+++ b/wicket-extensions/src/main/java/org/apache/wicket/extensions/markup/html/repeater/tree/table/ITreeColumn.java
@@@ -1,0 -1,0 +1,28 @@@
++/*
++ * 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.extensions.markup.html.repeater.tree.table;
++
++import org.apache.wicket.extensions.markup.html.repeater.data.table.IColumn;
++import org.apache.wicket.extensions.markup.html.repeater.tree.TableTree;
++
++/**
++ * @author svenmeier
++ */
++public interface ITreeColumn<T> extends IColumn<T>
++{
++ public void setTree(TableTree<T> t);
++}
http://git-wip-us.apache.org/repos/asf/wicket/blob/05840d1c/wicket-extensions/src/main/java/org/apache/wicket/extensions/markup/html/repeater/tree/table/ITreeDataProvider.java
----------------------------------------------------------------------
diff --cc wicket-extensions/src/main/java/org/apache/wicket/extensions/markup/html/repeater/tree/table/ITreeDataProvider.java
index 0000000,0000000..dd56242
new file mode 100644
--- /dev/null
+++ b/wicket-extensions/src/main/java/org/apache/wicket/extensions/markup/html/repeater/tree/table/ITreeDataProvider.java
@@@ -1,0 -1,0 +1,34 @@@
++/*
++ * 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.extensions.markup.html.repeater.tree.table;
++
++import org.apache.wicket.extensions.markup.html.repeater.tree.ITreeProvider;
++import org.apache.wicket.markup.repeater.data.IDataProvider;
++
++/**
++ * An adapter from a {@link ITreeProvider} to a {@link IDataProvider}.
++ *
++ * @author svenmeier
++ */
++public interface ITreeDataProvider<T> extends IDataProvider<T>
++{
++ /**
++ * Wrap the given node in a {@link NodeModel} which provides additional branch information
++ * needed by {@link TreeColumn}
++ */
++ public NodeModel<T> model(T object);
++}