View Javadoc

1   package de.fzi.wim.guibase.graphview.view;
2   
3   import java.util.Iterator;
4   import java.util.ListIterator;
5   import java.util.Collection;
6   import java.util.Map;
7   import java.util.HashMap;
8   import java.util.Set;
9   import java.util.HashSet;
10  import java.util.List;
11  import java.util.ArrayList;
12  import java.awt.Color;
13  import java.awt.Graphics;
14  import java.awt.Graphics2D;
15  import java.awt.Point;
16  import java.awt.Rectangle;
17  import java.awt.geom.Point2D;
18  import java.awt.event.MouseEvent;
19  import java.awt.event.KeyEvent;
20  import java.awt.event.FocusEvent;
21  import java.awt.event.ComponentEvent;
22  import javax.swing.JPanel;
23  import javax.swing.ToolTipManager;
24  import javax.swing.SwingUtilities;
25  
26  import de.fzi.wim.guibase.graphview.graph.*;
27  import de.fzi.wim.guibase.graphview.lens.*;
28  
29  /// ADDED BY TL
30  import org.apache.log4j.Logger;
31  ///
32  
33  /***
34   * The panel capable of visualizing the graph.
35   */
36  public class JGraphPane extends JPanel {
37      /// ADDED BY TL
38      private static final Logger logger = Logger.getLogger(JGraphPane.class);
39      ///
40      /*** The graph being visualized. */
41      protected Graph m_graph;
42      /*** The listener for the graph. */
43      protected GraphListener m_graphListner;
44      /*** The listener for the lens. */
45      protected LensListener m_lensListener;
46      /*** The currently active lens. */
47      protected Lens m_lens;
48      /*** The map of node positions. */
49      protected Map m_nodePositions;
50      /*** The array of registered manipulators in the order they were registered. */
51      protected List m_manipulators;
52      /*** The map of rigestered manipulators keyed by their name. */
53      protected Map m_manipulatorsByName;
54  
55     /***
56      * Creates a graph pane.
57      *
58      * @param graph                      the graph
59      */
60      public JGraphPane(Graph graph) {
61          super(null);
62          m_graphListner=new GraphHandler();
63          m_lensListener=new LensHandler();
64          m_nodePositions=new HashMap();
65          m_manipulators=new ArrayList();
66          m_manipulatorsByName=new HashMap();
67          setGraph(graph);
68          enableEvents(MouseEvent.MOUSE_EVENT_MASK | MouseEvent.MOUSE_MOTION_EVENT_MASK | KeyEvent.KEY_EVENT_MASK | FocusEvent.FOCUS_EVENT_MASK | ComponentEvent.COMPONENT_EVENT_MASK);
69          setBackground(Color.white);
70          ToolTipManager.sharedInstance().setDismissDelay(10000);
71          ToolTipManager.sharedInstance().registerComponent(this);
72      }
73      /***
74       * Adds a manipulator to this pane. If a manipulator with the same name if registered, if is rist removed.
75       *
76       * @param manipulator               the manipulator
77       */
78      public void addManipulator(Manipulator manipulator) {
79          removeManipulator(manipulator.getName());
80          m_manipulators.add(manipulator);
81          m_manipulatorsByName.put(manipulator.getName(),manipulator);
82          manipulator.setGraphPane(this);
83      }
84      /***
85       * Returns a manipulator with given name.
86       *
87       * @param name                      the name of the manpulator
88       * @return                          the manipulator with given name (or <code>null</code> if the manipualtor with given name is not registered)
89       */
90      public Manipulator getManipulator(String name) {
91          return (Manipulator)m_manipulatorsByName.get(name);
92      }
93      /***
94       * Removes a manipulator with given name.
95       *
96       * @param name                      the name of the manpulator
97       */
98      public void removeManipulator(String name) {
99          Manipulator manipulator=(Manipulator)m_manipulatorsByName.remove(name);
100         if (manipulator!=null) {
101             m_manipulators.remove(manipulator);
102             manipulator.setGraphPane(null);
103         }
104     }
105     /***
106      * Returns the current lens.
107      *
108      * @return                          the current lens (may be <code>null</code>)
109      */
110     public Lens getLens() {
111         return m_lens;
112     }
113     /***
114      * Sets the new lens.
115      *
116      * @param lens                      the new lens
117      */
118     public void setLens(Lens lens) {
119         Lens oldLens=m_lens;
120         if (m_lens!=null)
121             m_lens.removeLensListener(m_lensListener);
122         m_lens=lens;
123         if (m_lens!=null)
124             m_lens.addLensListener(m_lensListener);
125         m_nodePositions.clear();
126         repaint();
127         firePropertyChange("lens",oldLens,m_lens);
128     }
129     /***
130      * Returns the current graph.
131      *
132      * @return                          the current graph
133      */
134     public Graph getGraph() {
135         return m_graph;
136     }
137     /***
138      * Sets the current graph.
139      *
140      * @param graph                     the new graph
141      */
142     public void setGraph(Graph graph) {
143         Graph oldGraph=m_graph;
144         if (m_graph!=null)
145             m_graph.removeGraphListener(m_graphListner);
146         m_graph=graph;
147         if (m_graph!=null)
148             m_graph.addGraphListener(m_graphListner);
149         m_nodePositions.clear();
150         repaint();
151         firePropertyChange("graph",oldGraph,m_graph);
152     }
153     /***
154      * Updates the component.
155      *
156      * @param g                         the graphics
157      */
158     public void paintComponent(Graphics g) {
159         Graphics2D g2d=(Graphics2D)g;
160         Rectangle clipRectangle=g.getClipBounds();
161         Color oldColor=g.getColor();
162         g.setColor(getBackground());
163         g.fillRect(clipRectangle.x,clipRectangle.y,clipRectangle.width,clipRectangle.height);
164         g.setColor(oldColor);
165 	/// ATL
166 	logger.debug("Clip: "+clipRectangle);
167 	///
168         if (m_graph!=null)
169             synchronized (m_graph) {
170                 Rectangle bounds=new Rectangle();
171                 Iterator iterator=m_graph.getEdges().iterator();
172                 while (iterator.hasNext()) {
173                     Edge edge=(Edge)iterator.next();
174                     getEdgeScreenBounds(edge,bounds);
175                     if (clipRectangle.intersects(bounds))
176                         paintEdge(g2d,edge);
177                 }
178 		/// ATL
179 		logger.debug("Painting nodes.");
180 		///
181                 iterator=m_graph.getNodes().iterator();
182                 while (iterator.hasNext()) {
183                     Node node=(Node)iterator.next();
184                     getNodeScreenBounds(node,bounds);
185 		    /// ATL
186 		    logger.debug("Checking clip for node with bounds "+bounds);
187 		    ///
188                     if (clipRectangle.intersects(bounds))
189                         paintNode(g2d,node);
190                 }
191                 for (int i=0;i<m_manipulators.size();i++)
192                     ((Manipulator)m_manipulators.get(i)).paint(g2d);
193             }
194 	/// ATL
195 	logger.debug("paintComponent().exit");
196 	///
197     }
198     /***
199      * Paints the edge.
200      *
201      * @param g                         the graphics
202      * @param edge                      the edge
203      */
204     protected void paintEdge(Graphics2D g,Edge edge) {
205         EdgePainter edgePainter=getPainterForEdge(edge);
206         edgePainter.paintEdge(this,g,edge);
207     }
208     /***
209      * Returns the painter for the edge.
210      *
211      * @param edge                      the edge
212      * @return                          the painter for the edge
213      */
214     public EdgePainter getPainterForEdge(Edge edge) {
215         return ArrowEdgePainter.INSTANCE;
216     }
217     /***
218      * Paints the node.
219      *
220      * @param g                         the graphics
221      * @param node                      the node
222      */
223     protected void paintNode(Graphics2D g,Node node) {
224         NodePainter nodePainter=getPainterForNode(node);
225         nodePainter.paintNode(this,g,node);
226     }
227     /***
228      * Returns the painter for the node.
229      *
230      * @param node                      the node
231      * @return                          the painter for the node
232      */
233     public NodePainter getPainterForNode(Node node) {
234         return RectangleNodePainter.INSTANCE;
235     }
236     /***
237      * Converts a given screen point into a point on the graph.
238      *
239      * @param point                     the sreen point
240      * @param graphPoint                the calculatedpoint in the graph
241      */
242     public void screenToGraphPoint(Point point,Point2D graphPoint) {
243         graphPoint.setLocation(point.x-getWidth()/2,point.y-getHeight()/2);
244         if (m_lens!=null)
245             m_lens.undoLens(graphPoint);
246     }
247     /***
248      * Converts a given graph point into a point on the screen.
249      *
250      * @param graphPoint                the point in the graph
251      * @param point                     the calculated screen point
252      */
253     public void graphToScreenPoint(Point2D graphPoint,Point point) {
254         double oldX=graphPoint.getX();
255         double oldY=graphPoint.getY();
256         if (m_lens!=null)
257             m_lens.applyLens(graphPoint);
258         point.setLocation((int)graphPoint.getX()+getWidth()/2,(int)graphPoint.getY()+getHeight()/2);
259         graphPoint.setLocation(oldX,oldY);
260     }
261     /***
262      * Returns the node at given point, or <code>null</code> if there is no such node.
263      *
264      * @param point                     the screen point
265      * @return                          the node at given point (or <code>null</code> if there is no such node)
266      */
267     public Node getNodeAtPoint(Point point) {
268         synchronized (m_graph) {
269             List nodes=m_graph.getNodes();
270             ListIterator iterator=nodes.listIterator(nodes.size());
271             while (iterator.hasPrevious()) {
272                 Node node=(Node)iterator.previous();
273                 NodePainter nodePainter=getPainterForNode(node);
274                 if (nodePainter.isInNode(this,node,point))
275                     return node;
276             }
277             return null;
278         }
279     }
280     /***
281      * Returns the set of nodes in given rectangle.
282      *
283      * @param rectangle                 the rectangle in which the nodes must be located
284      * @return                          the set of nodes in the region
285      */
286     public Set getNodesInRectangle(Rectangle rectangle) {
287         synchronized (m_graph) {
288             Set nodesInRectangle=new HashSet();
289             Rectangle nodeRectangle=new Rectangle();
290             Iterator nodes=m_graph.getNodes().iterator();
291             while (nodes.hasNext()) {
292                 Node node=(Node)nodes.next();
293                 getNodeScreenBounds(node,nodeRectangle);
294                 if (rectangle.contains(nodeRectangle))
295                     nodesInRectangle.add(node);
296             }
297             return nodesInRectangle;
298         }
299     }
300     /***
301      * Returns the edge at given point, or <code>null</code> if there is no such edge.
302      *
303      * @param point                     the screen point
304      * @return                          the edge at given point (or <code>null</code> if there is no such edge)
305      */
306     public Edge getNearestEdge(Point point) {
307         Edge nearestEdge=null;
308         double minDistance=4;
309         synchronized (m_graph) {
310             List edges=m_graph.getEdges();
311             ListIterator iterator=edges.listIterator(edges.size());
312             while (iterator.hasPrevious()) {
313                 Edge edge=(Edge)iterator.previous();
314                 EdgePainter edgePainter=getPainterForEdge(edge);
315                 double distance=edgePainter.screenDistanceFromEdge(this,edge,point);
316                 if (distance<minDistance) {
317                     minDistance=distance;
318                     nearestEdge=edge;
319                 }
320             }
321             return nearestEdge;
322         }
323     }
324     /***
325      * Returns the position of the node on the screen.
326      *
327      * @param node                      the node whose on-screen position is required
328      * @return                          the position of the node on screen
329      */
330     public Point getScreenPointForNode(Node node) {
331         Point point=(Point)m_nodePositions.get(node);
332         if (point==null) {
333             point=new Point();
334             graphToScreenPoint(new Point2D.Double(node.getX(),node.getY()),point);
335             m_nodePositions.put(node,point);
336         }
337         return point;
338     }
339     /***
340      * Updates the map of screen positions of nodes.
341      */
342     protected void updateNodeScreenPositions() {
343         synchronized (m_graph) {
344             Point2D graphPoint=new Point2D.Double();
345             Iterator nodes=m_graph.getNodes().iterator();
346             while (nodes.hasNext()) {
347                 Node node=(Node)nodes.next();
348                 Point point=(Point)m_nodePositions.get(node);
349                 if (point==null) {
350                     point=new Point();
351                     m_nodePositions.put(node,point);
352                 }
353                 graphPoint.setLocation(node.getX(),node.getY());
354                 graphToScreenPoint(graphPoint,point);
355             }
356         }
357     }
358     /***
359      * Returns the screen bounds of given node.
360      *
361      * @param node                      the node for which the bounds must be returned
362      * @param nodeScreenRectangle       the rectangle receiving the node's coordinates
363      */
364     public void getNodeScreenBounds(Node node,Rectangle nodeScreenRectangle) {
365         NodePainter nodePainter=getPainterForNode(node);
366         nodePainter.getNodeScreenBounds(this,node,nodeScreenRectangle);
367     }
368     /***
369      * Repaints the given node.
370      *
371      * @param node                      the node that needs to be repainted
372      */
373     public void repaintNode(Node node) {
374         Rectangle nodeScreenRectangle=new Rectangle();
375         getNodeScreenBounds(node,nodeScreenRectangle);
376         repaint(nodeScreenRectangle);
377     }
378     /***
379      * Returns the screen bounds of given edge.
380      *
381      * @param edge                      the edge for which the bounds must be returned
382      * @param edgeScreenRectangle       the rectangle receiving the edge's coordinates
383      */
384     public void getEdgeScreenBounds(Edge edge,Rectangle edgeScreenRectangle) {
385         EdgePainter edgePainter=getPainterForEdge(edge);
386         edgePainter.getEdgeScreenBounds(this,edge,edgeScreenRectangle);
387     }
388     /***
389      * Repaints the given edge.
390      *
391      * @param edge                      the edge that needs to be repainted
392      */
393     public void repaintEdge(Edge edge) {
394         Rectangle edgeScreenRectangle=new Rectangle();
395         getEdgeScreenBounds(edge,edgeScreenRectangle);
396         edgeScreenRectangle.grow(5,5);
397         repaint(edgeScreenRectangle);
398     }
399     /***
400      * Returns the text for the tool-tip.
401      *
402      * @param event                     the mouse event
403      * @return                          the text for the tool-tip
404      */
405     public String getToolTipText(MouseEvent event) {
406         Point point=event.getPoint();
407         Node node=getNodeAtPoint(point);
408         if (node!=null) {
409             NodePainter nodePainter=getPainterForNode(node);
410             String toolTipText=nodePainter.getToolTipText(this,node,point);
411             if (toolTipText!=null)
412                 return toolTipText;
413         }
414         return super.getToolTipText(event);
415     }
416     /***
417      * Processes the component event.
418      *
419      * @param e                         the event
420      */
421     protected void processComponentEvent(ComponentEvent e) {
422         super.processComponentEvent(e);
423         updateNodeScreenPositions();
424         repaint();
425     }
426     /***
427      * Processes the mouse event.
428      *
429      * @param e                         the event
430      */
431     protected void processMouseEvent(MouseEvent e) {
432         super.processMouseEvent(e);
433         switch (e.getID()) {
434             case MouseEvent.MOUSE_PRESSED:
435             if (!hasFocus() && isRequestFocusEnabled())
436                 requestFocus();
437             for (int i=0;i<m_manipulators.size() && !e.isConsumed();i++)
438                 ((Manipulator)m_manipulators.get(i)).mousePressed(e);
439             break;
440         case MouseEvent.MOUSE_RELEASED:
441             for (int i=0;i<m_manipulators.size() && !e.isConsumed();i++)
442                 ((Manipulator)m_manipulators.get(i)).mouseReleased(e);
443             break;
444         case MouseEvent.MOUSE_CLICKED:
445             for (int i=0;i<m_manipulators.size() && !e.isConsumed();i++)
446                 ((Manipulator)m_manipulators.get(i)).mouseClicked(e);
447             break;
448         case MouseEvent.MOUSE_ENTERED:
449             for (int i=0;i<m_manipulators.size() && !e.isConsumed();i++)
450                 ((Manipulator)m_manipulators.get(i)).mouseEntered(e);
451             break;
452         case MouseEvent.MOUSE_EXITED:
453             for (int i=0;i<m_manipulators.size() && !e.isConsumed();i++)
454                 ((Manipulator)m_manipulators.get(i)).mouseExited(e);
455             break;
456         }
457     }
458     /***
459      * Processes the mouse motion events.
460      *
461      * @param e                         mouse event
462      */
463     protected void processMouseMotionEvent(MouseEvent e) {
464         super.processMouseMotionEvent(e);
465         switch (e.getID()) {
466         case MouseEvent.MOUSE_MOVED:
467             for (int i=0;i<m_manipulators.size() && !e.isConsumed();i++)
468                 ((Manipulator)m_manipulators.get(i)).mouseMoved(e);
469             break;
470         case MouseEvent.MOUSE_DRAGGED:
471             for (int i=0;i<m_manipulators.size() && !e.isConsumed();i++)
472                 ((Manipulator)m_manipulators.get(i)).mouseDragged(e);
473             break;
474         }
475     }
476     /***
477      * Processes the key event.
478      *
479      * @param e                         the event
480      */
481     protected void processKeyEvent(KeyEvent e) {
482         super.processKeyEvent(e);
483         switch (e.getID()) {
484         case KeyEvent.KEY_TYPED:
485             for (int i=0;i<m_manipulators.size() && !e.isConsumed();i++)
486                 ((Manipulator)m_manipulators.get(i)).keyTyped(e);
487             break;
488         case KeyEvent.KEY_PRESSED:
489             for (int i=0;i<m_manipulators.size() && !e.isConsumed();i++)
490                 ((Manipulator)m_manipulators.get(i)).keyPressed(e);
491             break;
492         case KeyEvent.KEY_RELEASED:
493             for (int i=0;i<m_manipulators.size() && !e.isConsumed();i++)
494                 ((Manipulator)m_manipulators.get(i)).keyReleased(e);
495             break;
496         }
497     }
498     /***
499      * Processes the focus event.
500      *
501      * @param e                         the event
502      */
503     protected void processFocusEvent(FocusEvent e) {
504         super.processFocusEvent(e);
505         switch (e.getID()) {
506         case FocusEvent.FOCUS_GAINED:
507             for (int i=0;i<m_manipulators.size();i++)
508                 ((Manipulator)m_manipulators.get(i)).focusGained(e);
509             break;
510         case FocusEvent.FOCUS_LOST:
511             for (int i=0;i<m_manipulators.size();i++)
512                 ((Manipulator)m_manipulators.get(i)).focusLost(e);
513             break;
514         }
515     }
516     /***
517      * Overridden to notify the manipulators that the scroll position has changed.
518      *
519      * @param rectangle                 the rectangle
520      */
521     public void scrollRectToVisible(Rectangle rectangle) {
522         super.scrollRectToVisible(rectangle);
523         for (int i=0;i<m_manipulators.size();i++)
524             ((Manipulator)m_manipulators.get(i)).notifyGraphPaneScrolled();
525     }
526 
527     /***
528      * The handler of graph events.
529      */
530     protected class GraphHandler implements GraphListener {
531         public void graphLayoutUpdated(Graph graph) {
532             if (SwingUtilities.isEventDispatchThread()) {
533                 updateNodeScreenPositions();
534                 repaint();
535             }
536             else
537                 SwingUtilities.invokeLater(new Runnable() {
538                     public void run() {
539                         updateNodeScreenPositions();
540                         repaint();
541                     }
542                 });
543         }
544         public void graphUpdated(Graph graph) {
545             if (SwingUtilities.isEventDispatchThread())
546                 repaint();
547             else
548                 SwingUtilities.invokeLater(new Runnable() {
549                     public void run() {
550                         repaint();
551                     }
552                 });
553         }
554         public void graphContentsChanged(Graph graph) {
555             m_nodePositions.clear();
556             repaint();
557         }
558         public void elementsAdded(Graph graph,Collection nodes,Collection edges) {
559             repaint();
560         }
561         public void elementsRemoved(Graph graph,Collection nodes,Collection edges) {
562             if (nodes!=null) {
563                 Iterator iterator=nodes.iterator();
564                 while (iterator.hasNext()) {
565                     Node node=(Node)iterator.next();
566                     m_nodePositions.remove(node);
567                 }
568             }
569             repaint();
570         }
571     }
572 
573     /***
574      * The handler of lens events.
575      */
576     protected class LensHandler implements LensListener {
577         public void lensUpdated(Lens lens) {
578             updateNodeScreenPositions();
579             repaint();
580         }
581     }
582 }