]> source.dussan.org Git - vaadin-framework.git/commitdiff
Refactored and cleaned up the newly add ordered layouts
authorJohn Ahlroos <john@vaadin.com>
Wed, 5 Sep 2012 14:58:12 +0000 (17:58 +0300)
committerJohn Ahlroos <john@vaadin.com>
Wed, 5 Sep 2012 14:58:12 +0000 (17:58 +0300)
12 files changed:
client/src/com/vaadin/client/ComponentLocator.java
client/src/com/vaadin/client/ui/orderedlayout/AbstractBoxLayoutConnector.java [deleted file]
client/src/com/vaadin/client/ui/orderedlayout/AbstractOrderedLayoutConnector.java
client/src/com/vaadin/client/ui/orderedlayout/HorizontalBoxLayoutConnector.java [deleted file]
client/src/com/vaadin/client/ui/orderedlayout/HorizontalLayoutConnector.java
client/src/com/vaadin/client/ui/orderedlayout/VBoxLayout.java [deleted file]
client/src/com/vaadin/client/ui/orderedlayout/VHorizontalLayout.java
client/src/com/vaadin/client/ui/orderedlayout/VMeasuringOrderedLayout.java [deleted file]
client/src/com/vaadin/client/ui/orderedlayout/VOrderedLayout.java [new file with mode: 0644]
client/src/com/vaadin/client/ui/orderedlayout/VVerticalLayout.java
client/src/com/vaadin/client/ui/orderedlayout/VerticalBoxLayoutConnector.java [deleted file]
client/src/com/vaadin/client/ui/orderedlayout/VerticalLayoutConnector.java

index 42b54ca49cf89c902c4ef540a2907d3b28e26cde..ce3ac4381250e4e1b6343884f86e118cb068740f 100644 (file)
@@ -27,8 +27,7 @@ import com.google.gwt.user.client.ui.SimplePanel;
 import com.google.gwt.user.client.ui.Widget;
 import com.vaadin.client.ui.SubPartAware;
 import com.vaadin.client.ui.gridlayout.VGridLayout;
-import com.vaadin.client.ui.orderedlayout.VBoxLayout;
-import com.vaadin.client.ui.orderedlayout.VMeasuringOrderedLayout;
+import com.vaadin.client.ui.orderedlayout.VOrderedLayout;
 import com.vaadin.client.ui.tabsheet.VTabsheetPanel;
 import com.vaadin.client.ui.ui.VUI;
 import com.vaadin.client.ui.window.VWindow;
