From 28f2a8c1668ce2e9d2bb2a6601a659c2bcc2676b Mon Sep 17 00:00:00 2001 From: Bruno Sinou Date: Mon, 14 Sep 2015 17:28:40 +0000 Subject: [PATCH] First draft of a drag and drop implementation to manage group. Implement create group command. git-svn-id: https://svn.argeo.org/commons/trunk@8392 4cfe0d0a-d680-48aa-b62c-e0a02a3f76cc --- .../META-INF/spring/commands.xml | 6 + .../security/ui/admin/commands/NewGroup.java | 231 ++++++++++++++---- .../ui/admin/editors/UserMainPage.java | 65 ++++- .../ui/admin/internal/UserAdminConstants.java | 2 + .../ui/admin/internal/UserDragListener.java | 39 +++ .../security/ui/admin/views/GroupsView.java | 10 + .../security/ui/admin/views/UsersView.java | 15 +- 7 files changed, 320 insertions(+), 48 deletions(-) create mode 100644 org.argeo.security.ui.admin/src/org/argeo/security/ui/admin/internal/UserDragListener.java diff --git a/org.argeo.security.ui.admin/META-INF/spring/commands.xml b/org.argeo.security.ui.admin/META-INF/spring/commands.xml index 23be58d8d..a2a25d7e8 100644 --- a/org.argeo.security.ui.admin/META-INF/spring/commands.xml +++ b/org.argeo.security.ui.admin/META-INF/spring/commands.xml @@ -11,6 +11,12 @@ + + + + + diff --git a/org.argeo.security.ui.admin/src/org/argeo/security/ui/admin/commands/NewGroup.java b/org.argeo.security.ui.admin/src/org/argeo/security/ui/admin/commands/NewGroup.java index 41672d5b6..22780f27c 100644 --- a/org.argeo.security.ui.admin/src/org/argeo/security/ui/admin/commands/NewGroup.java +++ b/org.argeo.security.ui.admin/src/org/argeo/security/ui/admin/commands/NewGroup.java @@ -15,12 +15,40 @@ */ package org.argeo.security.ui.admin.commands; +import java.util.Dictionary; + +import javax.transaction.Status; +import javax.transaction.UserTransaction; + +import org.argeo.ArgeoException; +import org.argeo.eclipse.ui.EclipseUiUtils; +import org.argeo.eclipse.ui.dialogs.ErrorFeedback; +import org.argeo.jcr.ArgeoNames; import org.argeo.security.ui.admin.SecurityAdminPlugin; +import org.argeo.security.ui.admin.internal.UiAdminUtils; +import org.argeo.security.ui.admin.internal.UserAdminConstants; +import org.argeo.security.ui.admin.views.GroupsView; import org.eclipse.core.commands.AbstractHandler; import org.eclipse.core.commands.ExecutionEvent; import org.eclipse.core.commands.ExecutionException; -import org.eclipse.jface.dialogs.MessageDialog; +import org.eclipse.jface.window.Window; +import org.eclipse.jface.wizard.Wizard; +import org.eclipse.jface.wizard.WizardDialog; +import org.eclipse.jface.wizard.WizardPage; +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.ModifyEvent; +import org.eclipse.swt.events.ModifyListener; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Label; +import org.eclipse.swt.widgets.Text; +import org.eclipse.ui.IWorkbenchPage; +import org.eclipse.ui.IWorkbenchPart; +import org.eclipse.ui.IWorkbenchWindow; import org.eclipse.ui.handlers.HandlerUtil; +import org.osgi.service.useradmin.Group; +import org.osgi.service.useradmin.Role; import org.osgi.service.useradmin.UserAdmin; /** Create a new group. */ @@ -28,53 +56,174 @@ public class NewGroup extends AbstractHandler { public final static String ID = SecurityAdminPlugin.PLUGIN_ID + ".newGroup"; private UserAdmin userAdmin; + private UserTransaction userTransaction; + + // TODO implement a dynamic choice of the base dn + private String getDn(String cn) { + return "cn=" + cn + ",dc=example,dc=com"; + } public Object execute(ExecutionEvent event) throws ExecutionException { + NewGroupWizard newGroupWizard = new NewGroupWizard(); + WizardDialog dialog = new WizardDialog( + HandlerUtil.getActiveShell(event), newGroupWizard); + dialog.setTitle("Create a new group"); - MessageDialog - .openError(HandlerUtil.getActiveShell(event), - "Unimplemented method", - "Group creation is not yet implemented"); + // Force refresh until the listener are implemented + if (Window.OK == dialog.open()) + forceRefresh(event); return null; } + private void forceRefresh(ExecutionEvent event) { + IWorkbenchWindow iww = HandlerUtil.getActiveWorkbenchWindow(event); + if (iww == null) + return; + IWorkbenchPage activePage = iww.getActivePage(); + IWorkbenchPart part = activePage.getActivePart(); + if (part instanceof GroupsView) + ((GroupsView) part).refresh(); + } + + private class NewGroupWizard extends Wizard { + + // pages + private MainGroupInfoWizardPage mainGroupInfo; + + // End user fields + private Text dNameTxt, commonNameTxt, descriptionTxt; + + public NewGroupWizard() { + } + + @Override + public void addPages() { + mainGroupInfo = new MainGroupInfoWizardPage(); + addPage(mainGroupInfo); + + setWindowTitle("Create a new group"); + // mainGroupInfo.setMessage(message, WizardPage.WARNING); + } + + @SuppressWarnings({ "rawtypes", "unchecked" }) + @Override + public boolean performFinish() { + if (!canFinish()) + return false; + String commonName = commonNameTxt.getText(); + + // Begin transaction if needed + try { + if (userTransaction.getStatus() == Status.STATUS_NO_TRANSACTION) + userTransaction.begin(); + } catch (Exception e) { + throw new ArgeoException("Unable to start " + + "transaction to create user " + commonName, e); + } + + try { + Group user = (Group) userAdmin.createRole(getDn(commonName), + Role.GROUP); + Dictionary props = user.getProperties(); + String descStr = descriptionTxt.getText(); + if (UiAdminUtils.notNull(descStr)) + props.put(UserAdminConstants.KEY_DESC, descStr); + return true; + } catch (Exception e) { + ErrorFeedback.show("Cannot create new group " + commonName, e); + return false; + } + } + + private class MainGroupInfoWizardPage extends WizardPage implements + ModifyListener, ArgeoNames { + private static final long serialVersionUID = -3150193365151601807L; + + public MainGroupInfoWizardPage() { + super("Main"); + setTitle("General information"); + setMessage("Please provide a common name and a free description"); + } + + @Override + public void createControl(Composite parent) { + Composite bodyCmp = new Composite(parent, SWT.NONE); + bodyCmp.setLayout(new GridLayout(2, false)); + dNameTxt = EclipseUiUtils.createGridLT(bodyCmp, + "Distinguished name", this); + dNameTxt.setEnabled(false); + commonNameTxt = EclipseUiUtils.createGridLT(bodyCmp, + "Common name", this); + commonNameTxt.addModifyListener(new ModifyListener() { + private static final long serialVersionUID = -1435351236582736843L; + + @Override + public void modifyText(ModifyEvent event) { + String name = commonNameTxt.getText(); + if (name.trim().equals("")) { + dNameTxt.setText(""); + } else { + dNameTxt.setText(getDn(name)); + } + } + }); + + Label descLbl = new Label(bodyCmp, SWT.LEAD); + descLbl.setText("Description"); + descLbl.setLayoutData(new GridData(SWT.RIGHT, SWT.TOP, false, + false)); + descriptionTxt = new Text(bodyCmp, SWT.LEAD | SWT.MULTI + | SWT.WRAP | SWT.BORDER); + descriptionTxt.setLayoutData(EclipseUiUtils.fillAll()); + descriptionTxt.addModifyListener(this); + + setControl(bodyCmp); + + // Initialize buttons + setPageComplete(false); + getContainer().updateButtons(); + } + + @Override + public void modifyText(ModifyEvent event) { + String message = checkComplete(); + if (message != null) { + setMessage(message, WizardPage.ERROR); + setPageComplete(false); + } else { + setMessage("Complete", WizardPage.INFORMATION); + setPageComplete(true); + } + getContainer().updateButtons(); + } + + /** @return error message or null if complete */ + protected String checkComplete() { + String name = commonNameTxt.getText(); + + if (name.trim().equals("")) + return "Common name must not be empty"; + Role role = userAdmin.getRole(getDn(name)); + if (role != null) + return "Group " + name + " already exists"; + return null; + } + + @Override + public void setVisible(boolean visible) { + super.setVisible(visible); + if (visible) + commonNameTxt.setFocus(); + } + } + } + /* DEPENDENCY INJECTION */ public void setUserAdmin(UserAdmin userAdmin) { this.userAdmin = userAdmin; } -} - -// JcrRolesView rolesView = (JcrRolesView) HandlerUtil -// .getActiveWorkbenchWindow(event).getActivePage() -// .findView(JcrRolesView.ID); -// String role = rolesView.getNewRole(); -// if (role.trim().equals("")) -// return null; -// if (role.equals(rolesView.getAddNewRoleText())) -// return null; -// role = role.trim().toUpperCase(); -// if (!role.startsWith(rolePrefix)) -// role = rolePrefix + role; -// if (userAdminService.listEditableRoles().contains(role)) -// throw new ArgeoException("Role " + role + " already exists"); -// userAdminService.newRole(role); -// rolesView.refresh(); -// -// // refresh editors -// IEditorReference[] refs = HandlerUtil.getActiveWorkbenchWindow(event) -// .getActivePage() -// .findEditors(null, JcrArgeoUserEditor.ID, IWorkbenchPage.MATCH_ID); -// for (IEditorReference ref : refs) { -// JcrArgeoUserEditor userEditor = (JcrArgeoUserEditor) ref.getEditor(false); -// if (userEditor != null) { -// userEditor.refresh(); -// } -// } -// return null; -// } -// -// public void setUserAdminService(UserAdminService userAdminService) { -// this.userAdminService = userAdminService; -// } -// -// } + + public void setUserTransaction(UserTransaction userTransaction) { + this.userTransaction = userTransaction; + } +} \ No newline at end of file diff --git a/org.argeo.security.ui.admin/src/org/argeo/security/ui/admin/editors/UserMainPage.java b/org.argeo.security.ui.admin/src/org/argeo/security/ui/admin/editors/UserMainPage.java index df8e505af..41b21651f 100644 --- a/org.argeo.security.ui.admin/src/org/argeo/security/ui/admin/editors/UserMainPage.java +++ b/org.argeo.security.ui.admin/src/org/argeo/security/ui/admin/editors/UserMainPage.java @@ -30,7 +30,14 @@ import org.argeo.security.ui.admin.internal.UserNameLP; import org.argeo.security.ui.admin.internal.UserTableDefaultDClickListener; import org.argeo.security.ui.admin.internal.UserTableViewer; import org.eclipse.jface.viewers.TableViewer; +import org.eclipse.jface.viewers.Viewer; +import org.eclipse.jface.viewers.ViewerDropAdapter; import org.eclipse.swt.SWT; +import org.eclipse.swt.dnd.DND; +import org.eclipse.swt.dnd.DropTargetEvent; +import org.eclipse.swt.dnd.TextTransfer; +import org.eclipse.swt.dnd.Transfer; +import org.eclipse.swt.dnd.TransferData; import org.eclipse.swt.events.ModifyEvent; import org.eclipse.swt.events.ModifyListener; import org.eclipse.swt.layout.GridData; @@ -46,6 +53,8 @@ import org.eclipse.ui.forms.editor.FormPage; import org.eclipse.ui.forms.widgets.FormToolkit; import org.eclipse.ui.forms.widgets.ScrolledForm; import org.eclipse.ui.forms.widgets.Section; +import org.osgi.service.useradmin.Group; +import org.osgi.service.useradmin.Role; import org.osgi.service.useradmin.User; import org.osgi.service.useradmin.UserAdmin; @@ -208,7 +217,7 @@ public class UserMainPage extends FormPage implements ArgeoNames { private UserTableViewer userTableViewerCmp; private TableViewer userViewer; - public void appendMemberOfPart(Composite parent) { + private void appendMemberOfPart(Composite parent) { FormToolkit tk = getManagedForm().getToolkit(); Composite body = addSection(tk, parent, "Roles"); body.setLayout(EclipseUiUtils.noSpaceGridLayout()); @@ -236,6 +245,13 @@ public class UserMainPage extends FormPage implements ArgeoNames { userViewer.addDoubleClickListener(new UserTableDefaultDClickListener()); // Really? userTableViewerCmp.refresh(); + + // Drag and drop + int operations = DND.DROP_COPY | DND.DROP_MOVE; + Transfer[] tt = new Transfer[] { TextTransfer.getInstance() }; + userViewer.addDropSupport(operations, tt, new ItemDropListener( + userViewer, userAdmin, editor.getDisplayedUser())); + } private class MyUserTableViewer extends UserTableViewer { @@ -252,6 +268,53 @@ public class UserMainPage extends FormPage implements ArgeoNames { } } + // DRAG & DROP MANAGEMENT + + private class ItemDropListener extends ViewerDropAdapter { + private static final long serialVersionUID = 2893468717831451621L; + + private final UserAdmin myUserAdmin; + private final User myUser; + + public ItemDropListener(Viewer viewer, UserAdmin userAdmin, User user) { + super(viewer); + this.myUserAdmin = userAdmin; + this.myUser = user; + } + + @Override + public boolean validateDrop(Object target, int operation, + TransferData transferType) { + // Target is always OK in a list only view + // TODO check if not a string + boolean validDrop = true; + return validDrop; + } + + @Override + public void drop(DropTargetEvent event) { + String name = (String) event.data; + Role role = myUserAdmin.getRole(name); + // TODO this check should be done before. + if (role.getType() == Role.GROUP) { + // TODO check if the user is already member of this group + // we expect here that there is already a begun transaction + // TODO implement the dirty state + Group group = (Group) role; + group.addMember(myUser); + } + super.drop(event); + } + + @Override + public boolean performDrop(Object data) { + userTableViewerCmp.refresh(); + return true; + } + } + + // LOCAL HELPERS + /** Appends a section with a title */ private Composite addSection(FormToolkit tk, Composite parent, String title) { Section section = tk.createSection(parent, Section.TITLE_BAR); GridData gd = EclipseUiUtils.fillWidth(); diff --git a/org.argeo.security.ui.admin/src/org/argeo/security/ui/admin/internal/UserAdminConstants.java b/org.argeo.security.ui.admin/src/org/argeo/security/ui/admin/internal/UserAdminConstants.java index ab9f0fbe2..4dbb358f0 100644 --- a/org.argeo.security.ui.admin/src/org/argeo/security/ui/admin/internal/UserAdminConstants.java +++ b/org.argeo.security.ui.admin/src/org/argeo/security/ui/admin/internal/UserAdminConstants.java @@ -9,4 +9,6 @@ public interface UserAdminConstants { public final static String KEY_FIRSTNAME = "givenname"; public final static String KEY_LASTNAME = "sn"; public final static String KEY_MAIL = "mail"; + public final static String KEY_DESC = "description"; + } \ No newline at end of file diff --git a/org.argeo.security.ui.admin/src/org/argeo/security/ui/admin/internal/UserDragListener.java b/org.argeo.security.ui.admin/src/org/argeo/security/ui/admin/internal/UserDragListener.java new file mode 100644 index 000000000..abaab3301 --- /dev/null +++ b/org.argeo.security.ui.admin/src/org/argeo/security/ui/admin/internal/UserDragListener.java @@ -0,0 +1,39 @@ +package org.argeo.security.ui.admin.internal; + +import org.eclipse.jface.viewers.IStructuredSelection; +import org.eclipse.jface.viewers.Viewer; +import org.eclipse.swt.dnd.DragSourceEvent; +import org.eclipse.swt.dnd.DragSourceListener; +import org.osgi.service.useradmin.User; + +public class UserDragListener implements DragSourceListener { + private static final long serialVersionUID = -2074337775033781454L; + private final Viewer viewer; + + public UserDragListener(Viewer viewer) { + this.viewer = viewer; + } + + public void dragStart(DragSourceEvent event) { + // TODO implement finer checks + IStructuredSelection selection = (IStructuredSelection) viewer + .getSelection(); + if (selection.isEmpty() || selection.size() > 1) + event.doit = false; + else + event.doit = true; + } + + public void dragSetData(DragSourceEvent event) { + // TODO Support multiple selection + Object obj = ((IStructuredSelection) viewer.getSelection()) + .getFirstElement(); + if (obj != null) { + User user = (User) obj; + event.data = user.getName(); + } + } + + public void dragFinished(DragSourceEvent event) { + } +} \ No newline at end of file diff --git a/org.argeo.security.ui.admin/src/org/argeo/security/ui/admin/views/GroupsView.java b/org.argeo.security.ui.admin/src/org/argeo/security/ui/admin/views/GroupsView.java index faf0e8025..74d2c995d 100644 --- a/org.argeo.security.ui.admin/src/org/argeo/security/ui/admin/views/GroupsView.java +++ b/org.argeo.security.ui.admin/src/org/argeo/security/ui/admin/views/GroupsView.java @@ -26,11 +26,15 @@ import org.argeo.security.ui.admin.internal.ColumnDefinition; import org.argeo.security.ui.admin.internal.CommonNameLP; import org.argeo.security.ui.admin.internal.UiAdminUtils; import org.argeo.security.ui.admin.internal.UserAdminConstants; +import org.argeo.security.ui.admin.internal.UserDragListener; import org.argeo.security.ui.admin.internal.UserNameLP; import org.argeo.security.ui.admin.internal.UserTableDefaultDClickListener; import org.argeo.security.ui.admin.internal.UserTableViewer; import org.eclipse.jface.viewers.TableViewer; import org.eclipse.swt.SWT; +import org.eclipse.swt.dnd.DND; +import org.eclipse.swt.dnd.TextTransfer; +import org.eclipse.swt.dnd.Transfer; import org.eclipse.swt.widgets.Composite; import org.osgi.framework.InvalidSyntaxException; import org.osgi.service.useradmin.Role; @@ -74,6 +78,12 @@ public class GroupsView extends UsersView implements ArgeoNames { // Really? groupTableViewerCmp.refresh(); + + // Drag and drop + int operations = DND.DROP_COPY | DND.DROP_MOVE; + Transfer[] tt = new Transfer[] { TextTransfer.getInstance() }; + userViewer.addDragSupport(operations, tt, new UserDragListener( + userViewer)); } private class MyUserTableViewer extends UserTableViewer { diff --git a/org.argeo.security.ui.admin/src/org/argeo/security/ui/admin/views/UsersView.java b/org.argeo.security.ui.admin/src/org/argeo/security/ui/admin/views/UsersView.java index 3438d85b0..538329559 100644 --- a/org.argeo.security.ui.admin/src/org/argeo/security/ui/admin/views/UsersView.java +++ b/org.argeo.security.ui.admin/src/org/argeo/security/ui/admin/views/UsersView.java @@ -27,11 +27,15 @@ import org.argeo.security.ui.admin.internal.CommonNameLP; import org.argeo.security.ui.admin.internal.MailLP; import org.argeo.security.ui.admin.internal.UiAdminUtils; import org.argeo.security.ui.admin.internal.UserAdminConstants; +import org.argeo.security.ui.admin.internal.UserDragListener; import org.argeo.security.ui.admin.internal.UserNameLP; import org.argeo.security.ui.admin.internal.UserTableDefaultDClickListener; import org.argeo.security.ui.admin.internal.UserTableViewer; import org.eclipse.jface.viewers.TableViewer; import org.eclipse.swt.SWT; +import org.eclipse.swt.dnd.DND; +import org.eclipse.swt.dnd.TextTransfer; +import org.eclipse.swt.dnd.Transfer; import org.eclipse.swt.widgets.Composite; import org.eclipse.ui.part.ViewPart; import org.osgi.framework.InvalidSyntaxException; @@ -79,12 +83,11 @@ public class UsersView extends ViewPart implements ArgeoNames { // Really? userTableViewerCmp.refresh(); - // try { - // if (userTransaction != null) - // userTransaction.begin(); - // } catch (Exception e) { - // throw new ArgeoException("Cannot begin transaction", e); - // } + // Drag and drop + int operations = DND.DROP_COPY | DND.DROP_MOVE; + Transfer[] tt = new Transfer[] { TextTransfer.getInstance() }; + userViewer.addDragSupport(operations, tt, new UserDragListener( + userViewer)); } private class MyUserTableViewer extends UserTableViewer { -- 2.30.2