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 "KChartAbstractProxyModel.h"
21 
22 #include "KChartMath_p.h"
23 
24 #include <QDebug>
25 
26 #ifdef __GNUC__
27 #if __GNUC__ > 3
28 #define MAY_ALIAS __attribute__((__may_alias__))
29 #endif
30 #else
31 #define MAY_ALIAS
32 #endif
33 
34 namespace KChart {
35 
AbstractProxyModel(QObject * parent)36   AbstractProxyModel::AbstractProxyModel(QObject* parent)
37   : QAbstractProxyModel(parent) {}
38 
39 // Allows access to QModelIndex's private data via type punning and a compatible data layout.
40 // Due to inlining in Qt and no d-pointer, it is safe to assume that the layout won't change except
41 // between major Qt versions. As it happens, the layout is the same in Qt4 and Qt5.
42 // The only change is void * -> quintptr.
43 struct MAY_ALIAS KDPrivateModelIndex
44 {
45   int r, c;
46   void *p;
47   const QAbstractItemModel *m;
48 };
49 
mapFromSource(const QModelIndex & sourceIndex) const50 QModelIndex AbstractProxyModel::mapFromSource( const QModelIndex & sourceIndex ) const
51 {
52   if ( !sourceIndex.isValid() )
53     return QModelIndex();
54   //qDebug() << "sourceIndex.model()="<<sourceIndex.model();
55   //qDebug() << "model()="<<sourceModel();
56   Q_ASSERT( sourceIndex.model() == sourceModel() );
57 
58   // Create an index that preserves the internal pointer from the source;
59   // this way AbstractProxyModel preserves the structure of the source model
60   return createIndex( sourceIndex.row(), sourceIndex.column(), sourceIndex.internalPointer() );
61 }
62 
mapToSource(const QModelIndex & proxyIndex) const63 QModelIndex AbstractProxyModel::mapToSource( const QModelIndex &proxyIndex ) const
64 {
65   if ( !proxyIndex.isValid() )
66     return QModelIndex();
67   if ( proxyIndex.model() != this )
68     qDebug() << proxyIndex.model() << this;
69   Q_ASSERT( proxyIndex.model() == this );
70   // So here we need to create a source index which holds that internal pointer.
71   // No way to pass it to sourceModel()->index... so we have to do the ugly way:
72   QModelIndex sourceIndex;
73   KDPrivateModelIndex* hack = reinterpret_cast<KDPrivateModelIndex*>(&sourceIndex);
74   hack->r = proxyIndex.row();
75   hack->c = proxyIndex.column();
76   hack->p = proxyIndex.internalPointer();
77   hack->m = sourceModel();
78   Q_ASSERT( sourceIndex.isValid() );
79   return sourceIndex;
80 }
81 
index(int row,int col,const QModelIndex & index) const82 QModelIndex AbstractProxyModel::index( int row, int col, const QModelIndex& index ) const
83 {
84     Q_ASSERT(sourceModel());
85     return mapFromSource(sourceModel()->index( row, col, mapToSource(index) ));
86 }
87 
parent(const QModelIndex & index) const88 QModelIndex AbstractProxyModel::parent( const QModelIndex& index ) const
89 {
90     Q_ASSERT(sourceModel());
91     return mapFromSource(sourceModel()->parent( mapToSource(index) ));
92 }
93 
94 }
95