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