]> gerrit.simantics Code Review - simantics/3d.git/blob - org.simantics.g3d/src/org/simantics/g3d/property/AnnotatedPropertyTabContributorFactory.java
Merge changes Ia3e00f11,I7f3a3a75
[simantics/3d.git] / org.simantics.g3d / src / org / simantics / g3d / property / AnnotatedPropertyTabContributorFactory.java
1 /*******************************************************************************
2  * Copyright (c) 2012, 2013 Association for Decentralized Information Management in
3  * Industry THTH ry.
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
8  *
9  * Contributors:
10  *     VTT Technical Research Centre of Finland - initial API and implementation
11  *******************************************************************************/
12 package org.simantics.g3d.property;
13
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.HashMap;
22 import java.util.HashSet;
23 import java.util.LinkedHashMap;
24 import java.util.List;
25 import java.util.Map;
26 import java.util.Set;
27 import java.util.function.Consumer;
28
29 import org.eclipse.jface.layout.GridDataFactory;
30 import org.eclipse.jface.viewers.AbstractTableViewer;
31 import org.eclipse.jface.viewers.CellEditor;
32 import org.eclipse.jface.viewers.CellEditor.LayoutData;
33 import org.eclipse.jface.viewers.CellLabelProvider;
34 import org.eclipse.jface.viewers.CellNavigationStrategy;
35 import org.eclipse.jface.viewers.ColumnViewer;
36 import org.eclipse.jface.viewers.ColumnViewerEditor;
37 import org.eclipse.jface.viewers.ColumnViewerEditorActivationEvent;
38 import org.eclipse.jface.viewers.ColumnViewerEditorActivationListener;
39 import org.eclipse.jface.viewers.ColumnViewerEditorActivationStrategy;
40 import org.eclipse.jface.viewers.ColumnViewerEditorDeactivationEvent;
41 import org.eclipse.jface.viewers.EditingSupport;
42 import org.eclipse.jface.viewers.FocusCellOwnerDrawHighlighter;
43 import org.eclipse.jface.viewers.ISelection;
44 import org.eclipse.jface.viewers.ISelectionChangedListener;
45 import org.eclipse.jface.viewers.ISelectionProvider;
46 import org.eclipse.jface.viewers.IStructuredContentProvider;
47 import org.eclipse.jface.viewers.SelectionChangedEvent;
48 import org.eclipse.jface.viewers.StructuredSelection;
49 import org.eclipse.jface.viewers.TableViewer;
50 import org.eclipse.jface.viewers.TableViewerColumn;
51 import org.eclipse.jface.viewers.TableViewerFocusCellManager;
52 import org.eclipse.jface.viewers.TextCellEditor;
53 import org.eclipse.jface.viewers.Viewer;
54 import org.eclipse.jface.viewers.ViewerCell;
55 import org.eclipse.jface.viewers.ViewerColumn;
56 import org.eclipse.jface.viewers.ViewerRow;
57 import org.eclipse.swt.SWT;
58 import org.eclipse.swt.custom.TableEditor;
59 import org.eclipse.swt.events.TraverseEvent;
60 import org.eclipse.swt.widgets.Composite;
61 import org.eclipse.swt.widgets.Control;
62 import org.eclipse.swt.widgets.Display;
63 import org.eclipse.swt.widgets.Event;
64 import org.eclipse.swt.widgets.Item;
65 import org.eclipse.swt.widgets.TableColumn;
66 import org.eclipse.swt.widgets.TableItem;
67 import org.eclipse.ui.IWorkbenchSite;
68 import org.simantics.db.management.ISessionContext;
69 import org.simantics.g3d.property.annotations.CompoundGetPropertyValue;
70 import org.simantics.g3d.property.annotations.CompoundSetPropertyValue;
71 import org.simantics.g3d.property.annotations.GetPropertyValue;
72 import org.simantics.g3d.property.annotations.PropertyTabBlacklist;
73 import org.simantics.g3d.property.annotations.SetPropertyValue;
74 import org.simantics.g3d.scenegraph.IG3DNode;
75 import org.simantics.g3d.scenegraph.NodeMap;
76 import org.simantics.g3d.scenegraph.NodeMapProvider;
77 import org.simantics.g3d.scenegraph.base.INode;
78 import org.simantics.g3d.scenegraph.base.NodeListener;
79 import org.simantics.g3d.scenegraph.base.ParentNode;
80 import org.simantics.g3d.scenegraph.structural.IStructuralNode;
81 import org.simantics.g3d.tools.AdaptationUtils;
82 import org.simantics.selectionview.IPropertyTab;
83 import org.simantics.selectionview.IPropertyTab2;
84 import org.simantics.utils.datastructures.Callback;
85 import org.simantics.utils.datastructures.MapList;
86
87 public class AnnotatedPropertyTabContributorFactory implements PropertyTabContributorFactory {
88
89         private static final boolean DEBUG = false;
90         
91         @SuppressWarnings("unchecked")
92         @Override
93         public List<PropertyTabContributor> getContributors(Object input) {
94                 Map<String,IPropertyItem> items = new LinkedHashMap<String, IPropertyItem>();
95                 List<String> blacklist = new ArrayList<String>();
96                 try {
97                         collectItems(input.getClass(), items);
98                         collectBlacklist(input.getClass(), blacklist);
99                 } catch (InstantiationException e) {
100                         // TODO Auto-generated catch block
101                         e.printStackTrace();
102                 } catch (IllegalAccessException e) {
103                         // TODO Auto-generated catch block
104                         e.printStackTrace();
105                 }
106                 
107                 if (items.size() == 0)
108                         return Collections.EMPTY_LIST;
109                 
110                 MapList<String, IPropertyItem> tabMap = new MapList<String, IPropertyItem>();
111                 List<String> tabs = new ArrayList<String>();
112                 for (String id : items.keySet()) {
113                         IPropertyItem item = items.get(id);
114                         tabMap.add(item.getTabId(), item);
115                         if (!tabs.contains(item.getTabId())) {
116                                 tabs.add(item.getTabId());
117                                 //System.out.println(item.tabId + " " + item.name + " " + item.id);
118                         }
119                 }
120                 for (String s : blacklist) {
121                         tabs.remove(s);
122                 }
123                 
124                 List<PropertyTabContributor> contributors = new ArrayList<PropertyTabContributor>(tabs.size());
125                 for (String tabId : tabs) {
126                         contributors.add(new AnnotatedPropertyTabContributor(tabId, tabMap.getValues(tabId)));
127                 }
128                 
129                 return contributors;
130         }
131         
132         
133         private static void collectItems(Class<?> clazz, Map<String, IPropertyItem> items) throws InstantiationException, IllegalAccessException {
134                  Class<?> superclass = clazz.getSuperclass();
135                  if(superclass != null)
136                          collectItems(superclass, items);
137                  
138                  for (Method m : clazz.getDeclaredMethods()) {
139                          m.setAccessible(true);
140                 for (Annotation annotation : m.getAnnotations()) {
141                         if (annotation.annotationType().equals(GetPropertyValue.class)) {
142                                 GetPropertyValue get = (GetPropertyValue)annotation;
143                                 PropertyItem item = (PropertyItem)items.get(get.value());
144                                 if (item == null) {
145                                         item = new PropertyItem(get.value());
146                                         items.put(item.id, item);
147                                 }
148
149                                 item.getter = m;
150                                 item.manipulatorClass = get.manipulator().newInstance().get(m,null);
151
152                                 item.tabId = get.tabId();
153
154                                 item.name = get.name();
155                                 
156                                 
157                         } else if (annotation.annotationType().equals(SetPropertyValue.class)) {
158                                 SetPropertyValue set = (SetPropertyValue)annotation;
159                                 PropertyItem item = (PropertyItem)items.get(set.value());
160                                 if (item == null) {
161                                         item = new PropertyItem(set.value());
162                                         items.put(item.id, item);
163                                 }
164                                 
165                                 item.setter = m;
166                         } else if (annotation.annotationType().equals(CompoundGetPropertyValue.class)) {
167                                 CompoundGetPropertyValue get = (CompoundGetPropertyValue)annotation;
168                                 CompoundPropertyItem item = (CompoundPropertyItem)items.get(get.value());
169                                 if (item == null) {
170                                         item = new CompoundPropertyItem(get.value());
171                                         items.put(item.id, item);
172                                 }
173
174                                 item.getter = m;
175                                 item.manipulatorFactory = get.manipulator().newInstance();
176
177                                 item.tabId = get.tabId();
178
179                                 item.name = get.name();
180                         } else if (annotation.annotationType().equals(CompoundSetPropertyValue.class)) {
181                                 CompoundSetPropertyValue set = (CompoundSetPropertyValue)annotation;
182                                 CompoundPropertyItem item = (CompoundPropertyItem)items.get(set.value());
183                                 if (item == null) {
184                                         item = new CompoundPropertyItem(set.value());
185                                         items.put(item.id, item);
186                                 }
187                                 
188                                 item.setter = m;
189                         }
190                 }
191                  }
192                 
193                 
194         }
195         
196         private static void collectBlacklist(Class<?> clazz, List<String> blacklist) throws InstantiationException, IllegalAccessException {
197                  Class<?> superclass = clazz.getSuperclass();
198                  if(superclass != null)
199                          collectBlacklist(superclass, blacklist);
200                  
201                  PropertyTabBlacklist ann = clazz.getAnnotation(PropertyTabBlacklist.class);
202                  if (ann == null)
203                          return;
204                  String s = ann.value();
205                  if (s == null)
206                          return;
207                  if (s.length() == 0)
208                          return;
209                  for (String item : s.split(";")) {
210                          blacklist.add(item);
211                  }
212                  
213                 
214         }
215         
216         private static Map<PropertyItem, PropertyManipulator> createManipulators(CompoundPropertyItem item, Object obj) {
217                 try {
218                         
219                         Map<String,Object> map = (Map<String, Object>)item.getter.invoke(obj);
220                         Map<PropertyItem, PropertyManipulator> result = new HashMap<AnnotatedPropertyTabContributorFactory.PropertyItem, PropertyManipulator>();
221                         for (String key : map.keySet()) {
222                                 MethodWithMapValueProvider provider = new MethodWithMapValueProvider(item.getter, item.setter, key);
223                                 Class<? extends PropertyManipulator> clazz = item.manipulatorFactory.get(null,map.get(key));
224                                 PropertyManipulator manipulator = clazz.getConstructor(ValueProvider.class,Object.class).newInstance(provider,obj);
225                                 PropertyItem i = new PropertyItem(item.id+"."+key);
226                                 i.getter = item.getter;
227                                 i.setter = item.setter;
228                                 i.name = key;
229                                 i.tabId = item.tabId;
230                                 result.put(i,manipulator);
231                         }
232                         return result;
233                 } catch (Exception e) {
234                         e.printStackTrace();
235                         return Collections.EMPTY_MAP;
236                 } 
237                 
238         }
239         
240         private static PropertyManipulator createManipulator(PropertyItem item, Object obj) {
241                 try {
242                         MethodValueProvider provider = new MethodValueProvider(item.getter, item.setter);
243                         PropertyManipulator manipulator = item.manipulatorClass.getConstructor(ValueProvider.class,Object.class).newInstance(provider,obj);
244                         return manipulator;
245                 } catch (Exception e) {
246                         e.printStackTrace();
247                         return null;
248                 } 
249         }
250         
251         private static interface IPropertyItem {
252                 public String getTabId();
253         }
254         
255         private static class PropertyItem implements IPropertyItem{
256                 private String id;
257                 private String name;
258                 private String tabId;
259                 private Method getter;
260                 private Method setter;
261                 private Class<? extends PropertyManipulator> manipulatorClass;
262                 
263                 
264                 public PropertyItem(String id) {
265                         if (id == null)
266                                 throw new NullPointerException();
267                         this.id = id;
268                 }
269                 
270                 @Override
271                 public int hashCode() {
272                         return id.hashCode();
273                 }
274                 
275                 @Override
276                 public String getTabId() {
277                         return tabId;
278                 }
279         }
280         
281         private static class CompoundPropertyItem implements IPropertyItem{
282                 private String id;
283                 private String name;
284                 private String tabId;
285                 private Method getter;
286                 private Method setter;
287                 private PropertyManipulatorFactory manipulatorFactory;
288                 
289                 
290                 public CompoundPropertyItem(String id) {
291                         if (id == null)
292                                 throw new NullPointerException();
293                         this.id = id;
294                 }
295                 
296                 @Override
297                 public int hashCode() {
298                         return id.hashCode();
299                 }
300                 
301                 @Override
302                 public String getTabId() {
303                         return tabId;
304                 }
305         }
306         
307         private static class AnnotatedPropertyTabContributor implements PropertyTabContributor {
308                 private String id; 
309                 List<IPropertyItem> items;
310                 
311                 public AnnotatedPropertyTabContributor(String id, List<IPropertyItem> items) {
312                         if (id == null)
313                                 throw new NullPointerException();
314                         this.id = id;
315                         this.items = items;
316                 }
317                 
318                 @Override
319                 public IPropertyTab create(Composite parent, IWorkbenchSite site,
320                                 ISessionContext context, Object input) {
321                         AnnotatedPropertyTab tab = new AnnotatedPropertyTab(id, items);
322                         tab.createControl(parent, context);
323                         return tab;
324                 }
325                 
326                 @Override
327                 public String getId() {
328                         return id;
329                 }
330                 
331         }
332         
333         private static class AnnotatedPropertyTab implements IPropertyTab2, NodeListener {
334                 //private String id; 
335                 List<IPropertyItem> contibutedItems;
336                 List<PropertyItem> resolvedItems = new ArrayList<PropertyItem>();
337                 private Map<PropertyItem,PropertyManipulator> manipulators = new HashMap<PropertyItem, PropertyManipulator>();
338                 
339                 private TableViewer viewer;
340                 
341                 private IG3DNode node;
342                 private NodeMap<?,?> nodeMap;
343                 
344                 private List<TableViewerColumn> valueColumns = new ArrayList<TableViewerColumn>();
345                 
346                 public AnnotatedPropertyTab(String id, List<IPropertyItem> items) {
347                         //this.id = id;
348                         this.contibutedItems = items;
349                         
350                                         
351                 }
352                 
353                 @Override
354                 public void createControl(Composite parent, ISessionContext context) {
355                         //parent.setLayout(new FillLayout());
356                         viewer = new TableViewer(parent, SWT.FULL_SELECTION | SWT.SINGLE);
357                         
358                         GridDataFactory.fillDefaults().align(SWT.FILL, SWT.FILL).grab(true, true).applyTo(viewer.getTable());
359                         
360                         //viewer.setLabelProvider(new AnnotatedTableLabelProvider(object))
361                         
362                         viewer.setContentProvider(new PropertyItemContentsProvider());
363                         
364                         TableViewerColumn name = new TableViewerColumn(viewer, SWT.LEFT);
365                         //TableViewerColumn value = new TableViewerColumn(viewer, SWT.LEFT);
366                         name.setLabelProvider(new PropertyItemNameProvider());
367                         //value.setLabelProvider(new PropertyValueLabelProvider(null));
368                         name.getColumn().setText("Property");
369                         //value.getColumn().setText("Value");
370                         name.getColumn().setWidth(200);
371                         //value.getColumn().setWidth(200);
372                         name.getViewer().addSelectionChangedListener(new ISelectionChangedListener() {
373                                 
374                                 @Override
375                                 public void selectionChanged(SelectionChangedEvent event) {
376                                         PropertyItem item = AdaptationUtils.adaptToSingle(event.getSelection(),PropertyItem.class);
377                                         if (item != null) {
378                                                 PropertyManipulator manipulator = manipulators.get(item);//createManipulator(item, null);
379                                                 for (int i = 0; i < valueColumns.size(); i++) {
380                                                         TableViewerColumn c = valueColumns.get(i);
381                                                         if (i < manipulator.getValueCount()) {
382                                                                 c.getColumn().setText(manipulator.getDescription(i));
383                                                         } else {
384                                                                 c.getColumn().setText("");
385                                                         }
386                                                 }
387                                         }
388                                         
389                                 }
390                         });
391                         
392                         int valueCount = 0;
393                         for (IPropertyItem item : contibutedItems) {
394                                 if (item instanceof PropertyItem) {
395                                         PropertyManipulator manipulator = createManipulator((PropertyItem)item, null);
396                                         if (manipulator == null)
397                                                 continue;
398                                         if (valueCount < manipulator.getValueCount())
399                                                 valueCount = manipulator.getValueCount();
400                                 } else if (item instanceof CompoundPropertyItem) {
401                                         if (valueCount < 1)
402                                                 valueCount = 1;
403                                 }
404                         }
405                         for (int i = 0; i < valueCount; i++) {
406                                 TableViewerColumn value = new TableViewerColumn(viewer, SWT.LEFT);
407                                 //value.getColumn().setText("Value " + (i+1));
408                                 value.getColumn().setText("");
409                                 value.getColumn().setWidth(200);
410                                 valueColumns.add(value);
411                                 //value.setEditingSupport(new )
412                         }
413                         viewer.getTable().setHeaderVisible(true);
414                         viewer.getTable().setLinesVisible(true);
415                         viewer.addSelectionChangedListener(new ISelectionChangedListener() {
416                                 
417                                 @Override
418                                 public void selectionChanged(SelectionChangedEvent event) {
419                                         PropertyItem item = AdaptationUtils.adaptToSingle(event.getSelection(), PropertyItem.class);
420                                         selectedItem = item;
421                                         if (!manipulators.get(selectedItem).getEditMode())
422                                                 manipulators.get(selectedItem).setEditMode(true);
423                                         
424
425                                         for (IPropertyItem i : delayedUpdate) {
426                                                 if (!i.equals(selectedItem)) {
427                                                         manipulators.get(i).setEditMode(false);
428                                                         viewer.update(i,null);
429                                                 }
430                                         }
431                                         if (delayedUpdate.contains(selectedItem)) {
432                                                 delayedUpdate.clear();
433                                                 delayedUpdate.add(selectedItem);
434                                         } else {
435                                                 delayedUpdate.clear();
436                                         }
437                                 }
438                         });
439                         
440                         CellNavigationStrategy nStrategy = new CellNavigationStrategy() {
441                                 private ViewerCell internalFindSelectedCell(
442                                                 ColumnViewer viewer, ViewerCell currentSelectedCell,
443                                                 Event event) {
444                                         switch (event.keyCode) {
445                                         case SWT.ARROW_UP:
446                                                 if (currentSelectedCell != null) {
447                                                         return getNeighbor(currentSelectedCell,
448                                                                         ViewerCell.ABOVE, false);
449                                                 }
450                                                 break;
451                                         case SWT.ARROW_DOWN:
452                                                 if (currentSelectedCell != null) {
453                                                         return getNeighbor(currentSelectedCell,
454                                                                         ViewerCell.BELOW, false);
455                                                 }
456                                                 break;
457                                         case SWT.ARROW_LEFT:
458                                                 if (currentSelectedCell != null) {
459                                                         return getNeighbor(currentSelectedCell,
460                                                                         ViewerCell.LEFT, true);
461                                                 }
462                                                 break;
463                                         case SWT.ARROW_RIGHT:
464                                                 if (currentSelectedCell != null) {
465                                                         return getNeighbor(currentSelectedCell,
466                                                                         ViewerCell.RIGHT, true);
467                                                 }
468                                                 break;
469                                         }
470                                         return null;
471                                 }
472                                 
473                                 public ViewerCell findSelectedCell(ColumnViewer viewer,
474                                                 ViewerCell currentSelectedCell, Event event) {
475                                         ViewerCell cell = internalFindSelectedCell(viewer,
476                                                         currentSelectedCell, event);
477                                         if (cell != null) {
478                                                 TableColumn t = AnnotatedPropertyTab.this.viewer.getTable().getColumn(
479                                                                 cell.getColumnIndex());
480                                                 AnnotatedPropertyTab.this.viewer.getTable().showColumn(t);
481                                         }
482                                         return cell;
483                                 }
484                         };
485                         
486                         TableViewerFocusCellManager focusCellManager = new TableViewerFocusCellManager(
487                                         viewer, new FocusCellOwnerDrawHighlighter(viewer));
488                         try {
489                                 Field f = focusCellManager.getClass().getSuperclass()
490                                                 .getDeclaredField("navigationStrategy");
491                                 f.setAccessible(true);
492                                 f.set(focusCellManager, nStrategy);
493                         } catch (SecurityException e) {
494                                 e.printStackTrace();
495                         } catch (NoSuchFieldException e) {
496                                 e.printStackTrace();
497                         } catch (IllegalArgumentException e) {
498                                 e.printStackTrace();
499                         } catch (IllegalAccessException e) {
500                                 e.printStackTrace();
501                         }
502                         ColumnViewerEditorActivationStrategy actSupport = new ColumnViewerEditorActivationStrategy(
503                                         viewer) {
504                                 protected boolean isEditorActivationEvent(
505                                                 ColumnViewerEditorActivationEvent event) {
506                                         return event.eventType == ColumnViewerEditorActivationEvent.TRAVERSAL
507                                                         || event.eventType == ColumnViewerEditorActivationEvent.MOUSE_DOUBLE_CLICK_SELECTION
508                                                         || (event.eventType == ColumnViewerEditorActivationEvent.KEY_PRESSED && event.keyCode == SWT.CR)
509                                                         || event.eventType == ColumnViewerEditorActivationEvent.PROGRAMMATIC;
510                                 }
511                         };
512                         TableViewerEditor.create(viewer, focusCellManager, actSupport,
513                                         ColumnViewerEditor.TABBING_HORIZONTAL
514                                                         | ColumnViewerEditor.TABBING_MOVE_TO_ROW_NEIGHBOR
515                                                         | ColumnViewerEditor.TABBING_VERTICAL
516                                                         | ColumnViewerEditor.KEYBOARD_ACTIVATION);
517                         viewer.getColumnViewerEditor().addEditorActivationListener(
518                                         new ColumnViewerEditorActivationListener() {
519                                                 public void afterEditorActivated(
520                                                                 ColumnViewerEditorActivationEvent event) {
521                                                 }
522
523                                                 public void afterEditorDeactivated(
524                                                                 ColumnViewerEditorDeactivationEvent event) {
525                                                 }
526
527                                                 public void beforeEditorActivated(
528                                                                 ColumnViewerEditorActivationEvent event) {
529                                                         ViewerCell cell = (ViewerCell) event.getSource();
530                                                         viewer.getTable().showColumn(
531                                                                         viewer.getTable().getColumn(cell.getColumnIndex()));
532                                                 }
533
534                                                 public void beforeEditorDeactivated(
535                                                                 ColumnViewerEditorDeactivationEvent event) {
536                                                 }
537                                         });
538                 }
539                 
540                 
541                 
542                 
543                 private IPropertyItem selectedItem = null;
544                 private Set<IPropertyItem> delayedUpdate = new HashSet<IPropertyItem>();
545                 
546                 
547                 @Override
548                 public void setInput(ISessionContext context, ISelection selection,
549                                 boolean force) {
550                         Collection<IG3DNode> nodes = AdaptationUtils.adaptToCollection(selection, IG3DNode.class);
551                         if (nodes.size() != 1) {
552                                 if (node != null) {
553                                         node.removeListener(this);
554                                         node = null;
555                                 }
556                                 return;
557                         }
558                         IG3DNode n = nodes.iterator().next();
559                         if (node != null) {
560                                 if (!node.equals(n)) {
561                                         node.removeListener(this);
562                                         setInput(n);
563                                 }
564                         } else {
565                                 setInput(n);
566                         }
567                 }
568                 
569                 
570                 
571                 private void setInput(IG3DNode node) {
572                         this.node = node;
573                         this.node.addListener(this);
574                         // resolve nodemap
575                         IG3DNode n = node;
576                         while (true) {
577                                 if (n == null) {
578                                         nodeMap = null;
579                                         break;
580                                 }
581                                 if (n instanceof NodeMapProvider<?,?>) {
582                                         nodeMap = ((NodeMapProvider<?,?>) n).getNodeMap();
583                                         if (nodeMap != null)
584                                                 break;
585                                 }
586                                 n = (IG3DNode)n.getParent();
587                         }
588                         boolean readOnly =  (node instanceof IStructuralNode && ((IStructuralNode)node).isPartOfInstantiatedModel() && !((IStructuralNode)node).isInstantiatedModelRoot());
589                         // create label providers
590                         PropertyValueLabelProvider2 p = new PropertyValueLabelProvider2(this);
591                         int index = 0;
592                         for (TableViewerColumn c : valueColumns) {
593                                 c.setLabelProvider(p);
594                                 if (!readOnly) {
595                                         PropertyEditingSupport support = new PropertyEditingSupport(this, viewer, index++, nodeMap);
596                                         c.setEditingSupport(support);
597                                 }
598                         }
599                         resolvedItems.clear();
600                         manipulators.clear();
601                         for (IPropertyItem item : contibutedItems) {
602                                 if (item instanceof PropertyItem) {
603                                         resolvedItems.add((PropertyItem)item);
604                                         manipulators.put((PropertyItem)item, createManipulator((PropertyItem)item, node));
605                                 }
606                                 else {
607                                         CompoundPropertyItem compound = (CompoundPropertyItem)item;
608                                         Map<PropertyItem, PropertyManipulator> manipulators = createManipulators(compound, node);
609                                         for (PropertyItem i : manipulators.keySet()) {
610                                                 resolvedItems.add(i);
611                                                 this.manipulators.put(i, manipulators.get(i));
612                                         }
613                                 }
614                         }
615                         
616                         viewer.getTable().setEnabled(!readOnly);
617                         viewer.setInput(resolvedItems);
618                 }
619                 
620                 @Override
621                 public void requestFocus() {
622                         viewer.getTable().forceFocus();
623                 }
624                 
625                 @Override
626                 public void dispose() {
627                         if (node != null) {
628                                 node.removeListener(this);
629                                 node = null;
630                         }
631                         
632                 }
633                 
634                 @Override
635                 public Control getControl() {
636                         return viewer.getTable();
637                 }
638                 
639                 @Override
640                 public ISelectionProvider getSelectionProvider() {
641                         return null;
642                 }
643                 
644                 @Override
645                 public boolean isDisposed() {
646                         return viewer.getTable().isDisposed();
647                 }
648                 
649                 @Override
650                 public <T extends INode> void nodeAdded(ParentNode<T> node,
651                                 INode child, String rel) {
652                         
653                 }
654                 
655                 @Override
656                 public <T extends INode> void nodeRemoved(ParentNode<T> node,
657                                 INode child, String rel) {
658                         
659                 }
660                 
661                 @Override
662                 public void propertyChanged(INode node, final String id) {
663 //                      for (final PropertyItem item : items) {
664 //                              if (item.id.equals(id)) {
665 //                                      Display.getDefault().asyncExec(new Runnable() {
666 //                                              
667 //                                              @Override
668 //                                              public void run() {
669 //                                                      viewer.update(item, null);
670 //                                                      
671 //                                              }
672 //                                      });
673 //                              }
674 //                      }
675                         if (Thread.currentThread() == Display.getDefault().getThread()) {
676                                 if (viewer.getTable().isDisposed())
677                                         return;
678                                 if (DEBUG)System.out.println("Viewer refresh " + id);
679                                 for (PropertyItem item : resolvedItems)
680                                         if (!item.equals(selectedItem))
681                                                 viewer.refresh(item);
682                                 if (selectedItem != null)
683                                         delayedUpdate.add(selectedItem);
684                         } else if (!editing){
685                                 // running delayed refresh when a cell editor is active would cancel cell editing.
686                                 Display.getDefault().asyncExec(new Runnable() {
687                                         @Override
688                                         public void run() {
689                                                 if (viewer.getTable().isDisposed()) {
690                                                         if (AnnotatedPropertyTab.this.node != null)
691                                                                 AnnotatedPropertyTab.this.node.removeListener(AnnotatedPropertyTab.this);
692                                                         return;
693                                                 }
694                                                 if (DEBUG) System.out.println("Viewer threaded refresh " + id);
695                                                 for (PropertyItem item : resolvedItems)
696                                                         if (!item.equals(selectedItem))
697                                                                 viewer.refresh(item);
698                                                 if (selectedItem != null)
699                                                         delayedUpdate.add(selectedItem);
700                                                 
701                                         }
702                                 });
703                         } else {
704                                 for (PropertyItem item : resolvedItems) {
705                                         delayedUpdate.add(item);
706                                 }
707                         }
708                         
709                 }
710                 
711
712                 
713                 @Override
714                 public void updatePartName(Consumer<String> updateCallback) {
715                         if (node != null)
716                                 updateCallback.accept(node.toString()); 
717                         
718                 }
719                 
720                 public PropertyManipulator getManipulator(PropertyItem item) {
721                         return manipulators.get(item);
722                 }
723                 
724                 private boolean editing = false;
725                 
726                 public void setEditing(boolean editing) {
727                         this.editing = editing;
728                 }
729         }
730         
731         
732         
733         private static class PropertyEditingSupport extends EditingSupport {
734                 AnnotatedPropertyTab tab;
735                 int index;
736                 NodeMap<?,?> nodeMap;
737                 TableViewer viewer;
738                 CellEditor editor;
739
740                 public PropertyEditingSupport(AnnotatedPropertyTab tab, TableViewer viewer, int index, NodeMap<?,?> nodeMap) {
741                         super(viewer);
742                         this.tab = tab;
743                         this.index = index;
744                         this.viewer = viewer;
745                         this.nodeMap = nodeMap;
746                 }
747                 
748                 @Override
749                 protected boolean canEdit(Object element) {
750                         PropertyItem item = (PropertyItem)element;
751                         if (tab.getManipulator(item).getValueCount() <= index)
752                                 return false;
753                         if (item.setter == null)
754                                 return false;
755                         if (getValue(element) == null)
756                                 return false;
757                         return true;
758                 }
759                 
760                 @Override
761                 protected CellEditor getCellEditor(Object element) {
762                         
763                         if (tab.getManipulator((PropertyItem)element).getValueCount() <= index)
764                                 return null;
765                         if (editor == null)
766                                 editor = new TextCellEditor(viewer.getTable(),SWT.NONE) {
767                                 @Override
768                                 public void activate() {
769                                         tab.setEditing(true);
770                                 }
771                                 
772                                 @Override
773                                 public void deactivate() {
774                                         super.deactivate();
775                                         tab.setEditing(false);
776                                 }
777                         };
778                         if (DEBUG)System.err.println("CELL EDITOR: " + element);
779                         return editor;
780                 }
781                 
782                 @Override
783                 protected Object getValue(Object element) {
784                         PropertyItem item = (PropertyItem)element;
785                         PropertyManipulator manipulator = tab.getManipulator(item);//createManipulator(item, obj);
786                         if (manipulator.getValueCount() <= index)
787                                 return null;
788                         Object value = manipulator.getValue(index);
789                         return value;
790                 }
791                 
792                 @Override
793                 protected void setValue(Object element, Object value) {
794                         
795                         PropertyItem item = (PropertyItem)element;
796                         PropertyManipulator manipulator = tab.getManipulator(item);//createManipulator(item, obj);
797                         if (manipulator.getValueCount() <= index)
798                                 throw new IllegalAccessError("Editing value in index " + index + " is not allowed.");
799                         if (DEBUG)System.err.println("CELL SET VALUE: " + element + " " + value);
800                         manipulator.setValue((String)value,index);
801                         viewer.refresh(item);
802                         nodeMap.commit("Set " + item.id + " value to " + value);
803                         
804                 }
805                 
806                 
807
808         }
809         
810         private static class PropertyItemNameProvider extends CellLabelProvider {
811
812                 
813                 @Override
814                 public void update(ViewerCell cell) {
815                         PropertyItem item = (PropertyItem)cell.getElement();
816
817                         if (item.name.length() > 0)
818                                 cell.setText(item.name);
819                         else
820                                 cell.setText(item.id);
821                         
822                         
823                 }
824         }
825         
826         private static class PropertyValueLabelProvider2 extends CellLabelProvider {
827                 AnnotatedPropertyTab tab;
828                 //private Object object;
829                 
830                 public PropertyValueLabelProvider2(AnnotatedPropertyTab tab) {
831                         this.tab = tab;
832                 }
833                 
834                 @Override
835                 public void update(ViewerCell cell) {
836                         PropertyItem item = (PropertyItem)cell.getElement();
837                         int index = cell.getColumnIndex() -1;
838                         PropertyManipulator manipulator = tab.getManipulator(item);//createManipulator(item, object);
839                         if (manipulator.getValueCount() <= index)
840                                 return;
841                         cell.setText(manipulator.getValue(index));
842                 }
843         }
844         
845         private static class PropertyItemContentsProvider implements IStructuredContentProvider {
846                 @SuppressWarnings("unchecked")
847                 @Override
848                 public Object[] getElements(Object inputElement) {
849                         List<PropertyItem> items = (List<PropertyItem>)inputElement;
850                         return items.toArray();
851                 }
852                 
853                 @Override
854                 public void dispose() {
855                         
856                 }
857                 
858                 @Override
859                 public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
860                         
861                 }
862         }
863         
864         
865         
866         private static ViewerCell getNeighbor(ViewerCell currentCell,
867                         int directionMask, boolean sameLevel) {
868                 ViewerRow row;
869                 if ((directionMask & ViewerCell.ABOVE) == ViewerCell.ABOVE) {
870                         row = currentCell.getViewerRow().getNeighbor(ViewerRow.ABOVE,
871                                         sameLevel);
872                 } else if ((directionMask & ViewerCell.BELOW) == ViewerCell.BELOW) {
873                         row = currentCell.getViewerRow().getNeighbor(ViewerRow.BELOW,
874                                         sameLevel);
875                 } else {
876                         row = currentCell.getViewerRow();
877                 }
878                 if (row != null) {
879                         int columnIndex;
880                         columnIndex = getVisualIndex(row, currentCell.getColumnIndex());
881                         int modifier = 0;
882                         if ((directionMask & ViewerCell.LEFT) == ViewerCell.LEFT) {
883                                 modifier = -1;
884                         } else if ((directionMask & ViewerCell.RIGHT) == ViewerCell.RIGHT) {
885                                 modifier = 1;
886                         }
887                         columnIndex += modifier;
888                         if (columnIndex >= 0 && columnIndex < row.getColumnCount()) {
889                                 ViewerCell cell = getCellAtVisualIndex(row, columnIndex);
890                                 if (cell != null) {
891                                         while (cell != null
892                                                         && columnIndex < row.getColumnCount() - 1
893                                                         && columnIndex > 0) {
894                                                 if (isVisible(cell)) {
895                                                         break;
896                                                 }
897                                                 columnIndex += modifier;
898                                                 cell = getCellAtVisualIndex(row, columnIndex);
899                                                 if (cell == null) {
900                                                         break;
901                                                 }
902                                         }
903                                 }
904                                 return cell;
905                         }
906                 }
907                 return null;
908         }
909         
910         
911         
912         public static class TableViewerEditor extends ColumnViewerEditor {
913                 /**
914                  * This viewer's table editor.
915                  */
916                 private TableEditor tableEditor;
917                 private TableViewerFocusCellManager focusCellManager;
918                 private int feature;
919
920                 /**
921                  * @param viewer
922                  *            the viewer the editor is attached to
923                  * @param focusCellManager
924                  *            the cell focus manager if one used or <code>null</code>
925                  * @param editorActivationStrategy
926                  *            the strategy used to decide about the editor activation
927                  * @param feature
928                  *            the feature mask
929                  */
930                 TableViewerEditor(TableViewer viewer,
931                                 TableViewerFocusCellManager focusCellManager,
932                                 ColumnViewerEditorActivationStrategy editorActivationStrategy,
933                                 int feature) {
934                         super(viewer, editorActivationStrategy, feature);
935                         this.feature = feature;
936                         tableEditor = new TableEditor(viewer.getTable());
937                         this.focusCellManager = focusCellManager;
938                 }
939
940                 /**
941                  * Create a customized editor with focusable cells
942                  * 
943                  * @param viewer
944                  *            the viewer the editor is created for
945                  * @param focusCellManager
946                  *            the cell focus manager if one needed else
947                  *            <code>null</code>
948                  * @param editorActivationStrategy
949                  *            activation strategy to control if an editor activated
950                  * @param feature
951                  *            bit mask controlling the editor
952                  *            <ul>
953                  *            <li>{@link ColumnViewerEditor#DEFAULT}</li>
954                  *            <li>{@link ColumnViewerEditor#TABBING_CYCLE_IN_ROW}</li>
955                  *            <li>{@link ColumnViewerEditor#TABBING_HORIZONTAL}</li>
956                  *            <li>
957                  *            {@link ColumnViewerEditor#TABBING_MOVE_TO_ROW_NEIGHBOR}</li>
958                  *            <li>{@link ColumnViewerEditor#TABBING_VERTICAL}</li>
959                  *            </ul>
960                  * @see #create(TableViewer, ColumnViewerEditorActivationStrategy, int)
961                  */
962                 public static void create(TableViewer viewer,
963                                 TableViewerFocusCellManager focusCellManager,
964                                 ColumnViewerEditorActivationStrategy editorActivationStrategy,
965                                 int feature) {
966                         TableViewerEditor editor = new TableViewerEditor(viewer,
967                                         focusCellManager, editorActivationStrategy, feature);
968                         viewer.setColumnViewerEditor(editor);
969                         if (focusCellManager != null) {
970                                 try {
971                                         Method m = focusCellManager.getClass().getSuperclass()
972                                                         .getDeclaredMethod("init", null);
973                                         m.setAccessible(true);
974                                         m.invoke(focusCellManager, null);
975                                 } catch (SecurityException e) {
976                                         e.printStackTrace();
977                                 } catch (IllegalArgumentException e) {
978                                         e.printStackTrace();
979                                 } catch (IllegalAccessException e) {
980                                         e.printStackTrace();
981                                 } catch (NoSuchMethodException e) {
982                                         e.printStackTrace();
983                                 } catch (InvocationTargetException e) {
984                                         e.printStackTrace();
985                                 }
986                                 // focusCellManager.init();
987                         }
988                 }
989
990                 /**
991                  * Create a customized editor whose activation process is customized
992                  * 
993                  * @param viewer
994                  *            the viewer the editor is created for
995                  * @param editorActivationStrategy
996                  *            activation strategy to control if an editor activated
997                  * @param feature
998                  *            bit mask controlling the editor
999                  *            <ul>
1000                  *            <li>{@link ColumnViewerEditor#DEFAULT}</li>
1001                  *            <li>{@link ColumnViewerEditor#TABBING_CYCLE_IN_ROW}</li>
1002                  *            <li>{@link ColumnViewerEditor#TABBING_HORIZONTAL}</li>
1003                  *            <li>
1004                  *            {@link ColumnViewerEditor#TABBING_MOVE_TO_ROW_NEIGHBOR}</li>
1005                  *            <li>{@link ColumnViewerEditor#TABBING_VERTICAL}</li>
1006                  *            </ul>
1007                  */
1008                 public static void create(TableViewer viewer,
1009                                 ColumnViewerEditorActivationStrategy editorActivationStrategy,
1010                                 int feature) {
1011                         create(viewer, null, editorActivationStrategy, feature);
1012                 }
1013
1014                 protected void setEditor(Control w, Item item, int columnNumber) {
1015                         tableEditor.setEditor(w, (TableItem) item, columnNumber);
1016                 }
1017
1018                 protected void setLayoutData(LayoutData layoutData) {
1019                         tableEditor.grabHorizontal = layoutData.grabHorizontal;
1020                         tableEditor.horizontalAlignment = layoutData.horizontalAlignment;
1021                         tableEditor.minimumWidth = layoutData.minimumWidth;
1022                 }
1023
1024                 public ViewerCell getFocusCell() {
1025                         if (focusCellManager != null) {
1026                                 return focusCellManager.getFocusCell();
1027                         }
1028                         return super.getFocusCell();
1029                 }
1030
1031                 protected void updateFocusCell(ViewerCell focusCell,
1032                                 ColumnViewerEditorActivationEvent event) {
1033                         // Update the focus cell when we activated the editor with these 2
1034                         // events
1035                         if (event.eventType == ColumnViewerEditorActivationEvent.PROGRAMMATIC
1036                                         || event.eventType == ColumnViewerEditorActivationEvent.TRAVERSAL) {
1037                                 if (focusCellManager != null) {
1038                                         try {
1039                                                 if (DEBUG)System.err.println("FOCUS CELL: " + focusCell);
1040                                                 
1041                                                 Method m = AbstractTableViewer.class.getDeclaredMethod(
1042                                                                 "getSelectionFromWidget", null);
1043                                                 m.setAccessible(true);
1044                                                 List l = (List) m.invoke(getViewer(), null);
1045                                                 if (focusCellManager != null) {
1046                                                         m = focusCellManager
1047                                                                         .getClass()
1048                                                                         .getSuperclass()
1049                                                                         .getDeclaredMethod("setFocusCell",
1050                                                                                         new Class[] { ViewerCell.class });
1051                                                         m.setAccessible(true);
1052                                                         m.invoke(focusCellManager,
1053                                                                         new Object[] { focusCell });
1054                                                 }
1055                                                 if (!l.contains(focusCell.getElement())) {
1056                                                         getViewer().setSelection(
1057                                                                         new StructuredSelection(focusCell
1058                                                                                         .getElement()));
1059                                                 }
1060                                         } catch (SecurityException e) {
1061                                                 e.printStackTrace();
1062                                         } catch (IllegalArgumentException e) {
1063                                                 e.printStackTrace();
1064                                         } catch (IllegalAccessException e) {
1065                                                 e.printStackTrace();
1066                                         } catch (NoSuchMethodException e) {
1067                                                 e.printStackTrace();
1068                                         } catch (InvocationTargetException e) {
1069                                                 e.printStackTrace();
1070                                         }
1071                                 }
1072                         }
1073                 }
1074
1075                 protected void processTraverseEvent(int columnIndex, ViewerRow row,
1076                                 TraverseEvent event) {
1077                         ViewerCell cell2edit = null;
1078                         if (event.detail == SWT.TRAVERSE_TAB_PREVIOUS) {
1079                                 event.doit = false;
1080                                 if ((event.stateMask & SWT.CTRL) == SWT.CTRL
1081                                                 && (feature & TABBING_VERTICAL) == TABBING_VERTICAL) {
1082                                         cell2edit = searchCellAboveBelow(row, getViewer(),
1083                                                         columnIndex, true);
1084                                 } else if ((feature & TABBING_HORIZONTAL) == TABBING_HORIZONTAL) {
1085                                         cell2edit = searchPreviousCell(row,
1086                                                         row.getCell(columnIndex), row.getCell(columnIndex),
1087                                                         getViewer());
1088                                 }
1089                         } else if (event.detail == SWT.TRAVERSE_TAB_NEXT) {
1090                                 event.doit = false;
1091                                 if ((event.stateMask & SWT.CTRL) == SWT.CTRL
1092                                                 && (feature & TABBING_VERTICAL) == TABBING_VERTICAL) {
1093                                         cell2edit = searchCellAboveBelow(row, getViewer(),
1094                                                         columnIndex, false);
1095                                 } else if ((feature & TABBING_HORIZONTAL) == TABBING_HORIZONTAL) {
1096                                         cell2edit = searchNextCell(row, row.getCell(columnIndex),
1097                                                         row.getCell(columnIndex), getViewer());
1098                                 }
1099                         }
1100                         if (DEBUG) System.err.println("NEXT CELL: " + cell2edit);
1101                         if (cell2edit != null) {
1102                                 getViewer().getControl().setRedraw(false);
1103                                 ColumnViewerEditorActivationEvent acEvent = new ColumnViewerEditorActivationEvent(
1104                                                 cell2edit, event);
1105                                 try {
1106                                         Method m = ColumnViewer.class
1107                                                         .getDeclaredMethod(
1108                                                                         "triggerEditorActivationEvent",
1109                                                                         new Class[] { ColumnViewerEditorActivationEvent.class });
1110                                         m.setAccessible(true);
1111                                         m.invoke(getViewer(), new Object[] { acEvent });
1112                                 } catch (SecurityException e) {
1113                                         e.printStackTrace();
1114                                 } catch (NoSuchMethodException e) {
1115                                         e.printStackTrace();
1116                                 } catch (IllegalArgumentException e) {
1117                                         e.printStackTrace();
1118                                 } catch (IllegalAccessException e) {
1119                                         e.printStackTrace();
1120                                 } catch (InvocationTargetException e) {
1121                                         e.printStackTrace();
1122                                 }
1123                                 getViewer().getControl().setRedraw(true);
1124                         }
1125                 }
1126
1127                 private ViewerCell searchCellAboveBelow(ViewerRow row,
1128                                 ColumnViewer viewer, int columnIndex, boolean above) {
1129                         ViewerCell rv = null;
1130                         ViewerRow newRow = null;
1131                         if (above) {
1132                                 newRow = row.getNeighbor(ViewerRow.ABOVE, false);
1133                         } else {
1134                                 newRow = row.getNeighbor(ViewerRow.BELOW, false);
1135                         }
1136                         try {
1137                                 if (newRow != null) {
1138                                         Method m = ColumnViewer.class.getDeclaredMethod(
1139                                                         "getViewerColumn", new Class[] { int.class });
1140                                         m.setAccessible(true);
1141                                         ViewerColumn column = (ViewerColumn) m.invoke(viewer,
1142                                                         new Object[] { new Integer(columnIndex) });
1143                                         m = ViewerColumn.class.getDeclaredMethod(
1144                                                         "getEditingSupport", null);
1145                                         m.setAccessible(true);
1146                                         EditingSupport es = (EditingSupport) m.invoke(column, null);
1147                                         if (column != null && es != null) {
1148                                                 m = EditingSupport.class.getDeclaredMethod("canEdit",
1149                                                                 new Class[] { Object.class });
1150                                                 m.setAccessible(true);
1151                                                 Boolean b = (Boolean) m.invoke(es,
1152                                                                 new Object[] { newRow.getItem().getData() });
1153                                                 if (b.booleanValue()) {
1154                                                         rv = newRow.getCell(columnIndex);
1155                                                 }
1156                                         } else {
1157                                                 rv = searchCellAboveBelow(newRow, viewer, columnIndex,
1158                                                                 above);
1159                                         }
1160                                 }
1161                         } catch (Exception e) {
1162                                 e.printStackTrace();
1163                         }
1164                         return rv;
1165                 }
1166
1167                 private ViewerCell searchPreviousCell(ViewerRow row,
1168                                 ViewerCell currentCell, ViewerCell originalCell,
1169                                 ColumnViewer viewer) {
1170                         ViewerCell rv = null;
1171                         ViewerCell previousCell;
1172                         if (currentCell != null) {
1173                                 previousCell = getNeighbor(currentCell, ViewerCell.LEFT, true);
1174                         } else {
1175                                 if (row.getColumnCount() != 0) {
1176                                         previousCell = row.getCell(getCreationIndex(row,
1177                                                         row.getColumnCount() - 1));
1178                                 } else {
1179                                         previousCell = row.getCell(0);
1180                                 }
1181                         }
1182                         // No endless loop
1183                         if (originalCell.equals(previousCell)) {
1184                                 return null;
1185                         }
1186                         if (previousCell != null) {
1187                                 if (isCellEditable(viewer, previousCell)) {
1188                                         rv = previousCell;
1189                                 } else {
1190                                         rv = searchPreviousCell(row, previousCell, originalCell,
1191                                                         viewer);
1192                                 }
1193                         } else {
1194                                 if ((feature & TABBING_CYCLE_IN_ROW) == TABBING_CYCLE_IN_ROW) {
1195                                         rv = searchPreviousCell(row, null, originalCell, viewer);
1196                                 } else if ((feature & TABBING_MOVE_TO_ROW_NEIGHBOR) == TABBING_MOVE_TO_ROW_NEIGHBOR) {
1197                                         ViewerRow rowAbove = row
1198                                                         .getNeighbor(ViewerRow.ABOVE, false);
1199                                         if (rowAbove != null) {
1200                                                 rv = searchPreviousCell(rowAbove, null, originalCell,
1201                                                                 viewer);
1202                                         }
1203                                 }
1204                         }
1205                         return rv;
1206                 }
1207
1208                 private ViewerCell searchNextCell(ViewerRow row,
1209                                 ViewerCell currentCell, ViewerCell originalCell,
1210                                 ColumnViewer viewer) {
1211                         ViewerCell rv = null;
1212                         ViewerCell nextCell;
1213                         if (currentCell != null) {
1214                                 nextCell = getNeighbor(currentCell, ViewerCell.RIGHT, true);
1215                         } else {
1216                                 nextCell = row.getCell(getCreationIndex(row, 0));
1217                         }
1218                         // No endless loop
1219                         if (originalCell.equals(nextCell)) {
1220                                 return null;
1221                         }
1222                         if (nextCell != null) {
1223                                 if (isCellEditable(viewer, nextCell)) {
1224                                         rv = nextCell;
1225                                 } else {
1226                                         rv = searchNextCell(row, nextCell, originalCell, viewer);
1227                                 }
1228                         } else {
1229                                 if ((feature & TABBING_CYCLE_IN_ROW) == TABBING_CYCLE_IN_ROW) {
1230                                         rv = searchNextCell(row, null, originalCell, viewer);
1231                                 } else if ((feature & TABBING_MOVE_TO_ROW_NEIGHBOR) == TABBING_MOVE_TO_ROW_NEIGHBOR) {
1232                                         ViewerRow rowBelow = row
1233                                                         .getNeighbor(ViewerRow.BELOW, false);
1234                                         if (rowBelow != null) {
1235                                                 rv = searchNextCell(rowBelow, null, originalCell,
1236                                                                 viewer);
1237                                         }
1238                                 }
1239                         }
1240                         return rv;
1241                 }
1242
1243                 private boolean isCellEditable(ColumnViewer viewer, ViewerCell cell) {
1244                         try {
1245                                 Method m = ColumnViewer.class.getDeclaredMethod(
1246                                                 "getViewerColumn", new Class[] { int.class });
1247                                 m.setAccessible(true);
1248                                 ViewerColumn column = (ViewerColumn) m.invoke(viewer,
1249                                                 new Object[] { new Integer(cell.getColumnIndex()) });
1250                                 m = ViewerColumn.class.getDeclaredMethod("getEditingSupport",
1251                                                 null);
1252                                 m.setAccessible(true);
1253                                 EditingSupport es = (EditingSupport) m.invoke(column, null);
1254                                 if (column != null && es != null) {
1255                                         m = EditingSupport.class.getDeclaredMethod("canEdit",
1256                                                         new Class[] { Object.class });
1257                                         m.setAccessible(true);
1258                                         // return true;
1259                                         Boolean b = (Boolean) m.invoke(es,
1260                                                         new Object[] { cell.getElement() });
1261                                         return b.booleanValue();
1262                                 }
1263                         } catch (Exception e) {
1264                                 e.printStackTrace();
1265                         }
1266                         return false;
1267                 }
1268         }
1269         
1270         // Reimplementation of ViewerCell-Methods
1271         private static int getVisualIndex(ViewerRow row, int creationIndex) {
1272                 TableItem item = (TableItem) row.getItem();
1273                 int[] order = item.getParent().getColumnOrder();
1274                 for (int i = 0; i < order.length; i++) {
1275                         if (order[i] == creationIndex) {
1276                                 return i;
1277                         }
1278                 }
1279                 return creationIndex;
1280         }
1281         
1282         private static int getCreationIndex(ViewerRow row, int visualIndex) {
1283                 TableItem item = (TableItem) row.getItem();
1284                 if (item != null && !item.isDisposed() /*
1285                                                                                                  * && hasColumns() &&
1286                                                                                                  * isValidOrderIndex
1287                                                                                                  * (visualIndex)
1288                                                                                                  */) {
1289                         return item.getParent().getColumnOrder()[visualIndex];
1290                 }
1291                 return visualIndex;
1292         }
1293         
1294         private static ViewerCell getCellAtVisualIndex(ViewerRow row,
1295                         int visualIndex) {
1296                 return getCell(row, getCreationIndex(row, visualIndex));
1297         }
1298
1299         private static boolean isVisible(ViewerCell cell) {
1300                 return getWidth(cell) > 0;
1301         }
1302
1303         private static int getWidth(ViewerCell cell) {
1304                 TableItem item = (TableItem) cell.getViewerRow().getItem();
1305                 return item.getParent().getColumn(cell.getColumnIndex()).getWidth();
1306         }
1307
1308         private static ViewerCell getCell(ViewerRow row, int index) {
1309                 return row.getCell(index);
1310         }
1311         
1312         
1313 }