Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Class Members | File Members | Related Pages

PhxListeners.h

Go to the documentation of this file.
00001 #ifndef PHX_LISTENERS_H
00002 #define PHX_LISTENERS_H
00003 
00011 #include <map>
00012 #include <Phx/PhxConfig.h>
00013 #include <Phx/PhxTypes.h>
00014 
00015 namespace Phx {
00016 
00081   template <class Notifier, class Listener>
00082   class BaseListener : public LockedPtrInterface<BaseListener<Notifier, Listener> > {
00083   public:
00084     class Manager;
00085     
00089     BaseListener(void) : mNotifier(0) {
00090     }
00091 
00095     virtual ~BaseListener(void) {
00096       if (mNotifier) {
00097         std::clog << "Deleting a listener without uninstalling." << std::endl;
00098       }
00099     }
00100 
00101   protected:
00102     
00125     Notifier* notifier(void) { return mNotifier; }
00126 
00127   private:
00128     // no copy or assignment
00129     BaseListener(BaseListener<Notifier, Listener>&);
00130     BaseListener<Notifier, Listener>&
00131       operator=(BaseListener<Notifier, Listener>&);
00132     
00133     friend class Manager;
00134     void setNotifier(Notifier* notifier) {
00135       mNotifier = notifier;
00136     }
00137 
00138     Notifier*  mNotifier;
00139   };
00140 
00150   template<class Notifier, class Listener>
00151   class BaseListener<Notifier, Listener>::Manager {
00152     typedef BaseListener<Notifier, Listener>  BaseListener;
00153   public:
00154     
00163     Manager(Notifier* notifier) : mListener(0), mNotifier(notifier) {
00164       if (mNotifier == 0) {
00165         std::clog << "Cannot create listener "
00166                   << "manager without notifier." << std::endl;
00167         throw InternalException(); // lame
00168       }
00169     }
00170 
00171     virtual ~Manager() {
00172       if (mListener) {
00173         // Setting notifier is okay since manager is not calling back
00174         // the listener at this time and the client has been told that
00175         // the notifier attribute is only safe then.
00176         ((BaseListener*)mListener)->setNotifier(0);
00177       }
00178     }
00179 
00199     void listener(Listener* listener) {
00200       // If listener already has a notifier that isn't the same as
00201       // ours, throw an exception.
00202       if (listener &&
00203           ((BaseListener*)listener)->notifier() != mNotifier &&
00204           ((BaseListener*)listener)->notifier() != 0) {
00205         std::clog << "Cannot install listener into a second notifier." << std::endl;
00206         throw PermissionException();
00207       }
00208 
00209       // If we have an existing listener, set its notifier() to 0.
00210       if (mListener) ((BaseListener*)mListener)->setNotifier(0);
00211 
00212       if (listener) {
00213         // Set listener's notifier() attribute
00214         ((BaseListener*)listener)->setNotifier(mNotifier);
00215       }
00216 
00217       // Set our listener attribute
00218       mListener = listener;
00219     }
00220 
00228     Listener* listener(void) { return mListener; }
00229 
00230   private:
00231     // no copy or assignment
00232     Manager(Manager&);
00233     Manager& operator=(Manager&);
00234 
00235     Listener* mListener;
00236     Notifier* mNotifier;
00237   };
00238 
00239 
00267   template <class Notifier, class Listener, class Selector>
00268   class BaseMultiListener : public LockedPtrInterface<BaseMultiListener<Notifier, Listener, Selector> > {
00269   public:
00270     class Manager;
00271 
00272     BaseMultiListener(void) : mNotifier(0) {}
00273 
00278     virtual ~BaseMultiListener(void) {
00279       if (mNotifier) {
00280         std::clog << "Deleting a multi-listener without uninstalling." << std::endl;
00281       }
00282     }
00283 
00284   protected:
00297     Notifier* notifier(void) { return mNotifier; }
00298     const Notifier* notifier(void) const { return mNotifier; }
00299 
00300   private:
00301     // no copy or assignment
00302     BaseMultiListener(BaseMultiListener<Notifier, Listener, Selector>&);
00303     BaseMultiListener<Notifier, Listener, Selector>& 
00304     operator=(BaseMultiListener<Notifier, Listener, Selector>&);
00305     
00306     friend class Manager;
00307     void setNotifier(Notifier* notifier) {
00308       mNotifier = notifier;
00309     }
00310 
00311     Notifier* mNotifier;
00312   };
00313   
00318   template<class Notifier, class Listener, class Selector>
00319   class BaseMultiListener<Notifier, Listener, Selector>::Manager {
00320   public:
00321     typedef BaseMultiListener<Notifier, Listener, Selector>  BaseListener;
00322     typedef std::map<Selector, Listener*> ListenerMapType;
00323     typedef typename ListenerMapType::iterator Iterator;
00324     typedef typename ListenerMapType::value_type ValueType;
00325 
00330     Manager(Notifier* notifier) : mNotifier(notifier) {
00331       if (notifier == 0) {
00332         std::clog << "Cannot create multi-listener "
00333                   << "manager without notifier." << std::endl;
00334         throw InternalException(); // lame
00335       }
00336     }
00337 
00342     virtual ~Manager() {
00343       for (Iterator itr = begin(); itr != end();  ++itr) {
00344         if (itr->second) ((BaseListener*)(itr->second))->setNotifier(0);
00345       }
00346     }
00347 
00348     Iterator begin() { return mListeners.begin(); }
00349     Iterator end() { return mListeners.end(); }
00350 
00370     void listener(Selector selector, Listener* listener) {
00371       // @optimization This code implements idempotency in an
00372       // inefficient way by first removing, then reinserting the
00373       // listener.
00374 
00375       if (listener) {
00376         // Listener is non-null -- put it into the collection.
00377         if (((BaseListener*)listener)->notifier() != mNotifier &&
00378             ((BaseListener*)listener)->notifier() != 0) {
00379           std::clog << "Cannot install listener into a second notifier." << std::endl;
00380           throw PermissionException();
00381         }
00382 
00383         // First remove any existing listener for this selector
00384         Manager::listener(selector, 0);
00385 
00386         // Update listener's notifier() attribute
00387         ((BaseListener*)listener)->setNotifier(mNotifier);
00388         // Insert into listeners list with given selector
00389         mListeners.insert(ValueType(selector, listener));
00390       } else {
00391         // listener == 0 means erase element with given selector.
00392         Iterator itr = mListeners.find(selector);
00393         if (itr != mListeners.end()) {
00394           // set notifier of old listener to 0
00395           itr->second->setNotifier(0);
00396           // remove the listener from the collection
00397           mListeners.erase(itr);
00398         } // else, do nothing (required by idempotence).
00399       }
00400     }
00401 
00411     Listener* listener(Selector selector) {
00412       Iterator itr = mListeners.find(selector);
00413       if (itr != mListeners.end()) {
00414         return itr->second;
00415       }
00416       return 0;
00417     }
00418 
00419   private:
00420     // no copy or assignment
00421     Manager(Manager&);
00422     Manager& operator=(Manager&);
00423 
00424     ListenerMapType   mListeners;
00425     Notifier*         mNotifier;
00426   };
00427 
00428 }; // namespace Phx
00429 
00430 #endif /* PHX_LISTENERS_H */

Generated on Wed Dec 21 22:05:37 2005 for Phoenix OSFS by  doxygen 1.4.2