Remove core module
[gpl/argeo-suite.git] / org.argeo.suite.workbench.rap / src / org / argeo / suite / workbench / parts / DefaultDashboardEditor.java
1 package org.argeo.suite.workbench.parts;
2
3 import java.util.ArrayList;
4 import java.util.Calendar;
5 import java.util.GregorianCalendar;
6 import java.util.List;
7
8 import javax.jcr.Node;
9 import javax.jcr.NodeIterator;
10 import javax.jcr.Property;
11 import javax.jcr.RepositoryException;
12
13 import org.apache.commons.logging.Log;
14 import org.apache.commons.logging.LogFactory;
15 import org.argeo.activities.ActivitiesNames;
16 import org.argeo.activities.ActivitiesService;
17 import org.argeo.activities.workbench.parts.TaskViewerContextMenu;
18 import org.argeo.cms.auth.CurrentUser;
19 import org.argeo.cms.ui.workbench.util.CommandUtils;
20 import org.argeo.cms.util.CmsUtils;
21 import org.argeo.connect.ConnectNames;
22 import org.argeo.connect.ui.ConnectUiUtils;
23 import org.argeo.connect.util.ConnectJcrUtils;
24 import org.argeo.connect.workbench.Refreshable;
25 import org.argeo.connect.workbench.commands.OpenEntityEditor;
26 import org.argeo.eclipse.ui.EclipseUiUtils;
27 import org.argeo.jcr.JcrUtils;
28 import org.argeo.node.NodeUtils;
29 import org.argeo.suite.workbench.SuiteWorkbenchException;
30 import org.argeo.suite.workbench.AsUiPlugin;
31 import org.argeo.tracker.TrackerNames;
32 import org.argeo.tracker.TrackerService;
33 import org.argeo.tracker.TrackerTypes;
34 import org.argeo.tracker.core.TrackerUtils;
35 import org.argeo.tracker.ui.TaskListLabelProvider;
36 import org.argeo.tracker.ui.TaskVirtualListComposite;
37 import org.eclipse.jface.viewers.ColumnLabelProvider;
38 import org.eclipse.jface.viewers.IStructuredSelection;
39 import org.eclipse.jface.viewers.TableViewer;
40 import org.eclipse.swt.SWT;
41 import org.eclipse.swt.events.MouseAdapter;
42 import org.eclipse.swt.events.MouseEvent;
43 import org.eclipse.swt.events.SelectionAdapter;
44 import org.eclipse.swt.events.SelectionEvent;
45 import org.eclipse.swt.graphics.Color;
46 import org.eclipse.swt.graphics.Point;
47 import org.eclipse.swt.layout.GridData;
48 import org.eclipse.swt.layout.GridLayout;
49 import org.eclipse.swt.layout.RowLayout;
50 import org.eclipse.swt.widgets.Composite;
51 import org.eclipse.swt.widgets.Display;
52 import org.eclipse.swt.widgets.Group;
53 import org.eclipse.swt.widgets.Label;
54 import org.eclipse.swt.widgets.Link;
55
56 /** Argeo Suite Default Dashboard */
57 public class DefaultDashboardEditor extends AbstractSuiteDashboard implements Refreshable {
58 final static Log log = LogFactory.getLog(DefaultDashboardEditor.class);
59 public final static String ID = AsUiPlugin.PLUGIN_ID + ".defaultDashboardEditor";
60
61 private ActivitiesService activitiesService;
62 private TrackerService trackerService;
63
64 private String datePattern = "dd MMM yyyy";
65
66 private Composite headerCmp;
67 private Composite taskListCmp;
68 private TaskVirtualListComposite tvlc;
69
70 @Override
71 public void createPartControl(Composite parent) {
72 super.createPartControl(parent);
73 parent.setLayout(EclipseUiUtils.noSpaceGridLayout());
74 Composite bodyCmp = new Composite(parent, SWT.NO_FOCUS);
75 bodyCmp.setLayoutData(EclipseUiUtils.fillAll());
76 bodyCmp.setLayout(new GridLayout());
77
78 headerCmp = new Composite(bodyCmp, SWT.NO_FOCUS);
79 headerCmp.setLayoutData(EclipseUiUtils.fillWidth());
80
81 taskListCmp = new Composite(bodyCmp, SWT.NO_FOCUS);
82 taskListCmp.setLayoutData(EclipseUiUtils.fillAll());
83 forceRefresh(null);
84 }
85
86 @Override
87 public void forceRefresh(Object object) {
88 CmsUtils.clear(headerCmp);
89 populateHeaderPart(headerCmp, NodeUtils.getUserHome(getSession()));
90
91 CmsUtils.clear(taskListCmp);
92 populateTaskListCmp(taskListCmp);
93
94 headerCmp.getParent().layout(true, true);
95 }
96
97 private void populateTaskListCmp(Composite parent) {
98 parent.setLayout(EclipseUiUtils.noSpaceGridLayout());
99 NodeIterator nit = activitiesService.getMyTasks(getSession(), true);
100 if (!nit.hasNext()) {
101 Composite noTaskCmp = new Composite(parent, SWT.NO_FOCUS);
102 noTaskCmp.setLayoutData(EclipseUiUtils.fillAll());
103 noTaskCmp.setLayout(new GridLayout());
104
105 Label noTaskLbl = new Label(noTaskCmp, SWT.CENTER);
106 noTaskLbl.setText("<i> <big> You have no pending Task. </big> </i>");
107 CmsUtils.markup(noTaskLbl);
108 noTaskLbl.setLayoutData(new GridData(SWT.CENTER, SWT.BOTTOM, true, true));
109
110 final Link createTaskLk = new Link(noTaskCmp, SWT.CENTER);
111 createTaskLk.setText("<a> Create a task </a>");
112 createTaskLk.setLayoutData(new GridData(SWT.CENTER, SWT.TOP, true, true));
113
114 createTaskLk.addSelectionListener(new SelectionAdapter() {
115 private static final long serialVersionUID = -9028457805156989935L;
116
117 @Override
118 public void widgetSelected(SelectionEvent e) {
119 String mainMixin = TrackerTypes.TRACKER_TASK;
120 String pathCreated = ConnectUiUtils.createAndConfigureEntity(createTaskLk.getShell(), getSession(),
121 getSystemAppService(), getSystemWorkbenchService(), mainMixin);
122 if (EclipseUiUtils.notEmpty(pathCreated))
123 forceRefresh(null);
124 }
125 });
126
127 } else {
128 TaskListLabelProvider labelProvider = new TaskListLabelProvider(trackerService);
129 tvlc = new TaskVirtualListComposite(parent, SWT.NO_FOCUS, labelProvider, 54);
130 tvlc.setLayoutData(EclipseUiUtils.fillAll());
131 final TableViewer viewer = tvlc.getTableViewer();
132 viewer.setInput(JcrUtils.nodeIteratorToList(nit).toArray());
133 final TaskViewerContextMenu contextMenu = new TaskViewerContextMenu(viewer, getSession(),
134 activitiesService) {
135 private static final long serialVersionUID = 1640863021424194303L;
136
137 @Override
138 public boolean performAction(String actionId) {
139 boolean hasChanged = super.performAction(actionId);
140 if (hasChanged) {
141 viewer.getTable().setFocus();
142 forceRefresh(null);
143 // NodeIterator nit =
144 // activitiesService.getMyTasks(getSession(), true);
145 // viewer.setInput(JcrUtils.nodeIteratorToList(nit).toArray());
146 }
147 return hasChanged;
148 }
149 };
150 viewer.getTable().addMouseListener(new MouseAdapter() {
151 private static final long serialVersionUID = 6737579410648595940L;
152
153 @Override
154 public void mouseDown(MouseEvent e) {
155 if (e.button == 3) {
156 // contextMenu.setCurrFolderPath(currDisplayedFolder);
157 contextMenu.show(viewer.getTable(), new Point(e.x, e.y),
158 (IStructuredSelection) viewer.getSelection());
159 }
160 }
161 });
162
163 }
164 }
165
166 private boolean isOverdue(Node node, String propName) {
167 try {
168 Calendar now = GregorianCalendar.getInstance();
169 return node.hasProperty(propName) && node.getProperty(propName).getDate().before(now);
170 } catch (RepositoryException e) {
171 throw new SuiteWorkbenchException("Cannot check overdue status with property " + propName + " on " + node, e);
172 }
173 }
174
175 private void populateHeaderPart(Composite bodyCmp, Node context) {
176 bodyCmp.setLayout(EclipseUiUtils.noSpaceGridLayout(new GridLayout(2, true)));
177
178 Composite leftCmp = new Composite(bodyCmp, SWT.NO_FOCUS);
179 leftCmp.setLayout(new GridLayout());
180 leftCmp.setLayoutData(EclipseUiUtils.fillWidth());
181 Composite rightCmp = new Composite(bodyCmp, SWT.NO_FOCUS);
182 rightCmp.setLayout(new GridLayout());
183 rightCmp.setLayoutData(EclipseUiUtils.fillWidth());
184
185 // Title
186 Label titleLbl = new Label(leftCmp, SWT.WRAP | SWT.LEAD);
187 CmsUtils.markup(titleLbl);
188 String titleStr = "<big><b> Hello " + CurrentUser.getDisplayName() + " </b></big>";
189 titleLbl.setText(titleStr);
190 GridData gd = new GridData(SWT.TOP, SWT.BOTTOM, false, false);
191 gd.verticalIndent = 5;
192 gd.horizontalIndent = 10;
193 titleLbl.setLayoutData(gd);
194
195 NodeIterator nit = activitiesService.getMyTasks(getSession(), true);
196 if (nit.hasNext()) {
197 List<Node> overdueTasks = new ArrayList<>();
198 while (nit.hasNext()) {
199 Node currNode = nit.nextNode();
200 if (isOverdue(currNode, ActivitiesNames.ACTIVITIES_DUE_DATE))
201 overdueTasks.add(currNode);
202 }
203 if (!overdueTasks.isEmpty()) {
204 Composite overdueCmp = new Composite(leftCmp, SWT.NO_FOCUS);
205 long size = overdueTasks.size();
206 String overdueStr = "You have " + size + " overdue task" + (size > 1 ? "s" : "") + ": ";
207 populateMuliValueClickableList(overdueCmp, overdueTasks.toArray(new Node[0]), new TaskLp(), overdueStr);
208 }
209 }
210
211 nit = trackerService.getMyMilestones(getSession(), true);
212 List<Node> openMilestones = new ArrayList<>();
213
214 if (nit.hasNext()) {
215 List<Node> overdueMilestones = new ArrayList<>();
216 while (nit.hasNext()) {
217 Node currNode = nit.nextNode();
218 openMilestones.add(currNode);
219 if (isOverdue(currNode, TrackerNames.TRACKER_TARGET_DATE))
220 overdueMilestones.add(currNode);
221 }
222 if (!overdueMilestones.isEmpty()) {
223 Composite overdueCmp = new Composite(leftCmp, SWT.NO_FOCUS);
224 long size = overdueMilestones.size();
225 String overdueStr = "You have " + size + " overdue milestone" + (size > 1 ? "s" : "") + ": ";
226 populateMuliValueClickableList(overdueCmp, overdueMilestones.toArray(new Node[0]), new MilestoneLp(),
227 overdueStr);
228 }
229 }
230
231 // My projects
232 List<Node> openProjects = JcrUtils.nodeIteratorToList(trackerService.getMyProjects(getSession(), true));
233 if (!openProjects.isEmpty()) {
234 Group myProjectsGp = new Group(rightCmp, SWT.NO_FOCUS);
235 myProjectsGp.setText("My open projects");
236 myProjectsGp.setLayoutData(EclipseUiUtils.fillWidth());
237 populateMuliValueClickableList(myProjectsGp, openProjects.toArray(new Node[0]), new ProjectLp(), null);
238 }
239
240 // My Milestones
241 if (!openMilestones.isEmpty()) {
242 Group myMilestoneGp = new Group(rightCmp, SWT.NO_FOCUS);
243 myMilestoneGp.setText("My open milestones");
244 myMilestoneGp.setLayoutData(EclipseUiUtils.fillWidth());
245 populateMuliValueClickableList(myMilestoneGp, openMilestones.toArray(new Node[0]), new MilestoneLp(), null);
246 }
247 }
248
249 private class ProjectLp extends ColumnLabelProvider {
250 private static final long serialVersionUID = 7231233932794865555L;
251
252 @Override
253 public String getText(Object element) {
254 Node project = (Node) element;
255
256 String percent;
257 NodeIterator nit = TrackerUtils.getIssues(project, null, null, null, true);
258 long openNb = nit.getSize();
259
260 nit = TrackerUtils.getIssues(project, null, null, null, false);
261 long allNb = nit.getSize();
262
263 if (allNb < 1)
264 percent = "empty";
265 else {
266 double num = allNb - openNb;
267 double result = num / allNb * 100;
268 percent = String.format("%.1f", result) + "% done";
269 }
270 StringBuilder builder = new StringBuilder();
271 builder.append("<a>").append(ConnectJcrUtils.get(project, Property.JCR_TITLE)).append("</a>");
272 builder.append(" (").append(percent).append(")");
273
274 return builder.toString();
275 }
276 }
277
278 private class MilestoneLp extends ColumnLabelProvider {
279 private static final long serialVersionUID = 7231233932794865555L;
280
281 @Override
282 public String getText(Object element) {
283 Node milestone = (Node) element;
284 Node project = TrackerUtils.getRelatedProject(trackerService, milestone);
285 String dueDate = ConnectJcrUtils.getDateFormattedAsString(milestone, TrackerNames.TRACKER_TARGET_DATE,
286 datePattern);
287
288 String percent;
289 String propName = TrackerNames.TRACKER_MILESTONE_UID;
290 String muid = ConnectJcrUtils.get(milestone, ConnectNames.CONNECT_UID);
291 NodeIterator nit = TrackerUtils.getIssues(project, null, propName, muid, true);
292 long openNb = nit.getSize();
293
294 nit = TrackerUtils.getIssues(project, null, propName, muid, false);
295 long allNb = nit.getSize();
296
297 if (allNb < 1)
298 percent = "empty";
299 else {
300 double num = allNb - openNb;
301 double result = num / allNb * 100;
302 percent = String.format("%.1f", result) + "% done";
303 }
304 StringBuilder builder = new StringBuilder();
305 builder.append("<a>").append(ConnectJcrUtils.get(milestone, Property.JCR_TITLE)).append("</a>");
306 builder.append(" (");
307 if (EclipseUiUtils.notEmpty(dueDate))
308 builder.append("due to ").append(dueDate).append(", ");
309
310 builder.append(percent).append(")");
311 return builder.toString();
312 }
313
314 @Override
315 public Color getForeground(Object element) {
316 Node milestone = (Node) element;
317 Calendar dueDate = ConnectJcrUtils.getDateValue(milestone, TrackerNames.TRACKER_TARGET_DATE);
318 if (dueDate != null && dueDate.before(Calendar.getInstance()))
319 return Display.getCurrent().getSystemColor(SWT.COLOR_RED);
320 return null;
321 }
322 }
323
324 private class TaskLp extends ColumnLabelProvider {
325 private static final long serialVersionUID = 7231233932794865555L;
326
327 @Override
328 public String getText(Object element) {
329 Node task = (Node) element;
330 String dueDate = ConnectJcrUtils.getDateFormattedAsString(task, ActivitiesNames.ACTIVITIES_DUE_DATE,
331 datePattern);
332
333 StringBuilder builder = new StringBuilder();
334 builder.append("<a>").append(ConnectJcrUtils.get(task, Property.JCR_TITLE)).append("</a>");
335 if (EclipseUiUtils.notEmpty(dueDate))
336 builder.append(" (").append("due to ").append(dueDate).append(")");
337 return builder.toString();
338 }
339
340 @Override
341 public Color getForeground(Object element) {
342 Node milestone = (Node) element;
343 Calendar dueDate = ConnectJcrUtils.getDateValue(milestone, TrackerNames.TRACKER_TARGET_DATE);
344 if (dueDate != null && dueDate.before(Calendar.getInstance()))
345 return Display.getCurrent().getSystemColor(SWT.COLOR_RED);
346 return null;
347 }
348 }
349
350 @Override
351 public void setFocus() {
352 // refreshDocListGadget();
353 }
354
355 public void setActivitiesService(ActivitiesService activitiesService) {
356 this.activitiesService = activitiesService;
357 }
358
359 public void setTrackerService(TrackerService trackerService) {
360 this.trackerService = trackerService;
361 }
362
363 // LOCAL HELPERS
364 private void populateMuliValueClickableList(Composite parent, Node[] nodes, ColumnLabelProvider lp,
365 String listLabel) {
366 CmsUtils.clear(parent);
367 RowLayout rl = new RowLayout(SWT.HORIZONTAL | SWT.WRAP);
368 rl.wrap = true;
369 rl.marginLeft = rl.marginTop = rl.marginBottom = 0;
370 rl.marginRight = 8;
371 parent.setLayout(rl);
372
373 if (EclipseUiUtils.notEmpty(listLabel)) {
374 Link link = new Link(parent, SWT.NONE);
375 link.setText(listLabel);
376 link.setFont(EclipseUiUtils.getBoldFont(parent));
377 }
378
379 int i = 1;
380 for (Node node : nodes) {
381 Link link = new Link(parent, SWT.NONE);
382 CmsUtils.markup(link);
383 link.setText(lp.getText(node) + (i != nodes.length ? ", " : ""));
384 i++;
385 // Color fc = lp.getForeground(node);
386 // if (fc != null)
387 // link.setForeground(fc);
388
389 link.addSelectionListener(new SelectionAdapter() {
390 private static final long serialVersionUID = 1L;
391
392 @Override
393 public void widgetSelected(final SelectionEvent event) {
394 CommandUtils.callCommand(getSystemWorkbenchService().getOpenEntityEditorCmdId(),
395 OpenEntityEditor.PARAM_JCR_ID, ConnectJcrUtils.getIdentifier(node));
396 }
397 });
398 }
399 }
400
401 }