1/*
2 SPDX-FileCopyrightText: 2015 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.com>
3 SPDX-FileContributor: David Faure <david.faure@kdab.com>
4
5 SPDX-License-Identifier: LGPL-2.0-or-later
6*/
7
8#include "krearrangecolumnsproxymodel.h"
9
10class KRearrangeColumnsProxyModelPrivate
11{
12public:
13 QList<int> m_sourceColumns;
14 bool m_resetting = false;
15 QMetaObject::Connection m_sourceModelAboutToBeResetConnection;
16 QMetaObject::Connection m_sourceModelResetConnection;
17};
18
19KRearrangeColumnsProxyModel::KRearrangeColumnsProxyModel(QObject *parent)
20 : QIdentityProxyModel(parent)
21 , d_ptr(new KRearrangeColumnsProxyModelPrivate)
22{
23}
24
25KRearrangeColumnsProxyModel::~KRearrangeColumnsProxyModel()
26{
27}
28
29void KRearrangeColumnsProxyModel::setSourceModel(QAbstractItemModel *sourceModel)
30{
31 disconnect(d_ptr->m_sourceModelAboutToBeResetConnection);
32 disconnect(d_ptr->m_sourceModelResetConnection);
33 d_ptr->m_sourceModelAboutToBeResetConnection = connect(sender: sourceModel, signal: &QAbstractItemModel::modelAboutToBeReset, context: this, slot: [this]() {
34 d_ptr->m_resetting = true;
35 });
36 d_ptr->m_sourceModelResetConnection = connect(sender: sourceModel, signal: &QAbstractItemModel::modelReset, context: this, slot: [this]() {
37 d_ptr->m_resetting = false;
38 });
39 QIdentityProxyModel::setSourceModel(sourceModel);
40}
41
42void KRearrangeColumnsProxyModel::setSourceColumns(const QList<int> &columns)
43{
44 // We could use layoutChanged() here, but we would have to map persistent
45 // indexes from the old to the new location...
46 if (!d_ptr->m_resetting)
47 beginResetModel();
48 d_ptr->m_sourceColumns = columns;
49 if (!d_ptr->m_resetting)
50 endResetModel();
51}
52
53int KRearrangeColumnsProxyModel::columnCount(const QModelIndex &parent) const
54{
55 Q_UNUSED(parent);
56 if (!sourceModel()) {
57 return 0;
58 }
59 return d_ptr->m_sourceColumns.count();
60}
61
62int KRearrangeColumnsProxyModel::rowCount(const QModelIndex &parent) const
63{
64 Q_ASSERT(parent.isValid() ? parent.model() == this : true);
65 if (!sourceModel()) {
66 return 0;
67 }
68 if (parent.column() > 0) {
69 return 0;
70 }
71 // The parent in the source model is on column 0, whatever swapping we are doing
72 const QModelIndex sourceParent = mapToSource(proxyIndex: parent).sibling(arow: parent.row(), acolumn: 0);
73 return sourceModel()->rowCount(parent: sourceParent);
74}
75
76bool KRearrangeColumnsProxyModel::hasChildren(const QModelIndex &parent) const
77{
78 Q_ASSERT(parent.isValid() ? parent.model() == this : true);
79 if (!sourceModel()) {
80 return false;
81 }
82 if (d_ptr->m_sourceColumns.isEmpty()) { // no columns configured yet
83 return false;
84 }
85 if (parent.column() > 0) {
86 return false;
87 }
88 const QModelIndex sourceParent = mapToSource(proxyIndex: parent).sibling(arow: parent.row(), acolumn: 0);
89 return sourceModel()->rowCount(parent: sourceParent) > 0;
90}
91
92QModelIndex KRearrangeColumnsProxyModel::index(int row, int column, const QModelIndex &parent) const
93{
94 Q_ASSERT(parent.isValid() ? parent.model() == this : true);
95 Q_ASSERT(row >= 0);
96 Q_ASSERT(column >= 0);
97
98 // Only first column has children
99 if (parent.column() > 0) {
100 return {};
101 }
102
103 if (!sourceModel()) {
104 return {};
105 }
106 if (d_ptr->m_sourceColumns.isEmpty()) {
107 return {};
108 }
109
110 // The parent in the source model is on column 0, whatever swapping we are doing
111 const QModelIndex sourceParent = mapToSource(proxyIndex: parent).sibling(arow: parent.row(), acolumn: 0);
112
113 // Find the child in the source model, we need its internal pointer
114 const QModelIndex sourceIndex = sourceModel()->index(row, column: sourceColumnForProxyColumn(proxyColumn: column), parent: sourceParent);
115 if (!sourceIndex.isValid()) {
116 return QModelIndex();
117 }
118
119 return createIndex(arow: row, acolumn: column, adata: sourceIndex.internalPointer());
120}
121
122QModelIndex KRearrangeColumnsProxyModel::parent(const QModelIndex &child) const
123{
124 Q_ASSERT(child.isValid() ? child.model() == this : true);
125 const QModelIndex sourceIndex = mapToSource(proxyIndex: child);
126 const QModelIndex sourceParent = sourceIndex.parent();
127 if (!sourceParent.isValid()) {
128 return QModelIndex();
129 }
130 return createIndex(arow: sourceParent.row(), acolumn: 0, adata: sourceParent.internalPointer());
131}
132
133QVariant KRearrangeColumnsProxyModel::headerData(int section, Qt::Orientation orientation, int role) const
134{
135 if (orientation == Qt::Horizontal) {
136 if (!sourceModel() || section >= d_ptr->m_sourceColumns.count()) {
137 return QVariant();
138 }
139 const int sourceCol = sourceColumnForProxyColumn(proxyColumn: section);
140 return sourceModel()->headerData(section: sourceCol, orientation, role);
141 } else {
142 return QIdentityProxyModel::headerData(section, orientation, role);
143 }
144}
145
146QModelIndex KRearrangeColumnsProxyModel::sibling(int row, int column, const QModelIndex &idx) const
147{
148 if (column >= d_ptr->m_sourceColumns.count()) {
149 return QModelIndex();
150 }
151 return index(row, column, parent: idx.parent());
152}
153
154QModelIndex KRearrangeColumnsProxyModel::mapFromSource(const QModelIndex &sourceIndex) const
155{
156 if (!sourceIndex.isValid()) {
157 return QModelIndex();
158 }
159 Q_ASSERT(sourceIndex.model() == sourceModel());
160 const int proxyColumn = proxyColumnForSourceColumn(sourceColumn: sourceIndex.column());
161 return createIndex(arow: sourceIndex.row(), acolumn: proxyColumn, adata: sourceIndex.internalPointer());
162}
163
164QModelIndex KRearrangeColumnsProxyModel::mapToSource(const QModelIndex &proxyIndex) const
165{
166 if (!proxyIndex.isValid()) {
167 return QModelIndex();
168 }
169 return createSourceIndex(row: proxyIndex.row(), col: sourceColumnForProxyColumn(proxyColumn: proxyIndex.column()), internalPtr: proxyIndex.internalPointer());
170}
171
172int KRearrangeColumnsProxyModel::proxyColumnForSourceColumn(int sourceColumn) const
173{
174 // If this is too slow, we could add a second QList with index=logical_source_column value=desired_pos_in_proxy.
175 return d_ptr->m_sourceColumns.indexOf(t: sourceColumn);
176}
177
178int KRearrangeColumnsProxyModel::sourceColumnForProxyColumn(int proxyColumn) const
179{
180 Q_ASSERT(proxyColumn >= 0);
181 Q_ASSERT(proxyColumn < d_ptr->m_sourceColumns.size());
182 return d_ptr->m_sourceColumns.at(i: proxyColumn);
183}
184
185#include "moc_krearrangecolumnsproxymodel.cpp"
186

source code of kitemmodels/src/core/krearrangecolumnsproxymodel.cpp