]> git.argeo.org Git - gpl/argeo-slc.git/blob - legacy/argeo-commons/org.argeo.cms.ui.workbench/src/org/argeo/cms/ui/workbench/internal/useradmin/parts/UserBatchUpdateWizard.java
9e3b068849538f51895801829b4ea89d9b2036c9
[gpl/argeo-slc.git] / legacy / argeo-commons / org.argeo.cms.ui.workbench / src / org / argeo / cms / ui / workbench / internal / useradmin / parts / UserBatchUpdateWizard.java
1 package org.argeo.cms.ui.workbench.internal.useradmin.parts;
2
3 import java.util.ArrayList;
4 import java.util.HashMap;
5 import java.util.List;
6 import java.util.Map;
7
8 import org.argeo.api.cms.CmsConstants;
9 import org.argeo.api.cms.CmsLog;
10 import org.argeo.cms.CmsException;
11 import org.argeo.cms.auth.CurrentUser;
12 import org.argeo.cms.auth.UserAdminUtils;
13 import org.argeo.cms.ui.workbench.internal.useradmin.UiAdminUtils;
14 import org.argeo.cms.ui.workbench.internal.useradmin.UserAdminWrapper;
15 import org.argeo.cms.ui.workbench.internal.useradmin.providers.CommonNameLP;
16 import org.argeo.cms.ui.workbench.internal.useradmin.providers.DomainNameLP;
17 import org.argeo.cms.ui.workbench.internal.useradmin.providers.MailLP;
18 import org.argeo.cms.ui.workbench.internal.useradmin.providers.UserNameLP;
19 import org.argeo.eclipse.ui.ColumnDefinition;
20 import org.argeo.eclipse.ui.EclipseUiUtils;
21 import org.argeo.eclipse.ui.parts.LdifUsersTable;
22 import org.argeo.osgi.transaction.WorkTransaction;
23 import org.argeo.util.naming.LdapAttrs;
24 import org.argeo.util.naming.LdapObjs;
25 import org.eclipse.jface.dialogs.IPageChangeProvider;
26 import org.eclipse.jface.dialogs.IPageChangedListener;
27 import org.eclipse.jface.dialogs.MessageDialog;
28 import org.eclipse.jface.dialogs.PageChangedEvent;
29 import org.eclipse.jface.wizard.IWizardContainer;
30 import org.eclipse.jface.wizard.Wizard;
31 import org.eclipse.jface.wizard.WizardPage;
32 import org.eclipse.swt.SWT;
33 import org.eclipse.swt.events.ModifyEvent;
34 import org.eclipse.swt.events.ModifyListener;
35 import org.eclipse.swt.events.SelectionAdapter;
36 import org.eclipse.swt.events.SelectionEvent;
37 import org.eclipse.swt.layout.GridData;
38 import org.eclipse.swt.layout.GridLayout;
39 import org.eclipse.swt.widgets.Button;
40 import org.eclipse.swt.widgets.Combo;
41 import org.eclipse.swt.widgets.Composite;
42 import org.eclipse.swt.widgets.Text;
43 import org.osgi.framework.InvalidSyntaxException;
44 import org.osgi.service.useradmin.Role;
45 import org.osgi.service.useradmin.User;
46 import org.osgi.service.useradmin.UserAdminEvent;
47
48 /** Wizard to update users */
49 public class UserBatchUpdateWizard extends Wizard {
50
51 private final static CmsLog log = CmsLog.getLog(UserBatchUpdateWizard.class);
52 private UserAdminWrapper userAdminWrapper;
53
54 // pages
55 private ChooseCommandWizardPage chooseCommandPage;
56 private ChooseUsersWizardPage userListPage;
57 private ValidateAndLaunchWizardPage validatePage;
58
59 // Various implemented commands keys
60 private final static String CMD_UPDATE_PASSWORD = "resetPassword";
61 private final static String CMD_UPDATE_EMAIL = "resetEmail";
62 private final static String CMD_GROUP_MEMBERSHIP = "groupMembership";
63
64 private final Map<String, String> commands = new HashMap<String, String>() {
65 private static final long serialVersionUID = 1L;
66 {
67 put("Reset password(s)", CMD_UPDATE_PASSWORD);
68 put("Reset email(s)", CMD_UPDATE_EMAIL);
69 // TODO implement role / group management
70 // put("Add/Remove from group", CMD_GROUP_MEMBERSHIP);
71 }
72 };
73
74 public UserBatchUpdateWizard(UserAdminWrapper userAdminWrapper) {
75 this.userAdminWrapper = userAdminWrapper;
76 }
77
78 @Override
79 public void addPages() {
80 chooseCommandPage = new ChooseCommandWizardPage();
81 addPage(chooseCommandPage);
82 userListPage = new ChooseUsersWizardPage();
83 addPage(userListPage);
84 validatePage = new ValidateAndLaunchWizardPage();
85 addPage(validatePage);
86 }
87
88 @Override
89 public boolean performFinish() {
90 if (!canFinish())
91 return false;
92 WorkTransaction ut = userAdminWrapper.getUserTransaction();
93 if (!ut.isNoTransactionStatus() && !MessageDialog.openConfirm(getShell(), "Existing Transaction",
94 "A user transaction is already existing, " + "are you sure you want to proceed ?"))
95 return false;
96
97 // We cannot use jobs, user modifications are still meant to be done in
98 // the UIThread
99 // UpdateJob job = null;
100 // if (job != null)
101 // job.schedule();
102
103 if (CMD_UPDATE_PASSWORD.equals(chooseCommandPage.getCommand())) {
104 char[] newValue = chooseCommandPage.getPwdValue();
105 if (newValue == null)
106 throw new CmsException("Password cannot be null or an empty string");
107 ResetPassword job = new ResetPassword(userAdminWrapper, userListPage.getSelectedUsers(), newValue);
108 job.doUpdate();
109 } else if (CMD_UPDATE_EMAIL.equals(chooseCommandPage.getCommand())) {
110 String newValue = chooseCommandPage.getEmailValue();
111 if (newValue == null)
112 throw new CmsException("Password cannot be null or an empty string");
113 ResetEmail job = new ResetEmail(userAdminWrapper, userListPage.getSelectedUsers(), newValue);
114 job.doUpdate();
115 }
116 return true;
117 }
118
119 public boolean canFinish() {
120 if (this.getContainer().getCurrentPage() == validatePage)
121 return true;
122 return false;
123 }
124
125 private class ResetPassword {
126 private char[] newPwd;
127 private UserAdminWrapper userAdminWrapper;
128 private List<User> usersToUpdate;
129
130 public ResetPassword(UserAdminWrapper userAdminWrapper, List<User> usersToUpdate, char[] newPwd) {
131 this.newPwd = newPwd;
132 this.usersToUpdate = usersToUpdate;
133 this.userAdminWrapper = userAdminWrapper;
134 }
135
136 @SuppressWarnings("unchecked")
137 protected void doUpdate() {
138 userAdminWrapper.beginTransactionIfNeeded();
139 try {
140 for (User user : usersToUpdate) {
141 // the char array is emptied after being used.
142 user.getCredentials().put(null, newPwd.clone());
143 }
144 userAdminWrapper.commitOrNotifyTransactionStateChange();
145 } catch (Exception e) {
146 throw new CmsException("Cannot perform batch update on users", e);
147 } finally {
148 WorkTransaction ut = userAdminWrapper.getUserTransaction();
149 if (!ut.isNoTransactionStatus())
150 ut.rollback();
151 }
152 }
153 }
154
155 private class ResetEmail {
156 private String newEmail;
157 private UserAdminWrapper userAdminWrapper;
158 private List<User> usersToUpdate;
159
160 public ResetEmail(UserAdminWrapper userAdminWrapper, List<User> usersToUpdate, String newEmail) {
161 this.newEmail = newEmail;
162 this.usersToUpdate = usersToUpdate;
163 this.userAdminWrapper = userAdminWrapper;
164 }
165
166 @SuppressWarnings("unchecked")
167 protected void doUpdate() {
168 userAdminWrapper.beginTransactionIfNeeded();
169 try {
170 for (User user : usersToUpdate) {
171 // the char array is emptied after being used.
172 user.getProperties().put(LdapAttrs.mail.name(), newEmail);
173 }
174
175 userAdminWrapper.commitOrNotifyTransactionStateChange();
176 if (!usersToUpdate.isEmpty())
177 userAdminWrapper.notifyListeners(
178 new UserAdminEvent(null, UserAdminEvent.ROLE_CHANGED, usersToUpdate.get(0)));
179 } catch (Exception e) {
180 throw new CmsException("Cannot perform batch update on users", e);
181 } finally {
182 WorkTransaction ut = userAdminWrapper.getUserTransaction();
183 if (!ut.isNoTransactionStatus())
184 ut.rollback();
185 }
186 }
187 }
188
189 // @SuppressWarnings("unused")
190 // private class AddToGroup extends UpdateJob {
191 // private String groupID;
192 // private Session session;
193 //
194 // public AddToGroup(Session session, List<Node> nodesToUpdate,
195 // String groupID) {
196 // super(session, nodesToUpdate);
197 // this.session = session;
198 // this.groupID = groupID;
199 // }
200 //
201 // protected void doUpdate(Node node) {
202 // log.info("Add/Remove to group actions are not yet implemented");
203 // // TODO implement this
204 // // try {
205 // // throw new CmsException("Not yet implemented");
206 // // } catch (RepositoryException re) {
207 // // throw new CmsException(
208 // // "Unable to update boolean value for node " + node, re);
209 // // }
210 // }
211 // }
212
213 // /**
214 // * Base privileged job that will be run asynchronously to perform the
215 // batch
216 // * update
217 // */
218 // private abstract class UpdateJob extends PrivilegedJob {
219 //
220 // private final UserAdminWrapper userAdminWrapper;
221 // private final List<User> usersToUpdate;
222 //
223 // protected abstract void doUpdate(User user);
224 //
225 // public UpdateJob(UserAdminWrapper userAdminWrapper,
226 // List<User> usersToUpdate) {
227 // super("Perform update");
228 // this.usersToUpdate = usersToUpdate;
229 // this.userAdminWrapper = userAdminWrapper;
230 // }
231 //
232 // @Override
233 // protected IStatus doRun(IProgressMonitor progressMonitor) {
234 // try {
235 // JcrMonitor monitor = new EclipseJcrMonitor(progressMonitor);
236 // int total = usersToUpdate.size();
237 // monitor.beginTask("Performing change", total);
238 // userAdminWrapper.beginTransactionIfNeeded();
239 // for (User user : usersToUpdate) {
240 // doUpdate(user);
241 // monitor.worked(1);
242 // }
243 // userAdminWrapper.getUserTransaction().commit();
244 // } catch (Exception e) {
245 // throw new CmsException(
246 // "Cannot perform batch update on users", e);
247 // } finally {
248 // UserTransaction ut = userAdminWrapper.getUserTransaction();
249 // try {
250 // if (ut.getStatus() != javax.transaction.Status.STATUS_NO_TRANSACTION)
251 // ut.rollback();
252 // } catch (IllegalStateException | SecurityException
253 // | SystemException e) {
254 // log.error("Unable to rollback session in 'finally', "
255 // + "the system might be in a dirty state");
256 // e.printStackTrace();
257 // }
258 // }
259 // return Status.OK_STATUS;
260 // }
261 // }
262
263 // PAGES
264 /**
265 * Displays a combo box that enables user to choose which action to perform
266 */
267 private class ChooseCommandWizardPage extends WizardPage {
268 private static final long serialVersionUID = -8069434295293996633L;
269 private Combo chooseCommandCmb;
270 private Button trueChk;
271 private Text valueTxt;
272 private Text pwdTxt;
273 private Text pwd2Txt;
274
275 public ChooseCommandWizardPage() {
276 super("Choose a command to run.");
277 setTitle("Choose a command to run.");
278 }
279
280 @Override
281 public void createControl(Composite parent) {
282 GridLayout gl = new GridLayout();
283 Composite container = new Composite(parent, SWT.NO_FOCUS);
284 container.setLayout(gl);
285
286 chooseCommandCmb = new Combo(container, SWT.READ_ONLY);
287 chooseCommandCmb.setLayoutData(EclipseUiUtils.fillWidth());
288 String[] values = commands.keySet().toArray(new String[0]);
289 chooseCommandCmb.setItems(values);
290
291 final Composite bottomPart = new Composite(container, SWT.NO_FOCUS);
292 bottomPart.setLayoutData(EclipseUiUtils.fillAll());
293 bottomPart.setLayout(EclipseUiUtils.noSpaceGridLayout());
294
295 chooseCommandCmb.addSelectionListener(new SelectionAdapter() {
296 private static final long serialVersionUID = 1L;
297
298 @Override
299 public void widgetSelected(SelectionEvent e) {
300 if (getCommand().equals(CMD_UPDATE_PASSWORD))
301 populatePasswordCmp(bottomPart);
302 else if (getCommand().equals(CMD_UPDATE_EMAIL))
303 populateEmailCmp(bottomPart);
304 else if (getCommand().equals(CMD_GROUP_MEMBERSHIP))
305 populateGroupCmp(bottomPart);
306 else
307 populateBooleanFlagCmp(bottomPart);
308 checkPageComplete();
309 bottomPart.layout(true, true);
310 }
311 });
312 setControl(container);
313 }
314
315 private void populateBooleanFlagCmp(Composite parent) {
316 EclipseUiUtils.clear(parent);
317 trueChk = new Button(parent, SWT.CHECK);
318 trueChk.setText("Do it. (It will to the contrary if unchecked)");
319 trueChk.setSelection(true);
320 trueChk.setLayoutData(new GridData(SWT.LEFT, SWT.TOP, false, false));
321 }
322
323 private void populatePasswordCmp(Composite parent) {
324 EclipseUiUtils.clear(parent);
325 Composite body = new Composite(parent, SWT.NO_FOCUS);
326
327 ModifyListener ml = new ModifyListener() {
328 private static final long serialVersionUID = -1558726363536729634L;
329
330 @Override
331 public void modifyText(ModifyEvent event) {
332 checkPageComplete();
333 }
334 };
335
336 body.setLayout(new GridLayout(2, false));
337 body.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
338 pwdTxt = EclipseUiUtils.createGridLP(body, "New password", ml);
339 pwd2Txt = EclipseUiUtils.createGridLP(body, "Repeat password", ml);
340 }
341
342 private void populateEmailCmp(Composite parent) {
343 EclipseUiUtils.clear(parent);
344 Composite body = new Composite(parent, SWT.NO_FOCUS);
345
346 ModifyListener ml = new ModifyListener() {
347 private static final long serialVersionUID = 2147704227294268317L;
348
349 @Override
350 public void modifyText(ModifyEvent event) {
351 checkPageComplete();
352 }
353 };
354
355 body.setLayout(new GridLayout(2, false));
356 body.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
357 valueTxt = EclipseUiUtils.createGridLT(body, "New e-mail", ml);
358 }
359
360 private void checkPageComplete() {
361 String errorMsg = null;
362 if (chooseCommandCmb.getSelectionIndex() < 0)
363 errorMsg = "Please select an action";
364 else if (CMD_UPDATE_EMAIL.equals(getCommand())) {
365 if (!valueTxt.getText().matches(UiAdminUtils.EMAIL_PATTERN))
366 errorMsg = "Not a valid e-mail address";
367 } else if (CMD_UPDATE_PASSWORD.equals(getCommand())) {
368 if (EclipseUiUtils.isEmpty(pwdTxt.getText()) || pwdTxt.getText().length() < 4)
369 errorMsg = "Please enter a password that is at least 4 character long";
370 else if (!pwdTxt.getText().equals(pwd2Txt.getText()))
371 errorMsg = "Passwords are different";
372 }
373 if (EclipseUiUtils.notEmpty(errorMsg)) {
374 setMessage(errorMsg, WizardPage.ERROR);
375 setPageComplete(false);
376 } else {
377 setMessage("Page complete, you can proceed to user choice", WizardPage.INFORMATION);
378 setPageComplete(true);
379 }
380
381 getContainer().updateButtons();
382 }
383
384 private void populateGroupCmp(Composite parent) {
385 EclipseUiUtils.clear(parent);
386 trueChk = new Button(parent, SWT.CHECK);
387 trueChk.setText("Add to group. (It will remove user(s) from the " + "corresponding group if unchecked)");
388 trueChk.setSelection(true);
389 trueChk.setLayoutData(new GridData(SWT.LEFT, SWT.TOP, false, false));
390 }
391
392 protected String getCommand() {
393 return commands.get(chooseCommandCmb.getItem(chooseCommandCmb.getSelectionIndex()));
394 }
395
396 protected String getCommandLbl() {
397 return chooseCommandCmb.getItem(chooseCommandCmb.getSelectionIndex());
398 }
399
400 @SuppressWarnings("unused")
401 protected boolean getBoleanValue() {
402 // FIXME this is not consistent and will lead to errors.
403 if ("argeo:enabled".equals(getCommand()))
404 return trueChk.getSelection();
405 else
406 return !trueChk.getSelection();
407 }
408
409 @SuppressWarnings("unused")
410 protected String getStringValue() {
411 String value = null;
412 if (valueTxt != null) {
413 value = valueTxt.getText();
414 if ("".equals(value.trim()))
415 value = null;
416 }
417 return value;
418 }
419
420 protected char[] getPwdValue() {
421 // We do not directly reset the password text fields: There is no
422 // need to over secure this process: setting a pwd to multi users
423 // at the same time is anyhow a bad practice and should be used only
424 // in test environment or for temporary access
425 if (pwdTxt == null || pwdTxt.isDisposed())
426 return null;
427 else
428 return pwdTxt.getText().toCharArray();
429 }
430
431 protected String getEmailValue() {
432 // We do not directly reset the password text fields: There is no
433 // need to over secure this process: setting a pwd to multi users
434 // at the same time is anyhow a bad practice and should be used only
435 // in test environment or for temporary access
436 if (valueTxt == null || valueTxt.isDisposed())
437 return null;
438 else
439 return valueTxt.getText();
440 }
441 }
442
443 /**
444 * Displays a list of users with a check box to be able to choose some of them
445 */
446 private class ChooseUsersWizardPage extends WizardPage implements IPageChangedListener {
447 private static final long serialVersionUID = 7651807402211214274L;
448 private ChooseUserTableViewer userTableCmp;
449
450 public ChooseUsersWizardPage() {
451 super("Choose Users");
452 setTitle("Select users who will be impacted");
453 }
454
455 @Override
456 public void createControl(Composite parent) {
457 Composite pageCmp = new Composite(parent, SWT.NONE);
458 pageCmp.setLayout(EclipseUiUtils.noSpaceGridLayout());
459
460 // Define the displayed columns
461 List<ColumnDefinition> columnDefs = new ArrayList<ColumnDefinition>();
462 columnDefs.add(new ColumnDefinition(new CommonNameLP(), "Common Name", 150));
463 columnDefs.add(new ColumnDefinition(new MailLP(), "E-mail", 150));
464 columnDefs.add(new ColumnDefinition(new DomainNameLP(), "Domain", 200));
465
466 // Only show technical DN to admin
467 if (CurrentUser.isInRole(CmsConstants.ROLE_ADMIN))
468 columnDefs.add(new ColumnDefinition(new UserNameLP(), "Distinguished Name", 300));
469
470 userTableCmp = new ChooseUserTableViewer(pageCmp, SWT.MULTI | SWT.H_SCROLL | SWT.V_SCROLL);
471 userTableCmp.setLayoutData(EclipseUiUtils.fillAll());
472 userTableCmp.setColumnDefinitions(columnDefs);
473 userTableCmp.populate(true, true);
474 userTableCmp.refresh();
475
476 setControl(pageCmp);
477
478 // Add listener to update message when shown
479 final IWizardContainer wContainer = this.getContainer();
480 if (wContainer instanceof IPageChangeProvider) {
481 ((IPageChangeProvider) wContainer).addPageChangedListener(this);
482 }
483
484 }
485
486 @Override
487 public void pageChanged(PageChangedEvent event) {
488 if (event.getSelectedPage() == this) {
489 String msg = "Chosen batch action: " + chooseCommandPage.getCommandLbl();
490 ((WizardPage) event.getSelectedPage()).setMessage(msg);
491 }
492 }
493
494 protected List<User> getSelectedUsers() {
495 return userTableCmp.getSelectedUsers();
496 }
497
498 private class ChooseUserTableViewer extends LdifUsersTable {
499 private static final long serialVersionUID = 5080437561015853124L;
500 private final String[] knownProps = { LdapAttrs.uid.name(), LdapAttrs.DN, LdapAttrs.cn.name(),
501 LdapAttrs.givenName.name(), LdapAttrs.sn.name(), LdapAttrs.mail.name() };
502
503 public ChooseUserTableViewer(Composite parent, int style) {
504 super(parent, style);
505 }
506
507 @Override
508 protected List<User> listFilteredElements(String filter) {
509 Role[] roles;
510
511 try {
512 StringBuilder builder = new StringBuilder();
513
514 StringBuilder tmpBuilder = new StringBuilder();
515 if (EclipseUiUtils.notEmpty(filter))
516 for (String prop : knownProps) {
517 tmpBuilder.append("(");
518 tmpBuilder.append(prop);
519 tmpBuilder.append("=*");
520 tmpBuilder.append(filter);
521 tmpBuilder.append("*)");
522 }
523 if (tmpBuilder.length() > 1) {
524 builder.append("(&(").append(LdapAttrs.objectClass.name()).append("=")
525 .append(LdapObjs.inetOrgPerson.name()).append(")(|");
526 builder.append(tmpBuilder.toString());
527 builder.append("))");
528 } else
529 builder.append("(").append(LdapAttrs.objectClass.name()).append("=")
530 .append(LdapObjs.inetOrgPerson.name()).append(")");
531 roles = userAdminWrapper.getUserAdmin().getRoles(builder.toString());
532 } catch (InvalidSyntaxException e) {
533 throw new CmsException("Unable to get roles with filter: " + filter, e);
534 }
535 List<User> users = new ArrayList<User>();
536 for (Role role : roles)
537 // Prevent current logged in user to perform batch on
538 // himself
539 if (!UserAdminUtils.isCurrentUser((User) role))
540 users.add((User) role);
541 return users;
542 }
543 }
544 }
545
546 /** Summary of input data before launching the process */
547 private class ValidateAndLaunchWizardPage extends WizardPage implements IPageChangedListener {
548 private static final long serialVersionUID = 7098918351451743853L;
549 private ChosenUsersTableViewer userTableCmp;
550
551 public ValidateAndLaunchWizardPage() {
552 super("Validate and launch");
553 setTitle("Validate and launch");
554 }
555
556 @Override
557 public void createControl(Composite parent) {
558 Composite pageCmp = new Composite(parent, SWT.NO_FOCUS);
559 pageCmp.setLayout(EclipseUiUtils.noSpaceGridLayout());
560
561 List<ColumnDefinition> columnDefs = new ArrayList<ColumnDefinition>();
562 columnDefs.add(new ColumnDefinition(new CommonNameLP(), "Common Name", 150));
563 columnDefs.add(new ColumnDefinition(new MailLP(), "E-mail", 150));
564 columnDefs.add(new ColumnDefinition(new DomainNameLP(), "Domain", 200));
565 // Only show technical DN to admin
566 if (CurrentUser.isInRole(CmsConstants.ROLE_ADMIN))
567 columnDefs.add(new ColumnDefinition(new UserNameLP(), "Distinguished Name", 300));
568 userTableCmp = new ChosenUsersTableViewer(pageCmp, SWT.MULTI | SWT.H_SCROLL | SWT.V_SCROLL);
569 userTableCmp.setLayoutData(EclipseUiUtils.fillAll());
570 userTableCmp.setColumnDefinitions(columnDefs);
571 userTableCmp.populate(false, false);
572 userTableCmp.refresh();
573 setControl(pageCmp);
574 // Add listener to update message when shown
575 final IWizardContainer wContainer = this.getContainer();
576 if (wContainer instanceof IPageChangeProvider) {
577 ((IPageChangeProvider) wContainer).addPageChangedListener(this);
578 }
579 }
580
581 @Override
582 public void pageChanged(PageChangedEvent event) {
583 if (event.getSelectedPage() == this) {
584 @SuppressWarnings({ "unchecked", "rawtypes" })
585 Object[] values = ((ArrayList) userListPage.getSelectedUsers())
586 .toArray(new Object[userListPage.getSelectedUsers().size()]);
587 userTableCmp.getTableViewer().setInput(values);
588 String msg = "Following batch action: [" + chooseCommandPage.getCommandLbl()
589 + "] will be perfomed on the users listed below.\n";
590 // + "Are you sure you want to proceed?";
591 setMessage(msg);
592 }
593 }
594
595 private class ChosenUsersTableViewer extends LdifUsersTable {
596 private static final long serialVersionUID = 7814764735794270541L;
597
598 public ChosenUsersTableViewer(Composite parent, int style) {
599 super(parent, style);
600 }
601
602 @Override
603 protected List<User> listFilteredElements(String filter) {
604 return userListPage.getSelectedUsers();
605 }
606 }
607 }
608 }