]> gerrit.simantics Code Review - simantics/3d.git/blob - org.simantics.g3d.vtk/src/org/simantics/g3d/vtk/common/AbstractVTKNodeMap.java
Recomplied G3D ontologies and updated AnntotatedPropertyTabContrubutor
[simantics/3d.git] / org.simantics.g3d.vtk / src / org / simantics / g3d / vtk / common / AbstractVTKNodeMap.java
1 /*******************************************************************************\r
2  * Copyright (c) 2012, 2013 Association for Decentralized Information Management in\r
3  * Industry THTH ry.\r
4  * All rights reserved. This program and the accompanying materials\r
5  * are made available under the terms of the Eclipse Public License v1.0\r
6  * which accompanies this distribution, and is available at\r
7  * http://www.eclipse.org/legal/epl-v10.html\r
8  *\r
9  * Contributors:\r
10  *     VTT Technical Research Centre of Finland - initial API and implementation\r
11  *******************************************************************************/\r
12 package org.simantics.g3d.vtk.common;\r
13 \r
14 import java.util.ArrayList;\r
15 import java.util.Collection;\r
16 import java.util.HashMap;\r
17 import java.util.HashSet;\r
18 import java.util.List;\r
19 import java.util.Map;\r
20 import java.util.Set;\r
21 import java.util.Stack;\r
22 \r
23 import org.simantics.db.ReadGraph;\r
24 import org.simantics.db.Resource;\r
25 import org.simantics.db.Session;\r
26 import org.simantics.db.WriteGraph;\r
27 import org.simantics.db.common.request.ReadRequest;\r
28 import org.simantics.db.common.request.WriteRequest;\r
29 import org.simantics.db.exception.DatabaseException;\r
30 import org.simantics.g3d.ontology.G3D;\r
31 import org.simantics.g3d.scenegraph.IG3DNode;\r
32 import org.simantics.g3d.scenegraph.RenderListener;\r
33 import org.simantics.g3d.scenegraph.base.INode;\r
34 import org.simantics.g3d.scenegraph.base.NodeListener;\r
35 import org.simantics.g3d.scenegraph.base.ParentNode;\r
36 import org.simantics.objmap.graph.IMapping;\r
37 import org.simantics.objmap.graph.IMappingListener;\r
38 import org.simantics.utils.datastructures.Callback;\r
39 import org.simantics.utils.datastructures.MapList;\r
40 import org.simantics.utils.datastructures.MapSet;\r
41 import org.simantics.utils.datastructures.Pair;\r
42 import org.simantics.utils.ui.ExceptionUtils;\r
43 \r
44 import vtk.vtkProp;\r
45 \r
46 public abstract class AbstractVTKNodeMap<E extends INode> implements VTKNodeMap, IMappingListener, RenderListener, NodeListener{\r
47 \r
48         private static final boolean DEBUG = false;\r
49         \r
50         protected Session session;\r
51         protected IMapping<Object,E> mapping;\r
52         protected InteractiveVtkPanel panel;\r
53         \r
54         protected MapList<E, vtkProp> nodeToActor = new MapList<E, vtkProp>();\r
55         protected Map<vtkProp,E> actorToNode = new HashMap<vtkProp, E>();\r
56 \r
57         protected ParentNode<E> rootNode;\r
58         \r
59         public AbstractVTKNodeMap(Session session, IMapping<Object,E> mapping, InteractiveVtkPanel panel, ParentNode<E> rootNode) {\r
60                 this.session = session;\r
61                 this.mapping = mapping;\r
62                 this.panel = panel;\r
63                 this.rootNode = rootNode;\r
64                 panel.addListener(this);\r
65                 mapping.addMappingListener(this);\r
66                 rootNode.addListener(this);\r
67         }\r
68         \r
69         \r
70         protected abstract void addActor(E node);\r
71         protected abstract void removeActor(E node);\r
72         protected abstract void updateActor(E node,Set<String> ids);\r
73         \r
74         public void repaint() {\r
75                 panel.repaint();\r
76         }\r
77         \r
78         public void populate() {\r
79                 for (E node : rootNode.getNodes()) {\r
80                         receiveAdd(node, node.getParentRel(),true);\r
81                 }\r
82                 repaint();\r
83         }\r
84         \r
85         @Override\r
86         public INode getNode(vtkProp prop) {\r
87                 return actorToNode.get(prop);\r
88         }\r
89         \r
90         @SuppressWarnings("unchecked")\r
91         @Override\r
92         public Collection<vtkProp> getRenderObjects(INode node) {\r
93                 return nodeToActor.getValues((E)node);\r
94         }\r
95         \r
96         @SuppressWarnings("unchecked")\r
97         @Override\r
98         public ParentNode<IG3DNode> getRootNode() {\r
99                 return (ParentNode<IG3DNode>)rootNode;\r
100         }\r
101         \r
102         \r
103         \r
104         @Override\r
105         public boolean isChangeTracking() {\r
106                 return changeTracking;\r
107         }\r
108         \r
109         @Override\r
110         public void setChangeTracking(boolean enabled) {\r
111                 changeTracking = enabled;\r
112         }\r
113         \r
114         private boolean changeTracking = true;\r
115         \r
116         protected Object syncMutex = new Object(); \r
117         \r
118 \r
119         private List<Pair<E,String>> added = new ArrayList<Pair<E,String>>();\r
120         private List<Pair<E,String>> removed = new ArrayList<Pair<E,String>>();\r
121         //private List<Pair<E,String>> updated = new ArrayList<Pair<E,String>>();\r
122         private MapSet<E, String> updated = new MapSet.Hash<E, String>();\r
123 \r
124         private boolean rangeModified = false;\r
125         \r
126         @SuppressWarnings("unchecked")\r
127         @Override\r
128         public void updateRenderObjectsFor(INode node) {\r
129                 List<vtkProp> toDelete = new ArrayList<vtkProp>();\r
130                 for (vtkProp prop : nodeToActor.getValues((E)node)) {\r
131                         if (prop.GetVTKId() != 0) {\r
132                                 panel.GetRenderer().RemoveActor(prop);\r
133                                 //prop.Delete();\r
134                                 toDelete.add(prop);\r
135                         }\r
136                         actorToNode.remove(prop);\r
137                 }\r
138                 nodeToActor.remove((E)node);\r
139                 Collection<vtkProp> coll = getActors((E)node);\r
140                 if (coll == null)\r
141                         return;\r
142                 for (vtkProp prop : coll) {\r
143                         nodeToActor.add((E)node,prop);\r
144                         actorToNode.put(prop, (E)node);\r
145                         toDelete.remove(prop);\r
146                 }\r
147                 for (vtkProp p : toDelete)\r
148                         p.Delete();\r
149         }\r
150         \r
151         protected abstract  Collection<vtkProp> getActors(E node);\r
152         \r
153         @SuppressWarnings("unchecked")\r
154         private void receiveAdd(E node, String id, boolean db) {\r
155                 if (DEBUG) System.out.println("receiveAdd " + node  + " " + id + " " + db);\r
156                 synchronized (syncMutex) {\r
157                         for (Pair<E, String> n : added) {\r
158                                 if (n.first.equals(node))\r
159                                         return;\r
160                         }\r
161                         if (changeTracking) {\r
162                                 mapping.rangeModified((E)node.getParent());\r
163                         }\r
164                         added.add(new Pair<E, String>(node, id));\r
165                         rangeModified = true;\r
166                 }\r
167                 panel.repaint();\r
168         }\r
169         \r
170         @SuppressWarnings("unchecked")\r
171         private void receiveRemove(E node, String id, boolean db) {\r
172                 if (DEBUG) System.out.println("receiveRemove " + node  + " " + id + " " + db);\r
173                 synchronized (syncMutex) {\r
174                         for (Pair<E, String> n : removed) {\r
175                                 if (n.first.equals(node))\r
176                                         return;\r
177                         }\r
178                         if (changeTracking && !db)\r
179                                 mapping.rangeModified((E)node.getParent());\r
180                         removed.add(new Pair<E, String>(node, id));\r
181                         rangeModified = true;\r
182                 }\r
183                 panel.repaint();\r
184         }\r
185         \r
186         @SuppressWarnings("unchecked")\r
187         private void receiveUpdate(E node, String id, boolean db) {\r
188                 if (DEBUG) System.out.println("receiveUpdate " + node  + " " + id + " " + db);\r
189                 synchronized (syncMutex) {\r
190 //                      for (Pair<E, String> n : updated) {\r
191 //                              if (n.first.equals(node))\r
192 //                                      return;\r
193 //                      }\r
194                         if (changeTracking && !db)\r
195                                 mapping.rangeModified(node);\r
196                         //updated.add(new Pair<E, String>(node, id));\r
197                         updated.add(node, id);\r
198                         rangeModified = true;\r
199                 }\r
200                 panel.repaint();\r
201         }\r
202         \r
203         private boolean graphUpdates = false;\r
204         private Set<E> graphModified = new HashSet<E>();\r
205         \r
206         private boolean requestCommit = false;\r
207         \r
208         @Override\r
209         public void commit() {\r
210                 requestCommit = true;\r
211         }\r
212         \r
213         protected void doCommit() {\r
214                 session.asyncRequest(new WriteRequest() {\r
215                         \r
216                         @Override\r
217                         public void perform(WriteGraph graph) throws DatabaseException {\r
218                                 commit(graph);\r
219                         }\r
220                         \r
221                 }, new Callback<DatabaseException>() {\r
222                         \r
223                         @Override\r
224                         public void run(DatabaseException parameter) {\r
225                                 if (parameter != null)\r
226                                         ExceptionUtils.logAndShowError("Cannot commit editor changes", parameter);\r
227                         }\r
228                 });\r
229         }\r
230         \r
231         protected void commit(WriteGraph graph) throws DatabaseException {\r
232                 synchronized(syncMutex) {\r
233                         if (DEBUG) System.out.println("Commit");\r
234                         graphUpdates = true;\r
235                         mapping.updateDomain(graph);\r
236                         graphUpdates = false;\r
237                 }\r
238         }\r
239         \r
240         @Override\r
241         public void domainModified() {\r
242                 if (graphUpdates)\r
243                         return;\r
244                 if (DEBUG)System.out.println("domainModified");\r
245                 session.asyncRequest(new ReadRequest() {\r
246                         \r
247                         @SuppressWarnings("unchecked")\r
248                         @Override\r
249                         public void run(ReadGraph graph) throws DatabaseException {\r
250                                 update(graph);\r
251                         }\r
252                 });\r
253                 \r
254         }\r
255         \r
256         protected void update(ReadGraph graph) throws DatabaseException {\r
257                 synchronized (syncMutex) {\r
258                         graphUpdates = true;\r
259                         for (Object domainObject : mapping.getDomainModified()) {\r
260                                 E rangeObject = mapping.get(domainObject);\r
261                                 if (rangeObject != null)\r
262                                         graphModified.add(rangeObject);\r
263                         }\r
264                         mapping.updateRange(graph);\r
265                         graphModified.clear();\r
266                         graphUpdates = false;\r
267                 }\r
268                 \r
269                 if (mapping.isRangeModified())\r
270                         commit();\r
271         }\r
272         \r
273         @Override\r
274         public void rangeModified() {\r
275                 //System.out.println("rangeModified");\r
276 \r
277         }\r
278         \r
279         @Override\r
280         public void postRender() {\r
281                 // Commit changes if\r
282                 // 1. Commit has been requested\r
283                 // 2. There are no pending changes that should be processed in preRender() \r
284                 if (requestCommit && !rangeModified) { // FIXME : not thread safe.\r
285                         requestCommit = false;\r
286                         doCommit();\r
287                 }\r
288         }\r
289         \r
290         List<Pair<E, String>> rem = new ArrayList<Pair<E,String>>();\r
291         List<Pair<E, String>> add = new ArrayList<Pair<E,String>>();\r
292         MapSet<E, String> mod = new MapSet.Hash<E, String>();\r
293         Set<E> propagation = new HashSet<E>();\r
294         Stack<E> stack = new Stack<E>();\r
295         \r
296         \r
297         @Override\r
298         public synchronized void preRender() {\r
299                 updateCycle();\r
300         }\r
301         \r
302         @SuppressWarnings("unchecked")\r
303         protected void updateCycle() {\r
304                 rem.clear();\r
305                 add.clear();\r
306                 mod.clear();\r
307                 propagation.clear();\r
308                 \r
309                 synchronized (syncMutex) {\r
310                         rem.addAll(removed);\r
311                         add.addAll(added);\r
312                         for (E e : updated.getKeys()) {\r
313                                 for (String s : updated.getValues(e)) {\r
314                                         mod.add(e, s);\r
315                                 }\r
316                         }\r
317                         \r
318                         removed.clear();\r
319                         added.clear();\r
320                         updated.clear();\r
321                 }\r
322                 \r
323                 for (Pair<E, String> n : rem) {\r
324                         stopListening(n.first);\r
325                         removeActor(n.first);\r
326                 \r
327                 }\r
328                 \r
329                 for (Pair<E, String> n : add) {\r
330                         addActor(n.first);\r
331                         listen(n.first);\r
332                 }\r
333                 \r
334                 for (E e : mod.getKeys()) {\r
335                         Set<String> ids = mod.getValues(e);\r
336                         if (ids.contains(G3D.URIs.hasPosition) || ids.contains(G3D.URIs.hasOrientation)) {\r
337                                 if (!propagation.contains(e))\r
338                                         propagation.add(e);\r
339                         }\r
340                 }\r
341 \r
342                 if (propagation.size() > 0) {\r
343                         stack.clear();\r
344                         stack.addAll(propagation);\r
345                         propagation.clear();\r
346                         while (!stack.isEmpty()) {\r
347                                 E node = stack.pop();\r
348                                 if (propagation.contains(node))\r
349                                         continue;\r
350                                 propagation.add(node);\r
351                                 for (NodeListener l : node.getListeners()) {\r
352                                         if (l == this) {\r
353                                                 //changeTracking = false;\r
354                                                 //l.propertyChanged(node, G3D.URIs.hasPosition);\r
355                                                 //changeTracking = true;\r
356                                         } else {\r
357                                                 l.propertyChanged(node, G3D.URIs.hasWorldPosition);\r
358                                         }\r
359                                 }\r
360                                 if (node instanceof ParentNode) {\r
361                                         stack.addAll(((ParentNode<E>)node).getNodes());\r
362                                 }\r
363                         }\r
364                 }\r
365                 \r
366 //              synchronized (syncMutex) {\r
367 //                      rem.addAll(removed);\r
368 //                      add.addAll(added);\r
369 //                      //mod.addAll(updated);\r
370 //                      for (E e : updated.getKeys()) {\r
371 //                              for (String s : updated.getValues(e))\r
372 //                                      mod.add(e, s);\r
373 //                      }\r
374 //                      \r
375 //                      removed.clear();\r
376 //                      added.clear();\r
377 //                      updated.clear();\r
378 //              }\r
379                 \r
380                 for (E e : mod.getKeys()) {\r
381                         Set<String> ids = mod.getValues(e);\r
382                         updateActor(e,ids);\r
383                 }\r
384                 \r
385                 \r
386                 for (Pair<E, String> n : rem) {\r
387                         for (NodeListener l : nodeListeners)\r
388                                 l.nodeRemoved(null, n.first, n.second);\r
389                 }\r
390                 for (Pair<E, String> n : add) {\r
391                         for (NodeListener l : nodeListeners)\r
392                                 l.nodeAdded(n.first.getParent(), n.first, n.second);\r
393                 }\r
394 //              for (Pair<E, String> n : mod) {\r
395 //                      for (NodeListener l : nodeListeners)\r
396 //                              l.propertyChanged(n.first, n.second);\r
397 //              }\r
398                 for (E e : mod.getKeys()) {\r
399                         for (NodeListener l : nodeListeners)\r
400                                 for (String s : mod.getValues(e))\r
401                                         l.propertyChanged(e, s);\r
402                 }\r
403                 synchronized (syncMutex) {\r
404                         if (added.isEmpty() && removed.isEmpty() && updated.getKeys().size() == 0)\r
405                                 rangeModified = false;\r
406                 }\r
407         }\r
408         \r
409         @SuppressWarnings("unchecked")\r
410         private void listen(INode node) {\r
411                 node.addListener(this);\r
412                 if (node instanceof ParentNode<?>) {\r
413                         ParentNode<INode> parentNode = (ParentNode<INode>)node;\r
414                         for (INode n : parentNode.getNodes())\r
415                                 listen(n);\r
416                 }\r
417         }\r
418         \r
419         private void stopListening(INode node) {\r
420                 node.removeListener(this);\r
421                 if (node instanceof ParentNode<?>) {\r
422                         @SuppressWarnings("unchecked")\r
423                         ParentNode<INode> parentNode = (ParentNode<INode>)node;\r
424                         for (INode n : parentNode.getNodes())\r
425                                 stopListening(n);\r
426                 }\r
427         }\r
428         \r
429         @SuppressWarnings("unchecked")\r
430         @Override\r
431         public void propertyChanged(INode node, String id) {\r
432                 //receiveUpdate((E)node, id, graphUpdates);\r
433                 receiveUpdate((E)node, id, graphModified.contains(node));\r
434                 \r
435         }\r
436         \r
437         @SuppressWarnings("unchecked")\r
438         @Override\r
439         public <T extends INode> void nodeAdded(ParentNode<T> node, INode child,\r
440                         String rel) {\r
441                 if (DEBUG) System.out.println("Node added " + child + " parent " + node);\r
442                 //receiveAdd((E)child, rel ,graphUpdates);\r
443                 receiveAdd((E)child, rel ,graphModified.contains(node));\r
444                 \r
445         }\r
446         \r
447         @SuppressWarnings("unchecked")\r
448         @Override\r
449         public <T extends INode> void nodeRemoved(ParentNode<T> node, INode child,\r
450                         String rel) {\r
451                 if (DEBUG) System.out.println("Node removed " + child + " parent " + node);\r
452                 //receiveRemove((E)child, rel, graphUpdates);\r
453                 receiveRemove((E)child, rel, graphModified.contains(node));\r
454                 \r
455                 //FIXME : sometimes removed structural models cause ObjMap to add their children again.\r
456                 //        removing the listener here prevents corruption of visual model, but better fix is needed.\r
457                 stopListening(child);\r
458         }\r
459         \r
460         @Override\r
461         public void delete() {\r
462                 changeTracking = false;\r
463                 panel.removeListener(this);\r
464                 mapping.removeMappingListener(this);\r
465 \r
466                 List<E> nodes = new ArrayList<E>(nodeToActor.getKeySize());\r
467                 nodes.addAll(nodeToActor.getKeys());\r
468                 for (E node : nodes) {\r
469                         node.removeListener(this);\r
470                         removeActor(node);\r
471                         node.cleanup();\r
472                 }\r
473                 for (vtkProp prop : actorToNode.keySet()) {\r
474                         if (prop.GetVTKId() != 0) \r
475                                 prop.Delete();\r
476                 }\r
477                 actorToNode.clear();\r
478                 nodeToActor.clear();\r
479                 \r
480         }\r
481         \r
482         \r
483         private List<NodeListener> nodeListeners = new ArrayList<NodeListener>();\r
484         @Override\r
485         public void addListener(NodeListener listener) {\r
486                 nodeListeners.add(listener);\r
487                 \r
488         }\r
489         \r
490         @Override\r
491         public void removeListener(NodeListener listener) {\r
492                 nodeListeners.remove(listener);\r
493                 \r
494         }\r
495         \r
496         public IMapping<Object,E> getMapping() {\r
497                 return mapping;\r
498         }\r
499         \r
500         \r
501 }\r