Finaly got rid of the synchronizers, making Quassel quite a bit more lightweight...
authorMarcus Eggenberger <egs@quassel-irc.org>
Tue, 13 Nov 2007 16:44:11 +0000 (16:44 +0000)
committerMarcus Eggenberger <egs@quassel-irc.org>
Tue, 13 Nov 2007 16:44:11 +0000 (16:44 +0000)
15 files changed:
src/client/client.cpp
src/client/client.h
src/common/common.pri
src/common/ircuser.cpp
src/common/ircuser.h
src/common/networkinfo.cpp
src/common/networkinfo.h
src/common/signalproxy.cpp
src/common/signalproxy.h
src/common/synchronizer.cpp [deleted file]
src/common/synchronizer.h [deleted file]
src/common/util.cpp
src/common/util.h
src/core/coresession.cpp
src/core/server.cpp

index 29e68d8..ec01b28 100644 (file)
@@ -30,7 +30,6 @@
 #include "buffertreemodel.h"
 #include "quasselui.h"
 #include "signalproxy.h"
-#include "synchronizer.h"
 #include "util.h"
 
 QPointer<Client> Client::instanceptr = 0;
@@ -232,9 +231,7 @@ void Client::connectToCore(const QVariantMap &conn) {
     socket = sock;
     connect(sock, SIGNAL(readyRead()), this, SLOT(coreHasData()));
     connect(sock, SIGNAL(connected()), this, SLOT(coreSocketConnected()));
-    connect(sock, SIGNAL(disconnected()), this, SLOT(coreSocketDisconnected()));
     connect(signalProxy(), SIGNAL(disconnected()), this, SLOT(coreSocketDisconnected()));
-    //connect(sock, SIGNAL(stateChanged(QAbstractSocket::SocketState)), this, SLOT(coreSocketStateChanged(QAbstractSocket::SocketState)));
     connect(sock, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(coreSocketError(QAbstractSocket::SocketError)));
     sock->connectToHost(conn["Host"].toString(), conn["Port"].toUInt());
   }
