]> gerrit.simantics Code Review - simantics/3d.git/commitdiff
Adding exact INode type as generic parameter to NodeMap interface 17/417/1
authorMarko Luukkainen <marko.luukkainen@vtt.fi>
Tue, 18 Apr 2017 10:46:51 +0000 (13:46 +0300)
committerMarko Luukkainen <marko.luukkainen@vtt.fi>
Tue, 18 Apr 2017 10:46:51 +0000 (13:46 +0300)
fixes #7143

Change-Id: Ieaca3070bf9c27bfbbb2252f7e7e1a99c3aee846

org.simantics.g3d.csg/src/org/simantics/g3d/csg/scenegraph2/CSGrootNode.java
org.simantics.g3d.vtk/src/org/simantics/g3d/vtk/common/AbstractVTKNodeMap.java
org.simantics.g3d.vtk/src/org/simantics/g3d/vtk/common/SelectionHighlighter.java
org.simantics.g3d.vtk/src/org/simantics/g3d/vtk/common/VTKNodeMap.java
org.simantics.g3d/src/org/simantics/g3d/math/MathTools.java
org.simantics.g3d/src/org/simantics/g3d/property/AnnotatedPropertyTabContributorFactory.java
org.simantics.g3d/src/org/simantics/g3d/scenegraph/NodeMap.java
org.simantics.g3d/src/org/simantics/g3d/scenegraph/NodeMapProvider.java
org.simantics.g3d/src/org/simantics/g3d/scenegraph/base/INode.java

