/* * (C) Copyright 2002 Arnaud Bailly (arnaud.oqube@gmail.com), * Yves Roos (yroos@lifl.fr) and others. * * Licensed under the Apache License, Version 2.0 (the License); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an AS IS BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package rationals.graph; import java.awt.Color; import java.awt.Font; import java.awt.event.MouseListener; import java.awt.event.MouseMotionListener; import java.awt.geom.Arc2D; import java.awt.geom.GeneralPath; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStream; import java.util.HashMap; import java.util.Iterator; import java.util.Map; import java.util.Set; import rationals.Automaton; import rationals.Transition; import salvo.jesus.graph.Edge; import salvo.jesus.graph.visual.Arrowhead; import salvo.jesus.graph.visual.VisualEdge; import salvo.jesus.graph.visual.VisualGraph; import salvo.jesus.graph.visual.VisualGraphComponent; import salvo.jesus.graph.visual.VisualGraphComponentFactory; import salvo.jesus.graph.visual.VisualVertex; import salvo.jesus.graph.visual.drawing.Painter; import salvo.jesus.graph.visual.drawing.VisualDirectedEdgePainterImpl; import salvo.jesus.graph.visual.drawing.VisualEdgePainter; import salvo.jesus.graph.visual.drawing.VisualVertexPainterFactory; import salvo.jesus.graph.visual.layout.DigraphLayeredLayout; import salvo.jesus.graph.visual.layout.GraphLayoutManager; import salvo.jesus.graph.visual.print.VisualGraphImageOutput; import salvo.jesus.util.VisualGraphComponentPath; /** * A class to produce VisualGraphComponent from Automaton states and * Transitions. * * This class creates VisualVertex and VisualEdges according to the following * rules : * <ul> * <li>a state is rendered as a round Node ;</li> * <li>an initial State is rendered as an inverted round node ;</li> * <li>a terminal State has an outward arrow</li> * </ul> * The background color, foreground color and font used to render edges and * vertices can be specified using the appropriate methods * * @author Arnaiud Bailly * @version 31082002 * @see salvo.jesus.graph.visual.VisualGraphComponentFactory */ public class AutomatonVisualFactory extends VisualVertexPainterFactory implements VisualGraphComponentFactory { // random seed private java.util.Random rand = new java.util.Random(new java.util.Date() .getTime()); // color to use for background private Color vertexBackground = Color.white; // color to use for foreground private Color vertexForeground = Color.black; // font to use private Font vertexFont = new Font("Helvetica", Font.BOLD, 9); // color for edges private Color edgeColor = Color.black; // font for edges private Font edgeFont = new Font("Helvetica", Font.PLAIN, 10); // fontcolor for edges private Color edgeFontColor = Color.black; private MouseListener mouseListener; private MouseMotionListener mouseMotionListener; private StatePainter1 statePainter = new StatePainter1(); private VisualEdgePainter edgePainter = new VisualDirectedEdgePainterImpl(); private Map /* < Transition, VisualEdge > */vemap = new HashMap(); // //////////////////////////////////////////////////////// // PUBLIC METHODS // //////////////////////////////////////////////////////// /** * Constructor AutomatonVisualFactory with a MouseListener * * @param popupDisplayer */ public AutomatonVisualFactory(MouseListener ml, MouseMotionListener mml) { this.mouseListener = ml; this.mouseMotionListener = mml; } public AutomatonVisualFactory() { } public Color getVertexBackground() { return vertexBackground; } public void setVertexBackground(Color color) { // System.out.println("[AutomatonVisualFactory] color : "+color); this.vertexBackground = color; } public Color getVertexForeground() { return vertexForeground; } public void setVertexForeground(Color color) { this.vertexForeground = color; } public Font getVertexFont() { return vertexFont; } public void setVertexFont(Font font) { this.vertexFont = font; } public Color getEdgeColor() { return edgeColor; } public void setEdgeColor(Color color) { edgeColor = color; } public Color getEdgeFontColor() { return edgeFontColor; } public void setEdgeFontColor(Color color) { this.edgeFontColor = color; } public Font getEdgeFont() { return edgeFont; } public void setEdgeFont(Font font) { edgeFont = font; } /** * The given Vertex must have been created containing an instance of State * * @see salvo.jesus.graph.visual.VisualGraphComponentFactory#createVisualVertex */ public VisualVertex createVisualVertex(Object vertex, VisualGraph graph) { // create VisualVertex VisualVertex vv = new VisualVertex(vertex, graph); vv.setPainter(statePainter); vv.setShape(new VisualGraphComponentPath(new GeneralPath(new Arc2D.Double( 0, 0, 30, 30, 0, 360, Arc2D.CHORD)))); // vv.setGeneralPath(new GeneralPath(new Arc2D.Double(0, 0, 20, 20, 0, // 360, // Arc2D.CHORD))); vv.setFillcolor(vertexForeground); vv.setFontcolor(vertexBackground); vv.setOutlinecolor(vertexForeground); vv.setFont(vertexFont); vv.setLocation(rand.nextInt(500), rand.nextInt(400)); if (mouseListener != null) vv.addMouseListener(mouseListener); if (mouseMotionListener != null) vv.addMouseMotionListener(mouseMotionListener); return vv; } /** * @see salvo.jesus.graph.visual.VisualGraphComponentFactory#createVisualEdge */ public VisualEdge createVisualEdge(Edge edge, VisualGraph graph) { /* merge edges with same source and sink */ Automaton a = ((AutomatonGraphAdapter) graph.getGraph()).getAutomaton(); VisualEdge ve = (VisualEdge) vemap.get(edge); if (ve != null) return ve; else ve = new VisualEdge(edge, graph); vemap.put(edge, ve); Transition tr = (Transition)edge.getData(); StringBuffer lbl = new StringBuffer(tr.label() != null ? tr.label() .toString() : ""); Set s = a.delta(tr.start()); for (Iterator i = s.iterator(); i.hasNext();) { Transition t = (Transition) i.next(); if (t != tr && t.end().equals(tr.end())) { lbl.append('+').append(t.label()); vemap.put(t, ve); } } ve.setFontcolor(edgeFontColor); ve.setOutlinecolor(edgeColor); ve.setFillcolor(edgeColor); ve.setFont(edgeFont); ve.setText(lbl.toString()); ve.setPainter(edgePainter); return ve; } /** * @see salvo.jesus.graph.visual.VisualGraphComponentFactory#createArrowhead */ public Arrowhead createArrowhead() { return new AutomatonArrowhead(); } /* * (non-Javadoc) * * @see salvo.jesus.graph.visual.drawing.PainterFactory#getPainter(salvo.jesus.graph.visual.VisualGraphComponent) */ public Painter getPainter(VisualGraphComponent component) { if (component instanceof VisualVertex) return statePainter; else if (component instanceof VisualEdge) return edgePainter; return null; } /** * @throws FileNotFoundException * @throws IOException */ public static void epsOutput(Automaton a, String fname, GraphLayoutManager lay) throws FileNotFoundException, IOException { FileOutputStream fos = new FileOutputStream(fname); epsOutput(a, fos, lay); fos.flush(); fos.close(); } /** * @param a * @param output * @param object * @throws IOException */ public static void epsOutput(Automaton a, OutputStream output, GraphLayoutManager lay) throws IOException { imageOutput(a, output, lay, "eps"); } public static void imageOutput(Automaton a, OutputStream output, GraphLayoutManager lay, String format) throws IOException { VisualGraph vg = new VisualGraph(); AutomatonVisualFactory fact = new AutomatonVisualFactory(); vg.setVisualGraphComponentFactory(fact); vg.setGraph(new AutomatonGraphAdapter(a)); if (lay == null) { lay = new DigraphLayeredLayout(vg); ((DigraphLayeredLayout) lay).setDirected(true); ((DigraphLayeredLayout) lay).setRoots(a.initials()); } vg.setGraphLayoutManager(lay); lay.setVisualGraph(vg); lay.setRepaint(false); lay.layout(); vg.repaint(); VisualGraphImageOutput out = new VisualGraphImageOutput(); out.setFormat(format); out.output(vg, output); } /** * @return Returns the edgePainter. */ public VisualEdgePainter getEdgePainter() { return edgePainter; } /** * @param edgePainter * The edgePainter to set. */ public void setEdgePainter(VisualEdgePainter edgePainter) { this.edgePainter = edgePainter; } /** * @return Returns the statePainter. */ public StatePainter1 getStatePainter() { return statePainter; } /** * @param statePainter * The statePainter to set. */ public void setStatePainter(StatePainter1 statePainter) { this.statePainter = statePainter; } }