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