@@ -44,6 +44,7 @@ import com.vaadin.terminal.gwt.client.communication.JsonEncoder; | |||
import com.vaadin.terminal.gwt.client.communication.MethodInvocation; | |||
import com.vaadin.terminal.gwt.client.communication.RpcManager; | |||
import com.vaadin.terminal.gwt.client.communication.SharedState; | |||
import com.vaadin.terminal.gwt.client.communication.StateChangeEvent; | |||
import com.vaadin.terminal.gwt.client.ui.RootConnector; | |||
import com.vaadin.terminal.gwt.client.ui.VContextMenu; | |||
import com.vaadin.terminal.gwt.client.ui.VNotification; | |||
@@ -1003,7 +1004,7 @@ public class ApplicationConnection { | |||
createConnectorsIfNeeded(json); | |||
// Update states, do not fire events | |||
updateConnectorState(json); | |||
Collection<StateChangeEvent> pendingStateChangeEvents = updateConnectorState(json); | |||
// Update hierarchy, do not fire events | |||
Collection<ConnectorHierarchyChangedEvent> pendingHierarchyChangeEvents = updateConnectorHierarchy(json); | |||
@@ -1011,12 +1012,8 @@ public class ApplicationConnection { | |||
// Fire hierarchy change events | |||
sendHierarchyChangeEvents(pendingHierarchyChangeEvents); | |||
// (TODO) Fire state change events. Should be after hierarchy | |||
// change listeners: At least caption updates for the parent are | |||
// strange if fired from state change listeners and thus calls | |||
// the parent BEFORE the parent is aware of the child (through a | |||
// hierarchy change event) | |||
VConsole.log(" * Sending state change events"); | |||
// Fire state change events. | |||
sendStateChangeEvents(pendingStateChangeEvents); | |||
// Update of legacy (UIDL) style connectors | |||
updateVaadin6StyleConnectors(json); | |||
@@ -1091,6 +1088,29 @@ public class ApplicationConnection { | |||
} | |||
/** | |||
* Sends the state change events created while updating the state | |||
* information. | |||
* | |||
* This must be called after hierarchy change listeners have been | |||
* called. At least caption updates for the parent are strange if | |||
* fired from state change listeners and thus calls the parent | |||
* BEFORE the parent is aware of the child (through a | |||
* ConnectorHierarchyChangedEvent) | |||
* | |||
* @param pendingStateChangeEvents | |||
* The events to send | |||
*/ | |||
private void sendStateChangeEvents( | |||
Collection<StateChangeEvent> pendingStateChangeEvents) { | |||
VConsole.log(" * Sending state change events"); | |||
for (StateChangeEvent sce : pendingStateChangeEvents) { | |||
sce.getConnector().fireEvent(sce); | |||
} | |||
} | |||
private void unregisterRemovedConnectors() { | |||
int unregistered = 0; | |||
List<ServerConnector> currentConnectors = new ArrayList<ServerConnector>( | |||
@@ -1204,10 +1224,12 @@ public class ApplicationConnection { | |||
} | |||
private void updateConnectorState(ValueMap json) { | |||
private Collection<StateChangeEvent> updateConnectorState( | |||
ValueMap json) { | |||
ArrayList<StateChangeEvent> events = new ArrayList<StateChangeEvent>(); | |||
VConsole.log(" * Updating connector states"); | |||
if (!json.containsKey("state")) { | |||
return; | |||
return events; | |||
} | |||
// set states for all paintables mentioned in "state" | |||
ValueMap states = json.getValueMap("state"); | |||
@@ -1215,9 +1237,9 @@ public class ApplicationConnection { | |||
for (int i = 0; i < keyArray.length(); i++) { | |||
try { | |||
String connectorId = keyArray.get(i); | |||
ServerConnector paintable = connectorMap | |||
ServerConnector connector = connectorMap | |||
.getConnector(connectorId); | |||
if (null != paintable) { | |||
if (null != connector) { | |||
JSONArray stateDataAndType = new JSONArray( | |||
states.getJavaScriptObject(connectorId)); | |||
@@ -1226,12 +1248,15 @@ public class ApplicationConnection { | |||
stateDataAndType, connectorMap, | |||
ApplicationConnection.this); | |||
paintable.setState((SharedState) state); | |||
connector.setState((SharedState) state); | |||
events.add(new StateChangeEvent(connector)); | |||
} | |||
} catch (final Throwable e) { | |||
VConsole.error(e); | |||
} | |||
} | |||
return events; | |||
} | |||
/** |
@@ -5,8 +5,11 @@ package com.vaadin.terminal.gwt.client; | |||
import java.util.Collection; | |||
import com.google.gwt.event.shared.GwtEvent; | |||
import com.google.web.bindery.event.shared.HandlerRegistration; | |||
import com.vaadin.terminal.gwt.client.communication.ClientRpc; | |||
import com.vaadin.terminal.gwt.client.communication.SharedState; | |||
import com.vaadin.terminal.gwt.client.communication.StateChangeEvent.StateChangeHandler; | |||
/** | |||
* Interface implemented by all client side classes that can be communicate with | |||
@@ -79,4 +82,20 @@ public interface ServerConnector extends Connector { | |||
public <T extends ClientRpc> Collection<T> getRpcImplementations( | |||
String rpcInterfaceId); | |||
/** | |||
* Adds a handler that is called whenever some part of the state has been | |||
* updated by the server. | |||
* | |||
* @param handler | |||
* The handler that should be added. | |||
*/ | |||
public HandlerRegistration addStateChangeHandler(StateChangeHandler handler); | |||
/** | |||
* Sends the given event to all registered handlers. | |||
* | |||
* @param event | |||
* The event to send. | |||
*/ | |||
public void fireEvent(GwtEvent<?> event); | |||
} |
@@ -0,0 +1,27 @@ | |||
package com.vaadin.terminal.gwt.client.communication; | |||
import com.google.gwt.event.shared.EventHandler; | |||
import com.google.gwt.event.shared.GwtEvent; | |||
import com.vaadin.terminal.gwt.client.ServerConnector; | |||
public abstract class AbstractServerConnectorEvent<H extends EventHandler> extends | |||
GwtEvent<H> { | |||
private ServerConnector connector; | |||
protected AbstractServerConnectorEvent(ServerConnector connector) { | |||
this.connector = connector; | |||
} | |||
public ServerConnector getConnector() { | |||
return connector; | |||
} | |||
/** | |||
* Sends this event to the given handler. | |||
* | |||
* @param handler | |||
* The handler to dispatch. | |||
*/ | |||
@Override | |||
public abstract void dispatch(H handler); | |||
} |
@@ -0,0 +1,33 @@ | |||
package com.vaadin.terminal.gwt.client.communication; | |||
import java.io.Serializable; | |||
import com.google.gwt.event.shared.EventHandler; | |||
import com.vaadin.terminal.gwt.client.ServerConnector; | |||
import com.vaadin.terminal.gwt.client.communication.StateChangeEvent.StateChangeHandler; | |||
public class StateChangeEvent extends | |||
AbstractServerConnectorEvent<StateChangeHandler> { | |||
/** | |||
* Type of this event, used by the event bus. | |||
*/ | |||
public static final Type<StateChangeHandler> TYPE = new Type<StateChangeHandler>(); | |||
@Override | |||
public Type<StateChangeHandler> getAssociatedType() { | |||
return TYPE; | |||
} | |||
public StateChangeEvent(ServerConnector connector) { | |||
super(connector); | |||
} | |||
@Override | |||
public void dispatch(StateChangeHandler listener) { | |||
listener.onStateChanged(this); | |||
} | |||
public interface StateChangeHandler extends Serializable, EventHandler { | |||
public void onStateChanged(StateChangeEvent stateChangeEvent); | |||
} | |||
} |
@@ -9,9 +9,15 @@ import java.util.Collections; | |||
import java.util.HashMap; | |||
import java.util.Map; | |||
import com.google.gwt.event.shared.GwtEvent; | |||
import com.google.gwt.event.shared.HandlerManager; | |||
import com.google.gwt.event.shared.HandlerRegistration; | |||
import com.vaadin.terminal.gwt.client.ApplicationConnection; | |||
import com.vaadin.terminal.gwt.client.ServerConnector; | |||
import com.vaadin.terminal.gwt.client.Util; | |||
import com.vaadin.terminal.gwt.client.communication.ClientRpc; | |||
import com.vaadin.terminal.gwt.client.communication.StateChangeEvent; | |||
import com.vaadin.terminal.gwt.client.communication.StateChangeEvent.StateChangeHandler; | |||
/** | |||
* An abstract implementation of Connector. | |||
@@ -21,11 +27,13 @@ import com.vaadin.terminal.gwt.client.communication.ClientRpc; | |||
* @since 7.0.0 | |||
* | |||
*/ | |||
public abstract class AbstractConnector implements ServerConnector { | |||
public abstract class AbstractConnector implements ServerConnector, | |||
StateChangeHandler { | |||
private ApplicationConnection connection; | |||
private String id; | |||
private HandlerManager handlerManager; | |||
private Map<String, Collection<ClientRpc>> rpcImplementations; | |||
/* | |||
@@ -59,6 +67,7 @@ public abstract class AbstractConnector implements ServerConnector { | |||
this.connection = connection; | |||
id = connectorId; | |||
addStateChangeHandler(this); | |||
init(); | |||
} | |||
@@ -132,4 +141,31 @@ public abstract class AbstractConnector implements ServerConnector { | |||
// Client side can always receive message from the server | |||
return true; | |||
} | |||
public void fireEvent(GwtEvent<?> event) { | |||
if (handlerManager != null) { | |||
handlerManager.fireEvent(event); | |||
} | |||
} | |||
protected HandlerManager ensureHandlerManager() { | |||
if (handlerManager == null) { | |||
handlerManager = new HandlerManager(this); | |||
} | |||
return handlerManager; | |||
} | |||
public HandlerRegistration addStateChangeHandler(StateChangeHandler handler) { | |||
return ensureHandlerManager() | |||
.addHandler(StateChangeEvent.TYPE, handler); | |||
} | |||
// TODO Should be abstract as all connectors need it | |||
public void onStateChanged(StateChangeEvent stateChangeEvent) { | |||
System.out.println("State change event for " | |||
+ Util.getConnectorString(stateChangeEvent.getConnector()) | |||
+ " received by " + Util.getConnectorString(this)); | |||
} | |||
} |