json.getValueMap("dd")); | json.getValueMap("dd")); | ||||
} | } | ||||
unregisterRemovedConnectors(); | |||||
VConsole.log("updateFromUidl: " | VConsole.log("updateFromUidl: " | ||||
+ updateDuration.elapsedMillis() + " ms"); | + 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 | // TODO build profiling for widget impl loading time | ||||
final long prosessingTime = (new Date().getTime()) | 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) { | private void createConnectorsIfNeeded(ValueMap json) { | ||||
VConsole.log(" * Creating connectors (if needed)"); | VConsole.log(" * Creating connectors (if needed)"); | ||||
.get(connectorIndex); | .get(connectorIndex); | ||||
ComponentConnector childConnector = (ComponentConnector) connectorMap | ComponentConnector childConnector = (ComponentConnector) connectorMap | ||||
.getConnector(childConnectorId); | .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); | newChildren.add(childConnector); | ||||
if (childConnector.getParent() != ccc) { | if (childConnector.getParent() != ccc) { | ||||
// Avoid extra calls to setParent | // Avoid extra calls to setParent | ||||
event.setParent(ccc); | event.setParent(ccc); | ||||
ccc.setChildren((List) newChildren); | ccc.setChildren((List) newChildren); | ||||
events.add(event); | 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) { | } catch (final Throwable e) { | ||||
VConsole.error(e); | VConsole.error(e); | ||||
} | } | ||||
@Deprecated | @Deprecated | ||||
public void unregisterPaintable(ServerConnector p) { | public void unregisterPaintable(ServerConnector p) { | ||||
connectorMap.unregisterConnector(p); | |||||
System.out.println("unregisterPaintable (unnecessarily) called for " | |||||
+ p.getConnectorId()); | |||||
// connectorMap.unregisterConnector(p); | |||||
} | } | ||||
public VTooltip getVTooltip() { | public VTooltip getVTooltip() { |
import java.util.Collection; | import java.util.Collection; | ||||
import java.util.Collections; | import java.util.Collections; | ||||
import java.util.HashMap; | import java.util.HashMap; | ||||
import java.util.HashSet; | |||||
import java.util.Iterator; | import java.util.Iterator; | ||||
import java.util.Map; | import java.util.Map; | ||||
import java.util.Set; | |||||
import com.google.gwt.core.client.GWT; | import com.google.gwt.core.client.GWT; | ||||
import com.google.gwt.dom.client.Element; | import com.google.gwt.dom.client.Element; | ||||
private final ComponentDetailMap idToComponentDetail = ComponentDetailMap | private final ComponentDetailMap idToComponentDetail = ComponentDetailMap | ||||
.create(); | .create(); | ||||
private Set<String> unregistryBag = new HashSet<String>(); | |||||
/** | /** | ||||
* Returns a {@link ServerConnector} by its id | * Returns a {@link ServerConnector} by its id | ||||
* | * | ||||
* the connector to remove | * the connector to remove | ||||
*/ | */ | ||||
public void unregisterConnector(ServerConnector connector) { | public void unregisterConnector(ServerConnector connector) { | ||||
// add to unregistry queue | |||||
if (connector == null) { | if (connector == null) { | ||||
VConsole.error("WARN: Trying to unregister null connector"); | |||||
VConsole.error("Trying to unregister null connector"); | |||||
return; | 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; | Widget widget = null; | ||||
if (connector instanceof ComponentConnector) { | if (connector instanceof ComponentConnector) { | ||||
widget = ((ComponentConnector) connector).getWidget(); | 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>(); | ArrayList<ComponentConnector> result = new ArrayList<ComponentConnector>(); | ||||
for (ServerConnector connector : getConnectors()) { | for (ServerConnector connector : getConnectors()) { | ||||
if (connector instanceof ComponentConnector) { | 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()]); | 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. | * Unregisters the child connectors for the given container recursively. | ||||
* | * | ||||
* @param container | * @param container | ||||
* The container that contains the connectors that should be | * The container that contains the connectors that should be | ||||
* unregistered | * unregistered | ||||
* @deprecated Only here for now to support the broken VScrollTable behavior | |||||
*/ | */ | ||||
@Deprecated | |||||
public void unregisterChildConnectors(HasWidgets container) { | public void unregisterChildConnectors(HasWidgets container) { | ||||
// FIXME: This should be based on the paintable hierarchy | // FIXME: This should be based on the paintable hierarchy | ||||
final Iterator<Widget> it = container.iterator(); | final Iterator<Widget> it = container.iterator(); | ||||
ComponentConnector p = getConnector(w); | ComponentConnector p = getConnector(w); | ||||
if (p != null) { | if (p != null) { | ||||
// This will unregister the paintable and all its children | // 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 | // For normal widget containers, unregister the children | ||||
unregisterChildConnectors((HasWidgets) w); | unregisterChildConnectors((HasWidgets) w); | ||||
} | } |
ConnectorMap paintableMap = connection.getConnectorMap(); | ConnectorMap paintableMap = connection.getConnectorMap(); | ||||
ComponentConnector[] paintableWidgets = paintableMap | ComponentConnector[] paintableWidgets = paintableMap | ||||
.getRegisteredComponentConnectors(); | |||||
.getComponentConnectors(); | |||||
int passes = 0; | int passes = 0; | ||||
Duration totalDuration = new Duration(); | Duration totalDuration = new Duration(); | ||||
public void foceLayout() { | public void foceLayout() { | ||||
ConnectorMap paintableMap = connection.getConnectorMap(); | ConnectorMap paintableMap = connection.getConnectorMap(); | ||||
ComponentConnector[] paintableWidgets = paintableMap | ComponentConnector[] paintableWidgets = paintableMap | ||||
.getRegisteredComponentConnectors(); | |||||
.getComponentConnectors(); | |||||
for (ComponentConnector vPaintableWidget : paintableWidgets) { | for (ComponentConnector vPaintableWidget : paintableWidgets) { | ||||
MeasuredSize measuredSize = getMeasuredSize(vPaintableWidget); | MeasuredSize measuredSize = getMeasuredSize(vPaintableWidget); | ||||
measuredSize.setHeightNeedsUpdate(); | measuredSize.setHeightNeedsUpdate(); |
} else { | } else { | ||||
VConsole.error("Parent of connector " | VConsole.error("Parent of connector " | ||||
+ getClass().getName() | + 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(). | * GWT.create(). | ||||
*/ | */ | ||||
protected <T extends ServerRpc> T initRPC(T clientToServerRpc) { | protected <T extends ServerRpc> T initRPC(T clientToServerRpc) { | ||||
((InitializableClientToServerRpc) clientToServerRpc).initRpc(getConnectorId(), | |||||
getConnection()); | |||||
((InitializableClientToServerRpc) clientToServerRpc).initRpc( | |||||
getConnectorId(), getConnection()); | |||||
return clientToServerRpc; | return clientToServerRpc; | ||||
} | } | ||||
@Override | @Override | ||||
public void connectorHierarchyChanged(ConnectorHierarchyChangedEvent event) { | public void connectorHierarchyChanged(ConnectorHierarchyChangedEvent event) { | ||||
super.connectorHierarchyChanged(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); | |||||
} | |||||
} | |||||
} | |||||
} | } |