X-Git-Url: https://git.quassel-irc.org/?p=quassel.git;a=blobdiff_plain;f=src%2Fcommon%2Fsignalproxy.cpp;h=ebcf507696fef745a454269335f34962789242c4;hp=9a7b77317199569864f1efd65e364e9d47609783;hb=70283ef877bdf3339fb067667ad9130ceabd8b9a;hpb=57e1cccf5a990b83bc8bde7959e85dec99db50a7 diff --git a/src/common/signalproxy.cpp b/src/common/signalproxy.cpp index 9a7b7731..ebcf5076 100644 --- a/src/common/signalproxy.cpp +++ b/src/common/signalproxy.cpp @@ -231,6 +231,18 @@ SignalProxy::SignalProxy(ProxyMode mode, QIODevice* device, QObject* parent) } SignalProxy::~SignalProxy() { + QHash::iterator classIter = _syncSlave.begin(); + while(classIter != _syncSlave.end()) { + ObjectId::iterator objIter = classIter->begin(); + while(objIter != classIter->end()) { + SyncableObject *obj = objIter.value(); + objIter = classIter->erase(objIter); + obj->stopSynchronize(this); + } + classIter++; + } + _syncSlave.clear(); + removeAllPeers(); } @@ -389,21 +401,23 @@ void SignalProxy::removePeerBySender() { removePeer(sender()); } -void SignalProxy::objectRenamed(const QString &newname, const QString &oldname) { - SyncableObject *syncObject = qobject_cast(sender()); - const QMetaObject *meta = syncObject->syncMetaObject(); - const QByteArray className(meta->className()); - objectRenamed(className, newname, oldname); - +void SignalProxy::renameObject(const SyncableObject *obj, const QString &newname, const QString &oldname) { if(proxyMode() == Client) return; + const QMetaObject *meta = obj->syncMetaObject(); + const QByteArray className(meta->className()); + objectRenamed(className, newname, oldname); + QVariantList params; params << "__objectRenamed__" << className << newname << oldname; dispatchSignal(RpcCall, params); } void SignalProxy::objectRenamed(const QByteArray &classname, const QString &newname, const QString &oldname) { + if(proxyMode() == Server) + return; + if(_syncSlave.contains(classname) && _syncSlave[classname].contains(oldname) && oldname != newname) { SyncableObject *obj = _syncSlave[classname][newname] = _syncSlave[classname].take(oldname); requestInit(obj); @@ -424,9 +438,9 @@ SignalProxy::ExtendedMetaObject *SignalProxy::extendedMetaObject(const QMetaObje return 0; } -SignalProxy::ExtendedMetaObject *SignalProxy::createExtendedMetaObject(const QMetaObject *meta) { +SignalProxy::ExtendedMetaObject *SignalProxy::createExtendedMetaObject(const QMetaObject *meta, bool checkConflicts) { if(!_extendedMetaObjects.contains(meta)) { - _extendedMetaObjects[meta] = new ExtendedMetaObject(meta); + _extendedMetaObjects[meta] = new ExtendedMetaObject(meta, checkConflicts); } return _extendedMetaObjects[meta]; } @@ -467,16 +481,13 @@ bool SignalProxy::attachSlot(const QByteArray& sigName, QObject* recv, const cha } void SignalProxy::synchronize(SyncableObject *obj) { - createExtendedMetaObject(obj); + createExtendedMetaObject(obj, true); // attaching as slave to receive sync Calls QByteArray className(obj->syncMetaObject()->className()); _syncSlave[className][obj->objectName()] = obj; - disconnect(obj, SIGNAL(destroyed(QObject *)), this, SLOT(detachObject(QObject *))); - connect(obj, SIGNAL(destroyed(QObject *)), this, SLOT(detachObject(QObject *))); if(proxyMode() == Server) { - connect(obj, SIGNAL(objectRenamed(QString, QString)), this, SLOT(objectRenamed(QString, QString))); obj->setInitialized(); emit objectInitialized(obj); } else { @@ -490,7 +501,6 @@ void SignalProxy::synchronize(SyncableObject *obj) { } void SignalProxy::detachObject(QObject *obj) { - stopSync(obj); detachSignals(obj); detachSlots(obj); } @@ -509,7 +519,7 @@ void SignalProxy::detachSlots(QObject* receiver) { } } -void SignalProxy::stopSync(QObject *obj) { +void SignalProxy::stopSynchronize(SyncableObject *obj) { // we can't use a className here, since it might be effed up, if we receive the call as a result of a decon // gladly the objectName() is still valid. So we have only to iterate over the classes not each instance! *sigh* QHash::iterator classIter = _syncSlave.begin(); @@ -520,6 +530,7 @@ void SignalProxy::stopSync(QObject *obj) { } classIter++; } + obj->stopSynchronize(this); } void SignalProxy::dispatchSignal(const RequestType &requestType, const QVariantList ¶ms) { @@ -570,6 +581,7 @@ void SignalProxy::receivePeerSignal(AbstractPeer *sender, const RequestType &req } } + // qDebug() << "SignalProxy::receivePeerSignal)" << requestType << params; switch(requestType) { case RpcCall: if(params.empty()) @@ -621,23 +633,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 +661,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; @@ -979,19 +997,18 @@ void SignalProxy::customEvent(QEvent *event) { } } -void SignalProxy::syncCall(const SyncableObject *obj, SignalProxy::ProxyMode modeType, const char *funcname, va_list ap) { +void SignalProxy::sync_call__(const SyncableObject *obj, SignalProxy::ProxyMode modeType, const char *funcname, va_list ap) { + // qDebug() << obj << modeType << "(" << _proxyMode << ")" << funcname; if(modeType != _proxyMode) return; ExtendedMetaObject *eMeta = extendedMetaObject(obj); QVariantList params; - params << eMeta->metaObject()->className() << obj->objectName() << QByteArray(funcname); - const QList &argTypes = eMeta->argTypes(eMeta->methodId(QByteArray(funcname))); for(int i = 0; i < argTypes.size(); i++) { @@ -1002,8 +1019,12 @@ 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) { if(!reason.isEmpty()) qWarning() << qPrintable(reason); @@ -1038,19 +1059,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; @@ -1068,10 +1076,48 @@ void SignalProxy::updateSecureState() { // ================================================== // ExtendedMetaObject // ================================================== -SignalProxy::ExtendedMetaObject::ExtendedMetaObject(const QMetaObject *meta) +SignalProxy::ExtendedMetaObject::ExtendedMetaObject(const QMetaObject *meta, bool checkConflicts) : _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(method.startsWith("init")) + continue; // skip initializers + + 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; + } + } + if(checkConflicts) { + 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 +1127,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 +1170,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 +1185,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 +1224,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; }