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

[1/9] git commit: Merge remote-tracking branch 'origin/master'

Updated Branches:
  refs/heads/master 41ddc9ce7 -> 31726809e


Merge remote-tracking branch 'origin/master'


Project: http://git-wip-us.apache.org/repos/asf/wicket/repo
Commit: http://git-wip-us.apache.org/repos/asf/wicket/commit/31726809
Tree: http://git-wip-us.apache.org/repos/asf/wicket/tree/31726809
Diff: http://git-wip-us.apache.org/repos/asf/wicket/diff/31726809

Branch: refs/heads/master
Commit: 31726809ec0401de0effd92060b99d6db3c83c21
Parents: 05840d1 41ddc9c
Author: Sven Meier <sv...@apache.org>
Authored: Sun Feb 5 21:31:14 2012 +0100
Committer: Sven Meier <sv...@apache.org>
Committed: Sun Feb 5 22:48:06 2012 +0100

----------------------------------------------------------------------
 release-igor.sh                                    |   25 +-
 .../main/java/org/apache/wicket/Application.java   |    5 +-
 .../src/main/java/org/apache/wicket/Behaviors.java |    3 +-
 .../src/main/java/org/apache/wicket/Component.java |  289 ++--
 .../java/org/apache/wicket/MarkupContainer.java    |   80 +-
 .../src/main/java/org/apache/wicket/Page.java      |   21 +-
 .../src/main/java/org/apache/wicket/Session.java   |   34 +-
 .../apache/wicket/ajax/AbstractAjaxResponse.java   |  748 +++++++
 .../wicket/ajax/AbstractAjaxTimerBehavior.java     |   22 +-
 .../wicket/ajax/AbstractDefaultAjaxBehavior.java   |  186 ++-
 .../org/apache/wicket/ajax/AjaxEventBehavior.java  |   33 +-
 .../org/apache/wicket/ajax/AjaxRequestHandler.java |  491 +++++
 .../org/apache/wicket/ajax/AjaxRequestTarget.java  | 1258 +----------
 .../ajax/AjaxRequestTargetListenerCollection.java  |    2 +-
 .../wicket/ajax/AjaxSelfUpdatingTimerBehavior.java |    2 +-
 .../org/apache/wicket/ajax/XmlAjaxResponse.java    |  230 ++
 .../AjaxFormChoiceComponentUpdatingBehavior.java   |   35 +-
 .../form/AjaxFormComponentUpdatingBehavior.java    |   24 +-
 .../wicket/ajax/form/OnChangeAjaxBehavior.java     |    2 +-
 .../wicket/ajax/markup/html/AjaxFallbackLink.java  |    4 -
 .../wicket/ajax/markup/html/form/AjaxButton.java   |    8 -
 .../wicket/ajax/markup/html/form/AjaxCheckBox.java |    3 +-
 .../ajax/markup/html/form/AjaxFallbackButton.java  |    2 +-
 .../wicket/ajax/res/js/wicket-ajax-jquery.js       |  167 +-
 .../wicket/ajax/res/js/wicket-event-jquery.js      |    4 +-
 .../strategy/DefaultAuthenticationStrategy.java    |    9 +-
 .../wicket/behavior/AbstractAjaxBehavior.java      |    8 +-
 .../behavior/InvalidBehaviorIdException.java       |   12 +-
 .../DefaultCleanupFeedbackMessageFilter.java       |   35 +
 .../feedback/ErrorLevelFeedbackMessageFilter.java  |    1 +
 .../apache/wicket/feedback/FeedbackCollector.java  |  135 ++
 .../apache/wicket/feedback/FeedbackMessages.java   |  112 +-
 .../wicket/feedback/FeedbackMessagesModel.java     |   14 +-
 .../wicket/feedback/IFeedbackMessageFilter.java    |   14 +
 .../org/apache/wicket/markup/MarkupParser.java     |    4 +-
 .../wicket/markup/head/CssContentHeaderItem.java   |   16 +-
 .../apache/wicket/markup/head/CssHeaderItem.java   |   62 +-
 .../wicket/markup/head/CssReferenceHeaderItem.java |   13 +-
 .../markup/head/CssUrlReferenceHeaderItem.java     |   11 +-
 .../markup/head/JavaScriptContentHeaderItem.java   |   17 +-
 .../wicket/markup/head/JavaScriptHeaderItem.java   |  124 +-
 .../markup/head/JavaScriptReferenceHeaderItem.java |    5 +-
 .../head/JavaScriptUrlReferenceHeaderItem.java     |    7 +-
 .../wicket/markup/head/ResourceAggregator.java     |    8 +-
 .../head/filter/AbstractHeaderResponseFilter.java  |   56 +
 .../filter/CssAcceptingHeaderResponseFilter.java   |   46 +
 .../CssAndPageAcceptingHeaderResponseFilter.java   |   47 +
 .../markup/head/filter/FilteredHeaderItem.java     |  120 +
 .../head/filter/FilteringHeaderResponse.java       |  239 ++
 .../head/filter/HeaderResponseContainer.java       |   73 +
 .../JavaScriptAcceptingHeaderResponseFilter.java   |   50 +
 ...JavaScriptFilteredIntoFooterHeaderResponse.java |   72 +
 .../head/filter/OppositeHeaderResponseFilter.java  |   60 +
 .../apache/wicket/markup/html/border/Border.java   |   12 +-
 .../org/apache/wicket/markup/html/form/Check.java  |   10 +-
 .../org/apache/wicket/markup/html/form/Form.java   |    6 +-
 .../wicket/markup/html/form/FormComponent.java     |   12 +-
 .../wicket/markup/html/form/StatelessForm.java     |   32 +
 .../validation/FormComponentFeedbackBorder.java    |    4 +-
 .../validation/FormComponentFeedbackIndicator.java |    5 +-
 .../org/apache/wicket/markup/html/image/Image.java |    4 +-
 .../wicket/markup/html/image/NonCachingImage.java  |    2 +-
 .../html/image/resource/BlobImageResource.java     |    8 +-
 .../wicket/markup/html/internal/Enclosure.java     |    1 -
 .../wicket/markup/parser/AbstractMarkupFilter.java |   32 +
 .../parser/filter/RelativePathPrefixHandler.java   |   24 +-
 .../parser/filter/WicketMessageTagHandler.java     |   37 +-
 .../parser/filter/WicketNamespaceHandler.java      |    7 +-
 .../markup/parser/filter/WicketTagIdentifier.java  |    7 +-
 .../markup/resolver/WicketMessageResolver.java     |    1 -
 .../main/java/org/apache/wicket/model/Model.java   |   32 +-
 .../wicket/page/DefaultPageManagerContext.java     |    2 +-
 .../protocol/http/AjaxEnclosureListener.java       |    4 +-
 .../wicket/protocol/http/WebApplication.java       |   37 +-
 .../apache/wicket/protocol/http/WebSession.java    |   62 -
 .../apache/wicket/protocol/http/WicketFilter.java  |   37 +-
 .../protocol/http/mock/MockHttpServletRequest.java |   22 +-
 .../protocol/http/servlet/ServletWebResponse.java  |   23 +-
 .../apache/wicket/request/cycle/RequestCycle.java  |   98 +-
 .../resource/ResourceReferenceRequestHandler.java  |    4 +-
 .../handler/resource/ResourceRequestHandler.java   |    7 +-
 .../request/mapper/AbstractBookmarkableMapper.java |    5 +
 .../request/mapper/BufferedResponseMapper.java     |   20 +-
 .../apache/wicket/request/mapper/CryptoMapper.java |    2 +-
 .../wicket/request/mapper/MountedMapper.java       |   12 +-
 .../wicket/request/resource/AbstractResource.java  |   17 +-
 .../wicket/request/resource/ClassScanner.java      |    2 +-
 .../wicket/request/resource/PackageResource.java   |   38 +-
 .../wicket/request/resource/ResourceReference.java |    2 +-
 .../resource/ResourceReferenceRegistry.java        |   16 +-
 .../request/resource/ResourceStreamResource.java   |    9 +-
 .../version/MessageDigestResourceVersion.java      |    2 +-
 .../filtering/AbstractHeaderResponseFilter.java    |   56 -
 .../CssAcceptingHeaderResponseFilter.java          |   53 -
 ...erResponseContainerFilteringHeaderResponse.java |  228 --
 .../HeaderResponseFilteredResponseContainer.java   |   73 -
 .../JavaScriptAcceptingHeaderResponseFilter.java   |   38 -
 ...JavaScriptFilteredIntoFooterHeaderResponse.java |   67 -
 .../filtering/OppositeHeaderResponseFilter.java    |   60 -
 .../apache/wicket/session/DefaultPageFactory.java  |    8 +-
 .../wicket/settings/IApplicationSettings.java      |   18 +
 .../org/apache/wicket/settings/IPageSettings.java  |   18 +
 .../wicket/settings/def/ApplicationSettings.java   |   18 +
 .../apache/wicket/settings/def/PageSettings.java   |   13 +
 .../util/io/WicketSerializeableException.java      |   92 -
 .../wicket/util/resource/UrlResourceStream.java    |    7 +-
 .../wicket/util/tester/BaseWicketTester.java       |   89 +-
 .../org/apache/wicket/util/tester/FormTester.java  |    2 +-
 .../apache/wicket/util/tester/WicketTester.java    |    7 +-
 ...ponentBehaviorOverComponentTagBehaviorTest.java |   83 +
 .../org/apache/wicket/FeedbackMessagesTest.java    |    6 +-
 .../java/org/apache/wicket/MockPanelWithLink.java  |    2 +-
 ...ResponseAtInterceptPageExceptionInAjaxTest.java |    7 -
 .../apache/wicket/ajax/AjaxRequestHandlerTest.java |  361 +++
 .../apache/wicket/ajax/AjaxRequestTargetTest.java  |  361 ---
 .../OnChangeAjaxBehaviorTestPage_expected.html     |    4 +-
 .../SimpleTestPageExpectedResult-1.html            |    2 +-
 .../componentMap/SimpleTestPageExpectedResult.html |    2 +-
 .../wicket/markup/html/HeaderContributorTest.java  |    4 +-
 .../markup/html/TransparentWithAjaxUpdatePage.java |    2 +-
 .../html/form/LocalizedErrorMessageTest.java       |    4 +-
 .../markup/html/form/ValidatorPropertiesTest.java  |  112 +-
 .../form/feedback/FeedbackFormPage_result2.html    |    2 +-
 .../form/validation/FormValidatorBehaviorTest.java |   27 +-
 .../innerfeedback/LocalizedFeedbackBorder.java     |   13 +-
 .../markup/html/internal/HeaderResponseTest.java   |  314 ++-
 .../internal/TraditionalEnclosureAjaxPage.java     |    1 -
 .../markup/html/link/HrefExpectedResult_2.html     |    4 +-
 .../markup/html/link/MountedPageLinkTest.java      |  108 +
 .../wicket/markup/html/link/PageWithLink.html      |    8 +
 .../wicket/markup/html/link/PageWithLink.java      |   40 +
 .../wicket/markup/html/panel/FragmentTestCase.java |    2 +-
 .../apache/wicket/markup/html/panel/PanelTest.java |    2 +-
 .../AbstractTransformerBehaviorTest.java           |    4 +-
 .../http/mock/MockHttpServletRequestTest.java      |   36 +
 .../http/servlet/ServletWebResponseTest.java       |   43 -
 .../request/cycle/RequestCycleUrlForTest.java      |  200 ++
 .../wicket/request/handler/PageIdPoliticTest.java  |    1 -
 .../wicket/request/mapper/CryptoMapperTest.java    |   18 +
 .../wicket/request/mapper/MountedMapperTest.java   |   18 +
 .../apache/wicket/request/mapper/UrlInfoTest.java  |    2 +-
 .../wicket/response/filter/ResponseFilterTest.java |    1 -
 .../wicket/stateless/StatelessFormUrlTest.java     |   35 +-
 .../wicket/util/tester/WicketTesterTest.java       |   48 +-
 .../wicket/util/tester/apps_4/FormTesterTest.java  |   14 +-
 .../wicket/validation/ValidatorBehaviorTest.java   |   27 +-
 wicket-core/src/test/js/ajax.js                    |   67 +-
 wicket-core/src/test/js/event.js                   |   22 +
 wicket-core/src/test/js/head.js                    |    3 +-
 .../wicket/extensions/yui/calendar/DatePicker.java |   15 +-
 .../wicket/extensions/yui/calendar/calendar-min.js |   28 +-
 .../apache/wicket/devutils/debugbar/DebugBar.java  |    1 -
 .../src/disabled/java/ng/NGApplication.java        |   48 -
 .../src/disabled/java/ng/TestPage1.java            |  146 --
 .../src/disabled/java/ng/TestPage2.java            |   28 -
 .../src/disabled/java/ng/TestPage3.java            |   45 -
 .../src/disabled/java/ng/TestPage4.java            |   42 -
 .../wicket/examples/ajax/builtin/EffectsPage.java  |    2 +-
 .../wicket/examples/ajax/builtin/GuestBook.java    |    8 +-
 .../wicket/examples/ajax/builtin/LinksPage.java    |    4 +-
 .../wicket/examples/ajax/builtin/TodoList.java     |    2 +-
 .../wicket/examples/compref/RadioChoicePage.java   |   17 +-
 .../wicket/examples/library/LibrarySession.java    |    4 +-
 .../examples/resourcedecoration/HomePage.html      |    3 +-
 .../examples/resourcedecoration/HomePage.java      |   18 +-
 .../ResourceDecorationApplication.java             |    2 +-
 .../wicket/examples/resourcedecoration/app.css     |    5 +-
 .../wicket/examples/resourcedecoration/top.js      |   20 +
 .../apache/wicket/examples/source/SourcesPage.java |   34 +-
 .../wicket/examples/stateless/StatelessPage3.java  |    3 -
 .../apache/wicket/examples/tree/InverseSet.java    |  143 ++
 .../org/apache/wicket/examples/tree/TreePage.java  |    3 +-
 .../tree/content/CheckedFolderContent.java         |    2 +-
 .../tree/content/MultiSelectableFolderContent.java |    2 +-
 .../org/apache/wicket/examples/StartExamples.java  |    2 +
 .../wicket/examples/tree/InverseSetTest.java       |   77 +
 .../ajax/markup/html/AjaxEditableLabel.java        |   77 +-
 .../ajax/markup/html/AjaxIndicatorAppender.java    |    2 +-
 .../ajax/markup/html/AjaxLazyLoadPanel.java        |    4 +-
 .../autocomplete/AbstractAutoCompleteBehavior.java |    2 +-
 .../html/autocomplete/wicket-autocomplete.js       |    2 -
 .../ajax/markup/html/modal/ModalWindow.java        |   16 +-
 .../extensions/ajax/markup/html/modal/res/modal.js |    2 +-
 .../data/sort/AjaxFallbackOrderByLink.java         |    2 +-
 .../repeater/data/table/AjaxNavigationToolbar.java |    2 +-
 .../breadcrumb/panel/BreadCrumbPanelFactory.java   |    6 +-
 .../breadcrumb/panel/BreadCrumbPanelLink.java      |   13 +-
 .../captcha/kittens/KittenCaptchaPanel.java        |   29 +-
 .../extensions/markup/html/form/select/Select.java |    9 +-
 .../image/resource/ThumbnailImageResource.java     |    2 +-
 .../markup/html/repeater/tree/AbstractTree.java    |    6 +-
 .../markup/html/repeater/tree/util/InverseSet.java |  143 --
 .../markup/html/repeater/tree/util/KeyingSet.java  |  164 --
 .../html/repeater/tree/util/ProviderSubset.java    |  242 --
 .../repeater/tree/util/SortableTreeProvider.java   |   97 -
 .../html/repeater/tree/util/TreeModelProvider.java |  258 ---
 .../markup/html/repeater/util/ProviderSubset.java  |  242 ++
 .../html/repeater/util/SortableTreeProvider.java   |   95 +
 .../html/repeater/util/TreeModelProvider.java      |  258 +++
 .../extensions/markup/html/tree/AbstractTree.java  |    8 +-
 .../extensions/markup/html/tree/BaseTree.java      |    2 +-
 .../markup/html/tree/DefaultAbstractTree.java      |    2 +-
 .../wicket/extensions/rating/RatingPanel.java      |    2 +-
 .../html/repeater/tree/util/InverseSetTest.java    |   77 -
 .../repeater/tree/util/ProviderSubsetTest.java     |  170 --
 .../repeater/tree/util/TreeModelProviderTest.java  |  155 --
 .../html/repeater/util/ProviderSubsetTest.java     |  171 ++
 .../html/repeater/util/TreeModelProviderTest.java  |  156 ++
 .../wicket/guice/GuiceComponentInjector.java       |   10 +-
 .../apache/wicket/proxy/LazyInitProxyFactory.java  |    4 +-
 .../apache/wicket/proxy/util/InterfaceObject.java  |    1 -
 .../apache/wicket/request/http/WebResponse.java    |    7 +-
 .../request/mapper/parameter/PageParameters.java   |   18 +
 .../mapper/parameter/PageParametersEncoder.java    |   15 +-
 .../parameter/UrlPathPageParametersEncoder.java    |    3 +
 .../CombinedRequestParametersAdapter.java          |   10 +-
 .../parameter/UrlRequestParametersAdapter.java     |    4 +-
 .../parameter/PageParametersEncoderTest.java       |  126 ++
 .../apache/wicket/spring/SpringWebApplication.java |    3 +-
 .../annot/AnnotProxyFieldValueFactory.java         |    9 +-
 .../injection/annot/SpringComponentInjector.java   |   10 +-
 .../org/apache/wicket/util/io/Connections.java     |   10 +
 .../apache/wicket/util/io/FullyBufferedReader.java |   13 -
 .../wicket/util/resource/IResourceStream.java      |    3 +-
 .../org/apache/wicket/util/string/StringValue.java | 1678 ++++++++-------
 .../wicket/util/value/CopyOnWriteValueMap.java     |  905 ++++----
 .../org/apache/wicket/util/value/ValueMap.java     | 1708 +++++++--------
 .../apache/wicket/util/string/StringValueTest.java |   52 +
 228 files changed, 8934 insertions(+), 7337 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/wicket/blob/31726809/wicket-examples/src/main/java/org/apache/wicket/examples/tree/InverseSet.java
