View Javadoc
1   /*
2    * Copyright (c) 2005, The JUNG Authors
3    * All rights reserved.
4    *
5    * This software is open-source under the BSD license; see either "license.txt"
6    * or https://github.com/jrtom/jung/blob/master/LICENSE for a description.
7    *
8    * Created on Aug 23, 2005
9    */
10  
11  package edu.uci.ics.jung.visualization.layout;
12  
13  import java.awt.geom.Point2D;
14  import java.util.ArrayList;
15  import java.util.List;
16  
17  import javax.swing.event.ChangeListener;
18  
19  import com.google.common.base.Function;
20  import com.google.common.base.Functions;
21  import com.google.common.cache.CacheBuilder;
22  import com.google.common.cache.CacheLoader;
23  import com.google.common.cache.LoadingCache;
24  
25  import edu.uci.ics.jung.algorithms.layout.Layout;
26  import edu.uci.ics.jung.algorithms.layout.LayoutDecorator;
27  import edu.uci.ics.jung.algorithms.util.IterativeContext;
28  import edu.uci.ics.jung.graph.Graph;
29  import edu.uci.ics.jung.visualization.util.Caching;
30  import edu.uci.ics.jung.visualization.util.ChangeEventSupport;
31  import edu.uci.ics.jung.visualization.util.DefaultChangeEventSupport;
32  
33  /**
34   * A LayoutDecorator that fires ChangeEvents when certain methods 
35   * are called. Used to wrap a Layout so that the visualization
36   * components can be notified of changes.
37   * 
38   * @see LayoutDecorator
39   * @author Tom Nelson 
40   *
41   */
42  public class ObservableCachingLayout<V, E> extends LayoutDecorator<V,E> 
43  	implements ChangeEventSupport, Caching, LayoutEventSupport<V,E> {
44      
45      protected ChangeEventSupport changeSupport = new DefaultChangeEventSupport(this);
46      
47      protected LoadingCache<V, Point2D> locations;
48      
49      private List<LayoutChangeListener<V,E>> layoutChangeListeners = 
50      	new ArrayList<LayoutChangeListener<V,E>>();
51  
52      public ObservableCachingLayout(Layout<V, E> delegate) {
53      	super(delegate);
54  		Function<V, Point2D> chain = Functions.<V, Point2D, Point2D> compose(
55  				new Function<Point2D, Point2D>() {
56  					public Point2D apply(Point2D p) {
57  						return (Point2D) p.clone();
58  					}
59  				},
60  				delegate);
61  		this.locations = CacheBuilder.newBuilder().build(CacheLoader.from(chain));
62      }
63      
64      @Override
65      public void step() {
66      	super.step();
67      	fireStateChanged();
68      }
69  
70  	@Override
71      public void initialize() {
72  		super.initialize();
73  		fireStateChanged();
74  	}
75  	
76      @Override
77      public boolean done() {
78      	if(delegate instanceof IterativeContext) {
79      		return ((IterativeContext)delegate).done();
80      	}
81      	return true;
82      }
83  
84  
85  	@Override
86      public void setLocation(V v, Point2D location) {
87  		super.setLocation(v, location);
88  		fireStateChanged();
89  		fireLayoutChanged(v);
90  	}
91  
92      public void addChangeListener(ChangeListener l) {
93          changeSupport.addChangeListener(l);
94      }
95  
96      public void removeChangeListener(ChangeListener l) {
97          changeSupport.removeChangeListener(l);
98      }
99  
100     public ChangeListener[] getChangeListeners() {
101         return changeSupport.getChangeListeners();
102     }
103 
104     public void fireStateChanged() {
105         changeSupport.fireStateChanged();
106     }
107     
108     @Override
109     public void setGraph(Graph<V, E> graph) {
110         delegate.setGraph(graph);
111     }
112 
113 	public void clear() {
114 		this.locations.invalidateAll();
115 	}
116 
117 	public void init() {
118 	}
119 
120 	public Point2D apply(V v) {
121 		return locations.getUnchecked(v);
122 	}
123 
124 	private void fireLayoutChanged(V v) {
125 		LayoutEvent<V,E> evt = new LayoutEvent<V,E>(v, this.getGraph());
126 		for(LayoutChangeListener<V,E> listener : layoutChangeListeners) {
127 			listener.layoutChanged(evt);
128 		}
129 	}
130 	
131 	public void addLayoutChangeListener(LayoutChangeListener<V, E> listener) {
132 		layoutChangeListeners.add(listener);
133 		
134 	}
135 
136 	public void removeLayoutChangeListener(LayoutChangeListener<V, E> listener) {
137 		layoutChangeListeners.remove(listener);
138 		
139 	}
140 }