Browse Source

Add LayoutManager.setNeedsMeasure and change how layouts are started

tags/7.0.0.alpha2
Leif Åstrand 12 years ago
parent
commit
c5ab6b8c89

+ 3
- 63
src/com/vaadin/terminal/gwt/client/ApplicationConnection.java View File

+ (updateDuration.elapsedMillis() - startProcessing) + (updateDuration.elapsedMillis() - startProcessing)
+ " ms"); + " ms");


doLayout(false);
LayoutManager layoutManager = getLayoutManager();
layoutManager.setEverythingNeedsMeasure();
layoutManager.layoutNow();


updateDuration updateDuration
.logDuration(" * Layout processing completed", 10); .logDuration(" * Layout processing completed", 10);


} }


/*
* 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); 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() { protected String getUidlSecurityKey() {
return uidlSecurityKey; return uidlSecurityKey;
} }
eventIdentifier); 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() { LayoutManager getLayoutManager() {
return layoutManager; return layoutManager;
} }

+ 74
- 27
src/com/vaadin/terminal/gwt/client/LayoutManager.java View File

import com.google.gwt.core.client.JsArrayString; import com.google.gwt.core.client.JsArrayString;
import com.google.gwt.dom.client.Element; import com.google.gwt.dom.client.Element;
import com.google.gwt.dom.client.Style.Unit; 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.MeasuredSize.MeasureResult;
import com.vaadin.terminal.gwt.client.ui.ManagedLayout; import com.vaadin.terminal.gwt.client.ui.ManagedLayout;
import com.vaadin.terminal.gwt.client.ui.PostLayoutListener; import com.vaadin.terminal.gwt.client.ui.PostLayoutListener;
private final Collection<ManagedLayout> needsHorizontalLayout = new HashSet<ManagedLayout>(); private final Collection<ManagedLayout> needsHorizontalLayout = new HashSet<ManagedLayout>();
private final Collection<ManagedLayout> needsVerticalLayout = 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 Collection<ComponentConnector> pendingOverflowFixes = new HashSet<ComponentConnector>();


private final Map<Element, Collection<ElementResizeListener>> elementResizeListeners = new HashMap<Element, Collection<ElementResizeListener>>(); private final Map<Element, Collection<ElementResizeListener>> elementResizeListeners = new HashMap<Element, Collection<ElementResizeListener>>();
private final Set<Element> listenersToFire = new HashSet<Element>(); 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) { public void setConnection(ApplicationConnection connection) {
if (this.connection != null) { if (this.connection != null) {
throw new RuntimeException( throw new RuntimeException(
} }
} }


public void doLayout() {
private void layoutLater() {
if (!layoutPending) {
layoutPending = true;
layoutTimer.schedule(100);
}
}

public void layoutNow() {
if (isLayoutRunning()) { if (isLayoutRunning()) {
throw new IllegalStateException( throw new IllegalStateException(
"Can't start a new layout phase before the previous layout phase ends."); "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"); VConsole.log("Starting layout phase");


Map<ManagedLayout, Integer> layoutCounts = new HashMap<ManagedLayout, Integer>(); Map<ManagedLayout, Integer> layoutCounts = new HashMap<ManagedLayout, Integer>();
int passes = 0; int passes = 0;
Duration totalDuration = new Duration(); Duration totalDuration = new Duration();


currentDependencyTree = new LayoutDependencyTree();

for (ManagedLayout layout : needsHorizontalLayout) { for (ManagedLayout layout : needsHorizontalLayout) {
currentDependencyTree.setNeedsHorizontalLayout(layout, true); currentDependencyTree.setNeedsHorizontalLayout(layout, true);
} }
} }
needsHorizontalLayout.clear(); needsHorizontalLayout.clear();
needsVerticalLayout.clear(); needsVerticalLayout.clear();

for (ComponentConnector connector : needsMeasure) {
currentDependencyTree.setNeedsMeasure(connector, true);
}
needsMeasure.clear();

measureNonPaintables(); measureNonPaintables();


VConsole.log("Layout init in " + totalDuration.elapsedMillis() + " ms"); VConsole.log("Layout init in " + totalDuration.elapsedMillis() + " ms");
passes++; passes++;


int measuredConnectorCount = measureConnectors( int measuredConnectorCount = measureConnectors(
currentDependencyTree, passes == 1);
currentDependencyTree, everythingNeedsMeasure);
everythingNeedsMeasure = false;


int measureTime = passDuration.elapsedMillis(); int measureTime = passDuration.elapsedMillis();
VConsole.log(" Measured " + measuredConnectorCount VConsole.log(" Measured " + measuredConnectorCount
VConsole.log("Invoke post layout listeners in " VConsole.log("Invoke post layout listeners in "
+ (totalDuration.elapsedMillis() - postLayoutStart) + " ms"); + (totalDuration.elapsedMillis() - postLayoutStart) + " ms");


currentDependencyTree = null;
VConsole.log("Total layout phase time: " VConsole.log("Total layout phase time: "
+ totalDuration.elapsedMillis() + "ms"); + totalDuration.elapsedMillis() + "ms");
} }
setNeedsUpdate((ManagedLayout) connector); setNeedsUpdate((ManagedLayout) connector);
} }
} }
doLayout();
setEverythingNeedsMeasure();
layoutNow();
} }


// TODO Rename to setNeedsLayout // TODO Rename to setNeedsLayout
} }


public void reportOuterHeight(ComponentConnector component, int outerHeight) { public void reportOuterHeight(ComponentConnector component, int outerHeight) {
if (!isLayoutRunning()) {
throw new IllegalStateException(
"Can only report sizes when layout is running");
}
MeasuredSize measuredSize = getMeasuredSize(component); 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, public void reportHeightAssignedToRelative(ComponentConnector component,
} }


public void reportOuterWidth(ComponentConnector component, int outerWidth) { public void reportOuterWidth(ComponentConnector component, int outerWidth) {
if (!isLayoutRunning()) {
throw new IllegalStateException(
"Can only report sizes when layout is running");
}

MeasuredSize measuredSize = getMeasuredSize(component); 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, public void addElementResizeListener(Element element,
setMeasuredSize(element, null); setMeasuredSize(element, null);
} }
} }

public void setNeedsMeasure(ComponentConnector component) {
if (isLayoutRunning()) {
currentDependencyTree.setNeedsMeasure(component, true);
} else {
needsMeasure.add(component);
layoutLater();
}
}

public void setEverythingNeedsMeasure() {
everythingNeedsMeasure = true;
}
} }

+ 13
- 13
src/com/vaadin/terminal/gwt/client/Util.java View File

* @param widget * @param widget
* @param lazy * @param lazy
* run componentSizeUpdated lazyly * run componentSizeUpdated lazyly
*
* @deprecated since 7.0, use
* {@link LayoutManager#setNeedsMeasure(ComponentConnector)}
* instead
*/ */
@Deprecated
public static void notifyParentOfSizeChange(Widget widget, boolean lazy) { 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 List<ApplicationConnection> runningApplications = ApplicationConfiguration
.getRunningApplications(); .getRunningApplications();
for (ApplicationConnection applicationConnection : runningApplications) { for (ApplicationConnection applicationConnection : runningApplications) {
continue; continue;
} }
if (connector.getConnection() == applicationConnection) { if (connector.getConnection() == applicationConnection) {
return applicationConnection;
return connector;
} }
} }



