View Javadoc
1   package org.argeo.tracker.e4.parts;
2   
3   import java.util.ArrayList;
4   import java.util.List;
5   
6   import javax.jcr.Node;
7   import javax.jcr.NodeIterator;
8   import javax.jcr.Property;
9   import javax.jcr.PropertyType;
10  import javax.jcr.RepositoryException;
11  import javax.jcr.Session;
12  
13  import org.argeo.cms.auth.CurrentUser;
14  import org.argeo.cms.ui.eclipse.forms.AbstractFormPart;
15  import org.argeo.cms.ui.eclipse.forms.IFormPart;
16  import org.argeo.cms.ui.eclipse.forms.IManagedForm;
17  import org.argeo.cms.util.CmsUtils;
18  import org.argeo.connect.ConnectNames;
19  import org.argeo.connect.UserAdminService;
20  import org.argeo.connect.ui.AppWorkbenchService;
21  import org.argeo.connect.ui.ConnectImages;
22  import org.argeo.connect.ui.ConnectUiConstants;
23  import org.argeo.connect.ui.ConnectUiSnippets;
24  import org.argeo.connect.ui.ConnectWorkbenchUtils;
25  import org.argeo.connect.ui.parts.AskTitleDescriptionDialog;
26  import org.argeo.connect.util.ConnectJcrUtils;
27  import org.argeo.eclipse.ui.ColumnDefinition;
28  import org.argeo.eclipse.ui.EclipseUiUtils;
29  import org.argeo.eclipse.ui.jcr.lists.SimpleJcrNodeLabelProvider;
30  import org.argeo.jcr.JcrUtils;
31  import org.argeo.node.NodeConstants;
32  import org.argeo.tracker.TrackerException;
33  import org.argeo.tracker.TrackerNames;
34  import org.argeo.tracker.TrackerService;
35  import org.argeo.tracker.TrackerTypes;
36  import org.argeo.tracker.core.TrackerUtils;
37  import org.argeo.tracker.ui.TrackerLps;
38  import org.argeo.tracker.ui.TrackerUiConstants;
39  import org.argeo.tracker.ui.VersionComparator;
40  import org.argeo.tracker.ui.dialogs.ConfigureVersionWizard;
41  import org.eclipse.jface.dialogs.MessageDialog;
42  import org.eclipse.jface.viewers.ColumnLabelProvider;
43  import org.eclipse.jface.viewers.DoubleClickEvent;
44  import org.eclipse.jface.viewers.IDoubleClickListener;
45  import org.eclipse.jface.viewers.IStructuredSelection;
46  import org.eclipse.jface.viewers.TableViewer;
47  import org.eclipse.jface.viewers.Viewer;
48  import org.eclipse.jface.viewers.ViewerComparator;
49  import org.eclipse.jface.window.Window;
50  import org.eclipse.jface.wizard.WizardDialog;
51  import org.eclipse.swt.SWT;
52  import org.eclipse.swt.custom.ScrolledComposite;
53  import org.eclipse.swt.events.ModifyEvent;
54  import org.eclipse.swt.events.ModifyListener;
55  import org.eclipse.swt.events.SelectionAdapter;
56  import org.eclipse.swt.events.SelectionEvent;
57  import org.eclipse.swt.layout.GridData;
58  import org.eclipse.swt.layout.GridLayout;
59  import org.eclipse.swt.widgets.Button;
60  import org.eclipse.swt.widgets.Composite;
61  import org.eclipse.swt.widgets.Shell;
62  import org.eclipse.swt.widgets.Table;
63  import org.eclipse.swt.widgets.Text;
64  
65  public class MilestoneListPage extends AbstractEditorPage {
66  
67  	private final UserAdminService userAdminService;
68  	private final TrackerService trackerService;
69  	private final AppWorkbenchService appWorkbenchService;
70  	private final Node project;
71  
72  	private TableViewer tableViewer;
73  	private Text filterTxt;
74  
75  	public MilestoneListPage(AbstractTrackerEditor editor, String id, Node project, UserAdminService userAdminService,
76  			TrackerService trackerService, AppWorkbenchService appWorkbenchService) {
77  		super(editor, id, "Milestones");
78  		this.userAdminService = userAdminService;
79  		this.trackerService = trackerService;
80  		this.appWorkbenchService = appWorkbenchService;
81  		this.project = project;
82  	}
83  
84  	private boolean canEdit() {
85  		boolean isDataAdmin = CurrentUser.isInRole(NodeConstants.ROLE_DATA_ADMIN);
86  		String managerId = ConnectJcrUtils.get(project, TrackerNames.TRACKER_MANAGER);
87  		// FIXME known issue: manager ID is uid=... where as CurrentUser own
88  		// role is UID=...
89  		boolean isManager = (EclipseUiUtils.notEmpty(managerId)
90  				&& (CurrentUser.getUsername().equalsIgnoreCase(managerId)) || CurrentUser.isInRole(managerId));
91  		return isDataAdmin || isManager;
92  		// return CurrentUser.isInRole(NodeConstants.ROLE_DATA_ADMIN)
93  		// || (EclipseUiUtils.notEmpty(managerId) &&
94  		// CurrentUser.isInRole(managerId));
95  	}
96  
97  	protected void createFormContent(IManagedForm mf) {
98  //		ScrolledForm form = mf.getForm();
99  //		Composite body = form.getBody();
100 		ScrolledComposite form = mf.getForm();
101 		Composite body = new Composite(form, SWT.NONE);
102 		form.setContent(body);
103 		GridLayout mainLayout = new GridLayout();
104 
105 		body.setLayout(mainLayout);
106 		Composite filterCmp = new Composite(body, SWT.NO_FOCUS);
107 		createFilterPart(filterCmp);
108 		filterCmp.setLayoutData(EclipseUiUtils.fillWidth());
109 		Composite tableCmp = new Composite(body, SWT.NO_FOCUS);
110 		appendMilestonesPart(mf, tableCmp);
111 		tableCmp.setLayoutData(EclipseUiUtils.fillAll());
112 
113 //		form.reflow(true);
114 	}
115 
116 	private void appendMilestonesPart(IManagedForm mf, Composite parent) {
117 		List<ColumnDefinition> columnDefs = new ArrayList<ColumnDefinition>();
118 		columnDefs.add(new ColumnDefinition(getJcrLP(Property.JCR_TITLE), "Name", 120));
119 		columnDefs.add(new ColumnDefinition(new TrackerLps().new DateLabelProvider(TrackerNames.TRACKER_TARGET_DATE),
120 				"Target Date", 120));
121 		columnDefs.add(new ColumnDefinition(
122 				new TrackerLps().new DnLabelProvider(userAdminService, TrackerNames.TRACKER_MANAGER), "Manager", 160));
123 		columnDefs.add(new ColumnDefinition(getJcrLP(Property.JCR_DESCRIPTION), "Description", 300));
124 		columnDefs.add(new ColumnDefinition(getMSIssuesLP(), "Open / All Tasks", 120));
125 		// columnDefs.add(new ColumnDefinition(getMSIssuesLP(false), "All
126 		// tasks", 120));
127 		columnDefs.add(new ColumnDefinition(new TrackerLps().new DateLabelProvider(ConnectNames.CONNECT_CLOSE_DATE),
128 				"Close Date", 120));
129 		if (canEdit())
130 			columnDefs.add(new ColumnDefinition(getEditionLP(), "", 120));
131 
132 		tableViewer = TrackerUiUtils.createTableViewer(parent, SWT.SINGLE, columnDefs);
133 		tableViewer.setComparator(new ViewerComparator() {
134 			private static final long serialVersionUID = 1L;
135 			VersionComparator comp = new VersionComparator();
136 
137 			public int compare(Viewer viewer, Object e1, Object e2) {
138 				Node n1 = (Node) e1;
139 				Node n2 = (Node) e2;
140 				// Last must be first: we skip 1 & 2
141 				return comp.compare(viewer, ConnectJcrUtils.getName(n2), ConnectJcrUtils.getName(n1));
142 			};
143 		});
144 		addDClickListener(tableViewer);
145 
146 		AbstractFormPart part = new AbstractFormPart() {
147 			@Override
148 			public void refresh() {
149 				refreshViewer(filterTxt.getText());
150 				super.refresh();
151 			}
152 		};
153 		mf.addPart(part);
154 
155 		if (canEdit()) {
156 			Table table = tableViewer.getTable();
157 			CmsUtils.setItemHeight(table, TrackerUiConstants.DEFAULT_ROW_HEIGHT);
158 			CmsUtils.markup(table);
159 			table.addSelectionListener(new EditionRwtAdapter(part));
160 		}
161 		refreshViewer(null);
162 	}
163 
164 	private void refreshViewer(String filter) {
165 		NodeIterator nit = TrackerUtils.getOpenMilestones(project, filter);
166 		tableViewer.setInput(JcrUtils.nodeIteratorToList(nit).toArray(new Node[0]));
167 		tableViewer.refresh();
168 	}
169 
170 	private void createFilterPart(Composite parent) {
171 		GridLayout layout = EclipseUiUtils.noSpaceGridLayout(new GridLayout(2, false));
172 		layout.horizontalSpacing = 5;
173 		parent.setLayout(layout);
174 		parent.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
175 
176 		filterTxt = new Text(parent, SWT.BORDER | SWT.SEARCH | SWT.ICON_SEARCH | SWT.ICON_CANCEL);
177 		filterTxt.setLayoutData(EclipseUiUtils.fillWidth());
178 
179 		final Button addBtn = new Button(parent, SWT.PUSH);
180 		addBtn.setToolTipText("Create a milestone");
181 		addBtn.setImage(ConnectImages.ADD);
182 
183 		filterTxt.addModifyListener(new ModifyListener() {
184 			private static final long serialVersionUID = 8130545587125370689L;
185 
186 			public void modifyText(ModifyEvent event) {
187 				refreshViewer(filterTxt.getText());
188 			}
189 		});
190 
191 		addBtn.addSelectionListener(new SelectionAdapter() {
192 			private static final long serialVersionUID = -6057495212496327413L;
193 
194 			@Override
195 			public void widgetSelected(SelectionEvent e) {
196 				Session session = ConnectJcrUtils.getSession(project);
197 				String mainMixin = TrackerTypes.TRACKER_MILESTONE;
198 				String propName1 = TrackerNames.TRACKER_PROJECT_UID;
199 				String value1 = ConnectJcrUtils.get(project, ConnectNames.CONNECT_UID);
200 
201 				String pathCreated = ConnectWorkbenchUtils.createAndConfigureEntity(addBtn.getShell(), session,
202 						trackerService, appWorkbenchService, mainMixin, propName1, value1);
203 				if (EclipseUiUtils.notEmpty(pathCreated))
204 					refreshViewer(filterTxt.getText());
205 			}
206 		});
207 	}
208 
209 	// LOCAL HELPERS
210 
211 	// Shorten this call
212 	private static ColumnLabelProvider getJcrLP(String propName) {
213 		return new SimpleJcrNodeLabelProvider(propName);
214 	}
215 
216 	private ColumnLabelProvider getMSIssuesLP() {
217 		return new ColumnLabelProvider() {
218 			private static final long serialVersionUID = -998161071505982347L;
219 
220 			@Override
221 			public String getText(Object element) {
222 				Node milestone = (Node) element;
223 				NodeIterator nit = TrackerUtils.getIssues(project, null, TrackerNames.TRACKER_MILESTONE_UID,
224 						ConnectJcrUtils.get(milestone, ConnectNames.CONNECT_UID), true);
225 				long openNb = nit.getSize();
226 
227 				nit = TrackerUtils.getIssues(project, null, TrackerNames.TRACKER_MILESTONE_UID,
228 						ConnectJcrUtils.get(milestone, ConnectNames.CONNECT_UID), false);
229 				long allNb = nit.getSize();
230 
231 				return openNb + " / " + allNb;
232 			}
233 		};
234 	}
235 
236 	private static ColumnLabelProvider getEditionLP() {
237 		return new ColumnLabelProvider() {
238 			private static final long serialVersionUID = 6502008085763687925L;
239 
240 			@Override
241 			public String getText(Object element) {
242 				Node category = (Node) element;
243 				String jcrId = ConnectJcrUtils.getIdentifier(category);
244 
245 				String editHref = ConnectUiConstants.CRUD_EDIT + "/" + jcrId;
246 				String editLinkStr = ConnectUiSnippets.getRWTLink(editHref, ConnectUiConstants.CRUD_EDIT);
247 
248 				// TODO enable deletion of referenced components
249 				if (TrackerUtils.getIssueNb(category, false) == 0) {
250 					String removeHref = ConnectUiConstants.CRUD_DELETE + "/" + jcrId;
251 					String removeLinkStr = ConnectUiSnippets.getRWTLink(removeHref, ConnectUiConstants.CRUD_DELETE);
252 					editLinkStr += "  or  " + removeLinkStr;
253 				}
254 				return editLinkStr;
255 			}
256 		};
257 	}
258 
259 	private void addDClickListener(TableViewer tableViewer) {
260 		tableViewer.addDoubleClickListener(new IDoubleClickListener() {
261 			@Override
262 			public void doubleClick(DoubleClickEvent event) {
263 				Object element = ((IStructuredSelection) event.getSelection()).getFirstElement();
264 				// String jcrId = ConnectJcrUtils.getIdentifier((Node) element);
265 				// CommandUtils.callCommand(appWorkbenchService.getOpenEntityEditorCmdId(),
266 				// ConnectEditor.PARAM_JCR_ID,
267 				// jcrId);
268 				appWorkbenchService.openEntityEditor((Node) element);
269 			}
270 		});
271 	}
272 
273 	private class EditionRwtAdapter extends SelectionAdapter {
274 		private static final long serialVersionUID = -7459078949241763141L;
275 
276 		private IFormPart part;
277 
278 		public EditionRwtAdapter(IFormPart part) {
279 			this.part = part;
280 		}
281 
282 		public void widgetSelected(SelectionEvent event) {
283 			if (event.detail == ConnectUiConstants.MARKUP_VIEWER_HYPERLINK) {
284 				String string = event.text;
285 				String[] token = string.split("/");
286 				String cmdId = token[0];
287 				String jcrId = token[1];
288 				Shell shell = event.display.getActiveShell();
289 				boolean hasChanged = false;
290 				try {
291 					Node node = project.getSession().getNodeByIdentifier(jcrId);
292 					if (ConnectUiConstants.CRUD_DELETE.equals(cmdId)) {
293 						if (MessageDialog.openConfirm(shell, "Confirm deletion",
294 								"Are you sure you want to delete " + ConnectJcrUtils.get(node, Property.JCR_TITLE))) {
295 							node.remove();
296 							project.getSession().save();
297 							hasChanged = true;
298 						}
299 					} else if (ConnectUiConstants.CRUD_EDIT.equals(cmdId)) {
300 						if (node.isNodeType(TrackerTypes.TRACKER_COMPONENT)) {
301 							String title = ConnectJcrUtils.get(node, Property.JCR_TITLE);
302 							String desc = ConnectJcrUtils.get(node, Property.JCR_DESCRIPTION);
303 							AskTitleDescriptionDialog dialog = new AskTitleDescriptionDialog(shell, "Edit component",
304 									title, desc);
305 							if (dialog.open() == Window.OK) {
306 								hasChanged = ConnectJcrUtils.setJcrProperty(node, Property.JCR_TITLE,
307 										PropertyType.STRING, dialog.getTitle());
308 								hasChanged |= ConnectJcrUtils.setJcrProperty(node, Property.JCR_DESCRIPTION,
309 										PropertyType.STRING, dialog.getDescription());
310 								if (hasChanged)
311 									project.getSession().save();
312 							}
313 						} else if (node.isNodeType(TrackerTypes.TRACKER_VERSION)) {
314 							ConfigureVersionWizard wizard = new ConfigureVersionWizard(trackerService, node);
315 							WizardDialog dialog = new WizardDialog(shell, wizard);
316 							if (dialog.open() == Window.OK) {
317 								if (project.getSession().hasPendingChanges()) {
318 									project.getSession().save();
319 									hasChanged = true;
320 								}
321 							}
322 						}
323 					}
324 				} catch (RepositoryException e) {
325 					throw new TrackerException("Cannot " + cmdId + " with JcrId " + jcrId, e);
326 				}
327 				if (hasChanged)
328 					part.refresh();
329 			}
330 		}
331 	}
332 }