package edu.ualberta.med.biobank.dialogs.user;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Set;
import org.eclipse.core.commands.ExecutionException;
import org.eclipse.core.runtime.Status;
import org.eclipse.jface.dialogs.IDialogConstants;
import org.eclipse.jface.wizard.WizardDialog;
import org.eclipse.osgi.util.NLS;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.BusyIndicator;
import org.eclipse.swt.events.ModifyEvent;
import org.eclipse.swt.events.ModifyListener;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.TabFolder;
import org.eclipse.swt.widgets.TabItem;
import org.eclipse.ui.PlatformUI;
import edu.ualberta.med.biobank.SessionManager;
import edu.ualberta.med.biobank.common.action.security.ManagerContext;
import edu.ualberta.med.biobank.common.action.security.MembershipContext;
import edu.ualberta.med.biobank.common.action.security.UserGetOutput;
import edu.ualberta.med.biobank.common.action.security.UserSaveAction;
import edu.ualberta.med.biobank.common.action.security.UserSaveInput;
import edu.ualberta.med.biobank.common.action.security.UserSaveOutput;
import edu.ualberta.med.biobank.common.peer.UserPeer;
import edu.ualberta.med.biobank.common.wrappers.UserWrapper;
import edu.ualberta.med.biobank.gui.common.BgcPlugin;
import edu.ualberta.med.biobank.gui.common.validators.AbstractValidator;
import edu.ualberta.med.biobank.gui.common.validators.EmailValidator;
import edu.ualberta.med.biobank.gui.common.validators.NonEmptyStringValidator;
import edu.ualberta.med.biobank.gui.common.widgets.BgcBaseText;
import edu.ualberta.med.biobank.gui.common.widgets.utils.BgcWidgetCreator;
import edu.ualberta.med.biobank.handlers.LogoutHandler;
import edu.ualberta.med.biobank.model.Group;
import edu.ualberta.med.biobank.model.Membership;
import edu.ualberta.med.biobank.model.User;
import edu.ualberta.med.biobank.server.applicationservice.BiobankApplicationService;
import edu.ualberta.med.biobank.validators.EmptyStringValidator;
import edu.ualberta.med.biobank.validators.MatchingTextValidator;
import edu.ualberta.med.biobank.validators.OrValidator;
import edu.ualberta.med.biobank.validators.StringLengthValidator;
import edu.ualberta.med.biobank.widgets.infotables.MembershipInfoTable;
import edu.ualberta.med.biobank.widgets.multiselect.MultiSelectWidget;
import gov.nih.nci.system.applicationservice.ApplicationException;
public class UserEditDialog extends AbstractSecurityEditDialog {
public static final int CLOSE_PARENT_RETURN_CODE = 3;
private static final int PASSWORD_LENGTH_MIN = 5;
private static final String MSG_PASSWORD_REQUIRED = NLS.bind(
"Passwords must be at least {0} characters long.", PASSWORD_LENGTH_MIN);
private final UserWrapper userWrapper;
private final User user;
private final MembershipContext membershipContext;
private final ManagerContext managerContext;
private final boolean isFullyManageable;
private BgcBaseText password;
private MembershipInfoTable membershipInfoTable;
private MultiSelectWidget<Group> groupsWidget;
public UserEditDialog(Shell parent, UserGetOutput output,
ManagerContext managerContext) {
super(parent);
this.user = output.getUser();
this.membershipContext = output.getContext();
this.isFullyManageable = output.isFullyManageable();
this.managerContext = managerContext;
BiobankApplicationService appService = SessionManager.getAppService();
this.userWrapper = new UserWrapper(appService, user);
if (user.isNew()) {
user.setNeedPwdChange(true);
}
}
@Override
protected void createButtonsForButtonBar(Composite parent) {
super.createButtonsForButtonBar(parent);
Button okButton = getButton(IDialogConstants.OK_ID);
okButton.setText("Save");
}
@Override
protected String getDialogShellTitle() {
if (user.isNew()) {
return "Add User";
}
return "Edit User";
}
@Override
protected String getTitleAreaMessage() {
if (user.isNew()) {
return "Add a new user";
}
return "Modify an existing user's information";
}
@Override
protected String getTitleAreaTitle() {
return getDialogShellTitle();
}
@Override
protected void createDialogAreaInternal(Composite parent)
throws ApplicationException {
Composite contents = new Composite(parent, SWT.NONE);
contents.setLayout(new GridLayout(1, false));
contents.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
TabFolder tb = new TabFolder(contents, SWT.TOP);
tb.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
createUserFields(createTabItem(tb,
"General", 2));
createMembershipsSection(createTabItem(tb,
"Roles and Permissions", 1));
createGroupsSection(createTabItem(tb,
"Groups", 1));
}
private Composite createTabItem(TabFolder tb, String title, int columns) {
TabItem item = new TabItem(tb, SWT.NONE);
item.setText(title);
Composite contents = new Composite(tb, SWT.NONE);
contents.setLayout(new GridLayout(columns, false));
item.setControl(contents);
return contents;
}
private void createUserFields(Composite contents) {
int readOnly = 0;
if (!isFullyManageable) {
readOnly = SWT.READ_ONLY;
}
Collection<Control> controls = new ArrayList<Control>();
controls.add(createBoundWidgetWithLabel(contents, BgcBaseText.class,
SWT.BORDER | readOnly,
"Login", null, userWrapper,
UserPeer.LOGIN.getName(), new NonEmptyStringValidator(
"A valid login name is required.")));
controls.add(createBoundWidgetWithLabel(contents, BgcBaseText.class,
SWT.BORDER | readOnly,
"Full Name", null, userWrapper,
UserPeer.FULL_NAME.getName(), new NonEmptyStringValidator(
"Full name of this user is required")));
controls.add(createBoundWidgetWithLabel(contents, BgcBaseText.class,
SWT.BORDER | readOnly,
"Email", null, userWrapper,
UserPeer.EMAIL.getName(), new EmailValidator(
"A valid email is required")));
Control checkbox = createBoundWidgetWithLabel(contents, Button.class,
SWT.CHECK | readOnly,
"Receive bulk emails", null, userWrapper,
UserPeer.RECV_BULK_EMAILS.getName(), null);
controls.add(checkbox);
if (!isFullyManageable) {
for (Control c : controls) {
c.setBackground(BgcWidgetCreator.READ_ONLY_TEXT_BGR);
}
checkbox.setEnabled(false);
} else {
if (!userWrapper.equals(SessionManager.getUser()))
createPasswordWidgets(contents);
}
}
private void createMembershipsSection(Composite contents) {
Button addButton = new Button(contents, SWT.PUSH);
addButton.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
addMembership();
}
});
addButton.setImage(BgcPlugin.getDefault().getImageRegistry()
.get(BgcPlugin.IMG_ADD));
GridData gd = new GridData();
gd.horizontalAlignment = SWT.RIGHT;
addButton.setLayoutData(gd);
membershipInfoTable =
new MembershipInfoTable(contents, user, membershipContext,
managerContext);
}
private void createGroupsSection(Composite contents) {
groupsWidget = new MultiSelectWidget<Group>(contents, SWT.NONE,
"Available groups",
"Selected groups", 200) {
@Override
protected String getTextForObject(Group node) {
return node.getName();
}
};
Set<Group> available = membershipContext.getGroups();
groupsWidget.setSelections(
new ArrayList<Group>(available),
new ArrayList<Group>(user.getGroups()));
}
protected void addMembership() {
BusyIndicator.showWhile(Display.getDefault(), new Runnable() {
@Override
public void run() {
Membership m = new Membership();
m.setPrincipal(user);
Shell shell = PlatformUI.getWorkbench()
.getActiveWorkbenchWindow().getShell();
MembershipEditWizard wiz =
new MembershipEditWizard(m, managerContext);
WizardDialog dlg = new SecurityWizardDialog(shell, wiz);
int res = dlg.open();
if (res == Status.OK) {
m.setPrincipal(user);
user.getMemberships().add(m);
membershipInfoTable.setCollection(user.getMemberships());
membershipInfoTable.setSelection(m);
} else {
m.setPrincipal(null);
}
}
});
}
@Override
protected void okPressed() {
// try saving or updating the user inside this dialog so that if there
// is an error the entered information is not lost
try {
user.getGroups().removeAll(groupsWidget.getRemovedFromSelection());
user.getGroups().addAll(groupsWidget.getAddedToSelection());
String pw = null;
String pwText = password != null ? password.getText() : null;
if (pwText != null && !pwText.isEmpty()) {
pw = pwText;
}
UserSaveOutput res = SessionManager.getAppService()
.doAction(new UserSaveAction(
new UserSaveInput(user, membershipContext, pw)));
user.setId(res.getUserId());
user.setCsmUserId(res.getCsmUserId());
if (SessionManager.getUser().equals(user)) {
// if the User is making changes to himself, logout
BgcPlugin
.openInformation(
"User Information Saved",
"Your information has been successfully updated. You will be logged out and have to reconnect.");
LogoutHandler lh = new LogoutHandler();
try {
lh.execute(null);
} catch (ExecutionException e) {
}
setReturnCode(CLOSE_PARENT_RETURN_CODE);
} else {
setReturnCode(OK);
}
close();
} catch (Throwable t) {
TmpUtil.displayException(t);
}
}
private void createPasswordWidgets(Composite parent) {
AbstractValidator passwordValidator;
passwordValidator = new StringLengthValidator(PASSWORD_LENGTH_MIN,
MSG_PASSWORD_REQUIRED);
if (!user.isNew()) {
// existing users can have their password field left blank
passwordValidator = new OrValidator(Arrays.asList(
new EmptyStringValidator(""), passwordValidator),
MSG_PASSWORD_REQUIRED);
}
password = (BgcBaseText) createBoundWidgetWithLabel(parent,
BgcBaseText.class, SWT.BORDER | SWT.PASSWORD,
(user.isNew() ? "New Password"
: "Password"), new String[0],
userWrapper, "password", passwordValidator);
password.addModifyListener(new ModifyListener() {
@Override
public void modifyText(ModifyEvent e) {
user.setNeedPwdChange(true);
}
});
BgcBaseText passwordRetyped =
(BgcBaseText) createBoundWidgetWithLabel(
parent,
BgcBaseText.class,
SWT.BORDER | SWT.PASSWORD,
(user.isNew() ? "Re-Type New Password"
: "Re-Type Password"),
new String[0],
userWrapper,
"password", new MatchingTextValidator(
"The passwords entered do not match.", password));
MatchingTextValidator.addListener(password, passwordRetyped);
}
}