1 /*******************************************************************************
2 * Copyright (c) 2012, 2013 Association for Decentralized Information Management in
4 * All rights reserved. This program and the accompanying materials
5 * are made available under the terms of the Eclipse Public License v1.0
6 * which accompanies this distribution, and is available at
7 * http://www.eclipse.org/legal/epl-v10.html
10 * VTT Technical Research Centre of Finland - initial API and implementation
11 *******************************************************************************/
12 package org.simantics.g3d.property;
14 import java.lang.annotation.Annotation;
15 import java.lang.reflect.Field;
16 import java.lang.reflect.InvocationTargetException;
17 import java.lang.reflect.Method;
18 import java.util.ArrayList;
19 import java.util.Collection;
20 import java.util.Collections;
21 import java.util.Comparator;
22 import java.util.HashMap;
23 import java.util.HashSet;
24 import java.util.LinkedHashMap;
25 import java.util.List;
28 import java.util.function.Consumer;
30 import org.eclipse.jface.layout.GridDataFactory;
31 import org.eclipse.jface.viewers.AbstractTableViewer;
32 import org.eclipse.jface.viewers.CellEditor;
33 import org.eclipse.jface.viewers.CellEditor.LayoutData;
34 import org.eclipse.jface.viewers.CellLabelProvider;
35 import org.eclipse.jface.viewers.CellNavigationStrategy;
36 import org.eclipse.jface.viewers.ColumnViewer;
37 import org.eclipse.jface.viewers.ColumnViewerEditor;
38 import org.eclipse.jface.viewers.ColumnViewerEditorActivationEvent;
39 import org.eclipse.jface.viewers.ColumnViewerEditorActivationListener;
40 import org.eclipse.jface.viewers.ColumnViewerEditorActivationStrategy;
41 import org.eclipse.jface.viewers.ColumnViewerEditorDeactivationEvent;
42 import org.eclipse.jface.viewers.ComboBoxCellEditor;
43 import org.eclipse.jface.viewers.EditingSupport;
44 import org.eclipse.jface.viewers.FocusCellOwnerDrawHighlighter;
45 import org.eclipse.jface.viewers.ISelection;
46 import org.eclipse.jface.viewers.ISelectionChangedListener;
47 import org.eclipse.jface.viewers.ISelectionProvider;
48 import org.eclipse.jface.viewers.IStructuredContentProvider;
49 import org.eclipse.jface.viewers.SelectionChangedEvent;
50 import org.eclipse.jface.viewers.StructuredSelection;
51 import org.eclipse.jface.viewers.TableViewer;
52 import org.eclipse.jface.viewers.TableViewerColumn;
53 import org.eclipse.jface.viewers.TableViewerFocusCellManager;
54 import org.eclipse.jface.viewers.TextCellEditor;
55 import org.eclipse.jface.viewers.Viewer;
56 import org.eclipse.jface.viewers.ViewerCell;
57 import org.eclipse.jface.viewers.ViewerColumn;
58 import org.eclipse.jface.viewers.ViewerRow;
59 import org.eclipse.swt.SWT;
60 import org.eclipse.swt.custom.TableEditor;
61 import org.eclipse.swt.events.TraverseEvent;
62 import org.eclipse.swt.widgets.Composite;
63 import org.eclipse.swt.widgets.Control;
64 import org.eclipse.swt.widgets.Display;
65 import org.eclipse.swt.widgets.Event;
66 import org.eclipse.swt.widgets.Item;
67 import org.eclipse.swt.widgets.TableColumn;
68 import org.eclipse.swt.widgets.TableItem;
69 import org.eclipse.ui.IWorkbenchSite;
70 import org.simantics.db.management.ISessionContext;
71 import org.simantics.g3d.property.annotations.CompoundGetPropertyValue;
72 import org.simantics.g3d.property.annotations.CompoundSetPropertyValue;
73 import org.simantics.g3d.property.annotations.GetComboProperty;
74 import org.simantics.g3d.property.annotations.GetComboPropertyValue;
75 import org.simantics.g3d.property.annotations.GetPropertyValue;
76 import org.simantics.g3d.property.annotations.PropertyTabBlacklist;
77 import org.simantics.g3d.property.annotations.SetComboPropertyValue;
78 import org.simantics.g3d.property.annotations.SetPropertyValue;
79 import org.simantics.g3d.scenegraph.IG3DNode;
80 import org.simantics.g3d.scenegraph.NodeMap;
81 import org.simantics.g3d.scenegraph.NodeMapProvider;
82 import org.simantics.g3d.scenegraph.base.INode;
83 import org.simantics.g3d.scenegraph.base.NodeListener;
84 import org.simantics.g3d.scenegraph.base.ParentNode;
85 import org.simantics.g3d.scenegraph.structural.IStructuralNode;
86 import org.simantics.g3d.tools.AdaptationUtils;
87 import org.simantics.selectionview.IPropertyTab;
88 import org.simantics.selectionview.IPropertyTab2;
89 import org.simantics.utils.datastructures.MapList;
91 public class AnnotatedPropertyTabContributorFactory implements PropertyTabContributorFactory {
93 private static final boolean DEBUG = false;
95 @SuppressWarnings("unchecked")
97 public List<PropertyTabContributor> getContributors(Object input) {
98 Map<String,IPropertyItem> items = new LinkedHashMap<String, IPropertyItem>();
99 List<String> blacklist = new ArrayList<String>();
101 collectItems(input.getClass(), items);
102 collectBlacklist(input.getClass(), blacklist);
103 } catch (InstantiationException e) {
104 // TODO Auto-generated catch block
106 } catch (IllegalAccessException e) {
107 // TODO Auto-generated catch block
111 if (items.size() == 0)
112 return Collections.EMPTY_LIST;
114 MapList<String, IPropertyItem> tabMap = new MapList<String, IPropertyItem>();
115 List<String> tabs = new ArrayList<String>();
116 for (String id : items.keySet()) {
117 IPropertyItem item = items.get(id);
118 tabMap.add(item.getTabId(), item);
119 if (!tabs.contains(item.getTabId())) {
120 tabs.add(item.getTabId());
121 //System.out.println(item.tabId + " " + item.name + " " + item.id);
124 for (String s : blacklist) {
128 List<PropertyTabContributor> contributors = new ArrayList<PropertyTabContributor>(tabs.size());
129 for (String tabId : tabs) {
130 contributors.add(new AnnotatedPropertyTabContributor(tabId, tabMap.getValues(tabId)));
137 private static void collectItems(Class<?> clazz, Map<String, IPropertyItem> items) throws InstantiationException, IllegalAccessException {
138 Class<?> superclass = clazz.getSuperclass();
139 if(superclass != null)
140 collectItems(superclass, items);
142 for (Method m : clazz.getDeclaredMethods()) {
143 m.setAccessible(true);
144 for (Annotation annotation : m.getAnnotations()) {
145 if (annotation.annotationType().equals(GetPropertyValue.class)) {
146 GetPropertyValue get = (GetPropertyValue)annotation;
147 PropertyItem item = (PropertyItem)items.get(get.value());
149 item = new PropertyItem(get.value());
150 items.put(item.id, item);
154 item.manipulatorClass = get.manipulator().newInstance().get(m,null);
156 item.tabId = get.tabId();
158 item.name = get.name();
161 } else if (annotation.annotationType().equals(SetPropertyValue.class)) {
162 SetPropertyValue set = (SetPropertyValue)annotation;
163 PropertyItem item = (PropertyItem)items.get(set.value());
165 item = new PropertyItem(set.value());
166 items.put(item.id, item);
170 } else if (annotation.annotationType().equals(CompoundGetPropertyValue.class)) {
171 CompoundGetPropertyValue get = (CompoundGetPropertyValue)annotation;
172 CompoundPropertyItem item = (CompoundPropertyItem)items.get(get.value());
174 item = new CompoundPropertyItem(get.value());
175 items.put(item.id, item);
179 item.manipulatorFactory = get.manipulator().newInstance();
181 item.tabId = get.tabId();
183 item.name = get.name();
184 } else if (annotation.annotationType().equals(CompoundSetPropertyValue.class)) {
185 CompoundSetPropertyValue set = (CompoundSetPropertyValue)annotation;
186 CompoundPropertyItem item = (CompoundPropertyItem)items.get(set.value());
188 item = new CompoundPropertyItem(set.value());
189 items.put(item.id, item);
193 } else if (annotation.annotationType().equals(GetComboPropertyValue.class)) {
194 GetComboPropertyValue get = (GetComboPropertyValue)annotation;
195 ComboPropertyItem item = (ComboPropertyItem)items.get(get.value());
197 item = new ComboPropertyItem(get.value());
198 items.put(item.id, item);
201 item.manipulatorClass = ComboPropertyManipulator.class;
203 item.tabId = get.tabId();
205 item.name = get.name();
206 } else if (annotation.annotationType().equals(SetComboPropertyValue.class)) {
207 SetComboPropertyValue set = (SetComboPropertyValue)annotation;
208 ComboPropertyItem item = (ComboPropertyItem)items.get(set.value());
210 item = new ComboPropertyItem(set.value());
211 items.put(item.id, item);
214 } else if (annotation.annotationType().equals(GetComboProperty.class)) {
215 GetComboProperty get = (GetComboProperty)annotation;
216 ComboPropertyItem item = (ComboPropertyItem)items.get(get.value());
218 item = new ComboPropertyItem(get.value());
219 items.put(item.id, item);
229 private static void collectBlacklist(Class<?> clazz, List<String> blacklist) throws InstantiationException, IllegalAccessException {
230 Class<?> superclass = clazz.getSuperclass();
231 if(superclass != null)
232 collectBlacklist(superclass, blacklist);
234 PropertyTabBlacklist ann = clazz.getAnnotation(PropertyTabBlacklist.class);
237 String s = ann.value();
242 for (String item : s.split(";")) {
249 private static Map<PropertyItem, PropertyManipulator> createManipulators(CompoundPropertyItem item, Object obj) {
252 @SuppressWarnings("unchecked")
253 Map<String,Object> map = (Map<String, Object>)item.getter.invoke(obj);
254 Map<PropertyItem, PropertyManipulator> result = new HashMap<AnnotatedPropertyTabContributorFactory.PropertyItem, PropertyManipulator>();
255 for (String key : map.keySet()) {
256 MethodWithMapValueProvider provider = new MethodWithMapValueProvider(item.getter, item.setter, key);
257 Class<? extends PropertyManipulator> clazz = item.manipulatorFactory.get(null,map.get(key));
258 PropertyManipulator manipulator = clazz.getConstructor(ValueProvider.class,Object.class).newInstance(provider,obj);
259 PropertyItem i = new PropertyItem(item.id+"."+key);
260 i.getter = item.getter;
261 i.setter = item.setter;
263 i.tabId = item.tabId;
264 result.put(i,manipulator);
267 } catch (Exception e) {
269 return Collections.emptyMap();
274 private static PropertyManipulator createManipulator(PropertyItem item, Object obj) {
276 MethodValueProvider provider = new MethodValueProvider(item.getter, item.setter);
277 PropertyManipulator manipulator = item.manipulatorClass.getConstructor(ValueProvider.class,Object.class).newInstance(provider,obj);
279 } catch (Exception e) {
285 private static PropertyManipulator createManipulator(ComboPropertyItem item, Object obj) {
287 MethodComboValueProvider provider = new MethodComboValueProvider(item.getter, item.setter,item.values);
288 PropertyManipulator manipulator = item.manipulatorClass.getConstructor(ValueProvider.class,Object.class).newInstance(provider,obj);
290 } catch (Exception e) {
296 private static interface IPropertyItem {
297 public String getTabId();
298 public String getName();
299 public String getId();
300 public boolean editable();
303 private static class PropertyItem implements IPropertyItem{
306 private String tabId;
307 private Method getter;
308 private Method setter;
309 private Class<? extends PropertyManipulator> manipulatorClass;
312 public PropertyItem(String id) {
314 throw new NullPointerException();
319 public String getId() {
324 public int hashCode() {
325 return id.hashCode();
329 public String getTabId() {
334 public String getName() {
339 public boolean editable() {
340 return setter != null;
344 private static class CompoundPropertyItem implements IPropertyItem{
347 private String tabId;
348 private Method getter;
349 private Method setter;
350 private PropertyManipulatorFactory manipulatorFactory;
353 public CompoundPropertyItem(String id) {
355 throw new NullPointerException();
360 public String getId() {
365 public int hashCode() {
366 return id.hashCode();
370 public String getTabId() {
375 public String getName() {
380 public boolean editable() {
381 return setter != null;
385 private static class ComboPropertyItem implements IPropertyItem{
388 private String tabId;
389 private Method getter;
390 private Method setter;
391 private Method values;
392 private Class<? extends ComboPropertyManipulator> manipulatorClass;
395 public ComboPropertyItem(String id) {
397 throw new NullPointerException();
402 public String getId() {
407 public int hashCode() {
408 return id.hashCode();
412 public String getTabId() {
417 public String getName() {
422 public boolean editable() {
423 return setter != null;
427 private static class AnnotatedPropertyTabContributor implements PropertyTabContributor {
429 List<IPropertyItem> items;
431 public AnnotatedPropertyTabContributor(String id, List<IPropertyItem> items) {
433 throw new NullPointerException();
439 public IPropertyTab create(Composite parent, IWorkbenchSite site,
440 ISessionContext context, Object input) {
441 AnnotatedPropertyTab tab = new AnnotatedPropertyTab(id, items);
442 tab.createControl(parent, context);
447 public String getId() {
453 private static class AnnotatedPropertyTab implements IPropertyTab2, NodeListener {
455 List<IPropertyItem> contibutedItems;
456 List<IPropertyItem> resolvedItems = new ArrayList<IPropertyItem>();
457 private Map<IPropertyItem,PropertyManipulator> manipulators = new HashMap<IPropertyItem, PropertyManipulator>();
459 private TableViewer viewer;
462 private NodeMap<?,?,?> nodeMap;
464 private List<TableViewerColumn> valueColumns = new ArrayList<TableViewerColumn>();
466 public AnnotatedPropertyTab(String id, List<IPropertyItem> items) {
468 this.contibutedItems = items;
474 public void createControl(Composite parent, ISessionContext context) {
475 //parent.setLayout(new FillLayout());
476 viewer = new TableViewer(parent, SWT.FULL_SELECTION | SWT.SINGLE);
478 GridDataFactory.fillDefaults().align(SWT.FILL, SWT.FILL).grab(true, true).applyTo(viewer.getTable());
480 //viewer.setLabelProvider(new AnnotatedTableLabelProvider(object))
482 viewer.setContentProvider(new PropertyItemContentsProvider());
484 TableViewerColumn name = new TableViewerColumn(viewer, SWT.LEFT);
485 //TableViewerColumn value = new TableViewerColumn(viewer, SWT.LEFT);
486 name.setLabelProvider(new PropertyItemNameProvider());
487 //value.setLabelProvider(new PropertyValueLabelProvider(null));
488 name.getColumn().setText("Property");
489 //value.getColumn().setText("Value");
490 name.getColumn().setWidth(200);
491 //value.getColumn().setWidth(200);
492 name.getViewer().addSelectionChangedListener(new ISelectionChangedListener() {
495 public void selectionChanged(SelectionChangedEvent event) {
496 PropertyItem item = AdaptationUtils.adaptToSingle(event.getSelection(),PropertyItem.class);
498 PropertyManipulator manipulator = manipulators.get(item);//createManipulator(item, null);
499 for (int i = 0; i < valueColumns.size(); i++) {
500 TableViewerColumn c = valueColumns.get(i);
501 if (i < manipulator.getValueCount()) {
502 c.getColumn().setText(manipulator.getDescription(i));
504 c.getColumn().setText("");
512 viewer.getTable().setHeaderVisible(true);
513 viewer.getTable().setLinesVisible(true);
514 viewer.addSelectionChangedListener(new ISelectionChangedListener() {
517 public void selectionChanged(SelectionChangedEvent event) {
518 IPropertyItem item = AdaptationUtils.adaptToSingle(event.getSelection(), IPropertyItem.class);
520 if (!manipulators.get(selectedItem).getEditMode())
521 manipulators.get(selectedItem).setEditMode(true);
524 for (IPropertyItem i : delayedUpdate) {
525 if (!i.equals(selectedItem)) {
526 manipulators.get(i).setEditMode(false);
527 viewer.update(i,null);
530 if (delayedUpdate.contains(selectedItem)) {
531 delayedUpdate.clear();
532 delayedUpdate.add(selectedItem);
534 delayedUpdate.clear();
539 CellNavigationStrategy nStrategy = new CellNavigationStrategy() {
540 private ViewerCell internalFindSelectedCell(
541 ColumnViewer viewer, ViewerCell currentSelectedCell,
543 switch (event.keyCode) {
545 if (currentSelectedCell != null) {
546 return getNeighbor(currentSelectedCell,
547 ViewerCell.ABOVE, false);
551 if (currentSelectedCell != null) {
552 return getNeighbor(currentSelectedCell,
553 ViewerCell.BELOW, false);
557 if (currentSelectedCell != null) {
558 return getNeighbor(currentSelectedCell,
559 ViewerCell.LEFT, true);
562 case SWT.ARROW_RIGHT:
563 if (currentSelectedCell != null) {
564 return getNeighbor(currentSelectedCell,
565 ViewerCell.RIGHT, true);
572 public ViewerCell findSelectedCell(ColumnViewer viewer,
573 ViewerCell currentSelectedCell, Event event) {
574 ViewerCell cell = internalFindSelectedCell(viewer,
575 currentSelectedCell, event);
577 TableColumn t = AnnotatedPropertyTab.this.viewer.getTable().getColumn(
578 cell.getColumnIndex());
579 AnnotatedPropertyTab.this.viewer.getTable().showColumn(t);
585 TableViewerFocusCellManager focusCellManager = new TableViewerFocusCellManager(
586 viewer, new FocusCellOwnerDrawHighlighter(viewer));
588 Field f = focusCellManager.getClass().getSuperclass()
589 .getDeclaredField("navigationStrategy");
590 f.setAccessible(true);
591 f.set(focusCellManager, nStrategy);
592 } catch (SecurityException e) {
594 } catch (NoSuchFieldException e) {
596 } catch (IllegalArgumentException e) {
598 } catch (IllegalAccessException e) {
601 ColumnViewerEditorActivationStrategy actSupport = new ColumnViewerEditorActivationStrategy(
603 protected boolean isEditorActivationEvent(
604 ColumnViewerEditorActivationEvent event) {
605 return event.eventType == ColumnViewerEditorActivationEvent.TRAVERSAL
606 || event.eventType == ColumnViewerEditorActivationEvent.MOUSE_DOUBLE_CLICK_SELECTION
607 || (event.eventType == ColumnViewerEditorActivationEvent.KEY_PRESSED && event.keyCode == SWT.CR)
608 || event.eventType == ColumnViewerEditorActivationEvent.PROGRAMMATIC;
611 TableViewerEditor.create(viewer, focusCellManager, actSupport,
612 ColumnViewerEditor.TABBING_HORIZONTAL
613 | ColumnViewerEditor.TABBING_MOVE_TO_ROW_NEIGHBOR
614 | ColumnViewerEditor.TABBING_VERTICAL
615 | ColumnViewerEditor.KEYBOARD_ACTIVATION);
616 viewer.getColumnViewerEditor().addEditorActivationListener(
617 new ColumnViewerEditorActivationListener() {
618 public void afterEditorActivated(
619 ColumnViewerEditorActivationEvent event) {
622 public void afterEditorDeactivated(
623 ColumnViewerEditorDeactivationEvent event) {
626 public void beforeEditorActivated(
627 ColumnViewerEditorActivationEvent event) {
628 ViewerCell cell = (ViewerCell) event.getSource();
629 viewer.getTable().showColumn(
630 viewer.getTable().getColumn(cell.getColumnIndex()));
633 public void beforeEditorDeactivated(
634 ColumnViewerEditorDeactivationEvent event) {
642 private IPropertyItem selectedItem = null;
643 private Set<IPropertyItem> delayedUpdate = new HashSet<IPropertyItem>();
647 public void setInput(ISessionContext context, ISelection selection,
649 Collection<INode> nodes = AdaptationUtils.adaptToCollection(selection, INode.class);
650 if (nodes.size() != 1) {
652 node.removeListener(this);
657 INode n = nodes.iterator().next();
659 if (!node.equals(n)) {
660 node.removeListener(this);
670 private void setInput(INode node) {
672 this.node.addListener(this);
680 if (n instanceof NodeMapProvider<?,?,?>) {
681 nodeMap = ((NodeMapProvider<?,?,?>) n).getNodeMap();
685 n = (IG3DNode)n.getParent();
687 boolean readOnly = (node instanceof IStructuralNode && ((IStructuralNode)node).isPartOfInstantiatedModel() && !((IStructuralNode)node).isInstantiatedModelRoot());
689 resolvedItems.clear();
690 manipulators.clear();
691 for (IPropertyItem item : contibutedItems) {
692 if (item instanceof PropertyItem) {
693 resolvedItems.add((PropertyItem)item);
694 manipulators.put((PropertyItem)item, createManipulator((PropertyItem)item, node));
695 } else if (item instanceof ComboPropertyItem) {
696 resolvedItems.add((ComboPropertyItem)item);
697 manipulators.put((ComboPropertyItem)item, createManipulator((ComboPropertyItem)item, node));
698 } else if (item instanceof CompoundPropertyItem) {
699 CompoundPropertyItem compound = (CompoundPropertyItem)item;
700 Map<PropertyItem, PropertyManipulator> manipulators = createManipulators(compound, node);
701 for (PropertyItem i : manipulators.keySet()) {
702 resolvedItems.add(i);
703 this.manipulators.put(i, manipulators.get(i));
711 for (PropertyManipulator manipulator : manipulators.values()) {
712 if (valueCount < manipulator.getValueCount())
713 valueCount = manipulator.getValueCount();
715 for (int i = 0; i < valueCount; i++) {
716 TableViewerColumn value = new TableViewerColumn(viewer, SWT.LEFT);
717 //value.getColumn().setText("Value " + (i+1));
718 value.getColumn().setText("");
719 value.getColumn().setWidth(200);
720 valueColumns.add(value);
721 //value.setEditingSupport(new )
724 // create label providers
725 PropertyValueLabelProvider2 p = new PropertyValueLabelProvider2(this);
727 for (TableViewerColumn c : valueColumns) {
728 c.setLabelProvider(p);
730 PropertyEditingSupport support = new PropertyEditingSupport(this, viewer, index++, nodeMap);
731 c.setEditingSupport(support);
734 Collections.sort(resolvedItems, new Comparator<IPropertyItem>() {
736 public int compare(IPropertyItem o1, IPropertyItem o2) {
737 return o1.getName().compareTo(o2.getName());
740 viewer.getTable().setEnabled(!readOnly);
741 viewer.setInput(resolvedItems);
745 public void requestFocus() {
746 viewer.getTable().forceFocus();
750 public void dispose() {
752 node.removeListener(this);
759 public Control getControl() {
760 return viewer.getTable();
764 public ISelectionProvider getSelectionProvider() {
769 public boolean isDisposed() {
770 return viewer.getTable().isDisposed();
774 public <T extends INode> void nodeAdded(ParentNode<T> node,
775 INode child, String rel) {
780 public <T extends INode> void nodeRemoved(ParentNode<T> node,
781 INode child, String rel) {
786 public void propertyChanged(INode node, final String id) {
787 // for (final PropertyItem item : items) {
788 // if (item.id.equals(id)) {
789 // Display.getDefault().asyncExec(new Runnable() {
792 // public void run() {
793 // viewer.update(item, null);
799 if (Thread.currentThread() == Display.getDefault().getThread()) {
800 if (viewer.getTable().isDisposed())
802 if (DEBUG)System.out.println("Viewer refresh " + id);
803 for (IPropertyItem item : resolvedItems)
804 if (!item.equals(selectedItem))
805 viewer.refresh(item);
806 if (selectedItem != null)
807 delayedUpdate.add(selectedItem);
808 } else if (!editing){
809 // running delayed refresh when a cell editor is active would cancel cell editing.
810 Display.getDefault().asyncExec(new Runnable() {
813 if (viewer.getTable().isDisposed()) {
814 if (AnnotatedPropertyTab.this.node != null)
815 AnnotatedPropertyTab.this.node.removeListener(AnnotatedPropertyTab.this);
818 if (DEBUG) System.out.println("Viewer threaded refresh " + id);
819 for (IPropertyItem item : resolvedItems)
820 if (!item.equals(selectedItem))
821 viewer.refresh(item);
822 if (selectedItem != null)
823 delayedUpdate.add(selectedItem);
828 for (IPropertyItem item : resolvedItems) {
829 delayedUpdate.add(item);
838 public void updatePartName(Consumer<String> updateCallback) {
840 updateCallback.accept(node.toString());
844 public PropertyManipulator getManipulator(IPropertyItem item) {
845 return manipulators.get(item);
848 private boolean editing = false;
850 public void setEditing(boolean editing) {
851 this.editing = editing;
857 private static class PropertyEditingSupport extends EditingSupport {
858 AnnotatedPropertyTab tab;
860 NodeMap<?,?,?> nodeMap;
864 public PropertyEditingSupport(AnnotatedPropertyTab tab, TableViewer viewer, int index, NodeMap<?,?,?> nodeMap) {
868 this.viewer = viewer;
869 this.nodeMap = nodeMap;
873 protected boolean canEdit(Object element) {
874 IPropertyItem item = (IPropertyItem)element;
875 if (tab.getManipulator(item).getValueCount() <= index)
877 if (!item.editable())
879 if (getValue(element) == null)
885 protected CellEditor getCellEditor(Object element) {
886 IPropertyItem item = (IPropertyItem)element;
887 if (tab.getManipulator(item).getValueCount() <= index)
890 if (item instanceof PropertyItem)
891 editor = new TextCellEditor(viewer.getTable(),SWT.NONE) {
893 public void activate() {
894 tab.setEditing(true);
898 public void deactivate() {
900 tab.setEditing(false);
903 else if (item instanceof ComboPropertyItem) {
904 ComboPropertyItem comboPropertyItem = (ComboPropertyItem)item;
905 ComboPropertyManipulator manipulator = (ComboPropertyManipulator)tab.manipulators.get(comboPropertyItem);
906 editor = new ComboBoxCellEditor(viewer.getTable(), manipulator.getItems()) {
908 public void activate() {
909 tab.setEditing(true);
913 public void deactivate() {
915 tab.setEditing(false);
919 if (DEBUG)System.err.println("CELL EDITOR: " + element);
924 protected Object getValue(Object element) {
925 IPropertyItem item = (IPropertyItem)element;
926 PropertyManipulator manipulator = tab.getManipulator(item);//createManipulator(item, obj);
927 if (manipulator.getValueCount() <= index)
929 if (manipulator instanceof ComboPropertyManipulator) {
930 return ((ComboPropertyManipulator)manipulator).getValueIndex();
932 Object value = manipulator.getValue(index);
937 protected void setValue(Object element, Object value) {
939 IPropertyItem item = (IPropertyItem)element;
940 PropertyManipulator manipulator = tab.getManipulator(item);//createManipulator(item, obj);
941 if (manipulator.getValueCount() <= index)
942 throw new IllegalAccessError("Editing value in index " + index + " is not allowed.");
943 if (DEBUG)System.err.println("CELL SET VALUE: " + element + " " + value);
944 manipulator.setValue(value.toString(),index);
945 viewer.refresh(item);
946 nodeMap.commit("Set " + item.getId() + " value to " + value);
954 private static class PropertyItemNameProvider extends CellLabelProvider {
958 public void update(ViewerCell cell) {
959 IPropertyItem item = (IPropertyItem)cell.getElement();
961 if (item.getName().length() > 0)
962 cell.setText(item.getName());
964 cell.setText(item.getId());
970 private static class PropertyValueLabelProvider2 extends CellLabelProvider {
971 AnnotatedPropertyTab tab;
972 //private Object object;
974 public PropertyValueLabelProvider2(AnnotatedPropertyTab tab) {
979 public void update(ViewerCell cell) {
980 IPropertyItem item = (IPropertyItem)cell.getElement();
981 int index = cell.getColumnIndex() -1;
982 PropertyManipulator manipulator = tab.getManipulator(item);//createManipulator(item, object);
983 if (manipulator.getValueCount() <= index)
985 cell.setText(manipulator.getValue(index));
989 private static class PropertyItemContentsProvider implements IStructuredContentProvider {
990 @SuppressWarnings("unchecked")
992 public Object[] getElements(Object inputElement) {
993 List<PropertyItem> items = (List<PropertyItem>)inputElement;
994 return items.toArray();
998 public void dispose() {
1003 public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
1010 private static ViewerCell getNeighbor(ViewerCell currentCell,
1011 int directionMask, boolean sameLevel) {
1013 if ((directionMask & ViewerCell.ABOVE) == ViewerCell.ABOVE) {
1014 row = currentCell.getViewerRow().getNeighbor(ViewerRow.ABOVE,
1016 } else if ((directionMask & ViewerCell.BELOW) == ViewerCell.BELOW) {
1017 row = currentCell.getViewerRow().getNeighbor(ViewerRow.BELOW,
1020 row = currentCell.getViewerRow();
1024 columnIndex = getVisualIndex(row, currentCell.getColumnIndex());
1026 if ((directionMask & ViewerCell.LEFT) == ViewerCell.LEFT) {
1028 } else if ((directionMask & ViewerCell.RIGHT) == ViewerCell.RIGHT) {
1031 columnIndex += modifier;
1032 if (columnIndex >= 0 && columnIndex < row.getColumnCount()) {
1033 ViewerCell cell = getCellAtVisualIndex(row, columnIndex);
1036 && columnIndex < row.getColumnCount() - 1
1037 && columnIndex > 0) {
1038 if (isVisible(cell)) {
1041 columnIndex += modifier;
1042 cell = getCellAtVisualIndex(row, columnIndex);
1056 public static class TableViewerEditor extends ColumnViewerEditor {
1058 * This viewer's table editor.
1060 private TableEditor tableEditor;
1061 private TableViewerFocusCellManager focusCellManager;
1062 private int feature;
1066 * the viewer the editor is attached to
1067 * @param focusCellManager
1068 * the cell focus manager if one used or <code>null</code>
1069 * @param editorActivationStrategy
1070 * the strategy used to decide about the editor activation
1074 TableViewerEditor(TableViewer viewer,
1075 TableViewerFocusCellManager focusCellManager,
1076 ColumnViewerEditorActivationStrategy editorActivationStrategy,
1078 super(viewer, editorActivationStrategy, feature);
1079 this.feature = feature;
1080 tableEditor = new TableEditor(viewer.getTable());
1081 this.focusCellManager = focusCellManager;
1085 * Create a customized editor with focusable cells
1088 * the viewer the editor is created for
1089 * @param focusCellManager
1090 * the cell focus manager if one needed else
1092 * @param editorActivationStrategy
1093 * activation strategy to control if an editor activated
1095 * bit mask controlling the editor
1097 * <li>{@link ColumnViewerEditor#DEFAULT}</li>
1098 * <li>{@link ColumnViewerEditor#TABBING_CYCLE_IN_ROW}</li>
1099 * <li>{@link ColumnViewerEditor#TABBING_HORIZONTAL}</li>
1101 * {@link ColumnViewerEditor#TABBING_MOVE_TO_ROW_NEIGHBOR}</li>
1102 * <li>{@link ColumnViewerEditor#TABBING_VERTICAL}</li>
1104 * @see #create(TableViewer, ColumnViewerEditorActivationStrategy, int)
1106 public static void create(TableViewer viewer,
1107 TableViewerFocusCellManager focusCellManager,
1108 ColumnViewerEditorActivationStrategy editorActivationStrategy,
1110 TableViewerEditor editor = new TableViewerEditor(viewer,
1111 focusCellManager, editorActivationStrategy, feature);
1112 viewer.setColumnViewerEditor(editor);
1113 if (focusCellManager != null) {
1115 Method m = focusCellManager.getClass().getSuperclass()
1116 .getDeclaredMethod("init");
1117 m.setAccessible(true);
1118 m.invoke(focusCellManager);
1119 } catch (SecurityException e) {
1120 e.printStackTrace();
1121 } catch (IllegalArgumentException e) {
1122 e.printStackTrace();
1123 } catch (IllegalAccessException e) {
1124 e.printStackTrace();
1125 } catch (NoSuchMethodException e) {
1126 e.printStackTrace();
1127 } catch (InvocationTargetException e) {
1128 e.printStackTrace();
1130 // focusCellManager.init();
1135 * Create a customized editor whose activation process is customized
1138 * the viewer the editor is created for
1139 * @param editorActivationStrategy
1140 * activation strategy to control if an editor activated
1142 * bit mask controlling the editor
1144 * <li>{@link ColumnViewerEditor#DEFAULT}</li>
1145 * <li>{@link ColumnViewerEditor#TABBING_CYCLE_IN_ROW}</li>
1146 * <li>{@link ColumnViewerEditor#TABBING_HORIZONTAL}</li>
1148 * {@link ColumnViewerEditor#TABBING_MOVE_TO_ROW_NEIGHBOR}</li>
1149 * <li>{@link ColumnViewerEditor#TABBING_VERTICAL}</li>
1152 public static void create(TableViewer viewer,
1153 ColumnViewerEditorActivationStrategy editorActivationStrategy,
1155 create(viewer, null, editorActivationStrategy, feature);
1158 protected void setEditor(Control w, Item item, int columnNumber) {
1159 tableEditor.setEditor(w, (TableItem) item, columnNumber);
1162 protected void setLayoutData(LayoutData layoutData) {
1163 tableEditor.grabHorizontal = layoutData.grabHorizontal;
1164 tableEditor.horizontalAlignment = layoutData.horizontalAlignment;
1165 tableEditor.minimumWidth = layoutData.minimumWidth;
1168 public ViewerCell getFocusCell() {
1169 if (focusCellManager != null) {
1170 return focusCellManager.getFocusCell();
1172 return super.getFocusCell();
1175 protected void updateFocusCell(ViewerCell focusCell,
1176 ColumnViewerEditorActivationEvent event) {
1177 // Update the focus cell when we activated the editor with these 2
1179 if (event.eventType == ColumnViewerEditorActivationEvent.PROGRAMMATIC
1180 || event.eventType == ColumnViewerEditorActivationEvent.TRAVERSAL) {
1181 if (focusCellManager != null) {
1183 if (DEBUG)System.err.println("FOCUS CELL: " + focusCell);
1185 Method m = AbstractTableViewer.class.getDeclaredMethod(
1186 "getSelectionFromWidget");
1187 m.setAccessible(true);
1188 @SuppressWarnings("rawtypes")
1189 List l = (List) m.invoke(getViewer());
1190 if (focusCellManager != null) {
1191 m = focusCellManager
1194 .getDeclaredMethod("setFocusCell",
1195 new Class[] { ViewerCell.class });
1196 m.setAccessible(true);
1197 m.invoke(focusCellManager,
1198 new Object[] { focusCell });
1200 if (!l.contains(focusCell.getElement())) {
1201 getViewer().setSelection(
1202 new StructuredSelection(focusCell
1205 } catch (SecurityException e) {
1206 e.printStackTrace();
1207 } catch (IllegalArgumentException e) {
1208 e.printStackTrace();
1209 } catch (IllegalAccessException e) {
1210 e.printStackTrace();
1211 } catch (NoSuchMethodException e) {
1212 e.printStackTrace();
1213 } catch (InvocationTargetException e) {
1214 e.printStackTrace();
1220 protected void processTraverseEvent(int columnIndex, ViewerRow row,
1221 TraverseEvent event) {
1222 ViewerCell cell2edit = null;
1223 if (event.detail == SWT.TRAVERSE_TAB_PREVIOUS) {
1225 if ((event.stateMask & SWT.CTRL) == SWT.CTRL
1226 && (feature & TABBING_VERTICAL) == TABBING_VERTICAL) {
1227 cell2edit = searchCellAboveBelow(row, getViewer(),
1229 } else if ((feature & TABBING_HORIZONTAL) == TABBING_HORIZONTAL) {
1230 cell2edit = searchPreviousCell(row,
1231 row.getCell(columnIndex), row.getCell(columnIndex),
1234 } else if (event.detail == SWT.TRAVERSE_TAB_NEXT) {
1236 if ((event.stateMask & SWT.CTRL) == SWT.CTRL
1237 && (feature & TABBING_VERTICAL) == TABBING_VERTICAL) {
1238 cell2edit = searchCellAboveBelow(row, getViewer(),
1239 columnIndex, false);
1240 } else if ((feature & TABBING_HORIZONTAL) == TABBING_HORIZONTAL) {
1241 cell2edit = searchNextCell(row, row.getCell(columnIndex),
1242 row.getCell(columnIndex), getViewer());
1245 if (DEBUG) System.err.println("NEXT CELL: " + cell2edit);
1246 if (cell2edit != null) {
1247 getViewer().getControl().setRedraw(false);
1248 ColumnViewerEditorActivationEvent acEvent = new ColumnViewerEditorActivationEvent(
1251 Method m = ColumnViewer.class
1253 "triggerEditorActivationEvent",
1254 new Class[] { ColumnViewerEditorActivationEvent.class });
1255 m.setAccessible(true);
1256 m.invoke(getViewer(), new Object[] { acEvent });
1257 } catch (SecurityException e) {
1258 e.printStackTrace();
1259 } catch (NoSuchMethodException e) {
1260 e.printStackTrace();
1261 } catch (IllegalArgumentException e) {
1262 e.printStackTrace();
1263 } catch (IllegalAccessException e) {
1264 e.printStackTrace();
1265 } catch (InvocationTargetException e) {
1266 e.printStackTrace();
1268 getViewer().getControl().setRedraw(true);
1272 private ViewerCell searchCellAboveBelow(ViewerRow row,
1273 ColumnViewer viewer, int columnIndex, boolean above) {
1274 ViewerCell rv = null;
1275 ViewerRow newRow = null;
1277 newRow = row.getNeighbor(ViewerRow.ABOVE, false);
1279 newRow = row.getNeighbor(ViewerRow.BELOW, false);
1282 if (newRow != null) {
1283 Method m = ColumnViewer.class.getDeclaredMethod(
1284 "getViewerColumn", new Class[] { int.class });
1285 m.setAccessible(true);
1286 ViewerColumn column = (ViewerColumn) m.invoke(viewer,
1287 new Object[] { new Integer(columnIndex) });
1288 m = ViewerColumn.class.getDeclaredMethod(
1289 "getEditingSupport");
1290 m.setAccessible(true);
1291 EditingSupport es = (EditingSupport) m.invoke(column);
1292 if (column != null && es != null) {
1293 m = EditingSupport.class.getDeclaredMethod("canEdit",
1294 new Class[] { Object.class });
1295 m.setAccessible(true);
1296 Boolean b = (Boolean) m.invoke(es,
1297 new Object[] { newRow.getItem().getData() });
1298 if (b.booleanValue()) {
1299 rv = newRow.getCell(columnIndex);
1302 rv = searchCellAboveBelow(newRow, viewer, columnIndex,
1306 } catch (Exception e) {
1307 e.printStackTrace();
1312 private ViewerCell searchPreviousCell(ViewerRow row,
1313 ViewerCell currentCell, ViewerCell originalCell,
1314 ColumnViewer viewer) {
1315 ViewerCell rv = null;
1316 ViewerCell previousCell;
1317 if (currentCell != null) {
1318 previousCell = getNeighbor(currentCell, ViewerCell.LEFT, true);
1320 if (row.getColumnCount() != 0) {
1321 previousCell = row.getCell(getCreationIndex(row,
1322 row.getColumnCount() - 1));
1324 previousCell = row.getCell(0);
1328 if (originalCell.equals(previousCell)) {
1331 if (previousCell != null) {
1332 if (isCellEditable(viewer, previousCell)) {
1335 rv = searchPreviousCell(row, previousCell, originalCell,
1339 if ((feature & TABBING_CYCLE_IN_ROW) == TABBING_CYCLE_IN_ROW) {
1340 rv = searchPreviousCell(row, null, originalCell, viewer);
1341 } else if ((feature & TABBING_MOVE_TO_ROW_NEIGHBOR) == TABBING_MOVE_TO_ROW_NEIGHBOR) {
1342 ViewerRow rowAbove = row
1343 .getNeighbor(ViewerRow.ABOVE, false);
1344 if (rowAbove != null) {
1345 rv = searchPreviousCell(rowAbove, null, originalCell,
1353 private ViewerCell searchNextCell(ViewerRow row,
1354 ViewerCell currentCell, ViewerCell originalCell,
1355 ColumnViewer viewer) {
1356 ViewerCell rv = null;
1357 ViewerCell nextCell;
1358 if (currentCell != null) {
1359 nextCell = getNeighbor(currentCell, ViewerCell.RIGHT, true);
1361 nextCell = row.getCell(getCreationIndex(row, 0));
1364 if (originalCell.equals(nextCell)) {
1367 if (nextCell != null) {
1368 if (isCellEditable(viewer, nextCell)) {
1371 rv = searchNextCell(row, nextCell, originalCell, viewer);
1374 if ((feature & TABBING_CYCLE_IN_ROW) == TABBING_CYCLE_IN_ROW) {
1375 rv = searchNextCell(row, null, originalCell, viewer);
1376 } else if ((feature & TABBING_MOVE_TO_ROW_NEIGHBOR) == TABBING_MOVE_TO_ROW_NEIGHBOR) {
1377 ViewerRow rowBelow = row
1378 .getNeighbor(ViewerRow.BELOW, false);
1379 if (rowBelow != null) {
1380 rv = searchNextCell(rowBelow, null, originalCell,
1388 private boolean isCellEditable(ColumnViewer viewer, ViewerCell cell) {
1390 Method m = ColumnViewer.class.getDeclaredMethod(
1391 "getViewerColumn", new Class[] { int.class });
1392 m.setAccessible(true);
1393 ViewerColumn column = (ViewerColumn) m.invoke(viewer,
1394 new Object[] { new Integer(cell.getColumnIndex()) });
1395 m = ViewerColumn.class.getDeclaredMethod("getEditingSupport");
1396 m.setAccessible(true);
1397 EditingSupport es = (EditingSupport) m.invoke(column);
1398 if (column != null && es != null) {
1399 m = EditingSupport.class.getDeclaredMethod("canEdit",
1400 new Class[] { Object.class });
1401 m.setAccessible(true);
1403 Boolean b = (Boolean) m.invoke(es,
1404 new Object[] { cell.getElement() });
1405 return b.booleanValue();
1407 } catch (Exception e) {
1408 e.printStackTrace();
1414 // Reimplementation of ViewerCell-Methods
1415 private static int getVisualIndex(ViewerRow row, int creationIndex) {
1416 TableItem item = (TableItem) row.getItem();
1417 int[] order = item.getParent().getColumnOrder();
1418 for (int i = 0; i < order.length; i++) {
1419 if (order[i] == creationIndex) {
1423 return creationIndex;
1426 private static int getCreationIndex(ViewerRow row, int visualIndex) {
1427 TableItem item = (TableItem) row.getItem();
1428 if (item != null && !item.isDisposed() /*
1429 * && hasColumns() &&
1433 return item.getParent().getColumnOrder()[visualIndex];
1438 private static ViewerCell getCellAtVisualIndex(ViewerRow row,
1440 return getCell(row, getCreationIndex(row, visualIndex));
1443 private static boolean isVisible(ViewerCell cell) {
1444 return getWidth(cell) > 0;
1447 private static int getWidth(ViewerCell cell) {
1448 TableItem item = (TableItem) cell.getViewerRow().getItem();
1449 return item.getParent().getColumn(cell.getColumnIndex()).getWidth();
1452 private static ViewerCell getCell(ViewerRow row, int index) {
1453 return row.getCell(index);