org.sigmah.client.ui.presenter.base.AbstractPresenter.java Source code

Java tutorial

Introduction

Here is the source code for org.sigmah.client.ui.presenter.base.AbstractPresenter.java

Source

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;

/**
 * <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() {

        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();
    }

    /**
     * {@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.
    }

}