1
2
3
4
5
6
7
8
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
35
36
37
38
39
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 }