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 JPanel
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:       super.paintComponent(g);
125:       Graphics2D g2 = (Graphics2D) g;
126:       Rectangle2D bounds = getBounds();
127:       Rectangle2D graphBounds = graph.getBounds(g2);
128:       graph.draw(g2);
129: 
130:       if (selected instanceof Node)
131:       {
132:          Rectangle2D grabberBounds = ((Node) selected).getBounds();
133:          drawGrabber(g2, grabberBounds.getMinX(), grabberBounds.getMinY());
134:          drawGrabber(g2, grabberBounds.getMinX(), grabberBounds.getMaxY());
135:          drawGrabber(g2, grabberBounds.getMaxX(), grabberBounds.getMinY());
136:          drawGrabber(g2, grabberBounds.getMaxX(), grabberBounds.getMaxY());
137:       }
138: 
139:       if (selected instanceof Edge)
140:       {
141:          Line2D line = ((Edge) selected).getConnectionPoints();
142:          drawGrabber(g2, line.getX1(), line.getY1());
143:          drawGrabber(g2, line.getX2(), line.getY2());
144:       }
145: 
146:       if (rubberBandStart != null)
147:       {
148:          Color oldColor = g2.getColor();
149:          g2.setColor(PURPLE);
150:          g2.draw(new Line2D.Double(rubberBandStart, lastMousePoint));
151:          g2.setColor(oldColor);
152:       }
153:    }
154: 
155: 
156:    /**
157:       Removes the selected node or edge.
158:    */
159:    public void removeSelected()
160:    {
161:       if (selected instanceof Node)
162:       {
163:          graph.removeNode((Node) selected);
164:       }
165:       else if (selected instanceof Edge)
166:       {
167:          graph.removeEdge((Edge) selected);
168:       }          
169:       selected = null;
170:       repaint();               
171:    }
172: 
173:    /**
174:       Draws a single "grabber", a filled square
175:       @param g2 the graphics context
176:       @param x the x coordinate of the center of the grabber
177:       @param y the y coordinate of the center of the grabber
178:    */
179:    public static void drawGrabber(Graphics2D g2, double x, double y)
180:    {
181:       final int SIZE = 5;
182:       Color oldColor = g2.getColor();
183:       g2.setColor(PURPLE);
184:       g2.fill(new Rectangle2D.Double(x - SIZE / 2,
185:          y - SIZE / 2, SIZE, SIZE));      
186:       g2.setColor(oldColor);
187:    }
188: 
189:    public Dimension getPreferredSize()
190:    {
191:       Rectangle2D bounds 
192:          = graph.getBounds((Graphics2D) getGraphics());
193:       return new Dimension(
194:          (int) bounds.getMaxX(), 
195:          (int) bounds.getMaxY());
196:    }
197: 
198:    private Graph graph;
199:    private ToolBar toolBar;
200:    private Point2D lastMousePoint;
201:    private Point2D rubberBandStart;
202:    private Point2D dragStartPoint;
203:    private Rectangle2D dragStartBounds;
204:    private Object selected;
205:    private static final Color PURPLE = new Color(0.7f, 0.4f, 0.7f);   
206: }