]> git.argeo.org Git - gpl/argeo-slc.git/blob - eclipse/plugins/org.argeo.slc.client.ui/src/main/java/org/argeo/slc/client/ui/editors/ProcessBuilderPage.java
Make module operations interruptible
[gpl/argeo-slc.git] / eclipse / 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 return SlcJcrUtils.flowExecutionModuleName(path) + ":"
576 + SlcJcrUtils.flowRelativePath(path);
577 }
578 }
579 } catch (RepositoryException e) {
580 throw new SlcException("Cannot display " + element, e);
581 }
582 return super.getText(element);
583 }
584
585 @Override
586 public Image getImage(Object element) {
587 Node node = (Node) element;
588 try {
589 if (node.isNodeType(SlcTypes.SLC_REALIZED_FLOW)) {
590 if (node.hasProperty(SLC_STATUS)) {
591 String status = node.getProperty(SLC_STATUS)
592 .getString();
593 // TODO: factorize with process view ?
594 if (status.equals(ExecutionProcess.RUNNING))
595 return SlcImages.PROCESS_RUNNING;
596 else if (status.equals(ExecutionProcess.ERROR)
597 || status.equals(ExecutionProcess.KILLED))
598 return SlcImages.PROCESS_ERROR;
599 else if (status.equals(ExecutionProcess.COMPLETED))
600 return SlcImages.PROCESS_COMPLETED;
601 }
602 return SlcImages.FLOW;
603 }
604 } catch (RepositoryException e) {
605 throw new SlcException("Cannot display " + element, e);
606 }
607 return super.getImage(element);
608 }
609
610 }
611
612 /** Parameter view is updated each time a new line is selected */
613 class FlowsSelectionListener implements ISelectionChangedListener {
614 public void selectionChanged(SelectionChangedEvent evt) {
615 if (evt.getSelection().isEmpty()) {
616 valuesViewer.setInput(getEditorSite());
617 return;
618 }
619 Node realizedFlowNode = (Node) ((IStructuredSelection) evt
620 .getSelection()).getFirstElement();
621 valuesViewer.setInput(realizedFlowNode);
622 }
623 }
624
625 /** Manages drop event. */
626 class FlowsDropListener extends ViewerDropAdapter {
627
628 public FlowsDropListener(Viewer viewer) {
629 super(viewer);
630 }
631
632 @Override
633 public boolean performDrop(Object data) {
634 String path = data.toString();
635 try {
636 // either a node or a whole directory was dragged
637 QueryManager qm = processNode.getSession().getWorkspace()
638 .getQueryManager();
639 String statement = "SELECT * FROM ["
640 + SlcTypes.SLC_EXECUTION_FLOW
641 + "] WHERE ISDESCENDANTNODE(['" + path
642 + "']) OR ISSAMENODE(['" + path + "'])";
643 // log.debug(statement);
644 Query query = qm.createQuery(statement, Query.JCR_SQL2);
645
646 // order paths
647 SortedSet<String> paths = new TreeSet<String>();
648 for (NodeIterator nit = query.execute().getNodes(); nit
649 .hasNext();) {
650 paths.add(nit.nextNode().getPath());
651 }
652
653 for (String p : paths) {
654 addFlow(p);
655 }
656 return true;
657 } catch (RepositoryException e) {
658 throw new SlcException("Cannot query flows under " + path, e);
659 }
660 }
661
662 @Override
663 public boolean validateDrop(Object target, int operation,
664 TransferData transferType) {
665 return isEditable(getProcessStatus());
666 }
667 }
668
669 /*
670 * VALUES SUBCLASSES
671 */
672 static class ValuesContentProvider implements IStructuredContentProvider {
673
674 public Object[] getElements(Object inputElement) {
675 if (!(inputElement instanceof Node))
676 return new Object[0];
677
678 try {
679 Node realizedFlowNode = (Node) inputElement;
680 List<Node> specAttributes = new ArrayList<Node>();
681 specAttrs: for (NodeIterator nit = realizedFlowNode.getNodes(); nit
682 .hasNext();) {
683 Node specAttrNode = nit.nextNode();
684 if (!specAttrNode
685 .isNodeType(SlcTypes.SLC_EXECUTION_SPEC_ATTRIBUTE))
686 continue specAttrs;
687 specAttributes.add(specAttrNode);
688 }
689 return specAttributes.toArray();
690 } catch (RepositoryException e) {
691 throw new SlcException("Cannot get elements", e);
692 }
693 }
694
695 public void dispose() {
696 }
697
698 public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
699 }
700 }
701
702 class ValuesEditingSupport extends EditingSupport {
703 private final TableViewer tableViewer;
704
705 public ValuesEditingSupport(ColumnViewer viewer) {
706 super(viewer);
707 tableViewer = (TableViewer) viewer;
708 }
709
710 @Override
711 protected CellEditor getCellEditor(Object element) {
712 try {
713 Node specAttrNode = (Node) element;
714 if (specAttrNode
715 .isNodeType(SlcTypes.SLC_PRIMITIVE_SPEC_ATTRIBUTE)) {
716 return new TextCellEditor(tableViewer.getTable());
717 } else if (specAttrNode
718 .isNodeType(SlcTypes.SLC_REF_SPEC_ATTRIBUTE)) {
719 NodeIterator children = specAttrNode.getNodes();
720 ArrayList<String> items = new ArrayList<String>();
721 while (children.hasNext()) {
722 Node child = children.nextNode();
723 if (child.isNodeType(NodeType.MIX_TITLE))
724 items.add(child.getProperty(Property.JCR_TITLE)
725 .getString());
726 }
727 return new ComboBoxCellEditor(tableViewer.getTable(),
728 items.toArray(new String[items.size()]));
729 }
730 return null;
731 } catch (RepositoryException e) {
732 throw new SlcException("Cannot get celle editor", e);
733 }
734 }
735
736 @Override
737 protected boolean canEdit(Object element) {
738 try {
739 Node specAttrNode = (Node) element;
740 return !(specAttrNode.getProperty(SLC_IS_IMMUTABLE)
741 .getBoolean() || specAttrNode.getProperty(
742 SLC_IS_CONSTANT).getBoolean())
743 && isSupportedAttributeType(specAttrNode);
744 } catch (RepositoryException e) {
745 throw new SlcException("Cannot check whether " + element
746 + " is editable", e);
747 }
748 }
749
750 /**
751 * Supports {@link SlcTypes#SLC_PRIMITIVE_SPEC_ATTRIBUTE} and
752 * {@link SlcTypes#SLC_REF_SPEC_ATTRIBUTE}
753 */
754 protected boolean isSupportedAttributeType(Node specAttrNode)
755 throws RepositoryException {
756 return specAttrNode
757 .isNodeType(SlcTypes.SLC_PRIMITIVE_SPEC_ATTRIBUTE)
758 || specAttrNode.isNodeType(SlcTypes.SLC_REF_SPEC_ATTRIBUTE);
759 }
760
761 @Override
762 protected Object getValue(Object element) {
763 Node specAttrNode = (Node) element;
764 try {
765 // Object value = getAttributeSpecValue(specAttrNode);
766 // if (value == null)
767 // throw new SlcException("Unsupported attribute " + element);
768 if (specAttrNode
769 .isNodeType(SlcTypes.SLC_PRIMITIVE_SPEC_ATTRIBUTE)) {
770 if (!specAttrNode.hasProperty(SLC_VALUE))
771 return NONE;
772 String type = specAttrNode.getProperty(SLC_TYPE)
773 .getString();
774 // TODO optimize based on data type?
775 Object value = PrimitiveUtils.convert(type, specAttrNode
776 .getProperty(SLC_VALUE).getString());
777 return value.toString();
778 } else if (specAttrNode
779 .isNodeType(SlcTypes.SLC_REF_SPEC_ATTRIBUTE)) {
780 if (!specAttrNode.hasProperty(SLC_VALUE))
781 return 0;
782 // return the index of the sub node as set by setValue()
783 // in the future we may manage references as well
784 return (int) specAttrNode.getProperty(SLC_VALUE).getLong();
785 }
786 throw new SlcException("Unsupported type for spec attribute "
787 + specAttrNode);
788 } catch (RepositoryException e) {
789 throw new SlcException("Cannot get value for " + element, e);
790 }
791 }
792
793 @Override
794 protected void setValue(Object element, Object value) {
795 try {
796 Node specAttrNode = (Node) element;
797 if (specAttrNode
798 .isNodeType(SlcTypes.SLC_PRIMITIVE_SPEC_ATTRIBUTE)) {
799 String type = specAttrNode.getProperty(SLC_TYPE)
800 .getString();
801 SlcJcrUtils.setPrimitiveAsProperty(specAttrNode, SLC_VALUE,
802 type, value);
803 valuesViewer.refresh();
804 formPart.markDirty();
805 } else if (specAttrNode
806 .isNodeType(SlcTypes.SLC_REF_SPEC_ATTRIBUTE)) {
807 specAttrNode.setProperty(SLC_VALUE,
808 ((Integer) value).longValue());
809 valuesViewer.refresh();
810 formPart.markDirty();
811 }
812 } catch (RepositoryException e) {
813 throw new SlcException("Cannot get celle editor", e);
814 }
815 }
816
817 }
818 }