]> source.dussan.org Git - vaadin-framework.git/commitdiff
Merge branch 'layoutperformance'
authorLeif Åstrand <leif@vaadin.com>
Mon, 27 Feb 2012 12:02:33 +0000 (14:02 +0200)
committerLeif Åstrand <leif@vaadin.com>
Mon, 27 Feb 2012 12:02:33 +0000 (14:02 +0200)
Conflicts:
src/com/vaadin/terminal/gwt/client/ApplicationConnection.java
src/com/vaadin/terminal/gwt/client/Util.java
src/com/vaadin/terminal/gwt/client/VCaption.java
src/com/vaadin/terminal/gwt/client/ui/VAbstractPaintableWidget.java
src/com/vaadin/terminal/gwt/client/ui/VFormLayout.java
src/com/vaadin/terminal/gwt/client/ui/VGridLayout.java
src/com/vaadin/terminal/gwt/client/ui/VGridLayoutPaintable.java
src/com/vaadin/terminal/gwt/client/ui/VOrderedLayoutPaintable.java
src/com/vaadin/terminal/gwt/client/ui/VScrollTable.java
src/com/vaadin/terminal/gwt/client/ui/VTabsheet.java
src/com/vaadin/terminal/gwt/client/ui/layout/CellBasedLayoutPaintable.java
src/com/vaadin/terminal/gwt/client/ui/layout/ChildComponentContainer.java

33 files changed:
1  2 
src/com/vaadin/terminal/gwt/client/ApplicationConnection.java
src/com/vaadin/terminal/gwt/client/Util.java
src/com/vaadin/terminal/gwt/client/VCaption.java
src/com/vaadin/terminal/gwt/client/VPaintableMap.java
src/com/vaadin/terminal/gwt/client/VPaintableWidget.java
src/com/vaadin/terminal/gwt/client/ui/VAbsoluteLayout.java
src/com/vaadin/terminal/gwt/client/ui/VAbstractPaintableWidget.java
src/com/vaadin/terminal/gwt/client/ui/VAbstractSplitPanelPaintable.java
src/com/vaadin/terminal/gwt/client/ui/VAccordion.java
src/com/vaadin/terminal/gwt/client/ui/VCssLayout.java
src/com/vaadin/terminal/gwt/client/ui/VCustomLayout.java
src/com/vaadin/terminal/gwt/client/ui/VDragAndDropWrapper.java
src/com/vaadin/terminal/gwt/client/ui/VFilterSelect.java
src/com/vaadin/terminal/gwt/client/ui/VFilterSelectPaintable.java
src/com/vaadin/terminal/gwt/client/ui/VFormLayout.java
src/com/vaadin/terminal/gwt/client/ui/VFormPaintable.java
src/com/vaadin/terminal/gwt/client/ui/VGridLayout.java
src/com/vaadin/terminal/gwt/client/ui/VGridLayoutPaintable.java
src/com/vaadin/terminal/gwt/client/ui/VMeasuringOrderedLayoutPaintable.java
src/com/vaadin/terminal/gwt/client/ui/VMenuBar.java
src/com/vaadin/terminal/gwt/client/ui/VMenuBarPaintable.java
src/com/vaadin/terminal/gwt/client/ui/VPanel.java
src/com/vaadin/terminal/gwt/client/ui/VPanelPaintable.java
src/com/vaadin/terminal/gwt/client/ui/VPopupCalendarPaintable.java
src/com/vaadin/terminal/gwt/client/ui/VScrollTable.java
src/com/vaadin/terminal/gwt/client/ui/VScrollTablePaintable.java
src/com/vaadin/terminal/gwt/client/ui/VTabsheet.java
src/com/vaadin/terminal/gwt/client/ui/VTabsheetPaintable.java
src/com/vaadin/terminal/gwt/client/ui/VTextualDate.java
src/com/vaadin/terminal/gwt/client/ui/VViewPaintable.java
src/com/vaadin/terminal/gwt/client/ui/VWindow.java
src/com/vaadin/terminal/gwt/client/ui/VWindowPaintable.java
src/com/vaadin/terminal/gwt/client/ui/label/VLabel.java

index cecfcfd39ab052432de60df308e5bb1b443f7af5,24683b0c9c33f64259f7ec94994df6e7fa1de0f0..372a7a39f594ee999d2741b0e860576d783d8078
@@@ -1002,53 -996,11 +1003,54 @@@ public class ApplicationConnection 
                  JsArray<ValueMap> changes = json.getJSValueMapArray("changes");
  
                  ArrayList<VPaintableWidget> updatedVPaintableWidgets = new ArrayList<VPaintableWidget>();
-                 relativeSizeChanges.clear();
                  componentCaptionSizeChanges.clear();
  
