From 5f0ac5ea9c7bbcb2e3bb3182ae9eb19d48ef2b8b Mon Sep 17 00:00:00 2001 From: =?utf8?q?Leif=20=C3=85strand?= Date: Thu, 5 Apr 2012 13:53:21 +0300 Subject: [PATCH] Implement support for ElementResizeListener --- .../terminal/gwt/client/LayoutManager.java | 164 +++++++++++++----- .../terminal/gwt/client/ui/FormConnector.java | 50 ++++-- .../client/ui/layout/ElementResizeEvent.java | 25 +++ .../ui/layout/ElementResizeListener.java | 9 + 4 files changed, 189 insertions(+), 59 deletions(-) create mode 100644 src/com/vaadin/terminal/gwt/client/ui/layout/ElementResizeEvent.java create mode 100644 src/com/vaadin/terminal/gwt/client/ui/layout/ElementResizeListener.java diff --git a/src/com/vaadin/terminal/gwt/client/LayoutManager.java b/src/com/vaadin/terminal/gwt/client/LayoutManager.java index 98784a0d7d..a9a58845b4 100644 --- a/src/com/vaadin/terminal/gwt/client/LayoutManager.java +++ b/src/com/vaadin/terminal/gwt/client/LayoutManager.java @@ -18,13 +18,15 @@ import com.vaadin.terminal.gwt.client.ui.ManagedLayout; 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 nonPaintableElements = new HashSet(); + private final Set measuredNonPaintableElements = new HashSet(); private final MeasuredSize nullSize = new MeasuredSize(); private LayoutDependencyTree currentDependencyTree; @@ -34,6 +36,9 @@ public class LayoutManager { private final Collection pendingOverflowFixes = new HashSet(); + private final Map> elementResizeListeners = new HashMap>(); + private final Set listenersToFire = new HashSet(); + public void setConnection(ApplicationConnection connection) { if (this.connection != null) { throw new RuntimeException( @@ -58,7 +63,7 @@ public class LayoutManager { measuredSize = new MeasuredSize(); if (ConnectorMap.get(connection).getConnector(element) == null) { - nonPaintableElements.add(element); + measuredNonPaintableElements.add(element); } setMeasuredSize(element, measuredSize); } @@ -68,6 +73,8 @@ public class LayoutManager { 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 { @@ -91,8 +98,8 @@ public class LayoutManager { 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(); @@ -107,10 +114,7 @@ public class LayoutManager { return; } measuredSize.removeDependent(owner.getConnectorId()); - if (!needsMeasure(element)) { - nonPaintableElements.remove(element); - setMeasuredSize(element, null); - } + stopMeasuringIfUnecessary(element); } public boolean isLayoutRunning() { @@ -154,7 +158,7 @@ public class LayoutManager { } needsHorizontalLayout.clear(); needsVerticalLayout.clear(); - measureNonPaintables(currentDependencyTree); + measureNonPaintables(); VConsole.log("Layout init in " + totalDuration.elapsedMillis() + " ms"); @@ -169,6 +173,26 @@ public class LayoutManager { VConsole.log(" Measured " + measuredConnectorCount + " elements in " + measureTime + " ms"); + if (!listenersToFire.isEmpty()) { + for (Element element : listenersToFire) { + Collection 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() @@ -310,7 +334,7 @@ public class LayoutManager { ComponentConnector[] connectors = ConnectorMap.get(connection) .getComponentConnectors(); for (ComponentConnector connector : connectors) { - measueConnector(layoutDependencyTree, connector); + measueConnector(connector); } for (ComponentConnector connector : connectors) { layoutDependencyTree.setNeedsMeasure(connector, false); @@ -322,7 +346,7 @@ public class LayoutManager { Collection measureTargets = layoutDependencyTree .getMeasureTargets(); for (ComponentConnector connector : measureTargets) { - measueConnector(layoutDependencyTree, connector); + measueConnector(connector); measureCount++; } for (ComponentConnector connector : measureTargets) { @@ -332,21 +356,25 @@ public class LayoutManager { 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); } } @@ -359,37 +387,49 @@ public class LayoutManager { } } - 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) { @@ -499,8 +539,9 @@ public class LayoutManager { 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); } @@ -539,9 +580,42 @@ public class LayoutManager { 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 listeners = elementResizeListeners + .get(element); + if (listeners == null) { + listeners = new HashSet(); + elementResizeListeners.put(element, listeners); + ensureMeasured(element); + } + listeners.add(listener); + } + + public void removeElementResizeListener(Element element, + ElementResizeListener listener) { + Collection 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); + } + } } diff --git a/src/com/vaadin/terminal/gwt/client/ui/FormConnector.java b/src/com/vaadin/terminal/gwt/client/ui/FormConnector.java index 8e05522eb5..3a15a4949a 100644 --- a/src/com/vaadin/terminal/gwt/client/ui/FormConnector.java +++ b/src/com/vaadin/terminal/gwt/client/ui/FormConnector.java @@ -14,11 +14,13 @@ import com.vaadin.terminal.gwt.client.Connector; 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; @@ -42,10 +44,32 @@ public class FormConnector extends AbstractComponentContainerConnector } + 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 @@ -115,10 +139,16 @@ public class FormConnector extends AbstractComponentContainerConnector .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); @@ -126,7 +156,10 @@ public class FormConnector extends AbstractComponentContainerConnector getWidget().footer = newFooterWidget; } else { if (getWidget().footer != null) { + getLayoutManager().removeElementResizeListener( + getWidget().footer.getElement(), footerResizeListener); getWidget().remove(getWidget().footer); + getWidget().footer = null; } } @@ -182,17 +215,6 @@ public class FormConnector extends AbstractComponentContainerConnector 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(); diff --git a/src/com/vaadin/terminal/gwt/client/ui/layout/ElementResizeEvent.java b/src/com/vaadin/terminal/gwt/client/ui/layout/ElementResizeEvent.java new file mode 100644 index 0000000000..a519f5db87 --- /dev/null +++ b/src/com/vaadin/terminal/gwt/client/ui/layout/ElementResizeEvent.java @@ -0,0 +1,25 @@ +/* +@VaadinApache2LicenseForJavaFiles@ + */ +package com.vaadin.terminal.gwt.client.ui.layout; + +import com.google.gwt.dom.client.Element; +import com.vaadin.terminal.gwt.client.LayoutManager; + +public class ElementResizeEvent { + private final Element element; + private final LayoutManager layoutManager; + + public ElementResizeEvent(LayoutManager layoutManager, Element element) { + this.layoutManager = layoutManager; + this.element = element; + } + + public Element getElement() { + return element; + } + + public LayoutManager getLayoutManager() { + return layoutManager; + } +} diff --git a/src/com/vaadin/terminal/gwt/client/ui/layout/ElementResizeListener.java b/src/com/vaadin/terminal/gwt/client/ui/layout/ElementResizeListener.java new file mode 100644 index 0000000000..d6d3de48b8 --- /dev/null +++ b/src/com/vaadin/terminal/gwt/client/ui/layout/ElementResizeListener.java @@ -0,0 +1,9 @@ +/* +@VaadinApache2LicenseForJavaFiles@ + */ + +package com.vaadin.terminal.gwt.client.ui.layout; + +public interface ElementResizeListener { + public void onElementResize(ElementResizeEvent e); +} \ No newline at end of file -- 2.39.5