index 58db64e71ab2e2a9e7c9f19449911f6ecd7ea118..d88b42ed66adbc77863f986c094c93315e3a7d6e 100644 (file)
-/*******************************************************************************\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.csg.scenegraph2;\r
-\r
-import java.util.Collection;\r
-import java.util.HashSet;\r
-import java.util.Set;\r
-import java.util.Stack;\r
-\r
-import javax.vecmath.Quat4d;\r
-import javax.vecmath.Vector3d;\r
-\r
-import org.simantics.g3d.csg.editor.CSGNodeMap;\r
-import org.simantics.g3d.csg.ontology.CSG;\r
-import org.simantics.g3d.math.MathTools;\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.NodeException;\r
-import org.simantics.g3d.scenegraph.base.ParentNode;\r
-import org.simantics.objmap.graph.annotations.GraphType;\r
-import org.simantics.objmap.graph.annotations.RelatedElementsAdd;\r
-import org.simantics.objmap.graph.annotations.RelatedElementsGet;\r
-import org.simantics.objmap.graph.annotations.RelatedElementsRem;\r
-\r
-import vtk.vtkProp;\r
-\r
-\r
-@GraphType(CSG.URIs.Model)\r
-public class CSGrootNode extends ParentNode<ICSGnode> implements IG3DNode, NodeMapProvider<vtkProp> {\r
-       \r
-       \r
-       private CSGNodeMap nodeMap;\r
-       \r
-       public void setNodeMap(CSGNodeMap nodeMap) {\r
-               this.nodeMap = nodeMap;\r
-       }\r
-       \r
-       @Override\r
-       public NodeMap<vtkProp> getNodeMap() {\r
-               return nodeMap;\r
-       }\r
-       \r
-       @Override\r
-       public ParentNode<?> getParent() {\r
-               return null;\r
-       }\r
-       \r
-       @Override\r
-       public ParentNode<?> getRootNode() {\r
-               return this;\r
-       }\r
-       \r
-       @RelatedElementsAdd(CSG.URIs.hasChildShape)\r
-       public void addChild(ICSGnode node) {\r
-               addNode("child",node);\r
-       }\r
-       \r
-       @RelatedElementsGet(CSG.URIs.hasChildShape)\r
-       public Collection<ICSGnode> getChild() {\r
-               return getNodes("child");\r
-       }\r
-       \r
-       @RelatedElementsRem(CSG.URIs.hasChildShape)\r
-       public void remChild(ICSGnode node) {\r
-               removeNode("child", node);\r
-       }\r
-       \r
-       public javax.vecmath.Quat4d getOrientation() {\r
-               return MathTools.getIdentityQuat();\r
-       };\r
-       \r
-       @Override\r
-       public Vector3d getPosition() {\r
-               return new Vector3d();\r
-       }\r
-       \r
-       @Override\r
-       public Quat4d getWorldOrientation() {\r
-               return MathTools.getIdentityQuat();\r
-       }\r
-       \r
-       @Override\r
-       public Vector3d getWorldPosition() {\r
-               return new Vector3d();\r
-       }\r
-       \r
-       @Override\r
-       public Quat4d getWorldOrientation(Quat4d localOrientation) {\r
-               return localOrientation;\r
-       }\r
-       \r
-       @Override\r
-       public Vector3d getWorldPosition(Vector3d localPosition) {\r
-               return localPosition;\r
-       }\r
-       \r
-       @Override\r
-       public Quat4d getLocalOrientation(Quat4d worldOrientation) {\r
-               return worldOrientation;\r
-       }\r
-       \r
-       @Override\r
-       public Vector3d getLocalPosition(Vector3d worldPosition) {\r
-               return worldPosition;\r
-       }\r
-       \r
-       @Override\r
-       public void setPosition(Vector3d position) {\r
-               throw new NodeException("Cannot set root node position");\r
-       }\r
-       \r
-       @Override\r
-       public void setOrientation(Quat4d orientation) {\r
-               throw new NodeException("Cannot set root node orientation");\r
-       }\r
-       \r
-       @Override\r
-       public void setWorldOrientation(Quat4d orientation) {\r
-               throw new NodeException("Cannot set root node orientation");\r
-       }\r
-       \r
-       @Override\r
-       public void setWorldPosition(Vector3d position) {\r
-               throw new NodeException("Cannot set root node orientation");\r
-       }\r
-       \r
-       public String getUniqueName(String prefix) {\r
-               Set<String> names = new HashSet<String>();\r
-               Stack<ICSGnode> nodes = new Stack<ICSGnode>();\r
-               nodes.addAll(getChild());\r
-               while (!nodes.isEmpty()) {\r
-                       ICSGnode n = nodes.pop();\r
-                       names.add(((ICSGnode)n).getName());\r
-                       if (n instanceof CSGparentNode) {\r
-                               nodes.addAll(((CSGparentNode)n).getChild());\r
-                               nodes.addAll(((CSGparentNode)n).getPrimaryChild());\r
-                               nodes.addAll(((CSGparentNode)n).getSecondaryChild());\r
-                       }\r
-               }\r
-               int i = 1;\r
-               while (true) {\r
-                       String genName = prefix + "_" + i;\r
-                       if (!names.contains(genName))\r
-                               return genName;\r
-                       i++;\r
-               }\r
-       }\r
-       \r
-\r
-       @Override\r
-       public Object getAdapter(Class adapter) {\r
-               if (NodeMap.class == adapter)\r
-                       return nodeMap;\r
-               return null;\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.csg.scenegraph2;
+
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Set;
+import java.util.Stack;
+
+import javax.vecmath.Quat4d;
+import javax.vecmath.Vector3d;
+
+import org.simantics.g3d.csg.editor.CSGNodeMap;
+import org.simantics.g3d.csg.ontology.CSG;
+import org.simantics.g3d.math.MathTools;
+import org.simantics.g3d.scenegraph.IG3DNode;
+import org.simantics.g3d.scenegraph.NodeMap;
+import org.simantics.g3d.scenegraph.NodeMapProvider;
+import org.simantics.g3d.scenegraph.base.NodeException;
+import org.simantics.g3d.scenegraph.base.ParentNode;
+import org.simantics.objmap.graph.annotations.GraphType;
+import org.simantics.objmap.graph.annotations.RelatedElementsAdd;
+import org.simantics.objmap.graph.annotations.RelatedElementsGet;
+import org.simantics.objmap.graph.annotations.RelatedElementsRem;
+
+import vtk.vtkProp;
+
+
+@GraphType(CSG.URIs.Model)
+public class CSGrootNode extends ParentNode<ICSGnode> implements IG3DNode, NodeMapProvider<vtkProp, ICSGnode> {
+       
+       
+       private CSGNodeMap nodeMap;
+       
+       public void setNodeMap(CSGNodeMap nodeMap) {
+               this.nodeMap = nodeMap;
+       }
+       
+       @Override
+       public NodeMap<vtkProp, ICSGnode> getNodeMap() {
+               return nodeMap;
+       }
+       
+       @Override
+       public ParentNode<?> getParent() {
+               return null;
+       }
+       
+       @Override
+       public ParentNode<?> getRootNode() {
+               return this;
+       }
+       
+       @RelatedElementsAdd(CSG.URIs.hasChildShape)
+       public void addChild(ICSGnode node) {
+               addNode("child",node);
+       }
+       
+       @RelatedElementsGet(CSG.URIs.hasChildShape)
+       public Collection<ICSGnode> getChild() {
+               return getNodes("child");
+       }
+       
+       @RelatedElementsRem(CSG.URIs.hasChildShape)
+       public void remChild(ICSGnode node) {
+               removeNode("child", node);
+       }
+       
+       public javax.vecmath.Quat4d getOrientation() {
+               return MathTools.getIdentityQuat();
+       };
+       
+       @Override
+       public Vector3d getPosition() {
+               return new Vector3d();
+       }
+       
+       @Override
+       public Quat4d getWorldOrientation() {
+               return MathTools.getIdentityQuat();
+       }
+       
+       @Override
+       public Vector3d getWorldPosition() {
+               return new Vector3d();
+       }
+       
+       @Override
+       public Quat4d getWorldOrientation(Quat4d localOrientation) {
+               return localOrientation;
+       }
+       
+       @Override
+       public Vector3d getWorldPosition(Vector3d localPosition) {
+               return localPosition;
+       }
+       
+       @Override
+       public Quat4d getLocalOrientation(Quat4d worldOrientation) {
+               return worldOrientation;
+       }
+       
+       @Override
+       public Vector3d getLocalPosition(Vector3d worldPosition) {
+               return worldPosition;
+       }
+       
+       @Override
+       public void setPosition(Vector3d position) {
+               throw new NodeException("Cannot set root node position");
+       }
+       
+       @Override
+       public void setOrientation(Quat4d orientation) {
+               throw new NodeException("Cannot set root node orientation");
+       }
+       
+       @Override
+       public void setWorldOrientation(Quat4d orientation) {
+               throw new NodeException("Cannot set root node orientation");
+       }
+       
+       @Override
+       public void setWorldPosition(Vector3d position) {
+               throw new NodeException("Cannot set root node orientation");
+       }
+       
+       public String getUniqueName(String prefix) {
+               Set<String> names = new HashSet<String>();
+               Stack<ICSGnode> nodes = new Stack<ICSGnode>();
+               nodes.addAll(getChild());
+               while (!nodes.isEmpty()) {
+                       ICSGnode n = nodes.pop();
+                       names.add(((ICSGnode)n).getName());
+                       if (n instanceof CSGparentNode) {
+                               nodes.addAll(((CSGparentNode)n).getChild());
+                               nodes.addAll(((CSGparentNode)n).getPrimaryChild());
+                               nodes.addAll(((CSGparentNode)n).getSecondaryChild());
+                       }
+               }
+               int i = 1;
+               while (true) {
+                       String genName = prefix + "_" + i;
+                       if (!names.contains(genName))
+                               return genName;
+                       i++;
+               }
+       }
+       
+
+       @Override
+       public Object getAdapter(Class adapter) {
+               if (NodeMap.class == adapter)
+                       return nodeMap;
+               return null;
+       }
+       
+
+}
index d9c4b5b1a35e9fe48f61deae7b493f032c7e8abb..8b04a7755b93cc6c79567fe4445c5644e51f2899 100644 (file)
-/*******************************************************************************\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.vtk.common;\r
-\r
-import java.util.ArrayList;\r
-import java.util.Collection;\r
-import java.util.HashMap;\r
-import java.util.HashSet;\r
-import java.util.List;\r
-import java.util.Map;\r
-import java.util.Set;\r
-import java.util.Stack;\r
-\r
-import org.simantics.db.ReadGraph;\r
-import org.simantics.db.Resource;\r
-import org.simantics.db.Session;\r
-import org.simantics.db.WriteGraph;\r
-import org.simantics.db.common.request.ReadRequest;\r
-import org.simantics.db.common.request.WriteRequest;\r
-import org.simantics.db.exception.DatabaseException;\r
-import org.simantics.g3d.ontology.G3D;\r
-import org.simantics.g3d.scenegraph.IG3DNode;\r
-import org.simantics.g3d.scenegraph.RenderListener;\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.objmap.graph.IMapping;\r
-import org.simantics.objmap.graph.IMappingListener;\r
-import org.simantics.utils.datastructures.Callback;\r
-import org.simantics.utils.datastructures.MapList;\r
-import org.simantics.utils.datastructures.MapSet;\r
-import org.simantics.utils.datastructures.Pair;\r
-import org.simantics.utils.ui.ExceptionUtils;\r
-\r
-import vtk.vtkProp;\r
-\r
-public abstract class AbstractVTKNodeMap<E extends INode> implements VTKNodeMap, IMappingListener, RenderListener, NodeListener{\r
-\r
-       private static final boolean DEBUG = false;\r
-       \r
-       protected Session session;\r
-       protected IMapping<Object,E> mapping;\r
-       protected InteractiveVtkPanel panel;\r
-       \r
-       protected MapList<E, vtkProp> nodeToActor = new MapList<E, vtkProp>();\r
-       protected Map<vtkProp,E> actorToNode = new HashMap<vtkProp, E>();\r
-\r
-       protected ParentNode<E> rootNode;\r
-       \r
-       public AbstractVTKNodeMap(Session session, IMapping<Object,E> mapping, InteractiveVtkPanel panel, ParentNode<E> rootNode) {\r
-               this.session = session;\r
-               this.mapping = mapping;\r
-               this.panel = panel;\r
-               this.rootNode = rootNode;\r
-               panel.addListener(this);\r
-               mapping.addMappingListener(this);\r
-               rootNode.addListener(this);\r
-       }\r
-       \r
-       \r
-       protected abstract void addActor(E node);\r
-       protected abstract void removeActor(E node);\r
-       protected abstract void updateActor(E node,Set<String> ids);\r
-       \r
-       public void repaint() {\r
-               panel.repaint();\r
-       }\r
-       \r
-       public void populate() {\r
-               for (E node : rootNode.getNodes()) {\r
-                       receiveAdd(node, node.getParentRel(),true);\r
-               }\r
-               repaint();\r
-       }\r
-       \r
-       @Override\r
-       public INode getNode(vtkProp prop) {\r
-               return actorToNode.get(prop);\r
-       }\r
-       \r
-       @SuppressWarnings("unchecked")\r
-       @Override\r
-       public Collection<vtkProp> getRenderObjects(INode node) {\r
-               return nodeToActor.getValues((E)node);\r
-       }\r
-       \r
-       @SuppressWarnings("unchecked")\r
-       @Override\r
-       public ParentNode<IG3DNode> getRootNode() {\r
-               return (ParentNode<IG3DNode>)rootNode;\r
-       }\r
-       \r
-       \r
-       \r
-       @Override\r
-       public boolean isChangeTracking() {\r
-               return changeTracking;\r
-       }\r
-       \r
-       @Override\r
-       public void setChangeTracking(boolean enabled) {\r
-               changeTracking = enabled;\r
-       }\r
-       \r
-       private boolean changeTracking = true;\r
-       \r
-       protected Object syncMutex = new Object(); \r
-       \r
-\r
-       private List<Pair<E,String>> added = new ArrayList<Pair<E,String>>();\r
-       private List<Pair<E,String>> removed = new ArrayList<Pair<E,String>>();\r
-       //private List<Pair<E,String>> updated = new ArrayList<Pair<E,String>>();\r
-       private MapSet<E, String> updated = new MapSet.Hash<E, String>();\r
-\r
-       private boolean rangeModified = false;\r
-       \r
-       @SuppressWarnings("unchecked")\r
-       @Override\r
-       public void updateRenderObjectsFor(INode node) {\r
-               List<vtkProp> toDelete = new ArrayList<vtkProp>();\r
-               for (vtkProp prop : nodeToActor.getValues((E)node)) {\r
-                       if (prop.GetVTKId() != 0) {\r
-                               panel.GetRenderer().RemoveActor(prop);\r
-                               //prop.Delete();\r
-                               toDelete.add(prop);\r
-                       }\r
-                       actorToNode.remove(prop);\r
-               }\r
-               nodeToActor.remove((E)node);\r
-               Collection<vtkProp> coll = getActors((E)node);\r
-               if (coll == null)\r
-                       return;\r
-               for (vtkProp prop : coll) {\r
-                       nodeToActor.add((E)node,prop);\r
-                       actorToNode.put(prop, (E)node);\r
-                       toDelete.remove(prop);\r
-               }\r
-               for (vtkProp p : toDelete)\r
-                       p.Delete();\r
-       }\r
-       \r
-       protected abstract  Collection<vtkProp> getActors(E node);\r
-       \r
-       @SuppressWarnings("unchecked")\r
-       private void receiveAdd(E node, String id, boolean db) {\r
-               if (DEBUG) System.out.println("receiveAdd " + node  + " " + id + " " + db);\r
-               synchronized (syncMutex) {\r
-                       for (Pair<E, String> n : added) {\r
-                               if (n.first.equals(node))\r
-                                       return;\r
-                       }\r
-                       if (changeTracking) {\r
-                               mapping.rangeModified((E)node.getParent());\r
-                       }\r
-                       added.add(new Pair<E, String>(node, id));\r
-                       rangeModified = true;\r
-               }\r
-               panel.repaint();\r
-       }\r
-       \r
-       @SuppressWarnings("unchecked")\r
-       private void receiveRemove(E node, String id, boolean db) {\r
-               if (DEBUG) System.out.println("receiveRemove " + node  + " " + id + " " + db);\r
-               synchronized (syncMutex) {\r
-                       for (Pair<E, String> n : removed) {\r
-                               if (n.first.equals(node))\r
-                                       return;\r
-                       }\r
-                       if (changeTracking && !db)\r
-                               mapping.rangeModified((E)node.getParent());\r
-                       removed.add(new Pair<E, String>(node, id));\r
-                       rangeModified = true;\r
-               }\r
-               panel.repaint();\r
-       }\r
-       \r
-       @SuppressWarnings("unchecked")\r
-       private void receiveUpdate(E node, String id, boolean db) {\r
-               if (DEBUG) System.out.println("receiveUpdate " + node  + " " + id + " " + db);\r
-               synchronized (syncMutex) {\r
-//                     for (Pair<E, String> n : updated) {\r
-//                             if (n.first.equals(node))\r
-//                                     return;\r
-//                     }\r
-                       if (changeTracking && !db)\r
-                               mapping.rangeModified(node);\r
-                       //updated.add(new Pair<E, String>(node, id));\r
-                       updated.add(node, id);\r
-                       rangeModified = true;\r
-               }\r
-               panel.repaint();\r
-       }\r
-       \r
-       private boolean graphUpdates = false;\r
-       private Set<E> graphModified = new HashSet<E>();\r
-       \r
-       private boolean requestCommit = false;\r
-       \r
-       @Override\r
-       public void commit() {\r
-               requestCommit = true;\r
-       }\r
-       \r
-       protected void doCommit() {\r
-               session.asyncRequest(new WriteRequest() {\r
-                       \r
-                       @Override\r
-                       public void perform(WriteGraph graph) throws DatabaseException {\r
-                               commit(graph);\r
-                       }\r
-                       \r
-               }, new Callback<DatabaseException>() {\r
-                       \r
-                       @Override\r
-                       public void run(DatabaseException parameter) {\r
-                               if (parameter != null)\r
-                                       ExceptionUtils.logAndShowError("Cannot commit editor changes", parameter);\r
-                       }\r
-               });\r
-       }\r
-       \r
-       protected void commit(WriteGraph graph) throws DatabaseException {\r
-               synchronized(syncMutex) {\r
-                       if (DEBUG) System.out.println("Commit");\r
-                       graphUpdates = true;\r
-                       mapping.updateDomain(graph);\r
-                       graphUpdates = false;\r
-               }\r
-       }\r
-       \r
-       @Override\r
-       public void domainModified() {\r
-               if (graphUpdates)\r
-                       return;\r
-               if (DEBUG)System.out.println("domainModified");\r
-               session.asyncRequest(new ReadRequest() {\r
-                       \r
-                       @SuppressWarnings("unchecked")\r
-                       @Override\r
-                       public void run(ReadGraph graph) throws DatabaseException {\r
-                               update(graph);\r
-                       }\r
-               });\r
-               \r
-       }\r
-       \r
-       protected void update(ReadGraph graph) throws DatabaseException {\r
-               synchronized (syncMutex) {\r
-                       graphUpdates = true;\r
-                       for (Object domainObject : mapping.getDomainModified()) {\r
-                               E rangeObject = mapping.get(domainObject);\r
-                               if (rangeObject != null)\r
-                                       graphModified.add(rangeObject);\r
-                       }\r
-                       mapping.updateRange(graph);\r
-                       graphModified.clear();\r
-                       graphUpdates = false;\r
-               }\r
-               \r
-               if (mapping.isRangeModified())\r
-                       commit();\r
-       }\r
-       \r
-       @Override\r
-       public void rangeModified() {\r
-               //System.out.println("rangeModified");\r
-\r
-       }\r
-       \r
-       @Override\r
-       public void postRender() {\r
-               // Commit changes if\r
-               // 1. Commit has been requested\r
-               // 2. There are no pending changes that should be processed in preRender() \r
-               if (requestCommit && !rangeModified) { // FIXME : not thread safe.\r
-                       requestCommit = false;\r
-                       doCommit();\r
-               }\r
-       }\r
-       \r
-       List<Pair<E, String>> rem = new ArrayList<Pair<E,String>>();\r
-       List<Pair<E, String>> add = new ArrayList<Pair<E,String>>();\r
-       MapSet<E, String> mod = new MapSet.Hash<E, String>();\r
-       Set<E> propagation = new HashSet<E>();\r
-       Stack<E> stack = new Stack<E>();\r
-       \r
-       \r
-       @Override\r
-       public synchronized void preRender() {\r
-               updateCycle();\r
-       }\r
-       \r
-       @SuppressWarnings("unchecked")\r
-       protected void updateCycle() {\r
-               rem.clear();\r
-               add.clear();\r
-               mod.clear();\r
-               propagation.clear();\r
-               \r
-               synchronized (syncMutex) {\r
-                       rem.addAll(removed);\r
-                       add.addAll(added);\r
-                       for (E e : updated.getKeys()) {\r
-                               for (String s : updated.getValues(e)) {\r
-                                       mod.add(e, s);\r
-                               }\r
-                       }\r
-                       \r
-                       removed.clear();\r
-                       added.clear();\r
-                       updated.clear();\r
-               }\r
-               \r
-               for (Pair<E, String> n : rem) {\r
-                       stopListening(n.first);\r
-                       removeActor(n.first);\r
-               \r
-               }\r
-               \r
-               for (Pair<E, String> n : add) {\r
-                       addActor(n.first);\r
-                       listen(n.first);\r
-               }\r
-               \r
-               for (E e : mod.getKeys()) {\r
-                       Set<String> ids = mod.getValues(e);\r
-                       if (ids.contains(G3D.URIs.hasPosition) || ids.contains(G3D.URIs.hasOrientation)) {\r
-                               if (!propagation.contains(e))\r
-                                       propagation.add(e);\r
-                       }\r
-               }\r
-\r
-               if (propagation.size() > 0) {\r
-                       stack.clear();\r
-                       stack.addAll(propagation);\r
-                       propagation.clear();\r
-                       while (!stack.isEmpty()) {\r
-                               E node = stack.pop();\r
-                               if (propagation.contains(node))\r
-                                       continue;\r
-                               propagation.add(node);\r
-                               for (NodeListener l : node.getListeners()) {\r
-                                       if (l == this) {\r
-                                               //changeTracking = false;\r
-                                               //l.propertyChanged(node, G3D.URIs.hasPosition);\r
-                                               //changeTracking = true;\r
-                                       } else {\r
-                                               l.propertyChanged(node, G3D.URIs.hasWorldPosition);\r
-                                       }\r
-                               }\r
-                               if (node instanceof ParentNode) {\r
-                                       stack.addAll(((ParentNode<E>)node).getNodes());\r
-                               }\r
-                       }\r
-               }\r
-               \r
-//             synchronized (syncMutex) {\r
-//                     rem.addAll(removed);\r
-//                     add.addAll(added);\r
-//                     //mod.addAll(updated);\r
-//                     for (E e : updated.getKeys()) {\r
-//                             for (String s : updated.getValues(e))\r
-//                                     mod.add(e, s);\r
-//                     }\r
-//                     \r
-//                     removed.clear();\r
-//                     added.clear();\r
-//                     updated.clear();\r
-//             }\r
-               \r
-               for (E e : mod.getKeys()) {\r
-                       Set<String> ids = mod.getValues(e);\r
-                       updateActor(e,ids);\r
-               }\r
-               \r
-               \r
-               for (Pair<E, String> n : rem) {\r
-                       for (NodeListener l : nodeListeners)\r
-                               l.nodeRemoved(null, n.first, n.second);\r
-               }\r
-               for (Pair<E, String> n : add) {\r
-                       for (NodeListener l : nodeListeners)\r
-                               l.nodeAdded(n.first.getParent(), n.first, n.second);\r
-               }\r
-//             for (Pair<E, String> n : mod) {\r
-//                     for (NodeListener l : nodeListeners)\r
-//                             l.propertyChanged(n.first, n.second);\r
-//             }\r
-               for (E e : mod.getKeys()) {\r
-                       for (NodeListener l : nodeListeners)\r
-                               for (String s : mod.getValues(e))\r
-                                       l.propertyChanged(e, s);\r
-               }\r
-               synchronized (syncMutex) {\r
-                       if (added.isEmpty() && removed.isEmpty() && updated.getKeys().size() == 0)\r
-                               rangeModified = false;\r
-               }\r
-       }\r
-       \r
-       @SuppressWarnings("unchecked")\r
-       private void listen(INode node) {\r
-               node.addListener(this);\r
-               if (node instanceof ParentNode<?>) {\r
-                       ParentNode<INode> parentNode = (ParentNode<INode>)node;\r
-                       for (INode n : parentNode.getNodes())\r
-                               listen(n);\r
-               }\r
-       }\r
-       \r
-       private void stopListening(INode node) {\r
-               node.removeListener(this);\r
-               if (node instanceof ParentNode<?>) {\r
-                       @SuppressWarnings("unchecked")\r
-                       ParentNode<INode> parentNode = (ParentNode<INode>)node;\r
-                       for (INode n : parentNode.getNodes())\r
-                               stopListening(n);\r
-               }\r
-       }\r
-       \r
-       @SuppressWarnings("unchecked")\r
-       @Override\r
-       public void propertyChanged(INode node, String id) {\r
-               //receiveUpdate((E)node, id, graphUpdates);\r
-               receiveUpdate((E)node, id, graphModified.contains(node));\r
-               \r
-       }\r
-       \r
-       @SuppressWarnings("unchecked")\r
-       @Override\r
-       public <T extends INode> void nodeAdded(ParentNode<T> node, INode child,\r
-                       String rel) {\r
-               if (DEBUG) System.out.println("Node added " + child + " parent " + node);\r
-               //receiveAdd((E)child, rel ,graphUpdates);\r
-               receiveAdd((E)child, rel ,graphModified.contains(node));\r
-               \r
-       }\r
-       \r
-       @SuppressWarnings("unchecked")\r
-       @Override\r
-       public <T extends INode> void nodeRemoved(ParentNode<T> node, INode child,\r
-                       String rel) {\r
-               if (DEBUG) System.out.println("Node removed " + child + " parent " + node);\r
-               //receiveRemove((E)child, rel, graphUpdates);\r
-               receiveRemove((E)child, rel, graphModified.contains(node));\r
-               \r
-               //FIXME : sometimes removed structural models cause ObjMap to add their children again.\r
-               //        removing the listener here prevents corruption of visual model, but better fix is needed.\r
-               stopListening(child);\r
-       }\r
-       \r
-       @Override\r
-       public void delete() {\r
-               changeTracking = false;\r
-               panel.removeListener(this);\r
-               mapping.removeMappingListener(this);\r
-\r
-               List<E> nodes = new ArrayList<E>(nodeToActor.getKeySize());\r
-               nodes.addAll(nodeToActor.getKeys());\r
-               for (E node : nodes) {\r
-                       node.removeListener(this);\r
-                       removeActor(node);\r
-                       node.cleanup();\r
-               }\r
-               for (vtkProp prop : actorToNode.keySet()) {\r
-                       if (prop.GetVTKId() != 0) \r
-                               prop.Delete();\r
-               }\r
-               actorToNode.clear();\r
-               nodeToActor.clear();\r
-               \r
-       }\r
-       \r
-       \r
-       private List<NodeListener> nodeListeners = new ArrayList<NodeListener>();\r
-       @Override\r
-       public void addListener(NodeListener listener) {\r
-               nodeListeners.add(listener);\r
-               \r
-       }\r
-       \r
-       @Override\r
-       public void removeListener(NodeListener listener) {\r
-               nodeListeners.remove(listener);\r
-               \r
-       }\r
-       \r
-       public IMapping<Object,E> getMapping() {\r
-               return mapping;\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.vtk.common;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.Stack;
+
+import org.simantics.db.ReadGraph;
+import org.simantics.db.Resource;
+import org.simantics.db.Session;
+import org.simantics.db.WriteGraph;
+import org.simantics.db.common.request.ReadRequest;
+import org.simantics.db.common.request.WriteRequest;
+import org.simantics.db.exception.DatabaseException;
+import org.simantics.g3d.ontology.G3D;
+import org.simantics.g3d.scenegraph.G3DNode;
+import org.simantics.g3d.scenegraph.IG3DNode;
+import org.simantics.g3d.scenegraph.RenderListener;
+import org.simantics.g3d.scenegraph.base.INode;
+import org.simantics.g3d.scenegraph.base.NodeListener;
+import org.simantics.g3d.scenegraph.base.ParentNode;
+import org.simantics.objmap.graph.IMapping;
+import org.simantics.objmap.graph.IMappingListener;
+import org.simantics.utils.datastructures.Callback;
+import org.simantics.utils.datastructures.MapList;
+import org.simantics.utils.datastructures.MapSet;
+import org.simantics.utils.datastructures.Pair;
+import org.simantics.utils.ui.ExceptionUtils;
+
+import vtk.vtkProp;
+
+public abstract class AbstractVTKNodeMap<E extends IG3DNode> implements VTKNodeMap<E>, IMappingListener, RenderListener, NodeListener{
+
+       private static final boolean DEBUG = false;
+       
+       protected Session session;
+       protected IMapping<Object,E> mapping;
+       protected InteractiveVtkPanel panel;
+       
+       protected MapList<E, vtkProp> nodeToActor = new MapList<E, vtkProp>();
+       protected Map<vtkProp,E> actorToNode = new HashMap<vtkProp, E>();
+
+       protected ParentNode<E> rootNode;
+       
+       public AbstractVTKNodeMap(Session session, IMapping<Object,E> mapping, InteractiveVtkPanel panel, ParentNode<E> rootNode) {
+               this.session = session;
+               this.mapping = mapping;
+               this.panel = panel;
+               this.rootNode = rootNode;
+               panel.addListener(this);
+               mapping.addMappingListener(this);
+               rootNode.addListener(this);
+       }
+       
+       
+       protected abstract void addActor(E node);
+       protected abstract void removeActor(E node);
+       protected abstract void updateActor(E node,Set<String> ids);
+       
+       public void repaint() {
+               panel.repaint();
+       }
+       
+       public void populate() {
+               for (E node : rootNode.getNodes()) {
+                       receiveAdd(node, node.getParentRel(),true);
+               }
+               repaint();
+       }
+       
+       @Override
+       public E getNode(vtkProp prop) {
+               return actorToNode.get(prop);
+       }
+       
+       @SuppressWarnings("unchecked")
+       @Override
+       public Collection<vtkProp> getRenderObjects(IG3DNode node) {
+               return nodeToActor.getValues((E)node);
+       }
+       
+       @SuppressWarnings("unchecked")
+       @Override
+       public ParentNode<E> getRootNode() {
+               return (ParentNode<E>)rootNode;
+       }
+       
+       
+       
+       @Override
+       public boolean isChangeTracking() {
+               return changeTracking;
+       }
+       
+       @Override
+       public void setChangeTracking(boolean enabled) {
+               changeTracking = enabled;
+       }
+       
+       private boolean changeTracking = true;
+       
+       protected Object syncMutex = new Object(); 
+       
+
+       private List<Pair<E,String>> added = new ArrayList<Pair<E,String>>();
+       private List<Pair<E,String>> removed = new ArrayList<Pair<E,String>>();
+       //private List<Pair<E,String>> updated = new ArrayList<Pair<E,String>>();
+       private MapSet<E, String> updated = new MapSet.Hash<E, String>();
+
+       private boolean rangeModified = false;
+       
+       @SuppressWarnings("unchecked")
+       @Override
+       public void updateRenderObjectsFor(IG3DNode node) {
+               List<vtkProp> toDelete = new ArrayList<vtkProp>();
+               for (vtkProp prop : nodeToActor.getValues((E)node)) {
+                       if (prop.GetVTKId() != 0) {
+                               panel.GetRenderer().RemoveActor(prop);
+                               //prop.Delete();
+                               toDelete.add(prop);
+                       }
+                       actorToNode.remove(prop);
+               }
+               nodeToActor.remove((E)node);
+               Collection<vtkProp> coll = getActors((E)node);
+               if (coll == null)
+                       return;
+               for (vtkProp prop : coll) {
+                       nodeToActor.add((E)node,prop);
+                       actorToNode.put(prop, (E)node);
+                       toDelete.remove(prop);
+               }
+               for (vtkProp p : toDelete)
+                       p.Delete();
+       }
+       
+       protected abstract  Collection<vtkProp> getActors(E node);
+       
+       @SuppressWarnings("unchecked")
+       private void receiveAdd(E node, String id, boolean db) {
+               if (DEBUG) System.out.println("receiveAdd " + node  + " " + id + " " + db);
+               synchronized (syncMutex) {
+                       for (Pair<E, String> n : added) {
+                               if (n.first.equals(node))
+                                       return;
+                       }
+                       if (changeTracking) {
+                               mapping.rangeModified((E)node.getParent());
+                       }
+                       added.add(new Pair<E, String>(node, id));
+                       rangeModified = true;
+               }
+               panel.repaint();
+       }
+       
+       @SuppressWarnings("unchecked")
+       private void receiveRemove(E node, String id, boolean db) {
+               if (DEBUG) System.out.println("receiveRemove " + node  + " " + id + " " + db);
+               synchronized (syncMutex) {
+                       for (Pair<E, String> n : removed) {
+                               if (n.first.equals(node))
+                                       return;
+                       }
+                       if (changeTracking && !db)
+                               mapping.rangeModified((E)node.getParent());
+                       removed.add(new Pair<E, String>(node, id));
+                       rangeModified = true;
+               }
+               panel.repaint();
+       }
+       
+       @SuppressWarnings("unchecked")
+       private void receiveUpdate(E node, String id, boolean db) {
+               if (DEBUG) System.out.println("receiveUpdate " + node  + " " + id + " " + db);
+               synchronized (syncMutex) {
+//                     for (Pair<E, String> n : updated) {
+//                             if (n.first.equals(node))
+//                                     return;
+//                     }
+                       if (changeTracking && !db)
+                               mapping.rangeModified(node);
+                       //updated.add(new Pair<E, String>(node, id));
+                       updated.add(node, id);
+                       rangeModified = true;
+               }
+               panel.repaint();
+       }
+       
+       private boolean graphUpdates = false;
+       private Set<E> graphModified = new HashSet<E>();
+       
+       private boolean requestCommit = false;
+       
+       @Override
+       public void commit() {
+               requestCommit = true;
+       }
+       
+       protected void doCommit() {
+               session.asyncRequest(new WriteRequest() {
+                       
+                       @Override
+                       public void perform(WriteGraph graph) throws DatabaseException {
+                               commit(graph);
+                       }
+                       
+               }, new Callback<DatabaseException>() {
+                       
+                       @Override
+                       public void run(DatabaseException parameter) {
+                               if (parameter != null)
+                                       ExceptionUtils.logAndShowError("Cannot commit editor changes", parameter);
+                       }
+               });
+       }
+       
+       protected void commit(WriteGraph graph) throws DatabaseException {
+               synchronized(syncMutex) {
+                       if (DEBUG) System.out.println("Commit");
+                       graphUpdates = true;
+                       mapping.updateDomain(graph);
+                       graphUpdates = false;
+               }
+       }
+       
+       @Override
+       public void domainModified() {
+               if (graphUpdates)
+                       return;
+               if (DEBUG)System.out.println("domainModified");
+               session.asyncRequest(new ReadRequest() {
+                       
+                       @SuppressWarnings("unchecked")
+                       @Override
+                       public void run(ReadGraph graph) throws DatabaseException {
+                               update(graph);
+                       }
+               });
+               
+       }
+       
+       protected void update(ReadGraph graph) throws DatabaseException {
+               synchronized (syncMutex) {
+                       graphUpdates = true;
+                       for (Object domainObject : mapping.getDomainModified()) {
+                               E rangeObject = mapping.get(domainObject);
+                               if (rangeObject != null)
+                                       graphModified.add(rangeObject);
+                       }
+                       mapping.updateRange(graph);
+                       graphModified.clear();
+                       graphUpdates = false;
+               }
+               
+               if (mapping.isRangeModified())
+                       commit();
+       }
+       
+       @Override
+       public void rangeModified() {
+               //System.out.println("rangeModified");
+
+       }
+       
+       @Override
+       public void postRender() {
+               // Commit changes if
+               // 1. Commit has been requested
+               // 2. There are no pending changes that should be processed in preRender() 
+               if (requestCommit && !rangeModified) { // FIXME : not thread safe.
+                       requestCommit = false;
+                       doCommit();
+               }
+       }
+       
+       List<Pair<E, String>> rem = new ArrayList<Pair<E,String>>();
+       List<Pair<E, String>> add = new ArrayList<Pair<E,String>>();
+       MapSet<E, String> mod = new MapSet.Hash<E, String>();
+       Set<E> propagation = new HashSet<E>();
+       Stack<E> stack = new Stack<E>();
+       
+       
+       @Override
+       public synchronized void preRender() {
+               updateCycle();
+       }
+       
+       @SuppressWarnings("unchecked")
+       protected void updateCycle() {
+               rem.clear();
+               add.clear();
+               mod.clear();
+               propagation.clear();
+               
+               synchronized (syncMutex) {
+                       rem.addAll(removed);
+                       add.addAll(added);
+                       for (E e : updated.getKeys()) {
+                               for (String s : updated.getValues(e)) {
+                                       mod.add(e, s);
+                               }
+                       }
+                       
+                       removed.clear();
+                       added.clear();
+                       updated.clear();
+               }
+               
+               for (Pair<E, String> n : rem) {
+                       stopListening(n.first);
+                       removeActor(n.first);
+               
+               }
+               
+               for (Pair<E, String> n : add) {
+                       addActor(n.first);
+                       listen(n.first);
+               }
+               
+               for (E e : mod.getKeys()) {
+                       Set<String> ids = mod.getValues(e);
+                       if (ids.contains(G3D.URIs.hasPosition) || ids.contains(G3D.URIs.hasOrientation)) {
+                               if (!propagation.contains(e))
+                                       propagation.add(e);
+                       }
+               }
+
+               if (propagation.size() > 0) {
+                       stack.clear();
+                       stack.addAll(propagation);
+                       propagation.clear();
+                       while (!stack.isEmpty()) {
+                               E node = stack.pop();
+                               if (propagation.contains(node))
+                                       continue;
+                               propagation.add(node);
+                               for (NodeListener l : node.getListeners()) {
+                                       if (l == this) {
+                                               //changeTracking = false;
+                                               //l.propertyChanged(node, G3D.URIs.hasPosition);
+                                               //changeTracking = true;
+                                       } else {
+                                               l.propertyChanged(node, G3D.URIs.hasWorldPosition);
+                                       }
+                               }
+                               if (node instanceof ParentNode) {
+                                       stack.addAll(((ParentNode<E>)node).getNodes());
+                               }
+                       }
+               }
+               
+//             synchronized (syncMutex) {
+//                     rem.addAll(removed);
+//                     add.addAll(added);
+//                     //mod.addAll(updated);
+//                     for (E e : updated.getKeys()) {
+//                             for (String s : updated.getValues(e))
+//                                     mod.add(e, s);
+//                     }
+//                     
+//                     removed.clear();
+//                     added.clear();
+//                     updated.clear();
+//             }
+               
+               for (E e : mod.getKeys()) {
+                       Set<String> ids = mod.getValues(e);
+                       updateActor(e,ids);
+               }
+               
+               
+               for (Pair<E, String> n : rem) {
+                       for (NodeListener l : nodeListeners)
+                               l.nodeRemoved(null, n.first, n.second);
+               }
+               for (Pair<E, String> n : add) {
+                       for (NodeListener l : nodeListeners)
+                               l.nodeAdded(n.first.getParent(), n.first, n.second);
+               }
+//             for (Pair<E, String> n : mod) {
+//                     for (NodeListener l : nodeListeners)
+//                             l.propertyChanged(n.first, n.second);
+//             }
+               for (E e : mod.getKeys()) {
+                       for (NodeListener l : nodeListeners)
+                               for (String s : mod.getValues(e))
+                                       l.propertyChanged(e, s);
+               }
+               synchronized (syncMutex) {
+                       if (added.isEmpty() && removed.isEmpty() && updated.getKeys().size() == 0)
+                               rangeModified = false;
+               }
+       }
+       
+       @SuppressWarnings("unchecked")
+       private void listen(INode node) {
+               node.addListener(this);
+               if (node instanceof ParentNode<?>) {
+                       ParentNode<INode> parentNode = (ParentNode<INode>)node;
+                       for (INode n : parentNode.getNodes())
+                               listen(n);
+               }
+       }
+       
+       private void stopListening(INode node) {
+               node.removeListener(this);
+               if (node instanceof ParentNode<?>) {
+                       @SuppressWarnings("unchecked")
+                       ParentNode<INode> parentNode = (ParentNode<INode>)node;
+                       for (INode n : parentNode.getNodes())
+                               stopListening(n);
+               }
+       }
+       
+       @SuppressWarnings("unchecked")
+       @Override
+       public void propertyChanged(INode node, String id) {
+               //receiveUpdate((E)node, id, graphUpdates);
+               receiveUpdate((E)node, id, graphModified.contains(node));
+               
+       }
+       
+       @SuppressWarnings("unchecked")
+       @Override
+       public <T extends INode> void nodeAdded(ParentNode<T> node, INode child,
+                       String rel) {
+               if (DEBUG) System.out.println("Node added " + child + " parent " + node);
+               //receiveAdd((E)child, rel ,graphUpdates);
+               receiveAdd((E)child, rel ,graphModified.contains(node));
+               
+       }
+       
+       @SuppressWarnings("unchecked")
+       @Override
+       public <T extends INode> void nodeRemoved(ParentNode<T> node, INode child,
+                       String rel) {
+               if (DEBUG) System.out.println("Node removed " + child + " parent " + node);
+               //receiveRemove((E)child, rel, graphUpdates);
+               receiveRemove((E)child, rel, graphModified.contains(node));
+               
+               //FIXME : sometimes removed structural models cause ObjMap to add their children again.
+               //        removing the listener here prevents corruption of visual model, but better fix is needed.
+               stopListening(child);
+       }
+       
+       @Override
+       public void delete() {
+               changeTracking = false;
+               panel.removeListener(this);
+               mapping.removeMappingListener(this);
+
+               List<E> nodes = new ArrayList<E>(nodeToActor.getKeySize());
+               nodes.addAll(nodeToActor.getKeys());
+               for (E node : nodes) {
+                       node.removeListener(this);
+                       removeActor(node);
+                       node.cleanup();
+               }
+               for (vtkProp prop : actorToNode.keySet()) {
+                       if (prop.GetVTKId() != 0) 
+                               prop.Delete();
+               }
+               actorToNode.clear();
+               nodeToActor.clear();
+               
+       }
+       
+       
+       private List<NodeListener> nodeListeners = new ArrayList<NodeListener>();
+       @Override
+       public void addListener(NodeListener listener) {
+               nodeListeners.add(listener);
+               
+       }
+       
+       @Override
+       public void removeListener(NodeListener listener) {
+               nodeListeners.remove(listener);
+               
+       }
+       
+       public IMapping<Object,E> getMapping() {
+               return mapping;
+       }
+       
+       
+}
index 2d5f8fbe7cf1c20e9718d15c1c1cb57b171f42cd..95ba7aee2ef852e827a1070aa3c9dda48c15405f 100644 (file)
-/*******************************************************************************\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.vtk.common;\r
-\r
-import java.util.ArrayList;\r
-import java.util.Collection;\r
-import java.util.List;\r
-\r
-import org.eclipse.jface.viewers.ISelection;\r
-import org.eclipse.jface.viewers.ISelectionChangedListener;\r
-import org.eclipse.jface.viewers.SelectionChangedEvent;\r
-import org.simantics.g3d.scenegraph.IG3DNode;\r
-import org.simantics.g3d.scenegraph.NodeHighlighter;\r
-import org.simantics.g3d.scenegraph.NodeHighlighter.HighlightEventType;\r
-import org.simantics.g3d.scenegraph.NodeHighlighter.HighlightObjectType;\r
-import org.simantics.g3d.scenegraph.base.INode;\r
-import org.simantics.g3d.tools.AdaptationUtils;\r
-import org.simantics.utils.threads.AWTThread;\r
-import org.simantics.utils.threads.ThreadUtils;\r
-\r
-import vtk.vtkActor;\r
-import vtk.vtkAlgorithm;\r
-import vtk.vtkAlgorithmOutput;\r
-import vtk.vtkFeatureEdges;\r
-import vtk.vtkMapper;\r
-import vtk.vtkPanel;\r
-import vtk.vtkProp;\r
-import vtk.vtkProperty;\r
-\r
-public class SelectionHighlighter implements ISelectionChangedListener{\r
-\r
-       \r
-       \r
-       vtkPanel panel;\r
-       VTKNodeMap nodeMap;\r
-       \r
-       List<IG3DNode> selectedNodes = new ArrayList<IG3DNode>();\r
-       List<vtkActor> selectedActors = new ArrayList<vtkActor>();\r
-       \r
-       HighlightObjectType type = HighlightObjectType.Node;\r
-       \r
-       public SelectionHighlighter(vtkPanel panel, VTKNodeMap nodeMap) {\r
-               this.panel = panel;\r
-               this.nodeMap = nodeMap;\r
-       }\r
-       \r
-       @Override\r
-       public void selectionChanged(SelectionChangedEvent event) {\r
-               final ISelection s = event.getSelection();\r
-               \r
-               if (Thread.currentThread().equals(AWTThread.getThreadAccess().getThread()))\r
-                       highlight(s);\r
-               else {\r
-                       ThreadUtils.asyncExec(AWTThread.getThreadAccess(), new Runnable() {\r
-                               @Override\r
-                               public void run() {\r
-                                       highlight(s);\r
-                                       //System.out.println(this.getClass().getName() + " highlight ");\r
-                                       panel.Render();\r
-                                       //panel.repaint();\r
-                               }\r
-                       });\r
-               }\r
-                       \r
-       }\r
-       \r
-       protected void hilight(IG3DNode node, HighlightEventType type) {\r
-               if (node instanceof NodeHighlighter) {\r
-                       ((NodeHighlighter)node).highlight(type);\r
-                       return;\r
-               }\r
-               if (type == HighlightEventType.Selection) {\r
-                       setSelectedColor(node); \r
-               } else if (type == HighlightEventType.ClearSelection) {\r
-                       setDefaultColor(node);\r
-               }\r
-       }\r
-       \r
-       protected void hilight(vtkActor actor, HighlightEventType type) {\r
-               if (type == HighlightEventType.Selection) {\r
-                       setColor(actor,false,new double[]{1,0,0});\r
-                       setColor(actor,true,new double[]{1,0,1});\r
-               } else if (type == HighlightEventType.ClearSelection) {\r
-                       setColor(actor,false,new double[]{1,1,0});\r
-                       setColor(actor,true,new double[]{0,0,0});\r
-               }\r
-       }\r
-       \r
-       protected void highlight(ISelection s) {\r
-               highlight(s, HighlightEventType.Selection, HighlightEventType.ClearSelection);\r
-       }\r
-       \r
-       protected void highlight(ISelection s, HighlightEventType apply, HighlightEventType clear) {\r
-       \r
-               boolean changed = false;\r
-               if (type == HighlightObjectType.Node) {\r
-                       Collection<IG3DNode> currentSelectedNodes = AdaptationUtils.adaptToCollection(s,IG3DNode.class);//getSelectedNodes(currentSelectedActors);\r
-                       if (currentSelectedNodes.size() == 0) {\r
-                               Collection<vtkProp> currentSelectedActors = AdaptationUtils.adaptToCollection(s, vtkProp.class);\r
-                               currentSelectedNodes = getSelectedNodes(currentSelectedActors);\r
-                       }\r
-                       for (IG3DNode node : selectedNodes) {\r
-                               if (!currentSelectedNodes.contains(node)) {\r
-                                       hilight(node, clear);\r
-                                       changed = true;\r
-                               }\r
-                       }\r
-                       for (IG3DNode node : currentSelectedNodes) {\r
-                               if (!selectedNodes.contains(node)) {\r
-                                       hilight(node, apply);\r
-                                       changed = true;\r
-                               }\r
-                       }\r
-                       selectedNodes.clear();\r
-                       selectedNodes.addAll(currentSelectedNodes);\r
-                       //selectedNodes = currentSelectedNodes;\r
-                       \r
-               } else {\r
-                       \r
-                       Collection<vtkActor> currentSelectedActors = AdaptationUtils.adaptToCollection(s, vtkActor.class);\r
-                       \r
-                       for (vtkActor act : selectedActors) {\r
-                               if (!currentSelectedActors.contains(act)) {\r
-                                       hilight(act,clear);\r
-                                       changed = true;\r
-                               }\r
-                       }\r
-                       for (vtkActor act : currentSelectedActors) {\r
-                               if (!selectedActors.contains(act)) {\r
-                                       hilight(act,apply);\r
-                                       changed = true;\r
-                               }\r
-                       }\r
-                       selectedActors.clear();\r
-                       selectedActors.addAll(currentSelectedActors);\r
-               }\r
-               if (changed) {\r
-                       panel.repaint();\r
-               }\r
-       }\r
-       \r
-       protected List<IG3DNode> getSelectedNodes(Collection<vtkProp> selectedActors) {\r
-               List<IG3DNode> currentSelectedNodes = new ArrayList<IG3DNode>();\r
-               \r
-               for (vtkProp a : selectedActors) {\r
-                       INode node = nodeMap.getNode((vtkProp)a);\r
-                       if (node == null || !(node instanceof IG3DNode))\r
-                               continue;\r
-                       if (!currentSelectedNodes.contains(node))\r
-                               currentSelectedNodes.add((IG3DNode)node);\r
-               }\r
-               return currentSelectedNodes;\r
-       }\r
-       \r
-       protected void setDefaultColor(IG3DNode node) {\r
-               double color[] = new double[]{1,1,0};\r
-               setColor(node, false, color);\r
-       }\r
-       \r
-       protected void setSelectedColor(IG3DNode node) {\r
-               double color[] = new double[]{1,0,0};\r
-               setColor(node, false, color);\r
-       }\r
-       \r
-       \r
-       protected void setColor(IG3DNode node, boolean edge, double color[]) {\r
-               for (vtkProp prop : nodeMap.getRenderObjects(node)) {\r
-                       if (prop instanceof vtkActor) {\r
-                               vtkActor act = (vtkActor)prop;\r
-                               setColor(act, edge, color);\r
-                       }\r
-               }\r
-       }\r
-       \r
-       protected void setColor(vtkActor act, boolean edge, double color[]) {\r
-               \r
-               vtkMapper mapper = act.GetMapper();\r
-               vtkAlgorithmOutput out = mapper.GetInputConnection(0, 0);\r
-               vtkAlgorithm producer = out.GetProducer();\r
-               boolean isEdge = (producer instanceof vtkFeatureEdges);\r
-               producer.Delete();\r
-               if (isEdge == edge) {\r
-                       vtkProperty property = act.GetProperty();\r
-                       property.SetColor(color);\r
-                       property.Delete();\r
-               }\r
-               out.Delete();\r
-               mapper.Delete();\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.vtk.common;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.jface.viewers.ISelectionChangedListener;
+import org.eclipse.jface.viewers.SelectionChangedEvent;
+import org.simantics.g3d.scenegraph.IG3DNode;
+import org.simantics.g3d.scenegraph.NodeHighlighter;
+import org.simantics.g3d.scenegraph.NodeHighlighter.HighlightEventType;
+import org.simantics.g3d.scenegraph.NodeHighlighter.HighlightObjectType;
+import org.simantics.g3d.scenegraph.base.INode;
+import org.simantics.g3d.tools.AdaptationUtils;
+import org.simantics.utils.threads.AWTThread;
+import org.simantics.utils.threads.ThreadUtils;
+
+import vtk.vtkActor;
+import vtk.vtkAlgorithm;
+import vtk.vtkAlgorithmOutput;
+import vtk.vtkFeatureEdges;
+import vtk.vtkMapper;
+import vtk.vtkPanel;
+import vtk.vtkProp;
+import vtk.vtkProperty;
+
+public class SelectionHighlighter<E extends IG3DNode> implements ISelectionChangedListener{
+
+       
+       
+       vtkPanel panel;
+       VTKNodeMap<E> nodeMap;
+       
+       List<IG3DNode> selectedNodes = new ArrayList<IG3DNode>();
+       List<vtkActor> selectedActors = new ArrayList<vtkActor>();
+       
+       HighlightObjectType type = HighlightObjectType.Node;
+       
+       public SelectionHighlighter(vtkPanel panel, VTKNodeMap<E> nodeMap) {
+               this.panel = panel;
+               this.nodeMap = nodeMap;
+       }
+       
+       @Override
+       public void selectionChanged(SelectionChangedEvent event) {
+               final ISelection s = event.getSelection();
+               
+               if (Thread.currentThread().equals(AWTThread.getThreadAccess().getThread()))
+                       highlight(s);
+               else {
+                       ThreadUtils.asyncExec(AWTThread.getThreadAccess(), new Runnable() {
+                               @Override
+                               public void run() {
+                                       highlight(s);
+                                       //System.out.println(this.getClass().getName() + " highlight ");
+                                       panel.Render();
+                                       //panel.repaint();
+                               }
+                       });
+               }
+                       
+       }
+       
+       protected void hilight(E node, HighlightEventType type) {
+               if (node instanceof NodeHighlighter) {
+                       ((NodeHighlighter)node).highlight(type);
+                       return;
+               }
+               if (type == HighlightEventType.Selection) {
+                       setSelectedColor(node); 
+               } else if (type == HighlightEventType.ClearSelection) {
+                       setDefaultColor(node);
+               }
+       }
+       
+       protected void hilight(vtkActor actor, HighlightEventType type) {
+               if (type == HighlightEventType.Selection) {
+                       setColor(actor,false,new double[]{1,0,0});
+                       setColor(actor,true,new double[]{1,0,1});
+               } else if (type == HighlightEventType.ClearSelection) {
+                       setColor(actor,false,new double[]{1,1,0});
+                       setColor(actor,true,new double[]{0,0,0});
+               }
+       }
+       
+       protected void highlight(ISelection s) {
+               highlight(s, HighlightEventType.Selection, HighlightEventType.ClearSelection);
+       }
+       
+       protected void highlight(ISelection s, HighlightEventType apply, HighlightEventType clear) {
+       
+               boolean changed = false;
+               if (type == HighlightObjectType.Node) {
+                       Collection<IG3DNode> currentSelectedNodes = AdaptationUtils.adaptToCollection(s,IG3DNode.class);//getSelectedNodes(currentSelectedActors);
+                       if (currentSelectedNodes.size() == 0) {
+                               Collection<vtkProp> currentSelectedActors = AdaptationUtils.adaptToCollection(s, vtkProp.class);
+                               currentSelectedNodes = getSelectedNodes(currentSelectedActors);
+                       }
+                       for (IG3DNode node : selectedNodes) {
+                               if (!currentSelectedNodes.contains(node)) {
+                                       hilight((E)node, clear);
+                                       changed = true;
+                               }
+                       }
+                       for (IG3DNode node : currentSelectedNodes) {
+                               if (!selectedNodes.contains(node)) {
+                                       hilight((E)node, apply);
+                                       changed = true;
+                               }
+                       }
+                       selectedNodes.clear();
+                       selectedNodes.addAll(currentSelectedNodes);
+                       //selectedNodes = currentSelectedNodes;
+                       
+               } else {
+                       
+                       Collection<vtkActor> currentSelectedActors = AdaptationUtils.adaptToCollection(s, vtkActor.class);
+                       
+                       for (vtkActor act : selectedActors) {
+                               if (!currentSelectedActors.contains(act)) {
+                                       hilight(act,clear);
+                                       changed = true;
+                               }
+                       }
+                       for (vtkActor act : currentSelectedActors) {
+                               if (!selectedActors.contains(act)) {
+                                       hilight(act,apply);
+                                       changed = true;
+                               }
+                       }
+                       selectedActors.clear();
+                       selectedActors.addAll(currentSelectedActors);
+               }
+               if (changed) {
+                       panel.repaint();
+               }
+       }
+       
+       protected List<IG3DNode> getSelectedNodes(Collection<vtkProp> selectedActors) {
+               List<IG3DNode> currentSelectedNodes = new ArrayList<IG3DNode>();
+               
+               for (vtkProp a : selectedActors) {
+                       INode node = nodeMap.getNode((vtkProp)a);
+                       if (node == null || !(node instanceof IG3DNode))
+                               continue;
+                       if (!currentSelectedNodes.contains(node))
+                               currentSelectedNodes.add((IG3DNode)node);
+               }
+               return currentSelectedNodes;
+       }
+       
+       protected void setDefaultColor(E node) {
+               double color[] = new double[]{1,1,0};
+               setColor(node, false, color);
+       }
+       
+       protected void setSelectedColor(E node) {
+               double color[] = new double[]{1,0,0};
+               setColor(node, false, color);
+       }
+       
+       
+       protected void setColor(E node, boolean edge, double color[]) {
+               for (vtkProp prop : nodeMap.getRenderObjects(node)) {
+                       if (prop instanceof vtkActor) {
+                               vtkActor act = (vtkActor)prop;
+                               setColor(act, edge, color);
+                       }
+               }
+       }
+       
+       protected void setColor(vtkActor act, boolean edge, double color[]) {
+               
+               vtkMapper mapper = act.GetMapper();
+               vtkAlgorithmOutput out = mapper.GetInputConnection(0, 0);
+               vtkAlgorithm producer = out.GetProducer();
+               boolean isEdge = (producer instanceof vtkFeatureEdges);
+               producer.Delete();
+               if (isEdge == edge) {
+                       vtkProperty property = act.GetProperty();
+                       property.SetColor(color);
+                       property.Delete();
+               }
+               out.Delete();
+               mapper.Delete();
+       }
+}
index 81ed0ba15f6ab66e86a55116d04eef837bf0cd64..e72ea80808af52a35d3a303b392d3c24834bb9a5 100644 (file)
@@ -1,22 +1,24 @@
-/*******************************************************************************\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.vtk.common;\r
-\r
-import org.simantics.g3d.scenegraph.NodeMap;\r
-\r
-import vtk.vtkProp;\r
-\r
-public interface VTKNodeMap extends NodeMap<vtkProp>{\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.vtk.common;
+
+import org.simantics.g3d.scenegraph.IG3DNode;
+import org.simantics.g3d.scenegraph.NodeMap;
+import org.simantics.g3d.scenegraph.base.INode;
+
+import vtk.vtkProp;
+
+public interface VTKNodeMap<E extends IG3DNode> extends NodeMap<vtkProp, E>{
+
+       
+
+}
index 92d954f4b0375ce5ff855baafb13ff54bcbb5384..73d5e6067fdb255cd288d40cd2ad3e7c9e606fcb 100644 (file)
-/*******************************************************************************\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.math;\r
-\r
-import javax.vecmath.AxisAngle4d;\r
-import javax.vecmath.Matrix3d;\r
-import javax.vecmath.Matrix4d;\r
-import javax.vecmath.Quat4d;\r
-import javax.vecmath.Tuple3d;\r
-import javax.vecmath.Tuple4d;\r
-import javax.vecmath.Vector2f;\r
-import javax.vecmath.Vector3d;\r
-\r
-import org.simantics.g3d.math.EulerTools.Order;\r
-\r
-\r
-/**\r
- * Some useful geometry related math functions. Beware, methods may modify their input parameters!\r
- * \r
- * @author Marko Luukkainen\r
- *\r
- */\r
-public class MathTools {\r
-    \r
-    public static double NEAR_ZERO = 0.0000001;\r
-    public static double NEAR_HALF = 0.4999999;\r
-    \r
-    public static final Vector3d Z_AXIS = new Vector3d(0.0,0.0,1.0);\r
-       public static final Vector3d Y_AXIS = new Vector3d(0.0,1.0,0.0);\r
-       public static final Vector3d X_AXIS = new Vector3d(1.0,0.0,0.0);\r
-       public static final Vector3d ORIGIN = new Vector3d(0.0,0.0,0.0);\r
-       \r
-       final static double EPS = 1.0e-12;\r
-       \r
-       \r
-       public static boolean equals(double d1, double d2) {\r
-               return Math.abs(d1-d2) < EPS;\r
-       }\r
-       \r
-       public static boolean equals(Tuple3d p1, Tuple3d p2) {\r
-               return distanceSquared(p1, p2) < NEAR_ZERO;\r
-       }\r
-       \r
-       public static boolean equals(Tuple4d p1, Tuple4d p2) {\r
-               return distanceSquared(p1, p2) < NEAR_ZERO;\r
-       }\r
-       \r
-       public static double distance(Tuple3d p1, Tuple3d p2) {\r
-               double dx, dy, dz;\r
-\r
-               dx = p2.x - p1.x;\r
-               dy = p2.y - p1.y;\r
-               dz = p2.z - p1.z;\r
-               return Math.sqrt(dx*dx+dy*dy+dz*dz);\r
-       }\r
-       \r
-       public static double distance(Tuple4d p1, Tuple4d p2) {\r
-               double dx, dy, dz, dw;\r
-\r
-               dx = p2.x - p1.x;\r
-               dy = p2.y - p1.y;\r
-               dz = p2.z - p1.z;\r
-               dw = p2.w - p1.w;\r
-               return Math.sqrt(dx*dx+dy*dy+dz*dz+dw*dw);\r
-       }\r
-       \r
-       public static double distanceSquared(Tuple3d p1, Tuple3d p2) {\r
-               double dx, dy, dz;\r
-\r
-               dx = p2.x - p1.x;\r
-               dy = p2.y - p1.y;\r
-               dz = p2.z - p1.z;\r
-               return dx*dx+dy*dy+dz*dz;\r
-       }\r
-       \r
-       public static double distanceSquared(Tuple4d p1, Tuple4d p2) {\r
-               double dx, dy, dz, dw;\r
-\r
-               dx = p2.x - p1.x;\r
-               dy = p2.y - p1.y;\r
-               dz = p2.z - p1.z;\r
-               dw = p2.w - p1.w;\r
-               return dx*dx+dy*dy+dz*dz+dw*dw;\r
-       }\r
-       \r
-       public static boolean isValid(Tuple3d t) {\r
-               return !(Double.isInfinite(t.x) || Double.isNaN(t.x) ||\r
-                                Double.isInfinite(t.y) || Double.isNaN(t.y) ||\r
-                                Double.isInfinite(t.z) || Double.isNaN(t.z));\r
-       }\r
-    \r
-    public static Vector3d closestPointOnEdge(Vector3d point, Vector3d edgePoint1, Vector3d edgePoint2) {\r
-        point.sub(edgePoint1);\r
-        Vector3d v = new Vector3d(edgePoint2);\r
-        v.sub(edgePoint1);\r
-        double t = v.dot(point);\r
-        t /= v.lengthSquared();\r
-        if (t <= 0.0f)\r
-          return edgePoint1;\r
-        if (t >= 1.0f)\r
-          return edgePoint2;\r
-        v.scale(t);\r
-        v.add(edgePoint1);\r
-        return v;   \r
-    }\r
-    \r
-    public static Vector3d closestPointOnStraight(Tuple3d point, Tuple3d straightPoint, Vector3d straightDir) {\r
-        Vector3d v = new Vector3d(point);\r
-        v.sub(straightPoint);\r
-        double t = straightDir.dot(v);\r
-        t /= straightDir.lengthSquared();\r
-        v.set(straightDir);\r
-        v.scale(t);\r
-        v.add(straightPoint);\r
-        return v;   \r
-    }\r
-    \r
-    public static Vector3d closestPointOnStraight(Tuple3d point, Tuple3d straightPoint, Vector3d straightDir, double u[]) {\r
-        Vector3d v = new Vector3d(point);\r
-        v.sub(straightPoint);\r
-        u[0] = straightDir.dot(v);\r
-        u[0] /= straightDir.lengthSquared();\r
-        v.set(straightDir);\r
-        v.scale(u[0]);\r
-        v.add(straightPoint);\r
-        return v;   \r
-    }\r
-    \r
-    public static double distanceFromPlane(Vector3d point, Vector3d planeNormal, Tuple3d planePoint) {\r
-        point.sub(planePoint);\r
-        \r
-        return planeNormal.dot(point);\r
-    }\r
-      \r
-    public static double distanceFromPlane(Vector3d point, Vector3d planeNormal, float d) {\r
-        return (planeNormal.dot(point) + d);\r
-    }\r
-    \r
-    public static boolean intersectStraightPlane(Tuple3d linePoint, Vector3d lineDir, Tuple3d planePoint, Vector3d planeNormal, Tuple3d intersectPoint) {\r
-        intersectPoint.set(planePoint);\r
-        intersectPoint.sub(linePoint);\r
-        double u = planeNormal.dot(new Vector3d(intersectPoint));\r
-        double v = planeNormal.dot(lineDir);\r
-        if (Math.abs(v) < NEAR_ZERO)\r
-            return false;\r
-        u /= v;\r
-        intersectPoint.set(lineDir);\r
-        intersectPoint.scale(u);\r
-        intersectPoint.add(linePoint);\r
-        return true;\r
-    }\r
-    \r
-    public static boolean intersectStraightPlane(Tuple3d linePoint, Vector3d lineDir, Tuple3d planePoint, Vector3d planeNormal, Vector3d intersectPoint, double[] u) {\r
-        intersectPoint.set(planePoint);\r
-        intersectPoint.sub(linePoint);\r
-        u[0] = planeNormal.dot(intersectPoint);\r
-        double v = planeNormal.dot(lineDir);\r
-        if (Math.abs(v) < NEAR_ZERO)\r
-            return false;\r
-        u[0] /= v;\r
-        intersectPoint.set(lineDir);\r
-        intersectPoint.scale(u[0]);\r
-        intersectPoint.add(linePoint);\r
-        return true;\r
-    }\r
-    \r
-    public static boolean intersectLineLine(Tuple3d l1_start,Tuple3d l1_end,Tuple3d l2_start,Tuple3d l2_end,Tuple3d l1_pos, Tuple3d l2_pos) {\r
-            Vector3d p13 = new Vector3d();\r
-            Vector3d p43 = new Vector3d();\r
-            Vector3d p21 = new Vector3d();\r
-            double d1343,d4321,d1321,d4343,d2121;\r
-            double numer,denom;\r
-            p13.sub(l1_start, l2_start);\r
-            p43.sub(l2_end,l2_start);\r
-            if (Math.abs(p43.x)  < NEAR_ZERO && Math.abs(p43.y)  < NEAR_ZERO && Math.abs(p43.z)  < NEAR_ZERO)\r
-               return false;\r
-            p21.sub(l1_end,l1_start);\r
-            if (Math.abs(p21.x)  < NEAR_ZERO && Math.abs(p21.y)  < NEAR_ZERO && Math.abs(p21.z)  < NEAR_ZERO)\r
-               return false;\r
-\r
-            d1343 = p13.dot(p43);\r
-            d4321 = p43.dot(p21);\r
-            d1321 = p13.dot(p21);\r
-            d4343 = p43.lengthSquared();\r
-            d2121 = p21.lengthSquared();\r
-\r
-            denom = d2121 * d4343 - d4321 * d4321;\r
-            if (Math.abs(denom) < NEAR_ZERO)\r
-               return false;\r
-            numer = d1343 * d4321 - d1321 * d4343;\r
-\r
-            double mua = numer / denom;\r
-            double mub = (d1343 + d4321 * mua) / d4343;\r
\r
-            l1_pos.x = l1_start.x + mua * p21.x;\r
-            l1_pos.y = l1_start.y + mua * p21.y;\r
-            l1_pos.z = l1_start.z + mua * p21.z;\r
-            l2_pos.x = l2_start.x + mub * p43.x;\r
-            l2_pos.y = l2_start.y + mub * p43.y;\r
-            l2_pos.z = l2_start.z + mub * p43.z;\r
-\r
-            return true;\r
-    }\r
-    \r
-    public static boolean intersectStraightStraight(Tuple3d p1,Vector3d p21,Tuple3d p3,Vector3d p43,Tuple3d pa,Tuple3d pb) {\r
-        Vector3d p13 = new Vector3d();\r
-\r
-        double d1343,d4321,d1321,d4343,d2121;\r
-        double numer,denom;\r
-        \r
-        p13.sub(p1, p3);\r
-        if (Math.abs(p43.x)  < NEAR_ZERO && Math.abs(p43.y)  < NEAR_ZERO && Math.abs(p43.z)  < NEAR_ZERO)\r
-           return false;\r
-        if (Math.abs(p21.x)  < NEAR_ZERO && Math.abs(p21.y)  < NEAR_ZERO && Math.abs(p21.z)  < NEAR_ZERO)\r
-           return false;\r
-\r
-        d1343 = p13.dot(p43);\r
-        d4321 = p43.dot(p21);\r
-        d1321 = p13.dot(p21);\r
-        d4343 = p43.lengthSquared();\r
-        d2121 = p21.lengthSquared();\r
-\r
-        denom = d2121 * d4343 - d4321 * d4321;\r
-        if (Math.abs(denom) < NEAR_ZERO)\r
-           return false;\r
-        numer = d1343 * d4321 - d1321 * d4343;\r
-\r
-        double mua = numer / denom;\r
-        double mub = (d1343 + d4321 * mua) / d4343;\r
-\r
-        pa.x = p1.x + mua * p21.x;\r
-        pa.y = p1.y + mua * p21.y;\r
-        pa.z = p1.z + mua * p21.z;\r
-        pb.x = p3.x + mub * p43.x;\r
-        pb.y = p3.y + mub * p43.y;\r
-        pb.z = p3.z + mub * p43.z;\r
-\r
-        return true;\r
-   }\r
-    \r
-    /**\r
-     * Calculate the line segment PaPb that is the shortest route between\r
-     *  two lines P1P2 and P3P4. Calculate also the values of mua and mub where\r
-     *  Pa = P1 + mua (P2 - P1)\r
-     *  Pb = P3 + mub (P4 - P3)\r
-     * @param p1\r
-     * @param p21\r
-     * @param p3\r
-     * @param p43\r
-     * @param pa\r
-     * @param pb\r
-     * @param mu\r
-     * @return\r
-     */\r
-    public static boolean intersectStraightStraight(Tuple3d p1,Vector3d p21,Tuple3d p3,Vector3d p43,Tuple3d pa,Tuple3d pb, double mu[]) {\r
-        Vector3d p13 = new Vector3d();\r
-\r
-        double d1343,d4321,d1321,d4343,d2121;\r
-        double numer,denom;\r
-        double EPS = 0.001;\r
-        p13.sub(p1, p3);\r
-        if (Math.abs(p43.x)  < EPS && Math.abs(p43.y)  < EPS && Math.abs(p43.z)  < EPS)\r
-           return false;\r
-        if (Math.abs(p21.x)  < EPS && Math.abs(p21.y)  < EPS && Math.abs(p21.z)  < EPS)\r
-           return false;\r
-\r
-        d1343 = p13.dot(p43);\r
-        d4321 = p43.dot(p21);\r
-        d1321 = p13.dot(p21);\r
-        d4343 = p43.lengthSquared();\r
-        d2121 = p21.lengthSquared();\r
-\r
-        denom = d2121 * d4343 - d4321 * d4321;\r
-        if (Math.abs(denom) < EPS)\r
-           return false;\r
-        numer = d1343 * d4321 - d1321 * d4343;\r
-\r
-        mu[0] = numer / denom;\r
-        mu[1] = (d1343 + d4321 * mu[0]) / d4343;\r
-\r
-        pa.x = p1.x + mu[0] * p21.x;\r
-        pa.y = p1.y + mu[0] * p21.y;\r
-        pa.z = p1.z + mu[0] * p21.z;\r
-        pb.x = p3.x + mu[1] * p43.x;\r
-        pb.y = p3.y + mu[1] * p43.y;\r
-        pb.z = p3.z + mu[1] * p43.z;\r
-\r
-        return true;\r
-   }\r
-   \r
-  \r
-   \r
-   public static void rotate(Quat4d q, Tuple3d in, Tuple3d out) {\r
-       // p' = q * p * q'\r
-       double tw =           - q.x*in.x - q.y*in.y - q.z*in.z;\r
-       double tx =  q.w*in.x            + q.y*in.z - q.z*in.y;\r
-       double ty =  q.w*in.y - q.x*in.z            + q.z*in.x;\r
-       double tz =  q.w*in.z + q.x*in.y - q.y*in.x           ;\r
-       \r
-       //temp * q' -> x = -x, y = -y z = -z\r
-       //out.w = tw*q.w + tx*q.x + ty*q.y + tz*q.z;\r
-       out.x =  -tw*q.x + tx*q.w - ty*q.z + tz*q.y;\r
-       out.y =  -tw*q.y + tx*q.z + ty*q.w - tz*q.x;\r
-       out.z =  -tw*q.z - tx*q.y + ty*q.x + tz*q.w;  \r
-   }\r
-   \r
-   public static void getMatrix(Quat4d quat, Matrix3d m) {\r
-                  m.m00 = 1.0f - 2.0 * (quat.y * quat.y + quat.z * quat.z);\r
-                  m.m01 = 2.0 * (quat.x * quat.y + quat.w * quat.z);\r
-                  m.m02 = 2.0 * (quat.x * quat.z - quat.w * quat.y);\r
-                  m.m10 = 2.0 * (quat.x * quat.y - quat.w * quat.z);\r
-                  m.m11 = 1.0 - 2.0f * (quat.x * quat.x + quat.z * quat.z);\r
-                  m.m12 = 2.0 * (quat.y * quat.z + quat.w * quat.x);\r
-                  m.m20 = 2.0 * (quat.x * quat.z + quat.w * quat.y);\r
-                  m.m21 = 2.0 * (quat.y * quat.z - quat.w * quat.x);\r
-                  m.m22 = 1.0 - 2.0f * (quat.x * quat.x + quat.y * quat.y);\r
-\r
-   }\r
-   \r
-   \r
-   private static double q[] = new double[3];\r
-   private static int nxt[] = { 1, 2, 0 };\r
-   /**\r
-    * Converts Matrix to Quaternion\r
-    * \r
-    * Note: non-thread safe.\r
-    * \r
-    * @param mat\r
-    * @param quat\r
-    */\r
-   public static void getQuat(Matrix3d mat, Quat4d quat) {\r
-          double tr = mat.m00 + mat.m11 + mat.m22;\r
-               if (tr > 0.0) {\r
-                       double s = Math.sqrt(tr + 1.0);\r
-                       quat.w = 0.5 * s;\r
-                       s = 0.5 / s;\r
-                       quat.x = (mat.m21 - mat.m12) * s;\r
-                       quat.y = (mat.m02 - mat.m20) * s;\r
-                       quat.z = (mat.m10 - mat.m01) * s;\r
-               } else {\r
-                       int i = 0, j, k;\r
-                       if (mat.m11 > mat.m00)\r
-                               i = 1;\r
-                       if (mat.m22 > mat.getElement(i, i))\r
-                               i = 2;\r
-                       \r
-\r
-                       j = nxt[i];\r
-                       k = nxt[j];\r
-\r
-                       double s = Math.sqrt((mat.getElement(i, i) - (mat.getElement(j, j) + mat.getElement(k, k))) + 1.0);\r
-\r
-                       q[i] = s * 0.5;\r
-\r
-                       if (Math.abs(s) > 0.001)\r
-                               s = 0.5 / s;\r
-\r
-                       quat.w = (mat.getElement(k, j) - mat.getElement(j, k)) * s;\r
-                       q[j] = (mat.getElement(j, i) + mat.getElement(i, j)) * s;\r
-                       q[k] = (mat.getElement(k, i) + mat.getElement(i, k)) * s;\r
-\r
-                       quat.x = q[0];\r
-                       quat.y = q[1];\r
-                       quat.z = q[2];\r
-               }\r
-       }\r
-   \r
-   public static Quat4d getQuat(Matrix3d mat) {\r
-          Quat4d q = new Quat4d();\r
-          getQuat(mat, q);\r
-          return q;\r
-   }\r
-   \r
-   public static AxisAngle4d getFromPseudoEuler(Vector3d euler) {\r
-       AxisAngle4d aa = new AxisAngle4d();\r
-       aa.angle = euler.length();\r
-       Vector3d normal = new Vector3d(euler);\r
-       if (aa.angle > NEAR_ZERO) {\r
-           normal.normalize();\r
-           aa.x = normal.x;\r
-           aa.y = normal.y;\r
-           aa.z = normal.z;\r
-       } else {\r
-           aa.x = 1.0;\r
-           aa.y = 0.0;\r
-           aa.z = 0.0;\r
-       }\r
-       \r
-       return aa;\r
-   }\r
-   \r
-   public static Vector3d getPseudoEuler(AxisAngle4d aa) {\r
-       Vector3d euler = new Vector3d(aa.x,aa.y,aa.z);\r
-       euler.scale(aa.angle);\r
-       return euler;\r
-   }\r
-   \r
-   \r
-   public static void getQuat(Vector3d euler, Quat4d quat)  {\r
-          Quat4d q = EulerTools.getQuatFromEuler(Order.YXZ, euler.y,euler.x,euler.z);\r
-          quat.set(q);\r
-       // http://en.wikipedia.org/wiki/Rotation_formalisms_in_three_dimensions#Conversion_formulae_between_formalisms\r
-       // Using the x-convention, the 3-1-3 Euler angles phi, theta and psi (around the Z, X and again the Z-axis)   \r
-//        quat.x = -Math.cos((euler.x - euler.z)*0.5)*Math.sin(euler.y*0.5);\r
-//        quat.y = -Math.sin((euler.x - euler.z)*0.5)*Math.sin(euler.y*0.5);\r
-//        quat.z = -Math.sin((euler.x + euler.z)*0.5)*Math.cos(euler.y*0.5);\r
-//        quat.w = Math.sin((euler.x + euler.z)*0.5)*Math.cos(euler.y*0.5);\r
-          \r
-          // http://www.euclideanspace.com/maths/geometry/rotations/conversions/eulerToQuaternion/index.htm\r
-          // Y, Z, X order\r
-//         double c1 = Math.cos(euler.y*0.5);\r
-//         double s1 = Math.sin(euler.y*0.5);\r
-//         double c2 = Math.cos(euler.z*0.5);\r
-//         double s2 = Math.sin(euler.z*0.5);\r
-//         double c3 = Math.cos(euler.x*0.5);\r
-//         double s3 = Math.sin(euler.x*0.5);\r
-//         double c1c2 = c1*c2;\r
-//         double s1s2 = s1*s2;\r
-//         quat.w =c1c2*c3 - s1s2*s3;\r
-//         quat.x =c1c2*s3 + s1s2*c3;\r
-//         quat.y =s1*c2*c3 + c1*s2*s3;\r
-//         quat.z =c1*s2*c3 - s1*c2*s3;\r
-\r
-//         Quat4d q2 = EulerTools.getQuatFromEuler(Order.YZX, euler.y,euler.z,euler.x);\r
-//         System.out.println("Q " + quat + " Q2 " + q2);\r
-//        double c1 = Math.cos(euler.y);\r
-//         double s1 = Math.sin(euler.y);\r
-//         double c2 = Math.cos(euler.z);\r
-//         double s2 = Math.sin(euler.z);\r
-//         double c3 = Math.cos(euler.x);\r
-//         double s3 = Math.sin(euler.x);\r
-//         quat.w = Math.sqrt(1.0 + c1 * c2 + c1*c3 - s1 * s2 * s3 + c2*c3) / 2.0;\r
-//         double w4 = (4.0 * quat.w);\r
-//         quat.x = (c2 * s3 + c1 * s3 + s1 * s2 * c3) / w4 ;\r
-//         quat.y = (s1 * c2 + s1 * c3 + c1 * s2 * s3) / w4 ;\r
-//         quat.z = (-s1 * s3 + c1 * s2 * c3 +s2) / w4 ;\r
-   }\r
-   \r
-   \r
-  \r
-   \r
-   public static void getEuler(Quat4d quat,Vector3d euler)  {\r
-          Vector3d e = EulerTools.getEulerFromQuat(Order.YXZ, quat);\r
-          euler.x = e.y;\r
-          euler.y = e.x;\r
-          euler.z = e.z;\r
-          \r
-          // http://en.wikipedia.org/wiki/Rotation_formalisms_in_three_dimensions#Conversion_formulae_between_formalisms\r
-//        euler.x = Math.atan2(quat.x * quat.z + quat.y* quat.w, quat.y*quat.z - quat.x * quat.w);\r
-//        euler.y = Math.acos(-square(quat.x) - square(quat.y) + square(quat.z) + square(quat.w));\r
-//        euler.z = -Math.atan2(quat.x * quat.z - quat.y* quat.w, quat.y*quat.z + quat.x * quat.w);\r
-          \r
-          // http://www.euclideanspace.com/maths/geometry/rotations/conversions/quaternionToEuler/index.htm\r
-         // Y, Z, X order\r
-//        double test = quat.x * quat.y + quat.z * quat.w;\r
-//        if (test > NEAR_HALF) {\r
-//                euler.y = 2.0 * Math.atan2(quat.x,quat.w);\r
-//                euler.z = Math.PI * 0.5;\r
-//                euler.x = 0.0;\r
-//        } else if (test < -NEAR_HALF) {\r
-//                euler.y = -2.0 * Math.atan2(quat.x,quat.w);\r
-//                euler.z = -Math.PI * 0.5;\r
-//                euler.x = 0.0;\r
-//        } else {\r
-//                double sqx = square(quat.x);\r
-//                double sqy = square(quat.y);\r
-//                double sqz = square(quat.z);\r
-//                euler.y = Math.atan2(2.0*(quat.y*quat.w-quat.x*quat.z), 1.0 - 2.0*(sqy-sqz));\r
-//                euler.z = Math.asin(2.0*test);\r
-//                euler.x = Math.atan2(2.0*(quat.x*quat.w-quat.y*quat.z), 1.0 - 2.0*(sqx-sqz));\r
-//                System.out.println(euler + " " + EulerTools.getEulerFromQuat(Order.YXZ, quat) +  " " + quat);\r
-//        }\r
-//        double sqw = quat.w*quat.w;\r
-//         double sqx = quat.x*quat.x;\r
-//         double sqy = quat.y*quat.y;\r
-//         double sqz = quat.z*quat.z;\r
-//             double unit = sqx + sqy + sqz + sqw; // if normalised is one, otherwise is correction factor\r
-//             double test = quat.x*quat.y + quat.z*quat.w;\r
-//             if (test > 0.499*unit) { // singularity at north pole\r
-//                     euler.y = 2 * Math.atan2(quat.x,quat.w);\r
-//                     euler.z = Math.PI/2;\r
-//                     euler.x = 0;\r
-//                     return;\r
-//             }\r
-//             if (test < -0.499*unit) { // singularity at south pole\r
-//                     euler.y = -2 * Math.atan2(quat.x,quat.w);\r
-//                     euler.z = -Math.PI/2;\r
-//                     euler.x = 0;\r
-//                     return;\r
-//             }\r
-//             euler.y = Math.atan2(2*quat.y*quat.w-2*quat.x*quat.z , sqx - sqy - sqz + sqw);\r
-//             euler.z = Math.asin(2*test/unit);\r
-//             euler.x = Math.atan2(2*quat.x*quat.w-2*quat.y*quat.z , -sqx + sqy - sqz + sqw);\r
-   }\r
-   \r
-   public static Quat4d getQuat(Vector3d euler) {\r
-          Quat4d q = new Quat4d();\r
-          getQuat(euler,q);\r
-          return q;\r
-   }\r
-   \r
-   \r
-   public static Vector3d getEuler(Quat4d quat) {\r
-          Vector3d v = new Vector3d();\r
-          getEuler(quat, v);\r
-          return v;\r
-   }\r
-   \r
-   public static Quat4d getQuat(AxisAngle4d aa) {\r
-          Quat4d q = new Quat4d();\r
-          getQuat(aa, q);\r
-          return q;\r
-   }\r
-   \r
-   public static AxisAngle4d getAxisAngle(Quat4d q) {\r
-          AxisAngle4d aa = new AxisAngle4d();\r
-          aa.set(q);\r
-          return aa;\r
-   }\r
-   \r
-   public static Quat4d getIdentityQuat() {\r
-          return new Quat4d(0, 0, 0, 1);\r
-   }\r
-   \r
-   public static void getQuat(AxisAngle4d aa, Quat4d q) {\r
-          double mag,amag;\r
-               // Quat = cos(theta/2) + sin(theta/2)(roation_axis) \r
-               \r
-               amag = Math.sqrt( aa.x*aa.x + aa.y*aa.y + aa.z*aa.z);\r
-               if( amag < NEAR_ZERO ) {\r
-                   q.w = 1.0;\r
-                   q.x = 0.0;\r
-                   q.y = 0.0;\r
-                   q.z = 0.0;\r
-               } else {  \r
-                  amag = 1.0/amag; \r
-                  double a2 = aa.angle * 0.5;\r
-                  mag = Math.sin(a2);\r
-                  q.w = Math.cos(a2);\r
-              q.x = aa.x*amag*mag;\r
-              q.y = aa.y*amag*mag;\r
-              q.z = aa.z*amag*mag;\r
-               }\r
-   }\r
-   \r
-   \r
-       /*\r
-        * Cohen-Sutherland\r
-        */\r
-       \r
-       private static final int IN = 0;\r
-       private static final int LEFT = 1;\r
-       private static final int RIGHT = 2;\r
-       private static final int BOTTOM = 4;\r
-       private static final int TOP = 8;\r
-       \r
-       \r
-       private static int bitcode(Vector2f p1, Vector2f min, Vector2f max) {\r
-               int code = IN;\r
-               if (p1.x < min.x)\r
-                       code |= LEFT;\r
-               else if (p1.x > max.x)\r
-                       code |= RIGHT;\r
-               if (p1.y < min.y)\r
-                       code |= BOTTOM;\r
-               else if (p1.y > max.y)\r
-                       code |= TOP;\r
-               return code;\r
-       }\r
-       \r
-       public static boolean clipLineRectangle(Vector2f p1,Vector2f p2, Vector2f min, Vector2f max, Vector2f r1, Vector2f r2) {\r
-               while (true) {\r
-                       int o1 = bitcode(p1, min, max);\r
-                       int o2 = bitcode(p2, min, max);\r
-                       int and = o1 & o2;\r
-                       int or = o1 | o2;\r
-                       if (and != IN) {\r
-                               return false;\r
-                       }\r
-                       if (or == IN) {\r
-                               r1.set(p1);\r
-                               r2.set(p2);\r
-                               return true;\r
-                       }\r
-                       if (o1 == IN) {\r
-                               Vector2f t = p1;\r
-                               p1 = p2;\r
-                               p2 = t;\r
-                               int t2 = o1;\r
-                               o1 = o2;\r
-                               o2 = t2;\r
-                       }\r
-                       if ((o1 & TOP) != IN) {\r
-                               float t = (max.y - p1.y) / (p2.y - p1.y);\r
-                               p1.x += t * (p2.x - p1.x);\r
-                               p1.y = max.y;\r
-                       } else if ((o1 & BOTTOM) != IN) {\r
-                               float t = (min.y - p1.y) / (p2.y - p1.y);\r
-                               p1.x += t * (p2.x - p1.x);\r
-                               p1.y = min.y;\r
-                       } else if ((o1 & LEFT) != IN) {\r
-                               float t = (min.x - p1.x) / (p2.x - p1.x);\r
-                               p1.y += t * (p2.y - p1.y);\r
-                               p1.x = min.x;\r
-                       } else if ((o1 & RIGHT) != IN) {\r
-                               float t = (max.x - p1.x) / (p2.x - p1.x);\r
-                               p1.y += t * (p2.y - p1.y);\r
-                               p1.x = max.x;\r
-                       } else {\r
-                               throw new RuntimeException("Error in clipping code");\r
-                       }\r
-               }\r
-               \r
-       }\r
-       \r
-       public static double square(double d) {\r
-               return d * d;\r
-       }\r
-       \r
-       \r
-        public static void multiplyOrientation(AxisAngle4d aa, AxisAngle4d rot)  {\r
-               Quat4d q1 = new Quat4d();\r
-               getQuat(aa, q1);\r
-               Quat4d q2 = new Quat4d();\r
-               getQuat(rot, q2);\r
-               q2.mul(q1);\r
-               rot.set(q2);\r
-        }\r
-        \r
-        public static double radToDeg(double rad) {\r
-                return (rad / Math.PI) * 180.0;\r
-        }\r
-        \r
-        public static double degToRad(double deg) {\r
-                return (deg / 180.0) * Math.PI;\r
-        }\r
-        \r
-        public static double clamp(double min, double max,double v) {\r
-                if (v < min)\r
-                        return min;\r
-                if (v > max)\r
-                        return max;\r
-                return v;\r
-        }\r
-        \r
-        public static AxisAngle4d createRotation(Vector3d original, Vector3d rotated) { \r
-               AxisAngle4d result = new AxisAngle4d();\r
-               if (createRotation(original, rotated, result))\r
-                       return result;\r
-               return null;\r
-        }\r
-        \r
-        \r
-        public static void setIdentity(Quat4d q) {\r
-               q.w = 1.0;\r
-               q.x = 0.0;\r
-               q.y = 0.0;\r
-               q.z = 0.0;\r
-        }\r
-        \r
-       public static void setIdentity(AxisAngle4d aa) {\r
-               aa.angle = 0.0;\r
-               aa.x = 0.0;\r
-               aa.y = 1.0;\r
-               aa.z = 0.0;\r
-       }\r
-       \r
-       public static void set(Matrix3d mat, double m00, double m01, double m02,\r
-                       double m10, double m11, double m12, double m20, double m21,\r
-                       double m22) {\r
-               mat.m00 = m00;\r
-               mat.m01 = m01;\r
-               mat.m02 = m02;\r
-\r
-               mat.m10 = m10;\r
-               mat.m11 = m11;\r
-               mat.m12 = m12;\r
-\r
-               mat.m20 = m20;\r
-               mat.m21 = m21;\r
-               mat.m22 = m22;\r
-       }\r
-       \r
-       public static void set(Matrix4d mat, double[] v) {\r
-               mat.m00 = v[0];\r
-               mat.m01 = v[1];\r
-               mat.m02 = v[2];\r
-               mat.m03 = v[3];\r
-\r
-               mat.m10 = v[4];\r
-               mat.m11 = v[5];\r
-               mat.m12 = v[6];\r
-               mat.m13 = v[7];\r
-\r
-               mat.m20 = v[8];\r
-               mat.m21 = v[9];\r
-               mat.m22 = v[10];\r
-               mat.m23 = v[11];\r
-\r
-               mat.m30 = v[12];\r
-               mat.m31 = v[13];\r
-               mat.m32 = v[14];\r
-               mat.m33 = v[15];\r
-\r
-       }\r
-        \r
-        public static boolean createRotation(Vector3d original, Vector3d rotated, AxisAngle4d result) {\r
-                \r
-                       if (rotated.lengthSquared() > 0.01)\r
-                               rotated.normalize();\r
-                       else\r
-                               return false;\r
-                       double d = original.dot(rotated);\r
-                       if (d > 0.9999) {\r
-                               // original and rotated are parallel, pointing at the same direction\r
-                               result.angle = 0.0;\r
-                               result.x = 0.0;\r
-                               result.y = 1.0;\r
-                               result.z = 0.0;\r
-                       } else if (d < -0.9999) {\r
-                               // original and rotated are parallel, pointing at the opposite direction \r
-                               Vector3d a = Z_AXIS;\r
-                               if (Math.abs(a.dot(original)) > 0.8 )\r
-                                       a = Y_AXIS;\r
-                               result.set(a, Math.PI);\r
-                       } else {\r
-                               double angle = original.angle(rotated);\r
-                               Vector3d axis = new Vector3d();\r
-                               axis.cross(original, rotated);\r
-                               result.set(axis,angle);\r
-                       }\r
-                       return true;\r
-                }\r
-        \r
-        public static boolean createRotation(Vector3d original, Vector3d rotated, Quat4d result) {\r
-                \r
-                       if (rotated.lengthSquared() > 0.01)\r
-                               rotated.normalize();\r
-                       else\r
-                               return false;\r
-                       double d = original.dot(rotated);\r
-                       if (d > 0.9999) {\r
-                               // original and rotated are parallel, pointing at the same direction\r
-                               result.w = 1.0;\r
-                               result.x = 0.0;\r
-                               result.y = 0.0;\r
-                               result.z = 0.0;\r
-                       } else if (d < -0.9999) {\r
-                               // original and rotated are parallel, pointing at the opposite direction \r
-                               Vector3d a = Z_AXIS;\r
-                               if (Math.abs(a.dot(original)) > 0.8 )\r
-                                       a = Y_AXIS;\r
-                               getQuat(a, Math.PI, result);\r
-                               \r
-                       } else {\r
-                               double angle = original.angle(rotated);\r
-                               Vector3d axis = new Vector3d();\r
-                               axis.cross(original, rotated);\r
-                               getQuat(axis, angle, result);\r
-                       }\r
-                       return true;\r
-                }\r
-        \r
-        public static void getQuat(Vector3d axis, double angle, Quat4d q)\r
-    {\r
-               double mag,amag;\r
-               // Quat = cos(theta/2) + sin(theta/2)(roation_axis) \r
-               \r
-               amag = Math.sqrt( axis.x*axis.x + axis.y*axis.y + axis.z*axis.z);\r
-               if( amag < EPS ) {\r
-                   q.w = 1.0;\r
-                   q.x = 0.0;\r
-                   q.y = 0.0;\r
-                   q.z = 0.0;\r
-               } else {  \r
-                   amag = 1.0/amag; \r
-                   double a2 = angle*0.5;\r
-                   mag = Math.sin(a2);\r
-                   q.w = Math.cos(a2);\r
-                   q.x = axis.x*amag*mag;\r
-                   q.y = axis.y*amag*mag;\r
-                   q.z = axis.z*amag*mag;\r
-               }\r
-       \r
-    }\r
-        \r
-        /**\r
-         * Linear interpolation of quaternions. Result IS set to q1.\r
-         * @param q1\r
-         * @param q2\r
-         * @param alpha\r
-         */\r
-        public static void lip(Quat4d q1, Quat4d q2, double alpha) {\r
-                double s1 = 1.0 - alpha;\r
-                double s2 = alpha;\r
-                q1.scale(s1);\r
-                mad(q1,q2,s2);\r
-                q1.normalize();\r
-        }\r
-        \r
-        public static double dot(Quat4d q1, Quat4d q2) {\r
-                return q1.x * q2.x + q1.y * q2.y + q1.z * q2.z + q1.w * q2.w;\r
-        }\r
-        \r
-        public static void mad(Tuple3d q1, Tuple3d q2, double s2) {\r
-                q1.x += q2.x * s2;\r
-                q1.y += q2.y * s2;\r
-                q1.z += q2.z * s2;\r
-        }\r
-        \r
-        public static void mad(Quat4d q1, Quat4d q2, double s2) {\r
-                q1.x += q2.x * s2;\r
-                q1.y += q2.y * s2;\r
-                q1.z += q2.z * s2;\r
-                q1.w += q2.w * s2;\r
-        }\r
-        \r
-        /**\r
-         * Slerp\r
-         * \r
-         * Sets results to q1. Modifies q2.\r
-         * \r
-         * @param q1\r
-         * @param q2\r
-         * @param alpha\r
-         */\r
-        public static void sip(Quat4d q1, Quat4d q2, double alpha) {\r
-                double cosom = dot(q1,q2);\r
-                if (cosom < 0.0) {\r
-                        cosom = -cosom;\r
-                        q2.negate();\r
-                }\r
-                \r
-                if (cosom > 0.9999) {\r
-                        q2.sub(q1);\r
-                        q2.scale(alpha);\r
-                        q1.add(q2);\r
-                        q1.normalize();\r
-                        return;\r
-                }\r
-                double theta_0 = Math.acos(cosom);\r
-                double theta = theta_0 * alpha;\r
-                Quat4d t = new Quat4d(q1);\r
-                t.scale(-cosom);\r
-                t.add(q2);\r
-                t.normalize();\r
-                t.scale(Math.sin(theta));\r
-                q1.scale(Math.cos(theta));\r
-                q1.add(t);\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.math;
+
+import javax.vecmath.AxisAngle4d;
+import javax.vecmath.Matrix3d;
+import javax.vecmath.Matrix4d;
+import javax.vecmath.Quat4d;
+import javax.vecmath.Tuple2d;
+import javax.vecmath.Tuple3d;
+import javax.vecmath.Tuple4d;
+import javax.vecmath.Vector2d;
+import javax.vecmath.Vector2f;
+import javax.vecmath.Vector3d;
+
+import org.simantics.g3d.math.EulerTools.Order;
+
+
+/**
+ * Some useful geometry related math functions. Beware, methods may modify their input parameters!
+ * 
+ * @author Marko Luukkainen
+ *
+ */
+public class MathTools {
+    
+    public static double NEAR_ZERO = 0.0000001;
+    public static double NEAR_HALF = 0.4999999;
+    
+    public static final Vector3d Z_AXIS = new Vector3d(0.0,0.0,1.0);
+       public static final Vector3d Y_AXIS = new Vector3d(0.0,1.0,0.0);
+       public static final Vector3d X_AXIS = new Vector3d(1.0,0.0,0.0);
+       public static final Vector3d ORIGIN = new Vector3d(0.0,0.0,0.0);
+       
+       final static double EPS = 1.0e-12;
+       
+       
+       public static boolean equals(double d1, double d2) {
+               return Math.abs(d1-d2) < EPS;
+       }
+       
+       public static boolean equals(Tuple3d p1, Tuple3d p2) {
+               return distanceSquared(p1, p2) < NEAR_ZERO;
+       }
+       
+       public static boolean equals(Tuple4d p1, Tuple4d p2) {
+               return distanceSquared(p1, p2) < NEAR_ZERO;
+       }
+       
+       public static double distance(Tuple3d p1, Tuple3d p2) {
+               double dx, dy, dz;
+
+               dx = p2.x - p1.x;
+               dy = p2.y - p1.y;
+               dz = p2.z - p1.z;
+               return Math.sqrt(dx*dx+dy*dy+dz*dz);
+       }
+       
+       public static double distance(Tuple4d p1, Tuple4d p2) {
+               double dx, dy, dz, dw;
+
+               dx = p2.x - p1.x;
+               dy = p2.y - p1.y;
+               dz = p2.z - p1.z;
+               dw = p2.w - p1.w;
+               return Math.sqrt(dx*dx+dy*dy+dz*dz+dw*dw);
+       }
+       
+       public static double distanceSquared(Tuple3d p1, Tuple3d p2) {
+               double dx, dy, dz;
+
+               dx = p2.x - p1.x;
+               dy = p2.y - p1.y;
+               dz = p2.z - p1.z;
+               return dx*dx+dy*dy+dz*dz;
+       }
+       
+       public static double distanceSquared(Tuple4d p1, Tuple4d p2) {
+               double dx, dy, dz, dw;
+
+               dx = p2.x - p1.x;
+               dy = p2.y - p1.y;
+               dz = p2.z - p1.z;
+               dw = p2.w - p1.w;
+               return dx*dx+dy*dy+dz*dz+dw*dw;
+       }
+       
+       public static boolean isValid(Tuple3d t) {
+               return !(Double.isInfinite(t.x) || Double.isNaN(t.x) ||
+                                Double.isInfinite(t.y) || Double.isNaN(t.y) ||
+                                Double.isInfinite(t.z) || Double.isNaN(t.z));
+       }
+    
+    public static Vector3d closestPointOnEdge(Vector3d point, Vector3d edgePoint1, Vector3d edgePoint2) {
+        point.sub(edgePoint1);
+        Vector3d v = new Vector3d(edgePoint2);
+        v.sub(edgePoint1);
+        double t = v.dot(point);
+        t /= v.lengthSquared();
+        if (t <= 0.0f)
+          return edgePoint1;
+        if (t >= 1.0f)
+          return edgePoint2;
+        v.scale(t);
+        v.add(edgePoint1);
+        return v;   
+    }
+    
+    public static Vector3d closestPointOnStraight(Tuple3d point, Tuple3d straightPoint, Vector3d straightDir) {
+        Vector3d v = new Vector3d(point);
+        v.sub(straightPoint);
+        double t = straightDir.dot(v);
+        t /= straightDir.lengthSquared();
+        v.set(straightDir);
+        v.scale(t);
+        v.add(straightPoint);
+        return v;   
+    }
+    
+    public static Vector3d closestPointOnStraight(Tuple3d point, Tuple3d straightPoint, Vector3d straightDir, double u[]) {
+        Vector3d v = new Vector3d(point);
+        v.sub(straightPoint);
+        u[0] = straightDir.dot(v);
+        u[0] /= straightDir.lengthSquared();
+        v.set(straightDir);
+        v.scale(u[0]);
+        v.add(straightPoint);
+        return v;   
+    }
+    
+    public static double distanceFromPlane(Vector3d point, Vector3d planeNormal, Tuple3d planePoint) {
+        point.sub(planePoint);
+        
+        return planeNormal.dot(point);
+    }
+      
+    public static double distanceFromPlane(Vector3d point, Vector3d planeNormal, float d) {
+        return (planeNormal.dot(point) + d);
+    }
+    
+    public static boolean intersectStraightPlane(Tuple3d linePoint, Vector3d lineDir, Tuple3d planePoint, Vector3d planeNormal, Tuple3d intersectPoint) {
+        intersectPoint.set(planePoint);
+        intersectPoint.sub(linePoint);
+        double u = planeNormal.dot(new Vector3d(intersectPoint));
+        double v = planeNormal.dot(lineDir);
+        if (Math.abs(v) < NEAR_ZERO)
+            return false;
+        u /= v;
+        intersectPoint.set(lineDir);
+        intersectPoint.scale(u);
+        intersectPoint.add(linePoint);
+        return true;
+    }
+    
+    public static boolean intersectStraightPlane(Tuple3d linePoint, Vector3d lineDir, Tuple3d planePoint, Vector3d planeNormal, Vector3d intersectPoint, double[] u) {
+        intersectPoint.set(planePoint);
+        intersectPoint.sub(linePoint);
+        u[0] = planeNormal.dot(intersectPoint);
+        double v = planeNormal.dot(lineDir);
+        if (Math.abs(v) < NEAR_ZERO)
+            return false;
+        u[0] /= v;
+        intersectPoint.set(lineDir);
+        intersectPoint.scale(u[0]);
+        intersectPoint.add(linePoint);
+        return true;
+    }
+    
+    public static boolean intersectLineLine(Tuple3d l1_start,Tuple3d l1_end,Tuple3d l2_start,Tuple3d l2_end,Tuple3d l1_pos, Tuple3d l2_pos) {
+            Vector3d p13 = new Vector3d();
+            Vector3d p43 = new Vector3d();
+            Vector3d p21 = new Vector3d();
+            double d1343,d4321,d1321,d4343,d2121;
+            double numer,denom;
+            p13.sub(l1_start, l2_start);
+            p43.sub(l2_end,l2_start);
+            if (Math.abs(p43.x)  < NEAR_ZERO && Math.abs(p43.y)  < NEAR_ZERO && Math.abs(p43.z)  < NEAR_ZERO)
+               return false;
+            p21.sub(l1_end,l1_start);
+            if (Math.abs(p21.x)  < NEAR_ZERO && Math.abs(p21.y)  < NEAR_ZERO && Math.abs(p21.z)  < NEAR_ZERO)
+               return false;
+
+            d1343 = p13.dot(p43);
+            d4321 = p43.dot(p21);
+            d1321 = p13.dot(p21);
+            d4343 = p43.lengthSquared();
+            d2121 = p21.lengthSquared();
+
+            denom = d2121 * d4343 - d4321 * d4321;
+            if (Math.abs(denom) < NEAR_ZERO)
+               return false;
+            numer = d1343 * d4321 - d1321 * d4343;
+
+            double mua = numer / denom;
+            double mub = (d1343 + d4321 * mua) / d4343;
+            l1_pos.x = l1_start.x + mua * p21.x;
+            l1_pos.y = l1_start.y + mua * p21.y;
+            l1_pos.z = l1_start.z + mua * p21.z;
+            l2_pos.x = l2_start.x + mub * p43.x;
+            l2_pos.y = l2_start.y + mub * p43.y;
+            l2_pos.z = l2_start.z + mub * p43.z;
+
+            return true;
+    }
+    
+    public static boolean intersectStraightStraight(Tuple3d p1,Vector3d p21,Tuple3d p3,Vector3d p43,Tuple3d pa,Tuple3d pb) {
+        Vector3d p13 = new Vector3d();
+
+        double d1343,d4321,d1321,d4343,d2121;
+        double numer,denom;
+        
+        p13.sub(p1, p3);
+        if (Math.abs(p43.x)  < NEAR_ZERO && Math.abs(p43.y)  < NEAR_ZERO && Math.abs(p43.z)  < NEAR_ZERO)
+           return false;
+        if (Math.abs(p21.x)  < NEAR_ZERO && Math.abs(p21.y)  < NEAR_ZERO && Math.abs(p21.z)  < NEAR_ZERO)
+           return false;
+
+        d1343 = p13.dot(p43);
+        d4321 = p43.dot(p21);
+        d1321 = p13.dot(p21);
+        d4343 = p43.lengthSquared();
+        d2121 = p21.lengthSquared();
+
+        denom = d2121 * d4343 - d4321 * d4321;
+        if (Math.abs(denom) < NEAR_ZERO)
+           return false;
+        numer = d1343 * d4321 - d1321 * d4343;
+
+        double mua = numer / denom;
+        double mub = (d1343 + d4321 * mua) / d4343;
+
+        pa.x = p1.x + mua * p21.x;
+        pa.y = p1.y + mua * p21.y;
+        pa.z = p1.z + mua * p21.z;
+        pb.x = p3.x + mub * p43.x;
+        pb.y = p3.y + mub * p43.y;
+        pb.z = p3.z + mub * p43.z;
+
+        return true;
+   }
+    
+    /**
+     * Calculate the line segment PaPb that is the shortest route between
+     *  two lines P1P2 and P3P4. Calculate also the values of mua and mub where
+     *  Pa = P1 + mua (P2 - P1)
+     *  Pb = P3 + mub (P4 - P3)
+     * @param p1
+     * @param p21
+     * @param p3
+     * @param p43
+     * @param pa
+     * @param pb
+     * @param mu
+     * @return
+     */
+    public static boolean intersectStraightStraight(Tuple3d p1,Vector3d p21,Tuple3d p3,Vector3d p43,Tuple3d pa,Tuple3d pb, double mu[]) {
+        Vector3d p13 = new Vector3d();
+
+        double d1343,d4321,d1321,d4343,d2121;
+        double numer,denom;
+        double EPS = 0.001;
+        p13.sub(p1, p3);
+        if (Math.abs(p43.x)  < EPS && Math.abs(p43.y)  < EPS && Math.abs(p43.z)  < EPS)
+           return false;
+        if (Math.abs(p21.x)  < EPS && Math.abs(p21.y)  < EPS && Math.abs(p21.z)  < EPS)
+           return false;
+
+        d1343 = p13.dot(p43);
+        d4321 = p43.dot(p21);
+        d1321 = p13.dot(p21);
+        d4343 = p43.lengthSquared();
+        d2121 = p21.lengthSquared();
+
+        denom = d2121 * d4343 - d4321 * d4321;
+        if (Math.abs(denom) < EPS)
+           return false;
+        numer = d1343 * d4321 - d1321 * d4343;
+
+        mu[0] = numer / denom;
+        mu[1] = (d1343 + d4321 * mu[0]) / d4343;
+
+        pa.x = p1.x + mu[0] * p21.x;
+        pa.y = p1.y + mu[0] * p21.y;
+        pa.z = p1.z + mu[0] * p21.z;
+        pb.x = p3.x + mu[1] * p43.x;
+        pb.y = p3.y + mu[1] * p43.y;
+        pb.z = p3.z + mu[1] * p43.z;
+
+        return true;
+   }
+   
+  
+   
+   public static void rotate(Quat4d q, Tuple3d in, Tuple3d out) {
+       // p' = q * p * q'
+       double tw =           - q.x*in.x - q.y*in.y - q.z*in.z;
+       double tx =  q.w*in.x            + q.y*in.z - q.z*in.y;
+       double ty =  q.w*in.y - q.x*in.z            + q.z*in.x;
+       double tz =  q.w*in.z + q.x*in.y - q.y*in.x           ;
+       
+       //temp * q' -> x = -x, y = -y z = -z
+       //out.w = tw*q.w + tx*q.x + ty*q.y + tz*q.z;
+       out.x =  -tw*q.x + tx*q.w - ty*q.z + tz*q.y;
+       out.y =  -tw*q.y + tx*q.z + ty*q.w - tz*q.x;
+       out.z =  -tw*q.z - tx*q.y + ty*q.x + tz*q.w;  
+   }
+   
+   public static void getMatrix(Quat4d quat, Matrix3d m) {
+                  m.m00 = 1.0f - 2.0 * (quat.y * quat.y + quat.z * quat.z);
+                  m.m01 = 2.0 * (quat.x * quat.y + quat.w * quat.z);
+                  m.m02 = 2.0 * (quat.x * quat.z - quat.w * quat.y);
+                  m.m10 = 2.0 * (quat.x * quat.y - quat.w * quat.z);
+                  m.m11 = 1.0 - 2.0f * (quat.x * quat.x + quat.z * quat.z);
+                  m.m12 = 2.0 * (quat.y * quat.z + quat.w * quat.x);
+                  m.m20 = 2.0 * (quat.x * quat.z + quat.w * quat.y);
+                  m.m21 = 2.0 * (quat.y * quat.z - quat.w * quat.x);
+                  m.m22 = 1.0 - 2.0f * (quat.x * quat.x + quat.y * quat.y);
+
+   }
+   
+   
+   private static double q[] = new double[3];
+   private static int nxt[] = { 1, 2, 0 };
+   /**
+    * Converts Matrix to Quaternion
+    * 
+    * Note: non-thread safe.
+    * 
+    * @param mat
+    * @param quat
+    */
+   public static void getQuat(Matrix3d mat, Quat4d quat) {
+          double tr = mat.m00 + mat.m11 + mat.m22;
+               if (tr > 0.0) {
+                       double s = Math.sqrt(tr + 1.0);
+                       quat.w = 0.5 * s;
+                       s = 0.5 / s;
+                       quat.x = (mat.m21 - mat.m12) * s;
+                       quat.y = (mat.m02 - mat.m20) * s;
+                       quat.z = (mat.m10 - mat.m01) * s;
+               } else {
+                       int i = 0, j, k;
+                       if (mat.m11 > mat.m00)
+                               i = 1;
+                       if (mat.m22 > mat.getElement(i, i))
+                               i = 2;
+                       
+
+                       j = nxt[i];
+                       k = nxt[j];
+
+                       double s = Math.sqrt((mat.getElement(i, i) - (mat.getElement(j, j) + mat.getElement(k, k))) + 1.0);
+
+                       q[i] = s * 0.5;
+
+                       if (Math.abs(s) > 0.001)
+                               s = 0.5 / s;
+
+                       quat.w = (mat.getElement(k, j) - mat.getElement(j, k)) * s;
+                       q[j] = (mat.getElement(j, i) + mat.getElement(i, j)) * s;
+                       q[k] = (mat.getElement(k, i) + mat.getElement(i, k)) * s;
+
+                       quat.x = q[0];
+                       quat.y = q[1];
+                       quat.z = q[2];
+               }
+       }
+   
+   public static Quat4d getQuat(Matrix3d mat) {
+          Quat4d q = new Quat4d();
+          getQuat(mat, q);
+          return q;
+   }
+   
+   public static AxisAngle4d getFromPseudoEuler(Vector3d euler) {
+       AxisAngle4d aa = new AxisAngle4d();
+       aa.angle = euler.length();
+       Vector3d normal = new Vector3d(euler);
+       if (aa.angle > NEAR_ZERO) {
+           normal.normalize();
+           aa.x = normal.x;
+           aa.y = normal.y;
+           aa.z = normal.z;
+       } else {
+           aa.x = 1.0;
+           aa.y = 0.0;
+           aa.z = 0.0;
+       }
+       
+       return aa;
+   }
+   
+   public static Vector3d getPseudoEuler(AxisAngle4d aa) {
+       Vector3d euler = new Vector3d(aa.x,aa.y,aa.z);
+       euler.scale(aa.angle);
+       return euler;
+   }
+   
+   
+   public static void getQuat(Vector3d euler, Quat4d quat)  {
+          Quat4d q = EulerTools.getQuatFromEuler(Order.YXZ, euler.y,euler.x,euler.z);
+          quat.set(q);
+       // http://en.wikipedia.org/wiki/Rotation_formalisms_in_three_dimensions#Conversion_formulae_between_formalisms
+       // Using the x-convention, the 3-1-3 Euler angles phi, theta and psi (around the Z, X and again the Z-axis)   
+//        quat.x = -Math.cos((euler.x - euler.z)*0.5)*Math.sin(euler.y*0.5);
+//        quat.y = -Math.sin((euler.x - euler.z)*0.5)*Math.sin(euler.y*0.5);
+//        quat.z = -Math.sin((euler.x + euler.z)*0.5)*Math.cos(euler.y*0.5);
+//        quat.w = Math.sin((euler.x + euler.z)*0.5)*Math.cos(euler.y*0.5);
+          
+          // http://www.euclideanspace.com/maths/geometry/rotations/conversions/eulerToQuaternion/index.htm
+          // Y, Z, X order
+//         double c1 = Math.cos(euler.y*0.5);
+//         double s1 = Math.sin(euler.y*0.5);
+//         double c2 = Math.cos(euler.z*0.5);
+//         double s2 = Math.sin(euler.z*0.5);
+//         double c3 = Math.cos(euler.x*0.5);
+//         double s3 = Math.sin(euler.x*0.5);
+//         double c1c2 = c1*c2;
+//         double s1s2 = s1*s2;
+//         quat.w =c1c2*c3 - s1s2*s3;
+//         quat.x =c1c2*s3 + s1s2*c3;
+//         quat.y =s1*c2*c3 + c1*s2*s3;
+//         quat.z =c1*s2*c3 - s1*c2*s3;
+
+//         Quat4d q2 = EulerTools.getQuatFromEuler(Order.YZX, euler.y,euler.z,euler.x);
+//         System.out.println("Q " + quat + " Q2 " + q2);
+//        double c1 = Math.cos(euler.y);
+//         double s1 = Math.sin(euler.y);
+//         double c2 = Math.cos(euler.z);
+//         double s2 = Math.sin(euler.z);
+//         double c3 = Math.cos(euler.x);
+//         double s3 = Math.sin(euler.x);
+//         quat.w = Math.sqrt(1.0 + c1 * c2 + c1*c3 - s1 * s2 * s3 + c2*c3) / 2.0;
+//         double w4 = (4.0 * quat.w);
+//         quat.x = (c2 * s3 + c1 * s3 + s1 * s2 * c3) / w4 ;
+//         quat.y = (s1 * c2 + s1 * c3 + c1 * s2 * s3) / w4 ;
+//         quat.z = (-s1 * s3 + c1 * s2 * c3 +s2) / w4 ;
+   }
+   
+   
+  
+   
+   public static void getEuler(Quat4d quat,Vector3d euler)  {
+          Vector3d e = EulerTools.getEulerFromQuat(Order.YXZ, quat);
+          euler.x = e.y;
+          euler.y = e.x;
+          euler.z = e.z;
+          
+          // http://en.wikipedia.org/wiki/Rotation_formalisms_in_three_dimensions#Conversion_formulae_between_formalisms
+//        euler.x = Math.atan2(quat.x * quat.z + quat.y* quat.w, quat.y*quat.z - quat.x * quat.w);
+//        euler.y = Math.acos(-square(quat.x) - square(quat.y) + square(quat.z) + square(quat.w));
+//        euler.z = -Math.atan2(quat.x * quat.z - quat.y* quat.w, quat.y*quat.z + quat.x * quat.w);
+          
+          // http://www.euclideanspace.com/maths/geometry/rotations/conversions/quaternionToEuler/index.htm
+         // Y, Z, X order
+//        double test = quat.x * quat.y + quat.z * quat.w;
+//        if (test > NEAR_HALF) {
+//                euler.y = 2.0 * Math.atan2(quat.x,quat.w);
+//                euler.z = Math.PI * 0.5;
+//                euler.x = 0.0;
+//        } else if (test < -NEAR_HALF) {
+//                euler.y = -2.0 * Math.atan2(quat.x,quat.w);
+//                euler.z = -Math.PI * 0.5;
+//                euler.x = 0.0;
+//        } else {
+//                double sqx = square(quat.x);
+//                double sqy = square(quat.y);
+//                double sqz = square(quat.z);
+//                euler.y = Math.atan2(2.0*(quat.y*quat.w-quat.x*quat.z), 1.0 - 2.0*(sqy-sqz));
+//                euler.z = Math.asin(2.0*test);
+//                euler.x = Math.atan2(2.0*(quat.x*quat.w-quat.y*quat.z), 1.0 - 2.0*(sqx-sqz));
+//                System.out.println(euler + " " + EulerTools.getEulerFromQuat(Order.YXZ, quat) +  " " + quat);
+//        }
+//        double sqw = quat.w*quat.w;
+//         double sqx = quat.x*quat.x;
+//         double sqy = quat.y*quat.y;
+//         double sqz = quat.z*quat.z;
+//             double unit = sqx + sqy + sqz + sqw; // if normalised is one, otherwise is correction factor
+//             double test = quat.x*quat.y + quat.z*quat.w;
+//             if (test > 0.499*unit) { // singularity at north pole
+//                     euler.y = 2 * Math.atan2(quat.x,quat.w);
+//                     euler.z = Math.PI/2;
+//                     euler.x = 0;
+//                     return;
+//             }
+//             if (test < -0.499*unit) { // singularity at south pole
+//                     euler.y = -2 * Math.atan2(quat.x,quat.w);
+//                     euler.z = -Math.PI/2;
+//                     euler.x = 0;
+//                     return;
+//             }
+//             euler.y = Math.atan2(2*quat.y*quat.w-2*quat.x*quat.z , sqx - sqy - sqz + sqw);
+//             euler.z = Math.asin(2*test/unit);
+//             euler.x = Math.atan2(2*quat.x*quat.w-2*quat.y*quat.z , -sqx + sqy - sqz + sqw);
+   }
+   
+   public static Quat4d getQuat(Vector3d euler) {
+          Quat4d q = new Quat4d();
+          getQuat(euler,q);
+          return q;
+   }
+   
+   
+   public static Vector3d getEuler(Quat4d quat) {
+          Vector3d v = new Vector3d();
+          getEuler(quat, v);
+          return v;
+   }
+   
+   public static Quat4d getQuat(AxisAngle4d aa) {
+          Quat4d q = new Quat4d();
+          getQuat(aa, q);
+          return q;
+   }
+   
+       public static AxisAngle4d getAxisAngle(Quat4d q) {
+               AxisAngle4d aa = new AxisAngle4d();
+               double mag = q.x * q.x + q.y * q.y + q.z * q.z;
+
+               if (mag > EPS) {
+                       mag = Math.sqrt(mag);
+                       aa.angle = 2.0 * Math.atan2(mag, q.w);
+                       mag = 1.0 / mag;
+                       aa.x = q.x * mag;
+                       aa.y = q.y * mag;
+                       aa.z = q.z * mag;
+                       
+               } else {
+                       aa.x = 0.0;
+                       aa.y = 1.0;
+                       aa.z = 0.0;
+                       aa.angle = 0.0;
+               }
+               // aa.set(q);
+               return aa;
+       }
+   
+   public static Quat4d getIdentityQuat() {
+          return new Quat4d(0, 0, 0, 1);
+   }
+   
+   public static void getQuat(AxisAngle4d aa, Quat4d q) {
+          double mag,amag;
+               // Quat = cos(theta/2) + sin(theta/2)(roation_axis) 
+               
+               amag = Math.sqrt( aa.x*aa.x + aa.y*aa.y + aa.z*aa.z);
+               if( amag < NEAR_ZERO ) {
+                   q.w = 1.0;
+                   q.x = 0.0;
+                   q.y = 0.0;
+                   q.z = 0.0;
+               } else {  
+                  amag = 1.0/amag; 
+                  double a2 = aa.angle * 0.5;
+                  mag = Math.sin(a2);
+                  q.w = Math.cos(a2);
+              q.x = aa.x*amag*mag;
+              q.y = aa.y*amag*mag;
+              q.z = aa.z*amag*mag;
+               }
+   }
+   
+   
+       /*
+        * Cohen-Sutherland
+        */
+       
+       private static final int IN = 0;
+       private static final int LEFT = 1;
+       private static final int RIGHT = 2;
+       private static final int BOTTOM = 4;
+       private static final int TOP = 8;
+       
+       
+       private static int bitcode(Vector2f p1, Vector2f min, Vector2f max) {
+               int code = IN;
+               if (p1.x < min.x)
+                       code |= LEFT;
+               else if (p1.x > max.x)
+                       code |= RIGHT;
+               if (p1.y < min.y)
+                       code |= BOTTOM;
+               else if (p1.y > max.y)
+                       code |= TOP;
+               return code;
+       }
+       
+       public static boolean clipLineRectangle(Vector2f p1,Vector2f p2, Vector2f min, Vector2f max, Vector2f r1, Vector2f r2) {
+               while (true) {
+                       int o1 = bitcode(p1, min, max);
+                       int o2 = bitcode(p2, min, max);
+                       int and = o1 & o2;
+                       int or = o1 | o2;
+                       if (and != IN) {
+                               return false;
+                       }
+                       if (or == IN) {
+                               r1.set(p1);
+                               r2.set(p2);
+                               return true;
+                       }
+                       if (o1 == IN) {
+                               Vector2f t = p1;
+                               p1 = p2;
+                               p2 = t;
+                               int t2 = o1;
+                               o1 = o2;
+                               o2 = t2;
+                       }
+                       if ((o1 & TOP) != IN) {
+                               float t = (max.y - p1.y) / (p2.y - p1.y);
+                               p1.x += t * (p2.x - p1.x);
+                               p1.y = max.y;
+                       } else if ((o1 & BOTTOM) != IN) {
+                               float t = (min.y - p1.y) / (p2.y - p1.y);
+                               p1.x += t * (p2.x - p1.x);
+                               p1.y = min.y;
+                       } else if ((o1 & LEFT) != IN) {
+                               float t = (min.x - p1.x) / (p2.x - p1.x);
+                               p1.y += t * (p2.y - p1.y);
+                               p1.x = min.x;
+                       } else if ((o1 & RIGHT) != IN) {
+                               float t = (max.x - p1.x) / (p2.x - p1.x);
+                               p1.y += t * (p2.y - p1.y);
+                               p1.x = max.x;
+                       } else {
+                               throw new RuntimeException("Error in clipping code");
+                       }
+               }
+               
+       }
+       
+       public static double square(double d) {
+               return d * d;
+       }
+       
+       
+        public static void multiplyOrientation(AxisAngle4d aa, AxisAngle4d rot)  {
+               Quat4d q1 = new Quat4d();
+               getQuat(aa, q1);
+               Quat4d q2 = new Quat4d();
+               getQuat(rot, q2);
+               q2.mul(q1);
+               rot.set(q2);
+        }
+        
+        public static double radToDeg(double rad) {
+                return (rad / Math.PI) * 180.0;
+        }
+        
+        public static double degToRad(double deg) {
+                return (deg / 180.0) * Math.PI;
+        }
+        
+        public static double clamp(double min, double max,double v) {
+                if (v < min)
+                        return min;
+                if (v > max)
+                        return max;
+                return v;
+        }
+        
+        public static AxisAngle4d createRotation(Vector3d original, Vector3d rotated) { 
+               AxisAngle4d result = new AxisAngle4d();
+               if (createRotation(original, rotated, result))
+                       return result;
+               return null;
+        }
+        
+        
+        public static void setIdentity(Quat4d q) {
+               q.w = 1.0;
+               q.x = 0.0;
+               q.y = 0.0;
+               q.z = 0.0;
+        }
+        
+       public static void setIdentity(AxisAngle4d aa) {
+               aa.angle = 0.0;
+               aa.x = 0.0;
+               aa.y = 1.0;
+               aa.z = 0.0;
+       }
+       
+       public static void set(Matrix3d mat, double m00, double m01, double m02,
+                       double m10, double m11, double m12, double m20, double m21,
+                       double m22) {
+               mat.m00 = m00;
+               mat.m01 = m01;
+               mat.m02 = m02;
+
+               mat.m10 = m10;
+               mat.m11 = m11;
+               mat.m12 = m12;
+
+               mat.m20 = m20;
+               mat.m21 = m21;
+               mat.m22 = m22;
+       }
+       
+       public static void set(Matrix4d mat, double[] v) {
+               mat.m00 = v[0];
+               mat.m01 = v[1];
+               mat.m02 = v[2];
+               mat.m03 = v[3];
+
+               mat.m10 = v[4];
+               mat.m11 = v[5];
+               mat.m12 = v[6];
+               mat.m13 = v[7];
+
+               mat.m20 = v[8];
+               mat.m21 = v[9];
+               mat.m22 = v[10];
+               mat.m23 = v[11];
+
+               mat.m30 = v[12];
+               mat.m31 = v[13];
+               mat.m32 = v[14];
+               mat.m33 = v[15];
+
+       }
+        
+        public static boolean createRotation(Vector3d original, Vector3d rotated, AxisAngle4d result) {
+                
+                       if (rotated.lengthSquared() > 0.01)
+                               rotated.normalize();
+                       else
+                               return false;
+                       double d = original.dot(rotated);
+                       if (d > 0.9999) {
+                               // original and rotated are parallel, pointing at the same direction
+                               result.angle = 0.0;
+                               result.x = 0.0;
+                               result.y = 1.0;
+                               result.z = 0.0;
+                       } else if (d < -0.9999) {
+                               // original and rotated are parallel, pointing at the opposite direction 
+                               Vector3d a = Z_AXIS;
+                               if (Math.abs(a.dot(original)) > 0.8 )
+                                       a = Y_AXIS;
+                               result.set(a, Math.PI);
+                       } else {
+                               double angle = original.angle(rotated);
+                               Vector3d axis = new Vector3d();
+                               axis.cross(original, rotated);
+                               result.set(axis,angle);
+                       }
+                       return true;
+                }
+        
+        public static boolean createRotation(Vector3d original, Vector3d rotated, Quat4d result) {
+                
+                       if (rotated.lengthSquared() > 0.01)
+                               rotated.normalize();
+                       else
+                               return false;
+                       double d = original.dot(rotated);
+                       if (d > 0.9999) {
+                               // original and rotated are parallel, pointing at the same direction
+                               result.w = 1.0;
+                               result.x = 0.0;
+                               result.y = 0.0;
+                               result.z = 0.0;
+                       } else if (d < -0.9999) {
+                               // original and rotated are parallel, pointing at the opposite direction 
+                               Vector3d a = Z_AXIS;
+                               if (Math.abs(a.dot(original)) > 0.8 )
+                                       a = Y_AXIS;
+                               getQuat(a, Math.PI, result);
+                               
+                       } else {
+                               double angle = original.angle(rotated);
+                               Vector3d axis = new Vector3d();
+                               axis.cross(original, rotated);
+                               getQuat(axis, angle, result);
+                       }
+                       return true;
+                }
+        
+        public static void getQuat(Vector3d axis, double angle, Quat4d q)
+    {
+               double mag,amag;
+               // Quat = cos(theta/2) + sin(theta/2)(roation_axis) 
+               
+               amag = Math.sqrt( axis.x*axis.x + axis.y*axis.y + axis.z*axis.z);
+               if( amag < EPS ) {
+                   q.w = 1.0;
+                   q.x = 0.0;
+                   q.y = 0.0;
+                   q.z = 0.0;
+               } else {  
+                   amag = 1.0/amag; 
+                   double a2 = angle*0.5;
+                   mag = Math.sin(a2);
+                   q.w = Math.cos(a2);
+                   q.x = axis.x*amag*mag;
+                   q.y = axis.y*amag*mag;
+                   q.z = axis.z*amag*mag;
+               }
+       
+    }
+        
+        /**
+         * Linear interpolation of quaternions. Result IS set to q1.
+         * @param q1
+         * @param q2
+         * @param alpha
+         */
+        public static void lip(Quat4d q1, Quat4d q2, double alpha) {
+                double s1 = 1.0 - alpha;
+                double s2 = alpha;
+                q1.scale(s1);
+                mad(q1,q2,s2);
+                q1.normalize();
+        }
+        
+        public static double dot(Quat4d q1, Quat4d q2) {
+                return q1.x * q2.x + q1.y * q2.y + q1.z * q2.z + q1.w * q2.w;
+        }
+        
+        public static void mad(Tuple3d q1, Tuple3d q2, double s2) {
+                q1.x += q2.x * s2;
+                q1.y += q2.y * s2;
+                q1.z += q2.z * s2;
+        }
+        
+        public static void mad(Quat4d q1, Quat4d q2, double s2) {
+                q1.x += q2.x * s2;
+                q1.y += q2.y * s2;
+                q1.z += q2.z * s2;
+                q1.w += q2.w * s2;
+        }
+        
+        /**
+         * Slerp
+         * 
+         * Sets results to q1. Modifies q2.
+         * 
+         * @param q1
+         * @param q2
+         * @param alpha
+         */
+        public static void sip(Quat4d q1, Quat4d q2, double alpha) {
+                double cosom = dot(q1,q2);
+                if (cosom < 0.0) {
+                        cosom = -cosom;
+                        q2.negate();
+                }
+                
+                if (cosom > 0.9999) {
+                        q2.sub(q1);
+                        q2.scale(alpha);
+                        q1.add(q2);
+                        q1.normalize();
+                        return;
+                }
+                double theta_0 = Math.acos(cosom);
+                double theta = theta_0 * alpha;
+                Quat4d t = new Quat4d(q1);
+                t.scale(-cosom);
+                t.add(q2);
+                t.normalize();
+                t.scale(Math.sin(theta));
+                q1.scale(Math.cos(theta));
+                q1.add(t);
+        }
+        
+        
+        public static void rotate(double angle, Tuple2d v1, Tuple2d v2) {
+                // TODO : verify implementation
+        double sin = Math.sin(angle);
+        if (sin == 1.0) {
+            v2.x = v1.y;
+            v2.y = -v1.x;
+        } else if (sin == -1.0) {
+               v2.x = -v1.y;
+            v2.y = v1.x;
+        } else {
+            double cos = Math.cos(angle);
+            if (cos == -1.0) {
+                v2.x = -v1.x;
+                v2.y = -v1.y;
+            } else if (cos != 1.0) {
+                v2.x= v1.x * cos + v1.y * -sin;
+                v2.y= v1.x* sin + v1.y *cos;
+            }
+        }      
+        }
+        
+        public static Tuple3d getPosRot(double m3x2[]) {
+                Vector3d t = new Vector3d();
+                t.x = m3x2[4];
+                t.y = m3x2[5];
+                
+                
+                Vector2d v2 = new Vector2d(1,0);
+                Vector2d v = new Vector2d();
+                // use rotation of (1,0) to calculate the rotation component
+         v.x  =  m3x2[0];
+         v.y  =  m3x2[2];
+         double a1 = v2.angle(v);
+         if (v.y < 0) {
+                t.z = a1;
+         } else {
+                t.z = Math.PI*2.0 - a1;
+         }
+         return t;
+        }
+}
index b922e77d3fc937a19734bbd5ec6f388b286b6860..21e773c1c82c2fdf4dbda2e91a3e59afdeb272ee 100644 (file)
-/*******************************************************************************\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
-import java.util.function.Consumer;\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
-               @Override\r
-               public void updatePartName(Consumer<String> updateCallback) {\r
-                       if (node != null)\r
-                               updateCallback.accept(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 (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;
+                       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<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);
+       }
+       
+       
+}
index 7e0f31e6439c02112d4ce45ba0b350eab263fb0a..6324d90e9f8be9b85f50c02af69286301accc16f 100644 (file)
@@ -1,59 +1,62 @@
-/*******************************************************************************\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.scenegraph;\r
-\r
-import java.util.Collection;\r
-\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
-\r
-public interface NodeMap<T> {\r
-\r
-       public Collection<T> getRenderObjects(INode node);\r
-       \r
-       public void updateRenderObjectsFor(INode node);\r
-       \r
-       public INode getNode(T t);\r
-       \r
-       public ParentNode<IG3DNode> getRootNode();\r
-       \r
-       /**\r
-        * Commit changes to the database.\r
-        */\r
-       public void commit();\r
-       \r
-       \r
-       /**\r
-        * Deletes (Disposes) the map. \r
-        */\r
-       public void delete();\r
-       \r
-       \r
-       /**\r
-        * Track changes that are going to be committed into the database.\r
-        * \r
-        * Disabling change tracking causes commit() to do nothing. \r
-        * @param enabled\r
-        */\r
-       public void setChangeTracking(boolean enabled);\r
-       public boolean  isChangeTracking();\r
-       \r
-       \r
-       /**\r
-        * Add listener for all scene-graph events.\r
-        * @param listener\r
-        */\r
-       public void addListener(NodeListener listener);\r
-       \r
-       public void removeListener(NodeListener listener);\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.scenegraph;
+
+import java.util.Collection;
+
+import org.simantics.g3d.scenegraph.base.INode;
+import org.simantics.g3d.scenegraph.base.NodeListener;
+import org.simantics.g3d.scenegraph.base.ParentNode;
+import org.simantics.objmap.graph.IMapping;
+
+public interface NodeMap<T,E extends INode> {
+
+       public Collection<T> getRenderObjects(E node);
+       
+       public void updateRenderObjectsFor(E node);
+       
+       public E getNode(T t);
+       
+       public ParentNode<E> getRootNode();
+       
+       /**
+        * Commit changes to the database.
+        */
+       public void commit();
+       
+       
+       /**
+        * Deletes (Disposes) the map. 
+        */
+       public void delete();
+       
+       
+       /**
+        * Track changes that are going to be committed into the database.
+        * 
+        * Disabling change tracking causes commit() to do nothing. 
+        * @param enabled
+        */
+       public void setChangeTracking(boolean enabled);
+       public boolean  isChangeTracking();
+       
+       
+       /**
+        * Add listener for all scene-graph events.
+        * @param listener
+        */
+       public void addListener(NodeListener listener);
+       
+       public void removeListener(NodeListener listener);
+       
+       public IMapping<Object, E> getMapping();
+}
index 657fe1567b2b010d01f67547c17a8452861c3359..e9b7d4b4147eb7bdfa8d2019e0d937ea99c9db5f 100644 (file)
@@ -1,17 +1,19 @@
-/*******************************************************************************\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.scenegraph;\r
-\r
-public interface NodeMapProvider<T> {\r
-\r
-       public NodeMap<T> getNodeMap();\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.scenegraph;
+
+import org.simantics.g3d.scenegraph.base.INode;
+
+public interface NodeMapProvider<T,E extends INode> {
+
+       public NodeMap<T,E> getNodeMap();
+}
index d3d276d310770fe01d6bd85a0977562697298a53..a8379433428befd060ed916050646ea58c1e5029 100644 (file)
@@ -1,66 +1,66 @@
-/*******************************************************************************\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.scenegraph.base;\r
-\r
-import java.util.List;\r
-\r
-\r
-\r
-\r
-\r
-public interface INode {\r
-       \r
-       /**\r
-     * \r
-     * @return unique node identifier\r
-     */\r
-    public Long getId();\r
-\r
-        /**\r
-     * @return root node of the scene graph or <code>null</code> if this node is\r
-     *         not part of a properly rooted scene graph hierarchy\r
-     */\r
-    public ParentNode<?> getRootNode();\r
-\r
-    /**\r
-     * @return Parent node reference or <code>null</code> if not set\r
-     */\r
-    public ParentNode<?> getParent();\r
-    \r
-    public String getParentRel();\r
-    /**\r
-     * Set parent node. This method is for scene graph internal use only and\r
-     * should not be called outside the scene graph structure. This method\r
-     * simply sets the parent node parent field, and does not affect on parent\r
-     * node (i.e., should be called only from parent node).\r
-     */\r
-    public void setParent(ParentNode<?> parent, String name);\r
-\r
-    /**\r
-     * Perform cleanup for this node and for the child nodes. Any resources\r
-     * (including child nodes) related to this node are unusable after this\r
-     * operation. This method is for scene graph internal use only, thus should\r
-     * not be called outside the scene graph structure.\r
-     */\r
-    public void cleanup();\r
-    /**\r
-     * Remove this node and its children from the scene graph.\r
-     */\r
-    public void remove();\r
-\r
-    \r
-    public void addListener(NodeListener listener);\r
-       public void removeListener(NodeListener listener);\r
-       \r
-       public List<NodeListener> getListeners();\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.scenegraph.base;
+
+import java.util.List;
+
+
+
+
+
+public interface INode {
+       
+       /**
+     * 
+     * @return unique node identifier
+     */
+   // public Long getId();
+
+        /**
+     * @return root node of the scene graph or <code>null</code> if this node is
+     *         not part of a properly rooted scene graph hierarchy
+     */
+    public ParentNode<?> getRootNode();
+
+    /**
+     * @return Parent node reference or <code>null</code> if not set
+     */
+    public ParentNode<?> getParent();
+    
+    public String getParentRel();
+    /**
+     * Set parent node. This method is for scene graph internal use only and
+     * should not be called outside the scene graph structure. This method
+     * simply sets the parent node parent field, and does not affect on parent
+     * node (i.e., should be called only from parent node).
+     */
+    public void setParent(ParentNode<?> parent, String name);
+
+    /**
+     * Perform cleanup for this node and for the child nodes. Any resources
+     * (including child nodes) related to this node are unusable after this
+     * operation. This method is for scene graph internal use only, thus should
+     * not be called outside the scene graph structure.
+     */
+    public void cleanup();
+    /**
+     * Remove this node and its children from the scene graph.
+     */
+    public void remove();
+
+    
+    public void addListener(NodeListener listener);
+       public void removeListener(NodeListener listener);
+       
+       public List<NodeListener> getListeners();
+
+}