+                 Duration updateDuration = new Duration();
                  int length = changes.length();
 +
 +                // 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);
 +                        VPaintable paintable = paintableMap.getPaintable(uidl
 +                                .getId());
 +                        if (null == paintable
 +                                && !uidl.getTag().equals(
 +                                        configuration.getEncodedWindowTag())) {
 +                            // create, initialize and register the paintable
 +                            getPaintable(uidl);
 +                        }
 +                    } catch (final Throwable e) {
 +                        VConsole.error(e);
 +                    }
 +                }
 +
 +                // 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 paintableId = keyArray.get(i);
 +                        VPaintable paintable = paintableMap
 +                                .getPaintable(paintableId);
 +                        if (null != paintable) {
 +
 +                            JSONArray stateDataAndType = new JSONArray(
 +                                    states.getJavaScriptObject(paintableId));
 +
 +                            Object state = JsonDecoder.convertValue(
 +                                    stateDataAndType, paintableMap);
 +
 +                            paintable.setState((SharedState) state);
 +                        }
 +                    } catch (final Throwable e) {
 +                        VConsole.error(e);
 +                    }
 +                }
 +
 +                // update paintables
                  for (int i = 0; i < length; i++) {
                      try {
                          final UIDL change = changes.get(i).cast();
index be78959830d101a5fe16ed2696888f7170c7db87,a3604b6b639996301c43078fe4013c0d5440c30c..a563a534d521d1cb3685543e66a56bd0c37b4fcd
@@@ -5,12 -5,7 +5,8 @@@
  package com.vaadin.terminal.gwt.client;
  
  import java.util.ArrayList;
- import java.util.HashMap;
- import java.util.HashSet;
- import java.util.Iterator;
- import java.util.Map;
- import java.util.Set;
 +import java.util.Arrays;
+ import java.util.List;
  
  import com.google.gwt.core.client.Scheduler;
  import com.google.gwt.core.client.Scheduler.ScheduledCommand;
index 6e2c4a02d24411e30ad4c21e78972643412e64c3,286d3fc17f9370e719523044d416fe493d79bd11..21f1e453b8b2adbd67b9db4058e393ffe4dc444f
@@@ -34,40 -30,19 +32,45 @@@ public class VCaption extends HTML 
  
      private int maxWidth = -1;
  
-     private static final String CLASSNAME_CLEAR = CLASSNAME + "-clearelem";
+     protected static final String ATTRIBUTE_ICON = "icon";
+     protected static final String ATTRIBUTE_CAPTION = "caption";
+     protected static final String ATTRIBUTE_DESCRIPTION = "description";
+     protected static final String ATTRIBUTE_REQUIRED = "required";
+     protected static final String ATTRIBUTE_ERROR = "error";
+     protected static final String ATTRIBUTE_HIDEERRORS = "hideErrors";
  
 +    private enum InsertPosition {
 +        ICON, CAPTION, REQUIRED, ERROR
 +    }
 +
 +    /**
 +     * Creates a caption that is not linked to a {@link VPaintableWidget}.
 +     * 
 +     * When using this constructor, {@link #getOwner()} returns null.
 +     * 
 +     * @param client
 +     *            ApplicationConnection
 +     * @deprecated all captions should be associated with a paintable widget and
 +     *             be updated from shared state, not UIDL
 +     */
 +    @Deprecated
 +    public VCaption(ApplicationConnection client) {
 +        super();
 +        this.client = client;
 +        owner = null;
 +
 +        setStyleName(CLASSNAME);
 +        sinkEvents(VTooltip.TOOLTIP_EVENTS);
 +
 +    }
 +
      /**
 +     * Creates a caption for a {@link VPaintableWidget}.
       * 
       * @param component
 -     *            optional owner of caption. If not set, getOwner will return
 -     *            null
 +     *            owner of caption, not null
       * @param client
 +     *            ApplicationConnection
       */
      public VCaption(VPaintableWidget component, ApplicationConnection client) {
          super();
  
      }
  
-         if (clearElement == null) {
-             clearElement = DOM.createDiv();
-             clearElement.setClassName(CLASSNAME_CLEAR);
-             getElement().appendChild(clearElement);
-         }
 +    @Deprecated
 +    public boolean updateCaptionWithoutOwner(UIDL uidl, String caption,
 +            boolean disabled, boolean hasDescription) {
 +        // TODO temporary method, needed because some tabsheet and accordion
 +        // internal captions do not have an owner or shared state. Simplified to
 +        // only support those cases
 +        setVisible(!uidl.getBooleanAttribute("invisible"));
 +
 +        boolean wasPlacedAfterComponent = placedAfterComponent;
 +
 +        // Caption is placed after component unless there is some part which
 +        // moves it above.
 +        placedAfterComponent = true;
 +
 +        String style = VCaption.CLASSNAME;
 +        if (disabled) {
 +            style += " " + ApplicationConnection.DISABLED_CLASSNAME;
 +        }
 +        setStyleName(style);
 +        if (hasDescription) {
 +            if (captionText != null) {
 +                addStyleDependentName("hasdescription");
 +            } else {
 +                removeStyleDependentName("hasdescription");
 +            }
 +        }
 +        boolean hasIcon = uidl
 +                .hasAttribute(VAbstractPaintableWidget.ATTRIBUTE_ICON);
 +        boolean showError = uidl
 +                .hasAttribute(VAbstractPaintableWidget.ATTRIBUTE_ERROR)
 +                && !uidl.getBooleanAttribute(VAbstractPaintableWidget.ATTRIBUTE_HIDEERRORS);
 +
 +        if (hasIcon) {
 +            if (icon == null) {
 +                icon = new Icon(client);
 +                icon.setWidth("0");
 +                icon.setHeight("0");
 +
 +                DOM.insertChild(getElement(), icon.getElement(),
 +                        getInsertPosition(InsertPosition.ICON));
 +            }
 +            // Icon forces the caption to be above the component
 +            placedAfterComponent = false;
 +
 +            icon.setUri(uidl
 +                    .getStringAttribute(VAbstractPaintableWidget.ATTRIBUTE_ICON));
 +
 +        } else if (icon != null) {
 +            // Remove existing
 +            DOM.removeChild(getElement(), icon.getElement());
 +            icon = null;
 +        }
 +
 +        if (caption != null) {
 +            // A caption text should be shown if the attribute is set
 +            // If the caption is null the ATTRIBUTE_CAPTION should not be set to
 +            // avoid ending up here.
 +
 +            if (captionText == null) {
 +                captionText = DOM.createDiv();
 +                captionText.setClassName("v-captiontext");
 +
 +                DOM.insertChild(getElement(), captionText,
 +                        getInsertPosition(InsertPosition.CAPTION));
 +            }
 +
 +            // Update caption text
 +            // A text forces the caption to be above the component.
 +            placedAfterComponent = false;
 +            if (caption.trim().equals("")) {
 +                // This is required to ensure that the caption uses space in all
 +                // browsers when it is set to the empty string. If there is an
 +                // icon, error indicator or required indicator they will ensure
 +                // that space is reserved.
 +                if (!hasIcon && !showError) {
 +                    captionText.setInnerHTML("&nbsp;");
 +                }
 +            } else {
 +                DOM.setInnerText(captionText, caption);
 +            }
 +
 +        } else if (captionText != null) {
 +            // Remove existing
 +            DOM.removeChild(getElement(), captionText);
 +            captionText = null;
 +        }
 +
 +        if (showError) {
 +            if (errorIndicatorElement == null) {
 +                errorIndicatorElement = DOM.createDiv();
 +                DOM.setInnerHTML(errorIndicatorElement, "&nbsp;");
 +                DOM.setElementProperty(errorIndicatorElement, "className",
 +                        "v-errorindicator");
 +
 +                DOM.insertChild(getElement(), errorIndicatorElement,
 +                        getInsertPosition(InsertPosition.ERROR));
 +            }
 +        } else if (errorIndicatorElement != null) {
 +            // Remove existing
 +            getElement().removeChild(errorIndicatorElement);
 +            errorIndicatorElement = null;
 +        }
 +
 +        return (wasPlacedAfterComponent != placedAfterComponent);
 +    }
 +
      @Override
      public void onBrowserEvent(Event event) {
          super.onBrowserEvent(event);
index 0be1d5050c575a4095ec08701cf0171f632a1700,c42248e8354d6b89b36a2a2b838a1617764a044b..2eee3cc98d80927bc5afbcc1bf71261bf5621794
@@@ -33,5 -26,62 +33,61 @@@ public interface VPaintableWidget exten
       * 
       * @return
       */
 -    // FIXME: Rename to getParent()
      public VPaintableWidgetContainer getParent();
+     public LayoutManager getLayoutManager();
+     /**
+      * Returns <code>true</code> if the width of this paintable is currently
+      * undefined. If the width is undefined, the actual width of the paintable
+      * is defined by its contents.
+      * 
+      * @return <code>true</code> if the width is undefined, else
+      *         <code>false</code>
+      */
+     public boolean isUndefinedWidth();
+     /**
+      * Returns <code>true</code> if the height of this paintable is currently
+      * undefined. If the height is undefined, the actual height of the paintable
+      * is defined by its contents.
+      * 
+      * @return <code>true</code> if the height is undefined, else
+      *         <code>false</code>
+      */
+     public boolean isUndefinedHeight();
+     /**
+      * Returns <code>true</code> if the width of this paintable is currently
+      * relative. If the width is relative, the actual width of the paintable is
+      * a percentage of the size allocated to it by its parent.
+      * 
+      * @return <code>true</code> if the width is undefined, else
+      *         <code>false</code>
+      */
+     public boolean isRelativeWidth();
+     /**
+      * Returns <code>true</code> if the height of this paintable is currently
+      * relative. If the height is relative, the actual height of the paintable
+      * is a percentage of the size allocated to it by its parent.
+      * 
+      * @return <code>true</code> if the width is undefined, else
+      *         <code>false</code>
+      */
+     public boolean isRelativeHeight();
+     /**
+      * Gets the width of this paintable as defined on the server.
+      * 
+      * @return the server side width definition
+      */
+     public String getDeclaredWidth();
+     /**
+      * Gets the height of this paintable as defined on the server.
+      * 
+      * @return the server side height definition
+      */
+     public String getDeclaredHeight();
  }
index bff6f8ea3b190c120a3161bc7780b8cc3d022dd4,1fc995f584774b34ca9aba545964efad121418bb..ed45751312240cb4cad90eb96bdbb6cb725c81ce
@@@ -9,9 -8,9 +9,11 @@@ import com.google.gwt.user.client.ui.Fo
  import com.google.gwt.user.client.ui.Focusable;
  import com.google.gwt.user.client.ui.Widget;
  import com.vaadin.terminal.gwt.client.ApplicationConnection;
 +import com.vaadin.terminal.gwt.client.ComponentState;
+ import com.vaadin.terminal.gwt.client.LayoutManager;
  import com.vaadin.terminal.gwt.client.TooltipInfo;
  import com.vaadin.terminal.gwt.client.UIDL;
++import com.vaadin.terminal.gwt.client.VConsole;
  import com.vaadin.terminal.gwt.client.VPaintableMap;
  import com.vaadin.terminal.gwt.client.VPaintableWidget;
  import com.vaadin.terminal.gwt.client.VPaintableWidgetContainer;
@@@ -41,9 -28,9 +43,12 @@@ public abstract class VAbstractPaintabl
      private boolean enabled = true;
      private boolean visible = true;
  
 +    // shared state from the server to the client
 +    private ComponentState state;
 +
+     private String declaredWidth = "";
+     private String declaredHeight = "";
      /**
       * Default constructor
       */
           * taken into account
           */
  
-         getConnection().updateComponentSize(this);
 -        updateComponentSize(uidl);
++        updateComponentSize();
+     }
 -    private void updateComponentSize(UIDL uidl) {
 -        String w = uidl.hasAttribute("width") ? uidl
 -                .getStringAttribute("width") : "";
 -
 -        String h = uidl.hasAttribute("height") ? uidl
 -                .getStringAttribute("height") : "";
++    private void updateComponentSize() {
++        SharedState state = getState();
++
++        String w = "";
++        String h = "";
++        if (null != state || !(state instanceof ComponentState)) {
++            ComponentState componentState = (ComponentState) state;
++            // TODO move logging to VUIDLBrowser and VDebugConsole
++            // VConsole.log("Paintable state for "
++            // + getPaintableMap().getPid(paintable) + ": "
++            // + String.valueOf(state.getState()));
++            h = componentState.getHeight();
++            w = componentState.getWidth();
++        } else {
++            // TODO move logging to VUIDLBrowser and VDebugConsole
++            VConsole.log("No state for paintable " + getId()
++                    + " in VAbstractPaintableWidget.updateComponentSize()");
++        }
+         // Parent should be updated if either dimension changed between relative
+         // and non-relative
+         if (w.endsWith("%") != declaredWidth.endsWith("%")) {
+             VPaintableWidgetContainer parent = getParent();
+             if (parent instanceof ManagedLayout) {
+                 getLayoutManager().setWidthNeedsUpdate((ManagedLayout) parent);
+             }
+         }
+         if (h.endsWith("%") != declaredHeight.endsWith("%")) {
+             VPaintableWidgetContainer parent = getParent();
+             if (parent instanceof ManagedLayout) {
+                 getLayoutManager().setHeightNeedsUpdate((ManagedLayout) parent);
+             }
+         }
+         declaredWidth = w;
+         declaredHeight = h;
+         // Set defined sizes
+         Widget component = getWidgetForPaintable();
+         component.setStyleName("v-undefined-width", isUndefinedWidth());
+         component.setStyleName("v-undefined-height", isUndefinedHeight());
+         component.setHeight(h);
+         component.setWidth(w);
+     }
+     public boolean isRelativeHeight() {
+         return declaredHeight.endsWith("%");
+     }
+     public boolean isRelativeWidth() {
+         return declaredWidth.endsWith("%");
+     }
+     public boolean isUndefinedHeight() {
+         return declaredHeight.length() == 0;
+     }
+     public boolean isUndefinedWidth() {
+         return declaredWidth.length() == 0;
+     }
+     public String getDeclaredHeight() {
+         return declaredHeight;
+     }
+     public String getDeclaredWidth() {
+         return declaredWidth;
      }
  
      /**
          return styleBuf.toString();
      }
  
 +    /**
 +     * Sets the shared state for the paintable widget.
 +     * 
 +     * @param new shared state (must be compatible with the return value of
 +     *        {@link #getState()} - {@link ComponentState} if
 +     *        {@link #getState()} is not overridden
 +     */
 +    public final void setState(SharedState state) {
 +        this.state = (ComponentState) state;
 +    }
 +
 +    /**
 +     * Initialize the given RPC proxy object so it is connected to this
 +     * paintable.
 +     * 
 +     * @param clientToServerRpc
 +     *            The RPC instance to initialize. Must have been created using
 +     *            GWT.create().
 +     */
 +    protected <T extends ClientToServerRpc> T initRPC(T clientToServerRpc) {
 +        ((InitializableClientToServerRpc) clientToServerRpc).initRpc(getId(),
 +                getConnection());
 +        return clientToServerRpc;
 +    }
++
+     public LayoutManager getLayoutManager() {
+         return LayoutManager.get(connection);
+     }
  }
index cdbb895f2c8370b4195a737565d392e26f44c6b9,6242090f58bd3542cdc19dbbb7f2cf9d084f1fb5..c795479dd93ab403c77692286486c9780cf65068
@@@ -68,21 -68,20 +68,19 @@@ public abstract class VAbstractSplitPan
      public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
          getWidgetForPaintable().client = client;
          getWidgetForPaintable().id = uidl.getId();
-         getWidgetForPaintable().rendering = true;
  
 -        getWidgetForPaintable().immediate = uidl.hasAttribute("immediate");
 +        getWidgetForPaintable().immediate = getState().isImmediate();
  
          super.updateFromUIDL(uidl, client);
          if (!isRealUpdate(uidl)) {
-             getWidgetForPaintable().rendering = false;
              return;
          }
 -        getWidgetForPaintable().setEnabled(
 -                !uidl.getBooleanAttribute("disabled"));
 +        getWidgetForPaintable().setEnabled(!getState().isDisabled());
  
          clickEventHandler.handleEventHandlerRegistration(client);
 -        if (uidl.hasAttribute("style")) {
 -            getWidgetForPaintable().componentStyleNames = uidl
 -                    .getStringAttribute("style").split(" ");
 +        if (getState().hasStyles()) {
 +            getWidgetForPaintable().componentStyleNames = getState().getStyle()
 +                    .split(" ");
          } else {
              getWidgetForPaintable().componentStyleNames = new String[0];
          }
index f54c6dc05ddfe92047fd334f86b41e2a0cc42a1b,be8f5736afacfd0b963bb2ac1862da200a04f637..15ac97cd1c592782012c4df18e5835b0b944e16b
@@@ -21,13 -20,9 +20,10 @@@ import com.google.gwt.user.client.ui.Si
  import com.google.gwt.user.client.ui.Widget;
  import com.vaadin.terminal.gwt.client.ApplicationConnection;
  import com.vaadin.terminal.gwt.client.BrowserInfo;
- import com.vaadin.terminal.gwt.client.Container;
 +import com.vaadin.terminal.gwt.client.ComponentState;
  import com.vaadin.terminal.gwt.client.Focusable;
- import com.vaadin.terminal.gwt.client.RenderSpace;
  import com.vaadin.terminal.gwt.client.StyleConstants;
  import com.vaadin.terminal.gwt.client.UIDL;
- import com.vaadin.terminal.gwt.client.Util;
  import com.vaadin.terminal.gwt.client.VPaintableMap;
  import com.vaadin.terminal.gwt.client.VPaintableWidget;
  import com.vaadin.terminal.gwt.client.VTooltip;
@@@ -280,19 -211,6 +212,7 @@@ public class VFormLayout extends Simple
          }
      }
  
