Libkleo

keylistsortfilterproxymodel.cpp
1/* -*- mode: c++; c-basic-offset:4 -*-
2 models/keylistsortfilterproxymodel.cpp
3
4 This file is part of Kleopatra, the KDE keymanager
5 SPDX-FileCopyrightText: 2007 Klarälvdalens Datakonsult AB
6
7 SPDX-License-Identifier: GPL-2.0-or-later
8*/
9
10#include <config-libkleo.h>
11
12#include "keylistsortfilterproxymodel.h"
13
14#include "keylist.h"
15#include "keylistmodel.h"
16
17#include <libkleo/algorithm.h>
18#include <libkleo/keyfilter.h>
19#include <libkleo/keygroup.h>
20#include <libkleo/stl_util.h>
21
22#include <libkleo_debug.h>
23
24#include <gpgme++/key.h>
25
26using namespace Kleo;
27using namespace GpgME;
28
29AbstractKeyListSortFilterProxyModel::AbstractKeyListSortFilterProxyModel(QObject *p)
31 , KeyListModelInterface()
32{
33 init();
34}
35
36AbstractKeyListSortFilterProxyModel::AbstractKeyListSortFilterProxyModel(const AbstractKeyListSortFilterProxyModel &other)
38 , KeyListModelInterface()
39{
40 Q_UNUSED(other)
41 init();
42}
43
44void AbstractKeyListSortFilterProxyModel::init()
45{
47 setSortRole(Qt::EditRole); // EditRole can be expected to be in a less formatted way, better for sorting
50}
51
52AbstractKeyListSortFilterProxyModel::~AbstractKeyListSortFilterProxyModel()
53{
54}
55
56Key AbstractKeyListSortFilterProxyModel::key(const QModelIndex &idx) const
57{
58 const KeyListModelInterface *const klmi = dynamic_cast<KeyListModelInterface *>(sourceModel());
59 if (!klmi) {
60 static Key null;
61 return null;
62 }
63 return klmi->key(mapToSource(idx));
64}
65
66std::vector<Key> AbstractKeyListSortFilterProxyModel::keys(const QList<QModelIndex> &indexes) const
67{
68 const KeyListModelInterface *const klmi = dynamic_cast<KeyListModelInterface *>(sourceModel());
69 if (!klmi) {
70 return std::vector<Key>();
71 }
73 mapped.reserve(indexes.size());
74 std::transform(indexes.begin(), //
75 indexes.end(),
76 std::back_inserter(mapped),
77 [this](const QModelIndex &idx) {
78 return mapToSource(idx);
79 });
80 return klmi->keys(mapped);
81}
82
83KeyGroup AbstractKeyListSortFilterProxyModel::group(const QModelIndex &idx) const
84{
85 if (const KeyListModelInterface *const klmi = dynamic_cast<KeyListModelInterface *>(sourceModel())) {
86 return klmi->group(mapToSource(idx));
87 }
88 return KeyGroup();
89}
90
91QModelIndex AbstractKeyListSortFilterProxyModel::index(const Key &key) const
92{
93 if (const KeyListModelInterface *const klmi = dynamic_cast<KeyListModelInterface *>(sourceModel())) {
94 return mapFromSource(klmi->index(key));
95 }
96 return {};
97}
98
99QList<QModelIndex> AbstractKeyListSortFilterProxyModel::indexes(const std::vector<Key> &keys) const
100{
101 if (const KeyListModelInterface *const klmi = dynamic_cast<KeyListModelInterface *>(sourceModel())) {
102 const QList<QModelIndex> source = klmi->indexes(keys);
104 mapped.reserve(source.size());
105 std::transform(source.begin(), //
106 source.end(),
107 std::back_inserter(mapped),
108 [this](const QModelIndex &idx) {
109 return mapFromSource(idx);
110 });
111 return mapped;
112 }
113 return QList<QModelIndex>();
114}
115
116QModelIndex AbstractKeyListSortFilterProxyModel::index(const Kleo::KeyGroup &group) const
117{
118 if (const KeyListModelInterface *const klmi = dynamic_cast<KeyListModelInterface *>(sourceModel())) {
119 return mapFromSource(klmi->index(group));
120 }
121 return {};
122}
123
124class KeyListSortFilterProxyModel::Private
125{
126 friend class ::Kleo::KeyListSortFilterProxyModel;
127
128public:
129 explicit Private()
130 : keyFilter()
131 {
132 }
133 ~Private()
134 {
135 }
136
137private:
138 std::shared_ptr<const KeyFilter> keyFilter;
139};
140
141KeyListSortFilterProxyModel::KeyListSortFilterProxyModel(QObject *p)
142 : AbstractKeyListSortFilterProxyModel(p)
143 , d(new Private)
144{
145}
146
147KeyListSortFilterProxyModel::KeyListSortFilterProxyModel(const KeyListSortFilterProxyModel &other)
148 : AbstractKeyListSortFilterProxyModel(other)
149 , d(new Private(*other.d))
150{
151}
152
153KeyListSortFilterProxyModel::~KeyListSortFilterProxyModel()
154{
155}
156
157KeyListSortFilterProxyModel *KeyListSortFilterProxyModel::clone() const
158{
159 return new KeyListSortFilterProxyModel(*this);
160}
161
162std::shared_ptr<const KeyFilter> KeyListSortFilterProxyModel::keyFilter() const
163{
164 return d->keyFilter;
165}
166
167void KeyListSortFilterProxyModel::setKeyFilter(const std::shared_ptr<const KeyFilter> &kf)
168{
169 if (kf == d->keyFilter) {
170 return;
171 }
172 d->keyFilter = kf;
173 invalidate();
174}
175
176bool KeyListSortFilterProxyModel::filterAcceptsRow(int source_row, const QModelIndex &source_parent) const
177{
178 //
179 // 0. Keep parents of matching children:
180 //
181 const QModelIndex index = sourceModel()->index(source_row, 0, source_parent);
182 for (int i = 0, end = sourceModel()->rowCount(index); i != end; ++i) {
183 if (filterAcceptsRow(i, index)) {
184 return true;
185 }
186 }
187
188 //
189 // 1. Check filterRegExp
190 //
191 const int role = filterRole();
192 const int col = filterKeyColumn();
194 const QModelIndex nameIndex = sourceModel()->index(source_row, KeyList::PrettyName, source_parent);
195
196 const KeyListModelInterface *const klm = dynamic_cast<KeyListModelInterface *>(sourceModel());
197 Q_ASSERT(klm);
198 const Key key = klm->key(nameIndex);
199 const auto userID = nameIndex.data(KeyList::UserIDRole).value<UserID>();
200 const KeyGroup group = klm->group(nameIndex);
201 Q_ASSERT(!key.isNull() || !group.isNull());
202
203 if (col) {
204 const QModelIndex colIdx = sourceModel()->index(source_row, col, source_parent);
205 const QString content = colIdx.data(role).toString();
206 if (!content.contains(rx)) {
207 return false;
208 }
209 } else if (!key.isNull()) {
210 // By default match against the full uid data (name / email / comment / dn)
211 bool match = false;
212
213 if (userID.isNull()) {
214 for (const auto &uid : key.userIDs()) {
215 const auto id = QString::fromUtf8(uid.id());
216 if (id.contains(rx)) {
217 match = true;
218 break;
219 }
220 }
221 } else {
222 const auto id = QString::fromUtf8(userID.id());
223 if (id.contains(rx)) {
224 match = true;
225 }
226 }
227 if (!match) {
228 // Also match against remarks (search tags)
229 const auto alm = dynamic_cast<AbstractKeyListModel *>(sourceModel());
230 if (alm) {
231 const auto remarks = alm->data(alm->index(key, KeyList::Remarks));
232 if (!remarks.isNull() && remarks.toString().contains(rx)) {
233 match = true;
234 }
235 }
236 // Also match against fingerprints
237 for (const auto &subkey : key.subkeys()) {
238 const auto fpr = QString::fromLatin1(subkey.fingerprint());
239 if (fpr.contains(rx)) {
240 match = true;
241 break;
242 }
243 }
244
245 if (!match) {
246 return false;
247 }
248 }
249 } else if (!group.isNull()) {
250 if (!group.name().contains(rx)) {
251 return false;
252 }
253 } else {
254 return false;
255 }
256
257 //
258 // 2. For keys check that key filters match (if any are defined)
259 // For groups check that at least one key matches the key filter
260 //
261 if (d->keyFilter) { // avoid artifacts when no filters are defined
262 if (!key.isNull()) {
263 return d->keyFilter->matches(key, KeyFilter::Filtering);
264 } else if (!group.isNull()) {
265 return Kleo::any_of(group.keys(), [this](const auto &key) {
266 return d->keyFilter->matches(key, KeyFilter::Filtering);
267 });
268 }
269 }
270
271 // 3. match by default:
272 return true;
273}
274
275#include "moc_keylistsortfilterproxymodel.cpp"
const QList< QKeySequence > & end()
QCA_EXPORT void init()
iterator begin()
iterator end()
qsizetype size() const const
QVariant data(int role) const const
void setDynamicSortFilter(bool enable)
void setFilterCaseSensitivity(Qt::CaseSensitivity cs)
void setFilterRole(int role)
virtual QModelIndex mapFromSource(const QModelIndex &sourceIndex) const const override
virtual QModelIndex mapToSource(const QModelIndex &proxyIndex) const const override
virtual QModelIndexList match(const QModelIndex &start, int role, const QVariant &value, int hits, Qt::MatchFlags flags) const const override
virtual int rowCount(const QModelIndex &parent) const const override
void setSortRole(int role)
bool contains(QChar ch, Qt::CaseSensitivity cs) const const
QString fromLatin1(QByteArrayView str)
QString fromUtf8(QByteArrayView str)
CaseInsensitive
EditRole
QFuture< QtPrivate::MapResultType< Iterator, MapFunctor > > mapped(Iterator begin, Iterator end, MapFunctor &&function)
QString toString() const const
T value() const const
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Tue Mar 26 2024 11:14:12 by doxygen 1.10.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.