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 void EventManager::registerObject(QObject *object, Priority priority, const QString &methodPrefix) {
78 for(int i = object->metaObject()->methodOffset(); i < object->metaObject()->methodCount(); i++) {
79 QString methodSignature(object->metaObject()->method(i).signature());
81 if(!methodSignature.startsWith(methodPrefix))
84 methodSignature = methodSignature.section('(',0,0); // chop the attribute list
85 methodSignature = methodSignature.mid(methodPrefix.length()); // strip prefix
89 // special handling for numeric IrcEvents: IrcEvent042 gets mapped to IrcEventNumeric + 42
90 if(methodSignature.length() == 8+3 && methodSignature.startsWith("IrcEvent")) {
91 int num = methodSignature.right(3).toUInt();
93 QString numericSig = methodSignature.left(methodSignature.length() - 3) + "Numeric";
94 eventType = eventEnum().keyToValue(numericSig.toAscii());
96 qWarning() << Q_FUNC_INFO << "Could not find EventType" << numericSig << "for handling" << methodSignature;
104 eventType = eventEnum().keyToValue(methodSignature.toAscii());
106 qWarning() << Q_FUNC_INFO << "Could not find EventType" << methodSignature;
109 Handler handler(object, i, priority);
110 registeredHandlers()[eventType].append(handler);
111 qDebug() << "Registered event handler for" << methodSignature << "in" << object;
115 void EventManager::registerEventHandler(EventType event, QObject *object, const char *slot, Priority priority) {
116 registerEventHandler(QList<EventType>() << event, object, slot, priority);
119 void EventManager::registerEventHandler(QList<EventType> events, QObject *object, const char *slot, Priority priority) {
120 int methodIndex = object->metaObject()->indexOfMethod(slot);
121 if(methodIndex < 0) {
122 qWarning() << Q_FUNC_INFO << QString("Slot %1 not found in object %2").arg(slot).arg(object->objectName());
125 Handler handler(object, methodIndex, priority);
126 foreach(EventType event, events) {
127 registeredHandlers()[event].append(handler);
128 qDebug() << "Registered event handler for" << event << "in" << object;
132 // not threadsafe! if we should want that, we need to add a mutexed queue somewhere in this general area.
133 void EventManager::sendEvent(Event *event) {
134 // qDebug() << "Sending" << event;
135 _eventQueue.append(event);
136 if(_eventQueue.count() == 1) // we're not currently processing another event
140 void EventManager::customEvent(QEvent *event) {
141 if(event->type() == QEvent::User) {
147 void EventManager::processEvents() {
148 // we only process one event at a time for now, and let Qt's own event processing come in between
149 if(_eventQueue.isEmpty())
151 dispatchEvent(_eventQueue.first());
152 _eventQueue.removeFirst();
153 if(_eventQueue.count())
154 QCoreApplication::postEvent(this, new QEvent(QEvent::User));
157 void EventManager::dispatchEvent(Event *event) {
158 //qDebug() << "Dispatching" << event;
160 // we try handlers from specialized to generic by masking the enum
162 // build a list sorted by priorities that contains all eligible handlers
163 QList<Handler> handlers;
164 uint type = event->type();
166 // special handling for numeric IrcEvents
167 if((type & ~IrcEventNumericMask) == IrcEventNumeric) {
168 ::IrcEventNumeric *numEvent = static_cast< ::IrcEventNumeric *>(event);
170 qWarning() << "Invalid event type for IrcEventNumeric!";
172 int num = numEvent->number();
174 insertHandlers(registeredHandlers().value(type + num), handlers);
179 insertHandlers(registeredHandlers().value(type), handlers);
181 // check if we have a generic handler for the event group
182 if((type & EventGroupMask) != type)
183 insertHandlers(registeredHandlers().value(type & EventGroupMask), handlers);
185 // now dispatch the event
186 QList<Handler>::const_iterator it = handlers.begin();
187 while(it != handlers.end()) {
189 // TODO: check event flags here!
191 void *param[] = {0, Q_ARG(Event *, event).data() };
192 it->object->qt_metacall(QMetaObject::InvokeMetaMethod, it->methodIndex, param);
197 // finally, delete it
201 void EventManager::insertHandlers(const QList<Handler> &newHandlers, QList<Handler> &existing) {
202 foreach(Handler handler, newHandlers) {
203 if(existing.isEmpty())
204 existing.append(handler);
206 // need to insert it at the proper position
207 QList<Handler>::iterator it = existing.begin();
208 while(it != existing.end()) {
209 if(handler.priority > it->priority)
213 existing.insert(it, handler);