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 2012/01/08 06:23:23 UTC
git commit: queuing: bring code from hierarchy-completion branch sans
resolver support
Updated Branches:
refs/heads/sandbox/queueing b3d52388b -> 30162c67c
queuing: bring code from hierarchy-completion branch sans resolver support
Project: http://git-wip-us.apache.org/repos/asf/wicket/repo
Commit: http://git-wip-us.apache.org/repos/asf/wicket/commit/30162c67
Tree: http://git-wip-us.apache.org/repos/asf/wicket/tree/30162c67
Diff: http://git-wip-us.apache.org/repos/asf/wicket/diff/30162c67
Branch: refs/heads/sandbox/queueing
Commit: 30162c67c376ca85d1fcdde23d494ab4b57feb6d
Parents: b3d5238
Author: Igor Vaynberg <iv...@apache.org>
Authored: Sat Jan 7 21:23:09 2012 -0800
Committer: Igor Vaynberg <iv...@apache.org>
Committed: Sat Jan 7 21:23:09 2012 -0800
----------------------------------------------------------------------
.../java/org/apache/wicket/MarkupContainer.java | 221 ++++++++++++---
1 files changed, 179 insertions(+), 42 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/wicket/blob/30162c67/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 7e5d4c9..1782281 100644
--- a/wicket-core/src/main/java/org/apache/wicket/MarkupContainer.java
+++ b/wicket-core/src/main/java/org/apache/wicket/MarkupContainer.java
@@ -20,8 +20,10 @@ import java.util.AbstractList;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
+import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
+import java.util.Map;
import java.util.Stack;
import org.apache.wicket.markup.ComponentTag;
@@ -36,6 +38,7 @@ 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;
@@ -346,77 +349,211 @@ public abstract class MarkupContainer extends Component implements Iterable<Comp
@Override
void dequeue()
{
- ArrayList<Component> queue = getMetaData(QUEUE);
- if (queue == null)
+ /*
+ * WARNING: THIS CODE IS EXTREMELY ROUGH AND DOES NOT FUNCTION IN THE SAME WAY THAT FINAL
+ * CODE WILL. IT IS HERE ONLY SO VARIOUS TESTS CAN BE WRITTEN IN HierarchyCompletionTest TO
+ * EXPLORE THIS IDEA
+ */
+
+ class ComponentAndTag
+ {
+ ComponentTag tag;
+ MarkupContainer component;
+
+ public ComponentAndTag(ComponentTag tag, MarkupContainer component)
+ {
+ this.tag = tag;
+ this.component = component;
+ }
+ }
+
+ MarkupStream markup = null;
+
+ if (hasAssociatedMarkup())
{
+ markup = new MarkupStream(getMarkupSourcingStrategy().getMarkup(this, null));
+ // FIXME a hack to skip the first tag that does not resolve to any component such as
+ // wicket:panel or wicket:border
+ MarkupElement e = markup.get();
+ if (e instanceof WicketTag)
+ {
+ if (((WicketTag)e).isMajorWicketComponentTag())
+ {
+ markup.next();
+ }
+ }
+ }
+ else if (getParent() instanceof AbstractRepeater)
+ {
+ markup = new MarkupStream(getParent().getMarkup());
+
+ // skip the repeater tag, we only want to traverse the body
+ markup.next();
+ }
+ else
+ {
+ // we only complete the hierarchy of components with associated markup and direct
+ // children of repeaters. the rest of components should be inside the previous two
+ // types.
+
return;
}
+ // stack of components between the current tag in the markup and the markup's owner
+ Stack<ComponentAndTag> stack = new Stack<ComponentAndTag>();
- while (!queue.isEmpty())
+ // current component is the root of the stack. it has no component tag.
+ stack.push(new ComponentAndTag(null, this));
+
+ ComponentTag tag = null;
+
+ Map<Component, MarkupContainer> lateAdd = new HashMap<Component, MarkupContainer>();
+
+ while (markup.hasMore())
{
- Component resolved = dequeueChild(queue);
- if (resolved == null)
+ if (tag != null)
{
- // TODO message
- throw new WicketRuntimeException("Could not unqueue any child with id");
+ // advance the markup stream if this is not the first time through
+ markup.next();
}
- else
+ if (!markup.skipUntil(ComponentTag.class))
{
- queue.remove(resolved);
+ // TODO error if stack is not empty
+ break;
}
- }
- setMetaData(QUEUE, null);
- }
+ // the current markup tag
+ tag = (ComponentTag)markup.get();
- private Component dequeueChild(ArrayList<Component> queue)
- {
- IMarkupFragment markup = getMarkup();
- for (Component child : queue)
- {
- Stack<ComponentTag> stack = new Stack<ComponentTag>();
+ if (tag.isClose())
+ {
+ if (stack.isEmpty())
+ {
+ // we are now out of the markup owner's body markup, most likely on a
+ // </wicket:panel> or something similar, we are done
+ break;
+ // return;
+ }
+ stack.pop();
+ continue;
+ }
+
+ final MarkupContainer parent = stack.peek().component;
- for (int i = 0, size = markup.size(); i < size; i++)
+ // attempt to find a child component that corresponds to the markup tag
+
+ // TODO this should be get or resolve so transparent things work
+ Component child = parent.get(tag.getId());
+ if (child == null)
{
- MarkupElement e = markup.get(i);
- if (e instanceof ComponentTag)
+ // try to deque a child component if one has not been found
+
+
+ for (int j = stack.size() - 1; j >= 0; j--)
{
- ComponentTag ct = (ComponentTag)e;
- if (ct.isClose())
+ // we try to find a queued component from the deepest nested parent all the way
+ // to the owner of the markup
+ ComponentAndTag cat = stack.get(j);
+ ArrayList<Component> queue = cat.component.getMetaData(QUEUE);
+ if (queue == null)
{
- stack.pop();
continue;
}
- stack.push(ct);
- if (ct.getId().equals(child.getId()))
+
+ for (Component queued : queue)
{
- Component parent = this;
- for (int si = 0, ssize = stack.size(); si < ssize - 1; si++)
+ if (queued.getId().equals(tag.getId()))
{
- parent = parent.get(stack.get(si).getId());
- if (parent == null)
- {
- break;
- }
- }
- if (parent != null)
- {
- ((MarkupContainer)parent).add(child);
- return child;
+ child = queued;
+ break;
}
-
}
- if (ct.isOpenClose())
+ if (child != null)
+ {
+ queue.remove(child);
+ break;
+ }
+ }
+ }
+
+ if (child != null && child.getParent() == null)
+ {
+ if (parent.findParent(Page.class) != null)
+ {
+ // if the parent is linked to the page we will delay the lateadd call so
+ // onconfigure is now triggered on the child right away, but instead after its
+ // children have been resolved
+ lateAdd.put(child, parent);
+ }
+ else
+ {
+ parent.add(child);
+ }
+ // TODO do we need to continue unqueuing or can we skip this component
+ // and all its children if it has been deemed invisible? - dont think we can because
+ // that will leave components in the queue and ondetach() will bomb
+ }
+
+ if (child != null && child.isAuto())
+ {
+ // TODO this is yet another hack, need to figure out how auto components fit into
+ // this and why they dont get correctly resolved second time around
+ child.setAuto(false);
+ }
+
+ if (child == null)
+ {
+ // cannot resolve child component, error
+
+ // TODO make the mesage less queue-dependent. should be the same message that we
+ // throw during render when we cant resolve a child
+
+ String error = "Could not dequeue or resolve child: `" + tag.getId() + "`. ";
+ error += "Parent search stack: [";
+ for (int j = stack.size() - 1; j >= 0; j--)
+ {
+ if (j < stack.size() - 1)
{
- stack.pop();
+ error += ", ";
}
+ ComponentAndTag cat = stack.get(j);
+ error += cat.component.getClass().getSimpleName() + "('" +
+ cat.component.getId() + "')";
}
+ error += "]";
+ throw new WicketRuntimeException(error);
+ }
+
+ if (tag.isOpenClose())
+ {
+ // if this is an open/close tag we are done
+ continue;
+ }
+
+ if (child instanceof AbstractRepeater)
+ {
+ // TODO hack for repeaters, this will be delegated to repeaters themselves later
+
+ // skip inner markup, it will be processed by repeater items
+ markup.skipToMatchingCloseTag(tag);
+ }
+ else if (child instanceof MarkupContainer)
+ {
+ stack.push(new ComponentAndTag(tag, (MarkupContainer)child));
+ }
+ else
+ {
+ // the child is not a container so we can skip its inner markup
+ markup.skipToMatchingCloseTag(tag);
}
}
- return null;
+ for (Map.Entry<Component, MarkupContainer> delayed : lateAdd.entrySet())
+ {
+ delayed.getValue().add(delayed.getKey());
+ }
}
+
/**
* @param component
* The component to check