----------------------------------------------------------------------
diff --cc wicket-examples/src/main/java/org/apache/wicket/examples/tree/InverseSet.java
index 0000000,0000000..74f0258
new file mode 100644
--- /dev/null
+++ b/wicket-examples/src/main/java/org/apache/wicket/examples/tree/InverseSet.java
@@@ -1,0 -1,0 +1,143 @@@
++/*
++ * 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;
++
++import java.util.Collection;
++import java.util.Iterator;
++import java.util.Set;
++
++import org.apache.wicket.model.IDetachable;
++
++/**
++ * An inverse set.
++ * 
++ * @author svenmeier
++ */
++public class InverseSet<T> implements Set<T>, IDetachable
++{
++
++	private static final long serialVersionUID = 1L;
++
++	private Set<T> set;
++
++	/**
++	 * Create a full set.
++	 * 
++	 * @param set
++	 *            the contained set
++	 */
++	public InverseSet(Set<T> set)
++	{
++		this.set = set;
++	}
++
++	public void detach()
++	{
++		if (set instanceof IDetachable)
++		{
++			((IDetachable)set).detach();
++		}
++	}
++
++	public boolean isEmpty()
++	{
++		return !set.isEmpty();
++	}
++
++	public boolean contains(Object o)
++	{
++		return !set.contains(o);
++	}
++
++	public boolean add(T t)
++	{
++		return set.remove(t);
++	}
++
++	@SuppressWarnings("unchecked")
++	public boolean remove(Object o)
++	{
++		return set.add((T)o);
++	}
++
++	public boolean addAll(Collection<? extends T> ts)
++	{
++		boolean changed = false;
++
++		for (T t : ts)
++		{
++			changed |= set.remove(t);
++		}
++
++		return changed;
++	}
++
++	public boolean containsAll(Collection<?> cs)
++	{
++		for (Object c : cs)
++		{
++			if (set.contains(c))
++			{
++				return false;
++			}
++		}
++		return true;
++	}
++
++	@SuppressWarnings("unchecked")
++	public boolean removeAll(Collection<?> cs)
++	{
++		boolean changed = false;
++
++		for (Object c : cs)
++		{
++			changed |= set.add((T)c);
++		}
++
++		return changed;
++	}
++
++	public int size()
++	{
++		throw new UnsupportedOperationException();
++	}
++
++	public void clear()
++	{
++		throw new UnsupportedOperationException();
++	}
++
++	public Iterator<T> iterator()
++	{
++		throw new UnsupportedOperationException();
++	}
++
++	public boolean retainAll(Collection<?> c)
++	{
++		throw new UnsupportedOperationException();
++	}
++
++	public Object[] toArray()
++	{
++		throw new UnsupportedOperationException();
++	}
++
++	public <S> S[] toArray(S[] a)
++	{
++		throw new UnsupportedOperationException();
++	}
++}

