All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.jgrapht.graph.DefaultListenableGraph Maven / Gradle / Ivy

/* ==========================================
 * JGraphT : a free Java graph-theory library
 * ==========================================
 *
 * Project Info:  http://jgrapht.sourceforge.net/
 * Project Creator:  Barak Naveh (http://sourceforge.net/users/barak_naveh)
 *
 * (C) Copyright 2003-2008, by Barak Naveh and Contributors.
 *
 * This program and the accompanying materials are dual-licensed under
 * either
 *
 * (a) the terms of the GNU Lesser General Public License version 2.1
 * as published by the Free Software Foundation, or (at your option) any
 * later version.
 *
 * or (per the licensee's choosing)
 *
 * (b) the terms of the Eclipse Public License v1.0 as published by
 * the Eclipse Foundation.
 */
/* ---------------------------
 * DefaultListenableGraph.java
 * ---------------------------
 * (C) Copyright 2003-2008, by Barak Naveh and Contributors.
 *
 * Original Author:  Barak Naveh
 * Contributor(s):   Christian Hammer
 *
 * $Id$
 *
 * Changes
 * -------
 * 24-Jul-2003 : Initial revision (BN);
 * 04-Aug-2003 : Strong refs to listeners instead of weak refs (BN);
 * 10-Aug-2003 : Adaptation to new event model (BN);
 * 07-Mar-2004 : Fixed unnecessary clone bug #819075 (BN);
 * 11-Mar-2004 : Made generic (CH);
 * 07-May-2006 : Changed from List to Set (JVS);
 * 28-May-2006 : Moved connectivity info from edge to graph (JVS);
 *
 */
package org.jgrapht.graph;

import java.util.*;

import org.jgrapht.*;
import org.jgrapht.event.*;
import org.jgrapht.util.*;


