package org.sigmah.client.ui.presenter.base; /* * #%L * Sigmah * %% * Copyright (C) 2010 - 2016 URD * %% * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this program. If not, see * <http://www.gnu.org/licenses/gpl-3.0.html>. * #L% */ import java.util.ArrayList; import java.util.List; import org.sigmah.client.Sigmah; import org.sigmah.client.dispatch.DispatchAsync; import org.sigmah.client.event.EventBus; import org.sigmah.client.inject.Injector; import org.sigmah.client.ui.presenter.base.HasSubPresenter.SubPresenter; import org.sigmah.client.ui.view.base.AbstractView; import org.sigmah.client.ui.view.base.HasSubView; import org.sigmah.client.ui.view.base.ViewInterface; import org.sigmah.shared.command.result.Authentication; import com.allen_sauer.gwt.log.client.Log; import com.extjs.gxt.ui.client.widget.LayoutContainer; import com.google.gwt.event.shared.HandlerRegistration; import com.google.gwt.user.client.ui.Widget; import com.google.inject.Inject; import org.sigmah.client.util.profiler.Profiler; import org.sigmah.client.util.profiler.Scenario; /** * <p> * Abstract presenter. * </p> * <p> * <b>Rules to add a new presenter:</b> * <ol> * <li>Create a new class inheriting {@link AbstractPresenter} with {@link com.google.inject.Singleton} annotation or * not, depending on its uniqueness.</li> * <li>Define an inner <em>static</em> interface representing the presenter's view. This interface must have the * {@link com.google.inject.ImplementedBy} annotation referencing the view implementation (<u>crucial</u>). * See {@link AbstractView} javadoc to initialize the view implementation.</li> * <li>Add an accessor to the presenter into client-side {@link Injector} and call it into {@link Sigmah#onModuleLoad()} * entry point in order to register presenter.</li> * </ol> * </p> * <p> * <b>Utility methods provided to presenter implementations:</b> * <ul> * <li>{@link #auth()} to access the current authentication.</li> * <li>{@link #isAnonymous()} to check if no user is currently authenticated.</li> * </ul> * </p> * * @param <V> * Presenter's view interface extending the {@link ViewInterface} interface. * @author Denis Colliot (dcolliot@ideia.fr) * @author Tom Miette (tmiette@ideia.fr) */ public abstract class AbstractPresenter<V extends ViewInterface> implements Presenter<V> { /** * Events registrations handler. */ private final List<HandlerRegistration> handlerRegistrations; /** * Current zone presenter view. */ protected final V view; /** * Application event bus. */ protected final EventBus eventBus; /** * Application injector. */ protected final Injector injector; /** * Application command dispatcher. */ protected final DispatchAsync dispatch; /** * Flag indicating if the presenter has already been initialized. * Each presenter is initialized only once. */ private boolean initialized; /** * <p> * Default abstract presenter constructor. * </p> * <p> * Executes {@link #bind()} method. * </p> * * @param view * View associated to the presenter. * @param injector * Injected application injector allowing access to all useful objects. */ @Inject protected AbstractPresenter(V view, Injector injector) { this.injector = injector; this.eventBus = injector.getEventBus(); this.dispatch = injector.getDispatch(); this.view = view; this.handlerRegistrations = new ArrayList<HandlerRegistration>(); if (Log.isDebugEnabled()) { Log.debug("Binding '" + getClass() + "' presenter."); } bind(); } /** * {@inheritDoc} */ @Override final public V getView() { return view; } /** * {@inheritDoc} */ @Override public void bind() { // Default implementation does nothing. } /** * {@inheritDoc} */ @Override public void onBind() { // Default implementation does nothing. } /** * {@inheritDoc} */ @Override public void unbind() { for (final HandlerRegistration reg : handlerRegistrations) { reg.removeHandler(); } handlerRegistrations.clear(); onUnbind(); } /** * {@inheritDoc} */ @Override public void onUnbind() { // Default implementation does nothing. } /** * {@inheritDoc} */ @Override public final void initialize() { if (initialized) { return; } if (isSubPresenter()) { // Sub-presenter exception. final HasSubPresenter<?> parentPresenter = ((SubPresenter<?>) this).getParentPresenter(); parentPresenter.initialize(); } try { if (Log.isDebugEnabled()) { Log.debug("First initialization of '" + getClass().getName() + "'."); } view.initialize(); onBind(); } finally { // First load must be set to true. initialized = true; } } /** * {@inheritDoc} */ @Override public void revealView() { Profiler.INSTANCE.markCheckpoint(Scenario.OPEN_PROJECT, " revealView start "); if (Log.isTraceEnabled()) { Log.trace("Reveals '" + view.getClass().getName() + "' presenter's view."); } if (isSubPresenter()) { // Presenter's view is shown into parent presenter's placeholder. final HasSubPresenter<? extends HasSubView> parentPresenter = ((SubPresenter<?>) this).getParentPresenter(); final LayoutContainer placeHolder = parentPresenter.getView().getPlaceHolder(); placeHolder.removeAll(); placeHolder.add(Widget.asWidgetOrNull(getView())); injector.getApplicationPresenter().showPresenter(parentPresenter); placeHolder.layout(); } else { // Presenter's view is shown into application's main view. injector.getApplicationPresenter().showPresenter(this); } view.onViewRevealed(); onViewRevealed(); Profiler.INSTANCE.markCheckpoint(Scenario.OPEN_PROJECT, " revealView end "); } /** * {@inheritDoc} */ @Override public void beforeLeaving(EventBus.LeavingCallback callback) { // By default, the presenter is left. callback.leavingOk(); } // ------------------------------------------------------------------------ // // UTILITY METHODS. // // ------------------------------------------------------------------------ /** * 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 (does nothing if {@code null}). */ protected final void registerHandler(final HandlerRegistration handlerRegistration) { if (handlerRegistration == null) { return; } handlerRegistrations.add(handlerRegistration); } /** * Returns if this presenter has already been initialized. * * @return {@code true} if this presenter has already been initialized (i.e. already loaded once), {@code false} * otherwise. */ protected final boolean isInitialized() { return initialized; } /** * Returns if the current presenter is a <em>sub</em> presenter. * * @return {@code true} if the current presenter is a <em>sub</em> presenter. */ protected final boolean isSubPresenter() { return this instanceof SubPresenter; } /** * Checks if no user is currently authenticated. * * @return {@code true} if no user is currently authenticated, {@code false} otherwise. */ protected final boolean isAnonymous() { return injector.getAuthenticationProvider().isAnonymous(); } /** * Returns the current {@link Authentication}. * * @return The current {@link Authentication}, never {@code null}. */ protected final Authentication auth() { return injector.getAuthenticationProvider().get(); } /** * <p> * Method executed once the view has been rendered and the DOM has been created. * </p> * <em>Can be overridden by child implementation.</em>. */ protected void onViewRevealed() { // Default implementation does nothing. } }