]> git.argeo.org Git - gpl/argeo-slc.git/blob - eclipse/plugins/org.argeo.slc.client.ui/src/main/java/org/argeo/slc/client/ui/editors/ProcessBuilderPage.java
Improve JCR data model
[gpl/argeo-slc.git] / eclipse / plugins / org.argeo.slc.client.ui / src / main / java / org / argeo / slc / client / ui / editors / ProcessBuilderPage.java
1 package org.argeo.slc.client.ui.editors;
2
3 import java.util.ArrayList;
4 import java.util.Iterator;
5 import java.util.List;
6 import java.util.UUID;
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 import javax.jcr.nodetype.NodeType;
14 import javax.jcr.observation.Event;
15 import javax.jcr.observation.EventIterator;
16 import javax.jcr.observation.EventListener;
17 import javax.jcr.observation.ObservationManager;
18
19 import org.argeo.ArgeoException;
20 import org.argeo.eclipse.ui.jcr.AsyncUiEventListener;
21 import org.argeo.jcr.JcrUtils;
22 import org.argeo.slc.SlcException;
23 import org.argeo.slc.client.ui.SlcImages;
24 import org.argeo.slc.execution.ExecutionProcess;
25 import org.argeo.slc.jcr.SlcJcrUtils;
26 import org.argeo.slc.jcr.SlcNames;
27 import org.argeo.slc.jcr.SlcTypes;
28 import org.argeo.slc.process.RealizedFlow;
29 import org.eclipse.jface.viewers.ColumnLabelProvider;
30 import org.eclipse.jface.viewers.ISelectionChangedListener;
31 import org.eclipse.jface.viewers.IStructuredSelection;
32 import org.eclipse.jface.viewers.ITreeContentProvider;
33 import org.eclipse.jface.viewers.SelectionChangedEvent;
34 import org.eclipse.jface.viewers.StructuredSelection;
35 import org.eclipse.jface.viewers.TreeViewer;
36 import org.eclipse.jface.viewers.Viewer;
37 import org.eclipse.jface.viewers.ViewerDropAdapter;
38 import org.eclipse.swt.SWT;
39 import org.eclipse.swt.custom.SashForm;
40 import org.eclipse.swt.dnd.DND;
41 import org.eclipse.swt.dnd.TextTransfer;
42 import org.eclipse.swt.dnd.Transfer;
43 import org.eclipse.swt.dnd.TransferData;
44 import org.eclipse.swt.events.SelectionEvent;
45 import org.eclipse.swt.events.SelectionListener;
46 import org.eclipse.swt.graphics.Image;
47 import org.eclipse.swt.layout.FillLayout;
48 import org.eclipse.swt.layout.GridData;
49 import org.eclipse.swt.layout.GridLayout;
50 import org.eclipse.swt.layout.RowData;
51 import org.eclipse.swt.layout.RowLayout;
52 import org.eclipse.swt.widgets.Button;
53 import org.eclipse.swt.widgets.Composite;
54 import org.eclipse.swt.widgets.Label;
55 import org.eclipse.ui.PlatformUI;
56 import org.eclipse.ui.forms.AbstractFormPart;
57 import org.eclipse.ui.forms.IManagedForm;
58 import org.eclipse.ui.forms.editor.FormPage;
59 import org.eclipse.ui.forms.widgets.FormToolkit;
60 import org.eclipse.ui.forms.widgets.ScrolledForm;
61
62 public class ProcessBuilderPage extends FormPage implements SlcNames, SlcTypes {
63 public final static String ID = "processBuilderPage";
64 // private final static Log log =
65 // LogFactory.getLog(ProcessBuilderPage.class);
66
67 private Node processNode;
68
69 private TreeViewer flowsViewer;
70 private Label statusLabel;
71 private Button run;
72 private Button remove;
73 private Button clear;
74
75 private AbstractFormPart formPart;
76 private EventListener statusObserver;
77
78 public ProcessBuilderPage(ProcessEditor editor, Node processNode) {
79 super(editor, ID, "Definition");
80 this.processNode = processNode;
81 }
82
83 @Override
84 protected void createFormContent(IManagedForm mf) {
85 try {
86 ScrolledForm form = mf.getForm();
87 form.setText("Process " + processNode.getName());
88 GridLayout mainLayout = new GridLayout(1, true);
89 form.getBody().setLayout(mainLayout);
90
91 createControls(form.getBody());
92 createBuilder(form.getBody());
93
94 // form
95 formPart = new AbstractFormPart() {
96
97 };
98 getManagedForm().addPart(formPart);
99
100 // observation
101 statusObserver = new AsyncUiEventListener() {
102 protected void onEventInUiThread(EventIterator events) {
103 statusChanged();
104 }
105 };
106 ObservationManager observationManager = processNode.getSession()
107 .getWorkspace().getObservationManager();
108 observationManager.addEventListener(statusObserver,
109 Event.PROPERTY_CHANGED, processNode.getPath(), true, null,
110 null, false);
111
112 } catch (RepositoryException e) {
113 throw new ArgeoException("Cannot create form content", e);
114 }
115 }
116
117 protected void createControls(Composite parent) {
118 FormToolkit tk = getManagedForm().getToolkit();
119
120 Composite controls = tk.createComposite(parent);
121 controls.setLayout(new RowLayout());
122 controls.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
123
124 run = tk.createButton(controls, null, SWT.PUSH);
125 run.setToolTipText("Run");
126 run.setImage(SlcImages.LAUNCH);
127 run.addSelectionListener(new SelectionListener() {
128 public void widgetSelected(SelectionEvent e) {
129 if (isFinished(getProcessStatus())) {
130 relaunch();
131 } else {
132 ((ProcessEditor) getEditor()).process();
133 }
134 }
135
136 public void widgetDefaultSelected(SelectionEvent e) {
137 widgetSelected(e);
138 }
139 });
140
141 remove = tk.createButton(controls, null, SWT.PUSH);
142 remove.setImage(SlcImages.REMOVE_ONE);
143 remove.setToolTipText("Remove selected flows");
144 remove.addSelectionListener(new SelectionListener() {
145 public void widgetSelected(SelectionEvent e) {
146 removeSelectedFlows();
147 }
148
149 public void widgetDefaultSelected(SelectionEvent e) {
150 widgetSelected(e);
151 }
152 });
153
154 clear = tk.createButton(controls, null, SWT.PUSH);
155 clear.setImage(SlcImages.REMOVE_ALL);
156 clear.setToolTipText("Clear all flows");
157 clear.addSelectionListener(new SelectionListener() {
158 public void widgetSelected(SelectionEvent e) {
159 removeAllFlows();
160 }
161
162 public void widgetDefaultSelected(SelectionEvent e) {
163 widgetSelected(e);
164 }
165 });
166
167 Composite statusComposite = tk.createComposite(controls);
168 RowData rowData = new RowData();
169 rowData.width = 100;
170 rowData.height = 16;
171 statusComposite.setLayoutData(rowData);
172 statusComposite.setLayout(new FillLayout());
173 statusLabel = tk.createLabel(statusComposite, getProcessStatus());
174
175 // make sure all controls are in line with status
176 statusChanged();
177 }
178
179 protected void relaunch() {
180 try {
181 Node duplicatedNode = duplicateProcess();
182 PlatformUI
183 .getWorkbench()
184 .getActiveWorkbenchWindow()
185 .getActivePage()
186 .openEditor(
187 new ProcessEditorInput(duplicatedNode.getPath()),
188 ProcessEditor.ID);
189 getEditor().close(false);
190 } catch (Exception e1) {
191 throw new SlcException("Cannot relaunch " + processNode, e1);
192 }
193 }
194
195 protected Node duplicateProcess() {
196 try {
197 Session session = processNode.getSession();
198 String uuid = UUID.randomUUID().toString();
199 String destPath = SlcJcrUtils.createExecutionProcessPath(uuid);
200 Node newNode = JcrUtils.mkdirs(session, destPath, SLC_PROCESS);
201 JcrUtils.copy(processNode, newNode);
202 // session.getWorkspace().copy(processNode.getPath(), destPath);
203 // Node newNode = session.getNode(destPath);
204 // make sure that we kept the mixins
205 // newNode.addMixin(NodeType.MIX_CREATED);
206 // newNode.addMixin(NodeType.MIX_LAST_MODIFIED);
207 newNode.setProperty(SLC_UUID, uuid);
208 newNode.setProperty(SLC_STATUS, ExecutionProcess.INITIALIZED);
209 session.save();
210 return newNode;
211 } catch (RepositoryException e) {
212 throw new SlcException("Cannot duplicate process", e);
213 }
214 }
215
216 protected String getProcessStatus() {
217 try {
218 return processNode.getProperty(SLC_STATUS).getString();
219 } catch (RepositoryException e) {
220 throw new SlcException("Cannot retrieve status for " + processNode,
221 e);
222 }
223 }
224
225 protected void statusChanged() {
226 String status = getProcessStatus();
227 statusLabel.setText(status);
228 Boolean isEditable = isEditable(status);
229 run.setEnabled(isEditable);
230 remove.setEnabled(isEditable);
231 clear.setEnabled(isEditable);
232 // flowsViewer.getTree().setEnabled(isEditable);
233 if (status.equals(ExecutionProcess.COMPLETED)
234 || status.equals(ExecutionProcess.ERROR)) {
235 run.setEnabled(true);
236 run.setImage(SlcImages.RELAUNCH);
237 run.setToolTipText("Relaunch");
238 }
239 }
240
241 /** Optimization so that we don't call the node each time */
242 protected Boolean isEditable(String status) {
243 return status.equals(ExecutionProcess.NEW)
244 || status.equals(ExecutionProcess.INITIALIZED);
245 }
246
247 protected Boolean isFinished(String status) {
248 return status.equals(ExecutionProcess.COMPLETED)
249 || status.equals(ExecutionProcess.ERROR);
250 }
251
252 protected void createBuilder(Composite parent) {
253 FormToolkit tk = getManagedForm().getToolkit();
254 SashForm sashForm = new SashForm(parent, SWT.HORIZONTAL);
255 sashForm.setSashWidth(4);
256 sashForm.setLayout(new FillLayout());
257 sashForm.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
258
259 Composite top = tk.createComposite(sashForm);
260 GridLayout gl = new GridLayout(1, false);
261 top.setLayout(gl);
262
263 flowsViewer = new TreeViewer(top);
264 flowsViewer.getTree().setLayoutData(
265 new GridData(SWT.FILL, SWT.FILL, true, true));
266 flowsViewer.setLabelProvider(new ViewLabelProvider());
267 flowsViewer.setContentProvider(new ViewContentProvider());
268 flowsViewer.addSelectionChangedListener(new SelectionChangedListener());
269
270 int operations = DND.DROP_COPY | DND.DROP_MOVE;
271 Transfer[] tt = new Transfer[] { TextTransfer.getInstance() };
272 flowsViewer.addDropSupport(operations, tt, new ViewDropListener(
273 flowsViewer));
274
275 flowsViewer.setInput(getEditorSite());
276 flowsViewer.setInput(processNode);
277
278 Composite bottom = tk.createComposite(sashForm);
279 bottom.setLayout(new GridLayout(1, false));
280 sashForm.setWeights(getWeights());
281 }
282
283 protected int[] getWeights() {
284 return new int[] { 70, 30 };
285 }
286
287 /*
288 * CONTROLLERS
289 */
290 protected void addFlow(String path) {
291 try {
292 Node flowNode = processNode.getNode(SLC_FLOW).addNode(SLC_FLOW);
293 flowNode.addMixin(SLC_REALIZED_FLOW);
294 Node address = flowNode.addNode(SLC_ADDRESS, NodeType.NT_ADDRESS);
295 address.setProperty(Property.JCR_PATH, path);
296 flowsViewer.refresh();
297 formPart.markDirty();
298 } catch (RepositoryException e) {
299 throw new SlcException("Cannot drop " + path, e);
300 }
301 }
302
303 @SuppressWarnings("unchecked")
304 protected void removeSelectedFlows() {
305 if (!flowsViewer.getSelection().isEmpty()) {
306 Iterator<Object> it = ((StructuredSelection) flowsViewer
307 .getSelection()).iterator();
308 while (it.hasNext()) {
309 Node node = (Node) it.next();
310 try {
311 node.remove();
312 } catch (RepositoryException e) {
313 throw new ArgeoException("Cannot remove " + node, e);
314 }
315 }
316 flowsViewer.refresh();
317 formPart.markDirty();
318 }
319 }
320
321 protected void removeAllFlows() {
322 try {
323 for (NodeIterator nit = processNode.getNode(SLC_FLOW).getNodes(); nit
324 .hasNext();) {
325 nit.nextNode().remove();
326 }
327 flowsViewer.refresh();
328 formPart.markDirty();
329 } catch (RepositoryException e) {
330 throw new ArgeoException("Cannot remove flows from " + processNode,
331 e);
332 }
333 }
334
335 public void commit(Boolean onSave) {
336 if (onSave)
337 statusLabel.setText(getProcessStatus());
338 formPart.commit(onSave);
339 }
340
341 @Override
342 public void dispose() {
343 JcrUtils.unregisterQuietly(processNode, statusObserver);
344 super.dispose();
345 }
346
347 // Specific Providers for the current view.
348 protected class ViewContentProvider implements ITreeContentProvider {
349 public void inputChanged(Viewer arg0, Object arg1, Object arg2) {
350 }
351
352 public void dispose() {
353 }
354
355 public Object[] getElements(Object obj) {
356 if (!(obj instanceof Node))
357 return new Object[0];
358
359 try {
360 Node node = (Node) obj;
361 List<Node> children = new ArrayList<Node>();
362 for (NodeIterator nit = node.getNode(SLC_FLOW).getNodes(); nit
363 .hasNext();)
364 children.add(nit.nextNode());
365 return children.toArray();
366 } catch (RepositoryException e) {
367 throw new SlcException("Cannot list children of " + obj, e);
368 }
369 }
370
371 public Object[] getChildren(Object parentElement) {
372 return null;
373 }
374
375 public Object getParent(Object element) {
376 return null;
377 }
378
379 public boolean hasChildren(Object element) {
380 return false;
381 }
382
383 }
384
385 protected class ViewLabelProvider extends ColumnLabelProvider {
386
387 @Override
388 public String getText(Object element) {
389 Node node = (Node) element;
390 try {
391 if (node.isNodeType(SLC_REALIZED_FLOW)) {
392 if (node.hasNode(SLC_ADDRESS)) {
393 String path = node.getNode(SLC_ADDRESS)
394 .getProperty(Property.JCR_PATH).getString();
395 return SlcJcrUtils.flowExecutionModuleName(path) + ":"
396 + SlcJcrUtils.flowRelativePath(path);
397 }
398 }
399 } catch (RepositoryException e) {
400 throw new SlcException("Cannot display " + element, e);
401 }
402 return super.getText(element);
403 }
404
405 @Override
406 public Image getImage(Object element) {
407 Node node = (Node) element;
408 try {
409 if (node.isNodeType(SLC_REALIZED_FLOW)) {
410 return SlcImages.FLOW;
411 }
412 } catch (RepositoryException e) {
413 throw new SlcException("Cannot display " + element, e);
414 }
415 return super.getImage(element);
416 }
417
418 }
419
420 // Parameter view is updated each time a new line is selected
421 class SelectionChangedListener implements ISelectionChangedListener {
422 public void selectionChanged(SelectionChangedEvent evt) {
423
424 IStructuredSelection curSelection = (IStructuredSelection) evt
425 .getSelection();
426 Object obj = curSelection.getFirstElement();
427
428 if (obj instanceof RealizedFlow) {
429 // RealizedFlow rf = (RealizedFlow) obj;
430 // curSelectedRow = realizedFlows.indexOf(rf);
431 // refreshParameterview();
432 // setFocus();
433 }
434 }
435 }
436
437 protected class ViewDropListener extends ViewerDropAdapter {
438
439 public ViewDropListener(Viewer viewer) {
440 super(viewer);
441 }
442
443 @Override
444 public boolean performDrop(Object data) {
445 String path = data.toString();
446 addFlow(path);
447 return true;
448 }
449
450 @Override
451 public boolean validateDrop(Object target, int operation,
452 TransferData transferType) {
453 return isEditable(getProcessStatus());
454 }
455 }
456 }