KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > enhydra > jawe > JaWEGraphModel


1 /* PEGraphModel.java
2  *
3  * Authors:
4  * Stefanovic Nenad chupo@iis.ns.ac.yu
5  * Bojanic Sasa sasaboy@neobee.net
6  * Puskas Vladimir vpuskas@eunet.yu
7  * Pilipovic Goran zboniek@uns.ac.yu
8  *
9  */

10
11 package org.enhydra.jawe;
12
13 import org.enhydra.jawe.graph.*;
14
15 import org.jgraph.JGraph;
16 import org.jgraph.graph.*;
17 import org.jgraph.event.*;
18
19 import java.io.*;
20 import java.util.*;
21 import javax.swing.undo.*;
22 import javax.swing.tree.*;
23 import java.awt.Rectangle JavaDoc;
24 import javax.swing.event.*;
25
26 /**
27  * A process editor implementation of a graph model.
28  */

29 public class JaWEGraphModel
30    extends UndoableEditSupport
31    implements Serializable, GraphModel {
32
33    /** The list of listeners that listen to the model. */
34    protected transient EventListenerList listenerList =
35       new EventListenerList();
36
37    /** Default instance of an empty iterator. */
38    protected transient Iterator emptyIterator = new EmptyIterator();
39
40    /** Set that contains all root cells of this model. */
41    protected List roots = new ArrayList();
42
43    /** Indicates whether isLeaf is based on a node's allowsChildren value. */
44    protected boolean asksAllowsChildren = false;
45
46    /**
47     * Constructs a model that is not an attribute store.
48     */

49    public JaWEGraphModel() {
50    }
51
52    //
53
// Graph Model
54
//
55

56    /**
57     * Returns the number of roots in the model. Returns 0 if the
58     * model is empty.
59     *
60     * @return the number of roots in the model
61     */

62    public int getRootCount() {
63       return roots.size();
64    }
65
66    /**
67     * Returns the root at index <I>index</I> in the model.
68     * This should not return null if <i>index</i> is a valid
69     * index for the model (that is <i>index</i> >= 0 &&
70     * <i>index</i> < getRootCount()).
71     *
72     * @return the root of at index <I>index</I>
73     */

74    public Object JavaDoc getRootAt(int index) {
75       return roots.get(index);
76    }
77
78    /**
79     * Returns the index of <code>root</code> in the model.
80     * If root is <code>null</code>, returns -1.
81     * @param root a root in the model, obtained from this data source
82     * @return the index of the root in the model, or -1
83     * if the parent is <code>null</code>
84     */

85    public int getIndexOfRoot(Object JavaDoc root) {
86       return roots.indexOf(root);
87    }
88
89    /**
90     * Returns <code>true</code> if <code>node</code> or one of its
91     * ancestors is in the model.
92     *
93     * @return <code>true</code> if <code>node</code> is in the model
94     */

95    public boolean contains(Object JavaDoc node) {
96       Object JavaDoc parentNode = null;
97       while ((parentNode = getParent(node))
98              != null)
99          node = parentNode;
100       return roots.contains(node);
101    }
102
103    /**
104     * Returns a <code>Map</code> that represents the attributes for
105     * the specified cell. This attributes have precedence over each
106     * view's attributes, regardless of isAttributeStore.
107     *
108     * @return attributes of <code>node</code> as a <code>Map</code>
109     */

110    public Map getAttributes(Object JavaDoc node) {
111       if (node instanceof GraphCell)
112          return ((GraphCell) node).getAttributes();
113       return null;
114    }
115
116    //
117
// Graph Structure
118
//
119

120    /**
121     * Returns the source of <code>edge</code>. <I>edge</I> must be an object
122     * previously obtained from this data source.
123     *
124     * @return <code>Object</code> that represents the source of <i>edge</i>
125     */

126    public Object JavaDoc getSource(Object JavaDoc edge) {
127       if (edge instanceof Edge)
128          return ((Edge) edge).getSource();
129       return null;
130    }
131
132    /**
133     * Returns the target of <code>edge</code>. <I>edge</I> must be an object
134     * previously obtained from this data source.
135     *
136     * @return <code>Object</code> that represents the target of <i>edge</i>
137     */

138    public Object JavaDoc getTarget(Object JavaDoc edge) {
139       if (edge instanceof Edge)
140          return ((Edge) edge).getTarget();
141       return null;
142    }
143
144    /**
145     * Returns <code>true</code> if <code>port</code> is a valid source
146     * for <code>edge</code>. <I>edge</I> and <I>port</I> must be
147     * objects previously obtained from this data source.
148     *
149     * @return <code>true</code> if <code>port</code> is a valid source
150     * for <code>edge</code>.
151     */

152    public boolean acceptsSource(Object JavaDoc edge, Object JavaDoc port) {
153       return true;
154    }
155
156    /**
157     * Returns <code>true</code> if <code>port</code> is a valid target
158     * for <code>edge</code>. <I>edge</I> and <I>port</I> must be
159     * objects previously obtained from this data source.
160     *
161     * @return <code>true</code> if <code>port</code> is a valid target
162     * for <code>edge</code>.
163     */

164    public boolean acceptsTarget(Object JavaDoc edge, Object JavaDoc port) {
165       return true;
166    }
167
168    /**
169     * Returns an iterator of the edges connected to <code>port</code>.
170     * <I>port</I> must be a object previously obtained from
171     * this data source. This method never returns null.
172     *
173     * @param port a port in the graph, obtained from this data source
174     * @return <code>Iterator</code> that represents the connected edges
175     */

176    public Iterator edges(Object JavaDoc port) {
177       if (port instanceof Port)
178          return ((Port) port).edges();
179       return emptyIterator;
180    }
181
182    /**
183     * Returns <code>true</code> if <code>edge</code> is a valid edge.
184     *
185     * @return <code>true</code> if <code>edge</code> is a valid edge.
186     */

187    public boolean isEdge(Object JavaDoc edge) {
188       return edge instanceof Edge;
189    }
190
191    /**
192     * Returns <code>true</code> if <code>port</code> is a valid
193     * port, possibly supporting edge connection.
194     *
195     * @return <code>true</code> if <code>port</code> is a valid port.
196     */

197    public boolean isPort(Object JavaDoc port) {
198       return port instanceof Port;
199    }
200    //
201
// Group Structure
202
//
203

204    /**
205     * Returns a map of (cell, clone)-pairs for all <code>cells</code>
206     * and their children. Special care is taken to replace the anchor
207     * references between ports. (Iterative implementation.)
208     */

209    public Map cloneCells(Object JavaDoc[] cells) {
210       Map map = new Hashtable();
211       // Add Cells to Queue
212
ArrayList q = new ArrayList();
213       for (int i = 0; i < cells.length; i++)
214          q.add(cells[i]);
215       // Iterate Queue
216
while (!q.isEmpty()) {
217          // Remove Front Client From Queue
218
Object JavaDoc node = q.remove(0);
219          if (node instanceof DefaultGraphCell) {
220             // Enqueue Children
221
for (int i = 0; i < getChildCount(node); i++)
222                q.add(getChild(node, i));
223             // Re-Establish Parent Relation for Front Client
224
DefaultGraphCell cell = (DefaultGraphCell) node;
225             DefaultGraphCell clone = (DefaultGraphCell) cell.clone();
226             Object JavaDoc par = getParent(cell);
227             if (par != null) {
228                DefaultMutableTreeNode p =
229                   (DefaultMutableTreeNode) map.get(par);
230                if (p != null)
231                   p.add(clone);
232             }
233             // Store (cell, clone)-pair
234
map.put(cell, clone);
235          }
236       }
237       // Replace Anchors
238
Iterator it = map.values().iterator();
239       while (it.hasNext()) {
240          Object JavaDoc obj = it.next();
241          // For All Ports in Result Map do...
242
if (obj instanceof Port) {
243             Object JavaDoc anchor = ((Port) obj).getAnchor();
244             // Map Anchor to Cloned Anchor
245
if (anchor != null)
246                   ((Port) obj).setAnchor((Port) map.get(anchor));
247          }
248       }
249       return map;
250    }
251
252
253    /**
254     * Returns the parent of <I>child</I> in the model.
255     * <I>child</I> must be a node previously obtained from
256     * this data source. This returns null if <i>child</i> is
257     * a root in the model.
258     *
259     * @param child a node in the graph, obtained from this data source
260     * @return the parent of <I>child</I>
261     */

262    public Object JavaDoc getParent(Object JavaDoc child) {
263       if (child != null && child instanceof TreeNode)
264          return ((TreeNode) child).getParent();
265       return null;
266    }
267
268    /**
269     * Returns the index of child in parent.
270     * If either the parent or child is <code>null</code>, returns -1.
271     * @param parent a note in the tree, obtained from this data source
272     * @param child the node we are interested in
273     * @return the index of the child in the parent, or -1
274     * if either the parent or the child is <code>null</code>
275     */

276    public int getIndexOfChild(Object JavaDoc parent, Object JavaDoc child) {
277       if (parent == null || child == null)
278          return -1;
279       return ((TreeNode) parent).getIndex((TreeNode) child);
280    }
281
282    /**
283     * Returns the child of <I>parent</I> at index <I>index</I> in the parent's
284     * child array. <I>parent</I> must be a node previously obtained from
285     * this data source. This should not return null if <i>index</i>
286     * is a valid index for <i>parent</i> (that is <i>index</i> >= 0 &&
287     * <i>index</i> < getChildCount(<i>parent</i>)).
288     *
289     * @param parent a node in the tree, obtained from this data source
290     * @return the child of <I>parent</I> at index <I>index</I>
291     */

292    public Object JavaDoc getChild(Object JavaDoc parent, int index) {
293       if (parent instanceof TreeNode)
294          return ((TreeNode) parent).getChildAt(index);
295       return null;
296    }
297
298    /**
299     * Returns the number of children of <I>parent</I>. Returns 0 if the node
300     * is a leaf or if it has no children. <I>parent</I> must be a node
301     * previously obtained from this data source.
302     *
303     * @param parent a node in the tree, obtained from this data source
304     * @return the number of children of the node <I>parent</I>
305     */

306    public int getChildCount(Object JavaDoc parent) {
307       if (parent instanceof TreeNode)
308          return ((TreeNode) parent).getChildCount();
309       return 0;
310    }
311
312    /**
313     * Returns whether the specified node is a leaf node.
314     * The way the test is performed depends on the.
315     *
316     * @param node the node to check
317     * @return true if the node is a leaf node
318     */

319    public boolean isLeaf(Object JavaDoc node) {
320       if (asksAllowsChildren && node instanceof TreeNode)
321          return !((TreeNode) node).getAllowsChildren();
322       return ((TreeNode) node).isLeaf();
323    }
324
325
326    //
327
// Change Support
328
//
329

330    /**
331     * Inserts the <code>roots</code> and connections into the model.
332     * Notifies the model- and undo listeners of the change. The passed-in
333     * edits are executed if they implement the
334     * <code>GraphModelEvent.ExecutableGraphChange</code> interface
335     * in ascending array-order, after execution of the model change.
336     * (Note: The external order is important in a
337     * special case: After insertion on a partial view, ie. one that does not
338     * display all cells of the model, the cell is made visible after
339     * it is inserted into the model. This requires the inserting view
340     * to be able to add the cell to the visible set before it is
341     * inserted into the model.)
342     * Note: The passed-in propertyMap may contains PortViews
343     * which must be turned into Points when stored in the model.
344     */

345    public void insert(
346       Object JavaDoc[] roots,
347       Map attributes,
348       ConnectionSet cs,
349       ParentMap pm,
350       UndoableEdit[] edits) {
351       String JavaDoc undoMsg=ResourceManager.getLanguageDependentString("MessageInsertingObjects");
352       GraphModelEdit edit =
353          createInsertEdit(roots, attributes, cs, pm, edits, undoMsg);
354       if (edit != null) {
355          edit.execute();
356          if (edits != null) {
357             for (int i = 0; i < edits.length; i++)
358                if (edits[i]
359                    instanceof GraphModelEvent.ExecutableGraphChange)
360                      ((GraphModelEvent.ExecutableGraphChange) edits[i])
361                      .execute();
362          }
363          postEdit(edit);
364       }
365    }
366
367
368    /**
369     * Removes <code>cells</code> from the model.
370     * Notifies the model- and undo listeners of the change.
371     */

372    public void remove(Object JavaDoc[] roots) {
373       String JavaDoc undoMsg=ResourceManager.getLanguageDependentString("MessageRemovingObjects");
374       GraphModelEdit edit = createRemoveEdit(roots,undoMsg);
375       if (edit != null) {
376          edit.execute();
377          postEdit(edit);
378       }
379    }
380
381    /**
382     * Applies <code>attributes</code> and the connection changes to
383     * the model. The initial <code>edits</code> that triggered the call
384     * are considered to be part of this transaction. The passed-in
385     * edits are executed if they implement the
386     * <code>GraphModelEvent.ExecutableGraphChange</code> interface
387     * in ascending array-order, after execution of the model change.
388     * Notifies the model- and undo listeners of the change.
389     * <strong>Note:</strong> If only <code>edits</code> is non-null, the
390     * edits are directly passed to the UndoableEditListeners.
391     * Note: The passed-in propertyMap may contains PortViews
392     * which must be turned into Points when stored in the model.
393     */

394    public void edit(
395       Map attributes,
396       ConnectionSet cs,
397       ParentMap pm,
398       UndoableEdit[] edits) {
399       if ((attributes == null || attributes.isEmpty())
400           && (cs == null || cs.isEmpty())
401           && pm == null
402           && edits != null
403           && edits.length == 1) {
404          if (edits[0] instanceof GraphModelEvent.ExecutableGraphChange)
405                ((GraphModelEvent.ExecutableGraphChange) edits[0]).execute();
406          postEdit(edits[0]); // UndoableEdit Relay
407
} else {
408          String JavaDoc undoMsg=ResourceManager.getLanguageDependentString("MessageEditingObject");
409          GraphModelEdit edit = createCellEdit(attributes, cs, pm, edits, undoMsg);
410          //System.out.println("DefaultGraphModel_edit_attributes="+attributes);
411
if (edit != null) {
412             edit.execute();
413             if (edits != null) {
414                for (int i = 0; i < edits.length; i++)
415                   if (edits[i]
416                       instanceof GraphModelEvent.ExecutableGraphChange)
417                         ((GraphModelEvent.ExecutableGraphChange) edits[i])
418                         .execute();
419             }
420             postEdit(edit);
421          }
422       }
423    }
424
425    /**
426     * Used for editing font sizes without haveing an undo action set.
427     */

428    public void editFonts(Map attributes) {
429       GraphModelEdit edit = createCellEdit(attributes, null, null, null, null);
430       //System.out.println("DefaultGraphModel_edit_attributes="+attributes);
431
if (edit != null) {
432          edit.execute();
433       }
434    }
435
436
437    /**
438     * Used for editing font sizes without haveing an undo action set.
439     */

440    public void removeBubbles (Object JavaDoc[] bubbles,GraphModelListener gml) {
441       removeGraphModelListener(gml);
442       GraphModelEdit edit = createRemoveEdit(bubbles,null);
443       if (edit != null) {
444          edit.execute();
445       }
446       addGraphModelListener(gml);
447    }
448
449    /**
450     * Inserts the <code>roots</code> and connections into the model.
451     * Notifies the model- and undo listeners of the change. The passed-in
452     * edits are executed if they implement the
453     * <code>GraphModelEvent.ExecutableGraphChange</code> interface
454     * in ascending array-order, after execution of the model change.
455     * (Note: The external order is important in a
456     * special case: After insertion on a partial view, ie. one that does not
457     * display all cells of the model, the cell is made visible after
458     * it is inserted into the model. This requires the inserting view
459     * to be able to add the cell to the visible set before it is
460     * inserted into the model.)
461     * Note: The passed-in propertyMap may contains PortViews
462     * which must be turned into Points when stored in the model.
463     */

464    public void insertAndEdit(
465       Object JavaDoc[] roots,
466       Map attributes,
467       ConnectionSet cs,
468       ParentMap pm,
469       UndoableEdit[] edits,
470       String JavaDoc undoMsg) {
471       GraphModelEdit edit =
472          createInsertEdit(roots, attributes, cs, pm, edits, undoMsg);
473       if (edit != null) {
474          edit.execute();
475          if (edits != null) {
476             for (int i = 0; i < edits.length; i++)
477                if (edits[i]
478                    instanceof GraphModelEvent.ExecutableGraphChange)
479                      ((GraphModelEvent.ExecutableGraphChange) edits[i])
480                      .execute();
481          }
482          postEdit(edit);
483       }
484    }
485
486    /**
487     * Removes <code>cells</code> from the model and edits cells given in
488     * a <code>propertyMap</code>. If <code>removeChildren</code>
489     * is <code>true</code>, the children are also removed.
490     * Notifies the model- and undo listeners of the change.
491     */

492    public void removeAndEdit(Object JavaDoc[] roots,Map attributes,String JavaDoc name) {
493       GraphModelEdit edit = createRemoveAndCellEdit(roots,attributes,name);
494       if (edit!=null) {
495          edit.execute();
496          postEdit(edit);
497       }
498    }
499
500    /**
501     * Sends <code>cells</code> to back.
502     */

503    public void toBack(Object JavaDoc[] cells) {
504       GraphModelLayerEdit edit =
505          createLayerEdit(cells, GraphModelLayerEdit.BACK);
506       if (edit != null) {
507          edit.execute();
508          postEdit(edit);
509       }
510    }
511
512    /**
513     * Brings <code>cells</code> to front.
514     */

515    public void toFront(Object JavaDoc[] cells) {
516       GraphModelLayerEdit edit =
517          createLayerEdit(cells, GraphModelLayerEdit.FRONT);
518       if (edit != null) {
519          edit.execute();
520          postEdit(edit);
521       }
522    }
523
524    //
525
// Edit Creation
526
//
527

528    protected GraphModelLayerEdit createLayerEdit(Object JavaDoc[] cells, int layer) {
529       return new GraphModelLayerEdit(cells, layer);
530    }
531
532    /**
533     * Returns an edit that represents an insert.
534     */

535    protected GraphModelEdit createInsertEdit(
536       Object JavaDoc[] cells,
537       Map attributeMap,
538       ConnectionSet cs,
539       ParentMap pm,
540       UndoableEdit[] edits,
541       String JavaDoc name) {
542       //GraphModelEdit edit = new GraphModelEdit(cells, cs, pm, attributeMap);
543
GraphModelEdit edit =
544          createEdit(cells, null, attributeMap, cs, pm, name);
545       if (edit != null) {
546          if (edits != null)
547             for (int i = 0; i < edits.length; i++)
548                edit.addEdit(edits[i]);
549          edit.end();
550       }
551       return edit;
552    }
553
554    /**
555     * Returns an edit that represents a remove.
556     */

557    protected GraphModelEdit createRemoveEdit(Object JavaDoc[] cells,String JavaDoc name) {
558       // Remove from GraphStructure
559
ConnectionSet cs = ConnectionSet.create(this, cells, true);
560       // Remove from Group Structure
561
ParentMap pm = ParentMap.create(this, cells, true, false);
562       // Construct Edit
563
//GraphModelEdit edit = new GraphModelEdit(cells, cs, pm);
564
GraphModelEdit edit = createEdit(null, cells, null, cs, pm, name);
565       if (edit != null)
566          edit.end();
567       return edit;
568    }
569
570    /**
571     * Returns an edit that represents a change.
572     */

573    protected GraphModelEdit createCellEdit(
574       Map attributes,
575       ConnectionSet cs,
576       ParentMap pm,
577       UndoableEdit[] edits,
578       String JavaDoc name) {
579       //GraphModelEdit edit = new GraphModelEdit(cs, propertyMap, pm);
580
GraphModelEdit edit = createEdit(null, null, attributes, cs, pm, name);
581       if (edit != null) {
582          if (edits != null)
583             for (int i = 0; i < edits.length; i++)
584                edit.addEdit(edits[i]);
585          edit.end();
586       }
587       return edit;
588    }
589
590
591    protected GraphModelEdit createEdit(
592       Object JavaDoc[] inserted,
593       Object JavaDoc[] removed,
594       Map attributes,
595       ConnectionSet cs,
596       ParentMap pm,
597       String JavaDoc name) {
598       return new GraphModelEdit(
599          inserted,
600          removed,
601          attributes,
602          cs,
603          pm,
604          name);
605    }
606
607    /**
608     * Returns an edit that represents a remove and a change.
609     */

610    protected GraphModelEdit createRemoveAndCellEdit(Object JavaDoc[] cells,
611                                                     Map attributes,String JavaDoc name) {
612       // Remove from GraphStructure
613
ConnectionSet cs = ConnectionSet.create(this, cells, true);
614       // Remove from Group Structure
615
ParentMap pm = ParentMap.create(this, cells, true, false);
616       // Construct Edit
617
GraphModelEdit edit = createEdit (null,cells,attributes,cs,pm,name);
618       if (edit!=null) {
619          edit.end();
620       }
621       return edit;
622    }
623
624    //
625
// Change Handling
626
//
627

628    /**
629     * Inserts <code>cells</code> into the model. Returns
630     * the cells that were inserted (including descendants).
631     */

632    protected Object JavaDoc[] handleInsert(Object JavaDoc[] cells) {
633       Object JavaDoc[] inserted = null;
634       if (cells != null) {
635          for (int i = 0; i < cells.length; i++)
636             // Add to Roots if no parent
637
if (getParent(cells[i]) == null)
638                roots.add(cells[i]);
639          // Return *all* inserted cells
640
inserted = getDescendants(this, cells).toArray();
641       }
642       return inserted;
643    }
644
645    /**
646     * Removes <code>cells</code> from the model. Returns
647     * the cells that were removed as roots.
648     */

649    protected Object JavaDoc[] handleRemove(Object JavaDoc[] cells) {
650       List removedRoots = new ArrayList();
651       if (cells != null)
652          for (int i = 0; i < cells.length; i++)
653             if (getParent(cells[i]) == null && roots.remove(cells[i]))
654                removedRoots.add(cells[i]);
655       return removedRoots.toArray();
656    }
657
658    /**
659     * Applies <code>cells</code> to the model. Returns
660     * a parent map that may be used to undo this change.
661     */

662    protected ParentMap handleParentMap(ParentMap parentMap) {
663       if (parentMap != null) {
664          ParentMap undo = new ParentMap();
665          Iterator it = parentMap.entries();
666          while (it.hasNext()) {
667             ParentMap.Entry entry = (ParentMap.Entry) it.next();
668             Object JavaDoc child = entry.getChild();
669             Object JavaDoc parent = entry.getParent();
670             undo.addEntry(child, getParent(child));
671             if (parent == null){
672                if (child instanceof MutableTreeNode){
673                   ((MutableTreeNode)child).removeFromParent();
674                }
675             } else {
676                if (parent instanceof DefaultMutableTreeNode &&
677                    child instanceof MutableTreeNode){
678                   ((DefaultMutableTreeNode)parent).add((MutableTreeNode)child);
679                }
680             }
681
682             boolean isRoot = roots.contains(child);
683             if (parent == null && !isRoot)
684                roots.add(child);
685             else if (parent != null && isRoot)
686                roots.remove(child);
687          }
688          return undo;
689       }
690       return null;
691    }
692
693    /**
694     * Applies <code>attributes</code> to the cells specified as keys.
695     * Returns the <code>attributes</code> to undo the change.
696     */

697    protected Map handleAttributes(Map attributes) {
698       if (attributes != null) {
699          Hashtable undo = new Hashtable();
700          Iterator it = attributes.entrySet().iterator();
701          while (it.hasNext()) {
702             Map.Entry entry = (Map.Entry) it.next();
703             Object JavaDoc cell = entry.getKey();
704             Map deltaNew = (Map) entry.getValue();
705             //System.out.println("deltaNew="+deltaNew);
706
//System.out.println("stateOld="+getAttributes(cell));
707
if (cell instanceof GraphCell){
708                Map deltaOld = ((GraphCell)cell).changeAttributes(deltaNew);
709                //System.out.println("stateNew="+getAttributes(cell));
710
//System.out.println("deltaOld="+deltaOld);
711
undo.put(cell, deltaOld);
712             } else {
713                Map attr = getAttributes(cell);
714                if (attr != null){
715                   Map deltaOld = GraphConstants.applyMap(deltaNew, attr);
716                   //System.out.println("stateNew="+getAttributes(cell));
717
//System.out.println("deltaOld="+deltaOld);
718
undo.put(cell, deltaOld);
719                }
720             }
721          }
722          return undo;
723       }
724       return null;
725    }
726
727    //
728
// Connection Set Handling
729
//
730

731    /**
732     * Applies <code>connectionSet</code> to the model. Returns
733     * a connection set that may be used to undo this change.
734     */

735    protected ConnectionSet handleConnectionSet(ConnectionSet cs) {
736       if (cs != null) {
737          ConnectionSet csundo = new ConnectionSet();
738          Iterator it = cs.connections();
739          while (it.hasNext()) {
740             ConnectionSet.Connection c =
741                (ConnectionSet.Connection) it.next();
742             Object JavaDoc edge = c.getEdge();
743             if (c.isSource())
744                csundo.connect(edge, getSource(edge), true);
745             else
746                csundo.connect(edge, getTarget(edge), false);
747             handleConnection(c);
748          }
749          return csundo;
750       }
751       return null;
752    }
753
754    /**
755     * Inserts the specified connection into the model.
756     */

757    protected void handleConnection(ConnectionSet.Connection c) {
758       Object JavaDoc edge = c.getEdge();
759       Object JavaDoc old = (c.isSource()) ? getSource(edge) : getTarget(edge);
760       Object JavaDoc port = c.getPort();
761       if (port != old) {
762          connect(edge, old, c.isSource(), true);
763          if (contains(port) && contains(edge))
764             connect(edge, port, c.isSource(), false);
765       }
766    }
767
768    /**
769     * Connects or disconnects the edge and port in this model
770     * based on <code>remove</code>. Subclassers should override
771     * this to update connectivity datastructures.
772     */

773    protected void connect(
774       Object JavaDoc edge,
775       Object JavaDoc port,
776       boolean isSource,
777       boolean remove) {
778       if (port instanceof Port)
779          if (remove)
780                ((Port) port).removeEdge(edge);
781          else
782                ((Port) port).addEdge(edge);
783       if (remove)
784          port = null;
785       if (edge instanceof Edge) {
786          if (isSource)
787                ((Edge) edge).setSource(port);
788          else
789                ((Edge) edge).setTarget(port);
790       }
791    }
792
793    //
794
// GraphModelListeners
795
//
796

797    /**
798     * Adds a listener for the GraphModelEvent posted after the graph changes.
799     *
800     * @see #removeGraphModelListener
801     * @param l the listener to add
802     */

803    public void addGraphModelListener(GraphModelListener l) {
804       listenerList.add(GraphModelListener.class, l);
805    }
806
807    /**
808     * Removes a listener previously added with <B>addGraphModelListener()</B>.
809     *
810     * @see #addGraphModelListener
811     * @param l the listener to remove
812     */

813    public void removeGraphModelListener(GraphModelListener l) {
814       listenerList.remove(GraphModelListener.class, l);
815    }
816
817    /*
818     * Notify all listeners that have registered interest for
819     * notification on this event type. The event instance
820     * is lazily created using the parameters passed into
821     * the fire method.
822     * @see EventListenerList
823     */

824    protected void fireGraphChanged(
825       Object JavaDoc source,
826       GraphModelEvent.GraphModelChange edit) {
827       // Guaranteed to return a non-null array
828
Object JavaDoc[] listeners = listenerList.getListenerList();
829       GraphModelEvent e = null;
830       // Process the listeners last to first, notifying
831
// those that are interested in this event
832
for (int i = listeners.length - 2; i >= 0; i -= 2) {
833          if (listeners[i] == GraphModelListener.class) {
834             // Lazily create the event:
835
if (e == null)
836                e = new GraphModelEvent(source, edit);
837             ((GraphModelListener) listeners[i + 1]).graphChanged(e);
838          }
839       }
840    }
841
842    /**
843     * Return an array of all GraphModelListeners that were added to this model.
844     */

845    public GraphModelListener[] getGraphModelListeners() {
846       return (GraphModelListener[]) listenerList.getListeners(
847          GraphModelListener.class);
848    }
849
850    //
851
// GraphModelEdit
852
//
853

854    /**
855     * An implementation of GraphModelChange that can be added to the model
856     * event.
857     */

858    public class GraphModelEdit
859       extends CompoundEdit
860       implements
861       GraphModelEvent.GraphModelChange,
862       GraphModelEvent.ExecutableGraphChange {
863
864       /* Edit name. */
865       protected String JavaDoc name;
866
867       /* Cells that were inserted/removed/changed during the last execution. */
868       protected Object JavaDoc[] insert, changed, remove, context;
869
870       /* Cells that were inserted/removed/changed during the last execution. */
871       protected Object JavaDoc[] inserted, removed;
872
873       /* Property map for the next execution. Attribute Map is
874        passed to the views on inserts. */

875       protected Map attributes, previousAttributes;
876
877       /* Parent map for the next execution. */
878       protected ParentMap parentMap, previousParentMap;
879
880       /* ConnectionSet for the next execution. */
881       protected ConnectionSet connectionSet, previousConnectionSet;
882
883       /* Piggybacked undo from the views. */
884       protected Map cellViews = new Hashtable();
885
886       /**
887        *
888        * Constructs an edit record.
889        *
890        * @param inserted a set of roots that were inserted
891        * @param removed a set of elements that were removed
892        * @param attributes
893        * @param connectionSet
894        * @param parentMap
895        * @param name
896        */

897       public GraphModelEdit(
898          Object JavaDoc[] inserted,
899          Object JavaDoc[] removed,
900          Map attributes,
901          ConnectionSet connectionSet,
902          ParentMap parentMap,
903          String JavaDoc name) {
904          super();
905          this.insert = inserted;
906          this.remove = removed;
907          this.connectionSet = connectionSet;
908          this.attributes = attributes;
909          this.parentMap = parentMap;
910          this.name=name;
911          previousAttributes = attributes;
912          previousConnectionSet = connectionSet;
913          previousParentMap = parentMap;
914          // Remove Empty Parents
915
if (parentMap != null) {
916             // Compute Empty Group
917
/*Map childCount = new Hashtable();
918              Iterator it = parentMap.entries();
919              while (it.hasNext()) {
920              ParentMap.Entry entry = (ParentMap.Entry) it.next();
921              Object child = entry.getChild();
922              if (!isPort(child)) {
923              Object oldParent = getParent(child);
924              Object newParent = entry.getParent();
925              if (oldParent != newParent) {
926              changeChildCount(childCount, oldParent, -1);
927              changeChildCount(childCount, newParent, 1);
928              }
929              }
930              }
931              handleEmptyGroups(filterParents(childCount, 0));*/

932          }
933       }
934
935
936       public Object JavaDoc[] filterParents(Map childCount, int children) {
937          ArrayList list = new ArrayList();
938          Iterator it = childCount.entrySet().iterator();
939          while (it.hasNext()) {
940             Map.Entry entry = (Map.Entry) it.next();
941             if (entry.getValue() instanceof Integer JavaDoc) {
942                if (((Integer JavaDoc) entry.getValue()).intValue() == children)
943                   list.add(entry.getKey());
944             }
945          }
946          return list.toArray();
947       }
948
949       protected void changeChildCount(Map childCount, Object JavaDoc parent, int change) {
950          if (parent != null) {
951             Integer JavaDoc count = (Integer JavaDoc) childCount.get(parent);
952             if (count == null) {
953                count = new Integer JavaDoc(getChildCount(parent));
954             }
955             int newValue = count.intValue() + change;
956             childCount.put(parent, new Integer JavaDoc(newValue));
957          }
958       }
959
960       /**
961        * Adds the groups that become empty to the cells that
962        * will be removed. (Auto remove empty cells.) Removed
963        * cells will be re-inserted on undo, and the parent-
964        * child relations will be restored.
965        */

966       protected void handleEmptyGroups(Object JavaDoc[] groups) {
967          if (groups != null && groups.length > 0) {
968             if (remove == null)
969                remove = new Object JavaDoc[] {
970                };
971             Object JavaDoc[] tmp = new Object JavaDoc[remove.length + groups.length];
972             System.arraycopy(remove, 0, tmp, 0, remove.length);
973             System.arraycopy(groups, 0, tmp, remove.length, groups.length);
974             remove = tmp;
975          }
976       }
977
978       public boolean isSignificant() {
979          return true;
980       }
981
982       /**
983        * Returns <code>getPresentationName</code> from the
984        * last <code>UndoableEdit</code> added to
985        * <code>edits</code>. If <code>edits</code> is empty,
986        * calls super.
987        */

988       public String JavaDoc getPresentationName() {
989          return name;
990       }
991
992       /**
993        * Returns the source of this change. This can either be a
994        * view or a model, if this change is a GraphModelChange.
995        */

996       public Object JavaDoc getSource() {
997          return JaWEGraphModel.this;
998       }
999
1000      /**
1001       * Returns the cells that have changed. This includes the cells
1002       * that have been changed through a call to getAttributes and the
1003       * edges that have been changed with the ConnectionSet.
1004       */

1005      public Object JavaDoc[] getChanged() {
1006         return changed;
1007      }
1008
1009      /**
1010       * Returns the objects that have not changed explicitly, but
1011       * implicitly because one of their dependent cells has changed.
1012       */

1013      public Object JavaDoc[] getContext() {
1014         return context;
1015      }
1016
1017      /**
1018       * Returns the cells that were inserted.
1019       */

1020      public Object JavaDoc[] getInserted() {
1021         return inserted;
1022      }
1023
1024      /**
1025       * Returns the cells that were inserted.
1026       */

1027      public Object JavaDoc[] getRemoved() {
1028         return removed;
1029      }
1030
1031
1032      /**
1033       * Returns a map that contains (object, map) pairs
1034       * of the attributes that have been stored in the model.
1035       */

1036      public Map getPreviousAttributes() {
1037         return previousAttributes;
1038      }
1039
1040      /**
1041       * Returns a map of (object, view attributes). The objects
1042       * are model objects which need to be mapped to views.
1043       */

1044      public Map getAttributes() {
1045         return attributes;
1046      }
1047
1048      /**
1049       * Returns the connectionSet.
1050       * @return ConnectionSet
1051       */

1052      public ConnectionSet getConnectionSet() {
1053         return connectionSet;
1054      }
1055
1056      public ConnectionSet getPreviousConnectionSet() {
1057         return previousConnectionSet;
1058      }
1059
1060      /**
1061       * Returns the parentMap.
1062       * @return ParentMap
1063       */

1064      public ParentMap getParentMap() {
1065         return parentMap;
1066      }
1067
1068      public ParentMap getPreviousParentMap() {
1069         return previousParentMap;
1070      }
1071
1072      /**
1073       * Redoes a change.
1074       *
1075       * @exception CannotRedoException if the change cannot be redone
1076       */

1077      public void redo() throws CannotRedoException {
1078         super.redo();
1079         execute();
1080      }
1081
1082      /**
1083       * Undoes a change.
1084       *
1085       * @exception CannotUndoException if the change cannot be undone
1086       */

1087      public void undo() throws CannotUndoException {
1088         super.undo();
1089         execute();
1090      }
1091
1092      /**
1093       * Execute this edit such that the next invocation to this
1094       * method will invert the last execution.
1095       */

1096      public void execute() {
1097         // Compute Changed Cells
1098
Set tmp = new HashSet();
1099         if (attributes != null)
1100            tmp.addAll(attributes.keySet());
1101         if (parentMap != null)
1102            tmp.addAll(parentMap.getChangedNodes());
1103         // Note: One must also include the previous parents!
1104
if (connectionSet != null)
1105            tmp.addAll(connectionSet.getChangedEdges());
1106         if (remove != null) {
1107            for (int i = 0; i < remove.length; i++)
1108               tmp.remove(remove[i]);
1109         }
1110         changed = tmp.toArray();
1111         // Context cells
1112
Set ctx = getEdges(JaWEGraphModel.this, changed);
1113         context = ctx.toArray();
1114         // Do Execute
1115
inserted = insert;
1116         removed = remove;
1117         remove = handleInsert(inserted);
1118         previousParentMap = parentMap;
1119         parentMap = handleParentMap(parentMap);
1120         if (parentMap != null)
1121            tmp.addAll(parentMap.getChangedNodes());
1122         previousConnectionSet = connectionSet;
1123         connectionSet = handleConnectionSet(connectionSet);
1124         insert = handleRemove(removed);
1125         previousAttributes = attributes;
1126         attributes = handleAttributes(attributes);
1127         changed = tmp.toArray();
1128         // Fire Event
1129
fireGraphChanged(JaWEGraphModel.this, this);
1130      }
1131
1132      public void putViews(GraphLayoutCache view, CellView[] views) {
1133         if (view != null && views != null)
1134            cellViews.put(view, views);
1135      }
1136
1137      public CellView[] getViews(GraphLayoutCache view) {
1138         return (CellView[]) cellViews.get(view);
1139      }
1140
1141      public String JavaDoc toString() {
1142         String JavaDoc s = new String JavaDoc();
1143         if (inserted != null) {
1144            s += "Inserted:\n";
1145            for (int i = 0; i < inserted.length; i++)
1146               s += " " + inserted[i] + "\n";
1147         } else
1148            s += "None inserted\n";
1149         if (removed != null) {
1150            s += "Removed:\n";
1151            for (int i = 0; i < removed.length; i++)
1152               s += " " + removed[i] + "\n";
1153         } else
1154            s += "None removed\n";
1155         if (changed != null && changed.length > 0) {
1156            s += "Changed:\n";
1157            for (int i = 0; i < changed.length; i++)
1158               s += " " + changed[i] + "\n";
1159         } else
1160            s += "None changed\n";
1161         if (parentMap != null)
1162            s += parentMap.toString();
1163         else
1164            s += "No parent map\n";
1165         return s;
1166      }
1167
1168   } // ended class GraphModelEdit
1169

1170
1171   /**
1172    * An implementation of GraphViewChange.
1173    */

1174   public class GraphModelLayerEdit
1175      extends GraphLayoutCache.GraphViewLayerEdit
1176      implements GraphModelEvent.GraphModelChange {
1177
1178      // The cell that change are the parents, because they need to
1179
// reload their childs for reordering!
1180
protected Object JavaDoc[] parents;
1181
1182      /**
1183       * Constructs a GraphModelEdit. This modifies the order of the cells
1184       * in the model.
1185       */

1186      public GraphModelLayerEdit(Object JavaDoc[] cells, int layer) {
1187         super(JaWEGraphModel.this, cells, layer);
1188         // Construct Parent Array
1189
Set par = new HashSet();
1190         for (int i = 0; i < cells.length; i++) {
1191            if (cells[i] instanceof TreeNode)
1192               par.add(((TreeNode) cells[i]).getParent());
1193         }
1194         parents = par.toArray();
1195      }
1196
1197      public void execute () {
1198         super.execute();
1199      }
1200
1201      /**
1202       * Returns the source of this change. This can either be a
1203       * view or a model, if this change is a GraphModelChange.
1204       */

1205      public Object JavaDoc getSource() {
1206         return JaWEGraphModel.this;
1207      }
1208
1209      /**
1210       * Returns the cells that have changed.
1211       */

1212      public Object JavaDoc[] getChanged() {
1213         return parents;
1214      }
1215
1216      /**
1217       * Returns the cells that have changed.
1218       */

1219      public Object JavaDoc[] getInserted() {
1220         return null;
1221      }
1222
1223      /**
1224       * Returns the cells that have changed.
1225       */

1226      public Object JavaDoc[] getRemoved() {
1227         return null;
1228      }
1229
1230      /**
1231       * Returns null.
1232       */

1233      public Map getPreviousAttributes() {
1234         return null;
1235      }
1236      public ConnectionSet getPreviousConnectionSet() {
1237         return null;
1238      }
1239
1240      public ParentMap getPreviousParentMap() {
1241         return null;
1242      }
1243      /**
1244       * Allows a <code>GraphLayoutCache</code> to add and execute and
1245       * UndoableEdit in this change. This does also work if the
1246       * parent edit has already been executed, in which case the
1247       * to be added edit will be executed immediately, after
1248       * addition.
1249       * This is used to handle changes to the view that are
1250       * triggered by certain changes of the model. Such implicit
1251       * edits may be associated with the view so that they may be
1252       * undone and redone correctly, and are stored in the model's
1253       * global history together with the parent event as one unit.
1254       */

1255      public void addImplicitEdit(UndoableEdit edit) {
1256         // ignore
1257
}
1258
1259      /**
1260       * Returns the views that have not changed explicitly, but
1261       * implicitly because one of their dependent cells has changed.
1262       */

1263      public CellView[] getViews(GraphLayoutCache view) {
1264         return null;
1265      }
1266
1267      /**
1268       * Returns the views that have not changed explicitly, but
1269       * implicitly because one of their dependent cells has changed.
1270       */

1271      public void putViews(GraphLayoutCache view, CellView[] cellViews) {
1272         // ignore
1273
}
1274
1275      protected void updateListeners() {
1276         fireGraphChanged(JaWEGraphModel.this, this);
1277      }
1278
1279      /**
1280       * Returns the list that exclusively contains <code>view</code>.
1281       */

1282      protected List getParentList(Object JavaDoc cell) {
1283         List list = null;
1284         if (cell instanceof DefaultMutableTreeNode) {
1285            Object JavaDoc parent = ((DefaultMutableTreeNode) cell).getParent();
1286            if (parent instanceof DefaultGraphCell)
1287               list = ((DefaultGraphCell) parent).getChildren();
1288            else
1289               list = roots;
1290         }
1291         return list;
1292      }
1293
1294   }
1295
1296   //
1297
// Static Methods
1298
//
1299

1300   /**
1301    * Returns the source vertex of the edge by calling getParent on
1302    * getSource on the specified model.
1303    */

1304   public static Object JavaDoc getSourceVertex(GraphModel model, Object JavaDoc edge) {
1305      if (model != null)
1306         return model.getParent(model.getSource(edge));
1307      return null;
1308   }
1309
1310   /**
1311    * Returns the target vertex of the edge by calling getParent on
1312    * getTarget on the specified model.
1313    */

1314   public static Object JavaDoc getTargetVertex(GraphModel model, Object JavaDoc edge) {
1315      if (model != null)
1316         return model.getParent(model.getTarget(edge));
1317      return null;
1318   }
1319
1320   /**
1321    * Returns the roots of the specified model as an array.
1322    */

1323   public static Object JavaDoc[] getRoots(GraphModel model) {
1324      if (model instanceof JaWEGraphModel)
1325         return ((JaWEGraphModel) model).roots.toArray();
1326      Object JavaDoc[] cells = null;
1327      if (model != null) {
1328         cells = new Object JavaDoc[model.getRootCount()];
1329         for (int i = 0; i < cells.length; i++)
1330            cells[i] = model.getRootAt(i);
1331      }
1332      return cells;
1333   }
1334
1335   /**
1336    * Returns the root participants of the specified model as a set.
1337    */

1338   public static Set getRootParticipants(GraphModel model) {
1339      Object JavaDoc[] roots=getRoots(model);
1340      if (roots==null || roots.length==0) return null;
1341
1342      Set rootDeps=new HashSet();
1343
1344      // extracting only participants (transitions are also roots)
1345
for (int i=0; i<roots.length; i++) {
1346         if (roots[i] instanceof Participant) {
1347            rootDeps.add(roots[i]);
1348         }
1349      }
1350
1351      return rootDeps;
1352   }
1353
1354   /**
1355    * Return the set of edges that are connected to the
1356    * specified cells. The array is flattened and then
1357    * all attached edges that are not part of the cells
1358    * array are returned.
1359    */

1360   public static Set getEdges(GraphModel model, Object JavaDoc[] cells) {
1361      Set result = new HashSet();
1362      Set allCells = getDescendants(model, cells);
1363      if (allCells != null) {
1364         Iterator it = allCells.iterator();
1365         while (it.hasNext()) {
1366            Iterator edges = model.edges(it.next());
1367            while (edges.hasNext())
1368               result.add(edges.next());
1369         }
1370         result.removeAll(allCells);
1371      }
1372      return result;
1373   }
1374
1375   /**
1376    * Flattens the given array of root cells by adding the roots
1377    * and their descandants. The resulting set contains all cells,
1378    * which means it contains branches <strong>and</strong> leafs.
1379    * Note: This is an iterative implementation. No recursion used.
1380    */

1381   public static Set getDescendants(GraphModel model, Object JavaDoc[] cells) {
1382      if (cells != null) {
1383         Stack stack = new Stack();
1384         for (int i = 0; i < cells.length; i++)
1385            stack.add(cells[i]);
1386         HashSet result = new HashSet();
1387         while (!stack.isEmpty()) {
1388            Object JavaDoc tmp = stack.pop();
1389            for (int i = 0; i < model.getChildCount(tmp); i++)
1390               stack.add(model.getChild(tmp, i));
1391            if (tmp != null)
1392               result.add(tmp);
1393         }
1394         return result;
1395      }
1396      return null;
1397   }
1398
1399   public static List getDescendantList(GraphModel model, Object JavaDoc[] cells) {
1400      if (cells != null) {
1401         Stack stack = new Stack();
1402         for (int i = cells.length-1; i >= 0; i--)
1403            stack.add(cells[i]);
1404         LinkedList result = new LinkedList();
1405         while (!stack.isEmpty()) {
1406            Object JavaDoc tmp = stack.pop();
1407            for (int i = model.getChildCount(tmp)-1; i >= 0; i--)
1408               stack.add(model.getChild(tmp, i));
1409            if (tmp != null)
1410               result.add(tmp);
1411         }
1412         return result;
1413      }
1414      return null;
1415   }
1416
1417   /**
1418    * Gets all existing cells within model.
1419    */

1420   public static Set getAllCellsInModel (GraphModel model) {
1421      Set allCellsInModel=getDescendants(model,getRoots(model));
1422      if (allCellsInModel == null || allCellsInModel.size()==0) {
1423         return null;
1424      }
1425      else {
1426         return allCellsInModel;
1427      }
1428   }
1429
1430   /**
1431    * Gets all existing participants within model.
1432    */

1433   public static Set getAllParticipantsInModel (GraphModel model) {
1434      if (!(model instanceof JaWEGraphModel)) return null;
1435
1436      Set allCellsInModel=getAllCellsInModel(model);
1437      if (allCellsInModel == null) {
1438         return null;
1439      }
1440      else {
1441         Set participants=new HashSet();
1442         Iterator it=allCellsInModel.iterator();
1443         while (it.hasNext()) {
1444            Object JavaDoc cell=it.next();
1445            if (cell instanceof Participant) {
1446               participants.add(cell);
1447            }
1448         }
1449         if (participants.size()==0) {
1450            return null;
1451         }
1452         else {
1453            return participants;
1454         }
1455      }
1456   }
1457
1458   /**
1459    * Gets all existing activities within model.
1460    * <BR>NOTE:subflows are instances of activities.
1461    */

1462   public static Set getAllActivitiesInModel (GraphModel model) {
1463      if (!(model instanceof JaWEGraphModel)) return null;
1464
1465      Set allCellsInModel=getAllCellsInModel(model);
1466      if (allCellsInModel == null) {
1467         return null;
1468      }
1469      else {
1470         Set activities=new HashSet();
1471         Iterator it=allCellsInModel.iterator();
1472         while (it.hasNext()) {
1473            Object JavaDoc cell=it.next();
1474            if (cell instanceof Activity) {
1475               activities.add(cell);
1476            }
1477         }
1478         if (activities.size()==0) {
1479            return null;
1480         }
1481         else {
1482            return activities;
1483         }
1484      }
1485   }
1486
1487   /**
1488    * Gets all existing transitions within model.
1489    */

1490   public static Set getAllTransitionsInModel (GraphModel model) {
1491      if (!(model instanceof JaWEGraphModel)) return null;
1492      // Transitions are root objects
1493
Object JavaDoc[] roots=getRoots(model);
1494      if (roots==null || roots.length==0) return null;
1495
1496      Set transitions=new HashSet();
1497
1498      // extracting only transitions (participants are also roots)
1499
for (int i=0; i<roots.length; i++) {
1500         if (roots[i] instanceof Transition) {
1501            transitions.add(roots[i]);
1502         }
1503      }
1504
1505      return transitions;
1506   }
1507
1508   // Serialization support
1509
private void readObject(ObjectInputStream s)
1510      throws IOException, ClassNotFoundException JavaDoc {
1511      s.defaultReadObject();
1512      listenerList = new EventListenerList();
1513      emptyIterator = new EmptyIterator();
1514   }
1515
1516   public static class EmptyIterator implements Iterator, Serializable {
1517
1518      public boolean hasNext() {
1519         return false;
1520      }
1521
1522      public Object JavaDoc next() {
1523         return null;
1524      }
1525
1526      public void remove() {
1527         // nop
1528
}
1529   }
1530
1531}
1532
1533/* PEGraphModel.java */
1534
Popular Tags