001package horstmann.ch08_graphed;
002import java.awt.Color;
003import java.awt.Dimension;
004import java.awt.Graphics;
005import java.awt.Graphics2D;
006import java.awt.event.MouseAdapter;
007import java.awt.event.MouseEvent;
008import java.awt.event.MouseMotionAdapter;
009import java.awt.geom.Line2D;
010import java.awt.geom.Point2D;
011import java.awt.geom.Rectangle2D;
012
013import javax.swing.JComponent;
014
015/**
016   A panel to draw a graph
017 */
018@SuppressWarnings("serial")
019public class GraphPanel extends JComponent
020{
021        /**
022      Constructs a graph panel.
023      @param aToolBar the tool bar with the node and edge tools
024      @param aGraph the graph to be displayed and edited
025         */
026        public GraphPanel(ToolBar aToolBar, Graph aGraph)
027        {
028                toolBar = aToolBar;
029                graph = aGraph;
030                setBackground(Color.WHITE);
031
032                addMouseListener(new
033                                MouseAdapter()
034                {
035                        public void mousePressed(MouseEvent event)
036                        {
037                                Point2D mousePoint = event.getPoint();
038                                Node n = graph.findNode(mousePoint);
039                                Edge e = graph.findEdge(mousePoint);
040                                Object tool = toolBar.getSelectedTool();
041                                if (tool == null) // select
042                                {
043                                        if (e != null)
044                                        {
045                                                selected = e;
046                                        }
047                                        else if (n != null)
048                                        {
049                                                selected = n;
050                                                dragStartPoint = mousePoint;
051                                                dragStartBounds = n.getBounds();
052                                        }
053                                        else
054                                        {
055                                                selected = null;
056                                        }
057                                }
058                                else if (tool instanceof Node)
059                                {
060                                        Node prototype = (Node) tool;
061                                        Node newNode = (Node) prototype.clone();
062                                        boolean added = graph.add(newNode, mousePoint);
063                                        if (added)
064                                        {
065                                                selected = newNode;
066                                                dragStartPoint = mousePoint;
067                                                dragStartBounds = newNode.getBounds();
068                                        }
069                                        else if (n != null)
070                                        {
071                                                selected = n;
072                                                dragStartPoint = mousePoint;
073                                                dragStartBounds = n.getBounds();
074                                        }
075                                }
076                                else if (tool instanceof Edge)
077                                {
078                                        if (n != null) rubberBandStart = mousePoint;
079                                }
080                                lastMousePoint = mousePoint;
081                                repaint();
082                        }
083
084                        public void mouseReleased(MouseEvent event)
085                        {
086                                Object tool = toolBar.getSelectedTool();
087                                if (rubberBandStart != null)
088                                {
089                                        Point2D mousePoint = event.getPoint();
090                                        Edge prototype = (Edge) tool;
091                                        Edge newEdge = (Edge) prototype.clone();
092                                        if (graph.connect(newEdge,
093                                                        rubberBandStart, mousePoint))
094                                                selected = newEdge;
095                                }
096
097                                validate();
098                                repaint();
099
100                                lastMousePoint = null;
101                                dragStartBounds = null;
102                                rubberBandStart = null;
103                        }
104                });
105
106                addMouseMotionListener(new
107                                MouseMotionAdapter()
108                {
109                        public void mouseDragged(MouseEvent event)
110                        {
111                                Point2D mousePoint = event.getPoint();
112                                if (dragStartBounds != null)
113                                {
114                                        if (selected instanceof Node)
115                                        {
116                                                Node n = (Node) selected;
117                                                Rectangle2D bounds = n.getBounds();
118                                                n.translate(
119                                                                dragStartBounds.getX() - bounds.getX()
120                                                                + mousePoint.getX() - dragStartPoint.getX(),
121                                                                dragStartBounds.getY() - bounds.getY()
122                                                                + mousePoint.getY() - dragStartPoint.getY());
123                                        }
124                                }
125                                lastMousePoint = mousePoint;
126                                repaint();
127                        }
128                });
129        }
130
131        public void paintComponent(Graphics g)
132        {
133                Graphics2D g2 = (Graphics2D) g;
134                Rectangle2D bounds = getBounds();
135                Rectangle2D graphBounds = graph.getBounds(g2);
136                graph.draw(g2);
137
138                if (selected instanceof Node)
139                {
140                        Rectangle2D grabberBounds = ((Node) selected).getBounds();
141                        drawGrabber(g2, grabberBounds.getMinX(), grabberBounds.getMinY());
142                        drawGrabber(g2, grabberBounds.getMinX(), grabberBounds.getMaxY());
143                        drawGrabber(g2, grabberBounds.getMaxX(), grabberBounds.getMinY());
144                        drawGrabber(g2, grabberBounds.getMaxX(), grabberBounds.getMaxY());
145                }
146
147                if (selected instanceof Edge)
148                {
149                        Line2D line = ((Edge) selected).getConnectionPoints();
150                        drawGrabber(g2, line.getX1(), line.getY1());
151                        drawGrabber(g2, line.getX2(), line.getY2());
152                }
153
154                if (rubberBandStart != null)
155                {
156                        Color oldColor = g2.getColor();
157                        g2.setColor(PURPLE);
158                        g2.draw(new Line2D.Double(rubberBandStart, lastMousePoint));
159                        g2.setColor(oldColor);
160                }
161        }
162
163
164        /**
165      Removes the selected node or edge.
166         */
167        public void removeSelected()
168        {
169                if (selected instanceof Node)
170                {
171                        graph.removeNode((Node) selected);
172                }
173                else if (selected instanceof Edge)
174                {
175                        graph.removeEdge((Edge) selected);
176                }
177                selected = null;
178                repaint();
179        }
180
181        /**
182      Draws a single "grabber", a filled square
183      @param g2 the graphics context
184      @param x the x coordinate of the center of the grabber
185      @param y the y coordinate of the center of the grabber
186         */
187        public static void drawGrabber(Graphics2D g2, double x, double y)
188        {
189                final int SIZE = 5;
190                Color oldColor = g2.getColor();
191                g2.setColor(PURPLE);
192                g2.fill(new Rectangle2D.Double(x - SIZE / 2,
193                                y - SIZE / 2, SIZE, SIZE));
194                g2.setColor(oldColor);
195        }
196
197        public Dimension getPreferredSize()
198        {
199                Rectangle2D bounds
200                = graph.getBounds((Graphics2D) getGraphics());
201                return new Dimension(
202                                (int) bounds.getMaxX(),
203                                (int) bounds.getMaxY());
204        }
205
206        private Graph graph;
207        private ToolBar toolBar;
208        private Point2D lastMousePoint;
209        private Point2D rubberBandStart;
210        private Point2D dragStartPoint;
211        private Rectangle2D dragStartBounds;
212        private Object selected;
213        private static final Color PURPLE = new Color(0.7f, 0.4f, 0.7f);
214}