2 * Copyright (C) 2007-2012 Argeo GmbH
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
16 package org
.argeo
.slc
.client
.ui
.editors
;
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
;
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
;
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
;
90 /** Definition of the process. */
91 public class ProcessBuilderPage
extends FormPage
implements SlcNames
{
92 public final static String ID
= "processBuilderPage";
94 /** To be displayed in empty lists */
95 final static String NONE
= "<none>";
97 private Node processNode
;
98 private final ExecutionModulesManager modulesManager
;
100 private TreeViewer flowsViewer
;
101 private TableViewer valuesViewer
;
102 private Label statusLabel
;
104 private Button remove
;
105 private Button clear
;
107 private AbstractFormPart formPart
;
108 private EventListener statusObserver
;
110 public ProcessBuilderPage(ProcessEditor editor
, Node processNode
,
111 ExecutionModulesManager modulesManager
) {
112 super(editor
, ID
, "Definition");
113 this.processNode
= processNode
;
114 this.modulesManager
= modulesManager
;
118 protected void createFormContent(IManagedForm mf
) {
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
);
127 createControls(form
.getBody());
128 createBuilder(form
.getBody());
131 formPart
= new AbstractFormPart() {
134 getManagedForm().addPart(formPart
);
137 statusObserver
= new AsyncUiEventListener(form
.getDisplay()) {
138 protected void onEventInUiThread(List
<Event
> events
) {
142 ObservationManager observationManager
= processNode
.getSession()
143 .getWorkspace().getObservationManager();
144 observationManager
.addEventListener(statusObserver
,
145 Event
.PROPERTY_CHANGED
, processNode
.getPath(), true, null,
148 // make sure all controls are in line with status
154 } catch (RepositoryException e
) {
155 throw new ArgeoException("Cannot create form content", e
);
159 protected void createControls(Composite parent
) {
160 FormToolkit tk
= getManagedForm().getToolkit();
162 Composite controls
= tk
.createComposite(parent
);
163 controls
.setLayout(new RowLayout());
164 controls
.setLayoutData(new GridData(SWT
.FILL
, SWT
.FILL
, true, false));
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();
176 ((ProcessEditor
) getEditor()).process();
180 public void widgetDefaultSelected(SelectionEvent e
) {
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();
193 public void widgetDefaultSelected(SelectionEvent e
) {
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
) {
206 public void widgetDefaultSelected(SelectionEvent e
) {
211 Composite statusComposite
= tk
.createComposite(controls
);
212 RowData rowData
= new RowData();
215 statusComposite
.setLayoutData(rowData
);
216 statusComposite
.setLayout(new FillLayout());
217 statusLabel
= tk
.createLabel(statusComposite
, getProcessStatus());
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
);
229 Composite flowsComposite
= tk
.createComposite(sashForm
);
230 flowsComposite
.setLayout(new GridLayout(1, false));
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());
239 int operations
= DND
.DROP_COPY
| DND
.DROP_MOVE
;
240 Transfer
[] tt
= new Transfer
[] { TextTransfer
.getInstance() };
241 flowsViewer
.addDropSupport(operations
, tt
, new FlowsDropListener(
244 flowsViewer
.setInput(getEditorSite());
245 flowsViewer
.setInput(processNode
);
247 Composite valuesComposite
= tk
.createComposite(sashForm
);
248 valuesComposite
.setLayout(new GridLayout(1, false));
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());
260 /** Creates the columns of the values viewer */
261 protected void initializeValuesViewer(TableViewer viewer
) {
262 String
[] titles
= { "Name", "Value" };
263 int[] bounds
= { 200, 100 };
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);
272 column
.setLabelProvider(new ColumnLabelProvider() {
273 public String
getText(Object element
) {
275 Node specAttrNode
= (Node
) element
;
276 return specAttrNode
.getName();
277 } catch (RepositoryException e
) {
278 throw new SlcException("Cannot get value", e
);
283 column
.setLabelProvider(new ColumnLabelProvider() {
284 public String
getText(Object element
) {
285 return getAttributeSpecText((Node
) element
);
288 column
.setEditingSupport(new ValuesEditingSupport(viewer
));
292 Table table
= viewer
.getTable();
293 table
.setHeaderVisible(false);
294 table
.setLinesVisible(true);
297 protected int[] getWeights() {
298 return new int[] { 50, 50 };
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");
323 if (flowsViewer
!= null)
324 flowsViewer
.refresh();
327 /** Adds initial flows from the editor input if any */
328 protected void addInitialFlows() {
329 for (String path
: ((ProcessEditorInput
) getEditorInput())
330 .getInitialFlowPaths()) {
339 * the path of the flow
341 protected void addFlow(String path
) {
343 Node flowNode
= processNode
.getSession().getNode(path
);
344 Node realizedFlowNode
= processNode
.getNode(SLC_FLOW
).addNode(
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
);
351 // copy spec attributes
353 if (flowNode
.hasProperty(SLC_SPEC
)) {
354 Node executionSpecNode
= flowNode
.getProperty(SLC_SPEC
)
356 specAttrsBase
= executionSpecNode
;
357 String executionSpecName
= executionSpecNode
.getProperty(
358 SLC_NAME
).getString();
359 realizedFlowNode
.setProperty(SLC_SPEC
, executionSpecName
);
361 specAttrsBase
= flowNode
;
363 specAttrs
: for (NodeIterator nit
= specAttrsBase
.getNodes(); nit
365 Node specAttrNode
= nit
.nextNode();
366 String attrName
= specAttrNode
.getName();
368 .isNodeType(SlcTypes
.SLC_EXECUTION_SPEC_ATTRIBUTE
))
370 Node realizedAttrNode
= realizedFlowNode
.addNode(specAttrNode
372 JcrUtils
.copy(specAttrNode
, realizedAttrNode
);
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());
384 flowsViewer
.refresh();
385 formPart
.markDirty();
386 } catch (RepositoryException e
) {
387 throw new SlcException("Cannot drop " + path
, e
);
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();
400 } catch (RepositoryException e
) {
401 throw new ArgeoException("Cannot remove " + node
, e
);
404 flowsViewer
.refresh();
405 formPart
.markDirty();
409 protected void removeAllFlows() {
411 for (NodeIterator nit
= processNode
.getNode(SLC_FLOW
).getNodes(); nit
413 nit
.nextNode().remove();
415 flowsViewer
.refresh();
416 formPart
.markDirty();
417 } catch (RepositoryException e
) {
418 throw new ArgeoException("Cannot remove flows from " + processNode
,
423 public void commit(Boolean onSave
) {
425 statusLabel
.setText(getProcessStatus());
426 formPart
.commit(onSave
);
432 protected String
getProcessStatus() {
434 return processNode
.getProperty(SLC_STATUS
).getString();
435 } catch (RepositoryException e
) {
436 throw new SlcException("Cannot retrieve status for " + processNode
,
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
);
447 protected static Boolean
isFinished(String status
) {
448 return status
.equals(ExecutionProcess
.COMPLETED
)
449 || status
.equals(ExecutionProcess
.ERROR
)
450 || status
.equals(ExecutionProcess
.KILLED
);
453 protected static Boolean
isRunning(String status
) {
454 return status
.equals(ExecutionProcess
.RUNNING
);
461 public void dispose() {
462 JcrUtils
.unregisterQuietly(processNode
, statusObserver
);
469 protected static String
getAttributeSpecText(Node specAttrNode
) {
471 if (specAttrNode
.isNodeType(SlcTypes
.SLC_PRIMITIVE_SPEC_ATTRIBUTE
)) {
472 if (!specAttrNode
.hasProperty(SLC_VALUE
))
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
)
484 NodeIterator children
= specAttrNode
.getNodes();
486 while (children
.hasNext()) {
487 Node child
= children
.nextNode();
489 return child
.getProperty(Property
.JCR_TITLE
)
493 throw new SlcException("No child node with index " + value
494 + " for spec attribute " + specAttrNode
);
498 throw new SlcException("Unsupported type for spec attribute "
500 } catch (RepositoryException e
) {
501 throw new SlcException("Cannot get value", e
);
508 class FlowsContentProvider
implements ITreeContentProvider
{
509 public Object
[] getElements(Object obj
) {
510 if (!(obj
instanceof Node
))
511 return new Object
[0];
514 Node node
= (Node
) obj
;
515 List
<Node
> children
= new ArrayList
<Node
>();
516 for (NodeIterator nit
= node
.getNode(SLC_FLOW
).getNodes(); nit
518 Node flowNode
= nit
.nextNode();
519 children
.add(flowNode
);
521 return children
.toArray();
522 } catch (RepositoryException e
) {
523 throw new SlcException("Cannot list flows of " + obj
, e
);
527 public void inputChanged(Viewer arg0
, Object arg1
, Object arg2
) {
530 public void dispose() {
533 public Object
[] getChildren(Object parentElement
) {
534 // no children for the time being
538 public Object
getParent(Object element
) {
542 public boolean hasChildren(Object element
) {
548 static class FlowsLabelProvider
extends ColumnLabelProvider
{
550 public String
getText(Object element
) {
551 Node node
= (Node
) element
;
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
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
);
567 } catch (RepositoryException e
) {
568 throw new SlcException("Cannot display " + element
, e
);
570 return super.getText(element
);
574 public Image
getImage(Object element
) {
575 Node node
= (Node
) element
;
577 if (node
.isNodeType(SlcTypes
.SLC_REALIZED_FLOW
)) {
578 if (node
.hasProperty(SLC_STATUS
)) {
579 String status
= node
.getProperty(SLC_STATUS
)
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
;
590 return SlcImages
.FLOW
;
592 } catch (RepositoryException e
) {
593 throw new SlcException("Cannot display " + element
, e
);
595 return super.getImage(element
);
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());
607 Node realizedFlowNode
= (Node
) ((IStructuredSelection
) evt
608 .getSelection()).getFirstElement();
609 valuesViewer
.setInput(realizedFlowNode
);
613 /** Manages drop event. */
614 class FlowsDropListener
extends ViewerDropAdapter
{
616 public FlowsDropListener(Viewer viewer
) {
621 public boolean performDrop(Object data
) {
622 String path
= data
.toString();
624 // either a node or a whole directory was dragged
625 QueryManager qm
= processNode
.getSession().getWorkspace()
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
);
635 SortedSet
<String
> paths
= new TreeSet
<String
>();
636 for (NodeIterator nit
= query
.execute().getNodes(); nit
638 paths
.add(nit
.nextNode().getPath());
641 for (String p
: paths
) {
645 } catch (RepositoryException e
) {
646 throw new SlcException("Cannot query flows under " + path
, e
);
651 public boolean validateDrop(Object target
, int operation
,
652 TransferData transferType
) {
653 return isEditable(getProcessStatus());
660 static class ValuesContentProvider
implements IStructuredContentProvider
{
662 public Object
[] getElements(Object inputElement
) {
663 if (!(inputElement
instanceof Node
))
664 return new Object
[0];
667 Node realizedFlowNode
= (Node
) inputElement
;
668 List
<Node
> specAttributes
= new ArrayList
<Node
>();
669 specAttrs
: for (NodeIterator nit
= realizedFlowNode
.getNodes(); nit
671 Node specAttrNode
= nit
.nextNode();
673 .isNodeType(SlcTypes
.SLC_EXECUTION_SPEC_ATTRIBUTE
))
675 specAttributes
.add(specAttrNode
);
677 return specAttributes
.toArray();
678 } catch (RepositoryException e
) {
679 throw new SlcException("Cannot get elements", e
);
683 public void dispose() {
686 public void inputChanged(Viewer viewer
, Object oldInput
, Object newInput
) {
690 class ValuesEditingSupport
extends EditingSupport
{
691 private final TableViewer tableViewer
;
693 public ValuesEditingSupport(ColumnViewer viewer
) {
695 tableViewer
= (TableViewer
) viewer
;
699 protected CellEditor
getCellEditor(Object element
) {
701 Node specAttrNode
= (Node
) element
;
703 .isNodeType(SlcTypes
.SLC_PRIMITIVE_SPEC_ATTRIBUTE
)) {
704 String type
= specAttrNode
.getProperty(SLC_TYPE
)
706 if (PrimitiveAccessor
.TYPE_PASSWORD
.equals(type
)) {
707 return new TextCellEditor(tableViewer
.getTable(),
710 return new TextCellEditor(tableViewer
.getTable());
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
)
722 return new ComboBoxCellEditor(tableViewer
.getTable(),
723 items
.toArray(new String
[items
.size()]));
726 } catch (RepositoryException e
) {
727 throw new SlcException("Cannot get celle editor", e
);
732 protected boolean canEdit(Object element
) {
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
);
746 * Supports {@link SlcTypes#SLC_PRIMITIVE_SPEC_ATTRIBUTE} and
747 * {@link SlcTypes#SLC_REF_SPEC_ATTRIBUTE}
749 protected boolean isSupportedAttributeType(Node specAttrNode
)
750 throws RepositoryException
{
752 .isNodeType(SlcTypes
.SLC_PRIMITIVE_SPEC_ATTRIBUTE
)
753 || specAttrNode
.isNodeType(SlcTypes
.SLC_REF_SPEC_ATTRIBUTE
);
757 protected Object
getValue(Object element
) {
758 Node specAttrNode
= (Node
) element
;
761 .isNodeType(SlcTypes
.SLC_PRIMITIVE_SPEC_ATTRIBUTE
)) {
762 if (!specAttrNode
.hasProperty(SLC_VALUE
))
764 String type
= specAttrNode
.getProperty(SLC_TYPE
)
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
))
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();
778 throw new SlcException("Unsupported type for spec attribute "
780 } catch (RepositoryException e
) {
781 throw new SlcException("Cannot get value for " + element
, e
);
786 protected void setValue(Object element
, Object value
) {
788 Node specAttrNode
= (Node
) element
;
790 .isNodeType(SlcTypes
.SLC_PRIMITIVE_SPEC_ATTRIBUTE
)) {
791 String type
= specAttrNode
.getProperty(SLC_TYPE
)
793 SlcJcrUtils
.setPrimitiveAsProperty(specAttrNode
, SLC_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();
804 } catch (RepositoryException e
) {
805 throw new SlcException("Cannot get celle editor", e
);