View Javadoc

1   /*
2    * Copyright (c) 2005, The K-Wf Grid Consortium
3    * Fraunhofer Institute for Computer Architecture and Software Technology
4    * See http://www.kwfgrid.eu and http://www.first.fraunhofer.de for more details.
5    */
6   package net.kwfgrid.gwui.graphview;
7   
8   import net.kwfgrid.gwui.util.*;
9   import net.kwfgrid.gworkflowdl.protocol.structure.*;
10  import net.kwfgrid.gworkflowdl.structure.*;
11  
12  import java.util.*;
13  import javax.swing.*;
14  import java.beans.*;
15  
16  import org.apache.log4j.Logger;
17  
18  import org.glassbox.gui.Visible;
19  import org.glassbox.graphview.GGraphPane;
20  
21  import de.fzi.wim.guibase.graphview.layout.Layouter;
22  import de.fzi.wim.guibase.graphview.graph.Graph;
23  import de.fzi.wim.guibase.graphview.graph.Node;
24  
25  /***
26     A view for the workflow graph.
27   */
28  public class WorkflowGraphView implements IStructureListenerExt, Visible, PropertyChangeListener {
29      private static final Logger logger = Logger.getLogger(WorkflowGraphView.class);
30  
31      private ProtocolWorkflow _workflow;
32      private GGraphPane _graphpane;
33      /*** Place/Transition -> Node */
34      private HashMap _nodestoadd;
35      private List _nodestoremove;
36      /*** PlaceID/TransitionID -> Node */
37      private HashMap _tnodestoremove, _pnodestoremove;
38      private List _edgestoadd, _edgestoremove;
39      /*** (PlaceID, TransitionID) -> Edge */
40      private HashMapOfMaps _readedgestoremove, _inedgestoremove, _outedgestoremove;
41      private WorkflowGraphAnalyzer _analyzer;
42      private Layouter _layouter;
43      private LayoutFactory _layoutfactory;
44  
45      public WorkflowGraphView(WorkflowGraphAnalyzer analyzer, LayoutFactory layoutfactory) {
46  	_workflow = null;
47  	_graphpane = null;
48  	_edgestoadd = new LinkedList();
49  	_edgestoremove = new LinkedList();
50  	_nodestoadd = new HashMap();
51  	_nodestoremove = new LinkedList();
52  	_tnodestoremove = new HashMap();
53  	_pnodestoremove = new HashMap();
54      _readedgestoremove = new HashMapOfMaps();
55  	_inedgestoremove = new HashMapOfMaps();
56  	_outedgestoremove = new HashMapOfMaps();
57  	_layouter = null;
58  	_analyzer = analyzer;
59  	_layouter = null;
60  	if (layoutfactory == null) layoutfactory = NullLayoutFactory.getInstance();
61  	_layoutfactory = layoutfactory;
62      }
63      
64      ///
65      /// Public API
66      /// ....................................................................................................
67  
68      /***
69         Set the displayed workflow.
70      */
71      public void setWorkflow(ProtocolWorkflow workflow) {
72  	logger.debug("New workflow instance set: "+workflow);
73  
74  	if (_workflow!=null) {
75  	    _workflow.removeStructureListener(this);
76  	}
77  
78  	_workflow = workflow;
79  
80  	if (_workflow == null) {
81  	    _graphpane.setGraph(null);
82  	} else {
83  	    _workflow.addStructureListener(this);
84  	    buildNewGraph();
85  	}
86      }
87  
88      /*** 
89  	Set the <code>LayoutFactory</code> used by this view.
90  	This will immediately create a new layout based on the new factory.
91      */
92      public void setLayoutFactory(LayoutFactory lfact) {
93  	if (lfact == null) lfact = NullLayoutFactory.getInstance();
94  	_layoutfactory = lfact;
95  	// FIXME: immediately create new layout.
96      }
97  
98      /***
99         Dispose this view.
100     */
101     public void dispose() {
102 	setWorkflow(null);
103     }
104     
105     /***
106        Get the GraphPane used for painting.
107     */
108     public GGraphPane getGraphPane() {
109 	return (GGraphPane)getView();
110     }
111     
112     /***
113        Get the graph.
114     */
115     public WorkflowGraph getGraph() {
116 	return (WorkflowGraph)getGraphPane().getGraph();
117     }
118     
119     ///
120     /// Implementation of PropertyChangeListener
121     /// ....................................................................................................
122 
123     public void propertyChange(PropertyChangeEvent e) {
124 	if ("graph".equals(e.getPropertyName())) {	    
125 	    notifyNewGraph((Graph)e.getNewValue());
126 	}
127     }
128 
129     /***
130        Notify the instance that a new graph should be layouted.
131     */
132     protected void notifyNewGraph(Graph graph) {
133 	if (_layouter != null) {
134 	    _layouter.stop();
135 	    _layouter = null;
136 	}
137 	if (graph != null) {
138 	    // _layouter = new Layouter(new DOTLayoutStrategy(getGraphPane(), (WorkflowGraph)graph));
139 	    _layouter = new Layouter(_layoutfactory.createLayoutStrategy(graph));
140 	    _layouter.start();
141 	}
142     }
143 
144     ///
145     /// Check methods for IStructureListener
146     /// ....................................................................................................
147 
148     private boolean isTransition(String namespace, String name) {
149 	return ProtocolTransition.NAME.equals(name) && ProtocolTransition.NAMESPACE.equals(namespace);
150     }
151 
152     private boolean isPlace(String namespace, String name) {
153 	return ProtocolPlace.NAME.equals(name) && ProtocolPlace.NAMESPACE.equals(namespace);
154     }
155 
156     private boolean isReadEdge(String namespace, String name) {
157 	return ProtocolEdge.NAME_READPLACE.equals(name) && ProtocolEdge.NAMESPACE.equals(namespace);
158     }
159 
160     private boolean isWriteEdge(String namespace, String name) {
161 	return ProtocolEdge.NAME_WRITEPLACE.equals(name) && ProtocolEdge.NAMESPACE.equals(namespace);
162     }
163 
164     private boolean isInEdge(String namespace, String name) {
165 	return ProtocolEdge.NAME_INPUTPLACE.equals(name) && ProtocolEdge.NAMESPACE.equals(namespace);
166     }
167 
168     private boolean isOutEdge(String namespace, String name) {
169 	return ProtocolEdge.NAME_OUTPUTPLACE.equals(name) && ProtocolEdge.NAMESPACE.equals(namespace);
170     }
171 
172     private ProtocolTransition isChildOfTransition(IStructureObject parent) {
173 	while (parent instanceof IChildObject) {
174 	    if (parent instanceof Transition) return (ProtocolTransition)parent;
175 	    parent = ((IChildObject)parent).getParent();
176 	}
177 	return null;
178     }
179 
180     private ProtocolPlace isChildOfPlace(IStructureObject parent) {
181 	while (parent instanceof IChildObject) {
182 	    if (parent instanceof Place) return (ProtocolPlace)parent;
183 	    parent = ((IChildObject)parent).getParent();
184 	}
185 	return null;
186     }
187 
188     private ProtocolEdge isChildOfReadEdge(IStructureObject parent) {
189 	while (parent instanceof IChildObject) {
190 	    if (parent instanceof Edge) {
191 		ProtocolEdge edge = (ProtocolEdge)parent;
192 		Transition transition = (Transition)edge.getParent();
193         if (edge == transition.getReadEdge(edge.getPlaceID())) {
194             return edge;
195         } else {
196 		    return null;
197 		}
198 	    }
199 	    parent = ((IChildObject)parent).getParent();
200 	}
201 	return null;
202     }
203 
204     private ProtocolEdge isChildOfInEdge(IStructureObject parent) {
205 	while (parent instanceof IChildObject) {
206 	    if (parent instanceof Edge) {
207 		ProtocolEdge edge = (ProtocolEdge)parent;
208 		Transition transition = (Transition)edge.getParent();
209         if (edge == transition.getInEdge(edge.getPlaceID())) {
210 		    return edge;
211 		} else {
212 		    return null;
213 		}
214 	    }
215 	    parent = ((IChildObject)parent).getParent();
216 	}
217 	return null;
218     }
219 
220     private ProtocolEdge isChildOfOutEdge(IStructureObject parent) {
221 	while (parent instanceof IChildObject) {
222 	    if (parent instanceof Edge) {
223 		ProtocolEdge edge = (ProtocolEdge)parent;
224 		Transition transition = (Transition)edge.getParent();
225 		if (edge == transition.getOutEdge(edge.getPlaceID())) return edge;
226 		else return null;
227 	    }
228 	    parent = ((IChildObject)parent).getParent();
229 	}
230 	return null;
231     }
232 
233     ///
234     /// Methods to update the Graph
235     /// ....................................................................................................
236 
237     private void buildNewGraph() {
238 	WorkflowGraph current = getGraph();
239 	GraphBuilder graphbuilder = null;
240 	if (current!=null) {
241 	    graphbuilder = new GraphBuilder2(current, _workflow);
242 	} else {
243 	    graphbuilder = new GraphBuilder(_workflow);
244 	}
245 	graphbuilder.build();
246 	current = graphbuilder.getGraph();
247 	_analyzer.updateWorkflowGraph(current);
248 	Iterator nodes = current.getNodes().iterator(); while (nodes.hasNext()) {
249 	    Node node = (Node)nodes.next();
250 	    node.setLocation(Integer.MAX_VALUE, Integer.MAX_VALUE);
251 	    if (node instanceof TransitionNode) 
252 		_analyzer.updateTransitionNode((TransitionNode)node);
253 	    else
254 		_analyzer.updatePlaceNode((PlaceNode)node);	    
255 	}
256 	Iterator edges = current.getEdges().iterator(); while (edges.hasNext()) {
257 	    ArcEdge edge = (ArcEdge)edges.next();
258         if (edge instanceof ReadEdge)
259         _analyzer.updateReadEdge((ReadEdge)edge);
260 	    else if (edge instanceof InEdge)
261 		_analyzer.updateInEdge((InEdge)edge);
262 	    else
263 		_analyzer.updateOutEdge((OutEdge)edge);
264 	}
265 	getGraphPane().setGraph(current);
266     }
267  
268     /// Helpers
269 
270     private TransitionNode getTransitionNode(Transition t) {
271 	TransitionNode node = (TransitionNode)_nodestoadd.get(t);
272 	if (node == null) node = getGraph().getTransitionNode(t);
273 	return node;
274     }
275 
276     private PlaceNode getPlaceNode(Place p) {
277 	PlaceNode node = (PlaceNode)_nodestoadd.get(p);
278 	if (node == null) node = getGraph().getPlaceNode(p);
279 	return node;
280     }
281 
282     /// Add Nodes 
283 
284     private void addTransitionNode(Transition transition) {
285 	TransitionNode removednode = (TransitionNode)_tnodestoremove.remove(transition.getID());
286 	if (removednode != null) {
287 	    removednode.setTransition(transition);
288 	    _analyzer.updateTransitionNode(removednode);
289 	} else {
290 	    TransitionNode tn = new TransitionNode(transition);
291 	    tn.setLocation(Integer.MIN_VALUE, Integer.MIN_VALUE);
292 	    _analyzer.updateTransitionNode(tn);
293 	    _nodestoadd.put(transition, tn);	    
294 	}
295     }
296 
297     private void addPlaceNode(Place place) {
298 	PlaceNode removednode = (PlaceNode)_pnodestoremove.remove(place.getID());
299 	if (removednode != null) {
300 	    removednode.setPlace(place);
301 	    _analyzer.updatePlaceNode(removednode);
302 	} else {
303 	    PlaceNode pn = new PlaceNode(place);
304 	    pn.setLocation(Integer.MIN_VALUE, Integer.MIN_VALUE);
305 	    _analyzer.updatePlaceNode(pn);
306 	    _nodestoadd.put(place, pn);	    
307 	}	
308     }
309 
310     private void addTransitionNodes(List transitions) {
311 	Iterator i = transitions.iterator(); while (i.hasNext()) {
312 	    addTransitionNode((Transition)i.next());
313 	}
314     }
315 
316     private void addPlaceNodes(List places) {
317 	Iterator i = places.iterator(); while (i.hasNext()) {
318 	    addPlaceNode((Place)i.next());
319 	}
320     }
321 
322     /// Remove Nodes 
323 
324     private void removeTransitionNodes(List transitions) {
325 	Iterator i = transitions.iterator(); while (i.hasNext()) {
326 	    Transition t = (Transition)i.next();
327 	    _tnodestoremove.put(t.getID(), getGraph().getTransitionNode(t));
328 	}
329     }
330 
331     private void removePlaceNodes(List places) {
332 	Iterator i = places.iterator(); while (i.hasNext()) {
333 	    Place p = (Place)i.next();
334 	    _pnodestoremove.put(p.getID(), getGraph().getPlaceNode(p));
335 	}
336     }
337 
338     /// Add Edges 
339 
340     private void addReadEdge(Edge arc, TransitionNode tonode) {
341 	ReadEdge removededge = (ReadEdge)_readedgestoremove.remove(arc.getPlace().getID(), tonode.getTransition().getID());
342 	if (removededge != null) {
343 	    removededge.setArc(arc);
344 	    _analyzer.updateReadEdge(removededge);
345 	} else {
346 	    Place from = arc.getPlace();
347 	    ReadEdge ae = new ReadEdge(getPlaceNode(from), tonode, arc);
348 	    _analyzer.updateReadEdge(ae);
349 	    _edgestoadd.add(ae);
350 	}
351     }
352 
353     private void addInEdge(Edge arc, TransitionNode tonode) {
354 	InEdge removededge = (InEdge)_inedgestoremove.remove(arc.getPlace().getID(), tonode.getTransition().getID());
355 	if (removededge != null) {
356 	    removededge.setArc(arc);
357 	    _analyzer.updateInEdge(removededge);
358 	} else {
359 	    Place from = arc.getPlace();
360 	    InEdge ae = new InEdge(getPlaceNode(from), tonode, arc);
361 	    _analyzer.updateInEdge(ae);
362 	    _edgestoadd.add(ae);	    
363 	}
364     }
365 
366     private void addOutEdge(Edge arc, TransitionNode fromnode) {
367 	OutEdge removededge = (OutEdge)_outedgestoremove.remove(arc.getPlace().getID(), fromnode.getTransition().getID());
368 	if (removededge != null) {
369 	    removededge.setArc(arc);
370 	    _analyzer.updateOutEdge(removededge);
371 	} else {
372 	    Place to = arc.getPlace();
373 	    OutEdge ae = new OutEdge(fromnode, getPlaceNode(to), arc);
374 	    _analyzer.updateOutEdge(ae);
375 	    _edgestoadd.add(ae);
376 	}
377     }
378     
379     private void addReadEdges(List edges, Transition to) {
380 	TransitionNode tonode = getTransitionNode(to);
381 	Iterator i = edges.iterator(); while (i.hasNext()) {
382 	    addReadEdge((Edge)i.next(), tonode);
383 	}
384     }
385 
386     private void addReadEdges(Transition to) {
387 	Edge[] edges = to.getReadEdges();
388 	TransitionNode tonode = getTransitionNode(to);
389 	for (int i = 0; i<edges.length; i++) {
390 	    addReadEdge(edges[i], tonode);
391 	}
392     }
393 
394     private void addInEdges(List edges, Transition to) {
395 	TransitionNode tonode = getTransitionNode(to);
396 	Iterator i = edges.iterator(); while (i.hasNext()) {
397 	    addInEdge((Edge)i.next(), tonode);
398 	}
399     }
400 
401     private void addInEdges(Transition to) {
402 	Edge[] edges = to.getInEdges();
403 	TransitionNode tonode = getTransitionNode(to);
404 	for (int i = 0; i<edges.length; i++) {
405 	    addInEdge(edges[i], tonode);
406 	}
407     }
408 
409     private void addOutEdges(List edges, Transition from) {
410 	TransitionNode fromnode = getTransitionNode(from);
411 	Iterator i = edges.iterator(); while (i.hasNext()) {
412 	    addOutEdge((Edge)i.next(), fromnode);
413 	}
414     }
415     
416     private void addOutEdges(Transition from) {
417 	Edge[] edges = from.getOutEdges();
418 	TransitionNode fromnode = getTransitionNode(from);
419 	for (int i = 0; i<edges.length; i++) {
420 	    addOutEdge(edges[i], fromnode);
421 	}
422     }
423 
424     private void addEdges(List transitions) {
425 	Iterator it = transitions.iterator(); while (it.hasNext()) {
426 	    Transition t = (Transition)it.next();
427         addReadEdges(t);
428         addInEdges(t);
429 	    addOutEdges(t);
430 	}
431     }
432 
433     /// Remove Edges
434 
435     private void removeEdges(List transitions) {
436 	Iterator it = transitions.iterator(); while (it.hasNext()) {
437 	    Transition t = (Transition)it.next();
438         Edge[] e = t.getReadEdges();
439         for (int i=0; i<e.length; i++) {
440         ArcEdge ae = getGraph().getReadEdge(e[i].getPlace(), t);
441         _readedgestoremove.put(e[i].getPlace().getID(), t.getID(), ae);
442         }
443 	    e = t.getInEdges();
444 	    for (int i=0; i<e.length; i++) {
445 		ArcEdge ae = getGraph().getInEdge(e[i].getPlace(), t);
446 		_inedgestoremove.put(e[i].getPlace().getID(), t.getID(), ae);
447 	    }
448 	    e = t.getOutEdges();
449 	    for (int i=0; i<e.length; i++) {
450 		ArcEdge ae = getGraph().getOutEdge(t, e[i].getPlace());
451 		_outedgestoremove.put(e[i].getPlace().getID(), t.getID(), ae);
452 	    }
453 	}
454     }
455 
456     private void removeReadEdges(List edges, Transition to) {
457 	Iterator i = edges.iterator(); while (i.hasNext()) {
458 	    Edge e = (Edge)i.next();
459 	    Place from = e.getPlace();
460 	    _readedgestoremove.put(e.getPlace().getID(), to.getID(), getGraph().getReadEdge(from, to));
461 	}
462     }
463 
464     private void removeInEdges(List edges, Transition to) {
465 	Iterator i = edges.iterator(); while (i.hasNext()) {
466 	    Edge e = (Edge)i.next();
467 	    Place from = e.getPlace();
468 	    _inedgestoremove.put(e.getPlace().getID(), to.getID(), getGraph().getInEdge(from, to));
469 	}
470     }
471 
472     private void removeOutEdges(List edges, Transition from) {
473 	Iterator i = edges.iterator(); while (i.hasNext()) {
474 	    Edge e = (Edge)i.next();
475 	    Place to = e.getPlace();
476 	    _outedgestoremove.put(e.getPlace().getID(), from.getID(), getGraph().getOutEdge(from, to));
477 	}
478     }
479 
480     /// Update Nodes
481 
482     private void updateTransitionNode(Transition t) {
483 	TransitionNode node = getTransitionNode(t);
484 	_analyzer.updateTransitionNode(node);
485 	((org.glassbox.graphview.GGraphPane)getView()).repaintNode(node);
486     }
487 
488     private void updatePlaceNode(Place p) {	
489 	PlaceNode node = getPlaceNode(p);
490 	_analyzer.updatePlaceNode(node);
491 	((org.glassbox.graphview.GGraphPane)getView()).repaintNode(node);
492     }
493 
494     /// Update Edges
495 
496     private void updateReadEdge(Edge e, Transition to) {
497 	Place from = e.getPlace();
498 	ReadEdge arc = getGraph().getReadEdge(from, to);
499 	_analyzer.updateReadEdge(arc);
500 	((org.glassbox.graphview.GGraphPane)getView()).repaintEdge(arc);
501     }
502 
503     private void updateInEdge(Edge e, Transition to) {
504 	Place from = e.getPlace();
505 	InEdge arc = getGraph().getInEdge(from, to); 
506 	_analyzer.updateInEdge(arc);
507 	((org.glassbox.graphview.GGraphPane)getView()).repaintEdge(arc);
508     }
509 
510     private void updateOutEdge(Edge e, Transition from) {
511 	Place to = e.getPlace();
512 	OutEdge arc = getGraph().getOutEdge(from, to); 
513 	_analyzer.updateOutEdge(arc);
514 	((org.glassbox.graphview.GGraphPane)getView()).repaintEdge(arc);
515     }
516     
517     ///
518     /// Implementation of IStructureListener
519     /// ....................................................................................................
520 
521     public void objectsAdded(IStructureObject parent, String namespace, String name, List objects) {
522 	logger.debug("Objects added: {"+namespace+"}"+name);
523 
524 	IChildObject dummy = null;
525 	if (isTransition(namespace, name)) {
526 	    addTransitionNodes(objects);
527 	    addEdges(objects);
528 	} else if (isPlace(namespace, name)) {
529 	    addPlaceNodes(objects);
530     } else if (isReadEdge(namespace, name)) {
531         addReadEdges(objects, (ProtocolTransition)parent);
532 	} else if (isInEdge(namespace, name)) {
533 	    addInEdges(objects, (ProtocolTransition)parent);
534 	} else if (isOutEdge(namespace, name)) {
535 	    addOutEdges(objects, (ProtocolTransition)parent);
536 	} else if ((dummy = isChildOfTransition(parent)) != null) {
537 	    updateTransitionNode((ProtocolTransition)dummy);
538 	} else if ((dummy = isChildOfPlace(parent)) != null) {
539 	    updatePlaceNode((ProtocolPlace)dummy);
540 	}
541     }
542 
543     public void objectsRemoved(IStructureObject parent, String namespace, String name, List objects) {
544 	logger.debug("Objects removed: {"+namespace+"}"+name);
545 
546 	IChildObject dummy = null;
547 	if (isTransition(namespace, name)) {
548 	    removeTransitionNodes(objects);
549 	    removeEdges(objects);
550 	} else if (isPlace(namespace, name)) {
551 	    removePlaceNodes(objects);
552     } else if (isReadEdge(namespace, name)) {
553         removeReadEdges(objects, (ProtocolTransition)parent);
554 	} else if (isInEdge(namespace, name)) {
555 	    removeInEdges(objects, (ProtocolTransition)parent);
556 	} else if (isOutEdge(namespace, name)) {
557 	    removeOutEdges(objects, (ProtocolTransition)parent);
558 	} else if ((dummy = isChildOfTransition(parent)) != null) {
559 	    updateTransitionNode((ProtocolTransition)dummy);
560 	} else if ((dummy = isChildOfPlace(parent)) != null) {
561 	    updatePlaceNode((ProtocolPlace)dummy);
562 	}
563     }
564 
565     public void propertyChanged(IStructureObject parent, String namespace, String name, Object newvalue) {
566 	logger.debug("Property changed: {"+namespace+"}"+name);
567 
568 	IChildObject dummy = null;
569     if ((dummy = isChildOfReadEdge(parent)) != null) {
570             updateReadEdge((ProtocolEdge)dummy, (ProtocolTransition)dummy.getParent());
571     } else if ((dummy = isChildOfInEdge(parent)) != null) {
572 	    updateInEdge((ProtocolEdge)dummy, (ProtocolTransition)dummy.getParent());
573 	} else if ((dummy = isChildOfOutEdge(parent)) != null) {
574 	    updateOutEdge((ProtocolEdge)dummy, (ProtocolTransition)dummy.getParent());
575 	} else if ((dummy = isChildOfTransition(parent)) != null) {
576 	    updateTransitionNode((ProtocolTransition)dummy);
577 	} else if ((dummy = isChildOfPlace(parent)) != null) {
578 	    updatePlaceNode((ProtocolPlace)dummy);
579 	} 
580     }
581 
582     public void beginModifications(IRootObject structure) {
583  	logger.debug("Got begin modifications.");
584 
585 	_edgestoadd.clear();
586 	_nodestoadd.clear();
587 	_edgestoremove.clear();
588 	_nodestoremove.clear();
589 	_pnodestoremove.clear();
590 	_tnodestoremove.clear();
591     _readedgestoremove.clear();
592     _inedgestoremove.clear();
593 	_outedgestoremove.clear();	
594     }
595 
596     public void endModifications(IRootObject structure) {
597  	logger.debug("Got end modifications.");
598 	logger.debug("Graph has "+getGraph().getNodes().size()+" nodes and "+getGraph().getEdges().size()+" edges.");
599 
600 	_nodestoremove.addAll(_pnodestoremove.values());
601 	_nodestoremove.addAll(_tnodestoremove.values());
602 
603     Iterator i = _readedgestoremove.values().iterator(); while (i.hasNext()) {
604         _edgestoremove.addAll(((Map)i.next()).values());
605     }
606 	i = _inedgestoremove.values().iterator(); while (i.hasNext()) {
607 	    _edgestoremove.addAll(((Map)i.next()).values());
608 	}
609 
610 	i = _outedgestoremove.values().iterator(); while (i.hasNext()) {
611 	    _edgestoremove.addAll(((Map)i.next()).values());
612 	}
613 
614 	if (_nodestoadd.values().size() > 0 || _edgestoadd.size() > 0) {
615 	    // invalidate complete layout. FIXME: this should be done in the Layouter but it is here to avoid 
616 	    // ugly picture.
617 	    Iterator nodes = getGraph().getNodes().iterator(); while (nodes.hasNext()) {
618 		Node node = (Node)nodes.next();
619 		node.setLocation(Integer.MIN_VALUE, Integer.MIN_VALUE);
620 	    }
621 	    
622 	    Iterator edges = getGraph().getEdges().iterator(); while (edges.hasNext()) {
623 		ArcEdge edge = (ArcEdge)edges.next();
624 		edge.setControlPoints(null);
625 		edge.setPointOfArrowAtStart(null);
626 		edge.setPointOfArrowAtEnd(null);
627 		edge.setLabelPosition(null);
628 	    }
629 	}
630 
631 	logger.debug("Removing "+_nodestoremove.size()+" nodes and "+_edgestoremove.size()+" edges.");
632 
633 	getGraph().deleteElements(_nodestoremove, _edgestoremove);
634 
635 	logger.debug("Adding "+_nodestoadd.values().size()+" nodes and "+_edgestoadd.size()+" edges.");
636 
637 	getGraph().addElements(_nodestoadd.values(), _edgestoadd);
638 	if (_nodestoadd.size() <= 1 && _edgestoadd.size() <= 1) {
639 	    if (!_nodestoadd.isEmpty())
640 		getGraphPane().repaintNode((de.fzi.wim.guibase.graphview.graph.Node)_nodestoadd.values().iterator().next());
641 	    if (!_edgestoadd.isEmpty())
642 		getGraphPane().repaintEdge((ArcEdge)_edgestoadd.get(0));
643 	} else {
644 	    getGraphPane().repaint();
645 	}	
646     }
647 
648     public void exception(IRootObject structure, Throwable x) {
649  	logger.debug("Got exception.");
650 	//
651     }
652 
653     ///
654     /// Implementation of Visible
655     /// ....................................................................................................
656 
657     public JComponent getView() {
658 	if (_graphpane == null) {
659 	    _graphpane = new GGraphPane(null);
660 	    _graphpane.addPropertyChangeListener(this);
661 	}
662 	return _graphpane;
663     }
664 }
665