]> git.argeo.org Git - lgpl/argeo-commons.git/blob - org.argeo.security.ui.admin/src/org/argeo/security/ui/admin/internal/parts/UserMainPage.java
Work on user UI
[lgpl/argeo-commons.git] / org.argeo.security.ui.admin / src / org / argeo / security / ui / admin / internal / parts / UserMainPage.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.ArgeoException;
23 import org.argeo.eclipse.ui.ColumnDefinition;
24 import org.argeo.eclipse.ui.EclipseUiUtils;
25 import org.argeo.eclipse.ui.parts.LdifUsersTable;
26 import org.argeo.jcr.ArgeoNames;
27 import org.argeo.osgi.useradmin.LdifName;
28 import org.argeo.security.ui.admin.SecurityAdminImages;
29 import org.argeo.security.ui.admin.internal.UiAdminUtils;
30 import org.argeo.security.ui.admin.internal.UserAdminWrapper;
31 import org.argeo.security.ui.admin.internal.parts.UserEditor.GroupChangeListener;
32 import org.argeo.security.ui.admin.internal.parts.UserEditor.MainInfoListener;
33 import org.argeo.security.ui.admin.internal.providers.CommonNameLP;
34 import org.argeo.security.ui.admin.internal.providers.DomainNameLP;
35 import org.argeo.security.ui.admin.internal.providers.RoleIconLP;
36 import org.argeo.security.ui.admin.internal.providers.UserFilter;
37 import org.argeo.security.ui.admin.internal.providers.UserNameLP;
38 import org.argeo.security.ui.admin.internal.providers.UserTableDefaultDClickListener;
39 import org.eclipse.jface.action.Action;
40 import org.eclipse.jface.action.ToolBarManager;
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.Viewer;
46 import org.eclipse.jface.viewers.ViewerDropAdapter;
47 import org.eclipse.swt.SWT;
48 import org.eclipse.swt.dnd.DND;
49 import org.eclipse.swt.dnd.DropTargetEvent;
50 import org.eclipse.swt.dnd.TextTransfer;
51 import org.eclipse.swt.dnd.Transfer;
52 import org.eclipse.swt.dnd.TransferData;
53 import org.eclipse.swt.events.DisposeEvent;
54 import org.eclipse.swt.events.DisposeListener;
55 import org.eclipse.swt.events.ModifyEvent;
56 import org.eclipse.swt.events.ModifyListener;
57 import org.eclipse.swt.graphics.Cursor;
58 import org.eclipse.swt.layout.GridData;
59 import org.eclipse.swt.layout.GridLayout;
60 import org.eclipse.swt.widgets.Composite;
61 import org.eclipse.swt.widgets.Label;
62 import org.eclipse.swt.widgets.Text;
63 import org.eclipse.swt.widgets.ToolBar;
64 import org.eclipse.ui.forms.AbstractFormPart;
65 import org.eclipse.ui.forms.IManagedForm;
66 import org.eclipse.ui.forms.SectionPart;
67 import org.eclipse.ui.forms.editor.FormEditor;
68 import org.eclipse.ui.forms.editor.FormPage;
69 import org.eclipse.ui.forms.widgets.FormToolkit;
70 import org.eclipse.ui.forms.widgets.ScrolledForm;
71 import org.eclipse.ui.forms.widgets.Section;
72 import org.osgi.service.useradmin.Group;
73 import org.osgi.service.useradmin.Role;
74 import org.osgi.service.useradmin.User;
75 import org.osgi.service.useradmin.UserAdmin;
76 import org.osgi.service.useradmin.UserAdminEvent;
77
78 /** Display/edit the properties of a given user */
79 public class UserMainPage extends FormPage implements ArgeoNames {
80 final static String ID = "UserEditor.mainPage";
81
82 private final UserEditor editor;
83 private UserAdminWrapper userAdminWrapper;
84
85 // Local configuration
86 private final int PRE_TITLE_INDENT = 10;
87
88 public UserMainPage(FormEditor editor, UserAdminWrapper userAdminWrapper) {
89 super(editor, ID, "Main");
90 this.editor = (UserEditor) editor;
91 this.userAdminWrapper = userAdminWrapper;
92 }
93
94 protected void createFormContent(final IManagedForm mf) {
95 ScrolledForm form = mf.getForm();
96 Composite body = form.getBody();
97 GridLayout mainLayout = new GridLayout();
98 body.setLayout(mainLayout);
99 User user = editor.getDisplayedUser();
100 appendOverviewPart(body, user);
101 // Remove to ability to force the password for his own user. The user
102 // must then use the change pwd feature
103 if (!UiAdminUtils.isCurrentUser(user))
104 appendPasswordPart(body, user);
105 appendMemberOfPart(body, user);
106 }
107
108 /** Creates the general section */
109 private void appendOverviewPart(Composite parent, final User user) {
110 FormToolkit tk = getManagedForm().getToolkit();
111
112 Section section = addSection(tk, parent, "Main information");
113 Composite body = (Composite) section.getClient();
114 body.setLayout(new GridLayout(2, false));
115
116 final Text distinguishedName = createLT(tk, body, "User Name",
117 UiAdminUtils.getProperty(user, LdifName.uid.name()));
118 distinguishedName.setEnabled(false);
119
120 final Text commonName = createLT(tk, body, "Common Name",
121 UiAdminUtils.getProperty(user, LdifName.cn.name()));
122 commonName.setEnabled(false);
123
124 final Text firstName = createLT(tk, body, "First name",
125 UiAdminUtils.getProperty(user, LdifName.givenname.name()));
126
127 final Text lastName = createLT(tk, body, "Last name",
128 UiAdminUtils.getProperty(user, LdifName.sn.name()));
129
130 final Text email = createLT(tk, body, "Email",
131 UiAdminUtils.getProperty(user, LdifName.mail.name()));
132
133 // create form part (controller)
134 AbstractFormPart part = new SectionPart((Section) body.getParent()) {
135 private MainInfoListener listener;
136
137 @Override
138 public void initialize(IManagedForm form) {
139 super.initialize(form);
140 listener = editor.new MainInfoListener(this);
141 userAdminWrapper.addListener(listener);
142 }
143
144 @Override
145 public void dispose() {
146 userAdminWrapper.removeListener(listener);
147 super.dispose();
148 }
149
150 @SuppressWarnings("unchecked")
151 public void commit(boolean onSave) {
152 // TODO Sanity checks (mail validity...)
153 user.getProperties().put(LdifName.givenname.name(),
154 firstName.getText());
155 user.getProperties()
156 .put(LdifName.sn.name(), lastName.getText());
157 user.getProperties().put(LdifName.cn.name(),
158 commonName.getText());
159 user.getProperties().put(LdifName.mail.name(), email.getText());
160 // Enable common name ?
161 // editor.setProperty(UserAdminConstants.KEY_CN,
162 // email.getText());
163 super.commit(onSave);
164 }
165
166 @Override
167 public void refresh() {
168 distinguishedName.setText(UiAdminUtils.getProperty(user,
169 LdifName.uid.name()));
170 commonName.setText(UiAdminUtils.getProperty(user,
171 LdifName.cn.name()));
172 firstName.setText(UiAdminUtils.getProperty(user,
173 LdifName.givenname.name()));
174 lastName.setText(UiAdminUtils.getProperty(user,
175 LdifName.sn.name()));
176 email.setText(LdifName.mail.name());
177 refreshFormTitle(user);
178 super.refresh();
179 }
180 };
181
182 // Improve this: automatically generate CN when first or last name
183 // changes
184 ModifyListener cnML = new ModifyListener() {
185 private static final long serialVersionUID = 4298649222869835486L;
186
187 @Override
188 public void modifyText(ModifyEvent event) {
189 String first = firstName.getText();
190 String last = lastName.getText();
191 String cn = first.trim() + " " + last.trim() + " ";
192 cn = cn.trim();
193 commonName.setText(cn);
194 getManagedForm().getForm().setText(cn);
195 editor.updateEditorTitle(cn);
196 }
197 };
198 firstName.addModifyListener(cnML);
199 lastName.addModifyListener(cnML);
200
201 ModifyListener defaultListener = editor.new FormPartML(part);
202 firstName.addModifyListener(defaultListener);
203 lastName.addModifyListener(defaultListener);
204 email.addModifyListener(defaultListener);
205 getManagedForm().addPart(part);
206 }
207
208 /** Creates the password section */
209 private void appendPasswordPart(Composite parent, final User user) {
210 FormToolkit tk = getManagedForm().getToolkit();
211 Section section = addSection(tk, parent, "Password");
212 Composite body = (Composite) section.getClient();
213 body.setLayout(new GridLayout(2, false));
214
215 // add widgets (view)
216 final Text password1 = createLP(tk, body, "New password", "");
217 final Text password2 = createLP(tk, body, "Repeat password", "");
218
219 // create form part (controller)
220 AbstractFormPart part = new SectionPart((Section) body.getParent()) {
221 @SuppressWarnings("unchecked")
222 public void commit(boolean onSave) {
223 if (!password1.getText().equals("")
224 || !password2.getText().equals("")) {
225 if (password1.getText().equals(password2.getText())) {
226 char[] newPassword = password1.getText().toCharArray();
227 userAdminWrapper.beginTransactionIfNeeded();
228 user.getCredentials().put(null, newPassword);
229 password1.setText("");
230 password2.setText("");
231 super.commit(onSave);
232 } else {
233 password1.setText("");
234 password2.setText("");
235 throw new ArgeoException("Passwords are not equals");
236 }
237 }
238 }
239 };
240 ModifyListener defaultListener = editor.new FormPartML(part);
241 password1.addModifyListener(defaultListener);
242 password2.addModifyListener(defaultListener);
243 getManagedForm().addPart(part);
244 }
245
246 private LdifUsersTable appendMemberOfPart(Composite parent, User user) {
247 FormToolkit tk = getManagedForm().getToolkit();
248 Section section = addSection(tk, parent, "Roles");
249 Composite body = (Composite) section.getClient();
250 body.setLayout(EclipseUiUtils.noSpaceGridLayout());
251
252 // Displayed columns
253 List<ColumnDefinition> columnDefs = new ArrayList<ColumnDefinition>();
254 columnDefs.add(new ColumnDefinition(new RoleIconLP(), "", 0, 24));
255 columnDefs.add(new ColumnDefinition(new CommonNameLP(), "Common Name",
256 150));
257 columnDefs.add(new ColumnDefinition(new DomainNameLP(), "Domain Name",
258 120));
259 columnDefs.add(new ColumnDefinition(new UserNameLP(),
260 "Distinguished Name", 300));
261
262 // Create and configure the table
263 final LdifUsersTable userViewerCmp = new MyUserTableViewer(body,
264 SWT.MULTI | SWT.H_SCROLL | SWT.V_SCROLL, user);
265
266 userViewerCmp.setColumnDefinitions(columnDefs);
267 userViewerCmp.populate(true, false);
268 GridData gd = EclipseUiUtils.fillAll();
269 gd.heightHint = 300;
270 userViewerCmp.setLayoutData(gd);
271
272 // Controllers
273 TableViewer userViewer = userViewerCmp.getTableViewer();
274 userViewer.addDoubleClickListener(new UserTableDefaultDClickListener());
275 int operations = DND.DROP_COPY | DND.DROP_MOVE;
276 Transfer[] tt = new Transfer[] { TextTransfer.getInstance() };
277 GroupDropListener dropL = new GroupDropListener(userAdminWrapper,
278 userViewer, user);
279 userViewer.addDropSupport(operations, tt, dropL);
280
281 SectionPart part = new SectionPart((Section) body.getParent()) {
282
283 private GroupChangeListener listener;
284
285 @Override
286 public void initialize(IManagedForm form) {
287 super.initialize(form);
288 listener = editor.new GroupChangeListener(this);
289 userAdminWrapper.addListener(listener);
290 }
291
292 public void commit(boolean onSave) {
293 super.commit(onSave);
294 }
295
296 @Override
297 public void dispose() {
298 userAdminWrapper.removeListener(listener);
299 super.dispose();
300 }
301
302 @Override
303 public void refresh() {
304 userViewerCmp.refresh();
305 super.refresh();
306 }
307 };
308 getManagedForm().addPart(part);
309 addRemoveAbitily(part, userViewer, user);
310 return userViewerCmp;
311 }
312
313 private class MyUserTableViewer extends LdifUsersTable {
314 private static final long serialVersionUID = 8467999509931900367L;
315
316 private final User user;
317 private final UserFilter userFilter;
318
319 public MyUserTableViewer(Composite parent, int style, User user) {
320 super(parent, style, true);
321 this.user = user;
322 userFilter = new UserFilter();
323 }
324
325 @Override
326 protected List<User> listFilteredElements(String filter) {
327 List<User> users = (List<User>) editor.getFlatGroups(null);
328 List<User> filteredUsers = new ArrayList<User>();
329 if (users.contains(user))
330 users.remove(user);
331 userFilter.setSearchText(filter);
332 for (User user : users)
333 if (userFilter.select(null, null, user))
334 filteredUsers.add(user);
335 return filteredUsers;
336 }
337 }
338
339 private void addRemoveAbitily(SectionPart sectionPart,
340 TableViewer userViewer, User user) {
341 Section section = sectionPart.getSection();
342 ToolBarManager toolBarManager = new ToolBarManager(SWT.FLAT);
343 ToolBar toolbar = toolBarManager.createControl(section);
344 final Cursor handCursor = new Cursor(section.getDisplay(),
345 SWT.CURSOR_HAND);
346 toolbar.setCursor(handCursor);
347 toolbar.addDisposeListener(new DisposeListener() {
348 private static final long serialVersionUID = 3882131405820522925L;
349
350 public void widgetDisposed(DisposeEvent e) {
351 if ((handCursor != null) && (handCursor.isDisposed() == false)) {
352 handCursor.dispose();
353 }
354 }
355 });
356
357 String tooltip = "Remove " + UiAdminUtils.getUsername(user)
358 + " from the below selected groups";
359 Action action = new RemoveMembershipAction(userViewer, user, tooltip,
360 SecurityAdminImages.ICON_REMOVE_DESC);
361 toolBarManager.add(action);
362 toolBarManager.update(true);
363 section.setTextClient(toolbar);
364 }
365
366 private class RemoveMembershipAction extends Action {
367 private static final long serialVersionUID = -1337713097184522588L;
368
369 private final TableViewer userViewer;
370 private final User user;
371
372 RemoveMembershipAction(TableViewer userViewer, User user, String name,
373 ImageDescriptor img) {
374 super(name, img);
375 this.userViewer = userViewer;
376 this.user = user;
377 }
378
379 @Override
380 public void run() {
381 ISelection selection = userViewer.getSelection();
382 if (selection.isEmpty())
383 return;
384
385 @SuppressWarnings("unchecked")
386 Iterator<Group> it = ((IStructuredSelection) selection).iterator();
387 List<Group> groups = new ArrayList<Group>();
388 // StringBuilder builder = new StringBuilder();
389 while (it.hasNext()) {
390 Group currGroup = it.next();
391 // String groupName = UiAdminUtils.getUsername(currGroup);
392 // builder.append(groupName).append("; ");
393 groups.add(currGroup);
394 }
395
396 // if (!MessageDialog.openQuestion(
397 // HandlerUtil.getActiveShell(event),
398 // "Re",
399 // "Are you sure that you want to delete these users?\n"
400 // + builder.substring(0, builder.length() - 2)))
401 // return null;
402
403 userAdminWrapper.beginTransactionIfNeeded();
404 for (Group group : groups) {
405 group.removeMember(user);
406 // sectionPart.refresh();
407 userAdminWrapper.notifyListeners(new UserAdminEvent(null,
408 UserAdminEvent.ROLE_CHANGED, group));
409 }
410 }
411 }
412
413 /**
414 * Defines the table as being a potential target to add group memberships
415 * (roles) to this user
416 */
417 private class GroupDropListener extends ViewerDropAdapter {
418 private static final long serialVersionUID = 2893468717831451621L;
419
420 private final UserAdminWrapper myUserAdminWrapper;
421 private final User myUser;
422
423 public GroupDropListener(UserAdminWrapper userAdminWrapper,
424 Viewer userViewer, User user) {
425 super(userViewer);
426 this.myUserAdminWrapper = userAdminWrapper;
427 this.myUser = user;
428 }
429
430 @Override
431 public boolean validateDrop(Object target, int operation,
432 TransferData transferType) {
433 // Target is always OK in a list only view
434 // TODO check if not a string
435 boolean validDrop = true;
436 return validDrop;
437 }
438
439 @Override
440 public void drop(DropTargetEvent event) {
441 String name = (String) event.data;
442 UserAdmin myUserAdmin = myUserAdminWrapper.getUserAdmin();
443 Role role = myUserAdmin.getRole(name);
444 // TODO this check should be done before.
445 if (role.getType() == Role.GROUP) {
446 // TODO check if the user is already member of this group
447 myUserAdminWrapper.beginTransactionIfNeeded();
448 Group group = (Group) role;
449 group.addMember(myUser);
450 myUserAdminWrapper.notifyListeners(new UserAdminEvent(null,
451 UserAdminEvent.ROLE_CHANGED, group));
452 }
453 super.drop(event);
454 }
455
456 @Override
457 public boolean performDrop(Object data) {
458 // userTableViewerCmp.refresh();
459 return true;
460 }
461 }
462
463 // LOCAL HELPERS
464 private void refreshFormTitle(User group) {
465 getManagedForm().getForm().setText(
466 UiAdminUtils.getProperty(group, LdifName.cn.name()));
467 }
468
469 /** Appends a section with a title */
470 private Section addSection(FormToolkit tk, Composite parent, String title) {
471 Section section = tk.createSection(parent, Section.TITLE_BAR);
472 GridData gd = EclipseUiUtils.fillWidth();
473 gd.verticalAlignment = PRE_TITLE_INDENT;
474 section.setLayoutData(gd);
475 section.setText(title);
476 // section.getMenu().setVisible(true);
477
478 Composite body = tk.createComposite(section, SWT.WRAP);
479 body.setLayoutData(EclipseUiUtils.fillAll());
480 section.setClient(body);
481
482 return section;
483 }
484
485 /** Creates label and multiline text. */
486 Text createLMT(FormToolkit toolkit, Composite body, String label,
487 String value) {
488 Label lbl = toolkit.createLabel(body, label);
489 lbl.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false));
490 Text text = toolkit.createText(body, value, SWT.BORDER | SWT.MULTI);
491 text.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, true));
492 return text;
493 }
494
495 /** Creates label and password. */
496 Text createLP(FormToolkit toolkit, Composite body, String label,
497 String value) {
498 Label lbl = toolkit.createLabel(body, label);
499 lbl.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false));
500 Text text = toolkit.createText(body, value, SWT.BORDER | SWT.PASSWORD);
501 text.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
502 return text;
503 }
504
505 /** Creates label and text. */
506 Text createLT(FormToolkit toolkit, Composite body, String label,
507 String value) {
508 Label lbl = toolkit.createLabel(body, label);
509 lbl.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false));
510 Text text = toolkit.createText(body, value, SWT.BORDER);
511 text.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
512 return text;
513 }
514 }