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