import com.google.gwt.user.client.Element;
import com.google.gwt.user.client.ui.Widget;
import com.vaadin.terminal.gwt.client.AbstractFieldState;
-import com.vaadin.terminal.gwt.client.ApplicationConnection;
import com.vaadin.terminal.gwt.client.ComponentConnector;
import com.vaadin.terminal.gwt.client.ConnectorHierarchyChangeEvent;
-import com.vaadin.terminal.gwt.client.Paintable;
-import com.vaadin.terminal.gwt.client.UIDL;
import com.vaadin.terminal.gwt.client.Util;
-import com.vaadin.terminal.gwt.client.ValueMap;
import com.vaadin.terminal.gwt.client.communication.RpcProxy;
import com.vaadin.terminal.gwt.client.communication.StateChangeEvent;
import com.vaadin.terminal.gwt.client.communication.StateChangeEvent.StateChangeHandler;
import com.vaadin.terminal.gwt.client.ui.orderedlayout.AbstractOrderedLayoutState;
public abstract class AbstractBoxLayoutConnector extends
- AbstractLayoutConnector implements Paintable, /* PreLayoutListener, */
-PostLayoutListener {
+ AbstractLayoutConnector /* implements PostLayoutListener */{
AbstractOrderedLayoutServerRpc rpc;
*/
private HashMap<Element, Integer> childCaptionElementHeight = new HashMap<Element, Integer>();
- // For debugging
- private static int resizeCount = 0;
-
- public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
- if (!isRealUpdate(uidl)) {
- return;
- }
-
- clickEventHandler.handleEventHandlerRegistration();
-
- VBoxLayout layout = getWidget();
-
- ValueMap expandRatios = uidl.getMapAttribute("expandRatios");
- ValueMap alignments = uidl.getMapAttribute("alignments");
-
- for (ComponentConnector child : getChildren()) {
- Slot slot = layout.getSlot(child);
- String pid = child.getConnectorId();
-
- AlignmentInfo alignment;
- if (alignments.containsKey(pid)) {
- alignment = new AlignmentInfo(alignments.getInt(pid));
- if (alignment.isVerticalCenter() || alignment.isBottom()) {
- hasVerticalAlignment.add(child);
- } else {
- hasVerticalAlignment.remove(child);
- }
- } else {
- alignment = AlignmentInfo.TOP_LEFT;
- hasVerticalAlignment.remove(child);
- }
- slot.setAlignment(alignment);
-
- double expandRatio;
- // TODO discuss the layout specs, is this what we want: distribute
- // extra space equally if no expand ratios are specified inside a
- // layout with specified size
- if (expandRatios.getKeySet().size() == 0
- && ((getWidget().vertical && !isUndefinedHeight()) || (!getWidget().vertical && !isUndefinedWidth()))) {
- expandRatio = 1;
- hasExpandRatio.add(child);
- } else if (expandRatios.containsKey(pid)
- && expandRatios.getRawNumber(pid) > 0) {
- expandRatio = expandRatios.getRawNumber(pid);
- hasExpandRatio.add(child);
- } else {
- expandRatio = -1;
- hasExpandRatio.remove(child);
- if (expandRatios.getKeySet().size() > 0
- || hasExpandRatio.size() > 0) {
- // Only add resize listeners if there are expand ratios in
- // use
- getLayoutManager().addElementResizeListener(
- child.getWidget().getElement(),
- childComponentResizeListener);
- if (slot.hasCaption()) {
- getLayoutManager().addElementResizeListener(
- slot.getCaptionElement(),
- slotCaptionResizeListener);
- }
- }
- }
- slot.setExpandRatio(expandRatio);
-
- // TODO only needed if expand ratios are used
- if (slot.getSpacingElement() != null) {
- getLayoutManager().addElementResizeListener(
- slot.getSpacingElement(), spacingResizeListener);
- } else if (slot.getSpacingElement() != null) {
- getLayoutManager().removeElementResizeListener(
- slot.getSpacingElement(), spacingResizeListener);
- }
-
- }
-
- if (needsFixedHeight()) {
- for (ComponentConnector child : getChildren()) {
- Slot slot = layout.getSlot(child);
- getLayoutManager().addElementResizeListener(
- child.getWidget().getElement(),
- childComponentResizeListener);
- if (slot.hasCaption()) {
- getLayoutManager()
- .addElementResizeListener(slot.getCaptionElement(),
- slotCaptionResizeListener);
- }
- }
- }
-
- if (needsExpand()) {
- updateExpand();
- } else {
- getWidget().clearExpand();
- }
-
- }
-
public void updateCaption(ComponentConnector child) {
Slot slot = getWidget().getSlot(child);
getWidget().updateCaptionOffset(slot.getCaptionElement());
}
} else {
- // getLayoutManager().removeElementResizeListener(
- // slot.getCaptionElement(), slotCaptionResizeListener);
- }
-
- if (!slot.hasCaption()) {
childCaptionElementHeight.remove(child.getWidget().getElement());
}
- if (needsFixedHeight()) {
- getWidget().clearHeight();
- getLayoutManager().setNeedsMeasure(this);
- }
-
updateLayoutHeight();
if (needsExpand()) {
VBoxLayout layout = getWidget();
for (ComponentConnector child : getChildren()) {
- Widget childWidget = child.getWidget();
Slot slot = layout.getSlot(child);
if (slot.getParent() != layout) {
child.addStateChangeHandler(childStateChangeHandler);
}
}
+ // If some component is added/removed, we need to recalculate the expand
if (needsExpand()) {
- getWidget().updateExpand();
+ updateExpand();
} else {
getWidget().clearExpand();
}
public void onStateChanged(StateChangeEvent stateChangeEvent) {
super.onStateChanged(stateChangeEvent);
+ clickEventHandler.handleEventHandlerRegistration();
+
getWidget().setMargin(new VMarginInfo(getState().getMarginsBitmask()));
getWidget().setSpacing(getState().isSpacing());
- if (needsFixedHeight()) {
- getWidget().clearHeight();
- setLayoutHeightListener(true);
- getLayoutManager().setNeedsMeasure(this);
- } else {
- setLayoutHeightListener(false);
+ hasExpandRatio.clear();
+ hasVerticalAlignment.clear();
+ hasRelativeHeight.clear();
+ needsMeasure.clear();
+
+ for (ComponentConnector child : getChildren()) {
+ Slot slot = getWidget().getSlot(child);
+
+ AlignmentInfo alignment = new AlignmentInfo(getState()
+ .getChildData().get(child).getAlignmentBitmask());
+ slot.setAlignment(alignment);
+
+ double expandRatio = getState().getChildData().get(child)
+ .getExpandRatio();
+ 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());
+ }
}
- // TODO recognize special cases here, using child states
+ updateAllSlotListeners();
+
+ updateLayoutHeight();
}
StateChangeHandler childStateChangeHandler = new StateChangeHandler() {
public void onStateChanged(StateChangeEvent stateChangeEvent) {
+
ComponentConnector child = (ComponentConnector) stateChangeEvent
.getConnector();
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());
- }
- }
-
- // TODO 'needsExpand' might return false during the first render,
- // since updateFromUidl is called last
-
- // If the slot has caption, we need to listen for it's size changes
- // in order to update the padding/margin offset for relative sized
- // components
- if ((child.isRelativeHeight() || needsFixedHeight())
- && slot.hasCaption()) {
- getLayoutManager().addElementResizeListener(
- slot.getCaptionElement(), slotCaptionResizeListener);
- } else if (!needsExpand()) {
- // TODO recheck if removing the listener here breaks anything.
- // Should be cleaned up.
- // getLayoutManager().removeElementResizeListener(
- // slot.getCaptionElement(), slotCaptionResizeListener);
- }
-
- if (slot.getSpacingElement() != null && needsExpand()) {
- // Spacing is on
- getLayoutManager().addElementResizeListener(
- slot.getSpacingElement(), spacingResizeListener);
- } else if (slot.getSpacingElement() != null) {
- getLayoutManager().removeElementResizeListener(
- slot.getSpacingElement(), spacingResizeListener);
- }
-
- if (child.isRelativeHeight()) {
- hasRelativeHeight.add(child);
- needsMeasure.remove(child.getWidget().getElement());
- } else {
- hasRelativeHeight.remove(child);
- needsMeasure.add(child.getWidget().getElement());
- }
-
- if (needsFixedHeight()) {
- getLayoutManager().addElementResizeListener(
- child.getWidget().getElement(),
- childComponentResizeListener);
- } else if (!needsExpand()) {
- getLayoutManager().removeElementResizeListener(
- child.getWidget().getElement(),
- childComponentResizeListener);
- }
-
- if (needsFixedHeight()) {
- getWidget().clearHeight();
- setLayoutHeightListener(true);
- getLayoutManager().setNeedsMeasure(
- AbstractBoxLayoutConnector.this);
- } else {
- setLayoutHeightListener(false);
- }
+ // 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);
}
};
private boolean needsFixedHeight() {
- if (!getWidget().vertical
- && isUndefinedHeight()
- && (hasRelativeHeight.size() > 0 || hasVerticalAlignment.size() > 0)) {
+ if (!getWidget().vertical && isUndefinedHeight()
+ && (hasRelativeHeight.size() > 0 /*
+ * ||
+ * hasVerticalAlignment.size()
+ * > 0
+ */)) {
return true;
}
return false;
return hasExpandRatio.size() > 0 && canApplyExpand;
}
- // public void preLayout() {
- // resizeCount = 0;
- // }
+ private void updateAllSlotListeners() {
+ for (ComponentConnector child : getChildren()) {
+ updateSlotListeners(child);
+ }
+ // if (needsFixedHeight()) {
+ // getWidget().clearHeight();
+ // setLayoutHeightListener(true);
+ // getLayoutManager().setNeedsMeasure(AbstractBoxLayoutConnector.this);
+ // } else {
+ // setLayoutHeightListener(false);
+ // }
+ }
- public void postLayout() {
- if (needsFixedHeight()) {
- // Re-measure all elements that are available
- for (Element el : needsMeasure) {
- childElementHeight.put(el, getLayoutManager()
- .getOuterHeight(el));
+ /**
+ * 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);
- Element captionElement = el.getParentElement()
- .getFirstChildElement().cast();
- if (captionElement.getClassName().contains("v-caption")) {
- childCaptionElementHeight.put(el, getLayoutManager()
- .getOuterHeight(captionElement));
- }
+ // 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);
}
- System.out.println(" ### Child sizes: "
- + childElementHeight.values().toString());
- System.out.println(" ### Caption sizes: "
- + childCaptionElementHeight.values().toString());
-
- // If no height has been set, use the natural height for the
- // component (this is mostly just a precaution so that something
- // renders correctly)
- // String h = getWidget().getElement().getStyle().getHeight();
- // if (h == null || h.equals("")) {
- // int height = getLayoutManager().getOuterHeight(
- // getWidget().getElement())
- // - getLayoutManager().getMarginHeight(
- // getWidget().getElement());
- int height = getMaxHeight()
- + getLayoutManager().getBorderHeight(
- getWidget().getElement())
- + getLayoutManager().getPaddingHeight(
- getWidget().getElement());
- getWidget().getElement().getStyle().setHeight(height, Unit.PX);
- // }
+ } 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);
}
- // System.err.println("Element resize listeners fired for " +
- // resizeCount
- // + " times");
- }
- private ElementResizeListener layoutResizeListener = new ElementResizeListener() {
- public void onElementResize(ElementResizeEvent e) {
- resizeCount++;
- updateLayoutHeight();
- if (needsExpand() && (isUndefinedHeight() || isUndefinedWidth())) {
- updateExpand();
+ 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() {
public void onElementResize(ElementResizeEvent e) {
- resizeCount++;
+ // 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
- getLayoutManager().removeElementResizeListener(captionElement,
- slotCaptionResizeListener);
+ dontListen(captionElement, slotCaptionResizeListener);
childCaptionElementHeight.remove(widgetElement);
return;
}
int h = getLayoutManager().getOuterHeight(captionElement)
- getLayoutManager().getMarginHeight(captionElement);
childCaptionElementHeight.put(widgetElement, h);
- // System.out.println("Caption size: " + h);
- if (needsFixedHeight()) {
- getWidget().clearHeight();
- getLayoutManager().setNeedsMeasure(
- AbstractBoxLayoutConnector.this);
- }
+ // if (needsFixedHeight()) {
+ // getWidget().clearHeight();
+ // getLayoutManager().setNeedsMeasure(
+ // AbstractBoxLayoutConnector.this);
+ // }
updateLayoutHeight();
private ElementResizeListener childComponentResizeListener = new ElementResizeListener() {
public void onElementResize(ElementResizeEvent e) {
- resizeCount++;
int h = getLayoutManager().getOuterHeight(e.getElement());
childElementHeight.put((Element) e.getElement().cast(), h);
updateLayoutHeight();
private ElementResizeListener spacingResizeListener = new ElementResizeListener() {
public void onElementResize(ElementResizeEvent e) {
- resizeCount++;
if (needsExpand()) {
updateExpand();
}
}
private int getMaxHeight() {
+ // TODO should use layout manager instead of inner lists of element
+ // sizes
int highestNonRelative = -1;
int highestRelative = -1;
+ // System.out.println("Child sizes: "
+ // + childElementHeight.values().toString());
for (Element el : childElementHeight.keySet()) {
// TODO would be more efficient to measure the slot element if both
// caption and child widget elements need to be measured. Keeping
public void onUnregister() {
// Cleanup all ElementResizeListeners
- getLayoutManager().removeElementResizeListener(
- getWidget().getElement(), layoutResizeListener);
-
- for (int i = 0; i < getWidget().getWidgetCount(); i++) {
- // TODO unsafe
- Slot slot = (Slot) getWidget().getWidget(i);
+ // dontListen(getWidget().getElement(), layoutResizeListener);
+ for (ComponentConnector child : getChildren()) {
+ Slot slot = getWidget().getSlot(child);
if (slot.hasCaption()) {
- getLayoutManager().removeElementResizeListener(
- slot.getCaptionElement(), slotCaptionResizeListener);
+ dontListen(slot.getCaptionElement(), slotCaptionResizeListener);
}
if (slot.getSpacingElement() != null) {
- getLayoutManager().removeElementResizeListener(
- slot.getSpacingElement(), spacingResizeListener);
+ dontListen(slot.getSpacingElement(), spacingResizeListener);
}
- getLayoutManager()
- .removeElementResizeListener(slot.getWidget().getElement(),
- childComponentResizeListener);
-
+ dontListen(slot.getWidget().getElement(),
+ childComponentResizeListener);
}
super.onUnregister();
}
- private void setLayoutHeightListener(boolean add) {
- if (add) {
- getLayoutManager().addElementResizeListener(
- getWidget().getElement(), layoutResizeListener);
- } else {
- getLayoutManager().removeElementResizeListener(
- getWidget().getElement(), layoutResizeListener);
- if (!needsExpand()) {
- childElementHeight.clear();
- childCaptionElementHeight.clear();
- }
- }
+ // 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);
}
}