You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@wicket.apache.org by iv...@apache.org on 2014/02/16 06:56:23 UTC
git commit: dequeue docs
Repository: wicket
Updated Branches:
refs/heads/sandbox/component-queueing-2 384d748c1 -> 3a3e32a59
dequeue docs
Project: http://git-wip-us.apache.org/repos/asf/wicket/repo
Commit: http://git-wip-us.apache.org/repos/asf/wicket/commit/3a3e32a5
Tree: http://git-wip-us.apache.org/repos/asf/wicket/tree/3a3e32a5
Diff: http://git-wip-us.apache.org/repos/asf/wicket/diff/3a3e32a5
Branch: refs/heads/sandbox/component-queueing-2
Commit: 3a3e32a597aa312f97cc588a66780783cd0eb9ed
Parents: 384d748
Author: Igor Vaynberg <ig...@gmail.com>
Authored: Sat Feb 15 21:56:18 2014 -0800
Committer: Igor Vaynberg <ig...@gmail.com>
Committed: Sat Feb 15 21:56:18 2014 -0800
----------------------------------------------------------------------
.../java/org/apache/wicket/DequeueContext.java | 68 ++++++-
.../java/org/apache/wicket/IQueueRegion.java | 22 ++-
.../java/org/apache/wicket/MarkupContainer.java | 190 ++++++++++---------
.../wicket/markup/html/border/Border.java | 8 +-
.../markup/repeater/AbstractRepeater.java | 4 +
5 files changed, 188 insertions(+), 104 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/wicket/blob/3a3e32a5/wicket-core/src/main/java/org/apache/wicket/DequeueContext.java
----------------------------------------------------------------------
diff --git a/wicket-core/src/main/java/org/apache/wicket/DequeueContext.java b/wicket-core/src/main/java/org/apache/wicket/DequeueContext.java
index 4e62c3e..c13b0f2 100644
--- a/wicket-core/src/main/java/org/apache/wicket/DequeueContext.java
+++ b/wicket-core/src/main/java/org/apache/wicket/DequeueContext.java
@@ -2,19 +2,26 @@ package org.apache.wicket;
import org.apache.wicket.markup.ComponentTag;
import org.apache.wicket.markup.IMarkupFragment;
-import org.apache.wicket.markup.Markup;
import org.apache.wicket.markup.MarkupElement;
import org.apache.wicket.util.collections.ArrayListStack;
-public class DequeueContext
+/**
+ * Context for component dequeueing. Keeps track of markup position and container stack.
+ *
+ * @author igor
+ *
+ */
+public final class DequeueContext
{
private final IMarkupFragment markup;
private int index;
private ComponentTag next;
private ArrayListStack<ComponentTag> tags = new ArrayListStack<>();
+
private ArrayListStack<MarkupContainer> containers = new ArrayListStack<>();
- public static class Bookmark
+ /** A bookmark for the DequeueContext stack */
+ public static final class Bookmark
{
private final int index;
private final ComponentTag next;
@@ -45,21 +52,39 @@ public class DequeueContext
next=nextTag();
}
+ /**
+ * Saves the state of the context into a bookmark which can later be used to restore it.
+ */
public Bookmark save()
{
return new Bookmark(this);
}
+ /**
+ * Restores the state of the context from the bookmark
+ *
+ * @param bookmark
+ */
public void restore(Bookmark bookmark)
{
bookmark.restore(this);
}
+ /**
+ * Peeks markup tag that would be retrieved by call to {@link #popTag()}
+ *
+ * @return
+ */
public ComponentTag peekTag()
{
return next;
}
+ /**
+ * Retrieves the next markup tag
+ *
+ * @return
+ */
public ComponentTag popTag()
{
ComponentTag taken=next;
@@ -68,6 +93,9 @@ public class DequeueContext
return taken;
}
+ /**
+ * Skips to the closing tag of the tag retrieved from last call to {@link #popTag()}
+ */
public void skipToCloseTag()
{
if (tags.peek().isOpen())
@@ -89,7 +117,7 @@ public class DequeueContext
{
ComponentTag tag = (ComponentTag)element;
ComponentTag open = tag.isClose() ? tag.getOpenTag() : tag;
- if (canDequeue(open))
+ if (canDequeueTag(open))
{
index++;
return tag;
@@ -99,7 +127,7 @@ public class DequeueContext
return null;
}
- private boolean canDequeue(ComponentTag open)
+ private boolean canDequeueTag(ComponentTag open)
{
if (containers.size() < 1)
{
@@ -108,7 +136,7 @@ public class DequeueContext
}
for (int i = containers.size() - 1; i >= 0; i--)
{
- if (containers.get(i).supportsDequeueingFrom((open)))
+ if (containers.get(i).canDequeueTag((open)))
{
return true;
}
@@ -116,27 +144,53 @@ public class DequeueContext
return false;
}
+ /**
+ * Checks if the tag returned by {@link #peekTag()} is either open or open-close.
+ *
+ * @return
+ */
public boolean isAtOpenOrOpenCloseTag()
{
return peekTag() != null && (peekTag().isOpen() || peekTag().isOpenClose());
}
+ /**
+ * Retrieves the container on the top of the containers stack
+ *
+ * @return
+ */
public MarkupContainer peekContainer()
{
return containers.peek();
}
+ /**
+ * Pushes a container onto the container stack
+ *
+ * @param container
+ */
public void pushContainer(MarkupContainer container)
{
containers.push(container);
}
+ /**
+ * Pops a container from the container stack
+ *
+ * @return
+ */
public MarkupContainer popContainer()
{
return containers.pop();
}
- public Component dequeue(ComponentTag tag)
+ /**
+ * Searches the container stack for a component that can be dequeud
+ *
+ * @param tag
+ * @return
+ */
+ public Component findComponentToDequeue(ComponentTag tag)
{
for (int j = containers.size() - 1; j >= 0; j--)
{
http://git-wip-us.apache.org/repos/asf/wicket/blob/3a3e32a5/wicket-core/src/main/java/org/apache/wicket/IQueueRegion.java
----------------------------------------------------------------------
diff --git a/wicket-core/src/main/java/org/apache/wicket/IQueueRegion.java b/wicket-core/src/main/java/org/apache/wicket/IQueueRegion.java
index 86e30c6..beebdda 100644
--- a/wicket-core/src/main/java/org/apache/wicket/IQueueRegion.java
+++ b/wicket-core/src/main/java/org/apache/wicket/IQueueRegion.java
@@ -16,9 +16,11 @@
*/
package org.apache.wicket;
+import org.apache.wicket.markup.IMarkupFragment;
+
/**
- * Demarcates components that can dequeue children. These are usually components with associated
- * markup since the markup is needed to dequeue.
+ * Demarcates components that act as a root can dequeue children. These are usually components with
+ * associated markup since the markup is needed to dequeue.
*
* It is also important to note that components queued outside of a region cannot be dequeued into
* it since regions act as roots for the dequeue process because they contain the markup. As such,
@@ -30,5 +32,21 @@ package org.apache.wicket;
*/
public interface IQueueRegion
{
+ /**
+ * Gets the markup that will be used to dequeue components in this container. Usually containers
+ * will return their associated markup by simply delegating to
+ * {@link MarkupContainer#getAssociatedMarkup()}, but compoennts that do not render markup in a
+ * standard way (such as repeaters and borders) may choose to override this method to implement
+ * custom behavior for the dequeuing process.
+ */
+ public IMarkupFragment getDequeueMarkup();
+ /**
+ * Starts component dequeueing on this {@link IQueueRegion}. This is the entry point into the
+ * dequeuing process, it creates the {@link DequeueContext} and delegates the opreation to the
+ * {@link #dequeue(DequeueContext)} method which performs the actual dequeuing. The context's
+ * markup is retrieved using the {@link #getDequeueMarkup()} method which allows subclasses to
+ * provide dequeueing-specific markup.
+ */
+ public void dequeue();
}
http://git-wip-us.apache.org/repos/asf/wicket/blob/3a3e32a5/wicket-core/src/main/java/org/apache/wicket/MarkupContainer.java
----------------------------------------------------------------------
diff --git a/wicket-core/src/main/java/org/apache/wicket/MarkupContainer.java b/wicket-core/src/main/java/org/apache/wicket/MarkupContainer.java
index e213f35..3fe7c98 100644
--- a/wicket-core/src/main/java/org/apache/wicket/MarkupContainer.java
+++ b/wicket-core/src/main/java/org/apache/wicket/MarkupContainer.java
@@ -36,13 +36,11 @@ import org.apache.wicket.markup.MarkupType;
import org.apache.wicket.markup.WicketTag;
import org.apache.wicket.markup.html.border.Border;
import org.apache.wicket.markup.html.internal.InlineEnclosure;
-import org.apache.wicket.markup.repeater.AbstractRepeater;
import org.apache.wicket.markup.resolver.ComponentResolvers;
import org.apache.wicket.model.IComponentInheritedModel;
import org.apache.wicket.model.IModel;
import org.apache.wicket.model.IWrapModel;
import org.apache.wicket.settings.DebugSettings;
-import org.apache.wicket.util.collections.ArrayListStack;
import org.apache.wicket.util.io.IClusterable;
import org.apache.wicket.util.iterator.ComponentHierarchyIterator;
import org.apache.wicket.util.lang.Args;
@@ -1519,22 +1517,28 @@ public abstract class MarkupContainer extends Component implements Iterable<Comp
super.onInitialize();
if (this instanceof IQueueRegion)
{
- // dequeue auto components
- Markup markup = getAssociatedMarkup();
- if (markup != null)
+ // if this container is a queue region dequeue any queued up auto components
+ dequeueAutoComponents();
+ }
+ }
+
+ private void dequeueAutoComponents()
+ {
+ // dequeue auto components
+ IMarkupFragment markup = getDequeueMarkup();
+ if (markup != null)
+ {
+ // make sure we have markup, when running inside tests we wont
+ for (int i = 0; i < markup.size(); i++)
{
- // make sure we have markup, when running inside tests we wont
- for (int i = 0; i < markup.size(); i++)
+ MarkupElement element = markup.get(i);
+ if (element instanceof ComponentTag)
{
- MarkupElement element = markup.get(i);
- if (element instanceof ComponentTag)
+ ComponentTag tag = (ComponentTag)element;
+ if (tag.getAutoComponentFactory() != null)
{
- ComponentTag tag = (ComponentTag)element;
- if (tag.getAutoComponentFactory() != null)
- {
- Component auto = tag.getAutoComponentFactory().newComponent(tag);
- queue(auto);
- }
+ Component auto = tag.getAutoComponentFactory().newComponent(tag);
+ queue(auto);
}
}
}
@@ -1952,55 +1956,6 @@ public abstract class MarkupContainer extends Component implements Iterable<Comp
}
}
- /**
- * Automatically create components for <wicket:xxx> tag.
- */
- // to use it call it from #onInitialize()
- private void createAndAddComponentsForWicketTags()
- {
- // Markup must be available
- IMarkupFragment markup = getMarkup();
- if ((markup != null) && (markup.size() > 1))
- {
- MarkupStream stream = new MarkupStream(markup);
-
- // Skip the first component tag which already belongs to 'this' container
- if (stream.skipUntil(ComponentTag.class))
- {
- stream.next();
- }
-
- // Search for <wicket:xxx> in the remaining markup and try to resolve the component
- while (stream.skipUntil(ComponentTag.class))
- {
- ComponentTag tag = stream.getTag();
- if (tag.isOpen() || tag.isOpenClose())
- {
- if (tag instanceof WicketTag)
- {
- Component component = ComponentResolvers.resolve(this, stream, tag, null);
- if ((component != null) && (component.getParent() == null))
- {
- if (component.getId().equals(tag.getId()) == false)
- {
- // make sure we are able to get() the component during rendering
- tag.setId(component.getId());
- tag.setModified(true);
- }
- add(component);
- }
- }
-
- if (tag.isOpen())
- {
- stream.skipToMatchingCloseTag(tag);
- }
- }
- stream.next();
- }
- }
- }
-
@Override
protected void onDetach()
{
@@ -2017,6 +1972,17 @@ public abstract class MarkupContainer extends Component implements Iterable<Comp
private transient ComponentQueue queue;
+ /**
+ * Queues a component to be dequeued later. The advantage of this method over the
+ * {@link #add(Component...)} method is that the component does not have to be added to its
+ * direct parent, only to a parent upstream; it will be dequeued into the correct parent using
+ * the hierarchy defined in the markup. This allows the component hiearchy to be maintined only
+ * in markup instead of in markup and in java code; affording designers and developers more
+ * freedom when moving components in markup.
+ *
+ * @param components
+ * @return
+ */
public MarkupContainer queue(Component... components)
{
if (queue == null)
@@ -2054,7 +2020,10 @@ public abstract class MarkupContainer extends Component implements Iterable<Comp
return this;
}
- void dequeue()
+ /**
+ * @see IQueueRegion#dequeue()
+ */
+ public void dequeue()
{
if (!(this instanceof IQueueRegion))
{
@@ -2070,7 +2039,20 @@ public abstract class MarkupContainer extends Component implements Iterable<Comp
setRequestFlag(RFLAG_CONTAINER_DEQUEING, true);
try
{
- internalDequeue();
+ IMarkupFragment markup = getDequeueMarkup();
+ if (markup == null)
+ {
+ // markup not found, skip dequeuing
+ // this sometimes happens when we are in a unit test
+ return;
+ }
+
+ DequeueContext dequeue = new DequeueContext(markup, this);
+
+ if (dequeue.peekTag() != null)
+ {
+ dequeue(dequeue);
+ }
}
finally
{
@@ -2078,29 +2060,23 @@ public abstract class MarkupContainer extends Component implements Iterable<Comp
}
}
- private void internalDequeue()
- {
- IMarkupFragment markup = getDequeueMarkup();
- if (markup == null)
- {
- // markup not found, skip dequeuing
- // this sometimes happens when we are in a unit test
- return;
- }
-
- DequeueContext dequeue = new DequeueContext(markup, this);
-
- if (dequeue.peekTag() != null)
- {
- dequeue(dequeue);
- }
-
-
- }
+ /**
+ * Dequeues components. The default implementation iterates direct children of this container
+ * found in the markup (retrieved via {@link #getDequeueMarkup()}) and tries to find matching
+ * components in queues filled by a call to {@link #queue(Component...)}. It then delegates the
+ * dequeing to these children.
+ *
+ * The provided {@link DequeueContext} is used to maintain the place in markup as well as the
+ * stack of components whose queues will be searched. For example, before delegating the call to
+ * a child the container will push the child onto the stack of components.
+ *
+ * Certain components that implement custom markup behaviors (such as repeaters and borders)
+ * override this method to bring dequeuing in line with their custom markup handling.
+ *
+ * @param dequeue
+ */
public void dequeue(DequeueContext dequeue)
{
-
-
while (dequeue.isAtOpenOrOpenCloseTag())
{
@@ -2117,7 +2093,7 @@ public abstract class MarkupContainer extends Component implements Iterable<Comp
// the container does not yet have a child with this id, see if we can
// dequeue
- child = dequeue.dequeue(tag);
+ child = dequeue.findComponentToDequeue(tag);
if (child != null)
{
@@ -2154,17 +2130,28 @@ public abstract class MarkupContainer extends Component implements Iterable<Comp
throw new IllegalStateException();
}
}
-
-
}
}
- protected IMarkupFragment getDequeueMarkup() {
+ /** @see IQueueRegion#getDequeueMarkup() */
+ public IMarkupFragment getDequeueMarkup()
+ {
return getAssociatedMarkup();
}
- protected boolean supportsDequeueingFrom(ComponentTag tag) {
+ /**
+ * Checks if this container can dequeue a child represented by the specified tag. This method
+ * should be overridden when containers can dequeue components represented by non-standard tags.
+ * For example, borders override this method and dequeue their body container when processing
+ * the body tag.
+ *
+ * By default all {@link ComponentTag}s are supported as well as {@link WicketTag}s that return
+ * a non-null value from {@link WicketTag#getAutoComponentFactory()} method.
+ *
+ * @param tag
+ */
+ protected boolean canDequeueTag(ComponentTag tag) {
if (tag instanceof WicketTag) {
WicketTag wicketTag=(WicketTag)tag;
if (wicketTag.getAutoComponentFactory() != null)
@@ -2177,11 +2164,30 @@ public abstract class MarkupContainer extends Component implements Iterable<Comp
return true;
}
+ /**
+ * Queries this container to find a child that can be dequeued that matches the specified tag.
+ * The default implementation will check if there is a component in the queue that has the same
+ * id as a tag, but sometimes custom tags can be dequeued and in those situations this method
+ * should be overridden.
+ *
+ * @param tag
+ * @return
+ */
public Component findComponentToDequeue(ComponentTag tag)
{
return queue == null ? null : queue.remove(tag.getId());
}
+ /**
+ * Adds a dequeued component to this container. This method should rarely be overridden becase
+ * the common case of simply forwarding the component to
+ * {@link MarkupContainer#add(Component...))} method should cover most cases. Components that
+ * implement a custom hierarchy, such as borders, may wish to override it to support edge-case
+ * non-standard behavior.
+ *
+ * @param component
+ * @param tag
+ */
protected void addDequeuedComponent(Component component, ComponentTag tag) {
add(component);
}
http://git-wip-us.apache.org/repos/asf/wicket/blob/3a3e32a5/wicket-core/src/main/java/org/apache/wicket/markup/html/border/Border.java
----------------------------------------------------------------------
diff --git a/wicket-core/src/main/java/org/apache/wicket/markup/html/border/Border.java b/wicket-core/src/main/java/org/apache/wicket/markup/html/border/Border.java
index 54fa141..e916d18 100644
--- a/wicket-core/src/main/java/org/apache/wicket/markup/html/border/Border.java
+++ b/wicket-core/src/main/java/org/apache/wicket/markup/html/border/Border.java
@@ -537,7 +537,8 @@ public abstract class Border extends WebMarkupContainer implements IComponentRes
return markup.find(child.getId());
}
- protected IMarkupFragment getDequeueMarkup() {
+ public IMarkupFragment getDequeueMarkup()
+ {
Border border=findParent(Border.class);
IMarkupFragment fragment=findParent(Border.class).getMarkup();
/*
@@ -614,12 +615,12 @@ public abstract class Border extends WebMarkupContainer implements IComponentRes
@Override
- protected boolean supportsDequeueingFrom(ComponentTag tag) {
+ protected boolean canDequeueTag(ComponentTag tag) {
if ((tag instanceof WicketTag)&&((WicketTag)tag).isBodyTag()) {
return true;
}
- return super.supportsDequeueingFrom(tag);
+ return super.canDequeueTag(tag);
}
@Override
@@ -632,6 +633,7 @@ public abstract class Border extends WebMarkupContainer implements IComponentRes
@Override
protected void addDequeuedComponent(Component component, ComponentTag tag) {
+ // components queued in border get dequeued into the border not into the body container
addToBorder(component);
}
}
http://git-wip-us.apache.org/repos/asf/wicket/blob/3a3e32a5/wicket-core/src/main/java/org/apache/wicket/markup/repeater/AbstractRepeater.java
----------------------------------------------------------------------
diff --git a/wicket-core/src/main/java/org/apache/wicket/markup/repeater/AbstractRepeater.java b/wicket-core/src/main/java/org/apache/wicket/markup/repeater/AbstractRepeater.java
index 134e239..2b1a4bb 100644
--- a/wicket-core/src/main/java/org/apache/wicket/markup/repeater/AbstractRepeater.java
+++ b/wicket-core/src/main/java/org/apache/wicket/markup/repeater/AbstractRepeater.java
@@ -157,6 +157,10 @@ public abstract class AbstractRepeater extends WebMarkupContainer
@Override
public void dequeue(DequeueContext dequeue) {
if (size()>0) {
+ // essentially what we do is for every child replace the repeater with the child in
+ // dequeue container stack and run the dequeue on the child. we also take care to reset
+ // the state of the dequeue context after we process every child.
+
Bookmark bookmark=dequeue.save();
for (Component child:this) {