]> source.dussan.org Git - vaadin-framework.git/commitdiff
Set shared state for VPaintables before updateFromUIDL() (#8304).
authorHenri Sara <hesara@vaadin.com>
Tue, 14 Feb 2012 11:28:50 +0000 (13:28 +0200)
committerHenri Sara <hesara@vaadin.com>
Tue, 14 Feb 2012 11:28:50 +0000 (13:28 +0200)
Also includes minor fixes related to shared state painting and decoding.

Some data is currently duplicated in UIDL and shared state, and width
and height are used from shared state except for a few cases that still
parse them from UIDL explicitly.

src/com/vaadin/terminal/gwt/client/ApplicationConnection.java
src/com/vaadin/terminal/gwt/client/VPaintable.java
src/com/vaadin/terminal/gwt/client/communication/JsonDecoder.java
src/com/vaadin/terminal/gwt/client/ui/VAbstractPaintableWidget.java
src/com/vaadin/terminal/gwt/server/AbstractCommunicationManager.java

index b41b4f1b3c775603cc12e213f8a1aa4c6aaf64e0..c8a676d6fada911f8be9f0e2f07c412149463b4d 100644 (file)
@@ -993,30 +993,10 @@ public class ApplicationConnection {
                     redirectTimer.schedule(1000 * sessionExpirationInterval);
                 }
 
-                // TODO implement shared state handling
-
-                // map from paintable id to its shared state instance
-                Map<String, SharedState> sharedStates = new HashMap<String, SharedState>();
-
-                // TODO Cache shared state (if any) - components might not exist
-                // TODO cleanup later: keep only used states
-                ValueMap states = json.getValueMap("state");
-                JsArrayString keyArray = states.getKeyArray();
-                for (int i = 0; i < keyArray.length(); i++) {
-                    String paintableId = keyArray.get(i);
-                    // TODO handle as a ValueMap or similar object and native
-                    // JavaScript processing?
-                    JavaScriptObject value = states
-                            .getJavaScriptObject(paintableId);
-                    // TODO implement with shared state subclasses
-                    SharedState state = GWT.create(SharedState.class);
-                    Map<String, Object> stateMap = (Map<String, Object>) JsonDecoder
-                            .convertValue(new JSONArray(value),
-                                    getPaintableMap());
-                    state.setState(stateMap);
-                    // TODO cache state to temporary stateMap
-                    sharedStates.put(paintableId, state);
-                }
+                // three phases/loops:
+                // - changes: create paintables (if necessary)
+                // - state: set shared states
+                // - changes: call updateFromUIDL() for each paintable
 
                 // Process changes
                 JsArray<ValueMap> changes = json.getJSValueMapArray("changes");
@@ -1026,6 +1006,52 @@ public class ApplicationConnection {
                 componentCaptionSizeChanges.clear();
 
                 int length = changes.length();
+
+                // create paintables if necessary
+                for (int i = 0; i < length; i++) {
+                    try {
+                        final UIDL change = changes.get(i).cast();
+                        final UIDL uidl = change.getChildUIDL(0);
+                        VPaintable paintable = paintableMap.getPaintable(uidl
+                                .getId());
+                        if (null == paintable
+                                && !uidl.getTag().equals(
+                                        configuration.getEncodedWindowTag())) {
+                            // create, initialize and register the paintable
+                            getPaintable(uidl);
+                        }
+                    } catch (final Throwable e) {
+                        VConsole.error(e);
+                    }
+                }
+
+                // set states for all paintables mentioned in "state"
+                ValueMap states = json.getValueMap("state");
+                JsArrayString keyArray = states.getKeyArray();
+                for (int i = 0; i < keyArray.length(); i++) {
+                    try {
+                        String paintableId = keyArray.get(i);
+                        VPaintable paintable = paintableMap
+                                .getPaintable(paintableId);
+                        if (null != paintable) {
+                            // TODO handle as a ValueMap or similar object and
+                            // native JavaScript processing?
+                            JavaScriptObject value = states
+                                    .getJavaScriptObject(paintableId);
+                            // TODO implement with shared state subclasses
+                            SharedState state = GWT.create(SharedState.class);
+                            Map<String, Object> stateMap = (Map<String, Object>) JsonDecoder
+                                    .convertValue(new JSONArray(value),
+                                            getPaintableMap());
+                            state.setState(stateMap);
+                            paintable.updateState(state);
+                        }
+                    } catch (final Throwable e) {
+                        VConsole.error(e);
+                    }
+                }
+
+                // update paintables
                 for (int i = 0; i < length; i++) {
                     try {
                         final UIDL change = changes.get(i).cast();
@@ -1567,12 +1593,29 @@ public class ApplicationConnection {
         return result.toString();
     }
 
-    public void updateComponentSize(VPaintableWidget paintable, UIDL uidl) {
-        String w = uidl.hasAttribute("width") ? uidl
-                .getStringAttribute("width") : "";
-
-        String h = uidl.hasAttribute("height") ? uidl
-                .getStringAttribute("height") : "";
+    public void updateComponentSize(VPaintableWidget paintable) {
+        SharedState state = paintable.getState();
+        String w = "";
+        String h = "";
+        if (null != state) {
+            // TODO move logging to VUIDLBrowser and VDebugConsole
+            VConsole.log("Paintable state for "
+                    + getPaintableMap().getPid(paintable) + ": "
+                    + String.valueOf(state.getState()));
+            if (state.getState().containsKey(ComponentState.STATE_WIDTH)) {
+                w = String.valueOf(state.getState().get(
+                        ComponentState.STATE_WIDTH));
+            }
+            if (state.getState().containsKey(ComponentState.STATE_HEIGHT)) {
+                h = String.valueOf(state.getState().get(
+                        ComponentState.STATE_HEIGHT));
+            }
+        } else {
+            // TODO move logging to VUIDLBrowser and VDebugConsole
+            VConsole.log("No state for paintable "
+                    + getPaintableMap().getPid(paintable)
+                    + " in ApplicationConnection.updateComponentSize()");
+        }
 
         float relativeWidth = Util.parseRelativeSize(w);
         float relativeHeight = Util.parseRelativeSize(h);
index 032058b8d57cae3fd36c75b2e1b2f18d6cb8d587..666b620d82c7cf86c89a5082688e527bbafe1169 100644 (file)
@@ -3,6 +3,8 @@
  */
 package com.vaadin.terminal.gwt.client;
 
+import com.vaadin.terminal.gwt.client.communication.SharedState;
+
 /**
  * Interface implemented by all client side classes that can be communicate with
  * the server. Classes implementing this interface are initialized by the
@@ -21,6 +23,20 @@ public interface VPaintable {
      */
     public void updateFromUIDL(UIDL uidl, ApplicationConnection client);
 
+    /**
+     * Sets the shared state for the paintable.
+     * 
+     * @param state
+     */
+    public void updateState(SharedState state);
+
+    /**
+     * Gets the current shared state of the paintable.
+     * 
+     * @return state
+     */
+    public SharedState getState();
+
     /**
      * Returns the id for this VPaintable. This must always be what has been set
      * using {@link #setId(String)}.
@@ -73,7 +89,9 @@ public interface VPaintable {
 
     /**
      * 
-     * Called once when the connection and id has been set
+     * Called once when the connection and id has been set.
+     * 
+     * Note that the shared state is not yet available during init().
      */
     public void init();
 
index 7ed212af4903124abdcc39dd7e672ef136795fd1..e7369e1a8c20fe5ca3db8b430f9f641859c76c6e 100644 (file)
@@ -58,7 +58,7 @@ public class JsonDecoder {
             val = convertStringArray((JSONArray) value);
             break;
         case JsonEncoder.VTYPE_STRING:
-            val = value;
+            val = ((JSONString) value).stringValue();
             break;
         case JsonEncoder.VTYPE_INTEGER:
             // TODO handle properly
index 746bc99ba4b1e7a20f77a1f55f1f292c7f27541f..3cbe8da00f8a82859539d7680fda99d67dddc919 100644 (file)
@@ -13,6 +13,7 @@ import com.vaadin.terminal.gwt.client.UIDL;
 import com.vaadin.terminal.gwt.client.VPaintableMap;
 import com.vaadin.terminal.gwt.client.VPaintableWidget;
 import com.vaadin.terminal.gwt.client.VPaintableWidgetContainer;
+import com.vaadin.terminal.gwt.client.communication.SharedState;
 
 public abstract class VAbstractPaintableWidget implements VPaintableWidget {
 
@@ -27,6 +28,9 @@ public abstract class VAbstractPaintableWidget implements VPaintableWidget {
     private boolean enabled = true;
     private boolean visible = true;
 
+    // shared state from the server to the client
+    private SharedState state;
+
     /**
      * Default constructor
      */
@@ -89,6 +93,14 @@ public abstract class VAbstractPaintableWidget implements VPaintableWidget {
         this.id = id;
     }
 
+    public void updateState(SharedState state) {
+        this.state = state;
+    }
+
+    public SharedState getState() {
+        return state;
+    }
+
     public VPaintableWidgetContainer getParent() {
         // FIXME: Hierarchy should be set by framework instead of looked up here
         VPaintableMap paintableMap = VPaintableMap.get(getConnection());
@@ -181,7 +193,7 @@ public abstract class VAbstractPaintableWidget implements VPaintableWidget {
          * taken into account
          */
 
-        getConnection().updateComponentSize(this, uidl);
+        getConnection().updateComponentSize(this);
     }
 
     /**
index 7b75592442fdf5d97b8603fbfe814b5aaa3d8765..85643e2b8ab6153c23eeff3ccece507c963ee19e 100644 (file)
@@ -37,7 +37,6 @@ 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;
@@ -142,11 +141,12 @@ public abstract class AbstractCommunicationManager implements
 
     private static final String GET_PARAM_ANALYZE_LAYOUTS = "analyzeLayouts";
 
-    // TODO combine with paint queue?
+    // cannot combine with paint queue:
+    // this can contain dirty components from any Root
     private final ArrayList<Paintable> dirtyPaintables = new ArrayList<Paintable>();
 
     // queue used during painting to keep track of what still needs to be
-    // painted
+    // painted within the Root being painted
     private LinkedList<Paintable> paintQueue = new LinkedList<Paintable>();
 
     private final HashMap<Paintable, String> paintableIdMap = new HashMap<Paintable, String>();
@@ -747,7 +747,9 @@ public abstract class AbstractCommunicationManager implements
 
     // for internal use by JsonPaintTarget
     public void queuePaintable(Paintable paintable) {
-        paintQueue.push(paintable);
+        if (!paintQueue.contains(paintable)) {
+            paintQueue.add(paintable);
+        }
     }
 
     public void writeUidlResponce(boolean repaintAll,
@@ -835,6 +837,8 @@ public abstract class AbstractCommunicationManager implements
                     windowCache);
         }
 
+        LinkedList<Paintable> stateQueue = new LinkedList<Paintable>();
+
         if (paintables != null) {
 
             // clear and rebuild paint queue
@@ -843,6 +847,8 @@ public abstract class AbstractCommunicationManager implements
 
             while (!paintQueue.isEmpty()) {
                 final Paintable p = paintQueue.pop();
+                // for now, all painted components may need a state refresh
+                stateQueue.push(p);
 
                 // // TODO CLEAN
                 // if (p instanceof Root) {
@@ -891,7 +897,7 @@ public abstract class AbstractCommunicationManager implements
         paintTarget.close();
         outWriter.print("], "); // close changes
 
-        if (paintables != null) {
+        if (!stateQueue.isEmpty()) {
             // paint shared state
 
             // for now, send the complete state of all modified and new
@@ -904,11 +910,8 @@ public abstract class AbstractCommunicationManager implements
             // 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();
+            while (!stateQueue.isEmpty()) {
+                final Paintable p = stateQueue.pop();
                 String paintableId = getPaintableId(p);
                 SharedState state = p.getState();
                 if (null != state) {
@@ -1869,6 +1872,7 @@ public abstract class AbstractCommunicationManager implements
         final ArrayList<Paintable> resultset = new ArrayList<Paintable>(
                 dirtyPaintables);
 
+        // TODO mostly unnecessary?
         // The following algorithm removes any components that would be painted
         // as a direct descendant of other components from the dirty components
         // list. The result is that each component should be painted exactly