@@ -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; | |||
} |
@@ -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<ManagedLayout> needsHorizontalLayout = new HashSet<ManagedLayout>(); | |||
private final Collection<ManagedLayout> needsVerticalLayout = new HashSet<ManagedLayout>(); | |||
private final Collection<ComponentConnector> needsMeasure = new HashSet<ComponentConnector>(); | |||
private final Collection<ComponentConnector> pendingOverflowFixes = new HashSet<ComponentConnector>(); | |||
private final Map<Element, Collection<ElementResizeListener>> elementResizeListeners = new HashMap<Element, Collection<ElementResizeListener>>(); | |||
private final Set<Element> listenersToFire = new HashSet<Element>(); | |||
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<ManagedLayout, Integer> layoutCounts = new HashMap<ManagedLayout, Integer>(); | |||
@@ -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; | |||
} | |||
} |
@@ -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<ApplicationConnection> runningApplications = ApplicationConfiguration | |||
.getRunningApplications(); | |||
for (ApplicationConnection applicationConnection : runningApplications) { | |||
@@ -105,7 +105,7 @@ public class Util { | |||
continue; | |||
} | |||
if (connector.getConnection() == applicationConnection) { | |||
return applicationConnection; | |||
return connector; | |||
} | |||
} | |||
@@ -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 |
@@ -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) { |
@@ -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(); | |||
} | |||
} |
@@ -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); | |||
} | |||
/** |
@@ -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(); | |||
} | |||
} | |||
@@ -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 |