import java.util.Map;
import java.util.Set;
+import com.google.gwt.core.client.Duration;
import com.google.gwt.core.client.GWT;
import com.google.gwt.core.client.JavaScriptObject;
import com.google.gwt.core.client.JsArray;
import com.google.gwt.core.client.JsArrayString;
import com.google.gwt.core.client.Scheduler;
+import com.google.gwt.core.client.Scheduler.ScheduledCommand;
+import com.google.gwt.dom.client.Style;
import com.google.gwt.http.client.Request;
import com.google.gwt.http.client.RequestBuilder;
import com.google.gwt.http.client.RequestCallback;
import com.google.gwt.user.client.ui.HasWidgets;
import com.google.gwt.user.client.ui.Widget;
import com.vaadin.terminal.gwt.client.ApplicationConfiguration.ErrorMessage;
-import com.vaadin.terminal.gwt.client.RenderInformation.Size;
import com.vaadin.terminal.gwt.client.ui.Field;
import com.vaadin.terminal.gwt.client.ui.VAbstractPaintableWidget;
import com.vaadin.terminal.gwt.client.ui.VContextMenu;
ArrayList<VPaintableWidget> updatedVPaintableWidgets = new ArrayList<VPaintableWidget>();
componentCaptionSizeChanges.clear();
+ Duration updateDuration = new Duration();
+
int length = changes.length();
for (int i = 0; i < length; i++) {
try {
json.getValueMap("dd"));
}
- // Check which widgets' size has been updated
- Set<Widget> sizeUpdatedWidgets = new HashSet<Widget>();
-
- sizeUpdatedWidgets.addAll(componentCaptionSizeChanges);
-
- for (VPaintableWidget paintable : updatedVPaintableWidgets) {
- Widget widget = paintable.getWidgetForPaintable();
- Size oldSize = paintableMap.getOffsetSize(paintable);
- Size newSize = new Size(widget.getOffsetWidth(),
- widget.getOffsetHeight());
-
- if (oldSize == null || !oldSize.equals(newSize)) {
- sizeUpdatedWidgets.add(widget);
- paintableMap.setOffsetSize(paintable, newSize);
- }
-
- }
+ VConsole.log("updateFromUidl: "
+ + updateDuration.elapsedMillis() + " ms");
- Util.componentSizeUpdated(sizeUpdatedWidgets);
+ doLayout(false);
if (meta != null) {
if (meta.containsKey("appError")) {
Widget component = paintableMap.getWidget(paintable);
+ Style style = component.getElement().getStyle();
+
+ // Dirty if either dimension changed between relative and non-relative
+ if (w.endsWith("%") != style.getWidth().endsWith("%")
+ || h.endsWith("%") != style.getHeight().endsWith("%")) {
+ MeasureManager.MeasuredSize measuredSize = getMeasuredSize(paintable);
+ if (measuredSize != null) {
+ measuredSize.setDirty(true);
+ }
+ }
+
// Set defined sizes
component.setHeight(h);
component.setWidth(w);
* development. Published to JavaScript.
*/
public void forceLayout() {
- Set<Widget> set = new HashSet<Widget>();
- for (VPaintable paintable : paintableMap.getPaintables()) {
- if (paintable instanceof VPaintableWidget) {
- set.add(((VPaintableWidget) paintable).getWidgetForPaintable());
- }
- }
- Util.componentSizeUpdated(set);
+ Duration duration = new Duration();
+
+ doLayout(false);
+
+ VConsole.log("forceLayout in " + duration.elapsedMillis() + " ms");
}
private void internalRunDescendentsLayout(HasWidgets container) {
eventIdentifier);
}
+ private boolean layoutScheduled = false;
+ private ScheduledCommand layoutCommand = new ScheduledCommand() {
+ public void execute() {
+ layoutScheduled = false;
+
+ MeasureManager.get().doLayout(ApplicationConnection.this);
+ }
+ };
+
+ public void doLayout(boolean lazy) {
+ if (!lazy) {
+ layoutCommand.execute();
+ } else if (!layoutScheduled) {
+ layoutScheduled = true;
+ Scheduler.get().scheduleDeferred(layoutCommand);
+ }
+ }
+
+ public MeasureManager.MeasuredSize getMeasuredSize(
+ VPaintableWidget paintable) {
+ return paintableMap.getMeasuredSize(paintable);
+ }
+
}
import java.util.HashMap;
import com.google.gwt.core.client.JsArrayString;
+import com.vaadin.terminal.gwt.client.MeasureManager.MeasuredSize;
import com.vaadin.terminal.gwt.client.RenderInformation.Size;
class ComponentDetail {
private TooltipInfo tooltipInfo = new TooltipInfo();
+ private MeasureManager.MeasuredSize measuredSize = new MeasureManager.MeasuredSize();
public ComponentDetail() {
}
return false;
}
+
+ public MeasureManager.MeasuredSize getMeasuredSize() {
+ return measuredSize;
+ }
}
--- /dev/null
+package com.vaadin.terminal.gwt.client;
+
+import com.google.gwt.core.client.JavaScriptObject;
+import com.google.gwt.core.client.JsArrayString;
+
+public final class FastStringSet extends JavaScriptObject {
+ protected FastStringSet() {
+ // JSO constructor
+ }
+
+ public native boolean contains(String string)
+ /*-{
+ return this.hasOwnProperty(string);
+ }-*/;
+
+ public native void add(String string)
+ /*-{
+ this[string] = true;
+ }-*/;
+
+ public native void addAll(JsArrayString array)
+ /*-{
+ for(var i = 0; i < array.length; i++) {
+ this[array[i]] = true;
+ }
+ }-*/;
+
+ public native JsArrayString dump()
+ /*-{
+ var array = [];
+ for(var string in this) {
+ array.push(string);
+ }
+ return array;
+ }-*/;
+
+ public static FastStringSet create() {
+ return JavaScriptObject.createObject().cast();
+ }
+}
\ No newline at end of file
--- /dev/null
+package com.vaadin.terminal.gwt.client;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashSet;
+
+import com.google.gwt.core.client.JsArrayString;
+import com.google.gwt.user.client.ui.HasWidgets;
+import com.google.gwt.user.client.ui.RequiresResize;
+import com.google.gwt.user.client.ui.Widget;
+import com.vaadin.terminal.gwt.client.ui.VMeasuringOrderedLayout;
+
+public class MeasureManager {
+
+ public static final class MeasuredSize {
+ private int width = -1;
+ private int height = -1;
+ private boolean isDirty = true;
+ private int captionWidth = 0;
+ private int captionHeight = 0;
+
+ public int getHeight() {
+ return height;
+ }
+
+ public int getWidth() {
+ return width;
+ }
+
+ public void setHeight(int height) {
+ if (this.height != height) {
+ isDirty = true;
+ }
+ this.height = height;
+ }
+
+ public void setWidth(int width) {
+ if (width != this.width) {
+ isDirty = true;
+ }
+ this.width = width;
+ }
+
+ public boolean isDirty() {
+ return isDirty;
+ }
+
+ public void setDirty(boolean isDirty) {
+ this.isDirty = isDirty;
+ }
+
+ public void setCaptionHeight(int captionHeight) {
+ if (captionHeight != this.captionHeight) {
+ isDirty = true;
+ }
+ this.captionHeight = captionHeight;
+ }
+
+ public void setCaptionWidth(int captionWidth) {
+ if (captionWidth != this.captionWidth) {
+ isDirty = true;
+ }
+ this.captionWidth = captionWidth;
+ }
+
+ public int getCaptionHeight() {
+ return captionHeight;
+ }
+
+ public int getCaptionWidth() {
+ return captionWidth;
+ }
+ }
+
+ private static MeasureManager instance = new MeasureManager();
+
+ public static Collection<VPaintableWidget> getChildren(
+ VPaintableWidget paintable, ApplicationConnection client) {
+ if (!(paintable instanceof Container)) {
+ return Collections.emptySet();
+ }
+ Widget widget = paintable.getWidgetForPaintable();
+ Collection<VPaintableWidget> children = new ArrayList<VPaintableWidget>();
+
+ addDescendantPaintables(widget, children, client);
+
+ return children;
+ }
+
+ private static void addDescendantPaintables(Widget widget,
+ Collection<VPaintableWidget> paintables,
+ ApplicationConnection client) {
+ if (widget instanceof HasWidgets) {
+ VPaintableMap paintableMap = client.getPaintableMap();
+ for (Widget child : (HasWidgets) widget) {
+ VPaintableWidget paintable = paintableMap.getPaintable(child);
+ if (paintable != null) {
+ paintables.add(paintable);
+ } else {
+ addDescendantPaintables(child, paintables, client);
+ }
+ }
+ }
+ }
+
+ private static VPaintableWidget getParentPaintable(
+ VPaintableWidget paintable, VPaintableMap paintableMap) {
+ Widget widget = paintable.getWidgetForPaintable();
+ while (true) {
+ widget = widget.getParent();
+ if (widget == null) {
+ return null;
+ }
+ VPaintableWidget parentPaintable = paintableMap
+ .getPaintable(widget);
+ if (parentPaintable != null) {
+ return parentPaintable;
+ }
+ // Else continue with the parent
+ }
+ }
+
+ public void doLayout(ApplicationConnection client) {
+ VPaintableMap paintableMap = client.getPaintableMap();
+ VPaintableWidget[] paintableWidgets = paintableMap
+ .getRegisteredPaintableWidgets();
+
+ int passes = 0;
+ long start = System.currentTimeMillis();
+ while (true) {
+ long passStart = System.currentTimeMillis();
+ passes++;
+ long measureStart = System.currentTimeMillis();
+ FastStringSet changedSet = findChangedWidgets(paintableWidgets,
+ paintableMap);
+ JsArrayString changed = changedSet.dump();
+ long measureEnd = System.currentTimeMillis();
+
+ VConsole.log("Measure in " + (measureEnd - measureStart) + " ms");
+
+ if (changed.length() == 0) {
+ VConsole.log("No more changes in pass " + passes);
+ break;
+ }
+
+ if (passes > 100) {
+ VConsole.log("Aborting layout");
+ break;
+ }
+
+ FastStringSet affectedContainers = FastStringSet.create();
+ for (int i = 0; i < changed.length(); i++) {
+ VPaintableWidget paintable = (VPaintableWidget) paintableMap
+ .getPaintable(changed.get(i));
+ VPaintableWidget parentPaintable = getParentPaintable(
+ paintable, paintableMap);
+ if (parentPaintable instanceof Container) {
+ affectedContainers
+ .add(paintableMap.getPid(parentPaintable));
+ }
+ }
+
+ long layoutStart = System.currentTimeMillis();
+ for (int i = 0; i < changed.length(); i++) {
+ String pid = changed.get(i);
+ VPaintableWidget paintable = (VPaintableWidget) paintableMap
+ .getPaintable(pid);
+ if (!affectedContainers.contains(pid)) {
+ Widget widget = paintable.getWidgetForPaintable();
+ if (widget instanceof RequiresResize) {
+ // TODO Do nothing here if parent instanceof
+ // ProvidesRepaint?
+ ((RequiresResize) widget).onResize();
+ }
+ }
+ }
+
+ JsArrayString affectedPids = affectedContainers.dump();
+ for (int i = 0; i < affectedPids.length(); i++) {
+ // Find all changed children
+ String containerPid = affectedPids.get(i);
+ VPaintableWidget container = (VPaintableWidget) paintableMap
+ .getPaintable(containerPid);
+ Collection<VPaintableWidget> children = getChildren(container,
+ client);
+ HashSet<Widget> changedChildren = new HashSet<Widget>();
+
+ for (VPaintableWidget child : children) {
+ if (changedSet.contains(paintableMap.getPid(child))) {
+ changedChildren.add(child.getWidgetForPaintable());
+ }
+ }
+
+ ((Container) container).requestLayout(changedChildren);
+ }
+
+ long layoutEnd = System.currentTimeMillis();
+ VConsole.log(affectedPids.length()
+ + " requestLayout invocations in "
+ + (layoutEnd - layoutStart) + "ms");
+
+ long passEnd = System.currentTimeMillis();
+ StringBuilder b = new StringBuilder();
+ b.append(changed.length());
+ b.append(" changed widgets in pass ");
+ b.append(passes);
+ b.append(" in ");
+ b.append((passEnd - passStart));
+ b.append(" ms: ");
+ if (changed.length() < 10) {
+ for (int i = 0; i < changed.length(); i++) {
+ if (i != 0) {
+ b.append(", ");
+ }
+ b.append(changed.get(i));
+ }
+ }
+ VConsole.log(b.toString());
+ }
+ long end = System.currentTimeMillis();
+ VConsole.log("Total layout time: " + (end - start) + "ms");
+ }
+
+ private FastStringSet findChangedWidgets(
+ VPaintableWidget[] paintableWidgets, VPaintableMap paintableMap) {
+
+ FastStringSet changed = FastStringSet.create();
+ for (VPaintableWidget paintableWidget : paintableWidgets) {
+ Widget widget = paintableWidget.getWidgetForPaintable();
+ if (paintableWidget instanceof VMeasuringOrderedLayout) {
+ VMeasuringOrderedLayout hasCaptions = (VMeasuringOrderedLayout) paintableWidget;
+ Collection<VCaption> childCaptions = hasCaptions
+ .getChildCaptions();
+ for (VCaption vCaption : childCaptions) {
+ VPaintableWidget captionOwner = vCaption.getOwner();
+ MeasureManager.MeasuredSize measuredSize = paintableMap
+ .getMeasuredSize(captionOwner);
+
+ int captionHeight = vCaption.getOffsetHeight();
+ int captionWidth = vCaption.getOffsetWidth();
+ if (captionHeight == 0 || captionWidth == 0) {
+ // Empty caption is probably detached
+ if (!Util.isAttachedAndDisplayed(vCaption)) {
+ // Ignore if it is detached
+ continue;
+ }
+ }
+ measuredSize.setCaptionHeight(captionHeight);
+ measuredSize.setCaptionWidth(captionWidth);
+ if (measuredSize.isDirty()) {
+ changed.add(paintableMap.getPid(captionOwner));
+ measuredSize.setDirty(false);
+ }
+ }
+ }
+
+ MeasureManager.MeasuredSize measuredSize = paintableMap
+ .getMeasuredSize(paintableWidget);
+
+ measuredSize.setWidth(widget.getOffsetWidth());
+ measuredSize.setHeight(widget.getOffsetHeight());
+
+ if (measuredSize.isDirty()) {
+ changed.add(paintableMap.getPid(paintableWidget));
+ measuredSize.setDirty(false);
+ }
+ }
+
+ return changed;
+ }
+
+ private MeasureManager() {
+ // Singleton constructor
+ }
+
+ public static MeasureManager get() {
+ return instance;
+ }
+}
package com.vaadin.terminal.gwt.client;
import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.Map;
-import java.util.Set;
+import java.util.List;
import com.google.gwt.core.client.Scheduler;
import com.google.gwt.core.client.Scheduler.ScheduledCommand;
import com.google.gwt.user.client.Element;
import com.google.gwt.user.client.Event;
import com.google.gwt.user.client.EventListener;
-import com.google.gwt.user.client.Timer;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.ui.HasWidgets;
import com.google.gwt.user.client.ui.RootPanel;
return el;
}-*/;
- private static final int LAZY_SIZE_CHANGE_TIMEOUT = 400;
- private static Set<Widget> latelyChangedWidgets = new HashSet<Widget>();
-
- private static Timer lazySizeChangeTimer = new Timer() {
- private boolean lazySizeChangeTimerScheduled = false;
-
- @Override
- public void run() {
- componentSizeUpdated(latelyChangedWidgets);
- latelyChangedWidgets.clear();
- lazySizeChangeTimerScheduled = false;
- }
-
- @Override
- public void schedule(int delayMillis) {
- if (lazySizeChangeTimerScheduled) {
- cancel();
- } else {
- lazySizeChangeTimerScheduled = true;
- }
- super.schedule(delayMillis);
- }
- };
-
/**
* This helper method can be called if components size have been changed
* outside rendering phase. It notifies components parent about the size
* run componentSizeUpdated lazyly
*/
public static void notifyParentOfSizeChange(Widget widget, boolean lazy) {
- if (lazy) {
- latelyChangedWidgets.add(widget);
- lazySizeChangeTimer.schedule(LAZY_SIZE_CHANGE_TIMEOUT);
- } else {
- Set<Widget> widgets = new HashSet<Widget>();
- widgets.add(widget);
- Util.componentSizeUpdated(widgets);
+ ApplicationConnection applicationConnection = findApplicationConnectionFor(widget);
+ if (applicationConnection != null) {
+ applicationConnection.doLayout(lazy);
}
}
- /**
- * Called when the size of one or more widgets have changed during
- * rendering. Finds parent container and notifies them of the size change.
- *
- * @param paintables
- */
- public static void componentSizeUpdated(Set<Widget> widgets) {
- if (widgets.isEmpty()) {
- return;
- }
+ private static boolean findAppConnectionWarningDisplayed = false;
- Map<Container, Set<Widget>> childWidgets = new HashMap<Container, Set<Widget>>();
+ private static ApplicationConnection findApplicationConnectionFor(
+ Widget widget) {
+ if (!findAppConnectionWarningDisplayed) {
+ findAppConnectionWarningDisplayed = true;
+ VConsole.log("Warning: Using Util.findApplicationConnectionFor which should be eliminated once there is a better way to find the ApplicationConnection for a Paintable");
+ }
- for (Widget widget : widgets) {
- if (!widget.isAttached()) {
+ List<ApplicationConnection> runningApplications = ApplicationConfiguration
+ .getRunningApplications();
+ for (ApplicationConnection applicationConnection : runningApplications) {
+ VPaintableMap paintableMap = applicationConnection
+ .getPaintableMap();
+ VPaintableWidget paintable = paintableMap.getPaintable(widget);
+ if (paintable == null) {
continue;
}
-
- // ApplicationConnection.getConsole().log(
- // "Widget " + Util.getSimpleName(widget) + " size updated");
- Widget parent = widget.getParent();
- while (parent != null && !(parent instanceof Container)) {
- parent = parent.getParent();
- }
- if (parent != null) {
- Set<Widget> set = childWidgets.get(parent);
- if (set == null) {
- set = new HashSet<Widget>();
- childWidgets.put((Container) parent, set);
+ String pid = paintableMap.getPid(paintable);
+ if (pid != null) {
+ VPaintable otherPaintable = paintableMap.getPaintable(pid);
+ if (otherPaintable == paintable) {
+ return applicationConnection;
}
- set.add(widget);
- }
- }
-
- Set<Widget> parentChanges = new HashSet<Widget>();
- for (Container parent : childWidgets.keySet()) {
- if (!parent.requestLayout(childWidgets.get(parent))) {
- parentChanges.add(parent.getWidgetForPaintable());
}
}
- componentSizeUpdated(parentChanges);
+ return null;
}
public static float parseRelativeSize(String size) {
public static void updateRelativeChildrenAndSendSizeUpdateEvent(
ApplicationConnection client, HasWidgets container, Widget widget) {
- /*
- * Relative sized children must be updated first so the component has
- * the correct outer dimensions when signaling a size change to the
- * parent.
- */
- Iterator<Widget> childIterator = container.iterator();
- while (childIterator.hasNext()) {
- Widget w = childIterator.next();
- client.handleComponentRelativeSize(w);
- }
-
- HashSet<Widget> widgets = new HashSet<Widget>();
- widgets.add(widget);
- Util.componentSizeUpdated(widgets);
+ notifyParentOfSizeChange(widget, false);
}
public static native int getRequiredWidth(
*/\r
package com.vaadin.terminal.gwt.client;\r
\r
+import java.util.ArrayList;\r
import java.util.Collection;\r
import java.util.Collections;\r
import java.util.HashMap;\r
import com.google.gwt.user.client.ui.HasWidgets;\r
import com.google.gwt.user.client.ui.Widget;\r
import com.vaadin.terminal.Paintable;\r
+import com.vaadin.terminal.gwt.client.MeasureManager.MeasuredSize;\r
import com.vaadin.terminal.gwt.client.RenderInformation.Size;\r
\r
public class VPaintableMap {\r
\r
}\r
\r
+ public VPaintableWidget[] getRegisteredPaintableWidgets() {\r
+ ArrayList<VPaintableWidget> result = new ArrayList<VPaintableWidget>();\r
+\r
+ for (VPaintable paintable : getPaintables()) {\r
+ if (paintable instanceof VPaintableWidget) {\r
+ VPaintableWidget paintableWidget = (VPaintableWidget) paintable;\r
+ if (!unregistryBag.contains(getPid(paintable))) {\r
+ result.add(paintableWidget);\r
+ }\r
+ }\r
+ }\r
+\r
+ return result.toArray(new VPaintableWidget[result.size()]);\r
+ }\r
+\r
void purgeUnregistryBag(boolean unregisterPaintables) {\r
if (unregisterPaintables) {\r
for (String pid : unregistryBag) {\r
return getPid(w) != null;\r
}\r
\r
+ /**\r
+ * FIXME: Should not be here\r
+ */\r
+ @Deprecated\r
+ public MeasuredSize getMeasuredSize(VPaintableWidget paintable) {\r
+ ComponentDetail componentDetail = getComponentDetail(paintable);\r
+ if (componentDetail == null) {\r
+ return null;\r
+ }\r
+\r
+ return componentDetail.getMeasuredSize();\r
+ }\r
+\r
}\r
*/
package com.vaadin.terminal.gwt.client.ui;
-public class VHorizontalLayout extends VOrderedLayout {
+public class VHorizontalLayout extends VMeasuringOrderedLayout {
public static final String CLASSNAME = "v-horizontallayout";
public VHorizontalLayout() {
- super(CLASSNAME, ORIENTATION_HORIZONTAL);
+ super(CLASSNAME, false);
}
}
--- /dev/null
+/*
+@VaadinApache2LicenseForJavaFiles@
+ */
+package com.vaadin.terminal.gwt.client.ui;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
+
+import com.google.gwt.dom.client.DivElement;
+import com.google.gwt.dom.client.Document;
+import com.google.gwt.dom.client.Element;
+import com.google.gwt.dom.client.Style;
+import com.google.gwt.dom.client.Style.Overflow;
+import com.google.gwt.dom.client.Style.Position;
+import com.google.gwt.dom.client.Style.Unit;
+import com.google.gwt.user.client.DOM;
+import com.google.gwt.user.client.ui.ComplexPanel;
+import com.google.gwt.user.client.ui.RequiresResize;
+import com.google.gwt.user.client.ui.Widget;
+import com.vaadin.terminal.gwt.client.ApplicationConnection;
+import com.vaadin.terminal.gwt.client.Container;
+import com.vaadin.terminal.gwt.client.MeasureManager;
+import com.vaadin.terminal.gwt.client.RenderSpace;
+import com.vaadin.terminal.gwt.client.UIDL;
+import com.vaadin.terminal.gwt.client.VCaption;
+import com.vaadin.terminal.gwt.client.VPaintableMap;
+import com.vaadin.terminal.gwt.client.VPaintableWidget;
+import com.vaadin.terminal.gwt.client.ValueMap;
+
+public class VMeasuringOrderedLayout extends ComplexPanel implements Container,
+ RequiresResize {
+
+ public static final String CLASSNAME = "v-orderedlayout";
+
+ private static final int MARGIN_SIZE = 20;
+
+ private final boolean isVertical;
+
+ private ApplicationConnection client;
+
+ private String id;
+
+ private RenderSpace space;
+
+ private ValueMap expandRatios;
+
+ private ValueMap alignments;
+
+ private Map<VPaintableWidget, VCaption> captions = new HashMap<VPaintableWidget, VCaption>();
+
+ private boolean spacing;
+
+ private VMarginInfo activeMarginsInfo;
+
+ protected VMeasuringOrderedLayout(String className, boolean isVertical) {
+ DivElement element = Document.get().createDivElement();
+ setElement(element);
+ // TODO These should actually be defined in css
+ Style style = element.getStyle();
+ style.setOverflow(Overflow.HIDDEN);
+ style.setPosition(Position.RELATIVE);
+
+ setStyleName(className);
+ this.isVertical = isVertical;
+ }
+
+ public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
+ this.client = client;
+ id = uidl.getId();
+ if (client.updateComponent(this, uidl, true)) {
+ return;
+ }
+
+ long start = System.currentTimeMillis();
+ // long childTime = 0;
+
+ HashSet<Widget> previousChildren = new HashSet<Widget>();
+ for (Widget child : this) {
+ if (!(child instanceof VCaption)) {
+ previousChildren.add(child);
+ }
+ }
+ // TODO Support reordering elements!
+ for (final Iterator<Object> it = uidl.getChildIterator(); it.hasNext();) {
+ final UIDL childUIDL = (UIDL) it.next();
+ final VPaintableWidget child = client.getPaintable(childUIDL);
+ Widget widget = child.getWidgetForPaintable();
+
+ if (widget.getParent() != this) {
+ DivElement wrapper = Document.get().createDivElement();
+ wrapper.getStyle().setPosition(Position.ABSOLUTE);
+ getElement().appendChild(wrapper);
+ add(widget, wrapper);
+ }
+
+ if (!childUIDL.getBooleanAttribute("cached")) {
+ child.updateFromUIDL(childUIDL, client);
+ client.getMeasuredSize(child).setDirty(true);
+ }
+ // TODO Update alignments and expand ratios
+
+ previousChildren.remove(widget);
+ }
+
+ for (Widget widget : previousChildren) {
+ Element wrapper = getWrapper(widget);
+ VCaption caption = captions.remove(widget);
+ if (caption != null) {
+ remove(caption);
+ }
+ remove(widget);
+ // Remove the wrapper
+ getElement().removeChild(wrapper);
+
+ client.unregisterPaintable((VPaintableWidget) widget);
+ }
+
+ int bitMask = uidl.getIntAttribute("margins");
+ if (activeMarginsInfo == null
+ || activeMarginsInfo.getBitMask() != bitMask) {
+ activeMarginsInfo = new VMarginInfo(bitMask);
+ }
+
+ spacing = uidl.getBooleanAttribute("spacing");
+ expandRatios = uidl.getMapAttribute("expandRatios");
+ alignments = uidl.getMapAttribute("alignments");
+ client.getMeasuredSize(this).setDirty(true);
+ }
+
+ private static Element getWrapper(Widget widget) {
+ return widget.getElement().getParentElement();
+ }
+
+ private void add(Widget widget, DivElement wrapper) {
+ add(widget, (com.google.gwt.user.client.Element) wrapper.cast());
+ }
+
+ public void onResize() {
+ requestLayout(Collections.<Widget> emptySet());
+ }
+
+ private static boolean isUndefinedInDirection(Widget widget,
+ boolean isVertical) {
+ String dimension = getDimensionInDirection(widget, isVertical);
+ return dimension == null || dimension.length() == 0;
+ }
+
+ private static boolean isRelativeInDirection(Widget widget,
+ boolean isVertical) {
+ String dimension = getDimensionInDirection(widget, isVertical);
+ return dimension != null && dimension.endsWith("%");
+ }
+
+ private static String getDimensionInDirection(Widget widget,
+ boolean vertical) {
+ com.google.gwt.user.client.Element element = widget.getElement();
+ Style style = element.getStyle();
+ if (vertical) {
+ return style.getHeight();
+ } else {
+ return style.getWidth();
+ }
+ }
+
+ public void replaceChildComponent(Widget oldComponent, Widget newComponent) {
+ throw new UnsupportedOperationException();
+ }
+
+ public boolean hasChildComponent(Widget component) {
+ return component.getParent() == this;
+ }
+
+ public void updateCaption(VPaintableWidget component, UIDL uidl) {
+ if (VCaption.isNeeded(uidl)) {
+ VCaption caption = captions.get(component);
+ if (caption == null) {
+ caption = new VCaption(component, client);
+
+ Widget widget = (Widget) component;
+ Element wrapper = getWrapper(widget);
+
+ // Logical attach.
+ getChildren().add(caption);
+
+ // Physical attach.
+ DOM.insertBefore(
+ (com.google.gwt.user.client.Element) wrapper.cast(),
+ caption.getElement(), widget.getElement());
+
+ // Adopt.
+ adopt(caption);
+ captions.put(component, caption);
+ }
+ caption.updateCaption(uidl);
+ } else {
+ VCaption removedCaption = captions.remove(component);
+ if (removedCaption != null) {
+ remove(removedCaption);
+ MeasureManager.MeasuredSize measuredSize = client
+ .getMeasuredSize(component);
+ measuredSize.setCaptionHeight(0);
+ measuredSize.setCaptionWidth(0);
+ }
+ }
+
+ }
+
+ private void layoutPrimaryDirection() {
+ Collection<VPaintableWidget> children = MeasureManager.getChildren(
+ this, client);
+
+ // First pass - get total expand ratio and allocated size
+ int totalAllocated = 0;
+ double totalExpand = 0;
+ for (VPaintableWidget child : children) {
+ Widget widget = child.getWidgetForPaintable();
+
+ totalExpand += getExpandRatio(child);
+
+ int captionAllocation;
+ if (isVertical) {
+ captionAllocation = getCaptionHeight(child);
+ getWrapper(widget).getStyle().setPaddingTop(captionAllocation,
+ Unit.PX);
+ } else {
+ captionAllocation = 0;
+ }
+
+ if (!isRelativeInDirection(widget, isVertical)) {
+ totalAllocated += getMeasuredInDirection(child, isVertical)
+ + captionAllocation;
+ }
+ }
+ int startMargin = getStartMarginInDirection(isVertical);
+ int totalMargins = startMargin + getEndMarginInDirection(isVertical);
+
+ totalAllocated += totalMargins
+ + (getSpacingInDirection(isVertical) * (children.size() - 1));
+
+ Style ownStyle = getElement().getStyle();
+ double ownSize;
+ if (isUndefinedInDirection(this, isVertical)) {
+ ownSize = totalAllocated;
+ ownStyle.setProperty(getMinPropertyName(isVertical),
+ totalAllocated, Unit.PX);
+ } else {
+ ownSize = getMeasuredInDirection(this, isVertical);
+ ownStyle.clearProperty(getMinPropertyName(isVertical));
+ }
+
+ double unallocatedSpace = Math.max(0, ownSize - totalAllocated);
+
+ double currentLocation = startMargin;
+ for (VPaintableWidget child : children) {
+ Widget widget = child.getWidgetForPaintable();
+ Element wrapper = getWrapper(widget);
+ Style wrapperStyle = wrapper.getStyle();
+
+ double childExpandRatio;
+ if (totalExpand == 0) {
+ childExpandRatio = 1d / children.size();
+ } else {
+ childExpandRatio = getExpandRatio(child) / totalExpand;
+ }
+
+ double extraPixels = unallocatedSpace * childExpandRatio;
+
+ boolean relative = isRelativeInDirection(widget, isVertical);
+
+ double size = getMeasuredInDirection(child, isVertical);
+ int captionHeight = getCaptionHeight(child);
+
+ if (isVertical) {
+ size += captionHeight;
+ } else if (!relative) {
+ size = Math.max(size, getCaptionWidth(child));
+ }
+
+ double allocatedSpace = extraPixels;
+ if (!relative) {
+ allocatedSpace += size;
+ }
+
+ int alignment = getAlignmentInDirection(getAlignment(child),
+ isVertical);
+
+ if (relative) {
+ double captionReservation = isVertical ? captionHeight : 0;
+ wrapperStyle.setProperty(getSizeProperty(isVertical),
+ allocatedSpace - captionReservation, Unit.PX);
+ } else {
+ wrapperStyle.clearProperty(getSizeProperty(isVertical));
+ }
+
+ double startPosition = currentLocation;
+ if (alignment == 0) {
+ // Centered
+ startPosition += (allocatedSpace - size) / 2;
+ } else if (alignment == 1) {
+ // Right or bottom
+ startPosition += allocatedSpace - size;
+ }
+
+ wrapperStyle.setProperty(getStartProperty(isVertical),
+ startPosition, Unit.PX);
+
+ currentLocation += allocatedSpace
+ + getSpacingInDirection(isVertical);
+ }
+ }
+
+ private int getEndMarginInDirection(boolean isVertical) {
+ if (isVertical) {
+ return activeMarginsInfo.hasBottom() ? MARGIN_SIZE : 0;
+ } else {
+ return activeMarginsInfo.hasRight() ? MARGIN_SIZE : 0;
+ }
+ }
+
+ private int getStartMarginInDirection(boolean isVertical) {
+ if (isVertical) {
+ return activeMarginsInfo.hasTop() ? MARGIN_SIZE : 0;
+ } else {
+ return activeMarginsInfo.hasLeft() ? MARGIN_SIZE : 0;
+ }
+ }
+
+ private void layoutSecondaryDirection() {
+ Collection<VPaintableWidget> children = MeasureManager.getChildren(
+ this, client);
+
+ int maxSize = 0;
+ for (VPaintableWidget child : children) {
+ Widget widget = child.getWidgetForPaintable();
+
+ int captionAllocation;
+ if (!isVertical) {
+ captionAllocation = getCaptionHeight(child);
+ getWrapper(widget).getStyle().setPaddingTop(captionAllocation,
+ Unit.PX);
+ } else {
+ captionAllocation = 0;
+ }
+
+ if (!isRelativeInDirection(widget, !isVertical)) {
+ int childSize = getMeasuredInDirection(child, !isVertical)
+ + captionAllocation;
+ maxSize = Math.max(maxSize, childSize);
+ }
+ }
+
+ int startMargin = getStartMarginInDirection(!isVertical);
+ int totalMargins = startMargin + getEndMarginInDirection(!isVertical);
+
+ double availableSpace;
+ Style ownStyle = getElement().getStyle();
+
+ if (isUndefinedInDirection(this, !isVertical)) {
+ ownStyle.setProperty(getMinPropertyName(!isVertical), maxSize
+ + totalMargins, Unit.PX);
+ availableSpace = maxSize;
+ } else {
+ ownStyle.clearProperty(getMinPropertyName(!isVertical));
+ availableSpace = getMeasuredInDirection(this, !isVertical)
+ - totalMargins;
+ }
+
+ for (VPaintableWidget child : children) {
+ Widget widget = child.getWidgetForPaintable();
+ Element wrapper = getWrapper(widget);
+ Style wrapperStyle = wrapper.getStyle();
+
+ boolean relative = isRelativeInDirection(widget, !isVertical);
+
+ int captionHeight = getCaptionHeight(child);
+
+ double allocatedSize = getMeasuredInDirection(child, !isVertical);
+ if (!isVertical) {
+ allocatedSize += captionHeight;
+ } else if (!relative) {
+ allocatedSize = Math.max(allocatedSize, getCaptionWidth(child));
+ }
+
+ int alignment = getAlignmentInDirection(getAlignment(child),
+ !isVertical);
+
+ double startPosition = startMargin;
+ if (alignment == 0) {
+ startPosition += (availableSpace - allocatedSize) / 2;
+ // Centered
+ } else if (alignment == 1) {
+ // Right or bottom
+ startPosition += (availableSpace - allocatedSize);
+ }
+
+ wrapperStyle.setProperty(getStartProperty(!isVertical),
+ startPosition, Unit.PX);
+
+ if (relative) {
+ double captionReservation = !isVertical ? captionHeight : 0;
+ wrapperStyle.setProperty(getSizeProperty(!isVertical),
+ availableSpace - captionReservation, Unit.PX);
+ } else {
+ wrapperStyle.clearProperty(getSizeProperty(!isVertical));
+ }
+ }
+ }
+
+ public boolean requestLayout(Set<Widget> changed) {
+ layoutPrimaryDirection();
+ layoutSecondaryDirection();
+
+ // Doesn't matter right now...
+ return true;
+ }
+
+ private static int getAlignmentInDirection(AlignmentInfo alignment,
+ boolean isVertical) {
+ if (alignment == null) {
+ return -1;
+ }
+ if (isVertical) {
+ if (alignment.isTop()) {
+ return -1;
+ } else if (alignment.isBottom()) {
+ return 1;
+ } else {
+ return 0;
+ }
+ } else {
+ if (alignment.isLeft()) {
+ return -1;
+ } else if (alignment.isRight()) {
+ return 1;
+ } else {
+ return 0;
+ }
+ }
+ }
+
+ private int getSpacingInDirection(boolean isVertical) {
+ if (spacing) {
+ return 20;
+ } else {
+ return 0;
+ }
+ }
+
+ private int getCaptionWidth(VPaintableWidget child) {
+ MeasureManager.MeasuredSize measuredSize = client
+ .getMeasuredSize(child);
+ return measuredSize.getCaptionWidth();
+ }
+
+ private int getCaptionHeight(VPaintableWidget child) {
+ MeasureManager.MeasuredSize measuredSize = client
+ .getMeasuredSize(child);
+ int captionHeight = measuredSize.getCaptionHeight();
+
+ VCaption caption = captions.get(child);
+ if (caption != null) {
+ caption.getElement().getStyle()
+ .setMarginTop(-captionHeight, Unit.PX);
+ }
+ return captionHeight;
+ }
+
+ private AlignmentInfo getAlignment(VPaintableWidget child) {
+ String pid = VPaintableMap.get(client).getPid(child);
+ if (alignments.containsKey(pid)) {
+ return new AlignmentInfo(alignments.getInt(pid));
+ } else {
+ return AlignmentInfo.TOP_LEFT;
+ }
+ }
+
+ private double getExpandRatio(VPaintableWidget child) {
+ String pid = VPaintableMap.get(client).getPid(child);
+ if (expandRatios.containsKey(pid)) {
+ return expandRatios.getRawNumber(pid);
+ } else {
+ return 0;
+ }
+ }
+
+ private static String getSizeProperty(boolean isVertical) {
+ return isVertical ? "height" : "width";
+ }
+
+ private static String getStartProperty(boolean isVertical) {
+ return isVertical ? "top" : "left";
+ }
+
+ private static String getMinPropertyName(boolean isVertical) {
+ return isVertical ? "minHeight" : "minWidth";
+ }
+
+ private int getMeasuredInDirection(VPaintableWidget paintable,
+ boolean isVertical) {
+ MeasureManager.MeasuredSize measuredSize = client
+ .getMeasuredSize(paintable);
+ if (isVertical) {
+ return measuredSize.getHeight();
+ } else {
+ return measuredSize.getWidth();
+ }
+ }
+
+ public Collection<VCaption> getChildCaptions() {
+ return captions.values();
+ }
+
+ public RenderSpace getAllocatedSpace(Widget child) {
+ // Concept borrowed from CSS layout
+ if (space == null) {
+ space = new RenderSpace(-1, -1) {
+ @Override
+ public int getWidth() {
+ return getOffsetWidth();
+ }
+
+ @Override
+ public int getHeight() {
+ return getOffsetHeight();
+ }
+ };
+ }
+ return space;
+ }
+
+ public Widget getWidgetForPaintable() {
+ return this;
+ }
+}
+++ /dev/null
-/*
-@VaadinApache2LicenseForJavaFiles@
- */
-package com.vaadin.terminal.gwt.client.ui;
-
-import java.util.ArrayList;
-import java.util.Iterator;
-import java.util.Set;
-
-import com.google.gwt.core.client.JsArrayString;
-import com.google.gwt.dom.client.Style.Unit;
-import com.google.gwt.event.dom.client.DomEvent.Type;
-import com.google.gwt.event.shared.EventHandler;
-import com.google.gwt.event.shared.HandlerRegistration;
-import com.google.gwt.user.client.Element;
-import com.google.gwt.user.client.ui.Widget;
-import com.vaadin.terminal.gwt.client.ApplicationConnection;
-import com.vaadin.terminal.gwt.client.BrowserInfo;
-import com.vaadin.terminal.gwt.client.EventId;
-import com.vaadin.terminal.gwt.client.RenderInformation.FloatSize;
-import com.vaadin.terminal.gwt.client.RenderInformation.Size;
-import com.vaadin.terminal.gwt.client.RenderSpace;
-import com.vaadin.terminal.gwt.client.UIDL;
-import com.vaadin.terminal.gwt.client.Util;
-import com.vaadin.terminal.gwt.client.VPaintableMap;
-import com.vaadin.terminal.gwt.client.VPaintableWidget;
-import com.vaadin.terminal.gwt.client.ValueMap;
-import com.vaadin.terminal.gwt.client.ui.layout.CellBasedLayout;
-import com.vaadin.terminal.gwt.client.ui.layout.ChildComponentContainer;
-
-public class VOrderedLayout extends CellBasedLayout {
-
- public static final String CLASSNAME = "v-orderedlayout";
-
- private int orientation;
-
- // Can be removed once OrderedLayout is removed
- private boolean allowOrientationUpdate = false;
-
- /**
- * Size of the layout excluding any margins.
- */
- private Size activeLayoutSize = new Size(0, 0);
-
- private boolean isRendering = false;
-
- private String width = "";
-
- private boolean sizeHasChangedDuringRendering = false;
-
- private ValueMap expandRatios;
-
- private double expandRatioSum;
-
- private double defaultExpandRatio;
-
- private ValueMap alignments;
-
- private LayoutClickEventHandler clickEventHandler = new LayoutClickEventHandler(
- this, EventId.LAYOUT_CLICK) {
-
- @Override
- protected VPaintableWidget getChildComponent(Element element) {
- return getComponent(element);
- }
-
- @Override
- protected <H extends EventHandler> HandlerRegistration registerHandler(
- H handler, Type<H> type) {
- return addDomHandler(handler, type);
- }
- };
-
- public VOrderedLayout() {
- this(CLASSNAME, ORIENTATION_VERTICAL);
- allowOrientationUpdate = true;
- }
-
- protected VOrderedLayout(String className, int orientation) {
- setStyleName(className);
- this.orientation = orientation;
-
- STYLENAME_SPACING = className + "-spacing";
- STYLENAME_MARGIN_TOP = className + "-margin-top";
- STYLENAME_MARGIN_RIGHT = className + "-margin-right";
- STYLENAME_MARGIN_BOTTOM = className + "-margin-bottom";
- STYLENAME_MARGIN_LEFT = className + "-margin-left";
- }
-
- @Override
- public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
- isRendering = true;
- super.updateFromUIDL(uidl, client);
-
- // Only non-cached, visible UIDL:s can introduce changes
- if (uidl.getBooleanAttribute("cached")
- || uidl.getBooleanAttribute("invisible")) {
- isRendering = false;
- return;
- }
-
- clickEventHandler.handleEventHandlerRegistration(client);
-
- if (allowOrientationUpdate) {
- handleOrientationUpdate(uidl);
- }
-
- // IStopWatch w = new IStopWatch("OrderedLayout.updateFromUIDL");
-
- ArrayList<Widget> uidlWidgets = new ArrayList<Widget>(
- uidl.getChildCount());
- ArrayList<ChildComponentContainer> relativeSizeComponents = new ArrayList<ChildComponentContainer>();
- ArrayList<UIDL> relativeSizeComponentUIDL = new ArrayList<UIDL>();
-
- int pos = 0;
- for (final Iterator<Object> it = uidl.getChildIterator(); it.hasNext();) {
- final UIDL childUIDL = (UIDL) it.next();
- final VPaintableWidget childPaintable = client
- .getPaintable(childUIDL);
- Widget widget = childPaintable.getWidgetForPaintable();
-
- // Create container for component
- ChildComponentContainer childComponentContainer = getComponentContainer(widget);
-
- if (childComponentContainer == null) {
- // This is a new component
- childComponentContainer = createChildContainer(childPaintable);
- } else {
- /*
- * The widget may be null if the same paintable has been
- * rendered in a different component container while this has
- * been invisible. Ensure the childComponentContainer has the
- * widget attached. See e.g. #5372
- */
- childComponentContainer.setPaintable(childPaintable);
- }
-
- addOrMoveChild(childComponentContainer, pos++);
-
- /*
- * Components which are to be expanded in the same orientation as
- * the layout are rendered later when it is clear how much space
- * they can use
- */
- if (!Util.isCached(childUIDL)) {
- FloatSize relativeSize = Util.parseRelativeSize(childUIDL);
- childComponentContainer.setRelativeSize(relativeSize);
- }
-
- if (childComponentContainer.isComponentRelativeSized(orientation)) {
- relativeSizeComponents.add(childComponentContainer);
- relativeSizeComponentUIDL.add(childUIDL);
- } else {
- if (isDynamicWidth()) {
- childComponentContainer.renderChild(childUIDL, client, -1);
- } else {
- childComponentContainer.renderChild(childUIDL, client,
- activeLayoutSize.getWidth());
- }
- if (sizeHasChangedDuringRendering && Util.isCached(childUIDL)) {
- // notify cached relative sized component about size
- // chance
- client.handleComponentRelativeSize(childComponentContainer
- .getWidget());
- }
- }
-
- uidlWidgets.add(widget);
-
- }
-
- // w.mark("Rendering of "
- // + (uidlWidgets.size() - relativeSizeComponents.size())
- // + " absolute size components done");
-
- /*
- * Remove any children after pos. These are the ones that previously
- * were in the layout but have now been removed
- */
- removeChildrenAfter(pos);
-
- // w.mark("Old children removed");
-
- /* Fetch alignments and expand ratio from UIDL */
- updateAlignmentsAndExpandRatios(uidl, uidlWidgets);
- // w.mark("Alignments and expand ratios updated");
-
- /* Fetch widget sizes from rendered components */
- updateWidgetSizes();
- // w.mark("Widget sizes updated");
-
- recalculateLayout();
- // w.mark("Layout size calculated (" + activeLayoutSize +
- // ") offsetSize: "
- // + getOffsetWidth() + "," + getOffsetHeight());
-
- /* Render relative size components */
- for (int i = 0; i < relativeSizeComponents.size(); i++) {
- ChildComponentContainer childComponentContainer = relativeSizeComponents
- .get(i);
- UIDL childUIDL = relativeSizeComponentUIDL.get(i);
-
- if (isDynamicWidth()) {
- childComponentContainer.renderChild(childUIDL, client, -1);
- } else {
- childComponentContainer.renderChild(childUIDL, client,
- activeLayoutSize.getWidth());
- }
-
- if (Util.isCached(childUIDL)) {
- /*
- * We must update the size of the relative sized component if
- * the expand ratio or something else in the layout changes
- * which affects the size of a relative sized component
- */
- client.handleComponentRelativeSize(childComponentContainer
- .getWidget());
- }
-
- // childComponentContainer.updateWidgetSize();
- }
-
- // w.mark("Rendering of " + (relativeSizeComponents.size())
- // + " relative size components done");
-
- /* Fetch widget sizes for relative size components */
- for (ChildComponentContainer childComponentContainer : widgetToComponentContainer
- .values()) {
-
- /* Update widget size from DOM */
- childComponentContainer.updateWidgetSize();
- }
-
- // w.mark("Widget sizes updated");
-
- /*
- * Components with relative size in main direction may affect the layout
- * size in the other direction
- */
- if ((isHorizontal() && isDynamicHeight())
- || (isVertical() && isDynamicWidth())) {
- layoutSizeMightHaveChanged();
- }
- // w.mark("Layout dimensions updated");
-
- /* Update component spacing */
- updateContainerMargins();
-
- /*
- * Update component sizes for components with relative size in non-main
- * direction
- */
- if (updateRelativeSizesInNonMainDirection()) {
- // Sizes updated - might affect the other dimension so we need to
- // recheck the widget sizes and recalculate layout dimensions
- updateWidgetSizes();
- layoutSizeMightHaveChanged();
- }
- calculateAlignments();
- // w.mark("recalculateComponentSizesAndAlignments done");
-
- setRootSize();
-
- if (BrowserInfo.get().isIE()) {
- /*
- * This should fix the issue with padding not always taken into
- * account for the containers leading to no spacing between
- * elements.
- */
- root.getStyle().setProperty("zoom", "1");
- }
-
- // w.mark("runDescendentsLayout done");
- isRendering = false;
- sizeHasChangedDuringRendering = false;
- }
-
- private void layoutSizeMightHaveChanged() {
- Size oldSize = new Size(activeLayoutSize.getWidth(),
- activeLayoutSize.getHeight());
- calculateLayoutDimensions();
-
- /*
- * If layout dimension changes we must also update container sizes
- */
- if (!oldSize.equals(activeLayoutSize)) {
- calculateContainerSize();
- }
- }
-
- private void updateWidgetSizes() {
- for (ChildComponentContainer childComponentContainer : widgetToComponentContainer
- .values()) {
-
- /*
- * Update widget size from DOM
- */
- childComponentContainer.updateWidgetSize();
- }
- }
-
- private void recalculateLayout() {
-
- /* Calculate space for relative size components */
- int spaceForExpansion = calculateLayoutDimensions();
-
- if (!widgetToComponentContainer.isEmpty()) {
- /* Divide expansion space between component containers */
- expandComponentContainers(spaceForExpansion);
-
- /* Update container sizes */
- calculateContainerSize();
- }
-
- }
-
- private void expandComponentContainers(int spaceForExpansion) {
- int remaining = spaceForExpansion;
- for (ChildComponentContainer childComponentContainer : widgetToComponentContainer
- .values()) {
- remaining -= childComponentContainer.expand(orientation,
- spaceForExpansion);
- }
-
- if (remaining > 0) {
-
- // Some left-over pixels due to rounding errors
-
- // Add one pixel to each container until there are no pixels left
- // FIXME extra pixels should be divided among expanded widgets if
- // such a widgets exists
-
- Iterator<Widget> widgetIterator = iterator();
- while (widgetIterator.hasNext() && remaining-- > 0) {
- ChildComponentContainer childComponentContainer = (ChildComponentContainer) widgetIterator
- .next();
- childComponentContainer.expandExtra(orientation, 1);
- }
- }
-
- }
-
- private void handleOrientationUpdate(UIDL uidl) {
- int newOrientation = ORIENTATION_VERTICAL;
- if ("horizontal".equals(uidl.getStringAttribute("orientation"))) {
- newOrientation = ORIENTATION_HORIZONTAL;
- }
-
- if (orientation != newOrientation) {
- orientation = newOrientation;
-
- for (ChildComponentContainer childComponentContainer : widgetToComponentContainer
- .values()) {
- childComponentContainer.setOrientation(orientation);
- }
- }
-
- }
-
- /**
- * Updated components with relative height in horizontal layouts and
- * components with relative width in vertical layouts. This is only needed
- * if the height (horizontal layout) or width (vertical layout) has not been
- * specified.
- */
- private boolean updateRelativeSizesInNonMainDirection() {
- int updateDirection = 1 - orientation;
- if ((updateDirection == ORIENTATION_HORIZONTAL && !isDynamicWidth())
- || (updateDirection == ORIENTATION_VERTICAL && !isDynamicHeight())) {
- return false;
- }
-
- boolean updated = false;
- for (ChildComponentContainer componentContainer : widgetToComponentContainer
- .values()) {
- if (componentContainer.isComponentRelativeSized(updateDirection)) {
- client.handleComponentRelativeSize(componentContainer
- .getWidget());
- }
-
- updated = true;
- }
-
- return updated;
- }
-
- private int calculateLayoutDimensions() {
- int summedWidgetWidth = 0;
- int summedWidgetHeight = 0;
-
- int maxWidgetWidth = 0;
- int maxWidgetHeight = 0;
-
- // Calculate layout dimensions from component dimensions
- for (ChildComponentContainer childComponentContainer : widgetToComponentContainer
- .values()) {
-
- int widgetHeight = 0;
- int widgetWidth = 0;
- if (childComponentContainer.isComponentRelativeSized(orientation)) {
- if (orientation == ORIENTATION_HORIZONTAL) {
- widgetHeight = getWidgetHeight(childComponentContainer);
- } else {
- widgetWidth = getWidgetWidth(childComponentContainer);
- }
- } else {
- widgetWidth = getWidgetWidth(childComponentContainer);
- widgetHeight = getWidgetHeight(childComponentContainer);
- }
-
- summedWidgetWidth += widgetWidth;
- summedWidgetHeight += widgetHeight;
-
- maxWidgetHeight = Math.max(maxWidgetHeight, widgetHeight);
- maxWidgetWidth = Math.max(maxWidgetWidth, widgetWidth);
- }
-
- if (isHorizontal()) {
- summedWidgetWidth += activeSpacing.hSpacing
- * (widgetToComponentContainer.size() - 1);
- } else {
- summedWidgetHeight += activeSpacing.vSpacing
- * (widgetToComponentContainer.size() - 1);
- }
-
- Size layoutSize = updateLayoutDimensions(summedWidgetWidth,
- summedWidgetHeight, maxWidgetWidth, maxWidgetHeight);
-
- int remainingSpace;
- if (isHorizontal()) {
- remainingSpace = layoutSize.getWidth() - summedWidgetWidth;
- } else {
- remainingSpace = layoutSize.getHeight() - summedWidgetHeight;
- }
- if (remainingSpace < 0) {
- remainingSpace = 0;
- }
-
- // ApplicationConnection.getConsole().log(
- // "Layout size: " + activeLayoutSize);
- return remainingSpace;
- }
-
- private int getWidgetHeight(ChildComponentContainer childComponentContainer) {
- Size s = childComponentContainer.getWidgetSize();
- return s.getHeight()
- + childComponentContainer.getCaptionHeightAboveComponent();
- }
-
- private int getWidgetWidth(ChildComponentContainer childComponentContainer) {
- Size s = childComponentContainer.getWidgetSize();
- int widgetWidth = s.getWidth()
- + childComponentContainer.getCaptionWidthAfterComponent();
-
- /*
- * If the component does not have a specified size in the main direction
- * the caption may determine the space used by the component
- */
- if (!childComponentContainer.widgetHasSizeSpecified(orientation)) {
- int captionWidth = childComponentContainer
- .getCaptionRequiredWidth();
-
- if (captionWidth > widgetWidth) {
- widgetWidth = captionWidth;
- }
- }
-
- return widgetWidth;
- }
-
- private void calculateAlignments() {
- int w = 0;
- int h = 0;
-
- if (isHorizontal()) {
- // HORIZONTAL
- h = activeLayoutSize.getHeight();
- if (!isDynamicWidth()) {
- w = -1;
- }
-
- } else {
- // VERTICAL
- w = activeLayoutSize.getWidth();
- if (!isDynamicHeight()) {
- h = -1;
- }
- }
-
- for (ChildComponentContainer childComponentContainer : widgetToComponentContainer
- .values()) {
- childComponentContainer.updateAlignments(w, h);
- }
-
- }
-
- private void calculateContainerSize() {
-
- /*
- * Container size here means the size the container gets from the
- * component. The expansion size is not include in this but taken
- * separately into account.
- */
- int height = 0, width = 0;
- Iterator<Widget> widgetIterator = iterator();
- if (isHorizontal()) {
- height = activeLayoutSize.getHeight();
- int availableWidth = activeLayoutSize.getWidth();
- boolean first = true;
- while (widgetIterator.hasNext()) {
- ChildComponentContainer childComponentContainer = (ChildComponentContainer) widgetIterator
- .next();
- if (!childComponentContainer
- .isComponentRelativeSized(ORIENTATION_HORIZONTAL)) {
- /*
- * Only components with non-relative size in the main
- * direction has a container size
- */
- width = childComponentContainer.getWidgetSize().getWidth()
- + childComponentContainer
- .getCaptionWidthAfterComponent();
-
- /*
- * If the component does not have a specified size in the
- * main direction the caption may determine the space used
- * by the component
- */
- if (!childComponentContainer
- .widgetHasSizeSpecified(orientation)) {
- int captionWidth = childComponentContainer
- .getCaptionRequiredWidth();
- // ApplicationConnection.getConsole().log(
- // "Component width: " + width
- // + ", caption width: " + captionWidth);
- if (captionWidth > width) {
- width = captionWidth;
- }
- }
- } else {
- width = 0;
- }
-
- if (!isDynamicWidth()) {
- if (availableWidth == 0) {
- /*
- * Let the overflowing components overflow. IE has
- * problems with zero sizes.
- */
- // width = 0;
- // height = 0;
- } else if (width > availableWidth) {
- width = availableWidth;
-
- if (!first) {
- width -= activeSpacing.hSpacing;
- }
- availableWidth = 0;
- } else {
- availableWidth -= width;
- if (!first) {
- availableWidth -= activeSpacing.hSpacing;
- }
- }
-
- first = false;
- }
-
- childComponentContainer.setContainerSize(width, height);
- }
- } else {
- width = activeLayoutSize.getWidth();
- while (widgetIterator.hasNext()) {
- ChildComponentContainer childComponentContainer = (ChildComponentContainer) widgetIterator
- .next();
-
- if (!childComponentContainer
- .isComponentRelativeSized(ORIENTATION_VERTICAL)) {
- /*
- * Only components with non-relative size in the main
- * direction has a container size
- */
- height = childComponentContainer.getWidgetSize()
- .getHeight()
- + childComponentContainer
- .getCaptionHeightAboveComponent();
- } else {
- height = 0;
- }
-
- childComponentContainer.setContainerSize(width, height);
- }
-
- }
-
- }
-
- private Size updateLayoutDimensions(int totalComponentWidth,
- int totalComponentHeight, int maxComponentWidth,
- int maxComponentHeight) {
-
- /* Only need to calculate dynamic dimensions */
- if (!isDynamicHeight() && !isDynamicWidth()) {
- return activeLayoutSize;
- }
-
- int activeLayoutWidth = 0;
- int activeLayoutHeight = 0;
-
- // Update layout dimensions
- if (isHorizontal()) {
- // Horizontal
- if (isDynamicWidth()) {
- activeLayoutWidth = totalComponentWidth;
- }
-
- if (isDynamicHeight()) {
- activeLayoutHeight = maxComponentHeight;
- }
-
- } else {
- // Vertical
- if (isDynamicWidth()) {
- activeLayoutWidth = maxComponentWidth;
- }
-
- if (isDynamicHeight()) {
- activeLayoutHeight = totalComponentHeight;
- }
- }
-
- if (isDynamicWidth()) {
- setActiveLayoutWidth(activeLayoutWidth);
- setOuterLayoutWidth(activeLayoutSize.getWidth());
- }
-
- if (isDynamicHeight()) {
- setActiveLayoutHeight(activeLayoutHeight);
- setOuterLayoutHeight(activeLayoutSize.getHeight());
- }
-
- return activeLayoutSize;
- }
-
- private void setActiveLayoutWidth(int activeLayoutWidth) {
- if (activeLayoutWidth < 0) {
- activeLayoutWidth = 0;
- }
- activeLayoutSize.setWidth(activeLayoutWidth);
- }
-
- private void setActiveLayoutHeight(int activeLayoutHeight) {
- if (activeLayoutHeight < 0) {
- activeLayoutHeight = 0;
- }
- activeLayoutSize.setHeight(activeLayoutHeight);
-
- }
-
- private void setOuterLayoutWidth(int activeLayoutWidth) {
- // Don't call setWidth to avoid triggering all kinds of recalculations
- // Also don't call super.setWidth to avoid messing with the
- // dynamicWidth property
- int newPixelWidth = (activeLayoutWidth + activeMargins.getHorizontal());
- getElement().getStyle().setWidth(newPixelWidth, Unit.PX);
- }
-
- private void setOuterLayoutHeight(int activeLayoutHeight) {
- // Don't call setHeight to avoid triggering all kinds of recalculations
- // Also don't call super.setHeight to avoid messing with the
- // dynamicHeight property
- int newPixelHeight = (activeLayoutHeight + activeMargins.getVertical());
- getElement().getStyle().setHeight(newPixelHeight, Unit.PX);
- }
-
- /**
- * Updates the spacing between components. Needs to be done only when
- * components are added/removed.
- */
- private void updateContainerMargins() {
- ChildComponentContainer firstChildComponent = getFirstChildComponentContainer();
- if (firstChildComponent != null) {
- firstChildComponent.setMarginLeft(0);
- firstChildComponent.setMarginTop(0);
-
- for (ChildComponentContainer childComponent : widgetToComponentContainer
- .values()) {
- if (childComponent == firstChildComponent) {
- continue;
- }
-
- if (isHorizontal()) {
- childComponent.setMarginLeft(activeSpacing.hSpacing);
- } else {
- childComponent.setMarginTop(activeSpacing.vSpacing);
- }
- }
- }
- }
-
- private boolean isHorizontal() {
- return orientation == ORIENTATION_HORIZONTAL;
- }
-
- private boolean isVertical() {
- return orientation == ORIENTATION_VERTICAL;
- }
-
- private ChildComponentContainer createChildContainer(VPaintableWidget child) {
-
- // Create a container DIV for the child
- ChildComponentContainer childComponent = new ChildComponentContainer(
- child, orientation);
-
- return childComponent;
-
- }
-
- public RenderSpace getAllocatedSpace(Widget child) {
- int width = 0;
- int height = 0;
- ChildComponentContainer childComponentContainer = getComponentContainer(child);
- // WIDTH CALCULATION
- if (isVertical()) {
- width = activeLayoutSize.getWidth();
- width -= childComponentContainer.getCaptionWidthAfterComponent();
- } else if (!isDynamicWidth()) {
- // HORIZONTAL
- width = childComponentContainer.getContSize().getWidth();
- width -= childComponentContainer.getCaptionWidthAfterComponent();
- }
-
- // HEIGHT CALCULATION
- if (isHorizontal()) {
- height = activeLayoutSize.getHeight();
- height -= childComponentContainer.getCaptionHeightAboveComponent();
- } else if (!isDynamicHeight()) {
- // VERTICAL
- height = childComponentContainer.getContSize().getHeight();
- height -= childComponentContainer.getCaptionHeightAboveComponent();
- }
-
- // ApplicationConnection.getConsole().log(
- // "allocatedSpace for " + Util.getSimpleName(child) + ": "
- // + width + "," + height);
- RenderSpace space = new RenderSpace(width, height);
- return space;
- }
-
- private void recalculateLayoutAndComponentSizes() {
- recalculateLayout();
-
- if (!(isDynamicHeight() && isDynamicWidth())) {
- /* First update relative sized components */
- for (ChildComponentContainer componentContainer : widgetToComponentContainer
- .values()) {
- client.handleComponentRelativeSize(componentContainer
- .getWidget());
-
- // Update widget size from DOM
- componentContainer.updateWidgetSize();
- }
- }
-
- if (isDynamicHeight()) {
- /*
- * Height is not necessarily correct anymore as the height of
- * components might have changed if the width has changed.
- */
-
- /*
- * Get the new widget sizes from DOM and calculate new container
- * sizes
- */
- updateWidgetSizes();
-
- /* Update layout dimensions based on widget sizes */
- recalculateLayout();
- }
-
- updateRelativeSizesInNonMainDirection();
- calculateAlignments();
-
- setRootSize();
- }
-
- private void setRootSize() {
- root.getStyle().setPropertyPx("width", activeLayoutSize.getWidth());
- root.getStyle().setPropertyPx("height", activeLayoutSize.getHeight());
- }
-
- public boolean requestLayout(Set<Widget> children) {
- for (Widget p : children) {
- /* Update widget size from DOM */
- ChildComponentContainer componentContainer = getComponentContainer(p);
- // This should no longer be needed (after #2563)
- // if (isDynamicWidth()) {
- // componentContainer.setUnlimitedContainerWidth();
- // } else {
- // componentContainer.setLimitedContainerWidth(activeLayoutSize
- // .getWidth());
- // }
-
- componentContainer.updateWidgetSize();
-
- /*
- * If this is the result of an caption icon onload event the caption
- * size may have changed
- */
- componentContainer.updateCaptionSize();
- }
-
- Size sizeBefore = new Size(activeLayoutSize.getWidth(),
- activeLayoutSize.getHeight());
-
- recalculateLayoutAndComponentSizes();
- boolean sameSize = (sizeBefore.equals(activeLayoutSize));
- if (!sameSize) {
- /* Must inform child components about possible size updates */
- client.runDescendentsLayout(this);
- }
-
- /* Automatically propagated upwards if the size has changed */
-
- return sameSize;
- }
-
- @Override
- public void setHeight(String height) {
- Size sizeBefore = new Size(activeLayoutSize.getWidth(),
- activeLayoutSize.getHeight());
-
- super.setHeight(height);
-
- if (height != null && !height.equals("")) {
- setActiveLayoutHeight(getOffsetHeight()
- - activeMargins.getVertical());
- }
-
- if (isRendering) {
- sizeHasChangedDuringRendering = true;
- } else {
- recalculateLayoutAndComponentSizes();
- boolean sameSize = (sizeBefore.equals(activeLayoutSize));
- if (!sameSize) {
- /* Must inform child components about possible size updates */
- client.runDescendentsLayout(this);
- }
- }
- }
-
- @Override
- public void setWidth(String width) {
- if (this.width.equals(width) || !isVisible()) {
- return;
- }
- Size sizeBefore = new Size(activeLayoutSize.getWidth(),
- activeLayoutSize.getHeight());
-
- super.setWidth(width);
- this.width = width;
- if (width != null && !width.equals("")) {
- setActiveLayoutWidth(getOffsetWidth()
- - activeMargins.getHorizontal());
- }
-
- if (isRendering) {
- sizeHasChangedDuringRendering = true;
- } else {
- recalculateLayoutAndComponentSizes();
- boolean sameSize = (sizeBefore.equals(activeLayoutSize));
- if (!sameSize) {
- /* Must inform child components about possible size updates */
- client.runDescendentsLayout(this);
- }
- /*
- * If the height changes as a consequence of this we must inform the
- * parent also
- */
- if (isDynamicHeight()
- && sizeBefore.getHeight() != activeLayoutSize.getHeight()) {
- Util.notifyParentOfSizeChange(this, false);
- }
-
- }
- }
-
- protected void updateAlignmentsAndExpandRatios(UIDL uidl,
- ArrayList<Widget> renderedWidgets) {
-
- /*
- */
- alignments = uidl.getMapAttribute("alignments");
-
- /*
- * UIDL contains a map of paintable ids to expand ratios
- */
-
- expandRatios = uidl.getMapAttribute("expandRatios");
- expandRatioSum = -1.0;
-
- for (int i = 0; i < renderedWidgets.size(); i++) {
- Widget widget = renderedWidgets.get(i);
- String pid = VPaintableMap.get(client).getPid(widget);
-
- ChildComponentContainer container = getComponentContainer(widget);
-
- // Calculate alignment info
- container.setAlignment(getAlignment(pid));
-
- // Update expand ratio
- container.setNormalizedExpandRatio(getExpandRatio(pid));
- }
- }
-
- private AlignmentInfo getAlignment(String pid) {
- if (alignments.containsKey(pid)) {
- return new AlignmentInfo(alignments.getInt(pid));
- } else {
- return AlignmentInfo.TOP_LEFT;
- }
- }
-
- private double getExpandRatio(String pid) {
- if (expandRatioSum < 0) {
- expandRatioSum = 0;
- JsArrayString keyArray = expandRatios.getKeyArray();
- int length = keyArray.length();
- for (int i = 0; i < length; i++) {
- expandRatioSum += expandRatios.getRawNumber(keyArray.get(i));
- }
- if (expandRatioSum == 0) {
- // by default split equally among components
- defaultExpandRatio = 1.0 / widgetToComponentContainer.size();
- } else {
- defaultExpandRatio = 0;
- }
- }
- if (expandRatios.containsKey(pid)) {
- return expandRatios.getRawNumber(pid) / expandRatioSum;
- } else {
- return defaultExpandRatio;
- }
- }
-
- public void updateCaption(VPaintableWidget paintable, UIDL uidl) {
- Widget widget = paintable.getWidgetForPaintable();
- ChildComponentContainer componentContainer = getComponentContainer(widget);
- componentContainer.updateCaption(uidl, client);
- if (!isRendering) {
- /*
- * This was a component-only update and the possible size change
- * must be propagated to the layout
- */
- client.captionSizeUpdated(widget);
- }
- }
-
- /**
- * Returns the deepest nested child component which contains "element". The
- * child component is also returned if "element" is part of its caption.
- *
- * @param element
- * An element that is a nested sub element of the root element in
- * this layout
- * @return The Paintable which the element is a part of. Null if the element
- * belongs to the layout and not to a child.
- */
- private VPaintableWidget getComponent(Element element) {
- return Util.getPaintableForElement(client, this, element);
- }
-
- public Widget getWidgetForPaintable() {
- return this;
- }
-
-}
*/
package com.vaadin.terminal.gwt.client.ui;
-public class VVerticalLayout extends VOrderedLayout {
+public class VVerticalLayout extends VMeasuringOrderedLayout {
public static final String CLASSNAME = "v-verticallayout";
public VVerticalLayout() {
- super(CLASSNAME, ORIENTATION_VERTICAL);
+ super(CLASSNAME, true);
}
}