From c5ab6b8c898357ce73918da852307ad2c9840290 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Leif=20=C3=85strand?= Date: Tue, 10 Apr 2012 12:39:09 +0300 Subject: [PATCH] Add LayoutManager.setNeedsMeasure and change how layouts are started --- .../gwt/client/ApplicationConnection.java | 66 +----------- .../terminal/gwt/client/LayoutManager.java | 101 +++++++++++++----- src/com/vaadin/terminal/gwt/client/Util.java | 26 ++--- .../gwt/client/ui/TableConnector.java | 12 ++- .../gwt/client/ui/VAbstractSplitPanel.java | 70 ++++++------ .../gwt/client/ui/VDragAndDropWrapper.java | 12 ++- .../terminal/gwt/client/ui/VScrollTable.java | 7 +- .../vaadin/terminal/gwt/client/ui/VView.java | 8 +- .../terminal/gwt/client/ui/VWindow.java | 5 +- 9 files changed, 157 insertions(+), 150 deletions(-) diff --git a/src/com/vaadin/terminal/gwt/client/ApplicationConnection.java b/src/com/vaadin/terminal/gwt/client/ApplicationConnection.java index e9a2a5b8be..6a8856eaee 100644 --- a/src/com/vaadin/terminal/gwt/client/ApplicationConnection.java +++ b/src/com/vaadin/terminal/gwt/client/ApplicationConnection.java @@ -1123,7 +1123,9 @@ public class ApplicationConnection { + (updateDuration.elapsedMillis() - startProcessing) + " ms"); - doLayout(false); + LayoutManager layoutManager = getLayoutManager(); + layoutManager.setEverythingNeedsMeasure(); + layoutManager.layoutNow(); updateDuration .logDuration(" * Layout processing completed", 10); @@ -2182,40 +2184,8 @@ public class ApplicationConnection { } - /* - * Helper to run layout functions triggered by child components with a - * decent interval. - */ - private final Timer layoutTimer = new Timer() { - - private boolean isPending = false; - - @Override - public void schedule(int delayMillis) { - if (!isPending) { - super.schedule(delayMillis); - isPending = true; - } - } - - @Override - public void run() { - VConsole.log("Running re-layout of " + view.getClass().getName()); - runDescendentsLayout(view.getWidget()); - isPending = false; - } - }; - private ConnectorMap connectorMap = GWT.create(ConnectorMap.class); - /** - * Components can call this function to run all layout functions. This is - * usually done, when component knows that its size has changed. - */ - public void requestLayoutPhase() { - layoutTimer.schedule(500); - } - protected String getUidlSecurityKey() { return uidlSecurityKey; } @@ -2377,36 +2347,6 @@ public class ApplicationConnection { eventIdentifier); } - private boolean layoutPending = false; - private ScheduledCommand layoutCommand = new ScheduledCommand() { - public void execute() { - /* - * Layout again if a new layout is requested while the current one - * is running. - */ - while (layoutPending) { - layoutPending = false; - layoutManager.doLayout(); - } - } - }; - - public void doLayout(boolean lazy) { - if (!lazy) { - layoutPending = true; - layoutCommand.execute(); - } else if (!layoutPending) { - layoutPending = true; - /* - * Current layoutCommand will do layouts again if layoutScheduled is - * set to true -> no need to schedule another command - */ - if (!layoutManager.isLayoutRunning()) { - Scheduler.get().scheduleDeferred(layoutCommand); - } - } - } - LayoutManager getLayoutManager() { return layoutManager; } diff --git a/src/com/vaadin/terminal/gwt/client/LayoutManager.java b/src/com/vaadin/terminal/gwt/client/LayoutManager.java index a9a58845b4..875551e621 100644 --- a/src/com/vaadin/terminal/gwt/client/LayoutManager.java +++ b/src/com/vaadin/terminal/gwt/client/LayoutManager.java @@ -13,6 +13,7 @@ import com.google.gwt.core.client.Duration; import com.google.gwt.core.client.JsArrayString; import com.google.gwt.dom.client.Element; import com.google.gwt.dom.client.Style.Unit; +import com.google.gwt.user.client.Timer; import com.vaadin.terminal.gwt.client.MeasuredSize.MeasureResult; import com.vaadin.terminal.gwt.client.ui.ManagedLayout; import com.vaadin.terminal.gwt.client.ui.PostLayoutListener; @@ -34,11 +35,23 @@ public class LayoutManager { private final Collection needsHorizontalLayout = new HashSet(); private final Collection needsVerticalLayout = new HashSet(); + private final Collection needsMeasure = new HashSet(); + private final Collection pendingOverflowFixes = new HashSet(); private final Map> elementResizeListeners = new HashMap>(); private final Set listenersToFire = new HashSet(); + private boolean layoutPending = false; + private Timer layoutTimer = new Timer() { + @Override + public void run() { + cancel(); + layoutNow(); + } + }; + private boolean everythingNeedsMeasure = false; + public void setConnection(ApplicationConnection connection) { if (this.connection != null) { throw new RuntimeException( @@ -136,11 +149,28 @@ public class LayoutManager { } } - public void doLayout() { + private void layoutLater() { + if (!layoutPending) { + layoutPending = true; + layoutTimer.schedule(100); + } + } + + public void layoutNow() { if (isLayoutRunning()) { throw new IllegalStateException( "Can't start a new layout phase before the previous layout phase ends."); } + layoutPending = false; + try { + currentDependencyTree = new LayoutDependencyTree(); + doLayout(); + } finally { + currentDependencyTree = null; + } + } + + private void doLayout() { VConsole.log("Starting layout phase"); Map layoutCounts = new HashMap(); @@ -148,8 +178,6 @@ public class LayoutManager { int passes = 0; Duration totalDuration = new Duration(); - currentDependencyTree = new LayoutDependencyTree(); - for (ManagedLayout layout : needsHorizontalLayout) { currentDependencyTree.setNeedsHorizontalLayout(layout, true); } @@ -158,6 +186,12 @@ public class LayoutManager { } needsHorizontalLayout.clear(); needsVerticalLayout.clear(); + + for (ComponentConnector connector : needsMeasure) { + currentDependencyTree.setNeedsMeasure(connector, true); + } + needsMeasure.clear(); + measureNonPaintables(); VConsole.log("Layout init in " + totalDuration.elapsedMillis() + " ms"); @@ -167,7 +201,8 @@ public class LayoutManager { passes++; int measuredConnectorCount = measureConnectors( - currentDependencyTree, passes == 1); + currentDependencyTree, everythingNeedsMeasure); + everythingNeedsMeasure = false; int measureTime = passDuration.elapsedMillis(); VConsole.log(" Measured " + measuredConnectorCount @@ -287,7 +322,6 @@ public class LayoutManager { VConsole.log("Invoke post layout listeners in " + (totalDuration.elapsedMillis() - postLayoutStart) + " ms"); - currentDependencyTree = null; VConsole.log("Total layout phase time: " + totalDuration.elapsedMillis() + "ms"); } @@ -445,7 +479,8 @@ public class LayoutManager { setNeedsUpdate((ManagedLayout) connector); } } - doLayout(); + setEverythingNeedsMeasure(); + layoutNow(); } // TODO Rename to setNeedsLayout @@ -531,19 +566,19 @@ public class LayoutManager { } public void reportOuterHeight(ComponentConnector component, int outerHeight) { - if (!isLayoutRunning()) { - throw new IllegalStateException( - "Can only report sizes when layout is running"); - } MeasuredSize measuredSize = getMeasuredSize(component); - boolean heightChanged = measuredSize.setOuterHeight(outerHeight); + if (isLayoutRunning()) { + boolean heightChanged = measuredSize.setOuterHeight(outerHeight); - if (heightChanged) { - onConnectorChange(component, false, true); - notifyListenersAndDepdendents(component.getWidget().getElement(), - false, true); + if (heightChanged) { + onConnectorChange(component, false, true); + notifyListenersAndDepdendents(component.getWidget() + .getElement(), false, true); + } + currentDependencyTree.setNeedsVerticalMeasure(component, false); + } else if (measuredSize.getOuterHeight() != outerHeight) { + setNeedsMeasure(component); } - currentDependencyTree.setNeedsVerticalMeasure(component, false); } public void reportHeightAssignedToRelative(ComponentConnector component, @@ -571,20 +606,19 @@ public class LayoutManager { } public void reportOuterWidth(ComponentConnector component, int outerWidth) { - if (!isLayoutRunning()) { - throw new IllegalStateException( - "Can only report sizes when layout is running"); - } - MeasuredSize measuredSize = getMeasuredSize(component); - boolean widthChanged = measuredSize.setOuterWidth(outerWidth); + if (isLayoutRunning()) { + boolean widthChanged = measuredSize.setOuterWidth(outerWidth); - if (widthChanged) { - onConnectorChange(component, true, false); - notifyListenersAndDepdendents(component.getWidget().getElement(), - true, false); + if (widthChanged) { + onConnectorChange(component, true, false); + notifyListenersAndDepdendents(component.getWidget() + .getElement(), true, false); + } + currentDependencyTree.setNeedsHorizontalMeasure(component, false); + } else if (measuredSize.getOuterWidth() != outerWidth) { + setNeedsMeasure(component); } - currentDependencyTree.setNeedsHorizontalMeasure(component, false); } public void addElementResizeListener(Element element, @@ -618,4 +652,17 @@ public class LayoutManager { setMeasuredSize(element, null); } } + + public void setNeedsMeasure(ComponentConnector component) { + if (isLayoutRunning()) { + currentDependencyTree.setNeedsMeasure(component, true); + } else { + needsMeasure.add(component); + layoutLater(); + } + } + + public void setEverythingNeedsMeasure() { + everythingNeedsMeasure = true; + } } diff --git a/src/com/vaadin/terminal/gwt/client/Util.java b/src/com/vaadin/terminal/gwt/client/Util.java index 374d210379..bfe63caefd 100644 --- a/src/com/vaadin/terminal/gwt/client/Util.java +++ b/src/com/vaadin/terminal/gwt/client/Util.java @@ -79,23 +79,23 @@ public class Util { * @param widget * @param lazy * run componentSizeUpdated lazyly + * + * @deprecated since 7.0, use + * {@link LayoutManager#setNeedsMeasure(ComponentConnector)} + * instead */ + @Deprecated public static void notifyParentOfSizeChange(Widget widget, boolean lazy) { - ApplicationConnection applicationConnection = findApplicationConnectionFor(widget); - if (applicationConnection != null) { - applicationConnection.doLayout(lazy); + ComponentConnector connector = findConnectorFor(widget); + if (connector != null) { + connector.getLayoutManager().setNeedsMeasure(connector); + if (!lazy) { + connector.getLayoutManager().layoutNow(); + } } } - private static boolean findAppConnectionWarningDisplayed = false; - - 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"); - } - + private static ComponentConnector findConnectorFor(Widget widget) { List runningApplications = ApplicationConfiguration .getRunningApplications(); for (ApplicationConnection applicationConnection : runningApplications) { @@ -105,7 +105,7 @@ public class Util { continue; } if (connector.getConnection() == applicationConnection) { - return applicationConnection; + return connector; } } diff --git a/src/com/vaadin/terminal/gwt/client/ui/TableConnector.java b/src/com/vaadin/terminal/gwt/client/ui/TableConnector.java index 7acdc84b5f..2c546f40b1 100644 --- a/src/com/vaadin/terminal/gwt/client/ui/TableConnector.java +++ b/src/com/vaadin/terminal/gwt/client/ui/TableConnector.java @@ -7,6 +7,7 @@ import java.util.Iterator; import com.google.gwt.core.client.GWT; import com.google.gwt.core.client.Scheduler; +import com.google.gwt.core.client.Scheduler.ScheduledCommand; import com.google.gwt.dom.client.Style.Position; import com.google.gwt.user.client.Command; import com.google.gwt.user.client.ui.Widget; @@ -279,7 +280,16 @@ public class TableConnector extends AbstractComponentContainerConnector } public void postLayout() { - getWidget().sizeInit(); + VScrollTable table = getWidget(); + if (table.sizeNeedsInit) { + table.sizeInit(); + Scheduler.get().scheduleFinally(new ScheduledCommand() { + public void execute() { + getLayoutManager().setNeedsUpdate(TableConnector.this); + getLayoutManager().layoutNow(); + } + }); + } } @Override diff --git a/src/com/vaadin/terminal/gwt/client/ui/VAbstractSplitPanel.java b/src/com/vaadin/terminal/gwt/client/ui/VAbstractSplitPanel.java index 55742f24b3..f08cbf58e9 100644 --- a/src/com/vaadin/terminal/gwt/client/ui/VAbstractSplitPanel.java +++ b/src/com/vaadin/terminal/gwt/client/ui/VAbstractSplitPanel.java @@ -301,23 +301,25 @@ public class VAbstractSplitPanel extends ComplexPanel { (pixelPosition + getSplitterSize()) + "px"); LayoutManager layoutManager = LayoutManager.get(client); - if (layoutManager.isLayoutRunning()) { - ConnectorMap connectorMap = ConnectorMap.get(client); - if (firstChild != null) { - ComponentConnector connector = connectorMap - .getConnector(firstChild); - if (connector.isRelativeWidth()) { - layoutManager.reportWidthAssignedToRelative(connector, - pixelPosition); - } + ConnectorMap connectorMap = ConnectorMap.get(client); + if (firstChild != null) { + ComponentConnector connector = connectorMap + .getConnector(firstChild); + if (connector.isRelativeWidth()) { + layoutManager.reportWidthAssignedToRelative(connector, + pixelPosition); + } else { + layoutManager.setNeedsMeasure(connector); } - if (secondChild != null) { - ComponentConnector connector = connectorMap - .getConnector(secondChild); - if (connector.isRelativeWidth()) { - layoutManager.reportWidthAssignedToRelative(connector, - secondContainerWidth); - } + } + if (secondChild != null) { + ComponentConnector connector = connectorMap + .getConnector(secondChild); + if (connector.isRelativeWidth()) { + layoutManager.reportWidthAssignedToRelative(connector, + secondContainerWidth); + } else { + layoutManager.setNeedsMeasure(connector); } } break; @@ -348,23 +350,25 @@ public class VAbstractSplitPanel extends ComplexPanel { (pixelPosition + getSplitterSize()) + "px"); layoutManager = LayoutManager.get(client); - if (layoutManager.isLayoutRunning()) { - ConnectorMap connectorMap = ConnectorMap.get(client); - if (firstChild != null) { - ComponentConnector connector = connectorMap - .getConnector(firstChild); - if (connector.isRelativeHeight()) { - layoutManager.reportHeightAssignedToRelative(connector, - pixelPosition); - } + connectorMap = ConnectorMap.get(client); + if (firstChild != null) { + ComponentConnector connector = connectorMap + .getConnector(firstChild); + if (connector.isRelativeHeight()) { + layoutManager.reportHeightAssignedToRelative(connector, + pixelPosition); + } else { + layoutManager.setNeedsMeasure(connector); } - if (secondChild != null) { - ComponentConnector connector = connectorMap - .getConnector(secondChild); - if (connector.isRelativeHeight()) { - layoutManager.reportHeightAssignedToRelative(connector, - secondContainerHeight); - } + } + if (secondChild != null) { + ComponentConnector connector = connectorMap + .getConnector(secondChild); + if (connector.isRelativeHeight()) { + layoutManager.reportHeightAssignedToRelative(connector, + secondContainerHeight); + } else { + layoutManager.setNeedsMeasure(connector); } } @@ -504,7 +508,6 @@ public class VAbstractSplitPanel extends ComplexPanel { } setSplitPosition(newX + "px"); - client.doLayout(false); } private void onVerticalMouseMove(int y) { @@ -548,7 +551,6 @@ public class VAbstractSplitPanel extends ComplexPanel { } setSplitPosition(newY + "px"); - client.doLayout(false); } public void onMouseUp(Event event) { diff --git a/src/com/vaadin/terminal/gwt/client/ui/VDragAndDropWrapper.java b/src/com/vaadin/terminal/gwt/client/ui/VDragAndDropWrapper.java index d87bc78038..d87b7a5c21 100644 --- a/src/com/vaadin/terminal/gwt/client/ui/VDragAndDropWrapper.java +++ b/src/com/vaadin/terminal/gwt/client/ui/VDragAndDropWrapper.java @@ -25,6 +25,7 @@ import com.google.gwt.xhr.client.XMLHttpRequest; import com.vaadin.terminal.gwt.client.ApplicationConnection; import com.vaadin.terminal.gwt.client.ComponentConnector; import com.vaadin.terminal.gwt.client.ConnectorMap; +import com.vaadin.terminal.gwt.client.LayoutManager; import com.vaadin.terminal.gwt.client.MouseEventDetailsBuilder; import com.vaadin.terminal.gwt.client.Util; import com.vaadin.terminal.gwt.client.VConsole; @@ -564,10 +565,15 @@ public class VDragAndDropWrapper extends VCustomComponent implements + emphasizedHDrop.toString().toLowerCase(), false); } if (doLayout) { - client.doLayout(false); + notifySizePotentiallyChanged(); } } + private void notifySizePotentiallyChanged() { + LayoutManager.get(client).setNeedsMeasure( + ConnectorMap.get(client).getConnector(getElement())); + } + protected void emphasis(VDragEvent drag) { deEmphasis(false); VDragAndDropWrapper.setStyleName(getElement(), OVER_STYLE, true); @@ -578,9 +584,7 @@ public class VDragAndDropWrapper extends VCustomComponent implements emphasizedVDrop = verticalDropLocation; emphasizedHDrop = horizontalDropLocation; - // TODO build (to be an example) an emphasis mode where drag image - // is fitted before or after the content - client.doLayout(false); + notifySizePotentiallyChanged(); } } diff --git a/src/com/vaadin/terminal/gwt/client/ui/VScrollTable.java b/src/com/vaadin/terminal/gwt/client/ui/VScrollTable.java index b372ad7e13..6668afecdc 100644 --- a/src/com/vaadin/terminal/gwt/client/ui/VScrollTable.java +++ b/src/com/vaadin/terminal/gwt/client/ui/VScrollTable.java @@ -458,7 +458,7 @@ public class VScrollTable extends FlowPanel implements HasWidgets, int serverCacheFirst = -1; int serverCacheLast = -1; - private boolean sizeNeedsInit = true; + boolean sizeNeedsInit = true; /** * Used to recall the position of an open context menu if we need to close @@ -1622,9 +1622,6 @@ public class VScrollTable extends FlowPanel implements HasWidgets, * * Makes deferred request to get some cache rows */ void sizeInit() { - if (!sizeNeedsInit) { - return; - } sizeNeedsInit = false; scrollBody.setContainerHeight(); @@ -1877,8 +1874,6 @@ public class VScrollTable extends FlowPanel implements HasWidgets, Util.runWebkitOverflowAutoFix(scrollBodyPanel.getElement()); } }); - - client.doLayout(true); } /** diff --git a/src/com/vaadin/terminal/gwt/client/ui/VView.java b/src/com/vaadin/terminal/gwt/client/ui/VView.java index 1c655ec6d9..e69b11a8f3 100644 --- a/src/com/vaadin/terminal/gwt/client/ui/VView.java +++ b/src/com/vaadin/terminal/gwt/client/ui/VView.java @@ -24,6 +24,7 @@ import com.google.gwt.user.client.ui.SimplePanel; import com.vaadin.terminal.gwt.client.ApplicationConnection; import com.vaadin.terminal.gwt.client.BrowserInfo; import com.vaadin.terminal.gwt.client.ComponentConnector; +import com.vaadin.terminal.gwt.client.ConnectorMap; import com.vaadin.terminal.gwt.client.Focusable; import com.vaadin.terminal.gwt.client.UIDL; import com.vaadin.terminal.gwt.client.VConsole; @@ -155,13 +156,18 @@ public class VView extends SimplePanel implements ResizeHandler, */ protected void windowSizeMaybeChanged(int newWidth, int newHeight) { boolean changed = false; + ComponentConnector connector = ConnectorMap.get(connection) + .getConnector(this); if (width != newWidth) { width = newWidth; changed = true; + connector.getLayoutManager().reportOuterWidth(connector, newWidth); VConsole.log("New window width: " + width); } if (height != newHeight) { height = newHeight; + connector.getLayoutManager() + .reportOuterHeight(connector, newHeight); changed = true; VConsole.log("New window height: " + height); } @@ -169,7 +175,7 @@ public class VView extends SimplePanel implements ResizeHandler, VConsole.log("Running layout functions due to window resize"); sendClientResized(); - connection.doLayout(false); + connector.getLayoutManager().layoutNow(); } } diff --git a/src/com/vaadin/terminal/gwt/client/ui/VWindow.java b/src/com/vaadin/terminal/gwt/client/ui/VWindow.java index 4bc7bdf371..35dfc5225c 100644 --- a/src/com/vaadin/terminal/gwt/client/ui/VWindow.java +++ b/src/com/vaadin/terminal/gwt/client/ui/VWindow.java @@ -702,7 +702,10 @@ public class VWindow extends VOverlay implements ShortcutActionHandlerOwner, client.runDescendentsLayout((HasWidgets) layout.getWidget()); } - client.doLayout(false); + LayoutManager layoutManager = LayoutManager.get(client); + layoutManager.setNeedsMeasure(ConnectorMap.get(client).getConnector( + this)); + layoutManager.layoutNow(); } @Override -- 2.39.5