From: Marcus Eggenberger Date: Tue, 13 Nov 2007 16:44:11 +0000 (+0000) Subject: Finaly got rid of the synchronizers, making Quassel quite a bit more lightweight... X-Git-Tag: 0.1.0~72 X-Git-Url: https://git.quassel-irc.org/?p=quassel.git;a=commitdiff_plain;h=a7f5d6a23f7214b11f6db85346a67fd7d02767da;hp=1956aab57bf98ce072ed86f34785e5d7abba35a0 Finaly got rid of the synchronizers, making Quassel quite a bit more lightweight without losing the comfort of those Synchronizers. --- diff --git a/src/client/client.cpp b/src/client/client.cpp index 29e68d89..ec01b283 100644 --- a/src/client/client.cpp +++ b/src/client/client.cpp @@ -30,7 +30,6 @@ #include "buffertreemodel.h" #include "quasselui.h" #include "signalproxy.h" -#include "synchronizer.h" #include "util.h" QPointer Client::instanceptr = 0; @@ -232,9 +231,7 @@ void Client::connectToCore(const QVariantMap &conn) { socket = sock; connect(sock, SIGNAL(readyRead()), this, SLOT(coreHasData())); connect(sock, SIGNAL(connected()), this, SLOT(coreSocketConnected())); - connect(sock, SIGNAL(disconnected()), this, SLOT(coreSocketDisconnected())); connect(signalProxy(), SIGNAL(disconnected()), this, SLOT(coreSocketDisconnected())); - //connect(sock, SIGNAL(stateChanged(QAbstractSocket::SocketState)), this, SLOT(coreSocketStateChanged(QAbstractSocket::SocketState))); connect(sock, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(coreSocketError(QAbstractSocket::SocketError))); sock->connectToHost(conn["Host"].toString(), conn["Port"].toUInt()); } @@ -242,9 +239,6 @@ void Client::connectToCore(const QVariantMap &conn) { void Client::disconnectFromCore() { socket->close(); - if(clientMode == LocalCore) { - coreSocketDisconnected(); - } } void Client::setCoreConfiguration(const QVariantMap &settings) { @@ -269,26 +263,32 @@ void Client::coreSocketDisconnected() { /* Clear internal data. Hopefully nothing relies on it at this point. */ _bufferModel->clear(); - foreach(Buffer *buffer, _buffers.values()) { + + QHash::iterator bufferIter = _buffers.begin(); + while(bufferIter != _buffers.end()) { + Buffer *buffer = bufferIter.value(); + disconnect(buffer, SIGNAL(destroyed()), this, 0); + bufferIter = _buffers.erase(bufferIter); buffer->deleteLater(); } - _buffers.clear(); + Q_ASSERT(_buffers.isEmpty()); - foreach(NetworkInfo *networkinfo, _networkInfo.values()) { - networkinfo->deleteLater(); - } - _networkInfo.clear(); + QHash::iterator netIter = _networkInfo.begin(); + while(netIter != _networkInfo.end()) { + NetworkInfo *net = netIter.value(); + disconnect(net, SIGNAL(destroyed()), this, 0); + netIter = _networkInfo.erase(netIter); + net->deleteLater(); + } + Q_ASSERT(_networkInfo.isEmpty()); + coreConnectionInfo.clear(); sessionData.clear(); layoutQueue.clear(); layoutTimer->stop(); } -void Client::coreSocketStateChanged(QAbstractSocket::SocketState state) { - if(state == QAbstractSocket::UnconnectedState) coreSocketDisconnected(); -} - void Client::recvCoreState(const QVariant &state) { disconnect(this, SIGNAL(recvPartialItem(uint, uint)), this, SIGNAL(coreConnectionProgress(uint, uint))); disconnect(socket, 0, this, 0); // rest of communication happens through SignalProxy @@ -380,8 +380,7 @@ void Client::updateCoreConnectionProgress() { } emit coreConnectionProgress(1,1); - emit connected(); // FIXME EgS: This caused the double backlog... but... we shouldn't be calling this whole function all the time... - + emit connected(); foreach(NetworkInfo *net, networkInfos()) { disconnect(net, 0, this, SLOT(updateCoreConnectionProgress())); } @@ -442,8 +441,9 @@ void Client::networkConnected(uint netid) { //Buffer *b = buffer(id); //b->setActive(true); - // FIXME EgS: do we really need to call updateCoreConnectionProgress whenever a new network is connected? - NetworkInfo *netinfo = new NetworkInfo(netid, signalProxy(), this); + NetworkInfo *netinfo = new NetworkInfo(netid, this); + netinfo->setProxy(signalProxy()); + if(!isConnected()) { connect(netinfo, SIGNAL(initDone()), this, SLOT(updateCoreConnectionProgress())); connect(netinfo, SIGNAL(ircUserInitDone()), this, SLOT(updateCoreConnectionProgress())); diff --git a/src/client/client.h b/src/client/client.h index f3ac138e..2f3d907b 100644 --- a/src/client/client.h +++ b/src/client/client.h @@ -115,7 +115,6 @@ private slots: void coreHasData(); void coreSocketConnected(); void coreSocketDisconnected(); - void coreSocketStateChanged(QAbstractSocket::SocketState); void userInput(BufferInfo, QString); @@ -128,11 +127,12 @@ private slots: void recvBacklogData(BufferInfo, QVariantList, bool); void updateBufferInfo(BufferInfo); + void layoutMsg(); + +private slots: void bufferDestroyed(); void networkInfoDestroyed(); - void layoutMsg(); - private: Client(QObject *parent = 0); virtual ~Client(); diff --git a/src/common/common.pri b/src/common/common.pri index 94187649..dec566a4 100644 --- a/src/common/common.pri +++ b/src/common/common.pri @@ -1,4 +1,4 @@ DEPMOD = QT_MOD = network -SRCS += global.cpp logger.cpp message.cpp settings.cpp signalproxy.cpp util.cpp synchronizer.cpp networkinfo.cpp ircuser.cpp ircchannel.cpp bufferinfo.cpp -HDRS += global.h logger.h message.h settings.h signalproxy.h util.h synchronizer.h networkinfo.h ircuser.h ircchannel.h bufferinfo.h +SRCS += global.cpp logger.cpp message.cpp settings.cpp signalproxy.cpp util.cpp networkinfo.cpp ircuser.cpp ircchannel.cpp bufferinfo.cpp +HDRS += global.h logger.h message.h settings.h signalproxy.h util.h networkinfo.h ircuser.h ircchannel.h bufferinfo.h diff --git a/src/common/ircuser.cpp b/src/common/ircuser.cpp index bc341437..fb257495 100644 --- a/src/common/ircuser.cpp +++ b/src/common/ircuser.cpp @@ -35,7 +35,7 @@ IrcUser::IrcUser(const QString &hostmask, NetworkInfo *networkinfo) _host(hostFromMask(hostmask)), networkInfo(networkinfo) { - setObjectName(QString::number(networkInfo->networkId()) + "/" + IrcUser::hostmask()); + updateObjectName(); } IrcUser::~IrcUser() { @@ -72,11 +72,6 @@ QStringList IrcUser::channels() const { return _channels.toList(); } -void IrcUser::updateObjectName() { - setObjectName(QString::number(networkInfo->networkId()) + "/" + hostmask()); - emit objectNameSet(); -} - // ==================== // PUBLIC SLOTS: // ==================== @@ -84,9 +79,6 @@ void IrcUser::setUser(const QString &user) { if(!user.isEmpty() && _user != user) { _user = user; emit userSet(user); - - setObjectName(hostmask()); - emit objectNameSet(); } } @@ -94,7 +86,6 @@ void IrcUser::setHost(const QString &host) { if(!host.isEmpty() && _host != host) { _host = host; emit hostSet(host); - updateObjectName(); } } @@ -102,35 +93,28 @@ void IrcUser::setNick(const QString &nick) { if(!nick.isEmpty() && nick != _nick) { QString oldnick(_nick); _nick = nick; - emit nickSet(nick); updateObjectName(); + emit nickSet(nick); + } +} + +void IrcUser::updateObjectName() { + QString oldName(objectName()); + setObjectName(QString::number(networkInfo->networkId()) + "/" + _nick); + if(!oldName.isEmpty()) { + emit renameObject(oldName, objectName()); } } + void IrcUser::updateHostmask(const QString &mask) { if(mask == hostmask()) return; QString user = userFromMask(mask); QString host = hostFromMask(mask); - - // we only need to check user and hostmask. - // nick can't have changed since we're identifying IrcUsers by nick - - // we don't use setUser and setHost here. - // though this is unpretty code duplication this saves us one emit objectNameSet() - // the second one would be erroneous - - if(!user.isEmpty() && _user != user) { - _user = user; - } - - if(!host.isEmpty() && _host != host) { - _host = host; - } - - emit hostmaskUpdated(mask); - updateObjectName(); + setUser(user); + setHost(host); } void IrcUser::joinChannel(const QString &channel) { diff --git a/src/common/ircuser.h b/src/common/ircuser.h index 93ec9ebd..1ed1c85d 100644 --- a/src/common/ircuser.h +++ b/src/common/ircuser.h @@ -56,8 +56,6 @@ public: QStringList channels() const; - void updateObjectName(); - public slots: void setUser(const QString &user); void setHost(const QString &host); @@ -92,13 +90,16 @@ signals: void userModeAdded(QString mode); void userModeRemoved(QString mode); - void objectNameSet(); + void renameObject(QString oldname, QString newname); // void setUsermodes(const QSet &usermodes); // QSet usermodes() const; void initDone(); +private slots: + void updateObjectName(); + private: inline bool operator==(const IrcUser &ircuser2) { return (_nick.toLower() == ircuser2.nick().toLower()); diff --git a/src/common/networkinfo.cpp b/src/common/networkinfo.cpp index 24ed8d7f..8791ffff 100644 --- a/src/common/networkinfo.cpp +++ b/src/common/networkinfo.cpp @@ -20,7 +20,6 @@ #include "networkinfo.h" #include "signalproxy.h" -#include "synchronizer.h" #include "ircuser.h" #include "ircchannel.h" @@ -31,7 +30,7 @@ // ==================== // Public: // ==================== -NetworkInfo::NetworkInfo(const uint &networkid, SignalProxy *proxy, QObject *parent) +NetworkInfo::NetworkInfo(const uint &networkid, QObject *parent) : QObject(parent), _networkId(networkid), _initialized(false), @@ -39,10 +38,10 @@ NetworkInfo::NetworkInfo(const uint &networkid, SignalProxy *proxy, QObject *par _networkName(QString()), _currentServer(QString()), _prefixes(QString()), - _prefixModes(QString()) + _prefixModes(QString()), + _proxy(NULL) { setObjectName(QString::number(networkid)); - _synchronizer = new Synchronizer(this, proxy); } // I think this is unnecessary since IrcUsers have us as their daddy :) @@ -62,8 +61,13 @@ bool NetworkInfo::initialized() const { return _initialized; } -Synchronizer *NetworkInfo::synchronizer() { - return _synchronizer; +SignalProxy *NetworkInfo::proxy() const { + return _proxy; +} + +void NetworkInfo::setProxy(SignalProxy *proxy) { + _proxy = proxy; + proxy->synchronize(this); } bool NetworkInfo::isMyNick(const QString &nick) const { @@ -162,7 +166,11 @@ IrcUser *NetworkInfo::newIrcUser(const QString &hostmask) { QString nick(nickFromMask(hostmask)); if(!_ircUsers.contains(nick)) { IrcUser *ircuser = new IrcUser(hostmask, this); - new Synchronizer(ircuser, synchronizer()->proxy()); + // mark IrcUser as already initialized to keep the SignalProxy from requesting initData + if(initialized()) + ircuser->setInitialized(); + _proxy->synchronize(ircuser); + connect(ircuser, SIGNAL(nickSet(QString)), this, SLOT(ircUserNickChanged(QString))); connect(ircuser, SIGNAL(initDone()), this, SIGNAL(ircUserInitDone())); connect(ircuser, SIGNAL(destroyed()), this, SLOT(ircUserDestroyed())); @@ -186,7 +194,11 @@ QList NetworkInfo::ircUsers() const { IrcChannel *NetworkInfo::newIrcChannel(const QString &channelname) { if(!_ircChannels.contains(channelname)) { IrcChannel *channel = new IrcChannel(channelname, this); - new Synchronizer(channel, synchronizer()->proxy()); + // mark IrcUser as already initialized to keep the SignalProxy from requesting initData + if(initialized()) + channel->setInitialized(); + _proxy->synchronize(channel); + connect(channel, SIGNAL(initDone()), this, SIGNAL(ircChannelInitDone())); connect(channel, SIGNAL(destroyed()), this, SLOT(channelDestroyed())); _ircChannels[channelname] = channel; diff --git a/src/common/networkinfo.h b/src/common/networkinfo.h index 6f2ab482..8be0d98d 100644 --- a/src/common/networkinfo.h +++ b/src/common/networkinfo.h @@ -29,7 +29,6 @@ #include class SignalProxy; -class Synchronizer; class IrcUser; class IrcChannel; @@ -42,13 +41,15 @@ class NetworkInfo : public QObject { Q_PROPERTY(QString myNick READ myNick WRITE setMyNick STORED false) public: - NetworkInfo(const uint &networkid, SignalProxy *proxy, QObject *parent = 0); + NetworkInfo(const uint &networkid, QObject *parent = 0); // virtual ~NetworkInfo(); uint networkId() const; bool initialized() const; - Synchronizer *synchronizer(); + SignalProxy *proxy() const; + void setProxy(SignalProxy *proxy); + bool isMyNick(const QString &nick) const; bool isMyNick(IrcUser *ircuser) const; @@ -115,7 +116,7 @@ signals: void currentServerSet(const QString ¤tServer); void myNickSet(const QString &mynick); - void supportAdded(const QString ¶m, const QString &value = QString()); + void supportAdded(const QString ¶m, const QString &value); void supportRemoved(const QString ¶m); void ircUserAdded(QString hostmask); @@ -143,8 +144,7 @@ private: //QVariantMap networkSettings; //QVariantMap identity; - QPointer _synchronizer; - + QPointer _proxy; void determinePrefixes(); }; diff --git a/src/common/signalproxy.cpp b/src/common/signalproxy.cpp index c8f753da..b7ac9681 100644 --- a/src/common/signalproxy.cpp +++ b/src/common/signalproxy.cpp @@ -38,6 +38,9 @@ #include #include #include +#include +#include +#include "util.h" class SignalRelay: public QObject { @@ -51,18 +54,23 @@ public: void attachSignal(int methodId, const QByteArray &func); + void setSynchronize(bool); + bool synchronize() const; + int sigCount() const; private: SignalProxy* proxy; QObject* caller; QMultiHash sigNames; + bool _sync; }; SignalRelay::SignalRelay(SignalProxy* parent, QObject* source) : QObject(parent), proxy(parent), - caller(source) + caller(source), + _sync(false) { QObject::connect(source, SIGNAL(destroyed()), parent, SLOT(detachSender())); } @@ -72,7 +80,7 @@ int SignalRelay::qt_metacall(QMetaObject::Call _c, int _id, void **_a) { if(_id < 0) return _id; if(_c == QMetaObject::InvokeMetaMethod) { - if(sigNames.contains(_id)) { + if(sigNames.contains(_id) || synchronize()) { const QList &argTypes = proxy->argTypes(caller, _id); QVariantList params; int n = argTypes.size(); @@ -80,15 +88,46 @@ int SignalRelay::qt_metacall(QMetaObject::Call _c, int _id, void **_a) { params.append(QVariant(argTypes[i], _a[i+1])); QMultiHash::const_iterator funcIter = sigNames.constFind(_id); while(funcIter != sigNames.constEnd() && funcIter.key() == _id) { - proxy->call(funcIter.value(), params); + proxy->dispatchSignal(funcIter.value(), params); funcIter++; } + if(synchronize() && proxy->syncMap(caller).contains(_id)) { + // qDebug() << "__SYNC__ >>>" + // << caller->metaObject()->className() + // << caller->objectName() + // << proxy->methodName(caller, _id) + // << params; + params.prepend(QVariant(_id)); + params.prepend(caller->objectName()); + params.prepend(caller->metaObject()->className()); + proxy->dispatchSignal((int)SignalProxy::Sync, params); + } } _id -= 1; } return _id; } +void SignalRelay::setSynchronize(bool sync) { + QHash::const_iterator iter = proxy->syncMap(caller).constBegin(); + if(!_sync && sync) { + while(iter != proxy->syncMap(caller).constEnd()) { + QMetaObject::connect(caller, iter.key(), this, QObject::staticMetaObject.methodCount() + iter.key()); + iter++; + } + } else if (_sync && !sync) { + while(iter != proxy->syncMap(caller).constEnd()) { + QMetaObject::disconnect(caller, iter.key(), this, QObject::staticMetaObject.methodCount() + iter.key()); + iter++; + } + } + _sync = sync; +} + +bool SignalRelay::synchronize() const { + return _sync; +} + int SignalRelay::sigCount() const { // only for debuging purpose return sigNames.count(); @@ -117,21 +156,21 @@ void SignalRelay::attachSignal(int methodId, const QByteArray &func) { // SignalProxy // ==================== SignalProxy::SignalProxy(QObject* parent) - : QObject(parent), - _proxyMode(Client) + : QObject(parent) { + setProxyMode(Client); } SignalProxy::SignalProxy(ProxyMode mode, QObject* parent) - : QObject(parent), - _proxyMode(mode) + : QObject(parent) { + setProxyMode(mode); } SignalProxy::SignalProxy(ProxyMode mode, QIODevice* device, QObject* parent) - : QObject(parent), - _proxyMode(mode) + : QObject(parent) { + setProxyMode(mode); addPeer(device); } @@ -149,13 +188,23 @@ void SignalProxy::setProxyMode(ProxyMode mode) { } } _proxyMode = mode; + if(mode == Server) + initServer(); + else + initClient(); } - SignalProxy::ProxyMode SignalProxy::proxyMode() const { return _proxyMode; } +void SignalProxy::initServer() { +} + +void SignalProxy::initClient() { + attachSlot("__objectRenamed__", this, SLOT(objectRenamed(QByteArray, QString, QString))); +} + bool SignalProxy::addPeer(QIODevice* iodev) { if(!iodev) return false; @@ -193,6 +242,25 @@ void SignalProxy::removePeerBySender() { removePeer(ioDev); } +void SignalProxy::objectRenamed(QString oldname, QString newname) { + const QMetaObject *meta = sender()->metaObject(); + const QByteArray className(meta->className()); + objectRenamed(className, oldname, newname); + + if(proxyMode() == Client) + return; + + QVariantList params; + params << className << oldname << newname; + dispatchSignal("__objectRenamed__", params); +} + +void SignalProxy::objectRenamed(QByteArray classname, QString oldname, QString newname) { + if(_syncSlave.contains(classname) && _syncSlave[classname].contains(oldname)) + _syncSlave[classname][newname] = _syncSlave[classname].take(oldname); +} + + void SignalProxy::removePeer(QIODevice* iodev) { if(_peerByteCount.isEmpty()) { qWarning() << "SignalProxy: No peers in use!"; @@ -220,7 +288,7 @@ void SignalProxy::removePeer(QIODevice* iodev) { while(true) { QVariant var; if(readDataFromDevice(iodev, _peerByteCount[iodev], var)) - receivePeerSignal(var); + receivePeerSignal(iodev, var); else break; } @@ -234,49 +302,85 @@ void SignalProxy::removePeer(QIODevice* iodev) { } void SignalProxy::setArgTypes(QObject* obj, int methodId) { - QList p = obj->metaObject()->method(methodId).parameterTypes(); + const QMetaObject *meta = obj->metaObject(); + QList p = meta->method(methodId).parameterTypes(); QList argTypes; int ct = p.count(); for(int i=0; imetaObject()->className()); - Q_ASSERT(_classInfo.contains(className)); - Q_ASSERT(!_classInfo[className]->argTypes.contains(methodId)); - _classInfo[className]->argTypes[methodId] = argTypes; + Q_ASSERT(!_classInfo[meta]->argTypes.contains(methodId)); + _classInfo[meta]->argTypes[methodId] = argTypes; } const QList &SignalProxy::argTypes(QObject *obj, int methodId) { - const QByteArray &className(obj->metaObject()->className()); - Q_ASSERT(_classInfo.contains(className)); - if(!_classInfo[className]->argTypes.contains(methodId)) + Q_ASSERT(_classInfo.contains(obj->metaObject())); + if(!_classInfo[obj->metaObject()]->argTypes.contains(methodId)) setArgTypes(obj, methodId); - return _classInfo[className]->argTypes[methodId]; + return _classInfo[obj->metaObject()]->argTypes[methodId]; } void SignalProxy::setMethodName(QObject *obj, int methodId) { - const QByteArray &className(obj->metaObject()->className()); - QByteArray method = obj->metaObject()->method(methodId).signature(); - method = method.left(method.indexOf('(')); - - Q_ASSERT(_classInfo.contains(className)); - Q_ASSERT(!_classInfo[className]->methodNames.contains(methodId)); - _classInfo[className]->methodNames[methodId] = method; + const QMetaObject *meta = obj->metaObject(); + QByteArray method(::methodName(meta->method(methodId))); + Q_ASSERT(!_classInfo[meta]->methodNames.contains(methodId)); + _classInfo[meta]->methodNames[methodId] = method; } const QByteArray &SignalProxy::methodName(QObject *obj, int methodId) { - QByteArray className(obj->metaObject()->className()); - Q_ASSERT(_classInfo.contains(className)); - if(!_classInfo[className]->methodNames.contains(methodId)) + Q_ASSERT(_classInfo.contains(obj->metaObject())); + if(!_classInfo[obj->metaObject()]->methodNames.contains(methodId)) setMethodName(obj, methodId); - return _classInfo[className]->methodNames[methodId]; + return _classInfo[obj->metaObject()]->methodNames[methodId]; +} + + +void SignalProxy::setSyncMap(QObject *obj) { + const QMetaObject *meta = obj->metaObject(); + + QHash syncMap; + + QList slotIndexes; + for(int i = 0; i < meta->methodCount(); i++) { + if(meta->method(i).methodType() == QMetaMethod::Slot) + slotIndexes << i; + } + + QMetaMethod signal, slot; + int matchIdx; + for(int signalIdx = 0; signalIdx < meta->methodCount(); signalIdx++) { + signal = meta->method(signalIdx); + if(signal.methodType() != QMetaMethod::Signal) + continue; + + matchIdx = -1; + foreach(int slotIdx, slotIndexes) { + slot = meta->method(slotIdx); + if(methodsMatch(signal, slot)) { + matchIdx = slotIdx; + break; + } + } + if(matchIdx != -1) { + slotIndexes.removeAt(slotIndexes.indexOf(matchIdx)); + syncMap[signalIdx] = matchIdx; + } + } + + Q_ASSERT(_classInfo[meta]->syncMap.isEmpty()); + _classInfo[meta]->syncMap = syncMap; } +const QHash &SignalProxy::syncMap(QObject *obj) { + Q_ASSERT(_classInfo.contains(obj->metaObject())); + if(_classInfo[obj->metaObject()]->syncMap.isEmpty()) + setSyncMap(obj); + return _classInfo[obj->metaObject()]->syncMap; +} void SignalProxy::createClassInfo(QObject *obj) { - QByteArray className(obj->metaObject()->className()); - if(!_classInfo.contains(className)) - _classInfo[className] = new ClassInfo(); + if(!_classInfo.contains(obj->metaObject())) + _classInfo[obj->metaObject()] = new ClassInfo(); } bool SignalProxy::attachSignal(QObject* sender, const char* signal, const QByteArray& sigName) { @@ -320,6 +424,62 @@ bool SignalProxy::attachSlot(const QByteArray& sigName, QObject* recv, const cha return true; } +void SignalProxy::synchronize(QObject *obj) { + if(proxyMode() == Server) + return synchronizeAsMaster(obj); + else + return synchronizeAsSlave(obj); +} + +void SignalProxy::synchronizeAsMaster(QObject *sender) { + createClassInfo(sender); + + SignalRelay* relay; + if(_relayHash.contains(sender)) + relay = _relayHash[sender]; + else + relay = _relayHash[sender] = new SignalRelay(this, sender); + + relay->setSynchronize(true); + + if(sender->metaObject()->indexOfSignal(QMetaObject::normalizedSignature("renameObject(QString, QString)")) != -1) + connect(sender, SIGNAL(renameObject(QString, QString)), this, SLOT(objectRenamed(QString, QString))); + + QByteArray className(sender->metaObject()->className()); + _syncSlave[className][sender->objectName()] = sender; + + setInitialized(sender); +} + +void SignalProxy::synchronizeAsSlave(QObject *receiver) { + QByteArray className(receiver->metaObject()->className()); + _syncSlave[className][receiver->objectName()] = receiver; + + createClassInfo(receiver); + + requestInit(receiver); +} + +void SignalProxy::setInitialized(QObject *obj) { + QMetaObject::invokeMethod(obj, "setInitialized"); +} + +bool SignalProxy::initialized(QObject *obj) { + bool init; + if(!QMetaObject::invokeMethod(obj, "initialized", Q_RETURN_ARG(bool, init))) + init = false; + return init; +} + +void SignalProxy::requestInit(QObject *obj) { + if(proxyMode() == Server || initialized(obj)) + return; + + QVariantList params; + params << obj->metaObject()->className() + << obj->objectName(); + dispatchSignal((int)InitRequest, params); +} void SignalProxy::detachSender() { // this is a slot so we can bypass the QueuedConnection @@ -364,49 +524,153 @@ void SignalProxy::_detachSlots(QObject* receiver) { } } -void SignalProxy::call(const char* signal, QVariant p1, QVariant p2, QVariant p3, QVariant p4, QVariant p5, QVariant p6, QVariant p7, QVariant p8, QVariant p9) { - QByteArray func = QMetaObject::normalizedSignature(signal); - QVariantList params; - params << p1 << p2 << p3 << p4 << p5 << p6 << p7 << p8 << p9; - call(func, params); +void SignalProxy::dispatchSignal(QIODevice *receiver, const QVariant &identifier, const QVariantList ¶ms) { + QVariantList packedFunc; + packedFunc << identifier; + packedFunc << params; + writeDataToDevice(receiver, QVariant(packedFunc)); } -void SignalProxy::call(const QByteArray &funcName, const QVariantList ¶ms) { +void SignalProxy::dispatchSignal(const QVariant &identifier, const QVariantList ¶ms) { + // yes I know we have a little code duplication here... it's for the sake of performance QVariantList packedFunc; - packedFunc << funcName; + packedFunc << identifier; packedFunc << params; foreach(QIODevice* dev, _peerByteCount.keys()) writeDataToDevice(dev, QVariant(packedFunc)); } -void SignalProxy::receivePeerSignal(const QVariant &packedFunc) { +void SignalProxy::receivePeerSignal(QIODevice *sender, const QVariant &packedFunc) { QVariantList params(packedFunc.toList()); - QByteArray funcName = params.takeFirst().toByteArray(); - int numParams, methodId; - QObject* receiver; + QVariant call = params.takeFirst(); + if(call.type() != QVariant::Int) + return handleSignal(call.toByteArray(), params); + + switch(call.toInt()) { + case Sync: + return handleSync(params); + case InitRequest: + return handleInitRequest(sender, params); + case InitData: + return handleInitData(sender, params); + default: + qWarning() << "received undefined CallType" << call.toInt(); + return; + } +} + +void SignalProxy::handleSync(QVariantList params) { + if(params.count() < 3) { + qWarning() << "received invalid Sync call" << params; + return; + } + + QByteArray className =params.takeFirst().toByteArray(); + QString objectName = params.takeFirst().toString(); + int signalId = params.takeFirst().toInt(); + + if(!_syncSlave.contains(className) || !_syncSlave[className].contains(objectName)) { + qWarning() << "no registered receiver:" << className << objectName << "for Sync call" << signalId << params; + return; + } + + QObject *receiver = _syncSlave[className][objectName]; + if(!syncMap(receiver).contains(signalId)) { + qWarning() << "received Sync Call with invalid SignalId" << className << objectName << signalId; + } + int slotId = syncMap(receiver)[signalId]; + if(!invokeSlot(receiver, slotId, params)) + qWarning("SignalProxy::handleSync(): invokeMethod for \"%s\" failed ", methodName(receiver, slotId).constData()); +} + +void SignalProxy::handleInitRequest(QIODevice *sender, const QVariantList ¶ms) { + if(params.count() != 2) { + qWarning() << "SignalProxy::handleInitRequest() received initRequest with invalid param Count:" + << params; + return; + } + + QByteArray className(params[0].toByteArray()); + QString objectName(params[1].toString()); + + if(!_syncSlave.contains(className)) { + qWarning() << "SignalProxy::handleInitRequest() received initRequest for unregistered Class:" + << className; + return; + } + + if(!_syncSlave[className].contains(objectName)) { + qWarning() << "SignalProxy::handleInitRequest() received initRequest for unregistered Object:" + << className << objectName; + return; + } + + QObject *obj = _syncSlave[className][objectName]; + + QVariantList params_; + params_ << obj->metaObject()->className() + << obj->objectName() + << initData(obj); + + dispatchSignal(sender, (int)InitData, params_); +} + +void SignalProxy::handleInitData(QIODevice *sender, const QVariantList ¶ms) { + Q_UNUSED(sender) + if(params.count() != 3) { + qWarning() << "SignalProxy::handleInitRequest() received initRequest with invalid param Count:" + << params; + return; + } + + QByteArray className(params[0].toByteArray()); + QString objectName(params[1].toString()); + QVariantMap propertyMap(params[2].toMap()); + + if(!_syncSlave.contains(className)) { + qWarning() << "SignalProxy::handleInitRequest() received initRequest for unregistered Class:" + << className; + return; + } + + if(!_syncSlave[className].contains(objectName)) { + qWarning() << "SignalProxy::handleInitRequest() received initRequest for unregistered Object:" + << className << objectName; + return; + } + + QObject *obj = _syncSlave[className][objectName]; + setInitData(obj, propertyMap); +} + +void SignalProxy::handleSignal(const QByteArray &funcName, const QVariantList ¶ms) { + QObject* receiver; + int methodId; SlotHash::const_iterator slot = _attachedSlots.constFind(funcName); while(slot != _attachedSlots.constEnd() && slot.key() == funcName) { receiver = (*slot).first; methodId = (*slot).second; - numParams = argTypes(receiver, methodId).count(); - QGenericArgument args[9]; - for(int i = 0; i < numParams; i++) - args[i] = QGenericArgument(params[i].typeName(), params[i].constData()); - if(!QMetaObject::invokeMethod(receiver, methodName(receiver, methodId), - args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8])) { - qWarning("SignalProxy::receivePeerSignal(): invokeMethod for \"%s\" failed ", methodName(receiver, methodId).constData()); - } + if(!invokeSlot(receiver, methodId, params)) + qWarning("SignalProxy::handleSignal(): invokeMethod for \"%s\" failed ", methodName(receiver, methodId).constData()); slot++; } } +bool SignalProxy::invokeSlot(QObject *receiver, int methodId, const QVariantList ¶ms) { + int numParams = argTypes(receiver, methodId).count(); + QGenericArgument args[9]; + for(int i = 0; i < numParams; i++) + args[i] = QGenericArgument(params[i].typeName(), params[i].constData()); + return QMetaObject::invokeMethod(receiver, methodName(receiver, methodId), args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8]); +} + void SignalProxy::dataAvailable() { // yet again. it's a private slot. no need for checks. QIODevice* ioDev = qobject_cast(sender()); QVariant var; while(readDataFromDevice(ioDev, _peerByteCount[ioDev], var)) - receivePeerSignal(var); + receivePeerSignal(ioDev, var); } void SignalProxy::writeDataToDevice(QIODevice *dev, const QVariant &item) { @@ -440,6 +704,99 @@ bool SignalProxy::readDataFromDevice(QIODevice *dev, quint32 &blockSize, QVarian return true; } +bool SignalProxy::methodsMatch(const QMetaMethod &signal, const QMetaMethod &slot) const { + // if we don't even have the same basename it's a sure NO + if(methodBaseName(signal) != methodBaseName(slot)) + return false; + + // are the signatures compatible? + if(!QObject::staticMetaObject.checkConnectArgs(signal.signature(), slot.signature())) + return false; + + // we take an educated guess if the signals and slots match + QString signalsuffix = ::methodName(signal).mid(QString(::methodName(signal)).lastIndexOf(QRegExp("[A-Z]"))).toLower(); + QString slotprefix = ::methodName(slot).left(QString(::methodName(slot)).indexOf(QRegExp("[A-Z]"))).toLower(); + + uint sizediff = qAbs(slotprefix.size() - signalsuffix.size()); + int ratio = editingDistance(slotprefix, signalsuffix) - sizediff; + return (ratio < 2); +} + +QString SignalProxy::methodBaseName(const QMetaMethod &method) { + QString methodname = QString(method.signature()).section("(", 0, 0); + + // determine where we have to chop: + if(method.methodType() == QMetaMethod::Slot) { + // we take evertyhing from the first uppercase char if it's slot + methodname = methodname.mid(methodname.indexOf(QRegExp("[A-Z]"))); + } else { + // and if it's a signal we discard everything from the last uppercase char + methodname = methodname.left(methodname.lastIndexOf(QRegExp("[A-Z]"))); + } + + methodname[0] = methodname[0].toUpper(); + + return methodname; +} + +QVariantMap SignalProxy::initData(QObject *obj) const { + QVariantMap properties; + + const QMetaObject* meta = obj->metaObject(); + + // we collect data from properties + for(int i = 0; i < meta->propertyCount(); i++) { + QMetaProperty prop = meta->property(i); + properties[QString(prop.name())] = prop.read(obj); + } + + // ...as well as methods, which have names starting with "init" + for(int i = 0; i < meta->methodCount(); i++) { + QMetaMethod method = meta->method(i); + QString methodname(::methodName(method)); + if(!methodname.startsWith("init") || methodname.startsWith("initSet")) + continue; + + QVariant value = QVariant(QVariant::nameToType(method.typeName())); + QGenericReturnArgument genericvalue = QGenericReturnArgument(method.typeName(), &value); + QMetaObject::invokeMethod(obj, methodname.toAscii(), genericvalue); + + properties[methodBaseName(method)] = value; + // qDebug() << ">>> SYNC:" << methodBaseName(method) << value; + } + + // properties["Payload"] = QByteArray(10000000, 'a'); // for testing purposes + return properties; +} + +void SignalProxy::setInitData(QObject *obj, const QVariantMap &properties) { + if(initialized(obj)) + return; + + const QMetaObject *meta = obj->metaObject(); + + QVariantMap::const_iterator iterator = properties.constBegin(); + while(iterator != properties.constEnd()) { + QString name = iterator.key(); + int propertyIndex = meta->indexOfProperty(name.toAscii()); + + if(propertyIndex == -1 || !meta->property(propertyIndex).isWritable()) + setInitValue(obj, name, iterator.value()); + else + obj->setProperty(name.toAscii(), iterator.value()); + // qDebug() << "<<< SYNC:" << name << iterator.value(); + iterator++; + } + setInitialized(obj); +} + +bool SignalProxy::setInitValue(QObject *obj, const QString &property, const QVariant &value) { + QString handlername = QString("initSet") + property; + handlername[7] = handlername[7].toUpper(); + QGenericArgument param(value.typeName(), value.constData()); + return QMetaObject::invokeMethod(obj, handlername.toAscii(), param); +} + void SignalProxy::dumpProxyStats() { QString mode; if(proxyMode() == Server) @@ -451,10 +808,17 @@ void SignalProxy::dumpProxyStats() { foreach(SignalRelay *relay, _relayHash.values()) sigCount += relay->sigCount(); + int slaveCount = 0; + foreach(ObjectId oid, _syncSlave.values()) + slaveCount += oid.count(); + qDebug() << this; qDebug() << " Proxy Mode:" << mode; qDebug() << "attached sending Objects:" << _relayHash.count(); - qDebug() << " Number of Signals:" << sigCount; + qDebug() << " number of Signals:" << sigCount; qDebug() << " attached Slots:" << _attachedSlots.count(); + qDebug() << " number of synced Slaves:" << slaveCount; qDebug() << "number of Classes cached:" << _classInfo.count(); } + + diff --git a/src/common/signalproxy.h b/src/common/signalproxy.h index ebc4ae76..50010607 100644 --- a/src/common/signalproxy.h +++ b/src/common/signalproxy.h @@ -34,11 +34,13 @@ #include #include #include +#include #include #include #include class SignalRelay; +class QMetaObject; class SignalProxy : public QObject { Q_OBJECT @@ -49,9 +51,15 @@ public: Client }; - SignalProxy(QObject* parent); - SignalProxy(ProxyMode mode, QObject* parent); - SignalProxy(ProxyMode mode, QIODevice* device, QObject* parent); + enum RequestType { + Sync = 0, + InitRequest, + InitData + }; + + SignalProxy(QObject *parent); + SignalProxy(ProxyMode mode, QObject *parent); + SignalProxy(ProxyMode mode, QIODevice *device, QObject *parent); virtual ~SignalProxy(); void setProxyMode(ProxyMode mode); @@ -60,29 +68,36 @@ public: bool addPeer(QIODevice *iodev); void removePeer(QIODevice *iodev = 0); - bool attachSignal(QObject* sender, const char* signal, const QByteArray& sigName = QByteArray()); - bool attachSlot(const QByteArray& sigName, QObject* recv, const char* slot); + bool attachSignal(QObject *sender, const char *signal, const QByteArray& sigName = QByteArray()); + bool attachSlot(const QByteArray& sigName, QObject *recv, const char *slot); + + void synchronize(QObject *obj); + void synchronizeAsMaster(QObject *obj); + void synchronizeAsSlave(QObject *obj); + void setInitialized(QObject *obj); + bool initialized(QObject *obj); + void requestInit(QObject *obj); + void detachObject(QObject *obj); void detachSignals(QObject *sender); void detachSlots(QObject *receiver); - void call(const char *signal , QVariant p1, QVariant p2, QVariant p3, QVariant p4, - QVariant p5, QVariant p6, QVariant p7, QVariant p8, QVariant p9); - void call(const QByteArray &funcName, const QVariantList ¶ms); - static void writeDataToDevice(QIODevice *dev, const QVariant &item); static bool readDataFromDevice(QIODevice *dev, quint32 &blockSize, QVariant &item); + + static QString methodBaseName(const QMetaMethod &method); - const QList &argTypes(QObject* obj, int methodId); - const QByteArray &methodName(QObject* obj, int methodId); - + const QList &argTypes(QObject *obj, int methodId); + const QByteArray &methodName(QObject *obj, int methodId); + const QHash &syncMap(QObject *obj); + typedef QHash > ArgHash; typedef QHash MethodNameHash; struct ClassInfo { ArgHash argTypes; MethodNameHash methodNames; - // QHash syncMap + QHash syncMap; }; void dumpProxyStats(); @@ -91,24 +106,45 @@ private slots: void dataAvailable(); void detachSender(); void removePeerBySender(); + void objectRenamed(QString oldname, QString newname); + void objectRenamed(QByteArray classname, QString oldname, QString newname); signals: - void peerRemoved(QIODevice* obj); + void peerRemoved(QIODevice *obj); void connected(); void disconnected(); private: + void initServer(); + void initClient(); + void createClassInfo(QObject *obj); - void setArgTypes(QObject* obj, int methodId); - void setMethodName(QObject* obj, int methodId); + void setArgTypes(QObject *obj, int methodId); + void setMethodName(QObject *obj, int methodId); + void setSyncMap(QObject *obj); - void receivePeerSignal(const QVariant &packedFunc); + bool methodsMatch(const QMetaMethod &signal, const QMetaMethod &slot) const; + + void dispatchSignal(QIODevice *receiver, const QVariant &identifier, const QVariantList ¶ms); + void dispatchSignal(const QVariant &identifier, const QVariantList ¶ms); + + void receivePeerSignal(QIODevice *sender, const QVariant &packedFunc); + void handleSync(QVariantList params); + void handleInitRequest(QIODevice *sender, const QVariantList ¶ms); + void handleInitData(QIODevice *sender, const QVariantList ¶ms); + void handleSignal(const QByteArray &funcName, const QVariantList ¶ms); + + bool invokeSlot(QObject *receiver, int methodId, const QVariantList ¶ms); + + QVariantMap initData(QObject *obj) const; + void setInitData(QObject *obj, const QVariantMap &properties); + bool setInitValue(QObject *obj, const QString &property, const QVariant &value); void _detachSignals(QObject *sender); void _detachSlots(QObject *receiver); // containg a list of argtypes for fast access - QHash _classInfo; + QHash _classInfo; // we use one SignalRelay per QObject QHash _relayHash; @@ -117,15 +153,17 @@ private: typedef QPair MethodId; typedef QMultiHash SlotHash; SlotHash _attachedSlots; - + + // slaves for sync + typedef QHash ObjectId; + QHash _syncSlave; // Hash of used QIODevices QHash _peerByteCount; ProxyMode _proxyMode; -}; - - + friend class SignalRelay; +}; #endif diff --git a/src/common/synchronizer.cpp b/src/common/synchronizer.cpp deleted file mode 100644 index e2bed334..00000000 --- a/src/common/synchronizer.cpp +++ /dev/null @@ -1,345 +0,0 @@ -/*************************************************************************** - * Copyright (C) 2005-07 by The Quassel Team * - * devel@quassel-irc.org * - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation; either version 2 of the License, or * - * (at your option) any later version. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program; if not, write to the * - * Free Software Foundation, Inc., * - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * - ***************************************************************************/ -#include "synchronizer.h" - -#include -#include -#include -#include - -#include "util.h" -#include "signalproxy.h" - -#include -#include - -// ==================== -// Public: -// ==================== -Synchronizer::Synchronizer(QObject *parent, SignalProxy *signalproxy) - : QObject(parent), - _initialized(false), - _signalproxy(signalproxy) -{ - attach(); - if(!getMethodByName("objectNameSet()").isEmpty()) - connect(parent,SIGNAL(objectNameSet()), this, SLOT(parentChangedName())); -} - -bool Synchronizer::initialized() const { - return _initialized; -} - -SignalProxy *Synchronizer::proxy() const { - return _signalproxy; -} - -QVariantMap Synchronizer::initData() const { - QVariantMap properties; - - // we collect data from properties - foreach(QMetaProperty property, parentProperties()) { - QString name = QString(property.name()); - QVariant value = property.read(parent()); - properties[name] = value; - // qDebug() << ">>> SYNC:" << name << value; - } - - // ...as well as methods, which have names starting with "init" - foreach(QMetaMethod method, parentSlots()) { - QString methodname = QString(method.signature()).section("(", 0, 0); - if(methodname.startsWith("initSet") || - !methodname.startsWith("init")) - continue; - - QVariant value = QVariant(QVariant::nameToType(method.typeName())); - QGenericReturnArgument genericvalue = QGenericReturnArgument(method.typeName(), &value); - QMetaObject::invokeMethod(parent(), methodname.toAscii(), genericvalue); - - properties[methodBaseName(method)] = value; - // qDebug() << ">>> SYNC:" << methodBaseName(method) << value; - } - - // properties["Payload"] = QByteArray(10000000, 'a'); // for testing purposes - return properties; -} - -void Synchronizer::setInitData(const QVariantMap &properties) { - if(initialized()) - return; - - const QMetaObject *metaobject = parent()->metaObject(); - QMapIterator iterator(properties); - while(iterator.hasNext()) { - iterator.next(); - QString name = iterator.key(); - int propertyIndex = metaobject->indexOfProperty(name.toAscii()); - if(propertyIndex == -1) { - setInitValue(name, iterator.value()); - } else { - if((metaobject->property(propertyIndex)).isWritable()) - parent()->setProperty(name.toAscii(), iterator.value()); - else - setInitValue(name, iterator.value()); - } - // qDebug() << "<<< SYNC:" << name << iterator.value(); - } - - _initialized = true; - emit initDone(); -} - -// ==================== -// Public Slots -// ==================== -void Synchronizer::synchronizeClients() const { - emit sendInitData(initData()); -} - -void Synchronizer::recvInitData(QVariantMap properties) { - proxy()->detachObject(this); - setInitData(properties); -} - -void Synchronizer::parentChangedName() { - proxy()->detachObject(parent()); - proxy()->detachObject(this); - attach(); -} - -// ==================== -// Private -// ==================== -QString Synchronizer::signalPrefix() const { - return QString(parent()->metaObject()->className()) + "_" + QString(parent()->objectName()) + "_"; -} - -QString Synchronizer::initSignal() const { - return QString(metaObject()->className()) - + "_" + QString(parent()->metaObject()->className()) - + "_" + QString(parent()->objectName()) - + "_" + QString(SIGNAL(sendInitData(QVariantMap))); -} - -QString Synchronizer::requestSyncSignal() const { - return QString(metaObject()->className()) - + "_" + QString(parent()->metaObject()->className()) - + "_" + QString(parent()->objectName()) - + "_" + QString(SIGNAL(requestSync())); -} - -QString Synchronizer::methodBaseName(const QMetaMethod &method) const { - QString methodname = QString(method.signature()).section("(", 0, 0); - - // determine where we have to chop: - if(method.methodType() == QMetaMethod::Slot) { - // we take evertyhing from the first uppercase char if it's slot - methodname = methodname.mid(methodname.indexOf(QRegExp("[A-Z]"))); - } else { - // and if it's a signal we discard everything from the last uppercase char - methodname = methodname.left(methodname.lastIndexOf(QRegExp("[A-Z]"))); - } - - methodname[0] = methodname[0].toUpper(); - - return methodname; -} - -bool Synchronizer::methodsMatch(const QMetaMethod &signal, const QMetaMethod &slot) const { - // if we don't even have the same basename it's a sure NO - if(methodBaseName(signal) != methodBaseName(slot)) - return false; - - const QMetaObject *metaobject = parent()->metaObject(); - - // are the signatures compatible? - if(! metaobject->checkConnectArgs(signal.signature(), slot.signature())) - return false; - - // we take an educated guess if the signals and slots match - QString signalsuffix = QString(signal.signature()).section("(", 0, 0); - signalsuffix = signalsuffix.mid(signalsuffix.lastIndexOf(QRegExp("[A-Z]"))).toLower(); - - QString slotprefix = QString(slot.signature()).section("(", 0, 0); - slotprefix = slotprefix.left(slotprefix.indexOf(QRegExp("[A-Z]"))).toLower(); - - uint sizediff; - if(signalsuffix.size() < slotprefix.size()) - sizediff = slotprefix.size() - signalsuffix.size(); - else - sizediff = signalsuffix.size() - slotprefix.size(); - - int ratio = editingDistance(slotprefix, signalsuffix) - sizediff; - - return (ratio < 2); -} - -QList Synchronizer::parentProperties() const { - QList _properties; - - const QMetaObject *metaobject = parent()->metaObject(); - for(int i = metaobject->propertyOffset(); i < metaobject->propertyCount(); i++) { - _properties << metaobject->property(i); - } - - return _properties; -} - -QList Synchronizer::parentSlots() const { - QList _slots; - - const QMetaObject *metaobject = parent()->metaObject(); - for(int i = metaobject->methodOffset(); i < metaobject->methodCount(); i++) { - QMetaMethod method = metaobject->method(i); - if(method.methodType() == QMetaMethod::Slot) - _slots << method; - } - - return _slots; -} - - -QList Synchronizer::parentSignals() const { - QList _signals; - - const QMetaObject *metaobject = parent()->metaObject(); - for(int i = metaobject->methodOffset(); i < metaobject->methodCount(); i++) { - QMetaMethod method = metaobject->method(i); - if(method.methodType() == QMetaMethod::Signal) - _signals << method; - } - - return _signals; -} - -QList Synchronizer::getMethodByName(const QString &methodname) { - QList _methods; - - const QMetaObject* metaobject = parent()->metaObject(); - for(int i = metaobject->methodOffset(); i < metaobject->methodCount(); i++) { - if(QString(metaobject->method(i).signature()).startsWith(methodname)) - _methods << metaobject->method(i); - } - - return _methods; -} - -void Synchronizer::attach() { - if(proxy()->proxyMode() == SignalProxy::Server) - attachAsMaster(); - else - attachAsSlave(); -} - -void Synchronizer::attachAsSlave() { - QList signals_ = parentSignals(); - - foreach(QMetaMethod slot, parentSlots()) { - if(signals_.empty()) - break; - - for(int i = 0; i < signals_.count(); i++) { - QMetaMethod signal = signals_[i]; - if(!methodsMatch(signal, slot)) - continue; - - // we could simply put a "1" in front of the normalized signature - // but to guarantee future compatibility we construct a dummy signal - // and replace the known the fake signature by ours... - QString dummySlot = QString(SIGNAL(dummy())); - QString proxySignal = signalPrefix() + QString(signal.signature()); - QString slotsignature = dummySlot.replace("dummy()", QString(slot.signature())); - - // qDebug() << "attachSlot:" << proxySignal << slotsignature; - proxy()->attachSlot(proxySignal.toAscii(), parent(), slotsignature.toAscii()); - signals_.removeAt(i); - break; - } - } - - if(!getMethodByName("setInitialized()").isEmpty()) - connect(this, SIGNAL(initDone()), parent(), SLOT(setInitialized())); - - if(!initialized()) { - // and then we connect ourself, so we can receive init data - // qDebug() << "attachSlot:" << initSignal() << "recvInitData(QVariantMap)"; - // qDebug() << "attachSignal:" << "requestSync()" << requestSyncSignal(); - proxy()->attachSlot(initSignal().toAscii(), this, SLOT(recvInitData(QVariantMap))); - proxy()->attachSignal(this, SIGNAL(requestSync()), requestSyncSignal().toAscii()); - - emit requestSync(); - } -} - -void Synchronizer::attachAsMaster() { - QList slots_ = parentSlots(); - - foreach(QMetaMethod signal, parentSignals()) { - if(slots_.isEmpty()) - break; - - // we don't attach all signals, just the ones that have a maching counterpart - for(int i = 0; i < slots_.count(); i++) { - QMetaMethod slot = slots_[i]; - if(!methodsMatch(signal, slot)) - continue; - - // we could simply put a "2" in front of the normalized signature - // but to guarantee future compatibility we construct a dummy signal - // and replace the known the fake signature by ours... - QString dummySignal = QString(SIGNAL(dummy())); - QString proxySignal = signalPrefix() + QString(signal.signature()); - QString signalsignature = dummySignal.replace("dummy()", QString(signal.signature())); - - // qDebug() << "attachSignal:" << signalsignature << proxySignal; - proxy()->attachSignal(parent(), signalsignature.toAscii(), proxySignal.toAscii()); - slots_.removeAt(i); - break; - } - } - - // and then we connect ourself, so we can initialize slaves - // qDebug() << "attachSignal:" << "sendInitData(QVariantMap)" << initSignal(); - // qDebug() << "attachSlot:" << "synchronizeClients()" << requestSyncSignal(); - proxy()->attachSignal(this, SIGNAL(sendInitData(QVariantMap)), initSignal().toAscii()); - proxy()->attachSlot(requestSyncSignal().toAscii(), this, SLOT(synchronizeClients())); -} - -bool Synchronizer::setInitValue(const QString &property, const QVariant &value) { - QString handlername = QString("initSet") + property; - handlername[7] = handlername[7].toUpper(); - - //determine param type - QByteArray paramtype; - foreach(QMetaMethod method, getMethodByName(handlername)) { - if(method.parameterTypes().size() == 1) { - paramtype = method.parameterTypes()[0]; - break; - } - } - - if(paramtype.isNull()) - return false; - - QGenericArgument param = QGenericArgument(paramtype, &value); - return QMetaObject::invokeMethod(parent(), handlername.toAscii(), param); -} - - diff --git a/src/common/synchronizer.h b/src/common/synchronizer.h deleted file mode 100644 index fe407f8b..00000000 --- a/src/common/synchronizer.h +++ /dev/null @@ -1,79 +0,0 @@ -/*************************************************************************** - * Copyright (C) 2005/06 by The Quassel Team * - * devel@quassel-irc.org * - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation; either version 2 of the License, or * - * (at your option) any later version. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program; if not, write to the * - * Free Software Foundation, Inc., * - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * - ***************************************************************************/ - -#ifndef _SYNCHRONIZER_H_ -#define _SYNCHRONIZER_H_ - -class SignalProxy; - -#include -#include -#include -#include -#include -#include - -class Synchronizer : public QObject { - Q_OBJECT - -public: - Synchronizer(QObject *parent, SignalProxy *signalproxy); - - bool initialized() const; - SignalProxy *proxy() const; - - QVariantMap initData() const; - void setInitData(const QVariantMap &properties); - -public slots: - void synchronizeClients() const; - void recvInitData(QVariantMap properties); - void parentChangedName(); - -signals: - void requestSync() const; - void sendInitData(QVariantMap properties) const; - void initDone(); - -private: - bool _initialized; - QPointer _signalproxy; - - QString signalPrefix() const; - QString initSignal() const; - QString requestSyncSignal() const; - - QString methodBaseName(const QMetaMethod &method) const; - bool methodsMatch(const QMetaMethod &signal, const QMetaMethod &slot) const; - - QList parentProperties() const; - QList parentSlots() const; - QList parentSignals() const; - - QList getMethodByName(const QString &methodname); - - void attach(); - void attachAsSlave(); - void attachAsMaster(); - - bool setInitValue(const QString &property, const QVariant &value); -}; - -#endif diff --git a/src/common/util.cpp b/src/common/util.cpp index 2fdeead1..5cbfc861 100644 --- a/src/common/util.cpp +++ b/src/common/util.cpp @@ -22,6 +22,8 @@ #include #include +class QMetaMethod; + QString nickFromMask(QString mask) { return mask.section('!', 0, 0); } @@ -133,3 +135,8 @@ uint editingDistance(const QString &s1, const QString &s2) { } return matrix[n-1][m-1]; } + +QByteArray methodName(const QMetaMethod &method) { + QByteArray sig(method.signature()); + return sig.left(sig.indexOf("(")); +} diff --git a/src/common/util.h b/src/common/util.h index 01797233..695955bb 100644 --- a/src/common/util.h +++ b/src/common/util.h @@ -24,6 +24,7 @@ #include #include #include +#include QString nickFromMask(QString mask); QString userFromMask(QString mask); @@ -56,5 +57,6 @@ bool readDataFromDevice(QIODevice *, quint32 &, QVariant &); uint editingDistance(const QString &s1, const QString &s2); +QByteArray methodName(const QMetaMethod &method); #endif diff --git a/src/core/coresession.cpp b/src/core/coresession.cpp index 0accebbf..bf542c2a 100644 --- a/src/core/coresession.cpp +++ b/src/core/coresession.cpp @@ -24,7 +24,6 @@ #include "signalproxy.h" #include "storage.h" -#include "synchronizer.h" #include "networkinfo.h" #include "ircuser.h" #include "ircchannel.h" diff --git a/src/core/server.cpp b/src/core/server.cpp index 67cc6325..8e096f8e 100644 --- a/src/core/server.cpp +++ b/src/core/server.cpp @@ -28,7 +28,6 @@ #include "coresession.h" #include "networkinfo.h" -#include "synchronizer.h" #include "ircserverhandler.h" #include "userinputhandler.h" @@ -40,9 +39,10 @@ Server::Server(UserId uid, uint networkId, QString net) _ircServerHandler(new IrcServerHandler(this)), _userInputHandler(new UserInputHandler(this)), _ctcpHandler(new CtcpHandler(this)), - _networkInfo(new NetworkInfo(networkId, coreSession()->signalProxy(), this)) + _networkInfo(new NetworkInfo(networkId, this)) { networkInfo()->setNetworkName(net); + networkInfo()->setProxy(coreSession()->signalProxy()); } Server::~Server() {