#ifndef EVENT_SENDER_H #define EVENT_SENDER_H /** \file Class template definition file. \copyright Copyright (C) 2002, 2003 Oliver Schoenborn This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software. You can redistribute it and/or modify it under the terms found in the LICENSE file that is included in the library distribution. \endcopyright */ #include #include #include #include #include "Listener.h" // uses inline #include "EventFWD.h" #include "PolymorphEvent.h" //class PolymorphEvent; template class EventSender { public: // types /// Simpler form of Listener typedef Listener TListener; private: // types /// So Listener can call register etc friend class Listener; /// Short form of std::list. typedef std::list Registry; public: // static methods class IllegalSendError; inline static void remove(TListener&); inline static void add(TListener&); inline static void send(const EvType&); inline static bool isSending(); inline static bool hasListeners(); inline static unsigned int getNumListeners(); inline static unsigned int getMinNumIgnored(); private: // construct/destroy singleton EventSender(): _isBusySending(false), _eventIgnored(0) {} ~EventSender(); private: // methods called by Listener void registerListener(TListener*); void removeListener(TListener*); void incEventIgnored() {_eventIgnored ++;} static EventSender& instance(); // MUST NOT BE INLINE private: // utility methods void sendEvent(const EvType&); void cleanupQueues(); bool removeFrom(Registry&, TListener*); inline std::string lisnrID(TListener* = NULL) const; //bool hasListener(TListener*) const; private: // data /// Registry of listeners that want to hear events of this type Registry _registry; /// True if EvType events are being sent (ie calling listeners) bool _isBusySending; /// How many listeners ignored the last event sent (so far) unsigned int _eventIgnored; /// The queue for registering listeners when send() is in progress Registry _registrationQueue; /// The queue for removing listeners when send() is in progress Registry _removalQueue; }; /** Specialization of EventSender for events inheriting from PolymorphEvent. This provides a natural alternative to the call on Polymorph::send(). */ template <> class EventSender { public: /** Send the polymorphic event to its listeners. It simply calls PolymorphEvent::send(), which must be overriden by subclasses of PolymorphEvent to call EventSender::send(const EvType&). Hence see the latter for more info. */ static void send(const PolymorphEvent& event) { event.send(); } }; /* Include IllegalSendError in this header so users don't have to include manually. It has to be included after class definition since it is an inner class to EventSender. */ #include "IllegalSendError.h" /** Are there listeners currently registered? If this returns false, creating and send()ing and event just wastes cpu cycles since no one will hear event. \return true if there are listeners in registry */ template inline bool EventSender::hasListeners() { return ! instance()._registry.empty(); } /** Get how many listeners have ignored the event that is currently being sent and that they have received. This number is reset to 0 before every call to send(const EvType&). This number is a minimum, since a listener is not required to tell EventSender that it is ignoring an event. */ template inline unsigned int EventSender::getMinNumIgnored() { return instance()._eventIgnored; } /** Get how many listeners are currently registered. Note that if isSending() is true, then this number does not take into account listeners that are queued for registration/removal. */ template inline unsigned int EventSender::getNumListeners() { return instance()._registry.size(); } /** Send the \a event to its listeners. - Upon return, getNumIgnored() will have the number of listeners who have ignored the event. - If one of the called listeners calls registerListener or removeListener, the operation will be queued and processed only after the event has been sent to all listeners. This insures the integrity of the list of listeners during the send() process. - Throws an exception if called while another send() is taking place, see IllegalSendError. You can use isSending() to test whether a send is taking place. - All other exceptions are caught \exception IllegalSendError */ template inline void EventSender::send(const EvType& event) { instance().sendEvent(event); } /** Is this event sender currently sending the event to its listeners? True if yes, false otherwise. */ template inline bool EventSender::isSending() { return instance()._isBusySending; } /** Remove the \a listener from the registry. Does nothing if the listener is not in the registry. */ template inline void EventSender::remove(TListener& listener) { listener.TListener::ignoreEvents(); } /** Add the \a listener to the registry. Does nothing if the listener is already registered. */ template inline void EventSender::add(TListener& listener) { listener.TListener::listenForEvents(); } /// Shortcut for TypeID of a listener template inline std::string EventSender::lisnrID(TListener* lisnr) const { std::ostringstream lisnrStr; lisnrStr << typeid(TListener).name(); if (lisnr) lisnrStr << ":" << lisnr; return lisnrStr.str(); } //#ifdef __GNUG__ // // because gcc doesn't handle separate template definition // #include "EventSender.cc" //#endif #endif // EVENT_SENDER_H