]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.debug.ui/src/org/simantics/debug/ui/graph/GraphicalDebugger.java
Externalize strings in org.simantics.debug.ui
[simantics/platform.git] / bundles / org.simantics.debug.ui / src / org / simantics / debug / ui / graph / GraphicalDebugger.java
1 package org.simantics.debug.ui.graph;
2
3 import java.awt.Point;
4 import java.awt.event.MouseEvent;
5 import java.awt.event.MouseListener;
6 import java.awt.geom.AffineTransform;
7 import java.awt.geom.NoninvertibleTransformException;
8 import java.awt.geom.Point2D;
9 import java.util.ArrayList;
10 import java.util.Arrays;
11 import java.util.Collection;
12 import java.util.Comparator;
13 import java.util.HashMap;
14 import java.util.HashSet;
15 import java.util.List;
16 import java.util.Map;
17 import java.util.Set;
18
19 import javax.swing.SwingUtilities;
20
21 import org.eclipse.jface.layout.GridDataFactory;
22 import org.eclipse.osgi.util.NLS;
23 import org.eclipse.swt.SWT;
24 import org.eclipse.swt.browser.Browser;
25 import org.eclipse.swt.layout.GridData;
26 import org.eclipse.swt.layout.GridLayout;
27 import org.eclipse.swt.widgets.Composite;
28 import org.simantics.db.ReadGraph;
29 import org.simantics.db.Resource;
30 import org.simantics.db.Session;
31 import org.simantics.db.Statement;
32 import org.simantics.db.common.uri.ResourceToPossibleURI;
33 import org.simantics.db.common.utils.OrderedSetUtils;
34 import org.simantics.db.exception.DatabaseException;
35 import org.simantics.db.exception.ValidationException;
36 import org.simantics.db.service.ClusteringSupport;
37 import org.simantics.debug.ui.GraphDebugger;
38 import org.simantics.debug.ui.internal.HashMultiMap;
39 import org.simantics.graphviz.Edge;
40 import org.simantics.graphviz.Graph;
41 import org.simantics.graphviz.IGraphPart;
42 import org.simantics.graphviz.Node;
43 import org.simantics.graphviz.drawable.ViewerCanvas;
44 import org.simantics.graphviz.ui.GraphvizComponent2;
45 import org.simantics.layer0.Layer0;
46 import org.simantics.utils.datastructures.BijectionMap;
47 import org.simantics.utils.datastructures.MapList;
48 import org.simantics.utils.ui.ErrorLogger;
49
50
51
52 public class GraphicalDebugger extends GraphDebugger {
53         
54         public enum Style{dot,neato,fdp,sfdp,twopi,circo};
55         
56         private Graph graph;
57         private BijectionMap<Resource, Node> nodeMap = new BijectionMap<Resource, Node>();
58         private MapList<Resource, Edge> edgeMap = new MapList<Resource, Edge>();
59         private Map<Edge,Resource> edgeMap2 = new HashMap<Edge, Resource>();
60         private Set<Resource> processed = new HashSet<Resource>();
61         
62         private GraphvizComponent2 graphVizComponent;
63         
64         private int depth = 1;
65         private Style style = Style.dot;
66         
67         public GraphicalDebugger(Composite parent, int style, final Session session, Resource resource) {
68                 super(parent, style, session, resource);
69         }
70         
71         public void defaultInitializeUI() {
72         setLayout(new GridLayout(2, false));
73         setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
74
75         createResourceText(this);
76         createDropLabel(this);
77         createGraph(this);
78
79     }
80         
81         public int getDepth() {
82                 return depth;
83         }
84         
85         public void setDepth(int depth) {
86                 if (depth < 1)
87                         return;
88                 if(depth == this.depth)
89                         return;
90                 this.depth = depth;
91                 refreshBrowser();
92         }
93         
94         public Style getGraphStyle() {
95                 return style;
96         }
97         
98         public void setGraphStyle(Style style) {
99                 if (this.style == style)
100                         return;
101                 this.style = style;
102                 refreshBrowser();
103         }
104         
105         @Override
106         protected void initializeCSS() {
107                 // do nothing
108         }
109         
110         @Override
111         public Browser createBrowser(Composite parent) {
112                 // do nothing
113                 return null;
114         }
115         
116         public GraphvizComponent2 createGraph(Composite parent) {
117                 graph = new Graph();
118                 graph.setRankdir("LR"); //$NON-NLS-1$
119                 graphVizComponent = new GraphvizComponent2(parent, SWT.NONE);
120                 SwingUtilities.invokeLater(new Runnable() {
121                         
122                         @Override
123                         public void run() {
124                                 graphVizComponent.getCanvas().addMouseListener(new MouseListener() {
125                                         
126                                         @Override
127                                         public void mouseReleased(MouseEvent arg0) {
128
129                                         }
130                                         
131                                         @Override
132                                         public void mousePressed(MouseEvent arg0) {
133
134                                         }
135                                         
136                                         @Override
137                                         public void mouseExited(MouseEvent arg0) {
138
139                                         }
140                                         
141                                         @Override
142                                         public void mouseEntered(MouseEvent arg0) {
143
144                                         }
145                                         
146                                         @Override
147                                         public void mouseClicked(MouseEvent arg0) {
148                                                 if (arg0.getClickCount() > 1) {
149                                                         Point p = arg0.getPoint();
150                                                         pick(p);
151                                                 }
152                                         }
153                                 });
154                         }
155                 });
156
157                 GridDataFactory.fillDefaults().span(2, 1).grab(true, true).applyTo(graphVizComponent);
158                 refreshBrowser();
159                 return graphVizComponent;
160         }
161         
162         protected void pick(Point p) {
163                 
164                 AffineTransform at = ((ViewerCanvas)graphVizComponent.getCanvas()).getTransform();
165                 Point2D pickPoint = new Point2D.Double();
166                 try {
167                         at.inverseTransform(new Point2D.Double((double)p.x,(double)p.y), pickPoint);
168                 } catch (NoninvertibleTransformException e) {
169                         return;
170                 }
171
172                 Collection<IGraphPart> parts = graphVizComponent.getDrawable().pick(pickPoint);
173                 for (IGraphPart part : parts) {
174                         if (part instanceof Node) {
175                                 Resource r = nodeMap.getLeft((Node)part);
176                                 if (r != null && !r.equals(getDebuggerLocation())) {
177                                         changeLocation(r);
178                                         return;
179                                 } 
180                                 
181                         } 
182                 }
183                 for (IGraphPart part : parts) {
184                         if (part instanceof Edge) {
185                                 Resource r = edgeMap2.get(part);
186                                 if (r != null && !r.equals(getDebuggerLocation())) {
187                                         changeLocation(r);
188                                         return;
189                                 }
190                         }
191                 }
192         }
193         
194         protected Node getOrCreate(Resource r) {
195                 Node n = nodeMap.getRight(r);
196                 if (n == null) {
197                         n = new Node(graph);
198                         if (!r.isPersistent()) {
199                                 n.setShape("box"); //$NON-NLS-1$
200                                 n.setFontColor("blue"); //$NON-NLS-1$
201                         }
202                         nodeMap.map(r, n);
203                 }
204                 return n;
205         }
206         
207         @SuppressWarnings("unused")
208         protected void appendLabel(Node node, String text) {
209                 String label = node.get("label"); //$NON-NLS-1$
210                 if (true) {
211                         if (label == null || label.length() == 0)
212                                 label = text;//escape(text);
213                         else {
214                                 label = label.substring(1,label.length()-1);
215                                 label += "<br/>"+text; //$NON-NLS-1$
216                         }
217                         label = "<" + label + ">"; //$NON-NLS-1$ //$NON-NLS-2$
218                 } else {
219                         if (label == null || label.length() == 0)
220                                 label = text;
221                         else {
222                                 label += " "+text; //$NON-NLS-1$
223                         }
224                         
225                 }
226                 node.setLabel(label);
227         }
228         
229
230
231         
232         protected synchronized void updateContent(final ReadGraph g, Resource... resources) throws DatabaseException {
233                 L0 = Layer0.getInstance(g);
234                 
235                 graph = new Graph();
236                 graph.setRankdir("LR"); //$NON-NLS-1$
237                 
238                 nodeMap.clear();
239                 edgeMap.clear();
240                 edgeMap2.clear();
241                 processed.clear();
242                 
243                 //links.clear();
244         //StringBuffer content = new StringBuffer();
245
246         // Generate HTML -page
247 //        content.append("<html><head>" + getHead() + "</head>\n");
248 //        content.append("<body>\n");
249 //        content.append("<div id=\"mainContent\">\n");
250
251        // content.append("</div>\n");
252         //content.append("</body></html>\n");
253                 createContent(g, depth, resources);
254        
255                 // Update content
256         //graph.write(System.out);
257         graphVizComponent.setGraph(graph,style.toString());
258         }
259         
260         private void createContent(final ReadGraph g, int iter, Resource... resources) throws DatabaseException {
261                 if (iter == 0)
262                         return;
263         for (Resource r : resources) {
264             if (r == null)
265                 continue;
266             if (processed.contains(r))
267                 continue;
268             Node node = getResourceRef(g, r);
269             if (r.equals(getDebuggerLocation())) {
270                 node.setFillColor("#aaffaa"); //$NON-NLS-1$
271                                 node.setStyle("filled"); //$NON-NLS-1$
272             }
273           //Node node = getOrCreate(r);
274             processed.add(r);
275             
276             
277             
278             String uri = null;
279             try {
280                 uri = g.syncRequest(new ResourceToPossibleURI(r));
281             } catch (Exception e) {
282                 e.printStackTrace();
283                 uri = "Cannot get URI: " + e.getMessage(); //$NON-NLS-1$
284             }
285             if (uri != null)
286                 appendLabel(node, "URI: " + uri); //$NON-NLS-1$
287                 //content.append("\t\t<div class=\"monospaced\">" + uri + "</div><br/>");
288
289             Collection<Statement> statements = g.getStatements(r, L0.IsWeaklyRelatedTo);
290             HashMultiMap<Resource, Resource[]> map = new HashMultiMap<Resource, Resource[]>();
291             for(org.simantics.db.Statement statement : statements) {
292                 Resource predicate = null;
293                 Resource subject = null;
294                 Resource obj = null;
295                 try {
296                     predicate = statement.getPredicate();
297                     subject = statement.getSubject();
298                     obj = statement.getObject();
299                     map.add(predicate, new Resource[] {subject, obj});
300                 } catch (Throwable e) {
301                     e.printStackTrace();
302                     ErrorLogger.defaultLogError("Cannot find statement " + subject + " " + predicate + " " + obj, e); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
303                 }
304             }
305             ClusteringSupport support = g.getSession().getService(ClusteringSupport.class);
306             //content.append("<h3>" + " ["+ r.getResourceId() + "-" + support.getCluster(r) + "] " + "</h3>\n");
307             appendLabel(node,  " ["+ r.getResourceId() + "-" + support.getCluster(r) + "]"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
308             
309             //content.append("<table>\n");
310             //content.append("<tr><th>Predicate</th><th>Object</th></tr>");
311             //content.append("<tr><td class=\"subtitle\" colspan=\"2\">Basic information</td></tr>");
312
313             boolean isOrderedSet = g.isInstanceOf(r, L0.OrderedSet);
314             map.remove(r);
315
316             // BASIC INFORMATION:
317             for (Resource pred :
318                 new Resource[] {L0.HasName, L0.InstanceOf,
319                     L0.Inherits, L0.SubrelationOf,
320                     L0.ConsistsOf, L0.PartOf})
321                 if (map.containsKey(pred))
322                     updatePred(node, g, r, pred, map.remove(pred));
323
324             // TAGS
325             //content.append("<tr><td class=\"subtitle\" colspan=\"2\">Tags</td></tr>");
326             for(Statement stm : statements) {
327                 if(stm.getSubject().equals(stm.getObject())) {
328                     updateTag(node, g, r, stm.getPredicate(), "Tag"); //$NON-NLS-1$
329                     map.remove(stm.getPredicate());
330                 }
331             }
332
333             // ORDERED SETS
334             //content.append("<tr><td class=\"subtitle\" colspan=\"2\">Ordered Sets</td></tr>");
335             for(Statement stm : statements) {
336                 Resource predicate = stm.getPredicate();
337                 if(g.isInstanceOf(stm.getPredicate(), L0.OrderedSet)) {
338                     updateTag(node, g, r, stm.getPredicate(), "Ordered Set"); //$NON-NLS-1$
339                     map.remove(stm.getPredicate());
340                 }
341                 Resource inverse = g.getPossibleInverse(predicate);
342                 if (inverse != null) {
343                     if(g.isInstanceOf(inverse, L0.OrderedSet)) {
344                         map.remove(stm.getPredicate());
345                     }
346                 } else {
347                     // FIXME : should we inform missing inverse
348                 }
349             }
350
351             // IS RELATED TO
352             //content.append("<tr><td class=\"subtitle\" colspan=\"2\">Is Related To</td></tr>");
353
354             // ELEMENTS OF ORDERED SET
355             if(isOrderedSet) {
356                 //content.append("<tr><td class=\"subtitle\" colspan=\"2\">Ordered set</td></tr>");
357                 try {
358                     updateOrderedSet(node, g, r);
359                 } catch (ValidationException e) {
360                     //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>");
361                 }
362             }
363
364             // IS RELATED TO (other)
365             Resource[] preds = map.keySet().toArray(new Resource[0]);
366             final Map<Resource, String> strmap = new HashMap<Resource, String>(preds.length);
367             for(Resource pred : preds) {
368                 String str = htmlEscape(getResourceName(g, pred));
369                 if(str == null)
370                     str = "<null>"; //$NON-NLS-1$
371                 strmap.put(pred, str);
372             }
373             Arrays.sort(preds, new Comparator<Resource>() {
374                 @Override
375                 public int compare(Resource o1, Resource o2) {
376                     return strmap.get(o1).compareTo(strmap.get(o2));
377                 }
378             });
379             for(Resource pred : preds)
380                 if(g.isSubrelationOf(pred, L0.IsRelatedTo))
381                     updatePred(node, g, r, pred, map.get(pred));
382
383             // OTHER STATEMENTS
384             //content.append("<tr><td class=\"subtitle\" colspan=\"2\">Other statements</td></tr>");
385             for(Resource pred : preds)
386                 if(!g.isSubrelationOf(pred, L0.IsRelatedTo))
387                     updatePred(node, g, r, pred, map.get(pred));
388            // content.append("</table>\n");
389             
390             Resource objects[] = new Resource[statements.size()];
391             int i = 0;
392             for (Statement stm : statements) {
393                 objects[i] = stm.getObject();
394                 i++;
395             }
396             createContent(g, iter-1, objects);
397         }
398         }
399         
400         private Node getResourceRef(ReadGraph graph, Resource r) throws DatabaseException {
401         Node node = nodeMap.getRight(r);
402         if (node == null) {
403                 node = getOrCreate(r);
404                 appendLabel(node, htmlEscape(getResourceName(graph, r)));
405         }
406         return node;
407     }
408         
409         private class NodeObject {
410                 public String name;
411                 public Node node;
412                 @SuppressWarnings("unused")
413                 public Resource r;
414                 
415         }
416         
417         private void updatePred(Node node, ReadGraph graph, Resource subj, Resource pred, List<Resource[]> stats) throws DatabaseException {
418         // Generate output content from statements
419         NodeObject[] objects = new NodeObject[stats.size()];
420         for (int i = 0; i < stats.size(); ++i) {
421             Resource stmSubject = stats.get(i)[0];
422             Resource object = stats.get(i)[1];
423
424             objects[i] = new NodeObject();
425             objects[i].r = object;
426             objects[i].name = htmlEscape( getResourceName(graph, object) );
427             objects[i].node = getResourceRef(graph, object);
428
429             // Make a note if the statement was acquired.
430             if(!stmSubject.equals(subj)) {
431                 Node asserted = getResourceRef(graph, stmSubject);
432                 Edge e = new Edge(this.graph, objects[i].node, asserted);
433                 e.setLabel(Messages.GraphicalDebugger_AssertedIn);
434                 
435                 objects[i].node.setFillColor("#ffaaaa"); //$NON-NLS-1$
436                 objects[i].node.setStyle("filled"); //$NON-NLS-1$
437             }
438         }
439
440         // Sort statements by object name
441         Arrays.sort(objects, new Comparator<NodeObject>() {
442             @Override
443             public int compare(NodeObject o1, NodeObject o2) {
444                 return o1.name.compareTo(o2.name);
445             }
446         });
447
448         String predName = getResourceName(graph, pred);
449         // Output table rows
450         for (int i = 0; i < objects.length; ++i) {
451                 Edge e = new Edge(this.graph,node, objects[i].node);
452                 e.setLabel(predName);
453                 edgeMap.add(pred, e);
454                 edgeMap2.put(e, pred);
455             //content.append("<tr>");
456             // Predicate column
457             //if (i == 0)
458                 //content.append("<td rowspan=\"" + objects.length + "\" valign=\"top\">" + getResourceRef(graph, pred) + "</td>");
459
460             // Object column
461             //if (objects[i][3] == null) content.append("<td>");
462             //else content.append("<td class=\"acquired\">");
463
464             //content.append(objects[i][2]);
465             //if (objects[i][3] != null)
466             //    content.append(objects[i][3]);
467
468             //content.append("</td>");
469
470             // Statement remove -link column
471             // Only allowed for non-acquired statements.
472             //if (objects[i][3] == null) {
473             //    content.append("<td class=\"remove\">");
474             //    content.append(getStatementRemoveRef(subj, pred, links.getRight(objects[i][0])));
475             //    content.append("</td>");
476             //}
477             //content.append("</tr>");
478         }
479     }
480         
481         private void updateTag(Node node, ReadGraph graph, Resource subj, Resource tag, String title) throws DatabaseException {
482
483         // Generate output content from statements
484         Node ref = getResourceRef(graph, tag);
485         Edge e = new Edge(this.graph, node, ref);
486         e.setLabel(title);
487         
488 //        content.append("<tr>");
489 //        content.append("<td rowspan=\"1\" colspan=\"2\" valign=\"top\">" + ref + "</td>");
490 //        content.append("<td class=\"remove\">");
491 //        content.append(getStatementRemoveRef(subj, tag, subj));
492 //        content.append("</td>");
493 //        content.append("</tr>");
494
495     }
496         
497         
498         
499         private void updateOrderedSet(Node node, ReadGraph graph, Resource subj) throws DatabaseException {
500
501 //              StringBuffer content = new StringBuffer();
502         //List<String> list = new ArrayList<String>();
503                 List<Node> list = new ArrayList<Node>();
504         Resource cur = subj;
505         while(true) {
506             try {
507                 cur = OrderedSetUtils.next(graph, subj, cur);
508             } catch(DatabaseException e) {
509                 Edge edge = new Edge(this.graph, node, node);
510                 edge.setLabel(Messages.GraphicalDebugger_BrockenOrderedSet);
511                 //list.add("<span style=\"color:red;font-weight:bold\">BROKEN ORDERED SET:<br/></span><span style=\"color:red\">" + e.getMessage() + "</span>");
512 //                Resource inv = graph.getPossibleInverse(subj);
513 //                for(Statement stat : graph.getStatements(cur, L0.IsRelatedTo)) {
514 //                    if(stat.getSubject().equals(cur)) {
515 //                        if(stat.getPredicate().equals(subj)) {
516 //                            list.add("next " + getResourceRef(graph, stat.getObject()));
517 //                        }
518 //                        else if(stat.getPredicate().equals(inv)) {
519 //                            list.add("prev " + getResourceRef(graph, stat.getObject()));
520 //                        }
521 //                    }
522 //                }
523 //                break;
524             }
525             if(cur.equals(subj))
526                 break;
527             //list.add(getResourceName(graph, cur));
528             list.add(getResourceRef(graph, cur));
529         }
530         for (int i = 0; i < list.size() ; ++i) {
531                  Edge e = new Edge(this.graph, node, list.get(i));
532                  e.setLabel(NLS.bind(Messages.GraphicalDebugger_OrderedSetItem , i));
533         }
534
535         // Output table rows
536 //        content.append("<table>\n");
537 //        for (int i = 0; i < list.size() ; ++i) {
538 //            content.append("<tr>");
539 //            // Predicate column
540 //            if (i == 0)
541 //                content.append("<td rowspan=\"" + list.size() + "\" valign=\"top\">Ordered Set Elements</td>");
542 //
543 //            // Object column
544 //            content.append("<td>");
545 //            content.append(list.get(i));
546 //            content.append("</td>");
547 //
548 //            content.append("</tr>");
549 //        }
550 //        content.append("</table>\n");
551 //        appendLabel(node, content.toString());
552     }
553         
554         
555         
556 }