KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > jgrapht > ext > JGraphModelAdapter


1 /* ==========================================
2  * JGraphT : a free Java graph-theory library
3  * ==========================================
4  *
5  * Project Info: http://jgrapht.sourceforge.net/
6  * Project Creator: Barak Naveh (http://sourceforge.net/users/barak_naveh)
7  *
8  * (C) Copyright 2003-2006, by Barak Naveh and Contributors.
9  *
10  * This library is free software; you can redistribute it and/or modify it
11  * under the terms of the GNU Lesser General Public License as published by
12  * the Free Software Foundation; either version 2.1 of the License, or
13  * (at your option) any later version.
14  *
15  * This library is distributed in the hope that it will be useful, but
16  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
17  * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
18  * License for more details.
19  *
20  * You should have received a copy of the GNU Lesser General Public License
21  * along with this library; if not, write to the Free Software Foundation,
22  * Inc.,
23  * 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
24  */

25 /* -----------------------
26  * JGraphModelAdapter.java
27  * -----------------------
28  * (C) Copyright 2003-2006, by Barak Naveh and Contributors.
29  *
30  * Original Author: Barak Naveh
31  * Contributor(s): Erik Postma
32  *
33  * $Id: JGraphModelAdapter.java 504 2006-07-03 02:37:26Z perfecthash $
34  *
35  * Changes
36  * -------
37  * 02-Aug-2003 : Initial revision (BN);
38  * 10-Aug-2003 : Adaptation to new event model (BN);
39  * 06-Nov-2003 : Allowed non-listenable underlying JGraphT graph (BN);
40  * 12-Dec-2003 : Added CellFactory support (BN);
41  * 27-Jan-2004 : Added support for JGraph->JGraphT change propagation (EP);
42  * 29-Jan-2005 : Added support for JGraph dangling edges (BN);
43  * 07-May-2006 : Changed from List<Edge> to Set<Edge> (JVS);
44  * 28-May-2006 : Moved connectivity info from edge to graph (JVS);
45  *
46  */

47 package org.jgrapht.ext;
48
49 import java.awt.Color JavaDoc;
50 import java.awt.Font JavaDoc;
51 import java.awt.geom.*;
52
53 import java.io.*;
54
55 import java.util.ArrayList JavaDoc;
56 import java.util.Collection JavaDoc;
57 import java.util.HashMap JavaDoc;
58 import java.util.HashSet JavaDoc;
59 import java.util.Iterator JavaDoc;
60 import java.util.List JavaDoc;
61 import java.util.Map JavaDoc;
62 import java.util.Set JavaDoc;
63
64 import javax.swing.*;
65
66 import org.jgraph.event.*;
67 import org.jgraph.event.GraphModelEvent.*;
68 import org.jgraph.graph.*;
69
70 import org.jgrapht.*;
71 import org.jgrapht.event.*;
72
73
74 /**
75  * An adapter that reflects a JGraphT graph as a JGraph graph. This adapter is
76  * useful when using JGraph in order to visualize JGraphT graphs. For more about
77  * JGraph see <a HREF="http://jgraph.sourceforge.net">
78  * http://jgraph.sourceforge.net</a>
79  *
80  * <p>Modifications made to the underlying JGraphT graph are reflected to this
81  * JGraph model if and only if the underlying JGraphT graph is a {@link
82  * org.jgrapht.ListenableGraph}. If the underlying JGraphT graph is <i>not</i>
83  * ListenableGraph, then this JGraph model represent a snapshot if the graph at
84  * the time of its creation.</p>
85  *
86  * <p>Changes made to this JGraph model are also reflected back to the
87  * underlying JGraphT graph. To avoid confusion, variables are prefixed
88  * according to the JGraph/JGraphT object(s) they are referring to.</p>
89  *
90  * <p><b>KNOWN BUGS:</b> There is a small issue to be aware of. JGraph allows
91  * 'dangling edges' incident with just one vertex; JGraphT doesn't. Such a
92  * configuration can arise when adding an edge or removing a vertex. The code
93  * handles this by removing the newly-added dangling edge or removing all edges
94  * incident with the vertex before actually removing the vertex, respectively.
95  * This works very well, only it doesn't play all that nicely with the
96  * undo-manager in the JGraph: for the second situation where you remove a
97  * vertex incident with some edges, if you undo the removal, the vertex is
98  * 'unremoved' but the edges aren't.</p>
99  *
100  * @author Barak Naveh
101  * @since Aug 2, 2003
102  */

103
104 /*
105  * FUTURE WORK: Now that the adapter supports JGraph dangling edges, it is
106  * possible, with a little effort, to eliminate the "known bugs" above. Some
107  * todo and fixme marks in the code indicate where the possible improvements
108  * could be made to realize that.
109  */

