- improvements to the SignalProxy: return value of remotely called slots are return to the sending peer
- syncable objects can reside in libclient or libcore
- backlog is now handled by the BacklogManager
#include "bufferinfo.h"
#include "buffersyncer.h"
+#include "clientbacklogmanager.h"
#include "global.h"
#include "identity.h"
#include "ircchannel.h"
_networkModel(0),
_bufferModel(0),
_bufferSyncer(0),
+ _backlogManager(new ClientBacklogManager(this)),
_connectedToCore(false),
_syncedToCore(false)
{
_monitorBuffer = new Buffer(BufferInfo(), this);
+ connect(_backlogManager, SIGNAL(backlog(BufferId, const QVariantList &)),
+ this, SLOT(receiveBacklog(BufferId, const QVariantList &)));
}
Client::~Client() {
p->attachSlot(SIGNAL(displayMsg(const Message &)), this, SLOT(recvMessage(const Message &)));
p->attachSlot(SIGNAL(displayStatusMsg(QString, QString)), this, SLOT(recvStatusMsg(QString, QString)));
- p->attachSlot(SIGNAL(backlogData(BufferInfo, const QVariantList &, bool)), this, SLOT(recvBacklogData(BufferInfo, const QVariantList &, bool)));
p->attachSlot(SIGNAL(bufferInfoUpdated(BufferInfo)), this, SLOT(updateBufferInfo(BufferInfo)));
p->attachSignal(this, SIGNAL(sendInput(BufferInfo, QString)));
p->attachSignal(this, SIGNAL(requestNetworkStates()));
connect(bufferSyncer(), SIGNAL(bufferRenamed(BufferId, QString)), this, SLOT(bufferRenamed(BufferId, QString)));
signalProxy()->synchronize(bufferSyncer());
+ // attach backlog manager
+ signalProxy()->synchronize(backlogManager());
+
_syncedToCore = true;
emit connected();
emit coreConnectionStateChanged(true);
//recvMessage(net, Message::server("", QString("[STATUS] %1").arg(msg)));
}
-void Client::recvBacklogData(BufferInfo id, QVariantList msgs, bool /*done*/) {
- Buffer *b = buffer(id);
- if(!b) {
- qWarning() << "Client::recvBacklogData(): received Backlog for unknown Buffer:" << id;
+void Client::receiveBacklog(BufferId bufferId, const QVariantList &msgs) {
+ Buffer *buffer_ = buffer(bufferId);
+ if(!buffer_) {
+ qWarning() << "Client::recvBacklogData(): received Backlog for unknown Buffer:" << bufferId;
return;
}
-
- foreach(QVariant v, msgs) {
- Message msg = v.value<Message>();
- checkForHighlight(msg);
- b->prependMsg(msg);
- //networkModel()->updateBufferActivity(msg);
- if(!layoutQueue.contains(b)) layoutQueue.append(b);
+
+ if(msgs.isEmpty())
+ return; // no work to be done...
+
+ QVariantList::const_iterator msgIter = msgs.constBegin();
+ QVariantList::const_iterator msgIterEnd = msgs.constEnd();
+ Message msg;
+ while(msgIter != msgIterEnd) {
+ msg = (*msgIter).value<Message>();
+ buffer_->prependMsg(msg);
+ msgIter++;
+ }
+
+ if(!layoutQueue.contains(buffer_))
+ layoutQueue.append(buffer_);
+
+ if(!layoutTimer->isActive()) {
+ layoutTimer->start();
}
- if(layoutQueue.count() && !layoutTimer->isActive()) layoutTimer->start();
}
void Client::layoutMsg() {
- if(layoutQueue.count()) {
- Buffer *b = layoutQueue.takeFirst(); // TODO make this the current buffer
- if(b->layoutMsg())
- layoutQueue.append(b); // Buffer has more messages in its queue --> Round Robin
+ if(layoutQueue.isEmpty()) {
+ layoutTimer->stop();
+ return;
}
- if(!layoutQueue.count())
+ Buffer *buffer = layoutQueue.takeFirst();
+ if(buffer->layoutMsg()) {
+ layoutQueue.append(buffer); // Buffer has more messages in its queue --> Round Robin
+ return;
+ }
+
+ if(layoutQueue.isEmpty())
layoutTimer->stop();
}
class NetworkModel;
class BufferModel;
class BufferSyncer;
+class ClientBacklogManager;
class IrcUser;
class IrcChannel;
class SignalProxy;
static inline BufferModel *bufferModel() { return instance()->_bufferModel; }
static inline SignalProxy *signalProxy() { return instance()->_signalProxy; }
+ static inline ClientBacklogManager *backlogManager() { return instance()->_backlogManager; }
+
static AccountId currentCoreAccount();
static AbstractUiMsg *layoutMsg(const Message &);
void recvMessage(const Message &message);
void recvStatusMsg(QString network, QString message);
- void recvBacklogData(BufferInfo, QVariantList, bool);
+ void receiveBacklog(BufferId bufferId, const QVariantList &msgs);
void updateBufferInfo(BufferInfo);
void updateLastSeenMsg(BufferId id, const MsgId &msgId);
NetworkModel * _networkModel;
BufferModel * _bufferModel;
BufferSyncer * _bufferSyncer;
+ ClientBacklogManager *_backlogManager;
ClientMode clientMode;
DEPMOD = common
QT_MOD = core network gui
-SRCS += buffer.cpp buffersettings.cpp treemodel.cpp networkmodel.cpp buffermodel.cpp client.cpp clientsettings.cpp clientsyncer.cpp \
+SRCS += buffer.cpp buffersettings.cpp clientbacklogmanager.cpp treemodel.cpp networkmodel.cpp buffermodel.cpp client.cpp clientsettings.cpp clientsyncer.cpp \
mappedselectionmodel.cpp selectionmodelsynchronizer.cpp
-HDRS += buffer.h buffersettings.h treemodel.h networkmodel.h buffermodel.h client.h clientsettings.h clientsyncer.h quasselui.h \
+HDRS += buffer.h buffersettings.h clientbacklogmanager.h treemodel.h networkmodel.h buffermodel.h client.h clientsettings.h clientsyncer.h quasselui.h \
mappedselectionmodel.h selectionmodelsynchronizer.h
--- /dev/null
+/***************************************************************************
+ * Copyright (C) 2005-08 by the Quassel IRC 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) version 3. *
+ * *
+ * 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 "clientbacklogmanager.h"
+#include "client.h"
+
+#include <QDebug>
+
+ClientBacklogManager::ClientBacklogManager(QObject *parent)
+ : BacklogManager(parent)
+{
+}
+
+void ClientBacklogManager::receiveBacklog(BufferId bufferId, int lastMsgs, int offset, QVariantList msgs) {
+ Q_UNUSED(lastMsgs)
+ Q_UNUSED(offset)
+ emit backlog(bufferId, msgs);
+}
--- /dev/null
+/***************************************************************************
+ * Copyright (C) 2005-08 by the Quassel IRC 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) version 3. *
+ * *
+ * 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 CLIENTBACKLOGMANAGER_H
+#define CLIENTBACKLOGMANAGER_H
+
+#include "backlogmanager.h"
+
+class ClientBacklogManager : public BacklogManager {
+ Q_OBJECT
+
+public:
+ ClientBacklogManager(QObject *parent = 0);
+
+ virtual const QMetaObject *syncMetaObject() const { return &BacklogManager::staticMetaObject; }
+
+public slots:
+ virtual void receiveBacklog(BufferId bufferId, int lastMsgs, int offset, QVariantList msgs);
+
+signals:
+ void backlog(BufferId bufferId, const QVariantList &msgs);
+};
+
+#endif // CLIENTBACKLOGMANAGER_H
--- /dev/null
+/***************************************************************************
+ * Copyright (C) 2005-08 by the Quassel IRC 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) version 3. *
+ * *
+ * 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 "backlogmanager.h"
+
+#include <QDebug>
+
+BacklogManager::BacklogManager(QObject *parent)
+ : SyncableObject(parent)
+{
+}
+
+QVariantList BacklogManager::requestBacklog(BufferId bufferId, int lastMsgs, int offset) {
+ emit backlogRequested(bufferId, lastMsgs, offset);
+ return QVariantList();
+}
--- /dev/null
+/***************************************************************************
+ * Copyright (C) 2005-08 by the Quassel IRC 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) version 3. *
+ * *
+ * 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 BACKLOGMANAGER_H
+#define BACKLOGMANAGER_H
+
+#include "syncableobject.h"
+#include "types.h"
+
+class BacklogManager : public SyncableObject {
+ Q_OBJECT
+
+public:
+ BacklogManager(QObject *parent = 0);
+
+public slots:
+ virtual QVariantList requestBacklog(BufferId bufferId, int lastMsgs = -1, int offset = -1);
+ virtual void receiveBacklog(BufferId, int, int, QVariantList) {};
+
+signals:
+ void backlogRequested(BufferId, int, int);
+
+};
+
+#endif // BACKLOGMANAGER_H
DEPMOD =
QT_MOD = network
-SRCS += bufferinfo.cpp buffersyncer.cpp global.cpp identity.cpp logger.cpp message.cpp settings.cpp signalproxy.cpp syncableobject.cpp \
+SRCS += backlogmanager.cpp bufferinfo.cpp buffersyncer.cpp global.cpp identity.cpp logger.cpp message.cpp settings.cpp signalproxy.cpp syncableobject.cpp \
util.cpp network.cpp ircuser.cpp ircchannel.cpp
-HDRS += bufferinfo.h buffersyncer.h global.h identity.h logger.h message.h settings.h signalproxy.h syncableobject.h \
+HDRS += backlogmanager.h bufferinfo.h buffersyncer.h global.h identity.h logger.h message.h settings.h signalproxy.h syncableobject.h \
util.h network.h ircuser.h ircchannel.h types.h
// dispatch Sync Signal if necessary
QByteArray signature(caller->metaObject()->method(_id).signature());
- if(synchronize() && proxy->syncMap(qobject_cast<SyncableObject *>(caller)).contains(signature)) {
+ SyncableObject *syncObject = qobject_cast<SyncableObject *>(caller);
+ if(synchronize() && proxy->syncMap(syncObject).contains(signature)) {
//qDebug() << "__SYNC__ >>>"
// << caller->metaObject()->className()
// << caller->objectName()
// << params;
// params.prepend(QVariant(_id));
params.prepend(signature);
- params.prepend(caller->objectName());
- params.prepend(caller->metaObject()->className());
+ params.prepend(syncObject->objectName());
+ params.prepend(syncObject->syncMetaObject()->className());
proxy->dispatchSignal(SignalProxy::Sync, params);
}
}
}
void SignalRelay::setSynchronize(bool sync) {
- const QMetaObject *meta = caller->metaObject();
+ SyncableObject *syncObject = qobject_cast<SyncableObject *>(caller);
+ if(!syncObject)
+ return;
+
+ const QMetaObject *meta = syncObject->syncMetaObject();
if(!_sync && sync) {
// enable Sync
for(int i = 0; i < meta->methodCount(); i++ ) {
}
bool SignalRelay::isSyncMethod(int i) {
- QByteArray signature = caller->metaObject()->method(i).signature();
- if(!proxy->syncMap(qobject_cast<SyncableObject *>(caller)).contains(signature))
+ SyncableObject *syncObject = qobject_cast<SyncableObject *>(caller);
+ if(!syncObject)
+ return false;
+
+ QByteArray signature = syncObject->syncMetaObject()->method(i).signature();
+ if(!proxy->syncMap(syncObject).contains(signature))
return false;
if(proxy->proxyMode() == SignalProxy::Server && !signature.contains("Requested"))
}
void SignalProxy::objectRenamed(const QString &newname, const QString &oldname) {
- const QMetaObject *meta = sender()->metaObject();
+ SyncableObject *syncObject = qobject_cast<SyncableObject *>(sender());
+ const QMetaObject *meta = syncObject->metaObject();
const QByteArray className(meta->className());
objectRenamed(className, newname, oldname);
}
void SignalProxy::setArgTypes(QObject* obj, int methodId) {
- const QMetaObject *meta = obj->metaObject();
+ const QMetaObject *meta = metaObject(obj);
QList<QByteArray> p = meta->method(methodId).parameterTypes();
QList<int> argTypes;
int ct = p.count();
}
const QList<int> &SignalProxy::argTypes(QObject *obj, int methodId) {
- Q_ASSERT(_classInfo.contains(obj->metaObject()));
- if(!_classInfo[obj->metaObject()]->argTypes.contains(methodId))
+ const QMetaObject *meta = metaObject(obj);
+ Q_ASSERT(_classInfo.contains(meta));
+ if(!_classInfo[meta]->argTypes.contains(methodId))
setArgTypes(obj, methodId);
- return _classInfo[obj->metaObject()]->argTypes[methodId];
+ return _classInfo[meta]->argTypes[methodId];
+}
+
+void SignalProxy::setReturnType(QObject *obj, int methodId) {
+ const QMetaObject *meta = metaObject(obj);
+ int returnType = QMetaType::type(meta->method(methodId).typeName());
+
+ Q_ASSERT(!_classInfo[meta]->returnType.contains(methodId));
+ _classInfo[meta]->returnType[methodId] = returnType;
+}
+
+const int &SignalProxy::returnType(QObject *obj, int methodId) {
+ const QMetaObject *meta = metaObject(obj);
+ Q_ASSERT(_classInfo.contains(meta));
+ if(!_classInfo[meta]->returnType.contains(methodId))
+ setReturnType(obj, methodId);
+ return _classInfo[meta]->returnType[methodId];
}
void SignalProxy::setMinArgCount(QObject *obj, int methodId) {
- const QMetaObject *meta = obj->metaObject();
+ const QMetaObject *meta = metaObject(obj);
QString signature(meta->method(methodId).signature());
int minCount = meta->method(methodId).parameterTypes().count() - signature.count("=");
Q_ASSERT(!_classInfo[meta]->minArgCount.contains(methodId));
}
const int &SignalProxy::minArgCount(QObject *obj, int methodId) {
- Q_ASSERT(_classInfo.contains(obj->metaObject()));
- if(!_classInfo[obj->metaObject()]->minArgCount.contains(methodId))
+ const QMetaObject *meta = metaObject(obj);
+ Q_ASSERT(_classInfo.contains(meta));
+ if(!_classInfo[meta]->minArgCount.contains(methodId))
setMinArgCount(obj, methodId);
- return _classInfo[obj->metaObject()]->minArgCount[methodId];
+ return _classInfo[meta]->minArgCount[methodId];
}
void SignalProxy::setMethodName(QObject *obj, int methodId) {
- const QMetaObject *meta = obj->metaObject();
+ const QMetaObject *meta = metaObject(obj);
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) {
- Q_ASSERT(_classInfo.contains(obj->metaObject()));
- if(!_classInfo[obj->metaObject()]->methodNames.contains(methodId))
+ const QMetaObject *meta = metaObject(obj);
+ Q_ASSERT(_classInfo.contains(meta));
+ if(!_classInfo[meta]->methodNames.contains(methodId))
setMethodName(obj, methodId);
- return _classInfo[obj->metaObject()]->methodNames[methodId];
+ return _classInfo[meta]->methodNames[methodId];
}
void SignalProxy::setSyncMap(SyncableObject *obj) {
- const QMetaObject *meta = obj->metaObject();
+ const QMetaObject *meta = obj->syncMetaObject();
QHash<QByteArray, int> syncMap;
QList<int> slotIndexes;
slotIndexes << i;
}
+ // we're faking sync pairs for sync replies
+ QByteArray slotSignature;
+ foreach(int slotIdx, slotIndexes) {
+ slotSignature = QByteArray(meta->method(slotIdx).signature());
+ if(!slotSignature.startsWith("receive"))
+ continue;
+ syncMap[slotSignature] = slotIdx;
+ }
+
QMetaMethod signal, slot;
int matchIdx;
for(int signalIdx = 0; signalIdx < meta->methodCount(); signalIdx++) {
}
const QHash<QByteArray,int> &SignalProxy::syncMap(SyncableObject *obj) {
- Q_ASSERT(_classInfo.contains(obj->metaObject()));
- if(_classInfo[obj->metaObject()]->syncMap.isEmpty())
+ const QMetaObject *meta = obj->syncMetaObject();
+ Q_ASSERT(_classInfo.contains(meta));
+ if(_classInfo[meta]->syncMap.isEmpty())
setSyncMap(obj);
- return _classInfo[obj->metaObject()]->syncMap;
+ return _classInfo[meta]->syncMap;
+}
+
+void SignalProxy::setReceiveMap(SyncableObject *obj) {
+ const QMetaObject *meta = obj->syncMetaObject();
+ Q_ASSERT(_classInfo.contains(meta));
+
+ QHash<int, int> receiveMap;
+
+ QMetaMethod requestSlot;
+ QByteArray returnTypeName;
+ QByteArray signature;
+ QByteArray methodName;
+ QByteArray params;
+ int paramsPos;
+ int receiverId;
+ const int methodCount = meta->methodCount();
+ for(int i = 0; i < methodCount; i++) {
+ requestSlot = meta->method(i);
+ if(requestSlot.methodType() != QMetaMethod::Slot)
+ continue;
+
+ returnTypeName = requestSlot.typeName();
+ if(QMetaType::Void == (QMetaType::Type)returnType(obj, i))
+ continue;
+
+ signature = QByteArray(requestSlot.signature());
+ if(!signature.startsWith("request"))
+ continue;
+
+ paramsPos = signature.indexOf('(');
+ if(paramsPos == -1)
+ continue;
+
+ methodName = signature.left(paramsPos);
+ params = signature.mid(paramsPos);
+
+ methodName = methodName.replace("request", "receive");
+ params = params.left(params.count() - 1) + ", " + returnTypeName + ")";
+
+ signature = QMetaObject::normalizedSignature(methodName + params);
+ receiverId = meta->indexOfSlot(signature);
+
+ if(receiverId == -1) {
+ signature = QMetaObject::normalizedSignature(methodName + "(" + returnTypeName + ")");
+ receiverId = meta->indexOfSlot(signature);
+ }
+
+ if(receiverId != -1)
+ receiveMap[i] = receiverId;
+ }
+ _classInfo[meta]->receiveMap = receiveMap;
+}
+
+const QHash<int, int> &SignalProxy::receiveMap(SyncableObject *obj) {
+ const QMetaObject *meta = obj->syncMetaObject();
+ Q_ASSERT(_classInfo.contains(meta));
+ if(_classInfo[meta]->receiveMap.isEmpty())
+ setReceiveMap(obj);
+ return _classInfo[meta]->receiveMap;
}
-void SignalProxy::setUpdatedRemotelyId(QObject *obj) {
- const QMetaObject *meta = obj->metaObject();
+void SignalProxy::setUpdatedRemotelyId(SyncableObject *obj) {
+ const QMetaObject *meta = obj->syncMetaObject();
Q_ASSERT(_classInfo.contains(meta));
_classInfo[meta]->updatedRemotelyId = meta->indexOfSignal("updatedRemotely()");
}
int SignalProxy::updatedRemotelyId(SyncableObject *obj) {
- Q_ASSERT(_classInfo.contains(obj->metaObject()));
- return _classInfo[obj->metaObject()]->updatedRemotelyId;
+ Q_ASSERT(_classInfo.contains(obj->syncMetaObject()));
+ return _classInfo[obj->syncMetaObject()]->updatedRemotelyId;
+}
+
+const QMetaObject *SignalProxy::metaObject(QObject *obj) {
+ if(SyncableObject *syncObject = qobject_cast<SyncableObject *>(obj))
+ return syncObject->syncMetaObject();
+ else
+ return obj->metaObject();
}
void SignalProxy::createClassInfo(QObject *obj) {
- if(_classInfo.contains(obj->metaObject()))
+ const QMetaObject *meta = metaObject(obj);
+ if(_classInfo.contains(meta))
return;
ClassInfo *classInfo = new ClassInfo();
- _classInfo[obj->metaObject()] = classInfo;
- setUpdatedRemotelyId(obj);
+ _classInfo[meta] = classInfo;
}
bool SignalProxy::attachSignal(QObject* sender, const char* signal, const QByteArray& sigName) {
- const QMetaObject* meta = sender->metaObject();
+ const QMetaObject* meta = metaObject(sender);
QByteArray sig(meta->normalizedSignature(signal).mid(1));
int methodId = meta->indexOfMethod(sig.constData());
if(methodId == -1 || meta->method(methodId).methodType() != QMetaMethod::Signal) {
void SignalProxy::synchronize(SyncableObject *obj) {
createClassInfo(obj);
-
+ setUpdatedRemotelyId(obj);
+
// attaching all the Signals
SignalRelay* relay;
if(_relayHash.contains(obj))
relay->setSynchronize(true);
// attaching as slave to receive sync Calls
- QByteArray className(obj->metaObject()->className());
+ QByteArray className(obj->syncMetaObject()->className());
_syncSlave[className][obj->objectName()] = obj;
if(proxyMode() == Server) {
return;
QVariantList params;
- params << obj->metaObject()->className()
+ params << obj->syncMetaObject()->className()
<< obj->objectName();
dispatchSignal(InitRequest, params);
}
return handleSignal(params.takeFirst().toByteArray(), params);
}
case Sync:
- return handleSync(params);
+ return handleSync(sender, params);
case InitRequest:
return handleInitRequest(sender, params);
case InitData:
}
}
-void SignalProxy::handleSync(QVariantList params) {
+void SignalProxy::handleSync(QIODevice *sender, QVariantList params) {
if(params.count() < 3) {
qWarning() << "received invalid Sync call" << params;
return;
}
int slotId = syncMap(receiver)[signal];
- if(!invokeSlot(receiver, slotId, params)) {
+
+ QVariant returnValue((QVariant::Type)returnType(receiver, slotId));
+ if(!invokeSlot(receiver, slotId, params, returnValue)) {
qWarning("SignalProxy::handleSync(): invokeMethod for \"%s\" failed ", methodName(receiver, slotId).constData());
return;
}
+
+ if(returnValue.type() != QVariant::Invalid && receiveMap(receiver).contains(slotId)) {
+ int receiverId = receiveMap(receiver)[slotId];
+ QVariantList returnParams;
+ returnParams << className
+ << objectName
+ << QByteArray(receiver->metaObject()->method(receiverId).signature());
+ if(argTypes(receiver, receiverId).count() > 1)
+ returnParams << params;
+ returnParams << returnValue;
+ dispatchSignal(sender, Sync, returnParams);
+ }
+
+ // send emit update signal
invokeSlot(receiver, updatedRemotelyId(receiver));
}
SyncableObject *obj = _syncSlave[className][objectName];
QVariantList params_;
- params_ << obj->metaObject()->className()
- << obj->objectName()
+ params_ << className
+ << objectName
<< initData(obj);
dispatchSignal(sender, InitData, params_);
}
}
-bool SignalProxy::invokeSlot(QObject *receiver, int methodId, const QVariantList ¶ms) {
+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()
return false;
}
- void *_a[] = {0, // return type
+ 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()) {
_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
return receiver->qt_metacall(QMetaObject::InvokeMetaMethod, methodId, _a) < 0;
} else {
qWarning() << "Queued Connections are not implemented yet";
- // not to self: qmetaobject.cpp:990 ff
+ // 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());
static QString methodBaseName(const QMetaMethod &method);
const QList<int> &argTypes(QObject *obj, int methodId);
+ const int &returnType(QObject *obj, int methodId);
const int &minArgCount(QObject *obj, int methodId);
const QByteArray &methodName(QObject *obj, int methodId);
const QHash<QByteArray, int> &syncMap(SyncableObject *obj);
+ const QHash<int, int> &receiveMap(SyncableObject *obj);
int updatedRemotelyId(SyncableObject *obj);
typedef QHash<int, QList<int> > ArgHash;
typedef QHash<int, QByteArray> MethodNameHash;
struct ClassInfo {
ArgHash argTypes;
+ QHash<int, int> returnType;
QHash<int, int> minArgCount;
MethodNameHash methodNames;
int updatedRemotelyId; // id of the updatedRemotely() signal - makes things faster
QHash<QByteArray, int> syncMap;
+ QHash<int, int> receiveMap;
};
void dumpProxyStats();
void initServer();
void initClient();
+ const QMetaObject *metaObject(QObject *obj);
void createClassInfo(QObject *obj);
void setArgTypes(QObject *obj, int methodId);
+ void setReturnType(QObject *obj, int methodId);
void setMinArgCount(QObject *obj, int methodId);
void setMethodName(QObject *obj, int methodId);
void setSyncMap(SyncableObject *obj);
- void setUpdatedRemotelyId(QObject *obj);
+ void setReceiveMap(SyncableObject *obj);
+ void setUpdatedRemotelyId(SyncableObject *obj);
bool methodsMatch(const QMetaMethod &signal, const QMetaMethod &slot) const;
void dispatchSignal(const RequestType &requestType, const QVariantList ¶ms);
void receivePeerSignal(QIODevice *sender, const QVariant &packedFunc);
- void handleSync(QVariantList params);
+ void handleSync(QIODevice *sender, QVariantList params);
void handleInitRequest(QIODevice *sender, const QVariantList ¶ms);
void handleInitData(QIODevice *sender, const QVariantList ¶ms);
void handleSignal(const QByteArray &funcName, const QVariantList ¶ms);
+ bool invokeSlot(QObject *receiver, int methodId, const QVariantList ¶ms, QVariant &returnValue);
bool invokeSlot(QObject *receiver, int methodId, const QVariantList ¶ms = QVariantList());
QVariantMap initData(SyncableObject *obj) const;
virtual bool isInitialized() const;
+ virtual const QMetaObject *syncMetaObject() const { return metaObject(); };
+
public slots:
virtual void setInitialized();
return instance()->storage->logMessage(message);
}
-QList<Message> Core::requestMsgs(BufferInfo buffer, int lastmsgs, int offset) {
+QList<Message> Core::requestMsgs(UserId user, BufferId buffer, int lastmsgs, int offset) {
QMutexLocker locker(&mutex);
- return instance()->storage->requestMsgs(buffer, lastmsgs, offset);
+ return instance()->storage->requestMsgs(user, buffer, lastmsgs, offset);
}
-QList<Message> Core::requestMsgs(BufferInfo buffer, QDateTime since, int offset) {
+QList<Message> Core::requestMsgs(UserId user, BufferId buffer, QDateTime since, int offset) {
QMutexLocker locker(&mutex);
- return instance()->storage->requestMsgs(buffer, since, offset);
+ return instance()->storage->requestMsgs(user, buffer, since, offset);
}
-QList<Message> Core::requestMsgRange(BufferInfo buffer, int first, int last) {
+QList<Message> Core::requestMsgRange(UserId user, BufferId buffer, int first, int last) {
QMutexLocker locker(&mutex);
- return instance()->storage->requestMsgRange(buffer, first, last);
+ return instance()->storage->requestMsgRange(user, buffer, first, last);
}
QList<BufferInfo> Core::requestBuffers(UserId user, QDateTime since) {
* \param offset Do not return (but DO count) messages with MsgId >= offset, if offset >= 0
* \return The requested list of messages
*/
- static QList<Message> requestMsgs(BufferInfo buffer, int lastmsgs = -1, int offset = -1);
+ static QList<Message> requestMsgs(UserId user, BufferId buffer, int lastmsgs = -1, int offset = -1);
//! Request messages stored in a given buffer since a certain point in time.
/** \note This method is threadsafe.
* \param offset Do not return messages with MsgId >= offset, if offset >= 0
* \return The requested list of messages
*/
- static QList<Message> requestMsgs(BufferInfo buffer, QDateTime since, int offset = -1);
+ static QList<Message> requestMsgs(UserId user, BufferId buffer, QDateTime since, int offset = -1);
//! Request a range of messages stored in a given buffer.
/** \note This method is threadsafe.
* \param last Return messages with first <= MsgId <= last
* \return The requested list of messages
*/
- static QList<Message> requestMsgRange(BufferInfo buffer, int first, int last);
+ static QList<Message> requestMsgRange(UserId user, BufferId buffer, int first, int last);
//! Request a list of all buffers known to a user since a certain point in time.
/** This method is used to get a list of all buffers we have stored a backlog from.
DEPMOD = common
QT_MOD = core network sql script
-SRCS = core.cpp coresession.cpp coresettings.cpp networkconnection.cpp sqlitestorage.cpp abstractsqlstorage.cpp storage.cpp basichandler.cpp \
+SRCS = core.cpp corebacklogmanager.cpp coresession.cpp coresettings.cpp networkconnection.cpp sqlitestorage.cpp abstractsqlstorage.cpp storage.cpp basichandler.cpp \
ircserverhandler.cpp userinputhandler.cpp ctcphandler.cpp coreusersettings.cpp sessionthread.cpp
-HDRS = core.h coresession.h coresettings.h networkconnection.h sqlitestorage.h abstractsqlstorage.h storage.h basichandler.h \
+HDRS = core.h corebacklogmanager.h coresession.h coresettings.h networkconnection.h sqlitestorage.h abstractsqlstorage.h storage.h basichandler.h \
ircserverhandler.h userinputhandler.h ctcphandler.h coreusersettings.h sessionthread.h
--- /dev/null
+/***************************************************************************
+ * Copyright (C) 2005-08 by the Quassel IRC 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) version 3. *
+ * *
+ * 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 "corebacklogmanager.h"
+#include "core.h"
+#include "coresession.h"
+
+#include <QDebug>
+
+CoreBacklogManager::CoreBacklogManager(CoreSession *coreSession)
+ : BacklogManager(coreSession),
+ _coreSession(coreSession)
+{
+}
+
+QVariantList CoreBacklogManager::requestBacklog(BufferId bufferId, int lastMsgs, int offset) {
+ QVariantList backlog;
+ QList<Message> msgList;
+ msgList = Core::requestMsgs(coreSession()->user(), bufferId, lastMsgs, offset);
+
+ QList<Message>::const_iterator msgIter = msgList.constBegin();
+ QList<Message>::const_iterator msgListEnd = msgList.constEnd();
+ while(msgIter != msgListEnd) {
+ backlog << qVariantFromValue(*msgIter);
+ msgIter++;
+ }
+ return backlog;
+}
--- /dev/null
+/***************************************************************************
+ * Copyright (C) 2005-08 by the Quassel IRC 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) version 3. *
+ * *
+ * 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 COREBACKLOGMANAGER_H
+#define COREBACKLOGMANAGER_H
+
+#include "backlogmanager.h"
+
+class CoreSession;
+
+class CoreBacklogManager : public BacklogManager {
+ Q_OBJECT
+
+public:
+ CoreBacklogManager(CoreSession *coreSession = 0);
+
+ virtual const QMetaObject *syncMetaObject() const { return &BacklogManager::staticMetaObject; }
+
+ CoreSession *coreSession() { return _coreSession; }
+
+public slots:
+ virtual QVariantList requestBacklog(BufferId bufferId, int lastMsgs = -1, int offset = -1);
+
+private:
+ CoreSession *_coreSession;
+};
+
+#endif // COREBACKLOGMANAGER_H
#include "signalproxy.h"
#include "buffersyncer.h"
+#include "corebacklogmanager.h"
#include "storage.h"
#include "network.h"
#include "util.h"
#include "coreusersettings.h"
-CoreSession::CoreSession(UserId uid, bool restoreState, QObject *parent) : QObject(parent),
+CoreSession::CoreSession(UserId uid, bool restoreState, QObject *parent)
+ : QObject(parent),
_user(uid),
_signalProxy(new SignalProxy(SignalProxy::Server, 0, this)),
_bufferSyncer(new BufferSyncer(this)),
+ _backlogManager(new CoreBacklogManager(this)),
scriptEngine(new QScriptEngine(this))
{
//p->attachSlot(SIGNAL(disconnectFromNetwork(NetworkId)), this, SLOT(disconnectFromNetwork(NetworkId))); // FIXME
p->attachSlot(SIGNAL(sendInput(BufferInfo, QString)), this, SLOT(msgFromClient(BufferInfo, QString)));
- p->attachSlot(SIGNAL(requestBacklog(BufferInfo, QVariant, QVariant)), this, SLOT(sendBacklog(BufferInfo, QVariant, QVariant)));
p->attachSignal(this, SIGNAL(displayMsg(Message)));
p->attachSignal(this, SIGNAL(displayStatusMsg(QString, QString)));
- p->attachSignal(this, SIGNAL(backlogData(BufferInfo, QVariantList, bool)));
p->attachSignal(this, SIGNAL(bufferInfoUpdated(BufferInfo)));
p->attachSignal(this, SIGNAL(identityCreated(const Identity &)));
connect(this, SIGNAL(bufferRenamed(BufferId, QString)), _bufferSyncer, SLOT(renameBuffer(BufferId, QString)));
p->synchronize(_bufferSyncer);
+
+ // init BacklogManager;
+ p->synchronize(_backlogManager);
+
// Restore session state
if(restoreState) restoreSessionState();
Core::setBufferLastSeenMsg(user(), buffer, msgId);
}
-void CoreSession::sendBacklog(BufferInfo id, QVariant v1, QVariant v2) {
- QList<QVariant> log;
- QList<Message> msglist;
- if(v1.type() == QVariant::DateTime) {
-
-
- } else {
- msglist = Core::requestMsgs(id, v1.toInt(), v2.toInt());
- }
-
- // Send messages out in smaller packages - we don't want to make the signal data too large!
- for(int i = 0; i < msglist.count(); i++) {
- log.append(qVariantFromValue(msglist[i]));
- if(log.count() >= 5) {
- emit backlogData(id, log, i >= msglist.count() - 1);
- log.clear();
- }
- }
- if(log.count() > 0) emit backlogData(id, log, true);
-}
-
-
void CoreSession::initScriptEngine() {
signalProxy()->attachSlot(SIGNAL(scriptRequest(QString)), this, SLOT(scriptRequest(QString)));
signalProxy()->attachSignal(this, SIGNAL(scriptResult(QString)));
#include "message.h"
class BufferSyncer;
+class CoreBacklogManager;
class Identity;
class NetworkConnection;
class Network;
void connectToNetwork(NetworkId);
void disconnectFromNetwork(NetworkId id);
- void sendBacklog(BufferInfo, QVariant, QVariant);
void msgFromClient(BufferInfo, QString message);
//! Create an identity and propagate the changes to the clients.
//void connectToIrc(QString net);
//void disconnectFromIrc(QString net);
- void backlogData(BufferInfo, QVariantList, bool done);
-
void bufferInfoUpdated(BufferInfo);
void scriptResult(QString result);
QHash<IdentityId, Identity *> _identities;
BufferSyncer *_bufferSyncer;
+ CoreBacklogManager *_backlogManager;
QScriptEngine *scriptEngine;
return msgId;
}
-QList<Message> SqliteStorage::requestMsgs(BufferInfo buffer, int lastmsgs, int offset) {
+QList<Message> SqliteStorage::requestMsgs(UserId user, BufferId bufferId, int lastmsgs, int offset) {
QList<Message> messagelist;
+
+ BufferInfo bufferInfo = getBufferInfo(user, bufferId);
+ if(!bufferInfo.isValid())
+ return messagelist;
+
// we have to determine the real offset first
QSqlQuery *offsetQuery = cachedQuery("select_messagesOffset");
- offsetQuery->bindValue(":bufferid", buffer.bufferId().toInt());
+ offsetQuery->bindValue(":bufferid", bufferId.toInt());
offsetQuery->bindValue(":messageid", offset);
offsetQuery->exec();
offsetQuery->first();
// now let's select the messages
QSqlQuery *msgQuery = cachedQuery("select_messages");
- msgQuery->bindValue(":bufferid", buffer.bufferId().toInt());
+ msgQuery->bindValue(":bufferid", bufferId.toInt());
msgQuery->bindValue(":limit", lastmsgs);
msgQuery->bindValue(":offset", offset);
msgQuery->exec();
while(msgQuery->next()) {
Message msg(QDateTime::fromTime_t(msgQuery->value(1).toInt()),
- buffer,
+ bufferInfo,
(Message::Type)msgQuery->value(2).toUInt(),
msgQuery->value(5).toString(),
msgQuery->value(4).toString(),
}
-QList<Message> SqliteStorage::requestMsgs(BufferInfo buffer, QDateTime since, int offset) {
+QList<Message> SqliteStorage::requestMsgs(UserId user, BufferId bufferId, QDateTime since, int offset) {
QList<Message> messagelist;
+
+ BufferInfo bufferInfo = getBufferInfo(user, bufferId);
+ if(!bufferInfo.isValid())
+ return messagelist;
+
// we have to determine the real offset first
QSqlQuery *offsetQuery = cachedQuery("select_messagesSinceOffset");
- offsetQuery->bindValue(":bufferid", buffer.bufferId().toInt());
+ offsetQuery->bindValue(":bufferid", bufferId.toInt());
offsetQuery->bindValue(":since", since.toTime_t());
offsetQuery->exec();
offsetQuery->first();
// now let's select the messages
QSqlQuery *msgQuery = cachedQuery("select_messagesSince");
- msgQuery->bindValue(":bufferid", buffer.bufferId().toInt());
+ msgQuery->bindValue(":bufferid", bufferId.toInt());
msgQuery->bindValue(":since", since.toTime_t());
msgQuery->bindValue(":offset", offset);
msgQuery->exec();
while(msgQuery->next()) {
Message msg(QDateTime::fromTime_t(msgQuery->value(1).toInt()),
- buffer,
+ bufferInfo,
(Message::Type)msgQuery->value(2).toUInt(),
msgQuery->value(5).toString(),
msgQuery->value(4).toString(),
}
-QList<Message> SqliteStorage::requestMsgRange(BufferInfo buffer, int first, int last) {
+QList<Message> SqliteStorage::requestMsgRange(UserId user, BufferId bufferId, int first, int last) {
QList<Message> messagelist;
+
+ BufferInfo bufferInfo = getBufferInfo(user, bufferId);
+ if(!bufferInfo.isValid())
+ return messagelist;
+
QSqlQuery *rangeQuery = cachedQuery("select_messageRange");
- rangeQuery->bindValue(":bufferid", buffer.bufferId().toInt());
+ rangeQuery->bindValue(":bufferid", bufferId.toInt());
rangeQuery->bindValue(":firstmsg", first);
rangeQuery->bindValue(":lastmsg", last);
rangeQuery->exec();
while(rangeQuery->next()) {
Message msg(QDateTime::fromTime_t(rangeQuery->value(1).toInt()),
- buffer,
+ bufferInfo,
(Message::Type)rangeQuery->value(2).toUInt(),
rangeQuery->value(5).toString(),
rangeQuery->value(4).toString(),
/* Message handling */
virtual MsgId logMessage(Message msg);
- virtual QList<Message> requestMsgs(BufferInfo buffer, int lastmsgs = -1, int offset = -1);
- virtual QList<Message> requestMsgs(BufferInfo buffer, QDateTime since, int offset = -1);
- virtual QList<Message> requestMsgRange(BufferInfo buffer, int first, int last);
+ virtual QList<Message> requestMsgs(UserId user, BufferId bufferId, int lastmsgs = -1, int offset = -1);
+ virtual QList<Message> requestMsgs(UserId user, BufferId bufferId, QDateTime since, int offset = -1);
+ virtual QList<Message> requestMsgRange(UserId user, BufferId bufferId, int first, int last);
protected:
inline virtual QString driverName() { return "QSQLITE"; }
* \param offset Do not return (but DO count) messages with MsgId >= offset, if offset >= 0
* \return The requested list of messages
*/
- virtual QList<Message> requestMsgs(BufferInfo buffer, int lastmsgs = -1, int offset = -1) = 0;
+ virtual QList<Message> requestMsgs(UserId user, BufferId buffer, int lastmsgs = -1, int offset = -1) = 0;
//! Request messages stored in a given buffer since a certain point in time.
/** \param buffer The buffer we request messages from
* \param offset Do not return messages with MsgId >= offset, if offset >= 0
* \return The requested list of messages
*/
- virtual QList<Message> requestMsgs(BufferInfo buffer, QDateTime since, int offset = -1) = 0;
+ virtual QList<Message> requestMsgs(UserId user, BufferId buffer, QDateTime since, int offset = -1) = 0;
//! Request a range of messages stored in a given buffer.
/** \param buffer The buffer we request messages from
* \param last Return messages with first <= MsgId <= last
* \return The requested list of messages
*/
- virtual QList<Message> requestMsgRange(BufferInfo buffer, int first, int last) = 0;
+ virtual QList<Message> requestMsgRange(UserId user, BufferId buffer, int first, int last) = 0;
signals:
//! Sent when a new BufferInfo is created, or an existing one changed somehow.
#include "chatline.h"
#include "chatline-old.h"
#include "client.h"
+#include "clientbacklogmanager.h"
#include "coreconnectdlg.h"
#include "networkmodel.h"
#include "buffermodel.h"
void MainWin::connectedToCore() {
foreach(BufferInfo id, Client::allBufferInfos()) {
- emit requestBacklog(id, 1000, -1);
+ // emit requestBacklog(id, 1000, -1);
+ Client::backlogManager()->requestBacklog(id.bufferId(), 1000, -1);
}
ui.menuViews->setEnabled(true);
{ using namespace Global;
- quasselVersion = "0.2.0-alpha3";
+ quasselVersion = "0.2.0-alpha4-pre";
quasselDate = "2008-03-16";
- quasselBuild = 640;
+ quasselBuild = 641;
//! Minimum client build number the core needs
- clientBuildNeeded = 628;
+ clientBuildNeeded = 641;
clientVersionNeeded = quasselVersion;
//! Minimum core build number the client needs
- coreBuildNeeded = 628;
+ coreBuildNeeded = 641;
coreVersionNeeded = quasselVersion;
}