http://git-wip-us.apache.org/repos/asf/wicket/blob/31726809/wicket-examples/src/main/java/org/apache/wicket/examples/tree/TreePage.java
----------------------------------------------------------------------
diff --cc wicket-examples/src/main/java/org/apache/wicket/examples/tree/TreePage.java
index eb5b9f8,0000000..da6a7bf
mode 100644,000000..100644
--- a/wicket-examples/src/main/java/org/apache/wicket/examples/tree/TreePage.java
+++ b/wicket-examples/src/main/java/org/apache/wicket/examples/tree/TreePage.java
@@@ -1,236 -1,0 +1,235 @@@
 +/*
 + * 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;
 +
 +import java.util.ArrayList;
 +import java.util.List;
 +import java.util.Set;
 +
 +import org.apache.wicket.Component;
 +import org.apache.wicket.behavior.Behavior;
 +import org.apache.wicket.examples.WicketExamplePage;
 +import org.apache.wicket.examples.tree.content.BookmarkableFolderContent;
 +import org.apache.wicket.examples.tree.content.CheckedFolderContent;
 +import org.apache.wicket.examples.tree.content.CheckedSelectableFolderContent;
 +import org.apache.wicket.examples.tree.content.Content;
 +import org.apache.wicket.examples.tree.content.EditableFolderContent;
 +import org.apache.wicket.examples.tree.content.FolderContent;
 +import org.apache.wicket.examples.tree.content.LabelContent;
 +import org.apache.wicket.examples.tree.content.MixedContent;
 +import org.apache.wicket.examples.tree.content.MultiLineLabelContent;
 +import org.apache.wicket.examples.tree.content.MultiSelectableFolderContent;
 +import org.apache.wicket.examples.tree.content.PanelContent;
 +import org.apache.wicket.examples.tree.content.SelectableFolderContent;
 +import org.apache.wicket.extensions.markup.html.repeater.tree.AbstractTree;
 +import org.apache.wicket.extensions.markup.html.repeater.tree.theme.HumanTheme;
 +import org.apache.wicket.extensions.markup.html.repeater.tree.theme.WindowsTheme;
- import org.apache.wicket.extensions.markup.html.repeater.tree.util.InverseSet;
- import org.apache.wicket.extensions.markup.html.repeater.tree.util.ProviderSubset;
++import org.apache.wicket.extensions.markup.html.repeater.util.ProviderSubset;
 +import org.apache.wicket.markup.ComponentTag;
 +import org.apache.wicket.markup.head.IHeaderResponse;
 +import org.apache.wicket.markup.html.form.Button;
 +import org.apache.wicket.markup.html.form.ChoiceRenderer;
 +import org.apache.wicket.markup.html.form.DropDownChoice;
 +import org.apache.wicket.markup.html.form.Form;
 +import org.apache.wicket.markup.html.link.Link;
 +import org.apache.wicket.model.AbstractReadOnlyModel;
 +import org.apache.wicket.model.IDetachable;
 +import org.apache.wicket.model.IModel;
 +import org.apache.wicket.model.PropertyModel;
 +
 +/**
 + * @author Sven Meier
 + */
 +public abstract class TreePage extends WicketExamplePage
 +{
 +
 +	private static final long serialVersionUID = 1L;
 +
 +	private Behavior theme;
 +
 +	private AbstractTree<Foo> tree;
 +
 +	private FooProvider provider = new FooProvider();
 +
 +	private Set<Foo> state = new ProviderSubset<Foo>(provider);
 +
 +	private Content content;
 +
 +	private List<Content> contents;
 +
 +	private List<Behavior> themes;
 +
 +	/**
 +	 * Construct.
 +	 */
 +	public TreePage()
 +	{
 +		content = new CheckedFolderContent(provider);
 +
 +		Form<Void> form = new Form<Void>("form");
 +		add(form);
 +
 +		tree = createTree(provider, newStateModel());
 +		tree.add(new Behavior()
 +		{
 +			private static final long serialVersionUID = 1L;
 +
 +			@Override
 +			public void onComponentTag(Component component, ComponentTag tag)
 +			{
 +				theme.onComponentTag(component, tag);
 +			}
 +
 +			@Override
 +			public void renderHead(Component component, IHeaderResponse response)
 +			{
 +				theme.renderHead(component, response);
 +			}
 +		});
 +		form.add(tree);
 +
 +		form.add(new DropDownChoice<Content>("content",
 +			new PropertyModel<Content>(this, "content"), initContents(),
 +			new ChoiceRenderer<Content>("class.simpleName"))
 +		{
 +			private static final long serialVersionUID = 1L;
 +
 +			@Override
 +			protected boolean wantOnSelectionChangedNotifications()
 +			{
 +				return true;
 +			}
 +		});
 +
 +		form.add(new DropDownChoice<Behavior>("theme", new PropertyModel<Behavior>(this, "theme"),
 +			initThemes(), new ChoiceRenderer<Behavior>("class.simpleName"))
 +		{
 +			private static final long serialVersionUID = 1L;
 +
 +			@Override
 +			protected boolean wantOnSelectionChangedNotifications()
 +			{
 +				return true;
 +			}
 +		});
 +
 +		form.add(new Link<Void>("expandAll")
 +		{
 +			private static final long serialVersionUID = 1L;
 +
 +			@Override
 +			public void onClick()
 +			{
 +				((IDetachable)state).detach();
 +				state = new InverseSet<Foo>(new ProviderSubset<Foo>(provider));
 +			}
 +		});
 +
 +		form.add(new Link<Void>("collapseAll")
 +		{
 +			private static final long serialVersionUID = 1L;
 +
 +			@Override
 +			public void onClick()
 +			{
 +				((IDetachable)state).detach();
 +				state = new ProviderSubset<Foo>(provider);
 +			}
 +		});
 +
 +		form.add(new Button("submit")
 +		{
 +			private static final long serialVersionUID = 1L;
 +
 +			@Override
 +			public void onSubmit()
 +			{
 +			}
 +		});
 +	}
 +
 +	private IModel<Set<Foo>> newStateModel()
 +	{
 +		return new AbstractReadOnlyModel<Set<Foo>>()
 +		{
 +			private static final long serialVersionUID = 1L;
 +
 +			@Override
 +			public Set<Foo> getObject()
 +			{
 +				return state;
 +			}
 +
 +			@Override
 +			public void detach()
 +			{
 +				((IDetachable)state).detach();
 +			}
 +		};
 +	}
 +
 +	protected abstract AbstractTree<Foo> createTree(FooProvider provider, IModel<Set<Foo>> state);
 +
 +	private List<Content> initContents()
 +	{
 +		contents = new ArrayList<Content>();
 +
 +		contents.add(new BookmarkableFolderContent(tree));
 +		contents.add(new LabelContent());
 +		contents.add(new MultiLineLabelContent());
 +		contents.add(new FolderContent());
 +		contents.add(new EditableFolderContent());
 +		contents.add(new SelectableFolderContent(provider));
 +		contents.add(new MultiSelectableFolderContent(provider));
 +		contents.add(new CheckedFolderContent(provider));
 +		contents.add(new CheckedSelectableFolderContent(provider));
 +		contents.add(new PanelContent());
 +		contents.add(new MixedContent(contents));
 +
 +		content = contents.get(0);
 +
 +		return contents;
 +	}
 +
 +	private List<Behavior> initThemes()
 +	{
 +		themes = new ArrayList<Behavior>();
 +
 +		themes.add(new WindowsTheme());
 +		themes.add(new HumanTheme());
 +
 +		theme = themes.get(0);
 +
 +		return themes;
 +	}
 +
 +	@Override
 +	public void detachModels()
 +	{
 +		for (Content content : contents)
 +		{
 +			content.detach();
 +		}
 +
 +		super.detachModels();
 +	}
 +
 +	protected Component newContentComponent(String id, IModel<Foo> model)
 +	{
 +		return content.newContentComponent(id, tree, model);
 +	}
 +}

