]> gerrit.simantics Code Review - simantics/3d.git/blob - org.simantics.g3d.jme/src/org/simantics/g3d/jme/common/AbstractJMENodeMap.java
Alpha-version of jME-bindings for g3d.
[simantics/3d.git] / org.simantics.g3d.jme / src / org / simantics / g3d / jme / common / AbstractJMENodeMap.java
1 package org.simantics.g3d.jme.common;\r
2 \r
3 import java.util.ArrayList;\r
4 import java.util.Collection;\r
5 import java.util.HashMap;\r
6 import java.util.HashSet;\r
7 import java.util.List;\r
8 import java.util.Map;\r
9 import java.util.Set;\r
10 import java.util.Stack;\r
11 \r
12 import org.simantics.db.ReadGraph;\r
13 import org.simantics.db.Session;\r
14 import org.simantics.db.WriteGraph;\r
15 import org.simantics.db.common.request.ReadRequest;\r
16 import org.simantics.db.common.request.WriteRequest;\r
17 import org.simantics.db.exception.DatabaseException;\r
18 import org.simantics.g3d.ontology.G3D;\r
19 import org.simantics.g3d.scenegraph.IG3DNode;\r
20 import org.simantics.g3d.scenegraph.RenderListener;\r
21 import org.simantics.g3d.scenegraph.base.INode;\r
22 import org.simantics.g3d.scenegraph.base.NodeListener;\r
23 import org.simantics.g3d.scenegraph.base.ParentNode;\r
24 import org.simantics.objmap.graph.IMapping;\r
25 import org.simantics.objmap.graph.IMappingListener;\r
26 import org.simantics.utils.datastructures.MapList;\r
27 import org.simantics.utils.datastructures.MapSet;\r
28 import org.simantics.utils.datastructures.Pair;\r
29 \r
30 import com.jme3.app.Application;\r
31 import com.jme3.scene.Spatial;\r
32 \r
33 public abstract class AbstractJMENodeMap<E extends IG3DNode> implements JMENodeMap, IMappingListener, NodeListener, RenderListener {\r
34 \r
35         protected Session session;\r
36         protected IMapping mapping;\r
37         protected Application app;\r
38 //      protected InteractiveVtkPanel panel;\r
39         \r
40         protected MapList<E, Spatial> nodeToActor = new MapList<E, Spatial>();\r
41         protected Map<Spatial,E> actorToNode = new HashMap<Spatial, E>();\r
42 \r
43         protected ParentNode<E> rootNode;\r
44         \r
45         public AbstractJMENodeMap(Session session, IMapping mapping, Application app, ParentNode<E> rootNode) {\r
46                 this.session = session;\r
47                 this.mapping = mapping;\r
48                 this.rootNode = rootNode;\r
49                 this.app = app;\r
50 //              this.panel = panel;\r
51 //              panel.addListener(this);\r
52                 mapping.addMappingListener(this);\r
53                 rootNode.addListener(this);\r
54         }\r
55         \r
56         protected abstract void addActor(E node);\r
57         protected abstract void removeActor(E node);\r
58         protected abstract void updateActor(E node,Set<String> ids);\r
59         \r
60         \r
61         public void repaint() {\r
62                 \r
63         }\r
64         \r
65         public void populate() {\r
66                 for (E node : rootNode.getNodes()) {\r
67                         receiveAdd(node, node.getParentRel(),true);\r
68                 }\r
69                 repaint();\r
70         }\r
71         \r
72         @Override\r
73         public IG3DNode getNode(Spatial prop) {\r
74                 return actorToNode.get(prop);\r
75         }\r
76         \r
77         @SuppressWarnings("unchecked")\r
78         @Override\r
79         public Collection<Spatial> getRenderObjects(IG3DNode node) {\r
80                 return nodeToActor.getValues((E)node);\r
81         }\r
82         \r
83         @SuppressWarnings("unchecked")\r
84         @Override\r
85         public ParentNode<IG3DNode> getRootNode() {\r
86                 return (ParentNode<IG3DNode>)rootNode;\r
87         }\r
88         \r
89         @Override\r
90         public void commit() {\r
91                 session.asyncRequest(new WriteRequest() {\r
92                         \r
93                         @Override\r
94                         public void perform(WriteGraph graph) throws DatabaseException {\r
95                                 synchronized(syncMutex) {\r
96                                         graphUpdates = true;\r
97                                         mapping.updateDomain(graph);\r
98                                         graphUpdates = false;\r
99                                 }\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         private 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<E, String>();//new MapSet.Hash<E, String>();\r
123 \r
124         \r
125         @SuppressWarnings("unchecked")\r
126         @Override\r
127         public void updateRenderObjectsFor(IG3DNode node) {\r
128                 List<Spatial> toDelete = new ArrayList<Spatial>();\r
129                 for (Spatial prop : nodeToActor.getValues((E)node)) {\r
130 //                      if (prop.GetVTKId() != 0) {\r
131 //                              panel.GetRenderer().RemoveActor(prop);\r
132 //                              //prop.Delete();\r
133 //                              toDelete.add(prop);\r
134 //                      }\r
135                         prop.removeFromParent();\r
136                         actorToNode.remove(prop);\r
137                 }\r
138                 nodeToActor.remove((E)node);\r
139                 Collection<Spatial> coll = getActors((E)node);\r
140                 if (coll == null)\r
141                         return;\r
142                 for (Spatial 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 (Spatial p : toDelete) {\r
148                         //p.Delete();\r
149                 }\r
150         }\r
151         \r
152         protected abstract  Collection<Spatial> getActors(E node);\r
153         \r
154         @SuppressWarnings("unchecked")\r
155         private void receiveAdd(E node, String id, boolean 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(node.getParent());\r
163                         }\r
164                         added.add(new Pair<E, String>(node, id));       \r
165                 }\r
166                 repaint();\r
167         }\r
168         \r
169         @SuppressWarnings("unchecked")\r
170         private void receiveRemove(E node, String id, boolean db) {\r
171                 synchronized (syncMutex) {\r
172                         for (Pair<E, String> n : removed) {\r
173                                 if (n.first.equals(node))\r
174                                         return;\r
175                         }\r
176                         if (changeTracking && !db)\r
177                                 mapping.rangeModified(node.getParent());\r
178                         removed.add(new Pair<E, String>(node, id));\r
179                 }\r
180                 repaint();\r
181         }\r
182         \r
183         @SuppressWarnings("unchecked")\r
184         private void receiveUpdate(E node, String id, boolean db) {\r
185                 synchronized (syncMutex) {\r
186 //                      for (Pair<E, String> n : updated) {\r
187 //                              if (n.first.equals(node))\r
188 //                                      return;\r
189 //                      }\r
190                         if (changeTracking && !db)\r
191                                 mapping.rangeModified(node);\r
192                         //updated.add(new Pair<E, String>(node, id));\r
193                         updated.add(node, id);\r
194                 }\r
195                 repaint();\r
196         }\r
197         \r
198         private boolean graphUpdates = false;\r
199         private Set<Object> graphModified = new HashSet<Object>();\r
200         \r
201         @Override\r
202         public void domainModified() {\r
203                 if (graphUpdates)\r
204                         return;\r
205                 //System.out.println("domainModified");\r
206                 session.asyncRequest(new ReadRequest() {\r
207                         \r
208                         @SuppressWarnings("unchecked")\r
209                         @Override\r
210                         public void run(ReadGraph graph) throws DatabaseException {\r
211                                 graphUpdates = true;\r
212                                 for (Object domainObject : mapping.getDomainModified()) {\r
213                                         Object rangeObject = mapping.get(domainObject);\r
214                                         if (rangeObject != null)\r
215                                                 graphModified.add(rangeObject);\r
216                                 }\r
217                                 mapping.updateRange(graph);\r
218                                 graphModified.clear();\r
219                                 graphUpdates = false;\r
220                                 if (mapping.isRangeModified())\r
221                                         commit();\r
222                         }\r
223                 });\r
224                 \r
225         }\r
226         \r
227         @Override\r
228         public void rangeModified() {\r
229                 //System.out.println("rangeModified");\r
230 \r
231         }\r
232         \r
233         @Override\r
234         public void postRender() {\r
235                 \r
236         }\r
237         \r
238         List<Pair<E, String>> rem = new ArrayList<Pair<E,String>>();\r
239         List<Pair<E, String>> add = new ArrayList<Pair<E,String>>();\r
240         MapSet<E, String> mod = new MapSet<E, String>();//new MapSet.Hash<E, String>();\r
241         Set<E> propagation = new HashSet<E>();\r
242         Stack<E> stack = new Stack<E>();\r
243         \r
244         @SuppressWarnings("unchecked")\r
245         @Override\r
246         public synchronized void preRender() {\r
247                 rem.clear();\r
248                 add.clear();\r
249                 mod.clear();\r
250                 propagation.clear();\r
251                 \r
252                 synchronized (syncMutex) {\r
253                         rem.addAll(removed);\r
254                         add.addAll(added);\r
255                         //mod.addAll(updated);\r
256                         for (E e : updated.getKeys()) {\r
257                                 for (String s : updated.getValues(e))\r
258                                         mod.add(e, s);\r
259                         }\r
260                         \r
261                         removed.clear();\r
262                         added.clear();\r
263                         updated.clear();\r
264                 }\r
265                 \r
266                 for (Pair<E, String> n : rem) {\r
267                         stopListening(n.first);\r
268                         removeActor(n.first);\r
269                 \r
270                 }\r
271                 \r
272                 for (Pair<E, String> n : add) {\r
273                         addActor(n.first);\r
274                         listen(n.first);\r
275                 }\r
276                 \r
277                 for (E e : mod.getKeys()) {\r
278                         Set<String> ids = mod.getValues(e);\r
279                         if (ids.contains(G3D.URIs.hasPosition) || ids.contains(G3D.URIs.hasOrientation)) {\r
280                                 if (!propagation.contains(e))\r
281                                         propagation.add(e);\r
282                         }\r
283                 }\r
284                 \r
285                 if (propagation.size() > 0) {\r
286                         stack.clear();\r
287                         stack.addAll(propagation);\r
288                         propagation.clear();\r
289                         while (!stack.isEmpty()) {\r
290                                 E node = stack.pop();\r
291                                 if (propagation.contains(node))\r
292                                         continue;\r
293                                 propagation.add(node);\r
294                                 for (NodeListener l : node.getListeners()) {\r
295                                         if (l == this) {\r
296                                                 //changeTracking = false;\r
297                                                 //l.propertyChanged(node, G3D.URIs.hasPosition);\r
298                                                 //changeTracking = true;\r
299                                         } else {\r
300                                                 l.propertyChanged(node, G3D.URIs.hasPosition);\r
301                                         }\r
302                                 }\r
303                                 if (node instanceof ParentNode) {\r
304                                         stack.addAll(((ParentNode<E>)node).getNodes());\r
305                                 }\r
306                         }\r
307                 }\r
308                 \r
309                 for (E e : mod.getKeys()) {\r
310                         Set<String> ids = mod.getValues(e);\r
311                         updateActor(e,ids);\r
312                 }\r
313                 \r
314                 for (Pair<E, String> n : rem) {\r
315                         for (NodeListener l : nodeListeners)\r
316                                 l.nodeRemoved(null, n.first, n.second);\r
317                 }\r
318                 for (Pair<E, String> n : add) {\r
319                         for (NodeListener l : nodeListeners)\r
320                                 l.nodeAdded(n.first.getParent(), n.first, n.second);\r
321                 }\r
322 //              for (Pair<E, String> n : mod) {\r
323 //                      for (NodeListener l : nodeListeners)\r
324 //                              l.propertyChanged(n.first, n.second);\r
325 //              }\r
326                 for (E e : mod.getKeys()) {\r
327                         for (NodeListener l : nodeListeners)\r
328                                 for (String s : mod.getValues(e))\r
329                                         l.propertyChanged(e, s);\r
330                 }\r
331         }\r
332         \r
333         @SuppressWarnings("unchecked")\r
334         private void listen(INode node) {\r
335                 node.addListener(this);\r
336                 if (node instanceof ParentNode<?>) {\r
337                         ParentNode<INode> parentNode = (ParentNode<INode>)node;\r
338                         for (INode n : parentNode.getNodes())\r
339                                 listen(n);\r
340                 }\r
341         }\r
342         \r
343         private void stopListening(INode node) {\r
344                 node.removeListener(this);\r
345                 if (node instanceof ParentNode<?>) {\r
346                         @SuppressWarnings("unchecked")\r
347                         ParentNode<INode> parentNode = (ParentNode<INode>)node;\r
348                         for (INode n : parentNode.getNodes())\r
349                                 stopListening(n);\r
350                 }\r
351         }\r
352         \r
353         @SuppressWarnings("unchecked")\r
354         @Override\r
355         public void propertyChanged(INode node, String id) {\r
356                 //receiveUpdate((E)node, id, graphUpdates);\r
357                 receiveUpdate((E)node, id, graphModified.contains(node));\r
358                 \r
359         }\r
360         \r
361         @SuppressWarnings("unchecked")\r
362         @Override\r
363         public <T extends INode> void nodeAdded(ParentNode<T> node, INode child,\r
364                         String rel) {\r
365                 //receiveAdd((E)child, rel ,graphUpdates);\r
366                 receiveAdd((E)child, rel ,graphModified.contains(node));\r
367                 \r
368         }\r
369         \r
370         @SuppressWarnings("unchecked")\r
371         @Override\r
372         public <T extends INode> void nodeRemoved(ParentNode<T> node, INode child,\r
373                         String rel) {\r
374                 //receiveRemove((E)child, rel, graphUpdates);\r
375                 receiveRemove((E)child, rel, graphModified.contains(node));\r
376         }\r
377         \r
378         @Override\r
379         public void delete() {\r
380                 changeTracking = false;\r
381                 //panel.removeListener(this);\r
382                 mapping.removeMappingListener(this);\r
383 \r
384                 List<E> nodes = new ArrayList<E>(nodeToActor.getKeySize());\r
385                 nodes.addAll(nodeToActor.getKeys());\r
386                 for (E node : nodes) {\r
387                         node.removeListener(this);\r
388                         removeActor(node);\r
389                         node.cleanup();\r
390                 }\r
391                 for (Spatial prop : actorToNode.keySet()) {\r
392                         prop.removeFromParent();\r
393                         //if (prop.GetVTKId() != 0) \r
394                         //      prop.Delete();\r
395                 }\r
396                 actorToNode.clear();\r
397                 nodeToActor.clear();\r
398                 \r
399         }\r
400         \r
401         \r
402         private List<NodeListener> nodeListeners = new ArrayList<NodeListener>();\r
403         @Override\r
404         public void addListener(NodeListener listener) {\r
405                 nodeListeners.add(listener);\r
406                 \r
407         }\r
408         \r
409         @Override\r
410         public void removeListener(NodeListener listener) {\r
411                 nodeListeners.remove(listener);\r
412                 \r
413         }\r
414 \r
415 }\r