1 /***************************************************************************
2 * Copyright (C) 2005-2014 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 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
19 ***************************************************************************/
21 #include "eventmanager.h"
23 #include <QCoreApplication>
30 // ============================================================
32 // ============================================================
33 class QueuedQuasselEvent : public QEvent
36 QueuedQuasselEvent(Event *event)
37 : QEvent(QEvent::User), event(event) {}
42 // ============================================================
44 // ============================================================
45 EventManager::EventManager(QObject *parent)
51 QMetaEnum EventManager::eventEnum()
53 if (!_enum.isValid()) {
54 int eventEnumIndex = staticMetaObject.indexOfEnumerator("EventType");
55 Q_ASSERT(eventEnumIndex >= 0);
56 _enum = staticMetaObject.enumerator(eventEnumIndex);
57 Q_ASSERT(_enum.isValid());
63 EventManager::EventType EventManager::eventTypeByName(const QString &name)
65 int val = eventEnum().keyToValue(name.toLatin1());
66 return (val == -1) ? Invalid : static_cast<EventType>(val);
70 EventManager::EventType EventManager::eventGroupByName(const QString &name)
72 EventType type = eventTypeByName(name);
73 return type == Invalid ? Invalid : static_cast<EventType>(type & EventGroupMask);
77 QString EventManager::enumName(EventType type)
79 return eventEnum().valueToKey(type);
83 QString EventManager::enumName(int type)
85 return eventEnum().valueToKey(type);
89 Event *EventManager::createEvent(const QVariantMap &map)
93 Network *net = networkById(m.take("network").toInt());
94 return Event::fromVariantMap(m, net);
99 Registering and calling handlers works fine even if they specify a subclass of Event as their parameter.
100 However, this most probably is a result from a reinterpret_cast somewhere deep inside Qt, so there is *no*
101 type safety. If the event sent is of the wrong class type, you'll get a neat segfault!
102 Thus, we need to make sure that events are of the correct class type when sending!
104 We might add a registration-time check later, which will require matching the enum base name (e.g. "IrcEvent") with
105 the type the handler claims to support. This still won't protect us from someone sending an IrcEvent object
106 with an enum type "NetworkIncoming", for example.
108 Another way would be to add a check into the various Event subclasses, such that the ctor matches the given event type
109 with the actual class. Possibly (optionally) using rtti...
112 int EventManager::findEventType(const QString &methodSignature_, const QString &methodPrefix) const
114 if (!methodSignature_.startsWith(methodPrefix))
117 QString methodSignature = methodSignature_;
119 methodSignature = methodSignature.section('(', 0, 0); // chop the attribute list
120 methodSignature = methodSignature.mid(methodPrefix.length()); // strip prefix
124 // special handling for numeric IrcEvents: IrcEvent042 gets mapped to IrcEventNumeric + 42
125 if (methodSignature.length() == 8+3 && methodSignature.startsWith("IrcEvent")) {
126 int num = methodSignature.right(3).toUInt();
128 QString numericSig = methodSignature.left(methodSignature.length() - 3) + "Numeric";
129 eventType = eventEnum().keyToValue(numericSig.toAscii());
131 qWarning() << Q_FUNC_INFO << "Could not find EventType" << numericSig << "for handling" << methodSignature;
139 eventType = eventEnum().keyToValue(methodSignature.toAscii());
141 qWarning() << Q_FUNC_INFO << "Could not find EventType" << methodSignature;
148 void EventManager::registerObject(QObject *object, Priority priority, const QString &methodPrefix, const QString &filterPrefix)
150 for (int i = object->metaObject()->methodOffset(); i < object->metaObject()->methodCount(); i++) {
151 QString methodSignature(object->metaObject()->method(i).signature());
153 int eventType = findEventType(methodSignature, methodPrefix);
155 Handler handler(object, i, priority);
156 registeredHandlers()[eventType].append(handler);
157 //qDebug() << "Registered event handler for" << methodSignature << "in" << object;
159 eventType = findEventType(methodSignature, filterPrefix);
161 Handler handler(object, i, priority);
162 registeredFilters()[eventType].append(handler);
163 //qDebug() << "Registered event filterer for" << methodSignature << "in" << object;
169 void EventManager::registerEventFilter(EventType event, QObject *object, const char *slot)
171 registerEventHandler(QList<EventType>() << event, object, slot, NormalPriority, true);
175 void EventManager::registerEventFilter(QList<EventType> events, QObject *object, const char *slot)
177 registerEventHandler(events, object, slot, NormalPriority, true);
181 void EventManager::registerEventHandler(EventType event, QObject *object, const char *slot, Priority priority, bool isFilter)
183 registerEventHandler(QList<EventType>() << event, object, slot, priority, isFilter);
187 void EventManager::registerEventHandler(QList<EventType> events, QObject *object, const char *slot, Priority priority, bool isFilter)
189 int methodIndex = object->metaObject()->indexOfMethod(slot);
190 if (methodIndex < 0) {
191 qWarning() << Q_FUNC_INFO << QString("Slot %1 not found in object %2").arg(slot).arg(object->objectName());
194 Handler handler(object, methodIndex, priority);
195 foreach(EventType event, events) {
197 registeredFilters()[event].append(handler);
198 qDebug() << "Registered event filter for" << event << "in" << object;
201 registeredHandlers()[event].append(handler);
202 qDebug() << "Registered event handler for" << event << "in" << object;
208 void EventManager::postEvent(Event *event)
210 if (sender() && sender()->thread() != this->thread()) {
211 QueuedQuasselEvent *queuedEvent = new QueuedQuasselEvent(event);
212 QCoreApplication::postEvent(this, queuedEvent);
215 if (_eventQueue.isEmpty())
216 // we're currently not processing events
219 _eventQueue.append(event);
224 void EventManager::customEvent(QEvent *event)
226 if (event->type() == QEvent::User) {
227 QueuedQuasselEvent *queuedEvent = static_cast<QueuedQuasselEvent *>(event);
228 processEvent(queuedEvent->event);
234 void EventManager::processEvent(Event *event)
236 Q_ASSERT(_eventQueue.isEmpty());
237 dispatchEvent(event);
238 // dispatching the event might cause new events to be generated. we process those afterwards.
239 while (!_eventQueue.isEmpty()) {
240 dispatchEvent(_eventQueue.first());
241 _eventQueue.removeFirst();
246 void EventManager::dispatchEvent(Event *event)
248 //qDebug() << "Dispatching" << event;
250 // we try handlers from specialized to generic by masking the enum
252 // build a list sorted by priorities that contains all eligible handlers
253 QList<Handler> handlers;
254 QHash<QObject *, Handler> filters;
255 QSet<QObject *> ignored;
256 uint type = event->type();
258 bool checkDupes = false;
260 // special handling for numeric IrcEvents
261 if ((type & ~IrcEventNumericMask) == IrcEventNumeric) {
262 ::IrcEventNumeric *numEvent = static_cast< ::IrcEventNumeric *>(event);
264 qWarning() << "Invalid event type for IrcEventNumeric!";
266 int num = numEvent->number();
268 insertHandlers(registeredHandlers().value(type + num), handlers, false);
269 insertFilters(registeredFilters().value(type + num), filters);
276 insertHandlers(registeredHandlers().value(type), handlers, checkDupes);
277 insertFilters(registeredFilters().value(type), filters);
279 // check if we have a generic handler for the event group
280 if ((type & EventGroupMask) != type) {
281 insertHandlers(registeredHandlers().value(type & EventGroupMask), handlers, true);
282 insertFilters(registeredFilters().value(type & EventGroupMask), filters);
285 // now dispatch the event
286 QList<Handler>::const_iterator it;
287 for (it = handlers.begin(); it != handlers.end() && !event->isStopped(); ++it) {
288 QObject *obj = it->object;
290 if (ignored.contains(obj)) // object has filtered the event
293 if (filters.contains(obj)) { // we have a filter, so let's check if we want to deliver the event
294 Handler filter = filters.value(obj);
296 void *param[] = { Q_RETURN_ARG(bool, result).data(), Q_ARG(Event *, event).data() };
297 obj->qt_metacall(QMetaObject::InvokeMetaMethod, filter.methodIndex, param);
300 continue; // mmmh, event filter told us to not accept
304 // finally, deliverance!
305 void *param[] = { 0, Q_ARG(Event *, event).data() };
306 obj->qt_metacall(QMetaObject::InvokeMetaMethod, it->methodIndex, param);
314 void EventManager::insertHandlers(const QList<Handler> &newHandlers, QList<Handler> &existing, bool checkDupes)
316 foreach(const Handler &handler, newHandlers) {
317 if (existing.isEmpty())
318 existing.append(handler);
320 // need to insert it at the proper position, but only if we don't yet have a handler for this event and object!
322 QList<Handler>::iterator insertpos = existing.end();
323 QList<Handler>::iterator it = existing.begin();
324 while (it != existing.end()) {
325 if (checkDupes && handler.object == it->object) {
329 if (insertpos == existing.end() && handler.priority > it->priority)
335 existing.insert(it, handler);
341 // priority is ignored, and only the first (should be most specialized) filter is being used
342 // fun things could happen if you used the registerEventFilter() methods in the wrong order though
343 void EventManager::insertFilters(const QList<Handler> &newFilters, QHash<QObject *, Handler> &existing)
345 foreach(const Handler &filter, newFilters) {
346 if (!existing.contains(filter.object))
347 existing[filter.object] = filter;
352 QMetaEnum EventManager::_enum;