]> gerrit.simantics Code Review - simantics/platform.git/blobdiff - bundles/org.simantics.debug.ui/src/org/simantics/debug/ui/graph/GraphicalDebugger.java
Fixed all line endings of the repository
[simantics/platform.git] / bundles / org.simantics.debug.ui / src / org / simantics / debug / ui / graph / GraphicalDebugger.java
index c2ad9f18afa0c52a93d1f7cebd57a4864e054b1c..fef011b8d4efdcc754d314d23f8df5003ce53b59 100644 (file)
-package org.simantics.debug.ui.graph;\r
-\r
-import java.awt.Point;\r
-import java.awt.event.MouseEvent;\r
-import java.awt.event.MouseListener;\r
-import java.awt.geom.AffineTransform;\r
-import java.awt.geom.NoninvertibleTransformException;\r
-import java.awt.geom.Point2D;\r
-import java.util.ArrayList;\r
-import java.util.Arrays;\r
-import java.util.Collection;\r
-import java.util.Comparator;\r
-import java.util.HashMap;\r
-import java.util.HashSet;\r
-import java.util.List;\r
-import java.util.Map;\r
-import java.util.Set;\r
-\r
-import javax.swing.SwingUtilities;\r
-\r
-import org.eclipse.jface.layout.GridDataFactory;\r
-import org.eclipse.swt.SWT;\r
-import org.eclipse.swt.browser.Browser;\r
-import org.eclipse.swt.layout.GridData;\r
-import org.eclipse.swt.layout.GridLayout;\r
-import org.eclipse.swt.widgets.Composite;\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.uri.ResourceToPossibleURI;\r
-import org.simantics.db.common.utils.OrderedSetUtils;\r
-import org.simantics.db.exception.DatabaseException;\r
-import org.simantics.db.exception.ValidationException;\r
-import org.simantics.db.service.ClusteringSupport;\r
-import org.simantics.debug.ui.GraphDebugger;\r
-import org.simantics.debug.ui.internal.HashMultiMap;\r
-import org.simantics.graphviz.Edge;\r
-import org.simantics.graphviz.Graph;\r
-import org.simantics.graphviz.IGraphPart;\r
-import org.simantics.graphviz.Node;\r
-import org.simantics.graphviz.drawable.ViewerCanvas;\r
-import org.simantics.graphviz.ui.GraphvizComponent2;\r
-import org.simantics.layer0.Layer0;\r
-import org.simantics.utils.datastructures.BijectionMap;\r
-import org.simantics.utils.datastructures.MapList;\r
-import org.simantics.utils.ui.ErrorLogger;\r
-\r
-\r
-\r
-public class GraphicalDebugger extends GraphDebugger {\r
-       \r
-       public enum Style{dot,neato,fdp,sfdp,twopi,circo};\r
-       \r
-       private Graph graph;\r
-       private BijectionMap<Resource, Node> nodeMap = new BijectionMap<Resource, Node>();\r
-       private MapList<Resource, Edge> edgeMap = new MapList<Resource, Edge>();\r
-       private Map<Edge,Resource> edgeMap2 = new HashMap<Edge, Resource>();\r
-       private Set<Resource> processed = new HashSet<Resource>();\r
-       \r
-       private GraphvizComponent2 graphVizComponent;\r
-       \r
-       private int depth = 1;\r
-       private Style style = Style.dot;\r
-       \r
-       public GraphicalDebugger(Composite parent, int style, final Session session, Resource resource) {\r
-               super(parent, style, session, resource);\r
-       }\r
-       \r
-       public void defaultInitializeUI() {\r
-        setLayout(new GridLayout(2, false));\r
-        setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));\r
-\r
-        createResourceText(this);\r
-        createDropLabel(this);\r
-        createGraph(this);\r
-\r
-    }\r
-       \r
-       public int getDepth() {\r
-               return depth;\r
-       }\r
-       \r
-       public void setDepth(int depth) {\r
-               if (depth < 1)\r
-                       return;\r
-               if(depth == this.depth)\r
-                       return;\r
-               this.depth = depth;\r
-               refreshBrowser();\r
-       }\r
-       \r
-       public Style getGraphStyle() {\r
-               return style;\r
-       }\r
-       \r
-       public void setGraphStyle(Style style) {\r
-               if (this.style == style)\r
-                       return;\r
-               this.style = style;\r
-               refreshBrowser();\r
-       }\r
-       \r
-       @Override\r
-       protected void initializeCSS() {\r
-               // do nothing\r
-       }\r
-       \r
-       @Override\r
-       public Browser createBrowser(Composite parent) {\r
-               // do nothing\r
-               return null;\r
-       }\r
-       \r
-       public GraphvizComponent2 createGraph(Composite parent) {\r
-               graph = new Graph();\r
-               graph.setRankdir("LR");\r
-               graphVizComponent = new GraphvizComponent2(parent, SWT.NONE);\r
-               SwingUtilities.invokeLater(new Runnable() {\r
-                       \r
-                       @Override\r
-                       public void run() {\r
-                               graphVizComponent.getCanvas().addMouseListener(new MouseListener() {\r
-                                       \r
-                                       @Override\r
-                                       public void mouseReleased(MouseEvent arg0) {\r
-\r
-                                       }\r
-                                       \r
-                                       @Override\r
-                                       public void mousePressed(MouseEvent arg0) {\r
-\r
-                                       }\r
-                                       \r
-                                       @Override\r
-                                       public void mouseExited(MouseEvent arg0) {\r
-\r
-                                       }\r
-                                       \r
-                                       @Override\r
-                                       public void mouseEntered(MouseEvent arg0) {\r
-\r
-                                       }\r
-                                       \r
-                                       @Override\r
-                                       public void mouseClicked(MouseEvent arg0) {\r
-                                               if (arg0.getClickCount() > 1) {\r
-                                                       Point p = arg0.getPoint();\r
-                                                       pick(p);\r
-                                               }\r
-                                       }\r
-                               });\r
-                       }\r
-               });\r
-\r
-               GridDataFactory.fillDefaults().span(2, 1).grab(true, true).applyTo(graphVizComponent);\r
-               refreshBrowser();\r
-               return graphVizComponent;\r
-       }\r
-       \r
-       protected void pick(Point p) {\r
-               \r
-               AffineTransform at = ((ViewerCanvas)graphVizComponent.getCanvas()).getTransform();\r
-               Point2D pickPoint = new Point2D.Double();\r
-               try {\r
-                       at.inverseTransform(new Point2D.Double((double)p.x,(double)p.y), pickPoint);\r
-               } catch (NoninvertibleTransformException e) {\r
-                       return;\r
-               }\r
-\r
-               Collection<IGraphPart> parts = graphVizComponent.getDrawable().pick(pickPoint);\r
-               for (IGraphPart part : parts) {\r
-                       if (part instanceof Node) {\r
-                               Resource r = nodeMap.getLeft((Node)part);\r
-                               if (r != null && !r.equals(getDebuggerLocation())) {\r
-                                       changeLocation(r);\r
-                                       return;\r
-                               } \r
-                               \r
-                       } \r
-               }\r
-               for (IGraphPart part : parts) {\r
-                       if (part instanceof Edge) {\r
-                               Resource r = edgeMap2.get(part);\r
-                               if (r != null && !r.equals(getDebuggerLocation())) {\r
-                                       changeLocation(r);\r
-                                       return;\r
-                               }\r
-                       }\r
-               }\r
-       }\r
-       \r
-       protected Node getOrCreate(Resource r) {\r
-               Node n = nodeMap.getRight(r);\r
-               if (n == null) {\r
-                       n = new Node(graph);\r
-                       if (!r.isPersistent()) {\r
-                               n.setShape("box");\r
-                               n.setFontColor("blue");\r
-                       }\r
-                       nodeMap.map(r, n);\r
-               }\r
-               return n;\r
-       }\r
-       \r
-       @SuppressWarnings("unused")\r
-       protected void appendLabel(Node node, String text) {\r
-               String label = node.get("label");\r
-               if (true) {\r
-                       if (label == null || label.length() == 0)\r
-                               label = text;//escape(text);\r
-                       else {\r
-                               label = label.substring(1,label.length()-1);\r
-                               label += "<br/>"+text;\r
-                       }\r
-                       label = "<" + label + ">";\r
-               } else {\r
-                       if (label == null || label.length() == 0)\r
-                               label = text;\r
-                       else {\r
-                               label += " "+text;\r
-                       }\r
-                       \r
-               }\r
-               node.setLabel(label);\r
-       }\r
-       \r
-\r
-\r
-       \r
-       protected synchronized void updateContent(final ReadGraph g, Resource... resources) throws DatabaseException {\r
-               L0 = Layer0.getInstance(g);\r
-               \r
-               graph = new Graph();\r
-               graph.setRankdir("LR");\r
-               \r
-               nodeMap.clear();\r
-               edgeMap.clear();\r
-               edgeMap2.clear();\r
-               processed.clear();\r
-               \r
-               //links.clear();\r
-        //StringBuffer content = new StringBuffer();\r
-\r
-        // Generate HTML -page\r
-//        content.append("<html><head>" + getHead() + "</head>\n");\r
-//        content.append("<body>\n");\r
-//        content.append("<div id=\"mainContent\">\n");\r
-\r
-       // content.append("</div>\n");\r
-        //content.append("</body></html>\n");\r
-               createContent(g, depth, resources);\r
-       \r
-               // Update content\r
-        //graph.write(System.out);\r
-        graphVizComponent.setGraph(graph,style.toString());\r
-       }\r
-       \r
-       private void createContent(final ReadGraph g, int iter, Resource... resources) throws DatabaseException {\r
-               if (iter == 0)\r
-                       return;\r
-        for (Resource r : resources) {\r
-            if (r == null)\r
-                continue;\r
-            if (processed.contains(r))\r
-               continue;\r
-            Node node = getResourceRef(g, r);\r
-            if (r.equals(getDebuggerLocation())) {\r
-               node.setFillColor("#aaffaa");\r
-                               node.setStyle("filled");\r
-            }\r
-          //Node node = getOrCreate(r);\r
-            processed.add(r);\r
-            \r
-            \r
-            \r
-            String uri = null;\r
-            try {\r
-                uri = g.syncRequest(new ResourceToPossibleURI(r));\r
-            } catch (Exception e) {\r
-                e.printStackTrace();\r
-                uri = "Cannot get URI: " + e.getMessage();\r
-            }\r
-            if (uri != null)\r
-               appendLabel(node, "URI: " + uri);\r
-                //content.append("\t\t<div class=\"monospaced\">" + uri + "</div><br/>");\r
-\r
-            Collection<Statement> statements = g.getStatements(r, L0.IsWeaklyRelatedTo);\r
-            HashMultiMap<Resource, Resource[]> map = new HashMultiMap<Resource, Resource[]>();\r
-            for(org.simantics.db.Statement statement : statements) {\r
-                Resource predicate = null;\r
-                Resource subject = null;\r
-                Resource obj = null;\r
-                try {\r
-                    predicate = statement.getPredicate();\r
-                    subject = statement.getSubject();\r
-                    obj = statement.getObject();\r
-                    map.add(predicate, new Resource[] {subject, obj});\r
-                } catch (Throwable e) {\r
-                    e.printStackTrace();\r
-                    ErrorLogger.defaultLogError("Cannot find statement " + subject + " " + predicate + " " + obj, e);\r
-                }\r
-            }\r
-            ClusteringSupport support = g.getSession().getService(ClusteringSupport.class);\r
-            //content.append("<h3>" + " ["+ r.getResourceId() + "-" + support.getCluster(r) + "] " + "</h3>\n");\r
-            appendLabel(node,  " ["+ r.getResourceId() + "-" + support.getCluster(r) + "]");\r
-            \r
-            //content.append("<table>\n");\r
-            //content.append("<tr><th>Predicate</th><th>Object</th></tr>");\r
-            //content.append("<tr><td class=\"subtitle\" colspan=\"2\">Basic information</td></tr>");\r
-\r
-            boolean isOrderedSet = g.isInstanceOf(r, L0.OrderedSet);\r
-            map.remove(r);\r
-\r
-            // BASIC INFORMATION:\r
-            for (Resource pred :\r
-                new Resource[] {L0.HasName, L0.InstanceOf,\r
-                    L0.Inherits, L0.SubrelationOf,\r
-                    L0.ConsistsOf, L0.PartOf})\r
-                if (map.containsKey(pred))\r
-                    updatePred(node, g, r, pred, map.remove(pred));\r
-\r
-            // TAGS\r
-            //content.append("<tr><td class=\"subtitle\" colspan=\"2\">Tags</td></tr>");\r
-            for(Statement stm : statements) {\r
-                if(stm.getSubject().equals(stm.getObject())) {\r
-                    updateTag(node, g, r, stm.getPredicate(), "Tag");\r
-                    map.remove(stm.getPredicate());\r
-                }\r
-            }\r
-\r
-            // ORDERED SETS\r
-            //content.append("<tr><td class=\"subtitle\" colspan=\"2\">Ordered Sets</td></tr>");\r
-            for(Statement stm : statements) {\r
-                Resource predicate = stm.getPredicate();\r
-                if(g.isInstanceOf(stm.getPredicate(), L0.OrderedSet)) {\r
-                    updateTag(node, g, r, stm.getPredicate(), "Ordered Set");\r
-                    map.remove(stm.getPredicate());\r
-                }\r
-                Resource inverse = g.getPossibleInverse(predicate);\r
-                if (inverse != null) {\r
-                    if(g.isInstanceOf(inverse, L0.OrderedSet)) {\r
-                        map.remove(stm.getPredicate());\r
-                    }\r
-                } else {\r
-                    // FIXME : should we inform missing inverse\r
-                }\r
-            }\r
-\r
-            // IS RELATED TO\r
-            //content.append("<tr><td class=\"subtitle\" colspan=\"2\">Is Related To</td></tr>");\r
-\r
-            // ELEMENTS OF ORDERED SET\r
-            if(isOrderedSet) {\r
-                //content.append("<tr><td class=\"subtitle\" colspan=\"2\">Ordered set</td></tr>");\r
-                try {\r
-                    updateOrderedSet(node, g, r);\r
-                } catch (ValidationException e) {\r
-                    //content.append("<td colspan=\"2\"><span style=\"color:red;font-weight:bold\">BROKEN ORDERED SET:<br/></span><span style=\"color:red\">" + e.getMessage() + "</span></td>");\r
-                }\r
-            }\r
-\r
-            // IS RELATED TO (other)\r
-            Resource[] preds = map.keySet().toArray(new Resource[0]);\r
-            final Map<Resource, String> strmap = new HashMap<Resource, String>(preds.length);\r
-            for(Resource pred : preds) {\r
-                String str = htmlEscape(getResourceName(g, pred));\r
-                if(str == null)\r
-                    str = "<null>";\r
-                strmap.put(pred, str);\r
-            }\r
-            Arrays.sort(preds, new Comparator<Resource>() {\r
-                @Override\r
-                public int compare(Resource o1, Resource o2) {\r
-                    return strmap.get(o1).compareTo(strmap.get(o2));\r
-                }\r
-            });\r
-            for(Resource pred : preds)\r
-                if(g.isSubrelationOf(pred, L0.IsRelatedTo))\r
-                    updatePred(node, g, r, pred, map.get(pred));\r
-\r
-            // OTHER STATEMENTS\r
-            //content.append("<tr><td class=\"subtitle\" colspan=\"2\">Other statements</td></tr>");\r
-            for(Resource pred : preds)\r
-                if(!g.isSubrelationOf(pred, L0.IsRelatedTo))\r
-                    updatePred(node, g, r, pred, map.get(pred));\r
-           // content.append("</table>\n");\r
-            \r
-            Resource objects[] = new Resource[statements.size()];\r
-            int i = 0;\r
-            for (Statement stm : statements) {\r
-               objects[i] = stm.getObject();\r
-               i++;\r
-            }\r
-            createContent(g, iter-1, objects);\r
-        }\r
-       }\r
-       \r
-       private Node getResourceRef(ReadGraph graph, Resource r) throws DatabaseException {\r
-        Node node = nodeMap.getRight(r);\r
-        if (node == null) {\r
-               node = getOrCreate(r);\r
-               appendLabel(node, htmlEscape(getResourceName(graph, r)));\r
-        }\r
-        return node;\r
-    }\r
-       \r
-       private class NodeObject {\r
-               public String name;\r
-               public Node node;\r
-               @SuppressWarnings("unused")\r
-               public Resource r;\r
-               \r
-       }\r
-       \r
-       private void updatePred(Node node, ReadGraph graph, Resource subj, Resource pred, List<Resource[]> stats) throws DatabaseException {\r
-        // Generate output content from statements\r
-        NodeObject[] objects = new NodeObject[stats.size()];\r
-        for (int i = 0; i < stats.size(); ++i) {\r
-            Resource stmSubject = stats.get(i)[0];\r
-            Resource object = stats.get(i)[1];\r
-\r
-            objects[i] = new NodeObject();\r
-            objects[i].r = object;\r
-            objects[i].name = htmlEscape( getResourceName(graph, object) );\r
-            objects[i].node = getResourceRef(graph, object);\r
-\r
-            // Make a note if the statement was acquired.\r
-            if(!stmSubject.equals(subj)) {\r
-                Node asserted = getResourceRef(graph, stmSubject);\r
-                Edge e = new Edge(this.graph, objects[i].node, asserted);\r
-                e.setLabel("Asserted in");\r
-                \r
-                objects[i].node.setFillColor("#ffaaaa");\r
-                objects[i].node.setStyle("filled");\r
-            }\r
-        }\r
-\r
-        // Sort statements by object name\r
-        Arrays.sort(objects, new Comparator<NodeObject>() {\r
-            @Override\r
-            public int compare(NodeObject o1, NodeObject o2) {\r
-                return o1.name.compareTo(o2.name);\r
-            }\r
-        });\r
-\r
-        String predName = getResourceName(graph, pred);\r
-        // Output table rows\r
-        for (int i = 0; i < objects.length; ++i) {\r
-               Edge e = new Edge(this.graph,node, objects[i].node);\r
-               e.setLabel(predName);\r
-               edgeMap.add(pred, e);\r
-               edgeMap2.put(e, pred);\r
-            //content.append("<tr>");\r
-            // Predicate column\r
-            //if (i == 0)\r
-                //content.append("<td rowspan=\"" + objects.length + "\" valign=\"top\">" + getResourceRef(graph, pred) + "</td>");\r
-\r
-            // Object column\r
-            //if (objects[i][3] == null) content.append("<td>");\r
-            //else content.append("<td class=\"acquired\">");\r
-\r
-            //content.append(objects[i][2]);\r
-            //if (objects[i][3] != null)\r
-            //    content.append(objects[i][3]);\r
-\r
-            //content.append("</td>");\r
-\r
-            // Statement remove -link column\r
-            // Only allowed for non-acquired statements.\r
-            //if (objects[i][3] == null) {\r
-            //    content.append("<td class=\"remove\">");\r
-            //    content.append(getStatementRemoveRef(subj, pred, links.getRight(objects[i][0])));\r
-            //    content.append("</td>");\r
-            //}\r
-            //content.append("</tr>");\r
-        }\r
-    }\r
-       \r
-       private void updateTag(Node node, ReadGraph graph, Resource subj, Resource tag, String title) throws DatabaseException {\r
-\r
-        // Generate output content from statements\r
-        Node ref = getResourceRef(graph, tag);\r
-        Edge e = new Edge(this.graph, node, ref);\r
-        e.setLabel(title);\r
-        \r
-//        content.append("<tr>");\r
-//        content.append("<td rowspan=\"1\" colspan=\"2\" valign=\"top\">" + ref + "</td>");\r
-//        content.append("<td class=\"remove\">");\r
-//        content.append(getStatementRemoveRef(subj, tag, subj));\r
-//        content.append("</td>");\r
-//        content.append("</tr>");\r
-\r
-    }\r
-       \r
-       \r
-       \r
-       private void updateOrderedSet(Node node, ReadGraph graph, Resource subj) throws DatabaseException {\r
-\r
-//             StringBuffer content = new StringBuffer();\r
-        //List<String> list = new ArrayList<String>();\r
-               List<Node> list = new ArrayList<Node>();\r
-        Resource cur = subj;\r
-        while(true) {\r
-            try {\r
-                cur = OrderedSetUtils.next(graph, subj, cur);\r
-            } catch(DatabaseException e) {\r
-               Edge edge = new Edge(this.graph, node, node);\r
-               edge.setLabel("Broken Ordered Set");\r
-                //list.add("<span style=\"color:red;font-weight:bold\">BROKEN ORDERED SET:<br/></span><span style=\"color:red\">" + e.getMessage() + "</span>");\r
-//                Resource inv = graph.getPossibleInverse(subj);\r
-//                for(Statement stat : graph.getStatements(cur, L0.IsRelatedTo)) {\r
-//                    if(stat.getSubject().equals(cur)) {\r
-//                        if(stat.getPredicate().equals(subj)) {\r
-//                            list.add("next " + getResourceRef(graph, stat.getObject()));\r
-//                        }\r
-//                        else if(stat.getPredicate().equals(inv)) {\r
-//                            list.add("prev " + getResourceRef(graph, stat.getObject()));\r
-//                        }\r
-//                    }\r
-//                }\r
-//                break;\r
-            }\r
-            if(cur.equals(subj))\r
-                break;\r
-            //list.add(getResourceName(graph, cur));\r
-            list.add(getResourceRef(graph, cur));\r
-        }\r
-        for (int i = 0; i < list.size() ; ++i) {\r
-                Edge e = new Edge(this.graph, node, list.get(i));\r
-                e.setLabel("Oredered set item " + i);\r
-        }\r
-\r
-        // Output table rows\r
-//        content.append("<table>\n");\r
-//        for (int i = 0; i < list.size() ; ++i) {\r
-//            content.append("<tr>");\r
-//            // Predicate column\r
-//            if (i == 0)\r
-//                content.append("<td rowspan=\"" + list.size() + "\" valign=\"top\">Ordered Set Elements</td>");\r
-//\r
-//            // Object column\r
-//            content.append("<td>");\r
-//            content.append(list.get(i));\r
-//            content.append("</td>");\r
-//\r
-//            content.append("</tr>");\r
-//        }\r
-//        content.append("</table>\n");\r
-//        appendLabel(node, content.toString());\r
-    }\r
-       \r
-       \r
-       \r
-}\r
+package org.simantics.debug.ui.graph;
+
+import java.awt.Point;
+import java.awt.event.MouseEvent;
+import java.awt.event.MouseListener;
+import java.awt.geom.AffineTransform;
+import java.awt.geom.NoninvertibleTransformException;
+import java.awt.geom.Point2D;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import javax.swing.SwingUtilities;
+
+import org.eclipse.jface.layout.GridDataFactory;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.browser.Browser;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Composite;
+import org.simantics.db.ReadGraph;
+import org.simantics.db.Resource;
+import org.simantics.db.Session;
+import org.simantics.db.Statement;
+import org.simantics.db.common.uri.ResourceToPossibleURI;
+import org.simantics.db.common.utils.OrderedSetUtils;
+import org.simantics.db.exception.DatabaseException;
+import org.simantics.db.exception.ValidationException;
+import org.simantics.db.service.ClusteringSupport;
+import org.simantics.debug.ui.GraphDebugger;
+import org.simantics.debug.ui.internal.HashMultiMap;
+import org.simantics.graphviz.Edge;
+import org.simantics.graphviz.Graph;
+import org.simantics.graphviz.IGraphPart;
+import org.simantics.graphviz.Node;
+import org.simantics.graphviz.drawable.ViewerCanvas;
+import org.simantics.graphviz.ui.GraphvizComponent2;
+import org.simantics.layer0.Layer0;
+import org.simantics.utils.datastructures.BijectionMap;
+import org.simantics.utils.datastructures.MapList;
+import org.simantics.utils.ui.ErrorLogger;
+
+
+
+public class GraphicalDebugger extends GraphDebugger {
+       
+       public enum Style{dot,neato,fdp,sfdp,twopi,circo};
+       
+       private Graph graph;
+       private BijectionMap<Resource, Node> nodeMap = new BijectionMap<Resource, Node>();
+       private MapList<Resource, Edge> edgeMap = new MapList<Resource, Edge>();
+       private Map<Edge,Resource> edgeMap2 = new HashMap<Edge, Resource>();
+       private Set<Resource> processed = new HashSet<Resource>();
+       
+       private GraphvizComponent2 graphVizComponent;
+       
+       private int depth = 1;
+       private Style style = Style.dot;
+       
+       public GraphicalDebugger(Composite parent, int style, final Session session, Resource resource) {
+               super(parent, style, session, resource);
+       }
+       
+       public void defaultInitializeUI() {
+        setLayout(new GridLayout(2, false));
+        setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
+
+        createResourceText(this);
+        createDropLabel(this);
+        createGraph(this);
+
+    }
+       
+       public int getDepth() {
+               return depth;
+       }
+       
+       public void setDepth(int depth) {
+               if (depth < 1)
+                       return;
+               if(depth == this.depth)
+                       return;
+               this.depth = depth;
+               refreshBrowser();
+       }
+       
+       public Style getGraphStyle() {
+               return style;
+       }
+       
+       public void setGraphStyle(Style style) {
+               if (this.style == style)
+                       return;
+               this.style = style;
+               refreshBrowser();
+       }
+       
+       @Override
+       protected void initializeCSS() {
+               // do nothing
+       }
+       
+       @Override
+       public Browser createBrowser(Composite parent) {
+               // do nothing
+               return null;
+       }
+       
+       public GraphvizComponent2 createGraph(Composite parent) {
+               graph = new Graph();
+               graph.setRankdir("LR");
+               graphVizComponent = new GraphvizComponent2(parent, SWT.NONE);
+               SwingUtilities.invokeLater(new Runnable() {
+                       
+                       @Override
+                       public void run() {
+                               graphVizComponent.getCanvas().addMouseListener(new MouseListener() {
+                                       
+                                       @Override
+                                       public void mouseReleased(MouseEvent arg0) {
+
+                                       }
+                                       
+                                       @Override
+                                       public void mousePressed(MouseEvent arg0) {
+
+                                       }
+                                       
+                                       @Override
+                                       public void mouseExited(MouseEvent arg0) {
+
+                                       }
+                                       
+                                       @Override
+                                       public void mouseEntered(MouseEvent arg0) {
+
+                                       }
+                                       
+                                       @Override
+                                       public void mouseClicked(MouseEvent arg0) {
+                                               if (arg0.getClickCount() > 1) {
+                                                       Point p = arg0.getPoint();
+                                                       pick(p);
+                                               }
+                                       }
+                               });
+                       }
+               });
+
+               GridDataFactory.fillDefaults().span(2, 1).grab(true, true).applyTo(graphVizComponent);
+               refreshBrowser();
+               return graphVizComponent;
+       }
+       
+       protected void pick(Point p) {
+               
+               AffineTransform at = ((ViewerCanvas)graphVizComponent.getCanvas()).getTransform();
+               Point2D pickPoint = new Point2D.Double();
+               try {
+                       at.inverseTransform(new Point2D.Double((double)p.x,(double)p.y), pickPoint);
+               } catch (NoninvertibleTransformException e) {
+                       return;
+               }
+
+               Collection<IGraphPart> parts = graphVizComponent.getDrawable().pick(pickPoint);
+               for (IGraphPart part : parts) {
+                       if (part instanceof Node) {
+                               Resource r = nodeMap.getLeft((Node)part);
+                               if (r != null && !r.equals(getDebuggerLocation())) {
+                                       changeLocation(r);
+                                       return;
+                               } 
+                               
+                       } 
+               }
+               for (IGraphPart part : parts) {
+                       if (part instanceof Edge) {
+                               Resource r = edgeMap2.get(part);
+                               if (r != null && !r.equals(getDebuggerLocation())) {
+                                       changeLocation(r);
+                                       return;
+                               }
+                       }
+               }
+       }
+       
+       protected Node getOrCreate(Resource r) {
+               Node n = nodeMap.getRight(r);
+               if (n == null) {
+                       n = new Node(graph);
+                       if (!r.isPersistent()) {
+                               n.setShape("box");
+                               n.setFontColor("blue");
+                       }
+                       nodeMap.map(r, n);
+               }
+               return n;
+       }
+       
+       @SuppressWarnings("unused")
+       protected void appendLabel(Node node, String text) {
+               String label = node.get("label");
+               if (true) {
+                       if (label == null || label.length() == 0)
+                               label = text;//escape(text);
+                       else {
+                               label = label.substring(1,label.length()-1);
+                               label += "<br/>"+text;
+                       }
+                       label = "<" + label + ">";
+               } else {
+                       if (label == null || label.length() == 0)
+                               label = text;
+                       else {
+                               label += " "+text;
+                       }
+                       
+               }
+               node.setLabel(label);
+       }
+       
+
+
+       
+       protected synchronized void updateContent(final ReadGraph g, Resource... resources) throws DatabaseException {
+               L0 = Layer0.getInstance(g);
+               
+               graph = new Graph();
+               graph.setRankdir("LR");
+               
+               nodeMap.clear();
+               edgeMap.clear();
+               edgeMap2.clear();
+               processed.clear();
+               
+               //links.clear();
+        //StringBuffer content = new StringBuffer();
+
+        // Generate HTML -page
+//        content.append("<html><head>" + getHead() + "</head>\n");
+//        content.append("<body>\n");
+//        content.append("<div id=\"mainContent\">\n");
+
+       // content.append("</div>\n");
+        //content.append("</body></html>\n");
+               createContent(g, depth, resources);
+       
+               // Update content
+        //graph.write(System.out);
+        graphVizComponent.setGraph(graph,style.toString());
+       }
+       
+       private void createContent(final ReadGraph g, int iter, Resource... resources) throws DatabaseException {
+               if (iter == 0)
+                       return;
+        for (Resource r : resources) {
+            if (r == null)
+                continue;
+            if (processed.contains(r))
+               continue;
+            Node node = getResourceRef(g, r);
+            if (r.equals(getDebuggerLocation())) {
+               node.setFillColor("#aaffaa");
+                               node.setStyle("filled");
+            }
+          //Node node = getOrCreate(r);
+            processed.add(r);
+            
+            
+            
+            String uri = null;
+            try {
+                uri = g.syncRequest(new ResourceToPossibleURI(r));
+            } catch (Exception e) {
+                e.printStackTrace();
+                uri = "Cannot get URI: " + e.getMessage();
+            }
+            if (uri != null)
+               appendLabel(node, "URI: " + uri);
+                //content.append("\t\t<div class=\"monospaced\">" + uri + "</div><br/>");
+
+            Collection<Statement> statements = g.getStatements(r, L0.IsWeaklyRelatedTo);
+            HashMultiMap<Resource, Resource[]> map = new HashMultiMap<Resource, Resource[]>();
+            for(org.simantics.db.Statement statement : statements) {
+                Resource predicate = null;
+                Resource subject = null;
+                Resource obj = null;
+                try {
+                    predicate = statement.getPredicate();
+                    subject = statement.getSubject();
+                    obj = statement.getObject();
+                    map.add(predicate, new Resource[] {subject, obj});
+                } catch (Throwable e) {
+                    e.printStackTrace();
+                    ErrorLogger.defaultLogError("Cannot find statement " + subject + " " + predicate + " " + obj, e);
+                }
+            }
+            ClusteringSupport support = g.getSession().getService(ClusteringSupport.class);
+            //content.append("<h3>" + " ["+ r.getResourceId() + "-" + support.getCluster(r) + "] " + "</h3>\n");
+            appendLabel(node,  " ["+ r.getResourceId() + "-" + support.getCluster(r) + "]");
+            
+            //content.append("<table>\n");
+            //content.append("<tr><th>Predicate</th><th>Object</th></tr>");
+            //content.append("<tr><td class=\"subtitle\" colspan=\"2\">Basic information</td></tr>");
+
+            boolean isOrderedSet = g.isInstanceOf(r, L0.OrderedSet);
+            map.remove(r);
+
+            // BASIC INFORMATION:
+            for (Resource pred :
+                new Resource[] {L0.HasName, L0.InstanceOf,
+                    L0.Inherits, L0.SubrelationOf,
+                    L0.ConsistsOf, L0.PartOf})
+                if (map.containsKey(pred))
+                    updatePred(node, g, r, pred, map.remove(pred));
+
+            // TAGS
+            //content.append("<tr><td class=\"subtitle\" colspan=\"2\">Tags</td></tr>");
+            for(Statement stm : statements) {
+                if(stm.getSubject().equals(stm.getObject())) {
+                    updateTag(node, g, r, stm.getPredicate(), "Tag");
+                    map.remove(stm.getPredicate());
+                }
+            }
+
+            // ORDERED SETS
+            //content.append("<tr><td class=\"subtitle\" colspan=\"2\">Ordered Sets</td></tr>");
+            for(Statement stm : statements) {
+                Resource predicate = stm.getPredicate();
+                if(g.isInstanceOf(stm.getPredicate(), L0.OrderedSet)) {
+                    updateTag(node, g, r, stm.getPredicate(), "Ordered Set");
+                    map.remove(stm.getPredicate());
+                }
+                Resource inverse = g.getPossibleInverse(predicate);
+                if (inverse != null) {
+                    if(g.isInstanceOf(inverse, L0.OrderedSet)) {
+                        map.remove(stm.getPredicate());
+                    }
+                } else {
+                    // FIXME : should we inform missing inverse
+                }
+            }
+
+            // IS RELATED TO
+            //content.append("<tr><td class=\"subtitle\" colspan=\"2\">Is Related To</td></tr>");
+
+            // ELEMENTS OF ORDERED SET
+            if(isOrderedSet) {
+                //content.append("<tr><td class=\"subtitle\" colspan=\"2\">Ordered set</td></tr>");
+                try {
+                    updateOrderedSet(node, g, r);
+                } catch (ValidationException e) {
+                    //content.append("<td colspan=\"2\"><span style=\"color:red;font-weight:bold\">BROKEN ORDERED SET:<br/></span><span style=\"color:red\">" + e.getMessage() + "</span></td>");
+                }
+            }
+
+            // IS RELATED TO (other)
+            Resource[] preds = map.keySet().toArray(new Resource[0]);
+            final Map<Resource, String> strmap = new HashMap<Resource, String>(preds.length);
+            for(Resource pred : preds) {
+                String str = htmlEscape(getResourceName(g, pred));
+                if(str == null)
+                    str = "<null>";
+                strmap.put(pred, str);
+            }
+            Arrays.sort(preds, new Comparator<Resource>() {
+                @Override
+                public int compare(Resource o1, Resource o2) {
+                    return strmap.get(o1).compareTo(strmap.get(o2));
+                }
+            });
+            for(Resource pred : preds)
+                if(g.isSubrelationOf(pred, L0.IsRelatedTo))
+                    updatePred(node, g, r, pred, map.get(pred));
+
+            // OTHER STATEMENTS
+            //content.append("<tr><td class=\"subtitle\" colspan=\"2\">Other statements</td></tr>");
+            for(Resource pred : preds)
+                if(!g.isSubrelationOf(pred, L0.IsRelatedTo))
+                    updatePred(node, g, r, pred, map.get(pred));
+           // content.append("</table>\n");
+            
+            Resource objects[] = new Resource[statements.size()];
+            int i = 0;
+            for (Statement stm : statements) {
+               objects[i] = stm.getObject();
+               i++;
+            }
+            createContent(g, iter-1, objects);
+        }
+       }
+       
+       private Node getResourceRef(ReadGraph graph, Resource r) throws DatabaseException {
+        Node node = nodeMap.getRight(r);
+        if (node == null) {
+               node = getOrCreate(r);
+               appendLabel(node, htmlEscape(getResourceName(graph, r)));
+        }
+        return node;
+    }
+       
+       private class NodeObject {
+               public String name;
+               public Node node;
+               @SuppressWarnings("unused")
+               public Resource r;
+               
+       }
+       
+       private void updatePred(Node node, ReadGraph graph, Resource subj, Resource pred, List<Resource[]> stats) throws DatabaseException {
+        // Generate output content from statements
+        NodeObject[] objects = new NodeObject[stats.size()];
+        for (int i = 0; i < stats.size(); ++i) {
+            Resource stmSubject = stats.get(i)[0];
+            Resource object = stats.get(i)[1];
+
+            objects[i] = new NodeObject();
+            objects[i].r = object;
+            objects[i].name = htmlEscape( getResourceName(graph, object) );
+            objects[i].node = getResourceRef(graph, object);
+
+            // Make a note if the statement was acquired.
+            if(!stmSubject.equals(subj)) {
+                Node asserted = getResourceRef(graph, stmSubject);
+                Edge e = new Edge(this.graph, objects[i].node, asserted);
+                e.setLabel("Asserted in");
+                
+                objects[i].node.setFillColor("#ffaaaa");
+                objects[i].node.setStyle("filled");
+            }
+        }
+
+        // Sort statements by object name
+        Arrays.sort(objects, new Comparator<NodeObject>() {
+            @Override
+            public int compare(NodeObject o1, NodeObject o2) {
+                return o1.name.compareTo(o2.name);
+            }
+        });
+
+        String predName = getResourceName(graph, pred);
+        // Output table rows
+        for (int i = 0; i < objects.length; ++i) {
+               Edge e = new Edge(this.graph,node, objects[i].node);
+               e.setLabel(predName);
+               edgeMap.add(pred, e);
+               edgeMap2.put(e, pred);
+            //content.append("<tr>");
+            // Predicate column
+            //if (i == 0)
+                //content.append("<td rowspan=\"" + objects.length + "\" valign=\"top\">" + getResourceRef(graph, pred) + "</td>");
+
+            // Object column
+            //if (objects[i][3] == null) content.append("<td>");
+            //else content.append("<td class=\"acquired\">");
+
+            //content.append(objects[i][2]);
+            //if (objects[i][3] != null)
+            //    content.append(objects[i][3]);
+
+            //content.append("</td>");
+
+            // Statement remove -link column
+            // Only allowed for non-acquired statements.
+            //if (objects[i][3] == null) {
+            //    content.append("<td class=\"remove\">");
+            //    content.append(getStatementRemoveRef(subj, pred, links.getRight(objects[i][0])));
+            //    content.append("</td>");
+            //}
+            //content.append("</tr>");
+        }
+    }
+       
+       private void updateTag(Node node, ReadGraph graph, Resource subj, Resource tag, String title) throws DatabaseException {
+
+        // Generate output content from statements
+        Node ref = getResourceRef(graph, tag);
+        Edge e = new Edge(this.graph, node, ref);
+        e.setLabel(title);
+        
+//        content.append("<tr>");
+//        content.append("<td rowspan=\"1\" colspan=\"2\" valign=\"top\">" + ref + "</td>");
+//        content.append("<td class=\"remove\">");
+//        content.append(getStatementRemoveRef(subj, tag, subj));
+//        content.append("</td>");
+//        content.append("</tr>");
+
+    }
+       
+       
+       
+       private void updateOrderedSet(Node node, ReadGraph graph, Resource subj) throws DatabaseException {
+
+//             StringBuffer content = new StringBuffer();
+        //List<String> list = new ArrayList<String>();
+               List<Node> list = new ArrayList<Node>();
+        Resource cur = subj;
+        while(true) {
+            try {
+                cur = OrderedSetUtils.next(graph, subj, cur);
+            } catch(DatabaseException e) {
+               Edge edge = new Edge(this.graph, node, node);
+               edge.setLabel("Broken Ordered Set");
+                //list.add("<span style=\"color:red;font-weight:bold\">BROKEN ORDERED SET:<br/></span><span style=\"color:red\">" + e.getMessage() + "</span>");
+//                Resource inv = graph.getPossibleInverse(subj);
+//                for(Statement stat : graph.getStatements(cur, L0.IsRelatedTo)) {
+//                    if(stat.getSubject().equals(cur)) {
+//                        if(stat.getPredicate().equals(subj)) {
+//                            list.add("next " + getResourceRef(graph, stat.getObject()));
+//                        }
+//                        else if(stat.getPredicate().equals(inv)) {
+//                            list.add("prev " + getResourceRef(graph, stat.getObject()));
+//                        }
+//                    }
+//                }
+//                break;
+            }
+            if(cur.equals(subj))
+                break;
+            //list.add(getResourceName(graph, cur));
+            list.add(getResourceRef(graph, cur));
+        }
+        for (int i = 0; i < list.size() ; ++i) {
+                Edge e = new Edge(this.graph, node, list.get(i));
+                e.setLabel("Oredered set item " + i);
+        }
+
+        // Output table rows
+//        content.append("<table>\n");
+//        for (int i = 0; i < list.size() ; ++i) {
+//            content.append("<tr>");
+//            // Predicate column
+//            if (i == 0)
+//                content.append("<td rowspan=\"" + list.size() + "\" valign=\"top\">Ordered Set Elements</td>");
+//
+//            // Object column
+//            content.append("<td>");
+//            content.append(list.get(i));
+//            content.append("</td>");
+//
+//            content.append("</tr>");
+//        }
+//        content.append("</table>\n");
+//        appendLabel(node, content.toString());
+    }
+       
+       
+       
+}