1 /*******************************************************************************
2 * Copyright (c) 2007, 2010 Association for Decentralized Information Management
4 * All rights reserved. This program and the accompanying materials
5 * are made available under the terms of the Eclipse Public License v1.0
6 * which accompanies this distribution, and is available at
7 * http://www.eclipse.org/legal/epl-v10.html
10 * VTT Technical Research Centre of Finland - initial API and implementation
11 *******************************************************************************/
12 package org.simantics.graphviz.drawable;
14 import java.awt.Graphics2D;
15 import java.awt.Shape;
16 import java.awt.geom.Point2D;
17 import java.awt.geom.Rectangle2D;
18 import java.io.IOException;
19 import java.util.ArrayList;
20 import java.util.Collection;
21 import java.util.HashMap;
23 import java.util.concurrent.ExecutionException;
25 import org.simantics.graphviz.Edge;
26 import org.simantics.graphviz.Graph;
27 import org.simantics.graphviz.Graphs;
28 import org.simantics.graphviz.IGraphPart;
29 import org.simantics.graphviz.Identifiable;
30 import org.simantics.graphviz.continuation.Computation;
31 import org.simantics.graphviz.continuation.Continuation;
32 import org.simantics.graphviz.internal.parser.ParseException;
33 import org.simantics.graphviz.internal.xdot.DrawCommand;
34 import org.simantics.graphviz.internal.xdot.DrawCommandParser;
35 import org.simantics.graphviz.internal.xdot.ShapeCommand;
38 * A drawable that draws a given graph.
39 * Supports picking elements.
41 * TODO: optimize, uses hashmaps in places where those are not useful.
44 * @author Hannu Niemist�
45 * @author Marko Luukkainen
47 public class GraphDrawable2 implements Drawable {
49 private static String DEFAULT_ALGORITHM = "dot";
51 Collection<DrawCommand> commands;
52 Map<IGraphPart,Collection<DrawCommand>> partCommands;
53 Map<IGraphPart,Rectangle2D> partBounds;
57 public GraphDrawable2(Graph graph, String algorithm) {
59 setGraph(graph, algorithm).get();
60 } catch (Exception e) {
65 public GraphDrawable2(Graph graph) {
69 public GraphDrawable2() {
70 commands = new ArrayList<DrawCommand>();
71 partCommands = new HashMap<IGraphPart, Collection<DrawCommand>>();
72 partBounds = new HashMap<IGraphPart, Rectangle2D>();
73 bounds = new Rectangle2D.Double(0, 0, 100, 100);
77 * Sets a new graph to be drawn. This operation may take a while. It can
78 * be called from any thread.
81 public void setGraph(Graph graph) {
83 setGraph(graph, DEFAULT_ALGORITHM).get();
84 } catch(Exception e) {
92 * Sets a new graph to be drawn. This operation may take a while. It can
93 * be called from any thread.
96 public synchronized Computation<Graph> setGraph(final Graph graph, String algorithm) {
97 Computation<Graph> computation = Graphs.createXDot(graph, algorithm);
98 computation.addContinuation(new Continuation<Graph>() {
100 public void succeeded(Graph xgraph) {
101 commands = new ArrayList<DrawCommand>();
102 partCommands = new HashMap<IGraphPart, Collection<DrawCommand>>();
103 partBounds = new HashMap<IGraphPart, Rectangle2D>();
104 DrawCommandParser.parse(xgraph,commands,partCommands);
105 readBoundingBox(xgraph);
106 updatePartBoundingBoxes(graph, xgraph);
110 public void failed(Exception exception) {
116 private void readBoundingBox(Graph graph) {
117 String[] parts = graph.get("bb").split(",");
118 double minX = Double.parseDouble(parts[0]);
119 double maxY = -Double.parseDouble(parts[1]);
120 double maxX = Double.parseDouble(parts[2]);
121 double minY = -Double.parseDouble(parts[3]);
122 bounds = new Rectangle2D.Double(minX, minY, maxX-minX, maxY-minY);
125 private void updatePartBoundingBoxes(Graph graph, Graph xgraph) {
126 // we have to map input Nodes to XGraph nodes
128 Map<IGraphPart,IGraphPart> partMap = new HashMap<IGraphPart, IGraphPart>();
130 for (IGraphPart xPart : xgraph.getParts()) {
131 if (xPart instanceof Identifiable) {
132 String xID = ((Identifiable)xPart).getId();
133 for (IGraphPart gPart : graph.getParts()) {
134 if (gPart instanceof Identifiable) {
135 String gID = ((Identifiable)gPart).getId();
136 if (xID.equals(gID)) {
137 partMap.put(xPart, gPart);
141 } else if (xPart instanceof Edge) {
142 String xHeadId = ((Edge)xPart).getHead().getId();
143 String xTailId = ((Edge)xPart).getTail().getId();
144 for (IGraphPart gPart : graph.getParts()) {
145 if (gPart instanceof Edge) {
146 String gHeadId = ((Edge)gPart).getHead().getId();
147 String gTailId = ((Edge)gPart).getTail().getId();
149 if (xHeadId.equals(gHeadId) && xTailId.equals(gTailId)) {
150 partMap.put(xPart, gPart);
159 for (IGraphPart part : partCommands.keySet()) {
160 Collection<DrawCommand> pCommands = partCommands.get(part);
161 Rectangle2D r = null;
162 for (DrawCommand c : pCommands) {
163 if (c instanceof ShapeCommand) {
164 Shape s = ((ShapeCommand)c).getShape();
168 r.add(s.getBounds2D());
172 partBounds.put(partMap.get(part), r);
178 public synchronized Rectangle2D getBounds() {
183 public synchronized Rectangle2D getBounds(IGraphPart part) {
184 return partBounds.get(part);
187 public synchronized Collection<IGraphPart> pick(Point2D point) {
188 Collection<IGraphPart> picked = new ArrayList<IGraphPart>();
189 for (IGraphPart part : partBounds.keySet()) {
190 Rectangle2D r = partBounds.get(part);
191 if (r.contains(point))
198 public synchronized void draw(Graphics2D g, Rectangle2D area) {
199 for(DrawCommand command : commands)
202 // for (Rectangle2D r : partBounds.values()) {
203 // g.drawRect((int)r.getMinX(), (int)r.getMinY(), (int)r.getWidth(), (int)r.getHeight());