/*
* This is part of Geomajas, a GIS framework, http://www.geomajas.org/.
*
* Copyright 2008-2015 Geosparc nv, http://www.geosparc.com/, Belgium.
*
* The program is available in open source according to the GNU Affero
* General Public License. All contributions in this program are covered
* by the Geomajas Contributors License Agreement. For full licensing
* details, see LICENSE.txt in the project root.
*/
package org.geomajas.gwt.client.widget;
import org.geomajas.annotation.Api;
import org.geomajas.gwt.client.command.GwtCommandDispatcher;
import org.geomajas.gwt.client.command.event.DispatchStoppedEvent;
import org.geomajas.gwt.client.command.event.DispatchStoppedHandler;
import org.geomajas.gwt.client.i18n.I18nProvider;
import org.geomajas.gwt.client.map.event.MapModelEvent;
import org.geomajas.gwt.client.map.event.MapModelHandler;
import org.geomajas.gwt.client.util.Dom;
import org.geomajas.gwt.client.util.WidgetLayout;
import com.google.gwt.event.shared.HandlerRegistration;
import com.google.gwt.user.client.Timer;
import com.google.gwt.user.client.ui.Widget;
import com.smartgwt.client.types.Alignment;
import com.smartgwt.client.types.Cursor;
import com.smartgwt.client.types.VerticalAlignment;
import com.smartgwt.client.widgets.AnimationCallback;
import com.smartgwt.client.widgets.Img;
import com.smartgwt.client.widgets.Label;
import com.smartgwt.client.widgets.Progressbar;
import com.smartgwt.client.widgets.layout.HLayout;
import com.smartgwt.client.widgets.layout.LayoutSpacer;
import com.smartgwt.client.widgets.layout.VLayout;
/**
* <p>
* A widget that covers the entire browser window, displaying application loading progress, and that fades out after the
* application has been loaded. Your basic loading screen.
* </p>
* <p>
* A {@link View} strategy can be passed to the constructor to determine the appearance of the loading screen. Two
* strategies have been implemented:
* <ul>
* <li>{@link DefaultView} is the default strategy. This strategy displays a Geomajas logo, a title, and a progress bar
* that shows the loading progress. Both the logo width/height and the title can be changed to your wishes. The title is
* given to the constructor and the logo (together with it's width) can be given through getters and setters. Note that
* you have to set these before you call the draw. Also note that when setting a new logo, you have to set it's width
* and height. This width may not be larger than 480 pixels for the default.
* <li>{@link LogoOnlyView} is a strategy that just shows the logo. The logo and its width/height can be changed to your
* wishes, either through setters or through the {@link WidgetLayout} properties.
* </ul>
* </p>
* <p>
*
* </p>
* <p>
* Use: add this loading screen to the main page by calling it's {#link #draw()} method. Do this AFTER you have drawn
* your application layout, so the loading screen is placed on top of it.
* </p>
*
* @author Pieter De Graef
* @author Jan De Moerloose
* @since 1.10.0
*/
@Api(allMethods = true)
public class LoadingScreen extends VLayout {
private HandlerRegistration onLoadRegistration;
private HandlerRegistration onDispatchStopRegistration;
private View view;
private int progressPercentage;
private boolean fadingDone;
// -------------------------------------------------------------------------
// Constructor:
// -------------------------------------------------------------------------
/**
* Create a loading screen given the main map and a title to be displayed. This screen uses the
* {@link DefaultView} strategy.
*
* @param mapWidget The main map
* @param applicationTitle The application's title. This will be displayed right under the logo image.
*/
public LoadingScreen(MapWidget mapWidget, String applicationTitle) {
this(mapWidget, new DefaultView(applicationTitle));
}
/**
* Create a loading screen given the main map and a {@link View} strategy to be used.
*
* @param mapWidget
* The main map
* @param view
* The view object to use.
*/
public LoadingScreen(MapWidget mapWidget, View view) {
this.view = view;
setCursor(Cursor.WAIT);
addMember(view.getWidget());
setBackgroundColor(WidgetLayout.loadingScreenBackgroundColor);
setHeight100();
setWidth100();
setAlign(VerticalAlignment.CENTER);
setAlign(Alignment.CENTER);
// make sure we always fade out after 20s !
final MapWidget m = mapWidget;
Timer t = new Timer() {
@Override
public void run() {
fadeOut(m);
}
};
t.schedule(20000);
registerMap(mapWidget);
}
// -------------------------------------------------------------------------
// Getters and setters:
// -------------------------------------------------------------------------
/**
* Set a new image width for the logo. This should be done when a new logo image has been set.
*
* @param logoWidth
* The width of the logo image to be used.
*/
public void setLogoWidth(String logoWidth) {
view.setLogoWidth(logoWidth);
}
/**
* Set a new image height for the logo. This should be done when a new logo image has been set.
*
* @param logoHeight
* The height of the logo image to be used.
*/
public void setLogoHeight(String logoHeight) {
view.setLogoHeight(logoHeight);
}
/**
* Set a new URL to a new logo image to be used in this loading screen. After using this method, also set the
* image's width.
*
* @param logo logo
*/
public void setLogo(String logo) {
view.setLogo(logo);
}
// -------------------------------------------------------------------------
// Private methods:
// -------------------------------------------------------------------------
private void registerMap(final MapWidget mapWidget) {
if (mapWidget != null) {
onLoadRegistration = mapWidget.getMapModel().addMapModelHandler(new MapModelHandler() {
public void onMapModelChange(MapModelEvent event) {
onLoadRegistration.removeHandler();
view.onLoadStart();
if (GwtCommandDispatcher.getInstance().isBusy()) {
onDispatchStopRegistration = GwtCommandDispatcher.getInstance().addDispatchStoppedHandler(
new DispatchStoppedHandler() {
public void onDispatchStopped(DispatchStoppedEvent event) {
fadeOut(mapWidget);
}
});
} else {
fadeOut(mapWidget);
}
}
});
}
}
protected void onDraw() {
super.onDraw();
Timer timer = new Timer() {
public void run() {
progressPercentage += 10;
view.onLoadProgress(progressPercentage);
if (progressPercentage < 100) {
schedule(50);
}
}
};
timer.schedule(50);
}
private void fadeOut(final MapWidget mapWidget) {
if (!fadingDone) {
// progressBar.setPercentDone(100);
view.onLoadStop();
if (onDispatchStopRegistration != null) {
onDispatchStopRegistration.removeHandler();
}
setCursor(Cursor.DEFAULT);
setAnimateTime(1000);
if (!Dom.isIE()) {
// TODO Why should IE have a different approach??
mapWidget.setResizedHandlerDisabled(true);
}
animateFade(0, new AnimationCallback() {
public void execute(boolean earlyFinish) {
mapWidget.setResizedHandlerDisabled(false);
LoadingScreen.this.destroy();
}
});
fadingDone = true;
}
}
/**
* View strategy to be implemented by UI part of the loading screen. As a minimum, a {@link View} should implement
* the {@link #getWidget()} method. The returned widget will be shown in the center of the screen.
*
* @author Jan De Moerloose
* @since 1.10.0
*
*/
@Api(allMethods = true)
public interface View {
/**
* Returns this view's widget.
*
* @return the widget
*/
Widget getWidget();
/**
* Called when loading of the map is started.
*/
void onLoadStart();
/**
* Called at regular time intervals to indicate progress (fake percentage).
*
* @param progressPercentage percentage of progress passed (0-100)
*/
void onLoadProgress(int progressPercentage);
/**
* Called when loading of the map is done or more than 20 seconds have passed.
*/
void onLoadStop();
/**
* Set a new image width for the logo. This should be done when a new logo image has been set.
*
* @param logoWidth The width of the logo image to be used.
*/
void setLogoWidth(String logoWidth);
/**
* Set a new image height for the logo. This should be done when a new logo image has been set.
*
* @param logoHeight
* The height of the logo image to be used.
*/
void setLogoHeight(String logoHeight);
/**
* Set a new URL to a new logo image to be used in this loading screen. After using this method, also set the
* image's width.
*
* @param logo logo
*/
void setLogo(String logo);
}
/**
* Default implementation of UI part. This implementation displays a Geomajas logo, a title, and a progress bar that
* shows the loading progress. Both the logo width/height and the title can be changed to your wishes. The title is
* given to the constructor and the logo (together with it's width) can be given through getters and setters. Note
* that you have to set these before you call the draw. Also note that when setting a new logo, you have to set it's
* width and height. This width may not be larger than 480 pixels for the default.
*
* @author Jan De Moerloose
* @since 1.10.0
*
*/
@Api(allMethods = true)
public static class DefaultView extends HLayout implements View {
private String logoWidth = WidgetLayout.loadingScreenLogoWidth;
private String logoHeight = WidgetLayout.loadingScreenLogoHeight;
private String logo = WidgetLayout.loadingScreenLogo;
private Label label;
private Progressbar progressBar;
/**
* Construct a default UI with the specified title.
*
* @param applicationTitle title to display
*/
public DefaultView(String applicationTitle) {
VLayout banner = new VLayout();
banner.setLayoutAlign(Alignment.CENTER);
banner.setLayoutAlign(VerticalAlignment.CENTER);
LayoutSpacer spacerTop = new LayoutSpacer();
spacerTop.setHeight(WidgetLayout.loadingScreenTopSpacerHeight);
banner.addMember(spacerTop);
Img logoImg = new Img(logo);
logoImg.setWidth(logoWidth);
logoImg.setHeight(logoHeight);
logoImg.setLayoutAlign(Alignment.CENTER);
logoImg.setLayoutAlign(VerticalAlignment.CENTER);
banner.addMember(logoImg);
Label titleLabel = new Label(applicationTitle);
titleLabel.setWidth(logoWidth);
titleLabel.setHeight(WidgetLayout.loadingScreenTitleHeight);
titleLabel.setLayoutAlign(Alignment.CENTER);
titleLabel.setAlign(Alignment.CENTER);
banner.addMember(titleLabel);
LayoutSpacer spacer = new LayoutSpacer();
banner.addMember(spacer);
VLayout progressLayout = new VLayout();
progressLayout.setBackgroundColor(WidgetLayout.loadingScreenProgressBackgroundColor);
progressLayout.setOpacity(WidgetLayout.loadingScreenProgressOpacity);
progressLayout.setHeight(WidgetLayout.loadingScreenProgressHeight);
progressLayout.setPadding(WidgetLayout.loadingScreenProgressPadding);
label = new Label(I18nProvider.getGlobal().loadScreenDownLoadText());
label.setLayoutAlign(Alignment.CENTER);
label.setWidth100();
label.setHeight(WidgetLayout.loadingScreenProgressLabelHeight);
label.setStyleName("loadingScreenLabel");
label.setOpacity(100);
progressLayout.addMember(label);
progressBar = new Progressbar();
progressBar.setHeight(WidgetLayout.loadingScreenProgressBarHeight);
progressBar.setWidth100();
progressBar.setVertical(false);
progressBar.setLayoutAlign(Alignment.CENTER);
progressBar.setLayoutAlign(VerticalAlignment.CENTER);
progressBar.setOpacity(100);
progressLayout.addMember(progressBar);
banner.addMember(progressLayout);
setBackgroundColor(WidgetLayout.loadingScreenBackgroundColor);
setShowEdges(true);
setShowShadow(true);
setShadowDepth(WidgetLayout.loadingScreenShadowDepth);
setLayoutAlign(Alignment.CENTER);
setLayoutAlign(VerticalAlignment.CENTER);
setWidth(WidgetLayout.loadingScreenWidth);
setHeight(WidgetLayout.loadingScreenHeight);
if (!(WidgetLayout.loadingScreenBackgroundImage == null)) {
setBackgroundImage(WidgetLayout.loadingScreenBackgroundImage);
}
setEdgeOpacity(WidgetLayout.loadingScreenEdgeOpacity);
setAlign(Alignment.CENTER);
addMember(banner);
}
/**
* Set a new image width for the logo. This should be done when a new logo image has been set.
*
* @param logoWidth The width of the logo image to be used.
*/
public void setLogoWidth(String logoWidth) {
this.logoWidth = logoWidth;
}
/**
* Set a new image height for the logo. This should be done when a new logo image has been set.
*
* @param logoHeight
* The height of the logo image to be used.
*/
public void setLogoHeight(String logoHeight) {
this.logoHeight = logoHeight;
}
/**
* Set a new URL to a new logo image to be used in this loading screen. After using this method, also set the
* image's width.
*
* @param logo logo
*/
public void setLogo(String logo) {
this.logo = logo;
}
/**
* Returns this view's widget.
*
* @return the widget
*/
public Widget getWidget() {
return this;
}
/**
* Called when loading of the map is started.
*/
public void onLoadStart() {
label.setContents(I18nProvider.getGlobal().loadScreenLoadText());
}
/**
* Called at regular time intervals to indicate progress (fake percentage).
*
* @param progressPercentage percentage of progress passed (0-100)
*/
public void onLoadProgress(int progressPercentage) {
progressBar.setPercentDone(progressPercentage);
}
/**
* Called when loading of the map is done or more than 20 seconds have passed.
*/
public void onLoadStop() {
label.setContents(I18nProvider.getGlobal().loadScreenReadyText());
}
}
/**
* {@link View} strategy that just shows the logo. The logo and its width/height can be changed to your wishes,
* either through setters or through the {@link WidgetLayout} properties.
*
* @author Jan De Moerloose
* @since 1.10.0
*
*/
@Api(allMethods = true)
public static class LogoOnlyView extends HLayout implements View {
private String logoWidth = WidgetLayout.loadingScreenLogoWidth;
private String logoHeight = WidgetLayout.loadingScreenLogoHeight;
private String logo = WidgetLayout.loadingScreenLogo;
public LogoOnlyView() {
VLayout banner = new VLayout();
banner.setLayoutAlign(Alignment.CENTER);
banner.setLayoutAlign(VerticalAlignment.CENTER);
Img logoImg = new Img(logo);
logoImg.setWidth(logoWidth);
logoImg.setHeight(logoHeight);
logoImg.setLayoutAlign(Alignment.CENTER);
logoImg.setLayoutAlign(VerticalAlignment.CENTER);
banner.addMember(logoImg);
setShowShadow(true);
setShadowDepth(WidgetLayout.loadingScreenShadowDepth);
setLayoutAlign(Alignment.CENTER);
setLayoutAlign(VerticalAlignment.CENTER);
setWidth(logoWidth);
setHeight(logoHeight);
setAlign(Alignment.CENTER);
addMember(banner);
}
/**
* Set a new image width for the logo. This should be done when a new logo image has been set.
*
* @param logoWidth The width of the logo image to be used.
*/
public void setLogoWidth(String logoWidth) {
this.logoWidth = logoWidth;
}
/**
* Set a new image height for the logo. This should be done when a new logo image has been set.
*
* @param logoHeight
* The height of the logo image to be used.
*/
public void setLogoHeight(String logoHeight) {
this.logoHeight = logoHeight;
}
/**
* Set a new URL to a new logo image to be used in this loading screen. After using this method, also set the
* image's width.
*
* @param logo logo
*/
public void setLogo(String logo) {
this.logo = logo;
}
/**
* Returns this view's widget.
*
* @return the widget
*/
public Widget getWidget() {
return this;
}
/**
* Called when loading of the map is started.
*/
public void onLoadStart() {
}
/**
* Called at regular time intervals to indicate progress (fake percentage).
*
* @param progressPercentage percentage of progress passed (0-100)
*/
public void onLoadProgress(int progressPercentage) {
}
/**
* Called when loading of the map is done or more than 20 seconds have passed.
*/
public void onLoadStop() {
}
}
}