]> source.dussan.org Git - vaadin-framework.git/commitdiff
Split measuring ordered layout to paintable and widget (#8324)
authorLeif Åstrand <leif@vaadin.com>
Tue, 7 Feb 2012 10:10:40 +0000 (12:10 +0200)
committerLeif Åstrand <leif@vaadin.com>
Tue, 7 Feb 2012 10:10:40 +0000 (12:10 +0200)
src/com/vaadin/terminal/gwt/client/CalculatingLayout.java [new file with mode: 0644]
src/com/vaadin/terminal/gwt/client/MeasureManager.java
src/com/vaadin/terminal/gwt/client/ui/VHorizontalLayoutPaintable.java
src/com/vaadin/terminal/gwt/client/ui/VMeasuringOrderedLayout.java
src/com/vaadin/terminal/gwt/client/ui/VMeasuringOrderedLayoutPaintable.java [new file with mode: 0644]
src/com/vaadin/terminal/gwt/client/ui/VVerticalLayoutPaintable.java

diff --git a/src/com/vaadin/terminal/gwt/client/CalculatingLayout.java b/src/com/vaadin/terminal/gwt/client/CalculatingLayout.java
new file mode 100644 (file)
index 0000000..ada9ab1
--- /dev/null
@@ -0,0 +1,7 @@
+package com.vaadin.terminal.gwt.client;
+
+public interface CalculatingLayout extends VPaintableWidgetContainer {
+    public void updateVerticalSizes();
+
+    public void updateHorizontalSizes();
+}
\ No newline at end of file
index 46d1aeb9fcb386b32d946ae235d5d7159cf0f07e..9bcecfd7862204f5b834a2dc953dde6bbeacfb71 100644 (file)
@@ -2,9 +2,7 @@ package com.vaadin.terminal.gwt.client;
 
 import java.util.ArrayList;
 import java.util.Collection;
-import java.util.Collections;
 import java.util.HashMap;
-import java.util.HashSet;
 import java.util.Map;
 import java.util.Map.Entry;
 
@@ -85,10 +83,7 @@ public class MeasureManager {
     private static MeasureManager instance = new MeasureManager();
 
     public static Collection<VPaintableWidget> getChildren(
-            VPaintableWidget paintable, ApplicationConnection client) {
-        if (!(paintable instanceof Container)) {
-            return Collections.emptySet();
-        }
+            VPaintableWidgetContainer paintable, ApplicationConnection client) {
         Widget widget = paintable.getWidgetForPaintable();
         Collection<VPaintableWidget> children = new ArrayList<VPaintableWidget>();
 
@@ -113,23 +108,6 @@ public class MeasureManager {
         }
     }
 
-    private static VPaintableWidget getParentPaintable(
-            VPaintableWidget paintable, VPaintableMap paintableMap) {
-        Widget widget = paintable.getWidgetForPaintable();
-        while (true) {
-            widget = widget.getParent();
-            if (widget == null) {
-                return null;
-            }
-            VPaintableWidget parentPaintable = paintableMap
-                    .getPaintable(widget);
-            if (parentPaintable != null) {
-                return parentPaintable;
-            }
-            // Else continue with the parent
-        }
-    }
-
     public void doLayout(ApplicationConnection client) {
         VPaintableMap paintableMap = client.getPaintableMap();
         VPaintableWidget[] paintableWidgets = paintableMap
@@ -162,9 +140,8 @@ public class MeasureManager {
             for (int i = 0; i < changed.length(); i++) {
                 VPaintableWidget paintable = (VPaintableWidget) paintableMap
                         .getPaintable(changed.get(i));
-                VPaintableWidget parentPaintable = getParentPaintable(
-                        paintable, paintableMap);
-                if (parentPaintable instanceof Container) {
+                VPaintableWidget parentPaintable = paintable.getParent();
+                if (parentPaintable instanceof CalculatingLayout) {
                     affectedContainers
                             .add(paintableMap.getPid(parentPaintable));
                 }
@@ -181,6 +158,10 @@ public class MeasureManager {
                         // TODO Do nothing here if parent instanceof
                         // ProvidesRepaint?
                         ((RequiresResize) widget).onResize();
+                    } else if (paintable instanceof CalculatingLayout) {
+                        CalculatingLayout calculating = (CalculatingLayout) paintable;
+                        calculating.updateHorizontalSizes();
+                        calculating.updateVerticalSizes();
                     }
                 }
             }
@@ -189,19 +170,11 @@ public class MeasureManager {
             for (int i = 0; i < affectedPids.length(); i++) {
                 // Find all changed children
                 String containerPid = affectedPids.get(i);
-                VPaintableWidget container = (VPaintableWidget) paintableMap
+                CalculatingLayout container = (CalculatingLayout) paintableMap
                         .getPaintable(containerPid);
-                Collection<VPaintableWidget> children = getChildren(container,
-                        client);
-                HashSet<Widget> changedChildren = new HashSet<Widget>();
-
-                for (VPaintableWidget child : children) {
-                    if (changedSet.contains(paintableMap.getPid(child))) {
-                        changedChildren.add(child.getWidgetForPaintable());
-                    }
-                }
 
-                ((Container) container).requestLayout(changedChildren);
+                container.updateHorizontalSizes();
+                container.updateVerticalSizes();
             }
 
             long layoutEnd = System.currentTimeMillis();
index acc49ece187871e8fbebf2f3cf03d5499ed95c28..2fee82e97449839cabc3ee80a17e8483c84f4534 100644 (file)
@@ -5,7 +5,8 @@ package com.vaadin.terminal.gwt.client.ui;
 
 import com.google.gwt.core.client.GWT;
 
-public class VHorizontalLayoutPaintable extends VOrderedLayoutPaintable {
+public class VHorizontalLayoutPaintable extends
+        VMeasuringOrderedLayoutPaintable {
 
     @Override
     public VHorizontalLayout getWidgetForPaintable() {
index fa82c5b59f0ee410e652e4e0806b7714b92c37db..1154585191cb80d24c645d3acd762d4b945e2bc0 100644 (file)
@@ -3,13 +3,8 @@
  */
 package com.vaadin.terminal.gwt.client.ui;
 
-import java.util.Collection;
-import java.util.Collections;
 import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Iterator;
 import java.util.Map;
-import java.util.Set;
 
 import com.google.gwt.dom.client.DivElement;
 import com.google.gwt.dom.client.Document;
@@ -17,45 +12,39 @@ import com.google.gwt.dom.client.Element;
 import com.google.gwt.dom.client.Style;
 import com.google.gwt.dom.client.Style.Overflow;
 import com.google.gwt.dom.client.Style.Position;
-import com.google.gwt.dom.client.Style.Unit;
 import com.google.gwt.user.client.DOM;
 import com.google.gwt.user.client.ui.ComplexPanel;
-import com.google.gwt.user.client.ui.RequiresResize;
 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.MeasureManager;
 import com.vaadin.terminal.gwt.client.RenderSpace;
-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;
 
-public class VMeasuringOrderedLayout extends ComplexPanel implements Container,
-        RequiresResize {
+public class VMeasuringOrderedLayout extends ComplexPanel {
 
     public static final String CLASSNAME = "v-orderedlayout";
 
     private static final int MARGIN_SIZE = 20;
 
-    private final boolean isVertical;
+    final boolean isVertical;
 
-    private ApplicationConnection client;
+    ApplicationConnection client;
 
-    private String id;
+    String id;
 
     private RenderSpace space;
 
-    private ValueMap expandRatios;
+    ValueMap expandRatios;
 
-    private ValueMap alignments;
+    ValueMap alignments;
 
-    private Map<VPaintableWidget, VCaption> captions = new HashMap<VPaintableWidget, VCaption>();
+    Map<VPaintableWidget, VCaption> captions = new HashMap<VPaintableWidget, VCaption>();
 
-    private boolean spacing;
+    boolean spacing;
 
-    private VMarginInfo activeMarginsInfo;
+    VMarginInfo activeMarginsInfo;
 
     protected VMeasuringOrderedLayout(String className, boolean isVertical) {
         DivElement element = Document.get().createDivElement();
@@ -69,71 +58,7 @@ public class VMeasuringOrderedLayout extends ComplexPanel implements Container,
         this.isVertical = isVertical;
     }
 
-    public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
-        this.client = client;
-        id = uidl.getId();
-        if (client.updateComponent(this, uidl, true)) {
-            return;
-        }
-
-        long start = System.currentTimeMillis();
-        // long childTime = 0;
-
-        HashSet<Widget> previousChildren = new HashSet<Widget>();
-        for (Widget child : this) {
-            if (!(child instanceof VCaption)) {
-                previousChildren.add(child);
-            }
-        }
-        // 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();
-
-            if (widget.getParent() != this) {
-                DivElement wrapper = Document.get().createDivElement();
-                wrapper.getStyle().setPosition(Position.ABSOLUTE);
-                getElement().appendChild(wrapper);
-                add(widget, wrapper);
-            }
-
-            if (!childUIDL.getBooleanAttribute("cached")) {
-                child.updateFromUIDL(childUIDL, client);
-                client.getMeasuredSize(child).setDirty(true);
-            }
-            // TODO Update alignments and expand ratios
-
-            previousChildren.remove(widget);
-        }
-
-        for (Widget widget : previousChildren) {
-            Element wrapper = getWrapper(widget);
-            VCaption caption = captions.remove(widget);
-            if (caption != null) {
-                remove(caption);
-            }
-            remove(widget);
-            // Remove the wrapper
-            getElement().removeChild(wrapper);
-
-            client.unregisterPaintable(VPaintableMap.get(client).getPaintable(
-                    widget));
-        }
-
-        int bitMask = uidl.getIntAttribute("margins");
-        if (activeMarginsInfo == null
-                || activeMarginsInfo.getBitMask() != bitMask) {
-            activeMarginsInfo = new VMarginInfo(bitMask);
-        }
-
-        spacing = uidl.getBooleanAttribute("spacing");
-        expandRatios = uidl.getMapAttribute("expandRatios");
-        alignments = uidl.getMapAttribute("alignments");
-        client.getMeasuredSize(this).setDirty(true);
-    }
-
-    private static Element getWrapper(Widget widget) {
+    static Element getWrapper(Widget widget) {
         return widget.getElement().getParentElement();
     }
 
@@ -141,184 +66,7 @@ public class VMeasuringOrderedLayout extends ComplexPanel implements Container,
         add(widget, (com.google.gwt.user.client.Element) wrapper.cast());
     }
 
-    public void onResize() {
-        requestLayout(Collections.<Widget> emptySet());
-    }
-
-    private static boolean isUndefinedInDirection(Widget widget,
-            boolean isVertical) {
-        String dimension = getDimensionInDirection(widget, isVertical);
-        return dimension == null || dimension.length() == 0;
-    }
-
-    private static boolean isRelativeInDirection(Widget widget,
-            boolean isVertical) {
-        String dimension = getDimensionInDirection(widget, isVertical);
-        return dimension != null && dimension.endsWith("%");
-    }
-
-    private static String getDimensionInDirection(Widget widget,
-            boolean vertical) {
-        com.google.gwt.user.client.Element element = widget.getElement();
-        Style style = element.getStyle();
-        if (vertical) {
-            return style.getHeight();
-        } else {
-            return style.getWidth();
-        }
-    }
-
-    public void replaceChildComponent(Widget oldComponent, Widget newComponent) {
-        throw new UnsupportedOperationException();
-    }
-
-    public boolean hasChildComponent(Widget component) {
-        return component.getParent() == this;
-    }
-
-    public void updateCaption(VPaintableWidget component, UIDL uidl) {
-        if (VCaption.isNeeded(uidl)) {
-            VCaption caption = captions.get(component);
-            if (caption == null) {
-                caption = new VCaption(component, client);
-
-                Widget widget = (Widget) component;
-                Element wrapper = getWrapper(widget);
-
-                // Logical attach.
-                getChildren().add(caption);
-
-                // Physical attach.
-                DOM.insertBefore(
-                        (com.google.gwt.user.client.Element) wrapper.cast(),
-                        caption.getElement(), widget.getElement());
-
-                // Adopt.
-                adopt(caption);
-                captions.put(component, caption);
-                MeasureManager.MeasuredSize measuredSize = client
-                        .getMeasuredSize(component);
-
-                measuredSize.registerDependency(caption.getElement());
-            }
-            caption.updateCaption(uidl);
-        } else {
-            VCaption removedCaption = captions.remove(component);
-            if (removedCaption != null) {
-                remove(removedCaption);
-                MeasureManager.MeasuredSize measuredSize = client
-                        .getMeasuredSize(component);
-                measuredSize.deRegisterDependency(removedCaption.getElement());
-            }
-        }
-
-    }
-
-    private void layoutPrimaryDirection() {
-        Collection<VPaintableWidget> children = MeasureManager.getChildren(
-                this, client);
-
-        // First pass - get total expand ratio and allocated size
-        int totalAllocated = 0;
-        double totalExpand = 0;
-        for (VPaintableWidget child : children) {
-            Widget widget = child.getWidgetForPaintable();
-
-            totalExpand += getExpandRatio(child);
-
-            int captionAllocation;
-            if (isVertical) {
-                captionAllocation = getCaptionHeight(child);
-                getWrapper(widget).getStyle().setPaddingTop(captionAllocation,
-                        Unit.PX);
-            } else {
-                captionAllocation = 0;
-            }
-
-            if (!isRelativeInDirection(widget, isVertical)) {
-                totalAllocated += getMeasuredInDirection(child, isVertical)
-                        + captionAllocation;
-            }
-        }
-        int startMargin = getStartMarginInDirection(isVertical);
-        int totalMargins = startMargin + getEndMarginInDirection(isVertical);
-
-        totalAllocated += totalMargins
-                + (getSpacingInDirection(isVertical) * (children.size() - 1));
-
-        Style ownStyle = getElement().getStyle();
-        double ownSize;
-        if (isUndefinedInDirection(this, isVertical)) {
-            ownSize = totalAllocated;
-            ownStyle.setProperty(getMinPropertyName(isVertical),
-                    totalAllocated, Unit.PX);
-        } else {
-            ownSize = getMeasuredInDirection(this, isVertical);
-            ownStyle.clearProperty(getMinPropertyName(isVertical));
-        }
-
-        double unallocatedSpace = Math.max(0, ownSize - totalAllocated);
-
-        double currentLocation = startMargin;
-        for (VPaintableWidget child : children) {
-            Widget widget = child.getWidgetForPaintable();
-            Element wrapper = getWrapper(widget);
-            Style wrapperStyle = wrapper.getStyle();
-
-            double childExpandRatio;
-            if (totalExpand == 0) {
-                childExpandRatio = 1d / children.size();
-            } else {
-                childExpandRatio = getExpandRatio(child) / totalExpand;
-            }
-
-            double extraPixels = unallocatedSpace * childExpandRatio;
-
-            boolean relative = isRelativeInDirection(widget, isVertical);
-
-            double size = getMeasuredInDirection(child, isVertical);
-            int captionHeight = getCaptionHeight(child);
-
-            if (isVertical) {
-                size += captionHeight;
-            } else if (!relative) {
-                size = Math.max(size, getCaptionWidth(child));
-            }
-
-            double allocatedSpace = extraPixels;
-            if (!relative) {
-                allocatedSpace += size;
-            }
-
-            int alignment = getAlignmentInDirection(getAlignment(child),
-                    isVertical);
-
-            if (relative) {
-                double captionReservation = isVertical ? captionHeight : 0;
-                wrapperStyle.setProperty(getSizeProperty(isVertical),
-                        allocatedSpace - captionReservation, Unit.PX);
-            } else {
-                wrapperStyle.clearProperty(getSizeProperty(isVertical));
-            }
-
-            double startPosition = currentLocation;
-            if (alignment == 0) {
-                // Centered
-                startPosition += (allocatedSpace - size) / 2;
-            } else if (alignment == 1) {
-                // Right or bottom
-                startPosition += allocatedSpace - size;
-            }
-
-            wrapperStyle.setProperty(getStartProperty(isVertical),
-                    startPosition, Unit.PX);
-
-            currentLocation += allocatedSpace
-                    + getSpacingInDirection(isVertical);
-        }
-    }
-
-    private int getEndMarginInDirection(boolean isVertical) {
+    int getEndMarginInDirection(boolean isVertical) {
         if (isVertical) {
             return activeMarginsInfo.hasBottom() ? MARGIN_SIZE : 0;
         } else {
@@ -326,7 +74,7 @@ public class VMeasuringOrderedLayout extends ComplexPanel implements Container,
         }
     }
 
-    private int getStartMarginInDirection(boolean isVertical) {
+    int getStartMarginInDirection(boolean isVertical) {
         if (isVertical) {
             return activeMarginsInfo.hasTop() ? MARGIN_SIZE : 0;
         } else {
@@ -334,120 +82,7 @@ public class VMeasuringOrderedLayout extends ComplexPanel implements Container,
         }
     }
 
-    private void layoutSecondaryDirection() {
-        Collection<VPaintableWidget> children = MeasureManager.getChildren(
-                this, client);
-
-        int maxSize = 0;
-        for (VPaintableWidget child : children) {
-            Widget widget = child.getWidgetForPaintable();
-
-            int captionAllocation;
-            if (!isVertical) {
-                captionAllocation = getCaptionHeight(child);
-                getWrapper(widget).getStyle().setPaddingTop(captionAllocation,
-                        Unit.PX);
-            } else {
-                captionAllocation = 0;
-            }
-
-            if (!isRelativeInDirection(widget, !isVertical)) {
-                int childSize = getMeasuredInDirection(child, !isVertical)
-                        + captionAllocation;
-                maxSize = Math.max(maxSize, childSize);
-            }
-        }
-
-        int startMargin = getStartMarginInDirection(!isVertical);
-        int totalMargins = startMargin + getEndMarginInDirection(!isVertical);
-
-        double availableSpace;
-        Style ownStyle = getElement().getStyle();
-
-        if (isUndefinedInDirection(this, !isVertical)) {
-            ownStyle.setProperty(getMinPropertyName(!isVertical), maxSize
-                    + totalMargins, Unit.PX);
-            availableSpace = maxSize;
-        } else {
-            ownStyle.clearProperty(getMinPropertyName(!isVertical));
-            availableSpace = getMeasuredInDirection(this, !isVertical)
-                    - totalMargins;
-        }
-
-        for (VPaintableWidget child : children) {
-            Widget widget = child.getWidgetForPaintable();
-            Element wrapper = getWrapper(widget);
-            Style wrapperStyle = wrapper.getStyle();
-
-            boolean relative = isRelativeInDirection(widget, !isVertical);
-
-            int captionHeight = getCaptionHeight(child);
-
-            double allocatedSize = getMeasuredInDirection(child, !isVertical);
-            if (!isVertical) {
-                allocatedSize += captionHeight;
-            } else if (!relative) {
-                allocatedSize = Math.max(allocatedSize, getCaptionWidth(child));
-            }
-
-            int alignment = getAlignmentInDirection(getAlignment(child),
-                    !isVertical);
-
-            double startPosition = startMargin;
-            if (alignment == 0) {
-                startPosition += (availableSpace - allocatedSize) / 2;
-                // Centered
-            } else if (alignment == 1) {
-                // Right or bottom
-                startPosition += (availableSpace - allocatedSize);
-            }
-
-            wrapperStyle.setProperty(getStartProperty(!isVertical),
-                    startPosition, Unit.PX);
-
-            if (relative) {
-                double captionReservation = !isVertical ? captionHeight : 0;
-                wrapperStyle.setProperty(getSizeProperty(!isVertical),
-                        availableSpace - captionReservation, Unit.PX);
-            } else {
-                wrapperStyle.clearProperty(getSizeProperty(!isVertical));
-            }
-        }
-    }
-
-    public boolean requestLayout(Set<Widget> changed) {
-        layoutPrimaryDirection();
-        layoutSecondaryDirection();
-
-        // Doesn't matter right now...
-        return true;
-    }
-
-    private static int getAlignmentInDirection(AlignmentInfo alignment,
-            boolean isVertical) {
-        if (alignment == null) {
-            return -1;
-        }
-        if (isVertical) {
-            if (alignment.isTop()) {
-                return -1;
-            } else if (alignment.isBottom()) {
-                return 1;
-            } else {
-                return 0;
-            }
-        } else {
-            if (alignment.isLeft()) {
-                return -1;
-            } else if (alignment.isRight()) {
-                return 1;
-            } else {
-                return 0;
-            }
-        }
-    }
-
-    private int getSpacingInDirection(boolean isVertical) {
+    int getSpacingInDirection(boolean isVertical) {
         if (spacing) {
             return 20;
         } else {
@@ -455,35 +90,7 @@ public class VMeasuringOrderedLayout extends ComplexPanel implements Container,
         }
     }
 
-    private int getCaptionWidth(VPaintableWidget child) {
-        VCaption caption = captions.get(child);
-        if (caption == null) {
-            return 0;
-        } else {
-            MeasureManager.MeasuredSize measuredSize = client
-                    .getMeasuredSize(child);
-            return measuredSize.getDependencyWidth(caption.getElement());
-        }
-    }
-
-    private int getCaptionHeight(VPaintableWidget child) {
-
-        VCaption caption = captions.get(child);
-        if (caption != null) {
-            MeasureManager.MeasuredSize measuredSize = client
-                    .getMeasuredSize(child);
-            int captionHeight = measuredSize.getDependencyHeight(caption
-                    .getElement());
-
-            caption.getElement().getStyle()
-                    .setMarginTop(-captionHeight, Unit.PX);
-            return captionHeight;
-        } else {
-            return 0;
-        }
-    }
-
-    private AlignmentInfo getAlignment(VPaintableWidget child) {
+    AlignmentInfo getAlignment(VPaintableWidget child) {
         String pid = VPaintableMap.get(client).getPid(child);
         if (alignments.containsKey(pid)) {
             return new AlignmentInfo(alignments.getInt(pid));
@@ -492,7 +99,7 @@ public class VMeasuringOrderedLayout extends ComplexPanel implements Container,
         }
     }
 
-    private double getExpandRatio(VPaintableWidget child) {
+    double getExpandRatio(VPaintableWidget child) {
         String pid = VPaintableMap.get(client).getPid(child);
         if (expandRatios.containsKey(pid)) {
             return expandRatios.getRawNumber(pid);
@@ -501,52 +108,28 @@ public class VMeasuringOrderedLayout extends ComplexPanel implements Container,
         }
     }
 
-    private static String getSizeProperty(boolean isVertical) {
-        return isVertical ? "height" : "width";
-    }
-
-    private static String getStartProperty(boolean isVertical) {
-        return isVertical ? "top" : "left";
-    }
-
-    private static String getMinPropertyName(boolean isVertical) {
-        return isVertical ? "minHeight" : "minWidth";
+    void addChildWidget(Widget widget) {
+        DivElement wrapper = Document.get().createDivElement();
+        wrapper.getStyle().setPosition(Position.ABSOLUTE);
+        getElement().appendChild(wrapper);
+        add(widget, wrapper);
     }
 
-    private int getMeasuredInDirection(VPaintableWidget paintable,
-            boolean isVertical) {
-        MeasureManager.MeasuredSize measuredSize = client
-                .getMeasuredSize(paintable);
-        if (isVertical) {
-            return measuredSize.getHeight();
-        } else {
-            return measuredSize.getWidth();
-        }
-    }
+    void addCaption(VCaption caption, Widget widget) {
+        Element wrapper = getWrapper(widget);
 
-    public Collection<VCaption> getChildCaptions() {
-        return captions.values();
-    }
+        // Logical attach.
+        getChildren().add(caption);
 
-    public RenderSpace getAllocatedSpace(Widget child) {
-        // Concept borrowed from CSS layout
-        if (space == null) {
-            space = new RenderSpace(-1, -1) {
-                @Override
-                public int getWidth() {
-                    return getOffsetWidth();
-                }
+        // Physical attach.
+        DOM.insertBefore((com.google.gwt.user.client.Element) wrapper.cast(),
+                caption.getElement(), widget.getElement());
 
-                @Override
-                public int getHeight() {
-                    return getOffsetHeight();
-                }
-            };
-        }
-        return space;
+        // Adopt.
+        adopt(caption);
     }
 
-    public Widget getWidgetForPaintable() {
-        return this;
+    void remove(VCaption caption) {
+        remove(caption);
     }
 }
diff --git a/src/com/vaadin/terminal/gwt/client/ui/VMeasuringOrderedLayoutPaintable.java b/src/com/vaadin/terminal/gwt/client/ui/VMeasuringOrderedLayoutPaintable.java
new file mode 100644 (file)
index 0000000..d67574e
--- /dev/null
@@ -0,0 +1,446 @@
+package com.vaadin.terminal.gwt.client.ui;
+
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Iterator;
+
+import com.google.gwt.dom.client.Element;
+import com.google.gwt.dom.client.Style;
+import com.google.gwt.dom.client.Style.Unit;
+import com.google.gwt.user.client.ui.Widget;
+import com.vaadin.terminal.gwt.client.ApplicationConnection;
+import com.vaadin.terminal.gwt.client.CalculatingLayout;
+import com.vaadin.terminal.gwt.client.MeasureManager;
+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;
+
+public abstract class VMeasuringOrderedLayoutPaintable extends
+        VAbstractPaintableWidgetContainer implements CalculatingLayout {
+
+    public void updateCaption(VPaintableWidget component, UIDL uidl) {
+        if (VCaption.isNeeded(uidl)) {
+            VCaption caption = getWidgetForPaintable().captions.get(component);
+            if (caption == null) {
+                caption = new VCaption(component,
+                        getWidgetForPaintable().client);
+
+                Widget widget = component.getWidgetForPaintable();
+
+                getWidgetForPaintable().addCaption(caption, widget);
+                getWidgetForPaintable().captions.put(component, caption);
+
+                MeasureManager.MeasuredSize measuredSize = getWidgetForPaintable().client
+                        .getMeasuredSize(component);
+
+                measuredSize.registerDependency(caption.getElement());
+            }
+            caption.updateCaption(uidl);
+        } else {
+            VCaption removedCaption = getWidgetForPaintable().captions
+                    .remove(component);
+            if (removedCaption != null) {
+                getWidgetForPaintable().remove(removedCaption);
+                MeasureManager.MeasuredSize measuredSize = getWidgetForPaintable().client
+                        .getMeasuredSize(component);
+                measuredSize.deRegisterDependency(removedCaption.getElement());
+            }
+        }
+    }
+
+    @Override
+    public VMeasuringOrderedLayout getWidgetForPaintable() {
+        return (VMeasuringOrderedLayout) super.getWidgetForPaintable();
+    }
+
+    public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
+        getWidgetForPaintable().client = client;
+        getWidgetForPaintable().id = uidl.getId();
+        if (client.updateComponent(this, uidl, true)) {
+            return;
+        }
+
+        long start = System.currentTimeMillis();
+        // long childTime = 0;
+
+        HashSet<Widget> previousChildren = new HashSet<Widget>();
+        for (Widget child : getWidgetForPaintable()) {
+            if (!(child instanceof VCaption)) {
+                previousChildren.add(child);
+            }
+        }
+        // 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();
+
+            if (widget.getParent() != getWidgetForPaintable()) {
+                getWidgetForPaintable().addChildWidget(widget);
+            }
+
+            if (!childUIDL.getBooleanAttribute("cached")) {
+                child.updateFromUIDL(childUIDL, client);
+                client.getMeasuredSize(child).setDirty(true);
+            }
+            // TODO Update alignments and expand ratios
+
+            previousChildren.remove(widget);
+        }
+
+        for (Widget widget : previousChildren) {
+            Element wrapper = getWidgetForPaintable().getWrapper(widget);
+            VCaption caption = getWidgetForPaintable().captions.remove(widget);
+            if (caption != null) {
+                getWidgetForPaintable().remove(caption);
+            }
+            getWidgetForPaintable().remove(widget);
+            // Remove the wrapper
+            getWidgetForPaintable().getElement().removeChild(wrapper);
+
+            client.unregisterPaintable(VPaintableMap.get(client).getPaintable(
+                    widget));
+        }
+
+        int bitMask = uidl.getIntAttribute("margins");
+        if (getWidgetForPaintable().activeMarginsInfo == null
+                || getWidgetForPaintable().activeMarginsInfo.getBitMask() != bitMask) {
+            getWidgetForPaintable().activeMarginsInfo = new VMarginInfo(bitMask);
+        }
+
+        getWidgetForPaintable().spacing = uidl.getBooleanAttribute("spacing");
+        getWidgetForPaintable().expandRatios = uidl
+                .getMapAttribute("expandRatios");
+        getWidgetForPaintable().alignments = uidl.getMapAttribute("alignments");
+        client.getMeasuredSize(this).setDirty(true);
+    }
+
+    private int getCaptionWidth(VPaintableWidget child) {
+        VCaption caption = getWidgetForPaintable().captions.get(child);
+        if (caption == null) {
+            return 0;
+        } else {
+            MeasureManager.MeasuredSize measuredSize = getWidgetForPaintable().client
+                    .getMeasuredSize(child);
+            return measuredSize.getDependencyWidth(caption.getElement());
+        }
+    }
+
+    private int getCaptionHeight(VPaintableWidget child) {
+
+        VCaption caption = getWidgetForPaintable().captions.get(child);
+        if (caption != null) {
+            MeasureManager.MeasuredSize measuredSize = getWidgetForPaintable().client
+                    .getMeasuredSize(child);
+            int captionHeight = measuredSize.getDependencyHeight(caption
+                    .getElement());
+
+            caption.getElement().getStyle()
+                    .setMarginTop(-captionHeight, Unit.PX);
+            return captionHeight;
+        } else {
+            return 0;
+        }
+    }
+
+    private static boolean isRelativeInDirection(Widget widget,
+            boolean isVertical) {
+        String dimension = getDimensionInDirection(widget, isVertical);
+        return dimension != null && dimension.endsWith("%");
+    }
+
+    private static String getDimensionInDirection(Widget widget,
+            boolean vertical) {
+        com.google.gwt.user.client.Element element = widget.getElement();
+        Style style = element.getStyle();
+        if (vertical) {
+            return style.getHeight();
+        } else {
+            return style.getWidth();
+        }
+    }
+
+    private static String getSizeProperty(boolean isVertical) {
+        return isVertical ? "height" : "width";
+    }
+
+    private static String getStartProperty(boolean isVertical) {
+        return isVertical ? "top" : "left";
+    }
+
+    private static String getMinPropertyName(boolean isVertical) {
+        return isVertical ? "minHeight" : "minWidth";
+    }
+
+    private static boolean isUndefinedInDirection(Widget widget,
+            boolean isVertical) {
+        String dimension = getDimensionInDirection(widget, isVertical);
+        return dimension == null || dimension.length() == 0;
+    }
+
+    private int getMeasuredInDirection(VPaintableWidget paintable,
+            boolean isVertical) {
+        MeasureManager.MeasuredSize measuredSize = getWidgetForPaintable().client
+                .getMeasuredSize(paintable);
+        if (isVertical) {
+            return measuredSize.getHeight();
+        } else {
+            return measuredSize.getWidth();
+        }
+    }
+
+    private static int getAlignmentInDirection(AlignmentInfo alignment,
+            boolean isVertical) {
+        if (alignment == null) {
+            return -1;
+        }
+        if (isVertical) {
+            if (alignment.isTop()) {
+                return -1;
+            } else if (alignment.isBottom()) {
+                return 1;
+            } else {
+                return 0;
+            }
+        } else {
+            if (alignment.isLeft()) {
+                return -1;
+            } else if (alignment.isRight()) {
+                return 1;
+            } else {
+                return 0;
+            }
+        }
+    }
+
+    private void layoutPrimaryDirection() {
+        Collection<VPaintableWidget> children = MeasureManager.getChildren(
+                this, getWidgetForPaintable().client);
+
+        // First pass - get total expand ratio and allocated size
+        int totalAllocated = 0;
+        double totalExpand = 0;
+        for (VPaintableWidget child : children) {
+            Widget widget = child.getWidgetForPaintable();
+
+            totalExpand += getWidgetForPaintable().getExpandRatio(child);
+
+            int captionAllocation;
+            if (getWidgetForPaintable().isVertical) {
+                captionAllocation = getCaptionHeight(child);
+                getWidgetForPaintable().getWrapper(widget).getStyle()
+                        .setPaddingTop(captionAllocation, Unit.PX);
+            } else {
+                captionAllocation = 0;
+            }
+
+            if (!isRelativeInDirection(widget,
+                    getWidgetForPaintable().isVertical)) {
+                totalAllocated += getMeasuredInDirection(child,
+                        getWidgetForPaintable().isVertical) + captionAllocation;
+            }
+        }
+        int startMargin = getWidgetForPaintable().getStartMarginInDirection(
+                getWidgetForPaintable().isVertical);
+        int totalMargins = startMargin
+                + getWidgetForPaintable().getEndMarginInDirection(
+                        getWidgetForPaintable().isVertical);
+
+        totalAllocated += totalMargins
+                + (getWidgetForPaintable().getSpacingInDirection(
+                        getWidgetForPaintable().isVertical) * (children.size() - 1));
+
+        Style ownStyle = getWidgetForPaintable().getElement().getStyle();
+        double ownSize;
+        if (isUndefinedInDirection(getWidgetForPaintable(),
+                getWidgetForPaintable().isVertical)) {
+            ownSize = totalAllocated;
+            ownStyle.setProperty(
+                    getMinPropertyName(getWidgetForPaintable().isVertical),
+                    totalAllocated, Unit.PX);
+        } else {
+            ownSize = getMeasuredInDirection(this,
+                    getWidgetForPaintable().isVertical);
+            ownStyle.clearProperty(getMinPropertyName(getWidgetForPaintable().isVertical));
+        }
+
+        double unallocatedSpace = Math.max(0, ownSize - totalAllocated);
+
+        double currentLocation = startMargin;
+        for (VPaintableWidget child : children) {
+            Widget widget = child.getWidgetForPaintable();
+            Element wrapper = getWidgetForPaintable().getWrapper(widget);
+            Style wrapperStyle = wrapper.getStyle();
+
+            double childExpandRatio;
+            if (totalExpand == 0) {
+                childExpandRatio = 1d / children.size();
+            } else {
+                childExpandRatio = getWidgetForPaintable()
+                        .getExpandRatio(child) / totalExpand;
+            }
+
+            double extraPixels = unallocatedSpace * childExpandRatio;
+
+            boolean relative = isRelativeInDirection(widget,
+                    getWidgetForPaintable().isVertical);
+
+            double size = getMeasuredInDirection(child,
+                    getWidgetForPaintable().isVertical);
+            int captionHeight = getCaptionHeight(child);
+
+            if (getWidgetForPaintable().isVertical) {
+                size += captionHeight;
+            } else if (!relative) {
+                size = Math.max(size, getCaptionWidth(child));
+            }
+
+            double allocatedSpace = extraPixels;
+            if (!relative) {
+                allocatedSpace += size;
+            }
+
+            int alignment = getAlignmentInDirection(getWidgetForPaintable()
+                    .getAlignment(child), getWidgetForPaintable().isVertical);
+
+            if (relative) {
+                double captionReservation = getWidgetForPaintable().isVertical ? captionHeight
+                        : 0;
+                wrapperStyle.setProperty(
+                        getSizeProperty(getWidgetForPaintable().isVertical),
+                        allocatedSpace - captionReservation, Unit.PX);
+            } else {
+                wrapperStyle
+                        .clearProperty(getSizeProperty(getWidgetForPaintable().isVertical));
+            }
+
+            double startPosition = currentLocation;
+            if (alignment == 0) {
+                // Centered
+                startPosition += (allocatedSpace - size) / 2;
+            } else if (alignment == 1) {
+                // Right or bottom
+                startPosition += allocatedSpace - size;
+            }
+
+            wrapperStyle.setProperty(
+                    getStartProperty(getWidgetForPaintable().isVertical),
+                    startPosition, Unit.PX);
+
+            currentLocation += allocatedSpace
+                    + getWidgetForPaintable().getSpacingInDirection(
+                            getWidgetForPaintable().isVertical);
+        }
+    }
+
+    private void layoutSecondaryDirection() {
+        Collection<VPaintableWidget> children = MeasureManager.getChildren(
+                this, getWidgetForPaintable().client);
+
+        int maxSize = 0;
+        for (VPaintableWidget child : children) {
+            Widget widget = child.getWidgetForPaintable();
+
+            int captionAllocation;
+            if (!getWidgetForPaintable().isVertical) {
+                captionAllocation = getCaptionHeight(child);
+                getWidgetForPaintable().getWrapper(widget).getStyle()
+                        .setPaddingTop(captionAllocation, Unit.PX);
+            } else {
+                captionAllocation = 0;
+            }
+
+            if (!isRelativeInDirection(widget,
+                    !getWidgetForPaintable().isVertical)) {
+                int childSize = getMeasuredInDirection(child,
+                        !getWidgetForPaintable().isVertical)
+                        + captionAllocation;
+                maxSize = Math.max(maxSize, childSize);
+            }
+        }
+
+        int startMargin = getWidgetForPaintable().getStartMarginInDirection(
+                !getWidgetForPaintable().isVertical);
+        int totalMargins = startMargin
+                + getWidgetForPaintable().getEndMarginInDirection(
+                        !getWidgetForPaintable().isVertical);
+
+        double availableSpace;
+        Style ownStyle = getWidgetForPaintable().getElement().getStyle();
+
+        if (isUndefinedInDirection(getWidgetForPaintable(),
+                !getWidgetForPaintable().isVertical)) {
+            ownStyle.setProperty(
+                    getMinPropertyName(!getWidgetForPaintable().isVertical),
+                    maxSize + totalMargins, Unit.PX);
+            availableSpace = maxSize;
+        } else {
+            ownStyle.clearProperty(getMinPropertyName(!getWidgetForPaintable().isVertical));
+            availableSpace = getMeasuredInDirection(this,
+                    !getWidgetForPaintable().isVertical) - totalMargins;
+        }
+
+        for (VPaintableWidget child : children) {
+            Widget widget = child.getWidgetForPaintable();
+            Element wrapper = getWidgetForPaintable().getWrapper(widget);
+            Style wrapperStyle = wrapper.getStyle();
+
+            boolean relative = isRelativeInDirection(widget,
+                    !getWidgetForPaintable().isVertical);
+
+            int captionHeight = getCaptionHeight(child);
+
+            double allocatedSize = getMeasuredInDirection(child,
+                    !getWidgetForPaintable().isVertical);
+            if (!getWidgetForPaintable().isVertical) {
+                allocatedSize += captionHeight;
+            } else if (!relative) {
+                allocatedSize = Math.max(allocatedSize, getCaptionWidth(child));
+            }
+
+            int alignment = getAlignmentInDirection(getWidgetForPaintable()
+                    .getAlignment(child), !getWidgetForPaintable().isVertical);
+
+            double startPosition = startMargin;
+            if (alignment == 0) {
+                startPosition += (availableSpace - allocatedSize) / 2;
+                // Centered
+            } else if (alignment == 1) {
+                // Right or bottom
+                startPosition += (availableSpace - allocatedSize);
+            }
+
+            wrapperStyle.setProperty(
+                    getStartProperty(!getWidgetForPaintable().isVertical),
+                    startPosition, Unit.PX);
+
+            if (relative) {
+                double captionReservation = !getWidgetForPaintable().isVertical ? captionHeight
+                        : 0;
+                wrapperStyle.setProperty(
+                        getSizeProperty(!getWidgetForPaintable().isVertical),
+                        availableSpace - captionReservation, Unit.PX);
+            } else {
+                wrapperStyle
+                        .clearProperty(getSizeProperty(!getWidgetForPaintable().isVertical));
+            }
+        }
+    }
+
+    public void updateHorizontalSizes() {
+        if (getWidgetForPaintable().isVertical) {
+            layoutSecondaryDirection();
+        } else {
+            layoutPrimaryDirection();
+        }
+    }
+
+    public void updateVerticalSizes() {
+        if (getWidgetForPaintable().isVertical) {
+            layoutPrimaryDirection();
+        } else {
+            layoutSecondaryDirection();
+        }
+    }
+}
index 71c6d91c69eb879e8c6c02c7f2fd7b314584a924..2de30d4cc3a16e6f8d8dc75a22216e3f15d9f27b 100644 (file)
@@ -5,7 +5,7 @@ package com.vaadin.terminal.gwt.client.ui;
 
 import com.google.gwt.core.client.GWT;
 
-public class VVerticalLayoutPaintable extends VOrderedLayoutPaintable {
+public class VVerticalLayoutPaintable extends VMeasuringOrderedLayoutPaintable {
 
     @Override
     public VVerticalLayout getWidgetForPaintable() {