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