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