/*
* 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.plugin.staticsecurity.client;
import com.google.gwt.core.client.GWT;
import com.smartgwt.client.types.Alignment;
import com.smartgwt.client.types.KeyNames;
import com.smartgwt.client.types.VerticalAlignment;
import com.smartgwt.client.widgets.HTMLFlow;
import com.smartgwt.client.widgets.IButton;
import com.smartgwt.client.widgets.Img;
import com.smartgwt.client.widgets.Label;
import com.smartgwt.client.widgets.Window;
import com.smartgwt.client.widgets.events.ClickEvent;
import com.smartgwt.client.widgets.events.ClickHandler;
import com.smartgwt.client.widgets.form.DynamicForm;
import com.smartgwt.client.widgets.form.events.ItemKeyPressEvent;
import com.smartgwt.client.widgets.form.events.ItemKeyPressHandler;
import com.smartgwt.client.widgets.form.fields.PasswordItem;
import com.smartgwt.client.widgets.form.fields.TextItem;
import com.smartgwt.client.widgets.layout.HLayout;
import com.smartgwt.client.widgets.layout.LayoutSpacer;
import com.smartgwt.client.widgets.layout.VLayout;
import org.geomajas.annotation.Api;
import org.geomajas.gwt.client.command.event.TokenChangedEvent;
import org.geomajas.gwt.client.command.event.TokenChangedHandler;
import org.geomajas.gwt.client.util.HtmlBuilder;
import org.geomajas.gwt.client.util.WidgetLayout;
import org.geomajas.plugin.staticsecurity.client.util.SsecAccess;
import org.geomajas.plugin.staticsecurity.client.util.SsecLayout;
/**
* <p>
* Window used for logging in. Display a simple form for logging in, and 2 buttons. One buttons effectively logs you in,
* while the other allows you to reset the form. When logging in not all attempts are successful. You can pass a
* {@link TokenChangedHandler} which is called when the login was successful (specific to this window).
* </p>
* <p>
* Note that the login window cannot be cancelled. You have to pass valid credentials for the window to disappear.
* </p>
*
* @author Pieter De Graef
* @author Joachim Van der Auwera
* @since 1.9.0
*/
@Api
public class TokenRequestWindow extends Window implements TokenChangedHandler {
public static final String STYLE_NAME_WINDOW = "tokenRequestWindow";
public static final String STYLE_NAME_ERROR = "tokenRequestError";
private static final StaticSecurityMessages MESSAGES = GWT.create(StaticSecurityMessages.class);
private static final String FIELD_USER_NAME = "userName";
private static final String FIELD_PASSWORD = "password";
private TokenChangedHandler finishLoginHandler;
private DynamicForm loginForm;
private String slogan;
private HTMLFlow errorWidget;
private int loginAttempt;
// -------------------------------------------------------------------------
// Constructors:
// -------------------------------------------------------------------------
/**
* Create the default login window. Shows the login window with a default layout.
*/
@Api
public TokenRequestWindow() {
super();
errorWidget = new HTMLFlow();
errorWidget.setStyleName(STYLE_NAME_ERROR);
loginForm = new DynamicForm();
setHeaderIcon(WidgetLayout.iconGeomajas, 16, 16);
setTitle(MESSAGES.tokenRequestWindowTitle());
setIsModal(true);
setShowModalMask(true);
setModalMaskOpacity(WidgetLayout.modalMaskOpacity);
setAutoCenter(true);
setAutoSize(true);
setShowCloseButton(false);
setShowMinimizeButton(false);
setShowMaximizeButton(false);
setStyleName(STYLE_NAME_WINDOW);
}
/**
* Create the default login window with an extra {@link TokenChangedHandler} added to catch login events. Shows the
* login window with a default layout.
*
* @param tokenChangedHandler callback for when the token was modified
*/
@Api
public TokenRequestWindow(TokenChangedHandler tokenChangedHandler) {
this();
finishLoginHandler = tokenChangedHandler;
}
@Override
public void onTokenChanged(TokenChangedEvent event) {
String token = event.getToken();
if (null != token && token.length() > 0) {
if (finishLoginHandler != null) {
finishLoginHandler.onTokenChanged(event);
}
destroy();
} else {
String msg;
if (1 == ++loginAttempt) {
msg = MESSAGES.tokenRequestRetry();
} else {
msg = MESSAGES.tokenRequestRetryAgain(loginAttempt);
}
reportError(msg);
}
}
/**
* Set a new slogan for this window. If null, no slogan will be displayed (that is also the default value).
*
* @param slogan slogan
*/
@Api
public void setSlogan(String slogan) {
this.slogan = slogan;
}
@Override
public void onDraw() {
buildWidget();
// try to force to be inside the screen
if (SsecLayout.tokenRequestWindowKeepInScreen) {
WidgetLayout.keepWindowInScreen(this);
}
super.onDraw();
}
// -------------------------------------------------------------------------
// Private methods:
// -------------------------------------------------------------------------
protected void reportError(String error) {
errorWidget.setContents(HtmlBuilder.divStyle(SsecLayout.tokenRequestWindowErrorStyle, error));
}
private void buildWidget() {
VLayout layout = new VLayout();
layout.setWidth(SsecLayout.tokenRequestWindowWidth);
layout.setHeight(SsecLayout.tokenRequestWindowHeight);
if (null != SsecLayout.tokenRequestWindowBackground) {
layout.setBackgroundImage(SsecLayout.tokenRequestWindowBackground);
}
layout.setLayoutAlign(Alignment.CENTER);
layout.setMembersMargin(WidgetLayout.marginLarge);
layout.setPadding(WidgetLayout.marginLarge);
Img logoImg = new Img(SsecLayout.tokenRequestWindowLogo);
logoImg.setWidth(SsecLayout.tokenRequestWindowLogoWidth);
logoImg.setHeight(SsecLayout.tokenRequestWindowLogoHeight);
logoImg.setLayoutAlign(Alignment.CENTER);
logoImg.setLayoutAlign(VerticalAlignment.CENTER);
layout.addMember(logoImg);
if (slogan != null && slogan.length() > 0) {
Label titleLabel = new Label(slogan);
titleLabel.setWidth(SsecLayout.tokenRequestWindowLogoWidth);
titleLabel.setHeight(SsecLayout.tokenRequestWindowSloganHeight);
titleLabel.setLayoutAlign(Alignment.CENTER);
titleLabel.setAlign(Alignment.CENTER);
layout.addMember(titleLabel);
}
// User name:
TextItem userNameItem = new TextItem(FIELD_USER_NAME);
userNameItem.setWidth(SsecLayout.tokenRequestWindowFieldWidth);
userNameItem.setTitle(MESSAGES.tokenRequestUserId());
userNameItem.setSelectOnFocus(true);
userNameItem.setWrapTitle(false);
// Password:
PasswordItem passwordItem = new PasswordItem(FIELD_PASSWORD);
passwordItem.setWidth(SsecLayout.tokenRequestWindowFieldWidth);
passwordItem.setTitle(MESSAGES.tokenRequestPassword());
passwordItem.setWrapTitle(false);
// Login form:
loginForm.setAutoFocus(true);
loginForm.setNumCols(2);
loginForm.setWidth(SsecLayout.tokenRequestWindowLogoWidth);
loginForm.setLayoutAlign(Alignment.CENTER);
loginForm.setFields(userNameItem, passwordItem);
loginForm.setCanFocus(true);
loginForm.addItemKeyPressHandler(new ItemKeyPressHandler() {
public void onItemKeyPress(ItemKeyPressEvent event) {
if (KeyNames.ENTER.equals(event.getKeyName())) {
login();
}
}
});
layout.addMember(loginForm);
// Login button:
IButton loginButton = new IButton(MESSAGES.tokenRequestButtonLogin());
loginButton.setWidth(SsecLayout.tokenRequestWindowButtonWidth);
loginButton.setIcon(SsecLayout.iconLogin);
loginButton.addClickHandler(new TokenRequestLoginClickHandler());
loginButton.setLayoutAlign(Alignment.RIGHT);
// Reset button:
IButton resetButton = new IButton(MESSAGES.tokenRequestButtonReset());
resetButton.setWidth(SsecLayout.tokenRequestWindowButtonWidth);
resetButton.setIcon(WidgetLayout.iconUndo);
resetButton.addClickHandler(new TokenRequestResetClickHandler());
resetButton.setLayoutAlign(Alignment.LEFT);
HLayout buttonLayout = new HLayout();
buttonLayout.setHeight(30);
buttonLayout.setWidth(SsecLayout.tokenRequestWindowLogoWidth);
buttonLayout.setMembersMargin(WidgetLayout.marginSmall);
buttonLayout.setLayoutAlign(Alignment.CENTER);
VLayout loginBtnLayout = new VLayout();
loginBtnLayout.setWidth(SsecLayout.tokenRequestWindowButtonLayoutWidth);
loginBtnLayout.addMember(loginButton);
buttonLayout.addMember(loginBtnLayout);
VLayout resetBtnLayout = new VLayout();
resetBtnLayout.setWidth(SsecLayout.tokenRequestWindowButtonLayoutWidth);
resetBtnLayout.addMember(resetButton);
buttonLayout.addMember(resetBtnLayout);
layout.addMember(buttonLayout);
layout.addMember(new LayoutSpacer());
// Error label:
errorWidget.setWidth(SsecLayout.tokenRequestWindowLogoWidth);
errorWidget.setHeight(SsecLayout.tokenRequestWindowErrorHeight);
errorWidget.setLayoutAlign(Alignment.CENTER);
errorWidget.setAlign(Alignment.CENTER);
layout.addMember(errorWidget);
addItem(layout);
}
private void login() {
String userId = loginForm.getValueAsString(FIELD_USER_NAME);
String password = loginForm.getValueAsString(FIELD_PASSWORD);
if (userId == null || userId.length() == 0) {
reportError(MESSAGES.tokenRequestNoUserName());
} else if (password == null || password.length() == 0) {
reportError(MESSAGES.tokenRequestNoPassword());
} else {
reportError(MESSAGES.tokenLoggingIn());
SsecAccess.login(userId, password, this);
}
}
/**
* ClickHandler for the login button.
*
* @author Pieter De Graef
*/
private class TokenRequestLoginClickHandler implements ClickHandler {
public void onClick(ClickEvent event) {
login();
}
}
/**
* ClickHandler for the reset button.
*
* @author Pieter De Graef
*/
private class TokenRequestResetClickHandler implements ClickHandler {
public void onClick(ClickEvent event) {
loginForm.setValue(FIELD_USER_NAME, "");
loginForm.setValue(FIELD_PASSWORD, "");
reportError("");
}
}
}