--- /dev/null
+package org.simantics.sysdyn.ui.dependencies;\r
+\r
+import java.util.ArrayList;\r
+import java.util.Collection;\r
+import java.util.HashMap;\r
+\r
+import org.simantics.db.ReadGraph;\r
+import org.simantics.db.Resource;\r
+import org.simantics.db.exception.DatabaseException;\r
+import org.simantics.db.request.Read;\r
+import org.simantics.graphviz.Edge;\r
+import org.simantics.graphviz.Graph;\r
+import org.simantics.graphviz.IGraph;\r
+import org.simantics.graphviz.Node;\r
+import org.simantics.sysdyn.SysdynResource;\r
+\r
+public class CreateDependencyGraph implements Read<Graph> {\r
+\r
+ Resource root;\r
+ HashMap<Resource, Node> nodes;\r
+ boolean isInverted;\r
+ int levels;\r
+\r
+ public CreateDependencyGraph(Resource root, int levels, boolean isInverted) {\r
+ this.root = root;\r
+ this.nodes = new HashMap<Resource, Node>();\r
+ this.isInverted = isInverted; \r
+ this.levels = levels;\r
+ }\r
+\r
+ @Override\r
+ public Graph perform(ReadGraph g) throws DatabaseException {\r
+ Graph graph = new Graph();\r
+ graph.setRankdir("LR");\r
+ if (g.isInstanceOf(root, SysdynResource.getInstance(g).IndependentVariable)) {\r
+ Collection<Resource> resources = new ArrayList<Resource>(); \r
+ resources.add(root);\r
+ for (int i = 0; i < levels && !resources.isEmpty(); i++) {\r
+ Collection<Resource> newResources = new ArrayList<Resource>();\r
+ for(Resource r : resources) {\r
+ newResources.addAll(getDependencies(g, graph, r));\r
+ }\r
+ resources = new ArrayList<Resource>(newResources);\r
+ }\r
+ }\r
+ return graph;\r
+ }\r
+ \r
+ private Collection<Resource> getDependencies(ReadGraph g, IGraph graph, Resource r) throws DatabaseException{\r
+ SysdynResource sr = SysdynResource.getInstance(g);\r
+ Resource headRelation = sr.IsHeadOf;\r
+ Resource tailRelation = sr.HasTail; \r
+ if(isInverted) {\r
+ headRelation = sr.IsTailOf;\r
+ tailRelation = sr.HasHead;\r
+ }\r
+ \r
+ Node n;\r
+ if (!nodes.containsKey(r)) {\r
+ n = new Node(graph, getName(g, r));\r
+ setShape(g, r, n);\r
+ n.set("style", "filled");\r
+ n.setFillColor("#d3d3d3");\r
+ nodes.put(r, n);\r
+ }\r
+ \r
+ Collection<Resource> dependencies = g.getObjects(r, headRelation);\r
+ Collection<Resource> dependants = new ArrayList<Resource>();\r
+ for(Resource d : dependencies) {\r
+ Resource dependant = g.getSingleObject(d, tailRelation);\r
+ if(!g.isInstanceOf(dependant, sr.IndependentVariable)) {\r
+ break;\r
+ }\r
+ if( !nodes.containsKey(dependant)) {\r
+ n= new Node(graph, getName(g, dependant));\r
+ setShape(g, dependant, n);\r
+ nodes.put(dependant, n);\r
+ dependants.add(dependant);\r
+ } else {\r
+ n = nodes.get(dependant);\r
+ }\r
+ if(isInverted) \r
+ new Edge(graph, nodes.get(r), n);\r
+ else\r
+ new Edge(graph, n, nodes.get(r));\r
+ }\r
+ return dependants;\r
+ }\r
+\r
+ private void setShape(ReadGraph g, Resource r, Node n) throws DatabaseException {\r
+ SysdynResource sr = SysdynResource.getInstance(g);\r
+ if(g.isInstanceOf(r, sr.Stock))\r
+ n.setShape("rectangle");\r
+ else\r
+ n.setShape("ellipse");\r
+ }\r
+\r
+ private String getName(ReadGraph g, Resource r) throws DatabaseException {\r
+ return (String)g.getRelatedValue(r, g.getBuiltins().HasName);\r
+ }\r
+\r
+}\r
--- /dev/null
+package org.simantics.sysdyn.ui.dependencies;\r
+\r
+import org.eclipse.core.runtime.IProgressMonitor;\r
+import org.eclipse.core.runtime.IStatus;\r
+import org.eclipse.core.runtime.Status;\r
+import org.eclipse.core.runtime.jobs.Job;\r
+import org.eclipse.jface.layout.GridDataFactory;\r
+import org.eclipse.jface.layout.GridLayoutFactory;\r
+import org.eclipse.jface.viewers.ISelection;\r
+import org.eclipse.jface.viewers.IStructuredSelection;\r
+import org.eclipse.swt.SWT;\r
+import org.eclipse.swt.events.ModifyEvent;\r
+import org.eclipse.swt.events.ModifyListener;\r
+import org.eclipse.swt.events.SelectionAdapter;\r
+import org.eclipse.swt.events.SelectionEvent;\r
+import org.eclipse.swt.layout.RowLayout;\r
+import org.eclipse.swt.widgets.Button;\r
+import org.eclipse.swt.widgets.Composite;\r
+import org.eclipse.swt.widgets.Label;\r
+import org.eclipse.swt.widgets.Spinner;\r
+import org.eclipse.ui.ISelectionListener;\r
+import org.eclipse.ui.IWorkbenchPart;\r
+import org.eclipse.ui.part.ViewPart;\r
+import org.simantics.db.Resource;\r
+import org.simantics.db.procedure.Listener;\r
+import org.simantics.graphviz.Graph;\r
+import org.simantics.graphviz.ui.GraphvizComponent;\r
+import org.simantics.ui.SimanticsUI;\r
+\r
+public class DependencyView extends ViewPart {\r
+\r
+ private GraphvizComponent component;\r
+ private boolean disposed, isInverted = false;\r
+ private Button bButton, fButton;\r
+ private Resource currentSelection;\r
+ private int levels = 3;\r
+ private ISelectionListener selectionListener;\r
+\r
+ static int MAXLEVELS = 4;\r
+ static int MINLEVELS = 1;\r
+\r
+ @Override\r
+ public void createPartControl(Composite parent) {\r
+ disposed = false;\r
+ GridLayoutFactory.fillDefaults().margins(3, 3).applyTo(parent);\r
+\r
+ component = new GraphvizComponent(parent, SWT.BORDER);\r
+ GridDataFactory.fillDefaults().grab(true, true).applyTo(component);\r
+\r
+ Composite composite = new Composite(parent, SWT.NULL);\r
+ RowLayout layout = new RowLayout();\r
+ layout.center = true;\r
+ composite.setLayout(layout);\r
+\r
+ Label label = new Label(composite, SWT.NULL);\r
+ label.setText("Direction: ");\r
+\r
+ bButton = new Button(composite, SWT.RADIO);\r
+ bButton.setText("Backward");\r
+ bButton.setSelection(true);\r
+ bButton.addSelectionListener(new SelectionAdapter() {\r
+ public void widgetSelected(SelectionEvent event) {\r
+ if(bButton.getSelection())\r
+ isInverted = false;\r
+ else \r
+ isInverted = true;\r
+ if(currentSelection != null) {\r
+ readGraph(currentSelection);\r
+ }\r
+ }\r
+ });\r
+\r
+ fButton = new Button(composite, SWT.RADIO);\r
+ fButton.setText("Forward");\r
+\r
+ label = new Label(composite, SWT.NULL);\r
+ label.setText("Steps: ");\r
+\r
+ Spinner spinner = new Spinner(composite, SWT.BORDER);\r
+ spinner.setMaximum(MAXLEVELS);\r
+ spinner.setMinimum(MINLEVELS);\r
+ spinner.setTextLimit(1);\r
+ spinner.setSelection(levels);\r
+\r
+ spinner.addModifyListener(new ModifyListener() {\r
+\r
+ @Override\r
+ public void modifyText(ModifyEvent e) {\r
+ Spinner s = (Spinner)e.widget;\r
+ int lvls = Integer.parseInt(s.getText());\r
+ if(lvls > MAXLEVELS)\r
+ levels = MAXLEVELS;\r
+ else if (lvls < MINLEVELS)\r
+ levels = MINLEVELS;\r
+ levels = lvls;\r
+ if(currentSelection != null) {\r
+ readGraph(currentSelection);\r
+ }\r
+ \r
+ }\r
+ });\r
+\r
+ drawSelection(getSite().getWorkbenchWindow().getSelectionService().getSelection());\r
+\r
+ selectionListener = new ISelectionListener() {\r
+\r
+ @Override\r
+ public void selectionChanged(IWorkbenchPart part, ISelection selection) {\r
+ drawSelection(selection);\r
+ }\r
+ }; \r
+ getSite().getWorkbenchWindow().getSelectionService().addPostSelectionListener(selectionListener);\r
+ }\r
+\r
+ private void drawSelection(ISelection selection) {\r
+ if(selection == null || selection.isEmpty())\r
+ return;\r
+ if(selection instanceof IStructuredSelection) { \r
+ Object[] els = ((IStructuredSelection) selection).toArray();\r
+ if(els.length == 1) {\r
+ if(els[0] instanceof Resource && !els[0].equals(currentSelection)) {\r
+ currentSelection = (Resource)els[0];\r
+ readGraph(currentSelection);\r
+ }\r
+ }\r
+ } \r
+ }\r
+\r
+ private void readGraph(Resource resource) {\r
+ SimanticsUI.getSession().asyncRequest(new CreateDependencyGraph(\r
+ resource, levels, isInverted),\r
+ new Listener<Graph>() {\r
+\r
+ @Override\r
+ public void exception(Throwable e) {\r
+ e.printStackTrace();\r
+ }\r
+\r
+ @Override\r
+ public void execute(final Graph graph) {\r
+ Job job = new Job("Layout composite graph") {\r
+\r
+ @Override\r
+ protected IStatus run(IProgressMonitor monitor) {\r
+ if(!isDisposed()) {\r
+ component.setGraph(graph, "dot");\r
+ component.fit(); \r
+ }\r
+ return Status.OK_STATUS;\r
+ }\r
+ };\r
+ job.schedule();\r
+ }\r
+\r
+ @Override\r
+ public boolean isDisposed() {\r
+ return disposed;\r
+ }\r
+ });\r
+ }\r
+\r
+\r
+ @Override\r
+ public void setFocus() {\r
+ if (component != null && !component.isDisposed())\r
+ component.requestFocus();\r
+ }\r
+\r
+ \r
+ @Override\r
+ public void dispose() {\r
+ super.dispose();\r
+ getSite().getWorkbenchWindow().getSelectionService().removePostSelectionListener(selectionListener);\r
+ disposed = true;\r
+ }\r
+\r
+}\r