2 * Copyright (C) 2007-2012 Argeo GmbH
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
16 package org
.argeo
.cms
.ui
.workbench
.internal
.useradmin
.parts
;
18 import java
.util
.ArrayList
;
19 import java
.util
.Iterator
;
20 import java
.util
.List
;
22 import javax
.transaction
.UserTransaction
;
24 import org
.argeo
.cms
.CmsException
;
25 import org
.argeo
.cms
.ui
.workbench
.internal
.useradmin
.SecurityAdminImages
;
26 import org
.argeo
.cms
.ui
.workbench
.internal
.useradmin
.UserAdminWrapper
;
27 import org
.argeo
.cms
.ui
.workbench
.internal
.useradmin
.parts
.UserEditor
.GroupChangeListener
;
28 import org
.argeo
.cms
.ui
.workbench
.internal
.useradmin
.parts
.UserEditor
.MainInfoListener
;
29 import org
.argeo
.cms
.ui
.workbench
.internal
.useradmin
.providers
.CommonNameLP
;
30 import org
.argeo
.cms
.ui
.workbench
.internal
.useradmin
.providers
.MailLP
;
31 import org
.argeo
.cms
.ui
.workbench
.internal
.useradmin
.providers
.RoleIconLP
;
32 import org
.argeo
.cms
.ui
.workbench
.internal
.useradmin
.providers
.UserFilter
;
33 import org
.argeo
.cms
.ui
.workbench
.internal
.useradmin
.providers
.UserNameLP
;
34 import org
.argeo
.cms
.ui
.workbench
.internal
.useradmin
.providers
.UserTableDefaultDClickListener
;
35 import org
.argeo
.cms
.util
.useradmin
.UserAdminUtils
;
36 import org
.argeo
.eclipse
.ui
.ColumnDefinition
;
37 import org
.argeo
.eclipse
.ui
.EclipseUiUtils
;
38 import org
.argeo
.eclipse
.ui
.parts
.LdifUsersTable
;
39 import org
.argeo
.node
.ArgeoNames
;
40 import org
.argeo
.osgi
.useradmin
.LdifName
;
41 import org
.eclipse
.jface
.action
.Action
;
42 import org
.eclipse
.jface
.action
.ToolBarManager
;
43 import org
.eclipse
.jface
.dialogs
.MessageDialog
;
44 import org
.eclipse
.jface
.resource
.ImageDescriptor
;
45 import org
.eclipse
.jface
.viewers
.ISelection
;
46 import org
.eclipse
.jface
.viewers
.IStructuredSelection
;
47 import org
.eclipse
.jface
.viewers
.TableViewer
;
48 import org
.eclipse
.jface
.viewers
.ViewerDropAdapter
;
49 import org
.eclipse
.swt
.SWT
;
50 import org
.eclipse
.swt
.dnd
.DND
;
51 import org
.eclipse
.swt
.dnd
.DropTargetEvent
;
52 import org
.eclipse
.swt
.dnd
.TextTransfer
;
53 import org
.eclipse
.swt
.dnd
.Transfer
;
54 import org
.eclipse
.swt
.dnd
.TransferData
;
55 import org
.eclipse
.swt
.events
.DisposeEvent
;
56 import org
.eclipse
.swt
.events
.DisposeListener
;
57 import org
.eclipse
.swt
.events
.ModifyListener
;
58 import org
.eclipse
.swt
.graphics
.Cursor
;
59 import org
.eclipse
.swt
.layout
.GridData
;
60 import org
.eclipse
.swt
.layout
.GridLayout
;
61 import org
.eclipse
.swt
.widgets
.Composite
;
62 import org
.eclipse
.swt
.widgets
.Label
;
63 import org
.eclipse
.swt
.widgets
.Shell
;
64 import org
.eclipse
.swt
.widgets
.Text
;
65 import org
.eclipse
.swt
.widgets
.ToolBar
;
66 import org
.eclipse
.ui
.forms
.AbstractFormPart
;
67 import org
.eclipse
.ui
.forms
.IManagedForm
;
68 import org
.eclipse
.ui
.forms
.SectionPart
;
69 import org
.eclipse
.ui
.forms
.editor
.FormEditor
;
70 import org
.eclipse
.ui
.forms
.editor
.FormPage
;
71 import org
.eclipse
.ui
.forms
.widgets
.FormToolkit
;
72 import org
.eclipse
.ui
.forms
.widgets
.ScrolledForm
;
73 import org
.eclipse
.ui
.forms
.widgets
.Section
;
74 import org
.osgi
.service
.useradmin
.Group
;
75 import org
.osgi
.service
.useradmin
.Role
;
76 import org
.osgi
.service
.useradmin
.User
;
77 import org
.osgi
.service
.useradmin
.UserAdmin
;
78 import org
.osgi
.service
.useradmin
.UserAdminEvent
;
80 /** Display/edit main properties of a given group */
81 public class GroupMainPage
extends FormPage
implements ArgeoNames
{
82 final static String ID
= "GroupEditor.mainPage";
84 private final UserEditor editor
;
85 private UserAdminWrapper userAdminWrapper
;
87 // Local configuration
88 private final int PRE_TITLE_INDENT
= 10;
90 public GroupMainPage(FormEditor editor
, UserAdminWrapper userAdminWrapper
) {
91 super(editor
, ID
, "Main");
92 this.editor
= (UserEditor
) editor
;
93 this.userAdminWrapper
= userAdminWrapper
;
96 protected void createFormContent(final IManagedForm mf
) {
97 ScrolledForm form
= mf
.getForm();
98 Composite body
= form
.getBody();
99 GridLayout mainLayout
= new GridLayout();
100 body
.setLayout(mainLayout
);
101 Group group
= (Group
) editor
.getDisplayedUser();
102 appendOverviewPart(body
, group
);
103 appendMembersPart(body
, group
);
106 /** Creates the general section */
107 protected void appendOverviewPart(final Composite parent
, final Group group
) {
108 FormToolkit tk
= getManagedForm().getToolkit();
109 Composite body
= addSection(tk
, parent
, "Main information");
110 GridLayout layout
= new GridLayout(2, false);
111 body
.setLayout(layout
);
113 final Text dnTxt
= createLT(body
, "DN", group
.getName());
114 dnTxt
.setEnabled(false);
116 final Text cnTxt
= createLT(body
, "Common Name",
117 UserAdminUtils
.getProperty(group
, LdifName
.cn
.name()));
118 cnTxt
.setEnabled(false);
120 Label descLbl
= new Label(body
, SWT
.LEAD
);
121 descLbl
.setText("Description");
122 descLbl
.setLayoutData(new GridData(SWT
.RIGHT
, SWT
.TOP
, false, false));
123 final Text descTxt
= new Text(body
, SWT
.LEAD
| SWT
.MULTI
| SWT
.WRAP
125 GridData gd
= EclipseUiUtils
.fillAll();
127 descTxt
.setLayoutData(gd
);
129 // create form part (controller)
130 AbstractFormPart part
= new SectionPart((Section
) body
.getParent()) {
132 private MainInfoListener listener
;
135 public void initialize(IManagedForm form
) {
136 super.initialize(form
);
137 listener
= editor
.new MainInfoListener(parent
.getDisplay(),
139 userAdminWrapper
.addListener(listener
);
143 public void dispose() {
144 userAdminWrapper
.removeListener(listener
);
148 @SuppressWarnings("unchecked")
149 public void commit(boolean onSave
) {
150 group
.getProperties().put(LdifName
.description
.name(),
152 // Enable common name ?
153 // editor.setProperty(UserAdminConstants.KEY_CN,
155 super.commit(onSave
);
159 public void refresh() {
160 refreshFormTitle(group
);
161 dnTxt
.setText(group
.getName());
162 cnTxt
.setText(UserAdminUtils
.getProperty(group
,
163 LdifName
.cn
.name()));
164 descTxt
.setText(UserAdminUtils
.getProperty(group
,
165 LdifName
.description
.name()));
170 ModifyListener defaultListener
= editor
.new FormPartML(part
);
171 descTxt
.addModifyListener(defaultListener
);
172 getManagedForm().addPart(part
);
175 /** Filtered table with members. Has drag & drop ability */
176 protected void appendMembersPart(Composite parent
, Group group
) {
178 FormToolkit tk
= getManagedForm().getToolkit();
179 Section section
= tk
.createSection(parent
, Section
.TITLE_BAR
);
180 section
.setLayoutData(EclipseUiUtils
.fillAll());
182 Composite body
= new Composite(section
, SWT
.NO_FOCUS
);
183 section
.setClient(body
);
184 body
.setLayoutData(EclipseUiUtils
.fillAll());
186 LdifUsersTable userTableViewerCmp
= createMemberPart(body
, group
);
188 SectionPart part
= new GroupMembersPart(section
, userTableViewerCmp
,
190 getManagedForm().addPart(part
);
191 addRemoveAbitily(part
, userTableViewerCmp
.getTableViewer(), group
);
194 public LdifUsersTable
createMemberPart(Composite parent
, Group group
) {
195 parent
.setLayout(EclipseUiUtils
.noSpaceGridLayout());
197 // Define the displayed columns
198 List
<ColumnDefinition
> columnDefs
= new ArrayList
<ColumnDefinition
>();
199 columnDefs
.add(new ColumnDefinition(new RoleIconLP(), "", 0, 24));
200 columnDefs
.add(new ColumnDefinition(new CommonNameLP(), "Common Name",
202 columnDefs
.add(new ColumnDefinition(new MailLP(), "Primary Mail", 150));
203 columnDefs
.add(new ColumnDefinition(new UserNameLP(),
204 "Distinguished Name", 240));
206 // Create and configure the table
207 LdifUsersTable userViewerCmp
= new MyUserTableViewer(parent
, SWT
.MULTI
208 | SWT
.H_SCROLL
| SWT
.V_SCROLL
, userAdminWrapper
.getUserAdmin());
210 userViewerCmp
.setColumnDefinitions(columnDefs
);
211 userViewerCmp
.populate(true, false);
212 userViewerCmp
.setLayoutData(EclipseUiUtils
.fillAll());
215 TableViewer userViewer
= userViewerCmp
.getTableViewer();
216 userViewer
.addDoubleClickListener(new UserTableDefaultDClickListener());
217 int operations
= DND
.DROP_COPY
| DND
.DROP_MOVE
;
218 Transfer
[] tt
= new Transfer
[] { TextTransfer
.getInstance() };
219 userViewer
.addDropSupport(operations
, tt
,
220 new GroupDropListener(userAdminWrapper
, userViewerCmp
,
221 (Group
) editor
.getDisplayedUser()));
223 return userViewerCmp
;
227 private class MyUserTableViewer
extends LdifUsersTable
{
228 private static final long serialVersionUID
= 8467999509931900367L;
230 private final UserFilter userFilter
;
232 public MyUserTableViewer(Composite parent
, int style
,
233 UserAdmin userAdmin
) {
234 super(parent
, style
, true);
235 userFilter
= new UserFilter();
240 protected List
<User
> listFilteredElements(String filter
) {
241 Group group
= (Group
) editor
.getDisplayedUser();
242 Role
[] roles
= group
.getMembers();
243 List
<User
> users
= new ArrayList
<User
>();
244 userFilter
.setSearchText(filter
);
245 for (Role role
: roles
)
246 // if (role.getType() == Role.GROUP)
247 if (userFilter
.select(null, null, role
))
248 users
.add((User
) role
);
253 private void addRemoveAbitily(SectionPart sectionPart
,
254 TableViewer userViewer
, Group group
) {
255 Section section
= sectionPart
.getSection();
256 ToolBarManager toolBarManager
= new ToolBarManager(SWT
.FLAT
);
257 ToolBar toolbar
= toolBarManager
.createControl(section
);
258 final Cursor handCursor
= new Cursor(section
.getDisplay(),
260 toolbar
.setCursor(handCursor
);
261 toolbar
.addDisposeListener(new DisposeListener() {
262 private static final long serialVersionUID
= 3882131405820522925L;
264 public void widgetDisposed(DisposeEvent e
) {
265 if ((handCursor
!= null) && (handCursor
.isDisposed() == false)) {
266 handCursor
.dispose();
271 Action action
= new RemoveMembershipAction(userViewer
, group
,
272 "Remove selected items from this group",
273 SecurityAdminImages
.ICON_REMOVE_DESC
);
274 toolBarManager
.add(action
);
275 toolBarManager
.update(true);
276 section
.setTextClient(toolbar
);
279 private class RemoveMembershipAction
extends Action
{
280 private static final long serialVersionUID
= -1337713097184522588L;
282 private final TableViewer userViewer
;
283 private final Group group
;
285 RemoveMembershipAction(TableViewer userViewer
, Group group
,
286 String name
, ImageDescriptor img
) {
288 this.userViewer
= userViewer
;
294 ISelection selection
= userViewer
.getSelection();
295 if (selection
.isEmpty())
298 @SuppressWarnings("unchecked")
299 Iterator
<User
> it
= ((IStructuredSelection
) selection
).iterator();
300 List
<User
> users
= new ArrayList
<User
>();
301 while (it
.hasNext()) {
302 User currUser
= it
.next();
306 userAdminWrapper
.beginTransactionIfNeeded();
307 for (User user
: users
) {
308 group
.removeMember(user
);
310 userAdminWrapper
.commitOrNotifyTransactionStateChange();
311 userAdminWrapper
.notifyListeners(new UserAdminEvent(null,
312 UserAdminEvent
.ROLE_CHANGED
, group
));
317 private class GroupMembersPart
extends SectionPart
{
318 private final LdifUsersTable userViewer
;
319 private final Group group
;
321 private GroupChangeListener listener
;
323 public GroupMembersPart(Section section
, LdifUsersTable userViewer
,
326 this.userViewer
= userViewer
;
331 public void initialize(IManagedForm form
) {
332 super.initialize(form
);
333 listener
= editor
.new GroupChangeListener(userViewer
.getDisplay(),
334 GroupMembersPart
.this);
335 userAdminWrapper
.addListener(listener
);
339 public void dispose() {
340 userAdminWrapper
.removeListener(listener
);
345 public void refresh() {
346 refreshFormTitle(group
);
347 getSection().setText(
349 + UserAdminUtils
.getProperty(group
,
350 LdifName
.cn
.name()));
351 userViewer
.refresh();
357 * Defines this table as being a potential target to add group membership
358 * (roles) to this group
360 private class GroupDropListener
extends ViewerDropAdapter
{
361 private static final long serialVersionUID
= 2893468717831451621L;
363 private final UserAdminWrapper userAdminWrapper
;
364 // private final LdifUsersTable myUserViewerCmp;
365 private final Group myGroup
;
367 public GroupDropListener(UserAdminWrapper userAdminWrapper
,
368 LdifUsersTable userTableViewerCmp
, Group group
) {
369 super(userTableViewerCmp
.getTableViewer());
370 this.userAdminWrapper
= userAdminWrapper
;
371 this.myGroup
= group
;
372 // this.myUserViewerCmp = userTableViewerCmp;
376 public boolean validateDrop(Object target
, int operation
,
377 TransferData transferType
) {
378 // Target is always OK in a list only view
379 // TODO check if not a string
380 boolean validDrop
= true;
385 public void drop(DropTargetEvent event
) {
386 // TODO Is there an opportunity to perform the check before?
388 String newUserName
= (String
) event
.data
;
389 UserAdmin myUserAdmin
= userAdminWrapper
.getUserAdmin();
390 Role role
= myUserAdmin
.getRole(newUserName
);
391 if (role
.getType() == Role
.GROUP
) {
392 Group newGroup
= (Group
) role
;
393 Shell shell
= getViewer().getControl().getShell();
395 if (myGroup
== newGroup
) { // Equality
396 MessageDialog
.openError(shell
, "Forbidden addition ",
397 "A group cannot be a member of itself.");
402 String myName
= myGroup
.getName();
403 List
<User
> myMemberships
= editor
.getFlatGroups(myGroup
);
404 if (myMemberships
.contains(newGroup
)) {
405 MessageDialog
.openError(shell
, "Forbidden addition: cycle",
406 "Cannot add " + newUserName
+ " to group " + myName
407 + ". This would create a cycle");
412 List
<User
> newGroupMemberships
= editor
.getFlatGroups(newGroup
);
413 if (newGroupMemberships
.contains(myGroup
)) {
414 MessageDialog
.openError(shell
, "Forbidden addition",
415 "Cannot add " + newUserName
+ " to group " + myName
416 + ", this membership already exists");
419 userAdminWrapper
.beginTransactionIfNeeded();
420 myGroup
.addMember(newGroup
);
421 userAdminWrapper
.commitOrNotifyTransactionStateChange();
422 userAdminWrapper
.notifyListeners(new UserAdminEvent(null,
423 UserAdminEvent
.ROLE_CHANGED
, myGroup
));
424 } else if (role
.getType() == Role
.USER
) {
425 // TODO check if the group is already member of this group
426 UserTransaction transaction
= userAdminWrapper
427 .beginTransactionIfNeeded();
428 User user
= (User
) role
;
429 myGroup
.addMember(user
);
430 if (UserAdminWrapper
.COMMIT_ON_SAVE
)
432 transaction
.commit();
433 } catch (Exception e
) {
434 throw new CmsException("Cannot commit transaction "
435 + "after user group membership update", e
);
437 userAdminWrapper
.notifyListeners(new UserAdminEvent(null,
438 UserAdminEvent
.ROLE_CHANGED
, myGroup
));
444 public boolean performDrop(Object data
) {
445 // myUserViewerCmp.refresh();
451 private void refreshFormTitle(Group group
) {
452 getManagedForm().getForm().setText(
453 UserAdminUtils
.getProperty(group
, LdifName
.cn
.name()));
456 private Composite
addSection(FormToolkit tk
, Composite parent
, String title
) {
457 Section section
= tk
.createSection(parent
, Section
.TITLE_BAR
);
458 GridData gd
= EclipseUiUtils
.fillWidth();
459 gd
.verticalAlignment
= PRE_TITLE_INDENT
;
460 section
.setLayoutData(gd
);
461 section
.setText(title
);
462 Composite body
= tk
.createComposite(section
, SWT
.WRAP
);
463 body
.setLayoutData(EclipseUiUtils
.fillAll());
464 section
.setClient(body
);
468 /** Creates label and text. */
469 private Text
createLT(Composite body
, String label
, String value
) {
470 FormToolkit toolkit
= getManagedForm().getToolkit();
471 Label lbl
= toolkit
.createLabel(body
, label
);
472 lbl
.setLayoutData(new GridData(SWT
.RIGHT
, SWT
.CENTER
, false, false));
473 Text text
= toolkit
.createText(body
, value
, SWT
.BORDER
);
474 text
.setLayoutData(new GridData(SWT
.FILL
, SWT
.CENTER
, true, false));