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