From: Manuel Nickschas Date: Tue, 28 Sep 2010 16:37:14 +0000 (+0200) Subject: Introduce event filters X-Git-Tag: 0.8-beta1~112 X-Git-Url: https://git.quassel-irc.org/?p=quassel.git;a=commitdiff_plain;h=5e9a649d94d1832e0b4f3f296e8a2df2d8741d9b Introduce event filters You can now register event filters, either by using registerObject() and providing methods starting with "filter" (by default), similar to the process functions, or by using registerEventFilter(). These filter methods take an Event* and return a bool. If false, the event won't be delivered to the target object at all. A typical use case would be to only accept events that are targeted to a particular network and ignoring the rest, without having to check the net in each event handler. Note that priority is ignored; for registerObject(), filters are added with the most specialized first, and for registerEventFilter() you're responsible for the correct order. --- diff --git a/src/common/eventmanager.cpp b/src/common/eventmanager.cpp index 7ef44942..6c539e72 100644 --- a/src/common/eventmanager.cpp +++ b/src/common/eventmanager.cpp @@ -74,49 +74,72 @@ QString EventManager::enumName(EventType type) const { with the actual class. Possibly (optionally) using rtti... */ -void EventManager::registerObject(QObject *object, Priority priority, const QString &methodPrefix) { - for(int i = object->metaObject()->methodOffset(); i < object->metaObject()->methodCount(); i++) { - QString methodSignature(object->metaObject()->method(i).signature()); - - if(!methodSignature.startsWith(methodPrefix)) - continue; +int EventManager::findEventType(const QString &methodSignature_, const QString &methodPrefix) const { + if(!methodSignature_.startsWith(methodPrefix)) + return -1; + + QString methodSignature = methodSignature_; + + methodSignature = methodSignature.section('(',0,0); // chop the attribute list + methodSignature = methodSignature.mid(methodPrefix.length()); // strip prefix + + int eventType = -1; + + // special handling for numeric IrcEvents: IrcEvent042 gets mapped to IrcEventNumeric + 42 + if(methodSignature.length() == 8+3 && methodSignature.startsWith("IrcEvent")) { + int num = methodSignature.right(3).toUInt(); + if(num > 0) { + QString numericSig = methodSignature.left(methodSignature.length() - 3) + "Numeric"; + eventType = eventEnum().keyToValue(numericSig.toAscii()); + if(eventType < 0) { + qWarning() << Q_FUNC_INFO << "Could not find EventType" << numericSig << "for handling" << methodSignature; + return -1; + } + eventType += num; + } + } - methodSignature = methodSignature.section('(',0,0); // chop the attribute list - methodSignature = methodSignature.mid(methodPrefix.length()); // strip prefix + if(eventType < 0) + eventType = eventEnum().keyToValue(methodSignature.toAscii()); + if(eventType < 0) { + qWarning() << Q_FUNC_INFO << "Could not find EventType" << methodSignature; + return -1; + } + return eventType; +} - int eventType = -1; +void EventManager::registerObject(QObject *object, Priority priority, const QString &methodPrefix, const QString &filterPrefix) { + for(int i = object->metaObject()->methodOffset(); i < object->metaObject()->methodCount(); i++) { + QString methodSignature(object->metaObject()->method(i).signature()); - // special handling for numeric IrcEvents: IrcEvent042 gets mapped to IrcEventNumeric + 42 - if(methodSignature.length() == 8+3 && methodSignature.startsWith("IrcEvent")) { - int num = methodSignature.right(3).toUInt(); - if(num > 0) { - QString numericSig = methodSignature.left(methodSignature.length() - 3) + "Numeric"; - eventType = eventEnum().keyToValue(numericSig.toAscii()); - if(eventType < 0) { - qWarning() << Q_FUNC_INFO << "Could not find EventType" << numericSig << "for handling" << methodSignature; - continue; - } - eventType += num; - } + int eventType = findEventType(methodSignature, methodPrefix); + if(eventType > 0) { + Handler handler(object, i, priority); + registeredHandlers()[eventType].append(handler); + qDebug() << "Registered event handler for" << methodSignature << "in" << object; } - - if(eventType < 0) - eventType = eventEnum().keyToValue(methodSignature.toAscii()); - if(eventType < 0) { - qWarning() << Q_FUNC_INFO << "Could not find EventType" << methodSignature; - continue; + eventType = findEventType(methodSignature, filterPrefix); + if(eventType > 0) { + Handler handler(object, i, priority); + registeredFilters()[eventType].append(handler); + qDebug() << "Registered event filterer for" << methodSignature << "in" << object; } - Handler handler(object, i, priority); - registeredHandlers()[eventType].append(handler); - qDebug() << "Registered event handler for" << methodSignature << "in" << object; } } -void EventManager::registerEventHandler(EventType event, QObject *object, const char *slot, Priority priority) { - registerEventHandler(QList() << event, object, slot, priority); +void EventManager::registerEventFilter(EventType event, QObject *object, const char *slot) { + registerEventHandler(QList() << event, object, slot, NormalPriority, true); } -void EventManager::registerEventHandler(QList events, QObject *object, const char *slot, Priority priority) { +void EventManager::registerEventFilter(QList events, QObject *object, const char *slot) { + registerEventHandler(events, object, slot, NormalPriority, true); +} + +void EventManager::registerEventHandler(EventType event, QObject *object, const char *slot, Priority priority, bool isFilter) { + registerEventHandler(QList() << event, object, slot, priority, isFilter); +} + +void EventManager::registerEventHandler(QList events, QObject *object, const char *slot, Priority priority, bool isFilter) { 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()); @@ -124,8 +147,13 @@ void EventManager::registerEventHandler(QList events, QObject *object } Handler handler(object, methodIndex, priority); foreach(EventType event, events) { - registeredHandlers()[event].append(handler); - qDebug() << "Registered event handler for" << event << "in" << object; + if(isFilter) { + registeredFilters()[event].append(handler); + qDebug() << "Registered event filter for" << event << "in" << object; + } else { + registeredHandlers()[event].append(handler); + qDebug() << "Registered event handler for" << event << "in" << object; + } } } @@ -161,6 +189,8 @@ void EventManager::dispatchEvent(Event *event) { // build a list sorted by priorities that contains all eligible handlers QList handlers; + QHash filters; + QSet ignored; uint type = event->type(); // special handling for numeric IrcEvents @@ -170,36 +200,54 @@ void EventManager::dispatchEvent(Event *event) { qWarning() << "Invalid event type for IrcEventNumeric!"; else { int num = numEvent->number(); - if(num > 0) + if(num > 0) { insertHandlers(registeredHandlers().value(type + num), handlers); + insertFilters(registeredFilters().value(type + num), filters); + } } } // exact type insertHandlers(registeredHandlers().value(type), handlers); + insertFilters(registeredFilters().value(type), filters); // check if we have a generic handler for the event group - if((type & EventGroupMask) != type) + if((type & EventGroupMask) != type) { insertHandlers(registeredHandlers().value(type & EventGroupMask), handlers); + insertFilters(registeredFilters().value(type & EventGroupMask), filters); + } // now dispatch the event QList::const_iterator it = handlers.begin(); - while(it != handlers.end()) { + while(it != handlers.end() && !event->isStopped()) { + QObject *obj = it->object; + + if(ignored.contains(obj)) // we only deliver an event once to any given object + continue; - // TODO: check event flags here! + if(filters.contains(obj)) { // we have a filter, so let's check if we want to deliver the event + Handler filter = filters.value(obj); + bool result = false; + void *param[] = {Q_RETURN_ARG(bool, result).data(), Q_ARG(Event *, event).data() }; + obj->qt_metacall(QMetaObject::InvokeMetaMethod, filter.methodIndex, param); + ignored.insert(obj); // don't try to deliver the event again either way + if(!result) + continue; // mmmh, event filter told us to not accept + } + // finally, deliverance! void *param[] = {0, Q_ARG(Event *, event).data() }; - it->object->qt_metacall(QMetaObject::InvokeMetaMethod, it->methodIndex, param); + obj->qt_metacall(QMetaObject::InvokeMetaMethod, it->methodIndex, param); ++it; } - // finally, delete it + // that's it delete event; } void EventManager::insertHandlers(const QList &newHandlers, QList &existing) { - foreach(Handler handler, newHandlers) { + foreach(const Handler &handler, newHandlers) { if(existing.isEmpty()) existing.append(handler); else { @@ -214,3 +262,12 @@ void EventManager::insertHandlers(const QList &newHandlers, QList &newFilters, QHash &existing) { + foreach(const Handler &filter, newFilters) { + if(!existing.contains(filter.object)) + existing[filter.object] = filter; + } +} diff --git a/src/common/eventmanager.h b/src/common/eventmanager.h index 780d21b7..a5b7a272 100644 --- a/src/common/eventmanager.h +++ b/src/common/eventmanager.h @@ -109,9 +109,16 @@ public: QString enumName(EventType type) const; public slots: - 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 events, QObject *object, const char *slot, Priority priority = NormalPriority); + void registerObject(QObject *object, Priority priority = NormalPriority, + const QString &methodPrefix = "process", + const QString &filterPrefix = "filter"); + void registerEventHandler(EventType event, QObject *object, const char *slot, + Priority priority = NormalPriority, bool isFilter = false); + void registerEventHandler(QList events, QObject *object, const char *slot, + Priority priority = NormalPriority, bool isFilter = false); + + void registerEventFilter(EventType event, QObject *object, const char *slot); + void registerEventFilter(QList events, QObject *object, const char *slot); //! Send an event to the registered handlers /** @@ -142,8 +149,15 @@ private: inline const HandlerHash ®isteredHandlers() const { return _registeredHandlers; } inline HandlerHash ®isteredHandlers() { return _registeredHandlers; } + inline const HandlerHash ®isteredFilters() const { return _registeredFilters; } + inline HandlerHash ®isteredFilters() { return _registeredFilters; } + //! Add handlers to an existing sorted (by priority) handler list void insertHandlers(const QList &newHandlers, QList &existing); + //! Add filters to an existing filter hash + void insertFilters(const QList &newFilters, QHash &existing); + + int findEventType(const QString &methodSignature, const QString &methodPrefix) const; void processEvents(); void dispatchEvent(Event *event); @@ -152,6 +166,7 @@ private: QMetaEnum eventEnum() const; HandlerHash _registeredHandlers; + HandlerHash _registeredFilters; mutable QMetaEnum _enum; QList _eventQueue;