]> source.dussan.org Git - vaadin-framework.git/commitdiff
Update AbstractOrderedLayout calculation logic 65/565/1
authorLeif Åstrand <leif@vaadin.com>
Thu, 3 Jan 2013 09:13:17 +0000 (11:13 +0200)
committerLeif Åstrand <leif@vaadin.com>
Thu, 3 Jan 2013 09:17:54 +0000 (11:17 +0200)
* Always use expansion logic if the layout's size is fixed
* Ensure e.g. expansion changes happen even if no hierarchy or
measurement changes (#10161)
* Separate the calculation of expand ratios from the adjustment for the
sizes of children without expansion
* Ensure there are element resize listeners for all elements that should
be measured (#10488)
* Postpone calculations if there are elements that have not yet been
measured
* Use measurements for fixing the height under more circumstances
* Only update based on hierarchy & state if something might have changed

Change-Id: I8542afbcb7e93d44bd0dff751a56ed10033937fc

client/src/com/vaadin/client/ui/orderedlayout/AbstractOrderedLayoutConnector.java
client/src/com/vaadin/client/ui/orderedlayout/Slot.java
client/src/com/vaadin/client/ui/orderedlayout/VAbstractOrderedLayout.java
uitest/src/com/vaadin/tests/components/orderedlayout/OrderedLayoutCases.java

index e062d37dd6d229b3d4fbfb0962282aa8ca7bedbe..ce16b67d8b09e49bab29cadd117910ad71f1192b 100644 (file)
  */
 package com.vaadin.client.ui.orderedlayout;
 
-import java.util.HashMap;
-import java.util.HashSet;
 import java.util.List;
 
 import com.google.gwt.dom.client.Style.Unit;
 import com.google.gwt.user.client.Element;
+import com.vaadin.client.ApplicationConnection;
 import com.vaadin.client.ComponentConnector;
 import com.vaadin.client.ConnectorHierarchyChangeEvent;
+import com.vaadin.client.LayoutManager;
+import com.vaadin.client.ServerConnector;
 import com.vaadin.client.Util;
 import com.vaadin.client.communication.StateChangeEvent;
 import com.vaadin.client.communication.StateChangeEvent.StateChangeHandler;
@@ -62,35 +63,28 @@ public abstract class AbstractOrderedLayoutConnector extends
         @Override
         protected LayoutClickRpc getLayoutClickRPC() {
             return getRpcProxy(AbstractOrderedLayoutServerRpc.class);
-        };
+        }
     };
 
     private StateChangeHandler childStateChangeHandler = new StateChangeHandler() {
         @Override
         public void onStateChanged(StateChangeEvent stateChangeEvent) {
-
-            ComponentConnector child = (ComponentConnector) stateChangeEvent
-                    .getConnector();
-
-            // We need to update the slot size if the component size is changed
-            // to relative
-            Slot slot = getWidget().getSlot(child.getWidget());
-            slot.setRelativeWidth(child.isRelativeWidth());
-            slot.setRelativeHeight(child.isRelativeHeight());
-
-            // Update slot style names
-            List<String> childStyles = child.getState().styles;
-            if (childStyles == null) {
-                getWidget().setSlotStyleNames(child.getWidget(),
-                        (String[]) null);
-            } else {
-                getWidget().setSlotStyleNames(child.getWidget(),
-                        childStyles.toArray(new String[childStyles.size()]));
+            // Child state has changed, update stuff it hasn't already been done
+            updateInternalState();
+
+            /*
+             * Some changes must always be done after each child's own state
+             * change handler has been run because it might have changed some
+             * styles that are overridden here.
+             */
+            ServerConnector child = stateChangeEvent.getConnector();
+            if (child instanceof ComponentConnector) {
+                ComponentConnector component = (ComponentConnector) child;
+                Slot slot = getWidget().getSlot(component.getWidget());
+
+                slot.setRelativeWidth(component.isRelativeWidth());
+                slot.setRelativeHeight(component.isRelativeHeight());
             }
-
-            updateSlotListeners(child);
-
-            updateLayoutHeight();
         }
     };
 
@@ -123,7 +117,6 @@ public abstract class AbstractOrderedLayoutConnector extends
                 if (slot != null) {
                     slot.setCaptionResizeListener(null);
                 }
-                childCaptionElementHeight.remove(widgetElement);
                 return;
             }
 
