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