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