]> gerrit.simantics Code Review - simantics/platform.git/blobdiff - 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
diff --git a/bundles/org.simantics.debug.graphical/src/org/simantics/debug/graphical/DebuggerCanvas.java b/bundles/org.simantics.debug.graphical/src/org/simantics/debug/graphical/DebuggerCanvas.java
new file mode 100644 (file)
index 0000000..8600064
--- /dev/null
@@ -0,0 +1,610 @@
+package org.simantics.debug.graphical;\r
+\r
+import gnu.trove.list.array.TDoubleArrayList;\r
+import gnu.trove.map.hash.THashMap;\r
+import gnu.trove.map.hash.TObjectIntHashMap;\r
+\r
+import java.awt.Color;\r
+import java.awt.GradientPaint;\r
+import java.awt.Graphics;\r
+import java.awt.Graphics2D;\r
+import java.awt.RenderingHints;\r
+import java.awt.datatransfer.Transferable;\r
+import java.awt.datatransfer.UnsupportedFlavorException;\r
+import java.awt.dnd.DnDConstants;\r
+import java.awt.dnd.DropTarget;\r
+import java.awt.dnd.DropTargetAdapter;\r
+import java.awt.dnd.DropTargetDropEvent;\r
+import java.awt.event.KeyAdapter;\r
+import java.awt.event.KeyEvent;\r
+import java.awt.event.MouseAdapter;\r
+import java.awt.event.MouseEvent;\r
+import java.awt.event.MouseMotionAdapter;\r
+import java.awt.event.MouseWheelEvent;\r
+import java.awt.event.MouseWheelListener;\r
+import java.awt.geom.AffineTransform;\r
+import java.awt.geom.Point2D;\r
+import java.awt.geom.Rectangle2D;\r
+import java.io.IOException;\r
+import java.util.ArrayList;\r
+import java.util.Collection;\r
+import java.util.Random;\r
+\r
+import javax.swing.JPanel;\r
+import javax.swing.SwingUtilities;\r
+\r
+import org.eclipse.core.runtime.IAdaptable;\r
+import org.eclipse.jface.viewers.IStructuredSelection;\r
+import org.simantics.Simantics;\r
+import org.simantics.db.ChangeSet;\r
+import org.simantics.db.ChangeSetIdentifier;\r
+import org.simantics.db.ReadGraph;\r
+import org.simantics.db.Resource;\r
+import org.simantics.db.Session;\r
+import org.simantics.db.Statement;\r
+import org.simantics.db.common.request.ReadRequest;\r
+import org.simantics.db.common.utils.NameUtils;\r
+import org.simantics.db.exception.DatabaseException;\r
+import org.simantics.db.service.ManagementSupport;\r
+import org.simantics.debug.graphical.layout.ExtensionLayoutAlgorithm;\r
+import org.simantics.debug.graphical.layout.LayoutGraph;\r
+import org.simantics.debug.graphical.model.Edge;\r
+import org.simantics.debug.graphical.model.LabelContent;\r
+import org.simantics.debug.graphical.model.Node;\r
+import org.simantics.debug.graphical.model.NodeData;\r
+import org.simantics.layer0.Layer0;\r
+import org.simantics.ui.dnd.LocalObjectTransfer;\r
+import org.simantics.ui.dnd.LocalObjectTransferable;\r
+import org.simantics.ui.selection.AnyResource;\r
+import org.simantics.ui.selection.WorkbenchSelectionElement;\r
+\r
+public class DebuggerCanvas extends JPanel {\r
+\r
+    private static final long serialVersionUID = -718678297301786379L;\r
+    \r
+    ArrayList<Node> nodes = new ArrayList<Node>();\r
+    THashMap<Resource, Node> nodeMap = new THashMap<Resource, Node>(); \r
+    ArrayList<Edge> edges = new ArrayList<Edge>();\r
+    ArrayList<Node> extensionNodes = new ArrayList<Node>();\r
+    ArrayList<Edge> extensionEdges = new ArrayList<Edge>();\r
+    ArrayList<Edge> addedEdges = new ArrayList<Edge>();\r
+    ArrayList<Edge> removedEdges = new ArrayList<Edge>();\r
+    double canvasPosX = 0.0;\r
+    double canvasPosY = 0.0;\r
+    double canvasZoom = 1.0;\r
+    boolean extensionMode = false;\r
+    Random random = new Random();\r
+\r
+    LabelingPreferences labelingPreferences = \r
+            new LabelingPreferences();\r
+    \r
+    @Override\r
+    public void paint(Graphics _g) {\r
+        Graphics2D g = (Graphics2D)_g;\r
+        \r
+        g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, \r
+                RenderingHints.VALUE_ANTIALIAS_ON);\r
+        g.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, \r
+                RenderingHints.VALUE_FRACTIONALMETRICS_ON);\r
+        g.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, \r
+                RenderingHints.VALUE_TEXT_ANTIALIAS_ON);\r
+        \r
+        g.setPaint(new GradientPaint(0.0f, 0.0f, new Color(200, 200, 200), getWidth(), getHeight(), Color.WHITE));\r
+        g.fill(new Rectangle2D.Double(0, 0, getWidth(), getHeight()));\r
+        g.setColor(Color.BLACK);\r
+        g.setTransform(new AffineTransform(\r
+                canvasZoom, 0.0, \r
+                0.0, canvasZoom, \r
+                -canvasPosX*canvasZoom, -canvasPosY*canvasZoom));\r
+        for(Node node : nodes)\r
+            node.render(g);\r
+        for(Edge edge : edges)\r
+            edge.render(g);\r
+        if(extensionMode) {\r
+            for(Node node : extensionNodes)\r
+                node.render(g);\r
+            for(Edge edge : extensionEdges)\r
+                edge.render(g);\r
+        }\r
+        g.setColor(Color.GREEN);\r
+        for(Edge edge : addedEdges)\r
+            edge.render(g);\r
+        g.setColor(Color.RED);\r
+        for(Edge edge : removedEdges)\r
+            edge.render(g);\r
+    }\r
+    \r
+    public Node pick(double x, double y) {\r
+        for(Node node : nodes)\r
+            if(node.pick(x, y))\r
+                return node;\r
+        return null;\r
+    }\r
+    \r
+    public Node pickExtension(double x, double y) {\r
+        for(Node node : extensionNodes)\r
+            if(node.pick(x, y))\r
+                return node;\r
+        return null;\r
+    }\r
+    \r
+    {\r
+        addMouseListener(new MouseAdapter() {\r
+            @Override\r
+            public void mousePressed(MouseEvent e) {                \r
+                double x = canvasPosX+e.getX()/canvasZoom;\r
+                double y = canvasPosY+e.getY()/canvasZoom;\r
+                if(e.getButton() == MouseEvent.BUTTON1)\r
+                    handleMouseLeftPressed(x, y);\r
+                else if(e.getButton() == MouseEvent.BUTTON2)\r
+                    handleMouseMiddlePressed(x, y);\r
+            }\r
+            @Override\r
+            public void mouseMoved(MouseEvent e) {\r
+                handleMouseMoved(canvasPosX+e.getX()/canvasZoom, \r
+                        canvasPosY+e.getY()/canvasZoom);\r
+            }\r
+            @Override\r
+            public void mouseReleased(MouseEvent e) {\r
+                handleMouseReleased(canvasPosX+e.getX()/canvasZoom, \r
+                        canvasPosY+e.getY()/canvasZoom);\r
+            }\r
+            @Override\r
+            public void mouseWheelMoved(MouseWheelEvent e) {\r
+                double x = canvasPosX+e.getX()/canvasZoom;\r
+                double y = canvasPosY+e.getY()/canvasZoom;\r
+                handleMouseWheelMoved(x, y, e.getWheelRotation());\r
+            }\r
+        });\r
+        addMouseMotionListener(new MouseMotionAdapter() {\r
+            @Override\r
+            public void mouseDragged(MouseEvent e) {\r
+                handleMouseMoved(canvasPosX+e.getX()/canvasZoom, \r
+                        canvasPosY+e.getY()/canvasZoom);\r
+            }            \r
+        });\r
+        addMouseWheelListener(new MouseWheelListener() {            \r
+            @Override\r
+            public void mouseWheelMoved(MouseWheelEvent e) {\r
+                double x = canvasPosX+e.getX()/canvasZoom;\r
+                double y = canvasPosY+e.getY()/canvasZoom;\r
+                handleMouseWheelMoved(x, y, e.getWheelRotation());\r
+            }\r
+        });\r
+        addKeyListener(new UsefulKeyAdapter(new KeyAdapter() {\r
+            @Override\r
+            public void keyPressed(KeyEvent e) {\r
+                DebuggerCanvas.this.keyPressed(e);\r
+            }\r
+            @Override\r
+            public void keyReleased(KeyEvent e) {\r
+                DebuggerCanvas.this.keyReleased(e);\r
+            }\r
+        }));\r
+        DropTarget dropTarget = new DropTarget(this, new DropTargetAdapter() {\r
+            @Override\r
+            public void drop(DropTargetDropEvent dtde) {\r
+                try {\r
+                    Transferable transferable = dtde.getTransferable();\r
+                    \r
+                    if( transferable.isDataFlavorSupported( \r
+                            LocalObjectTransferable.FLAVOR ) ) {\r
+                        dtde.acceptDrop( DnDConstants.ACTION_MOVE );\r
+                        \r
+                        transferable.getTransferData(LocalObjectTransferable.FLAVOR );\r
+                        Object obj = LocalObjectTransfer.getTransfer().getObject();\r
+                        double x = canvasPosX+dtde.getLocation().getX()/canvasZoom;\r
+                        double y = canvasPosY+dtde.getLocation().getY()/canvasZoom;\r
+                        handleDrop(x, y, obj);\r
+                        \r
+                        dtde.getDropTargetContext().dropComplete( true );\r
+                    }\r
+                    else {\r
+                        dtde.rejectDrop();\r
+                    }\r
+                } catch( IOException exception ) {\r
+                    exception.printStackTrace();\r
+                    dtde.rejectDrop();\r
+                } catch( UnsupportedFlavorException ufException ) {\r
+                    ufException.printStackTrace();\r
+                    dtde.rejectDrop();\r
+                }\r
+            }     \r
+        });\r
+    }    \r
+    \r
+    public void keyPressed(KeyEvent e) {\r
+        switch(e.getKeyCode()) {\r
+        case KeyEvent.VK_1:\r
+            zoomToFit();\r
+            break;\r
+        case KeyEvent.VK_L:\r
+            layoutGraph();\r
+            break;\r
+        case KeyEvent.VK_CONTROL:\r
+            if(!extensionMode) {\r
+                initializeExtension();\r
+                extensionMode = true;\r
+                repaint();\r
+            }\r
+            break;\r
+        case KeyEvent.VK_C:\r
+            findPreviousChangeset();\r
+            break;\r
+        case KeyEvent.VK_DELETE:\r
+            if (!extensionMode && dragging != null) {\r
+                nodes.remove(dragging);\r
+                scheduleUpdate();\r
+                repaint();\r
+            }\r
+            break;\r
+        }\r
+    }\r
+    \r
+    public void keyReleased(KeyEvent e) {\r
+        if(e.getKeyCode() == KeyEvent.VK_CONTROL) {\r
+            extensionMode = false;\r
+            scheduleUpdate();\r
+            repaint();\r
+        }\r
+    }\r
+\r
+    private static Resource extractResource(Object obj) {\r
+        System.out.println("- " + obj.getClass().getName());\r
+        if(obj instanceof WorkbenchSelectionElement) {\r
+            Resource resource = ((WorkbenchSelectionElement)obj).getContent(new AnyResource(Simantics.getSession()));\r
+            if(resource != null)\r
+                return resource;\r
+        }\r
+        if(obj instanceof IAdaptable) {\r
+            Resource resource = (Resource)((IAdaptable)obj).getAdapter(Resource.class);\r
+            if(resource != null)\r
+                return resource;\r
+        }\r
+        return null;\r
+    }\r
+    \r
+    private void handleDrop(double x, double y, Object obj) {\r
+        //System.out.println(obj.getClass().getName());\r
+        if(obj instanceof IStructuredSelection) {\r
+            for(Object element : ((IStructuredSelection)obj).toArray()) {\r
+                Resource resource = extractResource(element);\r
+                if(resource != null && !nodeMap.containsKey(resource)) {\r
+                    addResource(x, y, resource);                    \r
+                    repaint();\r
+                }\r
+            }\r
+        }\r
+    }       \r
+    \r
+    private Node addResource(double x, double y, Resource resource) {\r
+        Node a = new Node(new NodeData(resource));\r
+        a.setPos(x, y);\r
+        scheduleUpdate();\r
+        nodes.add(a);\r
+        return a;\r
+    }\r
+\r
+    private void scheduleUpdate() {\r
+        Simantics.getSession().asyncRequest(new ReadRequest() {            \r
+            @Override\r
+            public void run(ReadGraph graph) throws DatabaseException {                \r
+                updateNodes(graph);\r
+                updateEdges(graph);\r
+                SwingUtilities.invokeLater(new Runnable() {\r
+                    @Override\r
+                    public void run() {\r
+                        repaint();\r
+                    }\r
+                    \r
+                });\r
+            }            \r
+        });        \r
+    }\r
+    \r
+    public void layoutGraph() {\r
+        ArrayList<Edge> allEdges = new ArrayList<Edge>(\r
+                edges.size() + addedEdges.size() + removedEdges.size()\r
+                );\r
+        allEdges.addAll(edges);\r
+        allEdges.addAll(addedEdges);\r
+        allEdges.addAll(removedEdges);\r
+        LayoutGraph.layout(\r
+                nodes.toArray(new Node[nodes.size()]), \r
+                allEdges.toArray(new Edge[edges.size()]));\r
+        repaint();                \r
+    }\r
+    \r
+    private void updateNodes(ReadGraph graph) throws DatabaseException {\r
+        for(Node node : nodes) {\r
+            node.getData().updateData(graph, labelingPreferences);\r
+            node.setContent(new LabelContent(node.getData().getLabels()));\r
+        }\r
+        nodeMap.clear();\r
+        for(Node node : nodes) {\r
+            NodeData data = node.getData();\r
+            nodeMap.put(data.getResource(), node);\r
+        }\r
+    }\r
+    \r
+    private void updateEdges(ReadGraph graph) throws DatabaseException {\r
+        ArrayList<Edge> edges = new ArrayList<Edge>();\r
+        for(Node node : nodes) {\r
+            NodeData data = node.getData();\r
+            Resource subject = data.getResource();\r
+            ArrayList<Statement> filteredStatements = new ArrayList<Statement>(data.getStatements().size());\r
+            for(Statement stat : data.getStatements()) {\r
+                Resource object = stat.getObject();\r
+                Node node2 = nodeMap.get(object);\r
+                if(node2 != null) {\r
+                    if(object.getResourceId() > subject.getResourceId() ||\r
+                            graph.getPossibleInverse(stat.getPredicate()) == null) {\r
+                        edges.add(createEdge(graph, stat, node, node2));\r
+                    }\r
+                }\r
+                else\r
+                    filteredStatements.add(stat);\r
+            }\r
+            data.setStatements(filteredStatements);\r
+        }\r
+        this.edges = edges;\r
+        this.addedEdges = filterEdgesWithoutNodes( this.addedEdges );\r
+        this.removedEdges = filterEdgesWithoutNodes( this.removedEdges );\r
+    }\r
+\r
+    private ArrayList<Edge> filterEdgesWithoutNodes(Collection<Edge> edges) {\r
+        ArrayList<Edge> result = new ArrayList<Edge>(edges.size());\r
+        for (Edge e : edges) {\r
+            if (!nodeMap.containsValue(e.getA()) || !nodeMap.containsValue(e.getB()))\r
+                continue;\r
+            result.add(e);\r
+        }\r
+        return result;\r
+    }\r
+\r
+    private Edge createEdge(ReadGraph graph, Statement stat, Node n1, Node n2) throws DatabaseException {\r
+        Resource predicate = stat.getPredicate();\r
+        Resource inverse = graph.getPossibleInverse(predicate);        \r
+        if(inverse != null) {\r
+            Layer0 L0 = Layer0.getInstance(graph);\r
+            if(graph.hasStatement(predicate, L0.PartOf, inverse)\r
+                    || predicate.equals(L0.PartOf)\r
+                    || predicate.equals(L0.SuperrelationOf)\r
+                    || predicate.equals(L0.SupertypeOf)) {\r
+                predicate = inverse;\r
+                Node temp = n1;\r
+                n1 = n2;\r
+                n2 = temp;\r
+            }\r
+        }\r
+        Edge edge = new Edge(n1, n2);\r
+        edge.setContent(new LabelContent(new String[] {\r
+                NameUtils.getSafeName(graph, predicate)}));\r
+        return edge;\r
+    }\r
+    \r
+    Node dragging = null;\r
+    double dragDX, dragDY;\r
+    private void handleMouseLeftPressed(double x, double y) {\r
+        Node node;\r
+        if(extensionMode) {\r
+            node = pickExtension(x, y);\r
+            if(node != null) {\r
+                nodes.add(node);\r
+                extensionNodes.remove(node);\r
+            }\r
+        }\r
+        else\r
+            node = pick(x, y);\r
+        if(node != null) {\r
+            dragDX = x - node.getX();\r
+            dragDY = y - node.getY();\r
+            dragging = node;\r
+        }\r
+    }\r
+    \r
+    Point2D panningStartMouse;\r
+    private void handleMouseMiddlePressed(double x, double y) {\r
+        panningStartMouse = new Point2D.Double(x, y);\r
+    }\r
+    \r
+    private void handleMouseMoved(double x, double y) {\r
+        if(dragging != null) {\r
+            dragging.setPos(x-dragDX, y-dragDY);\r
+            repaint();\r
+        }\r
+        if(panningStartMouse != null) {\r
+            canvasPosX -= x - panningStartMouse.getX();\r
+            canvasPosY -= y - panningStartMouse.getY();\r
+            repaint();\r
+        }\r
+    }\r
+    \r
+    private void handleMouseWheelMoved(double x, double y, double amount) {\r
+        double s = Math.exp(-0.2*amount);\r
+        canvasZoom *= s;\r
+        canvasPosX = x - (x-canvasPosX)/s;\r
+        canvasPosY = y - (y-canvasPosY)/s;\r
+        repaint();\r
+    }\r
+\r
+    private void handleMouseReleased(double x, double y) {\r
+        dragging = null;\r
+        panningStartMouse = null;\r
+    }\r
+    \r
+    public void zoomToFit() {\r
+        if(!nodes.isEmpty()) {\r
+            double minX = Double.POSITIVE_INFINITY;\r
+            double minY = Double.POSITIVE_INFINITY;\r
+            double maxX = Double.NEGATIVE_INFINITY;\r
+            double maxY = Double.NEGATIVE_INFINITY;\r
+            System.out.println("(" + minX + "," + minY + ") - (" + maxX + "," + maxY + ")");\r
+            for(Node node : nodes) {\r
+                minX = Math.min(minX, node.getMinX());\r
+                minY = Math.min(minY, node.getMinY());\r
+                maxX = Math.max(maxX, node.getMaxX());\r
+                maxY = Math.max(maxY, node.getMaxY());\r
+            }            \r
+            canvasZoom = Math.min(getWidth()/(maxX-minX), getHeight()/(maxY-minY));\r
+            canvasZoom *= 0.9;\r
+            canvasPosX = minX - 0.5 * (getWidth()/canvasZoom - maxX+minX);\r
+            canvasPosY = minY - 0.5 * (getHeight()/canvasZoom - maxY+minY);\r
+            repaint();\r
+        }\r
+    }\r
+\r
+    THashMap<Resource, Node> extensionNodeMap = new THashMap<Resource, Node>();\r
+    public void initializeExtension() {\r
+        extensionNodes.clear();\r
+        extensionEdges.clear();\r
+        try {\r
+            Simantics.getSession().syncRequest(new ReadRequest() {\r
+                @Override\r
+                public void run(ReadGraph graph) throws DatabaseException {\r
+                    THashMap<Resource, Node> oldExtensionNodeMap = DebuggerCanvas.this.extensionNodeMap;\r
+                    THashMap<Resource, Node> extensionNodeMap = new THashMap<Resource, Node>();\r
+                    for(Node node : nodes) {\r
+                        for(Statement stat : node.getData().getStatements()) {\r
+                            Resource object = stat.getObject();\r
+                            Node node2 = extensionNodeMap.get(object);\r
+                            if(node2 == null) {\r
+                                node2 = oldExtensionNodeMap.get(object);\r
+                                if(node2 == null) {\r
+                                    node2 = new Node(new NodeData(object));\r
+                                    double angle = random.nextDouble() * Math.PI * 2.0;\r
+                                    double dx = Math.cos(angle);\r
+                                    double dy = Math.sin(angle);\r
+                                    double len = 150.0;\r
+                                    node2.setPos(node.getX() + dx*len, node.getY() + dy*len);\r
+                                }\r
+                                node2.getData().updateData(graph, labelingPreferences);                                \r
+                                node2.setContent(new LabelContent(node2.getData().getLabels()));\r
+                                extensionNodeMap.put(object, node2);\r
+                                extensionNodes.add(node2);\r
+                            }\r
+                            extensionEdges.add(createEdge(graph, stat, node, node2));\r
+                        }\r
+                    }\r
+                    DebuggerCanvas.this.extensionNodeMap = extensionNodeMap;\r
+                    layoutExtension();\r
+                }      \r
+            });\r
+        } catch (DatabaseException e) {\r
+            e.printStackTrace();\r
+        }\r
+    }\r
+\r
+    private void layoutExtension() {        \r
+        TObjectIntHashMap<Node> extensionNodeIds = new TObjectIntHashMap<Node>();\r
+        for(int i=0;i<extensionNodes.size();++i)\r
+            extensionNodeIds.put(extensionNodes.get(i), i);\r
+        \r
+        double[][] neighbors = new double[extensionNodes.size()][];\r
+        {\r
+            TDoubleArrayList[] neighborLists = new TDoubleArrayList[neighbors.length];        \r
+            for(int i=0;i<neighborLists.length;++i)\r
+                neighborLists[i] = new TDoubleArrayList();\r
+            for(Edge edge : extensionEdges) {\r
+                int id;\r
+                Node node;\r
+                if(extensionNodeIds.containsKey(edge.getA())) {\r
+                    id = extensionNodeIds.get(edge.getA());\r
+                    node = edge.getB();\r
+                }\r
+                else {\r
+                    id = extensionNodeIds.get(edge.getB());\r
+                    node = edge.getA();\r
+                }\r
+                TDoubleArrayList list = neighborLists[id];\r
+                list.add(node.getX());\r
+                list.add(node.getY());\r
+            }            \r
+            for(int i=0;i<neighborLists.length;++i) {\r
+                neighbors[i] = neighborLists[i].toArray();\r
+            }\r
+        }\r
+        \r
+        double[] fixedRepulsiveX = new double[nodes.size()];\r
+        double[] fixedRepulsiveY = new double[nodes.size()];\r
+        for(int i=0;i<nodes.size();++i) {\r
+            Node node = nodes.get(i);\r
+            fixedRepulsiveX[i] = node.getX();\r
+            fixedRepulsiveY[i] = node.getY();\r
+        }\r
+        ExtensionLayoutAlgorithm algo = \r
+                new ExtensionLayoutAlgorithm(neighbors, fixedRepulsiveX, fixedRepulsiveY);\r
+        double[] posX = algo.getPosX();\r
+        double[] posY = algo.getPosY();\r
+        for(int i=0;i<extensionNodes.size();++i) {\r
+            posX[i] = extensionNodes.get(i).getX();\r
+            posY[i] = extensionNodes.get(i).getY();\r
+        }        \r
+        algo.optimize();\r
+        for(int i=0;i<extensionNodes.size();++i) {\r
+            extensionNodes.get(i).setPos(posX[i], posY[i]);\r
+        }        \r
+    }      \r
+    \r
+    private Node getNode(Resource resource) {\r
+        Node node = nodeMap.get(resource);\r
+        if(node == null) {\r
+            node = addResource(random.nextDouble()*200.0-100.0, \r
+                    random.nextDouble()*200.0-100.0, \r
+                    resource);\r
+            nodeMap.put(resource, node);\r
+        }\r
+        return node;\r
+    }\r
+    \r
+    public void findPreviousChangeset() {\r
+        try {\r
+            Session session = Simantics.getSession();\r
+            final ManagementSupport ms = session.getService(ManagementSupport.class);\r
+            final long lastId = ms.getHeadRevisionId();\r
+            final long firstId = getOpId(ms, lastId);\r
+            //System.out.println(firstId + "-" + lastId);\r
+            addedEdges.clear();\r
+            removedEdges.clear();            \r
+            session.asyncRequest(new ReadRequest() {\r
+                @Override\r
+                public void run(ReadGraph graph) throws DatabaseException {\r
+                    final Collection<ChangeSet> css = \r
+                            ms.fetchChangeSets(graph, firstId, lastId);\r
+                    Layer0 L0 = Layer0.getInstance(graph);\r
+                    for(ChangeSet cs : css) {\r
+                        for(ChangeSet.StatementChange stat : cs.changedStatements()) {\r
+                            Resource predicate = stat.getPredicate();\r
+                            if(predicate.equals(L0.InstanceOf) ||\r
+                                    predicate.equals(L0.HasName) ||\r
+                                    predicate.equals(L0.NameOf))\r
+                                continue;\r
+                            Edge edge = createEdge(graph, stat, \r
+                                    getNode(stat.getSubject()),\r
+                                    getNode(stat.getObject()));\r
+                            if(stat.isClaim())\r
+                                addedEdges.add(edge);\r
+                            else\r
+                                removedEdges.add(edge);\r
+                        }\r
+                    }    \r
+                    scheduleUpdate();\r
+                }                \r
+            });                  \r
+        } catch(DatabaseException e) {\r
+            e.printStackTrace();\r
+        }\r
+    } \r
+    \r
+    private static long getOpId(ManagementSupport ms, long revisionId) throws DatabaseException {\r
+        Collection<ChangeSetIdentifier> ids = ms.getChangeSetIdentifiers(revisionId, revisionId);\r
+        ChangeSetIdentifier curId = ids.iterator().next();\r
+        byte[] opIdData = curId.getMetadata().get("opid");\r
+        System.out.println(new String(opIdData));\r
+        long opId = Long.parseLong(new String(opIdData));\r
+        if(opId == 0)\r
+            opId = revisionId;\r
+        return opId;\r
+    }\r
+\r
+}\r