Basic event dispatching (with priorities)
authorManuel Nickschas <sputnick@quassel-irc.org>
Wed, 8 Sep 2010 16:44:07 +0000 (18:44 +0200)
committerManuel Nickschas <sputnick@quassel-irc.org>
Wed, 13 Oct 2010 23:06:31 +0000 (01:06 +0200)
I think priorities make more sense than the prepending/appending of handlers we've had before.

src/common/event.cpp
src/common/event.h
src/common/eventmanager.cpp
src/common/eventmanager.h

index 826af7c..3803ab9 100644 (file)
@@ -19,3 +19,9 @@
  ***************************************************************************/
 
 #include "event.h"
+
+Event::Event(EventManager::EventType type)
+  : _type(type)
+{
+
+}
index ed82f7e..b3fa8f5 100644 (file)
 
 #include <QStringList>
 
+#include "eventmanager.h"
+
 class Event {
 
 public:
-  Event();
-  virtual ~Event();
+  explicit Event(EventManager::EventType type = EventManager::Invalid);
+  virtual ~Event() {};
+
+  inline EventManager::EventType type() const { return _type; }
 
-  virtual QStringList params() const;
+  //virtual QStringList params() const;
 
+private:
+  EventManager::EventType _type;
 };
 
 #endif
index a8ddd67..c5f01b6 100644 (file)
 #include <QDebug>
 #include <QMetaEnum>
 
+#include "event.h"
+
 EventManager::EventManager(QObject *parent) : QObject(parent) {
 
 }
 
-void EventManager::registerObject(QObject *object, RegistrationMode mode, const QString &methodPrefix) {
+void EventManager::registerObject(QObject *object, Priority priority, const QString &methodPrefix) {
   int eventEnumIndex = metaObject()->indexOfEnumerator("EventType");
   Q_ASSERT(eventEnumIndex >= 0);
   QMetaEnum eventEnum = metaObject()->enumerator(eventEnumIndex);
@@ -46,29 +48,75 @@ void EventManager::registerObject(QObject *object, RegistrationMode mode, const
       qWarning() << Q_FUNC_INFO << QString("Could not find EventType %1").arg(methodSignature);
       continue;
     }
-    Handler handler(object, i);
-    mode == Prepend ? registeredHandlers()[static_cast<EventType>(eventType)].prepend(handler)
-                    : registeredHandlers()[static_cast<EventType>(eventType)].append(handler);
-
+    Handler handler(object, i, priority);
+    registeredHandlers()[static_cast<EventType>(eventType)].append(handler);
     qDebug() << "Registered event handler for" << methodSignature << "in" << object;
   }
 }
 