@@ -270,7 +269,7 @@ public class ComponentLocator {
                 String childIndexString = part.substring("domChild[".length(),
                         part.length() - 1);
 
-                if (Util.findWidget(baseElement, null) instanceof VBoxLayout) {
+                if (Util.findWidget(baseElement, null) instanceof VOrderedLayout) {
                     if (element.hasChildNodes()) {
                         Element e = element.getFirstChildElement().cast();
                         String cn = e.getClassName();
@@ -508,14 +507,9 @@ public class ComponentLocator {
                     continue;
                 }
 
-                if ("VVerticalLayout".equals(widgetClassName)
-                        || "VHorizontalLayout".equals(widgetClassName)) {
-                    widgetClassName = "VBoxLayout";
-                }
-
-                if (w instanceof VBoxLayout
+                if (w instanceof VOrderedLayout
                         && "ChildComponentContainer".equals(widgetClassName)) {
-                    widgetClassName = "VBoxLayout$Slot";
+                    widgetClassName = "VOrderedLayout$Slot";
                 }
 
                 if (w instanceof VTabsheetPanel && widgetPosition != 0) {
@@ -532,7 +526,7 @@ public class ComponentLocator {
                  * (which would originally have found the widget inside the
                  * ChildComponentContainer)
                  */
-                if ((w instanceof VMeasuringOrderedLayout || w instanceof VGridLayout)
+                if ((w instanceof VGridLayout)
                         && "ChildComponentContainer".equals(widgetClassName)
                         && i + 1 < parts.length) {
 
@@ -542,11 +536,6 @@ public class ComponentLocator {
                     String[] nextSplit = nextPart.split("\\[", 2);
                     String nextWidgetClassName = nextSplit[0];
 
-                    if ("VVerticalLayout".equals(nextWidgetClassName)
-                            || "VHorizontalLayout".equals(nextWidgetClassName)) {
-                        nextWidgetClassName = "VBoxLayout";
-                    }
-
                     // Find the n:th child and count the number of children with
                     // the same type before it
                     int nextIndex = 0;
@@ -616,8 +605,8 @@ public class ComponentLocator {
                         }
                         widgetPosition--;
 
-                    } else if (w instanceof VBoxLayout
-                            && "VBoxLayout$Slot".equals(simpleName2)) {
+                    } else if (w instanceof VOrderedLayout
+                            && "VOrderedLayout$Slot".equals(simpleName2)) {
                         child = ((SimplePanel) child).getWidget();
                         simpleName2 = Util.getSimpleName(child);
                         if (widgetClassName.equals(simpleName2)) {
diff --git a/client/src/com/vaadin/client/ui/orderedlayout/AbstractBoxLayoutConnector.java b/client/src/com/vaadin/client/ui/orderedlayout/AbstractBoxLayoutConnector.java
deleted file mode 100644 (file)
index 6402d06..0000000
+++ /dev/null
@@ -1,607 +0,0 @@
-/*
-@VaadinApache2LicenseForJavaFiles@
- */
-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.ComponentConnector;
-import com.vaadin.client.ConnectorHierarchyChangeEvent;
-import com.vaadin.client.Util;
-import com.vaadin.client.communication.RpcProxy;
-import com.vaadin.client.communication.StateChangeEvent;
-import com.vaadin.client.communication.StateChangeEvent.StateChangeHandler;
-import com.vaadin.client.ui.AbstractFieldConnector;
-import com.vaadin.client.ui.AbstractLayoutConnector;
-import com.vaadin.client.ui.LayoutClickEventHandler;
-import com.vaadin.client.ui.layout.ElementResizeEvent;
-import com.vaadin.client.ui.layout.ElementResizeListener;
-import com.vaadin.client.ui.orderedlayout.VBoxLayout.CaptionPosition;
-import com.vaadin.client.ui.orderedlayout.VBoxLayout.Slot;
-import com.vaadin.shared.AbstractFieldState;
-import com.vaadin.shared.ComponentConstants;
-import com.vaadin.shared.communication.URLReference;
-import com.vaadin.shared.ui.AlignmentInfo;
-import com.vaadin.shared.ui.LayoutClickRpc;
-import com.vaadin.shared.ui.MarginInfo;
-import com.vaadin.shared.ui.orderedlayout.AbstractOrderedLayoutServerRpc;
-import com.vaadin.shared.ui.orderedlayout.AbstractOrderedLayoutState;
-
-public abstract class AbstractBoxLayoutConnector extends
-        AbstractLayoutConnector /* implements PostLayoutListener */{
-
-    AbstractOrderedLayoutServerRpc rpc;
-
-    private LayoutClickEventHandler clickEventHandler = new LayoutClickEventHandler(
-            this) {
-
-        @Override
-        protected ComponentConnector getChildComponent(Element element) {
-            return Util.getConnectorForElement(getConnection(), getWidget(),
-                    element);
-        }
-
-        @Override
-        protected LayoutClickRpc getLayoutClickRPC() {
-            return rpc;
-        };
-
-    };
-
-    @Override
-    public void init() {
-        super.init();
-        rpc = RpcProxy.create(AbstractOrderedLayoutServerRpc.class, this);
-        getWidget().setLayoutManager(getLayoutManager());
-    }
-
-    @Override
-    public AbstractOrderedLayoutState getState() {
-        return (AbstractOrderedLayoutState) super.getState();
-    }
-
-    @Override
-    public VBoxLayout getWidget() {
-        return (VBoxLayout) super.getWidget();
-    }
-
-    /**
-     * 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.
-     */
-    private HashSet<ComponentConnector> hasExpandRatio = new HashSet<ComponentConnector>();
-
-    /**
-     * For bookkeeping. Used in extra calculations for horizontal layout.
-     */
-    private HashSet<Element> needsMeasure = new HashSet<Element>();
-
-    /**
-     * For bookkeeping. Used in extra calculations for horizontal layout.
-     */
-    // private HashMap<Element, Integer> childElementHeight = new
-    // HashMap<Element, Integer>();
-
-    /**
-     * For bookkeeping. Used in extra calculations for horizontal layout.
-     */
-    private HashMap<Element, Integer> childCaptionElementHeight = new HashMap<Element, Integer>();
-
-    @Override
-    public void updateCaption(ComponentConnector child) {
-        Slot slot = getWidget().getSlot(child);
-
-
-        String caption = child.getState().caption;
-        URLReference iconUrl = child.getState().resources
-                .get(ComponentConstants.ICON_RESOURCE);
-        String iconUrlString = iconUrl != null ? iconUrl.toString() : null;
-        List<String> styles = child.getState().styles;
-        String error = child.getState().errorMessage;
-                boolean showError = error != null;
-                if (child.getState() instanceof AbstractFieldState) {
-                    AbstractFieldState abstractFieldState = (AbstractFieldState) child
-                            .getState();
-            showError = showError && !abstractFieldState.hideErrors;
-                }
-                boolean required = false;
-                if (child instanceof AbstractFieldConnector) {
-                    required = ((AbstractFieldConnector) child).isRequired();
-                }
-        boolean enabled = child.getState().enabled;
-
-        slot.setCaption(caption, iconUrlString, styles, error, showError,
-                required,
-                        enabled);
-
-                slot.setRelativeWidth(child.isRelativeWidth());
-                slot.setRelativeHeight(child.isRelativeHeight());
-
-                if (slot.hasCaption()) {
-                    CaptionPosition pos = slot.getCaptionPosition();
-                    getLayoutManager().addElementResizeListener(
-                            slot.getCaptionElement(), slotCaptionResizeListener);
-                    if (child.isRelativeHeight()
-                            && (pos == CaptionPosition.TOP || pos == CaptionPosition.BOTTOM)) {
-                        getWidget().updateCaptionOffset(slot.getCaptionElement());
-                    } else if (child.isRelativeWidth()
-                            && (pos == CaptionPosition.LEFT || pos == CaptionPosition.RIGHT)) {
-                        getWidget().updateCaptionOffset(slot.getCaptionElement());
-                    }
-                } else {
-                    childCaptionElementHeight.remove(child.getWidget().getElement());
-                }
-
-                updateLayoutHeight();
-
-                if (needsExpand()) {
-                    updateExpand();
-                }
-    }
-
-    @Override
-    public void onConnectorHierarchyChange(ConnectorHierarchyChangeEvent event) {
-        super.onConnectorHierarchyChange(event);
-
-        List<ComponentConnector> previousChildren = event.getOldChildren();
-        int currentIndex = 0;
-        VBoxLayout layout = getWidget();
-
-        for (ComponentConnector child : getChildComponents()) {
-            Slot slot = layout.getSlot(child);
-            if (slot.getParent() != layout) {
-                child.addStateChangeHandler(childStateChangeHandler);
-            }
-            layout.addOrMoveSlot(slot, currentIndex++);
-        }
-
-        for (ComponentConnector child : previousChildren) {
-            if (child.getParent() != this) {
-                Slot slot = layout.getSlot(child);
-                hasVerticalAlignment.remove(child);
-                hasRelativeHeight.remove(child);
-                hasExpandRatio.remove(child);
-                needsMeasure.remove(child.getWidget().getElement());
-                // childElementHeight.remove(child.getWidget().getElement());
-                childCaptionElementHeight
-                .remove(child.getWidget().getElement());
-                getLayoutManager().removeElementResizeListener(
-                        child.getWidget().getElement(),
-                        childComponentResizeListener);
-                if (slot.hasCaption()) {
-                    getLayoutManager()
-                    .removeElementResizeListener(
-                            slot.getCaptionElement(),
-                            slotCaptionResizeListener);
-                }
-                if (slot.getSpacingElement() != null) {
-                    getLayoutManager().removeElementResizeListener(
-                            slot.getSpacingElement(), spacingResizeListener);
-                }
-                child.removeStateChangeHandler(childStateChangeHandler);
-                layout.removeSlot(child.getWidget());
-            }
-        }
-
-        // If some component is added/removed, we need to recalculate the expand
-        if (needsExpand()) {
-            updateExpand();
-        } else {
-            getWidget().clearExpand();
-        }
-
-    }
-
-    @Override
-    public void onStateChanged(StateChangeEvent stateChangeEvent) {
-        super.onStateChanged(stateChangeEvent);
-
-        clickEventHandler.handleEventHandlerRegistration();
-        getWidget().setMargin(new MarginInfo(getState().marginsBitmask));
-        getWidget().setSpacing(getState().spacing);
-
-        hasExpandRatio.clear();
-        hasVerticalAlignment.clear();
-        hasRelativeHeight.clear();
-        needsMeasure.clear();
-
-        boolean equalExpandRatio = getWidget().vertical ? !isUndefinedHeight()
-                : !isUndefinedWidth();
-        for (ComponentConnector child : getChildComponents()) {
-            double expandRatio = getState().childData.get(child).expandRatio;
-            if (expandRatio > 0) {
-                equalExpandRatio = false;
-                break;
-            }
-        }
-
-        for (ComponentConnector child : getChildComponents()) {
-            Slot slot = getWidget().getSlot(child);
-
-            AlignmentInfo alignment = new AlignmentInfo(
-                    getState().childData.get(child).alignmentBitmask);
-            slot.setAlignment(alignment);
-
-            double expandRatio = 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 (expandRatio > 0) {
-                hasExpandRatio.add(child);
-            }
-
-            // if (child.getState().isRelativeHeight()) {
-            // hasRelativeHeight.add(child);
-            // } else {
-            // needsMeasure.add(child.getWidget().getElement());
-            // }
-        }
-
-        updateAllSlotListeners();
-
-        updateLayoutHeight();
-    }
-
-    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);
-            slot.setRelativeWidth(child.isRelativeWidth());
-            slot.setRelativeHeight(child.isRelativeHeight());
-
-            // For relative sized widgets, we need to set the caption offset
-            // if (slot.hasCaption()) {
-            // CaptionPosition pos = slot.getCaptionPosition();
-            // if (child.isRelativeHeight()
-            // && (pos == CaptionPosition.TOP || pos == CaptionPosition.BOTTOM))
-            // {
-            // getWidget().updateCaptionOffset(slot.getCaptionElement());
-            // } else if (child.isRelativeWidth()
-            // && (pos == CaptionPosition.LEFT || pos == CaptionPosition.RIGHT))
-            // {
-            // getWidget().updateCaptionOffset(slot.getCaptionElement());
-            // }
-            // }
-
-            updateSlotListeners(child);
-            // updateAllSlotListeners();
-
-            updateLayoutHeight();
-        }
-    };
-
-    private boolean needsFixedHeight() {
-        if (!getWidget().vertical
-                && isUndefinedHeight()
-                && (hasRelativeHeight.size() > 0 || (hasVerticalAlignment
-                        .size() > 0 && hasVerticalAlignment.size() < getChildren()
-                        .size()))) {
-            return true;
-        }
-        return false;
-    }
-
-    private boolean needsExpand() {
-        boolean canApplyExpand = (getWidget().vertical && !isUndefinedHeight())
-                || (!getWidget().vertical && !isUndefinedWidth());
-        return hasExpandRatio.size() > 0 && canApplyExpand;
-    }
-
-    private void updateAllSlotListeners() {
-        for (ComponentConnector child : getChildComponents()) {
-            updateSlotListeners(child);
-        }
-        // if (needsFixedHeight()) {
-        // getWidget().clearHeight();
-        // setLayoutHeightListener(true);
-        // getLayoutManager().setNeedsMeasure(AbstractBoxLayoutConnector.this);
-        // } else {
-        // setLayoutHeightListener(false);
-        // }
-    }
-
-    /**
-     * Add/remove necessary ElementResizeListeners for one slot. This should be
-     * called after each update to the slot's or it's widget.
-     */
-    private void updateSlotListeners(ComponentConnector child) {
-        Slot slot = getWidget().getSlot(child);
-
-        // Clear all possible listeners first
-        dontListen(slot.getWidget().getElement(), childComponentResizeListener);
-        if (slot.hasCaption()) {
-            dontListen(slot.getCaptionElement(), slotCaptionResizeListener);
-        }
-        if (slot.hasSpacing()) {
-            dontListen(slot.getSpacingElement(), spacingResizeListener);
-        }
-
-        // Add all necessary listeners
-        if (needsFixedHeight()) {
-            listen(slot.getWidget().getElement(), childComponentResizeListener);
-            if (slot.hasCaption()) {
-                listen(slot.getCaptionElement(), slotCaptionResizeListener);
-            }
-        } 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
-            listen(slot.getCaptionElement(), slotCaptionResizeListener);
-        }
-
-        if (needsExpand()) {
-            listen(slot.getWidget().getElement(), childComponentResizeListener);
-            if (slot.hasSpacing()) {
-                listen(slot.getSpacingElement(), spacingResizeListener);
-            }
-        }
-
-        if (child.isRelativeHeight()) {
-            hasRelativeHeight.add(child);
-            needsMeasure.remove(child.getWidget().getElement());
-        } else {
-            hasRelativeHeight.remove(child);
-            needsMeasure.add(child.getWidget().getElement());
-        }
-
-    }
-
-    // public void postLayout() {
-    // if (needsFixedHeight()) {
-    // // Re-measure all elements that are available
-    // for (Element el : needsMeasure) {
-    // childElementHeight.put(el, getLayoutManager()
-    // .getOuterHeight(el));
-    //
-    // Element captionElement = el.getParentElement()
-    // .getFirstChildElement().cast();
-    // if (captionElement.getClassName().contains("v-caption")) {
-    // childCaptionElementHeight.put(el, getLayoutManager()
-    // .getOuterHeight(captionElement));
-    // }
-    // }
-    // // System.out.println("  ###  Child sizes: "
-    // // + childElementHeight.values().toString());
-    // // System.out.println("  ###  Caption sizes: "
-    // // + childCaptionElementHeight.values().toString());
-    //
-    // int height = getMaxHeight()
-    // + getLayoutManager().getBorderHeight(
-    // getWidget().getElement())
-    // + getLayoutManager().getPaddingHeight(
-    // getWidget().getElement());
-    // getWidget().getElement().getStyle().setHeight(height, Unit.PX);
-    // }
-    // }
-
-    // private ElementResizeListener layoutResizeListener = new
-    // ElementResizeListener() {
-    // public void onElementResize(ElementResizeEvent e) {
-    // updateLayoutHeight();
-    // if (needsExpand() && (isUndefinedHeight() || isUndefinedWidth())) {
-    // updateExpand();
-    // }
-    // }
-    // };
-
-    private ElementResizeListener slotCaptionResizeListener = new ElementResizeListener() {
-        @Override
-        public void onElementResize(ElementResizeEvent e) {
-
-            // Get all needed element references
-            Element captionElement = (Element) e.getElement().cast();
-
-            // Caption position determines if the widget element is the first or
-            // last child inside the caption wrap
-            CaptionPosition pos = getWidget().getCaptionPositionFromElement(
-                    (Element) captionElement.getParentElement().cast());
-
-            // The default is the last child
-            Element widgetElement = captionElement.getParentElement()
-                    .getLastChild().cast();
-
-            // ...but if caption position is bottom or right, the widget is the
-            // first child
-            if (pos == CaptionPosition.BOTTOM || pos == CaptionPosition.RIGHT) {
-                widgetElement = captionElement.getParentElement()
-                        .getFirstChildElement().cast();
-            }
-
-            if (captionElement == widgetElement) {
-                // Caption element already detached
-                dontListen(captionElement, slotCaptionResizeListener);
-                childCaptionElementHeight.remove(widgetElement);
-                return;
-            }
-
-            String widgetWidth = widgetElement.getStyle().getWidth();
-            String widgetHeight = widgetElement.getStyle().getHeight();
-
-            if (widgetHeight.endsWith("%")
-                    && (pos == CaptionPosition.TOP || pos == CaptionPosition.BOTTOM)) {
-                getWidget().updateCaptionOffset(captionElement);
-            } else if (widgetWidth.endsWith("%")
-                    && (pos == CaptionPosition.LEFT || pos == CaptionPosition.RIGHT)) {
-                getWidget().updateCaptionOffset(captionElement);
-            }
-
-            int h = getLayoutManager().getOuterHeight(captionElement)
-                    - getLayoutManager().getMarginHeight(captionElement);
-            childCaptionElementHeight.put(widgetElement, h);
-
-            // if (needsFixedHeight()) {
-            // getWidget().clearHeight();
-            // getLayoutManager().setNeedsMeasure(
-            // AbstractBoxLayoutConnector.this);
-            // }
-
-            updateLayoutHeight();
-
-            if (needsExpand()) {
-                updateExpand();
-            }
-        }
-    };
-
-    private ElementResizeListener childComponentResizeListener = new ElementResizeListener() {
-        @Override
-        public void onElementResize(ElementResizeEvent e) {
-            // int h = getLayoutManager().getOuterHeight(e.getElement());
-            // childElementHeight.put((Element) e.getElement().cast(), h);
-            updateLayoutHeight();
-
-            if (needsExpand()) {
-                updateExpand();
-            }
-        }
-    };
-
-    private ElementResizeListener spacingResizeListener = new ElementResizeListener() {
-        @Override
-        public void onElementResize(ElementResizeEvent e) {
-            if (needsExpand()) {
-                updateExpand();
-            }
-        }
-    };
-
-    private void updateLayoutHeight() {
-        if (needsFixedHeight()) {
-            int h = getMaxHeight();
-            h += getLayoutManager().getBorderHeight(getWidget().getElement())
-                    + getLayoutManager().getPaddingHeight(
-                            getWidget().getElement());
-            getWidget().getElement().getStyle().setHeight(h, Unit.PX);
-            getLayoutManager().setNeedsMeasure(this);
-        }
-    }
-
-    private void updateExpand() {
-        // System.out.println("All sizes: "
-        // + childElementHeight.values().toString() + " - Caption sizes: "
-        // + childCaptionElementHeight.values().toString());
-        getWidget().updateExpand();
-    }
-
-    private int getMaxHeight() {
-        int highestNonRelative = -1;
-        int highestRelative = -1;
-
-        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());
-            if (needsMeasure.contains(el)) {
-                int h = getLayoutManager().getOuterHeight(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);
-                }
-                if (h > highestNonRelative) {
-                    highestNonRelative = h;
-                }
-            } else {
-                int h = getLayoutManager().getOuterHeight(el);
-                if (childCaptionElementHeight.containsKey(el)
-                        && (pos == CaptionPosition.TOP || pos == CaptionPosition.BOTTOM)) {
-                    h += childCaptionElementHeight.get(el);
-                }
-                if (h > highestRelative) {
-                    highestRelative = h;
-                }
-            }
-        }
-        return highestNonRelative > -1 ? highestNonRelative : highestRelative;
-    }
-
-    @Override
-    public void onUnregister() {
-        // Cleanup all ElementResizeListeners
-
-        // dontListen(getWidget().getElement(), layoutResizeListener);
-
-        for (ComponentConnector child : getChildComponents()) {
-            Slot slot = getWidget().getSlot(child);
-            if (slot.hasCaption()) {
-                dontListen(slot.getCaptionElement(), slotCaptionResizeListener);
-            }
-
-            if (slot.getSpacingElement() != null) {
-                dontListen(slot.getSpacingElement(), spacingResizeListener);
-            }
-
-            dontListen(slot.getWidget().getElement(),
-                    childComponentResizeListener);
-        }
-
-        super.onUnregister();
-    }
-
-    // private void setLayoutHeightListener(boolean add) {
-    // if (add) {
-    // listen(getWidget().getElement(), layoutResizeListener);
-    // } else {
-    // dontListen(getWidget().getElement(), layoutResizeListener);
-    // if (!needsExpand()) {
-    // System.out.println("Clearing element sizes");
-    // childElementHeight.clear();
-    // childCaptionElementHeight.clear();
-    // }
-    // }
-    // }
-
-    /*
-     * Convenience methods
-     */
-
-    private void listen(Element el, ElementResizeListener listener) {
-        getLayoutManager().addElementResizeListener(el, listener);
-    }
-
-    private void dontListen(Element el, ElementResizeListener listener) {
-        getLayoutManager().removeElementResizeListener(el, listener);
-    }
-
-}
index 5b1462b33c38bfced2cd7db851ac2f1b72d544ae..8807fcfbc0cd4de0105cc6703df8d86e4d39a4bd 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;
 import com.google.gwt.dom.client.Style.Unit;
 import com.google.gwt.user.client.Element;
-import com.google.gwt.user.client.ui.Widget;
 import com.vaadin.client.ComponentConnector;
 import com.vaadin.client.ConnectorHierarchyChangeEvent;
-import com.vaadin.client.DirectionalManagedLayout;
-import com.vaadin.client.LayoutManager;
 import com.vaadin.client.Util;
-import com.vaadin.client.VCaption;
 import com.vaadin.client.communication.RpcProxy;
 import com.vaadin.client.communication.StateChangeEvent;
+import com.vaadin.client.communication.StateChangeEvent.StateChangeHandler;
+import com.vaadin.client.ui.AbstractFieldConnector;
 import com.vaadin.client.ui.AbstractLayoutConnector;
 import com.vaadin.client.ui.LayoutClickEventHandler;
-import com.vaadin.client.ui.layout.ComponentConnectorLayoutSlot;
-import com.vaadin.client.ui.layout.VLayoutSlot;
+import com.vaadin.client.ui.layout.ElementResizeEvent;
+import com.vaadin.client.ui.layout.ElementResizeListener;
+import com.vaadin.client.ui.orderedlayout.VOrderedLayout.CaptionPosition;
+import com.vaadin.client.ui.orderedlayout.VOrderedLayout.Slot;
+import com.vaadin.shared.AbstractFieldState;
+import com.vaadin.shared.ComponentConstants;
+import com.vaadin.shared.communication.URLReference;
 import com.vaadin.shared.ui.AlignmentInfo;
 import com.vaadin.shared.ui.LayoutClickRpc;
 import com.vaadin.shared.ui.MarginInfo;
 import com.vaadin.shared.ui.orderedlayout.AbstractOrderedLayoutServerRpc;
 import com.vaadin.shared.ui.orderedlayout.AbstractOrderedLayoutState;
 
+/**
+ * Base class for vertical and horizontal ordered layouts
+ */
 public abstract class AbstractOrderedLayoutConnector extends
-        AbstractLayoutConnector implements DirectionalManagedLayout {
+        AbstractLayoutConnector {
 
     AbstractOrderedLayoutServerRpc rpc;
 
+    /*
+     * Handlers & Listeners
+     */
+
     private LayoutClickEventHandler clickEventHandler = new LayoutClickEventHandler(
             this) {
 
@@ -57,275 +68,522 @@ public abstract class AbstractOrderedLayoutConnector extends
         protected LayoutClickRpc getLayoutClickRPC() {
             return rpc;
         };
+    };
+
+    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());
+
+            updateSlotListeners(child);
+            // updateAllSlotListeners();
+
+            updateLayoutHeight();
+        }
+    };
+
+    private ElementResizeListener slotCaptionResizeListener = new ElementResizeListener() {
+        @Override
+        public void onElementResize(ElementResizeEvent e) {
+
+            // Get all needed element references
+            Element captionElement = (Element) e.getElement().cast();
+
+            // Caption position determines if the widget element is the first or
+            // last child inside the caption wrap
+            CaptionPosition pos = getWidget().getCaptionPositionFromElement(
+                    (Element) captionElement.getParentElement().cast());
+
+            // The default is the last child
+            Element widgetElement = captionElement.getParentElement()
+                    .getLastChild().cast();
+
+            // ...but if caption position is bottom or right, the widget is the
+            // first child
+            if (pos == CaptionPosition.BOTTOM || pos == CaptionPosition.RIGHT) {
+                widgetElement = captionElement.getParentElement()
+                        .getFirstChildElement().cast();
+            }
+
+            if (captionElement == widgetElement) {
+                // Caption element already detached
+                rmeoveResizeListener(captionElement, slotCaptionResizeListener);
+                childCaptionElementHeight.remove(widgetElement);
+                return;
+            }
 
+            String widgetWidth = widgetElement.getStyle().getWidth();
+            String widgetHeight = widgetElement.getStyle().getHeight();
+
+            if (widgetHeight.endsWith("%")
+                    && (pos == CaptionPosition.TOP || pos == CaptionPosition.BOTTOM)) {
+                getWidget().updateCaptionOffset(captionElement);
+            } else if (widgetWidth.endsWith("%")
+                    && (pos == CaptionPosition.LEFT || pos == CaptionPosition.RIGHT)) {
+                getWidget().updateCaptionOffset(captionElement);
+            }
+
+            int h = getLayoutManager().getOuterHeight(captionElement)
+                    - getLayoutManager().getMarginHeight(captionElement);
+            childCaptionElementHeight.put(widgetElement, h);
+
+            updateLayoutHeight();
+
+            if (needsExpand()) {
+                getWidget().updateExpand();
+            }
+        }
+    };
+
+    private ElementResizeListener childComponentResizeListener = new ElementResizeListener() {
+        @Override
+        public void onElementResize(ElementResizeEvent e) {
+            updateLayoutHeight();
+            if (needsExpand()) {
+                getWidget().updateExpand();
+            }
+        }
     };
 
+    private ElementResizeListener spacingResizeListener = new ElementResizeListener() {
+        @Override
+        public void onElementResize(ElementResizeEvent e) {
+            if (needsExpand()) {
+                getWidget().updateExpand();
+            }
+        }
+    };
+
+    /*
+     * (non-Javadoc)
+     * 
+     * @see com.vaadin.client.ui.AbstractComponentConnector#init()
+     */
     @Override
     public void init() {
         super.init();
         rpc = RpcProxy.create(AbstractOrderedLayoutServerRpc.class, this);
-        getLayoutManager().registerDependency(this,
-                getWidget().spacingMeasureElement);
+        getWidget().setLayoutManager(getLayoutManager());
     }
 
+    /*
+     * (non-Javadoc)
+     * 
+     * @see com.vaadin.client.ui.AbstractLayoutConnector#getState()
+     */
     @Override
-    public void onUnregister() {
-        LayoutManager lm = getLayoutManager();
-
-        VMeasuringOrderedLayout layout = getWidget();
-        lm.unregisterDependency(this, layout.spacingMeasureElement);
+    public AbstractOrderedLayoutState getState() {
+        return (AbstractOrderedLayoutState) super.getState();
+    }
 
-        // Unregister child caption listeners
-        for (ComponentConnector child : getChildComponents()) {
-            VLayoutSlot slot = layout.getSlotForChild(child.getWidget());
-            slot.setCaption(null);
-        }
+    /*
+     * (non-Javadoc)
+     * 
+     * @see com.vaadin.client.ui.AbstractComponentConnector#getWidget()
+     */
+    @Override
+    public VOrderedLayout getWidget() {
+        return (VOrderedLayout) super.getWidget();
     }
 
+    /**
+     * 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.
+     */
+    private HashSet<ComponentConnector> hasExpandRatio = new HashSet<ComponentConnector>();
+
+    /**
+     * For bookkeeping. Used in extra calculations for horizontal layout.
+     */
+    private HashSet<Element> needsMeasure = new HashSet<Element>();
+
+    /**
+     * For bookkeeping. Used in extra calculations for horizontal layout.
+     */
+    private HashMap<Element, Integer> childCaptionElementHeight = new HashMap<Element, Integer>();
+
+    /*
+     * (non-Javadoc)
+     * 
+     * @see
+     * com.vaadin.client.ComponentContainerConnector#updateCaption(com.vaadin
+     * .client.ComponentConnector)
+     */
     @Override
-    public AbstractOrderedLayoutState getState() {
-        return (AbstractOrderedLayoutState) super.getState();
+    public void updateCaption(ComponentConnector child) {
+        Slot slot = getWidget().getSlot(child.getWidget());
+
+        String caption = child.getState().caption;
+        URLReference iconUrl = child.getState().resources
+                .get(ComponentConstants.ICON_RESOURCE);
+        String iconUrlString = iconUrl != null ? iconUrl.toString() : null;
+        List<String> styles = child.getState().styles;
+        String error = child.getState().errorMessage;
+                boolean showError = error != null;
+                if (child.getState() instanceof AbstractFieldState) {
+                    AbstractFieldState abstractFieldState = (AbstractFieldState) child
+                            .getState();
+            showError = showError && !abstractFieldState.hideErrors;
+                }
+                boolean required = false;
+                if (child instanceof AbstractFieldConnector) {
+                    required = ((AbstractFieldConnector) child).isRequired();
+                }
+        boolean enabled = child.getState().enabled;
+
+        slot.setCaption(caption, iconUrlString, styles, error, showError,
+                required,
+                        enabled);
+
+                slot.setRelativeWidth(child.isRelativeWidth());
+                slot.setRelativeHeight(child.isRelativeHeight());
+
+                if (slot.hasCaption()) {
+                    CaptionPosition pos = slot.getCaptionPosition();
+                    getLayoutManager().addElementResizeListener(
+                            slot.getCaptionElement(), slotCaptionResizeListener);
+                    if (child.isRelativeHeight()
+                            && (pos == CaptionPosition.TOP || pos == CaptionPosition.BOTTOM)) {
+                        getWidget().updateCaptionOffset(slot.getCaptionElement());
+                    } else if (child.isRelativeWidth()
+                            && (pos == CaptionPosition.LEFT || pos == CaptionPosition.RIGHT)) {
+                        getWidget().updateCaptionOffset(slot.getCaptionElement());
+                    }
+                } else {
+                    childCaptionElementHeight.remove(child.getWidget().getElement());
+                }
+
+                updateLayoutHeight();
+
+                if (needsExpand()) {
+            getWidget().updateExpand();
+                }
     }
 
+    /*
+     * (non-Javadoc)
+     * 
+     * @see com.vaadin.client.ui.AbstractComponentContainerConnector#
+     * onConnectorHierarchyChange
+     * (com.vaadin.client.ConnectorHierarchyChangeEvent)
+     */
     @Override
-    public void updateCaption(ComponentConnector component) {
-        VMeasuringOrderedLayout layout = getWidget();
-        if (VCaption.isNeeded(component.getState())) {
-            VLayoutSlot layoutSlot = layout.getSlotForChild(component
-                    .getWidget());
-            VCaption caption = layoutSlot.getCaption();
-            if (caption == null) {
-                caption = new VCaption(component, getConnection());
-
-                Widget widget = component.getWidget();
-
-                layout.setCaption(widget, caption);
+    public void onConnectorHierarchyChange(ConnectorHierarchyChangeEvent event) {
+        super.onConnectorHierarchyChange(event);
+
+        List<ComponentConnector> previousChildren = event.getOldChildren();
+        int currentIndex = 0;
+        VOrderedLayout layout = getWidget();
+
+        for (ComponentConnector child : getChildComponents()) {
+            Slot slot = layout.getSlot(child.getWidget());
+            if (slot.getParent() != layout) {
+                child.addStateChangeHandler(childStateChangeHandler);
+            }
+            layout.addOrMoveSlot(slot, currentIndex++);
+        }
+
+        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());
+                getLayoutManager().removeElementResizeListener(
+                        child.getWidget().getElement(),
+                        childComponentResizeListener);
+                if (slot.hasCaption()) {
+                    getLayoutManager()
+                    .removeElementResizeListener(
+                            slot.getCaptionElement(),
+                            slotCaptionResizeListener);
+                }
+                if (slot.getSpacingElement() != null) {
+                    getLayoutManager().removeElementResizeListener(
+                            slot.getSpacingElement(), spacingResizeListener);
+                }
+                child.removeStateChangeHandler(childStateChangeHandler);
+                layout.removeWidget(child.getWidget());
             }
-            caption.updateCaption();
+        }
+
+        // If some component is added/removed, we need to recalculate the expand
+        if (needsExpand()) {
+            getWidget().updateExpand();
         } else {
-            layout.setCaption(component.getWidget(), null);
-            getLayoutManager().setNeedsLayout(this);
+            getWidget().clearExpand();
         }
-    }
 
-    @Override
-    public VMeasuringOrderedLayout getWidget() {
-        return (VMeasuringOrderedLayout) super.getWidget();
     }
 
+    /*
+     * (non-Javadoc)
+     * 
+     * @see
+     * com.vaadin.client.ui.AbstractComponentConnector#onStateChanged(com.vaadin
+     * .client.communication.StateChangeEvent)
+     */
     @Override
     public void onStateChanged(StateChangeEvent stateChangeEvent) {
         super.onStateChanged(stateChangeEvent);
 
         clickEventHandler.handleEventHandlerRegistration();
+        getWidget().setMargin(new MarginInfo(getState().marginsBitmask));
+        getWidget().setSpacing(getState().spacing);
 
-        VMeasuringOrderedLayout layout = getWidget();
+        hasExpandRatio.clear();
+        hasVerticalAlignment.clear();
+        hasRelativeHeight.clear();
+        needsMeasure.clear();
 
+        boolean equalExpandRatio = getWidget().vertical ? !isUndefinedHeight()
+                : !isUndefinedWidth();
         for (ComponentConnector child : getChildComponents()) {
-            VLayoutSlot slot = layout.getSlotForChild(child.getWidget());
+            double expandRatio = getState().childData.get(child).expandRatio;
+            if (expandRatio > 0) {
+                equalExpandRatio = false;
+                break;
+            }
+        }
+
+        for (ComponentConnector child : getChildComponents()) {
+            Slot slot = getWidget().getSlot(child.getWidget());
 
             AlignmentInfo alignment = new AlignmentInfo(
                     getState().childData.get(child).alignmentBitmask);
             slot.setAlignment(alignment);
 
             double expandRatio = getState().childData.get(child).expandRatio;
-            slot.setExpandRatio(expandRatio);
-        }
 
-        layout.updateMarginStyleNames(new MarginInfo(getState().marginsBitmask));
-        layout.updateSpacingStyleName(getState().spacing);
+            if (equalExpandRatio) {
+                expandRatio = 1;
+            } else if (expandRatio == 0) {
+                expandRatio = -1;
+            }
+            slot.setExpandRatio(expandRatio);
 
-        getLayoutManager().setNeedsLayout(this);
-    }
+            // Bookkeeping to identify special cases that need extra
+            // calculations
+            if (alignment.isVerticalCenter() || alignment.isBottom()) {
+                hasVerticalAlignment.add(child);
+            }
 
-    private int getSizeForInnerSize(int size, boolean isVertical) {
-        LayoutManager layoutManager = getLayoutManager();
-        Element element = getWidget().getElement();
-        if (isVertical) {
-            return size + layoutManager.getBorderHeight(element)
-                    + layoutManager.getPaddingHeight(element);
-        } else {
-            return size + layoutManager.getBorderWidth(element)
-                    + layoutManager.getPaddingWidth(element);
+            if (expandRatio > 0) {
+                hasExpandRatio.add(child);
+            }
         }
-    }
-
-    private static String getSizeProperty(boolean isVertical) {
-        return isVertical ? "height" : "width";
-    }
 
-    private boolean isUndefinedInDirection(boolean isVertical) {
-        if (isVertical) {
-            return isUndefinedHeight();
-        } else {
-            return isUndefinedWidth();
-        }
-    }
+        updateAllSlotListeners();
 
-    private int getInnerSizeInDirection(boolean isVertical) {
-        if (isVertical) {
-            return getLayoutManager().getInnerHeight(getWidget().getElement());
-        } else {
-            return getLayoutManager().getInnerWidth(getWidget().getElement());
-        }
+        updateLayoutHeight();
     }
 
-    private void layoutPrimaryDirection() {
-        VMeasuringOrderedLayout layout = getWidget();
-        boolean isVertical = layout.isVertical;
-        boolean isUndefined = isUndefinedInDirection(isVertical);
 
-        int startPadding = getStartPadding(isVertical);
-        int endPadding = getEndPadding(isVertical);
-        int spacingSize = getSpacingInDirection(isVertical);
-        int allocatedSize;
-
-        if (isUndefined) {
-            allocatedSize = -1;
-        } else {
-            allocatedSize = getInnerSizeInDirection(isVertical);
-        }
-
-        allocatedSize = layout.layoutPrimaryDirection(spacingSize,
-                allocatedSize, startPadding, endPadding);
-
-        Style ownStyle = getWidget().getElement().getStyle();
-        if (isUndefined) {
-            int outerSize = getSizeForInnerSize(allocatedSize, isVertical);
-            ownStyle.setPropertyPx(getSizeProperty(isVertical), outerSize);
-            reportUndefinedSize(outerSize, isVertical);
-        } else {
-            ownStyle.setProperty(getSizeProperty(isVertical),
-                    getDefinedSize(isVertical));
+    /**
+     * Does the layout need a fixed height?
+     */
+    private boolean needsFixedHeight() {
+        if (!getWidget().vertical
+                && isUndefinedHeight()
+                && (hasRelativeHeight.size() > 0 || (hasVerticalAlignment
+                        .size() > 0 && hasVerticalAlignment.size() < getChildren()
+                        .size()))) {
+            return true;
         }
+        return false;
     }
 
-    private void reportUndefinedSize(int outerSize, boolean isVertical) {
-        if (isVertical) {
-            getLayoutManager().reportOuterHeight(this, outerSize);
-        } else {
-            getLayoutManager().reportOuterWidth(this, outerSize);
-        }
+    /**
+     * Does the layout need to expand?
+     */
+    private boolean needsExpand() {
+        boolean canApplyExpand = (getWidget().vertical && !isUndefinedHeight())
+                || (!getWidget().vertical && !isUndefinedWidth());
+        return hasExpandRatio.size() > 0 && canApplyExpand;
     }
 
-    private int getSpacingInDirection(boolean isVertical) {
-        if (isVertical) {
-            return getLayoutManager().getOuterHeight(
-                    getWidget().spacingMeasureElement);
-        } else {
-            return getLayoutManager().getOuterWidth(
-                    getWidget().spacingMeasureElement);
+    /**
+     * Add slot listeners
+     */
+    private void updateAllSlotListeners() {
+        for (ComponentConnector child : getChildComponents()) {
+            updateSlotListeners(child);
         }
     }
 
-    private void layoutSecondaryDirection() {
-        VMeasuringOrderedLayout layout = getWidget();
-        boolean isVertical = layout.isVertical;
-        boolean isUndefined = isUndefinedInDirection(!isVertical);
-
-        int startPadding = getStartPadding(!isVertical);
-        int endPadding = getEndPadding(!isVertical);
-
-        int allocatedSize;
-        if (isUndefined) {
-            allocatedSize = -1;
-        } else {
-            allocatedSize = getInnerSizeInDirection(!isVertical);
+    /**
+     * Add/remove necessary ElementResizeListeners for one slot. This should be
+     * called after each update to the slot's or it's widget.
+     */
+    private void updateSlotListeners(ComponentConnector child) {
+        Slot slot = getWidget().getSlot(child.getWidget());
+
+        // Clear all possible listeners first
+        rmeoveResizeListener(slot.getWidget().getElement(), childComponentResizeListener);
+        if (slot.hasCaption()) {
+            rmeoveResizeListener(slot.getCaptionElement(), slotCaptionResizeListener);
         }
-
-        allocatedSize = layout.layoutSecondaryDirection(allocatedSize,
-                startPadding, endPadding);
-
-        Style ownStyle = getWidget().getElement().getStyle();
-
-        if (isUndefined) {
-            int outerSize = getSizeForInnerSize(allocatedSize,
-                    !getWidget().isVertical);
-            ownStyle.setPropertyPx(getSizeProperty(!getWidget().isVertical),
-                    outerSize);
-            reportUndefinedSize(outerSize, !isVertical);
-        } else {
-            ownStyle.setProperty(getSizeProperty(!getWidget().isVertical),
-                    getDefinedSize(!getWidget().isVertical));
+        if (slot.hasSpacing()) {
+            rmeoveResizeListener(slot.getSpacingElement(), spacingResizeListener);
         }
-    }
 
-    private String getDefinedSize(boolean isVertical) {
-        if (isVertical) {
-            return getState().height == null ? "" : getState().height;
-        } else {
-            return getState().width == null ? "" : getState().width;
+        // Add all necessary listeners
+        if (needsFixedHeight()) {
+            addResizeListener(slot.getWidget().getElement(), childComponentResizeListener);
+            if (slot.hasCaption()) {
+                addResizeListener(slot.getCaptionElement(), slotCaptionResizeListener);
+            }
+        } 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
+            addResizeListener(slot.getCaptionElement(), slotCaptionResizeListener);
         }
-    }
 
-    private int getStartPadding(boolean isVertical) {
-        if (isVertical) {
-            return getLayoutManager().getPaddingTop(getWidget().getElement());
-        } else {
-            return getLayoutManager().getPaddingLeft(getWidget().getElement());
+        if (needsExpand()) {
+            addResizeListener(slot.getWidget().getElement(), childComponentResizeListener);
+            if (slot.hasSpacing()) {
+                addResizeListener(slot.getSpacingElement(), spacingResizeListener);
+            }
         }
-    }
 
-    private int getEndPadding(boolean isVertical) {
-        if (isVertical) {
-            return getLayoutManager()
-                    .getPaddingBottom(getWidget().getElement());
+        if (child.isRelativeHeight()) {
+            hasRelativeHeight.add(child);
+            needsMeasure.remove(child.getWidget().getElement());
         } else {
-            return getLayoutManager().getPaddingRight(getWidget().getElement());
+            hasRelativeHeight.remove(child);
+            needsMeasure.add(child.getWidget().getElement());
         }
+
     }
 
-    @Override
-    public void layoutHorizontally() {
-        if (getWidget().isVertical) {
-            layoutSecondaryDirection();
-        } else {
-            layoutPrimaryDirection();
+    /**
+     * Re-calculate the layout height
+     */
+    private void updateLayoutHeight() {
+        if (needsFixedHeight()) {
+            int h = getMaxHeight();
+            h += getLayoutManager().getBorderHeight(getWidget().getElement())
+                    + getLayoutManager().getPaddingHeight(
+                            getWidget().getElement());
+            getWidget().getElement().getStyle().setHeight(h, Unit.PX);
+            getLayoutManager().setNeedsMeasure(this);
         }
     }
 
-    @Override
-    public void layoutVertically() {
-        if (getWidget().isVertical) {
-            layoutPrimaryDirection();
-        } else {
-            layoutSecondaryDirection();
+    /**
+     * Measures the maximum height of the layout in pixels
+     */
+    private int getMaxHeight() {
+        int highestNonRelative = -1;
+        int highestRelative = -1;
+
+        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());
+            if (needsMeasure.contains(el)) {
+                int h = getLayoutManager().getOuterHeight(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);
+                }
+                if (h > highestNonRelative) {
+                    highestNonRelative = h;
+                }
+            } else {
+                int h = getLayoutManager().getOuterHeight(el);
+                if (childCaptionElementHeight.containsKey(el)
+                        && (pos == CaptionPosition.TOP || pos == CaptionPosition.BOTTOM)) {
+                    h += childCaptionElementHeight.get(el);
+                }
+                if (h > highestRelative) {
+                    highestRelative = h;
+                }
+            }
         }
+        return highestNonRelative > -1 ? highestNonRelative : highestRelative;
     }
 
+    /*
+     * (non-Javadoc)
+     * 
+     * @see com.vaadin.client.ui.AbstractComponentConnector#onUnregister()
+     */
     @Override
-    public void onConnectorHierarchyChange(ConnectorHierarchyChangeEvent event) {
-        super.onConnectorHierarchyChange(event);
-        List<ComponentConnector> previousChildren = event.getOldChildren();
-        int currentIndex = 0;
-        VMeasuringOrderedLayout layout = getWidget();
-
+    public void onUnregister() {
+        // Cleanup all ElementResizeListeners
         for (ComponentConnector child : getChildComponents()) {
-            Widget childWidget = child.getWidget();
-            VLayoutSlot slot = layout.getSlotForChild(childWidget);
-
-            if (childWidget.getParent() != layout) {
-                // If the child widget was previously attached to another
-                // AbstractOrderedLayout a slot might be found that belongs to
-                // another AbstractOrderedLayout. In this case we discard it and
-                // create a new slot.
-                slot = new ComponentConnectorLayoutSlot(getWidget()
-                        .getStylePrimaryName(), child, this);
-            }
-            layout.addOrMove(slot, currentIndex++);
-            if (child.isRelativeWidth()) {
-                slot.getWrapperElement().getStyle().setWidth(100, Unit.PCT);
+            Slot slot = getWidget().getSlot(child.getWidget());
+            if (slot.hasCaption()) {
+                rmeoveResizeListener(slot.getCaptionElement(), slotCaptionResizeListener);
             }
-        }
 
-        for (ComponentConnector child : previousChildren) {
-            if (child.getParent() != this) {
-                // Remove slot if the connector is no longer a child of this
-                // layout
-                layout.removeSlotForWidget(child.getWidget());
+            if (slot.getSpacingElement() != null) {
+                rmeoveResizeListener(slot.getSpacingElement(), spacingResizeListener);
             }
+
+            rmeoveResizeListener(slot.getWidget().getElement(),
+                    childComponentResizeListener);
         }
 
-    };
+        super.onUnregister();
+    }
+
+    /**
+     * Helper method to add a resize listener to an element
+     * 
+     * @param el
+     *            The element to add the resize listener to
+     * @param listener
+     *            The listener to add
+     */
+    private void addResizeListener(Element el, ElementResizeListener listener) {
+        getLayoutManager().addElementResizeListener(el, listener);
+    }
+
+    /**
+     * Helper method to remove a resize listener to an element
+     * 
+     * @param el
+     *            The element from where the resize listener should be removed
+     * @param listener
+     *            THe listener to remove
+     */
+    private void rmeoveResizeListener(Element el, ElementResizeListener listener) {
+        getLayoutManager().removeElementResizeListener(el, listener);
+    }
 
 }
diff --git a/client/src/com/vaadin/client/ui/orderedlayout/HorizontalBoxLayoutConnector.java b/client/src/com/vaadin/client/ui/orderedlayout/HorizontalBoxLayoutConnector.java
deleted file mode 100644 (file)
index 13e133d..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-/* 
-@VaadinApache2LicenseForJavaFiles@
- */
-package com.vaadin.client.ui.orderedlayout;
-
-import com.vaadin.shared.ui.Connect;
-import com.vaadin.shared.ui.Connect.LoadStyle;
-import com.vaadin.ui.HorizontalLayout;
-
-@Connect(value = HorizontalLayout.class, loadStyle = LoadStyle.EAGER)
-public class HorizontalBoxLayoutConnector extends AbstractBoxLayoutConnector {
-
-    @Override
-    public void init() {
-        super.init();
-        getWidget().setVertical(false);
-    }
-
-}
index a86baf9ceadcfaedafc2e9285134d8634e1169ab..aa33e99f45ab01ebf5b52efd218d5fda8773c900 100644 (file)
  */
 package com.vaadin.client.ui.orderedlayout;
 
+import com.vaadin.shared.ui.Connect;
+import com.vaadin.shared.ui.Connect.LoadStyle;
+import com.vaadin.ui.HorizontalLayout;
 
-//@Connect(value = HorizontalLayout.class, loadStyle = LoadStyle.EAGER)
+/**
+ * Connects the client widget {@link VHorizontalLayout} with the Vaadin server
+ * side counterpart {@link HorizontalLayout}
+ */
+@Connect(value = HorizontalLayout.class, loadStyle = LoadStyle.EAGER)
 public class HorizontalLayoutConnector extends AbstractOrderedLayoutConnector {
 
+    /*
+     * (non-Javadoc)
+     * 
+     * @see
+     * com.vaadin.client.ui.orderedlayout.AbstractOrderedLayoutConnector#getWidget
+     * ()
+     */
     @Override
     public VHorizontalLayout getWidget() {
         return (VHorizontalLayout) super.getWidget();
diff --git a/client/src/com/vaadin/client/ui/orderedlayout/VBoxLayout.java b/client/src/com/vaadin/client/ui/orderedlayout/VBoxLayout.java
deleted file mode 100644 (file)
index 4df4ce6..0000000
+++ /dev/null
@@ -1,750 +0,0 @@
-/*
-@VaadinApache2LicenseForJavaFiles@
- */
-package com.vaadin.client.ui.orderedlayout;
-
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-import com.google.gwt.dom.client.Node;
-import com.google.gwt.dom.client.Style;
-import com.google.gwt.dom.client.Style.Unit;
-import com.google.gwt.regexp.shared.MatchResult;
-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.Event;
-import com.google.gwt.user.client.ui.FlowPanel;
-import com.google.gwt.user.client.ui.SimplePanel;
-import com.google.gwt.user.client.ui.UIObject;
-import com.google.gwt.user.client.ui.Widget;
-import com.vaadin.client.ComponentConnector;
-import com.vaadin.client.LayoutManager;
-import com.vaadin.shared.ui.AlignmentInfo;
-import com.vaadin.shared.ui.MarginInfo;
-import com.vaadin.ui.themes.BaseTheme;
-
-public class VBoxLayout extends FlowPanel {
-
-    public static final String CLASSNAME = "v-boxlayout";
-
-    private static final String ALIGN_CLASS_PREFIX = "v-align-";
-
-    protected boolean spacing = false;
-
-    protected boolean vertical = true;
-
-    protected boolean definedHeight = false;
-
-    private Map<Widget, Slot> widgetToSlot = new HashMap<Widget, Slot>();
-
-    private LayoutManager layoutManager;
-
-    public VBoxLayout() {
-        setStyleName(CLASSNAME);
-        setVertical(true);
-    }
-
-    public void setVertical(boolean isVertical) {
-        vertical = isVertical;
-        if (vertical) {
-            addStyleName("v-vertical");
-            removeStyleName("v-horizontal");
-        } else {
-            addStyleName("v-horizontal");
-            removeStyleName("v-vertical");
-        }
-    }
-
-    public void addOrMoveSlot(Slot slot, int index) {
-        if (slot.getParent() == this) {
-            int currentIndex = getWidgetIndex(slot);
-            if (index == currentIndex) {
-                return;
-            }
-        }
-        insert(slot, index);
-    }
-
-    @Override
-    protected void insert(Widget child, Element container, int beforeIndex,
-            boolean domInsert) {
-        // Validate index; adjust if the widget is already a child of this
-        // panel.
-        beforeIndex = adjustIndex(child, beforeIndex);
-
-        // Detach new child.
-        child.removeFromParent();
-
-        // Logical attach.
-        getChildren().insert(child, beforeIndex);
-
-        // Physical attach.
-        container = expandWrapper != null ? expandWrapper : getElement();
-        if (domInsert) {
-            DOM.insertChild(container, child.getElement(),
-                    spacing ? beforeIndex * 2 : beforeIndex);
-        } else {
-            DOM.appendChild(container, child.getElement());
-        }
-
-        // Adopt.
-        adopt(child);
-    }
-
-    public Slot removeSlot(Widget widget) {
-        Slot slot = widgetToSlot.get(widget);
-        remove(slot);
-        widgetToSlot.remove(widget);
-        return slot;
-    }
-
-    public Slot getSlot(ComponentConnector connector) {
-        Slot slot = widgetToSlot.get(connector.getWidget());
-        if (slot == null) {
-            slot = new Slot(connector);
-            widgetToSlot.put(connector.getWidget(), slot);
-        }
-        return slot;
-    }
-
-    public enum CaptionPosition {
-        TOP, RIGHT, BOTTOM, LEFT
-    }
-
-    protected class Slot extends SimplePanel {
-
-        private ComponentConnector connector;
-
-        private Element spacer;
-
-        private Element captionWrap;
-        private Element caption;
-        private Element captionText;
-        private Icon icon;
-        private Element errorIcon;
-        private Element requiredIcon;
-
-        // Caption is placed after component unless there is some part which
-        // moves it above.
-        private CaptionPosition captionPosition = CaptionPosition.RIGHT;
-
-        private AlignmentInfo alignment;
-        private double expandRatio = -1;
-
-        public Slot(ComponentConnector connector) {
-            this.connector = connector;
-            setWidget(connector.getWidget());
-            setStylePrimaryName("v-slot");
-        }
-
-        public AlignmentInfo getAlignment() {
-            return alignment;
-        }
-
-        public void setAlignment(AlignmentInfo alignment) {
-            this.alignment = alignment;
-
-            if (alignment.isHorizontalCenter()) {
-                addStyleName(ALIGN_CLASS_PREFIX + "center");
-                removeStyleName(ALIGN_CLASS_PREFIX + "right");
-            } else if (alignment.isRight()) {
-                addStyleName(ALIGN_CLASS_PREFIX + "right");
-                removeStyleName(ALIGN_CLASS_PREFIX + "center");
-            } else {
-                removeStyleName(ALIGN_CLASS_PREFIX + "right");
-                removeStyleName(ALIGN_CLASS_PREFIX + "center");
-            }
-            if (alignment.isVerticalCenter()) {
-                addStyleName(ALIGN_CLASS_PREFIX + "middle");
-                removeStyleName(ALIGN_CLASS_PREFIX + "bottom");
-            } else if (alignment.isBottom()) {
-                addStyleName(ALIGN_CLASS_PREFIX + "bottom");
-                removeStyleName(ALIGN_CLASS_PREFIX + "middle");
-            } else {
-                removeStyleName(ALIGN_CLASS_PREFIX + "middle");
-                removeStyleName(ALIGN_CLASS_PREFIX + "bottom");
-            }
-        }
-
-        public void setExpandRatio(double expandRatio) {
-            this.expandRatio = expandRatio;
-        }
-
-        public double getExpandRatio() {
-            return expandRatio;
-        }
-
-        public void setSpacing(boolean spacing) {
-            if (spacing && spacer == null) {
-                spacer = DOM.createDiv();
-                spacer.addClassName("v-spacing");
-                getElement().getParentElement().insertBefore(spacer,
-                        getElement());
-            } else if (!spacing && spacer != null) {
-                spacer.removeFromParent();
-                spacer = null;
-            }
-        }
-
-        public Element getSpacingElement() {
-            return spacer;
-        }
-
-        public boolean hasSpacing() {
-            return getSpacingElement() != null;
-        }
-
-        protected int getSpacingSize(boolean vertical) {
-            if (spacer == null) {
-                return 0;
-            }
-
-            if (layoutManager != null) {
-                if (vertical) {
-                    return layoutManager.getOuterHeight(spacer);
-                } else {
-                    return layoutManager.getOuterWidth(spacer);
-                }
-            }
-            // TODO place for optimization (in expense of theme
-            // flexibility): only measure one of the elements and cache the
-            // value
-            return vertical ? spacer.getOffsetHeight() : spacer
-                    .getOffsetWidth();
-            // }
-        }
-
-        public void setCaptionPosition(CaptionPosition captionPosition) {
-            if (caption == null) {
-                return;
-            }
-
-            captionWrap.removeClassName("v-caption-on-"
-                    + this.captionPosition.name().toLowerCase());
-
-            this.captionPosition = captionPosition;
-            if (captionPosition == CaptionPosition.BOTTOM
-                    || captionPosition == CaptionPosition.RIGHT) {
-                captionWrap.appendChild(caption);
-            } else {
-                captionWrap.insertFirst(caption);
-            }
-
-            captionWrap.addClassName("v-caption-on-"
-                    + captionPosition.name().toLowerCase());
-        }
-
-        public CaptionPosition getCaptionPosition() {
-            return captionPosition;
-        }
-
-        // TODO refactor VCaption and use that instead: creates a tight coupling
-        // between this layout and Vaadin, but it's already coupled
-        public void setCaption(String captionText, String iconUrl,
-                List<String> styles, String error, boolean showError,
-                boolean required, boolean enabled) {
-
-            // TODO place for optimization: check if any of these have changed
-            // since last time, and only run those changes
-
-            // Caption wrappers
-            if (captionText != null || iconUrl != null || error != null
-                    || required) {
-                if (caption == null) {
-                    caption = DOM.createDiv();
-                    captionWrap = DOM.createDiv();
-                    captionWrap.addClassName(BaseTheme.UI_WIDGET);
-                    captionWrap.addClassName("v-has-caption");
-                    getElement().appendChild(captionWrap);
-                    captionWrap.appendChild(getWidget().getElement());
-                }
-            } else if (caption != null) {
-                getElement().appendChild(getWidget().getElement());
-                captionWrap.removeFromParent();
-                caption = null;
-                captionWrap = null;
-            }
-
-            // Caption text
-            if (captionText != null) {
-                if (this.captionText == null) {
-                    this.captionText = DOM.createSpan();
-                    this.captionText.addClassName("v-captiontext");
-                    caption.appendChild(this.captionText);
-                }
-                if (captionText.trim().equals("")) {
-                    this.captionText.setInnerHTML("&nbsp;");
-                } else {
-                    this.captionText.setInnerText(captionText);
-                }
-            } else if (this.captionText != null) {
-                this.captionText.removeFromParent();
-                this.captionText = null;
-            }
-
-            // Icon
-            if (iconUrl != null) {
-                if (icon == null) {
-                    icon = new Icon();
-                    // icon = DOM.createImg();
-                    // icon.setClassName("v-icon");
-                    caption.insertFirst(icon.getElement());
-                }
-                // icon.setAttribute("src", iconUrl);
-                icon.setUri(iconUrl);
-            } else if (icon != null) {
-                icon.getElement().removeFromParent();
-                icon = null;
-            }
-
-            // Required
-            if (required) {
-                if (requiredIcon == null) {
-                    requiredIcon = DOM.createSpan();
-                    // TODO decide something better (e.g. use CSS to insert the
-                    // character)
-                    requiredIcon.setInnerHTML("*");
-                    requiredIcon.setClassName("v-required-field-indicator");
-                }
-                caption.appendChild(requiredIcon);
-            } else if (requiredIcon != null) {
-                requiredIcon.removeFromParent();
-                requiredIcon = null;
-            }
-
-            // Error
-            if (error != null && showError) {
-                if (errorIcon == null) {
-                    errorIcon = DOM.createSpan();
-                    errorIcon.setClassName("v-errorindicator");
-                }
-                caption.appendChild(errorIcon);
-            } else if (errorIcon != null) {
-                errorIcon.removeFromParent();
-                errorIcon = null;
-            }
-
-            if (caption != null) {
-                // Styles
-                caption.setClassName("v-caption");
-
-                if (styles != null) {
-                    for (String style : styles) {
-                        caption.addClassName("v-caption-" + style);
-                    }
-                }
-
-                if (enabled) {
-                    caption.removeClassName("v-disabled");
-                } else {
-                    caption.addClassName("v-disabled");
-                }
-
-                // Caption position
-                if (captionText != null || iconUrl != null) {
-                    setCaptionPosition(CaptionPosition.TOP);
-                } else {
-                    setCaptionPosition(CaptionPosition.RIGHT);
-                }
-            }
-
-            // TODO theme flexibility: add extra styles to captionWrap as well?
-
-        }
-
-        public boolean hasCaption() {
-            return caption != null;
-        }
-
-        public Element getCaptionElement() {
-            return caption;
-        }
-
-        public void setRelativeWidth(boolean relativeWidth) {
-            updateRelativeSize(relativeWidth, "width");
-        }
-
-        public void setRelativeHeight(boolean relativeHeight) {
-            updateRelativeSize(relativeHeight, "height");
-        }
-
-        private void updateRelativeSize(boolean isRelativeSize, String direction) {
-            if (isRelativeSize && hasCaption()) {
-                captionWrap.getStyle().setProperty(
-                        direction,
-                        getWidget().getElement().getStyle()
-                        .getProperty(direction));
-                captionWrap.addClassName("v-has-" + direction);
-            } else if (hasCaption()) {
-                if (direction.equals("height")) {
-                    captionWrap.getStyle().clearHeight();
-                } else {
-                    captionWrap.getStyle().clearWidth();
-                }
-                captionWrap.removeClassName("v-has-" + direction);
-                captionWrap.getStyle().clearPaddingTop();
-                captionWrap.getStyle().clearPaddingRight();
-                captionWrap.getStyle().clearPaddingBottom();
-                captionWrap.getStyle().clearPaddingLeft();
-                caption.getStyle().clearMarginTop();
-                caption.getStyle().clearMarginRight();
-                caption.getStyle().clearMarginBottom();
-                caption.getStyle().clearMarginLeft();
-            }
-        }
-
-        @Override
-        public void onBrowserEvent(Event event) {
-            super.onBrowserEvent(event);
-            if (DOM.eventGetType(event) == Event.ONLOAD
-                    && icon.getElement() == DOM.eventGetTarget(event)) {
-                if (layoutManager != null) {
-                    layoutManager.layoutLater();
-                } else {
-                    updateCaptionOffset(caption);
-                }
-            }
-        }
-
-        @Override
-        protected Element getContainerElement() {
-            if (captionWrap == null) {
-                return getElement();
-            } else {
-                return captionWrap;
-            }
-        }
-
-        @Override
-        protected void onDetach() {
-            if (spacer != null) {
-                spacer.removeFromParent();
-            }
-            super.onDetach();
-        }
-
-        @Override
-        protected void onAttach() {
-            super.onAttach();
-            if (spacer != null) {
-                getElement().getParentElement().insertBefore(spacer,
-                        getElement());
-            }
-        }
-
-    }
-
-    protected class Icon extends UIObject {
-        public static final String CLASSNAME = "v-icon";
-        private String myUrl;
-
-        public Icon() {
-            setElement(DOM.createImg());
-            DOM.setElementProperty(getElement(), "alt", "");
-            setStyleName(CLASSNAME);
-        }
-
-        public void setUri(String url) {
-            if (!url.equals(myUrl)) {
-                /*
-                 * Start sinking onload events, widgets responsibility to react.
-                 * We must do this BEFORE we set src as IE fires the event
-                 * immediately if the image is found in cache (#2592).
-                 */
-                sinkEvents(Event.ONLOAD);
-
-                DOM.setElementProperty(getElement(), "src", url);
-                myUrl = url;
-            }
-        }
-
-    }
-
-    void setLayoutManager(LayoutManager manager) {
-        layoutManager = manager;
-    }
-
-    private static final RegExp captionPositionRegexp = RegExp
-            .compile("v-caption-on-(\\S+)");
-
-    CaptionPosition getCaptionPositionFromElement(Element captionWrap) {
-        // Get caption position from the classname
-        MatchResult matcher = captionPositionRegexp.exec(captionWrap
-                .getClassName());
-        if (matcher == null || matcher.getGroupCount() < 2) {
-            return CaptionPosition.TOP;
-        }
-        String captionClass = matcher.getGroup(1);
-        CaptionPosition captionPosition = CaptionPosition.valueOf(
-                CaptionPosition.class, captionClass.toUpperCase());
-        return captionPosition;
-    }
-
-    void updateCaptionOffset(Element caption) {
-
-        Element captionWrap = caption.getParentElement().cast();
-
-        Style captionWrapStyle = captionWrap.getStyle();
-        captionWrapStyle.clearPaddingTop();
-        captionWrapStyle.clearPaddingRight();
-        captionWrapStyle.clearPaddingBottom();
-        captionWrapStyle.clearPaddingLeft();
-
-        Style captionStyle = caption.getStyle();
-        captionStyle.clearMarginTop();
-        captionStyle.clearMarginRight();
-        captionStyle.clearMarginBottom();
-        captionStyle.clearMarginLeft();
-
-        // Get caption position from the classname
-        CaptionPosition captionPosition = getCaptionPositionFromElement(captionWrap);
-
-        if (captionPosition == CaptionPosition.LEFT
-                || captionPosition == CaptionPosition.RIGHT) {
-            int captionWidth;
-            if (layoutManager != null) {
-                captionWidth = layoutManager.getOuterWidth(caption)
-                        - layoutManager.getMarginWidth(caption);
-            } else {
-                captionWidth = caption.getOffsetWidth();
-            }
-            if (captionWidth > 0) {
-                if (captionPosition == CaptionPosition.LEFT) {
-                    captionWrapStyle.setPaddingLeft(captionWidth, Unit.PX);
-                    captionStyle.setMarginLeft(-captionWidth, Unit.PX);
-                } else {
-                    captionWrapStyle.setPaddingRight(captionWidth, Unit.PX);
-                    captionStyle.setMarginRight(-captionWidth, Unit.PX);
-                }
-            }
-        }
-        if (captionPosition == CaptionPosition.TOP
-                || captionPosition == CaptionPosition.BOTTOM) {
-            int captionHeight;
-            if (layoutManager != null) {
-                captionHeight = layoutManager.getOuterHeight(caption)
-                        - layoutManager.getMarginHeight(caption);
-            } else {
-                captionHeight = caption.getOffsetHeight();
-            }
-            if (captionHeight > 0) {
-                if (captionPosition == CaptionPosition.TOP) {
-                    captionWrapStyle.setPaddingTop(captionHeight, Unit.PX);
-                    captionStyle.setMarginTop(-captionHeight, Unit.PX);
-                } else {
-                    captionWrapStyle.setPaddingBottom(captionHeight, Unit.PX);
-                    captionStyle.setMarginBottom(-captionHeight, Unit.PX);
-                }
-            }
-        }
-    }
-
-    void setMargin(MarginInfo marginInfo) {
-        setStyleName("v-margin-top", marginInfo.hasTop());
-        setStyleName("v-margin-right", marginInfo.hasRight());
-        setStyleName("v-margin-bottom", marginInfo.hasBottom());
-        setStyleName("v-margin-left", marginInfo.hasLeft());
-    }
-
-    protected void setSpacing(boolean spacingEnabled) {
-        spacing = spacingEnabled;
-        for (Slot slot : widgetToSlot.values()) {
-            if (getWidgetIndex(slot) > 0) {
-                slot.setSpacing(spacingEnabled);
-            }
-        }
-    }
-
-    private void recalculateExpands() {
-        double total = 0;
-        for (Slot slot : widgetToSlot.values()) {
-            if (slot.getExpandRatio() > -1) {
-                total += slot.getExpandRatio();
-            } else {
-                if (vertical) {
-                    slot.getElement().getStyle().clearHeight();
-                } else {
-                    slot.getElement().getStyle().clearWidth();
-                }
-            }
-        }
-        for (Slot slot : widgetToSlot.values()) {
-            if (slot.getExpandRatio() > -1) {
-                if (vertical) {
-                    slot.setHeight((100 * (slot.getExpandRatio() / total))
-                            + "%");
-                    if (slot.connector.isRelativeHeight()) {
-                        layoutManager.setNeedsMeasure(slot.connector);
-                    }
-                } else {
-                    slot.setWidth((100 * (slot.getExpandRatio() / total)) + "%");
-                    if (slot.connector.isRelativeWidth()) {
-                        layoutManager.setNeedsMeasure(slot.connector);
-                    }
-                }
-            }
-        }
-    }
-
-    private Element expandWrapper;
-
-    void clearExpand() {
-        if (expandWrapper != null) {
-            for (; expandWrapper.getChildCount() > 0;) {
-                Element el = expandWrapper.getChild(0).cast();
-                getElement().appendChild(el);
-                if (vertical) {
-                    el.getStyle().clearHeight();
-                    el.getStyle().clearMarginTop();
-                } else {
-                    el.getStyle().clearWidth();
-                    el.getStyle().clearMarginLeft();
-                }
-            }
-            expandWrapper.removeFromParent();
-            expandWrapper = null;
-        }
-    }
-
-    public void updateExpand() {
-        boolean isExpanding = false;
-        for (Widget slot : getChildren()) {
-            if (((Slot) slot).getExpandRatio() > -1) {
-                isExpanding = true;
-            } else {
-                if (vertical) {
-                    slot.getElement().getStyle().clearHeight();
-                } else {
-                    slot.getElement().getStyle().clearWidth();
-                }
-            }
-            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 (layoutManager != null) {
-                        // TODO check caption position
-                        if (vertical) {
-                            int size = layoutManager.getOuterHeight(slot
-                                    .getWidget().getElement())
-                                    - layoutManager.getMarginHeight(slot
-                                            .getWidget().getElement());
-                            if (slot.hasCaption()) {
-                                size += layoutManager.getOuterHeight(slot
-                                        .getCaptionElement())
-                                        - layoutManager.getMarginHeight(slot
-                                                .getCaptionElement());
-                            }
-                            if (size > 0) {
-                                totalSize += size;
-                            }
-                        } else {
-                            int max = -1;
-                            max = layoutManager.getOuterWidth(slot.getWidget()
-                                    .getElement())
-                                    - layoutManager.getMarginWidth(slot
-                                            .getWidget().getElement());
-                            if (slot.hasCaption()) {
-                                int max2 = layoutManager.getOuterWidth(slot
-                                        .getCaptionElement())
-                                        - layoutManager.getMarginWidth(slot
-                                                .getCaptionElement());
-                                max = Math.max(max, max2);
-                            }
-                            if (max > 0) {
-                                totalSize += max;
-                            }
-                        }
-                    } else {
-                        totalSize += vertical ? slot.getOffsetHeight() : slot
-                                .getOffsetWidth();
-                    }
-                }
-                // TODO fails in Opera, always returns 0
-                int spacingSize = slot.getSpacingSize(vertical);
-                if (spacingSize > 0) {
-                    totalSize += spacingSize;
-                }
-            }
-
-            // When we set the margin to the first child, we don't need
-            // overflow:hidden in the layout root element, since the wrapper
-            // would otherwise be placed outside of the layout root element
-            // and block events on elements below it.
-            if (vertical) {
-                expandWrapper.getStyle().setPaddingTop(totalSize, Unit.PX);
-                expandWrapper.getFirstChildElement().getStyle()
-                .setMarginTop(-totalSize, Unit.PX);
-            } else {
-                expandWrapper.getStyle().setPaddingLeft(totalSize, Unit.PX);
-                expandWrapper.getFirstChildElement().getStyle()
-                .setMarginLeft(-totalSize, Unit.PX);
-            }
-
-            recalculateExpands();
-        }
-    }
-
-    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();
-            }
-            VBoxLayout.this.getElement().getStyle()
-            .setHeight(newHeight, Unit.PX);
-        }
-
-    }
-
-    void clearHeight() {
-        getElement().getStyle().clearHeight();
-    }
-
-    @Override
-    public void setHeight(String height) {
-        super.setHeight(height);
-        definedHeight = (height != null && !"".equals(height));
-    }
-}
index c72c44262b70e16729dca9fa65a34248d4a544c5..543eeafe88d43376e4e62beac27a67cad5d785be 100644 (file)
  */
 package com.vaadin.client.ui.orderedlayout;
 
-public class VHorizontalLayout extends VMeasuringOrderedLayout {
-
-    public static final String CLASSNAME = "v-horizontallayout";
+/**
+ * Represents a layout where the children is ordered vertically
+ */
+public class VHorizontalLayout extends VOrderedLayout {
 
+    /**
+     * Default constructor
+     */
     public VHorizontalLayout() {
-        super(CLASSNAME, false);
+        setVertical(false);
     }
-
 }
diff --git a/client/src/com/vaadin/client/ui/orderedlayout/VMeasuringOrderedLayout.java b/client/src/com/vaadin/client/ui/orderedlayout/VMeasuringOrderedLayout.java
deleted file mode 100644 (file)
index 94dfe22..0000000
+++ /dev/null
@@ -1,253 +0,0 @@
-/*
- * Copyright 2011 Vaadin Ltd.
- * 
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not
- * use this file except in compliance with the License. You may obtain a copy of
- * the License at
- * 
- * http://www.apache.org/licenses/LICENSE-2.0
- * 
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations under
- * the License.
- */
-package com.vaadin.client.ui.orderedlayout;
-
-import java.util.HashMap;
-import java.util.Map;
-
-import com.google.gwt.dom.client.DivElement;
-import com.google.gwt.dom.client.Document;
-import com.google.gwt.dom.client.Node;
-import com.google.gwt.dom.client.Style;
-import com.google.gwt.dom.client.Style.Position;
-import com.google.gwt.user.client.Element;
-import com.google.gwt.user.client.ui.ComplexPanel;
-import com.google.gwt.user.client.ui.Widget;
-import com.google.gwt.user.client.ui.WidgetCollection;
-import com.vaadin.client.VCaption;
-import com.vaadin.client.ui.layout.VLayoutSlot;
-import com.vaadin.shared.ui.MarginInfo;
-
-public class VMeasuringOrderedLayout extends ComplexPanel {
-
-    final boolean isVertical;
-
-    final DivElement spacingMeasureElement;
-
-    private Map<Widget, VLayoutSlot> widgetToSlot = new HashMap<Widget, VLayoutSlot>();
-
-    protected VMeasuringOrderedLayout(String className, boolean isVertical) {
-        DivElement element = Document.get().createDivElement();
-        setElement(element);
-
-        spacingMeasureElement = Document.get().createDivElement();
-        Style spacingStyle = spacingMeasureElement.getStyle();
-        spacingStyle.setPosition(Position.ABSOLUTE);
-        getElement().appendChild(spacingMeasureElement);
-
-        setStyleName(className);
-        this.isVertical = isVertical;
-    }
-
-    public void addOrMove(VLayoutSlot layoutSlot, int index) {
-        Widget widget = layoutSlot.getWidget();
-        Element wrapperElement = layoutSlot.getWrapperElement();
-
-        Element containerElement = getElement();
-        Node childAtIndex = containerElement.getChild(index);
-        if (childAtIndex != wrapperElement) {
-            // Insert at correct location not attached or at wrong location
-            containerElement.insertBefore(wrapperElement, childAtIndex);
-            insert(widget, wrapperElement, index, false);
-        }
-
-        widgetToSlot.put(widget, layoutSlot);
-    }
-
-    private void togglePrefixedStyleName(String name, boolean enabled) {
-        if (enabled) {
-            addStyleDependentName(name);
-        } else {
-            removeStyleDependentName(name);
-        }
-    }
-
-    void updateMarginStyleNames(MarginInfo marginInfo) {
-        togglePrefixedStyleName("margin-top", marginInfo.hasTop());
-        togglePrefixedStyleName("margin-right", marginInfo.hasRight());
-        togglePrefixedStyleName("margin-bottom", marginInfo.hasBottom());
-        togglePrefixedStyleName("margin-left", marginInfo.hasLeft());
-    }
-
-    void updateSpacingStyleName(boolean spacingEnabled) {
-        String styleName = getStylePrimaryName();
-        if (spacingEnabled) {
-            spacingMeasureElement.addClassName(styleName + "-spacing-on");
-            spacingMeasureElement.removeClassName(styleName + "-spacing-off");
-        } else {
-            spacingMeasureElement.removeClassName(styleName + "-spacing-on");
-            spacingMeasureElement.addClassName(styleName + "-spacing-off");
-        }
-    }
-
-    public void removeSlotForWidget(Widget widget) {
-        VLayoutSlot slot = getSlotForChild(widget);
-        VCaption caption = slot.getCaption();
-        if (caption != null) {
-            // Must remove using setCaption to ensure dependencies (layout ->
-            // caption) are unregistered
-            slot.setCaption(null);
-        }
-
-        remove(slot.getWidget());
-        getElement().removeChild(slot.getWrapperElement());
-        widgetToSlot.remove(widget);
-    }
-
-    public VLayoutSlot getSlotForChild(Widget widget) {
-        return widgetToSlot.get(widget);
-    }
-
-    public void setCaption(Widget child, VCaption caption) {
-        VLayoutSlot slot = getSlotForChild(child);
-
-        if (caption != null) {
-            // Logical attach.
-            getChildren().add(caption);
-        }
-
-        // Physical attach if not null, also removes old caption
-        slot.setCaption(caption);
-
-        if (caption != null) {
-            // Adopt.
-            adopt(caption);
-        }
-    }
-
-    public int layoutPrimaryDirection(int spacingSize, int allocatedSize,
-            int startPadding, int endPadding) {
-        int actuallyAllocated = 0;
-        double totalExpand = 0;
-
-        int childCount = 0;
-        for (Widget child : this) {
-            if (child instanceof VCaption) {
-                continue;
-            }
-            childCount++;
-
-            VLayoutSlot slot = getSlotForChild(child);
-            totalExpand += slot.getExpandRatio();
-
-            if (!slot.isRelativeInDirection(isVertical)) {
-                actuallyAllocated += slot.getUsedSizeInDirection(isVertical);
-            }
-        }
-
-        actuallyAllocated += spacingSize * (childCount - 1);
-
-        if (allocatedSize == -1) {
-            allocatedSize = actuallyAllocated;
-        }
-
-        double unallocatedSpace = Math
-                .max(0, allocatedSize - actuallyAllocated);
-
-        double currentLocation = startPadding;
-
-        WidgetCollection children = getChildren();
-        for (int i = 0; i < children.size(); i++) {
-            Widget child = children.get(i);
-            if (child instanceof VCaption) {
-                continue;
-            }
-
-            VLayoutSlot slot = getSlotForChild(child);
-
-            double childExpandRatio;
-            if (totalExpand == 0) {
-                childExpandRatio = 1d / childCount;
-            } else {
-                childExpandRatio = slot.getExpandRatio() / totalExpand;
-            }
-
-            double extraPixels = unallocatedSpace * childExpandRatio;
-            double endLocation = currentLocation + extraPixels;
-            if (!slot.isRelativeInDirection(isVertical)) {
-                endLocation += slot.getUsedSizeInDirection(isVertical);
-            }
-
-            /*
-             * currentLocation and allocatedSpace are used with full precision
-             * to avoid missing pixels in the end. The pixel dimensions passed
-             * to the DOM are still rounded. Otherwise e.g. 10.5px start
-             * position + 10.5px space might be cause the component to go 1px
-             * beyond the edge as the effect of the browser's rounding may cause
-             * something similar to 11px + 11px.
-             * 
-             * It's most efficient to use doubles all the way because native
-             * javascript emulates other number types using doubles.
-             */
-            double roundedLocation = Math.round(currentLocation);
-
-            /*
-             * Space is calculated as the difference between rounded start and
-             * end locations. Just rounding the space would cause e.g. 10.5px +
-             * 10.5px = 21px -> 11px + 11px = 22px but in this way we get 11px +
-             * 10px = 21px.
-             */
-            double roundedSpace = Math.round(endLocation) - roundedLocation;
-
-            // Reserve room for the padding if we're at the end
-            double slotEndMargin;
-            if (i == children.size() - 1) {
-                slotEndMargin = endPadding;
-            } else {
-                slotEndMargin = 0;
-            }
-
-            slot.positionInDirection(roundedLocation, roundedSpace,
-                    slotEndMargin, isVertical);
-
-            currentLocation = endLocation + spacingSize;
-        }
-
-        return allocatedSize;
-    }
-
-    public int layoutSecondaryDirection(int allocatedSize, int startPadding,
-            int endPadding) {
-        int maxSize = 0;
-        for (Widget child : this) {
-            if (child instanceof VCaption) {
-                continue;
-            }
-
-            VLayoutSlot slot = getSlotForChild(child);
-            if (!slot.isRelativeInDirection(!isVertical)) {
-                maxSize = Math.max(maxSize,
-                        slot.getUsedSizeInDirection(!isVertical));
-            }
-        }
-
-        if (allocatedSize == -1) {
-            allocatedSize = maxSize;
-        }
-
-        for (Widget child : this) {
-            if (child instanceof VCaption) {
-                continue;
-            }
-
-            VLayoutSlot slot = getSlotForChild(child);
-            slot.positionInDirection(startPadding, allocatedSize, endPadding,
-                    !isVertical);
-        }
-
-        return allocatedSize;
-    }
-}
diff --git a/client/src/com/vaadin/client/ui/orderedlayout/VOrderedLayout.java b/client/src/com/vaadin/client/ui/orderedlayout/VOrderedLayout.java
new file mode 100644 (file)
index 0000000..9c45680
--- /dev/null
@@ -0,0 +1,995 @@
+/*
+ * Copyright 2011 Vaadin Ltd.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ * 
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.vaadin.client.ui.orderedlayout;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import com.google.gwt.dom.client.Node;
+import com.google.gwt.dom.client.Style;
+import com.google.gwt.dom.client.Style.Unit;
+import com.google.gwt.regexp.shared.MatchResult;
+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.Event;
+import com.google.gwt.user.client.ui.FlowPanel;
+import com.google.gwt.user.client.ui.SimplePanel;
+import com.google.gwt.user.client.ui.UIObject;
+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;
+import com.vaadin.ui.themes.BaseTheme;
+
+/**
+ * Base class for ordered layouts
+ */
+public class VOrderedLayout extends FlowPanel {
+
+    public static final String CLASSNAME = "v-boxlayout";
+
+    private static final String ALIGN_CLASS_PREFIX = "v-align-";
+
+    protected boolean spacing = false;
+
+    protected boolean vertical = true;
+
+    protected boolean definedHeight = false;
+
+    private Map<Widget, Slot> widgetToSlot = new HashMap<Widget, Slot>();
+
+    private Element expandWrapper;
+
+    private LayoutManager layoutManager;
+
+    /**
+     * Constructor
+     */
+    public VOrderedLayout() {
+        setStyleName(CLASSNAME);
+        setVertical(true);
+    }
+
+    /**
+     * Does the layout order its children horizontally or vertically
+     * 
+     * @param vertical
+     *            true to order the childer vertically, false to order them
+     *            horizontally
+     * 
+     */
+    protected void setVertical(boolean vertical) {
+        this.vertical = vertical;
+        if (vertical) {
+            addStyleName("v-vertical");
+            removeStyleName("v-horizontal");
+        } else {
+            addStyleName("v-horizontal");
+            removeStyleName("v-vertical");
+        }
+    }
+
+    /**
+     * Add or move a slot to another index
+     * 
+     * @param slot
+     *            The slot to move or add
+     * @param index
+     *            The index where the slot should be placed
+     */
+    void addOrMoveSlot(Slot slot, int index) {
+        if (slot.getParent() == this) {
+            int currentIndex = getWidgetIndex(slot);
+            if (index == currentIndex) {
+                return;
+            }
+        }
+        insert(slot, index);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    protected void insert(Widget child, Element container, int beforeIndex,
+            boolean domInsert) {
+        // Validate index; adjust if the widget is already a child of this
+        // panel.
+        beforeIndex = adjustIndex(child, beforeIndex);
+
+        // Detach new child.
+        child.removeFromParent();
+
+        // Logical attach.
+        getChildren().insert(child, beforeIndex);
+
+        // Physical attach.
+        container = expandWrapper != null ? expandWrapper : getElement();
+        if (domInsert) {
+            DOM.insertChild(container, child.getElement(),
+                    spacing ? beforeIndex * 2 : beforeIndex);
+        } else {
+            DOM.appendChild(container, child.getElement());
+        }
+
+        // Adopt.
+        adopt(child);
+    }
+
+    /**
+     * Remove a slot from the layout
+     * 
+     * @param widget
+     * @return
+     */
+    public void removeWidget(Widget widget) {
+        Slot slot = widgetToSlot.get(widget);
+        remove(slot);
+        widgetToSlot.remove(widget);
+    }
+
+    /**
+     * Get the containing slot for a widget
+     * 
+     * @param widget
+     *            The widget whose slot you want to get
+     * 
+     * @return
+     */
+    public Slot getSlot(Widget widget) {
+        Slot slot = widgetToSlot.get(widget);
+        if (slot == null) {
+            slot = new Slot(widget, this);
+            widgetToSlot.put(widget, slot);
+        }
+        return slot;
+    }
+
+    /**
+     * Defines where the caption should be placed
+     */
+    public enum CaptionPosition {
+        TOP, RIGHT, BOTTOM, LEFT
+    }
+
+    /**
+     * Represents a slot which contains the actual widget in the layout.
+     */
+    public static final class Slot extends SimplePanel {
+
+        private Element spacer;
+        private Element captionWrap;
+        private Element caption;
+        private Element captionText;
+        private Icon icon;
+        private Element errorIcon;
+        private Element requiredIcon;
+        private final VOrderedLayout layout;
+
+        // Caption is placed after component unless there is some part which
+        // moves it above.
+        private CaptionPosition captionPosition = CaptionPosition.RIGHT;
+
+        private AlignmentInfo alignment;
+
+        private double expandRatio = -1;
+
+        /**
+         * Constructor
+         * 
+         * @param widget
+         *            The widget to put in the slot
+         * 
+         * @param layoutManager
+         *            The layout manager used by the layout
+         */
+        private Slot(Widget widget, VOrderedLayout layout) {
+            this.layout = layout;
+            setWidget(widget);
+            setStylePrimaryName("v-slot");
+        }
+
+        /**
+         * Returns the alignment for the slot
+         * 
+         */
+        public AlignmentInfo getAlignment() {
+            return alignment;
+        }
+
+        /**
+         * Sets how the widget is aligned inside the slot
+         * 
+         * @param alignment
+         *            The alignment inside the slot
+         */
+        public void setAlignment(AlignmentInfo alignment) {
+            this.alignment = alignment;
+
+            if (alignment.isHorizontalCenter()) {
+                addStyleName(ALIGN_CLASS_PREFIX + "center");
+                removeStyleName(ALIGN_CLASS_PREFIX + "right");
+            } else if (alignment.isRight()) {
+                addStyleName(ALIGN_CLASS_PREFIX + "right");
+                removeStyleName(ALIGN_CLASS_PREFIX + "center");
+            } else {
+                removeStyleName(ALIGN_CLASS_PREFIX + "right");
+                removeStyleName(ALIGN_CLASS_PREFIX + "center");
+            }
+            if (alignment.isVerticalCenter()) {
+                addStyleName(ALIGN_CLASS_PREFIX + "middle");
+                removeStyleName(ALIGN_CLASS_PREFIX + "bottom");
+            } else if (alignment.isBottom()) {
+                addStyleName(ALIGN_CLASS_PREFIX + "bottom");
+                removeStyleName(ALIGN_CLASS_PREFIX + "middle");
+            } else {
+                removeStyleName(ALIGN_CLASS_PREFIX + "middle");
+                removeStyleName(ALIGN_CLASS_PREFIX + "bottom");
+            }
+        }
+
+        /**
+         * Set how the slot should be expanded relative to the other slots
+         * 
+         * @param expandRatio
+         *            The ratio of the space the slot should occupy
+         * 
+         */
+        public void setExpandRatio(double expandRatio) {
+            this.expandRatio = expandRatio;
+        }
+
+        /**
+         * 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
+         */
+        public double getExpandRatio() {
+            return expandRatio;
+        }
+
+        /**
+         * Set the spacing for the slot. The spacing determines if there should
+         * be empty space around the slot when the slot.
+         * 
+         * @param spacing
+         *            Should spacing be enabled
+         */
+        public void setSpacing(boolean spacing) {
+            if (spacing && spacer == null) {
+                spacer = DOM.createDiv();
+                spacer.addClassName("v-spacing");
+                getElement().getParentElement().insertBefore(spacer,
+                        getElement());
+            } else if (!spacing && spacer != null) {
+                spacer.removeFromParent();
+                spacer = null;
+            }
+        }
+
+        /**
+         * Get the element which is added to make the spacing
+         * 
+         * @return
+         */
+        public Element getSpacingElement() {
+            return spacer;
+        }
+
+        /**
+         * Does the slot have spacing
+         */
+        public boolean hasSpacing() {
+            return getSpacingElement() != null;
+        }
+
+        /**
+         * Get the vertical amount in pixels of the spacing
+         */
+        protected int getVerticalSpacing() {
+            if (spacer == null) {
+                return 0;
+            } else if (layout.getLayoutManager() != null) {
+                return layout.getLayoutManager().getOuterHeight(spacer);
+            }
+            return spacer.getOffsetHeight();
+        }
+
+        /**
+         * Get the horizontal amount of pixels of the spacing
+         * 
+         * @return
+         */
+        protected int getHorizontalSpacing() {
+            if (spacer == null) {
+                return 0;
+            } else if (layout.getLayoutManager() != null) {
+                return layout.getLayoutManager().getOuterWidth(spacer);
+            }
+            return spacer.getOffsetWidth();
+        }
+
+        /**
+         * Set the position of the caption relative to the slot
+         * 
+         * @param captionPosition
+         *            The position of the caption
+         */
+        public void setCaptionPosition(CaptionPosition captionPosition) {
+            if (caption == null) {
+                return;
+            }
+            captionWrap.removeClassName("v-caption-on-"
+                    + this.captionPosition.name().toLowerCase());
+
+            this.captionPosition = captionPosition;
+            if (captionPosition == CaptionPosition.BOTTOM
+                    || captionPosition == CaptionPosition.RIGHT) {
+                captionWrap.appendChild(caption);
+            } else {
+                captionWrap.insertFirst(caption);
+            }
+
+            captionWrap.addClassName("v-caption-on-"
+                    + captionPosition.name().toLowerCase());
+        }
+
+        /**
+         * Get the position of the caption relative to the slot
+         */
+        public CaptionPosition getCaptionPosition() {
+            return captionPosition;
+        }
+
+        /**
+         * Set the caption of the slot
+         * 
+         * @param captionText
+         *            The text of the caption
+         * @param iconUrl
+         *            The icon URL
+         * @param styles
+         *            The style names
+         * @param error
+         *            The error message
+         * @param showError
+         *            Should the error message be shown
+         * @param required
+         *            Is the (field) required
+         * @param enabled
+         *            Is the component enabled
+         */
+        public void setCaption(String captionText, String iconUrl,
+                List<String> styles, String error, boolean showError,
+                boolean required, boolean enabled) {
+
+            // TODO place for optimization: check if any of these have changed
+            // since last time, and only run those changes
+
+            // Caption wrappers
+            if (captionText != null || iconUrl != null || error != null
+                    || required) {
+                if (caption == null) {
+                    caption = DOM.createDiv();
+                    captionWrap = DOM.createDiv();
+                    captionWrap.addClassName(BaseTheme.UI_WIDGET);
+                    captionWrap.addClassName("v-has-caption");
+                    getElement().appendChild(captionWrap);
+                    captionWrap.appendChild(getWidget().getElement());
+                }
+            } else if (caption != null) {
+                getElement().appendChild(getWidget().getElement());
+                captionWrap.removeFromParent();
+                caption = null;
+                captionWrap = null;
+            }
+
+            // Caption text
+            if (captionText != null) {
+                if (this.captionText == null) {
+                    this.captionText = DOM.createSpan();
+                    this.captionText.addClassName("v-captiontext");
+                    caption.appendChild(this.captionText);
+                }
+                if (captionText.trim().equals("")) {
+                    this.captionText.setInnerHTML("&nbsp;");
+                } else {
+                    this.captionText.setInnerText(captionText);
+                }
+            } else if (this.captionText != null) {
+                this.captionText.removeFromParent();
+                this.captionText = null;
+            }
+
+            // Icon
+            if (iconUrl != null) {
+                if (icon == null) {
+                    icon = new Icon();
+                    caption.insertFirst(icon.getElement());
+                }
+                icon.setUri(iconUrl);
+            } else if (icon != null) {
+                icon.getElement().removeFromParent();
+                icon = null;
+            }
+
+            // Required
+            if (required) {
+                if (requiredIcon == null) {
+                    requiredIcon = DOM.createSpan();
+                    // TODO decide something better (e.g. use CSS to insert the
+                    // character)
+                    requiredIcon.setInnerHTML("*");
+                    requiredIcon.setClassName("v-required-field-indicator");
+                }
+                caption.appendChild(requiredIcon);
+            } else if (requiredIcon != null) {
+                requiredIcon.removeFromParent();
+                requiredIcon = null;
+            }
+
+            // Error
+            if (error != null && showError) {
+                if (errorIcon == null) {
+                    errorIcon = DOM.createSpan();
+                    errorIcon.setClassName("v-errorindicator");
+                }
+                caption.appendChild(errorIcon);
+            } else if (errorIcon != null) {
+                errorIcon.removeFromParent();
+                errorIcon = null;
+            }
+
+            if (caption != null) {
+                // Styles
+                caption.setClassName("v-caption");
+
+                if (styles != null) {
+                    for (String style : styles) {
+                        caption.addClassName("v-caption-" + style);
+                    }
+                }
+
+                if (enabled) {
+                    caption.removeClassName("v-disabled");
+                } else {
+                    caption.addClassName("v-disabled");
+                }
+
+                // Caption position
+                if (captionText != null || iconUrl != null) {
+                    setCaptionPosition(CaptionPosition.TOP);
+                } else {
+                    setCaptionPosition(CaptionPosition.RIGHT);
+                }
+            }
+        }
+
+        /**
+         * Does the slot have a caption
+         */
+        public boolean hasCaption() {
+            return caption != null;
+        }
+
+        /**
+         * Get the slots caption element
+         */
+        public Element getCaptionElement() {
+            return caption;
+        }
+
+        /**
+         * Set if the slot has a relative width
+         * 
+         * @param relativeWidth
+         *            True if slot uses relative width, false if the slot has a
+         *            static width
+         */
+        private boolean relativeWidth = false;
+        protected void setRelativeWidth(boolean relativeWidth) {
+            this.relativeWidth = relativeWidth;
+            updateRelativeSize(relativeWidth, "width");
+        }
+
+        /**
+         * Set if the slot has a relative height
+         * 
+         * @param relativeHeight
+         *            Trie if the slot uses a relative height, false if the slot
+         *            has a static height
+         */
+        private boolean relativeHeight = false;
+        protected void setRelativeHeight(boolean relativeHeight) {
+            this.relativeHeight = relativeHeight;
+            updateRelativeSize(relativeHeight, "height");
+        }
+
+        /**
+         * Updates the captions size if the slot is relative
+         * 
+         * @param isRelativeSize
+         *            Is the slot relatived sized
+         * @param direction
+         *            The directorion of the caption
+         */
+        private void updateRelativeSize(boolean isRelativeSize, String direction) {
+            if (isRelativeSize && hasCaption()) {
+                captionWrap.getStyle().setProperty(
+                        direction,
+                        getWidget().getElement().getStyle()
+                        .getProperty(direction));
+                captionWrap.addClassName("v-has-" + direction);
+            } else if (hasCaption()) {
+                if (direction.equals("height")) {
+                    captionWrap.getStyle().clearHeight();
+                } else {
+                    captionWrap.getStyle().clearWidth();
+                }
+                captionWrap.removeClassName("v-has-" + direction);
+                captionWrap.getStyle().clearPaddingTop();
+                captionWrap.getStyle().clearPaddingRight();
+                captionWrap.getStyle().clearPaddingBottom();
+                captionWrap.getStyle().clearPaddingLeft();
+                caption.getStyle().clearMarginTop();
+                caption.getStyle().clearMarginRight();
+                caption.getStyle().clearMarginBottom();
+                caption.getStyle().clearMarginLeft();
+            }
+        }
+
+        /*
+         * (non-Javadoc)
+         * 
+         * @see
+         * com.google.gwt.user.client.ui.Widget#onBrowserEvent(com.google.gwt
+         * .user.client.Event)
+         */
+        @Override
+        public void onBrowserEvent(Event event) {
+            super.onBrowserEvent(event);
+            if (DOM.eventGetType(event) == Event.ONLOAD
+                    && icon.getElement() == DOM.eventGetTarget(event)) {
+                if (layout.getLayoutManager() != null) {
+                    layout.getLayoutManager().layoutLater();
+                } else {
+                    layout.updateCaptionOffset(caption);
+                }
+            }
+        }
+
+        /*
+         * (non-Javadoc)
+         * 
+         * @see com.google.gwt.user.client.ui.SimplePanel#getContainerElement()
+         */
+        @Override
+        protected Element getContainerElement() {
+            if (captionWrap == null) {
+                return getElement();
+            } else {
+                return captionWrap;
+            }
+        }
+
+        /*
+         * (non-Javadoc)
+         * 
+         * @see com.google.gwt.user.client.ui.Widget#onDetach()
+         */
+        @Override
+        protected void onDetach() {
+            if (spacer != null) {
+                spacer.removeFromParent();
+            }
+            super.onDetach();
+        }
+
+        /*
+         * (non-Javadoc)
+         * 
+         * @see com.google.gwt.user.client.ui.Widget#onAttach()
+         */
+        @Override
+        protected void onAttach() {
+            super.onAttach();
+            if (spacer != null) {
+                getElement().getParentElement().insertBefore(spacer,
+                        getElement());
+            }
+        }
+    }
+
+    /**
+     * The icon for each widget. Located in the caption of the slot.
+     */
+    public static class Icon extends UIObject {
+
+        public static final String CLASSNAME = "v-icon";
+
+        private String myUrl;
+
+        /**
+         * Constructor
+         */
+        public Icon() {
+            setElement(DOM.createImg());
+            DOM.setElementProperty(getElement(), "alt", "");
+            setStyleName(CLASSNAME);
+        }
+
+        /**
+         * Set the URL where the icon is located
+         * 
+         * @param url
+         *            A fully qualified URL
+         */
+        public void setUri(String url) {
+            if (!url.equals(myUrl)) {
+                /*
+                 * Start sinking onload events, widgets responsibility to react.
+                 * We must do this BEFORE we set src as IE fires the event
+                 * immediately if the image is found in cache (#2592).
+                 */
+                sinkEvents(Event.ONLOAD);
+
+                DOM.setElementProperty(getElement(), "src", url);
+                myUrl = url;
+            }
+        }
+    }
+
+    /**
+     * Set the layout manager for the layout
+     * 
+     * @param manager
+     *            The layout manager to use
+     */
+    public void setLayoutManager(LayoutManager manager) {
+        layoutManager = manager;
+    }
+    
+    /**
+     * Get the layout manager used by this layout
+     * 
+     */
+    public LayoutManager getLayoutManager() {
+        return layoutManager;
+    }
+
+    /**
+     * Deducts the caption position by examining the wrapping element
+     * 
+     * @param captionWrap
+     *            The wrapping element
+     * 
+     * @return The caption position
+     */
+    CaptionPosition getCaptionPositionFromElement(Element captionWrap) {
+        RegExp captionPositionRegexp = RegExp.compile("v-caption-on-(\\S+)");
+
+        // Get caption position from the classname
+        MatchResult matcher = captionPositionRegexp.exec(captionWrap
+                .getClassName());
+        if (matcher == null || matcher.getGroupCount() < 2) {
+            return CaptionPosition.TOP;
+        }
+        String captionClass = matcher.getGroup(1);
+        CaptionPosition captionPosition = CaptionPosition.valueOf(
+                CaptionPosition.class, captionClass.toUpperCase());
+        return captionPosition;
+    }
+
+    /**
+     * Update the offset off the caption relative to the slot
+     * 
+     * @param caption
+     *            The caption element
+     */
+    void updateCaptionOffset(Element caption) {
+
+        Element captionWrap = caption.getParentElement().cast();
+
+        Style captionWrapStyle = captionWrap.getStyle();
+        captionWrapStyle.clearPaddingTop();
+        captionWrapStyle.clearPaddingRight();
+        captionWrapStyle.clearPaddingBottom();
+        captionWrapStyle.clearPaddingLeft();
+
+        Style captionStyle = caption.getStyle();
+        captionStyle.clearMarginTop();
+        captionStyle.clearMarginRight();
+        captionStyle.clearMarginBottom();
+        captionStyle.clearMarginLeft();
+
+        // Get caption position from the classname
+        CaptionPosition captionPosition = getCaptionPositionFromElement(captionWrap);
+
+        if (captionPosition == CaptionPosition.LEFT
+                || captionPosition == CaptionPosition.RIGHT) {
+            int captionWidth;
+            if (layoutManager != null) {
+                captionWidth = layoutManager.getOuterWidth(caption)
+                        - layoutManager.getMarginWidth(caption);
+            } else {
+                captionWidth = caption.getOffsetWidth();
+            }
+            if (captionWidth > 0) {
+                if (captionPosition == CaptionPosition.LEFT) {
+                    captionWrapStyle.setPaddingLeft(captionWidth, Unit.PX);
+                    captionStyle.setMarginLeft(-captionWidth, Unit.PX);
+                } else {
+                    captionWrapStyle.setPaddingRight(captionWidth, Unit.PX);
+                    captionStyle.setMarginRight(-captionWidth, Unit.PX);
+                }
+            }
+        }
+        if (captionPosition == CaptionPosition.TOP
+                || captionPosition == CaptionPosition.BOTTOM) {
+            int captionHeight;
+            if (layoutManager != null) {
+                captionHeight = layoutManager.getOuterHeight(caption)
+                        - layoutManager.getMarginHeight(caption);
+            } else {
+                captionHeight = caption.getOffsetHeight();
+            }
+            if (captionHeight > 0) {
+                if (captionPosition == CaptionPosition.TOP) {
+                    captionWrapStyle.setPaddingTop(captionHeight, Unit.PX);
+                    captionStyle.setMarginTop(-captionHeight, Unit.PX);
+                } else {
+                    captionWrapStyle.setPaddingBottom(captionHeight, Unit.PX);
+                    captionStyle.setMarginBottom(-captionHeight, Unit.PX);
+                }
+            }
+        }
+    }
+
+    /**
+     * Set the margin of the layout
+     * 
+     * @param marginInfo
+     *            The margin information
+     */
+    public void setMargin(MarginInfo marginInfo) {
+        if (marginInfo != null) {
+            setStyleName("v-margin-top", marginInfo.hasTop());
+            setStyleName("v-margin-right", marginInfo.hasRight());
+            setStyleName("v-margin-bottom", marginInfo.hasBottom());
+            setStyleName("v-margin-left", marginInfo.hasLeft());
+        }
+    }
+
+    /**
+     * Turn on or off spacing in the layout
+     * 
+     * @param spacing
+     *            True if spacing should be used, false if not
+     */
+    public void setSpacing(boolean spacing) {
+        this.spacing = spacing;
+        for (Slot slot : widgetToSlot.values()) {
+            if (getWidgetIndex(slot) > 0) {
+                slot.setSpacing(spacing);
+            }
+        }
+    }
+
+    /**
+     * Triggers a recalculation of the expand width and heights
+     */
+    private void recalculateExpands() {
+        double total = 0;
+        for (Slot slot : widgetToSlot.values()) {
+            if (slot.getExpandRatio() > -1) {
+                total += slot.getExpandRatio();
+            } else {
+                if (vertical) {
+                    slot.getElement().getStyle().clearHeight();
+                } else {
+                    slot.getElement().getStyle().clearWidth();
+                }
+            }
+        }
+        for (Slot slot : widgetToSlot.values()) {
+            if (slot.getExpandRatio() > -1) {
+                if (vertical) {
+                    slot.setHeight((100 * (slot.getExpandRatio() / total))
+                            + "%");
+                    if (slot.relativeHeight) {
+                        Util.notifyParentOfSizeChange(this, true);
+                    }
+                } else {
+                    slot.setWidth((100 * (slot.getExpandRatio() / total)) + "%");
+                    if (slot.relativeWidth) {
+                        Util.notifyParentOfSizeChange(this, true);
+                    }
+                }
+            }
+        }
+    }
+
+    /**
+     * Removes elements used to expand a slot
+     */
+    void clearExpand() {
+        if (expandWrapper != null) {
+            for (; expandWrapper.getChildCount() > 0;) {
+                Element el = expandWrapper.getChild(0).cast();
+                getElement().appendChild(el);
+                if (vertical) {
+                    el.getStyle().clearHeight();
+                    el.getStyle().clearMarginTop();
+                } else {
+                    el.getStyle().clearWidth();
+                    el.getStyle().clearMarginLeft();
+                }
+            }
+            expandWrapper.removeFromParent();
+            expandWrapper = null;
+        }
+    }
+
+    /**
+     * Adds elements used to expand a slot
+     */
+    public void updateExpand() {
+        boolean isExpanding = false;
+        for (Widget slot : getChildren()) {
+            if (((Slot) slot).getExpandRatio() > -1) {
+                isExpanding = true;
+            } else {
+                if (vertical) {
+                    slot.getElement().getStyle().clearHeight();
+                } else {
+                    slot.getElement().getStyle().clearWidth();
+                }
+            }
+            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 (layoutManager != null) {
+                        // TODO check caption position
+                        if (vertical) {
+                            int size = layoutManager.getOuterHeight(slot
+                                    .getWidget().getElement())
+                                    - layoutManager.getMarginHeight(slot
+                                            .getWidget().getElement());
+                            if (slot.hasCaption()) {
+                                size += layoutManager.getOuterHeight(slot
+                                        .getCaptionElement())
+                                        - layoutManager.getMarginHeight(slot
+                                                .getCaptionElement());
+                            }
+                            if (size > 0) {
+                                totalSize += size;
+                            }
+                        } else {
+                            int max = -1;
+                            max = layoutManager.getOuterWidth(slot.getWidget()
+                                    .getElement())
+                                    - layoutManager.getMarginWidth(slot
+                                            .getWidget().getElement());
+                            if (slot.hasCaption()) {
+                                int max2 = layoutManager.getOuterWidth(slot
+                                        .getCaptionElement())
+                                        - layoutManager.getMarginWidth(slot
+                                                .getCaptionElement());
+                                max = Math.max(max, max2);
+                            }
+                            if (max > 0) {
+                                totalSize += max;
+                            }
+                        }
+                    } else {
+                        totalSize += vertical ? slot.getOffsetHeight() : slot
+                                .getOffsetWidth();
+                    }
+                }
+                // TODO fails in Opera, always returns 0
+                int spacingSize = vertical ? slot.getVerticalSpacing() : slot
+                        .getHorizontalSpacing();
+                if (spacingSize > 0) {
+                    totalSize += spacingSize;
+                }
+            }
+
+            // When we set the margin to the first child, we don't need
+            // overflow:hidden in the layout root element, since the wrapper
+            // would otherwise be placed outside of the layout root element
+            // and block events on elements below it.
+            if (vertical) {
+                expandWrapper.getStyle().setPaddingTop(totalSize, Unit.PX);
+                expandWrapper.getFirstChildElement().getStyle()
+                .setMarginTop(-totalSize, Unit.PX);
+            } else {
+                expandWrapper.getStyle().setPaddingLeft(totalSize, Unit.PX);
+                expandWrapper.getFirstChildElement().getStyle()
+                .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();
+            }
+            VOrderedLayout.this.getElement().getStyle()
+            .setHeight(newHeight, Unit.PX);
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void setHeight(String height) {
+        super.setHeight(height);
+        definedHeight = (height != null && !"".equals(height));
+    }
+}
index 76e5910bedbbb73f00417b1b57ddaa190a3a006c..3e597afec1fa9a63ff59dc391fc4b6bb787a922e 100644 (file)
  */
 package com.vaadin.client.ui.orderedlayout;
 
-public class VVerticalLayout extends VMeasuringOrderedLayout {
-
-    public static final String CLASSNAME = "v-verticallayout";
+/**
+ * Represents a layout where the children is ordered vertically
+ */
+public class VVerticalLayout extends VOrderedLayout {
 
+    /**
+     * Default constructor
+     */
     public VVerticalLayout() {
-        super(CLASSNAME, true);
+        setVertical(true);
     }
-
 }
diff --git a/client/src/com/vaadin/client/ui/orderedlayout/VerticalBoxLayoutConnector.java b/client/src/com/vaadin/client/ui/orderedlayout/VerticalBoxLayoutConnector.java
deleted file mode 100644 (file)
index 5d1e1d9..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-/* 
-@VaadinApache2LicenseForJavaFiles@
- */
-package com.vaadin.client.ui.orderedlayout;
-
-import com.vaadin.shared.ui.Connect;
-import com.vaadin.shared.ui.Connect.LoadStyle;
-import com.vaadin.ui.VerticalLayout;
-
-@Connect(value = VerticalLayout.class, loadStyle = LoadStyle.EAGER)
-public class VerticalBoxLayoutConnector extends AbstractBoxLayoutConnector {
-
-    @Override
-    public void init() {
-        super.init();
-        getWidget().setVertical(true);
-    }
-
-}
index 455c645144291b0356305d219e488e4c195998fb..13e9b3ecf786c96d52b7ce3e973e3413a68d08ce 100644 (file)
  */
 package com.vaadin.client.ui.orderedlayout;
 
+import com.vaadin.shared.ui.Connect;
+import com.vaadin.shared.ui.Connect.LoadStyle;
+import com.vaadin.ui.VerticalLayout;
 
-//@Connect(value = VerticalLayout.class, loadStyle = LoadStyle.EAGER)
+/**
+ * Connects the client widget {@link VVerticalLayout} with the Vaadin server
+ * side counterpart {@link VerticalLayout}
+ */
+@Connect(value = VerticalLayout.class, loadStyle = LoadStyle.EAGER)
 public class VerticalLayoutConnector extends AbstractOrderedLayoutConnector {
 
+    /*
+     * (non-Javadoc)
+     * 
+     * @see
+     * com.vaadin.client.ui.orderedlayout.AbstractOrderedLayoutConnector#getWidget
+     * ()
+     */
     @Override
     public VVerticalLayout getWidget() {
         return (VVerticalLayout) super.getWidget();