Tulip  4.3.0
Better Visualization Through Research
 All Classes Namespaces Files Functions Variables Enumerations Enumerator Properties Groups Pages
tlp::Observable Class Reference

#include <Observable.h>

Inherited by tlp::AcyclicTest [private], tlp::BiconnectedTest [private], tlp::Camera, tlp::ConnectedTest, tlp::GlGraphComposite, tlp::GlScene, tlp::Graph, tlp::GraphNeedsSavingObserver [private], tlp::PluginLister, tlp::PropertyInterface, and tlp::View.

Public Member Functions

void addListener (Observable *const listener) const
 
void addObserver (Observable *const observer) const
 
unsigned int countListeners () const
 
unsigned int countObservers () const
 
unsigned int getReceived () const
 
unsigned int getSent () const
 
void removeListener (Observable *const listener) const
 
void removeObserver (Observable *const observerver) const
 

Static Public Member Functions

static ObservablegetObject (tlp::node n)
 
static const tlp::VectorGraph & getObservableGraph ()
 
static void holdObservers ()
 
static bool isAlive (tlp::node n)
 
static unsigned int observersHoldCounter ()
 
static void unholdObservers ()
 

Protected Member Functions

 Observable (const Observable &)
 
tlp::Iterator< tlp::Observable * > * getObservables () const
 
bool hasOnlookers () const
 
void notifyObservers ()
 
void observableDeleted ()
 
Observableoperator= (const Observable &)
 
void sendEvent (const Event &message)
 
virtual void treatEvent (const Event &message)
 
virtual void treatEvents (const std::vector< Event > &events)
 

Friends

class Event
 

Detailed Description

The Observable class is the base of Tulip's observation system.

Each class that wishes to send or receive notifications needs to inherit from Observable.

Tulip has two separate mechanisms of observation, Observers and Listeners. These two mechanisms work through the same class, the difference lies in the way an Observer of Listener is attached to the object whose events it will receive.

The Listener is closer to the original pattern, where events are sent directly to the recipient. The Observer is a twist for performance purposes, it can receive the events in a delayed fashion, and cannot know if the event was just sent or was delayed.

The purpose of this twist is to allow algorithms that perform a high number of modifications (e.g. creating a grid to route edges, creating multiple subgraphs with metrics or layouts) to run smoothly without overcrowding the event queue. As events are sent for every graph modification (e.g. adding a node, deleting a node, setting a value on a node), the sheer quantity of events sent by these algortithms would cause a big performance hit.

This is avoided by using Observable::holdObservers(). This holds all events in a queue and only sends them when Observable::unholdObservers() is called.

The only exception to this mechanism is the Event::DELETE kind of event, that is never held back. Think of it as an unmaskable POSIX signal; whatever the connection to the object and the state of holdObserver, this event will get through. This is used to prevent crashes in the case where and object is listened or observed and is deleted, as it is likely the recipient keeps a pointer to the now deleted object.

The Listener however is not affected by the use of Observable::holdObservers() and Observable::unholdObservers().

The observables Observers and Listeners are internally stocked in a Graph structure, allowing to visualize the connections easily. This eases debugging of Observation-related bugs.

Events are always sent to Listeners first, and then to Observers, even when there is no hold.

If you wish to receive events, you must inherit from Observable, and implement one of two virtual functions.

If you need to received events without delay, you will be a Listener, and need to implement treatEvent(). You will attach to the object you wish to receive events from using addObserver().

If you can receive events after a delay, you will be an Observer, and need to implement treatEvents(). You will attach to the object you wish to receive events from using addListener().

Definition at line 123 of file Observable.h.

Member Function Documentation

void tlp::Observable::addListener ( Observable *const  listener) const

addListener Adds a Listener to this object.

The Listener will receive events regardless of the state of holdObservers() and unholdObservers().

Parameters
listenerThe object that will receive events.
void tlp::Observable::addObserver ( Observable *const  observer) const

addObserver Adds an Observer to this object.

The observer will receive events sent by this object, if there is no hold applied.

Parameters
observerThe object that will receive events.
unsigned int tlp::Observable::countListeners ( ) const

countListeners gets the number of listeners attached to this object.

Returns
the number of listeners attached to this object.
unsigned int tlp::Observable::countObservers ( ) const

countObservers gets the number of observers attached to this object.

Returns
the number of observers attached to this object.
static Observable* tlp::Observable::getObject ( tlp::node  n)
static

getObject Internal function for debugging.

If called during an update, it is possible the pointed object has been deleted. use isAlive() to check for this and avoid a crash.

