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}