Quassel no longer gets a nervous breakdown when you select too many buffers - fixes...
authorMarcus Eggenberger <egs@quassel-irc.org>
Fri, 9 Jan 2009 02:24:22 +0000 (03:24 +0100)
committerMarcus Eggenberger <egs@quassel-irc.org>
Fri, 9 Jan 2009 02:24:59 +0000 (03:24 +0100)
src/client/buffermodel.cpp
src/client/buffermodel.h
src/client/mappedselectionmodel.cpp [deleted file]
src/client/mappedselectionmodel.h [deleted file]
src/client/selectionmodelsynchronizer.cpp
src/client/selectionmodelsynchronizer.h
src/uisupport/bufferview.cpp
src/uisupport/bufferviewfilter.cpp

index de41550..2c003f3 100644 (file)
@@ -23,7 +23,6 @@
 #include <QAbstractItemView>
 
 #include "client.h"
-#include "mappedselectionmodel.h"
 #include "networkmodel.h"
 #include "quassel.h"
 
@@ -49,16 +48,8 @@ bool BufferModel::filterAcceptsRow(int sourceRow, const QModelIndex &parent) con
   return false;
 }
 
-void BufferModel::synchronizeSelectionModel(MappedSelectionModel *selectionModel) {
-  _selectionModelSynchronizer.addSelectionModel(selectionModel);
-}
-
 void BufferModel::synchronizeView(QAbstractItemView *view) {
-  MappedSelectionModel *mappedSelectionModel = new MappedSelectionModel(view->model());
-  _selectionModelSynchronizer.addSelectionModel(mappedSelectionModel);
-  Q_ASSERT(mappedSelectionModel);
-  delete view->selectionModel();
-  view->setSelectionModel(mappedSelectionModel);
+  _selectionModelSynchronizer.synchronizeSelectionModel(view->selectionModel());
 }
 
 void BufferModel::setCurrentIndex(const QModelIndex &newCurrent) {
index 37f8916..812bc84 100644 (file)
@@ -28,7 +28,6 @@
 #include "selectionmodelsynchronizer.h"
 
 class NetworkModel;
-class MappedSelectionModel;
 class QAbstractItemView;
 
 class BufferModel : public QSortFilterProxyModel {
@@ -42,7 +41,7 @@ public:
   inline const SelectionModelSynchronizer *selectionModelSynchronizer() const { return &_selectionModelSynchronizer; }
   inline QItemSelectionModel *standardSelectionModel() const { return _selectionModelSynchronizer.selectionModel(); }
   
-  void synchronizeSelectionModel(MappedSelectionModel *selectionModel);
+  inline void synchronizeSelectionModel(QItemSelectionModel *selectionModel) { _selectionModelSynchronizer.synchronizeSelectionModel(selectionModel); }
   void synchronizeView(QAbstractItemView *view);
 
   inline QModelIndex currentIndex() { return standardSelectionModel()->currentIndex(); }
diff --git a/src/client/mappedselectionmodel.cpp b/src/client/mappedselectionmodel.cpp
deleted file mode 100644 (file)
index 84cd9fe..0000000
+++ /dev/null
@@ -1,82 +0,0 @@
-/***************************************************************************
- *   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 "mappedselectionmodel.h"
-
-#include <QItemSelectionModel>
-#include <QAbstractItemModel>
-#include <QAbstractProxyModel>
-#include <QLinkedList>
-#include <QDebug>
-
-MappedSelectionModel::MappedSelectionModel(QAbstractItemModel *model)
-  : QItemSelectionModel(model)
-{
-}
-
-QModelIndex MappedSelectionModel::mapFromSource(const QModelIndex &sourceIndex) {
-  QModelIndex proxyIndex = sourceIndex;
-  QLinkedList<const QAbstractProxyModel *> proxies;
-  const QAbstractItemModel *baseModel = model();
-  const QAbstractProxyModel *proxyModel = 0;
-  while((proxyModel = qobject_cast<const QAbstractProxyModel *>(baseModel)) != 0) {
-    proxies.push_back(proxyModel);
-    baseModel = proxyModel->sourceModel();
-    if(baseModel == sourceIndex.model())
-      break;
-  }
-
-  while(!proxies.isEmpty()) {
-    proxyModel = proxies.takeLast();
-    proxyIndex = proxyModel->mapFromSource(proxyIndex);
-  }
-  return proxyIndex;
-}
-
-QItemSelection MappedSelectionModel::mapSelectionFromSource(const QItemSelection &sourceSelection) {
-  if(sourceSelection.isEmpty())
-    return sourceSelection;
-
-  QItemSelection proxySelection = sourceSelection;
-  QLinkedList<const QAbstractProxyModel *> proxies;
-  const QAbstractItemModel *baseModel = model();
-  const QAbstractProxyModel *proxyModel = 0;
-  while((proxyModel = qobject_cast<const QAbstractProxyModel *>(baseModel)) != 0) {
-    proxies.push_back(proxyModel);
-    baseModel = proxyModel->sourceModel();
-    if(baseModel == sourceSelection.first().model())
-      break;
-  }
-
-  while(!proxies.isEmpty()) {
-    proxyModel = proxies.takeLast();
-    proxySelection = proxyModel->mapSelectionFromSource(proxySelection);
-  }
-  return proxySelection;
-}
-                                   
-void MappedSelectionModel::mappedSetCurrentIndex(const QModelIndex &index, QItemSelectionModel::SelectionFlags command) {
-  setCurrentIndex(mapFromSource(index), command);
-}
-
-void MappedSelectionModel::mappedSelect(const QItemSelection &selection, QItemSelectionModel::SelectionFlags command) {
-  select(mapSelectionFromSource(selection), command);
-}
-
diff --git a/src/client/mappedselectionmodel.h b/src/client/mappedselectionmodel.h
deleted file mode 100644 (file)
index 9641658..0000000
+++ /dev/null
@@ -1,45 +0,0 @@
-/***************************************************************************
- *   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 _MAPPEDSELECTIONMODEL_H_
-#define _MAPPEDSELECTIONMODEL_H_
-
-#include <QObject>
-#include <QModelIndex>
-#include <QItemSelection>
-#include <QItemSelectionModel>
-
-class QAbstractProxyModel;
-
-class MappedSelectionModel : public QItemSelectionModel {
-  Q_OBJECT
-
-public:
-  MappedSelectionModel(QAbstractItemModel *model = 0);
-
-  QModelIndex mapFromSource(const QModelIndex &sourceIndex);
-  QItemSelection mapSelectionFromSource(const QItemSelection &sourceSelection);
-                                                                       
-public slots:
-  void mappedSelect(const QItemSelection &selection, QItemSelectionModel::SelectionFlags command);
-  void mappedSetCurrentIndex(const QModelIndex &index, QItemSelectionModel::SelectionFlags command);
-};
-
-#endif
index d533ea4..01d74fe 100644 (file)
@@ -22,7 +22,6 @@
 
 
 #include <QAbstractItemModel>
-#include "mappedselectionmodel.h"
 #include <QAbstractProxyModel>
 
 #include <QDebug>
@@ -30,7 +29,9 @@
 SelectionModelSynchronizer::SelectionModelSynchronizer(QAbstractItemModel *parent)
   : QObject(parent),
     _model(parent),
-    _selectionModel(parent)
+    _selectionModel(parent),
+    _changeCurrentEnabled(true),
+    _changeSelectionEnabled(true)
 {
   connect(&_selectionModel, SIGNAL(currentChanged(const QModelIndex &, const QModelIndex &)),
          this, SLOT(currentChanged(const QModelIndex &, const QModelIndex &)));
@@ -52,37 +53,52 @@ bool SelectionModelSynchronizer::checkBaseModel(QItemSelectionModel *selectionMo
   return baseModel == model();
 }
 
-void SelectionModelSynchronizer::addSelectionModel(QItemSelectionModel *selectionModel) {
+void SelectionModelSynchronizer::synchronizeSelectionModel(QItemSelectionModel *selectionModel) {
   if(!checkBaseModel(selectionModel)) {
     qWarning() << "cannot Syncronize SelectionModel" << selectionModel << "which has a different baseModel()";
     return;
   }
 
+  if(_selectionModels.contains(selectionModel)) {
+    selectionModel->setCurrentIndex(mapFromSource(currentIndex(), selectionModel), QItemSelectionModel::Current);
+    selectionModel->select(mapSelectionFromSource(currentSelection(), selectionModel), QItemSelectionModel::ClearAndSelect);
+    return;
+  }
+
   connect(selectionModel, SIGNAL(currentChanged(QModelIndex, QModelIndex)),
-         this, SLOT(mappedCurrentChanged(QModelIndex, QModelIndex)));
+         this, SLOT(syncedCurrentChanged(QModelIndex, QModelIndex)));
   connect(selectionModel, SIGNAL(selectionChanged(QItemSelection, QItemSelection)),
-         this, SLOT(mappedSelectionChanged(QItemSelection, QItemSelection)));
-
-  if(qobject_cast<MappedSelectionModel *>(selectionModel)) {
-    connect(this, SIGNAL(setCurrentIndex(QModelIndex, QItemSelectionModel::SelectionFlags)),
-           selectionModel, SLOT(mappedSetCurrentIndex(QModelIndex, QItemSelectionModel::SelectionFlags)));
-    connect(this, SIGNAL(select(QItemSelection, QItemSelectionModel::SelectionFlags)),
-           selectionModel, SLOT(mappedSelect(QItemSelection, QItemSelectionModel::SelectionFlags)));
-  } else {
-    connect(this, SIGNAL(setCurrentIndex(QModelIndex, QItemSelectionModel::SelectionFlags)),
-           selectionModel, SLOT(setCurrentIndex(QModelIndex, QItemSelectionModel::SelectionFlags)));
-    connect(this, SIGNAL(select(QItemSelection, QItemSelectionModel::SelectionFlags)),
-           selectionModel, SLOT(select(QItemSelection, QItemSelectionModel::SelectionFlags)));
-  }
+         this, SLOT(syncedSelectionChanged(QItemSelection, QItemSelection)));
+
+  connect(selectionModel, SIGNAL(destroyed(QObject *)), this, SLOT(selectionModelDestroyed(QObject *)));
+
+  _selectionModels << selectionModel;
 }
 
 void SelectionModelSynchronizer::removeSelectionModel(QItemSelectionModel *model) {
   disconnect(model, 0, this, 0);
   disconnect(this, 0, model, 0);
+  selectionModelDestroyed(model);
 }
 
-void SelectionModelSynchronizer::mappedCurrentChanged(const QModelIndex &current, const QModelIndex &previous) {
+void SelectionModelSynchronizer::selectionModelDestroyed(QObject *object) {
+  QItemSelectionModel *model = static_cast<QItemSelectionModel *>(object);
+  QSet<QItemSelectionModel *>::iterator iter = _selectionModels.begin();
+  while(iter != _selectionModels.end()) {
+    if(*iter == model) {
+      iter = _selectionModels.erase(iter);
+    } else {
+      iter++;
+    }
+  }
+}
+
+void SelectionModelSynchronizer::syncedCurrentChanged(const QModelIndex &current, const QModelIndex &previous) {
   Q_UNUSED(previous);
+
+  if(!_changeCurrentEnabled)
+    return;
+
   QItemSelectionModel *selectionModel = qobject_cast<QItemSelectionModel *>(sender());
   Q_ASSERT(selectionModel);
   QModelIndex newSourceCurrent = mapToSource(current, selectionModel);
@@ -90,16 +106,79 @@ void SelectionModelSynchronizer::mappedCurrentChanged(const QModelIndex &current
     setCurrentIndex(newSourceCurrent);
 }
 
-void SelectionModelSynchronizer::mappedSelectionChanged(const QItemSelection &selected, const QItemSelection &deselected) {
+void SelectionModelSynchronizer::syncedSelectionChanged(const QItemSelection &selected, const QItemSelection &deselected) {
   Q_UNUSED(selected);
   Q_UNUSED(deselected);
+
+  if(!_changeSelectionEnabled)
+    return;
+
   QItemSelectionModel *selectionModel = qobject_cast<QItemSelectionModel *>(sender());
   Q_ASSERT(selectionModel);
-  QItemSelection newSourceSelection = mapSelectionToSource(selectionModel->selection(), selectionModel);
-  QItemSelection currentContainsSelection = newSourceSelection;
-  currentContainsSelection.merge(currentSelection(), QItemSelectionModel::Deselect);
-  if(!currentContainsSelection.isEmpty())
-    setCurrentSelection(newSourceSelection);
+
+  QItemSelection mappedSelection = selectionModel->selection();
+  QItemSelection currentSelectionMapped = mapSelectionFromSource(currentSelection(), selectionModel);
+
+  QItemSelection checkSelection = currentSelectionMapped;
+  checkSelection.merge(mappedSelection, QItemSelectionModel::Deselect);
+  if(checkSelection.isEmpty()) {
+    // that means the new selection contains the current selection (currentSel - newSel = {})
+    checkSelection = mappedSelection;
+    checkSelection.merge(currentSelectionMapped, QItemSelectionModel::Deselect);
+    if(checkSelection.isEmpty()) {
+      // that means the current selection contains the new selection (newSel - currentSel = {})
+      // -> currentSel == newSel
+      return;
+    }
+  }
+  setCurrentSelection(mapSelectionToSource(mappedSelection, selectionModel));
+}
+
+QModelIndex SelectionModelSynchronizer::mapFromSource(const QModelIndex &sourceIndex, const QItemSelectionModel *selectionModel) {
+  Q_ASSERT(selectionModel);
+
+  QModelIndex mappedIndex = sourceIndex;
+
+  // make a list of all involved proxies, wie have to traverse backwards
+  QList<const QAbstractProxyModel *> proxyModels;
+  const QAbstractItemModel *baseModel = selectionModel->model();
+  const QAbstractProxyModel *proxyModel = 0;
+  while((proxyModel = qobject_cast<const QAbstractProxyModel *>(baseModel)) != 0) {
+    if(baseModel == model())
+      break;
+    proxyModels << proxyModel;
+    baseModel = proxyModel->sourceModel();
+  }
+
+  // now traverse it;
+  for(int i = proxyModels.count() - 1; i >= 0; i--) {
+    mappedIndex = proxyModels[i]->mapFromSource(mappedIndex);
+  }
+  
+  return mappedIndex;
+}
+
+QItemSelection SelectionModelSynchronizer::mapSelectionFromSource(const QItemSelection &sourceSelection, const QItemSelectionModel *selectionModel) {
+  Q_ASSERT(selectionModel);
+
+  QItemSelection mappedSelection = sourceSelection;
+
+  // make a list of all involved proxies, wie have to traverse backwards
+  QList<const QAbstractProxyModel *> proxyModels;
+  const QAbstractItemModel *baseModel = selectionModel->model();
+  const QAbstractProxyModel *proxyModel = 0;
+  while((proxyModel = qobject_cast<const QAbstractProxyModel *>(baseModel)) != 0) {
+    if(baseModel == model())
+      break;
+    proxyModels << proxyModel;
+    baseModel = proxyModel->sourceModel();
+  }
+
+  // now traverse it;
+  for(int i = proxyModels.count() - 1; i >= 0; i--) {
+    mappedSelection = proxyModels[i]->mapSelectionFromSource(mappedSelection);
+  }
+  return mappedSelection;
 }
 
 QModelIndex SelectionModelSynchronizer::mapToSource(const QModelIndex &index, QItemSelectionModel *selectionModel) {
@@ -136,16 +215,30 @@ void SelectionModelSynchronizer::setCurrentIndex(const QModelIndex &index) {
   _selectionModel.setCurrentIndex(index, QItemSelectionModel::Current);
 }
 void SelectionModelSynchronizer::setCurrentSelection(const QItemSelection &selection) {
-  _selectionModel.select(selection, QItemSelectionModel::Rows | QItemSelectionModel::ClearAndSelect);
+  _selectionModel.select(selection, QItemSelectionModel::ClearAndSelect);
 }
 
 void SelectionModelSynchronizer::currentChanged(const QModelIndex &current, const QModelIndex &previous) {
   Q_UNUSED(previous);
-  emit setCurrentIndex(current, QItemSelectionModel::Current);
+
+  _changeCurrentEnabled = false;
+  QSet<QItemSelectionModel *>::iterator iter = _selectionModels.begin();
+  while(iter != _selectionModels.end()) {
+    (*iter)->setCurrentIndex(mapFromSource(current, (*iter)), QItemSelectionModel::Current);
+    iter++;
+  }
+  _changeCurrentEnabled = true;
 }
 
 void SelectionModelSynchronizer::selectionChanged(const QItemSelection &selected, const QItemSelection &deselected) {
   Q_UNUSED(selected);
   Q_UNUSED(deselected);
-  emit select(_selectionModel.selection(), QItemSelectionModel::ClearAndSelect);
+
+  _changeSelectionEnabled = false;
+  QSet<QItemSelectionModel *>::iterator iter = _selectionModels.begin();
+  while(iter != _selectionModels.end()) {
+    (*iter)->select(mapSelectionFromSource(currentSelection(), (*iter)), QItemSelectionModel::ClearAndSelect);
+    iter++;
+  }
+  _changeSelectionEnabled = true;
 }
index 2e153b6..b43ef26 100644 (file)
@@ -32,7 +32,7 @@ class SelectionModelSynchronizer : public QObject {
 public:
   SelectionModelSynchronizer(QAbstractItemModel *parent = 0);
 
-  void addSelectionModel(QItemSelectionModel *selectionModel);
+  void synchronizeSelectionModel(QItemSelectionModel *selectionModel);
   void removeSelectionModel(QItemSelectionModel *selectionModel);
 
   inline QAbstractItemModel *model() { return _model; }
@@ -40,13 +40,9 @@ public:
   inline QModelIndex currentIndex() const { return _selectionModel.currentIndex(); }
   inline QItemSelection currentSelection() const { return _selectionModel.selection(); }
 
-signals:
-  void setCurrentIndex(const QModelIndex &current, QItemSelectionModel::SelectionFlags command);
-  void select(const QItemSelection &selected, QItemSelectionModel::SelectionFlags command);
-
 private slots:
-  void mappedCurrentChanged(const QModelIndex &current, const QModelIndex &previous);
-  void mappedSelectionChanged(const QItemSelection &selected, const QItemSelection &previous);
+  void syncedCurrentChanged(const QModelIndex &current, const QModelIndex &previous);
+  void syncedSelectionChanged(const QItemSelection &selected, const QItemSelection &previous);
 
   void setCurrentIndex(const QModelIndex &index);
   void setCurrentSelection(const QItemSelection &selection);
@@ -54,15 +50,21 @@ private slots:
   void currentChanged(const QModelIndex &current, const QModelIndex &previous);
   void selectionChanged(const QItemSelection &selected, const QItemSelection &deselected);
 
+  void selectionModelDestroyed(QObject *object);
+
 private:
   QAbstractItemModel *_model;
   QItemSelectionModel _selectionModel;
+  bool _changeCurrentEnabled;
+  bool _changeSelectionEnabled;
 
   bool checkBaseModel(QItemSelectionModel *model);
+  QModelIndex mapFromSource(const QModelIndex &sourceIndex, const QItemSelectionModel *selectionModel);
+  QItemSelection mapSelectionFromSource(const QItemSelection &sourceSelection, const QItemSelectionModel *selectionModel);
   QModelIndex mapToSource(const QModelIndex &index, QItemSelectionModel *selectionModel);
   QItemSelection mapSelectionToSource(const QItemSelection &selection, QItemSelectionModel *selectionModel);
 
-
+  QSet<QItemSelectionModel *> _selectionModels;
 };
 
 #endif
index a1435a6..aa349f6 100644 (file)
@@ -36,7 +36,6 @@
 #include "buffersyncer.h"
 #include "client.h"
 #include "iconloader.h"
-#include "mappedselectionmodel.h"
 #include "network.h"
 #include "networkmodel.h"
 #include "networkmodelactionprovider.h"
@@ -347,13 +346,12 @@ void BufferView::on_configChanged() {
       collapse(networkIdx);
   }
 
-  // update selection to current one
-  MappedSelectionModel *mappedSelectionModel = qobject_cast<MappedSelectionModel *>(selectionModel());
-  if(!config() || !mappedSelectionModel)
-    return;
+  if(config()) {
+    // update selection to current one
+    Client::bufferModel()->synchronizeView(this);
+  }
 
-  mappedSelectionModel->mappedSetCurrentIndex(Client::bufferModel()->standardSelectionModel()->currentIndex(), QItemSelectionModel::Current);
-  mappedSelectionModel->mappedSelect(Client::bufferModel()->standardSelectionModel()->selection(), QItemSelectionModel::ClearAndSelect | QItemSelectionModel::Rows);
+  return;
 }
 
 void BufferView::on_collapse(const QModelIndex &index) {
index 4d4d47d..bb67e50 100644 (file)
@@ -97,6 +97,7 @@ void BufferViewFilter::setConfig(BufferViewConfig *config) {
 
   if(!config) {
     invalidate();
+    setObjectName("");
     return;
   }
 
@@ -127,6 +128,8 @@ void BufferViewFilter::configInitialized() {
 
   disconnect(config(), SIGNAL(initDone()), this, SLOT(configInitialized()));
 
+  setObjectName(config()->bufferViewName());
+
   invalidate();
   emit configChanged();
 }