package com.vaadin.terminal.gwt.client;
import java.util.ArrayList;
+import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
import java.util.Map;
import java.util.Set;
redirectTimer.schedule(1000 * sessionExpirationInterval);
}
- // 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");
-
- ArrayList<ComponentConnector> updatedComponentConnectors = new ArrayList<ComponentConnector>();
componentCaptionSizeChanges.clear();
Duration updateDuration = new Duration();
- int length = changes.length();
-
- VConsole.log(" * Creating connectors (if needed)");
- // 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);
- Connector paintable = connectorMap.getConnector(uidl
- .getId());
- if (null == paintable
- && !uidl.getTag().equals(
- configuration.getEncodedWindowTag())) {
- // create, initialize and register the paintable
- getConnector(uidl.getId(), uidl.getTag());
- }
- } catch (final Throwable e) {
- VConsole.error(e);
- }
- }
-
- VConsole.log(" * Updating connector states");
- // 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 connectorId = keyArray.get(i);
- Connector paintable = connectorMap
- .getConnector(connectorId);
- if (null != paintable) {
-
- JSONArray stateDataAndType = new JSONArray(
- states.getJavaScriptObject(connectorId));
-
- Object state = JsonDecoder.convertValue(
- stateDataAndType, connectorMap);
-
- paintable.setState((SharedState) state);
- }
- } catch (final Throwable e) {
- VConsole.error(e);
- }
- }
-
- VConsole.log(" * Passing UIDL to Vaadin 6 style connectors");
- // update paintables
- for (int i = 0; i < length; i++) {
- try {
- final UIDL change = changes.get(i).cast();
- final UIDL uidl = change.getChildUIDL(0);
- String connectorId = uidl.getId();
-
- if (!connectorMap.hasConnector(connectorId)
- && uidl.getTag().equals(
- configuration.getEncodedWindowTag())) {
- // First RootConnector update. Up until this
- // point the connectorId for RootConnector has
- // not been known
- connectorMap.registerConnector(connectorId, view);
- view.doInit(connectorId, ApplicationConnection.this);
- }
+ // Ensure that all connectors that we are about to update exist
+ createConnectorsIfNeeded(json);
- final ComponentConnector paintable = (ComponentConnector) connectorMap
- .getConnector(connectorId);
- if (paintable != null) {
- paintable.updateFromUIDL(uidl,
- ApplicationConnection.this);
- updatedComponentConnectors.add(paintable);
- } else {
- VConsole.error("Received update for "
- + uidl.getTag()
- + ", but there is no such paintable ("
- + connectorId + ") rendered.");
+ // Update states, do not fire events
+ updateConnectorState(json);
- }
+ // Update hierarchy, do not fire events
+ Collection<ConnectorHierarchyChangedEvent> pendingHierarchyChangeEvents = updateConnectorHierarchy(json);
- } catch (final Throwable e) {
- VConsole.error(e);
- }
- }
+ // Fire state change events (TODO)
+ VConsole.log(" * Sending state change events");
- if (json.containsKey("rpc")) {
- VConsole.log(" * Performing server to client RPC calls");
+ // Fire hierarchy change events
+ sendHierarchyChangeEvents(pendingHierarchyChangeEvents);
- JSONArray rpcCalls = new JSONArray(
- json.getJavaScriptObject("rpc"));
+ // Update of legacy (UIDL) style connectors
+ updateVaadin6StyleConnectors(json);
- int rpcLength = rpcCalls.size();
- for (int i = 0; i < rpcLength; i++) {
- try {
- JSONArray rpcCall = (JSONArray) rpcCalls.get(i);
- MethodInvocation invocation = parseMethodInvocation(rpcCall);
- VConsole.log("Server to client RPC call: "
- + invocation);
- rpcManager.applyInvocation(invocation,
- getConnectorMap());
- } catch (final Throwable e) {
- VConsole.error(e);
- }
- }
- }
+ // Handle any RPC invocations done on the server side
+ handleRpcInvocations(json);
if (json.containsKey("dd")) {
// response contains data for drag and drop service
}
+ private void createConnectorsIfNeeded(ValueMap json) {
+ VConsole.log(" * Creating connectors (if needed)");
+
+ JsArray<ValueMap> changes = json.getJSValueMapArray("changes");
+ // FIXME: This should be based on shared state, not the old
+ // "changes"
+ int length = changes.length();
+ for (int i = 0; i < length; i++) {
+ try {
+ final UIDL change = changes.get(i).cast();
+ final UIDL uidl = change.getChildUIDL(0);
+ String connectorId = uidl.getId();
+ Connector connector = connectorMap
+ .getConnector(connectorId);
+ if (connector != null) {
+ continue;
+ }
+
+ // Connector does not exist so we must create it
+ if (!uidl.getTag().equals(
+ configuration.getEncodedWindowTag())) {
+ // create, initialize and register the paintable
+ getConnector(uidl.getId(), uidl.getTag());
+ } else {
+ // First RootConnector update. Before this the
+ // RootConnector has been created but not
+ // initialized as the connector id has not been
+ // known
+ connectorMap.registerConnector(connectorId, view);
+ view.doInit(connectorId, ApplicationConnection.this);
+ }
+ } catch (final Throwable e) {
+ VConsole.error(e);
+ }
+ }
+ }
+
+ private void updateVaadin6StyleConnectors(ValueMap json) {
+ JsArray<ValueMap> changes = json.getJSValueMapArray("changes");
+ int length = changes.length();
+
+ VConsole.log(" * Passing UIDL to Vaadin 6 style connectors");
+ // update paintables
+ for (int i = 0; i < length; i++) {
+ try {
+ final UIDL change = changes.get(i).cast();
+ final UIDL uidl = change.getChildUIDL(0);
+ String connectorId = uidl.getId();
+
+ final ComponentConnector paintable = (ComponentConnector) connectorMap
+ .getConnector(connectorId);
+ if (paintable != null) {
+ paintable.updateFromUIDL(uidl,
+ ApplicationConnection.this);
+ } else {
+ VConsole.error("Received update for "
+ + uidl.getTag()
+ + ", but there is no such paintable ("
+ + connectorId + ") rendered.");
+
+ }
+
+ } catch (final Throwable e) {
+ VConsole.error(e);
+ }
+ }
+ }
+
+ private void sendHierarchyChangeEvents(
+ Collection<ConnectorHierarchyChangedEvent> pendingHierarchyChangeEvents) {
+ if (pendingHierarchyChangeEvents.isEmpty()) {
+ return;
+ }
+
+ VConsole.log(" * Sending hierarchy change events");
+ for (ConnectorHierarchyChangedEvent event : pendingHierarchyChangeEvents) {
+ event.getParent().connectorHierarchyChanged(event);
+ }
+
+ }
+
+ private void updateConnectorState(ValueMap json) {
+ VConsole.log(" * Updating connector states");
+ // 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 connectorId = keyArray.get(i);
+ Connector paintable = connectorMap
+ .getConnector(connectorId);
+ if (null != paintable) {
+
+ JSONArray stateDataAndType = new JSONArray(
+ states.getJavaScriptObject(connectorId));
+
+ Object state = JsonDecoder.convertValue(
+ stateDataAndType, connectorMap);
+
+ paintable.setState((SharedState) state);
+ }
+ } catch (final Throwable e) {
+ VConsole.error(e);
+ }
+ }
+ }
+
+ /**
+ * Updates the connector hierarchy and returns a list of events that
+ * should be fired after update of the hierarchy and the state is
+ * done.
+ *
+ * @param json
+ * The JSON containing the hierarchy information
+ * @return A collection of events that should be fired when update
+ * of hierarchy and state is complete
+ */
+ private Collection<ConnectorHierarchyChangedEvent> updateConnectorHierarchy(
+ ValueMap json) {
+ List<ConnectorHierarchyChangedEvent> events = new LinkedList<ConnectorHierarchyChangedEvent>();
+
+ VConsole.log(" * Updating connector hierarchy");
+ ValueMap hierarchies = json.getValueMap("hierarchy");
+ JsArrayString hierarchyKeys = hierarchies.getKeyArray();
+ for (int i = 0; i < hierarchyKeys.length(); i++) {
+ try {
+ String connectorId = hierarchyKeys.get(i);
+ Connector connector = connectorMap
+ .getConnector(connectorId);
+ if (!(connector instanceof ComponentContainerConnector)) {
+ VConsole.error("Retrieved a hierarchy update for a connector ("
+ + connectorId
+ + ") that is not a ComponentContainerConnector");
+ continue;
+ }
+ ComponentContainerConnector ccc = (ComponentContainerConnector) connector;
+
+ JsArrayString childConnectorIds = hierarchies
+ .getJSStringArray(connectorId);
+ int childConnectorSize = childConnectorIds.length();
+
+ List<Connector> newChildren = new ArrayList<Connector>();
+ for (int connectorIndex = 0; connectorIndex < childConnectorSize; connectorIndex++) {
+ String childConnectorId = childConnectorIds
+ .get(connectorIndex);
+ ComponentConnector childConnector = (ComponentConnector) connectorMap
+ .getConnector(childConnectorId);
+ newChildren.add(childConnector);
+ if (childConnector.getParent() != ccc) {
+ // Avoid extra calls to setParent
+ childConnector.setParent(ccc);
+ }
+ }
+
+ // TODO This check should be done on the server side in
+ // the future so the hierarchy update is only sent when
+ // something actually has changed
+ Collection<ComponentConnector> oldChildren = ccc
+ .getChildren();
+ boolean actuallyChanged = !Util.collectionsEquals(
+ oldChildren, newChildren);
+
+ if (!actuallyChanged) {
+ continue;
+ }
+
+ // Fire change event if the hierarchy has changed
+ ConnectorHierarchyChangedEvent event = GWT
+ .create(ConnectorHierarchyChangedEvent.class);
+ event.setOldChildren(oldChildren);
+ event.setParent(ccc);
+ ccc.setChildren((Collection) newChildren);
+ events.add(event);
+ } catch (final Throwable e) {
+ VConsole.error(e);
+ }
+ }
+ return events;
+
+ }
+
+ private void handleRpcInvocations(ValueMap json) {
+ if (json.containsKey("rpc")) {
+ VConsole.log(" * Performing server to client RPC calls");
+
+ JSONArray rpcCalls = new JSONArray(
+ json.getJavaScriptObject("rpc"));
+
+ int rpcLength = rpcCalls.size();
+ for (int i = 0; i < rpcLength; i++) {
+ try {
+ JSONArray rpcCall = (JSONArray) rpcCalls.get(i);
+ MethodInvocation invocation = parseMethodInvocation(rpcCall);
+ VConsole.log("Server to client RPC call: "
+ + invocation);
+ rpcManager.applyInvocation(invocation,
+ getConnectorMap());
+ } catch (final Throwable e) {
+ VConsole.error(e);
+ }
+ }
+ }
+
+ }
+
};
ApplicationConfiguration.runWhenWidgetsLoaded(c);
}
*/
public Widget getWidget();
- /**
- * Returns the parent {@link ComponentContainerConnector}
- *
- * @return
- */
- public ComponentContainerConnector getParent();
-
public LayoutManager getLayoutManager();
/**
* @return the server side height definition
*/
public String getDeclaredHeight();
+
+ /**
+ * Returns the parent of this connector. Can be null for only the root
+ * connector.
+ *
+ * @return The parent of this connector, as set by
+ * {@link #setParent(ComponentContainerConnector)}.
+ */
+ public ComponentContainerConnector getParent();
+
+ /**
+ * Sets the parent for this connector. This method should only be called by
+ * the framework to ensure that the connector hierarchy on the client side
+ * and the server side are in sync.
+ * <p>
+ * Note that calling this method does not fire a
+ * {@link ConnectorHierarchyChangedEvent}. The event is fired only when the
+ * whole hierarchy has been updated.
+ *
+ * @param parent
+ * The new parent of the connector
+ */
+ public void setParent(ComponentContainerConnector parent);
}
import com.google.gwt.user.client.ui.HasWidgets;
/**
- * An interface used by client-side paintables whose widget is a component
+ * An interface used by client-side connectors whose widget is a component
* container (implements {@link HasWidgets}).
*/
public interface ComponentContainerConnector extends ComponentConnector {
* must provide service for it's childen to show those elements for them.
* </p>
*
- * @param paintable
+ * @param connector
* Child component for which service is requested.
* @param uidl
* UIDL of the child component.
*/
- void updateCaption(ComponentConnector paintable, UIDL uidl);
+ void updateCaption(ComponentConnector connector, UIDL uidl);
/**
- * Returns the children for this paintable.
+ * Returns the children for this connector.
* <p>
- * The children for this paintable are defined as all
+ * The children for this connector are defined as all
* {@link ComponentConnector}s whose parent is this
* {@link ComponentContainerConnector}.
* </p>
*
- * @return A collection of children for this paintable. An empty collection
- * if there are no children.
+ * @return A collection of children for this connector. An empty collection
+ * if there are no children. Never returns null.
*/
public Collection<ComponentConnector> getChildren();
+ /**
+ * Sets the children for this connector. This method should only be called
+ * by the framework to ensure that the connector hierarchy on the client
+ * side and the server side are in sync.
+ * <p>
+ * Note that calling this method does not call
+ * {@link #connectorHierarchyChanged(ConnectorHierarchyChangedEvent)}. The
+ * event method is called only when the hierarchy has been updated for all
+ * connectors.
+ *
+ * @param children
+ * The new child connectors
+ */
+ public void setChildren(Collection<ComponentConnector> children);
+
+ /**
+ * Called when the child connector hierarchy of this connector has changed.
+ * When this method is called the full hierarchy has been updated so
+ * {@link #getChildren()} returns the new child connectors of this
+ * connector.
+ *
+ * @param event
+ * An event containing additional information about how the
+ * hierarchy has changed.
+ */
+ public void connectorHierarchyChanged(ConnectorHierarchyChangedEvent event);
+
}
--- /dev/null
+package com.vaadin.terminal.gwt.client;
+
+import java.util.Collection;
+
+/**
+ * Event for containing data related to a change in the {@link Connector}
+ * hierarchy. A {@link ConnectorHierarchyChangedEvent} is fired when an update
+ * from the server has been fully processed and all hierarchy updates have been
+ * completed.
+ *
+ * @author Vaadin Ltd
+ * @version @VERSION@
+ * @since 7.0.0
+ *
+ */
+public class ConnectorHierarchyChangedEvent {
+ Collection<ComponentConnector> oldChildren;
+ private ComponentContainerConnector parent;
+
+ public ConnectorHierarchyChangedEvent() {
+ }
+
+ /**
+ * Returns a collection of the old children for the connector. This was the
+ * state before the update was received from the server.
+ *
+ * @return A collection of old child connectors. Never returns null.
+ */
+ public Collection<ComponentConnector> getOldChildren() {
+ return oldChildren;
+ }
+
+ /**
+ * Sets the collection of the old children for the connector.
+ *
+ * @param oldChildren
+ * The old child connectors. Must not be null.
+ */
+ public void setOldChildren(Collection<ComponentConnector> oldChildren) {
+ this.oldChildren = oldChildren;
+ }
+
+ /**
+ * Returns the {@link ComponentContainerConnector} for which this event
+ * occurred.
+ *
+ * @return The {@link ComponentContainerConnector} whose child collection
+ * has changed. Never returns null.
+ */
+ public ComponentContainerConnector getParent() {
+ return parent;
+ }
+
+ /**
+ * Sets the {@link ComponentContainerConnector} for which this event
+ * occurred.
+ *
+ * @param The
+ * {@link ComponentContainerConnector} whose child collection has
+ * changed.
+ */
+ public void setParent(ComponentContainerConnector parent) {
+ this.parent = parent;
+ }
+
+}
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Collection;
+import java.util.Iterator;
import java.util.List;
import com.google.gwt.core.client.Scheduler;
boolean touchEvent = Util.isTouchEvent(event);
return touchEvent || event.getButton() == Event.BUTTON_LEFT;
}
+
+ /**
+ * Performs a shallow comparison of the collections.
+ *
+ * @param collection1 The first collection
+ * @param collection2 The second collection
+ * @return true if the collections contain the same elements in the same
+ * order, false otherwise
+ */
+ public static boolean collectionsEquals(Collection collection1, Collection collection2) {
+ if (collection1 == null) {
+ return collection2 == null;
+ }
+ if (collection2 == null) {
+ return false;
+ }
+ Iterator<Object> collection1Iterator = collection1.iterator();
+ Iterator<Object> collection2Iterator = collection2.iterator();
+
+ while (collection1Iterator.hasNext()) {
+ if (!collection2Iterator.hasNext()) {
+ return false;
+ }
+ Object collection1Object = collection1Iterator.next();
+ Object collection2Object = collection2Iterator.next();
+ if (collection1Object != collection2Object) {
+ return false;
+ }
+ }
+ if (collection2Iterator.hasNext()) {
+ return false;
+ }
+
+ return true;
+ }
}
public abstract class AbstractComponentConnector extends AbstractConnector
implements ComponentConnector {
+ private ComponentContainerConnector parent;
+
// Generic UIDL parameter names, to be moved to shared state.
// Attributes are here mainly if they apply to all paintable widgets or
// affect captions - otherwise, they are in the relevant subclasses.
return GWT.create(ComponentState.class);
}
- public ComponentContainerConnector getParent() {
- // FIXME: Hierarchy should be set by framework instead of looked up here
- ConnectorMap paintableMap = ConnectorMap.get(getConnection());
-
- Widget w = getWidget();
- while (true) {
- w = w.getParent();
- if (w == null) {
- return null;
- }
- if (paintableMap.isConnector(w)) {
- return (ComponentContainerConnector) paintableMap
- .getConnector(w);
- }
- }
- }
-
protected static boolean isRealUpdate(UIDL uidl) {
return !isCachedUpdate(uidl) && !uidl.getBooleanAttribute("invisible")
&& !uidl.hasAttribute("deferred");
public LayoutManager getLayoutManager() {
return LayoutManager.get(getConnection());
}
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see com.vaadin.terminal.gwt.client.Connector#getParent()
+ */
+ public ComponentContainerConnector getParent() {
+ return parent;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * com.vaadin.terminal.gwt.client.Connector#setParent(com.vaadin.terminal
+ * .gwt.client.ComponentContainerConnector)
+ */
+ public void setParent(ComponentContainerConnector parent) {
+ this.parent = parent;
+ }
+
}
*/
package com.vaadin.terminal.gwt.client.ui;
-import java.util.ArrayList;
import java.util.Collection;
+import java.util.LinkedList;
-import com.google.gwt.user.client.ui.HasOneWidget;
-import com.google.gwt.user.client.ui.HasWidgets;
-import com.google.gwt.user.client.ui.Widget;
import com.vaadin.terminal.gwt.client.ComponentConnector;
import com.vaadin.terminal.gwt.client.ComponentContainerConnector;
-import com.vaadin.terminal.gwt.client.ConnectorMap;
+import com.vaadin.terminal.gwt.client.ConnectorHierarchyChangedEvent;
+import com.vaadin.terminal.gwt.client.Util;
public abstract class AbstractComponentContainerConnector extends
AbstractComponentConnector implements ComponentContainerConnector {
+ Collection<ComponentConnector> children;
+
/**
* Default constructor
*/
public AbstractComponentContainerConnector() {
}
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * com.vaadin.terminal.gwt.client.ComponentContainerConnector#getChildren()
+ */
public Collection<ComponentConnector> getChildren() {
- Collection<ComponentConnector> children = new ArrayList<ComponentConnector>();
-
- addDescendantPaintables(getWidget(), children,
- ConnectorMap.get(getConnection()));
+ if (children == null) {
+ return new LinkedList<ComponentConnector>();
+ }
return children;
}
- private static void addDescendantPaintables(Widget widget,
- Collection<ComponentConnector> paintables, ConnectorMap paintableMap) {
- // FIXME: Store hierarchy instead of doing lookup every time
-
- if (widget instanceof HasWidgets) {
- for (Widget child : (HasWidgets) widget) {
- addIfPaintable(child, paintables, paintableMap);
- }
- } else if (widget instanceof HasOneWidget) {
- Widget child = ((HasOneWidget) widget).getWidget();
- addIfPaintable(child, paintables, paintableMap);
- }
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * com.vaadin.terminal.gwt.client.ComponentContainerConnector#setChildren
+ * (java.util.Collection)
+ */
+ public void setChildren(Collection<ComponentConnector> children) {
+ this.children = children;
}
- private static void addIfPaintable(Widget widget,
- Collection<ComponentConnector> paintables, ConnectorMap paintableMap) {
- ComponentConnector paintable = paintableMap.getConnector(widget);
- if (paintable != null) {
- // If widget is a paintable, add it to the collection
- paintables.add(paintable);
- } else {
- // Else keep looking for paintables inside the widget
- addDescendantPaintables(widget, paintables, paintableMap);
- }
+ /*
+ * (non-Javadoc)
+ *
+ * @see com.vaadin.terminal.gwt.client.ComponentContainerConnector#
+ * connectorHierarchyChanged
+ * (com.vaadin.terminal.gwt.client.ConnectorHierarchyChangedEvent)
+ */
+ public void connectorHierarchyChanged(ConnectorHierarchyChangedEvent event) {
+ //TODO Remove debug info
+ System.out.println("Hierarchy changed for " + Util.getSimpleName(this));
+ System.out.println("* Old children: " + event.getOldChildren());
+ System.out.println("* New children: " + getChildren());
}
-
}
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collection;
+import java.util.Collections;
import java.util.GregorianCalendar;
import java.util.HashMap;
import java.util.HashSet;
import com.vaadin.ui.AbstractComponent;
import com.vaadin.ui.AbstractField;
import com.vaadin.ui.Component;
+import com.vaadin.ui.ComponentContainer;
+import com.vaadin.ui.Panel;
import com.vaadin.ui.Root;
/**
windowCache);
}
+ // TODO These seem unnecessary and could be removed/replaced by looping
+ // through paintQueue without removing paintables from it
LinkedList<Paintable> stateQueue = new LinkedList<Paintable>();
LinkedList<Paintable> rpcPendingQueue = new LinkedList<Paintable>();
+ LinkedList<Paintable> hierarchyPendingQueue = new LinkedList<Paintable>();
if (paintables != null) {
final Paintable p = paintQueue.removeFirst();
// for now, all painted components may need a state refresh
stateQueue.push(p);
+ // also a hierarchy update
+ hierarchyPendingQueue.push(p);
// ... and RPC calls to be sent
rpcPendingQueue.push(p);
outWriter.print("], "); // close changes
if (!stateQueue.isEmpty()) {
- // paint shared state
+ // send shared state to client
// for now, send the complete state of all modified and new
// components
outWriter.append(sharedStates.toString());
outWriter.print(", "); // close states
}
+ if (!hierarchyPendingQueue.isEmpty()) {
+ // Send update hierarchy information to the client.
+
+ // This could be optimized aswell to send only info if hierarchy has
+ // actually changed. Much like with the shared state. Note though
+ // that an empty hierarchy is information aswell (e.g. change from 1
+ // child to 0 children)
+
+ outWriter.print("\"hierarchy\":");
+
+ JSONObject hierarchyInfo = new JSONObject();
+ for (Paintable p : hierarchyPendingQueue) {
+ if (p instanceof ComponentContainer) {
+ ComponentContainer cc = (ComponentContainer) p;
+ String connectorId = paintableIdMap.get(cc);
+ JSONArray children = new JSONArray();
+
+ Iterator<Component> iterator = getChildComponentIterator(cc);
+ while (iterator.hasNext()) {
+ Component child = iterator.next();
+ if (child.getState().isVisible()) {
+ String childConnectorId = paintableIdMap.get(child);
+ children.put(childConnectorId);
+ }
+ }
+ try {
+ hierarchyInfo.put(connectorId, children);
+ } catch (JSONException e) {
+ throw new PaintException(
+ "Failed to send hierarchy information about "
+ + connectorId + " to the client: "
+ + e.getMessage());
+ }
+ }
+ }
+ outWriter.append(hierarchyInfo.toString());
+ outWriter.print(", "); // close states
+
+ }
// send server to client RPC calls for components in the root, in call
// order
}
}
+ private static class NullIterator<E> implements Iterator<E> {
+
+ public boolean hasNext() {
+ return false;
+ }
+
+ public E next() {
+ return null;
+ }
+
+ public void remove() {
+ }
+
+ }
+
+ private Iterator<Component> getChildComponentIterator(ComponentContainer cc) {
+ if (cc instanceof Panel) {
+ // This is so wrong.. (#2924)
+ if (((Panel) cc).getContent() == null) {
+ return new NullIterator<Component>();
+ } else {
+ return Collections.singleton(
+ (Component) ((Panel) cc).getContent()).iterator();
+ }
+ }
+ return cc.getComponentIterator();
+ }
+
/**
* Collects all pending RPC calls from listed {@link Paintable}s and clears
* their RPC queues.
writeUidlResponse(true, pWriter, root, false);
pWriter.print("}");
String initialUIDL = sWriter.toString();
+ System.out.println("Initial UIDL:");
+ System.out.println(initialUIDL);
return initialUIDL;
}
import com.vaadin.terminal.Resource;
import com.vaadin.terminal.Sizeable;
import com.vaadin.terminal.VariableOwner;
+import com.vaadin.terminal.gwt.client.ComponentState;
/**
* {@code Component} is the top-level interface that is and must be implemented
*/
public Locale getLocale();
+ /**
+ * Returns the current shared state bean for the component. The state (or
+ * changes to it) is communicated from the server to the client.
+ *
+ * Subclasses can use a more specific return type for this method.
+ *
+ * @return The state object for the component
+ *
+ * @since 7.0
+ */
+ public ComponentState getState();
+
/**
* The child components of the component must call this method when they
* need repainting. The call must be made even in the case in which the