+bool SignalProxy::invokeSlot(QObject *receiver, int methodId, const QVariantList ¶ms, QVariant &returnValue) {
+ const QList<int> args = argTypes(receiver, methodId);
+ const int numArgs = params.count() < args.count()
+ ? params.count()
+ : args.count();
+
+ if(minArgCount(receiver, methodId) > params.count()) {
+ qWarning() << "SignalProxy::invokeSlot(): not enough params to invoke" << methodName(receiver, methodId);
+ return false;
+ }
+
+ void *_a[] = {0, // return type...
+ 0, 0, 0, 0 , 0, // and 10 args - that's the max size qt can handle with signals and slots
+ 0, 0, 0, 0 , 0};
+
+ // check for argument compatibility and build params array
+ for(int i = 0; i < numArgs; i++) {
+ if(!params[i].isValid()) {
+ qWarning() << "SignalProxy::invokeSlot(): received invalid data for argument number" << i << "of method" << QString("%1::%2()").arg(receiver->metaObject()->className()).arg(receiver->metaObject()->method(methodId).signature());
+ qWarning() << " - make sure all your data types are known by the Qt MetaSystem";
+ return false;
+ }
+ if(args[i] != QMetaType::type(params[i].typeName())) {
+ qWarning() << "SignalProxy::invokeSlot(): incompatible param types to invoke" << methodName(receiver, methodId);
+ return false;
+ }
+ _a[i+1] = const_cast<void *>(params[i].constData());
+ }
+
+ if(returnValue.type() != QVariant::Invalid)
+ _a[0] = const_cast<void *>(returnValue.constData());
+
+ Qt::ConnectionType type = QThread::currentThread() == receiver->thread()
+ ? Qt::DirectConnection
+ : Qt::QueuedConnection;
+
+ if (type == Qt::DirectConnection) {
+ return receiver->qt_metacall(QMetaObject::InvokeMetaMethod, methodId, _a) < 0;
+ } else {
+ qWarning() << "Queued Connections are not implemented yet";
+ // note to self: qmetaobject.cpp:990 ff
+ return false;
+ }
+
+}
+
+bool SignalProxy::invokeSlot(QObject *receiver, int methodId, const QVariantList ¶ms) {
+ QVariant ret;
+ return invokeSlot(receiver, methodId, params, ret);
+}
+
+void SignalProxy::dataAvailable() {
+ // yet again. it's a private slot. no need for checks.
+ QIODevice* ioDev = qobject_cast<QIODevice* >(sender());
+ QVariant var;
+ while(readDataFromDevice(ioDev, _peerByteCount[ioDev], var))
+ receivePeerSignal(ioDev, var);
+}
+
+void SignalProxy::writeDataToDevice(QIODevice *dev, const QVariant &item) {
+ QAbstractSocket* sock = qobject_cast<QAbstractSocket*>(dev);
+ if(!dev->isOpen() || (sock && sock->state()!=QAbstractSocket::ConnectedState)) {
+ qWarning("SignalProxy: Can't call on a closed device");
+ return;
+ }
+ QByteArray block;
+ QDataStream out(&block, QIODevice::WriteOnly);
+ out.setVersion(QDataStream::Qt_4_2);
+ out << (quint32)0 << item;
+ out.device()->seek(0);
+ out << (quint32)(block.size() - sizeof(quint32));
+ dev->write(block);
+}
+
+bool SignalProxy::readDataFromDevice(QIODevice *dev, quint32 &blockSize, QVariant &item) {
+ QDataStream in(dev);
+ in.setVersion(QDataStream::Qt_4_2);
+
+ if(blockSize == 0) {
+ if(dev->bytesAvailable() < (int)sizeof(quint32)) return false;
+ in >> blockSize;
+ }
+
+ if(dev->bytesAvailable() < blockSize)
+ return false;
+ in >> item;
+ blockSize = 0;
+ 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(SyncableObject *obj) const {
+ return obj->toVariantMap();
+}
+
+void SignalProxy::setInitData(SyncableObject *obj, const QVariantMap &properties) {
+ if(isInitialized(obj))
+ return;
+ obj->fromVariantMap(properties);
+ setInitialized(obj);
+ invokeSlot(obj, updatedRemotelyId(obj));
+}
+
+void SignalProxy::sendHeartBeat() {
+ dispatchSignal(SignalProxy::HeartBeat, QVariantList());
+}
+
+void SignalProxy::dumpProxyStats() {
+ QString mode;
+ if(proxyMode() == Server)
+ mode = "Server";
+ else
+ mode = "Client";
+
+ int sigCount = 0;
+ 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() << " attached Slots:" << _attachedSlots.count();
+ qDebug() << " number of synced Slaves:" << slaveCount;
+ qDebug() << "number of Classes cached:" << _classInfo.count();
+}
+
+void SignalProxy::dumpSyncMap(SyncableObject *object) {
+ const QMetaObject *meta = object->metaObject();
+ qDebug() << "SignalProxy: SyncMap for Class" << meta->className();
+
+ QHash<QByteArray, int> syncMap_ = syncMap(object);
+ QHash<QByteArray, int>::const_iterator iter = syncMap_.constBegin();
+ while(iter != syncMap_.constEnd()) {
+ qDebug() << iter.key() << "-->" << iter.value() << meta->method(iter.value()).signature();
+ iter++;
+ }
+// QHash<int, int> syncMap_ = syncMap(object);
+// QHash<int, int>::const_iterator iter = syncMap_.constBegin();
+// while(iter != syncMap_.constEnd()) {
+// qDebug() << iter.key() << meta->method(iter.key()).signature() << "-->" << iter.value() << meta->method(iter.value()).signature();
+// iter++;
+// }
+}