View Javadoc
1   package org.argeo.tracker.e4.parts;
2   
3   import static org.argeo.activities.ActivitiesNames.ACTIVITIES_RELATED_TO;
4   import static org.argeo.eclipse.ui.EclipseUiUtils.notEmpty;
5   
6   import java.util.ArrayList;
7   import java.util.List;
8   
9   import javax.jcr.Node;
10  import javax.jcr.Property;
11  import javax.jcr.PropertyType;
12  import javax.jcr.RepositoryException;
13  import javax.jcr.Session;
14  import javax.jcr.Value;
15  
16  import org.argeo.activities.ActivitiesNames;
17  import org.argeo.cms.ui.CmsEditable;
18  import org.argeo.cms.ui.eclipse.forms.AbstractFormPart;
19  import org.argeo.cms.ui.eclipse.forms.IManagedForm;
20  import org.argeo.cms.util.CmsUtils;
21  import org.argeo.connect.ConnectConstants;
22  import org.argeo.connect.ui.ConnectImages;
23  import org.argeo.connect.ui.ConnectWorkbenchUtils;
24  import org.argeo.connect.util.ConnectJcrUtils;
25  import org.argeo.eclipse.ui.EclipseUiUtils;
26  import org.argeo.tracker.TrackerException;
27  import org.argeo.tracker.TrackerNames;
28  import org.argeo.tracker.TrackerTypes;
29  import org.argeo.tracker.core.TrackerUtils;
30  import org.argeo.tracker.ui.dialogs.ConfigureTaskWizard;
31  import org.eclipse.jface.action.Action;
32  import org.eclipse.jface.action.ToolBarManager;
33  import org.eclipse.jface.resource.ImageDescriptor;
34  import org.eclipse.jface.window.Window;
35  import org.eclipse.jface.wizard.WizardDialog;
36  import org.eclipse.swt.SWT;
37  import org.eclipse.swt.custom.ScrolledComposite;
38  import org.eclipse.swt.events.SelectionAdapter;
39  import org.eclipse.swt.events.SelectionEvent;
40  import org.eclipse.swt.layout.GridData;
41  import org.eclipse.swt.layout.GridLayout;
42  import org.eclipse.swt.layout.RowLayout;
43  import org.eclipse.swt.widgets.Combo;
44  import org.eclipse.swt.widgets.Composite;
45  import org.eclipse.swt.widgets.Label;
46  import org.eclipse.swt.widgets.Link;
47  import org.eclipse.swt.widgets.Listener;
48  import org.eclipse.swt.widgets.Shell;
49  
50  /** Default editor to display and edit a Tracker's task */
51  public class TaskEditor extends AbstractTrackerEditor implements CmsEditable {
52  	// private final static Log log = LogFactory.getLog(IssueEditor.class);
53  	// private static final long serialVersionUID = 1027157523552831925L;
54  	//
55  	// public static final String ID = TrackerUiPlugin.PLUGIN_ID + ".taskEditor";
56  
57  	// Context
58  	private Session session;
59  	private Node project;
60  	private Node task;
61  
62  	// public void init(IEditorSite site, IEditorInput input) throws
63  	// PartInitException {
64  	// super.init(site, input);
65  	// }
66  
67  	@Override
68  	protected void addPages() {
69  		// Initialise local cache to ease implementation
70  		task = getNode();
71  		session = ConnectJcrUtils.getSession(task);
72  		project = TrackerUtils.getRelatedProject(getAppService(), task);
73  		try {
74  			addPage(new TaskMainPage(this));
75  
76  			// if (CurrentUser.isInRole(NodeConstants.ROLE_ADMIN))
77  			// addPage(new TechnicalInfoPage(this, ID + ".techInfoPage", getNode()));
78  		} catch (Exception e) {
79  			throw new TrackerException("Cannot add pages for editor of " + getNode(), e);
80  		}
81  	}
82  
83  	// Specific pages
84  	private class TaskMainPage extends AbstractEditorPage {
85  		public final static String PAGE_ID = ".taskMainPage";
86  
87  		private Combo statusCmb;
88  		private Link projectLk;
89  		private Link milestoneLk;
90  		private Link dueDateLk;
91  		private Link reporterLk;
92  		private Link assignedToLk;
93  		private Composite relatedCmp;
94  		private Label descLbl;
95  
96  		public TaskMainPage(AbstractTrackerEditor editor) {
97  			super(editor, PAGE_ID, "Main");
98  		}
99  
100 		protected void createFormContentX(final IManagedForm mf) {
101 			// ScrolledForm form = mf.getForm();
102 			// Composite body = form.getBody();
103 			ScrolledComposite form = mf.getForm();
104 			Composite body = new Composite(form, SWT.NONE);
105 			GridLayout layout = new GridLayout();
106 			body.setLayout(layout);
107 			appendOverviewPartDebug(body);
108 
109 			// Composite commentFormPart = new CommentListFormPart(getManagedForm(), body,
110 			// SWT.NO_FOCUS,
111 			// getTrackerService(), getNode());
112 			// commentFormPart.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
113 		}
114 
115 		@Override
116 		protected void createFormContent(Composite body) {
117 			appendOverviewPart(body);
118 			Composite commentFormPart = new CommentListFormPart(getManagedForm(), body, SWT.NO_FOCUS,
119 					getTrackerService(), getNode());
120 			commentFormPart.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
121 		}
122 
123 		private void appendOverviewPartDebug(final Composite parent) {
124 			new Label(parent, SWT.NONE).setText("TEST");
125 
126 		}
127 
128 		/** Creates the general section */
129 		private void appendOverviewPart(final Composite parent) {
130 			// FormToolkit tk = getPageManagedForm().getToolkit();
131 
132 			// final Section section = TrackerUiUtils.addFormSection(tk, parent,
133 			// getIssueTitle());
134 			// section.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
135 			//
136 			// Composite body = (Composite) section.getClient();
137 			Composite body = new Composite(parent, SWT.NONE);
138 			GridLayout layout = new GridLayout();
139 			layout.numColumns = 2;
140 			body.setLayout(layout);
141 
142 			// Status
143 			createFormBoldLabel(body, "Status");
144 			statusCmb = new Combo(body, SWT.READ_ONLY);
145 			statusCmb.setLayoutData(new GridData(SWT.FILL, SWT.BOTTOM, true, false));
146 
147 			// Project
148 			createFormBoldLabel(body, "Project");
149 			projectLk = new Link(body, SWT.NONE);
150 			projectLk.setLayoutData(new GridData(SWT.FILL, SWT.BOTTOM, true, false));
151 			// configureOpenLink(projectLk, project);
152 
153 			// Target milestone
154 			createFormBoldLabel(body, "Milestone");
155 			milestoneLk = new Link(body, SWT.NONE);
156 			milestoneLk.setLayoutData(new GridData(SWT.FILL, SWT.BOTTOM, true, false));
157 
158 			// Assigned to
159 			createFormBoldLabel(body, "Assigned to");
160 			assignedToLk = new Link(body, SWT.NONE);
161 			assignedToLk.setLayoutData(new GridData(SWT.FILL, SWT.BOTTOM, false, false));
162 
163 			// Due Date
164 			createFormBoldLabel(body, "Due Date");
165 			dueDateLk = new Link(body, SWT.NONE);
166 			dueDateLk.setLayoutData(new GridData(SWT.FILL, SWT.BOTTOM, true, false));
167 
168 			// Reported by
169 			createFormBoldLabel(body, "Reported by");
170 			reporterLk = new Link(body, SWT.NONE);
171 			reporterLk.setLayoutData(new GridData(SWT.FILL, SWT.BOTTOM, true, false));
172 
173 			// Related entities
174 			createFormBoldLabel(body, "Related to");
175 			relatedCmp = new Composite(body, SWT.NO_FOCUS);
176 			GridData twd = new GridData(SWT.FILL, SWT.BOTTOM, true, false);
177 			// twd.colspan = 5;
178 			relatedCmp.setLayoutData(twd);
179 
180 			// TODO add linked documents
181 
182 			// Description
183 			twd = (GridData) createFormBoldLabel(body, "Details").getLayoutData();
184 			// twd.valign = GridData.TOP;
185 			descLbl = new Label(body, SWT.WRAP);
186 			twd = new GridData(SWT.FILL, SWT.TOP, true, false);
187 			// twd.colspan = 5;
188 			descLbl.setLayoutData(twd);
189 
190 			SectionPart part = new SectionPart(body.getParent()) {
191 
192 				@Override
193 				public void refresh() {
194 					// TODO Prevent edition for user without sufficient rights
195 					refreshStatusCombo(statusCmb, task);
196 					statusCmb.setText(ConnectJcrUtils.get(task, ActivitiesNames.ACTIVITIES_TASK_STATUS));
197 
198 					// Project cannot change
199 					// configureOpenLink(projectLk, project);
200 					Node milestone = TrackerUtils.getMilestone(getTrackerService(), task);
201 					if (milestone != null)
202 						configureOpenLink(milestoneLk, milestone);
203 
204 					String manager = getActivitiesService().getAssignedToDisplayName(task);
205 					String importance = TrackerUtils.getImportanceLabel(task);
206 					String priority = TrackerUtils.getPriorityLabel(task);
207 					String tmp = ConnectJcrUtils.concatIfNotEmpty(importance, priority, "/");
208 					if (EclipseUiUtils.notEmpty(tmp))
209 						manager += " (" + tmp + " )";
210 					// TODO make it clickable
211 					assignedToLk.setText(manager);
212 
213 					String dueDateStr = ConnectJcrUtils.getDateFormattedAsString(task,
214 							ActivitiesNames.ACTIVITIES_DUE_DATE, ConnectConstants.DEFAULT_DATE_TIME_FORMAT);
215 					if (EclipseUiUtils.notEmpty(dueDateStr))
216 						dueDateLk.setText(dueDateStr);
217 
218 					reporterLk.setText(TrackerUtils.getCreationLabel(getUserAdminService(), task));
219 
220 					try {
221 						List<Node> relatedTo = new ArrayList<>();
222 						if (task.hasProperty(ACTIVITIES_RELATED_TO)) {
223 							Value[] values = task.getProperty(ACTIVITIES_RELATED_TO).getValues();
224 							for (Value value : values) {
225 								String valueStr = value.getString();
226 								Node targetNode = task.getSession().getNodeByIdentifier(valueStr);
227 								relatedTo.add(targetNode);
228 							}
229 						}
230 						populateMultiValueClickableList(relatedCmp, relatedTo);
231 					} catch (RepositoryException re) {
232 						throw new TrackerException("Unable to refresh related to composite on " + task, re);
233 					}
234 
235 					String desc = ConnectJcrUtils.get(task, Property.JCR_DESCRIPTION);
236 					descLbl.setText(desc);
237 
238 					parent.layout(true, true);
239 					// section.setFocus();
240 					super.refresh();
241 				}
242 			};
243 			addStatusCmbSelListener(part, statusCmb, task, ActivitiesNames.ACTIVITIES_TASK_STATUS, PropertyType.STRING);
244 
245 			// addLongCmbSelListener(part, importanceCmb, task,
246 			// TrackerNames.TRACKER_IMPORTANCE,
247 			// TrackerUtils.MAPS_ISSUE_IMPORTANCES);
248 			// addLongCmbSelListener(part, priorityCmb, task,
249 			// TrackerNames.TRACKER_PRIORITY,
250 			// TrackerUtils.MAPS_ISSUE_PRIORITIES);
251 
252 			// addMilestoneDDFOListener(part, targetTxt, task);
253 			// addFocusOutListener(part, descTxt, task,
254 			// Property.JCR_DESCRIPTION);
255 			// addChangeAssignListener(part, assignedToLk);
256 
257 			part.initialize(getManagedForm());
258 			getManagedForm().addPart(part);
259 
260 			addMainSectionMenu(part);
261 		}
262 
263 		private void configureOpenLink(Link link, Node targetNode) {
264 			link.setText("<a>" + ConnectJcrUtils.get(targetNode, Property.JCR_TITLE) + "</a>");
265 
266 			// Remove existing if necessary
267 			Listener[] existings = link.getListeners(SWT.Selection);
268 			for (Listener l : existings)
269 				link.removeListener(SWT.Selection, l);
270 
271 			link.addSelectionListener(new SelectionAdapter() {
272 				private static final long serialVersionUID = 1L;
273 
274 				@Override
275 				public void widgetSelected(SelectionEvent e) {
276 					// CommandUtils.callCommand(getAppWorkbenchService().getOpenEntityEditorCmdId(),
277 					// ConnectEditor.PARAM_JCR_ID, ConnectJcrUtils.getIdentifier(targetNode));
278 					getAppWorkbenchService().openEntityEditor(targetNode);
279 				}
280 			});
281 		}
282 	}
283 
284 	private void populateMultiValueClickableList(Composite parent, List<Node> nodes) {
285 		CmsUtils.clear(parent);
286 		// GridData twd = ((GridData) parent.getLayoutData());
287 		// if (nodes == null || nodes.size() < 1) {
288 		// twd.heightHint = 0;
289 		// return;
290 		// } else
291 		// twd.heightHint = SWT.DEFAULT;
292 
293 		RowLayout rl = new RowLayout(SWT.HORIZONTAL);
294 		rl.wrap = true;
295 		rl.marginLeft = rl.marginTop = rl.marginBottom = 0;
296 		rl.marginRight = 8;
297 		parent.setLayout(rl);
298 
299 		for (Node node : nodes) {
300 			String value = ConnectJcrUtils.get(node, Property.JCR_TITLE);
301 			Link link = new Link(parent, SWT.NONE);
302 			CmsUtils.markup(link);
303 			link.setText(" <a>" + value + "</a>");
304 
305 			link.addSelectionListener(new SelectionAdapter() {
306 				private static final long serialVersionUID = 1L;
307 
308 				@Override
309 				public void widgetSelected(final SelectionEvent event) {
310 					// CommandUtils.callCommand(getAppWorkbenchService().getOpenEntityEditorCmdId(),
311 					// ConnectEditor.PARAM_JCR_ID, ConnectJcrUtils.getIdentifier(node));
312 					getAppWorkbenchService().openEntityEditor(node);
313 				}
314 			});
315 		}
316 	}
317 
318 	// SECTION MENU
319 	private void addMainSectionMenu(SectionPart sectionPart) {
320 		ToolBarManager toolBarManager = TrackerUiUtils.addMenu(sectionPart.getComposite());
321 		String tooltip = "Edit the task main information";
322 		Action action = new OpenConfigureDialog(tooltip, ConnectImages.IMG_DESC_EDIT, sectionPart);
323 		toolBarManager.add(action);
324 		toolBarManager.update(true);
325 	}
326 
327 	// MENU ACTIONS
328 	private class OpenConfigureDialog extends Action {
329 		private static final long serialVersionUID = -6798429720348536525L;
330 		private final SectionPart sectionPart;
331 
332 		private OpenConfigureDialog(String name, ImageDescriptor img, SectionPart sectionPart) {
333 			super(name, img);
334 			this.sectionPart = sectionPart;
335 		}
336 
337 		@Override
338 		public void run() {
339 			Shell currShell = sectionPart.getComposite().getShell();
340 			ConfigureTaskWizard wizard = new ConfigureTaskWizard(getUserAdminService(), getActivitiesService(),
341 					getTrackerService(), getAppWorkbenchService(), task);
342 			WizardDialog dialog = new WizardDialog(currShell, wizard);
343 			try {
344 				if (dialog.open() == Window.OK && task.getSession().hasPendingChanges()) {
345 					updatePartName();
346 					//sectionPart.getSection().setText(getIssueTitle());
347 					sectionPart.refresh();
348 					sectionPart.markDirty();
349 					sectionPart.getComposite().setFocus();
350 				}
351 			} catch (RepositoryException e) {
352 				throw new TrackerException("Cannot check session state on " + task, e);
353 			}
354 		}
355 	}
356 
357 	// LISTENERS
358 	private void addStatusCmbSelListener(final AbstractFormPart part, final Combo combo, final Node entity,
359 			final String propName, final int propType) {
360 		combo.addSelectionListener(new SelectionAdapter() {
361 			private static final long serialVersionUID = 1L;
362 
363 			@Override
364 			public void widgetSelected(SelectionEvent e) {
365 				int index = combo.getSelectionIndex();
366 				if (index != -1) {
367 					String selectedStatus = combo.getItem(index);
368 					try {
369 						if (getActivitiesService().updateStatus(TrackerTypes.TRACKER_TASK, task, selectedStatus,
370 								new ArrayList<String>()))
371 							part.markDirty();
372 					} catch (RepositoryException e1) {
373 						throw new TrackerException("Cannot update status to " + selectedStatus + " for " + task, e1);
374 					}
375 				}
376 			}
377 		});
378 	}
379 
380 	/** Override this to add specific rights for status change */
381 	private void refreshStatusCombo(Combo combo, Node currTask) {
382 //		List<String> values = getResourcesService().getTemplateCatalogue(session, ActivitiesTypes.ACTIVITIES_TASK,
383 //				ActivitiesNames.ACTIVITIES_TASK_STATUS, null);
384 		// FIXME Use resource catalogues
385 		List<String> values = new ArrayList<String>();
386 		values.add("In progress");
387 		values.add("Closed");
388 		combo.setItems(values.toArray(new String[values.size()]));
389 		ConnectWorkbenchUtils.refreshFormCombo(TaskEditor.this, combo, currTask,
390 				ActivitiesNames.ACTIVITIES_TASK_STATUS);
391 		combo.setEnabled(TaskEditor.this.isEditing());
392 	}
393 
394 	private String getIssueTitle() {
395 		String id = ConnectJcrUtils.get(getNode(), TrackerNames.TRACKER_ID);
396 		String name = ConnectJcrUtils.get(getNode(), Property.JCR_TITLE);
397 		if (notEmpty(name)) {
398 			Node project = TrackerUtils.getRelatedProject(getTrackerService(), getNode());
399 			String pname = ConnectJcrUtils.get(project, Property.JCR_TITLE);
400 			name = name + (notEmpty(pname) ? " (" + pname + ")" : "");
401 		}
402 		return "#" + id + " " + name;
403 	}
404 
405 	// private Label createFormBoldLabel(FormToolkit toolkit, Composite parent,
406 	// String value) {
407 	// // We add a blank space before to workaround the cropping of the
408 	// // word
409 	// // first letter in some OS/Browsers (typically MAC/Firefox 31 )
410 	// Label label = toolkit.createLabel(parent, " " + value, SWT.END);
411 	// label.setFont(EclipseUiUtils.getBoldFont(parent));
412 	// GridData twd = new GridData(SWT.END, SWT.BOTTOM);
413 	// label.setLayoutData(twd);
414 	// return label;
415 	// }
416 }