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