-     public boolean isDynamicWidth() {
-         return width.equals("");
-     }
-     public boolean hasChildComponent(Widget component) {
-         return table.hasChildComponent(component);
-     }
-     public void replaceChildComponent(Widget oldComponent, Widget newComponent) {
-         table.replaceChildComponent(oldComponent, newComponent);
-     }
 +    // TODO why duplicated here?
      public class Caption extends HTML {
  
          public static final String CLASSNAME = "v-caption";
index c8a0f813f32ed07320eb660a7b7bd35f3a0c4173,8ad4cd0496c86fc1a5095de68159c691d20d6b51..82176dd35326b95b60828cf908bd3085cef7b556
@@@ -13,24 -10,23 +10,26 @@@ import java.util.List
  
  import com.google.gwt.dom.client.DivElement;
  import com.google.gwt.dom.client.Document;
+ import com.google.gwt.dom.client.Style;
+ import com.google.gwt.dom.client.Style.Position;
+ import com.google.gwt.dom.client.Style.Unit;
  import com.google.gwt.user.client.Element;
- import com.google.gwt.user.client.ui.AbsolutePanel;
- import com.google.gwt.user.client.ui.SimplePanel;
+ import com.google.gwt.user.client.ui.ComplexPanel;
  import com.google.gwt.user.client.ui.Widget;
  import com.vaadin.terminal.gwt.client.ApplicationConnection;
- import com.vaadin.terminal.gwt.client.Container;
 +import com.vaadin.terminal.gwt.client.ComponentState;
 +import com.vaadin.terminal.gwt.client.RenderSpace;
 +import com.vaadin.terminal.gwt.client.StyleConstants;
+ import com.vaadin.terminal.gwt.client.LayoutManager;
  import com.vaadin.terminal.gwt.client.UIDL;
  import com.vaadin.terminal.gwt.client.Util;
+ import com.vaadin.terminal.gwt.client.VCaption;
  import com.vaadin.terminal.gwt.client.VPaintableMap;
  import com.vaadin.terminal.gwt.client.VPaintableWidget;
- import com.vaadin.terminal.gwt.client.ui.layout.CellBasedLayout;
- import com.vaadin.terminal.gwt.client.ui.layout.ChildComponentContainer;
+ import com.vaadin.terminal.gwt.client.ui.layout.VLayoutSlot;
+ import com.vaadin.terminal.gwt.client.ui.layout.VPaintableLayoutSlot;
  
- public class VGridLayout extends SimplePanel implements Container {
+ public class VGridLayout extends ComplexPanel {
  
      public static final String CLASSNAME = "v-gridlayout";
  
index 24d33fc1559cc7f633a58a2c7926fe1daf3bb348,2c896825ec08a1570cc6488bbebad68be7a31823..43dbdc9f61822a3eddcbedf45901005b04f872ef
@@@ -120,68 -100,47 +100,47 @@@ public class VGridLayoutPaintable exten
              }
          }
  
-         getWidgetForPaintable().colExpandRatioArray = uidl
-                 .getIntArrayAttribute("colExpand");
-         getWidgetForPaintable().rowExpandRatioArray = uidl
-                 .getIntArrayAttribute("rowExpand");
-         getWidgetForPaintable().distributeColSpanWidths();
-         getWidgetForPaintable().minColumnWidths = VGridLayout
-                 .cloneArray(getWidgetForPaintable().columnWidths);
-         getWidgetForPaintable().expandColumns();
-         getWidgetForPaintable().renderRemainingComponentsWithNoRelativeHeight(
-                 pendingCells);
-         getWidgetForPaintable().detectRowHeights();
-         getWidgetForPaintable().expandRows();
-         getWidgetForPaintable().renderRemainingComponents(pendingCells);
-         for (Cell cell : relativeHeighted) {
-             // rendering done above so cell.cc should not be null
-             Widget widget2 = cell.cc.getWidget();
-             client.handleComponentRelativeSize(widget2);
-             cell.cc.updateWidgetSize();
-         }
-         getWidgetForPaintable().layoutCells();
+         layout.colExpandRatioArray = uidl.getIntArrayAttribute("colExpand");
+         layout.rowExpandRatioArray = uidl.getIntArrayAttribute("rowExpand");
  
          // clean non rendered components
-         for (Widget w : getWidgetForPaintable().nonRenderedWidgets.keySet()) {
-             ChildComponentContainer childComponentContainer = getWidgetForPaintable().widgetToComponentContainer
-                     .get(w);
-             getWidgetForPaintable().widgetToCell.remove(w);
-             getWidgetForPaintable().widgetToComponentContainer.remove(w);
-             childComponentContainer.removeFromParent();
-             VPaintableMap paintableMap = VPaintableMap.get(client);
-             paintableMap.unregisterPaintable(paintableMap.getPaintable(w));
+         for (Widget w : nonRenderedWidgets) {
+             Cell cell = layout.widgetToCell.remove(w);
+             cell.slot.setCaption(null);
+             if (w.getParent() == layout) {
+                 w.removeFromParent();
+                 VPaintableMap paintableMap = VPaintableMap.get(client);
+                 paintableMap.unregisterPaintable(paintableMap.getPaintable(w));
+             }
+             cell.slot.getWrapperElement().removeFromParent();
          }
-         getWidgetForPaintable().nonRenderedWidgets = null;
  
-         getWidgetForPaintable().rendering = false;
-         getWidgetForPaintable().sizeChangedDuringRendering = false;
+         int bitMask = uidl.getIntAttribute("margins");
+         layout.updateMarginStyleNames(new VMarginInfo(bitMask));
+         layout.updateSpacingStyleName(uidl.getBooleanAttribute("spacing"));
  
+         getLayoutManager().setNeedsUpdate(this);
      }
  
 -    public void updateCaption(VPaintableWidget component, UIDL uidl) {
 +    public void updateCaption(VPaintableWidget paintable, UIDL uidl) {
-         Widget widget = paintable.getWidgetForPaintable();
-         ChildComponentContainer cc = getWidgetForPaintable().widgetToComponentContainer
-                 .get(widget);
-         if (cc != null) {
-             cc.updateCaption(uidl, getConnection());
-         }
-         if (!getWidgetForPaintable().rendering) {
-             // ensure rel size details are updated
-             boolean cached = uidl.getBooleanAttribute("cached");
-             getWidgetForPaintable().widgetToCell.get(widget)
-                     .updateRelSizeStatus(paintable.getState(), cached);
-             /*
-              * This was a component-only update and the possible size change
-              * must be propagated to the layout
-              */
-             getConnection().captionSizeUpdated(widget);
+         VGridLayout layout = getWidgetForPaintable();
 -        if (VCaption.isNeeded(uidl)) {
 -            Cell cell = layout.widgetToCell.get(component
++        if (VCaption.isNeeded(uidl, paintable.getState())) {
++            Cell cell = layout.widgetToCell.get(paintable
+                     .getWidgetForPaintable());
+             VLayoutSlot layoutSlot = cell.slot;
+             VCaption caption = layoutSlot.getCaption();
+             if (caption == null) {
 -                caption = new VCaption(component, getConnection());
++                caption = new VCaption(paintable, getConnection());
 -                Widget widget = component.getWidgetForPaintable();
++                Widget widget = paintable.getWidgetForPaintable();
+                 layout.setCaption(widget, caption);
+             }
+             caption.updateCaption(uidl);
+         } else {
 -            layout.setCaption(component.getWidgetForPaintable(), null);
++            layout.setCaption(paintable.getWidgetForPaintable(), null);
          }
      }
  
index 0000000000000000000000000000000000000000,5f35815cd8de7d236451ba69e0ac8da3cc2d090c..141726b90db6ab12ffa5b38e4f9beaa246efce33
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,290 +1,290 @@@
 -        if (VCaption.isNeeded(uidl)) {
+ /* 
+ @VaadinApache2LicenseForJavaFiles@
+  */
+ package com.vaadin.terminal.gwt.client.ui;
+ import java.util.HashSet;
+ import java.util.Iterator;
+ import com.google.gwt.dom.client.Node;
+ import com.google.gwt.dom.client.Style;
+ 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.DirectionalManagedLayout;
+ import com.vaadin.terminal.gwt.client.LayoutManager;
+ import com.vaadin.terminal.gwt.client.UIDL;
+ import com.vaadin.terminal.gwt.client.VCaption;
+ import com.vaadin.terminal.gwt.client.VPaintableMap;
+ import com.vaadin.terminal.gwt.client.VPaintableWidget;
+ import com.vaadin.terminal.gwt.client.ValueMap;
+ import com.vaadin.terminal.gwt.client.ui.layout.VLayoutSlot;
+ import com.vaadin.terminal.gwt.client.ui.layout.VPaintableLayoutSlot;
+ public abstract class VMeasuringOrderedLayoutPaintable extends
+         VAbstractPaintableWidgetContainer implements DirectionalManagedLayout {
+     @Override
+     public void init() {
+         getLayoutManager().registerDependency(this,
+                 getWidgetForPaintable().spacingMeasureElement);
+     }
+     public void updateCaption(VPaintableWidget component, UIDL uidl) {
+         VMeasuringOrderedLayout layout = getWidgetForPaintable();
++        if (VCaption.isNeeded(uidl, component.getState())) {
+             VLayoutSlot layoutSlot = layout.getSlotForChild(component
+                     .getWidgetForPaintable());
+             VCaption caption = layoutSlot.getCaption();
+             if (caption == null) {
+                 caption = new VCaption(component, getConnection());
+                 Widget widget = component.getWidgetForPaintable();
+                 layout.setCaption(widget, caption);
+             }
+             caption.updateCaption(uidl);
+         } else {
+             layout.setCaption(component.getWidgetForPaintable(), null);
+         }
+     }
+     @Override
+     public VMeasuringOrderedLayout getWidgetForPaintable() {
+         return (VMeasuringOrderedLayout) super.getWidgetForPaintable();
+     }
+     @Override
+     public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
+         super.updateFromUIDL(uidl, client);
+         if (!isRealUpdate(uidl)) {
+             return;
+         }
+         HashSet<VPaintableWidget> previousChildren = new HashSet<VPaintableWidget>(
+                 getChildren());
+         VMeasuringOrderedLayout layout = getWidgetForPaintable();
+         ValueMap expandRatios = uidl.getMapAttribute("expandRatios");
+         ValueMap alignments = uidl.getMapAttribute("alignments");
+         int currentIndex = 0;
+         // TODO Support reordering elements!
+         for (final Iterator<Object> it = uidl.getChildIterator(); it.hasNext();) {
+             final UIDL childUIDL = (UIDL) it.next();
+             final VPaintableWidget child = client.getPaintable(childUIDL);
+             Widget widget = child.getWidgetForPaintable();
+             VLayoutSlot slot = layout.getSlotForChild(widget);
+             if (widget.getParent() != layout) {
+                 slot = new VPaintableLayoutSlot(getWidgetForPaintable()
+                         .getStylePrimaryName(), child);
+             }
+             layout.addOrMove(slot, currentIndex++);
+             String pid = child.getId();
+             AlignmentInfo alignment;
+             if (alignments.containsKey(pid)) {
+                 alignment = new AlignmentInfo(alignments.getInt(pid));
+             } else {
+                 alignment = AlignmentInfo.TOP_LEFT;
+             }
+             slot.setAlignment(alignment);
+             double expandRatio;
+             if (expandRatios.containsKey(pid)) {
+                 expandRatio = expandRatios.getRawNumber(pid);
+             } else {
+                 expandRatio = 0;
+             }
+             slot.setExpandRatio(expandRatio);
+             if (!childUIDL.getBooleanAttribute("cached")) {
+                 child.updateFromUIDL(childUIDL, client);
+             }
+             previousChildren.remove(child);
+         }
+         for (VPaintableWidget child : previousChildren) {
+             Widget widget = child.getWidgetForPaintable();
+             // Don't remove and unregister if it has been moved to a different
+             // parent. Slot element will be left behind, but that is taken care
+             // of later
+             if (widget.getParent() == getWidgetForPaintable()) {
+                 layout.removeSlot(layout.getSlotForChild(widget));
+                 VPaintableMap vPaintableMap = VPaintableMap.get(client);
+                 vPaintableMap.unregisterPaintable(child);
+             }
+         }
+         // Remove empty layout slots left behind after children have moved to
+         // other paintables
+         while (true) {
+             int childCount = layout.getElement().getChildCount();
+             if (childCount <= 1) {
+                 // Stop if no more slots (spacing element is always present)
+                 break;
+             }
+             Node lastSlot = layout.getElement().getChild(childCount - 2);
+             if (lastSlot.getChildCount() == 0) {
+                 // Remove if empty
+                 lastSlot.removeFromParent();
+             } else {
+                 // Stop searching when last slot is not empty
+                 break;
+             }
+         }
+         int bitMask = uidl.getIntAttribute("margins");
+         layout.updateMarginStyleNames(new VMarginInfo(bitMask));
+         layout.updateSpacingStyleName(uidl.getBooleanAttribute("spacing"));
+         getLayoutManager().setNeedsUpdate(this);
+     }
+     private int getSizeForInnerSize(int size, boolean isVertical) {
+         LayoutManager layoutManager = getLayoutManager();
+         Element element = getWidgetForPaintable().getElement();
+         if (isVertical) {
+             return size + layoutManager.getBorderHeight(element)
+                     + layoutManager.getPaddingHeight(element);
+         } else {
+             return size + layoutManager.getBorderWidth(element)
+                     + layoutManager.getPaddingWidth(element);
+         }
+     }
+     private static String getSizeProperty(boolean isVertical) {
+         return isVertical ? "height" : "width";
+     }
+     private boolean isUndefinedInDirection(boolean isVertical) {
+         if (isVertical) {
+             return isUndefinedHeight();
+         } else {
+             return isUndefinedWidth();
+         }
+     }
+     private int getInnerSizeInDirection(boolean isVertical) {
+         if (isVertical) {
+             return getLayoutManager().getInnerHeight(
+                     getWidgetForPaintable().getElement());
+         } else {
+             return getLayoutManager().getInnerWidth(
+                     getWidgetForPaintable().getElement());
+         }
+     }
+     private void layoutPrimaryDirection() {
+         VMeasuringOrderedLayout layout = getWidgetForPaintable();
+         boolean isVertical = layout.isVertical;
+         boolean isUndefined = isUndefinedInDirection(isVertical);
+         int startPadding = getStartPadding(isVertical);
+         int spacingSize = getSpacingInDirection(isVertical);
+         int allocatedSize;
+         if (isUndefined) {
+             allocatedSize = -1;
+         } else {
+             allocatedSize = getInnerSizeInDirection(isVertical);
+         }
+         allocatedSize = layout.layoutPrimaryDirection(spacingSize,
+                 allocatedSize, startPadding);
+         Style ownStyle = getWidgetForPaintable().getElement().getStyle();
+         if (isUndefined) {
+             ownStyle.setPropertyPx(getSizeProperty(isVertical),
+                     getSizeForInnerSize(allocatedSize, isVertical));
+         } else {
+             ownStyle.setProperty(getSizeProperty(isVertical),
+                     getDefinedSize(isVertical));
+         }
+     }
+     private int getSpacingInDirection(boolean isVertical) {
+         if (isVertical) {
+             return getLayoutManager().getOuterHeight(
+                     getWidgetForPaintable().spacingMeasureElement);
+         } else {
+             return getLayoutManager().getOuterWidth(
+                     getWidgetForPaintable().spacingMeasureElement);
+         }
+     }
+     private void layoutSecondaryDirection() {
+         VMeasuringOrderedLayout layout = getWidgetForPaintable();
+         boolean isVertical = layout.isVertical;
+         boolean isUndefined = isUndefinedInDirection(!isVertical);
+         int startPadding = getStartPadding(!isVertical);
+         int allocatedSize;
+         if (isUndefined) {
+             allocatedSize = -1;
+         } else {
+             allocatedSize = getInnerSizeInDirection(!isVertical);
+         }
+         allocatedSize = layout.layoutSecondaryDirection(allocatedSize,
+                 startPadding);
+         Style ownStyle = getWidgetForPaintable().getElement().getStyle();
+         if (isUndefined) {
+             ownStyle.setPropertyPx(
+                     getSizeProperty(!getWidgetForPaintable().isVertical),
+                     getSizeForInnerSize(allocatedSize,
+                             !getWidgetForPaintable().isVertical));
+         } else {
+             ownStyle.setProperty(
+                     getSizeProperty(!getWidgetForPaintable().isVertical),
+                     getDefinedSize(!getWidgetForPaintable().isVertical));
+         }
+     }
+     private String getDefinedSize(boolean isVertical) {
+         if (isVertical) {
+             return getDeclaredHeight();
+         } else {
+             return getDeclaredWidth();
+         }
+     }
+     private int getStartPadding(boolean isVertical) {
+         if (isVertical) {
+             return getLayoutManager().getPaddingTop(
+                     getWidgetForPaintable().getElement());
+         } else {
+             return getLayoutManager().getPaddingLeft(
+                     getWidgetForPaintable().getElement());
+         }
+     }
+     public void layoutHorizontally() {
+         if (getWidgetForPaintable().isVertical) {
+             layoutSecondaryDirection();
+         } else {
+             layoutPrimaryDirection();
+         }
+     }
+     public void layoutVertically() {
+         if (getWidgetForPaintable().isVertical) {
+             layoutPrimaryDirection();
+         } else {
+             layoutSecondaryDirection();
+         }
+     }
+ }
index b4499cd2d52b8516383d463462ade88c65421f27,07d9de5f20f0b444b2ad5e35d4eacb85e90e3a20..c4651ee6266c22901578d25348e76859ddfaf012
@@@ -59,11 -59,8 +59,9 @@@ import com.google.gwt.user.client.ui.UI
  import com.google.gwt.user.client.ui.Widget;
  import com.vaadin.terminal.gwt.client.ApplicationConnection;
  import com.vaadin.terminal.gwt.client.BrowserInfo;
- import com.vaadin.terminal.gwt.client.Container;
 +import com.vaadin.terminal.gwt.client.ComponentState;
  import com.vaadin.terminal.gwt.client.Focusable;
  import com.vaadin.terminal.gwt.client.MouseEventDetails;
- import com.vaadin.terminal.gwt.client.RenderSpace;
  import com.vaadin.terminal.gwt.client.TooltipInfo;
  import com.vaadin.terminal.gwt.client.UIDL;
  import com.vaadin.terminal.gwt.client.Util;
index c126e81aecc24f83d395959a3489c769e30f8c06,0b5c43d30f1f56f527cc1a1d72aaa3960c929929..9b154c0d91bdd0a44c6e42d777484972bcc9df36
@@@ -23,9 -22,6 +22,7 @@@ import com.google.gwt.user.client.ui.Si
  import com.google.gwt.user.client.ui.Widget;
  import com.vaadin.terminal.gwt.client.ApplicationConnection;
  import com.vaadin.terminal.gwt.client.BrowserInfo;
- import com.vaadin.terminal.gwt.client.RenderInformation;
- import com.vaadin.terminal.gwt.client.RenderSpace;
 +import com.vaadin.terminal.gwt.client.ComponentState;
  import com.vaadin.terminal.gwt.client.TooltipInfo;
  import com.vaadin.terminal.gwt.client.UIDL;
  import com.vaadin.terminal.gwt.client.Util;