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