/**
 * A graph backed by the the graph specified at the constructor, which can be
 * listened by GraphListener s and by 
 * VertexSetListener s. Operations on this graph "pass through" to the to
 * the backing graph. Any modification made to this graph or the backing graph
 * is reflected by the other.
 *
 * 

This graph does not pass the hashCode and equals operations through * to the backing graph, but relies on Object's equals and * hashCode methods.

* * @author Barak Naveh * @see GraphListener * @see VertexSetListener * @since Jul 20, 2003 */ public class DefaultListenableGraph extends GraphDelegator implements ListenableGraph, Cloneable { private static final long serialVersionUID = 3977575900898471984L; private List> graphListeners = new ArrayList>(); private List> vertexSetListeners = new ArrayList>(); private FlyweightEdgeEvent reuseableEdgeEvent; private FlyweightVertexEvent reuseableVertexEvent; private boolean reuseEvents; /** * Creates a new listenable graph. * * @param g the backing graph. */ public DefaultListenableGraph(Graph g) { this(g, false); } /** * Creates a new listenable graph. If the reuseEvents flag is * set to true this class will reuse previously fired events * and will not create a new object for each event. This option increases * performance but should be used with care, especially in multithreaded * environment. * * @param g the backing graph. * @param reuseEvents whether to reuse previously fired event objects * instead of creating a new event object for each event. * * @throws IllegalArgumentException if the backing graph is already a * listenable graph. */ public DefaultListenableGraph(Graph g, boolean reuseEvents) { super(g); this.reuseEvents = reuseEvents; reuseableEdgeEvent = new FlyweightEdgeEvent(this, -1, null); reuseableVertexEvent = new FlyweightVertexEvent(this, -1, null); // the following restriction could be probably relaxed in the future. if (g instanceof ListenableGraph) { throw new IllegalArgumentException( "base graph cannot be listenable"); } } /** * If the reuseEvents flag is set to true this * class will reuse previously fired events and will not create a new object * for each event. This option increases performance but should be used with * care, especially in multithreaded environment. * * @param reuseEvents whether to reuse previously fired event objects * instead of creating a new event object for each event. */ public void setReuseEvents(boolean reuseEvents) { this.reuseEvents = reuseEvents; } /** * Tests whether the reuseEvents flag is set. If the flag is * set to true this class will reuse previously fired events * and will not create a new object for each event. This option increases * performance but should be used with care, especially in multithreaded * environment. * * @return the value of the reuseEvents flag. */ public boolean isReuseEvents() { return reuseEvents; } /** * @see Graph#addEdge(Object, Object) */ public E addEdge(V sourceVertex, V targetVertex) { E e = super.addEdge(sourceVertex, targetVertex); if (e != null) { fireEdgeAdded(e, sourceVertex, targetVertex); } return e; } /** * @see Graph#addEdge(Object, Object, Object) */ public boolean addEdge(V sourceVertex, V targetVertex, E e) { boolean added = super.addEdge(sourceVertex, targetVertex, e); if (added) { fireEdgeAdded(e, sourceVertex, targetVertex); } return added; } /** * @see ListenableGraph#addGraphListener(GraphListener) */ public void addGraphListener(GraphListener l) { addToListenerList(graphListeners, l); } /** * @see Graph#addVertex(Object) */ public boolean addVertex(V v) { boolean modified = super.addVertex(v); if (modified) { fireVertexAdded(v); } return modified; } /** * @see ListenableGraph#addVertexSetListener(VertexSetListener) */ public void addVertexSetListener(VertexSetListener l) { addToListenerList(vertexSetListeners, l); } /** * @see java.lang.Object#clone() */ public Object clone() { try { TypeUtil> typeDecl = null; DefaultListenableGraph g = TypeUtil.uncheckedCast(super.clone(), typeDecl); g.graphListeners = new ArrayList>(); g.vertexSetListeners = new ArrayList>(); return g; } catch (CloneNotSupportedException e) { // should never get here since we're Cloneable e.printStackTrace(); throw new RuntimeException("internal error"); } } /** * @see Graph#removeEdge(Object, Object) */ public E removeEdge(V sourceVertex, V targetVertex) { E e = super.removeEdge(sourceVertex, targetVertex); if (e != null) { fireEdgeRemoved(e, sourceVertex, targetVertex); } return e; } /** * @see Graph#removeEdge(Object) */ public boolean removeEdge(E e) { V sourceVertex = getEdgeSource(e); V targetVertex = getEdgeTarget(e); boolean modified = super.removeEdge(e); if (modified) { fireEdgeRemoved(e, sourceVertex, targetVertex); } return modified; } /** * @see ListenableGraph#removeGraphListener(GraphListener) */ public void removeGraphListener(GraphListener l) { graphListeners.remove(l); } /** * @see Graph#removeVertex(Object) */ public boolean removeVertex(V v) { if (containsVertex(v)) { Set touchingEdgesList = edgesOf(v); // copy set to avoid ConcurrentModificationException removeAllEdges(new ArrayList(touchingEdgesList)); super.removeVertex(v); // remove the vertex itself fireVertexRemoved(v); return true; } else { return false; } } /** * @see ListenableGraph#removeVertexSetListener(VertexSetListener) */ public void removeVertexSetListener(VertexSetListener l) { vertexSetListeners.remove(l); } /** * Notify listeners that the specified edge was added. * * @param edge the edge that was added. * @param source edge source * @param target edge target */ protected void fireEdgeAdded(E edge, V source, V target) { GraphEdgeChangeEvent e = createGraphEdgeChangeEvent( GraphEdgeChangeEvent.EDGE_ADDED, edge, source, target); for (GraphListener l : graphListeners) { l.edgeAdded(e); } } /** * Notify listeners that the specified edge was removed. * * @param edge the edge that was removed. * @param source edge source * @param target edge target */ protected void fireEdgeRemoved(E edge, V source, V target) { GraphEdgeChangeEvent e = createGraphEdgeChangeEvent( GraphEdgeChangeEvent.EDGE_REMOVED, edge, source, target); for (GraphListener l : graphListeners) { l.edgeRemoved(e); } } /** * Notify listeners that the specified vertex was added. * * @param vertex the vertex that was added. */ protected void fireVertexAdded(V vertex) { GraphVertexChangeEvent e = createGraphVertexChangeEvent( GraphVertexChangeEvent.VERTEX_ADDED, vertex); for (VertexSetListener l : vertexSetListeners) { l.vertexAdded(e); } for (GraphListener l : graphListeners) { l.vertexAdded(e); } } /** * Notify listeners that the specified vertex was removed. * * @param vertex the vertex that was removed. */ protected void fireVertexRemoved(V vertex) { GraphVertexChangeEvent e = createGraphVertexChangeEvent( GraphVertexChangeEvent.VERTEX_REMOVED, vertex); for (VertexSetListener l : vertexSetListeners) { l.vertexRemoved(e); } for (GraphListener l : graphListeners) { l.vertexRemoved(e); } } private static void addToListenerList( List list, L l) { if (!list.contains(l)) { list.add(l); } } private GraphEdgeChangeEvent createGraphEdgeChangeEvent( int eventType, E edge, V source, V target) { if (reuseEvents) { reuseableEdgeEvent.setType(eventType); reuseableEdgeEvent.setEdge(edge); reuseableEdgeEvent.setEdgeSource(source); reuseableEdgeEvent.setEdgeTarget(target); return reuseableEdgeEvent; } else { return new GraphEdgeChangeEvent( this, eventType, edge, source, target); } } private GraphVertexChangeEvent createGraphVertexChangeEvent( int eventType, V vertex) { if (reuseEvents) { reuseableVertexEvent.setType(eventType); reuseableVertexEvent.setVertex(vertex); return reuseableVertexEvent; } else { return new GraphVertexChangeEvent(this, eventType, vertex); } } /** * A reuseable edge event. * * @author Barak Naveh * @since Aug 10, 2003 */ private static class FlyweightEdgeEvent extends GraphEdgeChangeEvent { private static final long serialVersionUID = 3907207152526636089L; /** * @see GraphEdgeChangeEvent#GraphEdgeChangeEvent(Object, int, Edge) */ public FlyweightEdgeEvent(Object eventSource, int type, EE e) { super(eventSource, type, e); } /** * Sets the edge of this event. * * @param e the edge to be set. */ protected void setEdge(EE e) { this.edge = e; } protected void setEdgeSource(VV v) { this.edgeSource = v; } protected void setEdgeTarget(VV v) { this.edgeTarget = v; } /** * Set the event type of this event. * * @param type the type to be set. */ protected void setType(int type) { this.type = type; } } /** * A reuseable vertex event. * * @author Barak Naveh * @since Aug 10, 2003 */ private static class FlyweightVertexEvent extends GraphVertexChangeEvent { private static final long serialVersionUID = 3257848787857585716L; /** * @see GraphVertexChangeEvent#GraphVertexChangeEvent(Object, int, * Object) */ public FlyweightVertexEvent(Object eventSource, int type, VV vertex) { super(eventSource, type, vertex); } /** * Set the event type of this event. * * @param type type to be set. */ protected void setType(int type) { this.type = type; } /** * Sets the vertex of this event. * * @param vertex the vertex to be set. */ protected void setVertex(VV vertex) { this.vertex = vertex; } } } // End DefaultListenableGraph.java




© 2015 - 2024 Weber Informatics LLC | Privacy Policy