+ 11
- 1
src/com/vaadin/terminal/gwt/client/ui/TableConnector.java View File



import com.google.gwt.core.client.GWT; import com.google.gwt.core.client.GWT;
import com.google.gwt.core.client.Scheduler; 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.dom.client.Style.Position;
import com.google.gwt.user.client.Command; import com.google.gwt.user.client.Command;
import com.google.gwt.user.client.ui.Widget; import com.google.gwt.user.client.ui.Widget;
} }


public void postLayout() { 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 @Override

+ 36
- 34
src/com/vaadin/terminal/gwt/client/ui/VAbstractSplitPanel.java View File

(pixelPosition + getSplitterSize()) + "px"); (pixelPosition + getSplitterSize()) + "px");


LayoutManager layoutManager = LayoutManager.get(client); 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; break;
(pixelPosition + getSplitterSize()) + "px"); (pixelPosition + getSplitterSize()) + "px");


layoutManager = LayoutManager.get(client); 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);
} }
} }


} }


setSplitPosition(newX + "px"); setSplitPosition(newX + "px");
client.doLayout(false);
} }


private void onVerticalMouseMove(int y) { private void onVerticalMouseMove(int y) {
} }


setSplitPosition(newY + "px"); setSplitPosition(newY + "px");
client.doLayout(false);
} }


