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