]> git.argeo.org Git - gpl/argeo-slc.git/blob - cms/org.argeo.slc.client.ui/src/org/argeo/slc/client/ui/editors/ProcessBuilderPage.java
7c3d53228b68d0dbe7cb38b04ade03f3650fd9e9
[gpl/argeo-slc.git] / cms / org.argeo.slc.client.ui / src / 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.SortedSet;
7 import java.util.TreeSet;
8
9 import javax.jcr.LoginException;
10 import javax.jcr.Node;
11 import javax.jcr.NodeIterator;
12 import javax.jcr.Property;
13 import javax.jcr.RepositoryException;
14 import javax.jcr.Session;
15 import javax.jcr.nodetype.NodeType;
16 import javax.jcr.observation.Event;
17 import javax.jcr.observation.EventListener;
18 import javax.jcr.observation.ObservationManager;
19 import javax.jcr.query.Query;
20 import javax.jcr.query.QueryManager;
21
22 import org.argeo.eclipse.ui.jcr.AsyncUiEventListener;
23 import org.argeo.jcr.JcrUtils;
24 import org.argeo.slc.SlcException;
25 import org.argeo.slc.SlcNames;
26 import org.argeo.slc.SlcTypes;
27 import org.argeo.slc.client.ui.SlcImages;
28 import org.argeo.slc.execution.ExecutionProcess;
29 import org.argeo.slc.jcr.SlcJcrUtils;
30 import org.argeo.slc.primitive.PrimitiveAccessor;
31 import org.argeo.slc.primitive.PrimitiveUtils;
32 import org.eclipse.jface.viewers.CellEditor;
33 import org.eclipse.jface.viewers.ColumnLabelProvider;
34 import org.eclipse.jface.viewers.ColumnViewer;
35 import org.eclipse.jface.viewers.ComboBoxCellEditor;
36 import org.eclipse.jface.viewers.EditingSupport;
37 import org.eclipse.jface.viewers.ISelectionChangedListener;
38 import org.eclipse.jface.viewers.IStructuredContentProvider;
39 import org.eclipse.jface.viewers.IStructuredSelection;
40 import org.eclipse.jface.viewers.ITreeContentProvider;
41 import org.eclipse.jface.viewers.SelectionChangedEvent;
42 import org.eclipse.jface.viewers.StructuredSelection;
43 import org.eclipse.jface.viewers.TableViewer;
44 import org.eclipse.jface.viewers.TableViewerColumn;
45 import org.eclipse.jface.viewers.TextCellEditor;
46 import org.eclipse.jface.viewers.TreeViewer;
47 import org.eclipse.jface.viewers.Viewer;
48 import org.eclipse.jface.viewers.ViewerDropAdapter;
49 import org.eclipse.swt.SWT;
50 import org.eclipse.swt.custom.SashForm;
51 import org.eclipse.swt.dnd.DND;
52 import org.eclipse.swt.dnd.TextTransfer;
53 import org.eclipse.swt.dnd.Transfer;
54 import org.eclipse.swt.dnd.TransferData;
55 import org.eclipse.swt.events.SelectionEvent;
56 import org.eclipse.swt.events.SelectionListener;
57 import org.eclipse.swt.graphics.Image;
58 import org.eclipse.swt.layout.FillLayout;
59 import org.eclipse.swt.layout.GridData;
60 import org.eclipse.swt.layout.GridLayout;
61 import org.eclipse.swt.layout.RowData;
62 import org.eclipse.swt.layout.RowLayout;
63 import org.eclipse.swt.widgets.Button;
64 import org.eclipse.swt.widgets.Composite;
65 import org.eclipse.swt.widgets.Label;
66 import org.eclipse.swt.widgets.Menu;
67 import org.eclipse.swt.widgets.MenuItem;
68 import org.eclipse.swt.widgets.Table;
69 import org.eclipse.ui.forms.AbstractFormPart;
70 import org.eclipse.ui.forms.IManagedForm;
71 import org.eclipse.ui.forms.editor.FormPage;
72 import org.eclipse.ui.forms.widgets.FormToolkit;
73 import org.eclipse.ui.forms.widgets.ScrolledForm;
74
75 /** Definition of the process. */
76 public class ProcessBuilderPage extends FormPage implements SlcNames {
77 // private final static Log log =
78 // LogFactory.getLog(ProcessBuilderPage.class);
79
80 public final static String ID = "processBuilderPage";
81
82 /** To be displayed in empty lists */
83 final static String NONE = "<none>";
84
85 private Node processNode;
86 private Session agentSession;
87
88 private TreeViewer flowsViewer;
89 private TableViewer valuesViewer;
90 private Label statusLabel;
91 private Button run;
92 private Button remove;
93 private Button clear;
94
95 private AbstractFormPart formPart;
96 private EventListener statusObserver;
97
98 public ProcessBuilderPage(ProcessEditor editor, Node processNode) {
99 super(editor, ID, "Definition");
100 this.processNode = processNode;
101 try {
102 this.agentSession = processNode.getSession().getRepository().login();
103 } catch (RepositoryException e) {
104 throw new SlcException("Cannot open agent session", e);
105 }
106 }
107
108 @Override
109 protected void createFormContent(IManagedForm mf) {
110 try {
111 ScrolledForm form = mf.getForm();
112 form.setExpandHorizontal(true);
113 form.setExpandVertical(true);
114 form.setText("Process " + processNode.getName());
115 GridLayout mainLayout = new GridLayout(1, true);
116 form.getBody().setLayout(mainLayout);
117
118 createControls(form.getBody());
119 createBuilder(form.getBody());
120
121 // form
122 formPart = new AbstractFormPart() {
123
124 };
125 getManagedForm().addPart(formPart);
126
127 // observation
128 statusObserver = new AsyncUiEventListener(form.getDisplay()) {
129 protected void onEventInUiThread(List<Event> events) {
130 statusChanged();
131 }
132 };
133 ObservationManager observationManager = processNode.getSession().getWorkspace().getObservationManager();
134 observationManager.addEventListener(statusObserver, Event.PROPERTY_CHANGED, processNode.getPath(), true,
135 null, null, false);
136
137 // make sure all controls are in line with status
138 statusChanged();
139
140 // add initial flows
141 addInitialFlows();
142
143 } catch (RepositoryException e) {
144 throw new SlcException("Cannot create form content", e);
145 }
146 }
147
148 protected void createControls(Composite parent) {
149 FormToolkit tk = getManagedForm().getToolkit();
150
151 Composite controls = tk.createComposite(parent);
152 controls.setLayout(new RowLayout());
153 controls.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
154
155 run = tk.createButton(controls, null, SWT.PUSH);
156 run.setToolTipText("Run");
157 run.setImage(SlcImages.LAUNCH);
158 run.addSelectionListener(new SelectionListener() {
159 public void widgetSelected(SelectionEvent e) {
160 if (isFinished(getProcessStatus())) {
161 ((ProcessEditor) getEditor()).relaunch();
162 } else if (isRunning(getProcessStatus())) {
163 ((ProcessEditor) getEditor()).kill();
164 } else {
165 ((ProcessEditor) getEditor()).process();
166 }
167 }
168
169 public void widgetDefaultSelected(SelectionEvent e) {
170 widgetSelected(e);
171 }
172 });
173
174 remove = tk.createButton(controls, null, SWT.PUSH);
175 remove.setImage(SlcImages.REMOVE_ONE);
176 remove.setToolTipText("Remove selected flows");
177 remove.addSelectionListener(new SelectionListener() {
178 public void widgetSelected(SelectionEvent e) {
179 removeSelectedFlows();
180 }
181
182 public void widgetDefaultSelected(SelectionEvent e) {
183 widgetSelected(e);
184 }
185 });
186
187 clear = tk.createButton(controls, null, SWT.PUSH);
188 clear.setImage(SlcImages.REMOVE_ALL);
189 clear.setToolTipText("Clear all flows");
190 clear.addSelectionListener(new SelectionListener() {
191 public void widgetSelected(SelectionEvent e) {
192 removeAllFlows();
193 }
194
195 public void widgetDefaultSelected(SelectionEvent e) {
196 widgetSelected(e);
197 }
198 });
199
200 Composite statusComposite = tk.createComposite(controls);
201 RowData rowData = new RowData();
202 rowData.width = 100;
203 rowData.height = 16;
204 statusComposite.setLayoutData(rowData);
205 statusComposite.setLayout(new FillLayout());
206 statusLabel = tk.createLabel(statusComposite, getProcessStatus());
207
208 }
209
210 protected void createBuilder(Composite parent) {
211 FormToolkit tk = getManagedForm().getToolkit();
212 SashForm sashForm = new SashForm(parent, SWT.HORIZONTAL);
213 sashForm.setSashWidth(4);
214 GridData sahFormGd = new GridData(SWT.FILL, SWT.FILL, true, true);
215 sahFormGd.widthHint = 400;
216 sashForm.setLayoutData(sahFormGd);
217
218 Composite flowsComposite = tk.createComposite(sashForm);
219 flowsComposite.setLayout(new GridLayout(1, false));
220
221 flowsViewer = new TreeViewer(flowsComposite);
222 flowsViewer.getTree().setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
223 flowsViewer.setLabelProvider(new FlowsLabelProvider());
224 flowsViewer.setContentProvider(new FlowsContentProvider());
225 flowsViewer.addSelectionChangedListener(new FlowsSelectionListener());
226
227 int operations = DND.DROP_COPY | DND.DROP_MOVE;
228 Transfer[] tt = new Transfer[] { TextTransfer.getInstance() };
229 flowsViewer.addDropSupport(operations, tt, new FlowsDropListener(flowsViewer));
230
231 // Context menu
232 addContextMenu();
233
234 flowsViewer.setInput(getEditorSite());
235 flowsViewer.setInput(processNode);
236
237 Composite valuesComposite = tk.createComposite(sashForm);
238 valuesComposite.setLayout(new GridLayout(1, false));
239
240 valuesViewer = new TableViewer(valuesComposite);
241 GridData valuedGd = new GridData(SWT.FILL, SWT.FILL, true, true);
242 // valuedGd.widthHint = 200;
243 valuesViewer.getTable().setLayoutData(valuedGd);
244 valuesViewer.getTable().setHeaderVisible(true);
245
246 valuesViewer.setContentProvider(new ValuesContentProvider());
247 initializeValuesViewer(valuesViewer);
248 sashForm.setWeights(getWeights());
249 valuesViewer.setInput(getEditorSite());
250 }
251
252 /** Creates the columns of the values viewer */
253 protected void initializeValuesViewer(TableViewer viewer) {
254 String[] titles = { "Name", "Value" };
255 int[] bounds = { 200, 100 };
256
257 for (int i = 0; i < titles.length; i++) {
258 TableViewerColumn column = new TableViewerColumn(viewer, SWT.NONE);
259 column.getColumn().setText(titles[i]);
260 column.getColumn().setWidth(bounds[i]);
261 column.getColumn().setResizable(true);
262 column.getColumn().setMoveable(true);
263 if (i == 0) {
264 column.setLabelProvider(new ColumnLabelProvider() {
265 public String getText(Object element) {
266 try {
267 Node specAttrNode = (Node) element;
268 return specAttrNode.getName();
269 } catch (RepositoryException e) {
270 throw new SlcException("Cannot get value", e);
271 }
272 }
273 });
274 } else if (i == 1) {
275 column.setLabelProvider(new ColumnLabelProvider() {
276 public String getText(Object element) {
277 return getAttributeSpecText((Node) element);
278 }
279 });
280 column.setEditingSupport(new ValuesEditingSupport(viewer));
281 }
282
283 }
284 Table table = viewer.getTable();
285 table.setHeaderVisible(false);
286 table.setLinesVisible(true);
287 }
288
289 protected int[] getWeights() {
290 return new int[] { 50, 50 };
291 }
292
293 /*
294 * CONTROLLERS
295 */
296 /** Reflects a status change */
297 protected void statusChanged() {
298 String status = getProcessStatus();
299 statusLabel.setText(status);
300 Boolean isEditable = isEditable(status);
301 run.setEnabled(status.equals(ExecutionProcess.RUNNING) || isEditable);
302 remove.setEnabled(isEditable);
303 clear.setEnabled(isEditable);
304 // flowsViewer.getTree().setEnabled(isEditable);
305 if (status.equals(ExecutionProcess.RUNNING)) {
306 run.setEnabled(true);
307 run.setImage(SlcImages.KILL);
308 run.setToolTipText("Kill");
309 } else if (isFinished(status)) {
310 run.setEnabled(true);
311 run.setImage(SlcImages.RELAUNCH);
312 run.setToolTipText("Relaunch");
313 }
314
315 if (flowsViewer != null)
316 flowsViewer.refresh();
317 }
318
319 /** Adds initial flows from the editor input if any */
320 protected void addInitialFlows() {
321 for (String path : ((ProcessEditorInput) getEditorInput()).getInitialFlowPaths()) {
322 addFlow(path);
323 }
324 }
325
326 /**
327 * Adds a new flow.
328 *
329 * @param path the path of the flow
330 */
331 protected void addFlow(String path) {
332 try {
333 Node flowNode = agentSession.getNode(path);
334 Node realizedFlowNode = processNode.getNode(SLC_FLOW).addNode(SLC_FLOW);
335 realizedFlowNode.setProperty(SLC_NAME, flowNode.getProperty(SLC_NAME).getString());
336 realizedFlowNode.addMixin(SlcTypes.SLC_REALIZED_FLOW);
337 Node address = realizedFlowNode.addNode(SLC_ADDRESS, NodeType.NT_ADDRESS);
338 address.setProperty(Property.JCR_PATH, path);
339
340 // copy spec attributes
341 Node specAttrsBase;
342 if (flowNode.hasProperty(SLC_SPEC)) {
343 Node executionSpecNode = flowNode.getProperty(SLC_SPEC).getNode();
344 specAttrsBase = executionSpecNode;
345 String executionSpecName = executionSpecNode.getProperty(SLC_NAME).getString();
346 realizedFlowNode.setProperty(SLC_SPEC, executionSpecName);
347 } else
348 specAttrsBase = flowNode;
349
350 specAttrs: for (NodeIterator nit = specAttrsBase.getNodes(); nit.hasNext();) {
351 Node specAttrNode = nit.nextNode();
352 String attrName = specAttrNode.getName();
353 if (!specAttrNode.isNodeType(SlcTypes.SLC_EXECUTION_SPEC_ATTRIBUTE))
354 continue specAttrs;
355 Node realizedAttrNode = realizedFlowNode.addNode(specAttrNode.getName());
356 JcrUtils.copy(specAttrNode, realizedAttrNode);
357
358 // override with flow value
359 if (flowNode.hasNode(attrName)) {
360 // assuming this is a primitive
361 Node attrNode = flowNode.getNode(attrName);
362 if (attrNode.hasProperty(SLC_VALUE))
363 realizedAttrNode.setProperty(SLC_VALUE, attrNode.getProperty(SLC_VALUE).getValue());
364 }
365 }
366
367 // Part title
368 StringBuilder editorTitle = new StringBuilder();
369 NodeIterator it = realizedFlowNode.getParent().getNodes(SLC_FLOW);
370 while (it.hasNext()) {
371 Node rFlowNode = it.nextNode();
372 String name = rFlowNode.getProperty(SLC_NAME).getString();
373 editorTitle.append(name).append(' ');
374 }
375 ((ProcessEditor) getEditor()).setEditorTitle(editorTitle.toString());
376
377 flowsViewer.refresh();
378 formPart.markDirty();
379 } catch (RepositoryException e) {
380 throw new SlcException("Cannot add flow " + path, e);
381 }
382 }
383
384 @SuppressWarnings("unchecked")
385 protected void removeSelectedFlows() {
386 if (!flowsViewer.getSelection().isEmpty()) {
387 Iterator<Object> it = ((StructuredSelection) flowsViewer.getSelection()).iterator();
388 while (it.hasNext()) {
389 Node node = (Node) it.next();
390 try {
391 node.remove();
392 } catch (RepositoryException e) {
393 throw new SlcException("Cannot remove " + node, e);
394 }
395 }
396 flowsViewer.refresh();
397 formPart.markDirty();
398 }
399 }
400
401 protected void removeAllFlows() {
402 try {
403 for (NodeIterator nit = processNode.getNode(SLC_FLOW).getNodes(); nit.hasNext();) {
404 nit.nextNode().remove();
405 }
406 flowsViewer.refresh();
407 formPart.markDirty();
408 } catch (RepositoryException e) {
409 throw new SlcException("Cannot remove flows from " + processNode, e);
410 }
411 }
412
413 public void commit(Boolean onSave) {
414 if (onSave)
415 statusLabel.setText(getProcessStatus());
416 formPart.commit(onSave);
417 }
418
419 /*
420 * STATE
421 */
422 protected String getProcessStatus() {
423 try {
424 return processNode.getProperty(SLC_STATUS).getString();
425 } catch (RepositoryException e) {
426 throw new SlcException("Cannot retrieve status for " + processNode, e);
427 }
428 }
429
430 /** Optimization so that we don't call the node each time */
431 protected static Boolean isEditable(String status) {
432 return status.equals(ExecutionProcess.NEW) || status.equals(ExecutionProcess.INITIALIZED);
433 }
434
435 protected static Boolean isFinished(String status) {
436 return status.equals(ExecutionProcess.COMPLETED) || status.equals(ExecutionProcess.ERROR)
437 || status.equals(ExecutionProcess.KILLED);
438 }
439
440 protected static Boolean isRunning(String status) {
441 return status.equals(ExecutionProcess.RUNNING);
442 }
443
444 /*
445 * LIFECYCLE
446 */
447 @Override
448 public void dispose() {
449 JcrUtils.unregisterQuietly(processNode, statusObserver);
450 JcrUtils.logoutQuietly(agentSession);
451 super.dispose();
452 }
453
454 /*
455 * UTILITIES
456 */
457 protected static String getAttributeSpecText(Node specAttrNode) {
458 try {
459 if (specAttrNode.isNodeType(SlcTypes.SLC_PRIMITIVE_SPEC_ATTRIBUTE)) {
460 if (!specAttrNode.hasProperty(SLC_VALUE))
461 return "";
462 String type = specAttrNode.getProperty(SLC_TYPE).getString();
463 if (PrimitiveAccessor.TYPE_PASSWORD.equals(type))
464 return "****************";
465 Object value = PrimitiveUtils.convert(type, specAttrNode.getProperty(SLC_VALUE).getString());
466 return value.toString();
467 } else if (specAttrNode.isNodeType(SlcTypes.SLC_REF_SPEC_ATTRIBUTE)) {
468 if (specAttrNode.hasProperty(SLC_VALUE)) {
469 int value = (int) specAttrNode.getProperty(SLC_VALUE).getLong();
470 NodeIterator children = specAttrNode.getNodes();
471 int index = 0;
472 while (children.hasNext()) {
473 Node child = children.nextNode();
474 if (index == value)
475 return child.getProperty(Property.JCR_TITLE).getString();
476 index++;
477 }
478 throw new SlcException("No child node with index " + value + " for spec attribute " + specAttrNode);
479 } else
480 return "";
481 }
482 throw new SlcException("Unsupported type for spec attribute " + specAttrNode);
483 } catch (RepositoryException e) {
484 throw new SlcException("Cannot get value", e);
485 }
486 }
487
488 /*
489 * FLOWS SUBCLASSES
490 */
491 class FlowsContentProvider implements ITreeContentProvider {
492 public Object[] getElements(Object obj) {
493 if (!(obj instanceof Node))
494 return new Object[0];
495
496 try {
497 Node node = (Node) obj;
498 List<Node> children = new ArrayList<Node>();
499 for (NodeIterator nit = node.getNode(SLC_FLOW).getNodes(); nit.hasNext();) {
500 Node flowNode = nit.nextNode();
501 children.add(flowNode);
502 }
503 return children.toArray();
504 } catch (RepositoryException e) {
505 throw new SlcException("Cannot list flows of " + obj, e);
506 }
507 }
508
509 public void inputChanged(Viewer arg0, Object arg1, Object arg2) {
510 }
511
512 public void dispose() {
513 }
514
515 public Object[] getChildren(Object parentElement) {
516 // no children for the time being
517 return null;
518 }
519
520 public Object getParent(Object element) {
521 return null;
522 }
523
524 public boolean hasChildren(Object element) {
525 return false;
526 }
527
528 }
529
530 static class FlowsLabelProvider extends ColumnLabelProvider {
531 @Override
532 public String getText(Object element) {
533 Node node = (Node) element;
534 try {
535 if (node.isNodeType(SlcTypes.SLC_REALIZED_FLOW)) {
536 if (node.hasNode(SLC_ADDRESS)) {
537 String path = node.getNode(SLC_ADDRESS).getProperty(Property.JCR_PATH).getString();
538 String executionModuleName = SlcJcrUtils.moduleName(path);
539 // Node executionModuleNode = node.getSession().getNode(
540 // SlcJcrUtils.modulePath(path));
541 // String executionModuleName = executionModuleNode
542 // .getProperty(SLC_NAME).getString();
543 return executionModuleName + ":" + SlcJcrUtils.flowRelativePath(path);
544 }
545 }
546 } catch (RepositoryException e) {
547 throw new SlcException("Cannot display " + element, e);
548 }
549 return super.getText(element);
550 }
551
552 @Override
553 public Image getImage(Object element) {
554 Node node = (Node) element;
555 try {
556 if (node.isNodeType(SlcTypes.SLC_REALIZED_FLOW)) {
557 if (node.hasProperty(SLC_STATUS)) {
558 String status = node.getProperty(SLC_STATUS).getString();
559 // TODO: factorize with process view ?
560 if (status.equals(ExecutionProcess.RUNNING))
561 return SlcImages.PROCESS_RUNNING;
562 else if (status.equals(ExecutionProcess.ERROR) || status.equals(ExecutionProcess.KILLED))
563 return SlcImages.PROCESS_ERROR;
564 else if (status.equals(ExecutionProcess.COMPLETED))
565 return SlcImages.PROCESS_COMPLETED;
566 }
567 return SlcImages.FLOW;
568 }
569 } catch (RepositoryException e) {
570 throw new SlcException("Cannot display " + element, e);
571 }
572 return super.getImage(element);
573 }
574
575 }
576
577 /** Parameter view is updated each time a new line is selected */
578 class FlowsSelectionListener implements ISelectionChangedListener {
579 public void selectionChanged(SelectionChangedEvent evt) {
580 if (evt.getSelection().isEmpty()) {
581 valuesViewer.setInput(getEditorSite());
582 return;
583 }
584 Node realizedFlowNode = (Node) ((IStructuredSelection) evt.getSelection()).getFirstElement();
585 valuesViewer.setInput(realizedFlowNode);
586 }
587 }
588
589 /**
590 * Add a context menu that call private methods. It only relies on selected
591 * item(s) not on parameter that are passed in the menuAboutToShow method
592 **/
593 private void addContextMenu() {
594 Menu menu = new Menu(flowsViewer.getControl());
595
596 MenuItem removeItems = new MenuItem(menu, SWT.PUSH);
597 removeItems.addSelectionListener(new SelectionListener() {
598
599 public void widgetSelected(SelectionEvent e) {
600 removeSelectedFlows();
601 }
602
603 public void widgetDefaultSelected(SelectionEvent e) {
604 }
605 });
606 removeItems.setText("Remove selected flow(s)");
607
608 MenuItem removeAllItems = new MenuItem(menu, SWT.PUSH);
609 removeAllItems.addSelectionListener(new SelectionListener() {
610
611 public void widgetSelected(SelectionEvent e) {
612 removeAllFlows();
613 }
614
615 public void widgetDefaultSelected(SelectionEvent e) {
616 }
617 });
618 removeAllItems.setText("Remove all flows");
619 flowsViewer.getTree().setMenu(menu);
620 }
621
622 /** Manages drop event. */
623 class FlowsDropListener extends ViewerDropAdapter {
624
625 public FlowsDropListener(Viewer viewer) {
626 super(viewer);
627 }
628
629 @Override
630 public boolean performDrop(Object data) {
631
632 // Parse the received String, paths are separated with a carriage
633 // return
634 String[] paths = data.toString().split(new String("\n"));
635 SortedSet<String> resultPaths = new TreeSet<String>();
636 for (String path : paths) {
637 try {
638 // either a node or a whole directory can have been dragged
639 QueryManager qm = processNode.getSession().getWorkspace().getQueryManager();
640 String statement = "SELECT * FROM [" + SlcTypes.SLC_EXECUTION_FLOW + "] WHERE ISDESCENDANTNODE(['"
641 + path + "']) OR ISSAMENODE(['" + path + "'])";
642 Query query = qm.createQuery(statement, Query.JCR_SQL2);
643
644 // order paths
645 for (NodeIterator nit = query.execute().getNodes(); nit.hasNext();) {
646 String currPath = nit.nextNode().getPath();
647 // do not add twice a same flow
648 if (!resultPaths.contains(currPath))
649 resultPaths.add(currPath);
650 }
651 } catch (RepositoryException e) {
652 throw new SlcException("Cannot query flows under " + path, e);
653 }
654 }
655 for (String p : resultPaths) {
656 addFlow(p);
657 }
658 return true;
659
660 }
661
662 @Override
663 public boolean validateDrop(Object target, int operation, TransferData transferType) {
664 return isEditable(getProcessStatus());
665 }
666 }
667
668 /*
669 * VALUES SUBCLASSES
670 */
671 static class ValuesContentProvider implements IStructuredContentProvider {
672
673 public Object[] getElements(Object inputElement) {
674 if (!(inputElement instanceof Node))
675 return new Object[0];
676
677 try {
678 Node realizedFlowNode = (Node) inputElement;
679 List<Node> specAttributes = new ArrayList<Node>();
680 specAttrs: for (NodeIterator nit = realizedFlowNode.getNodes(); nit.hasNext();) {
681 Node specAttrNode = nit.nextNode();
682 if (!specAttrNode.isNodeType(SlcTypes.SLC_EXECUTION_SPEC_ATTRIBUTE))
683 continue specAttrs;
684 // workaround to enable hiding of necessary but unusable
685 // flow parameters
686 else if (specAttrNode.hasProperty(SlcNames.SLC_IS_HIDDEN)
687 && specAttrNode.getProperty(SlcNames.SLC_IS_HIDDEN).getBoolean())
688 continue specAttrs;
689 specAttributes.add(specAttrNode);
690 }
691 return specAttributes.toArray();
692 } catch (RepositoryException e) {
693 throw new SlcException("Cannot get elements", e);
694 }
695 }
696
697 public void dispose() {
698 }
699
700 public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
701 }
702 }
703
704 class ValuesEditingSupport extends EditingSupport {
705 private final TableViewer tableViewer;
706
707 public ValuesEditingSupport(ColumnViewer viewer) {
708 super(viewer);
709 tableViewer = (TableViewer) viewer;
710 }
711
712 @Override
713 protected CellEditor getCellEditor(Object element) {
714 try {
715 Node specAttrNode = (Node) element;
716 if (specAttrNode.isNodeType(SlcTypes.SLC_PRIMITIVE_SPEC_ATTRIBUTE)) {
717 String type = specAttrNode.getProperty(SLC_TYPE).getString();
718 if (PrimitiveAccessor.TYPE_PASSWORD.equals(type)) {
719 return new TextCellEditor(tableViewer.getTable(), SWT.PASSWORD);
720 } else {
721 return new TextCellEditor(tableViewer.getTable());
722 }
723 } else if (specAttrNode.isNodeType(SlcTypes.SLC_REF_SPEC_ATTRIBUTE)) {
724 NodeIterator children = specAttrNode.getNodes();
725 ArrayList<String> items = new ArrayList<String>();
726 while (children.hasNext()) {
727 Node child = children.nextNode();
728 if (child.isNodeType(NodeType.MIX_TITLE))
729 items.add(child.getProperty(Property.JCR_TITLE).getString());
730 }
731 return new ComboBoxCellEditor(tableViewer.getTable(), items.toArray(new String[items.size()]));
732 }
733 return null;
734 } catch (RepositoryException e) {
735 throw new SlcException("Cannot get cell editor", e);
736 }
737 }
738
739 @Override
740 protected boolean canEdit(Object element) {
741 try {
742 Node specAttrNode = (Node) element;
743 Boolean cannotEdit = specAttrNode.getProperty(SLC_IS_IMMUTABLE).getBoolean()
744 || specAttrNode.getProperty(SLC_IS_CONSTANT).getBoolean();
745 return !cannotEdit && isSupportedAttributeType(specAttrNode);
746 } catch (RepositoryException e) {
747 throw new SlcException("Cannot check whether " + element + " is editable", e);
748 }
749 }
750
751 /**
752 * Supports {@link SlcTypes#SLC_PRIMITIVE_SPEC_ATTRIBUTE} and
753 * {@link SlcTypes#SLC_REF_SPEC_ATTRIBUTE}
754 */
755 protected boolean isSupportedAttributeType(Node specAttrNode) throws RepositoryException {
756 return specAttrNode.isNodeType(SlcTypes.SLC_PRIMITIVE_SPEC_ATTRIBUTE)
757 || specAttrNode.isNodeType(SlcTypes.SLC_REF_SPEC_ATTRIBUTE);
758 }
759
760 @Override
761 protected Object getValue(Object element) {
762 Node specAttrNode = (Node) element;
763 try {
764 if (specAttrNode.isNodeType(SlcTypes.SLC_PRIMITIVE_SPEC_ATTRIBUTE)) {
765 if (!specAttrNode.hasProperty(SLC_VALUE))
766 return NONE;
767 String type = specAttrNode.getProperty(SLC_TYPE).getString();
768 // TODO optimize based on data type?
769 Object value = PrimitiveUtils.convert(type, specAttrNode.getProperty(SLC_VALUE).getString());
770 return value.toString();
771 } else if (specAttrNode.isNodeType(SlcTypes.SLC_REF_SPEC_ATTRIBUTE)) {
772 if (!specAttrNode.hasProperty(SLC_VALUE))
773 return 0;
774 // return the index of the sub node as set by setValue()
775 // in the future we may manage references as well
776 return (int) specAttrNode.getProperty(SLC_VALUE).getLong();
777 }
778 throw new SlcException("Unsupported type for spec attribute " + specAttrNode);
779 } catch (RepositoryException e) {
780 throw new SlcException("Cannot get value for " + element, e);
781 }
782 }
783
784 @Override
785 protected void setValue(Object element, Object value) {
786 try {
787 Node specAttrNode = (Node) element;
788 if (specAttrNode.isNodeType(SlcTypes.SLC_PRIMITIVE_SPEC_ATTRIBUTE)) {
789 String type = specAttrNode.getProperty(SLC_TYPE).getString();
790 SlcJcrUtils.setPrimitiveAsProperty(specAttrNode, SLC_VALUE, type, value);
791 valuesViewer.refresh();
792 formPart.markDirty();
793 } else if (specAttrNode.isNodeType(SlcTypes.SLC_REF_SPEC_ATTRIBUTE)) {
794 specAttrNode.setProperty(SLC_VALUE, ((Integer) value).longValue());
795 valuesViewer.refresh();
796 formPart.markDirty();
797 }
798 } catch (RepositoryException e) {
799 throw new SlcException("Cannot get celle editor", e);
800 }
801 }
802
803 }
804 }