http://git-wip-us.apache.org/repos/asf/wicket/blob/31726809/wicket-examples/src/main/java/org/apache/wicket/examples/tree/content/CheckedFolderContent.java
----------------------------------------------------------------------
diff --cc wicket-examples/src/main/java/org/apache/wicket/examples/tree/content/CheckedFolderContent.java
index b988b6c,0000000..2c393fe
mode 100644,000000..100644
--- a/wicket-examples/src/main/java/org/apache/wicket/examples/tree/content/CheckedFolderContent.java
+++ b/wicket-examples/src/main/java/org/apache/wicket/examples/tree/content/CheckedFolderContent.java
@@@ -1,96 -1,0 +1,96 @@@
 +/*
 + * 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.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.CheckedFolder;
- import org.apache.wicket.extensions.markup.html.repeater.tree.util.ProviderSubset;
++import org.apache.wicket.extensions.markup.html.repeater.util.ProviderSubset;
 +import org.apache.wicket.model.IModel;
 +
 +/**
 + * @author Sven Meier
 + */
 +public class CheckedFolderContent extends Content
 +{
 +
 +	private static final long serialVersionUID = 1L;
 +
 +	private ProviderSubset<Foo> checked;
 +
 +	public CheckedFolderContent(ITreeProvider<Foo> provider)
 +	{
 +		checked = new ProviderSubset<Foo>(provider, false);
 +	}
 +
 +	@Override
 +	public void detach()
 +	{
 +		checked.detach();
 +	}
 +
 +	protected boolean isChecked(Foo foo)
 +	{
 +		return checked.contains(foo);
 +	}
 +
 +	protected void check(Foo foo, boolean check)
 +	{
 +		if (check)
 +		{
 +			checked.add(foo);
 +		}
 +		else
 +		{
 +			checked.remove(foo);
 +		}
 +	}
 +
 +	@Override
 +	public Component newContentComponent(String id, final AbstractTree<Foo> tree, IModel<Foo> model)
 +	{
 +		return new CheckedFolder<Foo>(id, tree, model)
 +		{
 +			private static final long serialVersionUID = 1L;
 +
 +			@Override
 +			protected IModel<Boolean> newCheckBoxModel(final IModel<Foo> model)
 +			{
 +				return new IModel<Boolean>()
 +				{
 +					private static final long serialVersionUID = 1L;
 +
 +					public Boolean getObject()
 +					{
 +						return isChecked(model.getObject());
 +					}
 +
 +					public void setObject(Boolean object)
 +					{
 +						check(model.getObject(), object);
 +					}
 +
 +					public void detach()
 +					{
 +					}
 +				};
 +			}
 +		};
 +	}
 +}