@@ -242,9 +239,6 @@ void Client::connectToCore(const QVariantMap &conn) {
 
 void Client::disconnectFromCore() {
   socket->close();
-  if(clientMode == LocalCore) {
-    coreSocketDisconnected();
-  }
 }
 
 void Client::setCoreConfiguration(const QVariantMap &settings) {
@@ -269,26 +263,32 @@ void Client::coreSocketDisconnected() {
 
   /* Clear internal data. Hopefully nothing relies on it at this point. */
   _bufferModel->clear();
-  foreach(Buffer *buffer, _buffers.values()) {
+
+  QHash<uint, Buffer *>::iterator bufferIter =  _buffers.begin();
+  while(bufferIter != _buffers.end()) {
+    Buffer *buffer = bufferIter.value();
+    disconnect(buffer, SIGNAL(destroyed()), this, 0);
+    bufferIter = _buffers.erase(bufferIter);
     buffer->deleteLater();
   }
-  _buffers.clear();
+  Q_ASSERT(_buffers.isEmpty());
 
-  foreach(NetworkInfo *networkinfo, _networkInfo.values()) {
-    networkinfo->deleteLater();
-  }
-  _networkInfo.clear();
 
+  QHash<uint, NetworkInfo*>::iterator netIter = _networkInfo.begin();
+  while(netIter != _networkInfo.end()) {
+    NetworkInfo *net = netIter.value();
+    disconnect(net, SIGNAL(destroyed()), this, 0);
+    netIter = _networkInfo.erase(netIter);
+    net->deleteLater();
+  }
+  Q_ASSERT(_networkInfo.isEmpty());
+  
   coreConnectionInfo.clear();
   sessionData.clear();
   layoutQueue.clear();
   layoutTimer->stop();
 }
 
-void Client::coreSocketStateChanged(QAbstractSocket::SocketState state) {
-  if(state == QAbstractSocket::UnconnectedState) coreSocketDisconnected();
-}
-
 void Client::recvCoreState(const QVariant &state) {
   disconnect(this, SIGNAL(recvPartialItem(uint, uint)), this, SIGNAL(coreConnectionProgress(uint, uint)));
   disconnect(socket, 0, this, 0);  // rest of communication happens through SignalProxy
@@ -380,8 +380,7 @@ void Client::updateCoreConnectionProgress() {
   }
 
   emit coreConnectionProgress(1,1);
-  emit connected(); // FIXME EgS: This caused the double backlog... but... we shouldn't be calling this whole function all the time...
-
+  emit connected();
   foreach(NetworkInfo *net, networkInfos()) {
     disconnect(net, 0, this, SLOT(updateCoreConnectionProgress()));
   }
@@ -442,8 +441,9 @@ void Client::networkConnected(uint netid) {
   //Buffer *b = buffer(id);
   //b->setActive(true);
 
-  // FIXME EgS: do we really need to call updateCoreConnectionProgress whenever a new network is connected?
-  NetworkInfo *netinfo = new NetworkInfo(netid, signalProxy(), this);
+  NetworkInfo *netinfo = new NetworkInfo(netid, this);
+  netinfo->setProxy(signalProxy());
+  
   if(!isConnected()) {
     connect(netinfo, SIGNAL(initDone()), this, SLOT(updateCoreConnectionProgress()));
     connect(netinfo, SIGNAL(ircUserInitDone()), this, SLOT(updateCoreConnectionProgress()));
index f3ac138..2f3d907 100644 (file)
@@ -115,7 +115,6 @@ private slots:
   void coreHasData();
   void coreSocketConnected();
   void coreSocketDisconnected();
-  void coreSocketStateChanged(QAbstractSocket::SocketState);
 
   void userInput(BufferInfo, QString);
 
@@ -128,11 +127,12 @@ private slots:
   void recvBacklogData(BufferInfo, QVariantList, bool);
   void updateBufferInfo(BufferInfo);
 
+  void layoutMsg();
+
+private slots:
   void bufferDestroyed();
   void networkInfoDestroyed();
 
-  void layoutMsg();
-
 private:
   Client(QObject *parent = 0);
   virtual ~Client();
index 9418764..dec566a 100644 (file)
@@ -1,4 +1,4 @@
 DEPMOD = 
 QT_MOD = network
-SRCS += global.cpp logger.cpp message.cpp settings.cpp signalproxy.cpp util.cpp synchronizer.cpp networkinfo.cpp ircuser.cpp ircchannel.cpp bufferinfo.cpp
-HDRS += global.h logger.h message.h settings.h signalproxy.h util.h synchronizer.h networkinfo.h ircuser.h ircchannel.h bufferinfo.h
+SRCS += global.cpp logger.cpp message.cpp settings.cpp signalproxy.cpp util.cpp networkinfo.cpp ircuser.cpp ircchannel.cpp bufferinfo.cpp
+HDRS += global.h logger.h message.h settings.h signalproxy.h util.h networkinfo.h ircuser.h ircchannel.h bufferinfo.h
index bc34143..fb25749 100644 (file)
@@ -35,7 +35,7 @@ IrcUser::IrcUser(const QString &hostmask, NetworkInfo *networkinfo)
     _host(hostFromMask(hostmask)),
     networkInfo(networkinfo)
 {
-  setObjectName(QString::number(networkInfo->networkId()) + "/" + IrcUser::hostmask());
+  updateObjectName();
 }
 
 IrcUser::~IrcUser() {
@@ -72,11 +72,6 @@ QStringList IrcUser::channels() const {
   return _channels.toList();
 }
 
-void IrcUser::updateObjectName() {
-  setObjectName(QString::number(networkInfo->networkId()) + "/" +  hostmask());
-  emit objectNameSet();
-}
-
 // ====================
 //  PUBLIC SLOTS:
 // ====================
@@ -84,9 +79,6 @@ void IrcUser::setUser(const QString &user) {
   if(!user.isEmpty() && _user != user) {
     _user = user;
     emit userSet(user);
-
-    setObjectName(hostmask());
-    emit objectNameSet();
   }
 }
 
@@ -94,7 +86,6 @@ void IrcUser::setHost(const QString &host) {
   if(!host.isEmpty() && _host != host) {
     _host = host;
     emit hostSet(host);
-    updateObjectName();
   }
 }
 
@@ -102,35 +93,28 @@ void IrcUser::setNick(const QString &nick) {
   if(!nick.isEmpty() && nick != _nick) {
     QString oldnick(_nick);
     _nick = nick;
-    emit nickSet(nick);
     updateObjectName();
+    emit nickSet(nick);
+  }
+}
+
+void IrcUser::updateObjectName() {
+  QString oldName(objectName());
+  setObjectName(QString::number(networkInfo->networkId()) + "/" + _nick);
+  if(!oldName.isEmpty()) {
+    emit renameObject(oldName, objectName());
   }
 }
 
+
 void IrcUser::updateHostmask(const QString &mask) {
   if(mask == hostmask())
     return;
 
   QString user = userFromMask(mask);
   QString host = hostFromMask(mask);
-
-  // we only need to check user and hostmask.
-  // nick can't have changed since we're identifying IrcUsers by nick
-
-  // we don't use setUser and setHost here.
-  // though this is unpretty code duplication this saves us one emit objectNameSet()
-  // the second one would be erroneous
-  
-  if(!user.isEmpty() && _user != user) {
-    _user = user;
-  }
-
-  if(!host.isEmpty() && _host != host) {
-    _host = host;
-  }
-
-  emit hostmaskUpdated(mask);
-  updateObjectName();
+  setUser(user);
+  setHost(host);
 }
 
 void IrcUser::joinChannel(const QString &channel) {
index 93ec9eb..1ed1c85 100644 (file)
@@ -56,8 +56,6 @@ public:
 
   QStringList channels() const;
     
-  void updateObjectName();
-                        
 public slots:  
   void setUser(const QString &user);
   void setHost(const QString &host);
@@ -92,13 +90,16 @@ signals:
   void userModeAdded(QString mode);
   void userModeRemoved(QString mode);
 
-  void objectNameSet();
+  void renameObject(QString oldname, QString newname);
   
 //   void setUsermodes(const QSet<QString> &usermodes);
 //   QSet<QString> usermodes() const;
 
   void initDone();
 
+private slots:
+  void updateObjectName();
+  
 private:
   inline bool operator==(const IrcUser &ircuser2) {
     return (_nick.toLower() == ircuser2.nick().toLower());
index 24ed8d7..8791fff 100644 (file)
@@ -20,7 +20,6 @@
 #include "networkinfo.h"
 
 #include "signalproxy.h"
-#include "synchronizer.h"
 #include "ircuser.h"
 #include "ircchannel.h"
 
@@ -31,7 +30,7 @@
 // ====================
 //  Public:
 // ====================
-NetworkInfo::NetworkInfo(const uint &networkid, SignalProxy *proxy, QObject *parent)
+NetworkInfo::NetworkInfo(const uint &networkid, QObject *parent)
   : QObject(parent),
     _networkId(networkid),
     _initialized(false),
@@ -39,10 +38,10 @@ NetworkInfo::NetworkInfo(const uint &networkid, SignalProxy *proxy, QObject *par
     _networkName(QString()),
     _currentServer(QString()),
     _prefixes(QString()),
-    _prefixModes(QString())
+    _prefixModes(QString()),
+    _proxy(NULL)
 {
   setObjectName(QString::number(networkid));
-  _synchronizer = new Synchronizer(this, proxy);
 }
 
 // I think this is unnecessary since IrcUsers have us as their daddy :)
@@ -62,8 +61,13 @@ bool NetworkInfo::initialized() const {
   return _initialized;
 }
 
-Synchronizer *NetworkInfo::synchronizer() {
-  return _synchronizer;
+SignalProxy *NetworkInfo::proxy() const {
+  return _proxy;
+}
+
+void NetworkInfo::setProxy(SignalProxy *proxy) {
+  _proxy = proxy;
+  proxy->synchronize(this);
 }
 
 bool NetworkInfo::isMyNick(const QString &nick) const {
@@ -162,7 +166,11 @@ IrcUser *NetworkInfo::newIrcUser(const QString &hostmask) {
   QString nick(nickFromMask(hostmask));
   if(!_ircUsers.contains(nick)) {
     IrcUser *ircuser = new IrcUser(hostmask, this);
-    new Synchronizer(ircuser, synchronizer()->proxy());
+    // mark IrcUser as already initialized to keep the SignalProxy from requesting initData
+    if(initialized())
+      ircuser->setInitialized();
+    _proxy->synchronize(ircuser);
+    
     connect(ircuser, SIGNAL(nickSet(QString)), this, SLOT(ircUserNickChanged(QString)));
     connect(ircuser, SIGNAL(initDone()), this, SIGNAL(ircUserInitDone()));
     connect(ircuser, SIGNAL(destroyed()), this, SLOT(ircUserDestroyed()));
@@ -186,7 +194,11 @@ QList<IrcUser *> NetworkInfo::ircUsers() const {
 IrcChannel *NetworkInfo::newIrcChannel(const QString &channelname) {
   if(!_ircChannels.contains(channelname)) {
     IrcChannel *channel = new IrcChannel(channelname, this);
-    new Synchronizer(channel, synchronizer()->proxy());
+    // mark IrcUser as already initialized to keep the SignalProxy from requesting initData
+    if(initialized())
+      channel->setInitialized();
+    _proxy->synchronize(channel);
+
     connect(channel, SIGNAL(initDone()), this, SIGNAL(ircChannelInitDone()));
     connect(channel, SIGNAL(destroyed()), this, SLOT(channelDestroyed()));
     _ircChannels[channelname] = channel;
index 6f2ab48..8be0d98 100644 (file)
@@ -29,7 +29,6 @@
 #include <QPointer>
 
 class SignalProxy;
-class Synchronizer;
 class IrcUser;
 class IrcChannel;
 
@@ -42,13 +41,15 @@ class NetworkInfo : public QObject {
   Q_PROPERTY(QString myNick READ myNick WRITE setMyNick STORED false)
 
 public:
-  NetworkInfo(const uint &networkid, SignalProxy *proxy, QObject *parent = 0);
+  NetworkInfo(const uint &networkid, QObject *parent = 0);
   //  virtual ~NetworkInfo();
 
   uint networkId() const;
   bool initialized() const;
-  Synchronizer *synchronizer();
 
+  SignalProxy *proxy() const;
+  void setProxy(SignalProxy *proxy);
+  
   bool isMyNick(const QString &nick) const;
   bool isMyNick(IrcUser *ircuser) const;
 
@@ -115,7 +116,7 @@ signals:
   void currentServerSet(const QString &currentServer);
   void myNickSet(const QString &mynick);
 
-  void supportAdded(const QString &param, const QString &value = QString());
+  void supportAdded(const QString &param, const QString &value);
   void supportRemoved(const QString &param);
   
   void ircUserAdded(QString hostmask);
@@ -143,8 +144,7 @@ private:
   //QVariantMap networkSettings;
   //QVariantMap identity;
   
-  QPointer<Synchronizer> _synchronizer;
-  
+  QPointer<SignalProxy> _proxy;
   void determinePrefixes();
 };
 
index c8f753d..b7ac968 100644 (file)
@@ -38,6 +38,9 @@
 #include <QSet>
 #include <QDebug>
 #include <QMetaMethod>
+#include <QMetaProperty>
+#include <QRegExp>
+#include "util.h"
 
 class SignalRelay: public QObject {
 
@@ -51,18 +54,23 @@ public:
 
   void attachSignal(int methodId, const QByteArray &func);
 
+  void setSynchronize(bool);
+  bool synchronize() const;
+  
   int sigCount() const;
   
 private:
   SignalProxy* proxy;
   QObject* caller;
   QMultiHash<int, QByteArray> sigNames;
+  bool _sync;
 };
 
 SignalRelay::SignalRelay(SignalProxy* parent, QObject* source)
   : QObject(parent),
     proxy(parent),
-    caller(source)
+    caller(source),
+    _sync(false)
 {
   QObject::connect(source, SIGNAL(destroyed()), parent, SLOT(detachSender()));
 }
@@ -72,7 +80,7 @@ int SignalRelay::qt_metacall(QMetaObject::Call _c, int _id, void **_a) {
   if(_id < 0)
     return _id;
   if(_c == QMetaObject::InvokeMetaMethod) {
-    if(sigNames.contains(_id)) {
+    if(sigNames.contains(_id) || synchronize()) {
       const QList<int> &argTypes = proxy->argTypes(caller, _id);
       QVariantList params;
       int n = argTypes.size();
@@ -80,15 +88,46 @@ int SignalRelay::qt_metacall(QMetaObject::Call _c, int _id, void **_a) {
         params.append(QVariant(argTypes[i], _a[i+1]));
       QMultiHash<int, QByteArray>::const_iterator funcIter = sigNames.constFind(_id);
       while(funcIter != sigNames.constEnd() && funcIter.key() == _id) {
-        proxy->call(funcIter.value(), params);
+        proxy->dispatchSignal(funcIter.value(), params);
         funcIter++;
       }
+      if(synchronize() && proxy->syncMap(caller).contains(_id)) {
+       // qDebug() << "__SYNC__ >>>"
+       //       << caller->metaObject()->className()
+       //       << caller->objectName()
+       //       << proxy->methodName(caller, _id)
+       //       << params;
+       params.prepend(QVariant(_id));
+       params.prepend(caller->objectName());
+       params.prepend(caller->metaObject()->className());
+       proxy->dispatchSignal((int)SignalProxy::Sync, params);
+      }
     }
     _id -= 1;
   }
   return _id;
 }
 
+void SignalRelay::setSynchronize(bool sync) {
+  QHash<int, int>::const_iterator iter = proxy->syncMap(caller).constBegin();
+  if(!_sync && sync) {
+    while(iter != proxy->syncMap(caller).constEnd()) {
+      QMetaObject::connect(caller, iter.key(), this, QObject::staticMetaObject.methodCount() + iter.key());
+      iter++;
+    }
+  } else if (_sync && !sync) {
+    while(iter != proxy->syncMap(caller).constEnd()) {
+      QMetaObject::disconnect(caller, iter.key(), this, QObject::staticMetaObject.methodCount() + iter.key());
+      iter++;
+    }
+  }
+  _sync = sync;
+}
+
+bool SignalRelay::synchronize() const {
+  return _sync;
+}
+
 int SignalRelay::sigCount() const {
   // only for debuging purpose
   return sigNames.count();
@@ -117,21 +156,21 @@ void SignalRelay::attachSignal(int methodId, const QByteArray &func) {
 //  SignalProxy
 // ====================
 SignalProxy::SignalProxy(QObject* parent)
-  : QObject(parent),
-    _proxyMode(Client)
+  : QObject(parent)
 {
+  setProxyMode(Client);
 }
 
 SignalProxy::SignalProxy(ProxyMode mode, QObject* parent)
-  : QObject(parent),
-    _proxyMode(mode)
+  : QObject(parent)
 {
+  setProxyMode(mode);
 }
 
 SignalProxy::SignalProxy(ProxyMode mode, QIODevice* device, QObject* parent)
-  : QObject(parent),
-    _proxyMode(mode)
+  : QObject(parent)
 {
+  setProxyMode(mode);
   addPeer(device);
 } 
 
@@ -149,13 +188,23 @@ void SignalProxy::setProxyMode(ProxyMode mode) {
     }
   }
   _proxyMode = mode;
+  if(mode == Server)
+    initServer();
+  else
+    initClient();
 }
 
-
 SignalProxy::ProxyMode SignalProxy::proxyMode() const {
   return _proxyMode;
 }
 
+void SignalProxy::initServer() {
+}
+
+void SignalProxy::initClient() {
+  attachSlot("__objectRenamed__", this, SLOT(objectRenamed(QByteArray, QString, QString)));
+}
+
 bool SignalProxy::addPeer(QIODevice* iodev) {
   if(!iodev)
     return false;
@@ -193,6 +242,25 @@ void SignalProxy::removePeerBySender() {
   removePeer(ioDev);
 }
 
+void SignalProxy::objectRenamed(QString oldname, QString newname) {
+  const QMetaObject *meta = sender()->metaObject();
+  const QByteArray className(meta->className());
+  objectRenamed(className, oldname, newname);
+
+  if(proxyMode() == Client)
+    return;
+  
+  QVariantList params;
+  params << className << oldname << newname;
+  dispatchSignal("__objectRenamed__", params);
+}
+
+void SignalProxy::objectRenamed(QByteArray classname, QString oldname, QString newname) {
+  if(_syncSlave.contains(classname) && _syncSlave[classname].contains(oldname))
+    _syncSlave[classname][newname] = _syncSlave[classname].take(oldname);
+}
+
+
 void SignalProxy::removePeer(QIODevice* iodev) {
   if(_peerByteCount.isEmpty()) {
     qWarning() << "SignalProxy: No peers in use!";
@@ -220,7 +288,7 @@ void SignalProxy::removePeer(QIODevice* iodev) {
   while(true) {
     QVariant var;
     if(readDataFromDevice(iodev, _peerByteCount[iodev], var))
-      receivePeerSignal(var);
+      receivePeerSignal(iodev, var);
     else
       break;
   }
@@ -234,49 +302,85 @@ void SignalProxy::removePeer(QIODevice* iodev) {
 }
 
 void SignalProxy::setArgTypes(QObject* obj, int methodId) {
-  QList<QByteArray> p = obj->metaObject()->method(methodId).parameterTypes();
+  const QMetaObject *meta = obj->metaObject();
+  QList<QByteArray> p = meta->method(methodId).parameterTypes();
   QList<int> argTypes;
   int ct = p.count();
   for(int i=0; i<ct; i++)
     argTypes.append(QMetaType::type(p.value(i)));
 
-  const QByteArray &className(obj->metaObject()->className());
-  Q_ASSERT(_classInfo.contains(className));
-  Q_ASSERT(!_classInfo[className]->argTypes.contains(methodId));
-  _classInfo[className]->argTypes[methodId] = argTypes;
+  Q_ASSERT(!_classInfo[meta]->argTypes.contains(methodId));
+  _classInfo[meta]->argTypes[methodId] = argTypes;
 }
 
 const QList<int> &SignalProxy::argTypes(QObject *obj, int methodId) {
-  const QByteArray &className(obj->metaObject()->className());
-  Q_ASSERT(_classInfo.contains(className));
-  if(!_classInfo[className]->argTypes.contains(methodId))
+  Q_ASSERT(_classInfo.contains(obj->metaObject()));
+  if(!_classInfo[obj->metaObject()]->argTypes.contains(methodId))
     setArgTypes(obj, methodId);
-  return _classInfo[className]->argTypes[methodId];
+  return _classInfo[obj->metaObject()]->argTypes[methodId];
 }
 
 void SignalProxy::setMethodName(QObject *obj, int methodId) {
-  const QByteArray &className(obj->metaObject()->className());
-  QByteArray method = obj->metaObject()->method(methodId).signature();
-  method = method.left(method.indexOf('('));
-
-  Q_ASSERT(_classInfo.contains(className));
-  Q_ASSERT(!_classInfo[className]->methodNames.contains(methodId));
-  _classInfo[className]->methodNames[methodId] = method;
+  const QMetaObject *meta = obj->metaObject();
+  QByteArray method(::methodName(meta->method(methodId)));
+  Q_ASSERT(!_classInfo[meta]->methodNames.contains(methodId));
+  _classInfo[meta]->methodNames[methodId] = method;
 }
 
 const QByteArray &SignalProxy::methodName(QObject *obj, int methodId) {
-  QByteArray className(obj->metaObject()->className());
-  Q_ASSERT(_classInfo.contains(className));
-  if(!_classInfo[className]->methodNames.contains(methodId))
+  Q_ASSERT(_classInfo.contains(obj->metaObject()));
+  if(!_classInfo[obj->metaObject()]->methodNames.contains(methodId))
     setMethodName(obj, methodId);
-  return _classInfo[className]->methodNames[methodId];
+  return _classInfo[obj->metaObject()]->methodNames[methodId];
+}
+
+
+void SignalProxy::setSyncMap(QObject *obj) {
+  const QMetaObject *meta = obj->metaObject();
+
+  QHash<int, int> syncMap;
+  
+  QList<int> slotIndexes;
+  for(int i = 0; i < meta->methodCount(); i++) {
+    if(meta->method(i).methodType() == QMetaMethod::Slot)
+      slotIndexes << i;
+  }
+
+  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.removeAt(slotIndexes.indexOf(matchIdx));
+      syncMap[signalIdx] = matchIdx;
+    }
+  }
+
+  Q_ASSERT(_classInfo[meta]->syncMap.isEmpty());
+  _classInfo[meta]->syncMap = syncMap;
 }
 
+const QHash<int,int> &SignalProxy::syncMap(QObject *obj) {
+  Q_ASSERT(_classInfo.contains(obj->metaObject()));
+  if(_classInfo[obj->metaObject()]->syncMap.isEmpty())
+    setSyncMap(obj);
+  return _classInfo[obj->metaObject()]->syncMap;
+}
 
 void SignalProxy::createClassInfo(QObject *obj) {
-  QByteArray className(obj->metaObject()->className());
-  if(!_classInfo.contains(className))
-    _classInfo[className] = new ClassInfo();
+  if(!_classInfo.contains(obj->metaObject()))
+    _classInfo[obj->metaObject()] = new ClassInfo();
 }
 
 bool SignalProxy::attachSignal(QObject* sender, const char* signal, const QByteArray& sigName) {
@@ -320,6 +424,62 @@ bool SignalProxy::attachSlot(const QByteArray& sigName, QObject* recv, const cha
   return true;
 }
 
+void SignalProxy::synchronize(QObject *obj) {
+  if(proxyMode() == Server)
+    return synchronizeAsMaster(obj);
+  else
+    return synchronizeAsSlave(obj);
+}
+
+void SignalProxy::synchronizeAsMaster(QObject *sender) {
+  createClassInfo(sender);
+
+  SignalRelay* relay;
+  if(_relayHash.contains(sender))
+    relay = _relayHash[sender];
+  else
+    relay = _relayHash[sender] = new SignalRelay(this, sender);
+
+  relay->setSynchronize(true);
+
+  if(sender->metaObject()->indexOfSignal(QMetaObject::normalizedSignature("renameObject(QString, QString)")) != -1)
+    connect(sender, SIGNAL(renameObject(QString, QString)), this, SLOT(objectRenamed(QString, QString)));
+
+  QByteArray className(sender->metaObject()->className());
+  _syncSlave[className][sender->objectName()] = sender;
+
+  setInitialized(sender);
+}
+
+void SignalProxy::synchronizeAsSlave(QObject *receiver) {
+  QByteArray className(receiver->metaObject()->className());
+  _syncSlave[className][receiver->objectName()] = receiver;
+  
+  createClassInfo(receiver);
+
+  requestInit(receiver);
+}
+
+void SignalProxy::setInitialized(QObject *obj) {
+  QMetaObject::invokeMethod(obj, "setInitialized");
+}
+
+bool SignalProxy::initialized(QObject *obj) {
+  bool init;
+  if(!QMetaObject::invokeMethod(obj, "initialized", Q_RETURN_ARG(bool, init)))
+    init = false;
+  return init;
+}
+
+void SignalProxy::requestInit(QObject *obj) {
+  if(proxyMode() == Server || initialized(obj))
+    return;
+
+  QVariantList params;
+  params << obj->metaObject()->className()
+        << obj->objectName();
+  dispatchSignal((int)InitRequest, params);
+}
 
 void SignalProxy::detachSender() {
   // this is a slot so we can bypass the QueuedConnection
@@ -364,49 +524,153 @@ void SignalProxy::_detachSlots(QObject* receiver) {
   }
 }
 
-void SignalProxy::call(const char*  signal, QVariant p1, QVariant p2, QVariant p3, QVariant p4, QVariant p5, QVariant p6, QVariant p7, QVariant p8, QVariant p9) {
-  QByteArray func = QMetaObject::normalizedSignature(signal);
-  QVariantList params;
-  params << p1 << p2 << p3 << p4 << p5 << p6 << p7 << p8 << p9;
-  call(func, params);
+void SignalProxy::dispatchSignal(QIODevice *receiver, const QVariant &identifier, const QVariantList &params) {
+  QVariantList packedFunc;
+  packedFunc << identifier;
+  packedFunc << params;
+  writeDataToDevice(receiver, QVariant(packedFunc));
 }
 
-void SignalProxy::call(const QByteArray &funcName, const QVariantList &params) {
+void SignalProxy::dispatchSignal(const QVariant &identifier, const QVariantList &params) {
+  // yes I know we have a little code duplication here... it's for the sake of performance
   QVariantList packedFunc;
-  packedFunc << funcName;
+  packedFunc << identifier;
   packedFunc << params;
   foreach(QIODevice* dev, _peerByteCount.keys())
     writeDataToDevice(dev, QVariant(packedFunc));
 }
 
-void SignalProxy::receivePeerSignal(const QVariant &packedFunc) {
+void SignalProxy::receivePeerSignal(QIODevice *sender, const QVariant &packedFunc) {
   QVariantList params(packedFunc.toList());
-  QByteArray funcName = params.takeFirst().toByteArray();
-  int numParams, methodId;
-  QObject* receiver;
 
+  QVariant call = params.takeFirst();
+  if(call.type() != QVariant::Int)
+    return handleSignal(call.toByteArray(), params);
+
+  switch(call.toInt()) {
+  case Sync:
+    return handleSync(params);
+  case InitRequest:
+    return handleInitRequest(sender, params);
+  case InitData:
+    return handleInitData(sender, params);
+  default:
+    qWarning() << "received undefined CallType" << call.toInt();
+    return;
+  }
+}
+
+void SignalProxy::handleSync(QVariantList params) {
+  if(params.count() < 3) {
+    qWarning() << "received invalid Sync call" << params;
+    return;
+  }
+  
+  QByteArray className =params.takeFirst().toByteArray();
+  QString objectName = params.takeFirst().toString();
+  int signalId = params.takeFirst().toInt();
+
+  if(!_syncSlave.contains(className) || !_syncSlave[className].contains(objectName)) {
+    qWarning() << "no registered receiver:" << className << objectName << "for Sync call" << signalId << params;
+    return;
+  }
+
+  QObject *receiver = _syncSlave[className][objectName];
+  if(!syncMap(receiver).contains(signalId)) {
+    qWarning() << "received Sync Call with invalid SignalId" << className << objectName << signalId;
+  }
+  int slotId = syncMap(receiver)[signalId];
+  if(!invokeSlot(receiver, slotId, params))
+    qWarning("SignalProxy::handleSync(): invokeMethod for \"%s\" failed ", methodName(receiver, slotId).constData());
+}
+
+void SignalProxy::handleInitRequest(QIODevice *sender, const QVariantList &params) {
+  if(params.count() != 2) {
+    qWarning() << "SignalProxy::handleInitRequest() received initRequest with invalid param Count:"
+              << params;
+    return;
+  }
+  
+  QByteArray className(params[0].toByteArray());
+  QString objectName(params[1].toString());
+
+  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];
+
+  QVariantList params_;
+  params_ << obj->metaObject()->className()
+         << obj->objectName()
+         << initData(obj);
+
+  dispatchSignal(sender, (int)InitData, params_);
+}
+
+void SignalProxy::handleInitData(QIODevice *sender, const QVariantList &params) {
+  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 &params) {
+  QObject* receiver;
+  int methodId;
   SlotHash::const_iterator slot = _attachedSlots.constFind(funcName);
   while(slot != _attachedSlots.constEnd() && slot.key() == funcName) {
     receiver = (*slot).first;
     methodId = (*slot).second;
-    numParams = argTypes(receiver, methodId).count();
-    QGenericArgument args[9];
-    for(int i = 0; i < numParams; i++)
-      args[i] = QGenericArgument(params[i].typeName(), params[i].constData());
-    if(!QMetaObject::invokeMethod(receiver, methodName(receiver, methodId),
-                                 args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8])) {
-      qWarning("SignalProxy::receivePeerSignal(): invokeMethod for \"%s\" failed ", methodName(receiver, methodId).constData());
-    }
+    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 &params) {
+  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(var);
+    receivePeerSignal(ioDev, var);
 }
 
 void SignalProxy::writeDataToDevice(QIODevice *dev, const QVariant &item) {
@@ -440,6 +704,99 @@ bool SignalProxy::readDataFromDevice(QIODevice *dev, quint32 &blockSize, QVarian
   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)
@@ -451,10 +808,17 @@ void SignalProxy::dumpProxyStats() {
   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() << "       number of Signals:" << sigCount;
   qDebug() << "          attached Slots:" << _attachedSlots.count();
+  qDebug() << " number of synced Slaves:" << slaveCount;
   qDebug() << "number of Classes cached:" << _classInfo.count();
 }
+
+
index ebc4ae7..5001060 100644 (file)
 #include <QList>
 #include <QHash>
 #include <QVariant>
+#include <QVariantMap>
 #include <QPair>
 #include <QString>
 #include <QByteArray>
 
 class SignalRelay;
+class QMetaObject;
 
 class SignalProxy : public QObject {
   Q_OBJECT
@@ -49,9 +51,15 @@ public:
     Client
   };
 
-  SignalProxy(QObject* parent);
-  SignalProxy(ProxyMode mode, QObject* parent);
-  SignalProxy(ProxyMode mode, QIODevice* device, QObject* parent);
+  enum RequestType {
+    Sync = 0,
+    InitRequest,
+    InitData
+  };
+
+  SignalProxy(QObject *parent);
+  SignalProxy(ProxyMode mode, QObject *parent);
+  SignalProxy(ProxyMode mode, QIODevice *device, QObject *parent);
   virtual ~SignalProxy();
 
   void setProxyMode(ProxyMode mode);
@@ -60,29 +68,36 @@ public:
   bool addPeer(QIODevice *iodev);
   void removePeer(QIODevice *iodev = 0);
 
-  bool attachSignal(QObject* sender, const char* signal, const QByteArray& sigName = QByteArray());
-  bool attachSlot(const QByteArray& sigName, QObject* recv, const char* slot);
+  bool attachSignal(QObject *sender, const char *signal, const QByteArray& sigName = QByteArray());
+  bool attachSlot(const QByteArray& sigName, QObject *recv, const char *slot);
+
+  void synchronize(QObject *obj);
+  void synchronizeAsMaster(QObject *obj);
+  void synchronizeAsSlave(QObject *obj);
 
+  void setInitialized(QObject *obj);
+  bool initialized(QObject *obj);
+  void requestInit(QObject *obj);
+  
   void detachObject(QObject *obj);
   void detachSignals(QObject *sender);
   void detachSlots(QObject *receiver);
   
-  void call(const char *signal , QVariant p1, QVariant p2, QVariant p3, QVariant p4,
-           QVariant p5, QVariant p6, QVariant p7, QVariant p8, QVariant p9);
-  void call(const QByteArray &funcName, const QVariantList &params);
-
   static void writeDataToDevice(QIODevice *dev, const QVariant &item);
   static bool readDataFromDevice(QIODevice *dev, quint32 &blockSize, QVariant &item);
+
+  static QString methodBaseName(const QMetaMethod &method);
   
-  const QList<int> &argTypes(QObject* obj, int methodId);
-  const QByteArray &methodName(QObject* obj, int methodId);
-  
+  const QList<int> &argTypes(QObject *obj, int methodId);
+  const QByteArray &methodName(QObject *obj, int methodId);
+  const QHash<int, int> &syncMap(QObject *obj);
+
   typedef QHash<int, QList<int> > ArgHash;
   typedef QHash<int, QByteArray> MethodNameHash;
   struct ClassInfo {
     ArgHash argTypes;
     MethodNameHash methodNames;
-    // QHash<int, int> syncMap
+    QHash<int, int> syncMap;
   };
 
   void dumpProxyStats();
@@ -91,24 +106,45 @@ private slots:
   void dataAvailable();
   void detachSender();
   void removePeerBySender();
+  void objectRenamed(QString oldname, QString newname);
+  void objectRenamed(QByteArray classname, QString oldname, QString newname);
 
 signals:
-  void peerRemoved(QIODeviceobj);
+  void peerRemoved(QIODevice *obj);
   void connected();
   void disconnected();
   
 private:
+  void initServer();
+  void initClient();
+  
   void createClassInfo(QObject *obj);
-  void setArgTypes(QObject* obj, int methodId);
-  void setMethodName(QObject* obj, int methodId);
+  void setArgTypes(QObject *obj, int methodId);
+  void setMethodName(QObject *obj, int methodId);
+  void setSyncMap(QObject *obj);
 
-  void receivePeerSignal(const QVariant &packedFunc);
+  bool methodsMatch(const QMetaMethod &signal, const QMetaMethod &slot) const;
+
+  void dispatchSignal(QIODevice *receiver, const QVariant &identifier, const QVariantList &params);
+  void dispatchSignal(const QVariant &identifier, const QVariantList &params);
+  
+  void receivePeerSignal(QIODevice *sender, const QVariant &packedFunc);
+  void handleSync(QVariantList params);
+  void handleInitRequest(QIODevice *sender, const QVariantList &params);
+  void handleInitData(QIODevice *sender, const QVariantList &params);
+  void handleSignal(const QByteArray &funcName, const QVariantList &params);
+
+  bool invokeSlot(QObject *receiver, int methodId, const QVariantList &params);
+
+  QVariantMap initData(QObject *obj) const;
+  void setInitData(QObject *obj, const QVariantMap &properties);
+  bool setInitValue(QObject *obj, const QString &property, const QVariant &value);
 
   void _detachSignals(QObject *sender);
   void _detachSlots(QObject *receiver);
 
   // containg a list of argtypes for fast access
-  QHash<QByteArray, ClassInfo*> _classInfo;
+  QHash<const QMetaObject *, ClassInfo*> _classInfo;
 
   // we use one SignalRelay per QObject
   QHash<QObject*, SignalRelay *> _relayHash;
@@ -117,15 +153,17 @@ private:
   typedef QPair<QObject*, int> MethodId;
   typedef QMultiHash<QByteArray, MethodId> SlotHash;
   SlotHash _attachedSlots;
-  
+
+  // slaves for sync
+  typedef QHash<QString, QObject *> ObjectId;
+  QHash<QByteArray, ObjectId> _syncSlave;
 
   // Hash of used QIODevices
   QHash<QIODevice*, quint32> _peerByteCount;
 
   ProxyMode _proxyMode;
-};
-
-
 
+  friend class SignalRelay;
+};
 
 #endif
diff --git a/src/common/synchronizer.cpp b/src/common/synchronizer.cpp
deleted file mode 100644 (file)
index e2bed33..0000000
+++ /dev/null
@@ -1,345 +0,0 @@
-/***************************************************************************
- *   Copyright (C) 2005-07 by The Quassel Team                             *
- *   devel@quassel-irc.org                                                 *
- *                                                                         *
- *   This program is free software; you can redistribute it and/or modify  *
- *   it under the terms of the GNU General Public License as published by  *
- *   the Free Software Foundation; either version 2 of the License, or     *
- *   (at your option) any later version.                                   *
- *                                                                         *
- *   This program is distributed in the hope that it will be useful,       *
- *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
- *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
- *   GNU General Public License for more details.                          *
- *                                                                         *
- *   You should have received a copy of the GNU General Public License     *
- *   along with this program; if not, write to the                         *
- *   Free Software Foundation, Inc.,                                       *
- *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
- ***************************************************************************/
-#include "synchronizer.h"
-
-#include <QString>
-#include <QRegExp>
-#include <QMetaProperty>
-#include <QMetaMethod>
-
-#include "util.h"
-#include "signalproxy.h"
-
-#include <QByteArray>
-#include <QDebug>
-
-// ====================
-//  Public:
-// ====================
-Synchronizer::Synchronizer(QObject *parent, SignalProxy *signalproxy)
-  : QObject(parent),
-    _initialized(false),
-    _signalproxy(signalproxy)
-{
-  attach();
-  if(!getMethodByName("objectNameSet()").isEmpty())
-    connect(parent,SIGNAL(objectNameSet()), this, SLOT(parentChangedName()));
-}
-
-bool Synchronizer::initialized() const {
-  return _initialized;
-}
-
-SignalProxy *Synchronizer::proxy() const {
-  return _signalproxy;
-}
-
-QVariantMap Synchronizer::initData() const {
-  QVariantMap properties;
-  
-  // we collect data from properties
-  foreach(QMetaProperty property, parentProperties()) {
-    QString name = QString(property.name());
-    QVariant value = property.read(parent());
-    properties[name] = value;
-    // qDebug() << ">>> SYNC:" << name << value;
-  }
-
-  // ...as well as methods, which have names starting with "init"
-  foreach(QMetaMethod method, parentSlots()) {
-    QString methodname = QString(method.signature()).section("(", 0, 0);
-    if(methodname.startsWith("initSet") ||
-       !methodname.startsWith("init"))
-      continue;
-
-    QVariant value = QVariant(QVariant::nameToType(method.typeName()));
-    QGenericReturnArgument genericvalue = QGenericReturnArgument(method.typeName(), &value);
-    QMetaObject::invokeMethod(parent(), methodname.toAscii(), genericvalue);
-
-    properties[methodBaseName(method)] = value;
-    // qDebug() << ">>> SYNC:" << methodBaseName(method) << value;
-  }
-
-  // properties["Payload"] = QByteArray(10000000, 'a');  // for testing purposes
-  return properties;
-}
-
-void Synchronizer::setInitData(const QVariantMap &properties) {
-  if(initialized())
-    return;
-
-  const QMetaObject *metaobject = parent()->metaObject();  
-  QMapIterator<QString, QVariant> iterator(properties);
-  while(iterator.hasNext()) {
-    iterator.next();
-    QString name = iterator.key();
-    int propertyIndex = metaobject->indexOfProperty(name.toAscii());
-    if(propertyIndex == -1) {
-      setInitValue(name, iterator.value());
-    } else {
-      if((metaobject->property(propertyIndex)).isWritable())
-       parent()->setProperty(name.toAscii(), iterator.value());
-      else
-       setInitValue(name, iterator.value());   
-    }
-    // qDebug() << "<<< SYNC:" << name << iterator.value();
-  }
-
-  _initialized = true;
-  emit initDone();
-}
-
-// ====================
-//  Public Slots
-// ====================
-void Synchronizer::synchronizeClients() const {
-  emit sendInitData(initData());
-}
-
-void Synchronizer::recvInitData(QVariantMap properties) {
-  proxy()->detachObject(this);
-  setInitData(properties);
-}
-
-void Synchronizer::parentChangedName() {
-  proxy()->detachObject(parent());
-  proxy()->detachObject(this);
-  attach();
-}
-
-// ====================
-//  Private
-// ====================
-QString Synchronizer::signalPrefix() const {
-  return QString(parent()->metaObject()->className()) + "_" + QString(parent()->objectName()) + "_";
-}
-
-QString Synchronizer::initSignal() const {
-  return QString(metaObject()->className())
-    + "_" + QString(parent()->metaObject()->className())
-    + "_" + QString(parent()->objectName())
-    + "_" + QString(SIGNAL(sendInitData(QVariantMap)));
-}
-
-QString Synchronizer::requestSyncSignal() const {
-  return QString(metaObject()->className())
-    + "_" + QString(parent()->metaObject()->className())
-    + "_" + QString(parent()->objectName())
-    + "_" + QString(SIGNAL(requestSync()));
-}
-
-QString Synchronizer::methodBaseName(const QMetaMethod &method) const {
-  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;
-}
-
-bool Synchronizer::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;
-
-  const QMetaObject *metaobject = parent()->metaObject();
-
-  // are the signatures compatible?
-  if(! metaobject->checkConnectArgs(signal.signature(), slot.signature()))
-    return false;
-
-  // we take an educated guess if the signals and slots match
-  QString signalsuffix = QString(signal.signature()).section("(", 0, 0);
-  signalsuffix = signalsuffix.mid(signalsuffix.lastIndexOf(QRegExp("[A-Z]"))).toLower();
-    
-  QString slotprefix = QString(slot.signature()).section("(", 0, 0);
-  slotprefix = slotprefix.left(slotprefix.indexOf(QRegExp("[A-Z]"))).toLower();
-
-  uint sizediff;
-  if(signalsuffix.size() < slotprefix.size())
-    sizediff = slotprefix.size() - signalsuffix.size();
-  else
-    sizediff = signalsuffix.size() - slotprefix.size();
-
-  int ratio = editingDistance(slotprefix, signalsuffix) - sizediff;
-
-  return (ratio < 2);
-}
-
-QList<QMetaProperty> Synchronizer::parentProperties() const {
-  QList<QMetaProperty> _properties;
-
-  const QMetaObject *metaobject = parent()->metaObject();
-  for(int i = metaobject->propertyOffset(); i < metaobject->propertyCount(); i++) {
-    _properties << metaobject->property(i);
-  }
-  
-  return _properties;
-}
-
-QList<QMetaMethod> Synchronizer::parentSlots() const {
-  QList<QMetaMethod> _slots;
-
-  const QMetaObject *metaobject = parent()->metaObject();
-  for(int i = metaobject->methodOffset(); i < metaobject->methodCount(); i++) {
-    QMetaMethod method = metaobject->method(i);
-    if(method.methodType() == QMetaMethod::Slot)
-      _slots << method;
-  }
-
-  return _slots;
-}
-
-
-QList<QMetaMethod> Synchronizer::parentSignals() const {
-  QList<QMetaMethod> _signals;
-
-  const QMetaObject *metaobject = parent()->metaObject();
-  for(int i = metaobject->methodOffset(); i < metaobject->methodCount(); i++) {
-    QMetaMethod method = metaobject->method(i);
-    if(method.methodType() == QMetaMethod::Signal)
-      _signals << method;
-  }
-  
-  return _signals;
-}
-
-QList<QMetaMethod> Synchronizer::getMethodByName(const QString &methodname) {
-  QList<QMetaMethod> _methods;
-  
-  const QMetaObject* metaobject = parent()->metaObject();
-  for(int i = metaobject->methodOffset(); i < metaobject->methodCount(); i++) {
-    if(QString(metaobject->method(i).signature()).startsWith(methodname))
-      _methods << metaobject->method(i);
-  }
-
-  return _methods;
-}
-
-void Synchronizer::attach() {
-  if(proxy()->proxyMode() == SignalProxy::Server)
-    attachAsMaster();
-  else
-    attachAsSlave();
-}
-void Synchronizer::attachAsSlave() {
-  QList<QMetaMethod> signals_ = parentSignals();
-  
-  foreach(QMetaMethod slot, parentSlots()) {
-    if(signals_.empty())
-      break;
-    
-    for(int i = 0; i < signals_.count(); i++) {
-      QMetaMethod signal = signals_[i];
-      if(!methodsMatch(signal, slot))
-       continue;
-
-      // we could simply put a "1" in front of the normalized signature
-      // but to guarantee future compatibility we construct a dummy signal
-      // and replace the known the fake signature by ours...
-      QString dummySlot = QString(SIGNAL(dummy()));
-      QString proxySignal = signalPrefix() + QString(signal.signature());
-      QString slotsignature = dummySlot.replace("dummy()", QString(slot.signature()));
-
-      // qDebug() << "attachSlot:" << proxySignal << slotsignature;
-      proxy()->attachSlot(proxySignal.toAscii(), parent(), slotsignature.toAscii());
-      signals_.removeAt(i);
-      break;
-    }
-  }
-
-  if(!getMethodByName("setInitialized()").isEmpty())
-    connect(this, SIGNAL(initDone()), parent(), SLOT(setInitialized()));
-
-  if(!initialized()) {
-    // and then we connect ourself, so we can receive init data
-    // qDebug() << "attachSlot:" << initSignal() << "recvInitData(QVariantMap)";
-    // qDebug() << "attachSignal:" << "requestSync()" << requestSyncSignal();
-    proxy()->attachSlot(initSignal().toAscii(), this, SLOT(recvInitData(QVariantMap)));
-    proxy()->attachSignal(this, SIGNAL(requestSync()), requestSyncSignal().toAscii());
-
-    emit requestSync();
-  }
-}
-
-void Synchronizer::attachAsMaster() {
-  QList<QMetaMethod> slots_ = parentSlots();
-  
-  foreach(QMetaMethod signal, parentSignals()) {
-    if(slots_.isEmpty())
-      break;
-
-    // we don't attach all signals, just the ones that have a maching counterpart
-    for(int i = 0; i < slots_.count(); i++) {
-      QMetaMethod slot = slots_[i];
-      if(!methodsMatch(signal, slot))
-       continue;
-      
-      // we could simply put a "2" in front of the normalized signature
-      // but to guarantee future compatibility we construct a dummy signal
-      // and replace the known the fake signature by ours...
-      QString dummySignal = QString(SIGNAL(dummy()));
-      QString proxySignal = signalPrefix() + QString(signal.signature());
-      QString signalsignature = dummySignal.replace("dummy()", QString(signal.signature()));
-    
-      // qDebug() << "attachSignal:" << signalsignature << proxySignal;
-      proxy()->attachSignal(parent(), signalsignature.toAscii(), proxySignal.toAscii());
-      slots_.removeAt(i);
-      break;
-    }
-  }
-  
-  // and then we connect ourself, so we can initialize slaves
-  // qDebug() << "attachSignal:" << "sendInitData(QVariantMap)" << initSignal();
-  // qDebug() << "attachSlot:" << "synchronizeClients()" << requestSyncSignal();
-  proxy()->attachSignal(this, SIGNAL(sendInitData(QVariantMap)), initSignal().toAscii());
-  proxy()->attachSlot(requestSyncSignal().toAscii(), this, SLOT(synchronizeClients()));
-}
-
-bool Synchronizer::setInitValue(const QString &property, const QVariant &value) {
-  QString handlername = QString("initSet") + property;
-  handlername[7] = handlername[7].toUpper();
-
-  //determine param type
-  QByteArray paramtype;
-  foreach(QMetaMethod method, getMethodByName(handlername)) {
-    if(method.parameterTypes().size() == 1) {
-      paramtype = method.parameterTypes()[0];
-      break;
-    }
-  }
-
-  if(paramtype.isNull())
-    return false;
-
-  QGenericArgument param = QGenericArgument(paramtype, &value);
-  return QMetaObject::invokeMethod(parent(), handlername.toAscii(), param);
-}
-
-
diff --git a/src/common/synchronizer.h b/src/common/synchronizer.h
deleted file mode 100644 (file)
index fe407f8..0000000
+++ /dev/null
@@ -1,79 +0,0 @@
-/***************************************************************************
- *   Copyright (C) 2005/06 by The Quassel Team                             *
- *   devel@quassel-irc.org                                                 *
- *                                                                         *
- *   This program is free software; you can redistribute it and/or modify  *
- *   it under the terms of the GNU General Public License as published by  *
- *   the Free Software Foundation; either version 2 of the License, or     *
- *   (at your option) any later version.                                   *
- *                                                                         *
- *   This program is distributed in the hope that it will be useful,       *
- *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
- *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
- *   GNU General Public License for more details.                          *
- *                                                                         *
- *   You should have received a copy of the GNU General Public License     *
- *   along with this program; if not, write to the                         *
- *   Free Software Foundation, Inc.,                                       *
- *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
- ***************************************************************************/
-
-#ifndef _SYNCHRONIZER_H_
-#define _SYNCHRONIZER_H_
-
-class SignalProxy;
-
-#include <QObject>
-#include <QList>
-#include <QString>
-#include <QVariantMap>
-#include <QMetaMethod>
-#include <QPointer>
-
-class Synchronizer : public QObject {
-  Q_OBJECT
-
-public:
-  Synchronizer(QObject *parent, SignalProxy *signalproxy);
-  
-  bool initialized() const;
-  SignalProxy *proxy() const;
-
-  QVariantMap initData() const;
-  void setInitData(const QVariantMap &properties);
-
-public slots:
-  void synchronizeClients() const;
-  void recvInitData(QVariantMap properties);
-  void parentChangedName();
-  
-signals:
-  void requestSync() const;
-  void sendInitData(QVariantMap properties) const;
-  void initDone();
-  
-private:
-  bool _initialized;
-  QPointer<SignalProxy> _signalproxy;
-  
-  QString signalPrefix() const;
-  QString initSignal() const;
-  QString requestSyncSignal() const;
-  
-  QString methodBaseName(const QMetaMethod &method) const;
-  bool methodsMatch(const QMetaMethod &signal, const QMetaMethod &slot) const;
-
-  QList<QMetaProperty> parentProperties() const;
-  QList<QMetaMethod> parentSlots() const;
-  QList<QMetaMethod> parentSignals() const;
-  
-  QList<QMetaMethod> getMethodByName(const QString &methodname);
-  
-  void attach();
-  void attachAsSlave();
-  void attachAsMaster();
-                         
-  bool setInitValue(const QString &property, const QVariant &value);
-};
-
-#endif
index 2fdeead..5cbfc86 100644 (file)
@@ -22,6 +22,8 @@
 #include <QDebug>
 #include <QTextCodec>
 
+class QMetaMethod;
+
 QString nickFromMask(QString mask) {
   return mask.section('!', 0, 0);
 }
@@ -133,3 +135,8 @@ uint editingDistance(const QString &s1, const QString &s2) {
   }
   return matrix[n-1][m-1];
 }
+
+QByteArray methodName(const QMetaMethod &method) {
+  QByteArray sig(method.signature());
+  return sig.left(sig.indexOf("("));
+}
index 0179723..695955b 100644 (file)
@@ -24,6 +24,7 @@
 #include <QIODevice>
 #include <QVariant>
 #include <QString>
+#include <QMetaMethod>
 
 QString nickFromMask(QString mask);
 QString userFromMask(QString mask);
@@ -56,5 +57,6 @@ bool readDataFromDevice(QIODevice *, quint32 &, QVariant &);
 
 uint editingDistance(const QString &s1, const QString &s2);
 
+QByteArray methodName(const QMetaMethod &method);
 
 #endif
index 0accebb..bf542c2 100644 (file)
@@ -24,7 +24,6 @@
 #include "signalproxy.h"
 #include "storage.h"
 
-#include "synchronizer.h"
 #include "networkinfo.h"
 #include "ircuser.h"
 #include "ircchannel.h"
index 67cc632..8e096f8 100644 (file)
@@ -28,7 +28,6 @@
 #include "coresession.h"
 
 #include "networkinfo.h"
-#include "synchronizer.h"
 
 #include "ircserverhandler.h"
 #include "userinputhandler.h"
@@ -40,9 +39,10 @@ Server::Server(UserId uid, uint networkId, QString net)
     _ircServerHandler(new IrcServerHandler(this)),
     _userInputHandler(new UserInputHandler(this)),
     _ctcpHandler(new CtcpHandler(this)),
-    _networkInfo(new NetworkInfo(networkId, coreSession()->signalProxy(), this))
+    _networkInfo(new NetworkInfo(networkId, this))
 {
   networkInfo()->setNetworkName(net);
+  networkInfo()->setProxy(coreSession()->signalProxy());
 }
 
 Server::~Server() {