Tulip
5.3.1
Large graphs analysis and drawing
|
#include <Observable.h>
Public Member Functions | |
void | addListener (Observable *const listener) const |
void | addListener (Observable &listener) const |
void | addObserver (Observable *const observer) const |
void | addObserver (Observable &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 | removeListener (Observable &listener) const |
void | removeObserver (Observable *const observer) const |
void | removeObserver (Observable &observer) const |
Static Public Member Functions | |
static void | disableEventNotification () |
static void | enableEventNotification () |
static tlp::node | getNode (const tlp::Observable *obs) |
static Observable * | getObject (tlp::node n) |
static const tlp::VectorGraph & | getObservableGraph () |
static unsigned int | getScheduled (tlp::node n) |
static void | holdObservers () |
static bool | isAlive (tlp::node n) |
static unsigned int | observersHoldCounter () |
static void | unholdObservers () |
Protected Member Functions | |
Observable (const Observable &) | |
bool | hasOnlookers () const |
void | observableDeleted () |
Observable & | operator= (const Observable &) |
void | sendEvent (const Event &message) |
virtual void | treatEvent (const Event &message) |
virtual void | treatEvents (const std::vector< Event > &events) |
Friends | |
class | Event |
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 or a 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 algorithms would cause a big performance hit.
This can be 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 observable Observers and Listeners are internally store in a Graph structure, allowing to easily visualize their connections. 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 at least one of the two virtual functions below.
If you need to receive events without delay, you will be a Listener, and need to implement treatEvent(const Event &message). You will attach to the object you wish to receive events from using addListener().
If you can receive events after a delay, you will be an Observer, and need to implement treatEvents(const std::vector<Event> &events). You will attach to the object you wish to receive events from using addObserver().
Definition at line 127 of file Observable.h.
void tlp::Observable::addListener | ( | Observable *const | listener | ) | const |
Adds a Listener to this object.
The Listener will receive events regardless of the state of holdObservers() and unholdObservers().
listener | The object that will receive events. |
|
inline |
Adds a Listener to this object.
The Listener will receive events regardless of the state of holdObservers() and unholdObservers().
listener | The object that will receive events. |
Definition at line 232 of file Observable.h.
void tlp::Observable::addObserver | ( | Observable *const | observer | ) | const |
Adds an Observer to this object.
The observer will receive events sent by this object, if there is no hold applied.
observer | The object that will receive events. |
|
inline |
Adds an Observer to this object.
The observer will receive events sent by this object, if there is no hold applied.
observer | The object that will receive events. |
Definition at line 212 of file Observable.h.
unsigned int tlp::Observable::countListeners | ( | ) | const |
gets the number of listeners attached to this object.
unsigned int tlp::Observable::countObservers | ( | ) | const |
gets the number of observers attached to this object.
|
inlinestatic |
disable the whole event notification mechanism Until a call to enableEventNotification(), all sent events will be lost, except TLP_DELETE events which are synchronously processed, in order to void dangling pointers.
Definition at line 185 of file Observable.h.
|
inlinestatic |
re-enable the whole event notification mechanism All events sent since a previous call to enableEventNotification(), are definitively lost.
Definition at line 194 of file Observable.h.
|
static |
internal function for debugging purpose Get the node representing this object in the Observable Graph.
obs | the Observable object |
|
static |
internal function for debugging purpose If called during an update, it is possible the pointed object has been deleted. use isAlive() to check for this and avoid a crash.
n | The node representing the object to retrieve. |
|
static |
Gets the observation graph.
unsigned int tlp::Observable::getReceived | ( | ) | const |
get the number of received events.
|
static |
internal function for debugging purpose getScheduled get the number of scheduled events for this Observable.
n | The node of an Observable object |
unsigned int tlp::Observable::getSent | ( | ) | const |
gets the number of sent events.
|
protected |
Checks whether there are Observers/Listeners attached to this object.
Using this function avoids the creation of events that no-one will see :
|
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 TLP_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.
|
static |
internal function for debugging purpose If there is no hold currently applied, or no update ongoing, always returns true. Checks if the object represented by the node has been deleted.
n | The node to check for life signs. |
|
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.
|
inlinestatic |
observersHoldCounter gives the number of times holdObservers() has been called without a matching unholdObservers() call.
Definition at line 170 of file Observable.h.
void tlp::Observable::removeListener | ( | Observable *const | listener | ) | const |
Removes a listener from this object.
The listener will no longer receive events from this object.
listener | The listener to remove from this object. |
|
inline |
Removes a listener from this object.
The listener will no longer receive events from this object.
listener | The listener to remove from this object. |
Definition at line 268 of file Observable.h.
void tlp::Observable::removeObserver | ( | Observable *const | observer | ) | const |
Removes an observer from this object.
The observer will no longer receive events from this object.
observer | The observer to remove from this object. |
|
inline |
Removes an observer from this object.
The observer will no longer receive events from this object.
observer | The observer to remove from this object. |
Definition at line 250 of file Observable.h.
|
protected |
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 :
message | The message to send to the listeners/observers. |
|
protectedvirtual |
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.
message | The event that was sent. |
|
protectedvirtual |
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.
events | The events that happened since the last unHoldObservers(). |
Reimplemented in tlp::View.
|
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.