#include <QDebug>
+INIT_SYNCABLE_OBJECT(ClientBacklogManager)
ClientBacklogManager::ClientBacklogManager(QObject *parent)
: BacklogManager(parent),
_requester(0)
class BacklogRequester;
class ClientBacklogManager : public BacklogManager {
+ SYNCABLE_OBJECT
Q_OBJECT
public:
#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();
}
#include "types.h"
class BacklogManager : public SyncableObject {
+ SYNCABLE_OBJECT
Q_OBJECT
public:
#include <QTextCodec>
#include <QDebug>
+INIT_SYNCABLE_OBJECT(IrcUser)
IrcUser::IrcUser(const QString &hostmask, Network *network) : SyncableObject(network),
_initialized(false),
_nick(nickFromMask(hostmask)),
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))
}
}
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))
}
}
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))
}
}
void IrcUser::setUserModes(const QString &modes) {
_userModes = modes;
- emit userModesSet(modes);
+ SYNC(ARG(modes))
}
void IrcUser::addUserModes(const QString &modes) {
_userModes += modes[i];
}
- emit userModesAdded(modes);
+ SYNC(ARG(modes))
}
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) {
class IrcChannel;
class IrcUser : public SyncableObject {
+ SYNCABLE_OBJECT
Q_OBJECT
Q_PROPERTY(QString user READ user WRITE setUser STORED false)
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);
}
}
+ qDebug() << "SignalProxy::receivePeerSignal)" << requestType << params;
switch(requestType) {
case RpcCall:
if(params.empty())
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)) {
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;
}
void SignalProxy::syncCall(const SyncableObject *obj, SignalProxy::ProxyMode modeType, const char *funcname, va_list ap) {
+ qDebug() << obj << modeType << "(" << _proxyMode << ")" << funcname;
if(modeType != _proxyMode)
return;
}
params << QVariant(argTypes[i], va_arg(ap, void *));
}
+
+ dispatchSignal(Sync, params);
}
void SignalProxy::disconnectDevice(QIODevice *dev, const QString &reason) {
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<QByteArray, int> syncMap_ = eMeta->syncMap();
- QHash<QByteArray, int>::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;
: _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<QByteArray> 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<QByteArray> 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) {
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<QByteArray, int> &SignalProxy::ExtendedMetaObject::syncMap() {
- if(_syncMap.isEmpty()) {
- QHash<QByteArray, int> syncMap;
-
- QList<int> 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<int>::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<int, int> &SignalProxy::ExtendedMetaObject::receiveMap() {
if(_receiveMap.isEmpty()) {
QHash<int, int> 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;
}
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);
// determine minArgCount
QString signature(method.signature());
_minArgCount = method.parameterTypes().count() - signature.count("=");
+
+ _receiverMode = (_methodName.startsWith("request"))
+ ? SignalProxy::Server
+ : SignalProxy::Client;
}
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<int> &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<int> _argTypes;
int _returnType;
int _minArgCount;
+ SignalProxy::ProxyMode _receiverMode; // Only acceptable as a Sync Call if the receiving SignalProxy is in this mode.
};
public:
inline const QList<int> &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<QByteArray, int> &syncMap();
+ inline const QHash<QByteArray, int> &slotMap() { return _methodIds; }
const QHash<int, int> &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<int, MethodDescriptor> _methods;
- QHash<QByteArray, int> _methodIds;
-
int _updatedRemotelyId; // id of the updatedRemotely() signal - makes things faster
- QHash<QByteArray, int> _syncMap;
- QHash<int, int> _receiveMap;
+ QHash<int, MethodDescriptor> _methods;
+ QHash<QByteArray, int> _methodIds;
+ QHash<int, int> _receiveMap; // if slot x is called then hand over the result to slot y
};
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
void objectRenamed(QString newName, QString oldName);
private:
+ void synchronize(SignalProxy *proxy);
+
bool setInitValue(const QString &property, const QVariant &value);
bool _initialized;
bool _allowClientUpdates;
QList<SignalProxy *> _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<void *>(reinterpret_cast<const void*>(&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<void *>(reinterpret_cast<const void*>(&x))
+#define NO_ARG 0
#endif