]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.debug.graphical/src/org/simantics/debug/graphical/DebuggerCanvas.java
Migrated source code from Simantics SVN
[simantics/platform.git] / bundles / org.simantics.debug.graphical / src / org / simantics / debug / graphical / DebuggerCanvas.java
1 package org.simantics.debug.graphical;\r
2 \r
3 import gnu.trove.list.array.TDoubleArrayList;\r
4 import gnu.trove.map.hash.THashMap;\r
5 import gnu.trove.map.hash.TObjectIntHashMap;\r
6 \r
7 import java.awt.Color;\r
8 import java.awt.GradientPaint;\r
9 import java.awt.Graphics;\r
10 import java.awt.Graphics2D;\r
11 import java.awt.RenderingHints;\r
12 import java.awt.datatransfer.Transferable;\r
13 import java.awt.datatransfer.UnsupportedFlavorException;\r
14 import java.awt.dnd.DnDConstants;\r
15 import java.awt.dnd.DropTarget;\r
16 import java.awt.dnd.DropTargetAdapter;\r
17 import java.awt.dnd.DropTargetDropEvent;\r
18 import java.awt.event.KeyAdapter;\r
19 import java.awt.event.KeyEvent;\r
20 import java.awt.event.MouseAdapter;\r
21 import java.awt.event.MouseEvent;\r
22 import java.awt.event.MouseMotionAdapter;\r
23 import java.awt.event.MouseWheelEvent;\r
24 import java.awt.event.MouseWheelListener;\r
25 import java.awt.geom.AffineTransform;\r
26 import java.awt.geom.Point2D;\r
27 import java.awt.geom.Rectangle2D;\r
28 import java.io.IOException;\r
29 import java.util.ArrayList;\r
30 import java.util.Collection;\r
31 import java.util.Random;\r
32 \r
33 import javax.swing.JPanel;\r
34 import javax.swing.SwingUtilities;\r
35 \r
36 import org.eclipse.core.runtime.IAdaptable;\r
37 import org.eclipse.jface.viewers.IStructuredSelection;\r
38 import org.simantics.Simantics;\r
39 import org.simantics.db.ChangeSet;\r
40 import org.simantics.db.ChangeSetIdentifier;\r
41 import org.simantics.db.ReadGraph;\r
42 import org.simantics.db.Resource;\r
43 import org.simantics.db.Session;\r
44 import org.simantics.db.Statement;\r
45 import org.simantics.db.common.request.ReadRequest;\r
46 import org.simantics.db.common.utils.NameUtils;\r
47 import org.simantics.db.exception.DatabaseException;\r
48 import org.simantics.db.service.ManagementSupport;\r
49 import org.simantics.debug.graphical.layout.ExtensionLayoutAlgorithm;\r
50 import org.simantics.debug.graphical.layout.LayoutGraph;\r
51 import org.simantics.debug.graphical.model.Edge;\r
52 import org.simantics.debug.graphical.model.LabelContent;\r
53 import org.simantics.debug.graphical.model.Node;\r
54 import org.simantics.debug.graphical.model.NodeData;\r
55 import org.simantics.layer0.Layer0;\r
56 import org.simantics.ui.dnd.LocalObjectTransfer;\r
57 import org.simantics.ui.dnd.LocalObjectTransferable;\r
58 import org.simantics.ui.selection.AnyResource;\r
59 import org.simantics.ui.selection.WorkbenchSelectionElement;\r
60 \r
61 public class DebuggerCanvas extends JPanel {\r
62 \r
63     private static final long serialVersionUID = -718678297301786379L;\r
64     \r
65     ArrayList<Node> nodes = new ArrayList<Node>();\r
66     THashMap<Resource, Node> nodeMap = new THashMap<Resource, Node>(); \r
67     ArrayList<Edge> edges = new ArrayList<Edge>();\r
68     ArrayList<Node> extensionNodes = new ArrayList<Node>();\r
69     ArrayList<Edge> extensionEdges = new ArrayList<Edge>();\r
70     ArrayList<Edge> addedEdges = new ArrayList<Edge>();\r
71     ArrayList<Edge> removedEdges = new ArrayList<Edge>();\r
72     double canvasPosX = 0.0;\r
73     double canvasPosY = 0.0;\r
74     double canvasZoom = 1.0;\r
75     boolean extensionMode = false;\r
76     Random random = new Random();\r
77 \r
78     LabelingPreferences labelingPreferences = \r
79             new LabelingPreferences();\r
80     \r
81     @Override\r
82     public void paint(Graphics _g) {\r
83         Graphics2D g = (Graphics2D)_g;\r
84         \r
85         g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, \r
86                 RenderingHints.VALUE_ANTIALIAS_ON);\r
87         g.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, \r
88                 RenderingHints.VALUE_FRACTIONALMETRICS_ON);\r
89         g.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, \r
90                 RenderingHints.VALUE_TEXT_ANTIALIAS_ON);\r
91         \r
92         g.setPaint(new GradientPaint(0.0f, 0.0f, new Color(200, 200, 200), getWidth(), getHeight(), Color.WHITE));\r
93         g.fill(new Rectangle2D.Double(0, 0, getWidth(), getHeight()));\r
94         g.setColor(Color.BLACK);\r
95         g.setTransform(new AffineTransform(\r
96                 canvasZoom, 0.0, \r
97                 0.0, canvasZoom, \r
98                 -canvasPosX*canvasZoom, -canvasPosY*canvasZoom));\r
99         for(Node node : nodes)\r
100             node.render(g);\r
101         for(Edge edge : edges)\r
102             edge.render(g);\r
103         if(extensionMode) {\r
104             for(Node node : extensionNodes)\r
105                 node.render(g);\r
106             for(Edge edge : extensionEdges)\r
107                 edge.render(g);\r
108         }\r
109         g.setColor(Color.GREEN);\r
110         for(Edge edge : addedEdges)\r
111             edge.render(g);\r
112         g.setColor(Color.RED);\r
113         for(Edge edge : removedEdges)\r
114             edge.render(g);\r
115     }\r
116     \r
117     public Node pick(double x, double y) {\r
118         for(Node node : nodes)\r
119             if(node.pick(x, y))\r
120                 return node;\r
121         return null;\r
122     }\r
123     \r
124     public Node pickExtension(double x, double y) {\r
125         for(Node node : extensionNodes)\r
126             if(node.pick(x, y))\r
127                 return node;\r
128         return null;\r
129     }\r
130     \r
131     {\r
132         addMouseListener(new MouseAdapter() {\r
133             @Override\r
134             public void mousePressed(MouseEvent e) {                \r
135                 double x = canvasPosX+e.getX()/canvasZoom;\r
136                 double y = canvasPosY+e.getY()/canvasZoom;\r
137                 if(e.getButton() == MouseEvent.BUTTON1)\r
138                     handleMouseLeftPressed(x, y);\r
139                 else if(e.getButton() == MouseEvent.BUTTON2)\r
140                     handleMouseMiddlePressed(x, y);\r
141             }\r
142             @Override\r
143             public void mouseMoved(MouseEvent e) {\r
144                 handleMouseMoved(canvasPosX+e.getX()/canvasZoom, \r
145                         canvasPosY+e.getY()/canvasZoom);\r
146             }\r
147             @Override\r
148             public void mouseReleased(MouseEvent e) {\r
149                 handleMouseReleased(canvasPosX+e.getX()/canvasZoom, \r
150                         canvasPosY+e.getY()/canvasZoom);\r
151             }\r
152             @Override\r
153             public void mouseWheelMoved(MouseWheelEvent e) {\r
154                 double x = canvasPosX+e.getX()/canvasZoom;\r
155                 double y = canvasPosY+e.getY()/canvasZoom;\r
156                 handleMouseWheelMoved(x, y, e.getWheelRotation());\r
157             }\r
158         });\r
159         addMouseMotionListener(new MouseMotionAdapter() {\r
160             @Override\r
161             public void mouseDragged(MouseEvent e) {\r
162                 handleMouseMoved(canvasPosX+e.getX()/canvasZoom, \r
163                         canvasPosY+e.getY()/canvasZoom);\r
164             }            \r
165         });\r
166         addMouseWheelListener(new MouseWheelListener() {            \r
167             @Override\r
168             public void mouseWheelMoved(MouseWheelEvent e) {\r
169                 double x = canvasPosX+e.getX()/canvasZoom;\r
170                 double y = canvasPosY+e.getY()/canvasZoom;\r
171                 handleMouseWheelMoved(x, y, e.getWheelRotation());\r
172             }\r
173         });\r
174         addKeyListener(new UsefulKeyAdapter(new KeyAdapter() {\r
175             @Override\r
176             public void keyPressed(KeyEvent e) {\r
177                 DebuggerCanvas.this.keyPressed(e);\r
178             }\r
179             @Override\r
180             public void keyReleased(KeyEvent e) {\r
181                 DebuggerCanvas.this.keyReleased(e);\r
182             }\r
183         }));\r
184         DropTarget dropTarget = new DropTarget(this, new DropTargetAdapter() {\r
185             @Override\r
186             public void drop(DropTargetDropEvent dtde) {\r
187                 try {\r
188                     Transferable transferable = dtde.getTransferable();\r
189                     \r
190                     if( transferable.isDataFlavorSupported( \r
191                             LocalObjectTransferable.FLAVOR ) ) {\r
192                         dtde.acceptDrop( DnDConstants.ACTION_MOVE );\r
193                         \r
194                         transferable.getTransferData(LocalObjectTransferable.FLAVOR );\r
195                         Object obj = LocalObjectTransfer.getTransfer().getObject();\r
196                         double x = canvasPosX+dtde.getLocation().getX()/canvasZoom;\r
197                         double y = canvasPosY+dtde.getLocation().getY()/canvasZoom;\r
198                         handleDrop(x, y, obj);\r
199                         \r
200                         dtde.getDropTargetContext().dropComplete( true );\r
201                     }\r
202                     else {\r
203                         dtde.rejectDrop();\r
204                     }\r
205                 } catch( IOException exception ) {\r
206                     exception.printStackTrace();\r
207                     dtde.rejectDrop();\r
208                 } catch( UnsupportedFlavorException ufException ) {\r
209                     ufException.printStackTrace();\r
210                     dtde.rejectDrop();\r
211                 }\r
212             }     \r
213         });\r
214     }    \r
215     \r
216     public void keyPressed(KeyEvent e) {\r
217         switch(e.getKeyCode()) {\r
218         case KeyEvent.VK_1:\r
219             zoomToFit();\r
220             break;\r
221         case KeyEvent.VK_L:\r
222             layoutGraph();\r
223             break;\r
224         case KeyEvent.VK_CONTROL:\r
225             if(!extensionMode) {\r
226                 initializeExtension();\r
227                 extensionMode = true;\r
228                 repaint();\r
229             }\r
230             break;\r
231         case KeyEvent.VK_C:\r
232             findPreviousChangeset();\r
233             break;\r
234         case KeyEvent.VK_DELETE:\r
235             if (!extensionMode && dragging != null) {\r
236                 nodes.remove(dragging);\r
237                 scheduleUpdate();\r
238                 repaint();\r
239             }\r
240             break;\r
241         }\r
242     }\r
243     \r
244     public void keyReleased(KeyEvent e) {\r
245         if(e.getKeyCode() == KeyEvent.VK_CONTROL) {\r
246             extensionMode = false;\r
247             scheduleUpdate();\r
248             repaint();\r
249         }\r
250     }\r
251 \r
252     private static Resource extractResource(Object obj) {\r
253         System.out.println("- " + obj.getClass().getName());\r
254         if(obj instanceof WorkbenchSelectionElement) {\r
255             Resource resource = ((WorkbenchSelectionElement)obj).getContent(new AnyResource(Simantics.getSession()));\r
256             if(resource != null)\r
257                 return resource;\r
258         }\r
259         if(obj instanceof IAdaptable) {\r
260             Resource resource = (Resource)((IAdaptable)obj).getAdapter(Resource.class);\r
261             if(resource != null)\r
262                 return resource;\r
263         }\r
264         return null;\r
265     }\r
266     \r
267     private void handleDrop(double x, double y, Object obj) {\r
268         //System.out.println(obj.getClass().getName());\r
269         if(obj instanceof IStructuredSelection) {\r
270             for(Object element : ((IStructuredSelection)obj).toArray()) {\r
271                 Resource resource = extractResource(element);\r
272                 if(resource != null && !nodeMap.containsKey(resource)) {\r
273                     addResource(x, y, resource);                    \r
274                     repaint();\r
275                 }\r
276             }\r
277         }\r
278     }       \r
279     \r
280     private Node addResource(double x, double y, Resource resource) {\r
281         Node a = new Node(new NodeData(resource));\r
282         a.setPos(x, y);\r
283         scheduleUpdate();\r
284         nodes.add(a);\r
285         return a;\r
286     }\r
287 \r
288     private void scheduleUpdate() {\r
289         Simantics.getSession().asyncRequest(new ReadRequest() {            \r
290             @Override\r
291             public void run(ReadGraph graph) throws DatabaseException {                \r
292                 updateNodes(graph);\r
293                 updateEdges(graph);\r
294                 SwingUtilities.invokeLater(new Runnable() {\r
295                     @Override\r
296                     public void run() {\r
297                         repaint();\r
298                     }\r
299                     \r
300                 });\r
301             }            \r
302         });        \r
303     }\r
304     \r
305     public void layoutGraph() {\r
306         ArrayList<Edge> allEdges = new ArrayList<Edge>(\r
307                 edges.size() + addedEdges.size() + removedEdges.size()\r
308                 );\r
309         allEdges.addAll(edges);\r
310         allEdges.addAll(addedEdges);\r
311         allEdges.addAll(removedEdges);\r
312         LayoutGraph.layout(\r
313                 nodes.toArray(new Node[nodes.size()]), \r
314                 allEdges.toArray(new Edge[edges.size()]));\r
315         repaint();                \r
316     }\r
317     \r
318     private void updateNodes(ReadGraph graph) throws DatabaseException {\r
319         for(Node node : nodes) {\r
320             node.getData().updateData(graph, labelingPreferences);\r
321             node.setContent(new LabelContent(node.getData().getLabels()));\r
322         }\r
323         nodeMap.clear();\r
324         for(Node node : nodes) {\r
325             NodeData data = node.getData();\r
326             nodeMap.put(data.getResource(), node);\r
327         }\r
328     }\r
329     \r
330     private void updateEdges(ReadGraph graph) throws DatabaseException {\r
331         ArrayList<Edge> edges = new ArrayList<Edge>();\r
332         for(Node node : nodes) {\r
333             NodeData data = node.getData();\r
334             Resource subject = data.getResource();\r
335             ArrayList<Statement> filteredStatements = new ArrayList<Statement>(data.getStatements().size());\r
336             for(Statement stat : data.getStatements()) {\r
337                 Resource object = stat.getObject();\r
338                 Node node2 = nodeMap.get(object);\r
339                 if(node2 != null) {\r
340                     if(object.getResourceId() > subject.getResourceId() ||\r
341                             graph.getPossibleInverse(stat.getPredicate()) == null) {\r
342                         edges.add(createEdge(graph, stat, node, node2));\r
343                     }\r
344                 }\r
345                 else\r
346                     filteredStatements.add(stat);\r
347             }\r
348             data.setStatements(filteredStatements);\r
349         }\r
350         this.edges = edges;\r
351         this.addedEdges = filterEdgesWithoutNodes( this.addedEdges );\r
352         this.removedEdges = filterEdgesWithoutNodes( this.removedEdges );\r
353     }\r
354 \r
355     private ArrayList<Edge> filterEdgesWithoutNodes(Collection<Edge> edges) {\r
356         ArrayList<Edge> result = new ArrayList<Edge>(edges.size());\r
357         for (Edge e : edges) {\r
358             if (!nodeMap.containsValue(e.getA()) || !nodeMap.containsValue(e.getB()))\r
359                 continue;\r
360             result.add(e);\r
361         }\r
362         return result;\r
363     }\r
364 \r
365     private Edge createEdge(ReadGraph graph, Statement stat, Node n1, Node n2) throws DatabaseException {\r
366         Resource predicate = stat.getPredicate();\r
367         Resource inverse = graph.getPossibleInverse(predicate);        \r
368         if(inverse != null) {\r
369             Layer0 L0 = Layer0.getInstance(graph);\r
370             if(graph.hasStatement(predicate, L0.PartOf, inverse)\r
371                     || predicate.equals(L0.PartOf)\r
372                     || predicate.equals(L0.SuperrelationOf)\r
373                     || predicate.equals(L0.SupertypeOf)) {\r
374                 predicate = inverse;\r
375                 Node temp = n1;\r
376                 n1 = n2;\r
377                 n2 = temp;\r
378             }\r
379         }\r
380         Edge edge = new Edge(n1, n2);\r
381         edge.setContent(new LabelContent(new String[] {\r
382                 NameUtils.getSafeName(graph, predicate)}));\r
383         return edge;\r
384     }\r
385     \r
386     Node dragging = null;\r
387     double dragDX, dragDY;\r
388     private void handleMouseLeftPressed(double x, double y) {\r
389         Node node;\r
390         if(extensionMode) {\r
391             node = pickExtension(x, y);\r
392             if(node != null) {\r
393                 nodes.add(node);\r
394                 extensionNodes.remove(node);\r
395             }\r
396         }\r
397         else\r
398             node = pick(x, y);\r
399         if(node != null) {\r
400             dragDX = x - node.getX();\r
401             dragDY = y - node.getY();\r
402             dragging = node;\r
403         }\r
404     }\r
405     \r
406     Point2D panningStartMouse;\r
407     private void handleMouseMiddlePressed(double x, double y) {\r
408         panningStartMouse = new Point2D.Double(x, y);\r
409     }\r
410     \r
411     private void handleMouseMoved(double x, double y) {\r
412         if(dragging != null) {\r
413             dragging.setPos(x-dragDX, y-dragDY);\r
414             repaint();\r
415         }\r
416         if(panningStartMouse != null) {\r
417             canvasPosX -= x - panningStartMouse.getX();\r
418             canvasPosY -= y - panningStartMouse.getY();\r
419             repaint();\r
420         }\r
421     }\r
422     \r
423     private void handleMouseWheelMoved(double x, double y, double amount) {\r
424         double s = Math.exp(-0.2*amount);\r
425         canvasZoom *= s;\r
426         canvasPosX = x - (x-canvasPosX)/s;\r
427         canvasPosY = y - (y-canvasPosY)/s;\r
428         repaint();\r
429     }\r
430 \r
431     private void handleMouseReleased(double x, double y) {\r
432         dragging = null;\r
433         panningStartMouse = null;\r
434     }\r
435     \r
436     public void zoomToFit() {\r
437         if(!nodes.isEmpty()) {\r
438             double minX = Double.POSITIVE_INFINITY;\r
439             double minY = Double.POSITIVE_INFINITY;\r
440             double maxX = Double.NEGATIVE_INFINITY;\r
441             double maxY = Double.NEGATIVE_INFINITY;\r
442             System.out.println("(" + minX + "," + minY + ") - (" + maxX + "," + maxY + ")");\r
443             for(Node node : nodes) {\r
444                 minX = Math.min(minX, node.getMinX());\r
445                 minY = Math.min(minY, node.getMinY());\r
446                 maxX = Math.max(maxX, node.getMaxX());\r
447                 maxY = Math.max(maxY, node.getMaxY());\r
448             }            \r
449             canvasZoom = Math.min(getWidth()/(maxX-minX), getHeight()/(maxY-minY));\r
450             canvasZoom *= 0.9;\r
451             canvasPosX = minX - 0.5 * (getWidth()/canvasZoom - maxX+minX);\r
452             canvasPosY = minY - 0.5 * (getHeight()/canvasZoom - maxY+minY);\r
453             repaint();\r
454         }\r
455     }\r
456 \r
457     THashMap<Resource, Node> extensionNodeMap = new THashMap<Resource, Node>();\r
458     public void initializeExtension() {\r
459         extensionNodes.clear();\r
460         extensionEdges.clear();\r
461         try {\r
462             Simantics.getSession().syncRequest(new ReadRequest() {\r
463                 @Override\r
464                 public void run(ReadGraph graph) throws DatabaseException {\r
465                     THashMap<Resource, Node> oldExtensionNodeMap = DebuggerCanvas.this.extensionNodeMap;\r
466                     THashMap<Resource, Node> extensionNodeMap = new THashMap<Resource, Node>();\r
467                     for(Node node : nodes) {\r
468                         for(Statement stat : node.getData().getStatements()) {\r
469                             Resource object = stat.getObject();\r
470                             Node node2 = extensionNodeMap.get(object);\r
471                             if(node2 == null) {\r
472                                 node2 = oldExtensionNodeMap.get(object);\r
473                                 if(node2 == null) {\r
474                                     node2 = new Node(new NodeData(object));\r
475                                     double angle = random.nextDouble() * Math.PI * 2.0;\r
476                                     double dx = Math.cos(angle);\r
477                                     double dy = Math.sin(angle);\r
478                                     double len = 150.0;\r
479                                     node2.setPos(node.getX() + dx*len, node.getY() + dy*len);\r
480                                 }\r
481                                 node2.getData().updateData(graph, labelingPreferences);                                \r
482                                 node2.setContent(new LabelContent(node2.getData().getLabels()));\r
483                                 extensionNodeMap.put(object, node2);\r
484                                 extensionNodes.add(node2);\r
485                             }\r
486                             extensionEdges.add(createEdge(graph, stat, node, node2));\r
487                         }\r
488                     }\r
489                     DebuggerCanvas.this.extensionNodeMap = extensionNodeMap;\r
490                     layoutExtension();\r
491                 }      \r
492             });\r
493         } catch (DatabaseException e) {\r
494             e.printStackTrace();\r
495         }\r
496     }\r
497 \r
498     private void layoutExtension() {        \r
499         TObjectIntHashMap<Node> extensionNodeIds = new TObjectIntHashMap<Node>();\r
500         for(int i=0;i<extensionNodes.size();++i)\r
501             extensionNodeIds.put(extensionNodes.get(i), i);\r
502         \r
503         double[][] neighbors = new double[extensionNodes.size()][];\r
504         {\r
505             TDoubleArrayList[] neighborLists = new TDoubleArrayList[neighbors.length];        \r
506             for(int i=0;i<neighborLists.length;++i)\r
507                 neighborLists[i] = new TDoubleArrayList();\r
508             for(Edge edge : extensionEdges) {\r
509                 int id;\r
510                 Node node;\r
511                 if(extensionNodeIds.containsKey(edge.getA())) {\r
512                     id = extensionNodeIds.get(edge.getA());\r
513                     node = edge.getB();\r
514                 }\r
515                 else {\r
516                     id = extensionNodeIds.get(edge.getB());\r
517                     node = edge.getA();\r
518                 }\r
519                 TDoubleArrayList list = neighborLists[id];\r
520                 list.add(node.getX());\r
521                 list.add(node.getY());\r
522             }            \r
523             for(int i=0;i<neighborLists.length;++i) {\r
524                 neighbors[i] = neighborLists[i].toArray();\r
525             }\r
526         }\r
527         \r
528         double[] fixedRepulsiveX = new double[nodes.size()];\r
529         double[] fixedRepulsiveY = new double[nodes.size()];\r
530         for(int i=0;i<nodes.size();++i) {\r
531             Node node = nodes.get(i);\r
532             fixedRepulsiveX[i] = node.getX();\r
533             fixedRepulsiveY[i] = node.getY();\r
534         }\r
535         ExtensionLayoutAlgorithm algo = \r
536                 new ExtensionLayoutAlgorithm(neighbors, fixedRepulsiveX, fixedRepulsiveY);\r
537         double[] posX = algo.getPosX();\r
538         double[] posY = algo.getPosY();\r
539         for(int i=0;i<extensionNodes.size();++i) {\r
540             posX[i] = extensionNodes.get(i).getX();\r
541             posY[i] = extensionNodes.get(i).getY();\r
542         }        \r
543         algo.optimize();\r
544         for(int i=0;i<extensionNodes.size();++i) {\r
545             extensionNodes.get(i).setPos(posX[i], posY[i]);\r
546         }        \r
547     }      \r
548     \r
549     private Node getNode(Resource resource) {\r
550         Node node = nodeMap.get(resource);\r
551         if(node == null) {\r
552             node = addResource(random.nextDouble()*200.0-100.0, \r
553                     random.nextDouble()*200.0-100.0, \r
554                     resource);\r
555             nodeMap.put(resource, node);\r
556         }\r
557         return node;\r
558     }\r
559     \r
560     public void findPreviousChangeset() {\r
561         try {\r
562             Session session = Simantics.getSession();\r
563             final ManagementSupport ms = session.getService(ManagementSupport.class);\r
564             final long lastId = ms.getHeadRevisionId();\r
565             final long firstId = getOpId(ms, lastId);\r
566             //System.out.println(firstId + "-" + lastId);\r
567             addedEdges.clear();\r
568             removedEdges.clear();            \r
569             session.asyncRequest(new ReadRequest() {\r
570                 @Override\r
571                 public void run(ReadGraph graph) throws DatabaseException {\r
572                     final Collection<ChangeSet> css = \r
573                             ms.fetchChangeSets(graph, firstId, lastId);\r
574                     Layer0 L0 = Layer0.getInstance(graph);\r
575                     for(ChangeSet cs : css) {\r
576                         for(ChangeSet.StatementChange stat : cs.changedStatements()) {\r
577                             Resource predicate = stat.getPredicate();\r
578                             if(predicate.equals(L0.InstanceOf) ||\r
579                                     predicate.equals(L0.HasName) ||\r
580                                     predicate.equals(L0.NameOf))\r
581                                 continue;\r
582                             Edge edge = createEdge(graph, stat, \r
583                                     getNode(stat.getSubject()),\r
584                                     getNode(stat.getObject()));\r
585                             if(stat.isClaim())\r
586                                 addedEdges.add(edge);\r
587                             else\r
588                                 removedEdges.add(edge);\r
589                         }\r
590                     }    \r
591                     scheduleUpdate();\r
592                 }                \r
593             });                  \r
594         } catch(DatabaseException e) {\r
595             e.printStackTrace();\r
596         }\r
597     } \r
598     \r
599     private static long getOpId(ManagementSupport ms, long revisionId) throws DatabaseException {\r
600         Collection<ChangeSetIdentifier> ids = ms.getChangeSetIdentifiers(revisionId, revisionId);\r
601         ChangeSetIdentifier curId = ids.iterator().next();\r
602         byte[] opIdData = curId.getMetadata().get("opid");\r
603         System.out.println(new String(opIdData));\r
604         long opId = Long.parseLong(new String(opIdData));\r
605         if(opId == 0)\r
606             opId = revisionId;\r
607         return opId;\r
608     }\r
609 \r
610 }\r