@@ -138,14 +131,10 @@ public abstract class AbstractOrderedLayoutConnector extends
                 getWidget().updateCaptionOffset(captionElement);
             }
 
-            int h = getLayoutManager().getOuterHeight(captionElement)
-                    - getLayoutManager().getMarginHeight(captionElement);
-            childCaptionElementHeight.put(widgetElement, h);
-
             updateLayoutHeight();
 
             if (needsExpand()) {
-                getWidget().updateExpand();
+                getWidget().updateExpandCompensation();
             }
         }
     };
@@ -155,7 +144,7 @@ public abstract class AbstractOrderedLayoutConnector extends
         public void onElementResize(ElementResizeEvent e) {
             updateLayoutHeight();
             if (needsExpand()) {
-                getWidget().updateExpand();
+                getWidget().updateExpandCompensation();
             }
         }
     };
@@ -164,7 +153,7 @@ public abstract class AbstractOrderedLayoutConnector extends
         @Override
         public void onElementResize(ElementResizeEvent e) {
             if (needsExpand()) {
-                getWidget().updateExpand();
+                getWidget().updateExpandCompensation();
             }
         }
     };
@@ -201,42 +190,44 @@ public abstract class AbstractOrderedLayoutConnector extends
     }
 
     /**
-     * For bookkeeping. Used to determine if extra calculations are needed for
-     * horizontal layout.
-     */
-    private HashSet<ComponentConnector> hasVerticalAlignment = new HashSet<ComponentConnector>();
-
-    /**
-     * For bookkeeping. Used to determine if extra calculations are needed for
-     * horizontal layout.
-     */
-    private HashSet<ComponentConnector> hasRelativeHeight = new HashSet<ComponentConnector>();
-
-    /**
-     * For bookkeeping. Used to determine if extra calculations are needed for
-     * horizontal layout.
+     * Keep track of whether any child has relative height. Used to determine
+     * whether measurements are needed to make relative child heights work
+     * together with undefined container height.
      */
-    private HashSet<ComponentConnector> hasExpandRatio = new HashSet<ComponentConnector>();
+    private boolean hasChildrenWithRelativeHeight = false;
 
     /**
-     * For bookkeeping. Used in extra calculations for horizontal layout.
+     * Keeps track of whether slots should be expanded based on available space.
      */
-    private HashSet<Element> needsMeasure = new HashSet<Element>();
+    private boolean needsExpand = false;
 
     /**
-     * For bookkeeping. Used in extra calculations for horizontal layout.
+     * The id of the previous response for which state changes have been
+     * processed. If this is the same as the
+     * {@link ApplicationConnection#getLastResponseId()}, it means that we can
+     * skip some quite expensive calculations because we know that the state
+     * hasn't changed since the last time the values were calculated.
      */
-    private HashMap<Element, Integer> childCaptionElementHeight = new HashMap<Element, Integer>();
+    private int processedResponseId = -1;
 
     /*
      * (non-Javadoc)
      * 
-     * @see
-     * com.vaadin.client.HasComponentsConnector#updateCaption(com.vaadin
+     * @see com.vaadin.client.HasComponentsConnector#updateCaption(com.vaadin
      * .client.ComponentConnector)
      */
     @Override
-    public void updateCaption(ComponentConnector child) {
+    public void updateCaption(ComponentConnector connector) {
+        /*
+         * Don't directly update captions here to avoid calling e.g.
+         * updateLayoutHeight() before everything is initialized.
+         * updateInternalState() will ensure all captions are updated when
+         * appropriate.
+         */
+        updateInternalState();
+    }
+
+    private void updateCaptionInternal(ComponentConnector child) {
         Slot slot = getWidget().getSlot(child.getWidget());
 
         String caption = child.getState().caption;
@@ -274,15 +265,8 @@ public abstract class AbstractOrderedLayoutConnector extends
                     && (pos == CaptionPosition.LEFT || pos == CaptionPosition.RIGHT)) {
                 getWidget().updateCaptionOffset(slot.getCaptionElement());
             }
-        } else {
-            childCaptionElementHeight.remove(child.getWidget().getElement());
         }
 
