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