package edu.ualberta.med.biobank.dialogs.user; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Set; import org.eclipse.core.databinding.observable.value.WritableValue; import org.eclipse.jface.viewers.CheckStateChangedEvent; import org.eclipse.jface.viewers.ICheckStateListener; import org.eclipse.jface.viewers.ICheckable; import org.eclipse.swt.SWT; 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.Event; import org.eclipse.swt.widgets.Group; import org.eclipse.swt.widgets.Listener; import edu.ualberta.med.biobank.common.action.security.ManagerContext; import edu.ualberta.med.biobank.gui.common.dialogs.BgcWizardPage; import edu.ualberta.med.biobank.gui.common.widgets.BgcEntryFormWidgetListener; import edu.ualberta.med.biobank.gui.common.widgets.MultiSelectEvent; import edu.ualberta.med.biobank.model.Membership; import edu.ualberta.med.biobank.model.PermissionEnum; import edu.ualberta.med.biobank.model.Role; import edu.ualberta.med.biobank.widgets.multiselect.MultiSelectWidget; import edu.ualberta.med.biobank.widgets.trees.permission.PermissionCheckTreeWidget; import edu.ualberta.med.biobank.widgets.trees.permission.PermissionNode; public class MembershipPermissionsPage extends BgcWizardPage { // track the permissions and roles the the user explicitly clicks on and off // (as opposed to automatically removed by switching domains) private final Set<PermissionEnum> explicitPerms = new HashSet<PermissionEnum>(); private final Set<Role> explicitRoles = new HashSet<Role>(); private final PermissionsCheckStateHandler permissionsCheckStateHandler = new PermissionsCheckStateHandler(); private final RolesSelectionHandler rolesSelectionHandler = new RolesSelectionHandler(); private final Membership membership; private final ManagerContext context; private Button userManagerButton; private Button everyPermissionButton; private MultiSelectWidget<Role> rolesWidget; private PermissionCheckTreeWidget permissionsTree; private final WritableValue validPermissions = new WritableValue( Boolean.FALSE, Boolean.class); MembershipPermissionsPage(Membership membership, ManagerContext context) { super("", "Roles and Permissions", null); setMessage("What the user (or group) is allowed to do"); this.membership = membership; this.context = context; explicitPerms.addAll(membership.getPermissions()); explicitRoles.addAll(membership.getRoles()); } @Override public void setVisible(boolean visible) { super.setVisible(visible); updateEveryPermissionButton(); updateUserManagerButton(); updateRoleSelections(); updatePermissionSelections(); } @Override protected void createDialogAreaInternal(Composite parent) throws Exception { Composite container = new Composite(parent, SWT.NONE); container.setLayout(new GridLayout(1, false)); container.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); createEveryPermissionButton(container); createUserManagerButton(container); Group rolesGroup = createGroup(container, "Roles"); createRolesWidget(rolesGroup); updateRoleSelections(); createPermissionsTree(container); updatePermissionSelections(); createPermissionsValidation("Select at least one permission or role (with permissions) to grant"); rolesWidget.addSelectionChangedListener(rolesSelectionHandler); permissionsTree.addCheckStateListener(permissionsCheckStateHandler); setControl(container); } private void createPermissionsValidation(String message) { WritableValue dummy = new WritableValue(Boolean.FALSE, Boolean.class); getWidgetCreator().addBooleanBinding(dummy, validPermissions, message); } private void updatePermissionSelections() { permissionsTree.setEnabled(!membership.isEveryPermission()); Set<PermissionEnum> options = getPermissionOptions(); Set<PermissionEnum> selected = new HashSet<PermissionEnum>(explicitPerms); selected.retainAll(options); // don't listen to changes the user isn't making permissionsTree.removeCheckStateListener(permissionsCheckStateHandler); try { // select and disable options that the selected roles include, see // http://tom-eclipse-dev.blogspot.ca/2007/01/tableviewers-and-nativelooking.html for (Role role : membership.getRoles()) { selected.addAll(role.getPermissions()); } permissionsTree.setInput(options); permissionsTree.setSelections(selected); membership.getPermissions().clear(); membership.getPermissions().addAll(selected); updatePageComplete(); } finally { permissionsTree.addCheckStateListener(permissionsCheckStateHandler); } } private Set<PermissionEnum> getPermissionOptions() { Set<PermissionEnum> options = new HashSet<PermissionEnum>(); for (Membership managerMemb : context.getManager().getAllMemberships()) { if (membership.isManageable(managerMemb)) { if (managerMemb.isEveryPermission()) { options.addAll(PermissionEnum.valuesList()); break; } options.addAll(managerMemb.getAllPermissions()); } } // remove options that do not meet requirements Iterator<PermissionEnum> it = options.iterator(); while (it.hasNext()) { PermissionEnum permission = it.next(); if (!permission.isRequirementsMet(membership)) { it.remove(); } } return options; } private void updateRoleSelections() { rolesWidget.setEnabled(!membership.isEveryPermission()); Set<Role> options = getRoleOptions(); Set<Role> selected = new HashSet<Role>(explicitRoles); selected.retainAll(options); // don't listen to changes the user isn't making rolesWidget.removeSelectionChangedListener(rolesSelectionHandler); try { rolesWidget.setSelections(options, selected); membership.getRoles().clear(); membership.getRoles().addAll(selected); updatePageComplete(); } finally { rolesWidget.addSelectionChangedListener(rolesSelectionHandler); } } private Set<Role> getRoleOptions() { Set<Role> options = new HashSet<Role>(); for (Membership managerMemb : context.getManager().getAllMemberships()) { if (membership.isManageable(managerMemb)) { if (managerMemb.isEveryPermission()) { options.addAll(context.getRoles()); break; } options.addAll(managerMemb.getRoles()); } } return options; } private void createUserManagerButton(Composite parent) { userManagerButton = new Button(parent, SWT.CHECK); userManagerButton.setText("Can create users"); userManagerButton .setToolTipText("Can manage, create, edit, and delete users and groups (for the previously selected centers and studies)."); GridData gd = new GridData(); gd.horizontalIndent = 20; userManagerButton.setLayoutData(gd); userManagerButton.setSelection(membership.isUserManager()); userManagerButton.addListener(SWT.Selection, new Listener() { @Override public void handleEvent(Event event) { boolean userManager = userManagerButton.getSelection(); membership.setUserManager(userManager); } }); } private void createEveryPermissionButton(Composite parent) { everyPermissionButton = new Button(parent, SWT.CHECK); everyPermissionButton.setText("Grant all permissions and roles"); everyPermissionButton .setToolTipText("Grant all current and future roles and permissions"); everyPermissionButton.setSelection(membership.isEveryPermission()); everyPermissionButton.addListener(SWT.Selection, new Listener() { @Override public void handleEvent(Event event) { boolean everyPermission = everyPermissionButton.getSelection(); membership.setEveryPermission(everyPermission); updateUserManagerButton(); rolesWidget.setEnabled(!everyPermission); permissionsTree.setEnabled(!everyPermission); updatePageComplete(); } }); } private Group createGroup(Composite parent, String title) { Group group = new Group(parent, SWT.SHADOW_IN); group.setText(title); group.setLayout(new GridLayout(2, false)); group.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); return group; } private void createRolesWidget(Composite parent) { rolesWidget = new MultiSelectWidget<Role>(parent, SWT.NONE, "Available Roles", "Selected Roles", 100) { @Override protected String getTextForObject(Role role) { return role.getName(); } }; } private void createPermissionsTree(Composite parent) { permissionsTree = new PermissionCheckTreeWidget(parent, true, PermissionEnum.valuesList()); GridLayout gl = new GridLayout(2, false); gl.marginWidth = 5; gl.marginHeight = 0; gl.marginTop = 10; gl.horizontalSpacing = 10; gl.verticalSpacing = 5; GridData gd = new GridData(SWT.FILL, SWT.FILL, true, true); gd.heightHint = 160; permissionsTree.setLayout(gl); permissionsTree.setLayoutData(gd); } private void updateEveryPermissionButton() { boolean canGrantEveryPermission = false; for (Membership m : context.getManager().getAllMemberships()) { if (m.isUserManager() && m.isEveryPermission()) { if (m.getDomain().isSuperset(membership.getDomain())) { canGrantEveryPermission = true; break; } } } if (!canGrantEveryPermission) { everyPermissionButton.setSelection(false); } everyPermissionButton.setEnabled(canGrantEveryPermission); updateUserManagerButton(); } private void updateUserManagerButton() { boolean everyPermission = membership.isEveryPermission(); userManagerButton.setEnabled(everyPermission); if (!everyPermission) userManagerButton.setSelection(false); } private void updatePageComplete() { boolean permsSelected = !membership.getAllPermissions().isEmpty(); validPermissions.setValue(permsSelected); setPageComplete(permsSelected); } private class RolesSelectionHandler implements BgcEntryFormWidgetListener { @Override public void selectionChanged(MultiSelectEvent event) { List<Role> selected = rolesWidget.getSelected(); explicitRoles.clear(); explicitRoles.addAll(selected); membership.getRoles().clear(); membership.getRoles().addAll(selected); updatePermissionSelections(); } } private class PermissionsCheckStateHandler implements ICheckStateListener { @Override public void checkStateChanged(CheckStateChangedEvent event) { Object element = event.getElement(); if (!(element instanceof PermissionNode)) return; PermissionNode node = (PermissionNode) event.getElement(); PermissionEnum perm = node.getPermission(); ICheckable checkable = event.getCheckable(); if (isInRole(perm)) { checkable.setChecked(element, true); return; } if (event.getChecked()) { explicitPerms.add(perm); membership.getPermissions().add(perm); } else { explicitPerms.remove(perm); membership.getPermissions().remove(perm); } updatePageComplete(); } private boolean isInRole(Object o) { for (Role role : membership.getRoles()) if (role.getPermissions().contains(o)) return true; return false; } } }