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