-        updateLayoutHeight();
-
-        if (needsExpand()) {
-            getWidget().updateExpand();
-        }
     }
 
     /*
@@ -312,12 +296,6 @@ public abstract class AbstractOrderedLayoutConnector extends
         for (ComponentConnector child : previousChildren) {
             if (child.getParent() != this) {
                 Slot slot = layout.getSlot(child.getWidget());
-                hasVerticalAlignment.remove(child);
-                hasRelativeHeight.remove(child);
-                hasExpandRatio.remove(child);
-                needsMeasure.remove(child.getWidget().getElement());
-                childCaptionElementHeight
-                        .remove(child.getWidget().getElement());
                 slot.setWidgetResizeListener(null);
                 if (slot.hasCaption()) {
                     slot.setCaptionResizeListener(null);
@@ -330,13 +308,7 @@ public abstract class AbstractOrderedLayoutConnector extends
             }
         }
 
-        // If some component is added/removed, we need to recalculate the expand
-        if (needsExpand()) {
-            getWidget().updateExpand();
-        } else {
-            getWidget().clearExpand();
-        }
-
+        updateInternalState();
     }
 
     /*
@@ -354,51 +326,91 @@ public abstract class AbstractOrderedLayoutConnector extends
         getWidget().setMargin(new MarginInfo(getState().marginsBitmask));
         getWidget().setSpacing(getState().spacing);
 
-        hasExpandRatio.clear();
-        hasVerticalAlignment.clear();
-        hasRelativeHeight.clear();
-        needsMeasure.clear();
+        updateInternalState();
+    }
 
-        boolean equalExpandRatio = getWidget().vertical ? !isUndefinedHeight()
+    /**
+     * Updates DOM properties and listeners based on the current state of this
+     * layout and its children.
+     */
+    private void updateInternalState() {
+        // Avoid updating again for the same data
+        int lastResponseId = getConnection().getLastResponseId();
+        if (processedResponseId == lastResponseId) {
+            return;
+        }
+        // Remember that everything is updated for this response
+        processedResponseId = lastResponseId;
+
+        hasChildrenWithRelativeHeight = false;
+
+        needsExpand = getWidget().vertical ? !isUndefinedHeight()
                 : !isUndefinedWidth();
-        for (ComponentConnector child : getChildComponents()) {
-            double expandRatio = getState().childData.get(child).expandRatio;
-            if (expandRatio > 0) {
-                equalExpandRatio = false;
-                break;
+
+        boolean onlyZeroExpands = true;
+        if (needsExpand) {
+            for (ComponentConnector child : getChildComponents()) {
+                double expandRatio = getState().childData.get(child).expandRatio;
+                if (expandRatio != 0) {
+                    onlyZeroExpands = false;
+                    break;
+                }
             }
         }
 
+        // First update bookkeeping for all children
         for (ComponentConnector child : getChildComponents()) {
+            if (child.delegateCaptionHandling()) {
+                updateCaptionInternal(child);
+            }
+
             Slot slot = getWidget().getSlot(child.getWidget());
 
+            // Update slot style names
+            List<String> childStyles = child.getState().styles;
+            if (childStyles == null) {
+                getWidget().setSlotStyleNames(child.getWidget(),
+                        (String[]) null);
+            } else {
+                getWidget().setSlotStyleNames(child.getWidget(),
+                        childStyles.toArray(new String[childStyles.size()]));
+            }
+
             AlignmentInfo alignment = new AlignmentInfo(
                     getState().childData.get(child).alignmentBitmask);
             slot.setAlignment(alignment);
 
-            double expandRatio = getState().childData.get(child).expandRatio;
+            double expandRatio = onlyZeroExpands ? 1 : getState().childData
+                    .get(child).expandRatio;
 
-            if (equalExpandRatio) {
-                expandRatio = 1;
-            } else if (expandRatio == 0) {
-                expandRatio = -1;
-            }
             slot.setExpandRatio(expandRatio);
 
-            // Bookkeeping to identify special cases that need extra
-            // calculations
-            if (alignment.isVerticalCenter() || alignment.isBottom()) {
-                hasVerticalAlignment.add(child);
+            if (child.isRelativeHeight()) {
+                hasChildrenWithRelativeHeight = true;
             }
+        }
 
-            if (expandRatio > 0) {
-                hasExpandRatio.add(child);
-            }
+        if (needsFixedHeight()) {
+            // Add resize listener to ensure the widget itself is measured
+            getLayoutManager().addElementResizeListener(
+                    getWidget().getElement(), childComponentResizeListener);
+        } else {
+            getLayoutManager().removeElementResizeListener(
+                    getWidget().getElement(), childComponentResizeListener);
         }
 
+        // Then update listeners based on bookkeeping
         updateAllSlotListeners();
 
+        // Update the layout at this point to ensure it's OK even if we get no
+        // element resize events
         updateLayoutHeight();
+        if (needsExpand()) {
+            getWidget().updateExpandedSizes();
+            getWidget().updateExpandCompensation();
+        } else {
+            getWidget().clearExpand();
+        }
     }
 
     /**
@@ -406,29 +418,19 @@ public abstract class AbstractOrderedLayoutConnector extends
      */
     private boolean needsFixedHeight() {
         boolean isVertical = getWidget().vertical;
-        boolean hasChildrenWithVerticalAlignmentCenterOrBottom = !hasVerticalAlignment
-                .isEmpty();
-        boolean allChildrenHasVerticalAlignmentCenterOrBottom = hasVerticalAlignment
-                .size() == getChildren().size();
-        boolean hasChildrenWithRelativeHeight = !hasRelativeHeight.isEmpty();
 
         if (isVertical) {
+            // Doesn't need height fix for vertical layouts
             return false;
         }
 
         else if (!isUndefinedHeight()) {
+            // Fix not needed unless the height is undefined
             return false;
         }
 
         else if (!hasChildrenWithRelativeHeight) {
-            return false;
-        }
-
-        else if (!hasChildrenWithVerticalAlignmentCenterOrBottom) {
-            return false;
-        }
-
-        else if (allChildrenHasVerticalAlignmentCenterOrBottom) {
+            // Already works if there are no relative heights
             return false;
         }
 
@@ -439,9 +441,7 @@ public abstract class AbstractOrderedLayoutConnector extends
      * Does the layout need to expand?
      */
     private boolean needsExpand() {
-        boolean canApplyExpand = (getWidget().vertical && !isUndefinedHeight())
-                || (!getWidget().vertical && !isUndefinedWidth());
-        return hasExpandRatio.size() > 0 && canApplyExpand;
+        return needsExpand;
     }
 
     /**
@@ -477,27 +477,24 @@ public abstract class AbstractOrderedLayoutConnector extends
             }
         } else if ((child.isRelativeHeight() || child.isRelativeWidth())
                 && slot.hasCaption()) {
-            // If the slot has caption, we need to listen for it's size changes
-            // in order to update the padding/margin offset for relative sized
-            // components
+            /*
+             * If the slot has caption, we need to listen for its size changes
+             * in order to update the padding/margin offset for relative sized
+             * components.
+             * 
+             * TODO might only be needed if the caption is in the same direction
+             * as the relative size?
+             */
             slot.setCaptionResizeListener(slotCaptionResizeListener);
         }
 
         if (needsExpand()) {
+            // TODO widget resize only be needed for children without expand?
             slot.setWidgetResizeListener(childComponentResizeListener);
             if (slot.hasSpacing()) {
                 slot.setSpacingResizeListener(spacingResizeListener);
             }
         }
-
-        if (child.isRelativeHeight()) {
-            hasRelativeHeight.add(child);
-            needsMeasure.remove(child.getWidget().getElement());
-        } else {
-            hasRelativeHeight.remove(child);
-            needsMeasure.add(child.getWidget().getElement());
-        }
-
     }
 
     /**
@@ -506,7 +503,11 @@ public abstract class AbstractOrderedLayoutConnector extends
     private void updateLayoutHeight() {
         if (needsFixedHeight()) {
             int h = getMaxHeight();
-            assert (h >= 0);
+            if (h < 0) {
+                // Postpone change if there are elements that have not yet been
+                // measured
+                return;
+            }
             h += getLayoutManager().getBorderHeight(getWidget().getElement())
                     + getLayoutManager().getPaddingHeight(
                             getWidget().getElement());
@@ -522,37 +523,49 @@ public abstract class AbstractOrderedLayoutConnector extends
         int highestNonRelative = -1;
         int highestRelative = -1;
 
+        LayoutManager layoutManager = getLayoutManager();
+
         for (ComponentConnector child : getChildComponents()) {
-            // TODO would be more efficient to measure the slot element if both
-            // caption and child widget elements need to be measured. Keeping
-            // track of what to measure is the most difficult part of this
-            // layout.
-            Element el = child.getWidget().getElement();
-            CaptionPosition pos = getWidget().getCaptionPositionFromElement(
-                    (Element) el.getParentElement().cast());
-            int h = getLayoutManager().getOuterHeight(el);
+            Slot slot = getWidget().getSlot(child.getWidget());
+            Element captionElement = slot.getCaptionElement();
+            CaptionPosition pos = slot.getCaptionPosition();
+
+            Element childElement = child.getWidget().getElement();
+            int h = layoutManager.getOuterHeight(childElement);
             if (h == -1) {
-                // Height has not yet been measured so using a more
-                // conventional method instead.
-                h = Util.getRequiredHeight(el);
+                // Height has not yet been measured -> postpone actions that
+                // depend on the max height
+                return -1;
             }
-            if (needsMeasure.contains(el)) {
-                String sHeight = el.getStyle().getHeight();
-                // Only add the caption size to the height of the slot if
-                // coption position is top or bottom
-                if (childCaptionElementHeight.containsKey(el)
-                        && (sHeight == null || !sHeight.endsWith("%"))
-                        && (pos == CaptionPosition.TOP || pos == CaptionPosition.BOTTOM)) {
-                    h += childCaptionElementHeight.get(el);
+
+            boolean hasRelativeHeight = slot.hasRelativeHeight();
+
+            boolean includeCaptionHeight = captionElement != null
+                    && (pos == CaptionPosition.TOP || pos == CaptionPosition.BOTTOM);
+            if (!hasRelativeHeight && !includeCaptionHeight
+                    && captionElement != null) {
+                String sHeight = childElement.getStyle().getHeight();
+                includeCaptionHeight = (sHeight == null || !sHeight
+                        .endsWith("%"));
+            }
+
+            if (includeCaptionHeight) {
+                int captionHeight = layoutManager
+                        .getOuterHeight(captionElement)
+                        - getLayoutManager().getMarginHeight(captionElement);
+                if (captionHeight == -1) {
+                    // Height has not yet been measured -> postpone actions that
+                    // depend on the max height
+                    return -1;
                 }
+                h += captionHeight;
+            }
+
+            if (!hasRelativeHeight) {
                 if (h > highestNonRelative) {
                     highestNonRelative = h;
                 }
             } else {
-                if (childCaptionElementHeight.containsKey(el)
-                        && (pos == CaptionPosition.TOP || pos == CaptionPosition.BOTTOM)) {
-                    h += childCaptionElementHeight.get(el);
-                }
                 if (h > highestRelative) {
                     highestRelative = h;
                 }
index 094a7f1f0a15a5f068a320ed809f5d7429de5c1c..fc1c10de686b8eb2ffd6a8cfffe57d46db657f57 100644 (file)
@@ -276,7 +276,11 @@ public final class Slot extends SimplePanel {
     }
 
     /**
-     * Set how the slot should be expanded relative to the other slots
+     * Set how the slot should be expanded relative to the other slots. 0 means
+     * that the slot should not participate in the division of space based on
+     * the expand ratios but instead be allocated space based on its natural
+     * size. Other values causes the slot to get a share of the otherwise
+     * unallocated space in proportion to the slot's expand ratio value.
      * 
      * @param expandRatio
      *            The ratio of the space the slot should occupy
@@ -290,7 +294,9 @@ public final class Slot extends SimplePanel {
      * Get the expand ratio for the slot. The expand ratio describes how the
      * slot should be resized compared to other slots in the layout
      * 
-     * @return
+     * @return the expand ratio of the slot
+     * 
+     * @see #setExpandRatio(double)
      */
     public double getExpandRatio() {
         return expandRatio;
index 00b7092d813bcb55033959b01b03446a0b4a9644..0199e95c5898326b93d90c2dda4b4adefa65c9b2 100644 (file)
@@ -26,10 +26,10 @@ import com.google.gwt.regexp.shared.RegExp;
 import com.google.gwt.user.client.DOM;
 import com.google.gwt.user.client.Element;
 import com.google.gwt.user.client.ui.FlowPanel;
+import com.google.gwt.user.client.ui.RequiresResize;
 import com.google.gwt.user.client.ui.Widget;
 import com.vaadin.client.LayoutManager;
 import com.vaadin.client.Util;
-import com.vaadin.shared.ui.AlignmentInfo;
 import com.vaadin.shared.ui.MarginInfo;
 
 /**
@@ -50,6 +50,12 @@ public class VAbstractOrderedLayout extends FlowPanel {
 
     private LayoutManager layoutManager;
 
+    /**
+     * Keep track of the last allocated expand size to help detecting when it
+     * changes.
+     */
+    private int lastExpandSize = -1;
+
     public VAbstractOrderedLayout(boolean vertical) {
         this.vertical = vertical;
     }
@@ -332,12 +338,25 @@ public class VAbstractOrderedLayout extends FlowPanel {
     }
 
     /**
-     * Triggers a recalculation of the expand width and heights
+     * Assigns relative sizes to the children that should expand based on their
+     * expand ratios.
      */
-    private void recalculateExpands() {
+    public void updateExpandedSizes() {
+        // Ensure the expand wrapper is in place
+        if (expandWrapper == null) {
+            expandWrapper = DOM.createDiv();
+            expandWrapper.setClassName("v-expand");
+            while (getElement().getChildCount() > 0) {
+                Node el = getElement().getChild(0);
+                expandWrapper.appendChild(el);
+            }
+            getElement().appendChild(expandWrapper);
+        }
+
+        // Sum up expand ratios to get the denominator
         double total = 0;
         for (Slot slot : widgetToSlot.values()) {
-            if (slot.getExpandRatio() > -1) {
+            if (slot.getExpandRatio() != 0) {
                 total += slot.getExpandRatio();
             } else {
                 if (vertical) {
@@ -346,9 +365,13 @@ public class VAbstractOrderedLayout extends FlowPanel {
                     slot.getElement().getStyle().clearWidth();
                 }
             }
+            slot.getElement().getStyle().clearMarginLeft();
+            slot.getElement().getStyle().clearMarginTop();
         }
+
+        // Give each child its own share
         for (Slot slot : widgetToSlot.values()) {
-            if (slot.getExpandRatio() > -1) {
+            if (slot.getExpandRatio() != 0) {
                 if (vertical) {
                     slot.setHeight((100 * (slot.getExpandRatio() / total))
                             + "%");
@@ -372,7 +395,8 @@ public class VAbstractOrderedLayout extends FlowPanel {
      */
     public void clearExpand() {
         if (expandWrapper != null) {
-            for (; expandWrapper.getChildCount() > 0;) {
+            lastExpandSize = -1;
+            while (expandWrapper.getChildCount() > 0) {
                 Element el = expandWrapper.getChild(0).cast();
                 getElement().appendChild(el);
                 if (vertical) {
@@ -389,39 +413,23 @@ public class VAbstractOrderedLayout extends FlowPanel {
     }
 
     /**
-     * Adds elements used to expand a slot
+     * Updates the expand compensation based on the measured sizes of children
+     * without expand.
      */
-    public void updateExpand() {
+    public void updateExpandCompensation() {
         boolean isExpanding = false;
         for (Widget slot : getChildren()) {
-            if (((Slot) slot).getExpandRatio() > -1) {
+            if (((Slot) slot).getExpandRatio() != 0) {
                 isExpanding = true;
-            } else {
-                if (vertical) {
-                    slot.getElement().getStyle().clearHeight();
-                } else {
-                    slot.getElement().getStyle().clearWidth();
-                }
+                break;
             }
-            slot.getElement().getStyle().clearMarginLeft();
-            slot.getElement().getStyle().clearMarginTop();
         }
 
         if (isExpanding) {
-            if (expandWrapper == null) {
-                expandWrapper = DOM.createDiv();
-                expandWrapper.setClassName("v-expand");
-                for (; getElement().getChildCount() > 0;) {
-                    Node el = getElement().getChild(0);
-                    expandWrapper.appendChild(el);
-                }
-                getElement().appendChild(expandWrapper);
-            }
-
             int totalSize = 0;
             for (Widget w : getChildren()) {
                 Slot slot = (Slot) w;
-                if (slot.getExpandRatio() == -1) {
+                if (slot.getExpandRatio() == 0) {
 
                     if (layoutManager != null) {
                         // TODO check caption position
@@ -483,44 +491,21 @@ public class VAbstractOrderedLayout extends FlowPanel {
                         .setMarginLeft(-totalSize, Unit.PX);
             }
 
-            recalculateExpands();
-        }
-    }
-
-    /**
-     * Perform a recalculation of the layout height
-     */
-    public void recalculateLayoutHeight() {
-        // Only needed if a horizontal layout is undefined high, and contains
-        // relative height children or vertical alignments
-        if (vertical || definedHeight) {
-            return;
-        }
-
-        boolean hasRelativeHeightChildren = false;
-        boolean hasVAlign = false;
-
-        for (Widget slot : getChildren()) {
-            Widget widget = ((Slot) slot).getWidget();
-            String h = widget.getElement().getStyle().getHeight();
-            if (h != null && h.indexOf("%") > -1) {
-                hasRelativeHeightChildren = true;
-            }
-            AlignmentInfo a = ((Slot) slot).getAlignment();
-            if (a != null && (a.isVerticalCenter() || a.isBottom())) {
-                hasVAlign = true;
-            }
-        }
-
-        if (hasRelativeHeightChildren || hasVAlign) {
-            int newHeight;
-            if (layoutManager != null) {
-                newHeight = layoutManager.getOuterHeight(getElement())
-                        - layoutManager.getMarginHeight(getElement());
-            } else {
-                newHeight = getElement().getOffsetHeight();
+            // Measure expanded children again if their size might have changed
+            if (totalSize != lastExpandSize) {
+                lastExpandSize = totalSize;
+                for (Widget w : getChildren()) {
+                    Slot slot = (Slot) w;
+                    if (slot.getExpandRatio() != 0) {
+                        if (layoutManager != null) {
+                            layoutManager.setNeedsMeasure(Util
+                                    .findConnectorFor(slot.getWidget()));
+                        } else if (slot.getWidget() instanceof RequiresResize) {
+                            ((RequiresResize) slot.getWidget()).onResize();
+                        }
+                    }
+                }
             }
-            getElement().getStyle().setHeight(newHeight, Unit.PX);
         }
     }
 
index da6946f4325df70c9e75a8abdcfd1043c88414ee..fe1dfe3e6dc51d318b8ae45b0989288d0a025101 100644 (file)
@@ -321,6 +321,18 @@ public class OrderedLayoutCases extends AbstractTestUI {
                         setChildState(0, 2, 1);
                         // Height: 100% to middle child
                         setChildState(1, 1, 4);
+                    }
+                }));
+
+        caseBar.addComponent(new Button("Undefined + alignments",
+                new ClickListener() {
+                    @Override
+                    public void buttonClick(ClickEvent event) {
+                        resetState();
+                        // Height: 350px to left child
+                        setChildState(0, 1, 2);
+                        // Short caption to left child
+                        setChildState(0, 2, 1);
                         // Alignment: bottom left to right child
                         setChildState(2, 4, 7);
                     }