From 2a00e8f57d66d9913a10c30408b89676a74010a1 Mon Sep 17 00:00:00 2001 From: Marcus Eggenberger Date: Fri, 14 Aug 2009 19:09:08 +0200 Subject: [PATCH] Testing the new SyncObjects concept - looking good so far --- src/client/clientbacklogmanager.cpp | 1 + src/client/clientbacklogmanager.h | 1 + src/common/backlogmanager.cpp | 5 +- src/common/backlogmanager.h | 1 + src/common/ircuser.cpp | 34 +++--- src/common/ircuser.h | 37 +++---- src/common/signalproxy.cpp | 164 ++++++++++------------------ src/common/signalproxy.h | 21 ++-- src/common/syncableobject.h | 22 +++- 9 files changed, 125 insertions(+), 161 deletions(-) diff --git a/src/client/clientbacklogmanager.cpp b/src/client/clientbacklogmanager.cpp index 0a02e4ee..f579e60c 100644 --- a/src/client/clientbacklogmanager.cpp +++ b/src/client/clientbacklogmanager.cpp @@ -29,6 +29,7 @@ #include +INIT_SYNCABLE_OBJECT(ClientBacklogManager) ClientBacklogManager::ClientBacklogManager(QObject *parent) : BacklogManager(parent), _requester(0) diff --git a/src/client/clientbacklogmanager.h b/src/client/clientbacklogmanager.h index 2aa399b5..f52eb164 100644 --- a/src/client/clientbacklogmanager.h +++ b/src/client/clientbacklogmanager.h @@ -27,6 +27,7 @@ class BacklogRequester; class ClientBacklogManager : public BacklogManager { + SYNCABLE_OBJECT Q_OBJECT public: diff --git a/src/common/backlogmanager.cpp b/src/common/backlogmanager.cpp index 8f2c47a4..449b9cd5 100644 --- a/src/common/backlogmanager.cpp +++ b/src/common/backlogmanager.cpp @@ -20,12 +20,13 @@ #include "backlogmanager.h" +INIT_SYNCABLE_OBJECT(BacklogManager) QVariantList BacklogManager::requestBacklog(BufferId bufferId, MsgId first, MsgId last, int limit, int additional) { - emit backlogRequested(bufferId, first, last, limit, additional); + REQUEST(ARG(bufferId), ARG(first), ARG(last), ARG(limit), ARG(additional)) return QVariantList(); } QVariantList BacklogManager::requestBacklogAll(MsgId first, MsgId last, int limit, int additional) { - emit backlogAllRequested(first, last, limit, additional); + REQUEST(ARG(first), ARG(last), ARG(limit), ARG(additional)) return QVariantList(); } diff --git a/src/common/backlogmanager.h b/src/common/backlogmanager.h index 189d503c..95c87a04 100644 --- a/src/common/backlogmanager.h +++ b/src/common/backlogmanager.h @@ -25,6 +25,7 @@ #include "types.h" class BacklogManager : public SyncableObject { + SYNCABLE_OBJECT Q_OBJECT public: diff --git a/src/common/ircuser.cpp b/src/common/ircuser.cpp index fa206989..e42bea7d 100644 --- a/src/common/ircuser.cpp +++ b/src/common/ircuser.cpp @@ -28,6 +28,7 @@ #include #include +INIT_SYNCABLE_OBJECT(IrcUser) IrcUser::IrcUser(const QString &hostmask, Network *network) : SyncableObject(network), _initialized(false), _nick(nickFromMask(hostmask)), @@ -109,28 +110,28 @@ QByteArray IrcUser::encodeString(const QString &string) const { void IrcUser::setUser(const QString &user) { if(!user.isEmpty() && _user != user) { _user = user; - emit userSet(user); + SYNC(ARG(user)); } } void IrcUser::setRealName(const QString &realName) { if (!realName.isEmpty() && _realName != realName) { _realName = realName; - emit realNameSet(realName); + SYNC(ARG(realName)) } } void IrcUser::setAway(const bool &away) { if(away != _away) { _away = away; - emit awaySet(away); + SYNC(ARG(away)) } } void IrcUser::setAwayMessage(const QString &awayMessage) { if(!awayMessage.isEmpty() && _awayMessage != awayMessage) { _awayMessage = awayMessage; - emit awayMessageSet(awayMessage); + SYNC(ARG(awayMessage)) } } @@ -138,43 +139,42 @@ void IrcUser::setIdleTime(const QDateTime &idleTime) { if(idleTime.isValid() && _idleTime != idleTime) { _idleTime = idleTime; _idleTimeSet = QDateTime::currentDateTime(); - emit idleTimeSet(idleTime); + SYNC(ARG(idleTime)) } } void IrcUser::setLoginTime(const QDateTime &loginTime) { if(loginTime.isValid() && _loginTime != loginTime) { _loginTime = loginTime; - emit loginTimeSet(loginTime); + SYNC(ARG(loginTime)) } } void IrcUser::setServer(const QString &server) { if(!server.isEmpty() && _server != server) { _server = server; - emit serverSet(server); + SYNC(ARG(server)) } } void IrcUser::setIrcOperator(const QString &ircOperator) { if(!ircOperator.isEmpty() && _ircOperator != ircOperator) { _ircOperator = ircOperator; - emit ircOperatorSet(ircOperator); + SYNC(ARG(ircOperator)) } } void IrcUser::setLastAwayMessage(const int &lastAwayMessage) { if(lastAwayMessage > _lastAwayMessage) { _lastAwayMessage = lastAwayMessage; - emit lastAwayMessageSet(lastAwayMessage); + SYNC(ARG(lastAwayMessage)) } } void IrcUser::setHost(const QString &host) { - so_sync(so_arg_cast(host)); if(!host.isEmpty() && _host != host) { _host = host; - emit hostSet(host); + SYNC(ARG(host)) } } @@ -182,21 +182,21 @@ void IrcUser::setNick(const QString &nick) { if(!nick.isEmpty() && nick != _nick) { _nick = nick; updateObjectName(); - emit nickSet(nick); + SYNC(ARG(nick)) } } void IrcUser::setWhoisServiceReply(const QString &whoisServiceReply) { if(!whoisServiceReply.isEmpty() && whoisServiceReply != _whoisServiceReply) { _whoisServiceReply = whoisServiceReply; - emit whoisServiceReplySet(whoisServiceReply); + SYNC(ARG(whoisServiceReply)) } } void IrcUser::setSuserHost(const QString &suserHost) { if(!suserHost.isEmpty() && suserHost != _suserHost) { _suserHost = suserHost; - emit suserHostSet(suserHost); + SYNC(ARG(suserHost)) } } @@ -269,7 +269,7 @@ void IrcUser::channelDestroyed() { void IrcUser::setUserModes(const QString &modes) { _userModes = modes; - emit userModesSet(modes); + SYNC(ARG(modes)) } void IrcUser::addUserModes(const QString &modes) { @@ -281,7 +281,7 @@ void IrcUser::addUserModes(const QString &modes) { _userModes += modes[i]; } - emit userModesAdded(modes); + SYNC(ARG(modes)) } void IrcUser::removeUserModes(const QString &modes) { @@ -291,7 +291,7 @@ void IrcUser::removeUserModes(const QString &modes) { for(int i = 0; i < modes.count(); i++) { _userModes.remove(modes[i]); } - emit userModesRemoved(modes); + SYNC(ARG(modes)) } void IrcUser::setLastChannelActivity(BufferId buffer, const QDateTime &time) { diff --git a/src/common/ircuser.h b/src/common/ircuser.h index f624fb41..8499dd1c 100644 --- a/src/common/ircuser.h +++ b/src/common/ircuser.h @@ -35,6 +35,7 @@ class Network; class IrcChannel; class IrcUser : public SyncableObject { + SYNCABLE_OBJECT Q_OBJECT Q_PROPERTY(QString user READ user WRITE setUser STORED false) @@ -123,30 +124,28 @@ public slots: void removeUserModes(const QString &modes); signals: - void userSet(QString user); - void hostSet(QString host); - void nickSet(QString newnick); - void realNameSet(QString realName); - void awaySet(bool away); - void awayMessageSet(QString awayMessage); - void idleTimeSet(QDateTime idleTime); - void loginTimeSet(QDateTime loginTime); - void serverSet(QString server); - void ircOperatorSet(QString ircOperator); - void lastAwayMessageSet(int lastAwayMessage); - void whoisServiceReplySet(QString whoisServiceReply); - void suserHostSet(QString suserHost); - void hostmaskUpdated(QString mask); - - void userModesSet(QString modes); +// void userSet(QString user); +// void hostSet(QString host); +// void nickSet(QString newnick); +// void realNameSet(QString realName); +// void awaySet(bool away); +// void awayMessageSet(QString awayMessage); +// void idleTimeSet(QDateTime idleTime); +// void loginTimeSet(QDateTime loginTime); +// void serverSet(QString server); +// void ircOperatorSet(QString ircOperator); +// void lastAwayMessageSet(int lastAwayMessage); +// void whoisServiceReplySet(QString whoisServiceReply); +// void suserHostSet(QString suserHost); + +// void userModesSet(QString modes); +// void userModesAdded(QString modes); +// void userModesRemoved(QString modes); // void channelJoined(QString channel); void channelParted(QString channel); void quited(); - void userModesAdded(QString modes); - void userModesRemoved(QString modes); - void lastChannelActivityUpdated(BufferId id, const QDateTime &newTime); void lastSpokenToUpdated(BufferId id, const QDateTime &newTime); diff --git a/src/common/signalproxy.cpp b/src/common/signalproxy.cpp index 9a7b7731..08cdc7dc 100644 --- a/src/common/signalproxy.cpp +++ b/src/common/signalproxy.cpp @@ -570,6 +570,7 @@ void SignalProxy::receivePeerSignal(AbstractPeer *sender, const RequestType &req } } + qDebug() << "SignalProxy::receivePeerSignal)" << requestType << params; switch(requestType) { case RpcCall: if(params.empty()) @@ -621,23 +622,27 @@ void SignalProxy::handleSync(AbstractPeer *sender, QVariantList params) { QByteArray className = params.takeFirst().toByteArray(); QString objectName = params.takeFirst().toString(); - QByteArray signal = params.takeFirst().toByteArray(); + QByteArray slot = params.takeFirst().toByteArray(); if(!_syncSlave.contains(className) || !_syncSlave[className].contains(objectName)) { - qWarning() << QString("no registered receiver for sync call: %1::%2 (objectName=\"%3\"). Params are:").arg(QString(className)).arg(QString(signal)).arg(objectName) + qWarning() << QString("no registered receiver for sync call: %1::%2 (objectName=\"%3\"). Params are:").arg(QString(className)).arg(QString(slot)).arg(objectName) << params; return; } SyncableObject *receiver = _syncSlave[className][objectName]; ExtendedMetaObject *eMeta = extendedMetaObject(receiver); - if(!eMeta->syncMap().contains(signal)) { - qWarning() << QString("no matching slot for sync call: %1::%2 (objectName=\"%3\"). Params are:").arg(QString(className)).arg(QString(signal)).arg(objectName) + if(!eMeta->slotMap().contains(slot)) { + qWarning() << QString("no matching slot for sync call: %1::%2 (objectName=\"%3\"). Params are:").arg(QString(className)).arg(QString(slot)).arg(objectName) << params; return; } - int slotId = eMeta->syncMap()[signal]; + int slotId = eMeta->slotMap()[slot]; + if(proxyMode() != eMeta->receiverMode(slotId)) { + qWarning("SignalProxy::handleSync(): invokeMethod for \"%s\" failed. Wrong ProxyMode!", eMeta->methodName(slotId).constData()); + return; + } QVariant returnValue((QVariant::Type)eMeta->returnType(slotId)); if(!invokeSlot(receiver, slotId, params, returnValue)) { @@ -645,12 +650,14 @@ void SignalProxy::handleSync(AbstractPeer *sender, QVariantList params) { return; } + if(returnValue.type() != QVariant::Invalid && eMeta->receiveMap().contains(slotId)) { int receiverId = eMeta->receiveMap()[slotId]; QVariantList returnParams; returnParams << className << objectName - << QByteArray(receiver->metaObject()->method(receiverId).signature()); + << eMeta->methodName(receiverId); + //QByteArray(receiver->metaObject()->method(receiverId).signature()); if(eMeta->argTypes(receiverId).count() > 1) returnParams << params; returnParams << returnValue; @@ -980,6 +987,7 @@ void SignalProxy::customEvent(QEvent *event) { } void SignalProxy::syncCall(const SyncableObject *obj, SignalProxy::ProxyMode modeType, const char *funcname, va_list ap) { + qDebug() << obj << modeType << "(" << _proxyMode << ")" << funcname; if(modeType != _proxyMode) return; @@ -1002,6 +1010,8 @@ void SignalProxy::syncCall(const SyncableObject *obj, SignalProxy::ProxyMode mod } params << QVariant(argTypes[i], va_arg(ap, void *)); } + + dispatchSignal(Sync, params); } void SignalProxy::disconnectDevice(QIODevice *dev, const QString &reason) { @@ -1038,19 +1048,6 @@ void SignalProxy::dumpProxyStats() { qDebug() << "number of Classes cached:" << _extendedMetaObjects.count(); } -void SignalProxy::dumpSyncMap(SyncableObject *object) { - const QMetaObject *meta = object->metaObject(); - ExtendedMetaObject *eMeta = extendedMetaObject(object); - qDebug() << "SignalProxy: SyncMap for Class" << meta->className(); - - QHash syncMap_ = eMeta->syncMap(); - QHash::const_iterator iter = syncMap_.constBegin(); - while(iter != syncMap_.constEnd()) { - qDebug() << qPrintable(QString("%1 --> %2 %3").arg(QString(iter.key()), 40).arg(iter.value()).arg(QString(meta->method(iter.value()).signature()))); - iter++; - } -} - void SignalProxy::updateSecureState() { bool wasSecure = _secure; @@ -1072,6 +1069,39 @@ SignalProxy::ExtendedMetaObject::ExtendedMetaObject(const QMetaObject *meta) : _meta(meta), _updatedRemotelyId(_meta->indexOfSignal("updatedRemotely()")) { + for(int i = 0; i < _meta->methodCount(); i++) { + if(_meta->method(i).methodType() != QMetaMethod::Slot) + continue; + + if(QByteArray(_meta->method(i).signature()).contains('*')) + continue; // skip methods with ptr params + + QByteArray method = methodName(_meta->method(i)); + if(_methodIds.contains(method)) { + /* funny... moc creates for methods containing default parameters multiple metaMethod with separate methodIds. + we don't care... we just need the full fledged version + */ + const QMetaMethod ¤t = _meta->method(_methodIds[method]); + const QMetaMethod &candidate = _meta->method(i); + if(current.parameterTypes().count() > candidate.parameterTypes().count()) { + int minCount = candidate.parameterTypes().count(); + QList commonParams = current.parameterTypes().mid(0, minCount); + if(commonParams == candidate.parameterTypes()) + continue; // we already got the full featured version + } else { + int minCount = current.parameterTypes().count(); + QList commonParams = candidate.parameterTypes().mid(0, minCount); + if(commonParams == current.parameterTypes()) { + _methodIds[method] = i; // use the new one + continue; + } + } + qWarning() << "class" << meta->className() << "contains overloaded methods which is currently not supported!"; + qWarning() << " - " << _meta->method(i).signature() << "conflicts with" << _meta->method(_methodIds[method]).signature(); + continue; + } + _methodIds[method] = i; + } } const SignalProxy::ExtendedMetaObject::MethodDescriptor &SignalProxy::ExtendedMetaObject::methodDescriptor(int methodId) { @@ -1081,71 +1111,6 @@ const SignalProxy::ExtendedMetaObject::MethodDescriptor &SignalProxy::ExtendedMe return _methods[methodId]; } -int SignalProxy::ExtendedMetaObject::methodId(const QByteArray &methodName) { - if(_methodIds.contains(methodName)) { - return _methodIds[methodName]; - } else { - for(int i = _meta->methodOffset(); i < _meta->methodCount(); i++) { - if(ExtendedMetaObject::methodName(_meta->method(i)) == methodName) { - _methodIds[methodName] = i; - return i; - } - } - } - Q_ASSERT(false); - return -1; -} - -const QHash &SignalProxy::ExtendedMetaObject::syncMap() { - if(_syncMap.isEmpty()) { - QHash syncMap; - - QList slotIndexes; - for(int i = 0; i < _meta->methodCount(); i++) { - if(_meta->method(i).methodType() == QMetaMethod::Slot) - slotIndexes << i; - } - - // we're faking sync pairs for sync replies - // --> we deliver to every slot starting with "receive" - QByteArray slotSignature; - QList::iterator slotIter = slotIndexes.begin(); - while(slotIter != slotIndexes.end()) { - slotSignature = QByteArray(_meta->method(*slotIter).signature()); - if(slotSignature.startsWith("receive")) { - syncMap[slotSignature] = *slotIter; - slotIter = slotIndexes.erase(slotIter); - } else { - slotIter++; - } - } - - // find the proper sig -> slot matches - 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.removeAll(matchIdx); - syncMap[QByteArray(signal.signature())] = matchIdx; - } - } - _syncMap = syncMap; - } - return _syncMap; -} - const QHash &SignalProxy::ExtendedMetaObject::receiveMap() { if(_receiveMap.isEmpty()) { QHash receiveMap; @@ -1189,8 +1154,10 @@ const QHash &SignalProxy::ExtendedMetaObject::receiveMap() { receiverId = _meta->indexOfSlot(signature); } - if(receiverId != -1) + if(receiverId != -1) { receiveMap[i] = receiverId; + qDebug() << requestSlot.signature() << _meta->method(receiverId).signature() << "---" << i << receiverId; + } } _receiveMap = receiveMap; } @@ -1202,29 +1169,6 @@ QByteArray SignalProxy::ExtendedMetaObject::methodName(const QMetaMethod &method return sig.left(sig.indexOf("(")); } -bool SignalProxy::ExtendedMetaObject::methodsMatch(const QMetaMethod &signal, const QMetaMethod &slot) { - // if we don't even have the same basename it's a sure NO - QString baseName = methodBaseName(signal); - if(baseName != 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); - QString slotprefix = methodName(slot); - if(!baseName.isEmpty()) { - signalsuffix = signalsuffix.mid(baseName.count()).toLower(); - slotprefix = slotprefix.left(slotprefix.count() - baseName.count()).toLower(); - } - - uint sizediff = qAbs(slotprefix.size() - signalsuffix.size()); - int ratio = editingDistance(slotprefix, signalsuffix) - sizediff; - return (ratio < 2); -} - QString SignalProxy::ExtendedMetaObject::methodBaseName(const QMetaMethod &method) { QString methodname = QString(method.signature()).section("(", 0, 0); @@ -1264,5 +1208,9 @@ SignalProxy::ExtendedMetaObject::MethodDescriptor::MethodDescriptor(const QMetaM // determine minArgCount QString signature(method.signature()); _minArgCount = method.parameterTypes().count() - signature.count("="); + + _receiverMode = (_methodName.startsWith("request")) + ? SignalProxy::Server + : SignalProxy::Client; } diff --git a/src/common/signalproxy.h b/src/common/signalproxy.h index a76a3520..7f2a1ddc 100644 --- a/src/common/signalproxy.h +++ b/src/common/signalproxy.h @@ -210,18 +210,20 @@ class SignalProxy::ExtendedMetaObject { class MethodDescriptor { public: MethodDescriptor(const QMetaMethod &method); - MethodDescriptor() : _returnType(-1), _minArgCount(-1) {} + MethodDescriptor() : _returnType(-1), _minArgCount(-1), _receiverMode(SignalProxy::Client) {} inline const QByteArray &methodName() const { return _methodName; } inline const QList &argTypes() const { return _argTypes; } inline int returnType() const { return _returnType; } inline int minArgCount() const { return _minArgCount; } + inline SignalProxy::ProxyMode receiverMode() const { return _receiverMode; } private: QByteArray _methodName; QList _argTypes; int _returnType; int _minArgCount; + SignalProxy::ProxyMode _receiverMode; // Only acceptable as a Sync Call if the receiving SignalProxy is in this mode. }; public: @@ -231,30 +233,29 @@ public: inline const QList &argTypes(int methodId) { return methodDescriptor(methodId).argTypes(); } inline int returnType(int methodId) { return methodDescriptor(methodId).returnType(); } inline int minArgCount(int methodId) { return methodDescriptor(methodId).minArgCount(); } + inline SignalProxy::ProxyMode receiverMode(int methodId) { return methodDescriptor(methodId).receiverMode(); } + + inline int methodId(const QByteArray &methodName) { return _methodIds.contains(methodName) ? _methodIds[methodName] : -1; } inline int updatedRemotelyId() { return _updatedRemotelyId; } - int methodId(const QByteArray &methodName); - const QHash &syncMap(); + inline const QHash &slotMap() { return _methodIds; } const QHash &receiveMap(); const QMetaObject *metaObject() const { return _meta; } static QByteArray methodName(const QMetaMethod &method); - static bool methodsMatch(const QMetaMethod &signal, const QMetaMethod &slot); - static QString methodBaseName(const QMetaMethod &method); + static QString ExtendedMetaObject::methodBaseName(const QMetaMethod &method); private: const MethodDescriptor &methodDescriptor(int methodId); const QMetaObject *_meta; - QHash _methods; - QHash _methodIds; - int _updatedRemotelyId; // id of the updatedRemotely() signal - makes things faster - QHash _syncMap; - QHash _receiveMap; + QHash _methods; + QHash _methodIds; + QHash _receiveMap; // if slot x is called then hand over the result to slot y }; diff --git a/src/common/syncableobject.h b/src/common/syncableobject.h index 201c002c..92746f87 100644 --- a/src/common/syncableobject.h +++ b/src/common/syncableobject.h @@ -36,8 +36,6 @@ public: SyncableObject(const QString &objectName, QObject *parent = 0); SyncableObject(const SyncableObject &other, QObject *parent = 0); - void synchronize(SignalProxy *proxy); - //! Stores the object's state into a QVariantMap. /** The default implementation takes dynamic properties as well as getters that have * names starting with "init" and stores them in a QVariantMap. Override this method in @@ -82,17 +80,31 @@ signals: void objectRenamed(QString newName, QString oldName); private: + void synchronize(SignalProxy *proxy); + bool setInitValue(const QString &property, const QVariant &value); bool _initialized; bool _allowClientUpdates; QList _signalProxies; + + friend class SignalProxy; }; -#define so_sync(...) sync_call__(SignalProxy::Server, __func__, __VA_ARGS__); -#define so_request(...) sync_call__(SignalProxy::Client, __func__, __VA_ARGS__); -#define so_arg_cast(x) const_cast(reinterpret_cast(&x)) +#define SYNCABLE_OBJECT static const int _classNameOffset__; +#define INIT_SYNCABLE_OBJECT(x) const int x ::_classNameOffset__ = QByteArray(staticMetaObject.className()).length() + 2; + +#ifdef Q_WS_WIN +# define SYNC(...) sync_call__(SignalProxy::Server, (__FUNCTION__ + _classNameOffset__), __VA_ARGS__); +# define REQUEST(...) sync_call__(SignalProxy::Client, (__FUNCTION__ + _classNameOffset__) , __VA_ARGS__); +#else +# define SYNC(...) sync_call__(SignalProxy::Server, __func__, __VA_ARGS__); +# define REQUEST(...) sync_call__(SignalProxy::Client, __func__, __VA_ARGS__); +#endif //Q_WS_WIN + +#define ARG(x) const_cast(reinterpret_cast(&x)) +#define NO_ARG 0 #endif -- 2.20.1