1 /***************************************************************************
2 * Copyright (C) 2005-2015 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.toLatin1());
131 qWarning() << Q_FUNC_INFO << "Could not find EventType" << numericSig << "for handling" << methodSignature;
139 eventType = eventEnum().keyToValue(methodSignature.toLatin1());
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 #if QT_VERSION >= 0x050000
152 QString methodSignature = object->metaObject()->method(i).methodSignature();
154 QString methodSignature = object->metaObject()->method(i).signature();
157 int eventType = findEventType(methodSignature, methodPrefix);
159 Handler handler(object, i, priority);
160 registeredHandlers()[eventType].append(handler);
161 //qDebug() << "Registered event handler for" << methodSignature << "in" << object;
163 eventType = findEventType(methodSignature, filterPrefix);
165 Handler handler(object, i, priority);
166 registeredFilters()[eventType].append(handler);
167 //qDebug() << "Registered event filterer for" << methodSignature << "in" << object;
173 void EventManager::registerEventFilter(EventType event, QObject *object, const char *slot)
175 registerEventHandler(QList<EventType>() << event, object, slot, NormalPriority, true);
179 void EventManager::registerEventFilter(QList<EventType> events, QObject *object, const char *slot)
181 registerEventHandler(events, object, slot, NormalPriority, true);
185 void EventManager::registerEventHandler(EventType event, QObject *object, const char *slot, Priority priority, bool isFilter)
187 registerEventHandler(QList<EventType>() << event, object, slot, priority, isFilter);
191 void EventManager::registerEventHandler(QList<EventType> events, QObject *object, const char *slot, Priority priority, bool isFilter)
193 int methodIndex = object->metaObject()->indexOfMethod(slot);
194 if (methodIndex < 0) {
195 qWarning() << Q_FUNC_INFO << QString("Slot %1 not found in object %2").arg(slot).arg(object->objectName());
198 Handler handler(object, methodIndex, priority);
199 foreach(EventType event, events) {
201 registeredFilters()[event].append(handler);
202 qDebug() << "Registered event filter for" << event << "in" << object;
205 registeredHandlers()[event].append(handler);
206 qDebug() << "Registered event handler for" << event << "in" << object;
212 void EventManager::postEvent(Event *event)
214 if (sender() && sender()->thread() != this->thread()) {
215 QueuedQuasselEvent *queuedEvent = new QueuedQuasselEvent(event);
216 QCoreApplication::postEvent(this, queuedEvent);
219 if (_eventQueue.isEmpty())
220 // we're currently not processing events
223 _eventQueue.append(event);
228 void EventManager::customEvent(QEvent *event)
230 if (event->type() == QEvent::User) {
231 QueuedQuasselEvent *queuedEvent = static_cast<QueuedQuasselEvent *>(event);
232 processEvent(queuedEvent->event);
238 void EventManager::processEvent(Event *event)
240 Q_ASSERT(_eventQueue.isEmpty());
241 dispatchEvent(event);
242 // dispatching the event might cause new events to be generated. we process those afterwards.
243 while (!_eventQueue.isEmpty()) {
244 dispatchEvent(_eventQueue.first());
245 _eventQueue.removeFirst();
250 void EventManager::dispatchEvent(Event *event)
252 //qDebug() << "Dispatching" << event;
254 // we try handlers from specialized to generic by masking the enum
256 // build a list sorted by priorities that contains all eligible handlers
257 QList<Handler> handlers;
258 QHash<QObject *, Handler> filters;
259 QSet<QObject *> ignored;
260 uint type = event->type();
262 bool checkDupes = false;
264 // special handling for numeric IrcEvents
265 if ((type & ~IrcEventNumericMask) == IrcEventNumeric) {
266 ::IrcEventNumeric *numEvent = static_cast< ::IrcEventNumeric *>(event);
268 qWarning() << "Invalid event type for IrcEventNumeric!";
270 int num = numEvent->number();
272 insertHandlers(registeredHandlers().value(type + num), handlers, false);
273 insertFilters(registeredFilters().value(type + num), filters);
280 insertHandlers(registeredHandlers().value(type), handlers, checkDupes);
281 insertFilters(registeredFilters().value(type), filters);
283 // check if we have a generic handler for the event group
284 if ((type & EventGroupMask) != type) {
285 insertHandlers(registeredHandlers().value(type & EventGroupMask), handlers, true);
286 insertFilters(registeredFilters().value(type & EventGroupMask), filters);
289 // now dispatch the event
290 QList<Handler>::const_iterator it;
291 for (it = handlers.begin(); it != handlers.end() && !event->isStopped(); ++it) {
292 QObject *obj = it->object;
294 if (ignored.contains(obj)) // object has filtered the event
297 if (filters.contains(obj)) { // we have a filter, so let's check if we want to deliver the event
298 Handler filter = filters.value(obj);
300 void *param[] = { Q_RETURN_ARG(bool, result).data(), Q_ARG(Event *, event).data() };
301 obj->qt_metacall(QMetaObject::InvokeMetaMethod, filter.methodIndex, param);
304 continue; // mmmh, event filter told us to not accept
308 // finally, deliverance!
309 void *param[] = { 0, Q_ARG(Event *, event).data() };
310 obj->qt_metacall(QMetaObject::InvokeMetaMethod, it->methodIndex, param);
318 void EventManager::insertHandlers(const QList<Handler> &newHandlers, QList<Handler> &existing, bool checkDupes)
320 foreach(const Handler &handler, newHandlers) {
321 if (existing.isEmpty())
322 existing.append(handler);
324 // need to insert it at the proper position, but only if we don't yet have a handler for this event and object!
326 QList<Handler>::iterator insertpos = existing.end();
327 QList<Handler>::iterator it = existing.begin();
328 while (it != existing.end()) {
329 if (checkDupes && handler.object == it->object) {
333 if (insertpos == existing.end() && handler.priority > it->priority)
339 existing.insert(it, handler);
345 // priority is ignored, and only the first (should be most specialized) filter is being used
346 // fun things could happen if you used the registerEventFilter() methods in the wrong order though
347 void EventManager::insertFilters(const QList<Handler> &newFilters, QHash<QObject *, Handler> &existing)
349 foreach(const Handler &filter, newFilters) {
350 if (!existing.contains(filter.object))
351 existing[filter.object] = filter;
356 QMetaEnum EventManager::_enum;