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