Introduce QtUiStyleSettings and make highlight color configurable again
[quassel.git] / src / client / selectionmodelsynchronizer.cpp
1 /***************************************************************************
2  *   Copyright (C) 2005-08 by the Quassel Project                          *
3  *   devel@quassel-irc.org                                                 *
4  *                                                                         *
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.                                           *
9  *                                                                         *
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.                          *
14  *                                                                         *
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  ***************************************************************************/
20
21 #include "selectionmodelsynchronizer.h"
22
23
24 #include <QAbstractItemModel>
25 #include "mappedselectionmodel.h"
26 #include <QAbstractProxyModel>
27
28 #include <QDebug>
29
30 SelectionModelSynchronizer::SelectionModelSynchronizer(QAbstractItemModel *parent)
31   : QObject(parent),
32     _model(parent),
33     _selectionModel(parent)
34 {
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 &)));
39 }
40
41 bool SelectionModelSynchronizer::checkBaseModel(QItemSelectionModel *selectionModel) {
42   if(!selectionModel)
43     return false;
44
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())
50       break;
51   }
52   return baseModel == model();
53 }
54
55 void SelectionModelSynchronizer::addSelectionModel(QItemSelectionModel *selectionModel) {
56   if(!checkBaseModel(selectionModel)) {
57     qWarning() << "cannot Syncronize SelectionModel" << selectionModel << "which has a different baseModel()";
58     return;
59   }
60
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)));
65
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)));
71   } else {
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)));
76   }
77 }
78
79 void SelectionModelSynchronizer::removeSelectionModel(QItemSelectionModel *model) {
80   disconnect(model, 0, this, 0);
81   disconnect(this, 0, model, 0);
82 }
83
84 void SelectionModelSynchronizer::mappedCurrentChanged(const QModelIndex &current, const QModelIndex &previous) {
85   Q_UNUSED(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);
91 }
92
93 void SelectionModelSynchronizer::mappedSelectionChanged(const QItemSelection &selected, const QItemSelection &deselected) {
94   Q_UNUSED(selected);
95   Q_UNUSED(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);
103 }
104
105 QModelIndex SelectionModelSynchronizer::mapToSource(const QModelIndex &index, QItemSelectionModel *selectionModel) {
106   Q_ASSERT(selectionModel);
107
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())
115       break;
116   }
117   return sourceIndex;
118 }
119
120 QItemSelection SelectionModelSynchronizer::mapSelectionToSource(const QItemSelection &selection, QItemSelectionModel *selectionModel) {
121   Q_ASSERT(selectionModel);
122
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())
130       break;
131   }
132   return sourceSelection;
133 }
134
135 void SelectionModelSynchronizer::setCurrentIndex(const QModelIndex &index) {
136   _selectionModel.setCurrentIndex(index, QItemSelectionModel::Current);
137 }
138 void SelectionModelSynchronizer::setCurrentSelection(const QItemSelection &selection) {
139   _selectionModel.select(selection, QItemSelectionModel::Rows | QItemSelectionModel::ClearAndSelect);
140 }
141
142 void SelectionModelSynchronizer::currentChanged(const QModelIndex &current, const QModelIndex &previous) {
143   Q_UNUSED(previous);
144   emit setCurrentIndex(current, QItemSelectionModel::Current);
145 }
146
147 void SelectionModelSynchronizer::selectionChanged(const QItemSelection &selected, const QItemSelection &deselected) {
148   Q_UNUSED(selected);
149   Q_UNUSED(deselected);
150   emit select(_selectionModel.selection(), QItemSelectionModel::ClearAndSelect);
151 }