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
.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
.PrimitiveAccessor
;
41 import org
.argeo
.slc
.core
.execution
.PrimitiveUtils
;
42 import org
.argeo
.slc
.execution
.ExecutionProcess
;
43 import org
.argeo
.slc
.jcr
.SlcJcrUtils
;
44 import org
.argeo
.slc
.jcr
.SlcNames
;
45 import org
.argeo
.slc
.jcr
.SlcTypes
;
46 import org
.eclipse
.jface
.viewers
.CellEditor
;
47 import org
.eclipse
.jface
.viewers
.ColumnLabelProvider
;
48 import org
.eclipse
.jface
.viewers
.ColumnViewer
;
49 import org
.eclipse
.jface
.viewers
.ComboBoxCellEditor
;
50 import org
.eclipse
.jface
.viewers
.EditingSupport
;
51 import org
.eclipse
.jface
.viewers
.ISelectionChangedListener
;
52 import org
.eclipse
.jface
.viewers
.IStructuredContentProvider
;
53 import org
.eclipse
.jface
.viewers
.IStructuredSelection
;
54 import org
.eclipse
.jface
.viewers
.ITreeContentProvider
;
55 import org
.eclipse
.jface
.viewers
.SelectionChangedEvent
;
56 import org
.eclipse
.jface
.viewers
.StructuredSelection
;
57 import org
.eclipse
.jface
.viewers
.TableViewer
;
58 import org
.eclipse
.jface
.viewers
.TableViewerColumn
;
59 import org
.eclipse
.jface
.viewers
.TextCellEditor
;
60 import org
.eclipse
.jface
.viewers
.TreeViewer
;
61 import org
.eclipse
.jface
.viewers
.Viewer
;
62 import org
.eclipse
.jface
.viewers
.ViewerDropAdapter
;
63 import org
.eclipse
.swt
.SWT
;
64 import org
.eclipse
.swt
.custom
.SashForm
;
65 import org
.eclipse
.swt
.dnd
.DND
;
66 import org
.eclipse
.swt
.dnd
.TextTransfer
;
67 import org
.eclipse
.swt
.dnd
.Transfer
;
68 import org
.eclipse
.swt
.dnd
.TransferData
;
69 import org
.eclipse
.swt
.events
.SelectionEvent
;
70 import org
.eclipse
.swt
.events
.SelectionListener
;
71 import org
.eclipse
.swt
.graphics
.Image
;
72 import org
.eclipse
.swt
.layout
.FillLayout
;
73 import org
.eclipse
.swt
.layout
.GridData
;
74 import org
.eclipse
.swt
.layout
.GridLayout
;
75 import org
.eclipse
.swt
.layout
.RowData
;
76 import org
.eclipse
.swt
.layout
.RowLayout
;
77 import org
.eclipse
.swt
.widgets
.Button
;
78 import org
.eclipse
.swt
.widgets
.Composite
;
79 import org
.eclipse
.swt
.widgets
.Label
;
80 import org
.eclipse
.swt
.widgets
.Menu
;
81 import org
.eclipse
.swt
.widgets
.MenuItem
;
82 import org
.eclipse
.swt
.widgets
.Table
;
83 import org
.eclipse
.ui
.forms
.AbstractFormPart
;
84 import org
.eclipse
.ui
.forms
.IManagedForm
;
85 import org
.eclipse
.ui
.forms
.editor
.FormPage
;
86 import org
.eclipse
.ui
.forms
.widgets
.FormToolkit
;
87 import org
.eclipse
.ui
.forms
.widgets
.ScrolledForm
;
89 /** Definition of the process. */
90 public class ProcessBuilderPage
extends FormPage
implements SlcNames
{
91 // private final static Log log =
92 // LogFactory.getLog(ProcessBuilderPage.class);
94 public final static String ID
= "processBuilderPage";
96 /** To be displayed in empty lists */
97 final static String NONE
= "<none>";
99 private Node processNode
;
101 private TreeViewer flowsViewer
;
102 private TableViewer valuesViewer
;
103 private Label statusLabel
;
105 private Button remove
;
106 private Button clear
;
108 private AbstractFormPart formPart
;
109 private EventListener statusObserver
;
111 public ProcessBuilderPage(ProcessEditor editor
, Node processNode
) {
112 super(editor
, ID
, "Definition");
113 this.processNode
= processNode
;
117 protected void createFormContent(IManagedForm mf
) {
119 ScrolledForm form
= mf
.getForm();
120 form
.setExpandHorizontal(true);
121 form
.setExpandVertical(true);
122 form
.setText("Process " + processNode
.getName());
123 GridLayout mainLayout
= new GridLayout(1, true);
124 form
.getBody().setLayout(mainLayout
);
126 createControls(form
.getBody());
127 createBuilder(form
.getBody());
130 formPart
= new AbstractFormPart() {
133 getManagedForm().addPart(formPart
);
136 statusObserver
= new AsyncUiEventListener(form
.getDisplay()) {
137 protected void onEventInUiThread(List
<Event
> events
) {
141 ObservationManager observationManager
= processNode
.getSession()
142 .getWorkspace().getObservationManager();
143 observationManager
.addEventListener(statusObserver
,
144 Event
.PROPERTY_CHANGED
, processNode
.getPath(), true, null,
147 // make sure all controls are in line with status
153 } catch (RepositoryException e
) {
154 throw new ArgeoException("Cannot create form content", e
);
158 protected void createControls(Composite parent
) {
159 FormToolkit tk
= getManagedForm().getToolkit();
161 Composite controls
= tk
.createComposite(parent
);
162 controls
.setLayout(new RowLayout());
163 controls
.setLayoutData(new GridData(SWT
.FILL
, SWT
.FILL
, true, false));
165 run
= tk
.createButton(controls
, null, SWT
.PUSH
);
166 run
.setToolTipText("Run");
167 run
.setImage(SlcImages
.LAUNCH
);
168 run
.addSelectionListener(new SelectionListener() {
169 public void widgetSelected(SelectionEvent e
) {
170 if (isFinished(getProcessStatus())) {
171 ((ProcessEditor
) getEditor()).relaunch();
172 } else if (isRunning(getProcessStatus())) {
173 ((ProcessEditor
) getEditor()).kill();
175 ((ProcessEditor
) getEditor()).process();
179 public void widgetDefaultSelected(SelectionEvent e
) {
184 remove
= tk
.createButton(controls
, null, SWT
.PUSH
);
185 remove
.setImage(SlcImages
.REMOVE_ONE
);
186 remove
.setToolTipText("Remove selected flows");
187 remove
.addSelectionListener(new SelectionListener() {
188 public void widgetSelected(SelectionEvent e
) {
189 removeSelectedFlows();
192 public void widgetDefaultSelected(SelectionEvent e
) {
197 clear
= tk
.createButton(controls
, null, SWT
.PUSH
);
198 clear
.setImage(SlcImages
.REMOVE_ALL
);
199 clear
.setToolTipText("Clear all flows");
200 clear
.addSelectionListener(new SelectionListener() {
201 public void widgetSelected(SelectionEvent e
) {
205 public void widgetDefaultSelected(SelectionEvent e
) {
210 Composite statusComposite
= tk
.createComposite(controls
);
211 RowData rowData
= new RowData();
214 statusComposite
.setLayoutData(rowData
);
215 statusComposite
.setLayout(new FillLayout());
216 statusLabel
= tk
.createLabel(statusComposite
, getProcessStatus());
220 protected void createBuilder(Composite parent
) {
221 FormToolkit tk
= getManagedForm().getToolkit();
222 SashForm sashForm
= new SashForm(parent
, SWT
.HORIZONTAL
);
223 sashForm
.setSashWidth(4);
224 GridData sahFormGd
= new GridData(SWT
.FILL
, SWT
.FILL
, true, true);
225 sahFormGd
.widthHint
= 400;
226 sashForm
.setLayoutData(sahFormGd
);
228 Composite flowsComposite
= tk
.createComposite(sashForm
);
229 flowsComposite
.setLayout(new GridLayout(1, false));
231 flowsViewer
= new TreeViewer(flowsComposite
);
232 flowsViewer
.getTree().setLayoutData(
233 new GridData(SWT
.FILL
, SWT
.FILL
, true, true));
234 flowsViewer
.setLabelProvider(new FlowsLabelProvider());
235 flowsViewer
.setContentProvider(new FlowsContentProvider());
236 flowsViewer
.addSelectionChangedListener(new FlowsSelectionListener());
238 int operations
= DND
.DROP_COPY
| DND
.DROP_MOVE
;
239 Transfer
[] tt
= new Transfer
[] { TextTransfer
.getInstance() };
240 flowsViewer
.addDropSupport(operations
, tt
, new FlowsDropListener(
246 flowsViewer
.setInput(getEditorSite());
247 flowsViewer
.setInput(processNode
);
249 Composite valuesComposite
= tk
.createComposite(sashForm
);
250 valuesComposite
.setLayout(new GridLayout(1, false));
252 valuesViewer
= new TableViewer(valuesComposite
);
253 GridData valuedGd
= new GridData(SWT
.FILL
, SWT
.FILL
, true, true);
254 // valuedGd.widthHint = 200;
255 valuesViewer
.getTable().setLayoutData(valuedGd
);
256 valuesViewer
.getTable().setHeaderVisible(true);
258 valuesViewer
.setContentProvider(new ValuesContentProvider());
259 initializeValuesViewer(valuesViewer
);
260 sashForm
.setWeights(getWeights());
261 valuesViewer
.setInput(getEditorSite());
264 /** Creates the columns of the values viewer */
265 protected void initializeValuesViewer(TableViewer viewer
) {
266 String
[] titles
= { "Name", "Value" };
267 int[] bounds
= { 200, 100 };
269 for (int i
= 0; i
< titles
.length
; i
++) {
270 TableViewerColumn column
= new TableViewerColumn(viewer
, SWT
.NONE
);
271 column
.getColumn().setText(titles
[i
]);
272 column
.getColumn().setWidth(bounds
[i
]);
273 column
.getColumn().setResizable(true);
274 column
.getColumn().setMoveable(true);
276 column
.setLabelProvider(new ColumnLabelProvider() {
277 public String
getText(Object element
) {
279 Node specAttrNode
= (Node
) element
;
280 return specAttrNode
.getName();
281 } catch (RepositoryException e
) {
282 throw new SlcException("Cannot get value", e
);
287 column
.setLabelProvider(new ColumnLabelProvider() {
288 public String
getText(Object element
) {
289 return getAttributeSpecText((Node
) element
);
292 column
.setEditingSupport(new ValuesEditingSupport(viewer
));
296 Table table
= viewer
.getTable();
297 table
.setHeaderVisible(false);
298 table
.setLinesVisible(true);
301 protected int[] getWeights() {
302 return new int[] { 50, 50 };
308 /** Reflects a status change */
309 protected void statusChanged() {
310 String status
= getProcessStatus();
311 statusLabel
.setText(status
);
312 Boolean isEditable
= isEditable(status
);
313 run
.setEnabled(status
.equals(ExecutionProcess
.RUNNING
) || isEditable
);
314 remove
.setEnabled(isEditable
);
315 clear
.setEnabled(isEditable
);
316 // flowsViewer.getTree().setEnabled(isEditable);
317 if (status
.equals(ExecutionProcess
.RUNNING
)) {
318 run
.setEnabled(true);
319 run
.setImage(SlcImages
.KILL
);
320 run
.setToolTipText("Kill");
321 } else if (isFinished(status
)) {
322 run
.setEnabled(true);
323 run
.setImage(SlcImages
.RELAUNCH
);
324 run
.setToolTipText("Relaunch");
327 if (flowsViewer
!= null)
328 flowsViewer
.refresh();
331 /** Adds initial flows from the editor input if any */
332 protected void addInitialFlows() {
333 for (String path
: ((ProcessEditorInput
) getEditorInput())
334 .getInitialFlowPaths()) {
343 * the path of the flow
345 protected void addFlow(String path
) {
347 Node flowNode
= processNode
.getSession().getNode(path
);
348 Node realizedFlowNode
= processNode
.getNode(SLC_FLOW
).addNode(
350 realizedFlowNode
.addMixin(SlcTypes
.SLC_REALIZED_FLOW
);
351 Node address
= realizedFlowNode
.addNode(SLC_ADDRESS
,
352 NodeType
.NT_ADDRESS
);
353 address
.setProperty(Property
.JCR_PATH
, path
);
355 // copy spec attributes
357 if (flowNode
.hasProperty(SLC_SPEC
)) {
358 Node executionSpecNode
= flowNode
.getProperty(SLC_SPEC
)
360 specAttrsBase
= executionSpecNode
;
361 String executionSpecName
= executionSpecNode
.getProperty(
362 SLC_NAME
).getString();
363 realizedFlowNode
.setProperty(SLC_SPEC
, executionSpecName
);
365 specAttrsBase
= flowNode
;
367 specAttrs
: for (NodeIterator nit
= specAttrsBase
.getNodes(); nit
369 Node specAttrNode
= nit
.nextNode();
370 String attrName
= specAttrNode
.getName();
372 .isNodeType(SlcTypes
.SLC_EXECUTION_SPEC_ATTRIBUTE
))
374 Node realizedAttrNode
= realizedFlowNode
.addNode(specAttrNode
376 JcrUtils
.copy(specAttrNode
, realizedAttrNode
);
378 // override with flow value
379 if (flowNode
.hasNode(attrName
)) {
380 // assuming this is a primitive
381 Node attrNode
= flowNode
.getNode(attrName
);
382 if (attrNode
.hasProperty(SLC_VALUE
))
383 realizedAttrNode
.setProperty(SLC_VALUE
, attrNode
384 .getProperty(SLC_VALUE
).getValue());
388 flowsViewer
.refresh();
389 formPart
.markDirty();
390 } catch (RepositoryException e
) {
391 throw new SlcException("Cannot drop " + path
, e
);
395 @SuppressWarnings("unchecked")
396 protected void removeSelectedFlows() {
397 if (!flowsViewer
.getSelection().isEmpty()) {
398 Iterator
<Object
> it
= ((StructuredSelection
) flowsViewer
399 .getSelection()).iterator();
400 while (it
.hasNext()) {
401 Node node
= (Node
) it
.next();
404 } catch (RepositoryException e
) {
405 throw new ArgeoException("Cannot remove " + node
, e
);
408 flowsViewer
.refresh();
409 formPart
.markDirty();
413 protected void removeAllFlows() {
415 for (NodeIterator nit
= processNode
.getNode(SLC_FLOW
).getNodes(); nit
417 nit
.nextNode().remove();
419 flowsViewer
.refresh();
420 formPart
.markDirty();
421 } catch (RepositoryException e
) {
422 throw new ArgeoException("Cannot remove flows from " + processNode
,
427 public void commit(Boolean onSave
) {
429 statusLabel
.setText(getProcessStatus());
430 formPart
.commit(onSave
);
436 protected String
getProcessStatus() {
438 return processNode
.getProperty(SLC_STATUS
).getString();
439 } catch (RepositoryException e
) {
440 throw new SlcException("Cannot retrieve status for " + processNode
,
445 /** Optimization so that we don't call the node each time */
446 protected static Boolean
isEditable(String status
) {
447 return status
.equals(ExecutionProcess
.NEW
)
448 || status
.equals(ExecutionProcess
.INITIALIZED
);
451 protected static Boolean
isFinished(String status
) {
452 return status
.equals(ExecutionProcess
.COMPLETED
)
453 || status
.equals(ExecutionProcess
.ERROR
)
454 || status
.equals(ExecutionProcess
.KILLED
);
457 protected static Boolean
isRunning(String status
) {
458 return status
.equals(ExecutionProcess
.RUNNING
);
465 public void dispose() {
466 JcrUtils
.unregisterQuietly(processNode
, statusObserver
);
473 protected static String
getAttributeSpecText(Node specAttrNode
) {
475 if (specAttrNode
.isNodeType(SlcTypes
.SLC_PRIMITIVE_SPEC_ATTRIBUTE
)) {
476 if (!specAttrNode
.hasProperty(SLC_VALUE
))
478 String type
= specAttrNode
.getProperty(SLC_TYPE
).getString();
479 if (PrimitiveAccessor
.TYPE_PASSWORD
.equals(type
))
480 return "****************";
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
)
488 NodeIterator children
= specAttrNode
.getNodes();
490 while (children
.hasNext()) {
491 Node child
= children
.nextNode();
493 return child
.getProperty(Property
.JCR_TITLE
)
497 throw new SlcException("No child node with index " + value
498 + " for spec attribute " + specAttrNode
);
502 throw new SlcException("Unsupported type for spec attribute "
504 } catch (RepositoryException e
) {
505 throw new SlcException("Cannot get value", e
);
512 class FlowsContentProvider
implements ITreeContentProvider
{
513 public Object
[] getElements(Object obj
) {
514 if (!(obj
instanceof Node
))
515 return new Object
[0];
518 Node node
= (Node
) obj
;
519 List
<Node
> children
= new ArrayList
<Node
>();
520 for (NodeIterator nit
= node
.getNode(SLC_FLOW
).getNodes(); nit
522 Node flowNode
= nit
.nextNode();
523 children
.add(flowNode
);
525 return children
.toArray();
526 } catch (RepositoryException e
) {
527 throw new SlcException("Cannot list flows of " + obj
, e
);
531 public void inputChanged(Viewer arg0
, Object arg1
, Object arg2
) {
534 public void dispose() {
537 public Object
[] getChildren(Object parentElement
) {
538 // no children for the time being
542 public Object
getParent(Object element
) {
546 public boolean hasChildren(Object element
) {
552 static class FlowsLabelProvider
extends ColumnLabelProvider
{
554 public String
getText(Object element
) {
555 Node node
= (Node
) element
;
557 if (node
.isNodeType(SlcTypes
.SLC_REALIZED_FLOW
)) {
558 if (node
.hasNode(SLC_ADDRESS
)) {
559 String path
= node
.getNode(SLC_ADDRESS
)
560 .getProperty(Property
.JCR_PATH
).getString();
561 String executionModuleName
= SlcJcrUtils
563 // Node executionModuleNode = node.getSession().getNode(
564 // SlcJcrUtils.modulePath(path));
565 // String executionModuleName = executionModuleNode
566 // .getProperty(SLC_NAME).getString();
567 return executionModuleName
+ ":"
568 + SlcJcrUtils
.flowRelativePath(path
);
571 } catch (RepositoryException e
) {
572 throw new SlcException("Cannot display " + element
, e
);
574 return super.getText(element
);
578 public Image
getImage(Object element
) {
579 Node node
= (Node
) element
;
581 if (node
.isNodeType(SlcTypes
.SLC_REALIZED_FLOW
)) {
582 if (node
.hasProperty(SLC_STATUS
)) {
583 String status
= node
.getProperty(SLC_STATUS
)
585 // TODO: factorize with process view ?
586 if (status
.equals(ExecutionProcess
.RUNNING
))
587 return SlcImages
.PROCESS_RUNNING
;
588 else if (status
.equals(ExecutionProcess
.ERROR
)
589 || status
.equals(ExecutionProcess
.KILLED
))
590 return SlcImages
.PROCESS_ERROR
;
591 else if (status
.equals(ExecutionProcess
.COMPLETED
))
592 return SlcImages
.PROCESS_COMPLETED
;
594 return SlcImages
.FLOW
;
596 } catch (RepositoryException e
) {
597 throw new SlcException("Cannot display " + element
, e
);
599 return super.getImage(element
);
604 /** Parameter view is updated each time a new line is selected */
605 class FlowsSelectionListener
implements ISelectionChangedListener
{
606 public void selectionChanged(SelectionChangedEvent evt
) {
607 if (evt
.getSelection().isEmpty()) {
608 valuesViewer
.setInput(getEditorSite());
611 Node realizedFlowNode
= (Node
) ((IStructuredSelection
) evt
612 .getSelection()).getFirstElement();
613 valuesViewer
.setInput(realizedFlowNode
);
618 * Add a context menu that call private methods. It only relies on selected
619 * item(s) not on parameter that are passed in the menuAboutToShow method
621 private void addContextMenu() {
622 Menu menu
= new Menu(flowsViewer
.getControl());
624 MenuItem removeItems
= new MenuItem(menu
, SWT
.PUSH
);
625 removeItems
.addSelectionListener(new SelectionListener() {
627 public void widgetSelected(SelectionEvent e
) {
628 removeSelectedFlows();
631 public void widgetDefaultSelected(SelectionEvent e
) {
634 removeItems
.setText("Remove selected flow(s)");
636 MenuItem removeAllItems
= new MenuItem(menu
, SWT
.PUSH
);
637 removeAllItems
.addSelectionListener(new SelectionListener() {
639 public void widgetSelected(SelectionEvent e
) {
643 public void widgetDefaultSelected(SelectionEvent e
) {
646 removeAllItems
.setText("Remove all flows");
647 flowsViewer
.getTree().setMenu(menu
);
650 /** Manages drop event. */
651 class FlowsDropListener
extends ViewerDropAdapter
{
653 public FlowsDropListener(Viewer viewer
) {
658 public boolean performDrop(Object data
) {
660 // Parse the received String, paths are separated with a carriage
662 String
[] paths
= data
.toString().split(new String("\n"));
663 SortedSet
<String
> resultPaths
= new TreeSet
<String
>();
664 for (String path
: paths
) {
666 // either a node or a whole directory can have been dragged
667 QueryManager qm
= processNode
.getSession().getWorkspace()
669 String statement
= "SELECT * FROM ["
670 + SlcTypes
.SLC_EXECUTION_FLOW
671 + "] WHERE ISDESCENDANTNODE(['" + path
672 + "']) OR ISSAMENODE(['" + path
+ "'])";
673 Query query
= qm
.createQuery(statement
, Query
.JCR_SQL2
);
676 for (NodeIterator nit
= query
.execute().getNodes(); nit
678 String currPath
= nit
.nextNode().getPath();
679 // do not add twice a same flow
680 if (!resultPaths
.contains(currPath
))
681 resultPaths
.add(currPath
);
683 } catch (RepositoryException e
) {
684 throw new SlcException("Cannot query flows under " + path
,
688 for (String p
: resultPaths
) {
696 public boolean validateDrop(Object target
, int operation
,
697 TransferData transferType
) {
698 return isEditable(getProcessStatus());
705 static class ValuesContentProvider
implements IStructuredContentProvider
{
707 public Object
[] getElements(Object inputElement
) {
708 if (!(inputElement
instanceof Node
))
709 return new Object
[0];
712 Node realizedFlowNode
= (Node
) inputElement
;
713 List
<Node
> specAttributes
= new ArrayList
<Node
>();
714 specAttrs
: for (NodeIterator nit
= realizedFlowNode
.getNodes(); nit
716 Node specAttrNode
= nit
.nextNode();
718 .isNodeType(SlcTypes
.SLC_EXECUTION_SPEC_ATTRIBUTE
))
720 // workaround to enable hiding of necessary but unusable
722 else if (specAttrNode
.hasProperty(SlcNames
.SLC_IS_HIDDEN
)
723 && specAttrNode
.getProperty(SlcNames
.SLC_IS_HIDDEN
)
726 specAttributes
.add(specAttrNode
);
728 return specAttributes
.toArray();
729 } catch (RepositoryException e
) {
730 throw new SlcException("Cannot get elements", e
);
734 public void dispose() {
737 public void inputChanged(Viewer viewer
, Object oldInput
, Object newInput
) {
741 class ValuesEditingSupport
extends EditingSupport
{
742 private final TableViewer tableViewer
;
744 public ValuesEditingSupport(ColumnViewer viewer
) {
746 tableViewer
= (TableViewer
) viewer
;
750 protected CellEditor
getCellEditor(Object element
) {
752 Node specAttrNode
= (Node
) element
;
754 .isNodeType(SlcTypes
.SLC_PRIMITIVE_SPEC_ATTRIBUTE
)) {
755 String type
= specAttrNode
.getProperty(SLC_TYPE
)
757 if (PrimitiveAccessor
.TYPE_PASSWORD
.equals(type
)) {
758 return new TextCellEditor(tableViewer
.getTable(),
761 return new TextCellEditor(tableViewer
.getTable());
763 } else if (specAttrNode
764 .isNodeType(SlcTypes
.SLC_REF_SPEC_ATTRIBUTE
)) {
765 NodeIterator children
= specAttrNode
.getNodes();
766 ArrayList
<String
> items
= new ArrayList
<String
>();
767 while (children
.hasNext()) {
768 Node child
= children
.nextNode();
769 if (child
.isNodeType(NodeType
.MIX_TITLE
))
770 items
.add(child
.getProperty(Property
.JCR_TITLE
)
773 return new ComboBoxCellEditor(tableViewer
.getTable(),
774 items
.toArray(new String
[items
.size()]));
777 } catch (RepositoryException e
) {
778 throw new SlcException("Cannot get cell editor", e
);
783 protected boolean canEdit(Object element
) {
785 Node specAttrNode
= (Node
) element
;
786 Boolean cannotEdit
= specAttrNode
.getProperty(SLC_IS_IMMUTABLE
)
788 || specAttrNode
.getProperty(SLC_IS_CONSTANT
)
790 return !cannotEdit
&& isSupportedAttributeType(specAttrNode
);
791 } catch (RepositoryException e
) {
792 throw new SlcException("Cannot check whether " + element
793 + " is editable", e
);
798 * Supports {@link SlcTypes#SLC_PRIMITIVE_SPEC_ATTRIBUTE} and
799 * {@link SlcTypes#SLC_REF_SPEC_ATTRIBUTE}
801 protected boolean isSupportedAttributeType(Node specAttrNode
)
802 throws RepositoryException
{
804 .isNodeType(SlcTypes
.SLC_PRIMITIVE_SPEC_ATTRIBUTE
)
805 || specAttrNode
.isNodeType(SlcTypes
.SLC_REF_SPEC_ATTRIBUTE
);
809 protected Object
getValue(Object element
) {
810 Node specAttrNode
= (Node
) element
;
813 .isNodeType(SlcTypes
.SLC_PRIMITIVE_SPEC_ATTRIBUTE
)) {
814 if (!specAttrNode
.hasProperty(SLC_VALUE
))
816 String type
= specAttrNode
.getProperty(SLC_TYPE
)
818 // TODO optimize based on data type?
819 Object value
= PrimitiveUtils
.convert(type
, specAttrNode
820 .getProperty(SLC_VALUE
).getString());
821 return value
.toString();
822 } else if (specAttrNode
823 .isNodeType(SlcTypes
.SLC_REF_SPEC_ATTRIBUTE
)) {
824 if (!specAttrNode
.hasProperty(SLC_VALUE
))
826 // return the index of the sub node as set by setValue()
827 // in the future we may manage references as well
828 return (int) specAttrNode
.getProperty(SLC_VALUE
).getLong();
830 throw new SlcException("Unsupported type for spec attribute "
832 } catch (RepositoryException e
) {
833 throw new SlcException("Cannot get value for " + element
, e
);
838 protected void setValue(Object element
, Object value
) {
840 Node specAttrNode
= (Node
) element
;
842 .isNodeType(SlcTypes
.SLC_PRIMITIVE_SPEC_ATTRIBUTE
)) {
843 String type
= specAttrNode
.getProperty(SLC_TYPE
)
845 SlcJcrUtils
.setPrimitiveAsProperty(specAttrNode
, SLC_VALUE
,
847 valuesViewer
.refresh();
848 formPart
.markDirty();
849 } else if (specAttrNode
850 .isNodeType(SlcTypes
.SLC_REF_SPEC_ATTRIBUTE
)) {
851 specAttrNode
.setProperty(SLC_VALUE
,
852 ((Integer
) value
).longValue());
853 valuesViewer
.refresh();
854 formPart
.markDirty();
856 } catch (RepositoryException e
) {
857 throw new SlcException("Cannot get celle editor", e
);