    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: