1 package org
.argeo
.suite
.e4
.parts
;
3 import java
.util
.ArrayList
;
4 import java
.util
.Calendar
;
5 import java
.util
.GregorianCalendar
;
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
;
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
.ActivitiesTypes
;
20 import org
.argeo
.activities
.ui
.TaskViewerContextMenu
;
21 import org
.argeo
.cms
.auth
.CurrentUser
;
22 import org
.argeo
.cms
.util
.CmsUtils
;
23 import org
.argeo
.connect
.ConnectException
;
24 import org
.argeo
.connect
.ConnectNames
;
25 import org
.argeo
.connect
.ui
.ConnectWorkbenchUtils
;
26 import org
.argeo
.connect
.ui
.Refreshable
;
27 import org
.argeo
.connect
.util
.ConnectJcrUtils
;
28 import org
.argeo
.eclipse
.ui
.EclipseUiUtils
;
29 import org
.argeo
.jcr
.JcrUtils
;
30 import org
.argeo
.node
.NodeUtils
;
31 import org
.argeo
.suite
.e4
.SuiteMsg
;
32 import org
.argeo
.tracker
.TrackerNames
;
33 import org
.argeo
.tracker
.TrackerService
;
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
.e4
.core
.di
.annotations
.Optional
;
38 import org
.eclipse
.jface
.viewers
.ColumnLabelProvider
;
39 import org
.eclipse
.jface
.viewers
.DoubleClickEvent
;
40 import org
.eclipse
.jface
.viewers
.IDoubleClickListener
;
41 import org
.eclipse
.jface
.viewers
.ILabelProvider
;
42 import org
.eclipse
.jface
.viewers
.IStructuredSelection
;
43 import org
.eclipse
.jface
.viewers
.TableViewer
;
44 import org
.eclipse
.swt
.SWT
;
45 import org
.eclipse
.swt
.events
.MouseAdapter
;
46 import org
.eclipse
.swt
.events
.MouseEvent
;
47 import org
.eclipse
.swt
.events
.SelectionAdapter
;
48 import org
.eclipse
.swt
.events
.SelectionEvent
;
49 import org
.eclipse
.swt
.graphics
.Color
;
50 import org
.eclipse
.swt
.graphics
.Point
;
51 import org
.eclipse
.swt
.layout
.GridData
;
52 import org
.eclipse
.swt
.layout
.GridLayout
;
53 import org
.eclipse
.swt
.layout
.RowLayout
;
54 import org
.eclipse
.swt
.widgets
.Composite
;
55 import org
.eclipse
.swt
.widgets
.Display
;
56 import org
.eclipse
.swt
.widgets
.Group
;
57 import org
.eclipse
.swt
.widgets
.Label
;
58 import org
.eclipse
.swt
.widgets
.Link
;
60 /** Argeo Suite Default Dashboard */
61 public class DefaultDashboardEditor
extends AbstractSuiteDashboard
implements Refreshable
{
62 final static Log log
= LogFactory
.getLog(DefaultDashboardEditor
.class);
63 // public final static String ID = AsUiPlugin.PLUGIN_ID +
64 // ".defaultDashboardEditor";
67 private ActivitiesService activitiesService
;
71 private TrackerService trackerService
;
73 private String datePattern
= "dd MMM yyyy";
75 private Composite headerCmp
;
76 private Composite taskListCmp
;
77 private TaskVirtualListComposite tvlc
;
80 public void createPartControl(Composite parent
) {
81 super.createPartControl(parent
);
82 parent
.setLayout(EclipseUiUtils
.noSpaceGridLayout());
83 Composite bodyCmp
= new Composite(parent
, SWT
.NO_FOCUS
);
84 bodyCmp
.setLayoutData(EclipseUiUtils
.fillAll());
85 bodyCmp
.setLayout(new GridLayout());
87 headerCmp
= new Composite(bodyCmp
, SWT
.NO_FOCUS
);
88 headerCmp
.setLayoutData(EclipseUiUtils
.fillWidth());
90 taskListCmp
= new Composite(bodyCmp
, SWT
.NO_FOCUS
);
91 taskListCmp
.setLayoutData(EclipseUiUtils
.fillAll());
96 public void forceRefresh(Object object
) {
97 CmsUtils
.clear(headerCmp
);
98 populateHeaderPart(headerCmp
, NodeUtils
.getUserHome(getSession()));
100 CmsUtils
.clear(taskListCmp
);
101 populateTaskListCmp(taskListCmp
);
103 headerCmp
.getParent().layout(true, true);
106 private void populateTaskListCmp(Composite parent
) {
107 parent
.setLayout(EclipseUiUtils
.noSpaceGridLayout());
108 NodeIterator nit
= activitiesService
.getMyTasks(getSession(), true);
109 if (!nit
.hasNext()) {
110 Composite noTaskCmp
= new Composite(parent
, SWT
.NO_FOCUS
);
111 noTaskCmp
.setLayoutData(EclipseUiUtils
.fillAll());
112 noTaskCmp
.setLayout(new GridLayout());
114 // Label noTaskLbl = new Label(noTaskCmp, SWT.CENTER);
115 // noTaskLbl.setText("<i> <big> You have no pending Task. </big> </i>");
116 // CmsUtils.markup(noTaskLbl);
117 // noTaskLbl.setLayoutData(new GridData(SWT.CENTER, SWT.BOTTOM, true, true));
120 TaskListLabelProvider labelProvider
= new TaskListLabelProvider(getSystemAppService());
121 tvlc
= new TaskVirtualListComposite(parent
, SWT
.NO_FOCUS
, (ILabelProvider
) labelProvider
, 54);
122 tvlc
.setLayoutData(EclipseUiUtils
.fillAll());
123 final TableViewer viewer
= tvlc
.getTableViewer();
124 viewer
.setInput(JcrUtils
.nodeIteratorToList(nit
).toArray());
125 final TaskViewerContextMenu contextMenu
= new TaskViewerContextMenu(viewer
, getSession(),
128 public boolean performAction(String actionId
) {
129 boolean hasChanged
= super.performAction(actionId
);
131 viewer
.getTable().setFocus();
133 // NodeIterator nit =
134 // activitiesService.getMyTasks(getSession(), true);
135 // viewer.setInput(JcrUtils.nodeIteratorToList(nit).toArray());
140 viewer
.getTable().addMouseListener(new MouseAdapter() {
141 private static final long serialVersionUID
= 6737579410648595940L;
144 public void mouseDown(MouseEvent e
) {
146 // contextMenu.setCurrFolderPath(currDisplayedFolder);
147 contextMenu
.show(viewer
.getTable(), new Point(e
.x
, e
.y
),
148 (IStructuredSelection
) viewer
.getSelection());
152 viewer
.addDoubleClickListener(new IDoubleClickListener() {
155 public void doubleClick(DoubleClickEvent event
) {
156 IStructuredSelection sel
= (IStructuredSelection
) viewer
.getSelection();
157 Node task
= (Node
) sel
.getFirstElement();
158 getSystemWorkbenchService().openEntityEditor(task
);
164 private boolean isOverdue(Node node
, String propName
) {
166 Calendar now
= GregorianCalendar
.getInstance();
167 return node
.hasProperty(propName
) && node
.getProperty(propName
).getDate().before(now
);
168 } catch (RepositoryException e
) {
169 throw new ConnectException("Cannot check overdue status with property " + propName
+ " on " + node
, e
);
173 private void populateHeaderPart(Composite bodyCmp
, Node context
) {
174 bodyCmp
.setLayout(EclipseUiUtils
.noSpaceGridLayout(new GridLayout(2, true)));
176 Composite leftCmp
= new Composite(bodyCmp
, SWT
.NO_FOCUS
);
177 leftCmp
.setLayout(new GridLayout());
178 leftCmp
.setLayoutData(EclipseUiUtils
.fillWidth());
179 Composite rightCmp
= new Composite(bodyCmp
, SWT
.NO_FOCUS
);
180 rightCmp
.setLayout(new GridLayout());
181 rightCmp
.setLayoutData(EclipseUiUtils
.fillWidth());
184 Label titleLbl
= new Label(leftCmp
, SWT
.WRAP
| SWT
.LEAD
);
185 CmsUtils
.markup(titleLbl
);
186 String titleStr
= "<big><b>" + CurrentUser
.getDisplayName() + "</b></big>";
187 titleLbl
.setText(titleStr
);
188 GridData gd
= new GridData(SWT
.BEGINNING
, SWT
.TOP
, false, false);
189 // gd.verticalIndent = 5;
190 // gd.horizontalIndent = 10;
191 titleLbl
.setLayoutData(gd
);
193 final Link createTaskLk
= new Link(leftCmp
, SWT
.CENTER
);
194 // createTaskLk.setText("<a>Create a task</a>");
195 createTaskLk
.setText("<a>" + SuiteMsg
.newTodo
.lead() + "</a>");
196 gd
= new GridData(SWT
.BEGINNING
, SWT
.TOP
, false, false);
197 // gd.verticalIndent = 5;
198 gd
.horizontalIndent
= 10;
199 createTaskLk
.setLayoutData(gd
);
201 createTaskLk
.addSelectionListener(new SelectionAdapter() {
202 private static final long serialVersionUID
= -9028457805156989935L;
205 public void widgetSelected(SelectionEvent e
) {
206 // String mainMixin = TrackerTypes.TRACKER_TASK;
207 String mainMixin
= ActivitiesTypes
.ACTIVITIES_TASK
;
208 String pathCreated
= ConnectWorkbenchUtils
.createAndConfigureEntity(createTaskLk
.getShell(),
209 getSession(), getSystemAppService(), getSystemWorkbenchService(), mainMixin
);
210 if (EclipseUiUtils
.notEmpty(pathCreated
))
215 NodeIterator nit
= activitiesService
.getMyTasks(getSession(), true);
217 List
<Node
> overdueTasks
= new ArrayList
<>();
218 while (nit
.hasNext()) {
219 Node currNode
= nit
.nextNode();
220 if (isOverdue(currNode
, ActivitiesNames
.ACTIVITIES_DUE_DATE
))
221 overdueTasks
.add(currNode
);
223 if (!overdueTasks
.isEmpty()) {
224 Composite overdueCmp
= new Composite(leftCmp
, SWT
.NO_FOCUS
);
225 long size
= overdueTasks
.size();
226 String overdueStr
= "You have " + size
+ " overdue task" + (size
> 1 ?
"s" : "") + ": ";
227 populateMuliValueClickableList(overdueCmp
, overdueTasks
.toArray(new Node
[0]), new TaskLp(), overdueStr
);
231 if (trackerService
!= null) {
232 nit
= trackerService
.getMyMilestones(getSession(), true);
233 List
<Node
> openMilestones
= new ArrayList
<>();
236 List
<Node
> overdueMilestones
= new ArrayList
<>();
237 while (nit
.hasNext()) {
238 Node currNode
= nit
.nextNode();
239 openMilestones
.add(currNode
);
240 if (isOverdue(currNode
, TrackerNames
.TRACKER_TARGET_DATE
))
241 overdueMilestones
.add(currNode
);
243 if (!overdueMilestones
.isEmpty()) {
244 Composite overdueCmp
= new Composite(leftCmp
, SWT
.NO_FOCUS
);
245 long size
= overdueMilestones
.size();
246 String overdueStr
= "You have " + size
+ " overdue milestone" + (size
> 1 ?
"s" : "") + ": ";
247 populateMuliValueClickableList(overdueCmp
, overdueMilestones
.toArray(new Node
[0]),
248 new MilestoneLp(), overdueStr
);
253 List
<Node
> openProjects
= JcrUtils
.nodeIteratorToList(trackerService
.getMyProjects(getSession(), true));
254 if (!openProjects
.isEmpty()) {
255 Group myProjectsGp
= new Group(rightCmp
, SWT
.NO_FOCUS
);
256 myProjectsGp
.setText("My open projects");
257 myProjectsGp
.setLayoutData(EclipseUiUtils
.fillWidth());
258 populateMuliValueClickableList(myProjectsGp
, openProjects
.toArray(new Node
[0]), new ProjectLp(), null);
262 if (!openMilestones
.isEmpty()) {
263 Group myMilestoneGp
= new Group(rightCmp
, SWT
.NO_FOCUS
);
264 myMilestoneGp
.setText("My open milestones");
265 myMilestoneGp
.setLayoutData(EclipseUiUtils
.fillWidth());
266 populateMuliValueClickableList(myMilestoneGp
, openMilestones
.toArray(new Node
[0]), new MilestoneLp(),
272 private class ProjectLp
extends ColumnLabelProvider
{
273 private static final long serialVersionUID
= 7231233932794865555L;
276 public String
getText(Object element
) {
277 Node project
= (Node
) element
;
280 NodeIterator nit
= TrackerUtils
.getIssues(project
, null, null, null, true);
281 long openNb
= nit
.getSize();
283 nit
= TrackerUtils
.getIssues(project
, null, null, null, false);
284 long allNb
= nit
.getSize();
289 double num
= allNb
- openNb
;
290 double result
= num
/ allNb
* 100;
291 percent
= String
.format("%.1f", result
) + "% done";
293 StringBuilder builder
= new StringBuilder();
294 builder
.append("<a>").append(ConnectJcrUtils
.get(project
, Property
.JCR_TITLE
)).append("</a>");
295 builder
.append(" (").append(percent
).append(")");
297 return builder
.toString();
301 private class MilestoneLp
extends ColumnLabelProvider
{
302 private static final long serialVersionUID
= 7231233932794865555L;
305 public String
getText(Object element
) {
306 Node milestone
= (Node
) element
;
307 Node project
= TrackerUtils
.getRelatedProject(trackerService
, milestone
);
308 String dueDate
= ConnectJcrUtils
.getDateFormattedAsString(milestone
, TrackerNames
.TRACKER_TARGET_DATE
,
312 String propName
= TrackerNames
.TRACKER_MILESTONE_UID
;
313 String muid
= ConnectJcrUtils
.get(milestone
, ConnectNames
.CONNECT_UID
);
314 NodeIterator nit
= TrackerUtils
.getIssues(project
, null, propName
, muid
, true);
315 long openNb
= nit
.getSize();
317 nit
= TrackerUtils
.getIssues(project
, null, propName
, muid
, false);
318 long allNb
= nit
.getSize();
323 double num
= allNb
- openNb
;
324 double result
= num
/ allNb
* 100;
325 percent
= String
.format("%.1f", result
) + "% done";
327 StringBuilder builder
= new StringBuilder();
328 builder
.append("<a>").append(ConnectJcrUtils
.get(milestone
, Property
.JCR_TITLE
)).append("</a>");
329 builder
.append(" (");
330 if (EclipseUiUtils
.notEmpty(dueDate
))
331 builder
.append("due to ").append(dueDate
).append(", ");
333 builder
.append(percent
).append(")");
334 return builder
.toString();
338 public Color
getForeground(Object element
) {
339 Node milestone
= (Node
) element
;
340 Calendar dueDate
= ConnectJcrUtils
.getDateValue(milestone
, TrackerNames
.TRACKER_TARGET_DATE
);
341 if (dueDate
!= null && dueDate
.before(Calendar
.getInstance()))
342 return Display
.getCurrent().getSystemColor(SWT
.COLOR_RED
);
347 private class TaskLp
extends ColumnLabelProvider
{
348 private static final long serialVersionUID
= 7231233932794865555L;
351 public String
getText(Object element
) {
352 Node task
= (Node
) element
;
353 String dueDate
= ConnectJcrUtils
.getDateFormattedAsString(task
, ActivitiesNames
.ACTIVITIES_DUE_DATE
,
356 StringBuilder builder
= new StringBuilder();
357 builder
.append("<a>").append(ConnectJcrUtils
.get(task
, Property
.JCR_TITLE
)).append("</a>");
358 if (EclipseUiUtils
.notEmpty(dueDate
))
359 builder
.append(" (").append("due to ").append(dueDate
).append(")");
360 return builder
.toString();
364 public Color
getForeground(Object element
) {
365 Node milestone
= (Node
) element
;
366 Calendar dueDate
= ConnectJcrUtils
.getDateValue(milestone
, TrackerNames
.TRACKER_TARGET_DATE
);
367 if (dueDate
!= null && dueDate
.before(Calendar
.getInstance()))
368 return Display
.getCurrent().getSystemColor(SWT
.COLOR_RED
);
373 // public void setActivitiesService(ActivitiesService activitiesService) {
374 // this.activitiesService = activitiesService;
377 // public void setTrackerService(TrackerService trackerService) {
378 // this.trackerService = trackerService;
382 private void populateMuliValueClickableList(Composite parent
, Node
[] nodes
, ColumnLabelProvider lp
,
384 CmsUtils
.clear(parent
);
385 RowLayout rl
= new RowLayout(SWT
.HORIZONTAL
| SWT
.WRAP
);
387 rl
.marginLeft
= rl
.marginTop
= rl
.marginBottom
= 0;
389 parent
.setLayout(rl
);
391 if (EclipseUiUtils
.notEmpty(listLabel
)) {
392 Link link
= new Link(parent
, SWT
.NONE
);
393 link
.setText(listLabel
);
394 link
.setFont(EclipseUiUtils
.getBoldFont(parent
));
398 for (Node node
: nodes
) {
399 Link link
= new Link(parent
, SWT
.NONE
);
400 CmsUtils
.markup(link
);
401 link
.setText(lp
.getText(node
) + (i
!= nodes
.length ?
", " : ""));
403 // Color fc = lp.getForeground(node);
405 // link.setForeground(fc);
407 link
.addSelectionListener(new SelectionAdapter() {
408 private static final long serialVersionUID
= 1L;
411 public void widgetSelected(final SelectionEvent event
) {
412 // CommandUtils.callCommand(getSystemWorkbenchService().getOpenEntityEditorCmdId(),
413 // ConnectEditor.PARAM_JCR_ID, ConnectJcrUtils.getIdentifier(node));
414 getSystemWorkbenchService().openEntityEditor(node
);