Merge branch 'bufferviewoverlay'
authorMarcus Eggenberger <egs@quassel-irc.org>
Tue, 24 Mar 2009 16:36:06 +0000 (17:36 +0100)
committerMarcus Eggenberger <egs@quassel-irc.org>
Tue, 24 Mar 2009 16:36:06 +0000 (17:36 +0100)
Conflicts:

src/client/client.cpp
src/client/client.h

21 files changed:
src/client/CMakeLists.txt
src/client/backlogrequester.cpp
src/client/backlogrequester.h
src/client/bufferviewoverlay.cpp [new file with mode: 0644]
src/client/bufferviewoverlay.h [new file with mode: 0644]
src/client/client.cpp
src/client/client.h
src/client/clientbacklogmanager.cpp
src/client/clientbacklogmanager.h
src/client/clientbufferviewmanager.cpp
src/client/clientbufferviewmanager.h
src/client/messagemodel.cpp
src/common/types.h
src/qtui/mainwin.cpp
src/qtui/mainwin.h
src/uisupport/CMakeLists.txt
src/uisupport/abstractbuffercontainer.cpp
src/uisupport/bufferview.cpp
src/uisupport/bufferview.h
src/uisupport/bufferviewoverlayfilter.cpp [new file with mode: 0644]
src/uisupport/bufferviewoverlayfilter.h [new file with mode: 0644]

index 5277844..f60f66c 100644 (file)
@@ -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
index a08227d..3aee931 100644 (file)
 #include <QObject>
 
 #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<BufferId> 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<BufferId> 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<BufferId> 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);
   }
 }
index c3c6832..8aa3627 100644 (file)
@@ -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<Message> &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<BufferId> allBufferIds() const { return Client::networkModel()->allBufferIds(); }
+  BufferIdList allBufferIds() const;
   inline void setWaitingBuffers(const QList<BufferId> &buffers) { setWaitingBuffers(buffers.toSet()); }
   void setWaitingBuffers(const QSet<BufferId> &buffers);
   void addWaitingBuffer(BufferId buffer);
@@ -62,6 +64,7 @@ protected:
 
 private:
   bool _isBuffering;
+  RequesterType _requesterType;
   MessageList _bufferedMessages;
   int _totalBuffers;
   QSet<BufferId> _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 (file)
index 0000000..66dec13
--- /dev/null
@@ -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 <QEvent>
+
+#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<BufferViewConfig *>(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<BufferViewConfig *>(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<NetworkId> networkIds;
+  QSet<BufferId> buffers;
+  QSet<BufferId> removedBuffers;
+  QSet<BufferId> tempRemovedBuffers;
+
+  if(Client::bufferViewManager()) {
+    BufferViewConfig *config = 0;
+    QSet<int>::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<BufferId> 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 (file)
index 0000000..483a330
--- /dev/null
@@ -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 <QObject>
+
+#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<NetworkId> &networkIds() const { return _networkIds; }
+  inline const QSet<BufferId> &bufferIds() const { return _buffers; }
+  inline const QSet<BufferId> &removedBufferIds() const { return _removedBuffers; }
+  inline const QSet<BufferId> &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<int> _bufferViewIds;
+
+  QSet<NetworkId> _networkIds;
+
+  bool _addBuffersAutomatically;
+  bool _hideInactiveBuffers;
+  int _allowedBufferTypes;
+  int _minimumActivity;
+
+  QSet<BufferId> _buffers;
+  QSet<BufferId> _removedBuffers;
+  QSet<BufferId> _tempRemovedBuffers;
+
+  static const int _updateEventId;
+};
+
+#endif //BUFFERVIEWOVERLAY_H
index ca219bb..d04e258 100644 (file)
@@ -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() {
index 2821ab9..0c9922a 100644 (file)
@@ -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;
 
index 6f45da3..f88c606 100644 (file)
@@ -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<BufferId> &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();
 }
index 5a8585b..5f1e1cd 100644 (file)
@@ -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<BufferId> _buffersRequested;
 };
 
+// inlines
+inline void ClientBacklogManager::checkForBacklog(BufferId bufferId) {
+  checkForBacklog(BufferIdList() << bufferId);
+}
+
 #endif // CLIENTBACKLOGMANAGER_H
index c46ff3a..d7cd837 100644 (file)
 
 #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<ClientBufferViewConfig *>(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<BufferViewConfig *>(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();
+}
index 6ecef78..0963908 100644 (file)
@@ -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
index 122156a..58e3108 100644 (file)
@@ -219,7 +219,7 @@ int MessageModel::insertMessagesGracefully(const QList<Message> &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<Message> &msglist) {
     }
   } else {
     while(iter != msglist.constEnd()) {
-      if(!fastForward && (*iter).msgId() < minId)
+      if(!fastForward && (*iter).msgId() <= minId)
        break;
       processedMsgs++;
 
index 104deb7..fc46881 100644 (file)
@@ -95,6 +95,10 @@ Q_DECLARE_METATYPE(NetworkId)
 Q_DECLARE_METATYPE(IdentityId)
 Q_DECLARE_METATYPE(AccountId)
 
+// a few typedefs
+typedef QList<MsgId> MsgIdList;
+typedef QList<BufferId> BufferIdList;
+
 //! Base class for exceptions.
 struct Exception {
   Exception(QString msg = "Unknown Exception") : _msg(msg) {};
@@ -103,7 +107,6 @@ struct Exception {
 
   protected:
     QString _msg;
-
 };
 
 #endif
index b12fad4..5a484fe 100644 (file)
@@ -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<QAction *>(sender());
+  Q_ASSERT(action);
+  BufferViewDock *dock = qobject_cast<BufferViewDock *>(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);
index 000e570..76bf35e 100644 (file)
@@ -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();
index d3da1e1..92fc995 100644 (file)
@@ -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
index 88fb434..9861d14 100644 (file)
@@ -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();
 }
index 086af0a..4111ad3 100644 (file)
@@ -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();
+}
index 0b826e0..b2d1e0e 100644 (file)
@@ -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<BufferView *>(widget()); }
 
 public slots:
diff --git a/src/uisupport/bufferviewoverlayfilter.cpp b/src/uisupport/bufferviewoverlayfilter.cpp
new file mode 100644 (file)
index 0000000..97a3246
--- /dev/null
@@ -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<NetworkId>();
+  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<BufferId>();
+  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 (file)
index 0000000..706d3ac
--- /dev/null
@@ -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 <QSortFilterProxyModel>
+
+#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_