1 /***************************************************************************
2 * Copyright (C) 2005-2012 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 // ============================================================
32 // ============================================================
33 class QueuedQuasselEvent : public QEvent {
35 QueuedQuasselEvent(Event *event)
36 : QEvent(QEvent::User), event(event) {}
40 // ============================================================
42 // ============================================================
43 EventManager::EventManager(QObject *parent)
47 QMetaEnum EventManager::eventEnum() {
48 if(!_enum.isValid()) {
49 int eventEnumIndex = staticMetaObject.indexOfEnumerator("EventType");
50 Q_ASSERT(eventEnumIndex >= 0);
51 _enum = staticMetaObject.enumerator(eventEnumIndex);
52 Q_ASSERT(_enum.isValid());
57 EventManager::EventType EventManager::eventTypeByName(const QString &name) {
58 int val = eventEnum().keyToValue(name.toLatin1());
59 return (val == -1) ? Invalid : static_cast<EventType>(val);
62 EventManager::EventType EventManager::eventGroupByName(const QString &name) {
63 EventType type = eventTypeByName(name);
64 return type == Invalid? Invalid : static_cast<EventType>(type & EventGroupMask);
67 QString EventManager::enumName(EventType type) {
68 return eventEnum().valueToKey(type);
71 QString EventManager::enumName(int type) {
72 return eventEnum().valueToKey(type);
76 Registering and calling handlers works fine even if they specify a subclass of Event as their parameter.
77 However, this most probably is a result from a reinterpret_cast somewhere deep inside Qt, so there is *no*
78 type safety. If the event sent is of the wrong class type, you'll get a neat segfault!
79 Thus, we need to make sure that events are of the correct class type when sending!
81 We might add a registration-time check later, which will require matching the enum base name (e.g. "IrcEvent") with
82 the type the handler claims to support. This still won't protect us from someone sending an IrcEvent object
83 with an enum type "NetworkIncoming", for example.
85 Another way would be to add a check into the various Event subclasses, such that the ctor matches the given event type
86 with the actual class. Possibly (optionally) using rtti...
89 int EventManager::findEventType(const QString &methodSignature_, const QString &methodPrefix) const {
90 if(!methodSignature_.startsWith(methodPrefix))
93 QString methodSignature = methodSignature_;
95 methodSignature = methodSignature.section('(',0,0); // chop the attribute list
96 methodSignature = methodSignature.mid(methodPrefix.length()); // strip prefix
100 // special handling for numeric IrcEvents: IrcEvent042 gets mapped to IrcEventNumeric + 42
101 if(methodSignature.length() == 8+3 && methodSignature.startsWith("IrcEvent")) {
102 int num = methodSignature.right(3).toUInt();
104 QString numericSig = methodSignature.left(methodSignature.length() - 3) + "Numeric";
105 eventType = eventEnum().keyToValue(numericSig.toAscii());
107 qWarning() << Q_FUNC_INFO << "Could not find EventType" << numericSig << "for handling" << methodSignature;
115 eventType = eventEnum().keyToValue(methodSignature.toAscii());
117 qWarning() << Q_FUNC_INFO << "Could not find EventType" << methodSignature;
123 void EventManager::registerObject(QObject *object, Priority priority, const QString &methodPrefix, const QString &filterPrefix) {
124 for(int i = object->metaObject()->methodOffset(); i < object->metaObject()->methodCount(); i++) {
125 QString methodSignature(object->metaObject()->method(i).signature());
127 int eventType = findEventType(methodSignature, methodPrefix);
129 Handler handler(object, i, priority);
130 registeredHandlers()[eventType].append(handler);
131 //qDebug() << "Registered event handler for" << methodSignature << "in" << object;
133 eventType = findEventType(methodSignature, filterPrefix);
135 Handler handler(object, i, priority);
136 registeredFilters()[eventType].append(handler);
137 //qDebug() << "Registered event filterer for" << methodSignature << "in" << object;
142 void EventManager::registerEventFilter(EventType event, QObject *object, const char *slot) {
143 registerEventHandler(QList<EventType>() << event, object, slot, NormalPriority, true);
146 void EventManager::registerEventFilter(QList<EventType> events, QObject *object, const char *slot) {
147 registerEventHandler(events, object, slot, NormalPriority, true);
150 void EventManager::registerEventHandler(EventType event, QObject *object, const char *slot, Priority priority, bool isFilter) {
151 registerEventHandler(QList<EventType>() << event, object, slot, priority, isFilter);
154 void EventManager::registerEventHandler(QList<EventType> events, QObject *object, const char *slot, Priority priority, bool isFilter) {
155 int methodIndex = object->metaObject()->indexOfMethod(slot);
156 if(methodIndex < 0) {
157 qWarning() << Q_FUNC_INFO << QString("Slot %1 not found in object %2").arg(slot).arg(object->objectName());
160 Handler handler(object, methodIndex, priority);
161 foreach(EventType event, events) {
163 registeredFilters()[event].append(handler);
164 qDebug() << "Registered event filter for" << event << "in" << object;
166 registeredHandlers()[event].append(handler);
167 qDebug() << "Registered event handler for" << event << "in" << object;
172 void EventManager::postEvent(Event *event) {
173 if(sender() && sender()->thread() != this->thread()) {
174 QueuedQuasselEvent *queuedEvent = new QueuedQuasselEvent(event);
175 QCoreApplication::postEvent(this, queuedEvent);
177 if(_eventQueue.isEmpty())
178 // we're currently not processing events
181 _eventQueue.append(event);
185 void EventManager::customEvent(QEvent *event) {
186 if(event->type() == QEvent::User) {
187 QueuedQuasselEvent *queuedEvent = static_cast<QueuedQuasselEvent *>(event);
188 processEvent(queuedEvent->event);
193 void EventManager::processEvent(Event *event) {
194 Q_ASSERT(_eventQueue.isEmpty());
195 dispatchEvent(event);
196 // dispatching the event might cause new events to be generated. we process those afterwards.
197 while(!_eventQueue.isEmpty()) {
198 dispatchEvent(_eventQueue.first());
199 _eventQueue.removeFirst();
203 void EventManager::dispatchEvent(Event *event) {
204 //qDebug() << "Dispatching" << event;
206 // we try handlers from specialized to generic by masking the enum
208 // build a list sorted by priorities that contains all eligible handlers
209 QList<Handler> handlers;
210 QHash<QObject *, Handler> filters;
211 QSet<QObject *> ignored;
212 uint type = event->type();
214 bool checkDupes = false;
216 // special handling for numeric IrcEvents
217 if((type & ~IrcEventNumericMask) == IrcEventNumeric) {
218 ::IrcEventNumeric *numEvent = static_cast< ::IrcEventNumeric *>(event);
220 qWarning() << "Invalid event type for IrcEventNumeric!";
222 int num = numEvent->number();
224 insertHandlers(registeredHandlers().value(type + num), handlers, false);
225 insertFilters(registeredFilters().value(type + num), filters);
232 insertHandlers(registeredHandlers().value(type), handlers, checkDupes);
233 insertFilters(registeredFilters().value(type), filters);
235 // check if we have a generic handler for the event group
236 if((type & EventGroupMask) != type) {
237 insertHandlers(registeredHandlers().value(type & EventGroupMask), handlers, true);
238 insertFilters(registeredFilters().value(type & EventGroupMask), filters);
241 // now dispatch the event
242 QList<Handler>::const_iterator it;
243 for(it = handlers.begin(); it != handlers.end() && !event->isStopped(); ++it) {
244 QObject *obj = it->object;
246 if(ignored.contains(obj)) // object has filtered the event
249 if(filters.contains(obj)) { // we have a filter, so let's check if we want to deliver the event
250 Handler filter = filters.value(obj);
252 void *param[] = {Q_RETURN_ARG(bool, result).data(), Q_ARG(Event *, event).data() };
253 obj->qt_metacall(QMetaObject::InvokeMetaMethod, filter.methodIndex, param);
256 continue; // mmmh, event filter told us to not accept
260 // finally, deliverance!
261 void *param[] = {0, Q_ARG(Event *, event).data() };
262 obj->qt_metacall(QMetaObject::InvokeMetaMethod, it->methodIndex, param);
269 void EventManager::insertHandlers(const QList<Handler> &newHandlers, QList<Handler> &existing, bool checkDupes) {
270 foreach(const Handler &handler, newHandlers) {
271 if(existing.isEmpty())
272 existing.append(handler);
274 // need to insert it at the proper position, but only if we don't yet have a handler for this event and object!
276 QList<Handler>::iterator insertpos = existing.end();
277 QList<Handler>::iterator it = existing.begin();
278 while(it != existing.end()) {
279 if(checkDupes && handler.object == it->object) {
283 if(insertpos == existing.end() && handler.priority > it->priority)
289 existing.insert(it, handler);
294 // priority is ignored, and only the first (should be most specialized) filter is being used
295 // fun things could happen if you used the registerEventFilter() methods in the wrong order though
296 void EventManager::insertFilters(const QList<Handler> &newFilters, QHash<QObject *, Handler> &existing) {
297 foreach(const Handler &filter, newFilters) {
298 if(!existing.contains(filter.object))
299 existing[filter.object] = filter;
303 QMetaEnum EventManager::_enum;