From: Henri Sara Date: Thu, 9 Feb 2012 09:07:40 +0000 (+0200) Subject: Refactor paint target to use startPaintable() and endPaintable(). X-Git-Tag: 7.0.0.alpha2~440^2~23 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=815406969b267f0250339e53af4e69370375d90a;p=vaadin-framework.git Refactor paint target to use startPaintable() and endPaintable(). Also includes initial steps towards support for a queue of components to paint separately on the top level. --- diff --git a/src/com/vaadin/terminal/PaintTarget.java b/src/com/vaadin/terminal/PaintTarget.java index 68f68e2b51..78cc9e0af9 100644 --- a/src/com/vaadin/terminal/PaintTarget.java +++ b/src/com/vaadin/terminal/PaintTarget.java @@ -46,6 +46,14 @@ public interface PaintTarget extends Serializable { * omit the content and close the tag, in which case cached content should * be used. *

+ *

+ * This method may also add only a reference to the paintable and queue the + * paintable to be painted separately. + *

+ *

+ * Each paintable being painted should be closed by a matching + * {@link #endPaintable(Paintable)}. + *

* * @param paintable * the paintable to start. @@ -56,33 +64,25 @@ public interface PaintTarget extends Serializable { * @throws PaintException * if the paint operation failed. * @see #startTag(String) - * @since 3.1 + * @since 7.0 (previously using startTag(Paintable, String)) */ - public boolean startTag(Paintable paintable, String tag) + public boolean startPaintable(Paintable paintable, String tag) throws PaintException; /** - * Paints a component reference as an attribute to current tag. This method - * is meant to enable component interactions on client side. With reference - * the client side component can communicate directly to other component. + * Prints paintable element end tag. * - * Note! This was experimental api and got replaced by - * {@link #addAttribute(String, Paintable)} and - * {@link #addVariable(VariableOwner, String, Paintable)}. + * Calls to {@link #startPaintable(Paintable, String)} should be matched by + * {@link #endPaintable(Paintable)}. If the parent tag is closed before + * every child tag is closed a PaintException is raised. * * @param paintable - * the Paintable to reference - * @param referenceName + * the paintable to close. * @throws PaintException - * - * @since 5.2 - * @deprecated use {@link #addAttribute(String, Paintable)} or - * {@link #addVariable(VariableOwner, String, Paintable)} - * instead + * if the paint operation failed. + * @since 7.0 (previously using engTag(String)) */ - @Deprecated - public void paintReference(Paintable paintable, String referenceName) - throws PaintException; + public void endPaintable(Paintable paintable) throws PaintException; /** * Prints element start tag. diff --git a/src/com/vaadin/terminal/gwt/server/AbstractCommunicationManager.java b/src/com/vaadin/terminal/gwt/server/AbstractCommunicationManager.java index 168d6543f9..4421001a3f 100644 --- a/src/com/vaadin/terminal/gwt/server/AbstractCommunicationManager.java +++ b/src/com/vaadin/terminal/gwt/server/AbstractCommunicationManager.java @@ -37,6 +37,7 @@ import java.util.List; import java.util.Locale; import java.util.Map; import java.util.Set; +import java.util.Stack; import java.util.UUID; import java.util.logging.Level; import java.util.logging.Logger; @@ -141,8 +142,13 @@ public abstract class AbstractCommunicationManager implements private static final String GET_PARAM_ANALYZE_LAYOUTS = "analyzeLayouts"; + // TODO combine with paint queue? private final ArrayList dirtyPaintables = new ArrayList(); + // queue used during painting to keep track of what still needs to be + // painted + private LinkedList paintQueue = new LinkedList(); + private final HashMap paintableIdMap = new HashMap(); private final HashMap idPaintableMap = new HashMap(); @@ -739,6 +745,11 @@ public abstract class AbstractCommunicationManager implements return seckey; } + // for internal use by JsonPaintTarget + public void queuePaintable(Paintable paintable) { + paintQueue.push(paintable); + } + public void writeUidlResponce(boolean repaintAll, final PrintWriter outWriter, Root root, boolean analyzeLayouts) throws PaintException { @@ -777,6 +788,7 @@ public abstract class AbstractCommunicationManager implements dirtyPaintables.remove(p); } } + // TODO second list/stack for those whose state needs to be sent? paintables = getDirtyVisibleComponents(root); } @@ -809,37 +821,6 @@ public abstract class AbstractCommunicationManager implements }); } - if (paintables != null) { - // paint shared state before changes - for now, send the complete - // state of all modified and new components - - // TODO problem: some components will only be created and registered - // below in the paint phase - - JSONObject sharedStates = new JSONObject(); - for (final Iterator i = paintables.iterator(); i - .hasNext();) { - final Paintable p = i.next(); - String paintableId = getPaintableId(p); - SharedState state = p.getState(); - if (null != state) { - // encode and send shared state - try { - JSONArray stateJsonArray = JsonCodec - .encode(state, this); - sharedStates.put(paintableId, stateJsonArray); - } catch (JSONException e) { - throw new PaintException( - "Failed to serialize shared state for paintable " - + paintableId + ": " + e.getMessage()); - } - } - } - outWriter.print("\"state\":"); - outWriter.append(sharedStates.toString()); - outWriter.print(", "); // close changes - } - outWriter.print("\"changes\":["); List invalidComponentRelativeSizes = null; @@ -856,9 +837,12 @@ public abstract class AbstractCommunicationManager implements if (paintables != null) { - for (final Iterator i = paintables.iterator(); i - .hasNext();) { - final Paintable p = i.next(); + // clear and rebuild paint queue + paintQueue.clear(); + paintQueue.addAll(paintables); + + while (!paintQueue.isEmpty()) { + final Paintable p = paintQueue.pop(); // // TODO CLEAN // if (p instanceof Root) { @@ -867,13 +851,6 @@ public abstract class AbstractCommunicationManager implements // r.setTerminal(application.getRoot().getTerminal()); // } // } - /* - * This does not seem to happen in tk5, but remember this case: - * else if (p instanceof Component) { if (((Component) - * p).getParent() == null || ((Component) p).getApplication() == - * null) { // Component requested repaint, but is no // longer - * attached: skip paintablePainted(p); continue; } } - */ // TODO we may still get changes that have been // rendered already (changes with only cached flag) @@ -883,6 +860,8 @@ public abstract class AbstractCommunicationManager implements final String pid = getPaintableId(p); paintTarget.addAttribute("pid", pid); + // TODO this should paint subcomponents as references and + // defer painting their contents to another top-level change p.paint(paintTarget); paintTarget.endTag("change"); @@ -911,6 +890,46 @@ public abstract class AbstractCommunicationManager implements paintTarget.close(); outWriter.print("], "); // close changes + if (paintables != null) { + // paint shared state + + // for now, send the complete state of all modified and new + // components + + // Ideally, all this would be sent before "changes", but that causes + // complications with legacy components that create sub-components + // in their paint phase. Nevertheless, this will be processed on the + // client after component creation but before legacy UIDL + // processing. + + JSONObject sharedStates = new JSONObject(); + Stack paintablesWithModifiedState = new Stack(); + paintablesWithModifiedState.addAll(paintables); + // TODO add all sub-components that were painted + while (!paintablesWithModifiedState.empty()) { + final Paintable p = paintablesWithModifiedState.pop(); + String paintableId = getPaintableId(p); + SharedState state = p.getState(); + if (null != state) { + // encode and send shared state + try { + JSONArray stateJsonArray = JsonCodec + .encode(state, this); + sharedStates.put(paintableId, stateJsonArray); + } catch (JSONException e) { + throw new PaintException( + "Failed to serialize shared state for paintable " + + paintableId + ": " + e.getMessage()); + } + } + } + outWriter.print("\"state\":"); + outWriter.append(sharedStates.toString()); + outWriter.print(", "); // close changes + } + + // TODO send server to client RPC calls in call order here + outWriter.print("\"meta\" : {"); boolean metaOpen = false; diff --git a/src/com/vaadin/terminal/gwt/server/JsonPaintTarget.java b/src/com/vaadin/terminal/gwt/server/JsonPaintTarget.java index 91c15df5b2..3f68577f8c 100644 --- a/src/com/vaadin/terminal/gwt/server/JsonPaintTarget.java +++ b/src/com/vaadin/terminal/gwt/server/JsonPaintTarget.java @@ -64,6 +64,10 @@ public class JsonPaintTarget implements PaintTarget { private final Stack openJsonTags; + // these match each other element-wise + private final Stack openPaintables; + private final Stack openPaintableTags; + private final PrintWriter uidlBuffer; private boolean closed = false; @@ -89,9 +93,8 @@ public class JsonPaintTarget implements PaintTarget { private final Collection> usedPaintableTypes = new LinkedList>(); /** - * Creates a new XMLPrintWriter, without automatic line flushing. + * Creates a new JsonPaintTarget. * - * @param variableMap * @param manager * @param outWriter * A character-output stream. @@ -113,6 +116,10 @@ public class JsonPaintTarget implements PaintTarget { // Initialize tag-writing mOpenTags = new Stack(); openJsonTags = new Stack(); + + openPaintables = new Stack(); + openPaintableTags = new Stack(); + cacheEnabled = cachingRequired; } @@ -673,7 +680,7 @@ public class JsonPaintTarget implements PaintTarget { * @see com.vaadin.terminal.PaintTarget#startTag(com.vaadin.terminal * .Paintable, java.lang.String) */ - public boolean startTag(Paintable paintable, String tagName) + public boolean startPaintable(Paintable paintable, String tagName) throws PaintException { startTag(tagName, true); final boolean isPreviouslyPainted = manager.hasPaintableId(paintable) @@ -682,7 +689,19 @@ public class JsonPaintTarget implements PaintTarget { final String id = manager.getPaintableId(paintable); paintable.addListener(manager); addAttribute("id", id); + + // TODO if to queue if already painting a paintable + // if (openPaintables.isEmpty()) { + openPaintables.push(paintable); + openPaintableTags.push(tagName); + paintedComponents.add(paintable); + // } else { + // // notify manager: add to paint queue instead of painting now + // manager.queuePaintable(paintable); + // // TODO return suitable value to defer painting and close tag if a + // // paintable tag is already open + // } if (paintable instanceof CustomLayout) { customLayoutArgumentsOpen = true; @@ -691,10 +710,17 @@ public class JsonPaintTarget implements PaintTarget { return cacheEnabled && isPreviouslyPainted; } - @Deprecated - public void paintReference(Paintable paintable, String referenceName) - throws PaintException { - addAttribute(referenceName, paintable); + public void endPaintable(Paintable paintable) throws PaintException { + Paintable openPaintable = openPaintables.peek(); + if (paintable != openPaintable) { + throw new PaintException("Invalid UIDL: closing wrong paintable: '" + + getPaintIdentifier(paintable) + "' expected: '" + + getPaintIdentifier(openPaintable) + "'."); + } + // remove paintable from the stack + openPaintables.pop(); + String openTag = openPaintableTags.pop(); + endTag(openTag); } public String getPaintIdentifier(Paintable paintable) throws PaintException { diff --git a/src/com/vaadin/ui/AbstractComponent.java b/src/com/vaadin/ui/AbstractComponent.java index e27670530b..fa46441d06 100644 --- a/src/com/vaadin/ui/AbstractComponent.java +++ b/src/com/vaadin/ui/AbstractComponent.java @@ -753,7 +753,8 @@ public abstract class AbstractComponent implements Component, MethodEventSource */ public void paint(PaintTarget target) throws PaintException { final String tag = target.getTag(this); - if (!target.startTag(this, tag) || repaintRequestListenersNotified) { + if (!target.startPaintable(this, tag) + || repaintRequestListenersNotified) { // Paint the contents of the component @@ -813,7 +814,7 @@ public abstract class AbstractComponent implements Component, MethodEventSource // Contents have not changed, only cached presentation can be used target.addAttribute("cached", true); } - target.endTag(tag); + target.endPaintable(this); repaintRequestListenersNotified = false; }