http://git-wip-us.apache.org/repos/asf/wicket/blob/31726809/wicket-examples/src/main/java/org/apache/wicket/examples/tree/content/MultiSelectableFolderContent.java
----------------------------------------------------------------------
diff --cc wicket-examples/src/main/java/org/apache/wicket/examples/tree/content/MultiSelectableFolderContent.java
index 1579002,0000000..af99373
mode 100644,000000..100644
--- a/wicket-examples/src/main/java/org/apache/wicket/examples/tree/content/MultiSelectableFolderContent.java
+++ b/wicket-examples/src/main/java/org/apache/wicket/examples/tree/content/MultiSelectableFolderContent.java
@@@ -1,97 -1,0 +1,97 @@@
 +/*
 + * 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.extensions.markup.html.repeater.tree.util.ProviderSubset;
++import org.apache.wicket.extensions.markup.html.repeater.util.ProviderSubset;
 +import org.apache.wicket.model.IModel;
 +
 +/**
 + * @author Sven Meier
 + */
 +public class MultiSelectableFolderContent extends Content
 +{
 +
 +	private static final long serialVersionUID = 1L;
 +
 +	private ProviderSubset<Foo> selected;
 +
 +	public MultiSelectableFolderContent(ITreeProvider<Foo> provider)
 +	{
 +		selected = new ProviderSubset<Foo>(provider, false);
 +	}
 +
 +	@Override
 +	public void detach()
 +	{
 +		selected.detach();
 +	}
 +
 +	protected boolean isSelected(Foo foo)
 +	{
 +		return selected.contains(foo);
 +	}
 +
 +	protected void toggle(Foo foo, AbstractTree<Foo> tree, final AjaxRequestTarget target)
 +	{
 +		if (isSelected(foo))
 +		{
 +			selected.remove(foo);
 +		}
 +		else
 +		{
 +			selected.add(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)
 +			{
 +				MultiSelectableFolderContent.this.toggle(getModelObject(), tree, target);
 +			}
 +
 +			@Override
 +			protected boolean isSelected()
 +			{
 +				return MultiSelectableFolderContent.this.isSelected(getModelObject());
 +			}
 +		};
 +	}
 +}

