1 /***************************************************************************
2 * Copyright (C) 2005-08 by the Quassel Project *
3 * devel@quassel-irc.org *
5 * This program is free software; you can redistribute it and/or modify *
6 * it under the terms of the GNU General Public License as published by *
7 * the Free Software Foundation; either version 2 of the License, or *
8 * (at your option) version 3. *
10 * This program is distributed in the hope that it will be useful, *
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
13 * GNU General Public License for more details. *
15 * You should have received a copy of the GNU General Public License *
16 * along with this program; if not, write to the *
17 * Free Software Foundation, Inc., *
18 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
19 ***************************************************************************/
21 #include "selectionmodelsynchronizer.h"
24 #include <QAbstractItemModel>
25 #include "mappedselectionmodel.h"
26 #include <QAbstractProxyModel>
30 SelectionModelSynchronizer::SelectionModelSynchronizer(QAbstractItemModel *parent)
33 _selectionModel(parent)
35 connect(&_selectionModel, SIGNAL(currentChanged(const QModelIndex &, const QModelIndex &)),
36 this, SLOT(currentChanged(const QModelIndex &, const QModelIndex &)));
37 connect(&_selectionModel, SIGNAL(selectionChanged(const QItemSelection &, const QItemSelection &)),
38 this, SLOT(selectionChanged(const QItemSelection &, const QItemSelection &)));
41 bool SelectionModelSynchronizer::checkBaseModel(QItemSelectionModel *selectionModel) {
45 const QAbstractItemModel *baseModel = selectionModel->model();
46 const QAbstractProxyModel *proxyModel = 0;
47 while((proxyModel = qobject_cast<const QAbstractProxyModel *>(baseModel)) != 0) {
48 baseModel = proxyModel->sourceModel();
49 if(baseModel == model())
52 return baseModel == model();
55 void SelectionModelSynchronizer::addSelectionModel(QItemSelectionModel *selectionModel) {
56 if(!checkBaseModel(selectionModel)) {
57 qWarning() << "cannot Syncronize SelectionModel" << selectionModel << "which has a different baseModel()";
61 connect(selectionModel, SIGNAL(currentChanged(QModelIndex, QModelIndex)),
62 this, SLOT(mappedCurrentChanged(QModelIndex, QModelIndex)));
63 connect(selectionModel, SIGNAL(selectionChanged(QItemSelection, QItemSelection)),
64 this, SLOT(mappedSelectionChanged(QItemSelection, QItemSelection)));
66 if(qobject_cast<MappedSelectionModel *>(selectionModel)) {
67 connect(this, SIGNAL(setCurrentIndex(QModelIndex, QItemSelectionModel::SelectionFlags)),
68 selectionModel, SLOT(mappedSetCurrentIndex(QModelIndex, QItemSelectionModel::SelectionFlags)));
69 connect(this, SIGNAL(select(QItemSelection, QItemSelectionModel::SelectionFlags)),
70 selectionModel, SLOT(mappedSelect(QItemSelection, QItemSelectionModel::SelectionFlags)));
72 connect(this, SIGNAL(setCurrentIndex(QModelIndex, QItemSelectionModel::SelectionFlags)),
73 selectionModel, SLOT(setCurrentIndex(QModelIndex, QItemSelectionModel::SelectionFlags)));
74 connect(this, SIGNAL(select(QItemSelection, QItemSelectionModel::SelectionFlags)),
75 selectionModel, SLOT(select(QItemSelection, QItemSelectionModel::SelectionFlags)));
79 void SelectionModelSynchronizer::removeSelectionModel(QItemSelectionModel *model) {
80 disconnect(model, 0, this, 0);
81 disconnect(this, 0, model, 0);
84 void SelectionModelSynchronizer::mappedCurrentChanged(const QModelIndex ¤t, const QModelIndex &previous) {
86 QItemSelectionModel *selectionModel = qobject_cast<QItemSelectionModel *>(sender());
87 Q_ASSERT(selectionModel);
88 QModelIndex newSourceCurrent = mapToSource(current, selectionModel);
89 if(newSourceCurrent.isValid() && newSourceCurrent != currentIndex())
90 setCurrentIndex(newSourceCurrent);
93 void SelectionModelSynchronizer::mappedSelectionChanged(const QItemSelection &selected, const QItemSelection &deselected) {
96 QItemSelectionModel *selectionModel = qobject_cast<QItemSelectionModel *>(sender());
97 Q_ASSERT(selectionModel);
98 QItemSelection newSourceSelection = mapSelectionToSource(selectionModel->selection(), selectionModel);
99 QItemSelection currentContainsSelection = newSourceSelection;
100 currentContainsSelection.merge(currentSelection(), QItemSelectionModel::Deselect);
101 if(!currentContainsSelection.isEmpty())
102 setCurrentSelection(newSourceSelection);
105 QModelIndex SelectionModelSynchronizer::mapToSource(const QModelIndex &index, QItemSelectionModel *selectionModel) {
106 Q_ASSERT(selectionModel);
108 QModelIndex sourceIndex = index;
109 const QAbstractItemModel *baseModel = selectionModel->model();
110 const QAbstractProxyModel *proxyModel = 0;
111 while((proxyModel = qobject_cast<const QAbstractProxyModel *>(baseModel)) != 0) {
112 sourceIndex = proxyModel->mapToSource(sourceIndex);
113 baseModel = proxyModel->sourceModel();
114 if(baseModel == model())
120 QItemSelection SelectionModelSynchronizer::mapSelectionToSource(const QItemSelection &selection, QItemSelectionModel *selectionModel) {
121 Q_ASSERT(selectionModel);
123 QItemSelection sourceSelection = selection;
124 const QAbstractItemModel *baseModel = selectionModel->model();
125 const QAbstractProxyModel *proxyModel = 0;
126 while((proxyModel = qobject_cast<const QAbstractProxyModel *>(baseModel)) != 0) {
127 sourceSelection = proxyModel->mapSelectionToSource(sourceSelection);
128 baseModel = proxyModel->sourceModel();
129 if(baseModel == model())
132 return sourceSelection;
135 void SelectionModelSynchronizer::setCurrentIndex(const QModelIndex &index) {
136 _selectionModel.setCurrentIndex(index, QItemSelectionModel::Current);
138 void SelectionModelSynchronizer::setCurrentSelection(const QItemSelection &selection) {
139 _selectionModel.select(selection, QItemSelectionModel::Rows | QItemSelectionModel::ClearAndSelect);
142 void SelectionModelSynchronizer::currentChanged(const QModelIndex ¤t, const QModelIndex &previous) {
144 emit setCurrentIndex(current, QItemSelectionModel::Current);
147 void SelectionModelSynchronizer::selectionChanged(const QItemSelection &selected, const QItemSelection &deselected) {
149 Q_UNUSED(deselected);
150 emit select(_selectionModel.selection(), QItemSelectionModel::ClearAndSelect);