X-Git-Url: https://gerrit.simantics.org/r/gitweb?a=blobdiff_plain;f=org.simantics.g3d%2Fsrc%2Forg%2Fsimantics%2Fg3d%2Fproperty%2FAnnotatedPropertyTabContributorFactory.java;h=7e3f85333bb88022ce5038e43670bdf0ab792346;hb=ebfe6b0245b5cf9231cecedf0aaacd891eb5d344;hp=c0ea36e9005351f57075256e79aa664ace4281e5;hpb=289aaab900078ef56efc8779e4b15830e472149e;p=simantics%2F3d.git diff --git a/org.simantics.g3d/src/org/simantics/g3d/property/AnnotatedPropertyTabContributorFactory.java b/org.simantics.g3d/src/org/simantics/g3d/property/AnnotatedPropertyTabContributorFactory.java index c0ea36e9..7e3f8533 100644 --- a/org.simantics.g3d/src/org/simantics/g3d/property/AnnotatedPropertyTabContributorFactory.java +++ b/org.simantics.g3d/src/org/simantics/g3d/property/AnnotatedPropertyTabContributorFactory.java @@ -1,1308 +1,1325 @@ -/******************************************************************************* - * Copyright (c) 2012, 2013 Association for Decentralized Information Management in - * Industry THTH ry. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * VTT Technical Research Centre of Finland - initial API and implementation - *******************************************************************************/ -package org.simantics.g3d.property; - -import java.lang.annotation.Annotation; -import java.lang.reflect.Field; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.HashMap; -import java.util.HashSet; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; -import java.util.Set; - -import org.eclipse.jface.layout.GridDataFactory; -import org.eclipse.jface.viewers.AbstractTableViewer; -import org.eclipse.jface.viewers.CellEditor; -import org.eclipse.jface.viewers.CellEditor.LayoutData; -import org.eclipse.jface.viewers.CellLabelProvider; -import org.eclipse.jface.viewers.CellNavigationStrategy; -import org.eclipse.jface.viewers.ColumnViewer; -import org.eclipse.jface.viewers.ColumnViewerEditor; -import org.eclipse.jface.viewers.ColumnViewerEditorActivationEvent; -import org.eclipse.jface.viewers.ColumnViewerEditorActivationListener; -import org.eclipse.jface.viewers.ColumnViewerEditorActivationStrategy; -import org.eclipse.jface.viewers.ColumnViewerEditorDeactivationEvent; -import org.eclipse.jface.viewers.EditingSupport; -import org.eclipse.jface.viewers.FocusCellOwnerDrawHighlighter; -import org.eclipse.jface.viewers.ISelection; -import org.eclipse.jface.viewers.ISelectionChangedListener; -import org.eclipse.jface.viewers.ISelectionProvider; -import org.eclipse.jface.viewers.IStructuredContentProvider; -import org.eclipse.jface.viewers.SelectionChangedEvent; -import org.eclipse.jface.viewers.StructuredSelection; -import org.eclipse.jface.viewers.TableViewer; -import org.eclipse.jface.viewers.TableViewerColumn; -import org.eclipse.jface.viewers.TableViewerFocusCellManager; -import org.eclipse.jface.viewers.TextCellEditor; -import org.eclipse.jface.viewers.Viewer; -import org.eclipse.jface.viewers.ViewerCell; -import org.eclipse.jface.viewers.ViewerColumn; -import org.eclipse.jface.viewers.ViewerRow; -import org.eclipse.swt.SWT; -import org.eclipse.swt.custom.TableEditor; -import org.eclipse.swt.events.TraverseEvent; -import org.eclipse.swt.widgets.Composite; -import org.eclipse.swt.widgets.Control; -import org.eclipse.swt.widgets.Display; -import org.eclipse.swt.widgets.Event; -import org.eclipse.swt.widgets.Item; -import org.eclipse.swt.widgets.TableColumn; -import org.eclipse.swt.widgets.TableItem; -import org.eclipse.ui.IWorkbenchSite; -import org.simantics.db.management.ISessionContext; -import org.simantics.g3d.property.annotations.CompoundGetPropertyValue; -import org.simantics.g3d.property.annotations.CompoundSetPropertyValue; -import org.simantics.g3d.property.annotations.GetPropertyValue; -import org.simantics.g3d.property.annotations.PropertyTabBlacklist; -import org.simantics.g3d.property.annotations.SetPropertyValue; -import org.simantics.g3d.scenegraph.IG3DNode; -import org.simantics.g3d.scenegraph.NodeMap; -import org.simantics.g3d.scenegraph.NodeMapProvider; -import org.simantics.g3d.scenegraph.base.INode; -import org.simantics.g3d.scenegraph.base.NodeListener; -import org.simantics.g3d.scenegraph.base.ParentNode; -import org.simantics.g3d.scenegraph.structural.IStructuralNode; -import org.simantics.g3d.tools.AdaptationUtils; -import org.simantics.selectionview.IPropertyTab; -import org.simantics.selectionview.IPropertyTab2; -import org.simantics.utils.datastructures.Callback; -import org.simantics.utils.datastructures.MapList; - -public class AnnotatedPropertyTabContributorFactory implements PropertyTabContributorFactory { - - private static final boolean DEBUG = false; - - @SuppressWarnings("unchecked") - @Override - public List getContributors(Object input) { - Map items = new LinkedHashMap(); - List blacklist = new ArrayList(); - try { - collectItems(input.getClass(), items); - collectBlacklist(input.getClass(), blacklist); - } catch (InstantiationException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } catch (IllegalAccessException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - - if (items.size() == 0) - return Collections.EMPTY_LIST; - - MapList tabMap = new MapList(); - List tabs = new ArrayList(); - for (String id : items.keySet()) { - IPropertyItem item = items.get(id); - tabMap.add(item.getTabId(), item); - if (!tabs.contains(item.getTabId())) { - tabs.add(item.getTabId()); - //System.out.println(item.tabId + " " + item.name + " " + item.id); - } - } - for (String s : blacklist) { - tabs.remove(s); - } - - List contributors = new ArrayList(tabs.size()); - for (String tabId : tabs) { - contributors.add(new AnnotatedPropertyTabContributor(tabId, tabMap.getValues(tabId))); - } - - return contributors; - } - - - private static void collectItems(Class clazz, Map items) throws InstantiationException, IllegalAccessException { - Class superclass = clazz.getSuperclass(); - if(superclass != null) - collectItems(superclass, items); - - for (Method m : clazz.getDeclaredMethods()) { - m.setAccessible(true); - for (Annotation annotation : m.getAnnotations()) { - if (annotation.annotationType().equals(GetPropertyValue.class)) { - GetPropertyValue get = (GetPropertyValue)annotation; - PropertyItem item = (PropertyItem)items.get(get.value()); - if (item == null) { - item = new PropertyItem(get.value()); - items.put(item.id, item); - } - - item.getter = m; - item.manipulatorClass = get.manipulator().newInstance().get(m,null); - - item.tabId = get.tabId(); - - item.name = get.name(); - - - } else if (annotation.annotationType().equals(SetPropertyValue.class)) { - SetPropertyValue set = (SetPropertyValue)annotation; - PropertyItem item = (PropertyItem)items.get(set.value()); - if (item == null) { - item = new PropertyItem(set.value()); - items.put(item.id, item); - } - - item.setter = m; - } else if (annotation.annotationType().equals(CompoundGetPropertyValue.class)) { - CompoundGetPropertyValue get = (CompoundGetPropertyValue)annotation; - CompoundPropertyItem item = (CompoundPropertyItem)items.get(get.value()); - if (item == null) { - item = new CompoundPropertyItem(get.value()); - items.put(item.id, item); - } - - item.getter = m; - item.manipulatorFactory = get.manipulator().newInstance(); - - item.tabId = get.tabId(); - - item.name = get.name(); - } else if (annotation.annotationType().equals(CompoundSetPropertyValue.class)) { - CompoundSetPropertyValue set = (CompoundSetPropertyValue)annotation; - CompoundPropertyItem item = (CompoundPropertyItem)items.get(set.value()); - if (item == null) { - item = new CompoundPropertyItem(set.value()); - items.put(item.id, item); - } - - item.setter = m; - } - } - } - - - } - - private static void collectBlacklist(Class clazz, List blacklist) throws InstantiationException, IllegalAccessException { - Class superclass = clazz.getSuperclass(); - if(superclass != null) - collectBlacklist(superclass, blacklist); - - PropertyTabBlacklist ann = clazz.getAnnotation(PropertyTabBlacklist.class); - if (ann == null) - return; - String s = ann.value(); - if (s == null) - return; - if (s.length() == 0) - return; - for (String item : s.split(";")) { - blacklist.add(item); - } - - - } - - private static Map createManipulators(CompoundPropertyItem item, Object obj) { - try { - - Map map = (Map)item.getter.invoke(obj); - Map result = new HashMap(); - for (String key : map.keySet()) { - MethodWithMapValueProvider provider = new MethodWithMapValueProvider(item.getter, item.setter, key); - Class clazz = item.manipulatorFactory.get(null,map.get(key)); - PropertyManipulator manipulator = clazz.getConstructor(ValueProvider.class,Object.class).newInstance(provider,obj); - PropertyItem i = new PropertyItem(item.id+"."+key); - i.getter = item.getter; - i.setter = item.setter; - i.name = key; - i.tabId = item.tabId; - result.put(i,manipulator); - } - return result; - } catch (Exception e) { - e.printStackTrace(); - return Collections.EMPTY_MAP; - } - - } - - private static PropertyManipulator createManipulator(PropertyItem item, Object obj) { - try { - MethodValueProvider provider = new MethodValueProvider(item.getter, item.setter); - PropertyManipulator manipulator = item.manipulatorClass.getConstructor(ValueProvider.class,Object.class).newInstance(provider,obj); - return manipulator; - } catch (Exception e) { - e.printStackTrace(); - return null; - } - } - - private static interface IPropertyItem { - public String getTabId(); - } - - private static class PropertyItem implements IPropertyItem{ - private String id; - private String name; - private String tabId; - private Method getter; - private Method setter; - private Class manipulatorClass; - - - public PropertyItem(String id) { - if (id == null) - throw new NullPointerException(); - this.id = id; - } - - @Override - public int hashCode() { - return id.hashCode(); - } - - @Override - public String getTabId() { - return tabId; - } - } - - private static class CompoundPropertyItem implements IPropertyItem{ - private String id; - private String name; - private String tabId; - private Method getter; - private Method setter; - private PropertyManipulatorFactory manipulatorFactory; - - - public CompoundPropertyItem(String id) { - if (id == null) - throw new NullPointerException(); - this.id = id; - } - - @Override - public int hashCode() { - return id.hashCode(); - } - - @Override - public String getTabId() { - return tabId; - } - } - - private static class AnnotatedPropertyTabContributor implements PropertyTabContributor { - private String id; - List items; - - public AnnotatedPropertyTabContributor(String id, List items) { - if (id == null) - throw new NullPointerException(); - this.id = id; - this.items = items; - } - - @Override - public IPropertyTab create(Composite parent, IWorkbenchSite site, - ISessionContext context, Object input) { - AnnotatedPropertyTab tab = new AnnotatedPropertyTab(id, items); - tab.createControl(parent, context); - return tab; - } - - @Override - public String getId() { - return id; - } - - } - - private static class AnnotatedPropertyTab implements IPropertyTab2, NodeListener { - //private String id; - List contibutedItems; - List resolvedItems = new ArrayList(); - private Map manipulators = new HashMap(); - - private TableViewer viewer; - - private IG3DNode node; - private NodeMap nodeMap; - - private List valueColumns = new ArrayList(); - - public AnnotatedPropertyTab(String id, List items) { - //this.id = id; - this.contibutedItems = items; - - - } - - @Override - public void createControl(Composite parent, ISessionContext context) { - //parent.setLayout(new FillLayout()); - viewer = new TableViewer(parent, SWT.FULL_SELECTION | SWT.SINGLE); - - GridDataFactory.fillDefaults().align(SWT.FILL, SWT.FILL).grab(true, true).applyTo(viewer.getTable()); - - //viewer.setLabelProvider(new AnnotatedTableLabelProvider(object)) - - viewer.setContentProvider(new PropertyItemContentsProvider()); - - TableViewerColumn name = new TableViewerColumn(viewer, SWT.LEFT); - //TableViewerColumn value = new TableViewerColumn(viewer, SWT.LEFT); - name.setLabelProvider(new PropertyItemNameProvider()); - //value.setLabelProvider(new PropertyValueLabelProvider(null)); - name.getColumn().setText("Property"); - //value.getColumn().setText("Value"); - name.getColumn().setWidth(200); - //value.getColumn().setWidth(200); - name.getViewer().addSelectionChangedListener(new ISelectionChangedListener() { - - @Override - public void selectionChanged(SelectionChangedEvent event) { - PropertyItem item = AdaptationUtils.adaptToSingle(event.getSelection(),PropertyItem.class); - if (item != null) { - PropertyManipulator manipulator = manipulators.get(item);//createManipulator(item, null); - for (int i = 0; i < valueColumns.size(); i++) { - TableViewerColumn c = valueColumns.get(i); - if (i < manipulator.getValueCount()) { - c.getColumn().setText(manipulator.getDescription(i)); - } else { - c.getColumn().setText(""); - } - } - } - - } - }); - - int valueCount = 0; - for (IPropertyItem item : contibutedItems) { - if (item instanceof PropertyItem) { - PropertyManipulator manipulator = createManipulator((PropertyItem)item, null); - if (manipulator == null) - continue; - if (valueCount < manipulator.getValueCount()) - valueCount = manipulator.getValueCount(); - } else if (item instanceof CompoundPropertyItem) { - if (valueCount < 1) - valueCount = 1; - } - } - for (int i = 0; i < valueCount; i++) { - TableViewerColumn value = new TableViewerColumn(viewer, SWT.LEFT); - //value.getColumn().setText("Value " + (i+1)); - value.getColumn().setText(""); - value.getColumn().setWidth(200); - valueColumns.add(value); - //value.setEditingSupport(new ) - } - viewer.getTable().setHeaderVisible(true); - viewer.getTable().setLinesVisible(true); - viewer.addSelectionChangedListener(new ISelectionChangedListener() { - - @Override - public void selectionChanged(SelectionChangedEvent event) { - PropertyItem item = AdaptationUtils.adaptToSingle(event.getSelection(), PropertyItem.class); - selectedItem = item; - if (!manipulators.get(selectedItem).getEditMode()) - manipulators.get(selectedItem).setEditMode(true); - - - for (IPropertyItem i : delayedUpdate) { - if (!i.equals(selectedItem)) { - manipulators.get(i).setEditMode(false); - viewer.update(i,null); - } - } - if (delayedUpdate.contains(selectedItem)) { - delayedUpdate.clear(); - delayedUpdate.add(selectedItem); - } else { - delayedUpdate.clear(); - } - } - }); - - CellNavigationStrategy nStrategy = new CellNavigationStrategy() { - private ViewerCell internalFindSelectedCell( - ColumnViewer viewer, ViewerCell currentSelectedCell, - Event event) { - switch (event.keyCode) { - case SWT.ARROW_UP: - if (currentSelectedCell != null) { - return getNeighbor(currentSelectedCell, - ViewerCell.ABOVE, false); - } - break; - case SWT.ARROW_DOWN: - if (currentSelectedCell != null) { - return getNeighbor(currentSelectedCell, - ViewerCell.BELOW, false); - } - break; - case SWT.ARROW_LEFT: - if (currentSelectedCell != null) { - return getNeighbor(currentSelectedCell, - ViewerCell.LEFT, true); - } - break; - case SWT.ARROW_RIGHT: - if (currentSelectedCell != null) { - return getNeighbor(currentSelectedCell, - ViewerCell.RIGHT, true); - } - break; - } - return null; - } - - public ViewerCell findSelectedCell(ColumnViewer viewer, - ViewerCell currentSelectedCell, Event event) { - ViewerCell cell = internalFindSelectedCell(viewer, - currentSelectedCell, event); - if (cell != null) { - TableColumn t = AnnotatedPropertyTab.this.viewer.getTable().getColumn( - cell.getColumnIndex()); - AnnotatedPropertyTab.this.viewer.getTable().showColumn(t); - } - return cell; - } - }; - - TableViewerFocusCellManager focusCellManager = new TableViewerFocusCellManager( - viewer, new FocusCellOwnerDrawHighlighter(viewer)); - try { - Field f = focusCellManager.getClass().getSuperclass() - .getDeclaredField("navigationStrategy"); - f.setAccessible(true); - f.set(focusCellManager, nStrategy); - } catch (SecurityException e) { - e.printStackTrace(); - } catch (NoSuchFieldException e) { - e.printStackTrace(); - } catch (IllegalArgumentException e) { - e.printStackTrace(); - } catch (IllegalAccessException e) { - e.printStackTrace(); - } - ColumnViewerEditorActivationStrategy actSupport = new ColumnViewerEditorActivationStrategy( - viewer) { - protected boolean isEditorActivationEvent( - ColumnViewerEditorActivationEvent event) { - return event.eventType == ColumnViewerEditorActivationEvent.TRAVERSAL - || event.eventType == ColumnViewerEditorActivationEvent.MOUSE_DOUBLE_CLICK_SELECTION - || (event.eventType == ColumnViewerEditorActivationEvent.KEY_PRESSED && event.keyCode == SWT.CR) - || event.eventType == ColumnViewerEditorActivationEvent.PROGRAMMATIC; - } - }; - TableViewerEditor.create(viewer, focusCellManager, actSupport, - ColumnViewerEditor.TABBING_HORIZONTAL - | ColumnViewerEditor.TABBING_MOVE_TO_ROW_NEIGHBOR - | ColumnViewerEditor.TABBING_VERTICAL - | ColumnViewerEditor.KEYBOARD_ACTIVATION); - viewer.getColumnViewerEditor().addEditorActivationListener( - new ColumnViewerEditorActivationListener() { - public void afterEditorActivated( - ColumnViewerEditorActivationEvent event) { - } - - public void afterEditorDeactivated( - ColumnViewerEditorDeactivationEvent event) { - } - - public void beforeEditorActivated( - ColumnViewerEditorActivationEvent event) { - ViewerCell cell = (ViewerCell) event.getSource(); - viewer.getTable().showColumn( - viewer.getTable().getColumn(cell.getColumnIndex())); - } - - public void beforeEditorDeactivated( - ColumnViewerEditorDeactivationEvent event) { - } - }); - } - - - - - private IPropertyItem selectedItem = null; - private Set delayedUpdate = new HashSet(); - - - @Override - public void setInput(ISessionContext context, ISelection selection, - boolean force) { - Collection nodes = AdaptationUtils.adaptToCollection(selection, IG3DNode.class); - if (nodes.size() != 1) { - if (node != null) { - node.removeListener(this); - node = null; - } - return; - } - IG3DNode n = nodes.iterator().next(); - if (node != null) { - if (!node.equals(n)) { - node.removeListener(this); - setInput(n); - } - } else { - setInput(n); - } - } - - - - private void setInput(IG3DNode node) { - this.node = node; - this.node.addListener(this); - // resolve nodemap - IG3DNode n = node; - while (true) { - if (n == null) { - nodeMap = null; - break; - } - if (n instanceof NodeMapProvider) { - nodeMap = ((NodeMapProvider) n).getNodeMap(); - if (nodeMap != null) - break; - } - n = (IG3DNode)n.getParent(); - } - boolean readOnly = (node instanceof IStructuralNode && ((IStructuralNode)node).isPartOfInstantiatedModel() && !((IStructuralNode)node).isInstantiatedModelRoot()); - // create label providers - PropertyValueLabelProvider2 p = new PropertyValueLabelProvider2(this); - int index = 0; - for (TableViewerColumn c : valueColumns) { - c.setLabelProvider(p); - if (!readOnly) { - PropertyEditingSupport support = new PropertyEditingSupport(this, viewer, index++, nodeMap); - c.setEditingSupport(support); - } - } - resolvedItems.clear(); - manipulators.clear(); - for (IPropertyItem item : contibutedItems) { - if (item instanceof PropertyItem) { - resolvedItems.add((PropertyItem)item); - manipulators.put((PropertyItem)item, createManipulator((PropertyItem)item, node)); - } - else { - CompoundPropertyItem compound = (CompoundPropertyItem)item; - Map manipulators = createManipulators(compound, node); - for (PropertyItem i : manipulators.keySet()) { - resolvedItems.add(i); - this.manipulators.put(i, manipulators.get(i)); - } - } - } - - viewer.getTable().setEnabled(!readOnly); - viewer.setInput(resolvedItems); - } - - @Override - public void requestFocus() { - viewer.getTable().forceFocus(); - } - - @Override - public void dispose() { - if (node != null) { - node.removeListener(this); - node = null; - } - - } - - @Override - public Control getControl() { - return viewer.getTable(); - } - - @Override - public ISelectionProvider getSelectionProvider() { - return null; - } - - @Override - public boolean isDisposed() { - return viewer.getTable().isDisposed(); - } - - @Override - public void nodeAdded(ParentNode node, - INode child, String rel) { - - } - - @Override - public void nodeRemoved(ParentNode node, - INode child, String rel) { - - } - - @Override - public void propertyChanged(INode node, final String id) { -// for (final PropertyItem item : items) { -// if (item.id.equals(id)) { -// Display.getDefault().asyncExec(new Runnable() { -// -// @Override -// public void run() { -// viewer.update(item, null); -// -// } -// }); -// } -// } - if (Thread.currentThread() == Display.getDefault().getThread()) { - if (DEBUG)System.out.println("Viewer refresh " + id); - for (PropertyItem item : resolvedItems) - if (!item.equals(selectedItem)) - viewer.refresh(item); - if (selectedItem != null) - delayedUpdate.add(selectedItem); - } else if (!editing){ - // running delayed refresh when a cell editor is active would cancel cell editing. - Display.getDefault().asyncExec(new Runnable() { - @Override - public void run() { - if (viewer.getTable().isDisposed()) { - if (AnnotatedPropertyTab.this.node != null) - AnnotatedPropertyTab.this.node.removeListener(AnnotatedPropertyTab.this); - return; - } - if (DEBUG) System.out.println("Viewer threaded refresh " + id); - for (PropertyItem item : resolvedItems) - if (!item.equals(selectedItem)) - viewer.refresh(item); - if (selectedItem != null) - delayedUpdate.add(selectedItem); - - } - }); - } else { - for (PropertyItem item : resolvedItems) { - delayedUpdate.add(item); - } - } - - } - - - - - - @Override - public void updatePartName(Callback updateCallback) { - if (node != null) - updateCallback.run(node.toString()); - - } - - public PropertyManipulator getManipulator(PropertyItem item) { - return manipulators.get(item); - } - - private boolean editing = false; - - public void setEditing(boolean editing) { - this.editing = editing; - } - } - - - - private static class PropertyEditingSupport extends EditingSupport { - AnnotatedPropertyTab tab; - int index; - NodeMap nodeMap; - TableViewer viewer; - CellEditor editor; - - public PropertyEditingSupport(AnnotatedPropertyTab tab, TableViewer viewer, int index, NodeMap nodeMap) { - super(viewer); - this.tab = tab; - this.index = index; - this.viewer = viewer; - this.nodeMap = nodeMap; - } - - @Override - protected boolean canEdit(Object element) { - PropertyItem item = (PropertyItem)element; - if (tab.getManipulator(item).getValueCount() <= index) - return false; - return (item.setter != null); - } - - @Override - protected CellEditor getCellEditor(Object element) { - - if (tab.getManipulator((PropertyItem)element).getValueCount() <= index) - return null; - if (editor == null) - editor = new TextCellEditor(viewer.getTable(),SWT.NONE) { - @Override - public void activate() { - tab.setEditing(true); - } - - @Override - public void deactivate() { - super.deactivate(); - tab.setEditing(false); - } - }; - if (DEBUG)System.err.println("CELL EDITOR: " + element); - return editor; - } - - @Override - protected Object getValue(Object element) { - PropertyItem item = (PropertyItem)element; - PropertyManipulator manipulator = tab.getManipulator(item);//createManipulator(item, obj); - if (manipulator.getValueCount() <= index) - return null; - Object value = manipulator.getValue(index); - return value; - } - - @Override - protected void setValue(Object element, Object value) { - - PropertyItem item = (PropertyItem)element; - PropertyManipulator manipulator = tab.getManipulator(item);//createManipulator(item, obj); - if (manipulator.getValueCount() <= index) - throw new IllegalAccessError("Editing value in index " + index + " is not allowed."); - if (DEBUG)System.err.println("CELL SET VALUE: " + element + " " + value); - manipulator.setValue((String)value,index); - viewer.refresh(item); - nodeMap.commit(); - - } - - - - } - - private static class PropertyItemNameProvider extends CellLabelProvider { - - - @Override - public void update(ViewerCell cell) { - PropertyItem item = (PropertyItem)cell.getElement(); - - if (item.name.length() > 0) - cell.setText(item.name); - else - cell.setText(item.id); - - - } - } - - private static class PropertyValueLabelProvider2 extends CellLabelProvider { - AnnotatedPropertyTab tab; - //private Object object; - - public PropertyValueLabelProvider2(AnnotatedPropertyTab tab) { - this.tab = tab; - } - - @Override - public void update(ViewerCell cell) { - PropertyItem item = (PropertyItem)cell.getElement(); - int index = cell.getColumnIndex() -1; - PropertyManipulator manipulator = tab.getManipulator(item);//createManipulator(item, object); - if (manipulator.getValueCount() <= index) - return; - cell.setText(manipulator.getValue(index)); - } - } - - private static class PropertyItemContentsProvider implements IStructuredContentProvider { - @SuppressWarnings("unchecked") - @Override - public Object[] getElements(Object inputElement) { - List items = (List)inputElement; - return items.toArray(); - } - - @Override - public void dispose() { - - } - - @Override - public void inputChanged(Viewer viewer, Object oldInput, Object newInput) { - - } - } - - - - private static ViewerCell getNeighbor(ViewerCell currentCell, - int directionMask, boolean sameLevel) { - ViewerRow row; - if ((directionMask & ViewerCell.ABOVE) == ViewerCell.ABOVE) { - row = currentCell.getViewerRow().getNeighbor(ViewerRow.ABOVE, - sameLevel); - } else if ((directionMask & ViewerCell.BELOW) == ViewerCell.BELOW) { - row = currentCell.getViewerRow().getNeighbor(ViewerRow.BELOW, - sameLevel); - } else { - row = currentCell.getViewerRow(); - } - if (row != null) { - int columnIndex; - columnIndex = getVisualIndex(row, currentCell.getColumnIndex()); - int modifier = 0; - if ((directionMask & ViewerCell.LEFT) == ViewerCell.LEFT) { - modifier = -1; - } else if ((directionMask & ViewerCell.RIGHT) == ViewerCell.RIGHT) { - modifier = 1; - } - columnIndex += modifier; - if (columnIndex >= 0 && columnIndex < row.getColumnCount()) { - ViewerCell cell = getCellAtVisualIndex(row, columnIndex); - if (cell != null) { - while (cell != null - && columnIndex < row.getColumnCount() - 1 - && columnIndex > 0) { - if (isVisible(cell)) { - break; - } - columnIndex += modifier; - cell = getCellAtVisualIndex(row, columnIndex); - if (cell == null) { - break; - } - } - } - return cell; - } - } - return null; - } - - - - public static class TableViewerEditor extends ColumnViewerEditor { - /** - * This viewer's table editor. - */ - private TableEditor tableEditor; - private TableViewerFocusCellManager focusCellManager; - private int feature; - - /** - * @param viewer - * the viewer the editor is attached to - * @param focusCellManager - * the cell focus manager if one used or null - * @param editorActivationStrategy - * the strategy used to decide about the editor activation - * @param feature - * the feature mask - */ - TableViewerEditor(TableViewer viewer, - TableViewerFocusCellManager focusCellManager, - ColumnViewerEditorActivationStrategy editorActivationStrategy, - int feature) { - super(viewer, editorActivationStrategy, feature); - this.feature = feature; - tableEditor = new TableEditor(viewer.getTable()); - this.focusCellManager = focusCellManager; - } - - /** - * Create a customized editor with focusable cells - * - * @param viewer - * the viewer the editor is created for - * @param focusCellManager - * the cell focus manager if one needed else - * null - * @param editorActivationStrategy - * activation strategy to control if an editor activated - * @param feature - * bit mask controlling the editor - *
    - *
  • {@link ColumnViewerEditor#DEFAULT}
  • - *
  • {@link ColumnViewerEditor#TABBING_CYCLE_IN_ROW}
  • - *
  • {@link ColumnViewerEditor#TABBING_HORIZONTAL}
  • - *
  • - * {@link ColumnViewerEditor#TABBING_MOVE_TO_ROW_NEIGHBOR}
  • - *
  • {@link ColumnViewerEditor#TABBING_VERTICAL}
  • - *
- * @see #create(TableViewer, ColumnViewerEditorActivationStrategy, int) - */ - public static void create(TableViewer viewer, - TableViewerFocusCellManager focusCellManager, - ColumnViewerEditorActivationStrategy editorActivationStrategy, - int feature) { - TableViewerEditor editor = new TableViewerEditor(viewer, - focusCellManager, editorActivationStrategy, feature); - viewer.setColumnViewerEditor(editor); - if (focusCellManager != null) { - try { - Method m = focusCellManager.getClass().getSuperclass() - .getDeclaredMethod("init", null); - m.setAccessible(true); - m.invoke(focusCellManager, null); - } catch (SecurityException e) { - e.printStackTrace(); - } catch (IllegalArgumentException e) { - e.printStackTrace(); - } catch (IllegalAccessException e) { - e.printStackTrace(); - } catch (NoSuchMethodException e) { - e.printStackTrace(); - } catch (InvocationTargetException e) { - e.printStackTrace(); - } - // focusCellManager.init(); - } - } - - /** - * Create a customized editor whose activation process is customized - * - * @param viewer - * the viewer the editor is created for - * @param editorActivationStrategy - * activation strategy to control if an editor activated - * @param feature - * bit mask controlling the editor - *
    - *
  • {@link ColumnViewerEditor#DEFAULT}
  • - *
  • {@link ColumnViewerEditor#TABBING_CYCLE_IN_ROW}
  • - *
  • {@link ColumnViewerEditor#TABBING_HORIZONTAL}
  • - *
  • - * {@link ColumnViewerEditor#TABBING_MOVE_TO_ROW_NEIGHBOR}
  • - *
  • {@link ColumnViewerEditor#TABBING_VERTICAL}
  • - *
- */ - public static void create(TableViewer viewer, - ColumnViewerEditorActivationStrategy editorActivationStrategy, - int feature) { - create(viewer, null, editorActivationStrategy, feature); - } - - protected void setEditor(Control w, Item item, int columnNumber) { - tableEditor.setEditor(w, (TableItem) item, columnNumber); - } - - protected void setLayoutData(LayoutData layoutData) { - tableEditor.grabHorizontal = layoutData.grabHorizontal; - tableEditor.horizontalAlignment = layoutData.horizontalAlignment; - tableEditor.minimumWidth = layoutData.minimumWidth; - } - - public ViewerCell getFocusCell() { - if (focusCellManager != null) { - return focusCellManager.getFocusCell(); - } - return super.getFocusCell(); - } - - protected void updateFocusCell(ViewerCell focusCell, - ColumnViewerEditorActivationEvent event) { - // Update the focus cell when we activated the editor with these 2 - // events - if (event.eventType == ColumnViewerEditorActivationEvent.PROGRAMMATIC - || event.eventType == ColumnViewerEditorActivationEvent.TRAVERSAL) { - if (focusCellManager != null) { - try { - if (DEBUG)System.err.println("FOCUS CELL: " + focusCell); - - Method m = AbstractTableViewer.class.getDeclaredMethod( - "getSelectionFromWidget", null); - m.setAccessible(true); - List l = (List) m.invoke(getViewer(), null); - if (focusCellManager != null) { - m = focusCellManager - .getClass() - .getSuperclass() - .getDeclaredMethod("setFocusCell", - new Class[] { ViewerCell.class }); - m.setAccessible(true); - m.invoke(focusCellManager, - new Object[] { focusCell }); - } - if (!l.contains(focusCell.getElement())) { - getViewer().setSelection( - new StructuredSelection(focusCell - .getElement())); - } - } catch (SecurityException e) { - e.printStackTrace(); - } catch (IllegalArgumentException e) { - e.printStackTrace(); - } catch (IllegalAccessException e) { - e.printStackTrace(); - } catch (NoSuchMethodException e) { - e.printStackTrace(); - } catch (InvocationTargetException e) { - e.printStackTrace(); - } - } - } - } - - protected void processTraverseEvent(int columnIndex, ViewerRow row, - TraverseEvent event) { - ViewerCell cell2edit = null; - if (event.detail == SWT.TRAVERSE_TAB_PREVIOUS) { - event.doit = false; - if ((event.stateMask & SWT.CTRL) == SWT.CTRL - && (feature & TABBING_VERTICAL) == TABBING_VERTICAL) { - cell2edit = searchCellAboveBelow(row, getViewer(), - columnIndex, true); - } else if ((feature & TABBING_HORIZONTAL) == TABBING_HORIZONTAL) { - cell2edit = searchPreviousCell(row, - row.getCell(columnIndex), row.getCell(columnIndex), - getViewer()); - } - } else if (event.detail == SWT.TRAVERSE_TAB_NEXT) { - event.doit = false; - if ((event.stateMask & SWT.CTRL) == SWT.CTRL - && (feature & TABBING_VERTICAL) == TABBING_VERTICAL) { - cell2edit = searchCellAboveBelow(row, getViewer(), - columnIndex, false); - } else if ((feature & TABBING_HORIZONTAL) == TABBING_HORIZONTAL) { - cell2edit = searchNextCell(row, row.getCell(columnIndex), - row.getCell(columnIndex), getViewer()); - } - } - if (DEBUG) System.err.println("NEXT CELL: " + cell2edit); - if (cell2edit != null) { - getViewer().getControl().setRedraw(false); - ColumnViewerEditorActivationEvent acEvent = new ColumnViewerEditorActivationEvent( - cell2edit, event); - try { - Method m = ColumnViewer.class - .getDeclaredMethod( - "triggerEditorActivationEvent", - new Class[] { ColumnViewerEditorActivationEvent.class }); - m.setAccessible(true); - m.invoke(getViewer(), new Object[] { acEvent }); - } catch (SecurityException e) { - e.printStackTrace(); - } catch (NoSuchMethodException e) { - e.printStackTrace(); - } catch (IllegalArgumentException e) { - e.printStackTrace(); - } catch (IllegalAccessException e) { - e.printStackTrace(); - } catch (InvocationTargetException e) { - e.printStackTrace(); - } - getViewer().getControl().setRedraw(true); - } - } - - private ViewerCell searchCellAboveBelow(ViewerRow row, - ColumnViewer viewer, int columnIndex, boolean above) { - ViewerCell rv = null; - ViewerRow newRow = null; - if (above) { - newRow = row.getNeighbor(ViewerRow.ABOVE, false); - } else { - newRow = row.getNeighbor(ViewerRow.BELOW, false); - } - try { - if (newRow != null) { - Method m = ColumnViewer.class.getDeclaredMethod( - "getViewerColumn", new Class[] { int.class }); - m.setAccessible(true); - ViewerColumn column = (ViewerColumn) m.invoke(viewer, - new Object[] { new Integer(columnIndex) }); - m = ViewerColumn.class.getDeclaredMethod( - "getEditingSupport", null); - m.setAccessible(true); - EditingSupport es = (EditingSupport) m.invoke(column, null); - if (column != null && es != null) { - m = EditingSupport.class.getDeclaredMethod("canEdit", - new Class[] { Object.class }); - m.setAccessible(true); - Boolean b = (Boolean) m.invoke(es, - new Object[] { newRow.getItem().getData() }); - if (b.booleanValue()) { - rv = newRow.getCell(columnIndex); - } - } else { - rv = searchCellAboveBelow(newRow, viewer, columnIndex, - above); - } - } - } catch (Exception e) { - e.printStackTrace(); - } - return rv; - } - - private ViewerCell searchPreviousCell(ViewerRow row, - ViewerCell currentCell, ViewerCell originalCell, - ColumnViewer viewer) { - ViewerCell rv = null; - ViewerCell previousCell; - if (currentCell != null) { - previousCell = getNeighbor(currentCell, ViewerCell.LEFT, true); - } else { - if (row.getColumnCount() != 0) { - previousCell = row.getCell(getCreationIndex(row, - row.getColumnCount() - 1)); - } else { - previousCell = row.getCell(0); - } - } - // No endless loop - if (originalCell.equals(previousCell)) { - return null; - } - if (previousCell != null) { - if (isCellEditable(viewer, previousCell)) { - rv = previousCell; - } else { - rv = searchPreviousCell(row, previousCell, originalCell, - viewer); - } - } else { - if ((feature & TABBING_CYCLE_IN_ROW) == TABBING_CYCLE_IN_ROW) { - rv = searchPreviousCell(row, null, originalCell, viewer); - } else if ((feature & TABBING_MOVE_TO_ROW_NEIGHBOR) == TABBING_MOVE_TO_ROW_NEIGHBOR) { - ViewerRow rowAbove = row - .getNeighbor(ViewerRow.ABOVE, false); - if (rowAbove != null) { - rv = searchPreviousCell(rowAbove, null, originalCell, - viewer); - } - } - } - return rv; - } - - private ViewerCell searchNextCell(ViewerRow row, - ViewerCell currentCell, ViewerCell originalCell, - ColumnViewer viewer) { - ViewerCell rv = null; - ViewerCell nextCell; - if (currentCell != null) { - nextCell = getNeighbor(currentCell, ViewerCell.RIGHT, true); - } else { - nextCell = row.getCell(getCreationIndex(row, 0)); - } - // No endless loop - if (originalCell.equals(nextCell)) { - return null; - } - if (nextCell != null) { - if (isCellEditable(viewer, nextCell)) { - rv = nextCell; - } else { - rv = searchNextCell(row, nextCell, originalCell, viewer); - } - } else { - if ((feature & TABBING_CYCLE_IN_ROW) == TABBING_CYCLE_IN_ROW) { - rv = searchNextCell(row, null, originalCell, viewer); - } else if ((feature & TABBING_MOVE_TO_ROW_NEIGHBOR) == TABBING_MOVE_TO_ROW_NEIGHBOR) { - ViewerRow rowBelow = row - .getNeighbor(ViewerRow.BELOW, false); - if (rowBelow != null) { - rv = searchNextCell(rowBelow, null, originalCell, - viewer); - } - } - } - return rv; - } - - private boolean isCellEditable(ColumnViewer viewer, ViewerCell cell) { - try { - Method m = ColumnViewer.class.getDeclaredMethod( - "getViewerColumn", new Class[] { int.class }); - m.setAccessible(true); - ViewerColumn column = (ViewerColumn) m.invoke(viewer, - new Object[] { new Integer(cell.getColumnIndex()) }); - m = ViewerColumn.class.getDeclaredMethod("getEditingSupport", - null); - m.setAccessible(true); - EditingSupport es = (EditingSupport) m.invoke(column, null); - if (column != null && es != null) { - m = EditingSupport.class.getDeclaredMethod("canEdit", - new Class[] { Object.class }); - m.setAccessible(true); - // return true; - Boolean b = (Boolean) m.invoke(es, - new Object[] { cell.getElement() }); - return b.booleanValue(); - } - } catch (Exception e) { - e.printStackTrace(); - } - return false; - } - } - - // Reimplementation of ViewerCell-Methods - private static int getVisualIndex(ViewerRow row, int creationIndex) { - TableItem item = (TableItem) row.getItem(); - int[] order = item.getParent().getColumnOrder(); - for (int i = 0; i < order.length; i++) { - if (order[i] == creationIndex) { - return i; - } - } - return creationIndex; - } - - private static int getCreationIndex(ViewerRow row, int visualIndex) { - TableItem item = (TableItem) row.getItem(); - if (item != null && !item.isDisposed() /* - * && hasColumns() && - * isValidOrderIndex - * (visualIndex) - */) { - return item.getParent().getColumnOrder()[visualIndex]; - } - return visualIndex; - } - - private static ViewerCell getCellAtVisualIndex(ViewerRow row, - int visualIndex) { - return getCell(row, getCreationIndex(row, visualIndex)); - } - - private static boolean isVisible(ViewerCell cell) { - return getWidth(cell) > 0; - } - - private static int getWidth(ViewerCell cell) { - TableItem item = (TableItem) cell.getViewerRow().getItem(); - return item.getParent().getColumn(cell.getColumnIndex()).getWidth(); - } - - private static ViewerCell getCell(ViewerRow row, int index) { - return row.getCell(index); - } - - -} +/******************************************************************************* + * Copyright (c) 2012, 2013 Association for Decentralized Information Management in + * Industry THTH ry. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.g3d.property; + +import java.lang.annotation.Annotation; +import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.Comparator; +import java.util.HashMap; +import java.util.HashSet; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.function.Consumer; + +import org.eclipse.jface.layout.GridDataFactory; +import org.eclipse.jface.viewers.AbstractTableViewer; +import org.eclipse.jface.viewers.CellEditor; +import org.eclipse.jface.viewers.CellEditor.LayoutData; +import org.eclipse.jface.viewers.CellLabelProvider; +import org.eclipse.jface.viewers.CellNavigationStrategy; +import org.eclipse.jface.viewers.ColumnViewer; +import org.eclipse.jface.viewers.ColumnViewerEditor; +import org.eclipse.jface.viewers.ColumnViewerEditorActivationEvent; +import org.eclipse.jface.viewers.ColumnViewerEditorActivationListener; +import org.eclipse.jface.viewers.ColumnViewerEditorActivationStrategy; +import org.eclipse.jface.viewers.ColumnViewerEditorDeactivationEvent; +import org.eclipse.jface.viewers.EditingSupport; +import org.eclipse.jface.viewers.FocusCellOwnerDrawHighlighter; +import org.eclipse.jface.viewers.ISelection; +import org.eclipse.jface.viewers.ISelectionChangedListener; +import org.eclipse.jface.viewers.ISelectionProvider; +import org.eclipse.jface.viewers.IStructuredContentProvider; +import org.eclipse.jface.viewers.SelectionChangedEvent; +import org.eclipse.jface.viewers.StructuredSelection; +import org.eclipse.jface.viewers.TableViewer; +import org.eclipse.jface.viewers.TableViewerColumn; +import org.eclipse.jface.viewers.TableViewerFocusCellManager; +import org.eclipse.jface.viewers.TextCellEditor; +import org.eclipse.jface.viewers.Viewer; +import org.eclipse.jface.viewers.ViewerCell; +import org.eclipse.jface.viewers.ViewerColumn; +import org.eclipse.jface.viewers.ViewerRow; +import org.eclipse.swt.SWT; +import org.eclipse.swt.custom.TableEditor; +import org.eclipse.swt.events.TraverseEvent; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.Display; +import org.eclipse.swt.widgets.Event; +import org.eclipse.swt.widgets.Item; +import org.eclipse.swt.widgets.TableColumn; +import org.eclipse.swt.widgets.TableItem; +import org.eclipse.ui.IWorkbenchSite; +import org.simantics.db.management.ISessionContext; +import org.simantics.g3d.property.annotations.CompoundGetPropertyValue; +import org.simantics.g3d.property.annotations.CompoundSetPropertyValue; +import org.simantics.g3d.property.annotations.GetPropertyValue; +import org.simantics.g3d.property.annotations.PropertyTabBlacklist; +import org.simantics.g3d.property.annotations.SetPropertyValue; +import org.simantics.g3d.scenegraph.IG3DNode; +import org.simantics.g3d.scenegraph.NodeMap; +import org.simantics.g3d.scenegraph.NodeMapProvider; +import org.simantics.g3d.scenegraph.base.INode; +import org.simantics.g3d.scenegraph.base.NodeListener; +import org.simantics.g3d.scenegraph.base.ParentNode; +import org.simantics.g3d.scenegraph.structural.IStructuralNode; +import org.simantics.g3d.tools.AdaptationUtils; +import org.simantics.selectionview.IPropertyTab; +import org.simantics.selectionview.IPropertyTab2; +import org.simantics.utils.datastructures.MapList; + +public class AnnotatedPropertyTabContributorFactory implements PropertyTabContributorFactory { + + private static final boolean DEBUG = false; + + @SuppressWarnings("unchecked") + @Override + public List getContributors(Object input) { + Map items = new LinkedHashMap(); + List blacklist = new ArrayList(); + try { + collectItems(input.getClass(), items); + collectBlacklist(input.getClass(), blacklist); + } catch (InstantiationException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (IllegalAccessException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + + if (items.size() == 0) + return Collections.EMPTY_LIST; + + MapList tabMap = new MapList(); + List tabs = new ArrayList(); + for (String id : items.keySet()) { + IPropertyItem item = items.get(id); + tabMap.add(item.getTabId(), item); + if (!tabs.contains(item.getTabId())) { + tabs.add(item.getTabId()); + //System.out.println(item.tabId + " " + item.name + " " + item.id); + } + } + for (String s : blacklist) { + tabs.remove(s); + } + + List contributors = new ArrayList(tabs.size()); + for (String tabId : tabs) { + contributors.add(new AnnotatedPropertyTabContributor(tabId, tabMap.getValues(tabId))); + } + + return contributors; + } + + + private static void collectItems(Class clazz, Map items) throws InstantiationException, IllegalAccessException { + Class superclass = clazz.getSuperclass(); + if(superclass != null) + collectItems(superclass, items); + + for (Method m : clazz.getDeclaredMethods()) { + m.setAccessible(true); + for (Annotation annotation : m.getAnnotations()) { + if (annotation.annotationType().equals(GetPropertyValue.class)) { + GetPropertyValue get = (GetPropertyValue)annotation; + PropertyItem item = (PropertyItem)items.get(get.value()); + if (item == null) { + item = new PropertyItem(get.value()); + items.put(item.id, item); + } + + item.getter = m; + item.manipulatorClass = get.manipulator().newInstance().get(m,null); + + item.tabId = get.tabId(); + + item.name = get.name(); + + + } else if (annotation.annotationType().equals(SetPropertyValue.class)) { + SetPropertyValue set = (SetPropertyValue)annotation; + PropertyItem item = (PropertyItem)items.get(set.value()); + if (item == null) { + item = new PropertyItem(set.value()); + items.put(item.id, item); + } + + item.setter = m; + } else if (annotation.annotationType().equals(CompoundGetPropertyValue.class)) { + CompoundGetPropertyValue get = (CompoundGetPropertyValue)annotation; + CompoundPropertyItem item = (CompoundPropertyItem)items.get(get.value()); + if (item == null) { + item = new CompoundPropertyItem(get.value()); + items.put(item.id, item); + } + + item.getter = m; + item.manipulatorFactory = get.manipulator().newInstance(); + + item.tabId = get.tabId(); + + item.name = get.name(); + } else if (annotation.annotationType().equals(CompoundSetPropertyValue.class)) { + CompoundSetPropertyValue set = (CompoundSetPropertyValue)annotation; + CompoundPropertyItem item = (CompoundPropertyItem)items.get(set.value()); + if (item == null) { + item = new CompoundPropertyItem(set.value()); + items.put(item.id, item); + } + + item.setter = m; + } + } + } + + + } + + private static void collectBlacklist(Class clazz, List blacklist) throws InstantiationException, IllegalAccessException { + Class superclass = clazz.getSuperclass(); + if(superclass != null) + collectBlacklist(superclass, blacklist); + + PropertyTabBlacklist ann = clazz.getAnnotation(PropertyTabBlacklist.class); + if (ann == null) + return; + String s = ann.value(); + if (s == null) + return; + if (s.length() == 0) + return; + for (String item : s.split(";")) { + blacklist.add(item); + } + + + } + + private static Map createManipulators(CompoundPropertyItem item, Object obj) { + try { + + @SuppressWarnings("unchecked") + Map map = (Map)item.getter.invoke(obj); + Map result = new HashMap(); + for (String key : map.keySet()) { + MethodWithMapValueProvider provider = new MethodWithMapValueProvider(item.getter, item.setter, key); + Class clazz = item.manipulatorFactory.get(null,map.get(key)); + PropertyManipulator manipulator = clazz.getConstructor(ValueProvider.class,Object.class).newInstance(provider,obj); + PropertyItem i = new PropertyItem(item.id+"."+key); + i.getter = item.getter; + i.setter = item.setter; + i.name = key; + i.tabId = item.tabId; + result.put(i,manipulator); + } + return result; + } catch (Exception e) { + e.printStackTrace(); + return Collections.emptyMap(); + } + + } + + private static PropertyManipulator createManipulator(PropertyItem item, Object obj) { + try { + MethodValueProvider provider = new MethodValueProvider(item.getter, item.setter); + PropertyManipulator manipulator = item.manipulatorClass.getConstructor(ValueProvider.class,Object.class).newInstance(provider,obj); + return manipulator; + } catch (Exception e) { + e.printStackTrace(); + return null; + } + } + + private static interface IPropertyItem { + public String getTabId(); + public String getName(); + } + + private static class PropertyItem implements IPropertyItem{ + private String id; + private String name; + private String tabId; + private Method getter; + private Method setter; + private Class manipulatorClass; + + + public PropertyItem(String id) { + if (id == null) + throw new NullPointerException(); + this.id = id; + } + + @Override + public int hashCode() { + return id.hashCode(); + } + + @Override + public String getTabId() { + return tabId; + } + + @Override + public String getName() { + return name; + } + } + + private static class CompoundPropertyItem implements IPropertyItem{ + private String id; + private String name; + private String tabId; + private Method getter; + private Method setter; + private PropertyManipulatorFactory manipulatorFactory; + + + public CompoundPropertyItem(String id) { + if (id == null) + throw new NullPointerException(); + this.id = id; + } + + @Override + public int hashCode() { + return id.hashCode(); + } + + @Override + public String getTabId() { + return tabId; + } + + @Override + public String getName() { + return name; + } + } + + private static class AnnotatedPropertyTabContributor implements PropertyTabContributor { + private String id; + List items; + + public AnnotatedPropertyTabContributor(String id, List items) { + if (id == null) + throw new NullPointerException(); + this.id = id; + this.items = items; + } + + @Override + public IPropertyTab create(Composite parent, IWorkbenchSite site, + ISessionContext context, Object input) { + AnnotatedPropertyTab tab = new AnnotatedPropertyTab(id, items); + tab.createControl(parent, context); + return tab; + } + + @Override + public String getId() { + return id; + } + + } + + private static class AnnotatedPropertyTab implements IPropertyTab2, NodeListener { + //private String id; + List contibutedItems; + List resolvedItems = new ArrayList(); + private Map manipulators = new HashMap(); + + private TableViewer viewer; + + private INode node; + private NodeMap nodeMap; + + private List valueColumns = new ArrayList(); + + public AnnotatedPropertyTab(String id, List items) { + //this.id = id; + this.contibutedItems = items; + + + } + + @Override + public void createControl(Composite parent, ISessionContext context) { + //parent.setLayout(new FillLayout()); + viewer = new TableViewer(parent, SWT.FULL_SELECTION | SWT.SINGLE); + + GridDataFactory.fillDefaults().align(SWT.FILL, SWT.FILL).grab(true, true).applyTo(viewer.getTable()); + + //viewer.setLabelProvider(new AnnotatedTableLabelProvider(object)) + + viewer.setContentProvider(new PropertyItemContentsProvider()); + + TableViewerColumn name = new TableViewerColumn(viewer, SWT.LEFT); + //TableViewerColumn value = new TableViewerColumn(viewer, SWT.LEFT); + name.setLabelProvider(new PropertyItemNameProvider()); + //value.setLabelProvider(new PropertyValueLabelProvider(null)); + name.getColumn().setText("Property"); + //value.getColumn().setText("Value"); + name.getColumn().setWidth(200); + //value.getColumn().setWidth(200); + name.getViewer().addSelectionChangedListener(new ISelectionChangedListener() { + + @Override + public void selectionChanged(SelectionChangedEvent event) { + PropertyItem item = AdaptationUtils.adaptToSingle(event.getSelection(),PropertyItem.class); + if (item != null) { + PropertyManipulator manipulator = manipulators.get(item);//createManipulator(item, null); + for (int i = 0; i < valueColumns.size(); i++) { + TableViewerColumn c = valueColumns.get(i); + if (i < manipulator.getValueCount()) { + c.getColumn().setText(manipulator.getDescription(i)); + } else { + c.getColumn().setText(""); + } + } + } + + } + }); + + viewer.getTable().setHeaderVisible(true); + viewer.getTable().setLinesVisible(true); + viewer.addSelectionChangedListener(new ISelectionChangedListener() { + + @Override + public void selectionChanged(SelectionChangedEvent event) { + PropertyItem item = AdaptationUtils.adaptToSingle(event.getSelection(), PropertyItem.class); + selectedItem = item; + if (!manipulators.get(selectedItem).getEditMode()) + manipulators.get(selectedItem).setEditMode(true); + + + for (IPropertyItem i : delayedUpdate) { + if (!i.equals(selectedItem)) { + manipulators.get(i).setEditMode(false); + viewer.update(i,null); + } + } + if (delayedUpdate.contains(selectedItem)) { + delayedUpdate.clear(); + delayedUpdate.add(selectedItem); + } else { + delayedUpdate.clear(); + } + } + }); + + CellNavigationStrategy nStrategy = new CellNavigationStrategy() { + private ViewerCell internalFindSelectedCell( + ColumnViewer viewer, ViewerCell currentSelectedCell, + Event event) { + switch (event.keyCode) { + case SWT.ARROW_UP: + if (currentSelectedCell != null) { + return getNeighbor(currentSelectedCell, + ViewerCell.ABOVE, false); + } + break; + case SWT.ARROW_DOWN: + if (currentSelectedCell != null) { + return getNeighbor(currentSelectedCell, + ViewerCell.BELOW, false); + } + break; + case SWT.ARROW_LEFT: + if (currentSelectedCell != null) { + return getNeighbor(currentSelectedCell, + ViewerCell.LEFT, true); + } + break; + case SWT.ARROW_RIGHT: + if (currentSelectedCell != null) { + return getNeighbor(currentSelectedCell, + ViewerCell.RIGHT, true); + } + break; + } + return null; + } + + public ViewerCell findSelectedCell(ColumnViewer viewer, + ViewerCell currentSelectedCell, Event event) { + ViewerCell cell = internalFindSelectedCell(viewer, + currentSelectedCell, event); + if (cell != null) { + TableColumn t = AnnotatedPropertyTab.this.viewer.getTable().getColumn( + cell.getColumnIndex()); + AnnotatedPropertyTab.this.viewer.getTable().showColumn(t); + } + return cell; + } + }; + + TableViewerFocusCellManager focusCellManager = new TableViewerFocusCellManager( + viewer, new FocusCellOwnerDrawHighlighter(viewer)); + try { + Field f = focusCellManager.getClass().getSuperclass() + .getDeclaredField("navigationStrategy"); + f.setAccessible(true); + f.set(focusCellManager, nStrategy); + } catch (SecurityException e) { + e.printStackTrace(); + } catch (NoSuchFieldException e) { + e.printStackTrace(); + } catch (IllegalArgumentException e) { + e.printStackTrace(); + } catch (IllegalAccessException e) { + e.printStackTrace(); + } + ColumnViewerEditorActivationStrategy actSupport = new ColumnViewerEditorActivationStrategy( + viewer) { + protected boolean isEditorActivationEvent( + ColumnViewerEditorActivationEvent event) { + return event.eventType == ColumnViewerEditorActivationEvent.TRAVERSAL + || event.eventType == ColumnViewerEditorActivationEvent.MOUSE_DOUBLE_CLICK_SELECTION + || (event.eventType == ColumnViewerEditorActivationEvent.KEY_PRESSED && event.keyCode == SWT.CR) + || event.eventType == ColumnViewerEditorActivationEvent.PROGRAMMATIC; + } + }; + TableViewerEditor.create(viewer, focusCellManager, actSupport, + ColumnViewerEditor.TABBING_HORIZONTAL + | ColumnViewerEditor.TABBING_MOVE_TO_ROW_NEIGHBOR + | ColumnViewerEditor.TABBING_VERTICAL + | ColumnViewerEditor.KEYBOARD_ACTIVATION); + viewer.getColumnViewerEditor().addEditorActivationListener( + new ColumnViewerEditorActivationListener() { + public void afterEditorActivated( + ColumnViewerEditorActivationEvent event) { + } + + public void afterEditorDeactivated( + ColumnViewerEditorDeactivationEvent event) { + } + + public void beforeEditorActivated( + ColumnViewerEditorActivationEvent event) { + ViewerCell cell = (ViewerCell) event.getSource(); + viewer.getTable().showColumn( + viewer.getTable().getColumn(cell.getColumnIndex())); + } + + public void beforeEditorDeactivated( + ColumnViewerEditorDeactivationEvent event) { + } + }); + } + + + + + private IPropertyItem selectedItem = null; + private Set delayedUpdate = new HashSet(); + + + @Override + public void setInput(ISessionContext context, ISelection selection, + boolean force) { + Collection nodes = AdaptationUtils.adaptToCollection(selection, INode.class); + if (nodes.size() != 1) { + if (node != null) { + node.removeListener(this); + node = null; + } + return; + } + INode n = nodes.iterator().next(); + if (node != null) { + if (!node.equals(n)) { + node.removeListener(this); + setInput(n); + } + } else { + setInput(n); + } + } + + + + private void setInput(INode node) { + this.node = node; + this.node.addListener(this); + // resolve nodemap + INode n = node; + while (true) { + if (n == null) { + nodeMap = null; + break; + } + if (n instanceof NodeMapProvider) { + nodeMap = ((NodeMapProvider) n).getNodeMap(); + if (nodeMap != null) + break; + } + n = (IG3DNode)n.getParent(); + } + boolean readOnly = (node instanceof IStructuralNode && ((IStructuralNode)node).isPartOfInstantiatedModel() && !((IStructuralNode)node).isInstantiatedModelRoot()); + + resolvedItems.clear(); + manipulators.clear(); + for (IPropertyItem item : contibutedItems) { + if (item instanceof PropertyItem) { + resolvedItems.add((PropertyItem)item); + manipulators.put((PropertyItem)item, createManipulator((PropertyItem)item, node)); + } + else { + CompoundPropertyItem compound = (CompoundPropertyItem)item; + Map manipulators = createManipulators(compound, node); + for (PropertyItem i : manipulators.keySet()) { + resolvedItems.add(i); + this.manipulators.put(i, manipulators.get(i)); + } + } + } + + int valueCount = 0; + for (PropertyManipulator manipulator : manipulators.values()) { + if (valueCount < manipulator.getValueCount()) + valueCount = manipulator.getValueCount(); + } + for (int i = 0; i < valueCount; i++) { + TableViewerColumn value = new TableViewerColumn(viewer, SWT.LEFT); + //value.getColumn().setText("Value " + (i+1)); + value.getColumn().setText(""); + value.getColumn().setWidth(200); + valueColumns.add(value); + //value.setEditingSupport(new ) + } + + // create label providers + PropertyValueLabelProvider2 p = new PropertyValueLabelProvider2(this); + int index = 0; + for (TableViewerColumn c : valueColumns) { + c.setLabelProvider(p); + if (!readOnly) { + PropertyEditingSupport support = new PropertyEditingSupport(this, viewer, index++, nodeMap); + c.setEditingSupport(support); + } + } + Collections.sort(resolvedItems, new Comparator() { + @Override + public int compare(IPropertyItem o1, IPropertyItem o2) { + return o1.getName().compareTo(o2.getName()); + } + }); + viewer.getTable().setEnabled(!readOnly); + viewer.setInput(resolvedItems); + } + + @Override + public void requestFocus() { + viewer.getTable().forceFocus(); + } + + @Override + public void dispose() { + if (node != null) { + node.removeListener(this); + node = null; + } + + } + + @Override + public Control getControl() { + return viewer.getTable(); + } + + @Override + public ISelectionProvider getSelectionProvider() { + return null; + } + + @Override + public boolean isDisposed() { + return viewer.getTable().isDisposed(); + } + + @Override + public void nodeAdded(ParentNode node, + INode child, String rel) { + + } + + @Override + public void nodeRemoved(ParentNode node, + INode child, String rel) { + + } + + @Override + public void propertyChanged(INode node, final String id) { +// for (final PropertyItem item : items) { +// if (item.id.equals(id)) { +// Display.getDefault().asyncExec(new Runnable() { +// +// @Override +// public void run() { +// viewer.update(item, null); +// +// } +// }); +// } +// } + if (Thread.currentThread() == Display.getDefault().getThread()) { + if (viewer.getTable().isDisposed()) + return; + if (DEBUG)System.out.println("Viewer refresh " + id); + for (PropertyItem item : resolvedItems) + if (!item.equals(selectedItem)) + viewer.refresh(item); + if (selectedItem != null) + delayedUpdate.add(selectedItem); + } else if (!editing){ + // running delayed refresh when a cell editor is active would cancel cell editing. + Display.getDefault().asyncExec(new Runnable() { + @Override + public void run() { + if (viewer.getTable().isDisposed()) { + if (AnnotatedPropertyTab.this.node != null) + AnnotatedPropertyTab.this.node.removeListener(AnnotatedPropertyTab.this); + return; + } + if (DEBUG) System.out.println("Viewer threaded refresh " + id); + for (PropertyItem item : resolvedItems) + if (!item.equals(selectedItem)) + viewer.refresh(item); + if (selectedItem != null) + delayedUpdate.add(selectedItem); + + } + }); + } else { + for (PropertyItem item : resolvedItems) { + delayedUpdate.add(item); + } + } + + } + + + + @Override + public void updatePartName(Consumer updateCallback) { + if (node != null) + updateCallback.accept(node.toString()); + + } + + public PropertyManipulator getManipulator(PropertyItem item) { + return manipulators.get(item); + } + + private boolean editing = false; + + public void setEditing(boolean editing) { + this.editing = editing; + } + } + + + + private static class PropertyEditingSupport extends EditingSupport { + AnnotatedPropertyTab tab; + int index; + NodeMap nodeMap; + TableViewer viewer; + CellEditor editor; + + public PropertyEditingSupport(AnnotatedPropertyTab tab, TableViewer viewer, int index, NodeMap nodeMap) { + super(viewer); + this.tab = tab; + this.index = index; + this.viewer = viewer; + this.nodeMap = nodeMap; + } + + @Override + protected boolean canEdit(Object element) { + PropertyItem item = (PropertyItem)element; + if (tab.getManipulator(item).getValueCount() <= index) + return false; + if (item.setter == null) + return false; + if (getValue(element) == null) + return false; + return true; + } + + @Override + protected CellEditor getCellEditor(Object element) { + + if (tab.getManipulator((PropertyItem)element).getValueCount() <= index) + return null; + if (editor == null) + editor = new TextCellEditor(viewer.getTable(),SWT.NONE) { + @Override + public void activate() { + tab.setEditing(true); + } + + @Override + public void deactivate() { + super.deactivate(); + tab.setEditing(false); + } + }; + if (DEBUG)System.err.println("CELL EDITOR: " + element); + return editor; + } + + @Override + protected Object getValue(Object element) { + PropertyItem item = (PropertyItem)element; + PropertyManipulator manipulator = tab.getManipulator(item);//createManipulator(item, obj); + if (manipulator.getValueCount() <= index) + return null; + Object value = manipulator.getValue(index); + return value; + } + + @Override + protected void setValue(Object element, Object value) { + + PropertyItem item = (PropertyItem)element; + PropertyManipulator manipulator = tab.getManipulator(item);//createManipulator(item, obj); + if (manipulator.getValueCount() <= index) + throw new IllegalAccessError("Editing value in index " + index + " is not allowed."); + if (DEBUG)System.err.println("CELL SET VALUE: " + element + " " + value); + manipulator.setValue((String)value,index); + viewer.refresh(item); + nodeMap.commit("Set " + item.id + " value to " + value); + + } + + + + } + + private static class PropertyItemNameProvider extends CellLabelProvider { + + + @Override + public void update(ViewerCell cell) { + PropertyItem item = (PropertyItem)cell.getElement(); + + if (item.name.length() > 0) + cell.setText(item.name); + else + cell.setText(item.id); + + + } + } + + private static class PropertyValueLabelProvider2 extends CellLabelProvider { + AnnotatedPropertyTab tab; + //private Object object; + + public PropertyValueLabelProvider2(AnnotatedPropertyTab tab) { + this.tab = tab; + } + + @Override + public void update(ViewerCell cell) { + PropertyItem item = (PropertyItem)cell.getElement(); + int index = cell.getColumnIndex() -1; + PropertyManipulator manipulator = tab.getManipulator(item);//createManipulator(item, object); + if (manipulator.getValueCount() <= index) + return; + cell.setText(manipulator.getValue(index)); + } + } + + private static class PropertyItemContentsProvider implements IStructuredContentProvider { + @SuppressWarnings("unchecked") + @Override + public Object[] getElements(Object inputElement) { + List items = (List)inputElement; + return items.toArray(); + } + + @Override + public void dispose() { + + } + + @Override + public void inputChanged(Viewer viewer, Object oldInput, Object newInput) { + + } + } + + + + private static ViewerCell getNeighbor(ViewerCell currentCell, + int directionMask, boolean sameLevel) { + ViewerRow row; + if ((directionMask & ViewerCell.ABOVE) == ViewerCell.ABOVE) { + row = currentCell.getViewerRow().getNeighbor(ViewerRow.ABOVE, + sameLevel); + } else if ((directionMask & ViewerCell.BELOW) == ViewerCell.BELOW) { + row = currentCell.getViewerRow().getNeighbor(ViewerRow.BELOW, + sameLevel); + } else { + row = currentCell.getViewerRow(); + } + if (row != null) { + int columnIndex; + columnIndex = getVisualIndex(row, currentCell.getColumnIndex()); + int modifier = 0; + if ((directionMask & ViewerCell.LEFT) == ViewerCell.LEFT) { + modifier = -1; + } else if ((directionMask & ViewerCell.RIGHT) == ViewerCell.RIGHT) { + modifier = 1; + } + columnIndex += modifier; + if (columnIndex >= 0 && columnIndex < row.getColumnCount()) { + ViewerCell cell = getCellAtVisualIndex(row, columnIndex); + if (cell != null) { + while (cell != null + && columnIndex < row.getColumnCount() - 1 + && columnIndex > 0) { + if (isVisible(cell)) { + break; + } + columnIndex += modifier; + cell = getCellAtVisualIndex(row, columnIndex); + if (cell == null) { + break; + } + } + } + return cell; + } + } + return null; + } + + + + public static class TableViewerEditor extends ColumnViewerEditor { + /** + * This viewer's table editor. + */ + private TableEditor tableEditor; + private TableViewerFocusCellManager focusCellManager; + private int feature; + + /** + * @param viewer + * the viewer the editor is attached to + * @param focusCellManager + * the cell focus manager if one used or null + * @param editorActivationStrategy + * the strategy used to decide about the editor activation + * @param feature + * the feature mask + */ + TableViewerEditor(TableViewer viewer, + TableViewerFocusCellManager focusCellManager, + ColumnViewerEditorActivationStrategy editorActivationStrategy, + int feature) { + super(viewer, editorActivationStrategy, feature); + this.feature = feature; + tableEditor = new TableEditor(viewer.getTable()); + this.focusCellManager = focusCellManager; + } + + /** + * Create a customized editor with focusable cells + * + * @param viewer + * the viewer the editor is created for + * @param focusCellManager + * the cell focus manager if one needed else + * null + * @param editorActivationStrategy + * activation strategy to control if an editor activated + * @param feature + * bit mask controlling the editor + *
    + *
  • {@link ColumnViewerEditor#DEFAULT}
  • + *
  • {@link ColumnViewerEditor#TABBING_CYCLE_IN_ROW}
  • + *
  • {@link ColumnViewerEditor#TABBING_HORIZONTAL}
  • + *
  • + * {@link ColumnViewerEditor#TABBING_MOVE_TO_ROW_NEIGHBOR}
  • + *
  • {@link ColumnViewerEditor#TABBING_VERTICAL}
  • + *
+ * @see #create(TableViewer, ColumnViewerEditorActivationStrategy, int) + */ + public static void create(TableViewer viewer, + TableViewerFocusCellManager focusCellManager, + ColumnViewerEditorActivationStrategy editorActivationStrategy, + int feature) { + TableViewerEditor editor = new TableViewerEditor(viewer, + focusCellManager, editorActivationStrategy, feature); + viewer.setColumnViewerEditor(editor); + if (focusCellManager != null) { + try { + Method m = focusCellManager.getClass().getSuperclass() + .getDeclaredMethod("init"); + m.setAccessible(true); + m.invoke(focusCellManager); + } catch (SecurityException e) { + e.printStackTrace(); + } catch (IllegalArgumentException e) { + e.printStackTrace(); + } catch (IllegalAccessException e) { + e.printStackTrace(); + } catch (NoSuchMethodException e) { + e.printStackTrace(); + } catch (InvocationTargetException e) { + e.printStackTrace(); + } + // focusCellManager.init(); + } + } + + /** + * Create a customized editor whose activation process is customized + * + * @param viewer + * the viewer the editor is created for + * @param editorActivationStrategy + * activation strategy to control if an editor activated + * @param feature + * bit mask controlling the editor + *
    + *
  • {@link ColumnViewerEditor#DEFAULT}
  • + *
  • {@link ColumnViewerEditor#TABBING_CYCLE_IN_ROW}
  • + *
  • {@link ColumnViewerEditor#TABBING_HORIZONTAL}
  • + *
  • + * {@link ColumnViewerEditor#TABBING_MOVE_TO_ROW_NEIGHBOR}
  • + *
  • {@link ColumnViewerEditor#TABBING_VERTICAL}
  • + *
+ */ + public static void create(TableViewer viewer, + ColumnViewerEditorActivationStrategy editorActivationStrategy, + int feature) { + create(viewer, null, editorActivationStrategy, feature); + } + + protected void setEditor(Control w, Item item, int columnNumber) { + tableEditor.setEditor(w, (TableItem) item, columnNumber); + } + + protected void setLayoutData(LayoutData layoutData) { + tableEditor.grabHorizontal = layoutData.grabHorizontal; + tableEditor.horizontalAlignment = layoutData.horizontalAlignment; + tableEditor.minimumWidth = layoutData.minimumWidth; + } + + public ViewerCell getFocusCell() { + if (focusCellManager != null) { + return focusCellManager.getFocusCell(); + } + return super.getFocusCell(); + } + + protected void updateFocusCell(ViewerCell focusCell, + ColumnViewerEditorActivationEvent event) { + // Update the focus cell when we activated the editor with these 2 + // events + if (event.eventType == ColumnViewerEditorActivationEvent.PROGRAMMATIC + || event.eventType == ColumnViewerEditorActivationEvent.TRAVERSAL) { + if (focusCellManager != null) { + try { + if (DEBUG)System.err.println("FOCUS CELL: " + focusCell); + + Method m = AbstractTableViewer.class.getDeclaredMethod( + "getSelectionFromWidget"); + m.setAccessible(true); + @SuppressWarnings("rawtypes") + List l = (List) m.invoke(getViewer()); + if (focusCellManager != null) { + m = focusCellManager + .getClass() + .getSuperclass() + .getDeclaredMethod("setFocusCell", + new Class[] { ViewerCell.class }); + m.setAccessible(true); + m.invoke(focusCellManager, + new Object[] { focusCell }); + } + if (!l.contains(focusCell.getElement())) { + getViewer().setSelection( + new StructuredSelection(focusCell + .getElement())); + } + } catch (SecurityException e) { + e.printStackTrace(); + } catch (IllegalArgumentException e) { + e.printStackTrace(); + } catch (IllegalAccessException e) { + e.printStackTrace(); + } catch (NoSuchMethodException e) { + e.printStackTrace(); + } catch (InvocationTargetException e) { + e.printStackTrace(); + } + } + } + } + + protected void processTraverseEvent(int columnIndex, ViewerRow row, + TraverseEvent event) { + ViewerCell cell2edit = null; + if (event.detail == SWT.TRAVERSE_TAB_PREVIOUS) { + event.doit = false; + if ((event.stateMask & SWT.CTRL) == SWT.CTRL + && (feature & TABBING_VERTICAL) == TABBING_VERTICAL) { + cell2edit = searchCellAboveBelow(row, getViewer(), + columnIndex, true); + } else if ((feature & TABBING_HORIZONTAL) == TABBING_HORIZONTAL) { + cell2edit = searchPreviousCell(row, + row.getCell(columnIndex), row.getCell(columnIndex), + getViewer()); + } + } else if (event.detail == SWT.TRAVERSE_TAB_NEXT) { + event.doit = false; + if ((event.stateMask & SWT.CTRL) == SWT.CTRL + && (feature & TABBING_VERTICAL) == TABBING_VERTICAL) { + cell2edit = searchCellAboveBelow(row, getViewer(), + columnIndex, false); + } else if ((feature & TABBING_HORIZONTAL) == TABBING_HORIZONTAL) { + cell2edit = searchNextCell(row, row.getCell(columnIndex), + row.getCell(columnIndex), getViewer()); + } + } + if (DEBUG) System.err.println("NEXT CELL: " + cell2edit); + if (cell2edit != null) { + getViewer().getControl().setRedraw(false); + ColumnViewerEditorActivationEvent acEvent = new ColumnViewerEditorActivationEvent( + cell2edit, event); + try { + Method m = ColumnViewer.class + .getDeclaredMethod( + "triggerEditorActivationEvent", + new Class[] { ColumnViewerEditorActivationEvent.class }); + m.setAccessible(true); + m.invoke(getViewer(), new Object[] { acEvent }); + } catch (SecurityException e) { + e.printStackTrace(); + } catch (NoSuchMethodException e) { + e.printStackTrace(); + } catch (IllegalArgumentException e) { + e.printStackTrace(); + } catch (IllegalAccessException e) { + e.printStackTrace(); + } catch (InvocationTargetException e) { + e.printStackTrace(); + } + getViewer().getControl().setRedraw(true); + } + } + + private ViewerCell searchCellAboveBelow(ViewerRow row, + ColumnViewer viewer, int columnIndex, boolean above) { + ViewerCell rv = null; + ViewerRow newRow = null; + if (above) { + newRow = row.getNeighbor(ViewerRow.ABOVE, false); + } else { + newRow = row.getNeighbor(ViewerRow.BELOW, false); + } + try { + if (newRow != null) { + Method m = ColumnViewer.class.getDeclaredMethod( + "getViewerColumn", new Class[] { int.class }); + m.setAccessible(true); + ViewerColumn column = (ViewerColumn) m.invoke(viewer, + new Object[] { new Integer(columnIndex) }); + m = ViewerColumn.class.getDeclaredMethod( + "getEditingSupport"); + m.setAccessible(true); + EditingSupport es = (EditingSupport) m.invoke(column); + if (column != null && es != null) { + m = EditingSupport.class.getDeclaredMethod("canEdit", + new Class[] { Object.class }); + m.setAccessible(true); + Boolean b = (Boolean) m.invoke(es, + new Object[] { newRow.getItem().getData() }); + if (b.booleanValue()) { + rv = newRow.getCell(columnIndex); + } + } else { + rv = searchCellAboveBelow(newRow, viewer, columnIndex, + above); + } + } + } catch (Exception e) { + e.printStackTrace(); + } + return rv; + } + + private ViewerCell searchPreviousCell(ViewerRow row, + ViewerCell currentCell, ViewerCell originalCell, + ColumnViewer viewer) { + ViewerCell rv = null; + ViewerCell previousCell; + if (currentCell != null) { + previousCell = getNeighbor(currentCell, ViewerCell.LEFT, true); + } else { + if (row.getColumnCount() != 0) { + previousCell = row.getCell(getCreationIndex(row, + row.getColumnCount() - 1)); + } else { + previousCell = row.getCell(0); + } + } + // No endless loop + if (originalCell.equals(previousCell)) { + return null; + } + if (previousCell != null) { + if (isCellEditable(viewer, previousCell)) { + rv = previousCell; + } else { + rv = searchPreviousCell(row, previousCell, originalCell, + viewer); + } + } else { + if ((feature & TABBING_CYCLE_IN_ROW) == TABBING_CYCLE_IN_ROW) { + rv = searchPreviousCell(row, null, originalCell, viewer); + } else if ((feature & TABBING_MOVE_TO_ROW_NEIGHBOR) == TABBING_MOVE_TO_ROW_NEIGHBOR) { + ViewerRow rowAbove = row + .getNeighbor(ViewerRow.ABOVE, false); + if (rowAbove != null) { + rv = searchPreviousCell(rowAbove, null, originalCell, + viewer); + } + } + } + return rv; + } + + private ViewerCell searchNextCell(ViewerRow row, + ViewerCell currentCell, ViewerCell originalCell, + ColumnViewer viewer) { + ViewerCell rv = null; + ViewerCell nextCell; + if (currentCell != null) { + nextCell = getNeighbor(currentCell, ViewerCell.RIGHT, true); + } else { + nextCell = row.getCell(getCreationIndex(row, 0)); + } + // No endless loop + if (originalCell.equals(nextCell)) { + return null; + } + if (nextCell != null) { + if (isCellEditable(viewer, nextCell)) { + rv = nextCell; + } else { + rv = searchNextCell(row, nextCell, originalCell, viewer); + } + } else { + if ((feature & TABBING_CYCLE_IN_ROW) == TABBING_CYCLE_IN_ROW) { + rv = searchNextCell(row, null, originalCell, viewer); + } else if ((feature & TABBING_MOVE_TO_ROW_NEIGHBOR) == TABBING_MOVE_TO_ROW_NEIGHBOR) { + ViewerRow rowBelow = row + .getNeighbor(ViewerRow.BELOW, false); + if (rowBelow != null) { + rv = searchNextCell(rowBelow, null, originalCell, + viewer); + } + } + } + return rv; + } + + private boolean isCellEditable(ColumnViewer viewer, ViewerCell cell) { + try { + Method m = ColumnViewer.class.getDeclaredMethod( + "getViewerColumn", new Class[] { int.class }); + m.setAccessible(true); + ViewerColumn column = (ViewerColumn) m.invoke(viewer, + new Object[] { new Integer(cell.getColumnIndex()) }); + m = ViewerColumn.class.getDeclaredMethod("getEditingSupport"); + m.setAccessible(true); + EditingSupport es = (EditingSupport) m.invoke(column); + if (column != null && es != null) { + m = EditingSupport.class.getDeclaredMethod("canEdit", + new Class[] { Object.class }); + m.setAccessible(true); + // return true; + Boolean b = (Boolean) m.invoke(es, + new Object[] { cell.getElement() }); + return b.booleanValue(); + } + } catch (Exception e) { + e.printStackTrace(); + } + return false; + } + } + + // Reimplementation of ViewerCell-Methods + private static int getVisualIndex(ViewerRow row, int creationIndex) { + TableItem item = (TableItem) row.getItem(); + int[] order = item.getParent().getColumnOrder(); + for (int i = 0; i < order.length; i++) { + if (order[i] == creationIndex) { + return i; + } + } + return creationIndex; + } + + private static int getCreationIndex(ViewerRow row, int visualIndex) { + TableItem item = (TableItem) row.getItem(); + if (item != null && !item.isDisposed() /* + * && hasColumns() && + * isValidOrderIndex + * (visualIndex) + */) { + return item.getParent().getColumnOrder()[visualIndex]; + } + return visualIndex; + } + + private static ViewerCell getCellAtVisualIndex(ViewerRow row, + int visualIndex) { + return getCell(row, getCreationIndex(row, visualIndex)); + } + + private static boolean isVisible(ViewerCell cell) { + return getWidth(cell) > 0; + } + + private static int getWidth(ViewerCell cell) { + TableItem item = (TableItem) cell.getViewerRow().getItem(); + return item.getParent().getColumn(cell.getColumnIndex()).getWidth(); + } + + private static ViewerCell getCell(ViewerRow row, int index) { + return row.getCell(index); + } + + +}