json.getValueMap("dd"));
}
+ unregisterRemovedConnectors();
VConsole.log("updateFromUidl: "
+ updateDuration.elapsedMillis() + " ms");
}
}
- if (repaintAll) {
- /*
- * idToPaintableDetail is already cleanded at the start of
- * the changeset handling, bypass cleanup.
- */
- connectorMap.purgeUnregistryBag(false);
- } else {
- connectorMap.purgeUnregistryBag(true);
- }
-
// TODO build profiling for widget impl loading time
final long prosessingTime = (new Date().getTime())
}
+ private void unregisterRemovedConnectors() {
+ List<ServerConnector> currentConnectors = new ArrayList<ServerConnector>(
+ connectorMap.getConnectors());
+ for (ServerConnector c : currentConnectors) {
+ if (c instanceof ComponentConnector) {
+ ComponentConnector cc = (ComponentConnector) c;
+ if (cc.getParent() == null
+ && !(cc instanceof RootConnector)) {
+ // The connector has been detached from the
+ // hierarchy, unregister it and any possible
+ // children. The RootConnector should never be
+ // unregistered even though it has no parent.
+ connectorMap.unregisterConnector(cc);
+ } else if (cc.getParent() != null
+ && !cc.getParent().getChildren().contains(cc)) {
+ VConsole.error("ERROR: Connector is connected to a parent but the parent does not contain the connector");
+ }
+ }
+
+ }
+
+ }
+
private void createConnectorsIfNeeded(ValueMap json) {
VConsole.log(" * Creating connectors (if needed)");
.get(connectorIndex);
ComponentConnector childConnector = (ComponentConnector) connectorMap
.getConnector(childConnectorId);
+ if (childConnector == null) {
+ VConsole.error("Hierarchy claims that "
+ + childConnectorId + " is a child for "
+ + connectorId + " ("
+ + connector.getClass().getName()
+ + ") but no connector with id "
+ + childConnectorId
+ + " has been registered");
+ continue;
+ }
newChildren.add(childConnector);
if (childConnector.getParent() != ccc) {
// Avoid extra calls to setParent
event.setParent(ccc);
ccc.setChildren((List) newChildren);
events.add(event);
+
+ // Remove parent for children that are no longer
+ // attached to this (avoid updating children if they
+ // have already been assigned to a new parent)
+ for (ComponentConnector oldChild : oldChildren) {
+ if (oldChild.getParent() != ccc) {
+ continue;
+ }
+
+ // TODO This could probably be optimized
+ if (!newChildren.contains(oldChild)) {
+ oldChild.setParent(null);
+ }
+ }
} catch (final Throwable e) {
VConsole.error(e);
}
@Deprecated
public void unregisterPaintable(ServerConnector p) {
- connectorMap.unregisterConnector(p);
+ System.out.println("unregisterPaintable (unnecessarily) called for "
+ + p.getConnectorId());
+ // connectorMap.unregisterConnector(p);
}
public VTooltip getVTooltip() {
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
-import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
-import java.util.Set;
import com.google.gwt.core.client.GWT;
import com.google.gwt.dom.client.Element;
private final ComponentDetailMap idToComponentDetail = ComponentDetailMap
.create();
- private Set<String> unregistryBag = new HashSet<String>();
-
/**
* Returns a {@link ServerConnector} by its id
*
* the connector to remove
*/
public void unregisterConnector(ServerConnector connector) {
-
- // add to unregistry queue
-
if (connector == null) {
- VConsole.error("WARN: Trying to unregister null connector");
+ VConsole.error("Trying to unregister null connector");
return;
}
- String id = connector.getConnectorId();
+
+ String connectorId = connector.getConnectorId();
+ VConsole.log("Unregistering connector " + connectorId + " ("
+ + connector.getClass().getName() + ")");
+
+ // Warn if widget is still attached to DOM. It should never be at this
+ // point.
Widget widget = null;
if (connector instanceof ComponentConnector) {
widget = ((ComponentConnector) connector).getWidget();
}
- if (id == null) {
- VConsole.log("Tried to unregister a "
- + connector.getClass().getName() + " (" + id
- + ") which was not registered");
- } else {
- unregistryBag.add(id);
- }
- if (widget != null && widget instanceof HasWidgets) {
- unregisterChildConnectors((HasWidgets) widget);
+ if (widget != null && widget.isAttached()) {
+ VConsole.log("Widget for unregistered connector " + connectorId
+ + " is still attached to the DOM.");
}
+ idToComponentDetail.remove(connectorId);
+ idToConnector.remove(connectorId);
+ if (connector instanceof ComponentContainerConnector) {
+ for (ComponentConnector child : ((ComponentContainerConnector) connector)
+ .getChildren()) {
+ unregisterConnector(child);
+ }
+ }
}
- public ComponentConnector[] getRegisteredComponentConnectors() {
+ /**
+ * Gets all registered {@link ComponentConnector} instances
+ *
+ * @return An array of all registered {@link ComponentConnector} instances
+ */
+ public ComponentConnector[] getComponentConnectors() {
ArrayList<ComponentConnector> result = new ArrayList<ComponentConnector>();
for (ServerConnector connector : getConnectors()) {
if (connector instanceof ComponentConnector) {
- ComponentConnector componentConnector = (ComponentConnector) connector;
- if (!unregistryBag.contains(connector.getConnectorId())) {
- result.add(componentConnector);
- }
+ result.add((ComponentConnector) connector);
}
}
return result.toArray(new ComponentConnector[result.size()]);
}
- void purgeUnregistryBag(boolean unregisterConnectors) {
- if (unregisterConnectors) {
- for (String connectorId : unregistryBag) {
- // TODO purge shared state for pid
- ServerConnector connector = getConnector(connectorId);
- if (connector == null) {
- /*
- * this should never happen, but it does :-( See e.g.
- * com.vaadin.tests.components.accordion.RemoveTabs (with
- * test script)
- */
- VConsole.error("Tried to unregister component (id="
- + connectorId
- + ") that is never registered (or already unregistered)");
- continue;
- }
- VConsole.log("Unregistering connector "
- + connector.getClass().getName() + " " + connectorId);
- Widget widget = null;
- if (connector instanceof ComponentConnector) {
- widget = ((ComponentConnector) connector).getWidget();
- }
-
- // check if can be cleaned
- if (widget == null || !widget.isAttached()) {
- // clean reference to paintable
- idToComponentDetail.remove(connectorId);
- idToConnector.remove(connectorId);
- }
- /*
- * else NOP : same component has been reattached to another
- * parent or replaced by another component implementation.
- */
- }
- }
-
- unregistryBag.clear();
- }
-
/**
* Unregisters the child connectors for the given container recursively.
*
* @param container
* The container that contains the connectors that should be
* unregistered
+ * @deprecated Only here for now to support the broken VScrollTable behavior
*/
+ @Deprecated
public void unregisterChildConnectors(HasWidgets container) {
// FIXME: This should be based on the paintable hierarchy
final Iterator<Widget> it = container.iterator();
ComponentConnector p = getConnector(w);
if (p != null) {
// This will unregister the paintable and all its children
- unregisterConnector(p);
- } else if (w instanceof HasWidgets) {
+ idToComponentDetail.remove(p.getConnectorId());
+ idToConnector.remove(p.getConnectorId());
+ }
+
+ if (w instanceof HasWidgets) {
// For normal widget containers, unregister the children
unregisterChildConnectors((HasWidgets) w);
}
ConnectorMap paintableMap = connection.getConnectorMap();
ComponentConnector[] paintableWidgets = paintableMap
- .getRegisteredComponentConnectors();
+ .getComponentConnectors();
int passes = 0;
Duration totalDuration = new Duration();
public void foceLayout() {
ConnectorMap paintableMap = connection.getConnectorMap();
ComponentConnector[] paintableWidgets = paintableMap
- .getRegisteredComponentConnectors();
+ .getComponentConnectors();
for (ComponentConnector vPaintableWidget : paintableWidgets) {
MeasuredSize measuredSize = getMeasuredSize(vPaintableWidget);
measuredSize.setHeightNeedsUpdate();
} else {
VConsole.error("Parent of connector "
+ getClass().getName()
- + " is null. This is typically an indication of a broken component hierarchy");
+ + " ("
+ + getConnectorId()
+ + ") is null. This is typically an indication of a broken component hierarchy");
}
}
* GWT.create().
*/
protected <T extends ServerRpc> T initRPC(T clientToServerRpc) {
- ((InitializableClientToServerRpc) clientToServerRpc).initRpc(getConnectorId(),
- getConnection());
+ ((InitializableClientToServerRpc) clientToServerRpc).initRpc(
+ getConnectorId(), getConnection());
return clientToServerRpc;
}
@Override
public void connectorHierarchyChanged(ConnectorHierarchyChangedEvent event) {
super.connectorHierarchyChanged(event);
+ // We always have 1 child, Panel takes care of ensuring content is never
+ // null
+ ComponentConnector newChild = getChildren().get(0);
+ Widget newChildWidget = newChild.getWidget();
- possiblyUnregisterOldChild(event);
-
- // We always have 0 or 1 child
- ComponentConnector newChild = null;
- if (getChildren().size() != 0) {
- // We now have one child
- newChild = getChildren().get(0);
- }
-
- getWidget().setWidget(newChild.getWidget());
+ getWidget().setWidget(newChildWidget);
}
- private void possiblyUnregisterOldChild(ConnectorHierarchyChangedEvent event) {
- // Did we have a child that needs to be unregistered?
- if (event.getOldChildren().size() != 0) {
- ComponentConnector oldChild = event.getOldChildren().get(0);
- // We had a child, unregister it
- // TODO Should be handled by the framework
- if (oldChild.getParent() == null) {
- getConnection().unregisterPaintable(oldChild);
- }
- }
- }
}