001: /*
002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003: *
004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
005: *
006: * The contents of this file are subject to the terms of either the GNU
007: * General Public License Version 2 only ("GPL") or the Common
008: * Development and Distribution License("CDDL") (collectively, the
009: * "License"). You may not use this file except in compliance with the
010: * License. You can obtain a copy of the License at
011: * http://www.netbeans.org/cddl-gplv2.html
012: * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
013: * specific language governing permissions and limitations under the
014: * License. When distributing the software, include this License Header
015: * Notice in each file and include the License file at
016: * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
017: * particular file as subject to the "Classpath" exception as provided
018: * by Sun in the GPL Version 2 section of the License file that
019: * accompanied this code. If applicable, add the following below the
020: * License Header, with the fields enclosed by brackets [] replaced by
021: * your own identifying information:
022: * "Portions Copyrighted [year] [name of copyright owner]"
023: *
024: * Contributor(s):
025: *
026: * The Original Software is NetBeans. The Initial Developer of the Original
027: * Software is Sun Microsystems, Inc. Portions Copyright 1997-2007 Sun
028: * Microsystems, Inc. All Rights Reserved.
029: *
030: * If you wish your version of this file to be governed by only the CDDL
031: * or only the GPL Version 2, indicate your decision by adding
032: * "[Contributor] elects to include this software in this distribution
033: * under the [CDDL or GPL Version 2] license." If you do not indicate a
034: * single choice of license, a recipient has the option to distribute
035: * your version of this file under either the CDDL, the GPL Version 2 or
036: * to extend the choice of license to its licensees as provided above.
037: * However, if you add GPL Version 2 code and therefore, elected the GPL
038: * Version 2 license, then the option applies only if the new code is
039: * made subject to such option by the copyright holder.
040: */
041: package org.netbeans.api.visual.graph.layout;
042:
043: import org.netbeans.api.visual.graph.GraphPinScene;
044: import org.netbeans.api.visual.graph.GraphScene;
045: import org.netbeans.api.visual.model.ObjectScene;
046: import org.netbeans.api.visual.widget.Widget;
047:
048: import java.util.Collection;
049: import java.util.ArrayList;
050: import java.awt.*;
051:
052: /**
053: * This class represents a graph-orinted layout.
054: * The layout is invoked using layoutGraph methods.
055: * The layoutNodes method could be called for resolving locations of a sub-set of all nodes.
056: * <p>
057: * Internally the invoked method creates an UniversalGraph from the scene in the arguments.
058: * Then it calls the particular (performGraphLayout or performNodesLayout) methods with the UniversalGraph as a parameter.
059: * These protected methods are implemented by the GraphLayout based class and performs particular layout using an UniversalGraph.
060: *
061: * @author David Kaspar
062: */
063: public abstract class GraphLayout<N, E> {
064:
065: private boolean animated = true;
066: private final ArrayList<GraphLayoutListener<N, E>> listeners = new ArrayList<GraphLayoutListener<N, E>>();
067:
068: /**
069: * Returns whether the layout uses animations.
070: * @return true if animated
071: */
072: public final boolean isAnimated() {
073: return animated;
074: }
075:
076: /**
077: * Sets whether the layout is animated.
078: * @param animated if true, then the layout is animated
079: */
080: public final void setAnimated(boolean animated) {
081: this .animated = animated;
082: }
083:
084: /**
085: * Adds a graph layout listener.
086: * @param listener the graph layout listener
087: */
088: public final void addGraphLayoutListener(
089: GraphLayoutListener<N, E> listener) {
090: synchronized (listeners) {
091: listeners.add(listener);
092: }
093: }
094:
095: /**
096: * Removes a graph layout listener.
097: * @param listener the graph layout listener
098: */
099: public final void removeGraphLayoutListener(
100: GraphLayoutListener<N, E> listener) {
101: synchronized (listeners) {
102: listeners.add(listener);
103: }
104: }
105:
106: /**
107: * Invokes graph-oriented layout on a GraphScene.
108: * @param graphScene the graph scene
109: */
110: public final void layoutGraph(GraphScene<N, E> graphScene) {
111: GraphLayoutListener<N, E>[] listeners = createListenersCopy();
112:
113: UniversalGraph<N, E> graph = UniversalGraph
114: .createUniversalGraph(graphScene);
115:
116: for (GraphLayoutListener<N, E> listener : listeners)
117: listener.graphLayoutStarted(graph);
118:
119: performGraphLayout(graph);
120:
121: for (GraphLayoutListener<N, E> listener : listeners)
122: listener.graphLayoutFinished(graph);
123: }
124:
125: @SuppressWarnings("unchecked")
126: private <N, E> GraphLayoutListener<N, E>[] createListenersCopy() {
127: GraphLayoutListener<N, E>[] listeners;
128: synchronized (this .listeners) {
129: listeners = this .listeners
130: .toArray(new GraphLayoutListener[this .listeners
131: .size()]);
132: }
133: return listeners;
134: }
135:
136: /**
137: * Invokes graph-oriented layout on a GraphPinScene.
138: * @param graphPinScene the graph pin scene
139: */
140: public final void layoutGraph(GraphPinScene<N, E, ?> graphPinScene) {
141: GraphLayoutListener<N, E>[] listeners = createListenersCopy();
142:
143: UniversalGraph<N, E> graph = UniversalGraph
144: .createUniversalGraph(graphPinScene);
145:
146: for (GraphLayoutListener<N, E> listener : listeners)
147: listener.graphLayoutStarted(graph);
148:
149: performGraphLayout(graph);
150:
151: for (GraphLayoutListener<N, E> listener : listeners)
152: listener.graphLayoutFinished(graph);
153: }
154:
155: /**
156: * Invokes resolving of locations for a collection of nodes in a GraphScene.
157: * @param graphScene the graph scene
158: * @param nodes the collection of nodes to resolve
159: */
160: public final void layoutNodes(GraphScene<N, E> graphScene,
161: Collection<N> nodes) {
162: GraphLayoutListener<N, E>[] listeners = createListenersCopy();
163:
164: UniversalGraph<N, E> graph = UniversalGraph
165: .createUniversalGraph(graphScene);
166:
167: for (GraphLayoutListener<N, E> listener : listeners)
168: listener.graphLayoutStarted(graph);
169:
170: performNodesLayout(graph, nodes);
171:
172: for (GraphLayoutListener<N, E> listener : listeners)
173: listener.graphLayoutFinished(graph);
174: }
175:
176: /**
177: * Invokes resolving of locations for a collection of nodes in a GraphPinScene.
178: * @param graphPinScene the graph pin scene
179: * @param nodes the collection of nodes to resolve
180: */
181: public final void layoutNodes(GraphPinScene<N, E, ?> graphPinScene,
182: Collection<N> nodes) {
183: GraphLayoutListener<N, E>[] listeners = createListenersCopy();
184:
185: UniversalGraph<N, E> graph = UniversalGraph
186: .createUniversalGraph(graphPinScene);
187:
188: for (GraphLayoutListener<N, E> listener : listeners)
189: listener.graphLayoutStarted(graph);
190:
191: performNodesLayout(graph, nodes);
192:
193: for (GraphLayoutListener<N, E> listener : listeners)
194: listener.graphLayoutFinished(graph);
195: }
196:
197: /**
198: * Should be called to set a new resolved preferred location of a node.
199: * @param graph the universal graph
200: * @param node the node with resolved location
201: * @param newPreferredLocation the new resolved location
202: */
203: protected final void setResolvedNodeLocation(
204: UniversalGraph<N, E> graph, N node,
205: Point newPreferredLocation) {
206: ObjectScene scene = graph.getScene();
207:
208: Widget widget = scene.findWidget(node);
209: if (widget == null)
210: return;
211:
212: Point previousPreferredLocation = widget.getPreferredLocation();
213:
214: if (animated)
215: scene.getSceneAnimator().animatePreferredLocation(widget,
216: newPreferredLocation);
217: else
218: widget.setPreferredLocation(newPreferredLocation);
219:
220: GraphLayoutListener<N, E>[] listeners = createListenersCopy();
221:
222: for (GraphLayoutListener<N, E> listener : listeners)
223: listener.nodeLocationChanged(graph, node,
224: previousPreferredLocation, newPreferredLocation);
225: }
226:
227: /**
228: * Implements and performs particular graph-oriented algorithm of a UniversalGraph.
229: * Call <code>GraphLayout.setResolvedNodeLocation</code> method for setting the resolved node location.
230: * @param graph the universal graph on which the layout should be performed
231: */
232: protected abstract void performGraphLayout(
233: UniversalGraph<N, E> graph);
234:
235: /**
236: * Implements and performs particular location resolution of a collection of nodes in a UniversalGraph.
237: * Call <code>GraphLayout.setResolvedNodeLocation</code> method for setting the resolved node location.
238: * @param graph the universal graph on which the nodes should be resolved
239: * @param nodes the collection of nodes to be resolved
240: */
241: protected abstract void performNodesLayout(
242: UniversalGraph<N, E> graph, Collection<N> nodes);
243:
244: }
|