1 /*
2 * Copyright (C) 2001-2015 Klaralvdalens Datakonsult AB. All rights reserved.
3 *
4 * This file is part of the KD Chart library.
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License as
8 * published by the Free Software Foundation; either version 2 of
9 * the License, or (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <https://www.gnu.org/licenses/>.
18 */
19
20 #include "KChartDatasetProxyModel.h"
21
22 #include "KChartMath_p.h"
23
24 #include <QtDebug>
25
26
27 using namespace KChart;
28
DatasetProxyModel(QObject * parent)29 DatasetProxyModel::DatasetProxyModel(QObject* parent)
30 : QSortFilterProxyModel( parent )
31 {
32 }
33
buddy(const QModelIndex & index) const34 QModelIndex DatasetProxyModel::buddy( const QModelIndex& index ) const
35 {
36 return index;
37 }
38
flags(const QModelIndex & index) const39 Qt::ItemFlags DatasetProxyModel::flags( const QModelIndex& index ) const
40 {
41 return sourceModel()->flags( mapToSource( index ) );
42 }
43
setDatasetRowDescriptionVector(const DatasetDescriptionVector & configuration)44 void DatasetProxyModel::setDatasetRowDescriptionVector(
45 const DatasetDescriptionVector& configuration )
46 {
47 Q_ASSERT_X( sourceModel(), "DatasetProxyModel::setDatasetRowDescriptionVector",
48 "A source model must be set before the selection can be configured." );
49 initializeDatasetDecriptors( configuration, sourceModel()->rowCount(mRootIndex),
50 mRowSrcToProxyMap, mRowProxyToSrcMap );
51 invalidate(); // clear emits layoutChanged()
52 }
53
setDatasetColumnDescriptionVector(const DatasetDescriptionVector & configuration)54 void DatasetProxyModel::setDatasetColumnDescriptionVector(
55 const DatasetDescriptionVector& configuration )
56 {
57 Q_ASSERT_X( sourceModel(), "DatasetProxyModel::setDatasetColumnDescriptionVector",
58 "A source model must be set before the selection can be configured." );
59 initializeDatasetDecriptors( configuration, sourceModel()->columnCount(mRootIndex),
60 mColSrcToProxyMap, mColProxyToSrcMap );
61 invalidate(); // clear emits layoutChanged()
62 }
63
setDatasetDescriptionVectors(const DatasetDescriptionVector & rowConfig,const DatasetDescriptionVector & columnConfig)64 void DatasetProxyModel::setDatasetDescriptionVectors(
65 const DatasetDescriptionVector& rowConfig,
66 const DatasetDescriptionVector& columnConfig )
67 {
68 setDatasetRowDescriptionVector( rowConfig );
69 setDatasetColumnDescriptionVector( columnConfig );
70 }
71
index(int row,int column,const QModelIndex & parent) const72 QModelIndex DatasetProxyModel::index( int row, int column,
73 const QModelIndex &parent ) const
74 {
75 return mapFromSource( sourceModel()->index( mapProxyRowToSource(row),
76 mapProxyColumnToSource(column),
77 parent ) );
78 }
79
parent(const QModelIndex & child) const80 QModelIndex DatasetProxyModel::parent( const QModelIndex& child ) const
81 {
82 // return mapFromSource( sourceModel()->parent( child ) );
83 return mapFromSource( sourceModel()->parent( mapToSource( child ) ) );
84 }
85
mapFromSource(const QModelIndex & sourceIndex) const86 QModelIndex DatasetProxyModel::mapFromSource( const QModelIndex & sourceIndex ) const
87 {
88 Q_ASSERT_X( sourceModel(), "DatasetProxyModel::mapFromSource", "A source "
89 "model must be set before the selection can be configured." );
90
91 if ( !sourceIndex.isValid() ) return sourceIndex;
92
93 if ( mRowSrcToProxyMap.isEmpty() && mColSrcToProxyMap.isEmpty() )
94 {
95 return createIndex( sourceIndex.row(), sourceIndex.column(),
96 sourceIndex.internalPointer() );
97 } else {
98 int row = mapSourceRowToProxy( sourceIndex.row() );
99 int column = mapSourceColumnToProxy( sourceIndex.column() );
100 return createIndex( row, column, sourceIndex.internalPointer() );
101 }
102 }
103
mapToSource(const QModelIndex & proxyIndex) const104 QModelIndex DatasetProxyModel::mapToSource( const QModelIndex& proxyIndex ) const
105 {
106 Q_ASSERT_X( sourceModel(), "DatasetProxyModel::mapToSource", "A source "
107 "model must be set before the selection can be configured." );
108
109 if ( !proxyIndex.isValid() ) return proxyIndex;
110 if ( mRowSrcToProxyMap.isEmpty() && mColSrcToProxyMap.isEmpty() )
111 {
112 return sourceModel()->index( proxyIndex.row(), proxyIndex.column(), mRootIndex );
113 } else {
114 int row = mapProxyRowToSource( proxyIndex.row() );
115 int column = mapProxyColumnToSource( proxyIndex.column() );
116 return sourceModel()->index( row, column, mRootIndex );
117 }
118 }
119
filterAcceptsRow(int sourceRow,const QModelIndex &) const120 bool DatasetProxyModel::filterAcceptsRow( int sourceRow,
121 const QModelIndex & ) const
122 {
123 if ( mRowSrcToProxyMap.isEmpty() )
124 { // no row mapping set, all rows are passed down:
125 return true;
126 } else {
127 Q_ASSERT( sourceModel() );
128 Q_ASSERT( mRowSrcToProxyMap.size() == sourceModel()->rowCount(mRootIndex) );
129 if ( mRowSrcToProxyMap[sourceRow] == -1 )
130 { // this row is explicitly not accepted:
131 return false;
132 } else {
133 Q_ASSERT( mRowSrcToProxyMap[sourceRow] >= 0
134 && mRowSrcToProxyMap[sourceRow] < mRowSrcToProxyMap.size() );
135 return true;
136 }
137 }
138 }
139
filterAcceptsColumn(int sourceColumn,const QModelIndex &) const140 bool DatasetProxyModel::filterAcceptsColumn( int sourceColumn,
141 const QModelIndex & ) const
142 {
143 if ( mColSrcToProxyMap.isEmpty() )
144 { // no column mapping set up yet, all columns are passed down:
145 return true;
146 } else {
147 Q_ASSERT( sourceModel() );
148 Q_ASSERT( mColSrcToProxyMap.size() == sourceModel()->columnCount(mRootIndex) );
149 if ( mColSrcToProxyMap[sourceColumn] == -1 )
150 { // this column is explicitly not accepted:
151 return false;
152 } else {
153 Q_ASSERT( mColSrcToProxyMap[sourceColumn] >= 0
154 && mColSrcToProxyMap[sourceColumn] < mColSrcToProxyMap.size() );
155 return true;
156 }
157 }
158 }
159
mapProxyRowToSource(const int & proxyRow) const160 int DatasetProxyModel::mapProxyRowToSource( const int& proxyRow ) const
161 {
162 if ( mRowProxyToSrcMap.isEmpty() )
163 { // if no row mapping is set, we pass down the row:
164 return proxyRow;
165 } else {
166 Q_ASSERT( proxyRow >= 0 && proxyRow < mRowProxyToSrcMap.size() );
167 return mRowProxyToSrcMap[ proxyRow ];
168 }
169 }
170
mapProxyColumnToSource(const int & proxyColumn) const171 int DatasetProxyModel::mapProxyColumnToSource( const int& proxyColumn ) const
172 {
173 if ( mColProxyToSrcMap.isEmpty() )
174 { // if no column mapping is set, we pass down the column:
175 return proxyColumn;
176 } else {
177 Q_ASSERT( proxyColumn >= 0 && proxyColumn < mColProxyToSrcMap.size() );
178 return mColProxyToSrcMap[ proxyColumn ];
179 }
180 }
181
mapSourceRowToProxy(const int & sourceRow) const182 int DatasetProxyModel::mapSourceRowToProxy( const int& sourceRow ) const
183 {
184 if ( mRowSrcToProxyMap.isEmpty() )
185 {
186 return sourceRow;
187 } else {
188 Q_ASSERT( sourceRow >= 0 && sourceRow < mRowSrcToProxyMap.size() );
189 return mRowSrcToProxyMap[sourceRow];
190 }
191 }
192
mapSourceColumnToProxy(const int & sourceColumn) const193 int DatasetProxyModel::mapSourceColumnToProxy( const int& sourceColumn ) const
194 {
195 if ( mColSrcToProxyMap.isEmpty() )
196 {
197 return sourceColumn;
198 } else {
199 Q_ASSERT( sourceColumn >= 0 && sourceColumn < mColSrcToProxyMap.size() );
200 return mColSrcToProxyMap.at( sourceColumn ) ;
201 }
202 }
203
resetDatasetDescriptions()204 void DatasetProxyModel::resetDatasetDescriptions()
205 {
206 mRowSrcToProxyMap.clear();
207 mRowProxyToSrcMap.clear();
208 mColSrcToProxyMap.clear();
209 mColProxyToSrcMap.clear();
210 invalidate();
211 }
212
data(const QModelIndex & index,int role) const213 QVariant DatasetProxyModel::data(const QModelIndex &index, int role) const
214 {
215 return sourceModel()->data( mapToSource( index ), role );
216 }
217
setData(const QModelIndex & index,const QVariant & value,int role)218 bool DatasetProxyModel::setData( const QModelIndex& index, const QVariant& value, int role )
219 {
220 return sourceModel()->setData( mapToSource( index ), value, role );
221 }
222
headerData(int section,Qt::Orientation orientation,int role) const223 QVariant DatasetProxyModel::headerData( int section, Qt::Orientation orientation, int role ) const
224 {
225 if ( orientation == Qt::Horizontal )
226 {
227 if ( mapProxyColumnToSource ( section ) == -1 )
228 {
229 return QVariant();
230 } else {
231 return sourceModel()->headerData( mapProxyColumnToSource( section ), orientation, role );
232 }
233 } else {
234 if ( mapProxyRowToSource ( section ) == -1 )
235 {
236 return QVariant();
237 } else {
238 return sourceModel()->headerData( mapProxyRowToSource ( section ), orientation, role );
239 }
240 }
241 }
242
initializeDatasetDecriptors(const DatasetDescriptionVector & inConfiguration,const int sourceCount,DatasetDescriptionVector & outSourceToProxyMap,DatasetDescriptionVector & outProxyToSourceMap)243 void DatasetProxyModel::initializeDatasetDecriptors(
244 const DatasetDescriptionVector& inConfiguration,
245 const int sourceCount,
246 DatasetDescriptionVector& outSourceToProxyMap,
247 DatasetDescriptionVector& outProxyToSourceMap )
248 {
249 // in the current mapping implementation, the proxy-to-source map is
250 // identical to the configuration vector:
251 outProxyToSourceMap = inConfiguration;
252 outSourceToProxyMap.fill( -1, sourceCount );
253
254 for ( int index = 0; index < inConfiguration.size(); ++index ) {
255 // make sure the values in inConfiguration point to columns in the
256 // source model:
257
258 if ( inConfiguration[index] == -1 ) {
259 continue;
260 }
261
262 Q_ASSERT_X( inConfiguration[ index ] >= 0 && inConfiguration[ index ] < sourceCount,
263 "DatasetProxyModel::initializeDatasetDecriptors",
264 "column index outside of source model" );
265 Q_ASSERT_X( outSourceToProxyMap[ inConfiguration[ index ] ] == -1 ,
266 "DatasetProxyModel::initializeDatasetDecriptors",
267 "no duplicates allowed in mapping configuration, mapping has to be reversible" );
268
269 outSourceToProxyMap[ inConfiguration[ index ] ] = index;
270 }
271 }
272
setSourceModel(QAbstractItemModel * m)273 void DatasetProxyModel::setSourceModel(QAbstractItemModel *m)
274 {
275 if ( sourceModel() ) {
276 disconnect( sourceModel(), SIGNAL(layoutChanged()),
277 this, SLOT(resetDatasetDescriptions()) );
278 }
279 QSortFilterProxyModel::setSourceModel( m );
280 mRootIndex = QModelIndex();
281 if ( m ) {
282 connect( m, SIGNAL(layoutChanged()),
283 this, SLOT(resetDatasetDescriptions()) );
284 connect( m, SIGNAL(layoutChanged()), this, SIGNAL(layoutChanged()) );
285 }
286 resetDatasetDescriptions();
287 }
288
setSourceRootIndex(const QModelIndex & rootIdx)289 void DatasetProxyModel::setSourceRootIndex(const QModelIndex& rootIdx)
290 {
291 mRootIndex = rootIdx;
292 resetDatasetDescriptions();
293 }
294
295