-void EventManager::registerEventHandler(EventType event, QObject *object, const char *slot, RegistrationMode mode) {
-  registerEventHandler(QList<EventType>() << event, object, slot, mode);
+void EventManager::registerEventHandler(EventType event, QObject *object, const char *slot, Priority priority) {
+  registerEventHandler(QList<EventType>() << event, object, slot, priority);
 }
 
-void EventManager::registerEventHandler(QList<EventType> events, QObject *object, const char *slot, RegistrationMode mode) {
+void EventManager::registerEventHandler(QList<EventType> events, QObject *object, const char *slot, Priority priority) {
   int methodIndex = object->metaObject()->indexOfMethod(slot);
   if(methodIndex < 0) {
     qWarning() << Q_FUNC_INFO << QString("Slot %1 not found in object %2").arg(slot).arg(object->objectName());
     return;
   }
-  Handler handler(object, methodIndex);
+  Handler handler(object, methodIndex, priority);
   foreach(EventType event, events) {
-    mode == Prepend ? registeredHandlers()[event].prepend(handler)
-                    : registeredHandlers()[event].append(handler);
-
+    registeredHandlers()[event].append(handler);
     qDebug() << "Registered event handler for" << event << "in" << object;
   }
 }
+
+// not threadsafe! if we should want that, we need to add a mutexed queue somewhere in this general area.
+void EventManager::sendEvent(Event *event) {
+  dispatchEvent(event);
+}
+
+void EventManager::dispatchEvent(Event *event) {
+  // we try handlers from specialized to generic by masking the enum
+
+  // build a list sorted by priorities that contains all eligible handlers
+  QList<Handler> handlers;
+  EventType type = event->type();
+  insertHandlers(registeredHandlers().value(type), handlers);
+
+  // check if we have a generic handler for the event group
+  if((type & EventGroupMask) != type)
+    insertHandlers(registeredHandlers().value(type & EventGroupMask), handlers);
+
+  // now dispatch the event
+  QList<Handler>::const_iterator it = handlers.begin();
+  while(it != handlers.end()) {
+
+    // TODO: check event flags here!
+
+    void *param[] = {0, Q_ARG(Event *, event).data() };
+    it->object->qt_metacall(QMetaObject::InvokeMetaMethod, it->methodIndex, param);
+
+    ++it;
+  }
+
+  // finally, delete it
+  delete event;
+}
+
+void EventManager::insertHandlers(const QList<Handler> &newHandlers, QList<Handler> &existing) {
+  foreach(Handler handler, newHandlers) {
+    if(existing.isEmpty())
+      existing.append(handler);
+    else {
+      // need to insert it at the proper position
+      QList<Handler>::iterator it = existing.begin();
+      while(it != existing.end()) {
+        if(handler.priority > it->priority)
+          break;
+        ++it;
+      }
+      existing.insert(it, handler);
+    }
+  }
+}
index 78a72ac..b19e8ee 100644 (file)
@@ -37,40 +37,55 @@ public:
     Append
   };
 
+  enum Priority {
+    VeryLowPriority,
+    LowPriority,
+    NormalPriority,
+    HighPriority,
+    HighestPriority
+  };
+
   /*
 
   */
+  /* These values make sense! Don't change without knowing what you do! */
   enum EventType {
     Invalid                     = 0xffffffff,
-    GenericEvent                  = 0x000000,
-
-    IrcServerEvent                = 0x010000,
-    IrcServerLooking              = 0x010001,
-    IrcServerConnecting           = 0x010002,
-    IrcServerConnected            = 0x010003,
-    IrcServerConnectionFailure    = 0x010004,
-    IrcServerDisconnected         = 0x010005,
-    IrcServerQuit                 = 0x010006,
-
-    IrcServerIncoming             = 0x010007,
-
-    IrcEvent                      = 0x020000,
-    IrcEventCap                   = 0x020001,
-    IrcEventCapAuthenticate       = 0x020002,
-    IrcEventInvite                = 0x020003,
-    IrcEventJoin                  = 0x020004,
-    IrcEventKick                  = 0x020005,
-    IrcEventMode                  = 0x020006,
-    IrcEventNick                  = 0x020007,
-    IrcEventNotice                = 0x020008,
-    IrcEventPart                  = 0x020009,
-    IrcEventPing                  = 0x02000a,
-    IrcEventPong                  = 0x02000b,
-    IrcEventPrivmsg               = 0x02000c,
-    IrcEventQuit                  = 0x02000d,
-    IrcEventTopic                 = 0x02000e,
-
-    IrcEventNumeric               = 0x021000 /* needs 1000 (0x03e8) consecutive free values! */
+    GenericEvent                = 0x00000000,
+
+    // for event group handlers (handleIrcEvent() will handle all IrcEvent* enums)
+    // event groups are specified by bits 20-24
+    EventGroupMask              = 0x00ff0000,
+
+    NetworkEvent                = 0x00010000,
+    NetworkConnecting,
+    NetworkInitializing,
+    NetworkInitialized,
+    NetworkReconnecting,
+    NetworkDisconnecting,
+    NetworkDisconnected,
+    NetworkIncoming,
+
+    IrcServerEvent              = 0x00020000,
+    IrcServerIncoming,
+
+    IrcEvent                    = 0x00030000,
+    IrcEventCap,
+    IrcEventCapAuthenticate,
+    IrcEventInvite,
+    IrcEventJoin,
+    IrcEventKick,
+    IrcEventMode,
+    IrcEventNick,
+    IrcEventNotice,
+    IrcEventPart,
+    IrcEventPing,
+    IrcEventPong,
+    IrcEventPrivmsg,
+    IrcEventQuit,
+    IrcEventTopic,
+
+    IrcEventNumeric             = 0x00031000, /* needs 1000 (0x03e8) consecutive free values! */
   };
 
   EventManager(QObject *parent = 0);
@@ -79,27 +94,41 @@ public:
   QStringList providesEnums();
 
 public slots:
-  void registerObject(QObject *object, RegistrationMode mode = Append, const QString &methodPrefix = "handle");
-  void registerEventHandler(EventType event, QObject *object, const char *slot, RegistrationMode mode = Append);
-  void registerEventHandler(QList<EventType> events, QObject *object, const char *slot, RegistrationMode mode = Append);
-
-  //void sendEvent(Event *event);
+  void registerObject(QObject *object, Priority priority = NormalPriority, const QString &methodPrefix = "handle");
+  void registerEventHandler(EventType event, QObject *object, const char *slot, Priority priority = NormalPriority);
+  void registerEventHandler(QList<EventType> events, QObject *object, const char *slot, Priority priority = NormalPriority);
+
+  //! Send an event to the registered handlers
+  /**
+    The EventManager takes ownership of the event and will delete it once it's processed.
+    NOTE: This method is not threadsafe!
+    @param event The event to be dispatched
+   */
+  void sendEvent(Event *event);
 
 private:
   struct Handler {
     QObject *object;
     int methodIndex;
+    Priority priority;
 
-    explicit Handler(QObject *obj = 0, int method = 0) {
+    explicit Handler(QObject *obj = 0, int method = 0, Priority prio = NormalPriority) {
       object = obj;
       methodIndex = method;
+      priority = prio;
     }
   };
 
-  typedef QHash<EventType, QList<Handler> > HandlerHash;
+  typedef QHash<uint, QList<Handler> > HandlerHash;
 
   inline const HandlerHash &registeredHandlers() const { return _registeredHandlers; }
   inline HandlerHash &registeredHandlers() { return _registeredHandlers; }
+
+  //! Add handlers to an existing sorted (by priority) handler list
+  void insertHandlers(const QList<Handler> &newHandlers, QList<Handler> &existing);
+
+  void dispatchEvent(Event *event);
+
   HandlerHash _registeredHandlers;
 
 };