1 /*******************************************************************************
\r
2 * Copyright (c) 2012, 2013 Association for Decentralized Information Management in
\r
4 * All rights reserved. This program and the accompanying materials
\r
5 * are made available under the terms of the Eclipse Public License v1.0
\r
6 * which accompanies this distribution, and is available at
\r
7 * http://www.eclipse.org/legal/epl-v10.html
\r
10 * VTT Technical Research Centre of Finland - initial API and implementation
\r
11 *******************************************************************************/
\r
12 package org.simantics.g3d.property;
\r
14 import java.lang.annotation.Annotation;
\r
15 import java.lang.reflect.Field;
\r
16 import java.lang.reflect.InvocationTargetException;
\r
17 import java.lang.reflect.Method;
\r
18 import java.util.ArrayList;
\r
19 import java.util.Collection;
\r
20 import java.util.Collections;
\r
21 import java.util.HashMap;
\r
22 import java.util.HashSet;
\r
23 import java.util.LinkedHashMap;
\r
24 import java.util.List;
\r
25 import java.util.Map;
\r
26 import java.util.Set;
\r
28 import org.eclipse.jface.layout.GridDataFactory;
\r
29 import org.eclipse.jface.viewers.AbstractTableViewer;
\r
30 import org.eclipse.jface.viewers.CellEditor;
\r
31 import org.eclipse.jface.viewers.CellEditor.LayoutData;
\r
32 import org.eclipse.jface.viewers.CellLabelProvider;
\r
33 import org.eclipse.jface.viewers.CellNavigationStrategy;
\r
34 import org.eclipse.jface.viewers.ColumnViewer;
\r
35 import org.eclipse.jface.viewers.ColumnViewerEditor;
\r
36 import org.eclipse.jface.viewers.ColumnViewerEditorActivationEvent;
\r
37 import org.eclipse.jface.viewers.ColumnViewerEditorActivationListener;
\r
38 import org.eclipse.jface.viewers.ColumnViewerEditorActivationStrategy;
\r
39 import org.eclipse.jface.viewers.ColumnViewerEditorDeactivationEvent;
\r
40 import org.eclipse.jface.viewers.EditingSupport;
\r
41 import org.eclipse.jface.viewers.FocusCellOwnerDrawHighlighter;
\r
42 import org.eclipse.jface.viewers.ISelection;
\r
43 import org.eclipse.jface.viewers.ISelectionChangedListener;
\r
44 import org.eclipse.jface.viewers.ISelectionProvider;
\r
45 import org.eclipse.jface.viewers.IStructuredContentProvider;
\r
46 import org.eclipse.jface.viewers.SelectionChangedEvent;
\r
47 import org.eclipse.jface.viewers.StructuredSelection;
\r
48 import org.eclipse.jface.viewers.TableViewer;
\r
49 import org.eclipse.jface.viewers.TableViewerColumn;
\r
50 import org.eclipse.jface.viewers.TableViewerFocusCellManager;
\r
51 import org.eclipse.jface.viewers.TextCellEditor;
\r
52 import org.eclipse.jface.viewers.Viewer;
\r
53 import org.eclipse.jface.viewers.ViewerCell;
\r
54 import org.eclipse.jface.viewers.ViewerColumn;
\r
55 import org.eclipse.jface.viewers.ViewerRow;
\r
56 import org.eclipse.swt.SWT;
\r
57 import org.eclipse.swt.custom.TableEditor;
\r
58 import org.eclipse.swt.events.TraverseEvent;
\r
59 import org.eclipse.swt.widgets.Composite;
\r
60 import org.eclipse.swt.widgets.Control;
\r
61 import org.eclipse.swt.widgets.Display;
\r
62 import org.eclipse.swt.widgets.Event;
\r
63 import org.eclipse.swt.widgets.Item;
\r
64 import org.eclipse.swt.widgets.TableColumn;
\r
65 import org.eclipse.swt.widgets.TableItem;
\r
66 import org.eclipse.ui.IWorkbenchSite;
\r
67 import org.simantics.db.management.ISessionContext;
\r
68 import org.simantics.g3d.property.annotations.CompoundGetPropertyValue;
\r
69 import org.simantics.g3d.property.annotations.CompoundSetPropertyValue;
\r
70 import org.simantics.g3d.property.annotations.GetPropertyValue;
\r
71 import org.simantics.g3d.property.annotations.PropertyTabBlacklist;
\r
72 import org.simantics.g3d.property.annotations.SetPropertyValue;
\r
73 import org.simantics.g3d.scenegraph.IG3DNode;
\r
74 import org.simantics.g3d.scenegraph.NodeMap;
\r
75 import org.simantics.g3d.scenegraph.NodeMapProvider;
\r
76 import org.simantics.g3d.scenegraph.base.INode;
\r
77 import org.simantics.g3d.scenegraph.base.NodeListener;
\r
78 import org.simantics.g3d.scenegraph.base.ParentNode;
\r
79 import org.simantics.g3d.scenegraph.structural.IStructuralNode;
\r
80 import org.simantics.g3d.tools.AdaptationUtils;
\r
81 import org.simantics.selectionview.IPropertyTab;
\r
82 import org.simantics.selectionview.IPropertyTab2;
\r
83 import org.simantics.utils.datastructures.Callback;
\r
84 import org.simantics.utils.datastructures.MapList;
\r
86 public class AnnotatedPropertyTabContributorFactory implements PropertyTabContributorFactory {
\r
88 private static final boolean DEBUG = false;
\r
90 @SuppressWarnings("unchecked")
\r
92 public List<PropertyTabContributor> getContributors(Object input) {
\r
93 Map<String,IPropertyItem> items = new LinkedHashMap<String, IPropertyItem>();
\r
94 List<String> blacklist = new ArrayList<String>();
\r
96 collectItems(input.getClass(), items);
\r
97 collectBlacklist(input.getClass(), blacklist);
\r
98 } catch (InstantiationException e) {
\r
99 // TODO Auto-generated catch block
\r
100 e.printStackTrace();
\r
101 } catch (IllegalAccessException e) {
\r
102 // TODO Auto-generated catch block
\r
103 e.printStackTrace();
\r
106 if (items.size() == 0)
\r
107 return Collections.EMPTY_LIST;
\r
109 MapList<String, IPropertyItem> tabMap = new MapList<String, IPropertyItem>();
\r
110 List<String> tabs = new ArrayList<String>();
\r
111 for (String id : items.keySet()) {
\r
112 IPropertyItem item = items.get(id);
\r
113 tabMap.add(item.getTabId(), item);
\r
114 if (!tabs.contains(item.getTabId())) {
\r
115 tabs.add(item.getTabId());
\r
116 //System.out.println(item.tabId + " " + item.name + " " + item.id);
\r
119 for (String s : blacklist) {
\r
123 List<PropertyTabContributor> contributors = new ArrayList<PropertyTabContributor>(tabs.size());
\r
124 for (String tabId : tabs) {
\r
125 contributors.add(new AnnotatedPropertyTabContributor(tabId, tabMap.getValues(tabId)));
\r
128 return contributors;
\r
132 private static void collectItems(Class<?> clazz, Map<String, IPropertyItem> items) throws InstantiationException, IllegalAccessException {
\r
133 Class<?> superclass = clazz.getSuperclass();
\r
134 if(superclass != null)
\r
135 collectItems(superclass, items);
\r
137 for (Method m : clazz.getDeclaredMethods()) {
\r
138 m.setAccessible(true);
\r
139 for (Annotation annotation : m.getAnnotations()) {
\r
140 if (annotation.annotationType().equals(GetPropertyValue.class)) {
\r
141 GetPropertyValue get = (GetPropertyValue)annotation;
\r
142 PropertyItem item = (PropertyItem)items.get(get.value());
\r
143 if (item == null) {
\r
144 item = new PropertyItem(get.value());
\r
145 items.put(item.id, item);
\r
149 item.manipulatorClass = get.manipulator().newInstance().get(m,null);
\r
151 item.tabId = get.tabId();
\r
153 item.name = get.name();
\r
156 } else if (annotation.annotationType().equals(SetPropertyValue.class)) {
\r
157 SetPropertyValue set = (SetPropertyValue)annotation;
\r
158 PropertyItem item = (PropertyItem)items.get(set.value());
\r
159 if (item == null) {
\r
160 item = new PropertyItem(set.value());
\r
161 items.put(item.id, item);
\r
165 } else if (annotation.annotationType().equals(CompoundGetPropertyValue.class)) {
\r
166 CompoundGetPropertyValue get = (CompoundGetPropertyValue)annotation;
\r
167 CompoundPropertyItem item = (CompoundPropertyItem)items.get(get.value());
\r
168 if (item == null) {
\r
169 item = new CompoundPropertyItem(get.value());
\r
170 items.put(item.id, item);
\r
174 item.manipulatorFactory = get.manipulator().newInstance();
\r
176 item.tabId = get.tabId();
\r
178 item.name = get.name();
\r
179 } else if (annotation.annotationType().equals(CompoundSetPropertyValue.class)) {
\r
180 CompoundSetPropertyValue set = (CompoundSetPropertyValue)annotation;
\r
181 CompoundPropertyItem item = (CompoundPropertyItem)items.get(set.value());
\r
182 if (item == null) {
\r
183 item = new CompoundPropertyItem(set.value());
\r
184 items.put(item.id, item);
\r
195 private static void collectBlacklist(Class<?> clazz, List<String> blacklist) throws InstantiationException, IllegalAccessException {
\r
196 Class<?> superclass = clazz.getSuperclass();
\r
197 if(superclass != null)
\r
198 collectBlacklist(superclass, blacklist);
\r
200 PropertyTabBlacklist ann = clazz.getAnnotation(PropertyTabBlacklist.class);
\r
203 String s = ann.value();
\r
206 if (s.length() == 0)
\r
208 for (String item : s.split(";")) {
\r
209 blacklist.add(item);
\r
215 private static Map<PropertyItem, PropertyManipulator> createManipulators(CompoundPropertyItem item, Object obj) {
\r
218 Map<String,Object> map = (Map<String, Object>)item.getter.invoke(obj);
\r
219 Map<PropertyItem, PropertyManipulator> result = new HashMap<AnnotatedPropertyTabContributorFactory.PropertyItem, PropertyManipulator>();
\r
220 for (String key : map.keySet()) {
\r
221 MethodWithMapValueProvider provider = new MethodWithMapValueProvider(item.getter, item.setter, key);
\r
222 Class<? extends PropertyManipulator> clazz = item.manipulatorFactory.get(null,map.get(key));
\r
223 PropertyManipulator manipulator = clazz.getConstructor(ValueProvider.class,Object.class).newInstance(provider,obj);
\r
224 PropertyItem i = new PropertyItem(item.id+"."+key);
\r
225 i.getter = item.getter;
\r
226 i.setter = item.setter;
\r
228 i.tabId = item.tabId;
\r
229 result.put(i,manipulator);
\r
232 } catch (Exception e) {
\r
233 e.printStackTrace();
\r
234 return Collections.EMPTY_MAP;
\r
239 private static PropertyManipulator createManipulator(PropertyItem item, Object obj) {
\r
241 MethodValueProvider provider = new MethodValueProvider(item.getter, item.setter);
\r
242 PropertyManipulator manipulator = item.manipulatorClass.getConstructor(ValueProvider.class,Object.class).newInstance(provider,obj);
\r
243 return manipulator;
\r
244 } catch (Exception e) {
\r
245 e.printStackTrace();
\r
250 private static interface IPropertyItem {
\r
251 public String getTabId();
\r
254 private static class PropertyItem implements IPropertyItem{
\r
256 private String name;
\r
257 private String tabId;
\r
258 private Method getter;
\r
259 private Method setter;
\r
260 private Class<? extends PropertyManipulator> manipulatorClass;
\r
263 public PropertyItem(String id) {
\r
265 throw new NullPointerException();
\r
270 public int hashCode() {
\r
271 return id.hashCode();
\r
275 public String getTabId() {
\r
280 private static class CompoundPropertyItem implements IPropertyItem{
\r
282 private String name;
\r
283 private String tabId;
\r
284 private Method getter;
\r
285 private Method setter;
\r
286 private PropertyManipulatorFactory manipulatorFactory;
\r
289 public CompoundPropertyItem(String id) {
\r
291 throw new NullPointerException();
\r
296 public int hashCode() {
\r
297 return id.hashCode();
\r
301 public String getTabId() {
\r
306 private static class AnnotatedPropertyTabContributor implements PropertyTabContributor {
\r
307 private String id;
\r
308 List<IPropertyItem> items;
\r
310 public AnnotatedPropertyTabContributor(String id, List<IPropertyItem> items) {
\r
312 throw new NullPointerException();
\r
314 this.items = items;
\r
318 public IPropertyTab create(Composite parent, IWorkbenchSite site,
\r
319 ISessionContext context, Object input) {
\r
320 AnnotatedPropertyTab tab = new AnnotatedPropertyTab(id, items);
\r
321 tab.createControl(parent, context);
\r
326 public String getId() {
\r
332 private static class AnnotatedPropertyTab implements IPropertyTab2, NodeListener {
\r
333 //private String id;
\r
334 List<IPropertyItem> contibutedItems;
\r
335 List<PropertyItem> resolvedItems = new ArrayList<PropertyItem>();
\r
336 private Map<PropertyItem,PropertyManipulator> manipulators = new HashMap<PropertyItem, PropertyManipulator>();
\r
338 private TableViewer viewer;
\r
340 private IG3DNode node;
\r
341 private NodeMap<?> nodeMap;
\r
343 private List<TableViewerColumn> valueColumns = new ArrayList<TableViewerColumn>();
\r
345 public AnnotatedPropertyTab(String id, List<IPropertyItem> items) {
\r
347 this.contibutedItems = items;
\r
353 public void createControl(Composite parent, ISessionContext context) {
\r
354 //parent.setLayout(new FillLayout());
\r
355 viewer = new TableViewer(parent, SWT.FULL_SELECTION | SWT.SINGLE);
\r
357 GridDataFactory.fillDefaults().align(SWT.FILL, SWT.FILL).grab(true, true).applyTo(viewer.getTable());
\r
359 //viewer.setLabelProvider(new AnnotatedTableLabelProvider(object))
\r
361 viewer.setContentProvider(new PropertyItemContentsProvider());
\r
363 TableViewerColumn name = new TableViewerColumn(viewer, SWT.LEFT);
\r
364 //TableViewerColumn value = new TableViewerColumn(viewer, SWT.LEFT);
\r
365 name.setLabelProvider(new PropertyItemNameProvider());
\r
366 //value.setLabelProvider(new PropertyValueLabelProvider(null));
\r
367 name.getColumn().setText("Property");
\r
368 //value.getColumn().setText("Value");
\r
369 name.getColumn().setWidth(200);
\r
370 //value.getColumn().setWidth(200);
\r
371 name.getViewer().addSelectionChangedListener(new ISelectionChangedListener() {
\r
374 public void selectionChanged(SelectionChangedEvent event) {
\r
375 PropertyItem item = AdaptationUtils.adaptToSingle(event.getSelection(),PropertyItem.class);
\r
376 if (item != null) {
\r
377 PropertyManipulator manipulator = manipulators.get(item);//createManipulator(item, null);
\r
378 for (int i = 0; i < valueColumns.size(); i++) {
\r
379 TableViewerColumn c = valueColumns.get(i);
\r
380 if (i < manipulator.getValueCount()) {
\r
381 c.getColumn().setText(manipulator.getDescription(i));
\r
383 c.getColumn().setText("");
\r
391 int valueCount = 0;
\r
392 for (IPropertyItem item : contibutedItems) {
\r
393 if (item instanceof PropertyItem) {
\r
394 PropertyManipulator manipulator = createManipulator((PropertyItem)item, null);
\r
395 if (manipulator == null)
\r
397 if (valueCount < manipulator.getValueCount())
\r
398 valueCount = manipulator.getValueCount();
\r
399 } else if (item instanceof CompoundPropertyItem) {
\r
400 if (valueCount < 1)
\r
404 for (int i = 0; i < valueCount; i++) {
\r
405 TableViewerColumn value = new TableViewerColumn(viewer, SWT.LEFT);
\r
406 //value.getColumn().setText("Value " + (i+1));
\r
407 value.getColumn().setText("");
\r
408 value.getColumn().setWidth(200);
\r
409 valueColumns.add(value);
\r
410 //value.setEditingSupport(new )
\r
412 viewer.getTable().setHeaderVisible(true);
\r
413 viewer.getTable().setLinesVisible(true);
\r
414 viewer.addSelectionChangedListener(new ISelectionChangedListener() {
\r
417 public void selectionChanged(SelectionChangedEvent event) {
\r
418 PropertyItem item = AdaptationUtils.adaptToSingle(event.getSelection(), PropertyItem.class);
\r
419 selectedItem = item;
\r
420 if (!manipulators.get(selectedItem).getEditMode())
\r
421 manipulators.get(selectedItem).setEditMode(true);
\r
424 for (IPropertyItem i : delayedUpdate) {
\r
425 if (!i.equals(selectedItem)) {
\r
426 manipulators.get(i).setEditMode(false);
\r
427 viewer.update(i,null);
\r
430 if (delayedUpdate.contains(selectedItem)) {
\r
431 delayedUpdate.clear();
\r
432 delayedUpdate.add(selectedItem);
\r
434 delayedUpdate.clear();
\r
439 CellNavigationStrategy nStrategy = new CellNavigationStrategy() {
\r
440 private ViewerCell internalFindSelectedCell(
\r
441 ColumnViewer viewer, ViewerCell currentSelectedCell,
\r
443 switch (event.keyCode) {
\r
445 if (currentSelectedCell != null) {
\r
446 return getNeighbor(currentSelectedCell,
\r
447 ViewerCell.ABOVE, false);
\r
450 case SWT.ARROW_DOWN:
\r
451 if (currentSelectedCell != null) {
\r
452 return getNeighbor(currentSelectedCell,
\r
453 ViewerCell.BELOW, false);
\r
456 case SWT.ARROW_LEFT:
\r
457 if (currentSelectedCell != null) {
\r
458 return getNeighbor(currentSelectedCell,
\r
459 ViewerCell.LEFT, true);
\r
462 case SWT.ARROW_RIGHT:
\r
463 if (currentSelectedCell != null) {
\r
464 return getNeighbor(currentSelectedCell,
\r
465 ViewerCell.RIGHT, true);
\r
472 public ViewerCell findSelectedCell(ColumnViewer viewer,
\r
473 ViewerCell currentSelectedCell, Event event) {
\r
474 ViewerCell cell = internalFindSelectedCell(viewer,
\r
475 currentSelectedCell, event);
\r
476 if (cell != null) {
\r
477 TableColumn t = AnnotatedPropertyTab.this.viewer.getTable().getColumn(
\r
478 cell.getColumnIndex());
\r
479 AnnotatedPropertyTab.this.viewer.getTable().showColumn(t);
\r
485 TableViewerFocusCellManager focusCellManager = new TableViewerFocusCellManager(
\r
486 viewer, new FocusCellOwnerDrawHighlighter(viewer));
\r
488 Field f = focusCellManager.getClass().getSuperclass()
\r
489 .getDeclaredField("navigationStrategy");
\r
490 f.setAccessible(true);
\r
491 f.set(focusCellManager, nStrategy);
\r
492 } catch (SecurityException e) {
\r
493 e.printStackTrace();
\r
494 } catch (NoSuchFieldException e) {
\r
495 e.printStackTrace();
\r
496 } catch (IllegalArgumentException e) {
\r
497 e.printStackTrace();
\r
498 } catch (IllegalAccessException e) {
\r
499 e.printStackTrace();
\r
501 ColumnViewerEditorActivationStrategy actSupport = new ColumnViewerEditorActivationStrategy(
\r
503 protected boolean isEditorActivationEvent(
\r
504 ColumnViewerEditorActivationEvent event) {
\r
505 return event.eventType == ColumnViewerEditorActivationEvent.TRAVERSAL
\r
506 || event.eventType == ColumnViewerEditorActivationEvent.MOUSE_DOUBLE_CLICK_SELECTION
\r
507 || (event.eventType == ColumnViewerEditorActivationEvent.KEY_PRESSED && event.keyCode == SWT.CR)
\r
508 || event.eventType == ColumnViewerEditorActivationEvent.PROGRAMMATIC;
\r
511 TableViewerEditor.create(viewer, focusCellManager, actSupport,
\r
512 ColumnViewerEditor.TABBING_HORIZONTAL
\r
513 | ColumnViewerEditor.TABBING_MOVE_TO_ROW_NEIGHBOR
\r
514 | ColumnViewerEditor.TABBING_VERTICAL
\r
515 | ColumnViewerEditor.KEYBOARD_ACTIVATION);
\r
516 viewer.getColumnViewerEditor().addEditorActivationListener(
\r
517 new ColumnViewerEditorActivationListener() {
\r
518 public void afterEditorActivated(
\r
519 ColumnViewerEditorActivationEvent event) {
\r
522 public void afterEditorDeactivated(
\r
523 ColumnViewerEditorDeactivationEvent event) {
\r
526 public void beforeEditorActivated(
\r
527 ColumnViewerEditorActivationEvent event) {
\r
528 ViewerCell cell = (ViewerCell) event.getSource();
\r
529 viewer.getTable().showColumn(
\r
530 viewer.getTable().getColumn(cell.getColumnIndex()));
\r
533 public void beforeEditorDeactivated(
\r
534 ColumnViewerEditorDeactivationEvent event) {
\r
542 private IPropertyItem selectedItem = null;
\r
543 private Set<IPropertyItem> delayedUpdate = new HashSet<IPropertyItem>();
\r
547 public void setInput(ISessionContext context, ISelection selection,
\r
549 Collection<IG3DNode> nodes = AdaptationUtils.adaptToCollection(selection, IG3DNode.class);
\r
550 if (nodes.size() != 1) {
\r
551 if (node != null) {
\r
552 node.removeListener(this);
\r
557 IG3DNode n = nodes.iterator().next();
\r
558 if (node != null) {
\r
559 if (!node.equals(n)) {
\r
560 node.removeListener(this);
\r
570 private void setInput(IG3DNode node) {
\r
572 this.node.addListener(this);
\r
580 if (n instanceof NodeMapProvider<?>) {
\r
581 nodeMap = ((NodeMapProvider<?>) n).getNodeMap();
\r
582 if (nodeMap != null)
\r
585 n = (IG3DNode)n.getParent();
\r
587 boolean readOnly = (node instanceof IStructuralNode && ((IStructuralNode)node).isPartOfInstantiatedModel() && !((IStructuralNode)node).isInstantiatedModelRoot());
\r
588 // create label providers
\r
589 PropertyValueLabelProvider2 p = new PropertyValueLabelProvider2(this);
\r
591 for (TableViewerColumn c : valueColumns) {
\r
592 c.setLabelProvider(p);
\r
594 PropertyEditingSupport support = new PropertyEditingSupport(this, viewer, index++, nodeMap);
\r
595 c.setEditingSupport(support);
\r
598 resolvedItems.clear();
\r
599 manipulators.clear();
\r
600 for (IPropertyItem item : contibutedItems) {
\r
601 if (item instanceof PropertyItem) {
\r
602 resolvedItems.add((PropertyItem)item);
\r
603 manipulators.put((PropertyItem)item, createManipulator((PropertyItem)item, node));
\r
606 CompoundPropertyItem compound = (CompoundPropertyItem)item;
\r
607 Map<PropertyItem, PropertyManipulator> manipulators = createManipulators(compound, node);
\r
608 for (PropertyItem i : manipulators.keySet()) {
\r
609 resolvedItems.add(i);
\r
610 this.manipulators.put(i, manipulators.get(i));
\r
615 viewer.getTable().setEnabled(!readOnly);
\r
616 viewer.setInput(resolvedItems);
\r
620 public void requestFocus() {
\r
621 viewer.getTable().forceFocus();
\r
625 public void dispose() {
\r
626 if (node != null) {
\r
627 node.removeListener(this);
\r
634 public Control getControl() {
\r
635 return viewer.getTable();
\r
639 public ISelectionProvider getSelectionProvider() {
\r
644 public boolean isDisposed() {
\r
645 return viewer.getTable().isDisposed();
\r
649 public <T extends INode> void nodeAdded(ParentNode<T> node,
\r
650 INode child, String rel) {
\r
655 public <T extends INode> void nodeRemoved(ParentNode<T> node,
\r
656 INode child, String rel) {
\r
661 public void propertyChanged(INode node, final String id) {
\r
662 // for (final PropertyItem item : items) {
\r
663 // if (item.id.equals(id)) {
\r
664 // Display.getDefault().asyncExec(new Runnable() {
\r
667 // public void run() {
\r
668 // viewer.update(item, null);
\r
674 if (Thread.currentThread() == Display.getDefault().getThread()) {
\r
675 if (DEBUG)System.out.println("Viewer refresh " + id);
\r
676 for (PropertyItem item : resolvedItems)
\r
677 if (!item.equals(selectedItem))
\r
678 viewer.refresh(item);
\r
679 if (selectedItem != null)
\r
680 delayedUpdate.add(selectedItem);
\r
681 } else if (!editing){
\r
682 // running delayed refresh when a cell editor is active would cancel cell editing.
\r
683 Display.getDefault().asyncExec(new Runnable() {
\r
685 public void run() {
\r
686 if (viewer.getTable().isDisposed()) {
\r
687 if (AnnotatedPropertyTab.this.node != null)
\r
688 AnnotatedPropertyTab.this.node.removeListener(AnnotatedPropertyTab.this);
\r
691 if (DEBUG) System.out.println("Viewer threaded refresh " + id);
\r
692 for (PropertyItem item : resolvedItems)
\r
693 if (!item.equals(selectedItem))
\r
694 viewer.refresh(item);
\r
695 if (selectedItem != null)
\r
696 delayedUpdate.add(selectedItem);
\r
701 for (PropertyItem item : resolvedItems) {
\r
702 delayedUpdate.add(item);
\r
713 public void updatePartName(Callback<String> updateCallback) {
\r
715 updateCallback.run(node.toString());
\r
719 public PropertyManipulator getManipulator(PropertyItem item) {
\r
720 return manipulators.get(item);
\r
723 private boolean editing = false;
\r
725 public void setEditing(boolean editing) {
\r
726 this.editing = editing;
\r
732 private static class PropertyEditingSupport extends EditingSupport {
\r
733 AnnotatedPropertyTab tab;
\r
735 NodeMap<?> nodeMap;
\r
736 TableViewer viewer;
\r
739 public PropertyEditingSupport(AnnotatedPropertyTab tab, TableViewer viewer, int index, NodeMap<?> nodeMap) {
\r
742 this.index = index;
\r
743 this.viewer = viewer;
\r
744 this.nodeMap = nodeMap;
\r
748 protected boolean canEdit(Object element) {
\r
749 PropertyItem item = (PropertyItem)element;
\r
750 if (tab.getManipulator(item).getValueCount() <= index)
\r
752 return (item.setter != null);
\r
756 protected CellEditor getCellEditor(Object element) {
\r
758 if (tab.getManipulator((PropertyItem)element).getValueCount() <= index)
\r
760 if (editor == null)
\r
761 editor = new TextCellEditor(viewer.getTable(),SWT.NONE) {
\r
763 public void activate() {
\r
764 tab.setEditing(true);
\r
768 public void deactivate() {
\r
769 super.deactivate();
\r
770 tab.setEditing(false);
\r
773 if (DEBUG)System.err.println("CELL EDITOR: " + element);
\r
778 protected Object getValue(Object element) {
\r
779 PropertyItem item = (PropertyItem)element;
\r
780 PropertyManipulator manipulator = tab.getManipulator(item);//createManipulator(item, obj);
\r
781 if (manipulator.getValueCount() <= index)
\r
783 Object value = manipulator.getValue(index);
\r
788 protected void setValue(Object element, Object value) {
\r
790 PropertyItem item = (PropertyItem)element;
\r
791 PropertyManipulator manipulator = tab.getManipulator(item);//createManipulator(item, obj);
\r
792 if (manipulator.getValueCount() <= index)
\r
793 throw new IllegalAccessError("Editing value in index " + index + " is not allowed.");
\r
794 if (DEBUG)System.err.println("CELL SET VALUE: " + element + " " + value);
\r
795 manipulator.setValue((String)value,index);
\r
796 viewer.refresh(item);
\r
805 private static class PropertyItemNameProvider extends CellLabelProvider {
\r
809 public void update(ViewerCell cell) {
\r
810 PropertyItem item = (PropertyItem)cell.getElement();
\r
812 if (item.name.length() > 0)
\r
813 cell.setText(item.name);
\r
815 cell.setText(item.id);
\r
821 private static class PropertyValueLabelProvider2 extends CellLabelProvider {
\r
822 AnnotatedPropertyTab tab;
\r
823 //private Object object;
\r
825 public PropertyValueLabelProvider2(AnnotatedPropertyTab tab) {
\r
830 public void update(ViewerCell cell) {
\r
831 PropertyItem item = (PropertyItem)cell.getElement();
\r
832 int index = cell.getColumnIndex() -1;
\r
833 PropertyManipulator manipulator = tab.getManipulator(item);//createManipulator(item, object);
\r
834 if (manipulator.getValueCount() <= index)
\r
836 cell.setText(manipulator.getValue(index));
\r
840 private static class PropertyItemContentsProvider implements IStructuredContentProvider {
\r
841 @SuppressWarnings("unchecked")
\r
843 public Object[] getElements(Object inputElement) {
\r
844 List<PropertyItem> items = (List<PropertyItem>)inputElement;
\r
845 return items.toArray();
\r
849 public void dispose() {
\r
854 public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
\r
861 private static ViewerCell getNeighbor(ViewerCell currentCell,
\r
862 int directionMask, boolean sameLevel) {
\r
864 if ((directionMask & ViewerCell.ABOVE) == ViewerCell.ABOVE) {
\r
865 row = currentCell.getViewerRow().getNeighbor(ViewerRow.ABOVE,
\r
867 } else if ((directionMask & ViewerCell.BELOW) == ViewerCell.BELOW) {
\r
868 row = currentCell.getViewerRow().getNeighbor(ViewerRow.BELOW,
\r
871 row = currentCell.getViewerRow();
\r
875 columnIndex = getVisualIndex(row, currentCell.getColumnIndex());
\r
877 if ((directionMask & ViewerCell.LEFT) == ViewerCell.LEFT) {
\r
879 } else if ((directionMask & ViewerCell.RIGHT) == ViewerCell.RIGHT) {
\r
882 columnIndex += modifier;
\r
883 if (columnIndex >= 0 && columnIndex < row.getColumnCount()) {
\r
884 ViewerCell cell = getCellAtVisualIndex(row, columnIndex);
\r
885 if (cell != null) {
\r
886 while (cell != null
\r
887 && columnIndex < row.getColumnCount() - 1
\r
888 && columnIndex > 0) {
\r
889 if (isVisible(cell)) {
\r
892 columnIndex += modifier;
\r
893 cell = getCellAtVisualIndex(row, columnIndex);
\r
894 if (cell == null) {
\r
907 public static class TableViewerEditor extends ColumnViewerEditor {
\r
909 * This viewer's table editor.
\r
911 private TableEditor tableEditor;
\r
912 private TableViewerFocusCellManager focusCellManager;
\r
913 private int feature;
\r
917 * the viewer the editor is attached to
\r
918 * @param focusCellManager
\r
919 * the cell focus manager if one used or <code>null</code>
\r
920 * @param editorActivationStrategy
\r
921 * the strategy used to decide about the editor activation
\r
925 TableViewerEditor(TableViewer viewer,
\r
926 TableViewerFocusCellManager focusCellManager,
\r
927 ColumnViewerEditorActivationStrategy editorActivationStrategy,
\r
929 super(viewer, editorActivationStrategy, feature);
\r
930 this.feature = feature;
\r
931 tableEditor = new TableEditor(viewer.getTable());
\r
932 this.focusCellManager = focusCellManager;
\r
936 * Create a customized editor with focusable cells
\r
939 * the viewer the editor is created for
\r
940 * @param focusCellManager
\r
941 * the cell focus manager if one needed else
\r
942 * <code>null</code>
\r
943 * @param editorActivationStrategy
\r
944 * activation strategy to control if an editor activated
\r
946 * bit mask controlling the editor
\r
948 * <li>{@link ColumnViewerEditor#DEFAULT}</li>
\r
949 * <li>{@link ColumnViewerEditor#TABBING_CYCLE_IN_ROW}</li>
\r
950 * <li>{@link ColumnViewerEditor#TABBING_HORIZONTAL}</li>
\r
952 * {@link ColumnViewerEditor#TABBING_MOVE_TO_ROW_NEIGHBOR}</li>
\r
953 * <li>{@link ColumnViewerEditor#TABBING_VERTICAL}</li>
\r
955 * @see #create(TableViewer, ColumnViewerEditorActivationStrategy, int)
\r
957 public static void create(TableViewer viewer,
\r
958 TableViewerFocusCellManager focusCellManager,
\r
959 ColumnViewerEditorActivationStrategy editorActivationStrategy,
\r
961 TableViewerEditor editor = new TableViewerEditor(viewer,
\r
962 focusCellManager, editorActivationStrategy, feature);
\r
963 viewer.setColumnViewerEditor(editor);
\r
964 if (focusCellManager != null) {
\r
966 Method m = focusCellManager.getClass().getSuperclass()
\r
967 .getDeclaredMethod("init", null);
\r
968 m.setAccessible(true);
\r
969 m.invoke(focusCellManager, null);
\r
970 } catch (SecurityException e) {
\r
971 e.printStackTrace();
\r
972 } catch (IllegalArgumentException e) {
\r
973 e.printStackTrace();
\r
974 } catch (IllegalAccessException e) {
\r
975 e.printStackTrace();
\r
976 } catch (NoSuchMethodException e) {
\r
977 e.printStackTrace();
\r
978 } catch (InvocationTargetException e) {
\r
979 e.printStackTrace();
\r
981 // focusCellManager.init();
\r
986 * Create a customized editor whose activation process is customized
\r
989 * the viewer the editor is created for
\r
990 * @param editorActivationStrategy
\r
991 * activation strategy to control if an editor activated
\r
993 * bit mask controlling the editor
\r
995 * <li>{@link ColumnViewerEditor#DEFAULT}</li>
\r
996 * <li>{@link ColumnViewerEditor#TABBING_CYCLE_IN_ROW}</li>
\r
997 * <li>{@link ColumnViewerEditor#TABBING_HORIZONTAL}</li>
\r
999 * {@link ColumnViewerEditor#TABBING_MOVE_TO_ROW_NEIGHBOR}</li>
\r
1000 * <li>{@link ColumnViewerEditor#TABBING_VERTICAL}</li>
\r
1003 public static void create(TableViewer viewer,
\r
1004 ColumnViewerEditorActivationStrategy editorActivationStrategy,
\r
1006 create(viewer, null, editorActivationStrategy, feature);
\r
1009 protected void setEditor(Control w, Item item, int columnNumber) {
\r
1010 tableEditor.setEditor(w, (TableItem) item, columnNumber);
\r
1013 protected void setLayoutData(LayoutData layoutData) {
\r
1014 tableEditor.grabHorizontal = layoutData.grabHorizontal;
\r
1015 tableEditor.horizontalAlignment = layoutData.horizontalAlignment;
\r
1016 tableEditor.minimumWidth = layoutData.minimumWidth;
\r
1019 public ViewerCell getFocusCell() {
\r
1020 if (focusCellManager != null) {
\r
1021 return focusCellManager.getFocusCell();
\r
1023 return super.getFocusCell();
\r
1026 protected void updateFocusCell(ViewerCell focusCell,
\r
1027 ColumnViewerEditorActivationEvent event) {
\r
1028 // Update the focus cell when we activated the editor with these 2
\r
1030 if (event.eventType == ColumnViewerEditorActivationEvent.PROGRAMMATIC
\r
1031 || event.eventType == ColumnViewerEditorActivationEvent.TRAVERSAL) {
\r
1032 if (focusCellManager != null) {
\r
1034 if (DEBUG)System.err.println("FOCUS CELL: " + focusCell);
\r
1036 Method m = AbstractTableViewer.class.getDeclaredMethod(
\r
1037 "getSelectionFromWidget", null);
\r
1038 m.setAccessible(true);
\r
1039 List l = (List) m.invoke(getViewer(), null);
\r
1040 if (focusCellManager != null) {
\r
1041 m = focusCellManager
\r
1044 .getDeclaredMethod("setFocusCell",
\r
1045 new Class[] { ViewerCell.class });
\r
1046 m.setAccessible(true);
\r
1047 m.invoke(focusCellManager,
\r
1048 new Object[] { focusCell });
\r
1050 if (!l.contains(focusCell.getElement())) {
\r
1051 getViewer().setSelection(
\r
1052 new StructuredSelection(focusCell
\r
1055 } catch (SecurityException e) {
\r
1056 e.printStackTrace();
\r
1057 } catch (IllegalArgumentException e) {
\r
1058 e.printStackTrace();
\r
1059 } catch (IllegalAccessException e) {
\r
1060 e.printStackTrace();
\r
1061 } catch (NoSuchMethodException e) {
\r
1062 e.printStackTrace();
\r
1063 } catch (InvocationTargetException e) {
\r
1064 e.printStackTrace();
\r
1070 protected void processTraverseEvent(int columnIndex, ViewerRow row,
\r
1071 TraverseEvent event) {
\r
1072 ViewerCell cell2edit = null;
\r
1073 if (event.detail == SWT.TRAVERSE_TAB_PREVIOUS) {
\r
1074 event.doit = false;
\r
1075 if ((event.stateMask & SWT.CTRL) == SWT.CTRL
\r
1076 && (feature & TABBING_VERTICAL) == TABBING_VERTICAL) {
\r
1077 cell2edit = searchCellAboveBelow(row, getViewer(),
\r
1078 columnIndex, true);
\r
1079 } else if ((feature & TABBING_HORIZONTAL) == TABBING_HORIZONTAL) {
\r
1080 cell2edit = searchPreviousCell(row,
\r
1081 row.getCell(columnIndex), row.getCell(columnIndex),
\r
1084 } else if (event.detail == SWT.TRAVERSE_TAB_NEXT) {
\r
1085 event.doit = false;
\r
1086 if ((event.stateMask & SWT.CTRL) == SWT.CTRL
\r
1087 && (feature & TABBING_VERTICAL) == TABBING_VERTICAL) {
\r
1088 cell2edit = searchCellAboveBelow(row, getViewer(),
\r
1089 columnIndex, false);
\r
1090 } else if ((feature & TABBING_HORIZONTAL) == TABBING_HORIZONTAL) {
\r
1091 cell2edit = searchNextCell(row, row.getCell(columnIndex),
\r
1092 row.getCell(columnIndex), getViewer());
\r
1095 if (DEBUG) System.err.println("NEXT CELL: " + cell2edit);
\r
1096 if (cell2edit != null) {
\r
1097 getViewer().getControl().setRedraw(false);
\r
1098 ColumnViewerEditorActivationEvent acEvent = new ColumnViewerEditorActivationEvent(
\r
1099 cell2edit, event);
\r
1101 Method m = ColumnViewer.class
\r
1102 .getDeclaredMethod(
\r
1103 "triggerEditorActivationEvent",
\r
1104 new Class[] { ColumnViewerEditorActivationEvent.class });
\r
1105 m.setAccessible(true);
\r
1106 m.invoke(getViewer(), new Object[] { acEvent });
\r
1107 } catch (SecurityException e) {
\r
1108 e.printStackTrace();
\r
1109 } catch (NoSuchMethodException e) {
\r
1110 e.printStackTrace();
\r
1111 } catch (IllegalArgumentException e) {
\r
1112 e.printStackTrace();
\r
1113 } catch (IllegalAccessException e) {
\r
1114 e.printStackTrace();
\r
1115 } catch (InvocationTargetException e) {
\r
1116 e.printStackTrace();
\r
1118 getViewer().getControl().setRedraw(true);
\r
1122 private ViewerCell searchCellAboveBelow(ViewerRow row,
\r
1123 ColumnViewer viewer, int columnIndex, boolean above) {
\r
1124 ViewerCell rv = null;
\r
1125 ViewerRow newRow = null;
\r
1127 newRow = row.getNeighbor(ViewerRow.ABOVE, false);
\r
1129 newRow = row.getNeighbor(ViewerRow.BELOW, false);
\r
1132 if (newRow != null) {
\r
1133 Method m = ColumnViewer.class.getDeclaredMethod(
\r
1134 "getViewerColumn", new Class[] { int.class });
\r
1135 m.setAccessible(true);
\r
1136 ViewerColumn column = (ViewerColumn) m.invoke(viewer,
\r
1137 new Object[] { new Integer(columnIndex) });
\r
1138 m = ViewerColumn.class.getDeclaredMethod(
\r
1139 "getEditingSupport", null);
\r
1140 m.setAccessible(true);
\r
1141 EditingSupport es = (EditingSupport) m.invoke(column, null);
\r
1142 if (column != null && es != null) {
\r
1143 m = EditingSupport.class.getDeclaredMethod("canEdit",
\r
1144 new Class[] { Object.class });
\r
1145 m.setAccessible(true);
\r
1146 Boolean b = (Boolean) m.invoke(es,
\r
1147 new Object[] { newRow.getItem().getData() });
\r
1148 if (b.booleanValue()) {
\r
1149 rv = newRow.getCell(columnIndex);
\r
1152 rv = searchCellAboveBelow(newRow, viewer, columnIndex,
\r
1156 } catch (Exception e) {
\r
1157 e.printStackTrace();
\r
1162 private ViewerCell searchPreviousCell(ViewerRow row,
\r
1163 ViewerCell currentCell, ViewerCell originalCell,
\r
1164 ColumnViewer viewer) {
\r
1165 ViewerCell rv = null;
\r
1166 ViewerCell previousCell;
\r
1167 if (currentCell != null) {
\r
1168 previousCell = getNeighbor(currentCell, ViewerCell.LEFT, true);
\r
1170 if (row.getColumnCount() != 0) {
\r
1171 previousCell = row.getCell(getCreationIndex(row,
\r
1172 row.getColumnCount() - 1));
\r
1174 previousCell = row.getCell(0);
\r
1177 // No endless loop
\r
1178 if (originalCell.equals(previousCell)) {
\r
1181 if (previousCell != null) {
\r
1182 if (isCellEditable(viewer, previousCell)) {
\r
1183 rv = previousCell;
\r
1185 rv = searchPreviousCell(row, previousCell, originalCell,
\r
1189 if ((feature & TABBING_CYCLE_IN_ROW) == TABBING_CYCLE_IN_ROW) {
\r
1190 rv = searchPreviousCell(row, null, originalCell, viewer);
\r
1191 } else if ((feature & TABBING_MOVE_TO_ROW_NEIGHBOR) == TABBING_MOVE_TO_ROW_NEIGHBOR) {
\r
1192 ViewerRow rowAbove = row
\r
1193 .getNeighbor(ViewerRow.ABOVE, false);
\r
1194 if (rowAbove != null) {
\r
1195 rv = searchPreviousCell(rowAbove, null, originalCell,
\r
1203 private ViewerCell searchNextCell(ViewerRow row,
\r
1204 ViewerCell currentCell, ViewerCell originalCell,
\r
1205 ColumnViewer viewer) {
\r
1206 ViewerCell rv = null;
\r
1207 ViewerCell nextCell;
\r
1208 if (currentCell != null) {
\r
1209 nextCell = getNeighbor(currentCell, ViewerCell.RIGHT, true);
\r
1211 nextCell = row.getCell(getCreationIndex(row, 0));
\r
1213 // No endless loop
\r
1214 if (originalCell.equals(nextCell)) {
\r
1217 if (nextCell != null) {
\r
1218 if (isCellEditable(viewer, nextCell)) {
\r
1221 rv = searchNextCell(row, nextCell, originalCell, viewer);
\r
1224 if ((feature & TABBING_CYCLE_IN_ROW) == TABBING_CYCLE_IN_ROW) {
\r
1225 rv = searchNextCell(row, null, originalCell, viewer);
\r
1226 } else if ((feature & TABBING_MOVE_TO_ROW_NEIGHBOR) == TABBING_MOVE_TO_ROW_NEIGHBOR) {
\r
1227 ViewerRow rowBelow = row
\r
1228 .getNeighbor(ViewerRow.BELOW, false);
\r
1229 if (rowBelow != null) {
\r
1230 rv = searchNextCell(rowBelow, null, originalCell,
\r
1238 private boolean isCellEditable(ColumnViewer viewer, ViewerCell cell) {
\r
1240 Method m = ColumnViewer.class.getDeclaredMethod(
\r
1241 "getViewerColumn", new Class[] { int.class });
\r
1242 m.setAccessible(true);
\r
1243 ViewerColumn column = (ViewerColumn) m.invoke(viewer,
\r
1244 new Object[] { new Integer(cell.getColumnIndex()) });
\r
1245 m = ViewerColumn.class.getDeclaredMethod("getEditingSupport",
\r
1247 m.setAccessible(true);
\r
1248 EditingSupport es = (EditingSupport) m.invoke(column, null);
\r
1249 if (column != null && es != null) {
\r
1250 m = EditingSupport.class.getDeclaredMethod("canEdit",
\r
1251 new Class[] { Object.class });
\r
1252 m.setAccessible(true);
\r
1254 Boolean b = (Boolean) m.invoke(es,
\r
1255 new Object[] { cell.getElement() });
\r
1256 return b.booleanValue();
\r
1258 } catch (Exception e) {
\r
1259 e.printStackTrace();
\r
1265 // Reimplementation of ViewerCell-Methods
\r
1266 private static int getVisualIndex(ViewerRow row, int creationIndex) {
\r
1267 TableItem item = (TableItem) row.getItem();
\r
1268 int[] order = item.getParent().getColumnOrder();
\r
1269 for (int i = 0; i < order.length; i++) {
\r
1270 if (order[i] == creationIndex) {
\r
1274 return creationIndex;
\r
1277 private static int getCreationIndex(ViewerRow row, int visualIndex) {
\r
1278 TableItem item = (TableItem) row.getItem();
\r
1279 if (item != null && !item.isDisposed() /*
\r
1280 * && hasColumns() &&
\r
1281 * isValidOrderIndex
\r
1284 return item.getParent().getColumnOrder()[visualIndex];
\r
1286 return visualIndex;
\r
1289 private static ViewerCell getCellAtVisualIndex(ViewerRow row,
\r
1290 int visualIndex) {
\r
1291 return getCell(row, getCreationIndex(row, visualIndex));
\r
1294 private static boolean isVisible(ViewerCell cell) {
\r
1295 return getWidth(cell) > 0;
\r
1298 private static int getWidth(ViewerCell cell) {
\r
1299 TableItem item = (TableItem) cell.getViewerRow().getItem();
\r
1300 return item.getParent().getColumn(cell.getColumnIndex()).getWidth();
\r
1303 private static ViewerCell getCell(ViewerRow row, int index) {
\r
1304 return row.getCell(index);
\r