@@ -12,11 +12,14 @@ import java.util.Iterator; | |||
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; | |||
@@ -34,7 +37,6 @@ import com.google.gwt.user.client.ui.Focusable; | |||
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; | |||
@@ -1000,6 +1002,8 @@ public class ApplicationConnection { | |||
ArrayList<VPaintableWidget> updatedVPaintableWidgets = new ArrayList<VPaintableWidget>(); | |||
componentCaptionSizeChanges.clear(); | |||
Duration updateDuration = new Duration(); | |||
int length = changes.length(); | |||
for (int i = 0; i < length; i++) { | |||
try { | |||
@@ -1045,25 +1049,10 @@ public class ApplicationConnection { | |||
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")) { | |||
@@ -1806,6 +1795,17 @@ public class ApplicationConnection { | |||
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); | |||
@@ -1838,13 +1838,11 @@ public class ApplicationConnection { | |||
* 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) { | |||
@@ -2249,4 +2247,27 @@ public class ApplicationConnection { | |||
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); | |||
} | |||
} |
@@ -6,11 +6,13 @@ package com.vaadin.terminal.gwt.client; | |||
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() { | |||
@@ -108,4 +110,8 @@ class ComponentDetail { | |||
} | |||
return false; | |||
} | |||
public MeasureManager.MeasuredSize getMeasuredSize() { | |||
return measuredSize; | |||
} | |||
} |
@@ -0,0 +1,40 @@ | |||
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(); | |||
} | |||
} |
@@ -0,0 +1,280 @@ | |||
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; | |||
} | |||
} |
@@ -5,11 +5,7 @@ | |||
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; | |||
@@ -24,7 +20,6 @@ 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.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; | |||
@@ -65,30 +60,6 @@ public class Util { | |||
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 | |||
@@ -106,58 +77,40 @@ public class Util { | |||
* 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) { | |||
@@ -614,20 +567,7 @@ public class Util { | |||
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( |
@@ -3,6 +3,7 @@ | |||
*/ | |||
package com.vaadin.terminal.gwt.client; | |||
import java.util.ArrayList; | |||
import java.util.Collection; | |||
import java.util.Collections; | |||
import java.util.HashMap; | |||
@@ -16,6 +17,7 @@ import com.google.gwt.user.client.Element; | |||
import com.google.gwt.user.client.ui.HasWidgets; | |||
import com.google.gwt.user.client.ui.Widget; | |||
import com.vaadin.terminal.Paintable; | |||
import com.vaadin.terminal.gwt.client.MeasureManager.MeasuredSize; | |||
import com.vaadin.terminal.gwt.client.RenderInformation.Size; | |||
public class VPaintableMap { | |||
@@ -208,6 +210,21 @@ public class VPaintableMap { | |||
} | |||
public VPaintableWidget[] getRegisteredPaintableWidgets() { | |||
ArrayList<VPaintableWidget> result = new ArrayList<VPaintableWidget>(); | |||
for (VPaintable paintable : getPaintables()) { | |||
if (paintable instanceof VPaintableWidget) { | |||
VPaintableWidget paintableWidget = (VPaintableWidget) paintable; | |||
if (!unregistryBag.contains(getPid(paintable))) { | |||
result.add(paintableWidget); | |||
} | |||
} | |||
} | |||
return result.toArray(new VPaintableWidget[result.size()]); | |||
} | |||
void purgeUnregistryBag(boolean unregisterPaintables) { | |||
if (unregisterPaintables) { | |||
for (String pid : unregistryBag) { | |||
@@ -375,4 +392,17 @@ public class VPaintableMap { | |||
return getPid(w) != null; | |||
} | |||
/** | |||
* FIXME: Should not be here | |||
*/ | |||
@Deprecated | |||
public MeasuredSize getMeasuredSize(VPaintableWidget paintable) { | |||
ComponentDetail componentDetail = getComponentDetail(paintable); | |||
if (componentDetail == null) { | |||
return null; | |||
} | |||
return componentDetail.getMeasuredSize(); | |||
} | |||
} |
@@ -3,12 +3,12 @@ | |||
*/ | |||
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); | |||
} | |||
} |
@@ -0,0 +1,539 @@ | |||
/* | |||
@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; | |||
} | |||
} |
@@ -1,976 +0,0 @@ | |||
/* | |||
@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; | |||
} | |||
} |
@@ -3,12 +3,12 @@ | |||
*/ | |||
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); | |||
} | |||
} |