110 public class JGraphModelAdapter<V, E>
111     extends DefaultGraphModel
112 {
113
114     //~ Static fields/initializers --------------------------------------------
115

116     private static final long serialVersionUID = 3256722883706302515L;
117
118     //~ Instance fields -------------------------------------------------------
119

120     /**
121      * The following (jCells|jtElement)Being(Added|Removed) sets are used to
122      * prevent bouncing of events between the JGraph and JGraphT listeners. They
123      * ensure that their respective add/remove operations are done exactly once.
124      * Here is an example of how jCellsBeingAdded is used when an edge is added
125      * to a JGraph graph:
126      *
127      * <pre>
128         1. First, we add the desired edge to jCellsBeingAdded to indicate
129         that the edge is being inserted internally.
130         2. Then we invoke the JGraph 'insert' operation.
131         3. The JGraph listener will detect the newly inserted edge.
132         4. It checks if the edge is contained in jCellsBeingAdded.
133         5. If yes,
134         it just removes it and does nothing else.
135         if no,
136         it knows that the edge was inserted externally and performs
137         the insertion.
138         6. Lastly, we remove the edge from the jCellsBeingAdded.
139      * </pre>
140      *
141      * <p>Step 6 is not always required but we do it anyway as a safeguard
142      * against the rare case where the edge to be added is already contained in
143      * the graph and thus NO event will be fired. If 6 is not done, a junk edge
144      * will remain in the jCellsBeingAdded set.</p>
145      *
146      * <p>The other sets are used in a similar manner to the above. Apparently,
147      * All that complication could be eliminated if JGraph and JGraphT had both
148      * allowed operations that do not inform listeners...</p>
149      */

150     final Set JavaDoc<GraphCell> jCellsBeingAdded = new HashSet JavaDoc<GraphCell>();
151     final Set JavaDoc<GraphCell> jCellsBeingRemoved = new HashSet JavaDoc<GraphCell>();
152     final Set JavaDoc<Object JavaDoc> jtElementsBeingAdded = new HashSet JavaDoc<Object JavaDoc>();
153     final Set JavaDoc<Object JavaDoc> jtElementsBeingRemoved = new HashSet JavaDoc<Object JavaDoc>();
154     private final CellFactory<V, E> cellFactory;
155
156     /**
157      * Maps JGraph edges to JGraphT edges
158      */

159     private final Map JavaDoc<org.jgraph.graph.Edge, E> cellToEdge =
160         new HashMap JavaDoc<org.jgraph.graph.Edge, E>();
161
162     /**
163      * Maps JGraph vertices to JGraphT vertices
164      */

165     private final Map JavaDoc<GraphCell, V> cellToVertex = new HashMap JavaDoc<GraphCell, V>();
166     private AttributeMap defaultEdgeAttributes;
167     private AttributeMap defaultVertexAttributes;
168
169     /**
170      * Maps JGraphT edges to JGraph edges
171      */

172     private final Map JavaDoc<E, org.jgraph.graph.Edge> edgeToCell =
173         new HashMap JavaDoc<E, org.jgraph.graph.Edge>();
174
175     /**
176      * Maps JGraphT vertices to JGraph vertices
177      */

178     private final Map JavaDoc<V, GraphCell> vertexToCell = new HashMap JavaDoc<V, GraphCell>();
179     private final ShieldedGraph jtGraph;
180
181     //~ Constructors ----------------------------------------------------------
182

183     /**
184      * Constructs a new JGraph model adapter for the specified JGraphT graph.
185      *
186      * @param jGraphTGraph the JGraphT graph for which JGraph model adapter to
187      * be created. <code>null</code> is NOT permitted.
188      */

189     public JGraphModelAdapter(Graph<V, E> jGraphTGraph)
190     {
191         this(
192             jGraphTGraph,
193             createDefaultVertexAttributes(),
194             createDefaultEdgeAttributes(jGraphTGraph));
195     }
196
197     /**
198      * Constructs a new JGraph model adapter for the specified JGraphT graph.
199      *
200      * @param jGraphTGraph the JGraphT graph for which JGraph model adapter to
201      * be created. <code>null</code> is NOT permitted.
202      * @param defaultVertexAttributes a default map of JGraph attributes to
203      * format vertices. <code>null</code> is NOT
204      * permitted.
205      * @param defaultEdgeAttributes a default map of JGraph attributes to format
206      * edges. <code>null</code> is NOT permitted.
207      */

208     public JGraphModelAdapter(
209         Graph<V, E> jGraphTGraph,
210         AttributeMap defaultVertexAttributes,
211         AttributeMap defaultEdgeAttributes)
212     {
213         this(
214             jGraphTGraph,
215             defaultVertexAttributes,
216             defaultEdgeAttributes,
217             new DefaultCellFactory<V, E>());
218     }
219
220     /**
221      * Constructs a new JGraph model adapter for the specified JGraphT graph.
222      *
223      * @param jGraphTGraph the JGraphT graph for which JGraph model adapter to
224      * be created. <code>null</code> is NOT permitted.
225      * @param defaultVertexAttributes a default map of JGraph attributes to
226      * format vertices. <code>null</code> is NOT
227      * permitted.
228      * @param defaultEdgeAttributes a default map of JGraph attributes to format
229      * edges. <code>null</code> is NOT permitted.
230      * @param cellFactory a {@link CellFactory} to be used to create the JGraph
231      * cells. <code>null</code> is NOT permitted.
232      *
233      * @throws IllegalArgumentException
234      */

235     public JGraphModelAdapter(
236         Graph<V, E> jGraphTGraph,
237         AttributeMap defaultVertexAttributes,
238         AttributeMap defaultEdgeAttributes,
239         CellFactory<V, E> cellFactory)
240     {
241         super();
242
243         if (
244             (jGraphTGraph == null)
245             || (defaultVertexAttributes == null)
246             || (defaultEdgeAttributes == null)
247             || (cellFactory == null)) {
248             throw new IllegalArgumentException JavaDoc("null is NOT permitted");
249         }
250
251         jtGraph = new ShieldedGraph(jGraphTGraph);
252         setDefaultVertexAttributes(defaultVertexAttributes);
253         setDefaultEdgeAttributes(defaultEdgeAttributes);
254         this.cellFactory = cellFactory;
255
256         if (jGraphTGraph instanceof ListenableGraph) {
257             ListenableGraph<V, E> g = (ListenableGraph<V, E>) jGraphTGraph;
258             g.addGraphListener(new JGraphTListener());
259         }
260
261         for (Iterator JavaDoc<V> i = jGraphTGraph.vertexSet().iterator();
262             i.hasNext();) {
263             handleJGraphTAddedVertex(i.next());
264         }
265
266         for (Iterator JavaDoc<E> i = jGraphTGraph.edgeSet().iterator(); i.hasNext();) {
267             handleJGraphTAddedEdge(i.next());
268         }
269
270         this.addGraphModelListener(new JGraphListener());
271     }
272
273     //~ Methods ---------------------------------------------------------------
274

275     /**
276      * Creates and returns a map of attributes to be used as defaults for edge
277      * attributes, depending on the specified graph.
278      *
279      * @param jGraphTGraph the graph for which default edge attributes to be
280      * created.
281      *
282      * @return a map of attributes to be used as default for edge attributes.
283      */

284     public static <V, E> AttributeMap createDefaultEdgeAttributes(
285         Graph<V, E> jGraphTGraph)
286     {
287         AttributeMap map = new AttributeMap();
288
289         if (jGraphTGraph instanceof DirectedGraph) {
290             GraphConstants.setLineEnd(map, GraphConstants.ARROW_TECHNICAL);
291             GraphConstants.setEndFill(map, true);
292             GraphConstants.setEndSize(map, 10);
293         }
294
295         GraphConstants.setForeground(map, Color.decode("#25507C"));
296         GraphConstants.setFont(
297             map,
298             GraphConstants.DEFAULTFONT.deriveFont(Font.BOLD, 12));
299         GraphConstants.setLineColor(map, Color.decode("#7AA1E6"));
300
301         return map;
302     }
303
304     /**
305      * Creates and returns a map of attributes to be used as defaults for vertex
306      * attributes.
307      *
308      * @return a map of attributes to be used as defaults for vertex attributes.
309      */

310     public static AttributeMap createDefaultVertexAttributes()
311     {
312         AttributeMap map = new AttributeMap();
313         Color JavaDoc c = Color.decode("#FF9900");
314
315         GraphConstants.setBounds(map, new Rectangle2D.Double(50, 50, 90, 30));
316         GraphConstants.setBorder(map, BorderFactory.createRaisedBevelBorder());
317         GraphConstants.setBackground(map, c);
318         GraphConstants.setForeground(map, Color.white);
319         GraphConstants.setFont(
320             map,
321             GraphConstants.DEFAULTFONT.deriveFont(Font.BOLD, 12));
322         GraphConstants.setOpaque(map, true);
323
324         return map;
325     }
326
327     /**
328      * Returns the cell factory used to create the JGraph cells.
329      *
330      * @return the cell factory used to create the JGraph cells.
331      */

332     public CellFactory<V, E> getCellFactory()
333     {
334         return cellFactory;
335     }
336
337     /**
338      * Sets the default edge attributes used for creating new JGraph edges.
339      *
340      * @param defaultEdgeAttributes the default edge attributes to set.
341      */

342     public void setDefaultEdgeAttributes(AttributeMap defaultEdgeAttributes)
343     {
344         this.defaultEdgeAttributes = defaultEdgeAttributes;
345     }
346
347     /**
348      * Returns the default edge attributes used for creating new JGraph edges.
349      *
350      * @return the default edge attributes used for creating new JGraph edges.
351      */

352     public AttributeMap getDefaultEdgeAttributes()
353     {
354         return defaultEdgeAttributes;
355     }
356
357     /**
358      * Sets the default vertex attributes used for creating new JGraph vertices.
359      *
360      * @param defaultVertexAttributes the default vertex attributes to set.
361      */

362     public void setDefaultVertexAttributes(
363         AttributeMap defaultVertexAttributes)
364     {
365         this.defaultVertexAttributes = defaultVertexAttributes;
366     }
367
368     /**
369      * Returns the default vertex attributes used for creating new JGraph
370      * vertices.
371      *
372      * @return the default vertex attributes used for creating new JGraph
373      * vertices.
374      */

375     public AttributeMap getDefaultVertexAttributes()
376     {
377         return defaultVertexAttributes;
378     }
379
380     /**
381      * Returns the JGraph edge cell that corresponds to the specified JGraphT
382      * edge. If no corresponding cell found, returns <code>null</code>.
383      *
384      * @param jGraphTEdge a JGraphT edge of the JGraphT graph.
385      *
386      * @return the JGraph edge cell that corresponds to the specified JGraphT
387      * edge, or <code>null</code> if no corresponding cell found.
388      */

389     public DefaultEdge getEdgeCell(E jGraphTEdge)
390     {
391         return (DefaultEdge) edgeToCell.get(jGraphTEdge);
392     }
393
394     /**
395      * Returns the JGraph vertex cell that corresponds to the specified JGraphT
396      * vertex. If no corresponding cell found, returns <code>null</code>.
397      *
398      * @param jGraphTVertex a JGraphT vertex of the JGraphT graph.
399      *
400      * @return the JGraph vertex cell that corresponds to the specified JGraphT
401      * vertex, or <code>null</code> if no corresponding cell found.
402      */

403     public DefaultGraphCell getVertexCell(Object JavaDoc jGraphTVertex)
404     {
405         return (DefaultGraphCell) vertexToCell.get(jGraphTVertex);
406     }
407
408     /**
409      * Returns the JGraph port cell that corresponds to the specified JGraphT
410      * vertex. If no corresponding port found, returns <code>null</code>.
411      *
412      * @param jGraphTVertex a JGraphT vertex of the JGraphT graph.
413      *
414      * @return the JGraph port cell that corresponds to the specified JGraphT
415      * vertex, or <code>null</code> if no corresponding cell found.
416      */

417     public DefaultPort getVertexPort(Object JavaDoc jGraphTVertex)
418     {
419         DefaultGraphCell vertexCell = getVertexCell(jGraphTVertex);
420
421         if (vertexCell == null) {
422             return null;
423         } else {
424             return (DefaultPort) vertexCell.getChildAt(0);
425         }
426     }
427
428     /**
429      * Adds/removes an edge to/from the underlying JGraphT graph according to
430      * the change in the specified JGraph edge. If both vertices are connected,
431      * we ensure to have a corresponding JGraphT edge. Otherwise, we ensure NOT
432      * to have a corresponding JGraphT edge.
433      *
434      * <p>This method is to be called only for edges that have already been
435      * changed in the JGraph graph.</p>
436      *
437      * @param jEdge the JGraph edge that has changed.
438      */

439     void handleJGraphChangedEdge(org.jgraph.graph.Edge jEdge)
440     {
441         if (isDangling(jEdge)) {
442             if (cellToEdge.containsKey(jEdge)) {
443                 // a non-dangling edge became dangling -- remove the JGraphT
444
// edge by faking as if the edge is removed from the JGraph.
445
// TODO: Consider keeping the JGraphT edges outside the graph
446
// to avoid loosing user data, such as weights.
447
handleJGraphRemovedEdge(jEdge);
448             } else {
449                 // a dangling edge is still dangling -- just ignore.
450
}
451         } else {
452             // edge is not dangling
453
if (cellToEdge.containsKey(jEdge)) {
454                 // edge already has a corresponding JGraphT edge.
455
// check if any change to its endpoints.
456
E jtEdge = cellToEdge.get(jEdge);
457
458                 Object JavaDoc jSource = getSourceVertex(this, jEdge);
459                 Object JavaDoc jTarget = getTargetVertex(this, jEdge);
460
461                 Object JavaDoc jtSource = cellToVertex.get(jSource);
462                 Object JavaDoc jtTarget = cellToVertex.get(jTarget);
463
464                 if (
465                     (jtGraph.getEdgeSource(jtEdge) == jtSource)
466                     && (jtGraph.getEdgeTarget(jtEdge) == jtTarget)) {
467                     // no change in edge's endpoints -- nothing to do.
468
} else {
469                     // edge's end-points have changed -- need to refresh the
470
// JGraphT edge. Refresh by faking as if the edge has been
471
// removed from JGraph and then added again.
472
// ALSO HERE: consider an alternative that maintains user
473
// data
474
handleJGraphRemovedEdge(jEdge);
475                     handleJGraphInsertedEdge(jEdge);
476                 }
477             } else {
478                 // a new edge
479
handleJGraphInsertedEdge(jEdge);
480             }
481         }
482     }
483
484     /**
485      * Adds to the underlying JGraphT graph an edge that corresponds to the
486      * specified JGraph edge. If the specified JGraph edge is a dangling edge,
487      * it is NOT added to the underlying JGraphT graph.
488      *
489      * <p>This method is to be called only for edges that have already been
490      * added to the JGraph graph.</p>
491      *
492      * @param jEdge the JGraph edge that has been added.
493      */

494     void handleJGraphInsertedEdge(org.jgraph.graph.Edge jEdge)
495     {
496         if (isDangling(jEdge)) {
497             // JGraphT forbid dangling edges so we cannot add the edge yet.
498
// If later the edge becomes connected, we will add it.
499
} else {
500             // FIXME hb 28-nov-05: waiting for jgraph to go generic
501
Object JavaDoc jSource = getSourceVertex(this, jEdge);
502             Object JavaDoc jTarget = getTargetVertex(this, jEdge);
503
504             V jtSource = cellToVertex.get(jSource);
505             V jtTarget = cellToVertex.get(jTarget);
506
507             E jtEdge = jtGraph.addEdge(jtSource, jtTarget);
508
509             if (jtEdge != null) {
510                 cellToEdge.put(jEdge, jtEdge);
511                 edgeToCell.put(jtEdge, jEdge);
512             } else {
513                 // Adding failed because user is using a JGraphT graph the
514
// forbids parallel edges.
515
// For consistency, we remove the edge from the JGraph too.
516
internalRemoveCell(jEdge);
517                 System.err.println(
518                     "Warning: an edge was deleted because the underlying "
519                     + "JGraphT graph refused to create it. "
520                     + "This situation can happen when a constraint of the "
521                     + "underlying graph is violated, e.g., an attempt to add "
522                     + "a parallel edge or a self-loop to a graph that forbids "
523                     + "them. To avoid this message, make sure to use a "
524                     + "suitable underlying JGraphT graph.");
525             }
526         }
527     }
528
529     /**
530      * Adds to the underlying JGraphT graph a vertex corresponding to the
531      * specified JGraph vertex. In JGraph, two vertices with the same user
532      * object are in principle allowed; in JGraphT, this would lead to duplicate
533      * vertices, which is not allowed. So if such vertex already exists, the
534      * specified vertex is REMOVED from the JGraph graph and a a warning is
535      * printed.
536      *
537      * <p>This method is to be called only for vertices that have already been
538      * added to the JGraph graph.</p>
539      *
540      * @param jVertex the JGraph vertex that has been added.
541      */

542     @SuppressWarnings JavaDoc("unchecked")
543     void handleJGraphInsertedVertex(GraphCell jVertex)
544     {
545         V jtVertex;
546
547         if (jVertex instanceof DefaultGraphCell) {
548             // FIXME hb 28-nov-05: waiting for jgraph to go generic
549
jtVertex = (V) ((DefaultGraphCell) jVertex).getUserObject();
550         } else {
551             // FIXME: Why toString? Explain if for a good reason otherwise fix.
552
jtVertex = (V) jVertex.toString();
553         }
554
555         if (vertexToCell.containsKey(jtVertex)) {
556             // We have to remove the new vertex, because it would lead to
557
// duplicate vertices. We can't use ShieldedGraph.removeVertex for
558
// that, because it would remove the wrong (existing) vertex.
559
System.err.println(
560                 "Warning: detected two JGraph vertices with "
561                 + "the same JGraphT vertex as user object. It is an "
562                 + "indication for a faulty situation that should NOT happen."
563                 + "Removing vertex: " + jVertex);
564             internalRemoveCell(jVertex);
565         } else {
566             jtGraph.addVertex(jtVertex);
567
568             cellToVertex.put(jVertex, jtVertex);
569             vertexToCell.put(jtVertex, jVertex);
570         }
571     }
572
573     /**
574      * Removes the edge corresponding to the specified JGraph edge from the
575      * JGraphT graph. If the specified edge is not contained in {@link
576      * #cellToEdge}, it is silently ignored.
577      *
578      * <p>This method is to be called only for edges that have already been
579      * removed from the JGraph graph.</p>
580      *
581      * @param jEdge the JGraph edge that has been removed.
582      */

583     void handleJGraphRemovedEdge(org.jgraph.graph.Edge jEdge)
584     {
585         if (cellToEdge.containsKey(jEdge)) {
586             E jtEdge = cellToEdge.get(jEdge);
587
588             jtGraph.removeEdge(jtEdge);
589
590             cellToEdge.remove(jEdge);
591             edgeToCell.remove(jtEdge);
592         }
593     }
594
595     /**
596      * Removes the vertex corresponding to the specified JGraph vertex from the
597      * JGraphT graph. If the specified vertex is not contained in {@link
598      * #cellToVertex}, it is silently ignored.
599      *
600      * <p>If any edges are incident with this vertex, we first remove them from
601      * the both graphs, because otherwise the JGraph graph would leave them
602      * intact and the JGraphT graph would throw them out. TODO: Revise this
603      * behavior now that we gracefully tolerate dangling edges. It might be
604      * possible to remove just the JGraphT edges. The JGraph edges will be left
605      * dangling, as a result.</p>
606      *
607      * <p>This method is to be called only for vertices that have already been
608      * removed from the JGraph graph.</p>
609      *
610      * @param jVertex the JGraph vertex that has been removed.
611      */

612     void handleJGraphRemovedVertex(GraphCell jVertex)
613     {
614         if (cellToVertex.containsKey(jVertex)) {
615             V jtVertex = cellToVertex.get(jVertex);
616             Set JavaDoc<E> jtIncidentEdges = jtGraph.edgesOf(jtVertex);
617
618             if (!jtIncidentEdges.isEmpty()) {
619                 // We can't just call removeAllEdges with this list: that
620
// would throw a ConcurrentModificationException. So we create
621
// a shallow copy.
622
// This also triggers removal of the corresponding JGraph
623
// edges.
624
jtGraph.removeAllEdges(new ArrayList JavaDoc<E>(jtIncidentEdges));
625             }
626
627             jtGraph.removeVertex(jtVertex);
628
629             cellToVertex.remove(jVertex);
630             vertexToCell.remove(jtVertex);
631         }
632     }
633
634     /**
635      * Adds the specified JGraphT edge to be reflected by this graph model. To
636      * be called only for edges that already exist in the JGraphT graph.
637      *
638      * @param jtEdge a JGraphT edge to be reflected by this graph model.
639      */

640     void handleJGraphTAddedEdge(E jtEdge)
641     {
642         DefaultEdge edgeCell = cellFactory.createEdgeCell(jtEdge);
643         edgeToCell.put(jtEdge, edgeCell);
644         cellToEdge.put(edgeCell, jtEdge);
645
646         ConnectionSet cs = new ConnectionSet();
647         cs.connect(
648             edgeCell,
649             getVertexPort(jtGraph.getEdgeSource(jtEdge)),
650             getVertexPort(jtGraph.getEdgeTarget(jtEdge)));
651
652         internalInsertCell(edgeCell, createEdgeAttributeMap(edgeCell), cs);
653     }
654
655     /**
656      * Adds the specified JGraphT vertex to be reflected by this graph model. To
657      * be called only for edges that already exist in the JGraphT graph.
658      *
659      * @param jtVertex a JGraphT vertex to be reflected by this graph model.
660      */

661     void handleJGraphTAddedVertex(V jtVertex)
662     {
663         DefaultGraphCell vertexCell = cellFactory.createVertexCell(jtVertex);
664         vertexCell.add(new DefaultPort());
665
666         vertexToCell.put(jtVertex, vertexCell);
667         cellToVertex.put(vertexCell, jtVertex);
668
669         internalInsertCell(
670             vertexCell,
671             createVertexAttributeMap(vertexCell),
672             null);
673     }
674
675     /**
676      * Removes the specified JGraphT vertex from being reflected by this graph
677      * model. To be called only for vertices that have already been removed from
678      * the JGraphT graph.
679      *
680      * @param jtVertex a JGraphT vertex to be removed from being reflected by
681      * this graph model.
682      */

683     void handleJGraphTRemoveVertex(Object JavaDoc jtVertex)
684     {
685         DefaultGraphCell vertexCell =
686             (DefaultGraphCell) vertexToCell.remove(jtVertex);
687         cellToVertex.remove(vertexCell);
688
689         internalRemoveCell(vertexCell);
690
691         // FIXME: Why remove childAt(0)? Explain if correct, otherwise fix.
692
if (vertexCell.getChildCount() > 0) {
693             remove(new Object JavaDoc [] { vertexCell.getChildAt(0) });
694         }
695     }
696
697     /**
698      * Removes the specified JGraphT edge from being reflected by this graph
699      * model. To be called only for edges that have already been removed from
700      * the JGraphT graph.
701      *
702      * @param jtEdge a JGraphT edge to be removed from being reflected by this
703      * graph model.
704      */

705     void handleJGraphTRemovedEdge(E jtEdge)
706     {
707         DefaultEdge edgeCell = (DefaultEdge) edgeToCell.remove(jtEdge);
708         cellToEdge.remove(edgeCell);
709         internalRemoveCell(edgeCell);
710     }
711
712     /**
713      * Tests if the specified JGraph edge is 'dangling', that is having at least
714      * one endpoint which is not connected to a vertex.
715      *
716      * @param jEdge the JGraph edge to be tested for being dangling.
717      *
718      * @return <code>true</code> if the specified edge is dangling, otherwise
719      * <code>false</code>.
720      */

721     private boolean isDangling(org.jgraph.graph.Edge jEdge)
722     {
723         Object JavaDoc jSource = getSourceVertex(this, jEdge);
724         Object JavaDoc jTarget = getTargetVertex(this, jEdge);
725
726         return
727             !cellToVertex.containsKey(jSource)
728             || !cellToVertex.containsKey(jTarget);
729     }
730
731     @SuppressWarnings JavaDoc("unchecked")
732     private AttributeMap createEdgeAttributeMap(DefaultEdge edgeCell)
733     {
734         AttributeMap attrs = new AttributeMap();
735
736         // FIXME hb 28-nov-05: waiting for graph to go generic
737
attrs.put(edgeCell, getDefaultEdgeAttributes().clone());
738
739         return attrs;
740     }
741
742     @SuppressWarnings JavaDoc("unchecked")
743     private AttributeMap createVertexAttributeMap(GraphCell vertexCell)
744     {
745         AttributeMap attrs = new AttributeMap();
746
747         // FIXME hb 28-nov-05: waiting for graph to go generic
748
attrs.put(vertexCell, getDefaultVertexAttributes().clone());
749
750         return attrs;
751     }
752
753     /**
754      * Inserts the specified cell into the JGraph graph model.
755      *
756      * @param cell
757      * @param attrs
758      * @param cs
759      */

760     // FIXME hb 28-nov-05: waiting for graph to go generic
761
private void internalInsertCell(
762         GraphCell cell,
763         AttributeMap attrs,
764         ConnectionSet cs)
765     {
766         jCellsBeingAdded.add(cell);
767         insert(new Object JavaDoc [] { cell }, attrs, cs, null, null);
768         jCellsBeingAdded.remove(cell);
769     }
770
771     /**
772      * Removed the specified cell from the JGraph graph model.
773      *
774      * @param cell
775      */

776     private void internalRemoveCell(GraphCell cell)
777     {
778         jCellsBeingRemoved.add(cell);
779         remove(new Object JavaDoc [] { cell });
780         jCellsBeingRemoved.remove(cell);
781     }
782
783     //~ Inner Interfaces ------------------------------------------------------
784

785     /**
786      * Creates the JGraph cells that reflect the respective JGraphT elements.
787      *
788      * @author Barak Naveh
789      * @since Dec 12, 2003
790      */

791     public static interface CellFactory<VV, EE>
792     {
793         /**
794          * Creates an edge cell that contains its respective JGraphT edge.
795          *
796          * @param jGraphTEdge a JGraphT edge to be contained.
797          *
798          * @return an edge cell that contains its respective JGraphT edge.
799          */

800         public DefaultEdge createEdgeCell(EE jGraphTEdge);
801
802         /**
803          * Creates a vertex cell that contains its respective JGraphT vertex.
804          *
805          * @param jGraphTVertex a JGraphT vertex to be contained.
806          *
807          * @return a vertex cell that contains its respective JGraphT vertex.
808          */

809         public DefaultGraphCell createVertexCell(VV jGraphTVertex);
810     }
811
812     //~ Inner Classes ---------------------------------------------------------
813

814     /**
815      * A simple default cell factory.
816      *
817      * @author Barak Naveh
818      * @since Dec 12, 2003
819      */

820     public static class DefaultCellFactory<VV, EE>
821         implements CellFactory<VV, EE>, Serializable
822     {
823         private static final long serialVersionUID = 3690194343461861173L;
824
825         /**
826          * @see JGraphModelAdapter.CellFactory#createEdgeCell(Object)
827          */

828         public DefaultEdge createEdgeCell(EE jGraphTEdge)
829         {
830             return new DefaultEdge(jGraphTEdge);
831         }
832
833         /**
834          * @see JGraphModelAdapter.CellFactory#createVertexCell(Object)
835          */

836         public DefaultGraphCell createVertexCell(VV jGraphTVertex)
837         {
838             return new DefaultGraphCell(jGraphTVertex);
839         }
840     }
841
842     /**
843      * <p>Inner class listening to the GraphModel. If something is changed in
844      * the GraphModel, this Listener gets notified and propagates the change
845      * back to the JGraphT graph, if it didn't originate there.</p>
846      *
847      * <p>If this change contains changes that would make this an illegal
848      * JGraphT graph, like adding an edge that is incident with only one vertex,
849      * the illegal parts of the change are undone.</p>
850      */

851     private class JGraphListener
852         implements GraphModelListener, Serializable
853     {
854         private static final long serialVersionUID = 3544673988098865209L;
855
856         /**
857          * This method is called for all JGraph changes.
858          *
859          * @param e
860          */

861         public void graphChanged(GraphModelEvent e)
862         {
863             // We first remove edges that have to be removed, then we
864
// remove vertices, then we add vertices and finally we add
865
// edges. Otherwise, things might go wrong: for example, if we
866
// would first remove vertices and then edges, removal of the
867
// vertices might induce 'automatic' removal of edges. If we
868
// later attempt to re-remove these edges, we get confused.
869
GraphModelChange change = e.getChange();
870
871             Object JavaDoc [] removedCells = change.getRemoved();
872
873             if (removedCells != null) {
874                 handleRemovedEdges(filterEdges(removedCells));
875                 handleRemovedVertices(filterVertices(removedCells));
876             }
877
878             Object JavaDoc [] insertedCells = change.getInserted();
879
880             if (insertedCells != null) {
881                 handleInsertedVertices(filterVertices(insertedCells));
882                 handleInsertedEdges(filterEdges(insertedCells));
883             }
884
885             // Now handle edges that became 'dangling' or became connected.
886
Object JavaDoc [] changedCells = change.getChanged();
887
888             if (changedCells != null) {
889                 handleChangedEdges(filterEdges(changedCells));
890             }
891         }
892
893         /**
894          * Filters a list of edges out of an array of JGraph GraphCell objects.
895          * Other objects are thrown away.
896          *
897          * @param cells Array of cells to be filtered.
898          *
899          * @return a list of edges.
900          */

901         private List JavaDoc<Object JavaDoc> filterEdges(Object JavaDoc [] cells)
902         {
903             List JavaDoc<Object JavaDoc> jEdges = new ArrayList JavaDoc<Object JavaDoc>();
904
905             for (int i = 0; i < cells.length; i++) {
906                 if (cells[i] instanceof org.jgraph.graph.Edge) {
907                     jEdges.add(cells[i]);
908                 }
909             }
910
911             return jEdges;
912         }
913
914         /**
915          * Filters a list of vertices out of an array of JGraph GraphCell
916          * objects. Other objects are thrown away.
917          *
918          * @param cells Array of cells to be filtered.
919          *
920          * @return a list of vertices.
921          */

922         private List JavaDoc<Object JavaDoc> filterVertices(Object JavaDoc [] cells)
923         {
924             List JavaDoc<Object JavaDoc> jVertices = new ArrayList JavaDoc<Object JavaDoc>();
925
926             for (int i = 0; i < cells.length; i++) {
927                 Object JavaDoc cell = cells[i];
928
929                 if (cell instanceof org.jgraph.graph.Edge) {
930                     // ignore -- we don't care about edges.
931
} else if (cell instanceof Port) {
932                     // ignore -- we don't care about ports.
933
} else if (cell instanceof DefaultGraphCell) {
934                     DefaultGraphCell graphCell = (DefaultGraphCell) cell;
935
936                     // If a DefaultGraphCell has a Port as a child, it is a
937
// vertex.
938
// Note: do not change the order of following conditions;
939
// the code uses the short-circuit evaluation of ||.
940
if (
941                         graphCell.isLeaf()
942                         || (graphCell.getFirstChild() instanceof Port)) {
943                         jVertices.add(cell);
944                     }
945                 } else if (cell instanceof GraphCell) {
946                     // If it is not a DefaultGraphCell, it doesn't have
947
// children.
948
jVertices.add(cell);
949                 }
950             }
951
952             return jVertices;
953         }
954
955         private void handleChangedEdges(List JavaDoc<Object JavaDoc> jEdges)
956         {
957             for (Iterator JavaDoc<Object JavaDoc> i = jEdges.iterator(); i.hasNext();) {
958                 org.jgraph.graph.Edge jEdge = (org.jgraph.graph.Edge) i.next();
959
960                 handleJGraphChangedEdge(jEdge);
961             }
962         }
963
964         private void handleInsertedEdges(List JavaDoc<Object JavaDoc> jEdges)
965         {
966             for (Iterator JavaDoc<Object JavaDoc> i = jEdges.iterator(); i.hasNext();) {
967                 org.jgraph.graph.Edge jEdge = (org.jgraph.graph.Edge) i.next();
968
969                 if (!jCellsBeingAdded.remove(jEdge)) {
970                     handleJGraphInsertedEdge(jEdge);
971                 }
972             }
973         }
974
975         private void handleInsertedVertices(List JavaDoc<Object JavaDoc> jVertices)
976         {
977             for (Iterator JavaDoc<Object JavaDoc> i = jVertices.iterator(); i.hasNext();) {
978                 GraphCell jVertex = (GraphCell) i.next();
979
980                 if (!jCellsBeingAdded.remove(jVertex)) {
981                     handleJGraphInsertedVertex(jVertex);
982                 }
983             }
984         }
985
986         private void handleRemovedEdges(List JavaDoc<Object JavaDoc> jEdges)
987         {
988             for (Iterator JavaDoc<Object JavaDoc> i = jEdges.iterator(); i.hasNext();) {
989                 org.jgraph.graph.Edge jEdge = (org.jgraph.graph.Edge) i.next();
990
991                 if (!jCellsBeingRemoved.remove(jEdge)) {
992                     handleJGraphRemovedEdge(jEdge);
993                 }
994             }
995         }
996
997         private void handleRemovedVertices(List JavaDoc<Object JavaDoc> jVertices)
998         {
999             for (Iterator JavaDoc<Object JavaDoc> i = jVertices.iterator(); i.hasNext();) {
1000                GraphCell jVertex = (GraphCell) i.next();
1001
1002                if (!jCellsBeingRemoved.remove(jVertex)) {
1003                    handleJGraphRemovedVertex(jVertex);
1004                }
1005            }
1006        }
1007    }
1008
1009    /**
1010     * A listener on the underlying JGraphT graph. This listener is used to keep
1011     * the JGraph model in sync. Whenever one of the event handlers is called,
1012     * it first checks whether the change is due to a previous change in the
1013     * JGraph model. If it is, then no action is taken.
1014     *
1015     * @author Barak Naveh
1016     * @since Aug 2, 2003
1017     */

1018    private class JGraphTListener
1019        implements GraphListener<V, E>, Serializable
1020    {
1021        private static final long serialVersionUID = 3616724963609360440L;
1022
1023        /**
1024         * @see GraphListener#edgeAdded(GraphEdgeChangeEvent)
1025         */

1026        public void edgeAdded(GraphEdgeChangeEvent<V, E> e)
1027        {
1028            E jtEdge = e.getEdge();
1029
1030            if (!jtElementsBeingAdded.remove(jtEdge)) {
1031                handleJGraphTAddedEdge(jtEdge);
1032            }
1033        }
1034
1035        /**
1036         * @see GraphListener#edgeRemoved(GraphEdgeChangeEvent)
1037         */

1038        public void edgeRemoved(GraphEdgeChangeEvent<V, E> e)
1039        {
1040            E jtEdge = e.getEdge();
1041
1042            if (!jtElementsBeingRemoved.remove(jtEdge)) {
1043                handleJGraphTRemovedEdge(jtEdge);
1044            }
1045        }
1046
1047        /**
1048         * @see VertexSetListener#vertexAdded(GraphVertexChangeEvent)
1049         */

1050        public void vertexAdded(GraphVertexChangeEvent<V> e)
1051        {
1052            V jtVertex = e.getVertex();
1053
1054            if (!jtElementsBeingAdded.remove(jtVertex)) {
1055                handleJGraphTAddedVertex(jtVertex);
1056            }
1057        }
1058
1059        /**
1060         * @see VertexSetListener#vertexRemoved(GraphVertexChangeEvent)
1061         */

1062        public void vertexRemoved(GraphVertexChangeEvent<V> e)
1063        {
1064            V jtVertex = e.getVertex();
1065
1066            if (!jtElementsBeingRemoved.remove(jtVertex)) {
1067                handleJGraphTRemoveVertex(jtVertex);
1068            }
1069        }
1070    }
1071
1072    /**
1073     * A wrapper around a JGraphT graph that ensures a few atomic operations.
1074     */

1075    private class ShieldedGraph
1076    {
1077        private final Graph<V, E> graph;
1078
1079        ShieldedGraph(Graph<V, E> graph)
1080        {
1081            this.graph = graph;
1082        }
1083
1084        EdgeFactory<V, E> getEdgeFactory()
1085        {
1086            return graph.getEdgeFactory();
1087        }
1088
1089        E addEdge(V jtSource, V jtTarget)
1090        {
1091            E jtEdge = graph.getEdgeFactory().createEdge(jtSource, jtTarget);
1092            jtElementsBeingAdded.add(jtEdge);
1093
1094            boolean added = graph.addEdge(jtSource, jtTarget, jtEdge);
1095            jtElementsBeingAdded.remove(jtEdge);
1096
1097            return added ? jtEdge : null;
1098        }
1099
1100        V getEdgeSource(E e)
1101        {
1102            return graph.getEdgeSource(e);
1103        }
1104
1105        V getEdgeTarget(E e)
1106        {
1107            return graph.getEdgeTarget(e);
1108        }
1109
1110        void addVertex(V jtVertex)
1111        {
1112            jtElementsBeingAdded.add(jtVertex);
1113            graph.addVertex(jtVertex);
1114            jtElementsBeingAdded.remove(jtVertex);
1115        }
1116
1117        Set JavaDoc<E> edgesOf(V vertex)
1118        {
1119            return graph.edgesOf(vertex);
1120        }
1121
1122        boolean removeAllEdges(Collection JavaDoc<E> edges)
1123        {
1124            return graph.removeAllEdges(edges);
1125        }
1126
1127        void removeEdge(E jtEdge)
1128        {
1129            jtElementsBeingRemoved.add(jtEdge);
1130            graph.removeEdge(jtEdge);
1131            jtElementsBeingRemoved.remove(jtEdge);
1132        }
1133
1134        void removeVertex(V jtVertex)
1135        {
1136            jtElementsBeingRemoved.add(jtVertex);
1137            graph.removeVertex(jtVertex);
1138            jtElementsBeingRemoved.remove(jtVertex);
1139        }
1140    }
1141}
1142
Popular Tags