00001 #ifndef callback_h
00002 #define callback_h
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016 #include "sets.h"
00017 #include <string>
00018
00035 struct CallBacker { virtual ~CallBacker() {} };
00036
00037
00038 typedef void (CallBacker::*CallBackFunction)(CallBacker*);
00040 #define mCBFn(clss,fn) ((CallBackFunction)(&clss::fn))
00041
00042 #define mCB(obj,clss,fn) CallBack( static_cast<clss*>(obj), mCBFn(clss,fn))
00043
00053 mClass CallBack
00054 {
00055 public:
00056 CallBack( CallBacker* o=0, CallBackFunction f=0 )
00057 { obj_ = o; fn_ = f; }
00058 inline int operator==( const CallBack& cb ) const
00059 { return obj_ == cb.obj_ && fn_ == cb.fn_; }
00060 inline int operator!=( const CallBack& cb ) const
00061 { return obj_ != cb.obj_ || fn_ != cb.fn_; }
00062
00063 inline bool willCall() const
00064 { return obj_ && fn_; }
00065 inline void doCall( CallBacker* o )
00066 { if ( obj_ && fn_ ) (obj_->*fn_)( o ); }
00067
00068 inline CallBacker* cbObj() { return obj_; }
00069 inline const CallBacker* cbObj() const { return obj_; }
00070 inline CallBackFunction cbFn() const { return fn_; }
00071
00072 protected:
00073
00074 CallBacker* obj_;
00075 CallBackFunction fn_;
00076
00077 };
00078
00079
00082 mClass CallBackSet : public TypeSet<CallBack>
00083 {
00084 public:
00085
00086 void doCall(CallBacker*,const bool* enabledflag=0,
00087 CallBacker* exclude=0);
00094 void removeWith(CallBacker*);
00096 };
00097
00098 inline void CallBackSet::doCall( CallBacker* obj,
00099 const bool* enabledflag,
00100 CallBacker* exclude )
00101 {
00102 const bool enabled_ = true;
00103 const bool& enabled = enabledflag ? *enabledflag : enabled_;
00104 if ( !enabled ) return;
00105
00106 TypeSet<CallBack> cbscopy = *this;
00107 for ( int idx=0; idx<cbscopy.size(); idx++ )
00108 {
00109 CallBack& cb = cbscopy[idx];
00110 if ( indexOf(cb)==-1 )
00111 continue;
00112
00113 if ( cb.cbObj() != exclude )
00114 cb.doCall( obj );
00115 }
00116 }
00117
00118
00119 inline void CallBackSet::removeWith( CallBacker* cbrm )
00120 {
00121 for ( int idx=0; idx<size(); idx++ )
00122 {
00123 CallBack& cb = (*this)[idx];
00124 if ( cb.cbObj() == cbrm )
00125 { remove( idx ); idx--; }
00126 }
00127 }
00128
00129
00141 template <class T>
00142 class CBCapsule : public CallBacker
00143 {
00144 public:
00145 CBCapsule( T d, CallBacker* c )
00146 : data(d), caller(c) {}
00147
00148 T data;
00149 CallBacker* caller;
00150 };
00151
00152
00175 #define mCBCapsuleGet(T,var,cb) \
00176 CBCapsule<T>* var = dynamic_cast< CBCapsule<T>* >( cb );
00177
00178 #define mCBCapsuleUnpack(T,var,cb) \
00179 mCBCapsuleGet(T,cb##caps,cb) \
00180 T var = cb##caps->data
00181
00182 #define mCBCapsuleUnpackWithCaller(T,var,cber,cb) \
00183 mCBCapsuleGet(T,cb##caps,cb) \
00184 T var = cb##caps->data; \
00185 CallBacker* cber = cb##caps->caller
00186
00187
00190 mClass NotifierAccess
00191 {
00192
00193 friend class NotifyStopper;
00194
00195 public:
00196
00197 NotifierAccess()
00198 : enabled_(true) {}
00199 virtual ~NotifierAccess() {}
00200
00201 virtual void notify(const CallBack&) =0;
00202 virtual void notifyIfNotNotified(const CallBack&) =0;
00203 virtual void remove(const CallBack&) =0;
00204
00205 bool enable( bool newstatus=true )
00206 { return doEnable(newstatus); }
00208 bool disable() { return doEnable(false); }
00210 bool isEnabled() const { return enabled_; }
00211
00212 protected:
00213
00214 bool enabled_;
00215 inline bool doEnable( bool newstatus=true )
00216 { bool res=enabled_; enabled_=newstatus; return res; }
00218 };
00219
00220
00235 mClass NamedNotifierSet
00236 {
00237 public:
00238 ~NamedNotifierSet()
00239 { deepErase( names_ ); }
00240
00241 void add(const char* nm,NotifierAccess&);
00242 NotifierAccess* find(const char*) const;
00243
00244 protected:
00245
00246 ObjectSet<NotifierAccess> notifs_;
00247 ObjectSet<std::string> names_;
00248
00249 };
00250
00251
00252 inline void NamedNotifierSet::add( const char* nm, NotifierAccess& na )
00253 {
00254 names_ += new std::string( nm );
00255 notifs_ += &na;
00256 }
00257
00258
00259 inline NotifierAccess* NamedNotifierSet::find( const char* nm ) const
00260 {
00261 for ( int idx=0; idx<names_.size(); idx++ )
00262 if ( *names_[idx] == nm )
00263 return const_cast<NotifierAccess*>( notifs_[idx] );
00264 return 0;
00265 }
00266
00267
00270 mClass i_Notifier : public NotifierAccess
00271 {
00272 public:
00273
00274 virtual void notify( const CallBack& cb ) { cbs_ += cb; }
00275 virtual void notifyIfNotNotified( const CallBack& cb )
00276 { if ( cbs_.indexOf(cb)==-1 ) notify(cb); }
00277 virtual void remove( const CallBack& cb ) { cbs_ -= cb; }
00278 virtual void removeWith(CallBacker*);
00279
00280 CallBackSet cbs_;
00281 CallBacker* cber_;
00282
00283 i_Notifier() {}
00284 };
00285
00286
00287 inline void i_Notifier::removeWith( CallBacker* cb )
00288 {
00289 if ( cber_ == cb )
00290 { cbs_.erase(); cber_ = 0; return; }
00291
00292 cbs_.removeWith( cb );
00293 }
00294
00295
00331 template <class T>
00332 class Notifier : public i_Notifier
00333 {
00334 public:
00335
00336 void trigger( T& t ) { trigger(&t); }
00337
00338
00339
00340 Notifier( T* c ) { cber_ = c; }
00341
00342 inline void trigger( CallBacker* c=0, CallBacker* exclude=0 )
00343 { cbs_.doCall(c ? c : cber_, &enabled_, exclude); }
00344
00345 };
00346
00347
00364 mClass NotifyStopper
00365 {
00366 public:
00367 NotifyStopper( NotifierAccess& n )
00368 : thenotif(n)
00369 , oldstatus( n.doEnable(false) )
00370 {}
00371
00372 inline ~NotifyStopper()
00373 { restore(); }
00374
00375 inline void enable() { thenotif.doEnable(false); }
00376 inline void disable() { thenotif.doEnable(true); }
00377 inline void restore() { thenotif.doEnable(oldstatus);}
00378
00379 protected:
00380
00381 NotifierAccess& thenotif;
00382 bool oldstatus;
00383 };
00384
00385
00398 template <class T,class C>
00399 class CNotifier : public i_Notifier
00400 {
00401 public:
00402
00403 void trigger( C c, T& t ) { trigger(c,&t); }
00404
00405
00406
00407 CNotifier( T* cb ) { cber_ = cb; }
00408
00409 inline void trigger( CallBacker* cb=0 )
00410 {
00411 if( !enabled_ ) return;
00412 C c;
00413 trigger(c,cb);
00414 }
00415
00416 inline void trigger( C c, CallBacker* cb=0 )
00417 {
00418 if( !enabled_ ) return;
00419 CBCapsule<C> caps( c, cb ? cb : cber_ );
00420 cbs_.doCall( &caps, &enabled_ );
00421 }
00422 };
00423
00424
00425
00426 #endif