1 package org.argeo.tracker.e4.parts;
2
3 import static org.argeo.eclipse.ui.EclipseUiUtils.notEmpty;
4
5 import java.util.ArrayList;
6 import java.util.List;
7
8 import javax.jcr.Node;
9 import javax.jcr.Property;
10 import javax.jcr.PropertyType;
11 import javax.jcr.RepositoryException;
12 import javax.jcr.Session;
13 import javax.jcr.Value;
14
15 import org.argeo.activities.ActivitiesNames;
16 import org.argeo.cms.ui.CmsEditable;
17 import org.argeo.cms.ui.eclipse.forms.AbstractFormPart;
18 import org.argeo.cms.ui.eclipse.forms.FormToolkit;
19 import org.argeo.cms.ui.eclipse.forms.IManagedForm;
20 import org.argeo.cms.util.CmsUtils;
21 import org.argeo.connect.ui.ConnectImages;
22 import org.argeo.connect.ui.ConnectWorkbenchUtils;
23 import org.argeo.connect.util.ConnectJcrUtils;
24 import org.argeo.eclipse.ui.EclipseUiUtils;
25 import org.argeo.tracker.TrackerException;
26 import org.argeo.tracker.TrackerNames;
27 import org.argeo.tracker.TrackerTypes;
28 import org.argeo.tracker.core.TrackerUtils;
29 import org.argeo.tracker.ui.dialogs.ConfigureIssueWizard;
30 import org.eclipse.jface.action.Action;
31 import org.eclipse.jface.action.ToolBarManager;
32 import org.eclipse.jface.resource.ImageDescriptor;
33 import org.eclipse.jface.window.Window;
34 import org.eclipse.jface.wizard.WizardDialog;
35 import org.eclipse.swt.SWT;
36 import org.eclipse.swt.custom.ScrolledComposite;
37 import org.eclipse.swt.events.SelectionAdapter;
38 import org.eclipse.swt.events.SelectionEvent;
39 import org.eclipse.swt.layout.GridData;
40 import org.eclipse.swt.layout.GridLayout;
41 import org.eclipse.swt.layout.RowLayout;
42 import org.eclipse.swt.widgets.Combo;
43 import org.eclipse.swt.widgets.Composite;
44 import org.eclipse.swt.widgets.Label;
45 import org.eclipse.swt.widgets.Link;
46 import org.eclipse.swt.widgets.Listener;
47 import org.eclipse.swt.widgets.Shell;
48
49
50 public class IssueEditor extends AbstractTrackerEditor implements CmsEditable {
51
52
53
54
55
56
57 private Session session;
58 private Node issue;
59 private Node project;
60
61
62
63
64
65
66 @Override
67 protected void addPages() {
68
69 issue = getNode();
70 session = ConnectJcrUtils.getSession(issue);
71 project = TrackerUtils.getRelatedProject(getTrackerService(), issue);
72 try {
73 addPage(new IssueMainPage(this));
74
75
76
77 } catch (Exception e) {
78 throw new TrackerException("Cannot add pages for editor of " + getNode(), e);
79 }
80 }
81
82
83 protected void updatePartName() {
84 String name = getIssueTitle();
85 if (notEmpty(name))
86 setPartName(name);
87 else
88 super.updatePartName();
89 }
90
91 @Override
92 public Boolean canEdit() {
93 return true;
94 }
95
96 @Override
97 public Boolean isEditing() {
98 return true;
99 }
100
101 @Override
102 public void startEditing() {
103 }
104
105 @Override
106 public void stopEditing() {
107 }
108
109
110 private class IssueMainPage extends AbstractEditorPage {
111 public final static String PAGE_ID = "issueMainPage";
112
113 private Combo statusCmb;
114 private Link projectLk;
115 private Link milestoneLk;
116 private Link assignedToLk;
117 private Composite versionsCmp;
118 private Composite componentsCmp;
119
120
121 private Label descLbl;
122
123 public IssueMainPage(AbstractTrackerEditor editor) {
124 super(editor, PAGE_ID, "Main");
125 }
126
127 protected void createFormContent(final IManagedForm mf) {
128 ScrolledComposite form = mf.getForm();
129 Composite body = new Composite(form, SWT.NONE);
130 GridLayout layout = new GridLayout();
131 body.setLayout(layout);
132 appendOverviewPart(body);
133
134 Composite commentFormPart = new CommentListFormPart(getPageManagedForm(), body, SWT.NO_FOCUS,
135 getTrackerService(), getNode());
136 commentFormPart.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
137 }
138
139
140 private void appendOverviewPart(Composite parent) {
141 FormToolkit tk = getPageManagedForm().getToolkit();
142
143 final Section section = TrackerUiUtils.addFormSection(tk, parent, getIssueTitle());
144 section.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
145
146 Composite body = (Composite) section.getClient();
147 GridLayout layout = new GridLayout();
148 layout.numColumns = 6;
149 body.setLayout(layout);
150
151
152 createFormBoldLabel(tk, body, "Status");
153 statusCmb = new Combo(body, SWT.READ_ONLY);
154 statusCmb.setLayoutData(new GridData(SWT.FILL, SWT.BOTTOM));
155
156
157 createFormBoldLabel(tk, body, "Project");
158 projectLk = new Link(body, SWT.NONE);
159 projectLk.setLayoutData(new GridData(SWT.FILL, SWT.BOTTOM, true, false));
160 configureOpenLink(projectLk, project);
161
162
163 createFormBoldLabel(tk, body, "Target milestone");
164 milestoneLk = new Link(body, SWT.NONE);
165 milestoneLk.setLayoutData(new GridData(SWT.FILL, SWT.BOTTOM, true, false));
166
167
168 createFormBoldLabel(tk, body, "Assigned to");
169 assignedToLk = new Link(body, SWT.NONE);
170 assignedToLk.setLayoutData(new GridData(SWT.FILL, SWT.BOTTOM));
171
172
173 TrackerUiUtils.createFormBoldLabel(tk, body, "Impacted versions");
174 versionsCmp = new Composite(body, SWT.NO_FOCUS);
175 versionsCmp.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
176
177
178 TrackerUiUtils.createFormBoldLabel(tk, body, "Related components");
179 componentsCmp = new Composite(body, SWT.NO_FOCUS);
180 componentsCmp.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
181
182
183
184
185 GridData twd = (GridData) TrackerUiUtils.createFormBoldLabel(tk, body, "Details").getLayoutData();
186
187 descLbl = new Label(body, SWT.WRAP);
188 twd = new GridData(SWT.FILL, SWT.TOP, true, false);
189
190 descLbl.setLayoutData(twd);
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209 SectionPart part = new SectionPart((Section) body.getParent()) {
210
211 @Override
212 public void refresh() {
213 refreshStatusCombo(statusCmb, issue);
214 statusCmb.setText(ConnectJcrUtils.get(issue, ActivitiesNames.ACTIVITIES_TASK_STATUS));
215
216 Node milestone = TrackerUtils.getMilestone(getTrackerService(), issue);
217 if (milestone != null)
218 configureOpenLink(milestoneLk, milestone);
219
220 String manager = getActivitiesService().getAssignedToDisplayName(issue);
221 String importance = TrackerUtils.getImportanceLabel(issue);
222 String priority = TrackerUtils.getPriorityLabel(issue);
223 String tmp = ConnectJcrUtils.concatIfNotEmpty(importance, priority, "/");
224 if (EclipseUiUtils.notEmpty(tmp))
225 manager += " (" + tmp + " )";
226
227 assignedToLk.setText(manager);
228
229
230 List<Node> nodes = new ArrayList<Node>();
231 try {
232 if (issue.hasProperty(TrackerNames.TRACKER_VERSION_IDS)) {
233 Value[] values = issue.getProperty(TrackerNames.TRACKER_VERSION_IDS).getValues();
234 for (int i = 0; i < values.length; i++) {
235 Node version = TrackerUtils.getVersionById(project, values[i].getString());
236 if (version != null)
237 nodes.add(version);
238 }
239 }
240
241 populateMuliValueClickableList(versionsCmp, nodes.toArray(new Node[0]));
242
243
244 nodes = new ArrayList<Node>();
245 if (issue.hasProperty(TrackerNames.TRACKER_COMPONENT_IDS)) {
246 Value[] values = issue.getProperty(TrackerNames.TRACKER_COMPONENT_IDS).getValues();
247 for (int i = 0; i < values.length; i++) {
248 Node component = TrackerUtils.getComponentById(project, values[i].getString());
249 if (component != null)
250 nodes.add(component);
251 }
252 }
253
254 populateMuliValueClickableList(componentsCmp, nodes.toArray(new Node[0]));
255
256 } catch (RepositoryException e) {
257 throw new TrackerException("Cannot update info for " + issue, e);
258 }
259
260 String desc = ConnectJcrUtils.get(issue, Property.JCR_DESCRIPTION);
261 descLbl.setText(desc);
262
263 parent.layout(true, true);
264 section.setFocus();
265 super.refresh();
266 }
267 };
268 addStatusCmbSelListener(part, statusCmb, issue, ActivitiesNames.ACTIVITIES_TASK_STATUS,
269 PropertyType.STRING);
270
271 getPageManagedForm().addPart(part);
272 addMainSectionMenu(part);
273 }
274
275 }
276
277
278 private void addMainSectionMenu(SectionPart sectionPart) {
279 ToolBarManager toolBarManager = TrackerUiUtils.addMenu(sectionPart.getSection());
280 String tooltip = "Edit this issue main information";
281 Action action = new OpenConfigureDialog(tooltip, ConnectImages.IMG_DESC_EDIT, sectionPart);
282 toolBarManager.add(action);
283 toolBarManager.update(true);
284 }
285
286
287 private class OpenConfigureDialog extends Action {
288 private static final long serialVersionUID = -6798429720348536525L;
289 private final SectionPart sectionPart;
290
291 private OpenConfigureDialog(String name, ImageDescriptor img, SectionPart sectionPart) {
292 super(name, img);
293 this.sectionPart = sectionPart;
294 }
295
296 @Override
297 public void run() {
298 Shell currShell = sectionPart.getSection().getShell();
299 ConfigureIssueWizard wizard = new ConfigureIssueWizard(getUserAdminService(), getTrackerService(), issue);
300 WizardDialog dialog = new WizardDialog(currShell, wizard);
301 try {
302 if (dialog.open() == Window.OK && issue.getSession().hasPendingChanges()) {
303 updatePartName();
304 sectionPart.getSection().setText(getIssueTitle());
305 sectionPart.refresh();
306 sectionPart.markDirty();
307 sectionPart.getSection().setFocus();
308 }
309 } catch (RepositoryException e) {
310 throw new TrackerException("Cannot check session state on " + issue, e);
311 }
312 }
313 }
314
315
316 private void addStatusCmbSelListener(final AbstractFormPart part, final Combo combo, final Node entity,
317 final String propName, final int propType) {
318 combo.addSelectionListener(new SelectionAdapter() {
319 private static final long serialVersionUID = 1L;
320
321 @Override
322 public void widgetSelected(SelectionEvent e) {
323 int index = combo.getSelectionIndex();
324 if (index != -1) {
325 String selectedStatus = combo.getItem(index);
326 try {
327 if (getActivitiesService().updateStatus(TrackerTypes.TRACKER_ISSUE, issue, selectedStatus,
328 new ArrayList<String>()))
329 part.markDirty();
330 } catch (RepositoryException e1) {
331 throw new TrackerException("Cannot update status to " + selectedStatus + " for " + issue, e1);
332 }
333 }
334 }
335 });
336 }
337
338
339 protected void refreshStatusCombo(Combo combo, Node currTask) {
340 List<String> values = getResourcesService().getTemplateCatalogue(session, TrackerTypes.TRACKER_ISSUE,
341 ActivitiesNames.ACTIVITIES_TASK_STATUS, null);
342 combo.setItems(values.toArray(new String[values.size()]));
343 ConnectWorkbenchUtils.refreshFormCombo(IssueEditor.this, combo, currTask,
344 ActivitiesNames.ACTIVITIES_TASK_STATUS);
345 combo.setEnabled(IssueEditor.this.isEditing());
346 }
347
348 private String getIssueTitle() {
349 String id = ConnectJcrUtils.get(getNode(), TrackerNames.TRACKER_ID);
350 String name = ConnectJcrUtils.get(getNode(), Property.JCR_TITLE);
351 if (notEmpty(name)) {
352 Node project = TrackerUtils.getProjectFromChild(getNode());
353 String pname = ConnectJcrUtils.get(project, Property.JCR_TITLE);
354 name = name + (notEmpty(pname) ? " (" + pname + ")" : "");
355 }
356 return "#" + id + " " + name;
357 }
358
359
360 private void populateMuliValueClickableList(Composite parent, Node[] nodes) {
361 CmsUtils.clear(parent);
362 GridData twd = ((GridData) parent.getLayoutData());
363 if (nodes == null || nodes.length < 1) {
364 twd.heightHint = 0;
365 return;
366 } else
367 twd.heightHint = SWT.DEFAULT;
368
369 RowLayout rl = new RowLayout(SWT.HORIZONTAL);
370 rl.wrap = true;
371 rl.marginLeft = rl.marginTop = rl.marginBottom = 0;
372 rl.marginRight = 8;
373 parent.setLayout(rl);
374
375 for (Node node : nodes) {
376 String value = ConnectJcrUtils.get(node, Property.JCR_TITLE);
377 Link link = new Link(parent, SWT.NONE);
378 CmsUtils.markup(link);
379 link.setText(" <a>" + value + "</a>");
380
381 link.addSelectionListener(new SelectionAdapter() {
382 private static final long serialVersionUID = 1L;
383
384 @Override
385 public void widgetSelected(final SelectionEvent event) {
386
387
388 getAppWorkbenchService().openEntityEditor(node);
389 }
390 });
391 }
392 }
393
394 private void configureOpenLink(Link link, Node targetNode) {
395 link.setText("<a>" + ConnectJcrUtils.get(targetNode, Property.JCR_TITLE) + "</a>");
396
397
398 Listener[] existings = link.getListeners(SWT.Selection);
399 for (Listener l : existings)
400 link.removeListener(SWT.Selection, l);
401
402 link.addSelectionListener(new SelectionAdapter() {
403 private static final long serialVersionUID = 1L;
404
405 @Override
406 public void widgetSelected(SelectionEvent e) {
407
408
409 getAppWorkbenchService().openEntityEditor(targetNode);
410 }
411 });
412 }
413
414
415
416
417
418
419
420
421
422
423 }