}
void IrcUser::setHost(const QString &host) {
+ so_sync(so_arg_cast(host));
if(!host.isEmpty() && _host != host) {
_host = host;
emit hostSet(host);
else
requestInit(obj);
}
+
+ obj->synchronize(this);
}
void SignalProxy::detachObject(QObject *obj) {
}
}
+void SignalProxy::syncCall(const SyncableObject *obj, SignalProxy::ProxyMode modeType, const char *funcname, va_list ap) {
+ if(modeType != _proxyMode)
+ return;
+
+ ExtendedMetaObject *eMeta = extendedMetaObject(obj);
+
+ QVariantList params;
+
+ params << eMeta->metaObject()->className()
+ << obj->objectName()
+ << QByteArray(funcname);
+
+
+ const QList<int> &argTypes = eMeta->argTypes(eMeta->methodId(QByteArray(funcname)));
+
+ for(int i = 0; i < argTypes.size(); i++) {
+ if(argTypes[i] == 0) {
+ qWarning() << Q_FUNC_INFO << "received invalid data for argument number" << i << "of signal" << QString("%1::%2").arg(eMeta->metaObject()->className()).arg(funcname);
+ qWarning() << " - make sure all your data types are known by the Qt MetaSystem";
+ return;
+ }
+ params << QVariant(argTypes[i], va_arg(ap, void *));
+ }
+}
+
void SignalProxy::disconnectDevice(QIODevice *dev, const QString &reason) {
if(!reason.isEmpty())
qWarning() << qPrintable(reason);
return _argTypes[methodId];
}
-const int &SignalProxy::ExtendedMetaObject::returnType(int methodId) {
+int SignalProxy::ExtendedMetaObject::returnType(int methodId) {
if(!_returnType.contains(methodId)) {
_returnType[methodId] = QMetaType::type(_meta->method(methodId).typeName());
}
return _returnType[methodId];
}
-const int &SignalProxy::ExtendedMetaObject::minArgCount(int methodId) {
+int SignalProxy::ExtendedMetaObject::minArgCount(int methodId) {
if(!_minArgCount.contains(methodId)) {
QString signature(_meta->method(methodId).signature());
_minArgCount[methodId] = _meta->method(methodId).parameterTypes().count() - signature.count("=");
return _methodNames[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<QByteArray, int> &SignalProxy::ExtendedMetaObject::syncMap() {
if(_syncMap.isEmpty()) {
QHash<QByteArray, int> syncMap;
protected:
void customEvent(QEvent *event);
+ void syncCall(const SyncableObject *obj, ProxyMode modeType, const char *funcname, va_list ap);
private slots:
void dataAvailable();
bool _secure; // determines if all connections are in a secured state (using ssl or internal connections)
friend class SignalRelay;
+ friend class SyncableObject;
};
ExtendedMetaObject(const QMetaObject *meta);
const QList<int> &argTypes(int methodId);
- const int &returnType(int methodId);
- const int &minArgCount(int methodId);
+ int returnType(int methodId);
+ int minArgCount(int methodId);
const QByteArray &methodName(int methodId);
+ int methodId(const QByteArray &methodName);
const QHash<QByteArray, int> &syncMap();
const QHash<int, int> &receiveMap();
int updatedRemotelyId();
private:
typedef QHash<int, QList<int> > ArgHash;
typedef QHash<int, QByteArray> MethodNameHash;
+ typedef QHash<QByteArray, int> MethodIdHash;
const QMetaObject *_meta;
ArgHash _argTypes;
QHash<int, int> _returnType;
QHash<int, int> _minArgCount;
MethodNameHash _methodNames;
+ MethodIdHash _methodIds;
int _updatedRemotelyId; // id of the updatedRemotely() signal - makes things faster
QHash<QByteArray, int> _syncMap;
QHash<int, int> _receiveMap;
return *this;
}
+void SyncableObject::synchronize(SignalProxy *proxy) {
+ if(_signalProxies.contains(proxy))
+ return;
+ _signalProxies << proxy;
+}
+
bool SyncableObject::isInitialized() const {
return _initialized;
}
}
emit updateRequested(properties);
}
+
+void SyncableObject::sync_call__(SignalProxy::ProxyMode modeType, const char *funcname, ...) {
+ qDebug() << Q_FUNC_INFO << modeType << funcname;
+ foreach(SignalProxy *proxy, _signalProxies) {
+ va_list ap;
+ va_start(ap, funcname);
+ proxy->syncCall(this, modeType, funcname, ap);
+ va_end(ap);
+ }
+}
#include <QObject>
#include <QVariantMap>
+#include "signalproxy.h"
+
class SyncableObject : public QObject {
Q_OBJECT
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
virtual void update(const QVariantMap &properties);
protected:
+ void sync_call__(SignalProxy::ProxyMode modeType, const char *funcname, ...);
+
void renameObject(const QString &newName);
SyncableObject &operator=(const SyncableObject &other);
bool _initialized;
bool _allowClientUpdates;
+ QList<SignalProxy *> _signalProxies;
};
+#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<void *>(reinterpret_cast<const void*>(&x))
+
+
#endif