/*
* (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.converters;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics2D;
import java.awt.GridLayout;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JPopupMenu;
import rationals.Automaton;
import rationals.graph.AutomatonVisualFactory;
import rationals.graph.AutomatonGraphAdapter;
import salvo.jesus.graph.Graph;
import salvo.jesus.graph.visual.GraphScrollPane;
import salvo.jesus.graph.visual.VisualGraph;
import salvo.jesus.graph.visual.VisualGraphComponent;
import salvo.jesus.graph.visual.drawing.VisualDirectedEdgePainterImpl;
import salvo.jesus.graph.visual.drawing.VisualEdgePainter;
import salvo.jesus.graph.visual.drawing.VisualVertexPainter;
import salvo.jesus.graph.visual.drawing.VisualVertexPainterImpl;
import salvo.jesus.graph.visual.layout.DigraphLayeredLayout;
import salvo.jesus.graph.visual.layout.GraphLayoutManager;
import salvo.jesus.graph.visual.print.VisualGraphImageOutput;
import salvo.jesus.graph.visual.print.VisualGraphPrinter;
import fr.lifl.utils.ExtensionFileFilter;
import fr.lifl.utils.FileDialog;
/**
* Display an Automaton in a window using JM Salvo openjgraph
*
*
* @author Arnaud Bailly
* @version 30082002
*/
public class SwingDisplayer extends JFrame implements Displayer {
/////////////////////////////////////////////////////////////
// PRIVATE MEMBERS
////////////////////////////////////////////////////////////
// the graph to displau
private Graph graph;
// the automaton
private Automaton automaton;
// the visual graph
private VisualGraph vgraph;
private GraphLayoutManager layout;
private GraphScrollPane gsp;
private AutomatonContextMenu contextMenu;
class AltDirectedEdgePainter extends VisualDirectedEdgePainterImpl {
private transient BasicStroke origStroke = null;
private transient BasicStroke fatStroke;
public void paint(VisualGraphComponent component, Graphics2D g2d) {
// Change the color to red and do not set the color back to its original
// so that when the user sees the visual properties of the edge, it is
// red.
// Set the stroke for edges in thesubgraph to be double the stroke
// of the default stroke.
if (this.origStroke == null) {
this.origStroke = new BasicStroke();
this.fatStroke = new BasicStroke(origStroke.getLineWidth() * 2);
}
g2d.setStroke(this.fatStroke);
super.paint(component, g2d);
// Restore the stroke to the default
g2d.setStroke(this.origStroke);
}
}
class AltVertexPainter extends VisualVertexPainterImpl {
private Color color;
AltVertexPainter(Color color) {
this.color = color;
}
public void paintFill(VisualGraphComponent component,
java.awt.Graphics2D g2d) {
component.setFillcolor(color);
super.paintFill(component, g2d);
}
}
class EnumeratingPainters {
private int curColor = 0x00ff0000;
private Color nextColor() {
curColor = (curColor + 0x00003201) & 0x00ffffff;
int r = (curColor >> 16) & 0xff;
int g = (curColor >> 8) & 0xff;
int b = curColor & 0xff;
System.err.println("Using color " + r + "," + g + "," + b);
return new Color(r, g, b);
}
VisualVertexPainter getVertexPainter() {
return new AltVertexPainter(nextColor());
}
VisualEdgePainter getEdgePainter() {
return new AltDirectedEdgePainter();
}
}
/*
* A contextual menu for automaton @author bailly
*
* @version $Id: SwingDisplayer.java 2 2006-08-24 14:41:48Z oqube $
*/
class AutomatonContextMenu extends JPopupMenu {
public AutomatonContextMenu() {
JMenuItem item = new JMenuItem("Print ...");
item.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
new VisualGraphPrinter(vgraph).showPrint(getX(), getY());
/*
* if (autos == null) return; for (int i = 0; i <
* autos.length; i++) print(autos[i]);
*/
}
});
add(item);
item = new JMenuItem("Save Image ...");
item.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
File file;
FileDialog fd = new FileDialog();
ExtensionFileFilter filter = new ExtensionFileFilter();
filter.addExtension("eps");
filter.addExtension("jpeg");
filter.addExtension("png");
filter.addExtension("gif");
filter.setDescription("FIDL Automaton image");
file = fd.userSelect(filter, new File("."));
if (file == null)
return;
/* set format */
String format = "eps";
if (file.getName().lastIndexOf('.') != -1)
format = file.getName().substring(
file.getName().lastIndexOf('.') + 1);
/* write file in selected format */
VisualGraphImageOutput out = new VisualGraphImageOutput();
out.setFormat(format);
try {
out.output(vgraph, new FileOutputStream(file));
/*
* if (autos == null) return; for (int i = 0; i <
* autos.length; i++) print(autos[i]);
*/
} catch (FileNotFoundException e1) {
JOptionPane.showMessageDialog(SwingDisplayer.this,
"Unable to write output file " + file + ": \n"
+ e1.getMessage());
e1.printStackTrace();
} catch (IOException e1) {
JOptionPane.showMessageDialog(SwingDisplayer.this,
"Unable to write output file " + file + ": \n"
+ e1.getMessage());
e1.printStackTrace();
}
}
});
add(item);
item = new JMenu("Zoom");
JMenuItem item2 = new JMenuItem("in");
item2.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
// zoomIn();
if (layout != null) {
layout.setRepaint(true);
}
vgraph.repaint();
}
});
item.add(item2);
item2 = new JMenuItem("out");
item2.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
//zoomOut();
if (layout != null) {
layout.setRepaint(true);
}
vgraph.repaint();
}
});
item.add(item2);
add(item);
}
// public void zoomIn() {
// if (gsp.() < maxZoom) {
// zoomFactor = zoomFactor * 2;
// gsp.setsetZoomFactor(((double) zoomFactor) / (double) 1024);
// }
// }
//
// public void zoomOut() {
// if (zoomFactor > minZoom) {
// zoomFactor = zoomFactor / 2;
// setZoomFactor(((double) zoomFactor) / (double) 1024);
// }
// }
}
/////////////////////////////////////////////////////////////
// CONSTRUCTORS
////////////////////////////////////////////////////////////
public SwingDisplayer() {
Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
Dimension frameSize = new Dimension(screenSize.width / 2,
screenSize.height / 2);
this.setSize(frameSize);
this.setLocation((int) (screenSize.getWidth() - frameSize.getWidth()) / 2,
(int) (screenSize.getHeight() - frameSize.getHeight()) / 2);
// Terminate the application when the window closes
this.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
setVisible(true);
}
/**
* Defines the Automaton to display with this displayer
*
* @param an
* Automaton object
*/
public void setAutomaton(Automaton a) throws ConverterException {
this.automaton = a;
try {
this.graph = new AutomatonGraphAdapter(a);
display();
} catch (Exception ex) {
throw new ConverterException(ex.getMessage());
}
}
/**
* Defines the algorithm to use for layout This is a no-op in this class.
*
* @param an
* Algorithm object
*/
public void setAlgorithm(rationals.converters.algorithms.LayoutAlgorithm algo) {
}
/**
* Asks the displayer to display the automaton
*/
public void display() throws ConverterException {
this.getContentPane().removeAll();
// command pane
JPanel cmdpanel = new JPanel();
JButton sccbutton = new JButton("SCC");
contextMenu = new AutomatonContextMenu();
// Get a VisualGraph
gsp = new GraphScrollPane();
vgraph = new VisualGraph();
vgraph.setVisualGraphComponentFactory(new AutomatonVisualFactory());
vgraph.setGraph(graph);
gsp.setVisualGraph(vgraph);
gsp.setAntialias(true);
layout = new DigraphLayeredLayout(vgraph);
((DigraphLayeredLayout)layout).setRoots(automaton.initials());
layout.setRepaint(true);
// Initialise a layout manager, though not really part of this eample
gsp.setGraphLayoutManager(layout);
gsp.addMouseListener(new MouseAdapter() {
public void mouseReleased(MouseEvent e) {
if(e.getButton() == MouseEvent.BUTTON3)
contextMenu.show(gsp,e.getX(),e.getY());
}
});
// Make it all visible
this.getContentPane().setLayout(new GridLayout(1, 2));
this.getContentPane().add(gsp);
this.validate();
layout.layout();
}
}