http://git-wip-us.apache.org/repos/asf/wicket/blob/31726809/wicket-examples/src/test/java/org/apache/wicket/examples/tree/InverseSetTest.java
----------------------------------------------------------------------
diff --cc wicket-examples/src/test/java/org/apache/wicket/examples/tree/InverseSetTest.java
index 0000000,0000000..c0788a6
new file mode 100644
--- /dev/null
+++ b/wicket-examples/src/test/java/org/apache/wicket/examples/tree/InverseSetTest.java
@@@ -1,0 -1,0 +1,77 @@@
++/*
++ * 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;
++
++import java.util.HashSet;
++
++import junit.framework.Assert;
++
++import org.apache.wicket.model.IDetachable;
++import org.junit.Test;
++
++/**
++ * Test for {@link InverseSet}.
++ * 
++ * @author svenmeier
++ */
++public class InverseSetTest extends Assert
++{
++	private TestSet set;
++
++	/**
++	 * Construct.
++	 */
++	public InverseSetTest()
++	{
++		set = new TestSet();
++		set.add("A");
++	}
++
++	/**
++	 * Test contains.
++	 */
++	@Test
++	public void contains()
++	{
++		InverseSet<String> inverse = new InverseSet<String>(set);
++		assertFalse(inverse.contains("A"));
++		assertTrue(inverse.contains("B"));
++
++		inverse.remove("B");
++		assertFalse(inverse.contains("A"));
++		assertFalse(inverse.contains("B"));
++
++		inverse.add("A");
++		assertTrue(inverse.contains("A"));
++		assertFalse(inverse.contains("B"));
++
++		inverse.detach();
++		assertTrue(set.detached);
++	}
++
++	private class TestSet extends HashSet<String> implements IDetachable
++	{
++		private static final long serialVersionUID = 1L;
++
++		boolean detached = false;
++
++		public void detach()
++		{
++			detached = true;
++		}
++	}
++}

