1 package org.argeo.tracker.e4.parts;
2
3 import static org.argeo.activities.ActivitiesNames.ACTIVITIES_DUE_DATE;
4 import static org.argeo.eclipse.ui.EclipseUiUtils.notEmpty;
5
6 import java.util.ArrayList;
7 import java.util.Calendar;
8 import java.util.GregorianCalendar;
9 import java.util.List;
10 import java.util.Map;
11
12 import javax.jcr.Node;
13 import javax.jcr.NodeIterator;
14 import javax.jcr.Property;
15 import javax.jcr.RepositoryException;
16 import javax.jcr.Session;
17 import javax.jcr.query.Query;
18
19 import org.argeo.activities.ActivitiesException;
20 import org.argeo.activities.ActivitiesNames;
21 import org.argeo.activities.ActivitiesTypes;
22 import org.argeo.activities.ui.AssignedToLP;
23 import org.argeo.cms.auth.CurrentUser;
24 import org.argeo.cms.ui.eclipse.forms.AbstractFormPart;
25 import org.argeo.cms.ui.eclipse.forms.FormToolkit;
26 import org.argeo.cms.util.CmsUtils;
27 import org.argeo.connect.ConnectConstants;
28 import org.argeo.connect.ConnectNames;
29 import org.argeo.connect.ui.ConnectColumnDefinition;
30 import org.argeo.connect.ui.ConnectImages;
31 import org.argeo.connect.ui.ConnectWorkbenchUtils;
32 import org.argeo.connect.ui.IJcrTableViewer;
33 import org.argeo.connect.ui.util.JcrRowLabelProvider;
34 import org.argeo.connect.ui.util.UserNameLP;
35 import org.argeo.connect.util.ConnectJcrUtils;
36 import org.argeo.connect.util.XPathUtils;
37 import org.argeo.eclipse.ui.ColumnDefinition;
38 import org.argeo.eclipse.ui.EclipseUiUtils;
39 import org.argeo.eclipse.ui.jcr.lists.SimpleJcrNodeLabelProvider;
40 import org.argeo.jcr.JcrUtils;
41 import org.argeo.tracker.TrackerException;
42 import org.argeo.tracker.TrackerNames;
43 import org.argeo.tracker.TrackerTypes;
44 import org.argeo.tracker.core.TrackerUtils;
45 import org.argeo.tracker.ui.TrackerLps;
46 import org.argeo.tracker.ui.controls.RepartitionChart;
47 import org.argeo.tracker.ui.dialogs.ConfigureMilestoneWizard;
48 import org.eclipse.jface.action.Action;
49 import org.eclipse.jface.action.ToolBarManager;
50 import org.eclipse.jface.dialogs.MessageDialog;
51 import org.eclipse.jface.resource.ImageDescriptor;
52 import org.eclipse.jface.viewers.DoubleClickEvent;
53 import org.eclipse.jface.viewers.IDoubleClickListener;
54 import org.eclipse.jface.viewers.IStructuredSelection;
55 import org.eclipse.jface.viewers.TableViewer;
56 import org.eclipse.jface.window.Window;
57 import org.eclipse.jface.wizard.WizardDialog;
58 import org.eclipse.swt.SWT;
59 import org.eclipse.swt.events.ModifyEvent;
60 import org.eclipse.swt.events.ModifyListener;
61 import org.eclipse.swt.events.SelectionAdapter;
62 import org.eclipse.swt.events.SelectionEvent;
63 import org.eclipse.swt.layout.GridData;
64 import org.eclipse.swt.layout.GridLayout;
65 import org.eclipse.swt.widgets.Button;
66 import org.eclipse.swt.widgets.Composite;
67 import org.eclipse.swt.widgets.Label;
68 import org.eclipse.swt.widgets.Link;
69 import org.eclipse.swt.widgets.Listener;
70 import org.eclipse.swt.widgets.Shell;
71 import org.eclipse.swt.widgets.Text;
72
73
74 public class MilestoneEditor extends AbstractTrackerEditor implements IJcrTableViewer {
75
76
77
78
79
80
81 private Node project;
82 private Node milestone;
83 private String milestoneUid;
84
85
86 private Text filterTxt;
87 private Button onlyMineBtn;
88 private Button onlyOpenBtn;
89 private Button overdueBtn;
90 private AbstractFormPart issueListPart;
91
92
93 private final static int CHART_DATA_LIMIT = 8;
94 private final static int CHART_WIDTH = 300;
95 private final static int CHART_HEIGHT = 200;
96
97
98
99
100
101
102
103
104 @Override
105 protected void addPages() {
106
107 milestone = getNode();
108 project = getAppService().getEntityByUid(ConnectJcrUtils.getSession(milestone), null,
109 ConnectJcrUtils.get(milestone, TrackerNames.TRACKER_PROJECT_UID));
110 milestoneUid = ConnectJcrUtils.get(milestone, ConnectNames.CONNECT_UID);
111 try {
112 addPage(new MainPage(this));
113
114
115
116 } catch (Exception e) {
117 throw new TrackerException("Cannot add pages for editor of " + getNode(), e);
118 }
119 }
120
121 private class MainPage extends AbstractEditorPage {
122 public final static String PAGE_ID = ".mainPage";
123
124 private Link projectLk;
125 private Link managerLk;
126 private Link overdueTasksLk;
127 private Link dueDateLk;
128 private Label dueDateLbl;
129 private Composite chartCmp;
130 private Label descLbl;
131
132 private TableViewer tableViewer;
133
134 public MainPage(AbstractTrackerEditor editor) {
135 super(editor, PAGE_ID, "Overview");
136 }
137
138 protected void createFormContent(Composite body) {
139
140
141
142
143 body.setLayout(new GridLayout());
144
145
146
147 Composite overview = appendOverviewPart(body);
148
149
150 Composite filterCmp = new Composite(body, SWT.NO_FOCUS);
151 createFilterPart(filterCmp);
152 filterCmp.setLayoutData(new GridData(SWT.FILL, SWT.FILL, false, false));
153
154 Composite tableCmp = new Composite(body, SWT.NO_FOCUS);
155 appendIssuesPart(tableCmp);
156 GridData twd = new GridData(SWT.FILL, SWT.FILL, false, false);
157 twd.heightHint = 300;
158 tableCmp.setLayoutData(twd);
159
160
161 }
162
163 private Composite appendOverviewPart(Composite parent) {
164 FormToolkit tk = getFormToolkit();
165
166
167
168
169 Composite body = new Composite(parent, SWT.BORDER);
170 body.setLayoutData(CmsUtils.fillAll());
171 GridLayout layout = new GridLayout(2, false);
172
173 body.setLayout(layout);
174
175
176 createFormBoldLabel(tk, body, "Project");
177 projectLk = new Link(body, SWT.NONE);
178 projectLk.setText("TEST LINK");
179 projectLk.setLayoutData(new GridData(SWT.FILL, SWT.FILL, false, false));
180 configureOpenLink(projectLk, project);
181
182
183 createFormBoldLabel(tk, body, "Manager");
184 managerLk = new Link(body, SWT.NONE);
185 managerLk.setLayoutData(new GridData(SWT.FILL, SWT.FILL, false, false));
186
187
188 chartCmp = new Composite(body, SWT.NO_FOCUS);
189 chartCmp.setLayout(EclipseUiUtils.noSpaceGridLayout());
190 GridData twd = new GridData(SWT.FILL, SWT.FILL, false, false);
191 twd.widthHint = CHART_WIDTH;
192 twd.horizontalSpan = 2;
193 twd.verticalSpan = 3;
194 chartCmp.setLayoutData(twd);
195
196
197 createFormBoldLabel(tk, body, "Overdue Tasks");
198 overdueTasksLk = new Link(body, SWT.NONE);
199 overdueTasksLk.setLayoutData(new GridData(SWT.FILL, SWT.FILL, false, false));
200
201
202 dueDateLbl = createFormBoldLabel(tk, body, "Due Date");
203 dueDateLk = new Link(body, SWT.NONE);
204 dueDateLk.setLayoutData(new GridData(SWT.FILL, SWT.FILL, false, false));
205
206
207
208
209
210
211
212
213
214 twd = (GridData) createFormBoldLabel(tk, body, "Details").getLayoutData();
215
216 descLbl = new Label(body, SWT.WRAP);
217 twd = new GridData(SWT.FILL, SWT.FILL, false, false);
218
219 descLbl.setLayoutData(twd);
220
221 SectionPart part = new SectionPart(body.getParent()) {
222
223 @Override
224 public void refresh() {
225 String managerId = ConnectJcrUtils.get(milestone, TrackerNames.TRACKER_MANAGER);
226 if (EclipseUiUtils.notEmpty(managerId))
227 managerLk.setText(getUserAdminService().getUserDisplayName(managerId));
228 else
229 managerLk.setText("");
230
231 String dueDateStr = ConnectJcrUtils.getDateFormattedAsString(milestone,
232 TrackerNames.TRACKER_TARGET_DATE, ConnectConstants.DEFAULT_DATE_TIME_FORMAT);
233 if (EclipseUiUtils.notEmpty(dueDateStr))
234 dueDateLk.setText(dueDateStr);
235
236 String desc = ConnectJcrUtils.get(milestone, Property.JCR_DESCRIPTION);
237 descLbl.setText(desc);
238
239
240 CmsUtils.clear(chartCmp);
241 GridData twd = (GridData) chartCmp.getLayoutData();
242 Map<String, String> ot = TrackerUtils.getOpenTasksByAssignee(getUserAdminService(), project,
243 milestoneUid, CHART_DATA_LIMIT);
244 if (ot == null || ot.isEmpty()) {
245 Label lbl = new Label(chartCmp, SWT.CENTER);
246 lbl.setFont(EclipseUiUtils.getItalicFont(body));
247 lbl.setText("No open task has been found for this milestone.");
248 twd.heightHint = SWT.DEFAULT;
249 } else {
250 RepartitionChart coc = new RepartitionChart(chartCmp, SWT.NO_FOCUS);
251 twd.heightHint = CHART_HEIGHT;
252 coc.setLayoutData(EclipseUiUtils.fillAll());
253 coc.setInput("Repartition by assignee - " + getOpenTaskNumber() + " open tasks", ot,
254 CHART_WIDTH, CHART_HEIGHT);
255 }
256
257
258 Long nb = getOverdueTaskNumber();
259 overdueTasksLk.setText(nb < 0 ? "-" : nb.toString());
260
261 String closedOn = ConnectJcrUtils.getDateFormattedAsString(milestone,
262 ConnectNames.CONNECT_CLOSE_DATE, ConnectConstants.DEFAULT_DATE_TIME_FORMAT);
263
264 if (EclipseUiUtils.notEmpty(closedOn)) {
265 dueDateLbl.setText("Close date");
266 dueDateLk.setText(closedOn);
267 }
268
269 parent.layout(true, true);
270 body.setFocus();
271 super.refresh();
272 }
273 };
274 getManagedForm().addPart(part);
275
276
277 return body;
278 }
279
280 private long getOpenTaskNumber() {
281 StringBuilder builder = new StringBuilder();
282 try {
283 builder.append(XPathUtils.descendantFrom(project.getPath()));
284 builder.append("//element(*, ").append(ActivitiesTypes.ACTIVITIES_TASK).append(")");
285 String milestoneCond = XPathUtils.getPropertyEquals(TrackerNames.TRACKER_MILESTONE_UID, milestoneUid);
286 String notClosedCond = "not(@" + ConnectNames.CONNECT_CLOSE_DATE + ")";
287 builder.append("[").append(XPathUtils.localAnd(milestoneCond, notClosedCond)).append("]");
288 Query query = XPathUtils.createQuery(getSession(), builder.toString());
289 return query.execute().getNodes().getSize();
290 } catch (RepositoryException e) {
291 throw new ActivitiesException("Unable to get overdue tasks number for " + milestone);
292 }
293 }
294
295 private long getOverdueTaskNumber() {
296 StringBuilder builder = new StringBuilder();
297 try {
298 builder.append(XPathUtils.descendantFrom(project.getPath()));
299 builder.append("//element(*, ").append(TrackerTypes.TRACKER_ISSUE).append(")");
300
301 String milestoneCond = XPathUtils.getPropertyEquals(TrackerNames.TRACKER_MILESTONE_UID, milestoneUid);
302
303
304 Calendar now = GregorianCalendar.getInstance();
305 String overdueCond = XPathUtils.getPropertyDateComparaison(ACTIVITIES_DUE_DATE, now, "<");
306
307 String notClosedCond = "not(@" + ConnectNames.CONNECT_CLOSE_DATE + ")";
308
309 builder.append("[").append(XPathUtils.localAnd(milestoneCond, overdueCond, notClosedCond)).append("]");
310 Query query = XPathUtils.createQuery(getSession(), builder.toString());
311 return query.execute().getNodes().getSize();
312 } catch (RepositoryException e) {
313 throw new ActivitiesException("Unable to get overdue tasks number for " + milestone);
314 }
315 }
316
317
318 private void appendIssuesPart(Composite parent) {
319 List<ColumnDefinition> columnDefs = new ArrayList<ColumnDefinition>();
320 columnDefs.add(new ColumnDefinition(new SimpleJcrNodeLabelProvider(TrackerNames.TRACKER_ID), "ID", 40));
321 columnDefs.add(new ColumnDefinition(new SimpleJcrNodeLabelProvider(Property.JCR_TITLE), "Title", 300));
322 columnDefs.add(new ColumnDefinition(new SimpleJcrNodeLabelProvider(ActivitiesNames.ACTIVITIES_TASK_STATUS),
323 "Status", 100));
324 columnDefs.add(new ColumnDefinition(
325 new TrackerLps().new DnLabelProvider(getUserAdminService(), ActivitiesNames.ACTIVITIES_ASSIGNED_TO),
326 "Assignee", 160));
327 columnDefs.add(new ColumnDefinition(new TrackerLps().new ImportanceLabelProvider(), "Importance", 100));
328 columnDefs.add(new ColumnDefinition(new TrackerLps().new PriorityLabelProvider(), "Priority", 100));
329
330
331 tableViewer = TrackerUiUtils.createTableViewer(parent, SWT.SINGLE, columnDefs);
332 tableViewer.addDoubleClickListener(new IDoubleClickListener() {
333
334 @Override
335 public void doubleClick(DoubleClickEvent event) {
336 Object element = ((IStructuredSelection) event.getSelection()).getFirstElement();
337
338
339
340 getAppWorkbenchService().openEntityEditor((Node) element);
341 }
342 });
343
344 issueListPart = new AbstractFormPart() {
345 @Override
346 public void refresh() {
347 refreshViewer(filterTxt.getText());
348
349 super.refresh();
350 }
351 };
352 getManagedForm().addPart(issueListPart);
353 }
354
355 public void setActive(boolean active) {
356 issueListPart.markStale();
357 super.setActive(active);
358 }
359
360 private void refreshViewer(String filter) {
361 NodeIterator nit = getTasks();
362 tableViewer.setInput(JcrUtils.nodeIteratorToList(nit).toArray(new Node[0]));
363 tableViewer.refresh();
364 }
365
366
367 private void createFilterPart(Composite parent) {
368 GridLayout layout = EclipseUiUtils.noSpaceGridLayout(new GridLayout(4, false));
369 layout.horizontalSpacing = 5;
370 parent.setLayout(layout);
371 parent.setLayoutData(new GridData(SWT.FILL, SWT.FILL, false, false));
372
373 filterTxt = new Text(parent, SWT.BORDER | SWT.SEARCH | SWT.ICON_SEARCH | SWT.ICON_CANCEL);
374 filterTxt.setLayoutData(EclipseUiUtils.fillWidth());
375
376 filterTxt.addModifyListener(new ModifyListener() {
377 private static final long serialVersionUID = 8130545587125370689L;
378
379 public void modifyText(ModifyEvent event) {
380 refreshViewer(filterTxt.getText());
381 }
382 });
383
384 SelectionAdapter adapter = new SelectionAdapter() {
385 private static final long serialVersionUID = 1L;
386
387 @Override
388 public void widgetSelected(SelectionEvent e) {
389 refreshViewer(filterTxt.getText());
390 }
391 };
392
393 onlyMineBtn = new Button(parent, SWT.CHECK);
394 onlyMineBtn.setText("Only mine ");
395 onlyMineBtn.addSelectionListener(adapter);
396 onlyOpenBtn = new Button(parent, SWT.CHECK);
397 onlyOpenBtn.setText("Only open ");
398 onlyOpenBtn.addSelectionListener(adapter);
399 overdueBtn = new Button(parent, SWT.CHECK);
400 overdueBtn.setText("Overdue ");
401 overdueBtn.addSelectionListener(adapter);
402
403 }
404
405
406 private void addMainSectionMenu(SectionPart sectionPart) {
407 ToolBarManager toolBarManager = TrackerUiUtils.addMenu(sectionPart.getSection());
408
409 String tooltip = "Mark this milestone as closed";
410 Action action = new CloseMilestone(tooltip, ConnectImages.IMG_DESC_CLOSE, sectionPart);
411 toolBarManager.add(action);
412
413 tooltip = "Edit the milestone main information";
414 action = new OpenConfigureDialog(tooltip, ConnectImages.IMG_DESC_EDIT, sectionPart);
415 toolBarManager.add(action);
416
417 tooltip = "Add a task to this milestone";
418 action = new AddTask(sectionPart.getSection().getShell(), tooltip, ConnectImages.IMG_DESC_ADD);
419 toolBarManager.add(action);
420
421 toolBarManager.update(true);
422
423 }
424
425
426 private class OpenConfigureDialog extends Action {
427 private static final long serialVersionUID = -6798429720348536525L;
428 private final SectionPart sectionPart;
429
430 private OpenConfigureDialog(String name, ImageDescriptor img, SectionPart sectionPart) {
431 super(name, img);
432 this.sectionPart = sectionPart;
433 }
434
435 @Override
436 public void run() {
437 Shell currShell = sectionPart.getSection().getShell();
438 ConfigureMilestoneWizard wizard = new ConfigureMilestoneWizard(getUserAdminService(),
439 getTrackerService(), milestone);
440 WizardDialog dialog = new WizardDialog(currShell, wizard);
441 try {
442 if (dialog.open() == Window.OK && milestone.getSession().hasPendingChanges()) {
443 updatePartName();
444 sectionPart.getSection().setText(getMilestoneTitle());
445 sectionPart.refresh();
446 sectionPart.markDirty();
447 sectionPart.getSection().setFocus();
448 }
449 } catch (RepositoryException e) {
450 throw new TrackerException("Cannot check session state on " + milestone, e);
451 }
452 }
453 }
454
455 private class CloseMilestone extends Action {
456 private static final long serialVersionUID = -6798429720348536525L;
457 private final SectionPart sectionPart;
458
459 private CloseMilestone(String name, ImageDescriptor img, SectionPart sectionPart) {
460 super(name, img);
461 this.sectionPart = sectionPart;
462 }
463
464 @Override
465 public void run() {
466 Shell currShell = sectionPart.getSection().getShell();
467 boolean doIt = MessageDialog.openConfirm(currShell, "Confirm before close",
468 "Are you sure you want to close milestone ["
469 + ConnectJcrUtils.get(milestone, Property.JCR_TITLE) + "] ?");
470 try {
471 if (doIt) {
472 milestone.setProperty(ConnectNames.CONNECT_CLOSE_DATE, new GregorianCalendar());
473 milestone.setProperty(ConnectNames.CONNECT_CLOSED_BY, milestone.getSession().getUserID());
474 sectionPart.getSection().setText(getMilestoneTitle());
475 sectionPart.refresh();
476 sectionPart.markDirty();
477 sectionPart.getSection().setFocus();
478 }
479 } catch (RepositoryException e) {
480 throw new TrackerException("Cannot check session state on " + milestone, e);
481 }
482 }
483 }
484
485 private class AddTask extends Action {
486 private static final long serialVersionUID = 5112793747049604434L;
487 final Shell shell;
488
489 private AddTask(Shell shell, String name, ImageDescriptor img) {
490 super(name, img);
491 this.shell = shell;
492 }
493
494 @Override
495 public void run() {
496 Session session = ConnectJcrUtils.getSession(project);
497 String mainMixin = ConnectJcrUtils.isNodeType(project, TrackerTypes.TRACKER_IT_PROJECT)
498 ? TrackerTypes.TRACKER_ISSUE
499 : TrackerTypes.TRACKER_TASK;
500 String propName1 = TrackerNames.TRACKER_PROJECT_UID;
501 String value1 = ConnectJcrUtils.get(project, ConnectNames.CONNECT_UID);
502 String propName2 = TrackerNames.TRACKER_MILESTONE_UID;
503 String value2 = ConnectJcrUtils.get(milestone, ConnectNames.CONNECT_UID);
504
505 String pathCreated = ConnectWorkbenchUtils.createAndConfigureEntity(shell, session, getTrackerService(),
506 getAppWorkbenchService(), mainMixin, propName1, value1, propName2, value2);
507 if (EclipseUiUtils.notEmpty(pathCreated))
508 refreshViewer(filterTxt.getText());
509 }
510 }
511 }
512
513 @Override
514 public Object[] getElements(String extractId) {
515 return JcrUtils.nodeIteratorToList(getTasks()).toArray(new Node[0]);
516 }
517
518 public NodeIterator getTasks() {
519 String filter = filterTxt.getText();
520 try {
521 StringBuilder builder = new StringBuilder();
522 builder.append(XPathUtils.descendantFrom(project.getPath()));
523 builder.append("//element(*, ").append(TrackerTypes.TRACKER_TASK).append(")");
524
525 String milestoneCond = XPathUtils.getPropertyEquals(TrackerNames.TRACKER_MILESTONE_UID, milestoneUid);
526
527 String onlyMineCond = null;
528 if (onlyMineBtn.getSelection()) {
529 List<String> normalisedRoles = new ArrayList<>();
530 for (String role : CurrentUser.roles())
531 normalisedRoles.add(TrackerUtils.normalizeDn(role));
532 String[] nrArr = normalisedRoles.toArray(new String[0]);
533 StringBuilder tmpBuilder = new StringBuilder();
534 for (String role : nrArr) {
535 String attrQuery = XPathUtils.getPropertyEquals(ActivitiesNames.ACTIVITIES_ASSIGNED_TO, role);
536 tmpBuilder.append(attrQuery).append(" or ");
537 }
538 if (tmpBuilder.length() > 4)
539 onlyMineCond = "(" + tmpBuilder.substring(0, tmpBuilder.length() - 3) + ")";
540 }
541
542 String overdueCond = null;
543 if (overdueBtn.getSelection()) {
544 Calendar now = GregorianCalendar.getInstance();
545 overdueCond = XPathUtils.getPropertyDateComparaison(ACTIVITIES_DUE_DATE, now, "<");
546 }
547
548 String notClosedCond = null;
549 if (onlyOpenBtn.getSelection())
550 notClosedCond = "not(@" + ConnectNames.CONNECT_CLOSE_DATE + ")";
551
552 String ftcCond = null;
553 if (EclipseUiUtils.notEmpty(filter))
554 ftcCond = XPathUtils.getFreeTextConstraint(filter);
555
556 String fullCond = XPathUtils.localAnd(milestoneCond, overdueCond, notClosedCond, ftcCond, onlyMineCond);
557 builder.append("[").append(fullCond).append("]");
558 builder.append(" order by @" + TrackerNames.TRACKER_ID);
559
560 Query query = XPathUtils.createQuery(getSession(), builder.toString());
561 return query.execute().getNodes();
562 } catch (RepositoryException e) {
563 throw new TrackerException("Unable to get filtered tasks for " + milestone + " with filter: " + filter, e);
564 }
565 }
566
567 @Override
568 public List<ConnectColumnDefinition> getColumnDefinition(String extractId) {
569 List<ConnectColumnDefinition> columns = new ArrayList<ConnectColumnDefinition>();
570 columns.add(new ConnectColumnDefinition("ID", new SimpleJcrNodeLabelProvider(TrackerNames.TRACKER_ID)));
571 columns.add(
572 new ConnectColumnDefinition("Status", new JcrRowLabelProvider(ActivitiesNames.ACTIVITIES_TASK_STATUS)));
573 columns.add(new ConnectColumnDefinition("Title", new JcrRowLabelProvider(Property.JCR_TITLE)));
574 columns.add(new ConnectColumnDefinition("Description", new JcrRowLabelProvider(Property.JCR_DESCRIPTION)));
575 columns.add(new ConnectColumnDefinition("Assigned To",
576 new AssignedToLP(getActivitiesService(), null, Property.JCR_DESCRIPTION)));
577 columns.add(
578 new ConnectColumnDefinition("Due Date", new JcrRowLabelProvider(ActivitiesNames.ACTIVITIES_DUE_DATE)));
579 columns.add(new ConnectColumnDefinition("Importance", new TrackerLps().new ImportanceLabelProvider()));
580 columns.add(new ConnectColumnDefinition("Priority", new TrackerLps().new PriorityLabelProvider()));
581 columns.add(new ConnectColumnDefinition("Components",
582 new SimpleJcrNodeLabelProvider(TrackerNames.TRACKER_COMPONENT_IDS)));
583
584 columns.add(new ConnectColumnDefinition("Wake-Up Date",
585 new JcrRowLabelProvider(ActivitiesNames.ACTIVITIES_WAKE_UP_DATE)));
586 columns.add(
587 new ConnectColumnDefinition("Close Date", new JcrRowLabelProvider(ConnectNames.CONNECT_CLOSE_DATE)));
588 columns.add(new ConnectColumnDefinition("Closed by",
589 new UserNameLP(getUserAdminService(), null, ConnectNames.CONNECT_CLOSED_BY)));
590 return columns;
591 }
592
593
594
595 private String getMilestoneTitle() {
596 String id = ConnectJcrUtils.get(getNode(), TrackerNames.TRACKER_ID);
597 String name = ConnectJcrUtils.get(getNode(), Property.JCR_TITLE);
598
599 String title = null;
600 if (notEmpty(id) && notEmpty(id))
601 if (id.equals(name))
602 title = "v" + id;
603 else
604 title = "v" + id + " aka " + name;
605 else if (notEmpty(id))
606 title = "v" + id;
607 else
608 title = name;
609
610 if (notEmpty(title)) {
611 Node project = TrackerUtils.getProjectFromChild(getNode());
612 String pname = ConnectJcrUtils.get(project, Property.JCR_TITLE);
613 title = title + (notEmpty(pname) ? " (" + pname + ")" : "");
614 }
615
616 String closedBy = ConnectJcrUtils.get(milestone, ConnectNames.CONNECT_CLOSED_BY);
617 String closedOn = ConnectJcrUtils.getDateFormattedAsString(milestone, ConnectNames.CONNECT_CLOSE_DATE,
618 ConnectConstants.DEFAULT_DATE_TIME_FORMAT);
619
620 if (EclipseUiUtils.notEmpty(closedOn))
621 title += " closed on " + closedOn + " by " + getUserAdminService().getUserDisplayName(closedBy);
622 return title;
623 }
624
625
626
627
628
629
630
631
632
633
634 private void configureOpenLink(Link link, Node targetNode) {
635 link.setText("<a>" + ConnectJcrUtils.get(targetNode, Property.JCR_TITLE) + "</a>");
636
637
638 Listener[] existings = link.getListeners(SWT.Selection);
639 for (Listener l : existings)
640 link.removeListener(SWT.Selection, l);
641
642 link.addSelectionListener(new SelectionAdapter() {
643 private static final long serialVersionUID = 1L;
644
645 @Override
646 public void widgetSelected(SelectionEvent e) {
647
648
649 getAppWorkbenchService().openEntityEditor(targetNode);
650 }
651 });
652 }
653 }