package fr.openwide.core.wicket.more.markup.repeater; import java.util.Iterator; import org.apache.wicket.Component; import org.apache.wicket.DequeueContext; import org.apache.wicket.DequeueContext.Bookmark; import org.apache.wicket.MarkupContainer; import org.apache.wicket.markup.IMarkupFragment; import org.apache.wicket.markup.html.WebMarkupContainer; import org.apache.wicket.markup.repeater.AbstractRepeater; import org.apache.wicket.markup.repeater.RepeatingView; import fr.openwide.core.wicket.more.markup.html.factory.IComponentFactory; import fr.openwide.core.wicket.more.markup.html.factory.IOneParameterComponentFactory; public class FactoryRepeatingView extends RepeatingView implements IRefreshableOnDemandRepeater { private static final long serialVersionUID = -5285541426332338090L; public FactoryRepeatingView(String id) { super(id); } @Override protected void onInitialize() { super.onInitialize(); getParent().setOutputMarkupId(true); } @Override public void refreshItems() { // Nothing to do : items have already been added or removed. } /** * Wraps the components before adding them to the view, so the uniqueness of their ID is no longer relevant. * <p>This allows to add components to this view without worrying at all about what their ID should be. */ public void addWrapped(Component ... components) { for (Component componentToWrap : components) { Wrapper wrapper = new Wrapper(newChildId()); wrapper.add(componentToWrap); add(wrapper); } } private static final class Wrapper extends WebMarkupContainer { private static final long serialVersionUID = 1L; public Wrapper(String id) { super(id); } @Override public MarkupContainer remove(Component componentToRemove) { MarkupContainer result = super.remove(componentToRemove); // Remove the wrapper if the child is removed if (size() == 0) { remove(); } return result; } /** * @see AbstractRepeater#dequeue() */ @Override protected final void onRender() { Iterator<? extends Component> it = iterator(); while (it.hasNext()) { Component child = it.next(); if (child == null) { throw new IllegalStateException("The render iterator returned null for a child. Container: " + this.toString() + "; Iterator=" + it.toString()); } child.render(); } } /** * @see AbstractRepeater#dequeue() */ @Override public IMarkupFragment getMarkup(final Component child) { return getMarkup(); } /** * @see AbstractRepeater#dequeue() */ @Override public void dequeue(DequeueContext dequeue) { if (size() > 0) { Bookmark bookmark = dequeue.save(); for (Component child : this) { if (child instanceof MarkupContainer) { dequeue.popContainer(); // pop the repeater MarkupContainer container = (MarkupContainer) child; dequeue.pushContainer(container); container.dequeue(dequeue); dequeue.restore(bookmark); } } } dequeue.skipToCloseTag(); } } public <T extends Component> T add(IComponentFactory<T> componentFactory) { T component = componentFactory.create(newChildId()); add(component); return component; } public <T extends Component, P> T add(IOneParameterComponentFactory<T, P> componentFactory, P parameter) { T component = componentFactory.create(newChildId(), parameter); add(component); return component; } public void addAll(Iterable<? extends IComponentFactory<?>> factories) { for (IComponentFactory<?> componentFactory : factories) { add(componentFactory); } } public <P> void addAll(Iterable<? extends IOneParameterComponentFactory<?, ? super P>> factories, P parameter) { for (IOneParameterComponentFactory<?, ? super P> componentFactory : factories) { add(componentFactory, parameter); } } }