From: Marcus Eggenberger Date: Fri, 9 Jan 2009 02:24:22 +0000 (+0100) Subject: Quassel no longer gets a nervous breakdown when you select too many buffers - fixes... X-Git-Tag: 0.4.0~253 X-Git-Url: https://git.quassel-irc.org/?p=quassel.git;a=commitdiff_plain;h=73696998505c35c02bd019f78e9f502cbc36da5b Quassel no longer gets a nervous breakdown when you select too many buffers - fixes #432 --- diff --git a/src/client/buffermodel.cpp b/src/client/buffermodel.cpp index de415503..2c003f33 100644 --- a/src/client/buffermodel.cpp +++ b/src/client/buffermodel.cpp @@ -23,7 +23,6 @@ #include #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) { diff --git a/src/client/buffermodel.h b/src/client/buffermodel.h index 37f8916c..812bc84b 100644 --- a/src/client/buffermodel.h +++ b/src/client/buffermodel.h @@ -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 index 84cd9fe0..00000000 --- a/src/client/mappedselectionmodel.cpp +++ /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 -#include -#include -#include -#include - -MappedSelectionModel::MappedSelectionModel(QAbstractItemModel *model) - : QItemSelectionModel(model) -{ -} - -QModelIndex MappedSelectionModel::mapFromSource(const QModelIndex &sourceIndex) { - QModelIndex proxyIndex = sourceIndex; - QLinkedList proxies; - const QAbstractItemModel *baseModel = model(); - const QAbstractProxyModel *proxyModel = 0; - while((proxyModel = qobject_cast(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 proxies; - const QAbstractItemModel *baseModel = model(); - const QAbstractProxyModel *proxyModel = 0; - while((proxyModel = qobject_cast(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 index 9641658a..00000000 --- a/src/client/mappedselectionmodel.h +++ /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 -#include -#include -#include - -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 diff --git a/src/client/selectionmodelsynchronizer.cpp b/src/client/selectionmodelsynchronizer.cpp index d533ea4a..01d74fe6 100644 --- a/src/client/selectionmodelsynchronizer.cpp +++ b/src/client/selectionmodelsynchronizer.cpp @@ -22,7 +22,6 @@ #include -#include "mappedselectionmodel.h" #include #include @@ -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(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 ¤t, const QModelIndex &previous) { +void SelectionModelSynchronizer::selectionModelDestroyed(QObject *object) { + QItemSelectionModel *model = static_cast(object); + QSet::iterator iter = _selectionModels.begin(); + while(iter != _selectionModels.end()) { + if(*iter == model) { + iter = _selectionModels.erase(iter); + } else { + iter++; + } + } +} + +void SelectionModelSynchronizer::syncedCurrentChanged(const QModelIndex ¤t, const QModelIndex &previous) { Q_UNUSED(previous); + + if(!_changeCurrentEnabled) + return; + QItemSelectionModel *selectionModel = qobject_cast(sender()); Q_ASSERT(selectionModel); QModelIndex newSourceCurrent = mapToSource(current, selectionModel); @@ -90,16 +106,79 @@ void SelectionModelSynchronizer::mappedCurrentChanged(const QModelIndex ¤t 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(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 proxyModels; + const QAbstractItemModel *baseModel = selectionModel->model(); + const QAbstractProxyModel *proxyModel = 0; + while((proxyModel = qobject_cast(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 proxyModels; + const QAbstractItemModel *baseModel = selectionModel->model(); + const QAbstractProxyModel *proxyModel = 0; + while((proxyModel = qobject_cast(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 ¤t, const QModelIndex &previous) { Q_UNUSED(previous); - emit setCurrentIndex(current, QItemSelectionModel::Current); + + _changeCurrentEnabled = false; + QSet::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::iterator iter = _selectionModels.begin(); + while(iter != _selectionModels.end()) { + (*iter)->select(mapSelectionFromSource(currentSelection(), (*iter)), QItemSelectionModel::ClearAndSelect); + iter++; + } + _changeSelectionEnabled = true; } diff --git a/src/client/selectionmodelsynchronizer.h b/src/client/selectionmodelsynchronizer.h index 2e153b65..b43ef26d 100644 --- a/src/client/selectionmodelsynchronizer.h +++ b/src/client/selectionmodelsynchronizer.h @@ -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 ¤t, QItemSelectionModel::SelectionFlags command); - void select(const QItemSelection &selected, QItemSelectionModel::SelectionFlags command); - private slots: - void mappedCurrentChanged(const QModelIndex ¤t, const QModelIndex &previous); - void mappedSelectionChanged(const QItemSelection &selected, const QItemSelection &previous); + void syncedCurrentChanged(const QModelIndex ¤t, 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 ¤t, 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 _selectionModels; }; #endif diff --git a/src/uisupport/bufferview.cpp b/src/uisupport/bufferview.cpp index a1435a6d..aa349f62 100644 --- a/src/uisupport/bufferview.cpp +++ b/src/uisupport/bufferview.cpp @@ -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(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) { diff --git a/src/uisupport/bufferviewfilter.cpp b/src/uisupport/bufferviewfilter.cpp index 4d4d47d4..bb67e506 100644 --- a/src/uisupport/bufferviewfilter.cpp +++ b/src/uisupport/bufferviewfilter.cpp @@ -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(); }