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