From: Marcus Eggenberger Date: Tue, 24 Mar 2009 16:36:06 +0000 (+0100) Subject: Merge branch 'bufferviewoverlay' X-Git-Tag: 0.5-rc1~250 X-Git-Url: https://git.quassel-irc.org/?a=commitdiff_plain;h=ab16c77fe03b73a863d9b52b11919bcbac903f58;hp=a99d5f205aeb71c48a94e79992252ba4f2163007;p=quassel.git Merge branch 'bufferviewoverlay' Conflicts: src/client/client.cpp src/client/client.h --- diff --git a/src/client/CMakeLists.txt b/src/client/CMakeLists.txt index 5277844e..f60f66c5 100644 --- a/src/client/CMakeLists.txt +++ b/src/client/CMakeLists.txt @@ -12,6 +12,7 @@ set(SOURCES backlogrequester.cpp buffermodel.cpp buffersettings.cpp + bufferviewoverlay.cpp client.cpp clientaliasmanager.cpp clientbacklogmanager.cpp @@ -34,6 +35,7 @@ set(MOC_HDRS abstractmessageprocessor.h abstractui.h buffermodel.h + bufferviewoverlay.h client.h clientaliasmanager.h clientbacklogmanager.h diff --git a/src/client/backlogrequester.cpp b/src/client/backlogrequester.cpp index a08227d8..3aee9313 100644 --- a/src/client/backlogrequester.cpp +++ b/src/client/backlogrequester.cpp @@ -23,11 +23,13 @@ #include #include "backlogsettings.h" +#include "bufferviewoverlay.h" #include "clientbacklogmanager.h" -BacklogRequester::BacklogRequester(bool buffering, ClientBacklogManager *backlogManager) +BacklogRequester::BacklogRequester(bool buffering, RequesterType requesterType, ClientBacklogManager *backlogManager) : backlogManager(backlogManager), _isBuffering(buffering), + _requesterType(requesterType), _totalBuffers(0) { Q_ASSERT(backlogManager); @@ -49,21 +51,26 @@ bool BacklogRequester::buffer(BufferId bufferId, const MessageList &messages) { return !_buffersWaiting.isEmpty(); } +BufferIdList BacklogRequester::allBufferIds() const { + QSet bufferIds = Client::bufferViewOverlay()->bufferIds(); + bufferIds += Client::bufferViewOverlay()->tempRemovedBufferIds(); + return bufferIds.toList(); +} + // ======================================== // FIXED BACKLOG REQUESTER // ======================================== FixedBacklogRequester::FixedBacklogRequester(ClientBacklogManager *backlogManager) - : BacklogRequester(true, backlogManager) + : BacklogRequester(true, BacklogRequester::PerBufferFixed, backlogManager) { BacklogSettings backlogSettings; _backlogCount = backlogSettings.fixedBacklogAmount(); } -void FixedBacklogRequester::requestBacklog() { - QList allBuffers = allBufferIds(); - setWaitingBuffers(allBuffers); - backlogManager->emitMessagesRequested(QObject::tr("Requesting a total of up to %1 backlog messages for %2 buffers").arg(_backlogCount * allBuffers.count()).arg(allBuffers.count())); - foreach(BufferId bufferId, allBuffers) { +void FixedBacklogRequester::requestBacklog(const BufferIdList &bufferIds) { + setWaitingBuffers(bufferIds); + backlogManager->emitMessagesRequested(QObject::tr("Requesting a total of up to %1 backlog messages for %2 buffers").arg(_backlogCount * bufferIds.count()).arg(bufferIds.count())); + foreach(BufferId bufferId, bufferIds) { backlogManager->requestBacklog(bufferId, -1, -1, _backlogCount); } } @@ -72,7 +79,7 @@ void FixedBacklogRequester::requestBacklog() { // GLOBAL UNREAD BACKLOG REQUESTER // ======================================== GlobalUnreadBacklogRequester::GlobalUnreadBacklogRequester(ClientBacklogManager *backlogManager) - : BacklogRequester(false, backlogManager) + : BacklogRequester(false, BacklogRequester::GlobalUnread, backlogManager) { BacklogSettings backlogSettings; _limit = backlogSettings.globalUnreadBacklogLimit(); @@ -94,18 +101,17 @@ void GlobalUnreadBacklogRequester::requestBacklog() { // PER BUFFER UNREAD BACKLOG REQUESTER // ======================================== PerBufferUnreadBacklogRequester::PerBufferUnreadBacklogRequester(ClientBacklogManager *backlogManager) - : BacklogRequester(true, backlogManager) + : BacklogRequester(true, BacklogRequester::PerBufferUnread, backlogManager) { BacklogSettings backlogSettings; _limit = backlogSettings.perBufferUnreadBacklogLimit(); _additional = backlogSettings.perBufferUnreadBacklogAdditional(); } -void PerBufferUnreadBacklogRequester::requestBacklog() { - QList allBuffers = allBufferIds(); - setWaitingBuffers(allBuffers); - backlogManager->emitMessagesRequested(QObject::tr("Requesting a total of up to %1 unread backlog messages for %2 buffers").arg((_limit + _additional) * allBuffers.count()).arg(allBuffers.count())); - foreach(BufferId bufferId, allBuffers) { +void PerBufferUnreadBacklogRequester::requestBacklog(const BufferIdList &bufferIds) { + setWaitingBuffers(bufferIds); + backlogManager->emitMessagesRequested(QObject::tr("Requesting a total of up to %1 unread backlog messages for %2 buffers").arg((_limit + _additional) * bufferIds.count()).arg(bufferIds.count())); + foreach(BufferId bufferId, bufferIds) { backlogManager->requestBacklog(bufferId, Client::networkModel()->lastSeenMsgId(bufferId), -1, _limit, _additional); } } diff --git a/src/client/backlogrequester.h b/src/client/backlogrequester.h index c3c6832b..8aa36274 100644 --- a/src/client/backlogrequester.h +++ b/src/client/backlogrequester.h @@ -32,17 +32,18 @@ class ClientBacklogManager; class BacklogRequester { public: - enum RequesterTypes { + enum RequesterType { InvalidRequester = 0, PerBufferFixed, PerBufferUnread, GlobalUnread }; - BacklogRequester(bool buffering, ClientBacklogManager *backlogManger); + BacklogRequester(bool buffering, RequesterType requesterType, ClientBacklogManager *backlogManger); virtual inline ~BacklogRequester() {} inline bool isBuffering() { return _isBuffering; } + inline RequesterType type() { return _requesterType; } inline const QList &bufferedMessages() { return _bufferedMessages; } inline int buffersWaiting() const { return _buffersWaiting.count(); } @@ -50,10 +51,11 @@ public: //! returns false if it was the last missing backlogpart bool buffer(BufferId bufferId, const MessageList &messages); - virtual void requestBacklog() = 0; + virtual void requestBacklog(const BufferIdList &bufferIds) = 0; + virtual inline void requestBacklog() { requestBacklog(allBufferIds()); } protected: - inline QList allBufferIds() const { return Client::networkModel()->allBufferIds(); } + BufferIdList allBufferIds() const; inline void setWaitingBuffers(const QList &buffers) { setWaitingBuffers(buffers.toSet()); } void setWaitingBuffers(const QSet &buffers); void addWaitingBuffer(BufferId buffer); @@ -62,6 +64,7 @@ protected: private: bool _isBuffering; + RequesterType _requesterType; MessageList _bufferedMessages; int _totalBuffers; QSet _buffersWaiting; @@ -73,7 +76,7 @@ private: class FixedBacklogRequester : public BacklogRequester { public: FixedBacklogRequester(ClientBacklogManager *backlogManager); - virtual void requestBacklog(); + virtual void requestBacklog(const BufferIdList &bufferIds); private: int _backlogCount; @@ -86,6 +89,7 @@ class GlobalUnreadBacklogRequester : public BacklogRequester { public: GlobalUnreadBacklogRequester(ClientBacklogManager *backlogManager); virtual void requestBacklog(); + virtual void requestBacklog(const BufferIdList &) {} private: int _limit; @@ -98,7 +102,7 @@ private: class PerBufferUnreadBacklogRequester : public BacklogRequester { public: PerBufferUnreadBacklogRequester(ClientBacklogManager *backlogManager); - virtual void requestBacklog(); + virtual void requestBacklog(const BufferIdList &bufferIds); private: int _limit; diff --git a/src/client/bufferviewoverlay.cpp b/src/client/bufferviewoverlay.cpp new file mode 100644 index 00000000..66dec133 --- /dev/null +++ b/src/client/bufferviewoverlay.cpp @@ -0,0 +1,194 @@ +/*************************************************************************** + * Copyright (C) 2005-08 by the Quassel Project * + * 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 "bufferviewoverlay.h" + +#include + +#include "bufferviewconfig.h" +#include "client.h" +#include "clientbufferviewmanager.h" +#include "networkmodel.h" + +const int BufferViewOverlay::_updateEventId = QEvent::registerEventType(); + +BufferViewOverlay::BufferViewOverlay(QObject *parent) + : QObject(parent), + _aboutToUpdate(false), + _addBuffersAutomatically(false), + _hideInactiveBuffers(false), + _allowedBufferTypes(0), + _minimumActivity(0) +{ +} + +void BufferViewOverlay::addView(int viewId) { + if(_bufferViewIds.contains(viewId)) + return; + + BufferViewConfig *config = Client::bufferViewManager()->bufferViewConfig(viewId); + if(!config) { + qDebug() << "BufferViewOverlay::addView(): no such buffer view:" << viewId; + return; + } + + _bufferViewIds << viewId; + if(config->isInitialized()) { + viewInitialized(config); + } else { + disconnect(config, SIGNAL(initDone()), this, SLOT(viewInitialized())); + connect(config, SIGNAL(initDone()), this, SLOT(viewInitialized())); + } +} + +void BufferViewOverlay::removeView(int viewId) { + if(!_bufferViewIds.contains(viewId)) + return; + + _bufferViewIds.remove(viewId); + BufferViewConfig *config = qobject_cast(sender()); + if(config) + disconnect(config, 0, this, 0); + update(); +} + +void BufferViewOverlay::viewInitialized(BufferViewConfig *config) { + if(!config) { + qWarning() << "BufferViewOverlay::viewInitialized() received invalid view!"; + return; + } + disconnect(config, SIGNAL(initDone()), this, SLOT(viewInitialized())); + + connect(config, SIGNAL(networkIdSet(const NetworkId &)), this, SLOT(update())); + connect(config, SIGNAL(addNewBuffersAutomaticallySet(bool)), this, SLOT(update())); + connect(config, SIGNAL(sortAlphabeticallySet(bool)), this, SLOT(update())); + connect(config, SIGNAL(hideInactiveBuffersSet(bool)), this, SLOT(update())); + connect(config, SIGNAL(allowedBufferTypesSet(int)), this, SLOT(update())); + connect(config, SIGNAL(minimumActivitySet(int)), this, SLOT(update())); + connect(config, SIGNAL(bufferListSet()), this, SLOT(update())); + connect(config, SIGNAL(bufferAdded(const BufferId &, int)), this, SLOT(update())); + connect(config, SIGNAL(bufferRemoved(const BufferId &)), this, SLOT(update())); + connect(config, SIGNAL(bufferPermanentlyRemoved(const BufferId &)), this, SLOT(update())); + + // check if the view was removed in the meantime... + if(_bufferViewIds.contains(config->bufferViewId())) + update(); +} + +void BufferViewOverlay::viewInitialized() { + BufferViewConfig *config = qobject_cast(sender()); + Q_ASSERT(config); + + viewInitialized(config); +} + +void BufferViewOverlay::update() { + if(_aboutToUpdate) { + return; + } + _aboutToUpdate = true; + QCoreApplication::postEvent(this, new QEvent((QEvent::Type)_updateEventId)); +} + +void BufferViewOverlay::updateHelper() { + bool changed = false; + + bool addBuffersAutomatically = false; + bool hideInactiveBuffers = true; + int allowedBufferTypes = 0; + int minimumActivity = -1; + QSet networkIds; + QSet buffers; + QSet removedBuffers; + QSet tempRemovedBuffers; + + if(Client::bufferViewManager()) { + BufferViewConfig *config = 0; + QSet::const_iterator viewIter; + for(viewIter = _bufferViewIds.constBegin(); viewIter != _bufferViewIds.constEnd(); viewIter++) { + config = Client::bufferViewManager()->bufferViewConfig(*viewIter); + if(!config) + continue; + + networkIds << config->networkId(); + if(config->networkId().isValid()) { + NetworkId networkId = config->networkId(); + // we have to filter out all the buffers that don't belong to this net... :/ + QSet bufferIds; + foreach(BufferId bufferId, config->bufferList()) { + if(Client::networkModel()->networkId(bufferId) == networkId) + bufferIds << bufferId; + } + buffers += bufferIds; + + bufferIds.clear(); + foreach(BufferId bufferId, config->temporarilyRemovedBuffers()) { + if(Client::networkModel()->networkId(bufferId) == networkId) + bufferIds << bufferId; + } + tempRemovedBuffers += bufferIds; + } else { + buffers += config->bufferList().toSet(); + tempRemovedBuffers += config->temporarilyRemovedBuffers(); + } + + // in the overlay a buffer is removed it is removed from all views + if(removedBuffers.isEmpty()) + removedBuffers = config->removedBuffers(); + else + removedBuffers.intersect(config->removedBuffers()); + + + addBuffersAutomatically |= config->addNewBuffersAutomatically(); + hideInactiveBuffers &= config->hideInactiveBuffers(); + allowedBufferTypes |= config->allowedBufferTypes(); + if(minimumActivity == -1 || config->minimumActivity() < minimumActivity) + minimumActivity = config->minimumActivity(); + } + } + + changed |= (addBuffersAutomatically != _addBuffersAutomatically); + changed |= (hideInactiveBuffers != _hideInactiveBuffers); + changed |= (allowedBufferTypes != _allowedBufferTypes); + changed |= (minimumActivity != _minimumActivity); + changed |= (networkIds != _networkIds); + changed |= (buffers != _buffers); + changed |= (removedBuffers != _removedBuffers); + changed |= (tempRemovedBuffers != _tempRemovedBuffers); + + _addBuffersAutomatically = addBuffersAutomatically; + _hideInactiveBuffers = hideInactiveBuffers; + _allowedBufferTypes = allowedBufferTypes; + _minimumActivity = minimumActivity; + _networkIds = networkIds; + _buffers = buffers; + _removedBuffers = removedBuffers; + _tempRemovedBuffers = tempRemovedBuffers; + + if(changed) + emit hasChanged(); +} + +void BufferViewOverlay::customEvent(QEvent *event) { + if(event->type() == _updateEventId) { + updateHelper(); + _aboutToUpdate = false; + } +} diff --git a/src/client/bufferviewoverlay.h b/src/client/bufferviewoverlay.h new file mode 100644 index 00000000..483a3302 --- /dev/null +++ b/src/client/bufferviewoverlay.h @@ -0,0 +1,86 @@ +/*************************************************************************** + * Copyright (C) 2005-08 by the Quassel Project * + * 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 BUFFERVIEWOVERLAY_H +#define BUFFERVIEWOVERLAY_H + +#include + +#include "types.h" + +class BufferViewConfig; +class ClientBufferViewConfig; + +class BufferViewOverlay : public QObject { + Q_OBJECT + +public: + BufferViewOverlay(QObject *parent = 0); + + inline bool allNetworks() const { return _networkIds.contains(NetworkId()); } + + inline const QSet &networkIds() const { return _networkIds; } + inline const QSet &bufferIds() const { return _buffers; } + inline const QSet &removedBufferIds() const { return _removedBuffers; } + inline const QSet &tempRemovedBufferIds() const { return _tempRemovedBuffers; } + + inline bool addBuffersAutomatically() const { return _addBuffersAutomatically; } + inline bool hideInactiveBuffers() const { return _hideInactiveBuffers; } + inline int allowedBufferTypes() const { return _allowedBufferTypes; } + inline int minimumActivity() const { return _minimumActivity; } + +public slots: + void addView(int viewId); + void removeView(int viewId); + + // updates propagated from the actual views + void update(); + +signals: + void hasChanged(); + +protected: + virtual void customEvent(QEvent *event); + +private slots: + void viewInitialized(); + void viewInitialized(BufferViewConfig *config); + +private: + void updateHelper(); + bool _aboutToUpdate; + + QSet _bufferViewIds; + + QSet _networkIds; + + bool _addBuffersAutomatically; + bool _hideInactiveBuffers; + int _allowedBufferTypes; + int _minimumActivity; + + QSet _buffers; + QSet _removedBuffers; + QSet _tempRemovedBuffers; + + static const int _updateEventId; +}; + +#endif //BUFFERVIEWOVERLAY_H diff --git a/src/client/client.cpp b/src/client/client.cpp index ca219bbd..d04e258d 100644 --- a/src/client/client.cpp +++ b/src/client/client.cpp @@ -27,6 +27,7 @@ #include "buffersettings.h" #include "buffersyncer.h" #include "bufferviewconfig.h" +#include "bufferviewoverlay.h" #include "clientaliasmanager.h" #include "clientbacklogmanager.h" #include "clientbufferviewmanager.h" @@ -85,6 +86,7 @@ Client::Client(QObject *parent) _aliasManager(0), _backlogManager(new ClientBacklogManager(this)), _bufferViewManager(0), + _bufferViewOverlay(new BufferViewOverlay(this)), _ircListHelper(new ClientIrcListHelper(this)), _inputHandler(0), _messageModel(0), @@ -95,6 +97,7 @@ Client::Client(QObject *parent) _debugLog(&_debugLogBuffer) { _signalProxy->synchronize(_ircListHelper); + connect(this, SIGNAL(requestInitialBacklog()), _backlogManager, SLOT(requestInitialBacklog()), Qt::QueuedConnection); } Client::~Client() { @@ -313,15 +316,14 @@ void Client::setSyncedToCore() { connect(bufferSyncer(), SIGNAL(bufferRenamed(BufferId, QString)), this, SLOT(bufferRenamed(BufferId, QString))); connect(bufferSyncer(), SIGNAL(buffersPermanentlyMerged(BufferId, BufferId)), this, SLOT(buffersPermanentlyMerged(BufferId, BufferId))); connect(bufferSyncer(), SIGNAL(buffersPermanentlyMerged(BufferId, BufferId)), _messageModel, SLOT(buffersPermanentlyMerged(BufferId, BufferId))); - connect(bufferSyncer(), SIGNAL(initDone()), this, SLOT(requestInitialBacklog())); connect(networkModel(), SIGNAL(setLastSeenMsg(BufferId, MsgId)), bufferSyncer(), SLOT(requestSetLastSeenMsg(BufferId, const MsgId &))); signalProxy()->synchronize(bufferSyncer()); // create a new BufferViewManager Q_ASSERT(!_bufferViewManager); _bufferViewManager = new ClientBufferViewManager(signalProxy(), this); - connect(bufferViewManager(), SIGNAL(initDone()), this, SLOT(requestInitialBacklog())); connect(bufferViewManager(), SIGNAL(initDone()), this, SLOT(createDefaultBufferView())); + connect(bufferViewManager(), SIGNAL(viewsInitialized()), this, SLOT(requestInitialBacklogBarrier())); // create AliasManager Q_ASSERT(!_aliasManager); @@ -334,9 +336,16 @@ void Client::setSyncedToCore() { emit coreConnectionStateChanged(true); } -void Client::requestInitialBacklog() { - if(bufferViewManager()->isInitialized() && bufferSyncer()->isInitialized()) - Client::backlogManager()->requestInitialBacklog(); +void Client::requestInitialBacklogBarrier() { + // usually it _should_ take longer until the bufferViews are initialized, so that's what + // triggers this slot. But we have to make sure that we know all buffers yet. + // so we check the BufferSyncer and in case it wasn't initialized we wait for that instead + if(!bufferSyncer()->isInitialized()) { + disconnect(bufferViewManager(), SIGNAL(viewsInitialized()), this, SLOT(requestInitialBacklogBarrier())); + connect(bufferSyncer(), SIGNAL(initDone()), this, SLOT(requestInitialBacklogBarrier())); + return; + } + emit requestInitialBacklog(); } void Client::createDefaultBufferView() { diff --git a/src/client/client.h b/src/client/client.h index 2821ab98..0c9922a4 100644 --- a/src/client/client.h +++ b/src/client/client.h @@ -42,6 +42,7 @@ class AbstractUiMsg; class NetworkModel; class BufferModel; class BufferSyncer; +class BufferViewOverlay; class ClientAliasManager; class ClientBacklogManager; class ClientBufferViewManager; @@ -107,6 +108,7 @@ public: static inline ClientBacklogManager *backlogManager() { return instance()->_backlogManager; } static inline ClientIrcListHelper *ircListHelper() { return instance()->_ircListHelper; } static inline ClientBufferViewManager *bufferViewManager() { return instance()->_bufferViewManager; } + static inline BufferViewOverlay *bufferViewOverlay() { return instance()->_bufferViewOverlay; } static inline ClientUserInputHandler *inputHandler() { return instance()->_inputHandler; } static AccountId currentCoreAccount(); @@ -129,6 +131,7 @@ public: static inline void registerClientSyncer(ClientSyncer *syncer) { emit instance()->newClientSyncer(syncer); } signals: + void requestInitialBacklog(); void requestNetworkStates(); void showConfigWizard(const QVariantMap &coredata); @@ -186,7 +189,7 @@ private slots: void setConnectedToCore(AccountId id, QIODevice *socket = 0); void setSyncedToCore(); - void requestInitialBacklog(); + void requestInitialBacklogBarrier(); void createDefaultBufferView(); void sendBufferedUserInput(); @@ -210,6 +213,7 @@ private: ClientAliasManager *_aliasManager; ClientBacklogManager *_backlogManager; ClientBufferViewManager *_bufferViewManager; + BufferViewOverlay *_bufferViewOverlay; ClientIrcListHelper *_ircListHelper; ClientUserInputHandler *_inputHandler; diff --git a/src/client/clientbacklogmanager.cpp b/src/client/clientbacklogmanager.cpp index 6f45da35..f88c606d 100644 --- a/src/client/clientbacklogmanager.cpp +++ b/src/client/clientbacklogmanager.cpp @@ -52,7 +52,6 @@ void ClientBacklogManager::receiveBacklog(BufferId bufferId, MsgId first, MsgId updateProgress(_requester->totalBuffers() - _requester->buffersWaiting(), _requester->totalBuffers()); if(lastPart) { stopBuffering(); - reset(); } } else { dispatchMessages(msglist); @@ -70,7 +69,6 @@ void ClientBacklogManager::receiveBacklogAll(MsgId first, MsgId last, int limit, } dispatchMessages(msglist); - reset(); } void ClientBacklogManager::requestInitialBacklog() { @@ -98,9 +96,34 @@ void ClientBacklogManager::requestInitialBacklog() { } } -void ClientBacklogManager::stopBuffering() { +BufferIdList ClientBacklogManager::filterNewBufferIds(const BufferIdList &bufferIds) { + BufferIdList newBuffers; + foreach(BufferId bufferId, bufferIds) { + if(!_buffersRequested.contains(bufferId)) + newBuffers << bufferId; + } + _buffersRequested += bufferIds.toSet(); + return newBuffers; +} + +void ClientBacklogManager::checkForBacklog(const QList &bufferIds) { Q_ASSERT(_requester); + switch(_requester->type()) { + case BacklogRequester::GlobalUnread: + break; + case BacklogRequester::PerBufferUnread: + case BacklogRequester::PerBufferFixed: + default: + { + BufferIdList buffers = filterNewBufferIds(bufferIds); + if(!buffers.isEmpty()) + _requester->requestBacklog(buffers); + } + }; +} +void ClientBacklogManager::stopBuffering() { + Q_ASSERT(_requester); dispatchMessages(_requester->bufferedMessages(), true); } @@ -126,4 +149,5 @@ void ClientBacklogManager::dispatchMessages(const MessageList &messages, bool so void ClientBacklogManager::reset() { delete _requester; _requester = 0; + _buffersRequested.clear(); } diff --git a/src/client/clientbacklogmanager.h b/src/client/clientbacklogmanager.h index 5a8585bd..5f1e1cd9 100644 --- a/src/client/clientbacklogmanager.h +++ b/src/client/clientbacklogmanager.h @@ -40,8 +40,12 @@ public: public slots: virtual void receiveBacklog(BufferId bufferId, MsgId first, MsgId last, int limit, int additional, QVariantList msgs); virtual void receiveBacklogAll(MsgId first, MsgId last, int limit, int additional, QVariantList msgs); + void requestInitialBacklog(); + void checkForBacklog(BufferId bufferId); + void checkForBacklog(const BufferIdList &bufferIds); + signals: void messagesReceived(BufferId bufferId, int count) const; void messagesRequested(const QString &) const; @@ -52,10 +56,17 @@ signals: private: bool isBuffering(); void stopBuffering(); + BufferIdList filterNewBufferIds(const BufferIdList &bufferIds); void dispatchMessages(const MessageList &messages, bool sort = false); BacklogRequester *_requester; + QSet _buffersRequested; }; +// inlines +inline void ClientBacklogManager::checkForBacklog(BufferId bufferId) { + checkForBacklog(BufferIdList() << bufferId); +} + #endif // CLIENTBACKLOGMANAGER_H diff --git a/src/client/clientbufferviewmanager.cpp b/src/client/clientbufferviewmanager.cpp index c46ff3ac..d7cd837f 100644 --- a/src/client/clientbufferviewmanager.cpp +++ b/src/client/clientbufferviewmanager.cpp @@ -20,11 +20,13 @@ #include "clientbufferviewmanager.h" +#include "bufferviewoverlay.h" #include "clientbufferviewconfig.h" ClientBufferViewManager::ClientBufferViewManager(SignalProxy *proxy, QObject *parent) : BufferViewManager(proxy, parent) { + connect(this, SIGNAL(initDone()), this, SLOT(waitForConfigInit())); } BufferViewConfig *ClientBufferViewManager::bufferViewConfigFactory(int bufferViewConfigId) { @@ -43,3 +45,27 @@ ClientBufferViewConfig *ClientBufferViewManager::clientBufferViewConfig(int buff return static_cast(bufferViewConfig(bufferViewId)); } +void ClientBufferViewManager::waitForConfigInit() { + bool initialized = true; + foreach(BufferViewConfig *config, bufferViewConfigs()) { + initialized &= config->isInitialized(); + if(config->isInitialized()) + continue; + connect(config, SIGNAL(initDone()), this, SLOT(configInitBarrier())); + } + if(initialized) + emit viewsInitialized(); +} + +void ClientBufferViewManager::configInitBarrier() { + BufferViewConfig *config = qobject_cast(sender()); + Q_ASSERT(config); + disconnect(config, SIGNAL(initDone()), this, SLOT(configInitBarrier())); + + bool initialized = true; + foreach(BufferViewConfig *config, bufferViewConfigs()) { + initialized &= config->isInitialized(); + } + if(initialized) + emit viewsInitialized(); +} diff --git a/src/client/clientbufferviewmanager.h b/src/client/clientbufferviewmanager.h index 6ecef78c..09639089 100644 --- a/src/client/clientbufferviewmanager.h +++ b/src/client/clientbufferviewmanager.h @@ -22,7 +22,9 @@ #define CLIENTBUFFERVIEWMANAGER_H #include "bufferviewmanager.h" + class ClientBufferViewConfig; +class BufferViewOverlay; class ClientBufferViewManager : public BufferViewManager { Q_OBJECT @@ -35,6 +37,13 @@ public: protected: virtual BufferViewConfig *bufferViewConfigFactory(int bufferViewConfigId); + +signals: + void viewsInitialized(); + +private slots: + void waitForConfigInit(); + void configInitBarrier(); }; #endif //CLIENTBUFFERVIEWMANAGER_H diff --git a/src/client/messagemodel.cpp b/src/client/messagemodel.cpp index 122156a5..58e3108d 100644 --- a/src/client/messagemodel.cpp +++ b/src/client/messagemodel.cpp @@ -219,7 +219,7 @@ int MessageModel::insertMessagesGracefully(const QList &msglist) { while(iter != msglist.constBegin()) { iter--; - if(!fastForward && (*iter).msgId() < minId) + if(!fastForward && (*iter).msgId() <= minId) break; processedMsgs++; @@ -250,7 +250,7 @@ int MessageModel::insertMessagesGracefully(const QList &msglist) { } } else { while(iter != msglist.constEnd()) { - if(!fastForward && (*iter).msgId() < minId) + if(!fastForward && (*iter).msgId() <= minId) break; processedMsgs++; diff --git a/src/common/types.h b/src/common/types.h index 104deb72..fc46881e 100644 --- a/src/common/types.h +++ b/src/common/types.h @@ -95,6 +95,10 @@ Q_DECLARE_METATYPE(NetworkId) Q_DECLARE_METATYPE(IdentityId) Q_DECLARE_METATYPE(AccountId) +// a few typedefs +typedef QList MsgIdList; +typedef QList BufferIdList; + //! Base class for exceptions. struct Exception { Exception(QString msg = "Unknown Exception") : _msg(msg) {}; @@ -103,7 +107,6 @@ struct Exception { protected: QString _msg; - }; #endif diff --git a/src/qtui/mainwin.cpp b/src/qtui/mainwin.cpp index b12fad43..5a484fe0 100644 --- a/src/qtui/mainwin.cpp +++ b/src/qtui/mainwin.cpp @@ -35,6 +35,8 @@ #include "actioncollection.h" #include "buffermodel.h" #include "bufferview.h" +#include "bufferviewoverlay.h" +#include "bufferviewoverlayfilter.h" #include "bufferwidget.h" #include "channellistdlg.h" #include "chatlinemodel.h" @@ -255,6 +257,8 @@ void MainWin::setupActions() { qApp, SLOT(aboutQt()))); coll->addAction("DebugNetworkModel", new Action(SmallIcon("tools-report-bug"), tr("Debug &NetworkModel"), coll, this, SLOT(on_actionDebugNetworkModel_triggered()))); + coll->addAction("DebugBufferViewOverlay", new Action(SmallIcon("tools-report-bug"), tr("Debug &BufferViewOverlay"), coll, + this, SLOT(on_actionDebugBufferViewOverlay_triggered()))); coll->addAction("DebugMessageModel", new Action(SmallIcon("tools-report-bug"), tr("Debug &MessageModel"), coll, this, SLOT(on_actionDebugMessageModel_triggered()))); coll->addAction("DebugLog", new Action(SmallIcon("tools-report-bug"), tr("Debug &Log"), coll, @@ -315,6 +319,7 @@ void MainWin::setupMenus() { _helpMenu->addSeparator(); _helpDebugMenu = _helpMenu->addMenu(SmallIcon("tools-report-bug"), tr("Debug")); _helpDebugMenu->addAction(coll->action("DebugNetworkModel")); + _helpDebugMenu->addAction(coll->action("DebugBufferViewOverlay")); _helpDebugMenu->addAction(coll->action("DebugMessageModel")); _helpDebugMenu->addAction(coll->action("DebugLog")); } @@ -351,6 +356,7 @@ void MainWin::addBufferView(ClientBufferViewConfig *config) { addDockWidget(Qt::LeftDockWidgetArea, dock); _bufferViewsMenu->addAction(dock->toggleViewAction()); + connect(dock->toggleViewAction(), SIGNAL(toggled(bool)), this, SLOT(bufferViewToggled(bool))); _bufferViews.append(dock); } @@ -370,6 +376,35 @@ void MainWin::removeBufferView(int bufferViewConfigId) { } } +void MainWin::bufferViewToggled(bool enabled) { + QAction *action = qobject_cast(sender()); + Q_ASSERT(action); + BufferViewDock *dock = qobject_cast(action->parent()); + Q_ASSERT(dock); + if(enabled) { + Client::bufferViewOverlay()->addView(dock->bufferViewId()); + BufferViewConfig *config = dock->config(); + if(config && config->isInitialized()) { + BufferIdList buffers; + if(config->networkId().isValid()) { + foreach(BufferId bufferId, config->bufferList()) { + if(Client::networkModel()->networkId(bufferId) == config->networkId()) + buffers << bufferId; + } + foreach(BufferId bufferId, config->temporarilyRemovedBuffers().toList()) { + if(Client::networkModel()->networkId(bufferId) == config->networkId()) + buffers << bufferId; + } + } else { + buffers = BufferIdList::fromSet(config->bufferList().toSet() + config->temporarilyRemovedBuffers()); + } + Client::backlogManager()->checkForBacklog(buffers); + } + } else { + Client::bufferViewOverlay()->removeView(dock->bufferViewId()); + } +} + BufferView *MainWin::allBuffersView() const { // "All Buffers" is always the first dock created if(_bufferViews.count() > 0) @@ -897,6 +932,20 @@ void MainWin::on_actionDebugNetworkModel_triggered() { view->show(); } +void MainWin::on_actionDebugBufferViewOverlay_triggered() { + QTreeView *view = new QTreeView; + view->setAttribute(Qt::WA_DeleteOnClose); + view->setWindowTitle("Debug BufferViewOverlay View"); + BufferViewOverlayFilter *filter = new BufferViewOverlayFilter(Client::bufferModel(), Client::bufferViewOverlay()); + filter->setParent(view); + view->setModel(filter); + view->setColumnWidth(0, 250); + view->setColumnWidth(1, 250); + view->setColumnWidth(2, 80); + view->resize(610, 300); + view->show(); +} + void MainWin::on_actionDebugMessageModel_triggered() { QTableView *view = new QTableView(0); DebugMessageModelFilter *filter = new DebugMessageModelFilter(view); diff --git a/src/qtui/mainwin.h b/src/qtui/mainwin.h index 000e5704..76bf35eb 100644 --- a/src/qtui/mainwin.h +++ b/src/qtui/mainwin.h @@ -112,6 +112,7 @@ class MainWin void on_actionConfigureViews_triggered(); void on_actionLockLayout_toggled(bool lock); void on_actionDebugNetworkModel_triggered(); + void on_actionDebugBufferViewOverlay_triggered(); void on_actionDebugMessageModel_triggered(); void on_actionDebugLog_triggered(); @@ -125,6 +126,8 @@ class MainWin void loadLayout(); void saveLayout(); + void bufferViewToggled(bool enabled); + signals: void connectToCore(const QVariantMap &connInfo); void disconnectFromCore(); diff --git a/src/uisupport/CMakeLists.txt b/src/uisupport/CMakeLists.txt index d3da1e1f..92fc9953 100644 --- a/src/uisupport/CMakeLists.txt +++ b/src/uisupport/CMakeLists.txt @@ -11,6 +11,7 @@ set(SOURCES actioncollection.cpp bufferview.cpp bufferviewfilter.cpp + bufferviewoverlayfilter.cpp clearablelineedit.cpp clickablelabel.cpp colorbutton.cpp @@ -37,6 +38,7 @@ set(MOC_HDRS actioncollection.h bufferview.h bufferviewfilter.h + bufferviewoverlayfilter.h clearablelineedit.h clickablelabel.h colorbutton.h diff --git a/src/uisupport/abstractbuffercontainer.cpp b/src/uisupport/abstractbuffercontainer.cpp index 88fb4348..9861d14b 100644 --- a/src/uisupport/abstractbuffercontainer.cpp +++ b/src/uisupport/abstractbuffercontainer.cpp @@ -20,6 +20,7 @@ #include "abstractbuffercontainer.h" #include "client.h" +#include "clientbacklogmanager.h" #include "networkmodel.h" AbstractBufferContainer::AbstractBufferContainer(QWidget *parent) @@ -93,5 +94,6 @@ void AbstractBufferContainer::setCurrentBuffer(BufferId bufferId) { _currentBuffer = bufferId; showChatView(bufferId); Client::networkModel()->clearBufferActivity(bufferId); + Client::backlogManager()->checkForBacklog(bufferId); setFocus(); } diff --git a/src/uisupport/bufferview.cpp b/src/uisupport/bufferview.cpp index 086af0aa..4111ad3a 100644 --- a/src/uisupport/bufferview.cpp +++ b/src/uisupport/bufferview.cpp @@ -598,3 +598,22 @@ void BufferViewDock::bufferViewRenamed(const QString &newName) { setWindowTitle(newName); toggleViewAction()->setText(newName); } + +int BufferViewDock::bufferViewId() const { + BufferView *view = bufferView(); + if(!view) + return 0; + + if(view->config()) + return view->config()->bufferViewId(); + else + return 0; +} + +BufferViewConfig *BufferViewDock::config() const { + BufferView *view = bufferView(); + if(!view) + return 0; + else + return view->config(); +} diff --git a/src/uisupport/bufferview.h b/src/uisupport/bufferview.h index 0b826e04..b2d1e0ed 100644 --- a/src/uisupport/bufferview.h +++ b/src/uisupport/bufferview.h @@ -135,6 +135,8 @@ class BufferViewDock : public QDockWidget { public: BufferViewDock(BufferViewConfig *config, QWidget *parent); + int bufferViewId() const; + BufferViewConfig *config() const; inline BufferView *bufferView() const { return qobject_cast(widget()); } public slots: diff --git a/src/uisupport/bufferviewoverlayfilter.cpp b/src/uisupport/bufferviewoverlayfilter.cpp new file mode 100644 index 00000000..97a3246e --- /dev/null +++ b/src/uisupport/bufferviewoverlayfilter.cpp @@ -0,0 +1,103 @@ +/*************************************************************************** + * Copyright (C) 2005-09 by the Quassel Project * + * 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 "bufferviewoverlayfilter.h" + +#include "bufferviewoverlay.h" +#include "networkmodel.h" +#include "types.h" + +BufferViewOverlayFilter::BufferViewOverlayFilter(QAbstractItemModel *model, BufferViewOverlay *overlay) + : QSortFilterProxyModel(model), + _overlay(0) +{ + setOverlay(overlay); + setSourceModel(model); + + setDynamicSortFilter(true); +} + +void BufferViewOverlayFilter::setOverlay(BufferViewOverlay *overlay) { + if(_overlay == overlay) + return; + + if(_overlay) { + disconnect(_overlay, 0, this, 0); + } + + _overlay = overlay; + + if(!overlay) { + invalidate(); + return; + } + + connect(overlay, SIGNAL(destroyed()), this, SLOT(overlayDestroyed())); + connect(overlay, SIGNAL(hasChanged()), this, SLOT(invalidate())); + invalidate(); +} + +void BufferViewOverlayFilter::overlayDestroyed() { + setOverlay(0); +} + +bool BufferViewOverlayFilter::filterAcceptsRow(int source_row, const QModelIndex &source_parent) const { + if(!_overlay) + return false; + + QModelIndex source_bufferIndex = sourceModel()->index(source_row, 0, source_parent); + + if(!source_bufferIndex.isValid()) { + qWarning() << "filterAcceptsRow has been called with an invalid Child"; + return false; + } + + NetworkId networkId = sourceModel()->data(source_bufferIndex, NetworkModel::NetworkIdRole).value(); + if(!_overlay->networkIds().contains(networkId) && ! _overlay->allNetworks()) + return false; + + int activityLevel = sourceModel()->data(source_bufferIndex, NetworkModel::BufferActivityRole).toInt(); + if(_overlay->minimumActivity() > activityLevel) + return false; + + bool isActive = sourceModel()->data(source_bufferIndex, NetworkModel::ItemActiveRole).toBool(); + if(_overlay->hideInactiveBuffers() && !isActive && activityLevel <= BufferInfo::OtherActivity) + return false; + + int bufferType = sourceModel()->data(source_bufferIndex, NetworkModel::BufferTypeRole).toInt(); + if(!(_overlay->allowedBufferTypes() & bufferType)) + return false; + + BufferId bufferId = sourceModel()->data(source_bufferIndex, NetworkModel::BufferIdRole).value(); + Q_ASSERT(bufferId.isValid()); + + if(_overlay->bufferIds().contains(bufferId)) + return true; + + if(_overlay->tempRemovedBufferIds().contains(bufferId)) + return activityLevel > BufferInfo::OtherActivity; + + if(_overlay->removedBufferIds().contains(bufferId)) + return false; + + // the buffer is not known to us + return _overlay->addBuffersAutomatically(); +} + diff --git a/src/uisupport/bufferviewoverlayfilter.h b/src/uisupport/bufferviewoverlayfilter.h new file mode 100644 index 00000000..706d3acb --- /dev/null +++ b/src/uisupport/bufferviewoverlayfilter.h @@ -0,0 +1,48 @@ +/*************************************************************************** + * Copyright (C) 2005-09 by the Quassel Project * + * 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 BUFFERVIEWOVERLAYFILTER_H_ +#define BUFFERVIEWOVERLAYFILTER_H_ + +#include + +#include "types.h" + +class BufferViewOverlay; + +class BufferViewOverlayFilter : public QSortFilterProxyModel { + Q_OBJECT + +public: + BufferViewOverlayFilter(QAbstractItemModel *model, BufferViewOverlay *overlay = 0); + + void setOverlay(BufferViewOverlay *overlay); + +protected: + bool filterAcceptsRow(int source_row, const QModelIndex &source_parent) const; + +private slots: + void overlayDestroyed(); + +private: + BufferViewOverlay *_overlay; +}; + +#endif // BUFFERVIEWOVERLAYFILTER_H_