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