]> source.dussan.org Git - vaadin-framework.git/commitdiff
Implement support for ElementResizeListener
authorLeif Åstrand <leif@vaadin.com>
Thu, 5 Apr 2012 10:53:21 +0000 (13:53 +0300)
committerLeif Åstrand <leif@vaadin.com>
Thu, 5 Apr 2012 10:53:21 +0000 (13:53 +0300)
src/com/vaadin/terminal/gwt/client/LayoutManager.java
src/com/vaadin/terminal/gwt/client/ui/FormConnector.java
src/com/vaadin/terminal/gwt/client/ui/layout/ElementResizeEvent.java [new file with mode: 0644]
src/com/vaadin/terminal/gwt/client/ui/layout/ElementResizeListener.java [new file with mode: 0644]

index 98784a0d7d67a05ee5d7343633e7be48b585df10..a9a58845b47c684a1ed545e1de35029099920a98 100644 (file)
@@ -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<Element> nonPaintableElements = new HashSet<Element>();
+    private final Set<Element> measuredNonPaintableElements = new HashSet<Element>();
     private final MeasuredSize nullSize = new MeasuredSize();
 
     private LayoutDependencyTree currentDependencyTree;
@@ -34,6 +36,9 @@ public class LayoutManager {
 
     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(
@@ -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<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()
@@ -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<ComponentConnector> 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<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);
+        }
+    }
 }
index 8e05522eb51adb85434d40e4afbedecf4b860b93..3a15a4949a5e13b072ccb90971ff92ea578caf4c 100644 (file)
@@ -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 (file)
index 0000000..a519f5d
--- /dev/null
@@ -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 (file)
index 0000000..d6d3de4
--- /dev/null
@@ -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