package org.sigmah.client.dispatch.monitor; /* * #%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 org.sigmah.client.i18n.I18N; import org.sigmah.client.ui.widget.Loadable; import com.extjs.gxt.ui.client.event.BaseEvent; import com.extjs.gxt.ui.client.event.ComponentEvent; import com.extjs.gxt.ui.client.event.EventType; import com.extjs.gxt.ui.client.event.Events; import com.extjs.gxt.ui.client.event.Listener; import com.extjs.gxt.ui.client.widget.Component; import com.extjs.gxt.ui.client.widget.Container; /** * <p> * Uses a GXT loading mask on a component to keep the user updated on the progress of an asynchronous call. * </p> * <p> * The monitor allows a limited number of retries (defaults to two) before giving up. * </p> * * @author Denis Colliot (dcolliot@ideia.fr) */ public class LoadingMask implements Loadable { private final String loadingText; private final Component component; private boolean loading; /** * <p> * Initializes a new loading mask for the given {@code component}. * </p> * <p> * Default loading text will be used. To specify custom loading text, see {@link #LoadingMask(Component, String)}. * </p> * * @param component * The GXT component. */ public LoadingMask(final Component component) { this(component, I18N.CONSTANTS.loading()); } /** * Initializes a new loading mask for the given {@code component} with the given {@code loadingText}. * * @param component * The GXT component. * @param loadingText * The custom loading text. */ public LoadingMask(final Component component, final String loadingText) { this.component = component; this.loadingText = loadingText; } protected final Component getComponent() { return component; } /** * {@inheritDoc} */ @Override public final void setLoading(final boolean loading) { this.loading = loading; if (loading) { mask(); } else { unmask(); } } /** * {@inheritDoc} */ @Override public final boolean isLoading() { return loading; } protected final void mask() { if (component == null) { return; } if (component.isRendered()) { // If the component is already rendered, apply mask immediately. handleRenderEvent(null, null); } else { // If the component is not rendered yet, wait until after it is all layed out before applying the mask. final EventType eventType = component instanceof Container ? Events.AfterLayout : Events.Render; component.addListener(eventType, new Listener<ComponentEvent>() { @Override public void handleEvent(final ComponentEvent be) { handleRenderEvent(eventType, this); } }); } } protected final void unmask() { if (component == null) { return; } if (component.isRendered()) { component.unmask(); onUnmask(); } } private void handleRenderEvent(final EventType eventType, final Listener<? extends BaseEvent> listener) { if (isLoading()) { // If the call is still in progress, apply the mask. component.el().mask(loadingText); } if (listener != null && eventType != null) { // If a listener has been registered, remove it. component.removeListener(eventType, listener); } onMask(); } /** * Method called when the component is masked.<br> * <em>Default implementation does nothing.</em> */ protected void onMask() { // Default implementation does nothing. } /** * Method called when the component is unmasked.<br> * <em>Default implementation does nothing.</em> */ protected void onUnmask() { // Default implementation does nothing. } }