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