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