1 | /* |
2 | SPDX-FileCopyrightText: 2010 Stephen Kelly <steveire@gmail.com> |
3 | |
4 | SPDX-License-Identifier: LGPL-2.0-or-later |
5 | */ |
6 | |
7 | #include "kcheckableproxymodel.h" |
8 | |
9 | #include <QItemSelectionModel> |
10 | |
11 | class KCheckableProxyModelPrivate |
12 | { |
13 | Q_DECLARE_PUBLIC(KCheckableProxyModel) |
14 | KCheckableProxyModel *q_ptr; |
15 | |
16 | KCheckableProxyModelPrivate(KCheckableProxyModel *checkableModel) |
17 | : q_ptr(checkableModel) |
18 | { |
19 | } |
20 | |
21 | QItemSelectionModel *m_itemSelectionModel = nullptr; |
22 | |
23 | void selectionChanged(const QItemSelection &selected, const QItemSelection &deselected); |
24 | }; |
25 | |
26 | KCheckableProxyModel::KCheckableProxyModel(QObject *parent) |
27 | : QIdentityProxyModel(parent) |
28 | , d_ptr(new KCheckableProxyModelPrivate(this)) |
29 | { |
30 | } |
31 | |
32 | KCheckableProxyModel::~KCheckableProxyModel() = default; |
33 | |
34 | void KCheckableProxyModel::setSelectionModel(QItemSelectionModel *itemSelectionModel) |
35 | { |
36 | Q_D(KCheckableProxyModel); |
37 | d->m_itemSelectionModel = itemSelectionModel; |
38 | Q_ASSERT(sourceModel() ? d->m_itemSelectionModel->model() == sourceModel() : true); |
39 | connect(sender: itemSelectionModel, signal: &QItemSelectionModel::selectionChanged, context: this, slot: [d](const QItemSelection &selected, const QItemSelection &deselected) { |
40 | d->selectionChanged(selected, deselected); |
41 | }); |
42 | } |
43 | |
44 | QItemSelectionModel *KCheckableProxyModel::selectionModel() const |
45 | { |
46 | Q_D(const KCheckableProxyModel); |
47 | return d->m_itemSelectionModel; |
48 | } |
49 | |
50 | Qt::ItemFlags KCheckableProxyModel::flags(const QModelIndex &index) const |
51 | { |
52 | if (!index.isValid() || index.column() != 0) { |
53 | return QIdentityProxyModel::flags(index); |
54 | } |
55 | return QIdentityProxyModel::flags(index) | Qt::ItemIsUserCheckable; |
56 | } |
57 | |
58 | QVariant KCheckableProxyModel::data(const QModelIndex &index, int role) const |
59 | { |
60 | Q_D(const KCheckableProxyModel); |
61 | |
62 | if (role == Qt::CheckStateRole) { |
63 | if (index.column() != 0) { |
64 | return QVariant(); |
65 | } |
66 | if (!d->m_itemSelectionModel) { |
67 | return Qt::Unchecked; |
68 | } |
69 | |
70 | return d->m_itemSelectionModel->selection().contains(index: mapToSource(proxyIndex: index)) ? Qt::Checked : Qt::Unchecked; |
71 | } |
72 | return QIdentityProxyModel::data(proxyIndex: index, role); |
73 | } |
74 | |
75 | bool KCheckableProxyModel::setData(const QModelIndex &index, const QVariant &value, int role) |
76 | { |
77 | Q_D(KCheckableProxyModel); |
78 | if (role == Qt::CheckStateRole) { |
79 | if (index.column() != 0) { |
80 | return false; |
81 | } |
82 | if (!d->m_itemSelectionModel) { |
83 | return false; |
84 | } |
85 | |
86 | Qt::CheckState state = static_cast<Qt::CheckState>(value.toInt()); |
87 | const QModelIndex srcIndex = mapToSource(proxyIndex: index); |
88 | bool result = select(selection: QItemSelection(srcIndex, srcIndex), command: state == Qt::Checked ? QItemSelectionModel::Select : QItemSelectionModel::Deselect); |
89 | Q_EMIT dataChanged(topLeft: index, bottomRight: index); |
90 | return result; |
91 | } |
92 | return QIdentityProxyModel::setData(index, value, role); |
93 | } |
94 | |
95 | void KCheckableProxyModel::setSourceModel(QAbstractItemModel *sourceModel) |
96 | { |
97 | QIdentityProxyModel::setSourceModel(sourceModel); |
98 | Q_ASSERT(d_ptr->m_itemSelectionModel ? d_ptr->m_itemSelectionModel->model() == sourceModel : true); |
99 | } |
100 | |
101 | void KCheckableProxyModelPrivate::selectionChanged(const QItemSelection &selected, const QItemSelection &deselected) |
102 | { |
103 | Q_Q(KCheckableProxyModel); |
104 | const auto lstSelected = q->mapSelectionFromSource(selection: selected); |
105 | for (const QItemSelectionRange &range : lstSelected) { |
106 | Q_EMIT q->dataChanged(topLeft: range.topLeft(), bottomRight: range.bottomRight()); |
107 | } |
108 | const auto lstDeselected = q->mapSelectionFromSource(selection: deselected); |
109 | for (const QItemSelectionRange &range : lstDeselected) { |
110 | Q_EMIT q->dataChanged(topLeft: range.topLeft(), bottomRight: range.bottomRight()); |
111 | } |
112 | } |
113 | |
114 | bool KCheckableProxyModel::select(const QItemSelection &selection, QItemSelectionModel::SelectionFlags command) |
115 | { |
116 | Q_D(KCheckableProxyModel); |
117 | d->m_itemSelectionModel->select(selection, command); |
118 | return true; |
119 | } |
120 | |
121 | QHash<int, QByteArray> KCheckableProxyModel::roleNames() const |
122 | { |
123 | auto roles = QIdentityProxyModel::roleNames(); |
124 | roles[Qt::CheckStateRole] = QByteArrayLiteral("checkState" ); |
125 | return roles; |
126 | } |
127 | |
128 | #include "moc_kcheckableproxymodel.cpp" |
129 | |