import com.vaadin.terminal.gwt.client.ui.PostLayoutListener;
import com.vaadin.terminal.gwt.client.ui.SimpleManagedLayout;
import com.vaadin.terminal.gwt.client.ui.VNotification;
+import com.vaadin.terminal.gwt.client.ui.layout.ElementResizeEvent;
+import com.vaadin.terminal.gwt.client.ui.layout.ElementResizeListener;
import com.vaadin.terminal.gwt.client.ui.layout.LayoutDependencyTree;
import com.vaadin.terminal.gwt.client.ui.layout.RequiresOverflowAutoFix;
public class LayoutManager {
private static final String LOOP_ABORT_MESSAGE = "Aborting layout after 100 passes. This would probably be an infinite loop.";
private ApplicationConnection connection;
- private final Set<Element> nonPaintableElements = new HashSet<Element>();
+ private final Set<Element> measuredNonPaintableElements = new HashSet<Element>();
private final MeasuredSize nullSize = new MeasuredSize();
private LayoutDependencyTree currentDependencyTree;
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>();
+
public void setConnection(ApplicationConnection connection) {
if (this.connection != null) {
throw new RuntimeException(
measuredSize = new MeasuredSize();
if (ConnectorMap.get(connection).getConnector(element) == null) {
- nonPaintableElements.add(element);
+ measuredNonPaintableElements.add(element);
}
setMeasuredSize(element, measuredSize);
}
private boolean needsMeasure(Element e) {
if (connection.getConnectorMap().getConnectorId(e) != null) {
return true;
+ } else if (elementResizeListeners.containsKey(e)) {
+ return true;
} else if (getMeasuredSize(e, nullSize).hasDependents()) {
return true;
} else {
return element.vMeasuredSize || defaultSize;
}-*/;
- private final MeasuredSize getMeasuredSize(ComponentConnector paintable) {
- Element element = paintable.getWidget().getElement();
+ private final MeasuredSize getMeasuredSize(ComponentConnector connector) {
+ Element element = connector.getWidget().getElement();
MeasuredSize measuredSize = getMeasuredSize(element, null);
if (measuredSize == null) {
measuredSize = new MeasuredSize();
return;
}
measuredSize.removeDependent(owner.getConnectorId());
- if (!needsMeasure(element)) {
- nonPaintableElements.remove(element);
- setMeasuredSize(element, null);
- }
+ stopMeasuringIfUnecessary(element);
}
public boolean isLayoutRunning() {
}
needsHorizontalLayout.clear();
needsVerticalLayout.clear();
- measureNonPaintables(currentDependencyTree);
+ measureNonPaintables();
VConsole.log("Layout init in " + totalDuration.elapsedMillis() + " ms");
VConsole.log(" Measured " + measuredConnectorCount
+ " elements in " + measureTime + " ms");
+ if (!listenersToFire.isEmpty()) {
+ for (Element element : listenersToFire) {
+ Collection<ElementResizeListener> listeners = elementResizeListeners
+ .get(element);
+ ElementResizeListener[] array = listeners
+ .toArray(new ElementResizeListener[listeners.size()]);
+ ElementResizeEvent event = new ElementResizeEvent(this,
+ element);
+ for (ElementResizeListener listener : array) {
+ listener.onElementResize(event);
+ }
+ }
+ int measureListenerTime = passDuration.elapsedMillis();
+ VConsole.log(" Fired resize listeners for "
+ + listenersToFire.size() + " elements in "
+ + (measureListenerTime - measureTime) + " ms");
+ measureTime = measuredConnectorCount;
+ listenersToFire.clear();
+ }
+
FastStringSet updatedSet = FastStringSet.create();
while (currentDependencyTree.hasHorizontalConnectorToLayout()
ComponentConnector[] connectors = ConnectorMap.get(connection)
.getComponentConnectors();
for (ComponentConnector connector : connectors) {
- measueConnector(layoutDependencyTree, connector);
+ measueConnector(connector);
}
for (ComponentConnector connector : connectors) {
layoutDependencyTree.setNeedsMeasure(connector, false);
Collection<ComponentConnector> measureTargets = layoutDependencyTree
.getMeasureTargets();
for (ComponentConnector connector : measureTargets) {
- measueConnector(layoutDependencyTree, connector);
+ measueConnector(connector);
measureCount++;
}
for (ComponentConnector connector : measureTargets) {
return measureCount;
}
- private void measueConnector(LayoutDependencyTree layoutDependencyTree,
- ComponentConnector connector) {
+ private void measueConnector(ComponentConnector connector) {
Element element = connector.getWidget().getElement();
MeasuredSize measuredSize = getMeasuredSize(connector);
- MeasureResult measureResult = measuredAndUpdate(element, measuredSize,
- layoutDependencyTree);
+ MeasureResult measureResult = measuredAndUpdate(element, measuredSize);
if (measureResult.isChanged()) {
- doOverflowAutoFix(connector);
+ onConnectorChange(connector, measureResult.isWidthChanged(),
+ measureResult.isHeightChanged());
}
- if (measureResult.isHeightChanged()) {
- layoutDependencyTree.markHeightAsChanged(connector);
+ }
+
+ private void onConnectorChange(ComponentConnector connector,
+ boolean widthChanged, boolean heightChanged) {
+ doOverflowAutoFix(connector);
+ if (heightChanged) {
+ currentDependencyTree.markHeightAsChanged(connector);
}
- if (measureResult.isWidthChanged()) {
- layoutDependencyTree.markWidthAsChanged(connector);
+ if (widthChanged) {
+ currentDependencyTree.markWidthAsChanged(connector);
}
}
}
}
- private void measureNonPaintables(LayoutDependencyTree layoutDependencyTree) {
- for (Element element : nonPaintableElements) {
- MeasuredSize measuredSize = getMeasuredSize(element, null);
- measuredAndUpdate(element, measuredSize, layoutDependencyTree);
+ private void measureNonPaintables() {
+ for (Element element : measuredNonPaintableElements) {
+ measuredAndUpdate(element, getMeasuredSize(element, null));
}
- VConsole.log("Measured " + nonPaintableElements.size()
+ VConsole.log("Measured " + measuredNonPaintableElements.size()
+ " non paintable elements");
}
private MeasureResult measuredAndUpdate(Element element,
- MeasuredSize measuredSize, LayoutDependencyTree layoutDependencyTree) {
+ MeasuredSize measuredSize) {
MeasureResult measureResult = measuredSize.measure(element);
if (measureResult.isChanged()) {
- JsArrayString dependents = measuredSize.getDependents();
- for (int i = 0; i < dependents.length(); i++) {
- String pid = dependents.get(i);
- ManagedLayout dependent = (ManagedLayout) connection
- .getConnectorMap().getConnector(pid);
- if (dependent != null) {
- if (measureResult.isHeightChanged()) {
- layoutDependencyTree.setNeedsVerticalLayout(dependent,
- true);
- }
- if (measureResult.isWidthChanged()) {
- layoutDependencyTree.setNeedsHorizontalLayout(
- dependent, true);
- }
+ notifyListenersAndDepdendents(element,
+ measureResult.isWidthChanged(),
+ measureResult.isHeightChanged());
+ }
+ return measureResult;
+ }
+
+ private void notifyListenersAndDepdendents(Element element,
+ boolean widthChanged, boolean heightChanged) {
+ assert widthChanged || heightChanged;
+
+ MeasuredSize measuredSize = getMeasuredSize(element, nullSize);
+ JsArrayString dependents = measuredSize.getDependents();
+ for (int i = 0; i < dependents.length(); i++) {
+ String pid = dependents.get(i);
+ ManagedLayout dependent = (ManagedLayout) connection
+ .getConnectorMap().getConnector(pid);
+ if (dependent != null) {
+ if (heightChanged) {
+ currentDependencyTree.setNeedsVerticalLayout(dependent,
+ true);
+ }
+ if (widthChanged) {
+ currentDependencyTree.setNeedsHorizontalLayout(dependent,
+ true);
}
}
}
- return measureResult;
+ if (elementResizeListeners.containsKey(element)) {
+ listenersToFire.add(element);
+ }
}
private static boolean isManagedLayout(ComponentConnector paintable) {
boolean heightChanged = measuredSize.setOuterHeight(outerHeight);
if (heightChanged) {
- currentDependencyTree.markHeightAsChanged(component);
- doOverflowAutoFix(component);
+ onConnectorChange(component, false, true);
+ notifyListenersAndDepdendents(component.getWidget().getElement(),
+ false, true);
}
currentDependencyTree.setNeedsVerticalMeasure(component, false);
}
boolean widthChanged = measuredSize.setOuterWidth(outerWidth);
if (widthChanged) {
- currentDependencyTree.markWidthAsChanged(component);
- doOverflowAutoFix(component);
+ onConnectorChange(component, true, false);
+ notifyListenersAndDepdendents(component.getWidget().getElement(),
+ true, false);
}
currentDependencyTree.setNeedsHorizontalMeasure(component, false);
}
+
+ public void addElementResizeListener(Element element,
+ ElementResizeListener listener) {
+ Collection<ElementResizeListener> listeners = elementResizeListeners
+ .get(element);
+ if (listeners == null) {
+ listeners = new HashSet<ElementResizeListener>();
+ elementResizeListeners.put(element, listeners);
+ ensureMeasured(element);
+ }
+ listeners.add(listener);
+ }
+
+ public void removeElementResizeListener(Element element,
+ ElementResizeListener listener) {
+ Collection<ElementResizeListener> listeners = elementResizeListeners
+ .get(element);
+ if (listeners != null) {
+ listeners.remove(listener);
+ if (listeners.isEmpty()) {
+ elementResizeListeners.remove(element);
+ stopMeasuringIfUnecessary(element);
+ }
+ }
+ }
+
+ private void stopMeasuringIfUnecessary(Element element) {
+ if (!needsMeasure(element)) {
+ measuredNonPaintableElements.remove(element);
+ setMeasuredSize(element, null);
+ }
+ }
}
import com.vaadin.terminal.gwt.client.LayoutManager;
import com.vaadin.terminal.gwt.client.Paintable;
import com.vaadin.terminal.gwt.client.UIDL;
+import com.vaadin.terminal.gwt.client.ui.layout.ElementResizeEvent;
+import com.vaadin.terminal.gwt.client.ui.layout.ElementResizeListener;
import com.vaadin.ui.Form;
@Component(Form.class)
public class FormConnector extends AbstractComponentContainerConnector
- implements Paintable, SimpleManagedLayout {
+ implements Paintable {
public static class FormState extends AbstractFieldState {
private Connector layout;
}
+ private final ElementResizeListener footerResizeListener = new ElementResizeListener() {
+ public void onElementResize(ElementResizeEvent e) {
+ VForm form = getWidget();
+
+ int footerHeight;
+ if (form.footer != null) {
+ LayoutManager lm = getLayoutManager();
+ footerHeight = lm.getOuterHeight(form.footer.getElement());
+ } else {
+ footerHeight = 0;
+ }
+
+ form.fieldContainer.getStyle().setPaddingBottom(footerHeight,
+ Unit.PX);
+ form.footerContainer.getStyle()
+ .setMarginTop(-footerHeight, Unit.PX);
+ }
+ };
+
@Override
- public void init() {
+ public void onUnregister() {
VForm form = getWidget();
- getLayoutManager().registerDependency(this, form.footerContainer);
+ if (form.footer != null) {
+ getLayoutManager().removeElementResizeListener(
+ form.footer.getElement(), footerResizeListener);
+ }
}
@Override
.getFooter();
Widget newFooterWidget = newFooter.getWidget();
if (getWidget().footer == null) {
+ getLayoutManager().addElementResizeListener(
+ newFooterWidget.getElement(), footerResizeListener);
getWidget().add(newFooter.getWidget(),
getWidget().footerContainer);
getWidget().footer = newFooterWidget;
} else if (newFooter != getWidget().footer) {
+ getLayoutManager().removeElementResizeListener(
+ getWidget().footer.getElement(), footerResizeListener);
+ getLayoutManager().addElementResizeListener(
+ newFooterWidget.getElement(), footerResizeListener);
getWidget().remove(getWidget().footer);
getWidget().add(newFooter.getWidget(),
getWidget().footerContainer);
getWidget().footer = newFooterWidget;
} else {
if (getWidget().footer != null) {
+ getLayoutManager().removeElementResizeListener(
+ getWidget().footer.getElement(), footerResizeListener);
getWidget().remove(getWidget().footer);
+ getWidget().footer = null;
}
}
return GWT.create(VForm.class);
}
- public void layout() {
- VForm form = getWidget();
-
- LayoutManager lm = getLayoutManager();
- int footerHeight = lm.getOuterHeight(form.footerContainer)
- - lm.getMarginTop(form.footerContainer);
-
- form.fieldContainer.getStyle().setPaddingBottom(footerHeight, Unit.PX);
- form.footerContainer.getStyle().setMarginTop(-footerHeight, Unit.PX);
- }
-
@Override
public boolean isReadOnly() {
return super.isReadOnly() || getState().isPropertyReadOnly();