From: Artur Signell Date: Tue, 3 Apr 2012 07:46:59 +0000 (+0300) Subject: Updated AbsoluteLayout to use hierarchy and state change events X-Git-Tag: 7.0.0.alpha2~143 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=68bd7a21eeb64909d55efbd147e5595feb21f993;p=vaadin-framework.git Updated AbsoluteLayout to use hierarchy and state change events --- diff --git a/src/com/vaadin/terminal/gwt/client/ui/AbsoluteLayoutConnector.java b/src/com/vaadin/terminal/gwt/client/ui/AbsoluteLayoutConnector.java index 72386400fe..51596adead 100644 --- a/src/com/vaadin/terminal/gwt/client/ui/AbsoluteLayoutConnector.java +++ b/src/com/vaadin/terminal/gwt/client/ui/AbsoluteLayoutConnector.java @@ -3,20 +3,23 @@ */ package com.vaadin.terminal.gwt.client.ui; -import java.util.HashSet; -import java.util.Iterator; +import java.util.HashMap; +import java.util.Map; import com.google.gwt.core.client.GWT; import com.google.gwt.dom.client.Style; import com.google.gwt.dom.client.Style.Unit; import com.google.gwt.user.client.Element; import com.google.gwt.user.client.ui.Widget; -import com.vaadin.terminal.gwt.client.ApplicationConnection; import com.vaadin.terminal.gwt.client.ComponentConnector; +import com.vaadin.terminal.gwt.client.ComponentState; +import com.vaadin.terminal.gwt.client.Connector; +import com.vaadin.terminal.gwt.client.ConnectorHierarchyChangeEvent; import com.vaadin.terminal.gwt.client.DirectionalManagedLayout; -import com.vaadin.terminal.gwt.client.UIDL; +import com.vaadin.terminal.gwt.client.VCaption; import com.vaadin.terminal.gwt.client.communication.RpcProxy; import com.vaadin.terminal.gwt.client.communication.ServerRpc; +import com.vaadin.terminal.gwt.client.communication.StateChangeEvent; import com.vaadin.terminal.gwt.client.ui.VAbsoluteLayout.AbsoluteWrapper; import com.vaadin.ui.AbsoluteLayout; @@ -24,6 +27,25 @@ import com.vaadin.ui.AbsoluteLayout; public class AbsoluteLayoutConnector extends AbstractComponentContainerConnector implements DirectionalManagedLayout { + public static class AbsoluteLayoutState extends ComponentState { + // Maps each component to a position + private Map connectorToCssPosition = new HashMap(); + + public String getConnectorPosition(Connector connector) { + return connectorToCssPosition.get(connector.getConnectorId()); + } + + public Map getConnectorToCssPosition() { + return connectorToCssPosition; + } + + public void setConnectorToCssPosition( + Map componentToCssPosition) { + connectorToCssPosition = componentToCssPosition; + } + + } + public interface AbsoluteLayoutServerRPC extends LayoutClickRPC, ServerRpc { } @@ -45,49 +67,35 @@ public class AbsoluteLayoutConnector extends private AbsoluteLayoutServerRPC rpc; + private Map connectorIdToComponentWrapper = new HashMap(); + @Override protected void init() { super.init(); rpc = RpcProxy.create(AbsoluteLayoutServerRPC.class, this); } - @Override - public void updateFromUIDL(UIDL uidl, ApplicationConnection client) { - getWidget().client = client; - // TODO margin handling - super.updateFromUIDL(uidl, client); - if (!isRealUpdate(uidl)) { - return; - } + public void updateCaption(ComponentConnector component) { + VAbsoluteLayout absoluteLayoutWidget = getWidget(); + AbsoluteWrapper componentWrapper = getWrapper(component); - clickEventHandler.handleEventHandlerRegistration(); + boolean captionIsNeeded = VCaption.isNeeded(component.getState()); + + VCaption caption = componentWrapper.getCaption(); - HashSet unrenderedPids = new HashSet( - getWidget().pidToComponentWrappper.keySet()); - - for (Iterator childIterator = uidl.getChildIterator(); childIterator - .hasNext();) { - UIDL cc = (UIDL) childIterator.next(); - if (cc.getTag().equals("cc")) { - UIDL componentUIDL = cc.getChildUIDL(0); - unrenderedPids.remove(componentUIDL.getId()); - getWidget().getWrapper(client, componentUIDL) - .updateFromUIDL(cc); + if (captionIsNeeded) { + if (caption == null) { + caption = new VCaption(component, getConnection()); + absoluteLayoutWidget.add(caption); + } + caption.updateCaption(); + componentWrapper.updateCaptionPosition(); + } else { + if (caption != null) { + caption.removeFromParent(); } } - for (String pid : unrenderedPids) { - AbsoluteWrapper absoluteWrapper = getWidget().pidToComponentWrappper - .get(pid); - getWidget().pidToComponentWrappper.remove(pid); - absoluteWrapper.destroy(); - } - } - - public void updateCaption(ComponentConnector component) { - AbsoluteWrapper parent2 = (AbsoluteWrapper) (component.getWidget()) - .getParent(); - parent2.updateCaption(); } @Override @@ -100,6 +108,56 @@ public class AbsoluteLayoutConnector extends return (VAbsoluteLayout) super.getWidget(); } + @Override + public AbsoluteLayoutState getState() { + return (AbsoluteLayoutState) super.getState(); + } + + @Override + public void onStateChanged(StateChangeEvent stateChangeEvent) { + super.onStateChanged(stateChangeEvent); + clickEventHandler.handleEventHandlerRegistration(); + + // TODO Margin handling + + for (ComponentConnector child : getChildren()) { + getWrapper(child).setPosition( + getState().getConnectorPosition(child)); + } + }; + + private AbsoluteWrapper getWrapper(ComponentConnector child) { + String childId = child.getConnectorId(); + AbsoluteWrapper wrapper = connectorIdToComponentWrapper.get(childId); + if (wrapper != null) { + return wrapper; + } + + wrapper = new AbsoluteWrapper(child.getWidget()); + connectorIdToComponentWrapper.put(childId, wrapper); + getWidget().add(wrapper); + return wrapper; + + } + + @Override + public void onConnectorHierarchyChange(ConnectorHierarchyChangeEvent event) { + super.onConnectorHierarchyChange(event); + + for (ComponentConnector child : getChildren()) { + getWrapper(child); + } + + for (ComponentConnector oldChild : event.getOldChildren()) { + if (oldChild.getParent() != this) { + String connectorId = oldChild.getConnectorId(); + AbsoluteWrapper absoluteWrapper = connectorIdToComponentWrapper + .remove(connectorId); + absoluteWrapper.destroy(); + } + } + } + public void layoutVertically() { VAbsoluteLayout layout = getWidget(); for (ComponentConnector paintable : getChildren()) { @@ -134,8 +192,7 @@ public class AbsoluteLayoutConnector extends public void layoutHorizontally() { VAbsoluteLayout layout = getWidget(); for (ComponentConnector paintable : getChildren()) { - Widget widget = paintable.getWidget(); - AbsoluteWrapper wrapper = (AbsoluteWrapper) widget.getParent(); + AbsoluteWrapper wrapper = getWrapper(paintable); Style wrapperStyle = wrapper.getElement().getStyle(); if (paintable.isRelativeWidth()) { diff --git a/src/com/vaadin/terminal/gwt/client/ui/VAbsoluteLayout.java b/src/com/vaadin/terminal/gwt/client/ui/VAbsoluteLayout.java index d4386e2b04..c5c3834d4b 100644 --- a/src/com/vaadin/terminal/gwt/client/ui/VAbsoluteLayout.java +++ b/src/com/vaadin/terminal/gwt/client/ui/VAbsoluteLayout.java @@ -3,9 +3,6 @@ */ package com.vaadin.terminal.gwt.client.ui; -import java.util.HashMap; -import java.util.Map; - import com.google.gwt.dom.client.DivElement; import com.google.gwt.dom.client.Document; import com.google.gwt.dom.client.Style; @@ -16,8 +13,6 @@ import com.google.gwt.user.client.ui.SimplePanel; import com.google.gwt.user.client.ui.Widget; import com.vaadin.terminal.gwt.client.ApplicationConnection; import com.vaadin.terminal.gwt.client.ComponentConnector; -import com.vaadin.terminal.gwt.client.ConnectorMap; -import com.vaadin.terminal.gwt.client.UIDL; import com.vaadin.terminal.gwt.client.Util; import com.vaadin.terminal.gwt.client.VCaption; @@ -35,8 +30,6 @@ public class VAbsoluteLayout extends ComplexPanel { private Object previousStyleName; - Map pidToComponentWrappper = new HashMap(); - protected ApplicationConnection client; public VAbsoluteLayout() { @@ -52,24 +45,12 @@ public class VAbsoluteLayout extends ComplexPanel { canvas.setClassName(CLASSNAME + "-margin"); } - AbsoluteWrapper getWrapper(ApplicationConnection client, UIDL componentUIDL) { - AbsoluteWrapper wrapper = pidToComponentWrappper.get(componentUIDL - .getId()); - if (wrapper == null) { - wrapper = new AbsoluteWrapper(client.getPaintable(componentUIDL)); - pidToComponentWrappper.put(componentUIDL.getId(), wrapper); - add(wrapper); - } - return wrapper; - - } - @Override public void add(Widget child) { super.add(child, canvas); } - public class AbsoluteWrapper extends SimplePanel { + public static class AbsoluteWrapper extends SimplePanel { private String css; String left; String top; @@ -77,62 +58,28 @@ public class VAbsoluteLayout extends ComplexPanel { String bottom; private String zIndex; - private ComponentConnector paintable; private VCaption caption; - public AbsoluteWrapper(ComponentConnector paintable) { - this.paintable = paintable; + public AbsoluteWrapper(Widget child) { + setWidget(child); setStyleName(CLASSNAME + "-wrapper"); } - public void updateCaption() { - - boolean captionIsNeeded = VCaption.isNeeded(paintable.getState()); - if (captionIsNeeded) { - if (caption == null) { - caption = new VCaption(paintable, client); - VAbsoluteLayout.this.add(caption); - } - caption.updateCaption(); - updateCaptionPosition(); - } else { - if (caption != null) { - caption.removeFromParent(); - caption = null; - } - } + public VCaption getCaption() { + return caption; } - @Override - public void setWidget(Widget w) { - // this fixes #5457 (Widget implementation can change on-the-fly) - paintable = ConnectorMap.get(client).getConnector(w); - super.setWidget(w); + public void setCaption(VCaption caption) { + this.caption = caption; } public void destroy() { if (caption != null) { caption.removeFromParent(); } - client.unregisterPaintable(paintable); removeFromParent(); } - public void updateFromUIDL(UIDL componentUIDL) { - setPosition(componentUIDL.getStringAttribute("css")); - if (getWidget() != paintable.getWidget()) { - setWidget(paintable.getWidget()); - } - UIDL childUIDL = componentUIDL.getChildUIDL(0); - paintable.updateFromUIDL(childUIDL, client); - if (childUIDL.hasAttribute("cached")) { - // child may need relative size adjustment if wrapper details - // have changed this could be optimized (check if wrapper size - // has changed) - client.handleComponentRelativeSize(paintable.getWidget()); - } - } - public void setPosition(String stringAttribute) { if (css == null || !css.equals(stringAttribute)) { css = stringAttribute; diff --git a/src/com/vaadin/terminal/gwt/server/AbstractCommunicationManager.java b/src/com/vaadin/terminal/gwt/server/AbstractCommunicationManager.java index a7bd69d620..17e504a3bb 100644 --- a/src/com/vaadin/terminal/gwt/server/AbstractCommunicationManager.java +++ b/src/com/vaadin/terminal/gwt/server/AbstractCommunicationManager.java @@ -821,7 +821,8 @@ public abstract class AbstractCommunicationManager implements Serializable { } catch (JSONException e) { throw new PaintException( "Failed to serialize shared state for connector " - + connector.getConnectorId() + ": " + + connector.getClass().getName() + " (" + + connector.getConnectorId() + "): " + e.getMessage()); } } diff --git a/src/com/vaadin/terminal/gwt/server/JsonCodec.java b/src/com/vaadin/terminal/gwt/server/JsonCodec.java index 1113d71f73..21a189a435 100644 --- a/src/com/vaadin/terminal/gwt/server/JsonCodec.java +++ b/src/com/vaadin/terminal/gwt/server/JsonCodec.java @@ -225,7 +225,7 @@ public class JsonCodec implements Serializable { JSONArray jsonArray = encodeArrayContents(array, application); return combineTypeAndValue(JsonEncoder.VTYPE_ARRAY, jsonArray); } else if (value instanceof Map) { - Map map = (Map) value; + Map map = (Map) value; JSONObject jsonMap = encodeMapContents(map, application); return combineTypeAndValue(JsonEncoder.VTYPE_MAP, jsonMap); } else if (value instanceof Connector) { @@ -324,13 +324,17 @@ public class JsonCodec implements Serializable { return jsonArray; } - private static JSONObject encodeMapContents(Map map, + private static JSONObject encodeMapContents(Map map, Application application) throws JSONException { JSONObject jsonMap = new JSONObject(); - for (String mapKey : map.keySet()) { - // TODO handle object graph loops? + for (Object mapKey : map.keySet()) { + if (!(mapKey instanceof String)) { + throw new JSONException( + "Only maps with String keys are currently supported (#8602)"); + } + Object mapValue = map.get(mapKey); - jsonMap.put(mapKey, encode(mapValue, application)); + jsonMap.put((String) mapKey, encode(mapValue, application)); } return jsonMap; } diff --git a/src/com/vaadin/ui/AbsoluteLayout.java b/src/com/vaadin/ui/AbsoluteLayout.java index 42ad0c5e4c..d347b74829 100644 --- a/src/com/vaadin/ui/AbsoluteLayout.java +++ b/src/com/vaadin/ui/AbsoluteLayout.java @@ -4,22 +4,20 @@ package com.vaadin.ui; import java.io.Serializable; -import java.util.Collection; import java.util.HashMap; import java.util.Iterator; -import java.util.LinkedHashSet; +import java.util.LinkedHashMap; import java.util.Map; import com.vaadin.event.LayoutEvents.LayoutClickEvent; import com.vaadin.event.LayoutEvents.LayoutClickListener; import com.vaadin.event.LayoutEvents.LayoutClickNotifier; -import com.vaadin.terminal.PaintException; -import com.vaadin.terminal.PaintTarget; import com.vaadin.terminal.Sizeable; import com.vaadin.terminal.gwt.client.Connector; import com.vaadin.terminal.gwt.client.MouseEventDetails; import com.vaadin.terminal.gwt.client.ui.AbsoluteLayoutConnector; import com.vaadin.terminal.gwt.client.ui.AbsoluteLayoutConnector.AbsoluteLayoutServerRPC; +import com.vaadin.terminal.gwt.client.ui.AbsoluteLayoutConnector.AbsoluteLayoutState; import com.vaadin.terminal.gwt.client.ui.LayoutClickEventHandler; /** @@ -39,11 +37,8 @@ public class AbsoluteLayout extends AbstractLayout implements mouseDetails, clickedConnector)); } }; - // The components in the layout - private Collection components = new LinkedHashSet(); - // Maps each component to a position - private Map componentToCoordinates = new HashMap(); + private LinkedHashMap componentToCoordinates = new LinkedHashMap(); /** * Creates an AbsoluteLayout with full size. @@ -53,12 +48,17 @@ public class AbsoluteLayout extends AbstractLayout implements setSizeFull(); } + @Override + public AbsoluteLayoutState getState() { + return (AbsoluteLayoutState) super.getState(); + } + /** * Gets an iterator for going through all components enclosed in the * absolute layout. */ public Iterator getComponentIterator() { - return components.iterator(); + return componentToCoordinates.keySet().iterator(); } /** @@ -68,7 +68,7 @@ public class AbsoluteLayout extends AbstractLayout implements * @return the number of contained components */ public int getComponentCount() { - return components.size(); + return componentToCoordinates.size(); } /** @@ -78,8 +78,7 @@ public class AbsoluteLayout extends AbstractLayout implements public void replaceComponent(Component oldComponent, Component newComponent) { ComponentPosition position = getPosition(oldComponent); removeComponent(oldComponent); - addComponent(newComponent); - componentToCoordinates.put(newComponent, position); + addComponent(newComponent, position); } /* @@ -91,29 +90,7 @@ public class AbsoluteLayout extends AbstractLayout implements */ @Override public void addComponent(Component c) { - components.add(c); - try { - super.addComponent(c); - requestRepaint(); - } catch (IllegalArgumentException e) { - components.remove(c); - throw e; - } - } - - /* - * (non-Javadoc) - * - * @see - * com.vaadin.ui.AbstractComponentContainer#removeComponent(com.vaadin.ui - * .Component) - */ - @Override - public void removeComponent(Component c) { - components.remove(c); - componentToCoordinates.remove(c); - super.removeComponent(c); - requestRepaint(); + addComponent(c, new ComponentPosition()); } /** @@ -131,28 +108,90 @@ public class AbsoluteLayout extends AbstractLayout implements * The css position string */ public void addComponent(Component c, String cssPosition) { + ComponentPosition position = new ComponentPosition(); + position.setCSSString(cssPosition); + addComponent(c, position); + } + + /** + * Adds the component using the given position. Ensures the position is only + * set if the component is added correctly. + * + * @param c + * The component to add + * @param position + * The position info for the component. Must not be null. + * @throws IllegalArgumentException + * If adding the component failed + */ + private void addComponent(Component c, ComponentPosition position) + throws IllegalArgumentException { /* * Create position instance and add it to componentToCoordinates map. We * need to do this before we call addComponent so the attachListeners * can access this position. #6368 */ - ComponentPosition position = new ComponentPosition(); - position.setCSSString(cssPosition); - componentToCoordinates.put(c, position); - + internalSetPosition(c, position); try { - addComponent(c); - + super.addComponent(c); } catch (IllegalArgumentException e) { - // Remove component coordinates if adding fails - componentToCoordinates.remove(c); + internalRemoveComponent(c); throw e; } + requestRepaint(); + } + + /** + * Removes the component from all internal data structures. Does not + * actually remove the component from the layout (this is assumed to have + * been done by the caller). + * + * @param c + * The component to remove + */ + private void internalRemoveComponent(Component c) { + componentToCoordinates.remove(c); + } + + @Override + public void updateState() { + super.updateState(); + + // This could be in internalRemoveComponent and internalSetComponent if + // Map was supported. We cannot get the child + // connectorId unless the component is attached to the application so + // the String->String map cannot be populated in internal* either. + Map connectorToPosition = new HashMap(); + for (Component c : this) { + connectorToPosition.put(c.getConnectorId(), getPosition(c) + .getCSSString()); + } + getState().setConnectorToCssPosition(connectorToPosition); + + } + + /* + * (non-Javadoc) + * + * @see + * com.vaadin.ui.AbstractComponentContainer#removeComponent(com.vaadin.ui + * .Component) + */ + @Override + public void removeComponent(Component c) { + super.removeComponent(c); + internalRemoveComponent(c); + requestRepaint(); } /** * Gets the position of a component in the layout. Returns null if component * is not attached to the layout. + *

+ * Note that you cannot update the position by updating this object. Call + * {@link #setPosition(Component, ComponentPosition)} with the updated + * {@link ComponentPosition} object. + *

* * @param component * The component which position is needed @@ -161,15 +200,36 @@ public class AbsoluteLayout extends AbstractLayout implements * layout. */ public ComponentPosition getPosition(Component component) { - if (component.getParent() != this) { - return null; - } else if (componentToCoordinates.containsKey(component)) { - return componentToCoordinates.get(component); - } else { - ComponentPosition coords = new ComponentPosition(); - componentToCoordinates.put(component, coords); - return coords; + return componentToCoordinates.get(component); + } + + /** + * Sets the position of a component in the layout. + * + * @param component + * @param position + */ + public void setPosition(Component component, ComponentPosition position) { + if (!componentToCoordinates.containsKey(component)) { + throw new IllegalArgumentException( + "Component must be a child of this layout"); } + internalSetPosition(component, position); + } + + /** + * Updates the position for a component. Caller must ensure component is a + * child of this layout. + * + * @param component + * The component. Must be a child for this layout. Not enforced. + * @param position + * New position. Must not be null. + */ + private void internalSetPosition(Component component, + ComponentPosition position) { + componentToCoordinates.put(component, position); + requestRepaint(); } /** @@ -552,24 +612,6 @@ public class AbsoluteLayout extends AbstractLayout implements } - /* - * (non-Javadoc) - * - * @see - * com.vaadin.ui.AbstractLayout#paintContent(com.vaadin.terminal.PaintTarget - * ) - */ - @Override - public void paintContent(PaintTarget target) throws PaintException { - super.paintContent(target); - for (Component component : components) { - target.startTag("cc"); - target.addAttribute("css", getPosition(component).getCSSString()); - component.paint(target); - target.endTag("cc"); - } - } - public void addListener(LayoutClickListener listener) { addListener(LayoutClickEventHandler.LAYOUT_CLICK_EVENT_IDENTIFIER, LayoutClickEvent.class, listener,