summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--client/src/com/vaadin/terminal/gwt/client/ApplicationConnection.java101
1 files changed, 101 insertions, 0 deletions
diff --git a/client/src/com/vaadin/terminal/gwt/client/ApplicationConnection.java b/client/src/com/vaadin/terminal/gwt/client/ApplicationConnection.java
index a984433907..da41df5303 100644
--- a/client/src/com/vaadin/terminal/gwt/client/ApplicationConnection.java
+++ b/client/src/com/vaadin/terminal/gwt/client/ApplicationConnection.java
@@ -193,6 +193,45 @@ public class ApplicationConnection {
private final RpcManager rpcManager;
+ /**
+ * If renderingLocks contains any objects, rendering is to be suspended
+ * until the collection is empty or a timeout has occurred.
+ */
+ private Set<Object> renderingLocks = new HashSet<Object>();
+
+ /**
+ * Data structure holding information about pending UIDL messages.
+ */
+ private class PendingUIDLMessage {
+ private Date start;
+ private String jsonText;
+ private ValueMap json;
+
+ public PendingUIDLMessage(Date start, String jsonText, ValueMap json) {
+ this.start = start;
+ this.jsonText = jsonText;
+ this.json = json;
+ }
+
+ public Date getStart() {
+ return start;
+ }
+
+ public String getJsonText() {
+ return jsonText;
+ }
+
+ public ValueMap getJson() {
+ return json;
+ }
+ }
+
+ /** Contains all UIDL messages received while the rendering is suspended */
+ private List<PendingUIDLMessage> pendingUIDLMessages = new ArrayList<PendingUIDLMessage>();
+
+ /** The max timeout the rendering phase may be suspended */
+ private static final int MAX_SUSPENDED_TIMEOUT = 5000;
+
public static class MultiStepDuration extends Duration {
private int previousStep = elapsedMillis();
@@ -1010,6 +1049,17 @@ public class ApplicationConnection {
protected void handleUIDLMessage(final Date start, final String jsonText,
final ValueMap json) {
+ if (!renderingLocks.isEmpty()) {
+ // Some component is doing something that can't be interrupted
+ // (e.g. animation that should be smooth). Enqueue the UIDL
+ // message for later processing.
+ VConsole.log("Postponing UIDL handling due to lock...");
+ pendingUIDLMessages.add(new PendingUIDLMessage(start, jsonText,
+ json));
+ forceHandleMessage.schedule(MAX_SUSPENDED_TIMEOUT);
+ return;
+ }
+
VConsole.log("Handling message from server");
// Handle redirect
if (json.containsKey("redirect")) {
@@ -2753,4 +2803,55 @@ public class ApplicationConnection {
callback.onError(null, re);
}
}
+
+ /**
+ * Timer used to make sure that no misbehaving components can lock the
+ * rendering phase forever.
+ */
+ Timer forceHandleMessage = new Timer() {
+ @Override
+ public void run() {
+ VConsole.log("WARNING: rendering was never resumed, forcing reload...");
+ renderingLocks.clear();
+ handlePendingMessages();
+ }
+ };
+
+ /**
+ * This method can be used to postpone rendering of a response for a short
+ * period of time (e.g. to avoid the rendering process during animation).
+ *
+ * @param lock
+ */
+ public void suspendRendering(Object lock) {
+ renderingLocks.add(lock);
+ }
+
+ /**
+ * Resumes the rendering process once all locks have been removed.
+ *
+ * @param lock
+ */
+ public void resumeRendering(Object lock) {
+ VConsole.log("...resuming UIDL handling.");
+ renderingLocks.remove(lock);
+ if (renderingLocks.isEmpty()) {
+ VConsole.log("No more rendering locks, rendering pending requests.");
+ forceHandleMessage.cancel();
+ handlePendingMessages();
+ }
+ }
+
+ /**
+ * Handles all pending UIDL messages queued while the rendering was
+ * suspended.
+ */
+ private void handlePendingMessages() {
+ for (PendingUIDLMessage pending : pendingUIDLMessages) {
+ handleUIDLMessage(pending.getStart(), pending.getJsonText(),
+ pending.getJson());
+ }
+ pendingUIDLMessages.clear();
+ }
+
}