/*
* Copyright (C) 2012 Jan Pokorsky
*
* 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/>.
*/
package cz.cas.lib.proarc.webapp.client.widget;
import com.smartgwt.client.data.DSCallback;
import com.smartgwt.client.data.DSRequest;
import com.smartgwt.client.data.DSResponse;
import com.smartgwt.client.types.ListGridComponent;
import com.smartgwt.client.types.ReadOnlyDisplayAppearance;
import com.smartgwt.client.types.SelectionStyle;
import com.smartgwt.client.widgets.Canvas;
import com.smartgwt.client.widgets.IconButton;
import com.smartgwt.client.widgets.Window;
import com.smartgwt.client.widgets.form.DynamicForm;
import com.smartgwt.client.widgets.form.FormItemIfFunction;
import com.smartgwt.client.widgets.form.events.SubmitValuesEvent;
import com.smartgwt.client.widgets.form.events.SubmitValuesHandler;
import com.smartgwt.client.widgets.form.fields.CancelItem;
import com.smartgwt.client.widgets.form.fields.FormItem;
import com.smartgwt.client.widgets.form.fields.PasswordItem;
import com.smartgwt.client.widgets.form.fields.RowSpacerItem;
import com.smartgwt.client.widgets.form.fields.SubmitItem;
import com.smartgwt.client.widgets.form.fields.TextItem;
import com.smartgwt.client.widgets.form.validator.LengthRangeValidator;
import com.smartgwt.client.widgets.form.validator.RegExpValidator;
import com.smartgwt.client.widgets.grid.ListGrid;
import com.smartgwt.client.widgets.grid.ListGridRecord;
import com.smartgwt.client.widgets.layout.VLayout;
import com.smartgwt.client.widgets.toolbar.ToolStrip;
import cz.cas.lib.proarc.webapp.client.ClientMessages;
import cz.cas.lib.proarc.webapp.client.action.AbstractAction;
import cz.cas.lib.proarc.webapp.client.action.ActionEvent;
import cz.cas.lib.proarc.webapp.client.action.Actions;
import cz.cas.lib.proarc.webapp.client.action.RefreshAction;
import cz.cas.lib.proarc.webapp.client.ds.RestConfig;
import cz.cas.lib.proarc.webapp.client.ds.UserDataSource;
import cz.cas.lib.proarc.webapp.shared.rest.UserResourceApi;
import java.util.logging.Logger;
/**
* Manages list of users and their profiles.
*
* @author Jan Pokorsky
*/
public final class UsersView implements RefreshAction.Refreshable {
private static final Logger LOG = Logger.getLogger(UsersView.class.getName());
private final ClientMessages i18n;
private final Canvas widget;
private final ListGrid userGrid;
private DynamicForm newEditor;
private DynamicForm rowEditor;
private Window window;
public UsersView(ClientMessages i18n) {
this.i18n = i18n;
ToolStrip toolbar = createToolbar(i18n);
userGrid = createUserList(toolbar);
VLayout main = new VLayout();
main.setWidth100();
main.setHeight100();
main.addMember(userGrid);
this.widget = main;
}
public Canvas asWidget() {
return widget;
}
public void onShow() {
refresh();
}
private ToolStrip createToolbar(ClientMessages i18n) {
ToolStrip gridEditControls = Actions.createToolStrip();
IconButton newButton = Actions.asIconButton(new AbstractAction(
i18n.UsersView_Button_New_Title(),
"[SKIN]/actions/add.png",
i18n.UsersView_Button_New_Hint()) {
@Override
public void performAction(ActionEvent event) {
showNewWindow();
}
}, this);
IconButton editButton = Actions.asIconButton(new AbstractAction(
i18n.UsersView_Button_Edit_Title(),
"[SKIN]/actions/edit.png",
i18n.UsersView_Button_Edit_Hint()) {
@Override
public void performAction(ActionEvent event) {
ListGridRecord selection = userGrid.getSelectedRecord();
if (selection != null) {
userGrid.expandRecord(selection);
}
}
}, this);
gridEditControls.setMembers(Actions.asIconButton(new RefreshAction(i18n), this), newButton, editButton);
return gridEditControls;
}
private ListGrid createUserList(ToolStrip gridEditControls) {
final ListGrid grid = new ListGrid() {
@Override
protected Canvas getExpansionComponent(ListGridRecord record) {
return getRowProfileEditor(record);
}
};
grid.setDataSource(UserDataSource.getInstance());
grid.setUseAllDataSourceFields(true);
grid.setSelectionType(SelectionStyle.SINGLE);
grid.setCanExpandRecords(true);
grid.setCanExpandMultipleRecords(false);
grid.setGridComponents(gridEditControls, ListGridComponent.HEADER, ListGridComponent.BODY);
// Since SmartGWT 4.0; disable auto-save to post updates of nested forms just on the submit actions.
grid.setAutoSaveEdits(false);
grid.setShowClippedValuesOnHover(true);
return grid;
}
private DynamicForm getNewProfileEditor() {
if (newEditor == null) {
newEditor = getProfileEditor(null);
}
newEditor.clearErrors(true);
newEditor.editNewRecord();
return newEditor;
}
private DynamicForm getRowProfileEditor(ListGridRecord record) {
boolean isNew = record == null;
if (rowEditor == null) {
rowEditor = getProfileEditor(record);
}
rowEditor.clearErrors(true);
if (isNew) {
rowEditor.editNewRecord();
} else {
rowEditor.editRecord(record);
}
return rowEditor;
}
private DynamicForm getProfileEditor(ListGridRecord record) {
final DynamicForm form = createUserEditor(record == null, i18n);
FormItem cancel = form.getField("cancel");
cancel.addClickHandler(new com.smartgwt.client.widgets.form.fields.events.ClickHandler() {
@Override
public void onClick(com.smartgwt.client.widgets.form.fields.events.ClickEvent event) {
form.clearErrors(true);
closeEditor();
}
});
form.addSubmitValuesHandler(new SubmitValuesHandler() {
@Override
public void onSubmitValues(SubmitValuesEvent event) {
form.saveData(new DSCallback() {
@Override
public void execute(DSResponse response, Object rawData, DSRequest request) {
if (RestConfig.isStatusOk(response)) {
closeEditor();
}
}
});
}
});
return form;
}
static DynamicForm createUserEditor(final boolean isNewUser, ClientMessages i18n) {
final DynamicForm form = new DynamicForm();
form.setMargin(15);
form.setDataSource(UserDataSource.getInstance());
form.setAutoWidth();
form.setNumCols(4);
form.setAutoFocus(true);
form.setBrowserSpellCheck(false);
TextItem username = new TextItem(UserDataSource.FIELD_USERNAME);
if (isNewUser) {
username.setValidators(new RegExpValidator("[a-z][a-z0-9]{4,}"));
username.setTooltip(i18n.UsersView_UserForm_Username_Hint());
}
username.setCanEdit(isNewUser);
username.setEndRow(true);
final PasswordItem password = new PasswordItem(UserDataSource.FIELD_PASSWORD);
password.setRequired(isNewUser);
password.setPrompt(i18n.UsersView_UserForm_Password_Hint());
LengthRangeValidator pswdLengthValidator = new LengthRangeValidator();
pswdLengthValidator.setMin(6);
pswdLengthValidator.setMax(20);
password.setValidators(pswdLengthValidator);
TextItem surname = new TextItem(UserResourceApi.USER_SURNAME);
TextItem forename = new TextItem(UserResourceApi.USER_FORENAME);
forename.setStartRow(true);
TextItem email = new TextItem(UserResourceApi.USER_EMAIL);
email.setColSpan("*");
email.setWidth(300);
email.setEndRow(true);
TextItem remoteName = new TextItem(UserResourceApi.USER_REMOTENAME);
remoteName.setReadOnlyDisplay(ReadOnlyDisplayAppearance.STATIC);
remoteName.setShowIfCondition(new FormItemIfFunction() {
@Override
public boolean execute(FormItem item, Object value, DynamicForm form) {
boolean isLocal = value == null;
password.setVisible(isLocal);
if (form.getFocusItem() == password) {
form.focusInNextTabElement();
}
password.setCanFocus(isLocal);
return !isLocal;
}
});
TextItem remoteType = new TextItem(UserResourceApi.USER_REMOTETYPE);
remoteType.setReadOnlyDisplay(ReadOnlyDisplayAppearance.STATIC);
remoteType.setShowIfCondition(new FormItemIfFunction() {
@Override
public boolean execute(FormItem item, Object value, DynamicForm form) {
return value != null;
}
});
TextItem home = new TextItem(UserResourceApi.USER_HOME);
home.setColSpan("*");
home.setWidth(300);
home.setEndRow(true);
form.setCanSubmit(false);
SubmitItem submit = new SubmitItem();
submit.setTitle(i18n.UsersView_UserForm_Submit_Title());
submit.setEndRow(false);
submit.setStartRow(false);
CancelItem cancel = new CancelItem("cancel", i18n.UsersView_UserForm_Cancel_Title());
cancel.setStartRow(false);
form.setFields(username, password, forename, surname, email,
remoteName, remoteType, home,
new RowSpacerItem(), submit, cancel);
return form;
}
private void showNewWindow() {
closeEditor();
DynamicForm form = getNewProfileEditor();
if (window == null) {
window = new Window();
window.setAutoSize(true);
window.setAutoCenter(true);
window.setDismissOnEscape(true);
window.setShowMaximizeButton(false);
window.setShowMinimizeButton(false);
window.setIsModal(true);
window.setModalMaskOpacity(10);
window.setShowModalMask(true);
window.setTitle(i18n.UsersView_NewUser_Window_Title());
window.addItem(form);
}
window.show();
form.focusInItem(0);
}
private void closeEditor() {
ListGridRecord selected = userGrid.getSelectedRecord();
if (selected != null) {
userGrid.collapseRecord(selected);
}
if (window != null && window.isVisible()) {
window.hide();
}
}
@Override
public void refresh() {
userGrid.invalidateCache();
userGrid.fetchData(null, new DSCallback() {
@Override
public void execute(DSResponse response, Object rawData, DSRequest request) {
if (RestConfig.isStatusOk(response) && response.getData().length > 0) {
userGrid.focus();
userGrid.selectSingleRecord(0);
}
}
});
}
}