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