http://git-wip-us.apache.org/repos/asf/wicket/blob/31726809/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 2dd8425,0000000..464fa35
mode 100644,000000..100644
--- a/wicket-extensions/src/main/java/org/apache/wicket/extensions/markup/html/repeater/tree/AbstractTree.java
+++ b/wicket-extensions/src/main/java/org/apache/wicket/extensions/markup/html/repeater/tree/AbstractTree.java
@@@ -1,343 -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.extensions.markup.html.repeater.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());
++		updateBranch(t, getRequestCycle().find(AjaxRequestTarget.class));
 +	}
 +
 +	/**
 +	 * 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());
++		updateBranch(t, getRequestCycle().find(AjaxRequestTarget.class));
 +	}
 +
 +	/**
 +	 * 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/31726809/wicket-extensions/src/main/java/org/apache/wicket/extensions/markup/html/repeater/util/ProviderSubset.java
----------------------------------------------------------------------
diff --cc wicket-extensions/src/main/java/org/apache/wicket/extensions/markup/html/repeater/util/ProviderSubset.java
index 0000000,0000000..dd9d46e
new file mode 100644
--- /dev/null
+++ b/wicket-extensions/src/main/java/org/apache/wicket/extensions/markup/html/repeater/util/ProviderSubset.java
@@@ -1,0 -1,0 +1,242 @@@
++/*
++ * 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.util;
++
++import java.util.Collection;
++import java.util.HashSet;
++import java.util.Iterator;
++import java.util.Set;
++
++import org.apache.wicket.extensions.markup.html.repeater.tree.ITreeProvider;
++import org.apache.wicket.model.AbstractReadOnlyModel;
++import org.apache.wicket.model.IDetachable;
++import org.apache.wicket.model.IModel;
++
++/**
++ * A subset of a {@link ITreeProvider}'s tree offering automatic detachment.
++ * 
++ * Make sure that the containing model calls {@link IDetachable#detach()} on its model object.
++ * 
++ * @see ITreeProvider#model(Object)
++ * 
++ * @author svenmeier
++ */
++public class ProviderSubset<T> implements Set<T>, IDetachable
++{
++
++	private static final long serialVersionUID = 1L;
++
++	private ITreeProvider<T> provider;
++
++	private Set<IModel<T>> models = new HashSet<IModel<T>>();
++
++	/**
++	 * Create an empty subset.
++	 * 
++	 * @param provider
++	 *            the provider of the complete set
++	 */
++	public ProviderSubset(ITreeProvider<T> provider)
++	{
++		this(provider, false);
++	}
++
++	/**
++	 * Create a subset optionally containing all roots of the provider.
++	 * 
++	 * @param provider
++	 *            the provider of the complete set
++	 * @param addRoots
++	 *            should all roots be added to this subset
++	 */
++	public ProviderSubset(ITreeProvider<T> provider, boolean addRoots)
++	{
++		this.provider = provider;
++
++		if (addRoots)
++		{
++			Iterator<? extends T> roots = provider.getRoots();
++			while (roots.hasNext())
++			{
++				add(roots.next());
++			}
++		}
++	}
++
++	public void detach()
++	{
++		for (IModel<T> model : models)
++		{
++			model.detach();
++		}
++	}
++
++	public int size()
++	{
++		return models.size();
++	}
++
++	public boolean isEmpty()
++	{
++		return models.size() == 0;
++	}
++
++	public void clear()
++	{
++		detach();
++
++		models.clear();
++	}
++
++	public boolean contains(Object o)
++	{
++		IModel<T> model = model(o);
++
++		boolean contains = models.contains(model);
++
++		model.detach();
++
++		return contains;
++	}
++
++	public boolean add(T t)
++	{
++		return models.add(model(t));
++	}
++
++	public boolean remove(Object o)
++	{
++		IModel<T> model = model(o);
++
++		boolean removed = models.remove(model);
++
++		model.detach();
++
++		return removed;
++	}
++
++	public Iterator<T> iterator()
++	{
++		return new Iterator<T>()
++		{
++
++			private Iterator<IModel<T>> iterator = models.iterator();
++
++			private IModel<T> current;
++
++			public boolean hasNext()
++			{
++				return iterator.hasNext();
++			}
++
++			public T next()
++			{
++				current = iterator.next();
++
++				return current.getObject();
++			}
++
++			public void remove()
++			{
++				iterator.remove();
++
++				current.detach();
++				current = null;
++			}
++		};
++	}
++
++	public boolean addAll(Collection<? extends T> ts)
++	{
++		boolean changed = false;
++
++		for (T t : ts)
++		{
++			changed |= add(t);
++		}
++
++		return changed;
++	}
++
++	public boolean containsAll(Collection<?> cs)
++	{
++		for (Object c : cs)
++		{
++			if (!contains(c))
++			{
++				return false;
++			}
++		}
++		return true;
++	}
++
++	public boolean removeAll(Collection<?> cs)
++	{
++		boolean changed = false;
++
++		for (Object c : cs)
++		{
++			changed |= remove(c);
++		}
++
++		return changed;
++	}
++
++	public boolean retainAll(Collection<?> c)
++	{
++		throw new UnsupportedOperationException();
++	}
++
++	public Object[] toArray()
++	{
++		throw new UnsupportedOperationException();
++	}
++
++	public <S> S[] toArray(S[] a)
++	{
++		throw new UnsupportedOperationException();
++	}
++
++	@SuppressWarnings("unchecked")
++	private IModel<T> model(Object o)
++	{
++		return provider.model((T)o);
++	}
++
++	/**
++	 * Create a model holding this set.
++	 * 
++	 * @return model
++	 */
++	public IModel<Set<T>> createModel()
++	{
++		return new AbstractReadOnlyModel<Set<T>>()
++		{
++			@Override
++			public Set<T> getObject()
++			{
++				return ProviderSubset.this;
++			}
++
++			@Override
++			public void detach()
++			{
++				ProviderSubset.this.detach();
++			}
++		};
++	}
++}

http://git-wip-us.apache.org/repos/asf/wicket/blob/31726809/wicket-extensions/src/main/java/org/apache/wicket/extensions/markup/html/repeater/util/SortableTreeProvider.java
----------------------------------------------------------------------
diff --cc wicket-extensions/src/main/java/org/apache/wicket/extensions/markup/html/repeater/util/SortableTreeProvider.java
index 0000000,0000000..9260508
new file mode 100644
--- /dev/null
+++ b/wicket-extensions/src/main/java/org/apache/wicket/extensions/markup/html/repeater/util/SortableTreeProvider.java
@@@ -1,0 -1,0 +1,95 @@@
++/*
++ * 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.util;
++
++import org.apache.wicket.extensions.markup.html.repeater.data.sort.ISortState;
++import org.apache.wicket.extensions.markup.html.repeater.data.table.ISortableDataProvider;
++import org.apache.wicket.extensions.markup.html.repeater.tree.ISortableTreeProvider;
++
++/**
++ * Convenience implementation of a tree provider that can also act as a locator for a
++ * {@link SingleSortState} object.
++ * 
++ * @author svenmeier
++ */
++public abstract class SortableTreeProvider<T> implements ISortableTreeProvider<T>
++{
++	private SingleSortState state = new SingleSortState();
++
++	/**
++	 * @see ISortableDataProvider#getSortState()
++	 */
++	public final ISortState getSortState()
++	{
++		return state;
++	}
++
++	/**
++	 * @see ISortableDataProvider#setSortState(org.apache.wicket.extensions.markup.html.repeater.data.sort.ISortState)
++	 */
++	public final void setSortState(ISortState state)
++	{
++		if (!(state instanceof SingleSortState))
++		{
++			throw new IllegalArgumentException(
++				"argument [state] must be an instance of SingleSortState, but it is [" +
++					state.getClass().getName() + "]:[" + state.toString() + "]");
++		}
++		this.state = (SingleSortState)state;
++	}
++
++	/**
++	 * Returns current sort state
++	 * 
++	 * @return current sort state
++	 */
++	public SortParam getSort()
++	{
++		return state.getSort();
++	}
++
++	/**
++	 * Sets the current sort state
++	 * 
++	 * @param param
++	 *            parameter containing new sorting information
++	 */
++	public void setSort(SortParam param)
++	{
++		state.setSort(param);
++	}
++
++	/**
++	 * Sets the current sort state
++	 * 
++	 * @param property
++	 *            sort property
++	 * @param ascending
++	 *            sort direction
++	 */
++	public void setSort(String property, boolean ascending)
++	{
++		setSort(new SortParam(property, ascending));
++	}
++
++	/**
++	 * @see ISortableDataProvider#detach()
++	 */
++	public void detach()
++	{
++	}
++}

