/* Copyright 2008-2011 Josh Drummond This file is part of WebPasswordSafe. WebPasswordSafe 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 2 of the License, or (at your option) any later version. WebPasswordSafe 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 WebPasswordSafe; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ package net.webpasswordsafe.client.ui; import java.util.ArrayList; import java.util.Arrays; import java.util.HashSet; import java.util.List; import java.util.Set; import net.webpasswordsafe.client.WebPasswordSafe; import net.webpasswordsafe.client.i18n.TextMessages; import net.webpasswordsafe.client.remote.PasswordService; import net.webpasswordsafe.common.model.AccessLevel; import net.webpasswordsafe.common.model.Password; import net.webpasswordsafe.common.model.Permission; import net.webpasswordsafe.common.model.Subject; import net.webpasswordsafe.common.model.Template; import net.webpasswordsafe.common.model.TemplateDetail; import net.webpasswordsafe.common.util.Constants; import com.extjs.gxt.ui.client.Style.HorizontalAlignment; import com.extjs.gxt.ui.client.Style.SelectionMode; import com.extjs.gxt.ui.client.data.BaseModel; import com.extjs.gxt.ui.client.event.ButtonEvent; import com.extjs.gxt.ui.client.event.Events; import com.extjs.gxt.ui.client.event.GridEvent; import com.extjs.gxt.ui.client.event.Listener; import com.extjs.gxt.ui.client.event.SelectionListener; import com.extjs.gxt.ui.client.store.ListStore; import com.extjs.gxt.ui.client.util.Format; import com.extjs.gxt.ui.client.widget.MessageBox; import com.extjs.gxt.ui.client.widget.Window; import com.extjs.gxt.ui.client.widget.button.Button; import com.extjs.gxt.ui.client.widget.form.ComboBox; import com.extjs.gxt.ui.client.widget.form.SimpleComboBox; import com.extjs.gxt.ui.client.widget.form.SimpleComboValue; import com.extjs.gxt.ui.client.widget.form.ComboBox.TriggerAction; import com.extjs.gxt.ui.client.widget.grid.CellEditor; import com.extjs.gxt.ui.client.widget.grid.ColumnConfig; import com.extjs.gxt.ui.client.widget.grid.ColumnModel; import com.extjs.gxt.ui.client.widget.grid.EditorGrid; import com.extjs.gxt.ui.client.widget.grid.GridSelectionModel; import com.extjs.gxt.ui.client.widget.layout.AbsoluteLayout; import com.extjs.gxt.ui.client.widget.layout.AbsoluteData; import com.google.gwt.core.client.GWT; import com.google.gwt.user.client.rpc.AsyncCallback; /** * @author Josh Drummond * */ public class PermissionDialog extends Window { private Password password; private ListStore<PermissionData> permissionStore; private EditorGrid<PermissionData> permissionGrid; private ComboBox<SubjectData> comboSubjects; private PermissionData selectedPermission; private PermissionListener permissionListener; private final static TextMessages textMessages = GWT.create(TextMessages.class); public PermissionDialog(PermissionListener permissionListener, Password password, List<Subject> subjects) { this.setSize("380", "350"); this.setResizable(false); this.password = password; this.permissionListener = permissionListener; boolean isPasswordGrantable = password.getMaxEffectiveAccessLevel().equals(AccessLevel.GRANT); this.setHeading(textMessages.permissions()); this.setModal(true); this.setLayout(new AbsoluteLayout()); permissionStore = new ListStore<PermissionData>(); final SimpleComboBox<AccessLevel> accessLevelCombo = new SimpleComboBox<AccessLevel>(); accessLevelCombo.setEnabled(isPasswordGrantable); accessLevelCombo.setForceSelection(true); accessLevelCombo.setEditable(false); accessLevelCombo.setTriggerAction(TriggerAction.ALL); accessLevelCombo.add(Arrays.asList(AccessLevel.values())); CellEditor accessLevelEditor = new CellEditor(accessLevelCombo) { @Override public Object preProcessValue(Object v) { if (v instanceof AccessLevel) { return accessLevelCombo.findModel((AccessLevel) v); } return null; } @Override @SuppressWarnings("unchecked") public Object postProcessValue(Object v) { return ((SimpleComboValue<AccessLevel>) v).get(Constants.VALUE); } }; ListStore<SubjectData> subjectStore = new ListStore<SubjectData>(); for (Subject subject : subjects) { subjectStore.add(new SubjectData(subject)); } List<ColumnConfig> config = new ArrayList<ColumnConfig>(2); ColumnConfig column = new ColumnConfig(); column.setId(Constants.SUBJECT); column.setHeader(textMessages.userGroup()); column.setWidth(216); config.add(column); column = new ColumnConfig(); column.setId(Constants.ACCESSLEVEL); column.setHeader(textMessages.accessLevel()); column.setWidth(113); column.setEditor(accessLevelEditor); config.add(column); ColumnModel cm = new ColumnModel(config); permissionGrid = new EditorGrid<PermissionData>(permissionStore, cm); permissionGrid.setBorders(true); permissionGrid.setStripeRows(true); GridSelectionModel<PermissionData> gsm = permissionGrid.getSelectionModel(); gsm.setSelectionMode(SelectionMode.SINGLE); permissionGrid.addListener(Events.CellClick, new Listener<GridEvent<PermissionData>>() { @Override public void handleEvent(GridEvent<PermissionData> ge) { selectedPermission = ge.getModel(); } }); permissionGrid.setSize(200, 200); add(permissionGrid, new AbsoluteData(3, 3)); permissionGrid.setSize("360px", "221px"); Button removeButton = new Button(textMessages.removeSelected(), new SelectionListener<ButtonEvent>() { @Override public void componentSelected(ButtonEvent ce) { doRemove(); } }); removeButton.setEnabled(isPasswordGrantable); add(removeButton, new AbsoluteData(258, 230)); removeButton.setSize("105px", "22px"); Button addUserButton = new Button(textMessages.add(), new SelectionListener<ButtonEvent>() { @Override public void componentSelected(ButtonEvent ce) { doAdd(); } }); addUserButton.setEnabled(isPasswordGrantable); add(addUserButton, new AbsoluteData(160, 230)); addUserButton.setSize("51px", "22px"); comboSubjects = new ComboBox<SubjectData>(); add(comboSubjects, new AbsoluteData(3, 230)); comboSubjects.setEmptyText(textMessages.selectUserGroup()); comboSubjects.setDisplayField(Constants.NAME); comboSubjects.setStore(subjectStore); comboSubjects.setTypeAhead(true); comboSubjects.setTriggerAction(TriggerAction.ALL); comboSubjects.setEnabled(isPasswordGrantable); Button btnRemoveAll = new Button(textMessages.removeAll()); btnRemoveAll.addSelectionListener(new SelectionListener<ButtonEvent>() { @Override public void componentSelected(ButtonEvent ce) { doRemoveAll(); } }); btnRemoveAll.setEnabled(isPasswordGrantable); add(btnRemoveAll, new AbsoluteData(258, 254)); btnRemoveAll.setSize("105px", "22px"); Button btnAddTemplate = new Button(textMessages.addTemplate(), new SelectionListener<ButtonEvent>() { @Override public void componentSelected(ButtonEvent ce) { doAddTemplate(); } }); btnAddTemplate.setEnabled(isPasswordGrantable); add(btnAddTemplate, new AbsoluteData(126, 254)); btnAddTemplate.setSize("85px", "22px"); Button okayButton = new Button(textMessages.okay(), new SelectionListener<ButtonEvent>() { @Override public void componentSelected(ButtonEvent ce) { doOkay(); } }); okayButton.setEnabled(isPasswordGrantable); Button cancelButton = new Button(textMessages.cancel(), new SelectionListener<ButtonEvent>() { @Override public void componentSelected(ButtonEvent ce) { doCancel(); } }); setButtonAlign(HorizontalAlignment.CENTER); addButton(okayButton); addButton(cancelButton); setFields(); } private void doAddTemplate() { AsyncCallback<List<Template>> callback = new AsyncCallback<List<Template>>() { @Override public void onFailure(Throwable caught) { WebPasswordSafe.handleServerFailure(caught); } @Override public void onSuccess(List<Template> result) { new TemplateSelectionDialog(new ApplyTemplateListener(), result, false).show(); } }; PasswordService.Util.getInstance().getTemplates(true, callback); } private void applyTemplateDetails(Template template) { for (TemplateDetail templateDetail : template.getTemplateDetails()) { permissionStore.add(new PermissionData(new Permission(templateDetail.getSubject(), templateDetail.getAccessLevelObj()))); } } private void doRemoveAll() { permissionStore.removeAll(); } private void doRemove() { //PermissionData data = permissionGrid.getSelectionModel().getSelectedItem(); PermissionData data = selectedPermission; if (null != data) { permissionStore.remove(data); selectedPermission = null; } } private void doAdd() { SubjectData data = comboSubjects.getValue(); if (null != data) { permissionStore.add(new PermissionData(new Permission((Subject)data.get(Constants.SUBJECT), AccessLevel.READ))); } } private void setFields() { permissionStore.removeAll(); for (Permission permission : password.getPermissions()) { permissionStore.add(new PermissionData(permission)); } } private void doCancel() { permissionStore.rejectChanges(); hide(); } private void doOkay() { permissionStore.commitChanges(); if (permissionStore.getCount() > 0) { Set<Permission> permissions = new HashSet<Permission>(permissionStore.getCount()); for (PermissionData data : permissionStore.getModels()) { Permission permission = (Permission)data.get(Constants.PERMISSION); String newAccessLevel = ((AccessLevel)data.get(Constants.ACCESSLEVEL)).name(); if (!newAccessLevel.equals(permission.getAccessLevel())) { // if user changed the access level value in the GUI, treat it like a new permission permission = new Permission(permission.getSubject(), AccessLevel.valueOf(newAccessLevel)); } permissions.add(permission); } permissionListener.doPermissionsChanged(permissions); hide(); } else { MessageBox.alert(textMessages.error(), textMessages.mustHaveOnePermission(), null); } } private class ApplyTemplateListener implements TemplateListener { @Override public void doTemplatesChosen(List<Template> templates) { if (templates.size() > 0) { AsyncCallback<Template> callback = new AsyncCallback<Template>() { @Override public void onFailure(Throwable caught) { WebPasswordSafe.handleServerFailure(caught); } @Override public void onSuccess(Template result) { applyTemplateDetails(result); } }; PasswordService.Util.getInstance().getTemplateWithDetails(templates.get(0).getId(), callback); } } } private class PermissionData extends BaseModel { private static final long serialVersionUID = 1L; public PermissionData(Permission permission) { set(Constants.ID, permission.getId()); set(Constants.SUBJECT, Format.htmlEncode(permission.getSubject().getName())); set(Constants.ACCESSLEVEL, permission.getAccessLevelObj()); set(Constants.PERMISSION, permission); } } private class SubjectData extends BaseModel { private static final long serialVersionUID = 1L; public SubjectData(Subject subject) { set(Constants.ID, subject.getId()); set(Constants.NAME, Format.htmlEncode(subject.getName())); set(Constants.SUBJECT, subject); } } }