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
*/
getUI().getConnectorTracker().registerConnector(this);
+ fireEvent(new AttachEvent(this));
+
for (ClientConnector connector : getAllChildrenIterable(this)) {
connector.attach();
}
-
}
/**
connector.detach();
}
+ fireEvent(new DetachEvent(this));
+
getUI().getConnectorTracker().unregisterConnector(this);
}
if (eventRouter != null) {
eventRouter.fireEvent(event);
}
-
}
/*
public void setErrorHandler(ErrorHandler errorHandler) {
this.errorHandler = errorHandler;
}
-
}
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;
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
*
*/
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()}
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();
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) {
+ }
}
import java.io.Serializable;
import java.util.EventListener;
-import java.util.EventObject;
import java.util.Locale;
import com.vaadin.event.FieldEvents;
* 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 {
* @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.
--- /dev/null
+/*
+@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);
+ }
+}