--- /dev/null
+/*******************************************************************************\r
+ * Copyright (c) 2007, 2010 Association for Decentralized Information Management\r
+ * in Industry THTH ry.\r
+ * All rights reserved. This program and the accompanying materials\r
+ * are made available under the terms of the Eclipse Public License v1.0\r
+ * which accompanies this distribution, and is available at\r
+ * http://www.eclipse.org/legal/epl-v10.html\r
+ *\r
+ * Contributors:\r
+ * VTT Technical Research Centre of Finland - initial API and implementation\r
+ *******************************************************************************/\r
+package org.simantics.graphviz.drawable;\r
+\r
+import java.awt.Graphics2D;\r
+import java.awt.Shape;\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.HashMap;\r
+import java.util.Map;\r
+import java.util.concurrent.ExecutionException;\r
+\r
+import org.simantics.graphviz.Edge;\r
+import org.simantics.graphviz.Graph;\r
+import org.simantics.graphviz.Graphs;\r
+import org.simantics.graphviz.IGraphPart;\r
+import org.simantics.graphviz.Identifiable;\r
+import org.simantics.graphviz.continuation.Computation;\r
+import org.simantics.graphviz.continuation.Continuation;\r
+import org.simantics.graphviz.internal.parser.ParseException;\r
+import org.simantics.graphviz.internal.xdot.DrawCommand;\r
+import org.simantics.graphviz.internal.xdot.DrawCommandParser;\r
+import org.simantics.graphviz.internal.xdot.ShapeCommand;\r
+\r
+/**\r
+ * A drawable that draws a given graph.\r
+ * Supports picking elements.\r
+ * \r
+ * TODO: optimize, uses hashmaps in places where those are not useful. \r
+ * \r
+ * \r
+ * @author Hannu Niemist�\r
+ * @author Marko Luukkainen\r
+ */\r
+public class GraphDrawable2 implements Drawable {\r
+\r
+ private static String DEFAULT_ALGORITHM = "dot";\r
+ \r
+ Collection<DrawCommand> commands;\r
+ Map<IGraphPart,Collection<DrawCommand>> partCommands;\r
+ Map<IGraphPart,Rectangle2D> partBounds;\r
+ \r
+ Rectangle2D bounds;\r
+ \r
+ public GraphDrawable2(Graph graph, String algorithm) {\r
+ try {\r
+ setGraph(graph, algorithm).get();\r
+ } catch (Exception e) {\r
+ e.printStackTrace();\r
+ }\r
+ }\r
+ \r
+ public GraphDrawable2(Graph graph) {\r
+ setGraph(graph);\r
+ }\r
+ \r
+ public GraphDrawable2() {\r
+ commands = new ArrayList<DrawCommand>();\r
+ partCommands = new HashMap<IGraphPart, Collection<DrawCommand>>();\r
+ partBounds = new HashMap<IGraphPart, Rectangle2D>();\r
+ bounds = new Rectangle2D.Double(0, 0, 100, 100);\r
+ }\r
+ \r
+ /**\r
+ * Sets a new graph to be drawn. This operation may take a while. It can\r
+ * be called from any thread.\r
+ * @param graph\r
+ */\r
+ public void setGraph(Graph graph) {\r
+ try {\r
+ setGraph(graph, DEFAULT_ALGORITHM).get();\r
+ } catch(Exception e) {\r
+ e.printStackTrace();\r
+ }\r
+ }\r
+ \r
+ \r
+ \r
+ /**\r
+ * Sets a new graph to be drawn. This operation may take a while. It can\r
+ * be called from any thread.\r
+ * @param graph\r
+ */\r
+ public synchronized Computation<Graph> setGraph(final Graph graph, String algorithm) {\r
+ Computation<Graph> computation = Graphs.createXDot(graph, algorithm);\r
+ computation.addContinuation(new Continuation<Graph>() {\r
+ @Override\r
+ public void succeeded(Graph xgraph) {\r
+ commands = new ArrayList<DrawCommand>();\r
+ partCommands = new HashMap<IGraphPart, Collection<DrawCommand>>();\r
+ partBounds = new HashMap<IGraphPart, Rectangle2D>();\r
+ DrawCommandParser.parse(xgraph,commands,partCommands);\r
+ readBoundingBox(xgraph);\r
+ updatePartBoundingBoxes(graph, xgraph);\r
+ }\r
+\r
+ @Override\r
+ public void failed(Exception exception) {\r
+ }\r
+ });\r
+ return computation;\r
+ }\r
+ \r
+ private void readBoundingBox(Graph graph) {\r
+ String[] parts = graph.get("bb").split(",");\r
+ double minX = Double.parseDouble(parts[0]);\r
+ double maxY = -Double.parseDouble(parts[1]);\r
+ double maxX = Double.parseDouble(parts[2]);\r
+ double minY = -Double.parseDouble(parts[3]);\r
+ bounds = new Rectangle2D.Double(minX, minY, maxX-minX, maxY-minY);\r
+ }\r
+ \r
+ private void updatePartBoundingBoxes(Graph graph, Graph xgraph) {\r
+ // we have to map input Nodes to XGraph nodes\r
+ \r
+ Map<IGraphPart,IGraphPart> partMap = new HashMap<IGraphPart, IGraphPart>();\r
+ \r
+ for (IGraphPart xPart : xgraph.getParts()) {\r
+ if (xPart instanceof Identifiable) {\r
+ String xID = ((Identifiable)xPart).getId();\r
+ for (IGraphPart gPart : graph.getParts()) {\r
+ if (gPart instanceof Identifiable) {\r
+ String gID = ((Identifiable)gPart).getId();\r
+ if (xID.equals(gID)) {\r
+ partMap.put(xPart, gPart);\r
+ }\r
+ }\r
+ }\r
+ } else if (xPart instanceof Edge) {\r
+ String xHeadId = ((Edge)xPart).getHead().getId();\r
+ String xTailId = ((Edge)xPart).getTail().getId();\r
+ for (IGraphPart gPart : graph.getParts()) {\r
+ if (gPart instanceof Edge) {\r
+ String gHeadId = ((Edge)gPart).getHead().getId();\r
+ String gTailId = ((Edge)gPart).getTail().getId();\r
+ \r
+ if (xHeadId.equals(gHeadId) && xTailId.equals(gTailId)) {\r
+ partMap.put(xPart, gPart);\r
+ }\r
+ }\r
+ }\r
+ }\r
+ }\r
+ \r
+ \r
+ \r
+ for (IGraphPart part : partCommands.keySet()) {\r
+ Collection<DrawCommand> pCommands = partCommands.get(part);\r
+ Rectangle2D r = null;\r
+ for (DrawCommand c : pCommands) {\r
+ if (c instanceof ShapeCommand) {\r
+ Shape s = ((ShapeCommand)c).getShape();\r
+ if (r == null)\r
+ r = s.getBounds2D();\r
+ else\r
+ r.add(s.getBounds2D());\r
+ }\r
+ }\r
+ if (r != null) {\r
+ partBounds.put(partMap.get(part), r);\r
+ }\r
+ }\r
+ }\r
+ \r
+ @Override\r
+ public synchronized Rectangle2D getBounds() {\r
+ return bounds;\r
+ }\r
+ \r
+ \r
+ public synchronized Rectangle2D getBounds(IGraphPart part) {\r
+ return partBounds.get(part);\r
+ }\r
+ \r
+ public synchronized Collection<IGraphPart> pick(Point2D point) {\r
+ Collection<IGraphPart> picked = new ArrayList<IGraphPart>();\r
+ for (IGraphPart part : partBounds.keySet()) {\r
+ Rectangle2D r = partBounds.get(part);\r
+ if (r.contains(point))\r
+ picked.add(part);\r
+ }\r
+ return picked;\r
+ }\r
+ \r
+ @Override\r
+ public synchronized void draw(Graphics2D g, Rectangle2D area) {\r
+ for(DrawCommand command : commands)\r
+ command.draw(g);\r
+ \r
+// for (Rectangle2D r : partBounds.values()) {\r
+// g.drawRect((int)r.getMinX(), (int)r.getMinY(), (int)r.getWidth(), (int)r.getHeight());\r
+// }\r
+ }\r
+ \r
+}\r