+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;
+ 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<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(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)
+ 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();
+}
+
+