001: import java.awt.*; 002: import java.awt.geom.*; 003: import java.io.*; 004: import java.util.*; 005: import java.util.List; 006: 007: /** 008: A graph consisting of selectable nodes and edges. 009: */ 010: public abstract class Graph implements Serializable 011: { 012: /** 013: Constructs a graph with no nodes or edges. 014: */ 015: public Graph() 016: { 017: nodes = new ArrayList<Node>(); 018: edges = new ArrayList<Edge>(); 019: } 020: 021: /** 022: Adds an edge to the graph that joins the nodes containing 023: the given points. If the points aren't both inside nodes, 024: then no edge is added. 025: @param e the edge to add 026: @param p1 a point in the starting node 027: @param p2 a point in the ending node 028: */ 029: public boolean connect(Edge e, Point2D p1, Point2D p2) 030: { 031: Node n1 = findNode(p1); 032: Node n2 = findNode(p2); 033: if (n1 != null && n2 != null) 034: { 035: e.connect(n1, n2); 036: edges.add(e); 037: return true; 038: } 039: return false; 040: } 041: 042: /** 043: Adds a node to the graph so that the top left corner of 044: the bounding rectangle is at the given point. 045: @param n the node to add 046: @param p the desired location 047: */ 048: public boolean add(Node n, Point2D p) 049: { 050: Rectangle2D bounds = n.getBounds(); 051: n.translate(p.getX() - bounds.getX(), 052: p.getY() - bounds.getY()); 053: nodes.add(n); 054: return true; 055: } 056: 057: /** 058: Finds a node containing the given point. 059: @param p a point 060: @return a node containing p or null if no nodes contain p 061: */ 062: public Node findNode(Point2D p) 063: { 064: for (int i = nodes.size() - 1; i >= 0; i--) 065: { 066: Node n = nodes.get(i); 067: if (n.contains(p)) return n; 068: } 069: return null; 070: } 071: 072: /** 073: Finds an edge containing the given point. 074: @param p a point 075: @return an edge containing p or null if no edges contain p 076: */ 077: public Edge findEdge(Point2D p) 078: { 079: for (int i = edges.size() - 1; i >= 0; i--) 080: { 081: Edge e = edges.get(i); 082: if (e.contains(p)) return e; 083: } 084: return null; 085: } 086: 087: /** 088: Draws the graph 089: @param g2 the graphics context 090: */ 091: public void draw(Graphics2D g2) 092: { 093: for (Node n : nodes) 094: n.draw(g2); 095: 096: for (Edge e : edges) 097: e.draw(g2); 098: 099: } 100: 101: /** 102: Removes a node and all edges that start or end with that node 103: @param n the node to remove 104: */ 105: public void removeNode(Node n) 106: { 107: for (int i = edges.size() - 1; i >= 0; i--) 108: { 109: Edge e = edges.get(i); 110: if (e.getStart() == n || e.getEnd() == n) 111: edges.remove(e); 112: } 113: nodes.remove(n); 114: } 115: 116: /** 117: Removes an edge from the graph. 118: @param e the edge to remove 119: */ 120: public void removeEdge(Edge e) 121: { 122: edges.remove(e); 123: } 124: 125: /** 126: Gets the smallest rectangle enclosing the graph 127: @param g2 the graphics context 128: @return the bounding rectangle 129: */ 130: public Rectangle2D getBounds(Graphics2D g2) 131: { 132: Rectangle2D r = null; 133: for (Node n : nodes) 134: { 135: Rectangle2D b = n.getBounds(); 136: if (r == null) r = b; 137: else r.add(b); 138: } 139: for (Edge e : edges) 140: r.add(e.getBounds(g2)); 141: return r == null ? new Rectangle2D.Double() : r; 142: } 143: 144: /** 145: Gets the node types of a particular graph type. 146: @return an array of node prototypes 147: */ 148: public abstract Node[] getNodePrototypes(); 149: 150: /** 151: Gets the edge types of a particular graph type. 152: @return an array of edge prototypes 153: */ 154: public abstract Edge[] getEdgePrototypes(); 155: 156: /** 157: Gets the nodes of this graph. 158: @return an unmodifiable list of the nodes 159: */ 160: public List<Node> getNodes() 161: { 162: return Collections.unmodifiableList(nodes); } 163: 164: /** 165: Gets the edges of this graph. 166: @return an unmodifiable list of the edges 167: */ 168: public List<Edge> getEdges() 169: { 170: return Collections.unmodifiableList(edges); 171: } 172: 173: private ArrayList<Node> nodes; 174: private ArrayList<Edge> edges; 175: } 176: 177: 178: 179: 180: