~ubuntu-branches/ubuntu/quantal/netbeans/quantal

« back to all changes in this revision

Viewing changes to graph/lib/src/org/netbeans/api/visual/graph/GraphPinScene.java

  • Committer: Bazaar Package Importer
  • Author(s): Marek Slama
  • Date: 2008-01-29 14:11:22 UTC
  • Revision ID: james.westby@ubuntu.com-20080129141122-fnzjbo11ntghxfu7
Tags: upstream-6.0.1
ImportĀ upstreamĀ versionĀ 6.0.1

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
 
3
 *
 
4
 * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
 
5
 *
 
6
 * The contents of this file are subject to the terms of either the GNU
 
7
 * General Public License Version 2 only ("GPL") or the Common
 
8
 * Development and Distribution License("CDDL") (collectively, the
 
9
 * "License"). You may not use this file except in compliance with the
 
10
 * License. You can obtain a copy of the License at
 
11
 * http://www.netbeans.org/cddl-gplv2.html
 
12
 * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
 
13
 * specific language governing permissions and limitations under the
 
14
 * License.  When distributing the software, include this License Header
 
15
 * Notice in each file and include the License file at
 
16
 * nbbuild/licenses/CDDL-GPL-2-CP.  Sun designates this
 
17
 * particular file as subject to the "Classpath" exception as provided
 
18
 * by Sun in the GPL Version 2 section of the License file that
 
19
 * accompanied this code. If applicable, add the following below the
 
20
 * License Header, with the fields enclosed by brackets [] replaced by
 
21
 * your own identifying information:
 
22
 * "Portions Copyrighted [year] [name of copyright owner]"
 
23
 *
 
24
 * Contributor(s):
 
25
 *
 
26
 * The Original Software is NetBeans. The Initial Developer of the Original
 
27
 * Software is Sun Microsystems, Inc. Portions Copyright 1997-2007 Sun
 
28
 * Microsystems, Inc. All Rights Reserved.
 
29
 *
 
30
 * If you wish your version of this file to be governed by only the CDDL
 
31
 * or only the GPL Version 2, indicate your decision by adding
 
32
 * "[Contributor] elects to include this software in this distribution
 
33
 * under the [CDDL or GPL Version 2] license." If you do not indicate a
 
34
 * single choice of license, a recipient has the option to distribute
 
35
 * your version of this file under either the CDDL, the GPL Version 2 or
 
36
 * to extend the choice of license to its licensees as provided above.
 
37
 * However, if you add GPL Version 2 code and therefore, elected the GPL
 
38
 * Version 2 license, then the option applies only if the new code is
 
39
 * made subject to such option by the copyright holder.
 
40
 */
 
41
package org.netbeans.api.visual.graph;
 
42
 
 
43
import org.netbeans.api.visual.model.ObjectScene;
 
44
import org.netbeans.api.visual.widget.Widget;
 
45
import org.netbeans.modules.visual.util.GeomUtil;
 
46
 
 
47
import java.util.*;
 
48
 
 
49
/**
 
50
 * This class holds and manages graph-oriented model.
 
51
 * <p>
 
52
 * In comparison with the GraphScene class, in this class the graph consists of nodes, edges and pins. Each pin is assigned to a node (the assigned cannot be change at any time.
 
53
 * Each edge could be attach to a single source and target pin.
 
54
 * <p>
 
55
 * The class is abstract and manages only data model and mapping with widgets. The graphics (widgets) has to be supplied
 
56
 * by a developer by overriding the attachNodeWidget, attachPinWidget, attachEdgeWidget, attachEdgeSourceAnchor and attachEdgeTargetAnchor abstract methods.
 
57
 * <p>
 
58
 * This class is using generics and allows you to specify type representation for nodes and edges in the graph model. Example:
 
59
 * <pre>
 
60
 * class MyGraph extends GraphScene&lt;MyNode, MyEdge, MyPin&gt; { ... }
 
61
 * </pre>
 
62
 * Since the type of nodes, edges and pins could be the same, all node, edge and pin instances have to be unique within the whole scene.
 
63
 *
 
64
 * @author David Kaspar
 
65
 */
 
66
// TODO - is it asserted that removing a node removes all its pins
 
67
// TODO - is it asserted that removing a pin disconnects all the attached edges
 
68
public abstract class GraphPinScene<N, E, P> extends ObjectScene {
 
69
 
 
70
    private HashSet<N> nodes = new HashSet<N> ();
 
71
    private Set<N> nodesUm = Collections.unmodifiableSet (nodes);
 
72
    private HashSet<E> edges = new HashSet<E> ();
 
73
    private Set<E> edgesUm = Collections.unmodifiableSet (edges);
 
74
    private HashSet<P> pins = new HashSet<P> ();
 
75
    private Set<P> pinsUm = Collections.unmodifiableSet (pins);
 
76
 
 
77
    private HashMap<N, HashSet<P>> nodePins = new HashMap<N, HashSet<P>> ();
 
78
    private HashMap<P, N> pinNodes = new HashMap<P, N> ();
 
79
    private HashMap<E, P> edgeSourcePins = new HashMap<E, P> ();
 
80
    private HashMap<E, P> edgeTargetPins = new HashMap<E, P> ();
 
81
    private HashMap<P, List<E>> pinInputEdges = new HashMap<P, List<E>> ();
 
82
    private HashMap<P, List<E>> pinOutputEdges = new HashMap<P, List<E>> ();
 
83
 
 
84
    /**
 
85
     * Creates a graph scene.
 
86
     */
 
87
    public GraphPinScene () {
 
88
    }
 
89
 
 
90
    /**
 
91
     * Adds a node.
 
92
     * @param node the node to be added; the node must not be null, must not be already in the model, must be unique in the model
 
93
     *           (means: there is no other node, edge or pin in the model has is equal to this node)
 
94
     *           and must not be a Widget
 
95
     * @return the widget that is created by attachNodeWidget; null if the node is non-visual
 
96
     */
 
97
    public final Widget addNode (N node) {
 
98
        assert node != null : "Null parameter";
 
99
        assert ! nodes.contains (node) : "Node (" + node + ") already added";
 
100
        Widget widget = attachNodeWidget (node);
 
101
        nodes.add (node);
 
102
        nodePins.put (node, new HashSet<P> ());
 
103
        addObject (node, widget);
 
104
        notifyNodeAdded (node, widget);
 
105
        return widget;
 
106
    }
 
107
 
 
108
    /**
 
109
     * Removes a node with all pins that are assigned to the node.
 
110
     * @param node the node to be removed; the node must not be null and must be already in the model
 
111
     */
 
112
    public final void removeNode (N node) {
 
113
        assert node != null  &&  nodes.contains (node);
 
114
        for (P pin : new HashSet<P> (nodePins.get (node)))
 
115
            removePin (pin);
 
116
        nodes.remove (node);
 
117
        nodePins.remove (node);
 
118
        Widget widget = findWidget (node);
 
119
        detachNodeWidget (node, widget);
 
120
        removeObject (node);
 
121
    }
 
122
 
 
123
    /**
 
124
     * Removes a node with all pins that are assign to the node and with all edges that are connected to the pins.
 
125
     * @param node the node to be removed; the node must not be null and must be already in the model
 
126
     */
 
127
    public final void removeNodeWithEdges (N node) {
 
128
        assert node != null && nodes.contains (node);
 
129
        for (P pin : nodePins.get (node))
 
130
            for (E edge : findPinEdges (pin, true, true))
 
131
                if (isEdge (edge))
 
132
                    removeEdge (edge);
 
133
        removeNode (node);
 
134
    }
 
135
 
 
136
    /**
 
137
     * Returns a collection of all nodes registered in the graph model.
 
138
     * @return the collection of all nodes registered in the graph model
 
139
     */
 
140
    public final Collection<N> getNodes () {
 
141
        return nodesUm;
 
142
    }
 
143
 
 
144
    /**
 
145
     * Adds an edge.
 
146
     * @param edge the edge to be added; the edge must not be null, must not be already in the model, must be unique in the model
 
147
     *           (means: there is no other node, edge or pin in the model has is equal to this edge)
 
148
     *           and must not be a Widget
 
149
     * @return the widget that is created by attachEdgeWidget; null if the edge is non-visual
 
150
     */
 
151
    public final Widget addEdge (E edge) {
 
152
        assert edge != null  &&  ! edges.contains (edge);
 
153
        Widget widget = attachEdgeWidget (edge);
 
154
        edges.add (edge);
 
155
        addObject (edge, widget);
 
156
        notifyEdgeAdded (edge, widget);
 
157
        return widget;
 
158
    }
 
159
 
 
160
    /**
 
161
     * Removes an edge and detaches it from its source and target pins.
 
162
     * @param edge the edge to be removed; the edge must not be null and must be already in the model
 
163
     */
 
164
    public final void removeEdge (E edge) {
 
165
        assert edge != null  &&  edges.contains (edge);
 
166
        setEdgeSource (edge, null);
 
167
        setEdgeTarget (edge, null);
 
168
        edges.remove (edge);
 
169
        edgeSourcePins.remove (edge);
 
170
        edgeTargetPins.remove (edge);
 
171
        Widget widget = findWidget (edge);
 
172
        detachEdgeWidget (edge, widget);
 
173
        removeObject (edge);
 
174
    }
 
175
 
 
176
    /**
 
177
     * Returns a collection of all edges registered in the graph model.
 
178
     * @return the collection of all edges registered in the graph model
 
179
     */
 
180
    public final Collection<E> getEdges () {
 
181
        return edgesUm;
 
182
    }
 
183
 
 
184
    /**
 
185
     * Adds a pin and assigns it to a specified node.
 
186
     * @param node the node where the pin is assigned to
 
187
     * @param pin the pin to be added; the pin must not be null, must not be already in the model, must be unique in the model
 
188
     *           (means: there is no other node, edge or pin in the model has is equal to this pin)
 
189
     *           and must not be a Widget
 
190
     * @return the widget that is created by attachPinWidget; null if the pin is non-visual
 
191
     */
 
192
    public final Widget addPin (N node, P pin) {
 
193
        assert node != null  &&  pin != null  &&  ! pins.contains (pin);
 
194
        Widget widget = attachPinWidget (node, pin);
 
195
        pins.add (pin);
 
196
        nodePins.get (node).add (pin);
 
197
        pinNodes.put (pin, node);
 
198
        pinInputEdges.put (pin, new ArrayList<E> ());
 
199
        pinOutputEdges.put (pin, new ArrayList<E> ());
 
200
        addObject (pin, widget);
 
201
        notifyPinAdded (node, pin, widget);
 
202
        return widget;
 
203
    }
 
204
 
 
205
    /**
 
206
     * Removes an pin and detaches all edges that are connected to it.
 
207
     * @param pin the pin to be removed; the pin must not be null and must be already in the model
 
208
     */
 
209
    public final void removePin (P pin) {
 
210
        assert pin != null  &&  pins.contains (pin);
 
211
        for (E edge : findPinEdges (pin, true, false))
 
212
            setEdgeSource (edge, null);
 
213
        for (E edge : findPinEdges (pin, false, true))
 
214
            setEdgeTarget (edge, null);
 
215
        pins.remove (pin);
 
216
        N node = pinNodes.remove (pin);
 
217
        nodePins.get (node).remove (pin);
 
218
        pinInputEdges.remove (pin);
 
219
        pinOutputEdges.remove (pin);
 
220
        Widget widget = findWidget (pin);
 
221
        detachPinWidget (pin, widget);
 
222
        removeObject (pin);
 
223
    }
 
224
 
 
225
    /**
 
226
     * Removes a pin with all edges that are connected to the pin.
 
227
     * @param pin the pin to be removed; the pin must not be null and must be already in the model
 
228
     */
 
229
    public final void removePinWithEdges (P pin) {
 
230
        assert pin != null && pins.contains (pin);
 
231
        for (E edge : findPinEdges (pin, true, true))
 
232
            if (isEdge (edge))
 
233
                removeEdge (edge);
 
234
        removePin (pin);
 
235
    }
 
236
 
 
237
    /**
 
238
     * Returns a node where the pin assigned to.
 
239
     * @param pin the pin
 
240
     * @return the node where the pin assigned to.
 
241
     */
 
242
    public final N getPinNode (P pin) {
 
243
        return pinNodes.get (pin);
 
244
    }
 
245
 
 
246
    /**
 
247
     * Returns all pins registered in the graph model.
 
248
     * @return the collection of all pins registered in the graph model
 
249
     */
 
250
    public final Collection<P> getPins () {
 
251
        return pinsUm;
 
252
    }
 
253
 
 
254
    /**
 
255
     * Returns a collection of pins that are assigned to a specified node
 
256
     * @param node the node
 
257
     * @return the collection of pins; null if node does not exist in the scene
 
258
     */
 
259
    public final Collection<P> getNodePins (N node) {
 
260
        if (node == null)
 
261
            return null;
 
262
        HashSet<P> ps = nodePins.get (node);
 
263
        if (ps == null)
 
264
            return null;
 
265
        return Collections.unmodifiableCollection (ps);
 
266
    }
 
267
 
 
268
    /**
 
269
     * Sets an edge source.
 
270
     * @param edge the edge which source is going to be changed
 
271
     * @param sourcePin the source pin; if null, then the edge source will be detached
 
272
     */
 
273
    public final void setEdgeSource (E edge, P sourcePin) {
 
274
        assert edge != null  &&  edges.contains (edge);
 
275
        if (sourcePin != null)
 
276
            assert pins.contains (sourcePin);
 
277
        P oldPin = edgeSourcePins.put (edge, sourcePin);
 
278
        if (GeomUtil.equals (oldPin, sourcePin))
 
279
            return;
 
280
        if (oldPin != null)
 
281
            pinOutputEdges.get (oldPin).remove (edge);
 
282
        if (sourcePin != null)
 
283
            pinOutputEdges.get (sourcePin).add (edge);
 
284
        attachEdgeSourceAnchor (edge, oldPin, sourcePin);
 
285
    }
 
286
 
 
287
    /**
 
288
     * Sets an edge target.
 
289
     * @param edge the edge which target is going to be changed
 
290
     * @param targetPin the target pin; if null, then the edge target will be detached
 
291
     */
 
292
    public final void setEdgeTarget (E edge, P targetPin) {
 
293
        assert edge != null  &&  edges.contains (edge);
 
294
        if (targetPin != null)
 
295
            assert pins.contains (targetPin);
 
296
        P oldPin = edgeTargetPins.put (edge, targetPin);
 
297
        if (GeomUtil.equals (oldPin, targetPin))
 
298
            return;
 
299
        if (oldPin != null)
 
300
            pinInputEdges.get (oldPin).remove (edge);
 
301
        if (targetPin != null)
 
302
            pinInputEdges.get (targetPin).add (edge);
 
303
        attachEdgeTargetAnchor (edge, oldPin, targetPin);
 
304
    }
 
305
 
 
306
    /**
 
307
     * Returns an edge source.
 
308
     * @param edge the edge
 
309
     * @return the edge source; null, if edge does not have source attached
 
310
     */
 
311
    public final P getEdgeSource (E edge) {
 
312
        return edgeSourcePins.get (edge);
 
313
    }
 
314
 
 
315
    /**
 
316
     * Returns an edge target.
 
317
     * @param edge the edge
 
318
     * @return the edge target; null, if edge does not have target attached
 
319
     */
 
320
    public final P getEdgeTarget (E edge) {
 
321
        return edgeTargetPins.get (edge);
 
322
    }
 
323
 
 
324
    /**
 
325
     * Returns a collection of edges that are attached to a specified pin.
 
326
     * @param pin the pin which edges connections are searched for
 
327
     * @param allowOutputEdges if true, the output edges are included in the collection; if false, the output edges are not included
 
328
     * @param allowInputEdges if true, the input edges are included in the collection; if false, the input edges are not included
 
329
     * @return the collection of edges
 
330
     */
 
331
    public final Collection<E> findPinEdges (P pin, boolean allowOutputEdges, boolean allowInputEdges) {
 
332
        assert isPin (pin) : "Pin " + pin + " is not in the scene";
 
333
        ArrayList<E> list = new ArrayList<E> ();
 
334
        if (allowInputEdges)
 
335
            list.addAll (pinInputEdges.get (pin));
 
336
        if (allowOutputEdges)
 
337
            list.addAll (pinOutputEdges.get (pin));
 
338
        return list;
 
339
    }
 
340
 
 
341
    /**
 
342
     * Returns a collection of edges that are between a source and a target pin.
 
343
     * @param sourcePin the source pin
 
344
     * @param targetPin the target pin
 
345
     * @return the collection of edges
 
346
     */
 
347
    public final Collection<E> findEdgesBetween (P sourcePin, P targetPin) {
 
348
        assert isPin (sourcePin) : "Source pin " + sourcePin + " is not in the scene";
 
349
        assert isPin (targetPin) : "Target pin " + targetPin + " is not in the scene";
 
350
        HashSet<E> list = new HashSet<E> ();
 
351
        List<E> inputEdges = pinInputEdges.get (targetPin);
 
352
        List<E> outputEdges = pinOutputEdges.get (sourcePin);
 
353
        for (E edge : inputEdges)
 
354
            if (outputEdges.contains (edge))
 
355
                list.add (edge);
 
356
        return list;
 
357
    }
 
358
 
 
359
    /**
 
360
     * Checks whether an object is registered as a node in the graph model.
 
361
     * @param object the object; must not be a Widget
 
362
     * @return true, if the object is registered as a node
 
363
     */
 
364
    public boolean isNode (Object object) {
 
365
        assert ! (object instanceof Widget) : "Use findObject method for getting an object assigned to a specific Widget"; // NOI18N
 
366
        return nodes.contains (object);
 
367
    }
 
368
 
 
369
    /**
 
370
     * Checks whether an object is registered as an edge in the graph model.
 
371
     * @param object the object; must not be a Widget
 
372
     * @return true, if the object is registered as a edge
 
373
     */
 
374
    public boolean isEdge (Object object) {
 
375
        assert ! (object instanceof Widget) : "Use findObject method for getting an object assigned to a specific Widget"; // NOI18N
 
376
        return edges.contains (object);
 
377
    }
 
378
 
 
379
    /**
 
380
     * Checks whether an object is registered as a pin in the graph model.
 
381
     * @param object the object; must not be a Widget
 
382
     * @return true, if the object is registered as a pin
 
383
     */
 
384
    public boolean isPin (Object object) {
 
385
        assert ! (object instanceof Widget) : "Use findObject method for getting an object assigned to a specific Widget"; // NOI18N
 
386
        return pins.contains (object);
 
387
    }
 
388
 
 
389
    /**
 
390
     * Called by the addNode method to notify that a node is added into the graph model.
 
391
     * @param node the added node
 
392
     * @param widget the widget created by the attachNodeWidget method as a visual representation of the node
 
393
     */
 
394
    protected void notifyNodeAdded (N node, Widget widget) {
 
395
    }
 
396
 
 
397
    /**
 
398
     * Called by the addEdge method to notify that an edge is added into the graph model.
 
399
     * @param edge the added node
 
400
     * @param widget the widget created by the attachEdgeWidget method as a visual representation of the edge
 
401
     */
 
402
    protected void notifyEdgeAdded (E edge, Widget widget) {
 
403
    }
 
404
 
 
405
    /**
 
406
     * Called by the addPin method to notify that a pin is added into the graph model.
 
407
     * @param node the node where the pin is assigned to
 
408
     * @param pin the added pin
 
409
     * @param widget the widget created by the attachPinWidget method as a visual representation of the pin
 
410
     */
 
411
    protected void notifyPinAdded (N node, P pin, Widget widget) {
 
412
    }
 
413
 
 
414
    /**
 
415
     * Called by the removeNode method to notify that a node is removed from the graph model.
 
416
     * The default implementation removes the node widget from its parent widget.
 
417
     * @param node the removed node
 
418
     * @param widget the removed node widget; null if the node is non-visual
 
419
     */
 
420
    protected void detachNodeWidget (N node, Widget widget) {
 
421
        if (widget != null)
 
422
            widget.removeFromParent ();
 
423
    }
 
424
 
 
425
    /**
 
426
     * Called by the removeEdge method to notify that an edge is removed from the graph model.
 
427
     * The default implementation removes the edge widget from its parent widget.
 
428
     * @param edge the removed edge
 
429
     * @param widget the removed edge widget; null if the edge is non-visual
 
430
     */
 
431
    protected void detachEdgeWidget (E edge, Widget widget) {
 
432
        if (widget != null)
 
433
            widget.removeFromParent ();
 
434
    }
 
435
 
 
436
    /**
 
437
     * Called by the removePin method to notify that a pin is removed from the graph model.
 
438
     * The default implementation removes the pin widget from its parent widget.
 
439
     * @param pin the removed pin
 
440
     * @param widget the removed pin widget; null if the pin is non-visual
 
441
     */
 
442
    protected void detachPinWidget (P pin, Widget widget) {
 
443
        if (widget != null)
 
444
            widget.removeFromParent ();
 
445
    }
 
446
 
 
447
    /**
 
448
     * Called by the addNode method before the node is registered to acquire a widget that is going to represent the node in the scene.
 
449
     * The method is responsible for creating the widget, adding it into the scene and returning it from the method.
 
450
     * @param node the node that is going to be added
 
451
     * @return the widget representing the node; null, if the node is non-visual
 
452
     */
 
453
    protected abstract Widget attachNodeWidget (N node);
 
454
 
 
455
    /**
 
456
     * Called by the addEdge method before the edge is registered to acquire a widget that is going to represent the edge in the scene.
 
457
     * The method is responsible for creating the widget, adding it into the scene and returning it from the method.
 
458
     * @param edge the edge that is going to be added
 
459
     * @return the widget representing the edge; null, if the edge is non-visual
 
460
     */
 
461
    protected abstract Widget attachEdgeWidget (E edge);
 
462
 
 
463
    /**
 
464
     * Called by the addPin method before the pin is registered to acquire a widget that is going to represent the pin in the scene.
 
465
     * The method is responsible for creating the widget, adding it into the scene and returning it from the method.
 
466
     * @param node the node where the pin is assigned to
 
467
     * @param pin the pin that is going to be added
 
468
     * @return the widget representing the pin; null, if the pin is non-visual
 
469
     */
 
470
    protected abstract Widget attachPinWidget (N node, P pin);
 
471
 
 
472
    /**
 
473
     * Called by the setEdgeSource method to notify about the changing the edge source in the graph model.
 
474
     * The method is responsible for attaching a new source pin to the edge in the visual representation.
 
475
     * <p>
 
476
     * Usually it is implemented as:
 
477
     * <pre>
 
478
     * Widget sourcePinWidget = findWidget (sourcePin);
 
479
     * Anchor sourceAnchor = AnchorFactory.createRectangularAnchor (sourcePinWidget)
 
480
     * ConnectionWidget edgeWidget = (ConnectionWidget) findWidget (edge);
 
481
     * edgeWidget.setSourceAnchor (sourceAnchor);
 
482
     * </pre>
 
483
     * @param edge the edge which source is changed in graph model
 
484
     * @param oldSourcePin the old source pin
 
485
     * @param sourcePin the new source pin
 
486
     */
 
487
    protected abstract void attachEdgeSourceAnchor (E edge, P oldSourcePin, P sourcePin);
 
488
 
 
489
    /**
 
490
     * Called by the setEdgeTarget method to notify about the changing the edge target in the graph model.
 
491
     * The method is responsible for attaching a new target pin to the edge in the visual representation.
 
492
     * <p>
 
493
     * Usually it is implemented as:
 
494
     * <pre>
 
495
     * Widget targetPinWidget = findWidget (targetPin);
 
496
     * Anchor targetAnchor = AnchorFactory.createRectangularAnchor (targetPinWidget)
 
497
     * ConnectionWidget edgeWidget = (ConnectionWidget) findWidget (edge);
 
498
     * edgeWidget.setTargetAnchor (targetAnchor);
 
499
     * </pre>
 
500
     * @param edge the edge which target is changed in graph model
 
501
     * @param oldTargetPin the old target pin
 
502
     * @param targetPin the new target pin
 
503
     */
 
504
    protected abstract void attachEdgeTargetAnchor (E edge, P oldTargetPin, P targetPin);
 
505
 
 
506
    /**
 
507
     * This class is a particular GraphPinScene where nodes, edges and pins are represented with String class.
 
508
     */
 
509
    public static abstract class StringGraph extends GraphPinScene<String, String, String> {
 
510
 
 
511
    }
 
512
 
 
513
}