View Javadoc
1   /*
2   * Copyright (c) 2003, The JUNG Authors 
3   *
4   * All rights reserved.
5   *
6   * This software is open-source under the BSD license; see either
7   * "license.txt" or
8   * https://github.com/jrtom/jung/blob/master/LICENSE for a description.
9   */
10  package edu.uci.ics.jung.visualization;
11  
12  import java.awt.Dimension;
13  
14  import javax.swing.event.ChangeEvent;
15  import javax.swing.event.ChangeListener;
16  import javax.swing.event.EventListenerList;
17  
18  import edu.uci.ics.jung.algorithms.layout.Layout;
19  import edu.uci.ics.jung.algorithms.layout.util.Relaxer;
20  import edu.uci.ics.jung.algorithms.layout.util.VisRunner;
21  import edu.uci.ics.jung.algorithms.util.IterativeContext;
22  import edu.uci.ics.jung.visualization.layout.ObservableCachingLayout;
23  import edu.uci.ics.jung.visualization.util.ChangeEventSupport;
24  import edu.uci.ics.jung.visualization.util.DefaultChangeEventSupport;
25  
26  /**
27   * The model containing state values for 
28   * visualizations of graphs. 
29   * Refactored and extracted from the 1.6.0 version of VisualizationViewer
30   * 
31   * @author Tom Nelson
32   */
33  public class DefaultVisualizationModel<V, E> implements VisualizationModel<V,E>, ChangeEventSupport {
34      
35      ChangeEventSupport changeSupport = new DefaultChangeEventSupport(this);
36  
37      /**
38  	 * manages the thread that applies the current layout algorithm
39  	 */
40  	protected Relaxer relaxer;
41  	
42  	/**
43  	 * the layout algorithm currently in use
44  	 */
45  	protected Layout<V,E> layout;
46  	
47  	/**
48  	 * listens for changes in the layout, forwards to the viewer
49  	 *
50  	 */
51      protected ChangeListener changeListener;
52      
53      /**
54       * 
55       * @param layout The Layout to apply, with its associated Graph
56       */
57  	public DefaultVisualizationModel(Layout<V,E> layout) {
58          this(layout, null);
59  	}
60      
61  	/**
62  	 * Create an instance with the specified layout and dimension.
63  	 * @param layout the layout to use
64  	 * @param d The preferred size of the View that will display this graph
65  	 */
66  	public DefaultVisualizationModel(Layout<V,E> layout, Dimension d) {
67          if(changeListener == null) {
68              changeListener = new ChangeListener() {
69                  public void stateChanged(ChangeEvent e) {
70                      fireStateChanged();
71                  }
72              };
73          }
74  		setGraphLayout(layout, d);
75  	}
76  	
77  	/**
78  	 * Removes the current graph layout, and adds a new one.
79  	 * @param layout   the new layout to use
80  	 * @param viewSize the size of the View that will display this layout
81  	 */
82  	public void setGraphLayout(Layout<V,E> layout, Dimension viewSize) {
83  		// remove listener from old layout
84  	    if(this.layout != null && this.layout instanceof ChangeEventSupport) {
85  	        ((ChangeEventSupport)this.layout).removeChangeListener(changeListener);
86          }
87  	    // set to new layout
88  	    if(layout instanceof ChangeEventSupport) {
89  	    	this.layout = layout;
90  	    } else {
91  	    	this.layout = new ObservableCachingLayout<V,E>(layout);
92  	    }
93  		
94  		((ChangeEventSupport)this.layout).addChangeListener(changeListener);
95  
96          if(viewSize == null) {
97              viewSize = new Dimension(600,600);
98          }
99  		Dimension layoutSize = layout.getSize();
100 		// if the layout has NOT been initialized yet, initialize its size
101 		// now to the size of the VisualizationViewer window
102 		if(layoutSize == null) {
103 		    layout.setSize(viewSize);
104         }
105         if(relaxer != null) {
106         	relaxer.stop();
107         	relaxer = null;
108         }
109         if(layout instanceof IterativeContext) {
110         	layout.initialize();
111             if(relaxer == null) {
112             	relaxer = new VisRunner((IterativeContext)this.layout);
113             	relaxer.prerelax();
114             	relaxer.relax();
115             }
116         }
117         fireStateChanged();
118 	}
119 
120 	/**
121 	 * set the graph Layout and if it is not already initialized, initialize
122 	 * it to the default VisualizationViewer preferred size of 600x600
123 	 */
124 	public void setGraphLayout(Layout<V,E> layout) {
125 	    setGraphLayout(layout, null);
126 	}
127 
128     /**
129 	 * Returns the current graph layout.
130 	 */
131 	public Layout<V,E> getGraphLayout() {
132 	        return layout;
133 	}
134 
135 	/**
136 	 * @return the relaxer
137 	 */
138 	public Relaxer getRelaxer() {
139 		return relaxer;
140 	}
141 
142 	/**
143 	 * @param relaxer the relaxer to set
144 	 */
145 	public void setRelaxer(VisRunner relaxer) {
146 		this.relaxer = relaxer;
147 	}
148 
149     /**
150      * Adds a <code>ChangeListener</code>.
151      * @param l the listener to be added
152      */
153     public void addChangeListener(ChangeListener l) {
154         changeSupport.addChangeListener(l);
155     }
156     
157     /**
158      * Removes a ChangeListener.
159      * @param l the listener to be removed
160      */
161     public void removeChangeListener(ChangeListener l) {
162         changeSupport.removeChangeListener(l);
163     }
164     
165     /**
166      * Returns an array of all the <code>ChangeListener</code>s added
167      * with addChangeListener().
168      *
169      * @return all of the <code>ChangeListener</code>s added or an empty
170      *         array if no listeners have been added
171      */
172     public ChangeListener[] getChangeListeners() {
173         return changeSupport.getChangeListeners();
174     }
175 
176     /**
177      * Notifies all listeners that have registered interest for
178      * notification on this event type.  The event instance 
179      * is lazily created.
180      * The primary listeners will be views that need to be repainted
181      * because of changes in this model instance
182      * @see EventListenerList
183      */
184     public void fireStateChanged() {
185         changeSupport.fireStateChanged();
186     }   
187     
188 }