File: nnevent.h

package info (click to toggle)
museek%2B 1%3A0.2%2Bsvn20100315.r1208-1
  • links: PTS
  • area: main
  • in suites: squeeze
  • size: 7,664 kB
  • ctags: 6,895
  • sloc: cpp: 28,853; python: 28,014; ansic: 538; makefile: 128; sh: 117
file content (279 lines) | stat: -rw-r--r-- 9,003 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
/*  NewNet - A networking framework in C++
    Copyright (C) 2006-2007 Ingmar K. Steen (iksteen@gmail.com)
    Copyright 2008 little blue poney <lbponey@users.sourceforge.net>

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 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 General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

 */

#ifndef NEWNET_EVENT_H
#define NEWNET_EVENT_H

#include "nnobject.h"
#include "nnrefptr.h"
#include <vector>
#include <functional>
#include <algorithm>

namespace NewNet
{
  //! Simple event dispatcher class.
  /*! The NewNet::Event class provides a simple and easy to use event
      aggregation solution. Callbacks can be registered to an event that
      will be invoked upon emitting the event. */
  template<typename T> class Event : public Object
  {
  public:
    //! Abstract callback type for Event.
    /*! A callback can be added to an event so that operator()(T t) will be
        called when the event is emitted. */
    class Callback : public Object
    {
    public:
      //! Constructor.
      Callback() { }

      //! Destructor.
      virtual ~Callback() { }

      //! Slot method.
      /*! Override this and implement your callback function. */
      virtual void operator()(T t) = 0;

#ifndef DOXYGEN_UNDOCUMENTED
      /* Callback was added to an Event */
      void onConnected(Event * event)
      {
        m_Events.push_back(event);
      }

      /* Callback was disconnected from an Event */
      void onDisconnected(Event * event)
      {
        typename std::vector<Event *>::iterator it;
        it = std::find(m_Events.begin(), m_Events.end(), event);
        if (it != m_Events.end())
            m_Events.erase(it);
      }
#endif // DOXYGEN_UNDOCUMENTED

      //! Disconnect this callback from all events.
      /*! Calling this will result in the disconnection of the callback from
          all the events it is registered to. Note: Events store a RefPtr to
          the callbacks. The callback class might be deleted when
          disconnecting from all registered events. */
      void disconnect()
      {
        /* Artificially increase our reference count. Otherwise we might get
           prematurely deleted when we get disconnected from the last Event */
        ++(this->refCounter());

        /* Disconnect from all the events we're registered to */
        while(! m_Events.empty())
          m_Events.front()->disconnect(this);

        /* Decrease the refrence count again and delete if necessary */
        if(--(this->refCounter()))
          delete this;
      }

    private:
      /* Private copy constructor, you don't want this happening */
      Callback(const Callback &) { }
      std::vector<Event *> m_Events;
    };

  private:
#ifndef DOXYGEN_UNDOCUMENTED
    /* Callback to a method of a NewNet::Object */
    template<class ObjectType, typename MethodType> class BoundCallback : public Callback
    {
    private:
      /* We use this to track deletion of our Object */
      class GuardObjectCallback : public GuardObject::Callback
      {
      public:
        GuardObjectCallback(BoundCallback * callback) : m_Callback(callback)
        {
        }

        /* If the Object is destroyed, notify our Callback */
        void operator()(Object *)
        {
          m_Callback->onObjectDeleted();
        }
      private:
        BoundCallback * m_Callback;
      };
      GuardObjectCallback * m_GuardObjectCallback;

    public:
      BoundCallback(ObjectType * object, MethodType method)
                   : m_Object(object), m_Method(method)
      {
        /* Register to the Object's delete guard */
        m_GuardObjectCallback = new GuardObjectCallback(this);
        m_Object->guardObject() += m_GuardObjectCallback;
      }

      ~BoundCallback()
      {
        /* If the object is still valid, remove our delete callback from
           its delete guard */
        if(m_Object)
          m_Object->guardObject() -= m_GuardObjectCallback;

        delete m_GuardObjectCallback;
      }

      void operator()(T t)
      {
        /* Since C++ methods are internally called as
           Class::Method(object, ...), this results in a valid C++ bound
           method call. */
        if(m_Object)
          std::bind1st(std::mem_fun(m_Method), m_Object)(t);
      }

    protected:
      /* Object we're bound to was deleted, reset pointer and disconnect
         from all Events we're registered to */
      void onObjectDeleted()
      {
        m_Object = 0;
        Callback::disconnect();
      }

    private:
      /* Private copy constructor, you don't want this happening */
      BoundCallback(const BoundCallback &) { }

      ObjectType * m_Object;
      MethodType m_Method;
    };
#endif // DOXYGEN_UNDOCUMENTED

  public:
    //! Constructor.
    /*! Create a new event to which you can register callbacks. */
    Event() { }

    //! Copy constructor.
    /*! When an event is copied, all the callbacks registered to the original
        event will also be connected to this event. */
    Event(const Event & that)
    {
      typename std::vector<RefPtr<Callback> >::const_iterator it, end;
      end = that.m_Callbacks.end();
      for(it = that.m_Callbacks.begin(); it != end; ++it)
        connect(*it);
    }

    //! Destructor.
    /*! Disconnects all callbacks from the event. Note: see clear(). */
    virtual ~Event()
    {
      /* Disconnect all Callbacks */
      clear();
    }

    //! Empty the event callback list.
    /*! Call this to remove all the callbacks from this event. Note: the
        event stores a RefPtr to all the callbacks registered. Clearing the
        event may delete the callback if there are no other references to
        it. */
    void clear()
    {
      while(! m_Callbacks.empty())
        disconnect(m_Callbacks.front());
    }

    //! Connect a callback to the event.
    /*! Add a callback to this event so that it will get invoked when the
        event is emitted. Note: stores a RefPtr to the callback. */
    Callback * connect(Callback * callback)
    {
      /* Push a RefPtr to the Callback to our list */
      m_Callbacks.push_back(callback);

      /* Notify the Callback that it's connected to us */
      callback->onConnected(this);

      return callback;
    }

    //! Create a callback to a bound method.
    /*! This will construct a callback object that will invoke a method
        of an object. */
    template<class ObjectType, typename MethodType>
    static Callback * bind(ObjectType * object, MethodType method)
    {
      return new BoundCallback<ObjectType, MethodType>(object, method);
    }

    //! Connect callback to a method of an object to the event.
    /*! Add a callback to a method of an object so that it will get
        invoked when the event is emitted. Note: stores a RefPtr to the newly
        created callback. */
    template<class ObjectType, typename MethodType>
    Callback * connect(ObjectType * object, MethodType method)
    {
      return connect(bind(object, method));
    }

    //! Disconnect a callback from the event.
    /*! Remove a callback from the invocation list. Note: the event stores
        a RefPtr to the callback. If the event holds the last RefPtr, the
        callback will be deleted. */
    void disconnect(Callback * callback)
    {
      /* Artificially increase the reference count so it doesn't get deleted
         prematurely */
      ++(callback->refCounter());

      /* Delete the Callback from our list */
      typename std::vector<RefPtr<Callback> >::iterator it;
      it = std::find(m_Callbacks.begin(), m_Callbacks.end(), callback);
      if (it != m_Callbacks.end())
        m_Callbacks.erase(it);

      /* Notify the Callback it was disconnected */
      callback->onDisconnected(this);

      /* Decrease the reference count of the Callback and delete if
         necessary */
      if(--(callback->refCounter()))
        delete callback;
    }

    //! Emit the event.
    /*! Emit the event, invokes the Callback::operator()(T t) method of all
        registered callbacks. */
    void operator()(T t)
    {
      std::vector<RefPtr<Callback> > callbacks(m_Callbacks);
      typename std::vector<RefPtr<Callback> >::iterator it, end = callbacks.end();
      for(it = callbacks.begin(); it != end; ++it)
      {
        (*(*it))(t);
      }
    }

  private:
    std::vector<RefPtr<Callback> > m_Callbacks;
  };
}

#endif // NEWNET_EVENT_H