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();
018:       edges = new ArrayList();
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 = (Node) 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 = (Edge) 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 (int i = 0; i < nodes.size(); i++)
094:       {
095:          Node n = (Node) nodes.get(i);
096:          n.draw(g2);
097:       }
098: 
099:       for (int i = 0; i < edges.size(); i++)
100:       {
101:          Edge e = (Edge) edges.get(i);
102:          e.draw(g2);
103:       }
104:    }
105:    
106:    /**
107:       Removes a node and all edges that start or end with that node
108:       @param n the node to remove
109:    */
110:    public void removeNode(Node n)
111:    {
112:       for (int i = edges.size() - 1; i >= 0; i--)
113:       {
114:          Edge e = (Edge) edges.get(i);
115:          if (e.getStart() == n || e.getEnd() == n)
116:             edges.remove(e);
117:       }
118:       nodes.remove(n);
119:    }
120: 
121:    /**
122:       Removes an edge from the graph.
123:       @param e the edge to remove
124:    */
125:    public void removeEdge(Edge e)
126:    {
127:       edges.remove(e);
128:    }
129: 
130:    /**
131:       Gets the smallest rectangle enclosing the graph
132:       @param g2 the graphics context
133:       @return the bounding rectangle
134:    */
135:    public Rectangle2D getBounds(Graphics2D g2)
136:    {
137:       Rectangle2D r = null;
138:       for (int i = 0; i < nodes.size(); i++)
139:       {
140:          Node n = (Node) nodes.get(i);
141:          Rectangle2D b = n.getBounds();
142:          if (r == null) r = b;
143:          else r.add(b);
144:       }
145:       for (int i = 0; i < edges.size(); i++)
146:       {
147:          Edge e = (Edge) edges.get(i);
148:          r.add(e.getBounds(g2));
149:       }
150:       return r == null ? new Rectangle2D.Double() : r;
151:    }
152: 
153:    /**
154:       Gets the node types of a particular graph type.
155:       @return an array of node prototypes
156:    */   
157:    public abstract Node[] getNodePrototypes();
158: 
159:    /**
160:       Gets the edge types of a particular graph type.
161:       @return an array of edge prototypes
162:    */   
163:    public abstract Edge[] getEdgePrototypes();
164: 
165:    /**
166:       Gets the nodes of this graph.
167:       @return an unmodifiable list of the nodes
168:    */
169:    public List getNodes() 
170:    { 
171:       return Collections.unmodifiableList(nodes); }
172: 
173:    /**
174:       Gets the edges of this graph.
175:       @return an unmodifiable list of the edges
176:    */
177:    public List getEdges() 
178:    { 
179:       return Collections.unmodifiableList(edges); 
180:    }
181: 
182:    private ArrayList nodes;
183:    private ArrayList edges;
184: }
185: 
186: 
187: 
188: 
189: