1 package org.argeo.tracker.e4.parts;
2
3 import java.util.ArrayList;
4 import java.util.List;
5
6 import javax.jcr.Node;
7 import javax.jcr.NodeIterator;
8 import javax.jcr.Property;
9 import javax.jcr.PropertyType;
10 import javax.jcr.RepositoryException;
11 import javax.jcr.Session;
12
13 import org.argeo.cms.auth.CurrentUser;
14 import org.argeo.cms.ui.eclipse.forms.AbstractFormPart;
15 import org.argeo.cms.ui.eclipse.forms.IFormPart;
16 import org.argeo.cms.ui.eclipse.forms.IManagedForm;
17 import org.argeo.cms.util.CmsUtils;
18 import org.argeo.connect.ConnectNames;
19 import org.argeo.connect.UserAdminService;
20 import org.argeo.connect.ui.AppWorkbenchService;
21 import org.argeo.connect.ui.ConnectImages;
22 import org.argeo.connect.ui.ConnectUiConstants;
23 import org.argeo.connect.ui.ConnectUiSnippets;
24 import org.argeo.connect.ui.ConnectWorkbenchUtils;
25 import org.argeo.connect.ui.parts.AskTitleDescriptionDialog;
26 import org.argeo.connect.util.ConnectJcrUtils;
27 import org.argeo.eclipse.ui.ColumnDefinition;
28 import org.argeo.eclipse.ui.EclipseUiUtils;
29 import org.argeo.eclipse.ui.jcr.lists.SimpleJcrNodeLabelProvider;
30 import org.argeo.jcr.JcrUtils;
31 import org.argeo.node.NodeConstants;
32 import org.argeo.tracker.TrackerException;
33 import org.argeo.tracker.TrackerNames;
34 import org.argeo.tracker.TrackerService;
35 import org.argeo.tracker.TrackerTypes;
36 import org.argeo.tracker.core.TrackerUtils;
37 import org.argeo.tracker.ui.TrackerLps;
38 import org.argeo.tracker.ui.TrackerUiConstants;
39 import org.argeo.tracker.ui.VersionComparator;
40 import org.argeo.tracker.ui.dialogs.ConfigureVersionWizard;
41 import org.eclipse.jface.dialogs.MessageDialog;
42 import org.eclipse.jface.viewers.ColumnLabelProvider;
43 import org.eclipse.jface.viewers.DoubleClickEvent;
44 import org.eclipse.jface.viewers.IDoubleClickListener;
45 import org.eclipse.jface.viewers.IStructuredSelection;
46 import org.eclipse.jface.viewers.TableViewer;
47 import org.eclipse.jface.viewers.Viewer;
48 import org.eclipse.jface.viewers.ViewerComparator;
49 import org.eclipse.jface.window.Window;
50 import org.eclipse.jface.wizard.WizardDialog;
51 import org.eclipse.swt.SWT;
52 import org.eclipse.swt.custom.ScrolledComposite;
53 import org.eclipse.swt.events.ModifyEvent;
54 import org.eclipse.swt.events.ModifyListener;
55 import org.eclipse.swt.events.SelectionAdapter;
56 import org.eclipse.swt.events.SelectionEvent;
57 import org.eclipse.swt.layout.GridData;
58 import org.eclipse.swt.layout.GridLayout;
59 import org.eclipse.swt.widgets.Button;
60 import org.eclipse.swt.widgets.Composite;
61 import org.eclipse.swt.widgets.Shell;
62 import org.eclipse.swt.widgets.Table;
63 import org.eclipse.swt.widgets.Text;
64
65 public class MilestoneListPage extends AbstractEditorPage {
66
67 private final UserAdminService userAdminService;
68 private final TrackerService trackerService;
69 private final AppWorkbenchService appWorkbenchService;
70 private final Node project;
71
72 private TableViewer tableViewer;
73 private Text filterTxt;
74
75 public MilestoneListPage(AbstractTrackerEditor editor, String id, Node project, UserAdminService userAdminService,
76 TrackerService trackerService, AppWorkbenchService appWorkbenchService) {
77 super(editor, id, "Milestones");
78 this.userAdminService = userAdminService;
79 this.trackerService = trackerService;
80 this.appWorkbenchService = appWorkbenchService;
81 this.project = project;
82 }
83
84 private boolean canEdit() {
85 boolean isDataAdmin = CurrentUser.isInRole(NodeConstants.ROLE_DATA_ADMIN);
86 String managerId = ConnectJcrUtils.get(project, TrackerNames.TRACKER_MANAGER);
87
88
89 boolean isManager = (EclipseUiUtils.notEmpty(managerId)
90 && (CurrentUser.getUsername().equalsIgnoreCase(managerId)) || CurrentUser.isInRole(managerId));
91 return isDataAdmin || isManager;
92
93
94
95 }
96
97 protected void createFormContent(IManagedForm mf) {
98
99
100 ScrolledComposite form = mf.getForm();
101 Composite body = new Composite(form, SWT.NONE);
102 form.setContent(body);
103 GridLayout mainLayout = new GridLayout();
104
105 body.setLayout(mainLayout);
106 Composite filterCmp = new Composite(body, SWT.NO_FOCUS);
107 createFilterPart(filterCmp);
108 filterCmp.setLayoutData(EclipseUiUtils.fillWidth());
109 Composite tableCmp = new Composite(body, SWT.NO_FOCUS);
110 appendMilestonesPart(mf, tableCmp);
111 tableCmp.setLayoutData(EclipseUiUtils.fillAll());
112
113
114 }
115
116 private void appendMilestonesPart(IManagedForm mf, Composite parent) {
117 List<ColumnDefinition> columnDefs = new ArrayList<ColumnDefinition>();
118 columnDefs.add(new ColumnDefinition(getJcrLP(Property.JCR_TITLE), "Name", 120));
119 columnDefs.add(new ColumnDefinition(new TrackerLps().new DateLabelProvider(TrackerNames.TRACKER_TARGET_DATE),
120 "Target Date", 120));
121 columnDefs.add(new ColumnDefinition(
122 new TrackerLps().new DnLabelProvider(userAdminService, TrackerNames.TRACKER_MANAGER), "Manager", 160));
123 columnDefs.add(new ColumnDefinition(getJcrLP(Property.JCR_DESCRIPTION), "Description", 300));
124 columnDefs.add(new ColumnDefinition(getMSIssuesLP(), "Open / All Tasks", 120));
125
126
127 columnDefs.add(new ColumnDefinition(new TrackerLps().new DateLabelProvider(ConnectNames.CONNECT_CLOSE_DATE),
128 "Close Date", 120));
129 if (canEdit())
130 columnDefs.add(new ColumnDefinition(getEditionLP(), "", 120));
131
132 tableViewer = TrackerUiUtils.createTableViewer(parent, SWT.SINGLE, columnDefs);
133 tableViewer.setComparator(new ViewerComparator() {
134 private static final long serialVersionUID = 1L;
135 VersionComparator comp = new VersionComparator();
136
137 public int compare(Viewer viewer, Object e1, Object e2) {
138 Node n1 = (Node) e1;
139 Node n2 = (Node) e2;
140
141 return comp.compare(viewer, ConnectJcrUtils.getName(n2), ConnectJcrUtils.getName(n1));
142 };
143 });
144 addDClickListener(tableViewer);
145
146 AbstractFormPart part = new AbstractFormPart() {
147 @Override
148 public void refresh() {
149 refreshViewer(filterTxt.getText());
150 super.refresh();
151 }
152 };
153 mf.addPart(part);
154
155 if (canEdit()) {
156 Table table = tableViewer.getTable();
157 CmsUtils.setItemHeight(table, TrackerUiConstants.DEFAULT_ROW_HEIGHT);
158 CmsUtils.markup(table);
159 table.addSelectionListener(new EditionRwtAdapter(part));
160 }
161 refreshViewer(null);
162 }
163
164 private void refreshViewer(String filter) {
165 NodeIterator nit = TrackerUtils.getOpenMilestones(project, filter);
166 tableViewer.setInput(JcrUtils.nodeIteratorToList(nit).toArray(new Node[0]));
167 tableViewer.refresh();
168 }
169
170 private void createFilterPart(Composite parent) {
171 GridLayout layout = EclipseUiUtils.noSpaceGridLayout(new GridLayout(2, false));
172 layout.horizontalSpacing = 5;
173 parent.setLayout(layout);
174 parent.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
175
176 filterTxt = new Text(parent, SWT.BORDER | SWT.SEARCH | SWT.ICON_SEARCH | SWT.ICON_CANCEL);
177 filterTxt.setLayoutData(EclipseUiUtils.fillWidth());
178
179 final Button addBtn = new Button(parent, SWT.PUSH);
180 addBtn.setToolTipText("Create a milestone");
181 addBtn.setImage(ConnectImages.ADD);
182
183 filterTxt.addModifyListener(new ModifyListener() {
184 private static final long serialVersionUID = 8130545587125370689L;
185
186 public void modifyText(ModifyEvent event) {
187 refreshViewer(filterTxt.getText());
188 }
189 });
190
191 addBtn.addSelectionListener(new SelectionAdapter() {
192 private static final long serialVersionUID = -6057495212496327413L;
193
194 @Override
195 public void widgetSelected(SelectionEvent e) {
196 Session session = ConnectJcrUtils.getSession(project);
197 String mainMixin = TrackerTypes.TRACKER_MILESTONE;
198 String propName1 = TrackerNames.TRACKER_PROJECT_UID;
199 String value1 = ConnectJcrUtils.get(project, ConnectNames.CONNECT_UID);
200
201 String pathCreated = ConnectWorkbenchUtils.createAndConfigureEntity(addBtn.getShell(), session,
202 trackerService, appWorkbenchService, mainMixin, propName1, value1);
203 if (EclipseUiUtils.notEmpty(pathCreated))
204 refreshViewer(filterTxt.getText());
205 }
206 });
207 }
208
209
210
211
212 private static ColumnLabelProvider getJcrLP(String propName) {
213 return new SimpleJcrNodeLabelProvider(propName);
214 }
215
216 private ColumnLabelProvider getMSIssuesLP() {
217 return new ColumnLabelProvider() {
218 private static final long serialVersionUID = -998161071505982347L;
219
220 @Override
221 public String getText(Object element) {
222 Node milestone = (Node) element;
223 NodeIterator nit = TrackerUtils.getIssues(project, null, TrackerNames.TRACKER_MILESTONE_UID,
224 ConnectJcrUtils.get(milestone, ConnectNames.CONNECT_UID), true);
225 long openNb = nit.getSize();
226
227 nit = TrackerUtils.getIssues(project, null, TrackerNames.TRACKER_MILESTONE_UID,
228 ConnectJcrUtils.get(milestone, ConnectNames.CONNECT_UID), false);
229 long allNb = nit.getSize();
230
231 return openNb + " / " + allNb;
232 }
233 };
234 }
235
236 private static ColumnLabelProvider getEditionLP() {
237 return new ColumnLabelProvider() {
238 private static final long serialVersionUID = 6502008085763687925L;
239
240 @Override
241 public String getText(Object element) {
242 Node category = (Node) element;
243 String jcrId = ConnectJcrUtils.getIdentifier(category);
244
245 String editHref = ConnectUiConstants.CRUD_EDIT + "/" + jcrId;
246 String editLinkStr = ConnectUiSnippets.getRWTLink(editHref, ConnectUiConstants.CRUD_EDIT);
247
248
249 if (TrackerUtils.getIssueNb(category, false) == 0) {
250 String removeHref = ConnectUiConstants.CRUD_DELETE + "/" + jcrId;
251 String removeLinkStr = ConnectUiSnippets.getRWTLink(removeHref, ConnectUiConstants.CRUD_DELETE);
252 editLinkStr += " or " + removeLinkStr;
253 }
254 return editLinkStr;
255 }
256 };
257 }
258
259 private void addDClickListener(TableViewer tableViewer) {
260 tableViewer.addDoubleClickListener(new IDoubleClickListener() {
261 @Override
262 public void doubleClick(DoubleClickEvent event) {
263 Object element = ((IStructuredSelection) event.getSelection()).getFirstElement();
264
265
266
267
268 appWorkbenchService.openEntityEditor((Node) element);
269 }
270 });
271 }
272
273 private class EditionRwtAdapter extends SelectionAdapter {
274 private static final long serialVersionUID = -7459078949241763141L;
275
276 private IFormPart part;
277
278 public EditionRwtAdapter(IFormPart part) {
279 this.part = part;
280 }
281
282 public void widgetSelected(SelectionEvent event) {
283 if (event.detail == ConnectUiConstants.MARKUP_VIEWER_HYPERLINK) {
284 String string = event.text;
285 String[] token = string.split("/");
286 String cmdId = token[0];
287 String jcrId = token[1];
288 Shell shell = event.display.getActiveShell();
289 boolean hasChanged = false;
290 try {
291 Node node = project.getSession().getNodeByIdentifier(jcrId);
292 if (ConnectUiConstants.CRUD_DELETE.equals(cmdId)) {
293 if (MessageDialog.openConfirm(shell, "Confirm deletion",
294 "Are you sure you want to delete " + ConnectJcrUtils.get(node, Property.JCR_TITLE))) {
295 node.remove();
296 project.getSession().save();
297 hasChanged = true;
298 }
299 } else if (ConnectUiConstants.CRUD_EDIT.equals(cmdId)) {
300 if (node.isNodeType(TrackerTypes.TRACKER_COMPONENT)) {
301 String title = ConnectJcrUtils.get(node, Property.JCR_TITLE);
302 String desc = ConnectJcrUtils.get(node, Property.JCR_DESCRIPTION);
303 AskTitleDescriptionDialog dialog = new AskTitleDescriptionDialog(shell, "Edit component",
304 title, desc);
305 if (dialog.open() == Window.OK) {
306 hasChanged = ConnectJcrUtils.setJcrProperty(node, Property.JCR_TITLE,
307 PropertyType.STRING, dialog.getTitle());
308 hasChanged |= ConnectJcrUtils.setJcrProperty(node, Property.JCR_DESCRIPTION,
309 PropertyType.STRING, dialog.getDescription());
310 if (hasChanged)
311 project.getSession().save();
312 }
313 } else if (node.isNodeType(TrackerTypes.TRACKER_VERSION)) {
314 ConfigureVersionWizard wizard = new ConfigureVersionWizard(trackerService, node);
315 WizardDialog dialog = new WizardDialog(shell, wizard);
316 if (dialog.open() == Window.OK) {
317 if (project.getSession().hasPendingChanges()) {
318 project.getSession().save();
319 hasChanged = true;
320 }
321 }
322 }
323 }
324 } catch (RepositoryException e) {
325 throw new TrackerException("Cannot " + cmdId + " with JcrId " + jcrId, e);
326 }
327 if (hasChanged)
328 part.refresh();
329 }
330 }
331 }
332 }