This repository has been archived on 2020-05-27. You can view files and clone it, but cannot push or open issues/pull-requests.
jgraph/GraphScreen.java

268 lines
10 KiB
Java

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.util.*;
import java.text.DecimalFormat;
/** This class defines a custom JPanel that will draw vertices, edges, and the shortest path of a Graph object. This custom JPanel is used because it is much easier to intercept x and y coordinates in this panel than in the frame and then having to compensate for the other graphical components. */
public class GraphScreen extends JPanel implements MouseListener {
/** defines the radius of the vertices in pixels */
private final int radius = 20;
/** the path of vertices for the currently displayed shortest path */
private ArrayList path;
/** the graph to add vertices/edges to */
private Graph mygraph;
/** the status bar in the parent jframe */
private JLabel information;
/* a flag to check if you are calculating the shortest path */
private boolean shortestpath;
/* a flag used to check if the mouseclick intercepted was the second in the series (add edge, shortest path) */
private boolean issecondvertex;
/* the data stored in the first vertex clicked in the series */
private Comparable firstvertex;
/**
* Default constructor for the GraphScreen panel. <BR>
* Preconditions: A JLabel status bar in the parent JFrame. <BR>
* Postconditions: Initializes all variables. <BR>
*/
public GraphScreen ( JLabel information ) {
super ( true );
this.information = information;
addMouseListener ( this );
mygraph = new Graph();
mygraph.setShortestPathDisplay ( new ArrayList() );
information.setText ( " Click to add vertex" );
issecondvertex = false;
firstvertex = null;
shortestpath = false;
}
/** mousePressed and mouseReleased could be used to move vertices around the graph,
but as per explicitly stated in the program requirements, the GraphNodes have no
setX ( int x ) and setY ( int y ) methods. */
public void mousePressed ( MouseEvent event ) {}
public void mouseReleased ( MouseEvent event ) {}
/** not used, just here to fully implement the MouseListener interface */
public void mouseEntered ( MouseEvent event ) {}
public void mouseExited ( MouseEvent event ) {}
/**
* Intercepts a mouse click in the drawing window. <BR>
* Preconditions: A mouse click. <BR>
* Postconditions: This method could add a vertex, add an edge, or calculate where the shortest path needs to be based upon flags and user interaction. <BR>
*/
public void mouseClicked ( MouseEvent event ) {
/* If it is a right mouse click, then we must add an edge */
if ( SwingUtilities.isRightMouseButton ( event ) ) {
/* the node that is contained within radius pixels of the MouseEvent */
GraphNode temp = findVertex ( event.getX(), event.getY() );
/* if temp is null then the user clicked in blank space */
if ( temp != null ) {
/* if this is the second right mouse click, and it is not the same vertex */
if ( issecondvertex && firstvertex.compareTo ( temp.getKey() ) != 0 ) {
/* lets add an edge, and hopefully it will work */
try {
addEdge ( firstvertex, temp.getKey() );
information.setText ( " Edge added between " + firstvertex.toString() + " and " + temp.getKey().toString() );
}
/* error exists between keyboard and chair */
catch ( GraphException exception ) {
information.setText ( " Could not add the edge" );
JOptionPane.showMessageDialog ( null, exception.toString(), "Exception caught", JOptionPane.WARNING_MESSAGE );
}
/* we will set all the flags to normal */
issecondvertex = false;
firstvertex = null;
}
/* this must be the first right click intercepted */
else {
/* save the data for use later */
firstvertex = temp.getKey();
issecondvertex = true;
information.setText ( " Right click on another vertex to create an edge" );
}
}
/* we don't care and set everything to normal since the user clicked in blank space */
else {
firstvertex = null;
issecondvertex = false;
information.setText ( " Right click on vertices to add and edge" );
}
}
/* not the right mouse button, so this could be shortest path or add a vertex */
/* if the shortest path flag is set, we must find two different vertices */
else if ( shortestpath ) {
/* if there are less than 2 vertices in the graph, it is impossible to find the shortest path */
if ( mygraph.numVertices() > 2 ) {
GraphNode temp = findVertex ( event.getX(), event.getY() );
/* if this is the second click and the user clicked on a node and the node is not the same node */
if ( issecondvertex && temp != null && firstvertex.compareTo ( temp.getKey() ) != 0 ) {
/* set the shortest path arraylist to the path in the graph */
try {
mygraph.setShortestPathDisplay ( mygraph.shortestPath ( firstvertex, temp.getKey() ) );
information.setText ( " Shortest path is displayed in green" );
repaint();
}
catch ( GraphException exception ) {
JOptionPane.showMessageDialog ( null, exception.toString(), "Exception caught", JOptionPane.WARNING_MESSAGE );
mygraph.setShortestPathDisplay ( new ArrayList() );
information.setText ( " Could not create the shortest path" );
}
shortestpath = false;
issecondvertex = false;
firstvertex = null;
}
/* the user is clicking on blank space */
else if ( temp == null ) {
information.setText ( " You must first click on vertices" );
shortestpath = false;
issecondvertex = false;
firstvertex = null;
}
/* must be the first click in the series then */
else {
firstvertex = temp.getKey();
issecondvertex = true;
information.setText ( " Click on the ending vertex of the path" );
}
}
/* not enough vertices to make a shortest path */
else {
information.setText ( " There must be at least 2 vertices in the graph before calculating the shortest path" );
shortestpath = false;
firstvertex = null;
issecondvertex = false;
}
}
/* well, the only thing left is to add a new vertex */
else {
/* if the user clicked in blank space for once */
if ( findVertex ( event.getX(), event.getY() ) == null ) {
information.setText ( " Click to add vertex" );
shortestpath = false;
issecondvertex = false;
firstvertex = null;
/* ask the user what they want to call it */
String name = JOptionPane.showInputDialog ( null, "Enter name: ","Add new graph node", JOptionPane.QUESTION_MESSAGE );
/* as long as the name appears somewhat valid anyways */
if ( name != null && !name.equals ( "" ) ) {
int x = event.getX(), y = event.getY();
/* these if's check to make sure the user didn't click too close to the edge */
if ( x + radius > getWidth() )
x = getWidth() - radius;
if ( x - radius < 0 )
x = radius;
if ( y - radius > getHeight() )
y = getHeight() - radius;
if ( y - radius < 0 )
y = radius;
try {
mygraph.addVertex ( new GraphNode ( name, x, y ) );
information.setText ( " Vertex added at (" + x + ", " + y + ")" );
repaint();
}
catch ( Exception exception ) {
JOptionPane.showMessageDialog ( null, exception.toString(), "Exception caught!", JOptionPane.WARNING_MESSAGE );
information.setText ( " Vertex could not be added" );
}
}
}
/* the user clicked on a vertex */
else {
information.setText ( " Vertex already added at location" );
JOptionPane.showMessageDialog ( null, "Vertex is already at that point!", "Waitaminit!", JOptionPane.WARNING_MESSAGE );
}
}
}
/**
* Empties the graph and sets all flags to default values. <BR>
* Preconditions: None. <BR>
* Postconditions: Resets all internally used variables to default values. <BR>
*/
public void clearGraph() {
mygraph.makeEmpty();
information.setText ( " Click to add vertex" );
mygraph.setShortestPathDisplay ( new ArrayList() );
issecondvertex = false;
firstvertex = null;
shortestpath = false;
repaint();
}
/**
* Used to set the flag to find the shortest path. <BR>
* Preconditions: None. <BR>
* Postconditions: Sets the shortestpath flag to true. <BR>
*/
public void findShortestPath() {
shortestpath = true;
information.setText ( " Click on the starting vertex" );
}
/**
* Attempts to locate a GraphNode within x +/- radius pixels and y +/- radius pixels of the given coordinate. <BR>
* Preconditions: Two integers representing coordinates inside the GraphScreen. <BR>
* Postconditions: Returns null if no GraphNode is close to the coord. or the GraphNode closest to that point. <BR>
*/
private GraphNode findVertex ( int x, int y ) {
/* look through all of the nodes one by one */
for ( int i = 0; i < mygraph.numVertices(); i++ ) {
GraphNode result = mygraph.getVertex ( i );
int tempx = result.getX();
int tempy = result.getY();
if ( tempx + radius >= x && tempx - radius <= x && tempy - radius <= y && tempy + radius >= y )
return result;
}
return null;
}
/**
* Adds an edge between two vertices. <BR>
* Preconditions: Two comparable objects that are in the graph. <BR>
* Postconditions: Adds an edge between the two vertices containing the comparable objects. <BR>
*/
public void addEdge ( Comparable first, Comparable second ) {
String temp = JOptionPane.showInputDialog ( null, "Enter a weight", "Add an edge", JOptionPane.QUESTION_MESSAGE );
double result = -1.0;
if ( temp != null ) {
try {
result = Double.parseDouble ( temp );
if ( result < 0 )
throw new GraphException ( "Invalid weight for edge." );
mygraph.addEdge ( first, second, result );
information.setText ( " New edge added between vertices {" + (String) first + "} and {" + (String) second + "}" );
repaint();
}
catch ( Exception exception ) {
information.setText ( " Edge could not be added" );
JOptionPane.showMessageDialog ( null, exception.toString(), "Exception Caught", JOptionPane.WARNING_MESSAGE );
}
}
}
/**
* Draws the background for the custom JPanel. <BR>
*/
public void paint ( Graphics g ) {
/* draw a black background */
g.setColor ( Color.black );
g.fillRect ( 0, 0, this.getWidth(), this.getHeight() );
mygraph.draw ( g, radius );
}
}