]> source.dussan.org Git - vaadin-framework.git/commitdiff
Add attach and detach listeners and events to ClientConnector (#8579, #10251) 10/310/3
authorJohannes Dahlström <johannesd@vaadin.com>
Tue, 20 Nov 2012 17:04:55 +0000 (19:04 +0200)
committerJohannes Dahlström <johannesd@vaadin.com>
Wed, 21 Nov 2012 13:48:44 +0000 (15:48 +0200)
Change-Id: Ifda4b4a770fb7d330f0fe5d606f8415961a574a2

server/src/com/vaadin/server/AbstractClientConnector.java
server/src/com/vaadin/server/ClientConnector.java
server/src/com/vaadin/server/DragAndDropService.java
server/src/com/vaadin/ui/Component.java
server/tests/src/com/vaadin/tests/server/clientconnector/AttachDetachListeners.java [new file with mode: 0644]

index 45c6da7e7744ea9e02766c631fa41cfb213f8e67..8b5bd78d017c75449ae35ae2c2e126aa2e577e8a 100644 (file)
@@ -92,6 +92,30 @@ public abstract class AbstractClientConnector implements ClientConnector,
 
     private ErrorHandler errorHandler = null;
 
+    @Override
+    public void addAttachListener(AttachListener listener) {
+        addListener(AttachEvent.ATTACH_EVENT_IDENTIFIER, AttachEvent.class,
+                listener, AttachListener.attachMethod);
+    }
+
+    @Override
+    public void removeAttachListener(AttachListener listener) {
+        removeListener(AttachEvent.ATTACH_EVENT_IDENTIFIER, AttachEvent.class,
+                listener);
+    }
+
+    @Override
+    public void addDetachListener(DetachListener listener) {
+        addListener(DetachEvent.DETACH_EVENT_IDENTIFIER, DetachEvent.class,
+                listener, DetachListener.detachMethod);
+    }
+
+    @Override
+    public void removeDetachListener(DetachListener listener) {
+        removeListener(DetachEvent.DETACH_EVENT_IDENTIFIER, DetachEvent.class,
+                listener);
+    }
+
     /**
      * @deprecated As of 7.0.0, use {@link #markAsDirty()} instead
      */
@@ -568,10 +592,11 @@ public abstract class AbstractClientConnector implements ClientConnector,
 
         getUI().getConnectorTracker().registerConnector(this);
 
+        fireEvent(new AttachEvent(this));
+
         for (ClientConnector connector : getAllChildrenIterable(this)) {
             connector.attach();
         }
-
     }
 
     /**
@@ -588,6 +613,8 @@ public abstract class AbstractClientConnector implements ClientConnector,
             connector.detach();
         }
 
+        fireEvent(new DetachEvent(this));
+
         getUI().getConnectorTracker().unregisterConnector(this);
     }
 
@@ -950,7 +977,6 @@ public abstract class AbstractClientConnector implements ClientConnector,
         if (eventRouter != null) {
             eventRouter.fireEvent(event);
         }
-
     }
 
     /*
@@ -971,5 +997,4 @@ public abstract class AbstractClientConnector implements ClientConnector,
     public void setErrorHandler(ErrorHandler errorHandler) {
         this.errorHandler = errorHandler;
     }
-
 }
index 440f2825081d236c4c85e93d6b979c3e077dcb8a..4a09158da5349fb58c97fc4e05793253da932fd3 100644 (file)
 package com.vaadin.server;
 
 import java.io.IOException;
+import java.io.Serializable;
+import java.lang.reflect.Method;
 import java.util.Collection;
+import java.util.EventListener;
+import java.util.EventObject;
 import java.util.List;
 
 import org.json.JSONException;
@@ -27,6 +31,7 @@ import com.vaadin.shared.communication.SharedState;
 import com.vaadin.ui.Component;
 import com.vaadin.ui.ComponentContainer;
 import com.vaadin.ui.UI;
+import com.vaadin.util.ReflectTools;
 
 /**
  * Interface implemented by all connectors that are capable of communicating
@@ -37,6 +42,81 @@ import com.vaadin.ui.UI;
  * 
  */
 public interface ClientConnector extends Connector {
+
+    public static abstract class ConnectorEvent extends EventObject {
+        public ConnectorEvent(ClientConnector source) {
+            super(source);
+        }
+
+        public ClientConnector getConnector() {
+            return (ClientConnector) getSource();
+        }
+    }
+
+    /**
+     * Event fired after a connector is attached to the application.
+     */
+    public static class AttachEvent extends ConnectorEvent {
+        public static final String ATTACH_EVENT_IDENTIFIER = "clientConnectorAttach";
+
+        public AttachEvent(ClientConnector source) {
+            super(source);
+        }
+    }
+
+    /**
+     * Interface for listening {@link DetachEvent connector detach events}.
+     * 
+     */
+    public static interface AttachListener extends EventListener, Serializable {
+        public static final Method attachMethod = ReflectTools.findMethod(
+                AttachListener.class, "attach", AttachEvent.class);
+
+        /**
+         * Called when a AttachListener is notified of a AttachEvent.
+         * 
+         * @param event
+         *            The attach event that was fired.
+         */
+        public void attach(AttachEvent event);
+    }
+
+    /**
+     * Event fired before a connector is detached from the application.
+     */
+    public static class DetachEvent extends ConnectorEvent {
+        public static final String DETACH_EVENT_IDENTIFIER = "clientConnectorDetach";
+
+        public DetachEvent(ClientConnector source) {
+            super(source);
+        }
+    }
+
+    /**
+     * Interface for listening {@link DetachEvent connector detach events}.
+     * 
+     */
+    public static interface DetachListener extends EventListener, Serializable {
+        public static final Method detachMethod = ReflectTools.findMethod(
+                DetachListener.class, "detach", DetachEvent.class);
+
+        /**
+         * Called when a DetachListener is notified of a DetachEvent.
+         * 
+         * @param event
+         *            The detach event that was fired.
+         */
+        public void detach(DetachEvent event);
+    }
+
+    public void addAttachListener(AttachListener listener);
+
+    public void removeAttachListener(AttachListener listener);
+
+    public void addDetachListener(DetachListener listener);
+
+    public void removeDetachListener(DetachListener listener);
+
     /**
      * An error event for connector related errors. Use {@link #getConnector()}
      * to find the connector where the error occurred or {@link #getComponent()}
@@ -174,13 +254,13 @@ public interface ClientConnector extends Connector {
     public void attach();
 
     /**
-     * Notifies the component that it is detached from the application.
+     * Notifies the connector that it is detached from the application.
      * 
      * <p>
      * The caller of this method is {@link #setParent(ClientConnector)} if the
      * parent is in the application. When the parent is detached from the
-     * application it is its response to call {@link #detach()} for all the
-     * children and to detach itself from the terminal.
+     * application it is its responsibility to call {@link #detach()} for each
+     * of its children.
      * </p>
      */
     public void detach();
index 0fa39fa0e82c29dbb7b3d76d1d43c7353d2f547c..529cce670eae8b2feb2c009fe5473ce744d64440 100644 (file)
@@ -358,4 +358,20 @@ public class DragAndDropService implements VariableOwner, ClientConnector {
     public void setErrorHandler(ErrorHandler errorHandler) {
         this.errorHandler = errorHandler;
     }
+
+    @Override
+    public void addAttachListener(AttachListener listener) {
+    }
+
+    @Override
+    public void removeAttachListener(AttachListener listener) {
+    }
+
+    @Override
+    public void addDetachListener(DetachListener listener) {
+    }
+
+    @Override
+    public void removeDetachListener(DetachListener listener) {
+    }
 }
index 85140a83516fb534957fd0bf5bd0d905e7ce84e8..afde1cdbdf49e71e8ed2ce26d67a2538f8f22240 100644 (file)
@@ -18,7 +18,6 @@ package com.vaadin.ui;
 
 import java.io.Serializable;
 import java.util.EventListener;
-import java.util.EventObject;
 import java.util.Locale;
 
 import com.vaadin.event.FieldEvents;
@@ -580,11 +579,6 @@ public interface Component extends ClientConnector, Sizeable, Serializable {
      * application, the {@code attach()} is called immediately from
      * {@link #setParent(Component)}.
      * </p>
-     * <p>
-     * This method must call {@link UI#componentAttached(Component)} to let the
-     * UI know that a new Component has been attached.
-     * </p>
-     * 
      * 
      * <pre>
      * public class AttachExample extends CustomComponent {
@@ -735,7 +729,7 @@ public interface Component extends ClientConnector, Sizeable, Serializable {
      * @see Component.Listener
      */
     @SuppressWarnings("serial")
-    public static class Event extends EventObject {
+    public static class Event extends ConnectorEvent {
 
         /**
          * Constructs a new event with the specified source component.
diff --git a/server/tests/src/com/vaadin/tests/server/clientconnector/AttachDetachListeners.java b/server/tests/src/com/vaadin/tests/server/clientconnector/AttachDetachListeners.java
new file mode 100644 (file)
index 0000000..f5b940d
--- /dev/null
@@ -0,0 +1,180 @@
+/*
+@VaadinApache2LicenseForJavaFiles@
+ */
+
+package com.vaadin.tests.server.clientconnector;
+
+import org.easymock.EasyMock;
+import org.easymock.IArgumentMatcher;
+import org.easymock.IMocksControl;
+import org.junit.Before;
+import org.junit.Test;
+
+import com.vaadin.server.ClientConnector.AttachEvent;
+import com.vaadin.server.ClientConnector.AttachListener;
+import com.vaadin.server.ClientConnector.ConnectorEvent;
+import com.vaadin.server.ClientConnector.DetachEvent;
+import com.vaadin.server.ClientConnector.DetachListener;
+import com.vaadin.server.VaadinRequest;
+import com.vaadin.server.VaadinService;
+import com.vaadin.server.VaadinSession;
+import com.vaadin.ui.Component;
+import com.vaadin.ui.CssLayout;
+import com.vaadin.ui.Label;
+import com.vaadin.ui.Layout;
+import com.vaadin.ui.UI;
+
+public class AttachDetachListeners {
+
+    private IMocksControl control;
+
+    private VaadinSession session;
+    private UI ui;
+    private Layout content;
+    private Component component;
+
+    AttachListener attachListener;
+    DetachListener detachListener;
+
+    @Before
+    public void setUp() {
+        control = EasyMock.createStrictControl();
+
+        session = new VaadinSession(control.createMock(VaadinService.class));
+
+        ui = new UI() {
+            @Override
+            protected void init(VaadinRequest request) {
+            }
+        };
+        content = new CssLayout();
+        component = new Label();
+
+        attachListener = control.createMock(AttachListener.class);
+        detachListener = control.createMock(DetachListener.class);
+    }
+
+    @Test
+    public void attachListeners_setSessionLast() {
+        setupAttachListeners();
+
+        ui.setContent(content);
+        content.addComponent(component);
+        ui.setSession(session);
+
+        control.verify();
+    }
+
+    @Test
+    public void attachListeners_setSessionFirst() {
+        setupAttachListeners();
+
+        ui.setSession(session);
+        ui.setContent(content);
+        content.addComponent(component);
+
+        control.verify();
+    }
+
+    @Test
+    public void attachListeners_setSessionBetween() {
+        setupAttachListeners();
+
+        ui.setContent(content);
+        ui.setSession(session);
+        content.addComponent(component);
+
+        control.verify();
+    }
+
+    @Test
+    public void detachListeners_setSessionNull() {
+        setupDetachListeners();
+
+        ui.setContent(content);
+        content.addComponent(component);
+        ui.setSession(null);
+
+        control.verify();
+    }
+
+    @Test
+    public void detachListeners_removeComponent() {
+        setupDetachListeners();
+
+        ui.setContent(content);
+        content.addComponent(component);
+        content.removeAllComponents();
+        ui.setSession(null);
+
+        control.verify();
+    }
+
+    @Test
+    public void detachListeners_setContentNull() {
+        setupDetachListeners();
+
+        ui.setContent(content);
+        content.addComponent(component);
+        ui.setContent(null);
+        ui.setSession(null);
+
+        control.verify();
+    }
+
+    public static class EventEquals<E extends ConnectorEvent> implements
+            IArgumentMatcher {
+
+        private E expected;
+
+        public EventEquals(E expected) {
+            this.expected = expected;
+        }
+
+        @Override
+        public void appendTo(StringBuffer buffer) {
+            buffer.append("EventEquals(");
+            buffer.append("expected " + expected.getClass().getSimpleName()
+                    + " with connector " + expected.getConnector());
+            buffer.append(")");
+        }
+
+        @Override
+        public boolean matches(Object argument) {
+            return expected.getClass().isInstance(argument)
+                    && ((ConnectorEvent) argument).getConnector() == expected
+                            .getConnector();
+        }
+    }
+
+    public static <E extends ConnectorEvent> E eventEquals(E expected) {
+        EasyMock.reportMatcher(new EventEquals<E>(expected));
+        return null;
+    }
+
+    private void setupDetachListeners() {
+        detachListener.detach(eventEquals(new DetachEvent(component)));
+        detachListener.detach(eventEquals(new DetachEvent(content)));
+        detachListener.detach(eventEquals(new DetachEvent(ui)));
+
+        control.replay();
+
+        ui.addDetachListener(detachListener);
+        content.addDetachListener(detachListener);
+        component.addDetachListener(detachListener);
+
+        ui.setSession(session);
+    }
+
+    private void setupAttachListeners() {
+        attachListener.attach(eventEquals(new AttachEvent(ui)));
+        attachListener.attach(eventEquals(new AttachEvent(content)));
+        attachListener.attach(eventEquals(new AttachEvent(component)));
+
+        control.replay();
+
+        ui.addAttachListener(attachListener);
+        content.addAttachListener(attachListener);
+        component.addAttachListener(attachListener);
+    }
+}