http://git-wip-us.apache.org/repos/asf/wicket/blob/31726809/wicket-extensions/src/main/java/org/apache/wicket/extensions/markup/html/repeater/util/TreeModelProvider.java
----------------------------------------------------------------------
diff --cc wicket-extensions/src/main/java/org/apache/wicket/extensions/markup/html/repeater/util/TreeModelProvider.java
index 0000000,0000000..9816d76
new file mode 100644
--- /dev/null
+++ b/wicket-extensions/src/main/java/org/apache/wicket/extensions/markup/html/repeater/util/TreeModelProvider.java
@@@ -1,0 -1,0 +1,258 @@@
++/*
++ * 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.util;
++
++import java.io.Serializable;
++import java.util.ArrayList;
++import java.util.Iterator;
++import java.util.List;
++
++import javax.swing.event.TreeModelEvent;
++import javax.swing.event.TreeModelListener;
++import javax.swing.tree.TreeModel;
++
++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.ITreeProvider;
++import org.apache.wicket.model.IModel;
++
++/**
++ * A provider wrapping a Swing {@link TreeModel}.
++ * 
++ * EXPERIMENTAL !
++ * 
++ * @author svenmeier
++ * @param <T>
++ *            model object type
++ */
++public abstract class TreeModelProvider<T> implements ITreeProvider<T>
++{
++
++	private static final long serialVersionUID = 1L;
++
++	private final TreeModel treeModel;
++
++	private final boolean rootVisible;
++
++	protected boolean completeUpdate;
++
++	protected List<T> nodeUpdates;
++
++	protected List<T> branchUpdates;
++
++	/**
++	 * Wrap the given {@link TreeModel}.
++	 * 
++	 * @param treeModel
++	 *            model to wrap
++	 */
++	public TreeModelProvider(TreeModel treeModel)
++	{
++		this(treeModel, true);
++	}
++
++	/**
++	 * Wrap the given {@link TreeModel}.
++	 * 
++	 * @param treeModel
++	 *            the wrapped model
++	 * @param rootVisible
++	 *            should the root be visible
++	 */
++	public TreeModelProvider(TreeModel treeModel, boolean rootVisible)
++	{
++		this.treeModel = treeModel;
++		this.rootVisible = rootVisible;
++
++		treeModel.addTreeModelListener(new Listener());
++	}
++
++	public Iterator<T> getRoots()
++	{
++		if (rootVisible)
++		{
++			return new Iterator<T>()
++			{
++				boolean next = true;
++
++				public boolean hasNext()
++				{
++					return next;
++				}
++
++				public T next()
++				{
++					next = false;
++					return cast(treeModel.getRoot());
++				}
++
++				public void remove()
++				{
++					throw new UnsupportedOperationException();
++				}
++			};
++		}
++		else
++		{
++			return getChildren(cast(treeModel.getRoot()));
++		}
++	}
++
++	public boolean hasChildren(T object)
++	{
++		return !treeModel.isLeaf(object);
++	}
++
++	public Iterator<T> getChildren(final T object)
++	{
++		return new Iterator<T>()
++		{
++			private int size = treeModel.getChildCount(object);
++			private int index = -1;
++
++			public boolean hasNext()
++			{
++				return index < size - 1;
++			}
++
++			public T next()
++			{
++				index++;
++				return cast(treeModel.getChild(object, index));
++			}
++
++			public void remove()
++			{
++				throw new UnsupportedOperationException();
++			}
++		};
++	}
++
++	@SuppressWarnings("unchecked")
++	protected T cast(Object object)
++	{
++		return (T)object;
++	}
++
++	public abstract IModel<T> model(T object);
++
++	public void detach()
++	{
++		completeUpdate = false;
++		nodeUpdates = null;
++		branchUpdates = null;
++	}
++
++	/**
++	 * Call this method after all change to the wrapped {@link TreeModel} being initiated via
++	 * {@link AjaxRequestTarget}.
++	 * 
++	 * @param tree
++	 *            the tree utilizing this {@link ITreeProvider}
++	 * @param target
++	 *            the {@link AjaxRequestTarget} which initiated the changes
++	 */
++	public void update(AbstractTree<T> tree, AjaxRequestTarget target)
++	{
++		if (completeUpdate)
++		{
++			target.add(tree);
++		}
++		else
++		{
++			if (nodeUpdates != null)
++			{
++				for (T object : nodeUpdates)
++				{
++					tree.updateNode(object, target);
++				}
++			}
++
++			if (branchUpdates != null)
++			{
++				for (T object : branchUpdates)
++				{
++					tree.updateBranch(object, target);
++				}
++			}
++		}
++
++		detach();
++	}
++
++	protected void nodeUpdate(Object[] nodes)
++	{
++		if (nodeUpdates == null)
++		{
++			nodeUpdates = new ArrayList<T>();
++		}
++
++		for (Object node : nodes)
++		{
++			nodeUpdates.add(cast(node));
++		}
++	}
++
++	protected void branchUpdate(Object branch)
++	{
++		if (branchUpdates == null)
++		{
++			branchUpdates = new ArrayList<T>();
++		}
++
++		branchUpdates.add(cast(branch));
++	}
++
++	private class Listener implements TreeModelListener, Serializable
++	{
++		private static final long serialVersionUID = 1L;
++
++		public void treeNodesChanged(TreeModelEvent e)
++		{
++			if (e.getChildIndices() == null)
++			{
++				completeUpdate = true;
++			}
++			else
++			{
++				nodeUpdate(e.getChildren());
++			}
++		}
++
++		public void treeNodesInserted(TreeModelEvent e)
++		{
++			branchUpdate(e.getTreePath().getLastPathComponent());
++		}
++
++		public void treeNodesRemoved(TreeModelEvent e)
++		{
++			branchUpdate(e.getTreePath().getLastPathComponent());
++		}
++
++		public void treeStructureChanged(TreeModelEvent e)
++		{
++			if (e.getTreePath().getPathCount() == 1)
++			{
++				completeUpdate = true;
++			}
++			else
++			{
++				branchUpdate(e.getTreePath().getLastPathComponent());
++			}
++		}
++	}
++}