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