import com.vaadin.terminal.gwt.client.communication.MethodInvocation; | import com.vaadin.terminal.gwt.client.communication.MethodInvocation; | ||||
import com.vaadin.terminal.gwt.client.communication.RpcManager; | import com.vaadin.terminal.gwt.client.communication.RpcManager; | ||||
import com.vaadin.terminal.gwt.client.communication.SharedState; | 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.RootConnector; | ||||
import com.vaadin.terminal.gwt.client.ui.VContextMenu; | import com.vaadin.terminal.gwt.client.ui.VContextMenu; | ||||
import com.vaadin.terminal.gwt.client.ui.VNotification; | import com.vaadin.terminal.gwt.client.ui.VNotification; | ||||
createConnectorsIfNeeded(json); | createConnectorsIfNeeded(json); | ||||
// Update states, do not fire events | // Update states, do not fire events | ||||
updateConnectorState(json); | |||||
Collection<StateChangeEvent> pendingStateChangeEvents = updateConnectorState(json); | |||||
// Update hierarchy, do not fire events | // Update hierarchy, do not fire events | ||||
Collection<ConnectorHierarchyChangedEvent> pendingHierarchyChangeEvents = updateConnectorHierarchy(json); | Collection<ConnectorHierarchyChangedEvent> pendingHierarchyChangeEvents = updateConnectorHierarchy(json); | ||||
// Fire hierarchy change events | // Fire hierarchy change events | ||||
sendHierarchyChangeEvents(pendingHierarchyChangeEvents); | 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 | // Update of legacy (UIDL) style connectors | ||||
updateVaadin6StyleConnectors(json); | updateVaadin6StyleConnectors(json); | ||||
} | } | ||||
/** | |||||
* 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() { | private void unregisterRemovedConnectors() { | ||||
int unregistered = 0; | int unregistered = 0; | ||||
List<ServerConnector> currentConnectors = new ArrayList<ServerConnector>( | List<ServerConnector> currentConnectors = new ArrayList<ServerConnector>( | ||||
} | } | ||||
private void updateConnectorState(ValueMap json) { | |||||
private Collection<StateChangeEvent> updateConnectorState( | |||||
ValueMap json) { | |||||
ArrayList<StateChangeEvent> events = new ArrayList<StateChangeEvent>(); | |||||
VConsole.log(" * Updating connector states"); | VConsole.log(" * Updating connector states"); | ||||
if (!json.containsKey("state")) { | if (!json.containsKey("state")) { | ||||
return; | |||||
return events; | |||||
} | } | ||||
// set states for all paintables mentioned in "state" | // set states for all paintables mentioned in "state" | ||||
ValueMap states = json.getValueMap("state"); | ValueMap states = json.getValueMap("state"); | ||||
for (int i = 0; i < keyArray.length(); i++) { | for (int i = 0; i < keyArray.length(); i++) { | ||||
try { | try { | ||||
String connectorId = keyArray.get(i); | String connectorId = keyArray.get(i); | ||||
ServerConnector paintable = connectorMap | |||||
ServerConnector connector = connectorMap | |||||
.getConnector(connectorId); | .getConnector(connectorId); | ||||
if (null != paintable) { | |||||
if (null != connector) { | |||||
JSONArray stateDataAndType = new JSONArray( | JSONArray stateDataAndType = new JSONArray( | ||||
states.getJavaScriptObject(connectorId)); | states.getJavaScriptObject(connectorId)); | ||||
stateDataAndType, connectorMap, | stateDataAndType, connectorMap, | ||||
ApplicationConnection.this); | ApplicationConnection.this); | ||||
paintable.setState((SharedState) state); | |||||
connector.setState((SharedState) state); | |||||
events.add(new StateChangeEvent(connector)); | |||||
} | } | ||||
} catch (final Throwable e) { | } catch (final Throwable e) { | ||||
VConsole.error(e); | VConsole.error(e); | ||||
} | } | ||||
} | } | ||||
return events; | |||||
} | } | ||||
/** | /** |
import java.util.Collection; | 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.ClientRpc; | ||||
import com.vaadin.terminal.gwt.client.communication.SharedState; | 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 | * Interface implemented by all client side classes that can be communicate with | ||||
public <T extends ClientRpc> Collection<T> getRpcImplementations( | public <T extends ClientRpc> Collection<T> getRpcImplementations( | ||||
String rpcInterfaceId); | 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); | |||||
} | } |
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); | |||||
} |
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); | |||||
} | |||||
} |
import java.util.HashMap; | import java.util.HashMap; | ||||
import java.util.Map; | 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.ApplicationConnection; | ||||
import com.vaadin.terminal.gwt.client.ServerConnector; | 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.ClientRpc; | ||||
import com.vaadin.terminal.gwt.client.communication.StateChangeEvent; | |||||
import com.vaadin.terminal.gwt.client.communication.StateChangeEvent.StateChangeHandler; | |||||
/** | /** | ||||
* An abstract implementation of Connector. | * An abstract implementation of Connector. | ||||
* @since 7.0.0 | * @since 7.0.0 | ||||
* | * | ||||
*/ | */ | ||||
public abstract class AbstractConnector implements ServerConnector { | |||||
public abstract class AbstractConnector implements ServerConnector, | |||||
StateChangeHandler { | |||||
private ApplicationConnection connection; | private ApplicationConnection connection; | ||||
private String id; | private String id; | ||||
private HandlerManager handlerManager; | |||||
private Map<String, Collection<ClientRpc>> rpcImplementations; | private Map<String, Collection<ClientRpc>> rpcImplementations; | ||||
/* | /* | ||||
this.connection = connection; | this.connection = connection; | ||||
id = connectorId; | id = connectorId; | ||||
addStateChangeHandler(this); | |||||
init(); | init(); | ||||
} | } | ||||
// Client side can always receive message from the server | // Client side can always receive message from the server | ||||
return true; | 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)); | |||||
} | |||||
} | } |