package jungnetwork;
/* This is a simple display capable of working with MASON and
* displaying JUNG graphs. It is composed of merged and
* lobotomized verions of JUNG's ZoomDemo and MASON's Display2D
* classes. Please refer to original code for details about uncommented code. */
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Container;
import java.awt.FileDialog;
import java.awt.Graphics2D;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.OutputStream;
import javax.swing.BorderFactory;
import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import sim.display.Display2D;
import sim.display.GUIState;
import sim.display.SimApplet;
import sim.engine.SimState;
import sim.engine.Steppable;
import sim.engine.Stoppable;
import sim.util.Utilities;
import sim.util.media.PngEncoder;
import edu.uci.ics.jung.visualization.BirdsEyeVisualizationViewer;
import edu.uci.ics.jung.visualization.Layout;
import edu.uci.ics.jung.visualization.PluggableRenderer;
import edu.uci.ics.jung.visualization.VisualizationViewer;
import edu.uci.ics.jung.visualization.contrib.KKLayout;
import edu.uci.ics.jung.visualization.control.ScalingControl;
import edu.uci.ics.jung.visualization.control.ViewScalingControl;
public class JungDisplay extends JComponent implements Steppable {
public static final ImageIcon CAMERA_ICON = iconFor("Camera.png");
public static final ImageIcon CAMERA_ICON_P = iconFor("CameraPressed.png");
private static final long serialVersionUID = 1L;
public Layout layout;
public VisualizationViewer viewer;
public JFrame frame;
/* Variable which will keep track of time of next update */
public double nextUpdate = 0;
GUIState simulation;
JDialog dialog;
Stoppable stopper;
Box header;
/* The button which snaps a screenshot */
JButton snapshotButton;
/* Set to true if we're running on a Mac */
public static final boolean isMacOSX = isMacOSX();
/* Set to true if we're running on Windows */
public static final boolean isWindows = isWindows();
static ImageIcon iconFor(String name) {
return new ImageIcon(Display2D.class.getResource(name));
}
public void step(SimState state) {
double currentTime = simulation.state.schedule.time();
/*
* Check if it is apropriate time to update, draw only if the display
* can be seen.
*/
if ((currentTime > nextUpdate)) {
if (frame.isShowing()) {
layout.restart();
while (!layout.incrementsAreDone()) {
layout.advancePositions();
}
viewer.repaint();
}
// Compute nextUpdate time.
nextUpdate = currentTime + ((PreferentialAttachment) simulation.state).updateInterval;
}
}
public JungDisplay(GUIState simulation) {
this.simulation = simulation;
this.frame = new JFrame();
/*
* Layout is the JUNG's procedure which plans how the graph will be
* drawn. Check out other layouts, by default we will use Kamada-Kawai.
*/
layout = new KKLayout(((GraphSimState) simulation.state).graph);
/*
* Viewer is AWT Component subclass, doing the rendering, which can be
* directly added to a JPanel.
*/
viewer = new VisualizationViewer(layout, new PluggableRenderer());
Container content = frame.getContentPane();
JPanel panel = new JPanel(new BorderLayout());
panel.add(viewer);
content.add(panel);
/*
* Additional BirdsEyeView for zooming / panning the graph will be
* created. See JUNG's ZoomDemo for explanations.
*/
dialog = new JDialog(frame);
content = dialog.getContentPane();
final BirdsEyeVisualizationViewer bird = new BirdsEyeVisualizationViewer(viewer, 0.25f, 0.25f);
JButton reset = new JButton("No Zoom");
reset.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
bird.resetLens();
}
});
final ScalingControl scaler = new ViewScalingControl();
JButton plus = new JButton("+");
plus.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
scaler.scale(viewer, 1.1f, viewer.getCenter());
}
});
JButton minus = new JButton("-");
minus.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
scaler.scale(viewer, 0.9f, viewer.getCenter());
}
});
JButton help = new JButton("Help");
help.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
String zoomHelp = "<html><center>Drag the rectangle to pan<p>" + "Drag one side of the rectangle to zoom</center></html>";
JOptionPane.showMessageDialog(dialog, zoomHelp);
}
});
JPanel controls = new JPanel(new GridLayout(2, 2));
controls.add(plus);
controls.add(minus);
controls.add(reset);
controls.add(help);
content.add(bird);
content.add(controls, BorderLayout.SOUTH);
JButton zoomer = new JButton("Show Zoom Window");
zoomer.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
dialog.pack();
dialog.setLocation((int) (frame.getLocationOnScreen().getX() + frame.getWidth()), (int) frame.getLocationOnScreen().getY());
dialog.show();
bird.initLens();
}
});
header = new Box(BoxLayout.X_AXIS);
JPanel p = new JPanel();
p.add(zoomer);
header.add(p);
// Add the snapshot button for making pictures of graph.
snapshotButton = new JButton(CAMERA_ICON);
snapshotButton.setPressedIcon(CAMERA_ICON_P);
snapshotButton.setBorder(BorderFactory.createEmptyBorder(4, 4, 4, 4));
snapshotButton.setToolTipText("Create a snapshot (as a PNG file)");
snapshotButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
takeSnapshot();
}
});
header.add(snapshotButton);
frame.getContentPane().add(header, BorderLayout.NORTH);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(600, 600);
frame.show();
}
public void reset() {
if (stopper != null) {
stopper.stop();
}
stopper = simulation.scheduleImmediateRepeat(true, this);
this.nextUpdate = 0;
}
public void quit() {
if (stopper != null)
stopper.stop();
stopper = null;
}
static boolean isMacOSX() {
try // we'll try to get certain properties if the security permits it
{
return (System.getProperty("mrj.version") != null); // Apple's
// official approach
} catch (Throwable e) {
return false;
} // Non-Mac Web browsers will fail here
}
static boolean isWindows() {
try // we'll try to get certain properties if the security permits it
{
return !isMacOSX() && (System.getProperty("os.name").startsWith("Win"));
} catch (Throwable e) {
return false;
}
}
static String getVersion() {
try {
return System.getProperty("java.version");
} catch (Throwable e) {
return "unknown";
}
}
public void takeSnapshot() {
if (SimApplet.isApplet) {
Object[] options = { "Oops" };
JOptionPane.showOptionDialog(this, "You cannot save snapshots from an applet.", "MASON Applet Restriction", JOptionPane.OK_OPTION,
JOptionPane.ERROR_MESSAGE, null, options, options[0]);
return;
}
int width = viewer.getSize().width;
System.out.println(width);
int height = viewer.getSize().height;
Color bg = getBackground();
BufferedImage bi = new BufferedImage(width, height, BufferedImage.TYPE_INT_BGR);
Graphics2D graphics = bi.createGraphics();
graphics.setColor(bg);
graphics.fillRect(0, 0, width, height);
viewer.paint(graphics);
// NOW pop up the save window
FileDialog fd = new FileDialog(this.frame, "Save Snapshot as 24-bit PNG...", FileDialog.SAVE);
fd.setFile("Untitled.png");
fd.setVisible(true);
if (fd.getFile() != null)
try {
OutputStream stream = new BufferedOutputStream(new FileOutputStream(new File(fd.getDirectory(), Utilities.ensureFileEndsWith(fd.getFile(),
".png"))));
PngEncoder tmpEncoder = new PngEncoder(bi, false, PngEncoder.FILTER_NONE, 9);
stream.write(tmpEncoder.pngEncode());
stream.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}