2 * Copyright (c) 2003, the JUNG Project and the Regents of the University of
3 * California All rights reserved.
5 * This software is open-source under the BSD license; see either "license.txt"
6 * or http://jung.sourceforge.net/license.txt for a description.
11 package edu.uci.ics.jung.algorithms.layout;
13 import java.awt.Dimension;
14 import java.awt.geom.AffineTransform;
15 import java.awt.geom.Point2D;
16 import java.util.HashMap;
19 import org.apache.commons.collections15.Transformer;
21 import edu.uci.ics.jung.algorithms.util.IterativeContext;
22 import edu.uci.ics.jung.graph.Graph;
25 * A {@code Layout} implementation that combines
26 * multiple other layouts so that they may be manipulated
27 * as one layout. The relaxer thread will step each layout
30 * @author Tom Nelson - tomnelson@dev.java.net
32 * @param <V> the vertex type
33 * @param <E> the edge type
35 public class AggregateLayout<V, E> implements Layout<V,E>, IterativeContext {
37 protected Layout<V,E> delegate;
38 protected Map<Layout<V,E>,Point2D> layouts = new HashMap<Layout<V,E>,Point2D>();
41 * Creates an instance backed by the specified {@code delegate}.
44 public AggregateLayout(Layout<V, E> delegate) {
45 this.delegate = delegate;
49 * @return the delegate
51 public Layout<V, E> getDelegate() {
56 * @param delegate the delegate to set
58 public void setDelegate(Layout<V, E> delegate) {
59 this.delegate = delegate;
63 * adds the passed layout as a sublayout, also specifying
64 * the center of where this sublayout should appear
68 public void put(Layout<V,E> layout, Point2D center) {
69 layouts.put(layout,center);
73 * Returns the center of the passed layout.
75 * @return the center of the passed layout
77 public Point2D get(Layout<V,E> layout) {
78 return layouts.get(layout);
82 * Removes {@code layout} from this instance.
84 public void remove(Layout<V,E> layout) {
85 layouts.remove(layout);
89 * Removes all layouts from this instance.
91 public void removeAll() {
96 * Returns the graph for which this layout is defined.
97 * @return the graph for which this layout is defined
98 * @see edu.uci.ics.jung.algorithms.layout.Layout#getGraph()
100 public Graph<V, E> getGraph() {
101 return delegate.getGraph();
105 * Returns the size of the underlying layout.
106 * @return the size of the underlying layout
107 * @see edu.uci.ics.jung.algorithms.layout.Layout#getSize()
109 public Dimension getSize() {
110 return delegate.getSize();
115 * @see edu.uci.ics.jung.algorithms.layout.Layout#initialize()
117 public void initialize() {
118 delegate.initialize();
119 for(Layout<V,E> layout : layouts.keySet()) {
125 * Override to test if the passed vertex is locked in
126 * any of the layouts.
128 * @return true if v is locked in any of the layouts, and false otherwise
129 * @see edu.uci.ics.jung.algorithms.layout.Layout#isLocked(java.lang.Object)
131 public boolean isLocked(V v) {
132 boolean locked = false;
133 for(Layout<V,E> layout : layouts.keySet()) {
134 locked |= layout.isLocked(v);
136 locked |= delegate.isLocked(v);
141 * override to lock or unlock this vertex in any layout with
142 * a subgraph containing it
145 * @see edu.uci.ics.jung.algorithms.layout.Layout#lock(java.lang.Object, boolean)
147 public void lock(V v, boolean state) {
148 for(Layout<V,E> layout : layouts.keySet()) {
149 if(layout.getGraph().getVertices().contains(v)) {
150 layout.lock(v, state);
153 delegate.lock(v, state);
158 * @see edu.uci.ics.jung.algorithms.layout.Layout#reset()
160 public void reset() {
161 for(Layout<V,E> layout : layouts.keySet()) {
169 * @see edu.uci.ics.jung.algorithms.layout.Layout#setGraph(edu.uci.ics.jung.graph.Graph)
171 public void setGraph(Graph<V, E> graph) {
172 delegate.setGraph(graph);
177 * @see edu.uci.ics.jung.algorithms.layout.Layout#setInitializer(org.apache.commons.collections15.Transformer)
179 public void setInitializer(Transformer<V, Point2D> initializer) {
180 delegate.setInitializer(initializer);
186 * @see edu.uci.ics.jung.algorithms.layout.Layout#setLocation(java.lang.Object, java.awt.geom.Point2D)
188 public void setLocation(V v, Point2D location) {
189 boolean wasInSublayout = false;
190 for(Layout<V,E> layout : layouts.keySet()) {
191 if(layout.getGraph().getVertices().contains(v)) {
192 Point2D center = layouts.get(layout);
193 // transform by the layout itself, but offset to the
194 // center of the sublayout
195 Dimension d = layout.getSize();
198 AffineTransform.getTranslateInstance(-center.getX()+d.width/2,-center.getY()+d.height/2);
199 Point2D localLocation = at.transform(location, null);
200 layout.setLocation(v, localLocation);
201 wasInSublayout = true;
204 if(wasInSublayout == false && getGraph().getVertices().contains(v)) {
205 delegate.setLocation(v, location);
211 * @see edu.uci.ics.jung.algorithms.layout.Layout#setSize(java.awt.Dimension)
213 public void setSize(Dimension d) {
218 * Returns a map from each {@code Layout} instance to its center point.
220 public Map<Layout<V,E>,Point2D> getLayouts() {
225 * Returns the location of the vertex. The location is specified first
226 * by the sublayouts, and then by the base layout if no sublayouts operate
228 * @return the location of the vertex
229 * @see org.apache.commons.collections15.Transformer#transform(java.lang.Object)
231 public Point2D transform(V v) {
232 boolean wasInSublayout = false;
233 for(Layout<V,E> layout : layouts.keySet()) {
234 if(layout.getGraph().getVertices().contains(v)) {
235 wasInSublayout = true;
236 Point2D center = layouts.get(layout);
237 // transform by the layout itself, but offset to the
238 // center of the sublayout
239 Dimension d = layout.getSize();
241 AffineTransform.getTranslateInstance(center.getX()-d.width/2,
242 center.getY()-d.height/2);
243 return at.transform(layout.transform(v),null);
246 if(wasInSublayout == false) {
247 return delegate.transform(v);
254 * Check all sublayouts.keySet() and the delegate layout, returning
255 * done == true iff all are done.
257 public boolean done() {
259 for(Layout<V,E> layout : layouts.keySet()) {
260 if(layout instanceof IterativeContext) {
261 done &= ((IterativeContext)layout).done();
264 if(delegate instanceof IterativeContext) {
265 done &= ((IterativeContext)delegate).done();
271 * call step on any sublayout that is also an IterativeContext
275 for(Layout<V,E> layout : layouts.keySet()) {
276 if(layout instanceof IterativeContext) {
277 IterativeContext context = (IterativeContext)layout;
278 if(context.done() == false) {
283 if(delegate instanceof IterativeContext) {
284 IterativeContext context = (IterativeContext)delegate;
285 if(context.done() == false) {