X-Git-Url: https://git.quassel-irc.org/?p=quassel.git;a=blobdiff_plain;f=src%2Fclient%2Fselectionmodelsynchronizer.cpp;h=fe93c41b7b0fafa9bbf3984b3520b0d9308cf793;hp=625ec3f3f699a4f92ba85a0d56923cd147601aa4;hb=1a45f16a9734820fba42fe1db3f38dd1eee49df6;hpb=6f4a6454e49db703bd6336f575bbbeff95388404 diff --git a/src/client/selectionmodelsynchronizer.cpp b/src/client/selectionmodelsynchronizer.cpp index 625ec3f3..fe93c41b 100644 --- a/src/client/selectionmodelsynchronizer.cpp +++ b/src/client/selectionmodelsynchronizer.cpp @@ -1,5 +1,5 @@ /*************************************************************************** - * Copyright (C) 2005-09 by the Quassel Project * + * Copyright (C) 2005-2018 by the Quassel Project * * devel@quassel-irc.org * * * * This program is free software; you can redistribute it and/or modify * @@ -15,230 +15,266 @@ * 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. * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * ***************************************************************************/ #include "selectionmodelsynchronizer.h" - #include #include #include SelectionModelSynchronizer::SelectionModelSynchronizer(QAbstractItemModel *parent) - : QObject(parent), + : QObject(parent), _model(parent), _selectionModel(parent), _changeCurrentEnabled(true), _changeSelectionEnabled(true) { - connect(&_selectionModel, SIGNAL(currentChanged(const QModelIndex &, const QModelIndex &)), - this, SLOT(currentChanged(const QModelIndex &, const QModelIndex &))); - connect(&_selectionModel, SIGNAL(selectionChanged(const QItemSelection &, const QItemSelection &)), - this, SLOT(selectionChanged(const QItemSelection &, const QItemSelection &))); + connect(&_selectionModel, SIGNAL(currentChanged(const QModelIndex &, const QModelIndex &)), + this, SLOT(currentChanged(const QModelIndex &, const QModelIndex &))); + connect(&_selectionModel, SIGNAL(selectionChanged(const QItemSelection &, const QItemSelection &)), + this, SLOT(selectionChanged(const QItemSelection &, const QItemSelection &))); } -bool SelectionModelSynchronizer::checkBaseModel(QItemSelectionModel *selectionModel) { - if(!selectionModel) - return false; - - const QAbstractItemModel *baseModel = selectionModel->model(); - const QAbstractProxyModel *proxyModel = 0; - while((proxyModel = qobject_cast(baseModel)) != 0) { - baseModel = proxyModel->sourceModel(); - if(baseModel == model()) - break; - } - return baseModel == model(); + +bool SelectionModelSynchronizer::checkBaseModel(QItemSelectionModel *selectionModel) +{ + if (!selectionModel) + return false; + + const QAbstractItemModel *baseModel = selectionModel->model(); + const QAbstractProxyModel *proxyModel = 0; + while ((proxyModel = qobject_cast(baseModel)) != 0) { + baseModel = proxyModel->sourceModel(); + if (baseModel == model()) + break; + } + return baseModel == model(); } -void SelectionModelSynchronizer::synchronizeSelectionModel(QItemSelectionModel *selectionModel) { - if(!checkBaseModel(selectionModel)) { - qWarning() << "cannot Synchronize 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; - } +void SelectionModelSynchronizer::synchronizeSelectionModel(QItemSelectionModel *selectionModel) +{ + if (!checkBaseModel(selectionModel)) { + qWarning() << "cannot Synchronize 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(syncedCurrentChanged(QModelIndex, QModelIndex))); - connect(selectionModel, SIGNAL(selectionChanged(QItemSelection, QItemSelection)), - this, SLOT(syncedSelectionChanged(QItemSelection, QItemSelection))); + connect(selectionModel, SIGNAL(currentChanged(QModelIndex, QModelIndex)), + this, SLOT(syncedCurrentChanged(QModelIndex, QModelIndex))); + connect(selectionModel, SIGNAL(selectionChanged(QItemSelection, QItemSelection)), + this, SLOT(syncedSelectionChanged(QItemSelection, QItemSelection))); - connect(selectionModel, SIGNAL(destroyed(QObject *)), this, SLOT(selectionModelDestroyed(QObject *))); + connect(selectionModel, SIGNAL(destroyed(QObject *)), this, SLOT(selectionModelDestroyed(QObject *))); - _selectionModels << selectionModel; + _selectionModels << selectionModel; } -void SelectionModelSynchronizer::removeSelectionModel(QItemSelectionModel *model) { - disconnect(model, 0, this, 0); - disconnect(this, 0, model, 0); - selectionModelDestroyed(model); + +void SelectionModelSynchronizer::removeSelectionModel(QItemSelectionModel *model) +{ + disconnect(model, 0, this, 0); + disconnect(this, 0, model, 0); + selectionModelDestroyed(model); } -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::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; +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); - if(newSourceCurrent.isValid() && newSourceCurrent != currentIndex()) - setCurrentIndex(newSourceCurrent); + QItemSelectionModel *selectionModel = qobject_cast(sender()); + Q_ASSERT(selectionModel); + QModelIndex newSourceCurrent = mapToSource(current, selectionModel); + if (newSourceCurrent.isValid() && newSourceCurrent != currentIndex()) + setCurrentIndex(newSourceCurrent); } -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 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; + +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 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)); + 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; + +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; + +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) { - Q_ASSERT(selectionModel); - - QModelIndex sourceIndex = index; - const QAbstractItemModel *baseModel = selectionModel->model(); - const QAbstractProxyModel *proxyModel = 0; - while((proxyModel = qobject_cast(baseModel)) != 0) { - sourceIndex = proxyModel->mapToSource(sourceIndex); - baseModel = proxyModel->sourceModel(); - if(baseModel == model()) - break; - } - return sourceIndex; + +QModelIndex SelectionModelSynchronizer::mapToSource(const QModelIndex &index, QItemSelectionModel *selectionModel) +{ + Q_ASSERT(selectionModel); + + QModelIndex sourceIndex = index; + const QAbstractItemModel *baseModel = selectionModel->model(); + const QAbstractProxyModel *proxyModel = 0; + while ((proxyModel = qobject_cast(baseModel)) != 0) { + sourceIndex = proxyModel->mapToSource(sourceIndex); + baseModel = proxyModel->sourceModel(); + if (baseModel == model()) + break; + } + return sourceIndex; } -QItemSelection SelectionModelSynchronizer::mapSelectionToSource(const QItemSelection &selection, QItemSelectionModel *selectionModel) { - Q_ASSERT(selectionModel); - - QItemSelection sourceSelection = selection; - const QAbstractItemModel *baseModel = selectionModel->model(); - const QAbstractProxyModel *proxyModel = 0; - while((proxyModel = qobject_cast(baseModel)) != 0) { - sourceSelection = proxyModel->mapSelectionToSource(sourceSelection); - baseModel = proxyModel->sourceModel(); - if(baseModel == model()) - break; - } - return sourceSelection; + +QItemSelection SelectionModelSynchronizer::mapSelectionToSource(const QItemSelection &selection, QItemSelectionModel *selectionModel) +{ + Q_ASSERT(selectionModel); + + QItemSelection sourceSelection = selection; + const QAbstractItemModel *baseModel = selectionModel->model(); + const QAbstractProxyModel *proxyModel = 0; + while ((proxyModel = qobject_cast(baseModel)) != 0) { + sourceSelection = proxyModel->mapSelectionToSource(sourceSelection); + baseModel = proxyModel->sourceModel(); + if (baseModel == model()) + break; + } + return sourceSelection; } -void SelectionModelSynchronizer::setCurrentIndex(const QModelIndex &index) { - _selectionModel.setCurrentIndex(index, QItemSelectionModel::Current); + +void SelectionModelSynchronizer::setCurrentIndex(const QModelIndex &index) +{ + _selectionModel.setCurrentIndex(index, QItemSelectionModel::Current); } -void SelectionModelSynchronizer::setCurrentSelection(const QItemSelection &selection) { - _selectionModel.select(selection, QItemSelectionModel::ClearAndSelect); + + +void SelectionModelSynchronizer::setCurrentSelection(const QItemSelection &selection) +{ + _selectionModel.select(selection, QItemSelectionModel::ClearAndSelect); } -void SelectionModelSynchronizer::currentChanged(const QModelIndex ¤t, const QModelIndex &previous) { - Q_UNUSED(previous); - _changeCurrentEnabled = false; - QSet::iterator iter = _selectionModels.begin(); - while(iter != _selectionModels.end()) { - (*iter)->setCurrentIndex(mapFromSource(current, (*iter)), QItemSelectionModel::Current); - iter++; - } - _changeCurrentEnabled = true; +void SelectionModelSynchronizer::currentChanged(const QModelIndex ¤t, const QModelIndex &previous) +{ + Q_UNUSED(previous); + + _changeCurrentEnabled = false; + QSet::iterator iter = _selectionModels.begin(); + while (iter != _selectionModels.end()) { + (*iter)->setCurrentIndex(mapFromSource(current, (*iter)), QItemSelectionModel::Current); + ++iter; + } + _changeCurrentEnabled = true; + + // Trigger a dataChanged() signal from the base model to update all proxy models (e.g. filters). + // Since signals are protected, we have to use invokeMethod for faking signal emission. + if (previous.isValid()) { + QMetaObject::invokeMethod(model(), "dataChanged", Qt::DirectConnection, + Q_ARG(QModelIndex, previous), Q_ARG(QModelIndex, previous)); + } } -void SelectionModelSynchronizer::selectionChanged(const QItemSelection &selected, const QItemSelection &deselected) { - Q_UNUSED(selected); - Q_UNUSED(deselected); - - _changeSelectionEnabled = false; - QSet::iterator iter = _selectionModels.begin(); - while(iter != _selectionModels.end()) { - (*iter)->select(mapSelectionFromSource(currentSelection(), (*iter)), QItemSelectionModel::ClearAndSelect); - iter++; - } - _changeSelectionEnabled = true; + +void SelectionModelSynchronizer::selectionChanged(const QItemSelection &selected, const QItemSelection &deselected) +{ + Q_UNUSED(selected); + Q_UNUSED(deselected); + + _changeSelectionEnabled = false; + QSet::iterator iter = _selectionModels.begin(); + while (iter != _selectionModels.end()) { + (*iter)->select(mapSelectionFromSource(currentSelection(), (*iter)), QItemSelectionModel::ClearAndSelect); + ++iter; + } + _changeSelectionEnabled = true; }