]> source.dussan.org Git - vaadin-framework.git/commitdiff
Refactor paint target to use startPaintable() and endPaintable().
authorHenri Sara <hesara@vaadin.com>
Thu, 9 Feb 2012 09:07:40 +0000 (11:07 +0200)
committerHenri Sara <hesara@vaadin.com>
Thu, 9 Feb 2012 09:07:40 +0000 (11:07 +0200)
Also includes initial steps towards support for a queue of components to
paint separately on the top level.

src/com/vaadin/terminal/PaintTarget.java
src/com/vaadin/terminal/gwt/server/AbstractCommunicationManager.java
src/com/vaadin/terminal/gwt/server/JsonPaintTarget.java
src/com/vaadin/ui/AbstractComponent.java

index 68f68e2b51b92c75527c4685b3d615641a3e78f9..78cc9e0af9916be4c3cc3aba524dfd53959d1f04 100644 (file)
@@ -46,6 +46,14 @@ public interface PaintTarget extends Serializable {
      * omit the content and close the tag, in which case cached content should
      * be used.
      * </p>
+     * <p>
+     * This method may also add only a reference to the paintable and queue the
+     * paintable to be painted separately.
+     * </p>
+     * <p>
+     * Each paintable being painted should be closed by a matching
+     * {@link #endPaintable(Paintable)}.
+     * </p>
      * 
      * @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.
index 168d6543f9069fd54fe50673202b4606231eef46..4421001a3f830e8a0562202bf6092aae71ef0927 100644 (file)
@@ -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<Paintable> dirtyPaintables = new ArrayList<Paintable>();
 
+    // queue used during painting to keep track of what still needs to be
+    // painted
+    private LinkedList<Paintable> paintQueue = new LinkedList<Paintable>();
+
     private final HashMap<Paintable, String> paintableIdMap = new HashMap<Paintable, String>();
 
     private final HashMap<String, Paintable> idPaintableMap = new HashMap<String, Paintable>();
@@ -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<Paintable> 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<InvalidLayout> invalidComponentRelativeSizes = null;
@@ -856,9 +837,12 @@ public abstract class AbstractCommunicationManager implements
 
         if (paintables != null) {
 
-            for (final Iterator<Paintable> 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<Paintable> paintablesWithModifiedState = new Stack<Paintable>();
+            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;
 
index 91c15df5b20cccd6b0b77efe93fa27dd7c97276f..3f68577f8c38fd7172e96394517947e473e9ea4b 100644 (file)
@@ -64,6 +64,10 @@ public class JsonPaintTarget implements PaintTarget {
 
     private final Stack<JsonTag> openJsonTags;
 
+    // these match each other element-wise
+    private final Stack<Paintable> openPaintables;
+    private final Stack<String> openPaintableTags;
+
     private final PrintWriter uidlBuffer;
 
     private boolean closed = false;
@@ -89,9 +93,8 @@ public class JsonPaintTarget implements PaintTarget {
     private final Collection<Class<? extends Paintable>> usedPaintableTypes = new LinkedList<Class<? extends Paintable>>();
 
     /**
-     * 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<String>();
         openJsonTags = new Stack<JsonTag>();
+
+        openPaintables = new Stack<Paintable>();
+        openPaintableTags = new Stack<String>();
+
         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 {
index e27670530b8f6e1881b92249bbded90a09a403f3..fa46441d06f4f8bea64c22454d621ada3acef522 100644 (file)
@@ -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;
     }