Parameters
nThe node representing the object to retrieve.
Returns
The object represented by the node.
static const tlp::VectorGraph& tlp::Observable::getObservableGraph ( )
static

getObservableGraph Gets the observation graph.

Returns
The graph containing a node for each Observable/Observer/Listener, and an edge between connected objects.
tlp::Iterator<tlp::Observable *>* tlp::Observable::getObservables ( ) const
protected

use for old observer tulip compatibility

unsigned int tlp::Observable::getReceived ( ) const

getReceived get the number of received events.

Returns
the number of received events.
unsigned int tlp::Observable::getSent ( ) const

getSent gets the number of sent events.

Returns
the number of sent events
bool tlp::Observable::hasOnlookers ( ) const
protected

hasOnlookers Checks whether there are Observers/Listeners attached to this object.

Using this function avoids the creation of events that no-one will see :

if (hasOnlookers()) {
sendEvent(GraphEvent(*this, GraphEvent::TLP_ADD_NODE, n));
}
Returns
static void tlp::Observable::holdObservers ( )
static

Holds back all events until Observable::unholdObservers() is called.

Listeners are not affected by this function. Once this function is called, all events heading to an Observer will be held, except DELETE events. The events are stored in a queue, and will be sent once Observable::unholdObservers() is called.

It is possible to nest calls to Observable::holdObservers() and Observable::unholdObservers(), and in this case the events will only be sent when there have been as many calls to Observable::unholdObservers() as to Observable::holdObservers().

It is possible to check whether the events are being help by checking the Observable::observersHoldCounter() function.

See Also
unholdObservers
observersHoldCounter
static bool tlp::Observable::isAlive ( tlp::node  n)
static

isAlive Internal function for debugging.

If there is no hold curretly applied, or no update ongoing, always returns true. Checks if the object represented by the node has been deleted.

Parameters
nThe node to check for life signs.
Returns
Whether the node is dead, Jim.
void tlp::Observable::notifyObservers ( )
protected

use for old observer tulip compatibility

void tlp::Observable::observableDeleted ( )
protected

Sends the Event::DELETE before the deletion of the subclass and its internal objects.

The observation system automatically sends the DELETE event when the Observable is deleted, but in the case you need to access members of the class inheriting from Observable, you need the event sent before the outermost objects are destroyed.

To achieve this, you can call this function in your destructor, and the DELETE event will be sent. This will allow your Listeners/Observers to access your members one last time before deletion.

Warning
This function must be called one time only per object. Make sure no other class in the inheritance tree calls this function before adding this call to your destructor.
static unsigned int tlp::Observable::observersHoldCounter ( )
inlinestatic

observersHoldCounter gives the number of times holdObservers() has been called without a matching unholdObservers() call.

Returns
the number of times holdObservers() has been called without a matching unholdObservers() call.

Definition at line 160 of file Observable.h.

void tlp::Observable::removeListener ( Observable *const  listener) const

removeListener Removes a listener from this object.

The listener will no longer receive events from this object.

Parameters
listenerThe listener to remove from this object.
void tlp::Observable::removeObserver ( Observable *const  observerver) const

removeObserver Removes an observer from this object.

The observer will no longer receive events from this object.

Parameters
observerThe observer to remove from this object.
void tlp::Observable::sendEvent ( const Event message)
protected

sendEvent Sends an event to all the Observers/Listeners. It is higly recommended to check if there are observers/listeners to send the event to before actually sending it to avoid the overhead of creating too many objects.

This can be achieved by using the hasOnLookers() function :

if (hasOnlookers()) {
sendEvent(GraphEvent(*this, GraphEvent::TLP_ADD_NODE, n));
}
Parameters
messageThe message to send to the listeners/observers.
virtual void tlp::Observable::treatEvent ( const Event message)
protectedvirtual

treatEvent This function is called when events are sent to the Listeners, and Listeners only.

Is it passed a reference to the event that just happened.

Parameters
messageThe event that was sent.
virtual void tlp::Observable::treatEvents ( const std::vector< Event > &  events)
protectedvirtual

treatEvents This function is called when events are sent to Observers, and Observers only.

It is passed a vector of all the events that happened since the last call. If events were held, this vector can be pretty large, and if events were not held it is likely it only contains a single element.

Parameters
eventsThe events that happened since the last unHoldObservers().

Reimplemented in tlp::View, and tlp::GraphNeedsSavingObserver.

static void tlp::Observable::unholdObservers ( )
static

Sends all held events to the Observers.

Listeners are not affected by this function.

In debug mode, if the hold counter is less than one when calling this function, an ObservableException will be raised.

See Also
holdObservers
observersHoldCounter