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