Coverage details for edu.uci.ics.jung.visualization.VisualizationViewer

LineHitsSource
1 /*
2 * Copyright (c) 2003, the JUNG Project and the Regents of the University
3 * of California
4 * All rights reserved.
5 *
6 * This software is open-source under the BSD license; see either
7 * "license.txt" or
8 * http://jung.sourceforge.net/license.txt for a description.
9 */
10 package edu.uci.ics.jung.visualization;
11  
12 import java.awt.Dimension;
13 import java.awt.Graphics;
14 import java.awt.Graphics2D;
15 import java.awt.RenderingHints;
16 import java.awt.event.ComponentAdapter;
17 import java.awt.event.ComponentEvent;
18 import java.awt.event.ItemEvent;
19 import java.awt.event.ItemListener;
20 import java.awt.event.MouseAdapter;
21 import java.awt.event.MouseEvent;
22 import java.awt.event.MouseListener;
23 import java.awt.event.MouseMotionListener;
24 import java.awt.event.MouseWheelEvent;
25 import java.awt.event.MouseWheelListener;
26 import java.awt.geom.AffineTransform;
27 import java.awt.geom.Point2D;
28 import java.awt.image.BufferedImage;
29 import java.util.ArrayList;
30 import java.util.ConcurrentModificationException;
31 import java.util.HashMap;
32 import java.util.Iterator;
33 import java.util.List;
34 import java.util.Map;
35  
36 import javax.swing.JPanel;
37 import javax.swing.ToolTipManager;
38 import javax.swing.event.ChangeEvent;
39 import javax.swing.event.ChangeListener;
40 import javax.swing.event.EventListenerList;
41  
42 import org.apache.commons.collections.Predicate;
43  
44 import edu.uci.ics.jung.graph.Edge;
45 import edu.uci.ics.jung.graph.Vertex;
46 import edu.uci.ics.jung.graph.decorators.ToolTipFunction;
47 import edu.uci.ics.jung.graph.decorators.ToolTipFunctionAdapter;
48 import edu.uci.ics.jung.utils.ChangeEventSupport;
49 import edu.uci.ics.jung.utils.DefaultChangeEventSupport;
50 import edu.uci.ics.jung.utils.Pair;
51 import edu.uci.ics.jung.visualization.transform.LayoutTransformer;
52 import edu.uci.ics.jung.visualization.transform.MutableAffineTransformer;
53 import edu.uci.ics.jung.visualization.transform.MutableTransformer;
54 import edu.uci.ics.jung.visualization.transform.Transformer;
55 import edu.uci.ics.jung.visualization.transform.ViewTransformer;
56  
57 /**
58  * A class that maintains many of the details necessary for creating
59  * visualizations of graphs.
60  *
61  * @author Joshua O'Madadhain
62  * @author Tom Nelson
63  * @author Danyel Fisher
64  */
65 public class VisualizationViewer extends JPanel
66                 implements Transformer, LayoutTransformer, ViewTransformer,
67                 HasGraphLayout, ChangeListener, ChangeEventSupport{
68  
690    protected ChangeEventSupport changeSupport =
70         new DefaultChangeEventSupport(this);
71  
72     /**
73      * holds the state of this View
74      */
75     protected VisualizationModel model;
76  
77     /**
78      * handles the actual drawing of graph elements
79      */
80     protected Renderer renderer;
81     
82     /** should be set to user-defined class to provide
83      * tooltips on the graph elements
84      */
85     protected ToolTipFunction toolTipFunction;
86     
87     /**
88      * rendering hints used in drawing. Anti-aliasing is on
89      * by default
90      */
910    protected Map renderingHints = new HashMap();
92         
93     /**
94      * pluggable support for picking graph elements by
95      * finding them based on their coordinates. Typically
96      * used in mouse events.
97      */
98     protected PickSupport pickSupport;
99     
100     /**
101      * holds the state of which elements of the graph are
102      * currently 'picked'
103      */
104     protected PickedState pickedState;
105     
106     /**
107      * a listener used to cause pick events to result in
108      * repaints, even if they come from another view
109      */
110     protected ItemListener pickEventListener;
111     
112     /**
113      * an offscreen image to render the graph
114      * Used if doubleBuffered is set to true
115      */
116     protected BufferedImage offscreen;
117     
118     /**
119      * graphics context for the offscreen image
120      * Used if doubleBuffered is set to true
121      */
122     protected Graphics2D offscreenG2d;
123     
124     /**
125      * user-settable choice to use the offscreen image
126      * or not. 'false' by default
127      */
128     protected boolean doubleBuffered;
129     
130     /**
131      * Provides support for mutating the AffineTransform that
132      * is supplied to the rendering Graphics2D
133      */
1340    protected MutableTransformer viewTransformer =
135         new MutableAffineTransformer(new AffineTransform());
136     
1370    protected MutableTransformer layoutTransformer =
138         new MutableAffineTransformer(new AffineTransform());
139     
140     /**
141      * a collection of user-implementable functions to render under
142      * the topology (before the graph is rendered)
143      */
1440    protected List preRenderers = new ArrayList();
145     
146     /**
147      * a collection of user-implementable functions to render over the
148      * topology (after the graph is rendered)
149      */
1500    protected List postRenderers = new ArrayList();
151     
152     /**
153      * provides MouseListener, MouseMotionListener, and MouseWheelListener
154      * events to the graph
155      */
156     protected GraphMouse graphMouse;
157     
158     /**
159      * if true, then when the View is resized, the current Layout
160      * is resized to the same size.
161      */
162 // protected boolean lockLayoutToViewSize;
163     
1640    protected Map locationMap = new HashMap();
165  
166     /**
167      * Create an instance with passed parameters.
168      *
169      * @param layout The Layout to apply, with its associated Graph
170      * @param renderer The Renderer to draw it with
171      */
172     public VisualizationViewer(Layout layout, Renderer renderer) {
1730        this(new DefaultVisualizationModel(layout), renderer);
1740    }
175     
176     /**
177      * Create an instance with passed parameters.
178      *
179      * @param layout The Layout to apply, with its associated Graph
180      * @param renderer The Renderer to draw it with
181      * @param preferredSize the preferred size of this View
182      */
183     public VisualizationViewer(Layout layout, Renderer renderer, Dimension preferredSize) {
1840        this(new DefaultVisualizationModel(layout, preferredSize), renderer, preferredSize);
1850    }
186     
187     /**
188      * Create an instance with passed parameters.
189      *
190      * @param model
191      * @param renderer
192      */
193     public VisualizationViewer(VisualizationModel model, Renderer renderer) {
1940        this(model, renderer, new Dimension(600,600));
1950    }
196     /**
197      * Create an instance with passed parameters.
198      *
199      * @param model
200      * @param renderer
201      * @param preferredSize initial preferred size of the view
202      */
203     public VisualizationViewer(VisualizationModel model, Renderer renderer,
2040            Dimension preferredSize) {
2050        this.model = model;
2060        model.addChangeListener(this);
2070        setDoubleBuffered(false);
2080        this.addComponentListener(new VisualizationListener(this));
209  
2100        setPickSupport(new ClassicPickSupport());
2110        setPickedState(new MultiPickedState());
2120        setRenderer(renderer);
2130        renderer.setPickedKey(pickedState);
214         
2150        setPreferredSize(preferredSize);
2160        renderingHints.put(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
2170        initMouseClicker();
2180        scaleToLayout(model.getGraphLayout().getCurrentSize());
2190        this.layoutTransformer.addChangeListener(this);
2200        this.viewTransformer.addChangeListener(this);
2210    }
222     
223     /**
224      * set whether this class uses its offscreen image or not. If
225      * true, then doubleBuffering in the superclass is set to 'false'
226      */
227     public void setDoubleBuffered(boolean doubleBuffered) {
2280        this.doubleBuffered = doubleBuffered;
2290    }
230     
231     /**
232      * whether this class uses double buffering. The superclass
233      * will be the opposite state.
234      */
235     public boolean isDoubleBuffered() {
2360        return doubleBuffered;
237     }
238     
239     /**
240      * Ensure that, if doubleBuffering is enabled, the offscreen
241      * image buffer exists and is the correct size.
242      * @param d
243      */
244     protected void checkOffscreenImage(Dimension d) {
2450        if(doubleBuffered) {
2460            if(offscreen == null || offscreen.getWidth() != d.width || offscreen.getHeight() != d.height) {
2470                offscreen = new BufferedImage(d.width, d.height, BufferedImage.TYPE_INT_ARGB);
2480                offscreenG2d = offscreen.createGraphics();
249             }
250         }
2510    }
252     
253     /**
254      * @return Returns the model.
255      */
256     public VisualizationModel getModel() {
2570        return model;
258     }
259     /**
260      * @param model The model to set.
261      */
262     public void setModel(VisualizationModel model) {
2630        this.model = model;
2640    }
265     /**
266      * In response to changes from the model, repaint the
267      * view, then fire an event to any listeners.
268      * Examples of listeners are the GraphZoomScrollPane and
269      * the BirdsEyeVisualizationViewer
270      */
271     public void stateChanged(ChangeEvent e) {
2720        repaint();
2730        fireStateChanged();
2740    }
275     
276     /**
277      * Creates a default mouseClicker behavior: a default.
278      * @see GraphMouseImpl
279      * @deprecated replaced by setGraphMouse()
280      */
281     protected void initMouseClicker() {
282         // GraphMouseImpl will give original behavior
2830        setGraphMouse(new GraphMouseImpl() );
2840    }
285     
286     /**
287      * convenience pass-thru to model
288      * @param scb
289      */
290     public void setTextCallback(StatusCallback scb) {
2910        model.setTextCallback(scb);
2920    }
293     
294     /**
295      * a setter for the GraphMouse. This will remove any
296      * previous GraphMouse (including the one that
297      * is added in the initMouseClicker method.
298      * @param graphMouse new value
299      */
300     public void setGraphMouse(GraphMouse graphMouse) {
3010        this.graphMouse = graphMouse;
3020        MouseListener[] ml = getMouseListeners();
3030        for(int i=0; i<ml.length; i++) {
3040            if(ml[i] instanceof GraphMouse) {
3050                removeMouseListener(ml[i]);
306             }
307         }
3080        MouseMotionListener[] mml = getMouseMotionListeners();
3090        for(int i=0; i<mml.length; i++) {
3100            if(mml[i] instanceof GraphMouse) {
3110                removeMouseMotionListener(mml[i]);
312             }
313         }
3140        MouseWheelListener[] mwl = getMouseWheelListeners();
3150        for(int i=0; i<mwl.length; i++) {
3160            if(mwl[i] instanceof GraphMouse) {
3170                removeMouseWheelListener(mwl[i]);
318             }
319         }
3200        addMouseListener(graphMouse);
3210        addMouseMotionListener(graphMouse);
3220        addMouseWheelListener(graphMouse);
3230    }
324     
325     /**
326      * @return the current <code>GraphMouse</code>
327      */
328     public GraphMouse getGraphMouse() {
3290        return graphMouse;
330     }
331  
332     /**
333      * Sets the showing Renderer to be the input Renderer. Also
334      * tells the Renderer to refer to this visualizationviewer
335      * as a PickedKey. (Because Renderers maintain a small
336      * amount of state, such as the PickedKey, it is important
337      * to create a separate instance for each VV instance.)
338      */
339     public void setRenderer(Renderer r) {
3400        this.renderer = r;
3410        if(renderer instanceof PluggableRenderer) {
3420            PluggableRenderer pr = (PluggableRenderer)renderer;
3430            pr.setScreenDevice(this);
3440            pr.setViewTransformer(getViewTransformer());
345             
3460            if(pickSupport instanceof ShapePickSupport) {
3470                ((ShapePickSupport)pickSupport).setHasShapes((HasShapeFunctions)renderer);
348             }
349         }
350         
3510        r.setPickedKey(pickedState);
3520        repaint();
3530    }
354     
355     /**
356      * Returns the renderer used by this instance.
357      */
358     public Renderer getRenderer() {
3590        return renderer;
360     }
361  
362     /**
363      * Removes the current graph layout, and adds a new one.
364      * @param layout the new layout to set
365      */
366     public void setGraphLayout(Layout layout) {
3670        setGraphLayout(layout, true);
3680    }
369     /**
370      * Removes the current graph layout, and adds a new one,
371      * optionally re-scaling the view to show the entire layout
372      * @param layout the new layout to set
373      * @param scaleToLayout whether to scale the view to show the whole layout
374      */
375     public void setGraphLayout(Layout layout, boolean scaleToLayout) {
376  
3770        Dimension viewSize = getSize();
3780        if(viewSize.width <= 0 || viewSize.height <= 0) {
3790            viewSize = getPreferredSize();
380         }
3810        model.setGraphLayout(layout, viewSize);
3820        if(scaleToLayout) scaleToLayout(layout.getCurrentSize());
3830    }
384     
385     protected void scaleToLayout(Dimension layoutSize) {
3860        Dimension viewSize = getSize();
3870        if(viewSize.width == 0 || viewSize.height == 0) {
3880            viewSize = getPreferredSize();
389         }
3900        float scalex = (float)viewSize.width/layoutSize.width;
3910        float scaley = (float)viewSize.height/layoutSize.height;
3920        float scale = 1;
3930        if(scalex - 1 < scaley - 1) {
3940                scale = scalex;
395         } else {
3960                scale = scaley;
397         }
398         // set scale to show the entire graph layout
3990        viewTransformer.setScale(scale, scale, new Point2D.Float());
4000    }
401     
402     /**
403      * Returns the current graph layout.
404      * Passes thru to the model
405      */
406     public Layout getGraphLayout() {
4070            return model.getGraphLayout();
408     }
409     
410     /**
411      * This is the interface for adding a mouse listener. The GEL
412      * will be called back with mouse clicks on vertices.
413      * @param gel
414      */
415     public void addGraphMouseListener( GraphMouseListener gel ) {
4160        addMouseListener( new MouseListenerTranslator( gel, this ));
4170    }
418     
419     /**
420      * Pre-relaxes and starts a visRunner thread
421      * Passes thru to the model
422      */
423     public synchronized void init() {
4240        model.init();
4250    }
426  
427     /**
428      * Restarts layout, then calls init();
429      * passes thru to the model
430      */
431     public synchronized void restart() {
4320        model.restart();
4330    }
434  
435     /**
436      *
437      * @see javax.swing.JComponent#setVisible(boolean)
438      */
439     public void setVisible(boolean aFlag) {
4400        super.setVisible(aFlag);
4410        model.getGraphLayout().resize(this.getSize());
4420    }
443  
444     /**
445      * convenience pass-thru to the model
446      */
447     public void prerelax() {
4480        model.prerelax();
4490    }
450  
451     /**
452      * convenience pass-thru to the model
453      */
454     protected synchronized void start() {
4550        model.start();
4560    }
457  
458     /**
459      * convenience pass-thru to the model
460      *
461      */
462     public synchronized void suspend() {
4630        model.suspend();
4640    }
465  
466     /**
467      * convenience pass-thru to the model
468      *
469      */
470     public synchronized void unsuspend() {
4710        model.unsuspend();
4720    }
473  
474     /**
475      * @deprecated Use <code>getPickedState.isPicked(e)</code>.
476      */
477     public boolean isPicked(Vertex v) {
4780        return pickedState.isPicked(v);
479     }
480     
481     /**
482      * @deprecated Use <code>getPickedState.isPicked(e)</code>.
483      */
484     public boolean isPicked(Edge e) {
4850        return pickedState.isPicked(e);
486     }
487     
488     /**
489      * @deprecated Use <code>getPickedState.pick(picked, b)</code>.
490      */
491     protected void pick(Vertex picked, boolean b)
492     {
4930        pickedState.pick(picked, b);
4940    }
495  
4960    long[] relaxTimes = new long[5];
4970    long[] paintTimes = new long[5];
4980    int relaxIndex = 0;
4990    int paintIndex = 0;
500     double paintfps, relaxfps;
501     
502     /**
503      * Returns a flag that says whether the visRunner thread is running. If
504      * it is not, then you may need to restart the thread.
505      */
506     public boolean isVisRunnerRunning() {
5070        return model.isVisRunnerRunning();
508     }
509  
510     /**
511      * setter for the scale
512      * fires a PropertyChangeEvent with the AffineTransforms representing
513      * the previous and new values for scale and offset
514      * @deprecated access via getViewTransformer method
515      * @param scalex
516      * @param scaley
517      */
518     public void scale(double scalex, double scaley) {
5190        scale(scalex, scaley, null);
5200    }
521     /**
522      * have the model scale the graph with the passed parameters.
523      * If 'from' is null, use the center of this View as the
524      * center to scale from
525      * @deprecated access via getViewTransformer method
526      * @param scalex
527      * @param scaley
528      * @param from
529      */
530     public void scale(double scalex, double scaley, Point2D from) {
5310        if(from == null) {
5320            from = getCenter();
533         }
5340        viewTransformer.scale(scalex, scaley, from);
5350    }
536     
537     /**
538      * have the model replace the transform scale values with the
539      * passed parameters
540      * @deprecated access via getViewTransformer method
541      * @param scalex
542      * @param scaley
543      */
544     public void setScale(double scalex, double scaley) {
5450        setScale(scalex, scaley, null);
5460    }
547     
548     /**
549      * Have the model replace the transform scale values with the
550      * passed parameters. If 'from' is null, use this View's center
551      * as the center to scale from.
552      * @deprecated access via getViewTransformer method
553      * @param scalex
554      * @param scaley
555      */
556     public void setScale(double scalex, double scaley, Point2D from) {
5570        viewTransformer.setScale(scalex, scaley, from);
5580    }
559     
560     /**
561      * getter for scalex
562      * @deprecated access via getViewTransformer method
563      * @return scalex
564      */
565     public double getScaleX() {
5660        return viewTransformer.getScaleX();
567     }
568     
569     /**
570      * getter for scaley
571      * @deprecated access via getViewTransformer method
572      */
573     public double getScaleY() {
5740        return viewTransformer.getScaleY();
575     }
576     
577     /**
578      * getter for offsetx
579      * @deprecated use getTranslateX
580      */
581     public double getOffsetX() {
5820        return getTranslateX();
583     }
584     /**
585      * gets the translateX from the model
586      * @deprecated access via getViewTransformer method
587      * @return the translateX
588      */
589     public double getTranslateX() {
5900        return viewTransformer.getTranslateX();
591     }
592     
593     /**
594      * getter for offsety
595      * @deprecated use getTranslateY()
596      */
597     public double getOffsetY() {
5980        return getTranslateY();
599     }
600     
601     /**
602      * gets the translateY from the model
603      * @deprecated access via getViewTransformer method
604      * @return the translateY
605      */
606     public double getTranslateY() {
6070        return viewTransformer.getTranslateY();
608     }
609     
610     /**
611      * set the offset values that will be used in the
612      * translation component of the graph rendering transform.
613      * Changes the transform to the identity transform, then
614      * sets the translation conponents to the passed values
615      * Fires a PropertyChangeEvent with the AffineTransforms representing
616      * the previous and new values for the transform
617      * @deprecated use setTranslate(double, offset, double offset)
618      * @param offsetx
619      * @param offsety
620      */
621     public void setOffset(double offsetx, double offsety) {
6220        setTranslate(offsetx, offsety);
6230    }
624     
625     /**
626      * sets the translate x,y in the model
627      * previous translate values are lost
628      * @deprecated access via getViewTransformer method
629      * @param tx
630      * @param ty
631      */
632     public void setTranslate(double tx, double ty) {
6330        viewTransformer.setTranslate(tx, ty);
6340    }
635     
636     /**
637      * Translates the model's current transform by tX and ty.
638      * @deprecated access via getViewTransformer method
639      */
640     public void translate(double tx, double ty) {
6410        viewTransformer.translate(tx, ty);
6420    }
643     
644     /**
645      * Transform the mouse point with the inverse transform
646      * of the VisualizationViewer. This maps from screen coordinates
647      * to graph coordinates.
648      * @param p the point to transform (typically, a mouse point)
649      * @return a transformed Point2D
650      */
651     public Point2D inverseTransform(Point2D p) {
6520        return layoutTransformer.inverseTransform(inverseViewTransform(p));
653     }
654     
655     public Point2D inverseViewTransform(Point2D p) {
6560        return viewTransformer.inverseTransform(p);
657     }
658  
659     public Point2D inverseLayoutTransform(Point2D p) {
6600        return layoutTransformer.inverseTransform(p);
661     }
662  
663     /**
664      * Transform the mouse point with the current transform
665      * of the VisualizationViewer. This maps from graph coordinates
666      * to screen coordinates.
667      * @param p the point to transform
668      * @return a transformed Point2D
669      */
670     public Point2D transform(Point2D p) {
671         // transform with vv transform
6720        return viewTransformer.transform(layoutTransform(p));
673     }
674     
675     public Point2D viewTransform(Point2D p) {
6760        return viewTransformer.transform(p);
677     }
678     
679     public Point2D layoutTransform(Point2D p) {
6800        return layoutTransformer.transform(p);
681     }
682     
683     /**
684      * @param transformer The transformer to set.
685      */
686     public void setViewTransformer(MutableTransformer transformer) {
6870        this.viewTransformer.removeChangeListener(this);
6880        this.viewTransformer = transformer;
6890        this.viewTransformer.addChangeListener(this);
6900        if(renderer instanceof PluggableRenderer) {
6910            ((PluggableRenderer)renderer).setViewTransformer(transformer);
692         }
6930    }
694  
695     public void setLayoutTransformer(MutableTransformer transformer) {
6960        this.layoutTransformer.removeChangeListener(this);
6970        this.layoutTransformer = transformer;
6980        this.layoutTransformer.addChangeListener(this);
6990    }
700  
701     public MutableTransformer getViewTransformer() {
7020        return viewTransformer;
703     }
704  
705     public MutableTransformer getLayoutTransformer() {
7060        return layoutTransformer;
707     }
708  
709     /**
710      * @return Returns the renderingHints.
711      */
712     public Map getRenderingHints() {
7130        return renderingHints;
714     }
715     /**
716      * @param renderingHints The renderingHints to set.
717      */
718     public void setRenderingHints(Map renderingHints) {
7190        this.renderingHints = renderingHints;
7200    }
721     
722     protected void paintComponent(Graphics g) {
7230        super.paintComponent(g);
724  
7250        checkOffscreenImage(getSize());
7260        model.start();
727  
7280        Graphics2D g2d = (Graphics2D)g;
7290        if(doubleBuffered) {
7300            renderGraph(offscreenG2d);
7310            g2d.drawImage(offscreen, null, 0, 0);
732         } else {
7330            renderGraph(g2d);
734         }
7350    }
736     
737     protected void renderGraph(Graphics2D g2d) {
738  
7390        Layout layout = model.getGraphLayout();
740  
7410        g2d.setRenderingHints(renderingHints);
742         
7430        long start = System.currentTimeMillis();
744         
745         // the size of the VisualizationViewer
7460        Dimension d = getSize();
747         
748         // clear the offscreen image
7490        g2d.setColor(getBackground());
7500        g2d.fillRect(0,0,d.width,d.height);
751  
7520        AffineTransform oldXform = g2d.getTransform();
7530        AffineTransform newXform = new AffineTransform(oldXform);
7540        newXform.concatenate(viewTransformer.getTransform());
755         
7560        g2d.setTransform(newXform);
757  
758         // if there are preRenderers set, paint them
7590        for(Iterator iterator=preRenderers.iterator(); iterator.hasNext(); ) {
7600            Paintable paintable = (Paintable)iterator.next();
7610            if(paintable.useTransform()) {
7620                paintable.paint(g2d);
763             } else {
7640                g2d.setTransform(oldXform);
7650                paintable.paint(g2d);
7660                g2d.setTransform(newXform);
767             }
768         }
769         
7700        locationMap.clear();
771         
772         // paint all the edges
773         try {
7740        for (Iterator iter = layout.getGraph().getEdges().iterator();
7750        iter.hasNext();
776         ) {
7770            Edge e = (Edge) iter.next();
7780            Vertex v1 = (Vertex) e.getEndpoints().getFirst();
7790            Vertex v2 = (Vertex) e.getEndpoints().getSecond();
780             
7810            Point2D p = (Point2D) locationMap.get(v1);
7820            if(p == null) {
783                 
7840                p = layout.getLocation(v1);
7850                p = layoutTransformer.transform(p);
7860                locationMap.put(v1, p);
787             }
7880            Point2D q = (Point2D) locationMap.get(v2);
7890            if(q == null) {
7900                q = layout.getLocation(v2);
7910                q = layoutTransformer.transform(q);
7920                locationMap.put(v2, q);
793             }
794  
7950            if(p != null && q != null) {
7960                renderer.paintEdge(
797                         g2d,
798                         e,
799                         (int) p.getX(),
800                         (int) p.getY(),
801                         (int) q.getX(),
802                         (int) q.getY());
803             }
804         }
8050        } catch(ConcurrentModificationException cme) {
8060            repaint();
8070        }
808         
809         // paint all the vertices
810         try {
8110        for (Iterator iter = layout.getGraph().getVertices().iterator();
8120        iter.hasNext();
813         ) {
814             
8150            Vertex v = (Vertex) iter.next();
8160            Point2D p = (Point2D) locationMap.get(v);
8170            if(p == null) {
8180                p = layout.getLocation(v);
8190                p = layoutTransformer.transform(p);
8200                locationMap.put(v, p);
821             }
8220            if(p != null) {
8230                renderer.paintVertex(
824                         g2d,
825                         v,
826                         (int) p.getX(),
827                         (int) p.getY());
828             }
829         }
8300        } catch(ConcurrentModificationException cme) {
8310            repaint();
8320        }
833         
8340        long delta = System.currentTimeMillis() - start;
8350        paintTimes[paintIndex++] = delta;
8360        paintIndex = paintIndex % paintTimes.length;
8370        paintfps = average(paintTimes);
838         
839         // if there are postRenderers set, do it
8400        for(Iterator iterator=postRenderers.iterator(); iterator.hasNext(); ) {
8410            Paintable paintable = (Paintable)iterator.next();
8420            if(paintable.useTransform()) {
8430                paintable.paint(g2d);
844             } else {
8450                g2d.setTransform(oldXform);
8460                paintable.paint(g2d);
8470                g2d.setTransform(newXform);
848             }
849         }
8500        g2d.setTransform(oldXform);
8510    }
852  
853     /**
854      * Returns the double average of a number of long values.
855      * @param paintTimes an array of longs
856      * @return the average of the doubles
857      */
858     protected double average(long[] paintTimes) {
8590        double l = 0;
8600        for (int i = 0; i < paintTimes.length; i++) {
8610            l += paintTimes[i];
862         }
8630        return l / paintTimes.length;
864     }
865  
866     /**
867      * VisualizationListener reacts to changes in the size of the
868      * VisualizationViewer. When the size changes, it ensures
869      * that the offscreen image is sized properly.
870      * If the layout is locked to this view size, then the layout
871      * is also resized to be the same as the view size.
872      *
873      *
874      */
875     protected class VisualizationListener extends ComponentAdapter {
876         protected VisualizationViewer vv;
877         public VisualizationListener(VisualizationViewer vv) {
878             this.vv = vv;
879         }
880  
881         /**
882          * create a new offscreen image for the graph
883          * whenever the window is resied
884          */
885         public void componentResized(ComponentEvent e) {
886             Dimension d = vv.getSize();
887             if(d.width <= 0 || d.height <= 0) return;
888             checkOffscreenImage(d);
889         // if(getLockLayoutToViewSize()) {
890                 // model.resizeLayout(vv.getSize());
891         // }
892                 repaint();
893         }
894     }
895  
896     /**
897      * convenience pass-thru to model
898      */
899     public synchronized void stop() {
9000        model.stop();
9010    }
902  
903     /**
904      * sets the tooltip listener to the user's defined implementation
905      * of ToolTipListener
906      * @param listener the listener to ser
907      */
908     public void setToolTipListener(ToolTipListener listener) {
9090        if(listener instanceof ToolTipFunction) {
9100            setToolTipFunction((ToolTipFunction)listener);
911         } else {
9120            setToolTipFunction(new ToolTipListenerWrapper(listener));
913         }
9140    }
915  
916     public void setToolTipFunction(ToolTipFunction toolTipFunction) {
9170        this.toolTipFunction = toolTipFunction;
9180        ToolTipManager.sharedInstance().registerComponent(this);
9190    }
920     /**
921      * called by the superclass to display tooltips
922      */
923     public String getToolTipText(MouseEvent event) {
9240        if(toolTipFunction != null) {
9250            if(toolTipFunction instanceof ToolTipListenerWrapper) {
9260                return toolTipFunction.getToolTipText(event);
927             }
9280            Point2D p = inverseViewTransform(event.getPoint());
9290            Vertex vertex = pickSupport.getVertex(p.getX(), p.getY());
9300            if(vertex != null && willRender(vertex)) {
9310                return toolTipFunction.getToolTipText(vertex);
932             }
9330            Edge edge = pickSupport.getEdge(p.getX(), p.getY());
9340            if(edge != null && willRender(edge)) {
9350                return toolTipFunction.getToolTipText(edge);
936             }
9370            return toolTipFunction.getToolTipText(event);
938         }
9390        return super.getToolTipText(event);
940     }
941     
942     private boolean willRender(Vertex v) {
9430        if(renderer instanceof PluggableRenderer) {
9440            Predicate vip = ((PluggableRenderer)renderer).getVertexIncludePredicate();
9450            return vip == null || vip.evaluate(v) == true;
946           }
9470        return true;
948     }
949  
950     private boolean willRender(Edge e) {
9510        if(renderer instanceof PluggableRenderer) {
9520            Predicate eip = ((PluggableRenderer)renderer).getEdgeIncludePredicate();
9530            Pair endpoints = e.getEndpoints();
9540            boolean edgeAnswer = eip == null || eip.evaluate(e);
9550            boolean endpointAnswer = willRender((Vertex)endpoints.getFirst()) &&
956                 willRender((Vertex)endpoints.getSecond());
9570            return edgeAnswer && endpointAnswer;
958           }
9590        return true;
960     }
961  
962     /**
963      * The interface for the tool tip listener. Implement this
964      * interface to add custom tool tip to the graph elements.
965      * See sample code for examples
966      */
967     public interface ToolTipListener {
968             String getToolTipText(MouseEvent event);
969     }
970     
971     /**
972      * used internally to wrap any legacy ToolTipListener
973      * implementations so they can be used as a ToolTipFunction
974      * @author Tom Nelson - RABA Technologies
975      *
976      *
977      */
978     protected static class ToolTipListenerWrapper extends ToolTipFunctionAdapter {
979         ToolTipListener listener;
980         public ToolTipListenerWrapper(ToolTipListener listener) {
981             this.listener = listener;
982         }
983         public String getToolTipText(MouseEvent e) {
984             return listener.getToolTipText(e);
985         }
986     }
987     
988     /**
989      * an interface for the preRender and postRender
990      */
991     public interface Paintable {
992         public void paint(Graphics g);
993         public boolean useTransform();
994     }
995  
996     /**
997      * a convenience type to represent a class that
998      * processes all types of mouse events for the graph
999      */
1000     public interface GraphMouse extends MouseListener, MouseMotionListener, MouseWheelListener {}
1001     
1002     /**
1003      * this is the original GraphMouse class, renamed to use GraphMouse as the interface name,
1004      * and updated to correctly apply the vv transform to the point point
1005      *
1006      */
1007     protected final class GraphMouseImpl extends MouseAdapter implements GraphMouse {
1008         protected Vertex picked;
1009         
1010         public void mousePressed(MouseEvent e) {
1011             
1012             Point2D p = inverseViewTransform(e.getPoint());
1013  
1014             Vertex v = pickSupport.getVertex(p.getX(), p.getY());
1015             if (v == null) {
1016                 return;
1017             }
1018             picked = v;
1019             pick(picked, true);
1020             model.getGraphLayout().forceMove(picked, p.getX(), p.getY());
1021             repaint();
1022         }
1023         public void mouseReleased(MouseEvent e) {
1024             if (picked == null)
1025                 return;
1026             pick(picked, false);
1027             picked = null;
1028             repaint();
1029         }
1030         public void mouseDragged(MouseEvent e) {
1031             if (picked == null)
1032                 return;
1033             Point2D p = inverseViewTransform(e.getPoint());
1034  
1035             model.getGraphLayout().forceMove(picked, p.getX(), p.getY());
1036             repaint();
1037         }
1038         
1039         public void mouseMoved(MouseEvent e) {
1040             return;
1041         }
1042         /**
1043          * @see java.awt.event.MouseWheelListener#mouseWheelMoved(java.awt.event.MouseWheelEvent)
1044          */
1045         public void mouseWheelMoved(MouseWheelEvent e) {
1046             return;
1047         }
1048     }
1049     
1050     /**
1051      * @param paintable The paintable to add.
1052      */
1053     public void addPreRenderPaintable(Paintable paintable) {
10540        if(preRenderers == null) {
10550            preRenderers = new ArrayList();
1056         }
10570        preRenderers.add(paintable);
10580    }
1059     
1060     /**
1061      * @param paintable The paintable to remove.
1062      */
1063     public void removePreRenderPaintable(Paintable paintable) {
10640        if(preRenderers != null) {
10650            preRenderers.remove(paintable);
1066         }
10670    }
1068     
1069     /**
1070      * @param paintable The paintable to add.
1071      */
1072     public void addPostRenderPaintable(Paintable paintable) {
10730        if(postRenderers == null) {
10740            postRenderers = new ArrayList();
1075         }
10760        postRenderers.add(paintable);
10770    }
1078     
1079     /**
1080      * @param paintable The paintable to remove.
1081      */
1082    public void removePostRenderPaintable(Paintable paintable) {
10830        if(postRenderers != null) {
10840            postRenderers.remove(paintable);
1085         }
10860    }
1087  
1088     /**
1089      * Adds a <code>ChangeListener</code>.
1090      * @param l the listener to be added
1091      */
1092     public void addChangeListener(ChangeListener l) {
10930        changeSupport.addChangeListener(l);
10940    }
1095     
1096     /**
1097      * Removes a ChangeListener.
1098      * @param l the listener to be removed
1099      */
1100     public void removeChangeListener(ChangeListener l) {
11010        changeSupport.removeChangeListener(l);
11020    }
1103     
1104     /**
1105      * Returns an array of all the <code>ChangeListener</code>s added
1106      * with addChangeListener().
1107      *
1108      * @return all of the <code>ChangeListener</code>s added or an empty
1109      * array if no listeners have been added
1110      */
1111     public ChangeListener[] getChangeListeners() {
11120        return changeSupport.getChangeListeners();
1113     }
1114  
1115     /**
1116      * Notifies all listeners that have registered interest for
1117      * notification on this event type. The event instance
1118      * is lazily created.
1119      * @see EventListenerList
1120      */
1121     public void fireStateChanged() {
11220        changeSupport.fireStateChanged();
11230    }
1124     
1125     /**
1126      * @return Returns the pickedState.
1127      */
1128     public PickedState getPickedState() {
11290        return pickedState;
1130     }
1131     /**
1132      * @param pickedState The pickedState to set.
1133      */
1134     public void setPickedState(PickedState pickedState) {
11350        if(pickEventListener != null && this.pickedState != null) {
11360            this.pickedState.removeItemListener(pickEventListener);
1137         }
11380        this.pickedState = pickedState;
11390        if(renderer != null) {
11400            renderer.setPickedKey(pickedState);
1141         }
11420        if(pickEventListener == null) {
11430            pickEventListener = new ItemListener() {
1144  
1145                 public void itemStateChanged(ItemEvent e) {
1146                     repaint();
1147                 }
1148             };
1149         }
11500        pickedState.addItemListener(pickEventListener);
11510    }
1152     
1153     /**
1154      * @return Returns the pickSupport.
1155      */
1156     public PickSupport getPickSupport() {
11570        return pickSupport;
1158     }
1159     /**
1160      * @param pickSupport The pickSupport to set.
1161      */
1162     public void setPickSupport(PickSupport pickSupport) {
11630        this.pickSupport = pickSupport;
11640        this.pickSupport.setHasGraphLayout(this);
11650        if(pickSupport instanceof ShapePickSupport && renderer instanceof HasShapeFunctions) {
11660            ((ShapePickSupport)pickSupport).setHasShapes((HasShapeFunctions)renderer);
11670            ((ShapePickSupport)pickSupport).setLayoutTransformer(this);
1168         }
11690    }
1170     
1171     public Point2D getCenter() {
11720        Dimension d = getSize();
11730        return new Point2D.Float(d.width/2, d.height/2);
1174     }
1175 }

this report was generated by version 1.0.5 of jcoverage.
visit www.jcoverage.com for updates.

copyright © 2003, jcoverage ltd. all rights reserved.
Java is a trademark of Sun Microsystems, Inc. in the United States and other countries.