]> git.argeo.org Git - lgpl/argeo-commons.git/blob - org.argeo.security.ui.admin/src/org/argeo/security/ui/admin/internal/parts/GroupMainPage.java
Re-add org.argeo.cms.util.useradmin
[lgpl/argeo-commons.git] / org.argeo.security.ui.admin / src / org / argeo / security / ui / admin / internal / parts / GroupMainPage.java
1 /*
2 * Copyright (C) 2007-2012 Argeo GmbH
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package org.argeo.security.ui.admin.internal.parts;
17
18 import java.util.ArrayList;
19 import java.util.Iterator;
20 import java.util.List;
21
22 import org.argeo.eclipse.ui.ColumnDefinition;
23 import org.argeo.eclipse.ui.EclipseUiUtils;
24 import org.argeo.eclipse.ui.parts.LdifUsersTable;
25 import org.argeo.jcr.ArgeoNames;
26 import org.argeo.osgi.useradmin.LdifName;
27 import org.argeo.security.ui.admin.SecurityAdminImages;
28 import org.argeo.security.ui.admin.internal.UserAdminUtils;
29 import org.argeo.security.ui.admin.internal.UserAdminWrapper;
30 import org.argeo.security.ui.admin.internal.parts.UserEditor.GroupChangeListener;
31 import org.argeo.security.ui.admin.internal.parts.UserEditor.MainInfoListener;
32 import org.argeo.security.ui.admin.internal.providers.CommonNameLP;
33 import org.argeo.security.ui.admin.internal.providers.MailLP;
34 import org.argeo.security.ui.admin.internal.providers.RoleIconLP;
35 import org.argeo.security.ui.admin.internal.providers.UserFilter;
36 import org.argeo.security.ui.admin.internal.providers.UserNameLP;
37 import org.argeo.security.ui.admin.internal.providers.UserTableDefaultDClickListener;
38 import org.eclipse.jface.action.Action;
39 import org.eclipse.jface.action.ToolBarManager;
40 import org.eclipse.jface.dialogs.MessageDialog;
41 import org.eclipse.jface.resource.ImageDescriptor;
42 import org.eclipse.jface.viewers.ISelection;
43 import org.eclipse.jface.viewers.IStructuredSelection;
44 import org.eclipse.jface.viewers.TableViewer;
45 import org.eclipse.jface.viewers.ViewerDropAdapter;
46 import org.eclipse.swt.SWT;
47 import org.eclipse.swt.dnd.DND;
48 import org.eclipse.swt.dnd.DropTargetEvent;
49 import org.eclipse.swt.dnd.TextTransfer;
50 import org.eclipse.swt.dnd.Transfer;
51 import org.eclipse.swt.dnd.TransferData;
52 import org.eclipse.swt.events.DisposeEvent;
53 import org.eclipse.swt.events.DisposeListener;
54 import org.eclipse.swt.events.ModifyListener;
55 import org.eclipse.swt.graphics.Cursor;
56 import org.eclipse.swt.layout.GridData;
57 import org.eclipse.swt.layout.GridLayout;
58 import org.eclipse.swt.widgets.Composite;
59 import org.eclipse.swt.widgets.Label;
60 import org.eclipse.swt.widgets.Shell;
61 import org.eclipse.swt.widgets.Text;
62 import org.eclipse.swt.widgets.ToolBar;
63 import org.eclipse.ui.forms.AbstractFormPart;
64 import org.eclipse.ui.forms.IManagedForm;
65 import org.eclipse.ui.forms.SectionPart;
66 import org.eclipse.ui.forms.editor.FormEditor;
67 import org.eclipse.ui.forms.editor.FormPage;
68 import org.eclipse.ui.forms.widgets.FormToolkit;
69 import org.eclipse.ui.forms.widgets.ScrolledForm;
70 import org.eclipse.ui.forms.widgets.Section;
71 import org.osgi.service.useradmin.Group;
72 import org.osgi.service.useradmin.Role;
73 import org.osgi.service.useradmin.User;
74 import org.osgi.service.useradmin.UserAdmin;
75 import org.osgi.service.useradmin.UserAdminEvent;
76
77 /** Display/edit main properties of a given group */
78 public class GroupMainPage extends FormPage implements ArgeoNames {
79 final static String ID = "GroupEditor.mainPage";
80
81 private final UserEditor editor;
82 private UserAdminWrapper userAdminWrapper;
83
84 // Local configuration
85 private final int PRE_TITLE_INDENT = 10;
86
87 public GroupMainPage(FormEditor editor, UserAdminWrapper userAdminWrapper) {
88 super(editor, ID, "Main");
89 this.editor = (UserEditor) editor;
90 this.userAdminWrapper = userAdminWrapper;
91 }
92
93 protected void createFormContent(final IManagedForm mf) {
94 ScrolledForm form = mf.getForm();
95 Composite body = form.getBody();
96 GridLayout mainLayout = new GridLayout();
97 body.setLayout(mainLayout);
98 Group group = (Group) editor.getDisplayedUser();
99 appendOverviewPart(body, group);
100 appendMembersPart(body, group);
101 }
102
103 /** Creates the general section */
104 protected void appendOverviewPart(final Composite parent, final Group group) {
105 FormToolkit tk = getManagedForm().getToolkit();
106 Composite body = addSection(tk, parent, "Main information");
107 GridLayout layout = new GridLayout(2, false);
108 body.setLayout(layout);
109
110 final Text dnTxt = createLT(body, "DN", group.getName());
111 dnTxt.setEnabled(false);
112
113 final Text cnTxt = createLT(body, "Common Name",
114 UserAdminUtils.getProperty(group, LdifName.cn.name()));
115 cnTxt.setEnabled(false);
116
117 Label descLbl = new Label(body, SWT.LEAD);
118 descLbl.setText("Description");
119 descLbl.setLayoutData(new GridData(SWT.RIGHT, SWT.TOP, false, false));
120 final Text descTxt = new Text(body, SWT.LEAD | SWT.MULTI | SWT.WRAP
121 | SWT.BORDER);
122 GridData gd = EclipseUiUtils.fillAll();
123 gd.heightHint = 100;
124 descTxt.setLayoutData(gd);
125
126 // create form part (controller)
127 AbstractFormPart part = new SectionPart((Section) body.getParent()) {
128
129 private MainInfoListener listener;
130
131 @Override
132 public void initialize(IManagedForm form) {
133 super.initialize(form);
134 listener = editor.new MainInfoListener(parent.getDisplay(), this);
135 userAdminWrapper.addListener(listener);
136 }
137
138 @Override
139 public void dispose() {
140 userAdminWrapper.removeListener(listener);
141 super.dispose();
142 }
143
144 @SuppressWarnings("unchecked")
145 public void commit(boolean onSave) {
146 group.getProperties().put(LdifName.description.name(),
147 descTxt.getText());
148 // Enable common name ?
149 // editor.setProperty(UserAdminConstants.KEY_CN,
150 // email.getText());
151 super.commit(onSave);
152 }
153
154 @Override
155 public void refresh() {
156 refreshFormTitle(group);
157 dnTxt.setText(group.getName());
158 cnTxt.setText(UserAdminUtils.getProperty(group,
159 LdifName.cn.name()));
160 descTxt.setText(UserAdminUtils.getProperty(group,
161 LdifName.description.name()));
162 super.refresh();
163 }
164 };
165
166 ModifyListener defaultListener = editor.new FormPartML(part);
167 descTxt.addModifyListener(defaultListener);
168 getManagedForm().addPart(part);
169 }
170
171 /** Filtered table with members. Has drag & drop ability */
172 protected void appendMembersPart(Composite parent, Group group) {
173
174 FormToolkit tk = getManagedForm().getToolkit();
175 Section section = tk.createSection(parent, Section.TITLE_BAR);
176 section.setLayoutData(EclipseUiUtils.fillAll());
177
178 Composite body = new Composite(section, SWT.NO_FOCUS);
179 section.setClient(body);
180 body.setLayoutData(EclipseUiUtils.fillAll());
181
182 LdifUsersTable userTableViewerCmp = createMemberPart(body, group);
183
184 SectionPart part = new GroupMembersPart(section, userTableViewerCmp,
185 group);
186 getManagedForm().addPart(part);
187 addRemoveAbitily(part, userTableViewerCmp.getTableViewer(), group);
188 }
189
190 public LdifUsersTable createMemberPart(Composite parent, Group group) {
191 parent.setLayout(EclipseUiUtils.noSpaceGridLayout());
192
193 // Define the displayed columns
194 List<ColumnDefinition> columnDefs = new ArrayList<ColumnDefinition>();
195 columnDefs.add(new ColumnDefinition(new RoleIconLP(), "", 0, 24));
196 columnDefs.add(new ColumnDefinition(new CommonNameLP(), "Common Name",
197 150));
198 columnDefs.add(new ColumnDefinition(new MailLP(), "Primary Mail", 150));
199 columnDefs.add(new ColumnDefinition(new UserNameLP(),
200 "Distinguished Name", 240));
201
202 // Create and configure the table
203 LdifUsersTable userViewerCmp = new MyUserTableViewer(parent, SWT.MULTI
204 | SWT.H_SCROLL | SWT.V_SCROLL, userAdminWrapper.getUserAdmin());
205
206 userViewerCmp.setColumnDefinitions(columnDefs);
207 userViewerCmp.populate(true, false);
208 userViewerCmp.setLayoutData(EclipseUiUtils.fillAll());
209
210 // Controllers
211 TableViewer userViewer = userViewerCmp.getTableViewer();
212 userViewer.addDoubleClickListener(new UserTableDefaultDClickListener());
213 int operations = DND.DROP_COPY | DND.DROP_MOVE;
214 Transfer[] tt = new Transfer[] { TextTransfer.getInstance() };
215 userViewer.addDropSupport(operations, tt,
216 new GroupDropListener(userAdminWrapper, userViewerCmp,
217 (Group) editor.getDisplayedUser()));
218
219 return userViewerCmp;
220 }
221
222 // Local viewers
223 private class MyUserTableViewer extends LdifUsersTable {
224 private static final long serialVersionUID = 8467999509931900367L;
225
226 private final UserFilter userFilter;
227
228 public MyUserTableViewer(Composite parent, int style,
229 UserAdmin userAdmin) {
230 super(parent, style, true);
231 userFilter = new UserFilter();
232
233 }
234
235 @Override
236 protected List<User> listFilteredElements(String filter) {
237 Group group = (Group) editor.getDisplayedUser();
238 Role[] roles = group.getMembers();
239 List<User> users = new ArrayList<User>();
240 userFilter.setSearchText(filter);
241 for (Role role : roles)
242 // if (role.getType() == Role.GROUP)
243 if (userFilter.select(null, null, role))
244 users.add((User) role);
245 return users;
246 }
247 }
248
249 private void addRemoveAbitily(SectionPart sectionPart,
250 TableViewer userViewer, Group group) {
251 Section section = sectionPart.getSection();
252 ToolBarManager toolBarManager = new ToolBarManager(SWT.FLAT);
253 ToolBar toolbar = toolBarManager.createControl(section);
254 final Cursor handCursor = new Cursor(section.getDisplay(),
255 SWT.CURSOR_HAND);
256 toolbar.setCursor(handCursor);
257 toolbar.addDisposeListener(new DisposeListener() {
258 private static final long serialVersionUID = 3882131405820522925L;
259
260 public void widgetDisposed(DisposeEvent e) {
261 if ((handCursor != null) && (handCursor.isDisposed() == false)) {
262 handCursor.dispose();
263 }
264 }
265 });
266
267 Action action = new RemoveMembershipAction(userViewer, group,
268 "Remove selected items from this group",
269 SecurityAdminImages.ICON_REMOVE_DESC);
270 toolBarManager.add(action);
271 toolBarManager.update(true);
272 section.setTextClient(toolbar);
273 }
274
275 private class RemoveMembershipAction extends Action {
276 private static final long serialVersionUID = -1337713097184522588L;
277
278 private final TableViewer userViewer;
279 private final Group group;
280
281 RemoveMembershipAction(TableViewer userViewer, Group group,
282 String name, ImageDescriptor img) {
283 super(name, img);
284 this.userViewer = userViewer;
285 this.group = group;
286 }
287
288 @Override
289 public void run() {
290 ISelection selection = userViewer.getSelection();
291 if (selection.isEmpty())
292 return;
293
294 @SuppressWarnings("unchecked")
295 Iterator<User> it = ((IStructuredSelection) selection).iterator();
296 List<User> users = new ArrayList<User>();
297 // StringBuilder builder = new StringBuilder();
298 while (it.hasNext()) {
299 User currUser = it.next();
300 // String groupName = UserAdminUtils.getUsername(currGroup);
301 // builder.append(groupName).append("; ");
302 users.add(currUser);
303 }
304
305 userAdminWrapper.beginTransactionIfNeeded();
306 for (User user : users) {
307 group.removeMember(user);
308 }
309 userAdminWrapper.notifyListeners(new UserAdminEvent(null,
310 UserAdminEvent.ROLE_CHANGED, group));
311 }
312 }
313
314 // LOCAL CONTROLLERS
315 private class GroupMembersPart extends SectionPart {
316 private final LdifUsersTable userViewer;
317 private final Group group;
318
319 private GroupChangeListener listener;
320
321 public GroupMembersPart(Section section, LdifUsersTable userViewer,
322 Group group) {
323 super(section);
324 this.userViewer = userViewer;
325 this.group = group;
326 }
327
328 @Override
329 public void initialize(IManagedForm form) {
330 super.initialize(form);
331 listener = editor.new GroupChangeListener(userViewer.getDisplay(), GroupMembersPart.this);
332 userAdminWrapper.addListener(listener);
333 }
334
335 @Override
336 public void dispose() {
337 userAdminWrapper.removeListener(listener);
338 super.dispose();
339 }
340
341 @Override
342 public void refresh() {
343 refreshFormTitle(group);
344 getSection().setText(
345 "Members of group "
346 + UserAdminUtils.getProperty(group,
347 LdifName.cn.name()));
348 userViewer.refresh();
349 super.refresh();
350 }
351 }
352
353 /**
354 * Defines this table as being a potential target to add group membership
355 * (roles) to this group
356 */
357 private class GroupDropListener extends ViewerDropAdapter {
358 private static final long serialVersionUID = 2893468717831451621L;
359
360 private final UserAdminWrapper userAdminWrapper;
361 // private final LdifUsersTable myUserViewerCmp;
362 private final Group myGroup;
363
364 public GroupDropListener(UserAdminWrapper userAdminWrapper,
365 LdifUsersTable userTableViewerCmp, Group group) {
366 super(userTableViewerCmp.getTableViewer());
367 this.userAdminWrapper = userAdminWrapper;
368 this.myGroup = group;
369 // this.myUserViewerCmp = userTableViewerCmp;
370 }
371
372 @Override
373 public boolean validateDrop(Object target, int operation,
374 TransferData transferType) {
375 // Target is always OK in a list only view
376 // TODO check if not a string
377 boolean validDrop = true;
378 return validDrop;
379 }
380
381 @Override
382 public void drop(DropTargetEvent event) {
383 // TODO Is there an opportunity to perform the check before?
384
385 String newUserName = (String) event.data;
386 UserAdmin myUserAdmin = userAdminWrapper.getUserAdmin();
387 Role role = myUserAdmin.getRole(newUserName);
388 if (role.getType() == Role.GROUP) {
389 Group newGroup = (Group) role;
390 Shell shell = getViewer().getControl().getShell();
391 // Sanity checks
392 if (myGroup == newGroup) { // Equality
393 MessageDialog.openError(shell, "Forbidden addition ",
394 "A group cannot be a member of itself.");
395 return;
396 }
397
398 // Cycle
399 String myName = myGroup.getName();
400 List<User> myMemberships = editor.getFlatGroups(myGroup);
401 if (myMemberships.contains(newGroup)) {
402 MessageDialog.openError(shell, "Forbidden addition: cycle",
403 "Cannot add " + newUserName + " to group " + myName
404 + ". This would create a cycle");
405 return;
406 }
407
408 // Already member
409 List<User> newGroupMemberships = editor.getFlatGroups(newGroup);
410 if (newGroupMemberships.contains(myGroup)) {
411 MessageDialog.openError(shell, "Forbidden addition",
412 "Cannot add " + newUserName + " to group " + myName
413 + ", this membership already exists");
414 return;
415 }
416 userAdminWrapper.beginTransactionIfNeeded();
417 // TODO implement the dirty state
418 myGroup.addMember(newGroup);
419 userAdminWrapper.notifyListeners(new UserAdminEvent(null,
420 UserAdminEvent.ROLE_CHANGED, myGroup));
421 } else if (role.getType() == Role.USER) {
422 // TODO check if the group is already member of this group
423 userAdminWrapper.beginTransactionIfNeeded();
424 User user = (User) role;
425 myGroup.addMember(user);
426 userAdminWrapper.notifyListeners(new UserAdminEvent(null,
427 UserAdminEvent.ROLE_CHANGED, myGroup));
428 }
429 super.drop(event);
430 }
431
432 @Override
433 public boolean performDrop(Object data) {
434 // myUserViewerCmp.refresh();
435 return true;
436 }
437 }
438
439 // LOCAL HELPERS
440 private void refreshFormTitle(Group group) {
441 getManagedForm().getForm().setText(
442 UserAdminUtils.getProperty(group, LdifName.cn.name()));
443 }
444
445 private Composite addSection(FormToolkit tk, Composite parent, String title) {
446 Section section = tk.createSection(parent, Section.TITLE_BAR);
447 GridData gd = EclipseUiUtils.fillWidth();
448 gd.verticalAlignment = PRE_TITLE_INDENT;
449 section.setLayoutData(gd);
450 section.setText(title);
451 Composite body = tk.createComposite(section, SWT.WRAP);
452 body.setLayoutData(EclipseUiUtils.fillAll());
453 section.setClient(body);
454 return body;
455 }
456
457 /** Creates label and text. */
458 private Text createLT(Composite body, String label, String value) {
459 FormToolkit toolkit = getManagedForm().getToolkit();
460 Label lbl = toolkit.createLabel(body, label);
461 lbl.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false));
462 Text text = toolkit.createText(body, value, SWT.BORDER);
463 text.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
464 return text;
465 }
466 }