/*
* Copyright 2006 - 2013
* Stefan Balev <stefan.balev@graphstream-project.org>
* Julien Baudry <julien.baudry@graphstream-project.org>
* Antoine Dutot <antoine.dutot@graphstream-project.org>
* Yoann Pigné <yoann.pigne@graphstream-project.org>
* Guilhelm Savin <guilhelm.savin@graphstream-project.org>
*
* This file is part of GraphStream <http://graphstream-project.org>.
*
* GraphStream is a library whose purpose is to handle static or dynamic
* graph, create them from scratch, file or any source and display them.
*
* This program is free software distributed under the terms of two licenses, the
* CeCILL-C license that fits European law, and the GNU Lesser General Public
* License. You can use, modify and/ or redistribute the software under the terms
* of the CeCILL-C license as circulated by CEA, CNRS and INRIA at the following
* URL <http://www.cecill.info> or under the terms of the GNU LGPL as published by
* the Free Software Foundation, either version 3 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
* PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* The fact that you are presently reading this means that you have had
* knowledge of the CeCILL-C and LGPL licenses and that you accept their terms.
*/
package org.graphstream.stream;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import org.graphstream.graph.implementations.AbstractElement.AttributeChangeEvent;
import org.graphstream.stream.sync.SourceTime;
/**
* Base implementation of an input that provide basic sink handling.
*
* <p>
* This implementation can register a set of graph sinks (or separate sets of
* attributes or elements sinks) and provides protected methods to easily
* broadcast events to all the sinks (beginning with "send").
* </p>
*
* <p>
* Each time you want to produce an event toward all registered sinks, you call
* one of the "send*" methods with correct parameters. The parameters of the
* "send*" methods maps to the usual GraphStream events.
* </p>
*
* <p>
* This class is "reentrant". This means that if a send*() method is called
* during the execution of another or the same send*() method, the event is
* deferred until the first send*() method is finished. This avoid recursive
* loops if a sink modifies the input during event handling.
* </p>
*/
public abstract class SourceBase implements Source {
// Attribute
public enum ElementType {
NODE, EDGE, GRAPH
};
/**
* Set of graph attributes sinks.
*/
protected ArrayList<AttributeSink> attrSinks = new ArrayList<AttributeSink>();
/**
* Set of graph elements sinks.
*/
protected ArrayList<ElementSink> eltsSinks = new ArrayList<ElementSink>();
/**
* A queue that allow the management of events (nodes/edge
* add/delete/change) in the right order.
*/
protected LinkedList<GraphEvent> eventQueue = new LinkedList<GraphEvent>();
/**
* A boolean that indicates whether or not an Sink event is being sent
* during another one.
*/
protected boolean eventProcessing = false;
/**
* Id of this source.
*/
protected String sourceId;
/**
* Time of this source.
*/
protected SourceTime sourceTime;
// Construction
protected SourceBase() {
this(String.format("sourceOnThread#%d_%d", Thread.currentThread()
.getId(), System.currentTimeMillis()
+ ((int) (Math.random() * 1000))));
}
protected SourceBase(String sourceId) {
this.sourceId = sourceId;
this.sourceTime = new SourceTime(sourceId);
}
// Access
public Iterable<AttributeSink> attributeSinks() {
return attrSinks;
}
public Iterable<ElementSink> elementSinks() {
return eltsSinks;
}
// Command
public void addSink(Sink sink) {
addAttributeSink(sink);
addElementSink(sink);
}
public void addAttributeSink(AttributeSink sink) {
if (!eventProcessing) {
eventProcessing = true;
manageEvents();
attrSinks.add(sink);
manageEvents();
eventProcessing = false;
} else {
eventQueue.add(new AddToListEvent<AttributeSink>(attrSinks, sink));
}
}
public void addElementSink(ElementSink sink) {
if (!eventProcessing) {
eventProcessing = true;
manageEvents();
eltsSinks.add(sink);
manageEvents();
eventProcessing = false;
} else {
eventQueue.add(new AddToListEvent<ElementSink>(eltsSinks, sink));
}
}
public void clearSinks() {
clearElementSinks();
clearAttributeSinks();
}
public void clearElementSinks() {
if (!eventProcessing) {
eventProcessing = true;
manageEvents();
eltsSinks.clear();
manageEvents();
eventProcessing = false;
} else {
eventQueue.add(new ClearListEvent<ElementSink>(eltsSinks));
}
}
public void clearAttributeSinks() {
if (!eventProcessing) {
eventProcessing = true;
manageEvents();
attrSinks.clear();
manageEvents();
eventProcessing = false;
} else {
eventQueue.add(new ClearListEvent<AttributeSink>(attrSinks));
}
}
public void removeSink(Sink sink) {
removeAttributeSink(sink);
removeElementSink(sink);
}
public void removeAttributeSink(AttributeSink sink) {
if (!eventProcessing) {
eventProcessing = true;
manageEvents();
attrSinks.remove(sink);
manageEvents();
eventProcessing = false;
} else {
eventQueue.add(new RemoveFromListEvent<AttributeSink>(attrSinks,
sink));
}
}
public void removeElementSink(ElementSink sink) {
if (!eventProcessing) {
eventProcessing = true;
manageEvents();
eltsSinks.remove(sink);
manageEvents();
eventProcessing = false;
} else {
eventQueue
.add(new RemoveFromListEvent<ElementSink>(eltsSinks, sink));
}
}
/**
* Send a "graph cleared" event to all element sinks.
*
* @param sourceId
* The source identifier.
*/
public void sendGraphCleared(String sourceId) {
sendGraphCleared(sourceId, sourceTime.newEvent());
}
/**
* Send a "graph cleared" event to all element sinks.
*
* @param sourceId
* The source identifier.
* @param timeId
*/
public void sendGraphCleared(String sourceId, long timeId) {
if (!eventProcessing) {
eventProcessing = true;
manageEvents();
for (int i = 0; i < eltsSinks.size(); i++)
eltsSinks.get(i).graphCleared(sourceId, timeId);
manageEvents();
eventProcessing = false;
} else {
eventQueue.add(new BeforeGraphClearEvent(sourceId, timeId));
}
}
/**
* Send a "step begins" event to all element sinks.
*
* @param sourceId
* The graph identifier.
* @param step
* The step time stamp.
*/
public void sendStepBegins(String sourceId, double step) {
sendStepBegins(sourceId, sourceTime.newEvent(), step);
}
/**
* Send a "step begins" event to all element sinks.
*
* @param sourceId
* The graph identifier.
* @param timeId
* @param step
* The step time stamp.
*/
public void sendStepBegins(String sourceId, long timeId, double step) {
if (!eventProcessing) {
eventProcessing = true;
manageEvents();
for (int i = 0; i < eltsSinks.size(); i++)
eltsSinks.get(i).stepBegins(sourceId, timeId, step);
manageEvents();
eventProcessing = false;
} else {
eventQueue.add(new StepBeginsEvent(sourceId, timeId, step));
}
}
/**
* Send a "node added" event to all element sinks.
*
* @param sourceId
* The source identifier.
* @param nodeId
* The node identifier.
*/
public void sendNodeAdded(String sourceId, String nodeId) {
sendNodeAdded(sourceId, sourceTime.newEvent(), nodeId);
}
/**
* Send a "node added" event to all element sinks.
*
* @param sourceId
* The source identifier.
* @param timeId
* @param nodeId
* The node identifier.
*/
public void sendNodeAdded(String sourceId, long timeId, String nodeId) {
if (!eventProcessing) {
eventProcessing = true;
manageEvents();
for (int i = 0; i < eltsSinks.size(); i++)
eltsSinks.get(i).nodeAdded(sourceId, timeId, nodeId);
manageEvents();
eventProcessing = false;
} else {
eventQueue.add(new AfterNodeAddEvent(sourceId, timeId, nodeId));
}
}
/**
* Send a "node removed" event to all element sinks.
*
* @param sourceId
* The graph identifier.
* @param nodeId
* The node identifier.
*/
public void sendNodeRemoved(String sourceId, String nodeId) {
sendNodeRemoved(sourceId, sourceTime.newEvent(), nodeId);
}
/**
* Send a "node removed" event to all element sinks.
*
* @param sourceId
* The graph identifier.
* @param timeId
* @param nodeId
* The node identifier.
*/
public void sendNodeRemoved(String sourceId, long timeId, String nodeId) {
if (!eventProcessing) {
eventProcessing = true;
manageEvents();
for (int i = 0; i < eltsSinks.size(); i++)
eltsSinks.get(i).nodeRemoved(sourceId, timeId, nodeId);
manageEvents();
eventProcessing = false;
} else {
eventQueue.add(new BeforeNodeRemoveEvent(sourceId, timeId, nodeId));
}
}
/**
* Send an "edge added" event to all element sinks.
*
* @param sourceId
* The source identifier.
* @param edgeId
* The edge identifier.
* @param fromNodeId
* The edge start node.
* @param toNodeId
* The edge end node.
* @param directed
* Is the edge directed?.
*/
public void sendEdgeAdded(String sourceId, String edgeId,
String fromNodeId, String toNodeId, boolean directed) {
sendEdgeAdded(sourceId, sourceTime.newEvent(), edgeId, fromNodeId,
toNodeId, directed);
}
/**
* Send an "edge added" event to all element sinks.
*
* @param sourceId
* The source identifier.
* @param timeId
* @param edgeId
* The edge identifier.
* @param fromNodeId
* The edge start node.
* @param toNodeId
* The edge end node.
* @param directed
* Is the edge directed?.
*/
public void sendEdgeAdded(String sourceId, long timeId, String edgeId,
String fromNodeId, String toNodeId, boolean directed) {
if (!eventProcessing) {
eventProcessing = true;
manageEvents();
for (int i = 0; i < eltsSinks.size(); i++)
eltsSinks.get(i).edgeAdded(sourceId, timeId, edgeId,
fromNodeId, toNodeId, directed);
manageEvents();
eventProcessing = false;
} else {
eventQueue.add(new AfterEdgeAddEvent(sourceId, timeId, edgeId,
fromNodeId, toNodeId, directed));
}
}
/**
* Send a "edge removed" event to all element sinks.
*
* @param sourceId
* The source identifier.
* @param edgeId
* The edge identifier.
*/
public void sendEdgeRemoved(String sourceId, String edgeId) {
sendEdgeRemoved(sourceId, sourceTime.newEvent(), edgeId);
}
/**
* Send a "edge removed" event to all element sinks.
*
* @param sourceId
* The source identifier.
* @param timeId
* @param edgeId
* The edge identifier.
*/
public void sendEdgeRemoved(String sourceId, long timeId, String edgeId) {
if (!eventProcessing) {
eventProcessing = true;
manageEvents();
for (int i = 0; i < eltsSinks.size(); i++)
eltsSinks.get(i).edgeRemoved(sourceId, timeId, edgeId);
manageEvents();
eventProcessing = false;
} else {
eventQueue.add(new BeforeEdgeRemoveEvent(sourceId, timeId, edgeId));
}
}
/**
* Send a "edge attribute added" event to all attribute sinks.
*
* @param sourceId
* The source identifier.
* @param edgeId
* The edge identifier.
* @param attribute
* The attribute name.
* @param value
* The attribute value.
*/
public void sendEdgeAttributeAdded(String sourceId, String edgeId,
String attribute, Object value) {
sendAttributeChangedEvent(sourceId, edgeId, ElementType.EDGE,
attribute, AttributeChangeEvent.ADD, null, value);
}
/**
* Send a "edge attribute added" event to all attribute sinks.
*
* @param sourceId
* The source identifier.
* @param timeId
* @param edgeId
* The edge identifier.
* @param attribute
* The attribute name.
* @param value
* The attribute value.
*/
public void sendEdgeAttributeAdded(String sourceId, long timeId,
String edgeId, String attribute, Object value) {
sendAttributeChangedEvent(sourceId, timeId, edgeId, ElementType.EDGE,
attribute, AttributeChangeEvent.ADD, null, value);
}
/**
* Send a "edge attribute changed" event to all attribute sinks.
*
* @param sourceId
* The source identifier.
* @param edgeId
* The edge identifier.
* @param attribute
* The attribute name.
* @param oldValue
* The old attribute value.
* @param newValue
* The new attribute value.
*/
public void sendEdgeAttributeChanged(String sourceId, String edgeId,
String attribute, Object oldValue, Object newValue) {
sendAttributeChangedEvent(sourceId, edgeId, ElementType.EDGE,
attribute, AttributeChangeEvent.CHANGE, oldValue, newValue);
}
/**
* Send a "edge attribute changed" event to all attribute sinks.
*
* @param sourceId
* The source identifier.
* @param timeId
* @param edgeId
* The edge identifier.
* @param attribute
* The attribute name.
* @param oldValue
* The old attribute value.
* @param newValue
* The new attribute value.
*/
public void sendEdgeAttributeChanged(String sourceId, long timeId,
String edgeId, String attribute, Object oldValue, Object newValue) {
sendAttributeChangedEvent(sourceId, timeId, edgeId, ElementType.EDGE,
attribute, AttributeChangeEvent.CHANGE, oldValue, newValue);
}
/**
* Send a "edge attribute removed" event to all attribute sinks.
*
* @param sourceId
* The source identifier.
* @param edgeId
* The edge identifier.
* @param attribute
* The attribute name.
*/
public void sendEdgeAttributeRemoved(String sourceId, String edgeId,
String attribute) {
sendAttributeChangedEvent(sourceId, edgeId, ElementType.EDGE,
attribute, AttributeChangeEvent.REMOVE, null, null);
}
/**
* Send a "edge attribute removed" event to all attribute sinks.
*
* @param sourceId
* The source identifier.
* @param timeId
* @param edgeId
* The edge identifier.
* @param attribute
* The attribute name.
*/
public void sendEdgeAttributeRemoved(String sourceId, long timeId,
String edgeId, String attribute) {
sendAttributeChangedEvent(sourceId, timeId, edgeId, ElementType.EDGE,
attribute, AttributeChangeEvent.REMOVE, null, null);
}
/**
* Send a "graph attribute added" event to all attribute sinks.
*
* @param sourceId
* The source identifier.
* @param attribute
* The attribute name.
* @param value
* The attribute value.
*/
public void sendGraphAttributeAdded(String sourceId, String attribute,
Object value) {
sendAttributeChangedEvent(sourceId, null, ElementType.GRAPH, attribute,
AttributeChangeEvent.ADD, null, value);
}
/**
* Send a "graph attribute added" event to all attribute sinks.
*
* @param sourceId
* The source identifier.
* @param timeId
* @param attribute
* The attribute name.
* @param value
* The attribute value.
*/
public void sendGraphAttributeAdded(String sourceId, long timeId,
String attribute, Object value) {
sendAttributeChangedEvent(sourceId, timeId, null, ElementType.GRAPH,
attribute, AttributeChangeEvent.ADD, null, value);
}
/**
* Send a "graph attribute changed" event to all attribute sinks.
*
* @param sourceId
* The source identifier.
* @param attribute
* The attribute name.
* @param oldValue
* The attribute old value.
* @param newValue
* The attribute new value.
*/
public void sendGraphAttributeChanged(String sourceId, String attribute,
Object oldValue, Object newValue) {
sendAttributeChangedEvent(sourceId, null, ElementType.GRAPH, attribute,
AttributeChangeEvent.CHANGE, oldValue, newValue);
}
/**
* Send a "graph attribute changed" event to all attribute sinks.
*
* @param sourceId
* The source identifier.
* @param timeId
* @param attribute
* The attribute name.
* @param oldValue
* The attribute old value.
* @param newValue
* The attribute new value.
*/
public void sendGraphAttributeChanged(String sourceId, long timeId,
String attribute, Object oldValue, Object newValue) {
sendAttributeChangedEvent(sourceId, timeId, null, ElementType.GRAPH,
attribute, AttributeChangeEvent.CHANGE, oldValue, newValue);
}
/**
* Send a "graph attribute removed" event to all attribute sinks.
*
* @param sourceId
* The source identifier.
* @param attribute
* The attribute name.
*/
public void sendGraphAttributeRemoved(String sourceId, String attribute) {
sendAttributeChangedEvent(sourceId, null, ElementType.GRAPH, attribute,
AttributeChangeEvent.REMOVE, null, null);
}
/**
* Send a "graph attribute removed" event to all attribute sinks.
*
* @param sourceId
* The source identifier.
* @param timeId
* @param attribute
* The attribute name.
*/
public void sendGraphAttributeRemoved(String sourceId, long timeId,
String attribute) {
sendAttributeChangedEvent(sourceId, timeId, null, ElementType.GRAPH,
attribute, AttributeChangeEvent.REMOVE, null, null);
}
/**
* Send a "node attribute added" event to all attribute sinks.
*
* @param sourceId
* The source identifier.
* @param nodeId
* The node identifier.
* @param attribute
* The attribute name.
* @param value
* The attribute value.
*/
public void sendNodeAttributeAdded(String sourceId, String nodeId,
String attribute, Object value) {
sendAttributeChangedEvent(sourceId, nodeId, ElementType.NODE,
attribute, AttributeChangeEvent.ADD, null, value);
}
/**
* Send a "node attribute added" event to all attribute sinks.
*
* @param sourceId
* The source identifier.
* @param timeId
* @param nodeId
* The node identifier.
* @param attribute
* The attribute name.
* @param value
* The attribute value.
*/
public void sendNodeAttributeAdded(String sourceId, long timeId,
String nodeId, String attribute, Object value) {
sendAttributeChangedEvent(sourceId, timeId, nodeId, ElementType.NODE,
attribute, AttributeChangeEvent.ADD, null, value);
}
/**
* Send a "node attribute changed" event to all attribute sinks.
*
* @param sourceId
* The source identifier.
* @param nodeId
* The node identifier.
* @param attribute
* The attribute name.
* @param oldValue
* The attribute old value.
* @param newValue
* The attribute new value.
*/
public void sendNodeAttributeChanged(String sourceId, String nodeId,
String attribute, Object oldValue, Object newValue) {
sendAttributeChangedEvent(sourceId, nodeId, ElementType.NODE,
attribute, AttributeChangeEvent.CHANGE, oldValue, newValue);
}
/**
* Send a "node attribute changed" event to all attribute sinks.
*
* @param sourceId
* The source identifier.
* @param timeId
* @param nodeId
* The node identifier.
* @param attribute
* The attribute name.
* @param oldValue
* The attribute old value.
* @param newValue
* The attribute new value.
*/
public void sendNodeAttributeChanged(String sourceId, long timeId,
String nodeId, String attribute, Object oldValue, Object newValue) {
sendAttributeChangedEvent(sourceId, timeId, nodeId, ElementType.NODE,
attribute, AttributeChangeEvent.CHANGE, oldValue, newValue);
}
/**
* Send a "node attribute removed" event to all attribute sinks.
*
* @param sourceId
* The source identifier.
* @param nodeId
* The node identifier.
* @param attribute
* The attribute name.
*/
public void sendNodeAttributeRemoved(String sourceId, String nodeId,
String attribute) {
sendAttributeChangedEvent(sourceId, nodeId, ElementType.NODE,
attribute, AttributeChangeEvent.REMOVE, null, null);
}
/**
* Send a "node attribute removed" event to all attribute sinks.
*
* @param sourceId
* The source identifier.
* @param timeId
* @param nodeId
* The node identifier.
* @param attribute
* The attribute name.
*/
public void sendNodeAttributeRemoved(String sourceId, long timeId,
String nodeId, String attribute) {
sendAttributeChangedEvent(sourceId, timeId, nodeId, ElementType.NODE,
attribute, AttributeChangeEvent.REMOVE, null, null);
}
/**
* Send a add/change/remove attribute event on an element. This method is a
* generic way of notifying of an attribute change and is equivalent to
* individual send*Attribute*() methods.
*
* @param sourceId
* The source identifier.
* @param eltId
* The changed element identifier.
* @param eltType
* The changed element type.
* @param attribute
* The changed attribute.
* @param event
* The add/change/remove action.
* @param oldValue
* The old attribute value (null if the attribute is removed or
* added).
* @param newValue
* The new attribute value (null if removed).
*/
public void sendAttributeChangedEvent(String sourceId, String eltId,
ElementType eltType, String attribute, AttributeChangeEvent event,
Object oldValue, Object newValue) {
sendAttributeChangedEvent(sourceId, sourceTime.newEvent(), eltId,
eltType, attribute, event, oldValue, newValue);
}
public void sendAttributeChangedEvent(String sourceId, long timeId,
String eltId, ElementType eltType, String attribute,
AttributeChangeEvent event, Object oldValue, Object newValue) {
if (!eventProcessing) {
eventProcessing = true;
manageEvents();
if (event == AttributeChangeEvent.ADD) {
if (eltType == ElementType.NODE) {
for (int i = 0; i < attrSinks.size(); i++)
attrSinks.get(i).nodeAttributeAdded(sourceId, timeId,
eltId, attribute, newValue);
} else if (eltType == ElementType.EDGE) {
for (int i = 0; i < attrSinks.size(); i++)
attrSinks.get(i).edgeAttributeAdded(sourceId, timeId,
eltId, attribute, newValue);
} else {
for (int i = 0; i < attrSinks.size(); i++)
attrSinks.get(i).graphAttributeAdded(sourceId, timeId,
attribute, newValue);
}
} else if (event == AttributeChangeEvent.REMOVE) {
if (eltType == ElementType.NODE) {
for (int i = 0; i < attrSinks.size(); i++)
attrSinks.get(i).nodeAttributeRemoved(sourceId, timeId,
eltId, attribute);
} else if (eltType == ElementType.EDGE) {
for (int i = 0; i < attrSinks.size(); i++)
attrSinks.get(i).edgeAttributeRemoved(sourceId, timeId,
eltId, attribute);
} else {
for (int i = 0; i < attrSinks.size(); i++)
attrSinks.get(i).graphAttributeRemoved(sourceId,
timeId, attribute);
}
} else {
if (eltType == ElementType.NODE) {
for (int i = 0; i < attrSinks.size(); i++)
attrSinks.get(i).nodeAttributeChanged(sourceId, timeId,
eltId, attribute, oldValue, newValue);
} else if (eltType == ElementType.EDGE) {
for (int i = 0; i < attrSinks.size(); i++)
attrSinks.get(i).edgeAttributeChanged(sourceId, timeId,
eltId, attribute, oldValue, newValue);
} else {
for (int i = 0; i < attrSinks.size(); i++)
attrSinks.get(i).graphAttributeChanged(sourceId,
timeId, attribute, oldValue, newValue);
}
}
manageEvents();
eventProcessing = false;
} else {
eventQueue.add(new AttributeChangedEvent(sourceId, timeId, eltId,
eltType, attribute, event, oldValue, newValue));
}
}
// Deferred event management
/**
* If in "event processing mode", ensure all pending events are processed.
*/
protected void manageEvents() {
if (eventProcessing) {
while (!eventQueue.isEmpty())
eventQueue.remove().trigger();
}
}
// Events Management
/**
* Interface that provide general purpose classification for evens involved
* in graph modifications
*/
abstract class GraphEvent {
String sourceId;
long timeId;
GraphEvent(String sourceId, long timeId) {
this.sourceId = sourceId;
this.timeId = timeId;
}
abstract void trigger();
}
class AfterEdgeAddEvent extends GraphEvent {
String edgeId;
String fromNodeId;
String toNodeId;
boolean directed;
AfterEdgeAddEvent(String sourceId, long timeId, String edgeId,
String fromNodeId, String toNodeId, boolean directed) {
super(sourceId, timeId);
this.edgeId = edgeId;
this.fromNodeId = fromNodeId;
this.toNodeId = toNodeId;
this.directed = directed;
}
void trigger() {
for (int i = 0; i < eltsSinks.size(); i++)
eltsSinks.get(i).edgeAdded(sourceId, timeId, edgeId,
fromNodeId, toNodeId, directed);
}
}
class BeforeEdgeRemoveEvent extends GraphEvent {
String edgeId;
BeforeEdgeRemoveEvent(String sourceId, long timeId, String edgeId) {
super(sourceId, timeId);
this.edgeId = edgeId;
}
void trigger() {
for (int i = 0; i < eltsSinks.size(); i++)
eltsSinks.get(i).edgeRemoved(sourceId, timeId, edgeId);
}
}
class AfterNodeAddEvent extends GraphEvent {
String nodeId;
AfterNodeAddEvent(String sourceId, long timeId, String nodeId) {
super(sourceId, timeId);
this.nodeId = nodeId;
}
void trigger() {
for (int i = 0; i < eltsSinks.size(); i++)
eltsSinks.get(i).nodeAdded(sourceId, timeId, nodeId);
}
}
class BeforeNodeRemoveEvent extends GraphEvent {
String nodeId;
BeforeNodeRemoveEvent(String sourceId, long timeId, String nodeId) {
super(sourceId, timeId);
this.nodeId = nodeId;
}
void trigger() {
for (int i = 0; i < eltsSinks.size(); i++)
eltsSinks.get(i).nodeRemoved(sourceId, timeId, nodeId);
}
}
class BeforeGraphClearEvent extends GraphEvent {
BeforeGraphClearEvent(String sourceId, long timeId) {
super(sourceId, timeId);
}
void trigger() {
for (int i = 0; i < eltsSinks.size(); i++)
eltsSinks.get(i).graphCleared(sourceId, timeId);
}
}
class StepBeginsEvent extends GraphEvent {
double step;
StepBeginsEvent(String sourceId, long timeId, double step) {
super(sourceId, timeId);
this.step = step;
}
void trigger() {
for (int i = 0; i < eltsSinks.size(); i++)
eltsSinks.get(i).stepBegins(sourceId, timeId, step);
}
}
class AttributeChangedEvent extends GraphEvent {
ElementType eltType;
String eltId;
String attribute;
AttributeChangeEvent event;
Object oldValue;
Object newValue;
AttributeChangedEvent(String sourceId, long timeId, String eltId,
ElementType eltType, String attribute,
AttributeChangeEvent event, Object oldValue, Object newValue) {
super(sourceId, timeId);
this.eltType = eltType;
this.eltId = eltId;
this.attribute = attribute;
this.event = event;
this.oldValue = oldValue;
this.newValue = newValue;
}
void trigger() {
switch (event) {
case ADD:
switch (eltType) {
case NODE:
for (int i = 0; i < attrSinks.size(); i++)
attrSinks.get(i).nodeAttributeAdded(sourceId, timeId,
eltId, attribute, newValue);
break;
case EDGE:
for (int i = 0; i < attrSinks.size(); i++)
attrSinks.get(i).edgeAttributeAdded(sourceId, timeId,
eltId, attribute, newValue);
break;
default:
for (int i = 0; i < attrSinks.size(); i++)
attrSinks.get(i).graphAttributeAdded(sourceId, timeId,
attribute, newValue);
}
break;
case REMOVE:
switch (eltType) {
case NODE:
for (int i = 0; i < attrSinks.size(); i++)
attrSinks.get(i).nodeAttributeRemoved(sourceId, timeId,
eltId, attribute);
break;
case EDGE:
for (int i = 0; i < attrSinks.size(); i++)
attrSinks.get(i).edgeAttributeRemoved(sourceId, timeId,
eltId, attribute);
break;
default:
for (int i = 0; i < attrSinks.size(); i++)
attrSinks.get(i).graphAttributeRemoved(sourceId,
timeId, attribute);
}
break;
default:
switch (eltType) {
case NODE:
for (int i = 0; i < attrSinks.size(); i++)
attrSinks.get(i).nodeAttributeChanged(sourceId, timeId,
eltId, attribute, oldValue, newValue);
break;
case EDGE:
for (int i = 0; i < attrSinks.size(); i++)
attrSinks.get(i).edgeAttributeChanged(sourceId, timeId,
eltId, attribute, oldValue, newValue);
break;
default:
for (int i = 0; i < attrSinks.size(); i++)
attrSinks.get(i).graphAttributeChanged(sourceId,
timeId, attribute, oldValue, newValue);
}
}
}
}
class AddToListEvent<T> extends GraphEvent {
List<T> l;
T obj;
AddToListEvent(List<T> l, T obj) {
super(null, -1);
this.l = l;
this.obj = obj;
}
void trigger() {
l.add(obj);
}
}
class RemoveFromListEvent<T> extends GraphEvent {
List<T> l;
T obj;
RemoveFromListEvent(List<T> l, T obj) {
super(null, -1);
this.l = l;
this.obj = obj;
}
void trigger() {
l.remove(obj);
}
}
class ClearListEvent<T> extends GraphEvent {
List<T> l;
ClearListEvent(List<T> l) {
super(null, -1);
this.l = l;
}
void trigger() {
l.clear();
}
}
}