1 /***************************************************************************
2 * Copyright (C) 2005-2010 by the Quassel Project *
3 * devel@quassel-irc.org *
5 * This program is free software; you can redistribute it and/or modify *
6 * it under the terms of the GNU General Public License as published by *
7 * the Free Software Foundation; either version 2 of the License, or *
8 * (at your option) version 3. *
10 * This program is distributed in the hope that it will be useful, *
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
13 * GNU General Public License for more details. *
15 * You should have received a copy of the GNU General Public License *
16 * along with this program; if not, write to the *
17 * Free Software Foundation, Inc., *
18 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
19 ***************************************************************************/
21 #include "eventmanager.h"
23 #include <QCoreApplication>
30 EventManager::EventManager(QObject *parent) : QObject(parent) {
34 EventManager::~EventManager() {
35 // pending events won't be delivered anymore, but we do need to delete them
36 qDeleteAll(_eventQueue);
39 QMetaEnum EventManager::eventEnum() const {
40 if(!_enum.isValid()) {
41 int eventEnumIndex = metaObject()->indexOfEnumerator("EventType");
42 Q_ASSERT(eventEnumIndex >= 0);
43 _enum = metaObject()->enumerator(eventEnumIndex);
44 Q_ASSERT(_enum.isValid());
49 EventManager::EventType EventManager::eventTypeByName(const QString &name) const {
50 int val = eventEnum().keyToValue(name.toLatin1());
51 return (val == -1) ? Invalid : static_cast<EventType>(val);
54 EventManager::EventType EventManager::eventGroupByName(const QString &name) const {
55 EventType type = eventTypeByName(name);
56 return type == Invalid? Invalid : static_cast<EventType>(type & EventGroupMask);
59 QString EventManager::enumName(EventType type) const {
60 return eventEnum().valueToKey(type);
64 Registering and calling handlers works fine even if they specify a subclass of Event as their parameter.
65 However, this most probably is a result from a reinterpret_cast somewhere deep inside Qt, so there is *no*
66 type safety. If the event sent is of the wrong class type, you'll get a neat segfault!
67 Thus, we need to make sure that events are of the correct class type when sending!
69 We might add a registration-time check later, which will require matching the enum base name (e.g. "IrcEvent") with
70 the type the handler claims to support. This still won't protect us from someone sending an IrcEvent object
71 with an enum type "NetworkIncoming", for example.
73 Another way would be to add a check into the various Event subclasses, such that the ctor matches the given event type
74 with the actual class. Possibly (optionally) using rtti...
77 int EventManager::findEventType(const QString &methodSignature_, const QString &methodPrefix) const {
78 if(!methodSignature_.startsWith(methodPrefix))
81 QString methodSignature = methodSignature_;
83 methodSignature = methodSignature.section('(',0,0); // chop the attribute list
84 methodSignature = methodSignature.mid(methodPrefix.length()); // strip prefix
88 // special handling for numeric IrcEvents: IrcEvent042 gets mapped to IrcEventNumeric + 42
89 if(methodSignature.length() == 8+3 && methodSignature.startsWith("IrcEvent")) {
90 int num = methodSignature.right(3).toUInt();
92 QString numericSig = methodSignature.left(methodSignature.length() - 3) + "Numeric";
93 eventType = eventEnum().keyToValue(numericSig.toAscii());
95 qWarning() << Q_FUNC_INFO << "Could not find EventType" << numericSig << "for handling" << methodSignature;
103 eventType = eventEnum().keyToValue(methodSignature.toAscii());
105 qWarning() << Q_FUNC_INFO << "Could not find EventType" << methodSignature;
111 void EventManager::registerObject(QObject *object, Priority priority, const QString &methodPrefix, const QString &filterPrefix) {
112 for(int i = object->metaObject()->methodOffset(); i < object->metaObject()->methodCount(); i++) {
113 QString methodSignature(object->metaObject()->method(i).signature());
115 int eventType = findEventType(methodSignature, methodPrefix);
117 Handler handler(object, i, priority);
118 registeredHandlers()[eventType].append(handler);
119 //qDebug() << "Registered event handler for" << methodSignature << "in" << object;
121 eventType = findEventType(methodSignature, filterPrefix);
123 Handler handler(object, i, priority);
124 registeredFilters()[eventType].append(handler);
125 //qDebug() << "Registered event filterer for" << methodSignature << "in" << object;
130 void EventManager::registerEventFilter(EventType event, QObject *object, const char *slot) {
131 registerEventHandler(QList<EventType>() << event, object, slot, NormalPriority, true);
134 void EventManager::registerEventFilter(QList<EventType> events, QObject *object, const char *slot) {
135 registerEventHandler(events, object, slot, NormalPriority, true);
138 void EventManager::registerEventHandler(EventType event, QObject *object, const char *slot, Priority priority, bool isFilter) {
139 registerEventHandler(QList<EventType>() << event, object, slot, priority, isFilter);
142 void EventManager::registerEventHandler(QList<EventType> events, QObject *object, const char *slot, Priority priority, bool isFilter) {
143 int methodIndex = object->metaObject()->indexOfMethod(slot);
144 if(methodIndex < 0) {
145 qWarning() << Q_FUNC_INFO << QString("Slot %1 not found in object %2").arg(slot).arg(object->objectName());
148 Handler handler(object, methodIndex, priority);
149 foreach(EventType event, events) {
151 registeredFilters()[event].append(handler);
152 qDebug() << "Registered event filter for" << event << "in" << object;
154 registeredHandlers()[event].append(handler);
155 qDebug() << "Registered event handler for" << event << "in" << object;
160 // not threadsafe! if we should want that, we need to add a mutexed queue somewhere in this general area.
161 void EventManager::sendEvent(Event *event) {
162 // qDebug() << "Sending" << event;
163 _eventQueue.append(event);
164 if(_eventQueue.count() == 1) // we're not currently processing another event
168 void EventManager::customEvent(QEvent *event) {
169 if(event->type() == QEvent::User) {
175 void EventManager::processEvents() {
176 // we only process one event at a time for now, and let Qt's own event processing come in between
177 if(_eventQueue.isEmpty())
179 dispatchEvent(_eventQueue.first());
180 _eventQueue.removeFirst();
181 if(_eventQueue.count())
182 QCoreApplication::postEvent(this, new QEvent(QEvent::User));
184 emit eventQueueEmptied();
187 void EventManager::dispatchEvent(Event *event) {
188 //qDebug() << "Dispatching" << event;
190 // we try handlers from specialized to generic by masking the enum
192 // build a list sorted by priorities that contains all eligible handlers
193 QList<Handler> handlers;
194 QHash<QObject *, Handler> filters;
195 QSet<QObject *> ignored;
196 uint type = event->type();
198 bool checkDupes = false;
200 // special handling for numeric IrcEvents
201 if((type & ~IrcEventNumericMask) == IrcEventNumeric) {
202 ::IrcEventNumeric *numEvent = static_cast< ::IrcEventNumeric *>(event);
204 qWarning() << "Invalid event type for IrcEventNumeric!";
206 int num = numEvent->number();
208 insertHandlers(registeredHandlers().value(type + num), handlers, false);
209 insertFilters(registeredFilters().value(type + num), filters);
216 insertHandlers(registeredHandlers().value(type), handlers, checkDupes);
217 insertFilters(registeredFilters().value(type), filters);
219 // check if we have a generic handler for the event group
220 if((type & EventGroupMask) != type) {
221 insertHandlers(registeredHandlers().value(type & EventGroupMask), handlers, true);
222 insertFilters(registeredFilters().value(type & EventGroupMask), filters);
225 // now dispatch the event
226 QList<Handler>::const_iterator it;
227 for(it = handlers.begin(); it != handlers.end() && !event->isStopped(); ++it) {
228 QObject *obj = it->object;
230 if(ignored.contains(obj)) // object has filtered the event
233 if(filters.contains(obj)) { // we have a filter, so let's check if we want to deliver the event
234 Handler filter = filters.value(obj);
236 void *param[] = {Q_RETURN_ARG(bool, result).data(), Q_ARG(Event *, event).data() };
237 obj->qt_metacall(QMetaObject::InvokeMetaMethod, filter.methodIndex, param);
240 continue; // mmmh, event filter told us to not accept
244 // finally, deliverance!
245 void *param[] = {0, Q_ARG(Event *, event).data() };
246 obj->qt_metacall(QMetaObject::InvokeMetaMethod, it->methodIndex, param);
253 void EventManager::insertHandlers(const QList<Handler> &newHandlers, QList<Handler> &existing, bool checkDupes) {
254 foreach(const Handler &handler, newHandlers) {
255 if(existing.isEmpty())
256 existing.append(handler);
258 // need to insert it at the proper position, but only if we don't yet have a handler for this event and object!
260 QList<Handler>::iterator insertpos = existing.end();
261 QList<Handler>::iterator it = existing.begin();
262 while(it != existing.end()) {
263 if(checkDupes && handler.object == it->object) {
267 if(insertpos == existing.end() && handler.priority > it->priority)
273 existing.insert(it, handler);
278 // priority is ignored, and only the first (should be most specialized) filter is being used
279 // fun things could happen if you used the registerEventFilter() methods in the wrong order though
280 void EventManager::insertFilters(const QList<Handler> &newFilters, QHash<QObject *, Handler> &existing) {
281 foreach(const Handler &filter, newFilters) {
282 if(!existing.contains(filter.object))
283 existing[filter.object] = filter;