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