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.tags/7.0.0.alpha2
@@ -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); |
@@ -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(); | |||
@@ -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 |
@@ -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); | |||
} | |||
/** |
@@ -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 |