Overview | Modules | Class Hierarchy | Classes | Members

# Listener Class Reference
[Observable]

Listener is the base class for the implementation of an Observbale listener. More...

`#include <Observable.h>`

## Detailed Description

Listener is the base class for the implementation of an Observbale listener.

All Observable Listener must inherit from that class. The update function will be call each time an Observable send notification. The event received in parameter is a reference, thus it is possible to dynamic_cast it into any kind of specialized Event.

On the destruction of a Listener, there is no need (and you should not) to remove it from the Observable it is listening to. The OLOObject manage automatically disconnection and coherency.

The update function is a call back function, it is invoked by the Observable himself. Thus it is not allowed to delete the sender Observable during an update. Take care not to delete an other observable that could be implied in nested notifying calls (An exception will raised in that case). Even if it is permitted, usually it is not a good practice to delete any existing Observable during an update. The main problem is that it is difficult to know which Observable are implied in nested notify calls. Deleting any Onlooker is safe and is well managed by the mechanism.

Warning:
  Destruction of an Observable implied in nested notifying calls during an update will raise an OLOException.

See also:
  Observable
  Event
  Observer In the following example we demonstrate the use of a Listener to display all modification applied to a Point:

     class Point : public Observable {
     public:
         ~Point() {
           //observableDeleted();
         }
         void setXY(const double x, const double y);
         void getXY(double &x, double &y) const {
             x = _x;
             y = _y;
         }
     private:
         double _x, _y;
     };

     class PointEvent : public Event {
     public:
         PointEvent(const Point &p, double px, double py):
                 Event(p, Event::MODIFICATION), prevX(px), prevY(py) {
         }
         double prevX, prevY;
     };

     void Point::setXY(const double x, const double y) {
         PointEvent ev(*this, _x, _y);
         _x = x;
         _y = y;
         if (hasOnlookers())
             notify(ev);
     }

     class PointsViewer : public Observer {
     public:
         void update(const vector<Event> &evs) {
             for (size_t i=0; i< evs.size(); ++i)
                 if (evs[i].type() == Event::DELETE)  {
                 points.erase(reinterpret_cast<Point *>(evs[i].sender()));
                 cout << "PointsViewer::Point has been deleted :" << reinterpret_cast<Point *>(evs[i].sender()) << endl << flush;
                 cout << "PointsViewer::updating view : ";
                 updateView();
                 return;
             }
             cout << "PointsViewer::objects modified : " << evs.size() << " updating view : ";
             updateView();
         }
         void addPoint(Point& p) {
             points.insert(&p);
             p.addOnlooker(*this);
             cout << "PointsViewer::point added : " << &p << endl;
         }
         void updateView() {
             for (set<const Point *>::const_iterator it = points.begin(); it != points.end(); ++it) {
                 double x,y;
                 (*it)->getXY(x, y);
                 cout << "(" << x << "," << y << ")";
             }
             cout << endl;
         }

     private:
         set<const Point *> points;
     };

     class PointListener : public Listener {
     public:
         void update(const Event &ev) {
             if (ev.type() == Event::DELETE)  {
                 cout << "PointListener::Point has been deleted : " << reinterpret_cast<Point *>(ev.sender()) << endl << flush;
                 return;
             }
             const PointEvent *event = dynamic_cast<const PointEvent *>(&ev);
             if (event) {
                 Point *p = reinterpret_cast<Point *>(ev.sender());
                 double x,y;
                 p->getXY(x, y);
                 cout << "PointListener::Point change (" << event->prevX << "," << event->prevY << ") ==> (" << x << "," << y << ")" << endl << flush;
             }
         }
     };

     int main() {
         Point *point[8];
         PointsViewer pv;
         PointListener pl;
         for (int i=0; i < 8; ++i) {
             point[i] = new Point();
             point[i]->setXY(i,i);
             pv.addPoint(*point[i]);
         }
         point[4]->addOnlooker(pl);
         pv.updateView();
         Observable::holdObservers();//all observers are holded;
         for (int i=0; i < 4; ++i) {
             delete point[i]; //pv receive 4 DELETE events (ie 4 call to update function);
         }
         for (int j = 0; j<5; ++j) {
             for (int i=4; i < 8; ++i) {
                 point[i]->setXY(i, j); //no event sent to pv
             }
         }
         Observable::unholdObservers(); //only one call to pointViewer::update with the 4 last event sent by the 4 observed points
         for (int i=4; i < 8; ++i) {
             delete point[i]; //pv receive 4 DELETE events (ie 10 call to update function);
         }
         return EXIT_SUCCESS;
     }

Tulip Software by LaBRI Visualization Team 2001 - 2012