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.
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:                revalidate();
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:       Removes the selected node or edge.
156:    */
157:    public void removeSelected()
158:    {
159:       if (selected instanceof Node)
160:       {
161:          graph.removeNode((Node) selected);
162:       }
163:       else if (selected instanceof Edge)
164:       {
165:          graph.removeEdge((Edge) selected);
166:       }          
167:       selected = null;
168:       repaint();               
169:    }
170: 
171:    /**
172:       Edits the properties of the selected graph element.
173:    */
174:    public void editSelected()
175:    {
176:       PropertySheet sheet = new PropertySheet(selected);
177:       sheet.addChangeListener(new
178:          ChangeListener()
179:          {
180:             public void stateChanged(ChangeEvent event)
181:             {
182:                repaint();
183:             }
184:          });
185:       JOptionPane.showMessageDialog(null, 
186:          sheet, 
187:          "Properties", 
188:          JOptionPane.QUESTION_MESSAGE);        
189:    }
190: 
191:    /**
192:       Draws a single "grabber", a filled square
193:       @param g2 the graphics context
194:       @param x the x coordinate of the center of the grabber
195:       @param y the y coordinate of the center of the grabber
196:    */
197:    public static void drawGrabber(Graphics2D g2, double x, double y)
198:    {
199:       final int SIZE = 5;
200:       Color oldColor = g2.getColor();
201:       g2.setColor(PURPLE);
202:       g2.fill(new Rectangle2D.Double(x - SIZE / 2,
203:          y - SIZE / 2, SIZE, SIZE));      
204:       g2.setColor(oldColor);
205:    }
206: 
207:    public Dimension getPreferredSize()
208:    {
209:       Rectangle2D bounds 
210:          = graph.getBounds((Graphics2D) getGraphics());
211:       return new Dimension(
212:          (int) bounds.getMaxX(), 
213:          (int) bounds.getMaxY());
214:    }
215: 
216:    private Graph graph;
217:    private ToolBar toolBar;
218:    private Point2D lastMousePoint;
219:    private Point2D rubberBandStart;
220:    private Point2D dragStartPoint;
221:    private Rectangle2D dragStartBounds;
222:    private Object selected;
223:    private static final Color PURPLE = new Color(0.7f, 0.4f, 0.7f);   
224: }