public void onMouseUp(Event event) { public void onMouseUp(Event event) {

+ 8
- 4
src/com/vaadin/terminal/gwt/client/ui/VDragAndDropWrapper.java View File

import com.vaadin.terminal.gwt.client.ApplicationConnection; import com.vaadin.terminal.gwt.client.ApplicationConnection;
import com.vaadin.terminal.gwt.client.ComponentConnector; import com.vaadin.terminal.gwt.client.ComponentConnector;
import com.vaadin.terminal.gwt.client.ConnectorMap; 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.MouseEventDetailsBuilder;
import com.vaadin.terminal.gwt.client.Util; import com.vaadin.terminal.gwt.client.Util;
import com.vaadin.terminal.gwt.client.VConsole; import com.vaadin.terminal.gwt.client.VConsole;
+ emphasizedHDrop.toString().toLowerCase(), false); + emphasizedHDrop.toString().toLowerCase(), false);
} }
if (doLayout) { if (doLayout) {
client.doLayout(false);
notifySizePotentiallyChanged();
} }
} }


private void notifySizePotentiallyChanged() {
LayoutManager.get(client).setNeedsMeasure(
ConnectorMap.get(client).getConnector(getElement()));
}

protected void emphasis(VDragEvent drag) { protected void emphasis(VDragEvent drag) {
deEmphasis(false); deEmphasis(false);
VDragAndDropWrapper.setStyleName(getElement(), OVER_STYLE, true); VDragAndDropWrapper.setStyleName(getElement(), OVER_STYLE, true);
emphasizedVDrop = verticalDropLocation; emphasizedVDrop = verticalDropLocation;
emphasizedHDrop = horizontalDropLocation; 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();
} }


} }

+ 1
- 6
src/com/vaadin/terminal/gwt/client/ui/VScrollTable.java View File

int serverCacheFirst = -1; int serverCacheFirst = -1;
int serverCacheLast = -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 * Used to recall the position of an open context menu if we need to close
* * Makes deferred request to get some cache rows * * Makes deferred request to get some cache rows
*/ */
void sizeInit() { void sizeInit() {
if (!sizeNeedsInit) {
return;
}
sizeNeedsInit = false; sizeNeedsInit = false;


scrollBody.setContainerHeight(); scrollBody.setContainerHeight();
Util.runWebkitOverflowAutoFix(scrollBodyPanel.getElement()); Util.runWebkitOverflowAutoFix(scrollBodyPanel.getElement());
} }
}); });

client.doLayout(true);
} }


/** /**

+ 7
- 1
src/com/vaadin/terminal/gwt/client/ui/VView.java View File

import com.vaadin.terminal.gwt.client.ApplicationConnection; import com.vaadin.terminal.gwt.client.ApplicationConnection;
import com.vaadin.terminal.gwt.client.BrowserInfo; import com.vaadin.terminal.gwt.client.BrowserInfo;
import com.vaadin.terminal.gwt.client.ComponentConnector; 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.Focusable;
import com.vaadin.terminal.gwt.client.UIDL; import com.vaadin.terminal.gwt.client.UIDL;
import com.vaadin.terminal.gwt.client.VConsole; import com.vaadin.terminal.gwt.client.VConsole;
*/ */
protected void windowSizeMaybeChanged(int newWidth, int newHeight) { protected void windowSizeMaybeChanged(int newWidth, int newHeight) {
boolean changed = false; boolean changed = false;
ComponentConnector connector = ConnectorMap.get(connection)
.getConnector(this);
if (width != newWidth) { if (width != newWidth) {
width = newWidth; width = newWidth;
changed = true; changed = true;
connector.getLayoutManager().reportOuterWidth(connector, newWidth);
VConsole.log("New window width: " + width); VConsole.log("New window width: " + width);
} }
if (height != newHeight) { if (height != newHeight) {
height = newHeight; height = newHeight;
connector.getLayoutManager()
.reportOuterHeight(connector, newHeight);
changed = true; changed = true;
VConsole.log("New window height: " + height); VConsole.log("New window height: " + height);
} }
VConsole.log("Running layout functions due to window resize"); VConsole.log("Running layout functions due to window resize");
sendClientResized(); sendClientResized();


connection.doLayout(false);
connector.getLayoutManager().layoutNow();
} }
} }



+ 4
- 1
src/com/vaadin/terminal/gwt/client/ui/VWindow.java View File

client.runDescendentsLayout((HasWidgets) layout.getWidget()); client.runDescendentsLayout((HasWidgets) layout.getWidget());
} }


client.doLayout(false);
LayoutManager layoutManager = LayoutManager.get(client);
layoutManager.setNeedsMeasure(ConnectorMap.get(client).getConnector(
this));
layoutManager.layoutNow();
} }


@Override @Override

Loading…
Cancel
Save