View Javadoc
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.NodeIterator;
10  import javax.jcr.Property;
11  import javax.jcr.RepositoryException;
12  import javax.jcr.Session;
13  
14  import org.argeo.activities.ActivitiesNames;
15  import org.argeo.activities.ui.AssignedToLP;
16  import org.argeo.cms.ui.eclipse.forms.AbstractFormPart;
17  import org.argeo.cms.ui.eclipse.forms.IManagedForm;
18  import org.argeo.connect.AppService;
19  import org.argeo.connect.ConnectNames;
20  import org.argeo.connect.ui.ConnectColumnDefinition;
21  import org.argeo.connect.ui.ConnectImages;
22  import org.argeo.connect.ui.IJcrTableViewer;
23  import org.argeo.connect.ui.util.JcrRowLabelProvider;
24  import org.argeo.connect.ui.util.UserNameLP;
25  import org.argeo.connect.util.ConnectJcrUtils;
26  import org.argeo.eclipse.ui.ColumnDefinition;
27  import org.argeo.eclipse.ui.EclipseUiUtils;
28  import org.argeo.eclipse.ui.jcr.lists.SimpleJcrNodeLabelProvider;
29  import org.argeo.jcr.JcrUtils;
30  import org.argeo.tracker.TrackerException;
31  import org.argeo.tracker.TrackerNames;
32  import org.argeo.tracker.TrackerTypes;
33  import org.argeo.tracker.core.TrackerUtils;
34  import org.argeo.tracker.ui.TrackerLps;
35  import org.argeo.tracker.ui.dialogs.ConfigureIssueWizard;
36  import org.eclipse.jface.viewers.DoubleClickEvent;
37  import org.eclipse.jface.viewers.IDoubleClickListener;
38  import org.eclipse.jface.viewers.IStructuredSelection;
39  import org.eclipse.jface.viewers.TableViewer;
40  import org.eclipse.jface.window.Window;
41  import org.eclipse.jface.wizard.WizardDialog;
42  import org.eclipse.swt.SWT;
43  import org.eclipse.swt.custom.ScrolledComposite;
44  import org.eclipse.swt.events.ModifyEvent;
45  import org.eclipse.swt.events.ModifyListener;
46  import org.eclipse.swt.events.SelectionAdapter;
47  import org.eclipse.swt.events.SelectionEvent;
48  import org.eclipse.swt.layout.GridData;
49  import org.eclipse.swt.layout.GridLayout;
50  import org.eclipse.swt.widgets.Button;
51  import org.eclipse.swt.widgets.Composite;
52  import org.eclipse.swt.widgets.Text;
53  
54  /**
55   * Basic editor to display a list of all issues that are related to a given
56   * category (a milestone, a version, a component ...) within a project. It also
57   * enable business admin to edit the main info of this category (typically :
58   * title & description)
59   */
60  public class CategoryEditor extends AbstractTrackerEditor implements IJcrTableViewer {
61  	// private static final long serialVersionUID = -6492660981141107302L;
62  	// private final static Log log = LogFactory.getLog(CategoryEditor.class);
63  	// public static final String ID = TrackerUiPlugin.PLUGIN_ID +
64  	// ".categoryEditor";
65  
66  	// Context
67  	private Node project;
68  	private Node category;
69  	private String relevantPropName;
70  	private String officeID;
71  
72  	// Ease implementation
73  	private Text filterTxt;
74  	private AbstractFormPart issueListPart;
75  
76  	@Override
77  	protected void addPages() {
78  		// Initialise local cache
79  		category = getNode();
80  		project = TrackerUtils.getProjectFromChild(category);
81  		officeID = ConnectJcrUtils.get(category, TrackerNames.TRACKER_ID);
82  		relevantPropName = TrackerUtils.getRelevantPropName(category);
83  		try {
84  			addPage(new MainPage(this));
85  
86  			// if (CurrentUser.isInRole(NodeConstants.ROLE_ADMIN))
87  			// addPage(new TechnicalInfoPage(this, ID + ".techInfoPage", getNode()));
88  		} catch (Exception e) {
89  			throw new TrackerException("Cannot add pages for editor of " + getNode(), e);
90  		}
91  	}
92  
93  	protected void updatePartName() {
94  		String name = getCategoryTitle();
95  		if (notEmpty(name))
96  			setPartName(name);
97  		else
98  			super.updatePartName();
99  	}
100 
101 	private class MainPage extends AbstractEditorPage {
102 		public final static String PAGE_ID = "mainPage";
103 
104 		private TableViewer tableViewer;
105 
106 		public MainPage(AbstractTrackerEditor editor) {
107 			super(editor, PAGE_ID, "Overview");
108 		}
109 
110 		protected void createFormContent(final IManagedForm mf) {
111 			// ScrolledForm form = mf.getForm();
112 			// Composite body = form.getBody();
113 			ScrolledComposite form = mf.getForm();
114 			Composite body = new Composite(form, SWT.NONE);
115 
116 			GridLayout mainLayout = new GridLayout();
117 			body.setLayout(mainLayout);
118 			Composite filterCmp = new Composite(body, SWT.NO_FOCUS);
119 			createFilterPart(filterCmp);
120 			filterCmp.setLayoutData(EclipseUiUtils.fillWidth());
121 			Composite tableCmp = new Composite(body, SWT.NO_FOCUS);
122 			appendIssuesPart(tableCmp, mf);
123 			tableCmp.setLayoutData(EclipseUiUtils.fillAll());
124 			// form.reflow(true);
125 		}
126 
127 		/** Creates the list of issues relevant for this category */
128 		private void appendIssuesPart(Composite parent, IManagedForm mf) {
129 			List<ColumnDefinition> columnDefs = new ArrayList<ColumnDefinition>();
130 			columnDefs.add(new ColumnDefinition(new SimpleJcrNodeLabelProvider(TrackerNames.TRACKER_ID), "ID", 40));
131 			columnDefs.add(new ColumnDefinition(new SimpleJcrNodeLabelProvider(Property.JCR_TITLE), "Title", 300));
132 			columnDefs.add(new ColumnDefinition(new SimpleJcrNodeLabelProvider(ActivitiesNames.ACTIVITIES_TASK_STATUS),
133 					"Status", 100));
134 			columnDefs.add(new ColumnDefinition(new TrackerLps().new ImportanceLabelProvider(), "Importance", 100));
135 			columnDefs.add(new ColumnDefinition(new TrackerLps().new PriorityLabelProvider(), "Priority", 100));
136 
137 			// Create and configure the table
138 			tableViewer = TrackerUiUtils.createTableViewer(parent, SWT.SINGLE, columnDefs);
139 			tableViewer.addDoubleClickListener(new IDoubleClickListener() {
140 
141 				@Override
142 				public void doubleClick(DoubleClickEvent event) {
143 					Object element = ((IStructuredSelection) event.getSelection()).getFirstElement();
144 					// String jcrId = ConnectJcrUtils.getIdentifier((Node) element);
145 					// CommandUtils.callCommand(getAppWorkbenchService().getOpenEntityEditorCmdId(),
146 					// ConnectEditor.PARAM_JCR_ID, jcrId);
147 					getAppWorkbenchService().openEntityEditor((Node) element);
148 				}
149 			});
150 
151 			issueListPart = new AbstractFormPart() {
152 				@Override
153 				public void refresh() {
154 					refreshViewer(filterTxt.getText());
155 					super.refresh();
156 				}
157 			};
158 			mf.addPart(issueListPart);
159 			refreshViewer(null);
160 		}
161 
162 		public void setActive(boolean active) {
163 			issueListPart.markStale();
164 			super.setActive(active);
165 		}
166 
167 		private void refreshViewer(String filter) {
168 			NodeIterator nit = TrackerUtils.getIssues(project, filter, relevantPropName, officeID);
169 			tableViewer.setInput(JcrUtils.nodeIteratorToList(nit).toArray(new Node[0]));
170 			tableViewer.refresh();
171 		}
172 
173 		// Add the filter ability
174 		private void createFilterPart(Composite parent) {
175 			GridLayout layout = EclipseUiUtils.noSpaceGridLayout(new GridLayout(2, false));
176 			layout.horizontalSpacing = 5;
177 			parent.setLayout(layout);
178 			parent.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
179 
180 			filterTxt = new Text(parent, SWT.BORDER | SWT.SEARCH | SWT.ICON_SEARCH | SWT.ICON_CANCEL);
181 			filterTxt.setLayoutData(EclipseUiUtils.fillWidth());
182 
183 			final Button addBtn = new Button(parent, SWT.PUSH);
184 			addBtn.setToolTipText("Create a new issue");
185 			addBtn.setImage(ConnectImages.ADD);
186 
187 			filterTxt.addModifyListener(new ModifyListener() {
188 				private static final long serialVersionUID = 8130545587125370689L;
189 
190 				public void modifyText(ModifyEvent event) {
191 					refreshViewer(filterTxt.getText());
192 				}
193 			});
194 
195 			addBtn.addSelectionListener(new SelectionAdapter() {
196 				private static final long serialVersionUID = -7249705366574519524L;
197 
198 				@Override
199 				public void widgetSelected(SelectionEvent e) {
200 
201 					Session tmpSession = null;
202 					Session targetSession = null;
203 					try {
204 						AppService as = getAppService();
205 						tmpSession = project.getSession().getRepository().login();
206 						Node draftIssue = as.createDraftEntity(tmpSession, TrackerTypes.TRACKER_ISSUE);
207 						draftIssue.setProperty(TrackerNames.TRACKER_PROJECT_UID,
208 								ConnectJcrUtils.get(project, ConnectNames.CONNECT_UID));
209 
210 						if (ConnectJcrUtils.isNodeType(category, TrackerTypes.TRACKER_COMPONENT))
211 							ConnectJcrUtils.setMultiValueStringPropFromString(draftIssue,
212 									TrackerNames.TRACKER_COMPONENT_IDS, officeID, "; ");
213 						else if (ConnectJcrUtils.isNodeType(category, TrackerTypes.TRACKER_VERSION))
214 							ConnectJcrUtils.setMultiValueStringPropFromString(draftIssue,
215 									TrackerNames.TRACKER_VERSION_IDS, officeID, "; ");
216 
217 						ConfigureIssueWizard wizard = new ConfigureIssueWizard(getUserAdminService(),
218 								getTrackerService(), draftIssue);
219 
220 						WizardDialog dialog = new WizardDialog(addBtn.getShell(), wizard);
221 						if (dialog.open() == Window.OK) {
222 							targetSession = category.getSession().getRepository().login();
223 							String issueBasePath = as.getBaseRelPath(TrackerTypes.TRACKER_ISSUE);
224 							Node parent = targetSession.getNode("/" + issueBasePath);
225 							Node issue = as.publishEntity(parent, TrackerTypes.TRACKER_ISSUE, draftIssue);
226 							issue = as.saveEntity(issue, false);
227 							project.getSession().refresh(true);
228 							refreshViewer(filterTxt.getText());
229 						}
230 					} catch (RepositoryException e1) {
231 						throw new TrackerException("Unable to create issue on " + project, e1);
232 					} finally {
233 						JcrUtils.logoutQuietly(tmpSession);
234 						JcrUtils.logoutQuietly(targetSession);
235 					}
236 				}
237 			});
238 		}
239 	}
240 
241 	private String getCategoryTitle() {
242 		String name = ConnectJcrUtils.get(getNode(), Property.JCR_TITLE);
243 		if (notEmpty(name)) {
244 			Node project = TrackerUtils.getProjectFromChild(getNode());
245 			String pname = ConnectJcrUtils.get(project, Property.JCR_TITLE);
246 			name = name + (notEmpty(pname) ? " (" + pname + ")" : "");
247 		}
248 		return name;
249 	}
250 
251 	@Override
252 	public Object[] getElements(String extractId) {
253 		String filter = "";
254 		if (filterTxt != null && !filterTxt.isDisposed())
255 			filter = filterTxt.getText();
256 		NodeIterator nit = TrackerUtils.getIssues(project, filter, relevantPropName, officeID);
257 		return JcrUtils.nodeIteratorToList(nit).toArray(new Node[0]);
258 	}
259 
260 	@Override
261 	public List<ConnectColumnDefinition> getColumnDefinition(String extractId) {
262 		List<ConnectColumnDefinition> columns = new ArrayList<ConnectColumnDefinition>();
263 		columns.add(new ConnectColumnDefinition("ID", new SimpleJcrNodeLabelProvider(TrackerNames.TRACKER_ID)));
264 		columns.add(
265 				new ConnectColumnDefinition("Status", new JcrRowLabelProvider(ActivitiesNames.ACTIVITIES_TASK_STATUS)));
266 		columns.add(new ConnectColumnDefinition("Title", new JcrRowLabelProvider(Property.JCR_TITLE)));
267 		columns.add(new ConnectColumnDefinition("Description", new JcrRowLabelProvider(Property.JCR_DESCRIPTION)));
268 		columns.add(new ConnectColumnDefinition("Assigned To",
269 				new AssignedToLP(getActivitiesService(), null, Property.JCR_DESCRIPTION)));
270 		columns.add(
271 				new ConnectColumnDefinition("Due Date", new JcrRowLabelProvider(ActivitiesNames.ACTIVITIES_DUE_DATE)));
272 		columns.add(new ConnectColumnDefinition("Importance", new TrackerLps().new ImportanceLabelProvider()));
273 		columns.add(new ConnectColumnDefinition("Priority", new TrackerLps().new PriorityLabelProvider()));
274 		columns.add(new ConnectColumnDefinition("Components",
275 				new SimpleJcrNodeLabelProvider(TrackerNames.TRACKER_COMPONENT_IDS)));
276 		// columns.add(new ConnectColumnDefinition("Target Milestone",
277 		// new SimpleJcrNodeLabelProvider(TrackerNames.TRACKER_MILESTONE_ID)));
278 
279 		columns.add(new ConnectColumnDefinition("Wake-Up Date",
280 				new JcrRowLabelProvider(ActivitiesNames.ACTIVITIES_WAKE_UP_DATE)));
281 		columns.add(
282 				new ConnectColumnDefinition("Close Date", new JcrRowLabelProvider(ConnectNames.CONNECT_CLOSE_DATE)));
283 		columns.add(new ConnectColumnDefinition("Closed by",
284 				new UserNameLP(getUserAdminService(), null, ConnectNames.CONNECT_CLOSED_BY)));
285 		return columns;
286 	}
287 }