package com.gwt.mvp.client.presenter; import java.util.ArrayList; import java.util.List; import com.google.gwt.event.shared.HandlerRegistration; import com.gwt.mvp.client.Display; import com.gwt.mvp.client.EventBus; import com.gwt.mvp.client.Presenter; import com.gwt.mvp.client.event.PresenterChangedEvent; import com.gwt.mvp.client.event.PresenterRevealedEvent; import com.gwt.mvp.client.presenter.notify.NotifyMessageEvent; /** * <code>BasePresenter<code> implement all basic for each presenter. * <p /> * Lazy initialization of <code>Display</code> (Based on idea found here @see http://borglin.net/gwt-project/ ). * <p /> * Based on initial work of David Peterson (@see project gwt-presenter-1.1.1-replace)). Here, we add special mechanism for reveal/dispose * display on request. * * * @author jguibert * */ public abstract class BasePresenter<D extends Display> implements Presenter { /** * Flag to manage display initialization. trie if the presenter is in a 'revealed' state. */ private boolean revealed; /** * true if the presenter is currently in a 'bound' state. */ private boolean bound; /** * The display for the presenter. */ protected final D display; /** * The {@link EventBus} for the application. */ protected final EventBus eventBus; /** * List of <code>HandlerRegistration</code>. */ private final List<HandlerRegistration> handlerRegistrations; /** * Build a new instance of <code>BasePresenter</code>. * * @param display * display instance * @param eventBus * event bus instance */ public BasePresenter(final D display, final EventBus eventBus) { super(); this.display = display; this.eventBus = eventBus; revealed = false; bound = false; handlerRegistrations = new ArrayList<HandlerRegistration>(); } @Override public void bind() { if (!bound) { bound = true; onBind(); } } @Override public void unbind() { if (bound) { bound = false; for (HandlerRegistration reg : handlerRegistrations) { reg.removeHandler(); } handlerRegistrations.clear(); disposeDisplay(); onUnbind(); } } /** * This method is called when binding the presenter. Any additional bindings * should be done here. */ protected abstract void onBind(); /** * This method is called when unbinding the presenter. Any handler * registrations recorded with {@link #registerHandler(HandlerRegistration)} will have already been removed at this point. */ protected abstract void onUnbind(); /** * Any {@link HandlerRegistration}s added will be removed when {@link #unbind()} is called. This provides a handy way to track event * handler registrations when binding and unbinding. * * @param handlerRegistration The registration. */ protected void registerHandler(final HandlerRegistration handlerRegistration) { handlerRegistrations.add(handlerRegistration); } /** * Checks if the presenter has been bound. Will be set to false after a call * to {@link #unbind()}. * * @return The current bound status. */ @Override public boolean isBound() { return bound; } /** * Returns the display for the presenter. * * @return The display. */ @Override public D getDisplay() { return display; } /** * Fires a {@link PresenterChangedEvent} to the {@link EventBus}. * Call this method any time the presenter's state has been modified. */ protected void firePresenterChangedEvent() { eventBus.fireEvent(new PresenterChangedEvent(this)); } /** * Fires a {@link PresenterRevealedEvent} to the {@link EventBus}. * Implementations should call this when the presenter has been * revealed onscreen. * * @param originator If set to true, this specifies that this presenter * was the originator of the 'revelation' request. */ protected void firePresenterRevealedEvent(final boolean originator) { eventBus.fireEvent(new PresenterRevealedEvent(this, originator)); } /** * Triggers a {@link PresenterRevealedEvent}. Subclasses should override * this method and call <code>super.revealDisplay()</code> if they need to * perform extra operations when being revealed. */ @Override public void revealDisplay() { if (!revealed) { revealed = true; /** initialize view */ display.init(); /** On reveal display */ onRevealDisplay(); firePresenterRevealedEvent(true); } } /** * Checks if the presenter has been revealed. Will be set to false after a call * to {@link #disposeDisplay()}. * * @return The current revealed status. */ @Override public boolean isRevealed() { return revealed; } /** * Called before firing a {@link PresenterRevealedEvent}. * Add all handler associated with the display here. */ protected abstract void onRevealDisplay(); /** * Dispose Display. Call @see {@link #onDisposeDisplay()}. */ @Override public void disposeDisplay() { if (revealed) { revealed = false; display.dispose(); onDisposeDisplay(); } } /** * This method is called after display disposed. * You could remove all display handler here. */ protected abstract void onDisposeDisplay(); @Override public String toString() { return getClass().getName(); } /** * Send a message to the user {@link NotifyMessageEvent}. * * @param message message to send */ protected void notifyMessage(String message) { eventBus.fireEvent(new NotifyMessageEvent(message)); } /** * Send a message to the user. * * @param message message to send * @param delayMillis time to live of this message */ protected void notifyMessage(String message, int delayMillis) { eventBus.fireEvent(new NotifyMessageEvent(message, delayMillis)); } /** * Inner implementation of BoundListener */ private class InnerBoundListener implements BoundListener { private final BasePresenter<?> target; public InnerBoundListener(final BasePresenter<?> target) { this.target = target; } @Override public void onBind() { target.onBind(); } @Override public void onUnbind() { target.onUnbind(); } } /** * Inner Implementation of DisplayListener. */ private class InnerDisplayListener implements DisplayListener { private final BasePresenter<?> target; public InnerDisplayListener(final BasePresenter<?> target) { this.target = target; } @Override public void onRevealDisplay() { target.onRevealDisplay(); } @Override public void onDisposeDisplay() { target.onDisposeDisplay(); } } }