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{
46 setSortRole(Qt::EditRole); // EditRole can be expected to be in a less formatted way, better for sorting
49}
50
51AbstractKeyListSortFilterProxyModel::~AbstractKeyListSortFilterProxyModel()
52{
53}
54
55Key AbstractKeyListSortFilterProxyModel::key(const QModelIndex &idx) const
56{
57 const KeyListModelInterface *const klmi = dynamic_cast<KeyListModelInterface *>(sourceModel());
58 if (!klmi) {
59 static Key null;
60 return null;
61 }
62 return klmi->key(mapToSource(idx));
63}
64
65std::vector<Key> AbstractKeyListSortFilterProxyModel::keys(const QList<QModelIndex> &indexes) const
66{
67 const KeyListModelInterface *const klmi = dynamic_cast<KeyListModelInterface *>(sourceModel());
68 if (!klmi) {
69 return std::vector<Key>();
70 }
72 mapped.reserve(indexes.size());
73 std::transform(indexes.begin(), //
74 indexes.end(),
75 std::back_inserter(mapped),
76 [this](const QModelIndex &idx) {
77 return mapToSource(idx);
78 });
79 return klmi->keys(mapped);
80}
81
82KeyGroup AbstractKeyListSortFilterProxyModel::group(const QModelIndex &idx) const
83{
84 if (const KeyListModelInterface *const klmi = dynamic_cast<KeyListModelInterface *>(sourceModel())) {
85 return klmi->group(mapToSource(idx));
86 }
87 return KeyGroup();
88}
89
90QModelIndex AbstractKeyListSortFilterProxyModel::index(const Key &key) const
91{
92 if (const KeyListModelInterface *const klmi = dynamic_cast<KeyListModelInterface *>(sourceModel())) {
93 return mapFromSource(klmi->index(key));
94 }
95 return {};
96}
97
98QList<QModelIndex> AbstractKeyListSortFilterProxyModel::indexes(const std::vector<Key> &keys) const
99{
100 if (const KeyListModelInterface *const klmi = dynamic_cast<KeyListModelInterface *>(sourceModel())) {
101 const QList<QModelIndex> source = klmi->indexes(keys);
103 mapped.reserve(source.size());
104 std::transform(source.begin(), //
105 source.end(),
106 std::back_inserter(mapped),
107 [this](const QModelIndex &idx) {
108 return mapFromSource(idx);
109 });
110 return mapped;
111 }
112 return QList<QModelIndex>();
113}
114
115QModelIndex AbstractKeyListSortFilterProxyModel::index(const Kleo::KeyGroup &group) const
116{
117 if (const KeyListModelInterface *const klmi = dynamic_cast<KeyListModelInterface *>(sourceModel())) {
118 return mapFromSource(klmi->index(group));
119 }
120 return {};
121}
122
123class KeyListSortFilterProxyModel::Private
124{
125 friend class ::Kleo::KeyListSortFilterProxyModel;
126
127public:
128 explicit Private()
129 : keyFilter()
130 {
131 }
132 ~Private()
133 {
134 }
135
136private:
137 std::shared_ptr<const KeyFilter> keyFilter;
138};
139
140KeyListSortFilterProxyModel::KeyListSortFilterProxyModel(QObject *p)
141 : AbstractKeyListSortFilterProxyModel(p)
142 , d(new Private)
143{
144}
145
146KeyListSortFilterProxyModel::KeyListSortFilterProxyModel(const KeyListSortFilterProxyModel &other)
147 : AbstractKeyListSortFilterProxyModel(other)
148 , d(new Private(*other.d))
149{
150}
151
152KeyListSortFilterProxyModel::~KeyListSortFilterProxyModel()
153{
154}
155
156KeyListSortFilterProxyModel *KeyListSortFilterProxyModel::clone() const
157{
158 return new KeyListSortFilterProxyModel(*this);
159}
160
161std::shared_ptr<const KeyFilter> KeyListSortFilterProxyModel::keyFilter() const
162{
163 return d->keyFilter;
164}
165
166void KeyListSortFilterProxyModel::setKeyFilter(const std::shared_ptr<const KeyFilter> &kf)
167{
168 if (kf == d->keyFilter) {
169 return;
170 }
171 d->keyFilter = kf;
172 invalidate();
173}
174
175bool KeyListSortFilterProxyModel::filterAcceptsRow(int source_row, const QModelIndex &source_parent) const
176{
177 //
178 // 0. Keep parents of matching children:
179 //
180 const QModelIndex index = sourceModel()->index(source_row, 0, source_parent);
181 for (int i = 0, end = sourceModel()->rowCount(index); i != end; ++i) {
182 if (filterAcceptsRow(i, index)) {
183 return true;
184 }
185 }
186
187 //
188 // 1. Check filterRegExp
189 //
190 const int role = filterRole();
191 const int col = filterKeyColumn();
193 const QModelIndex nameIndex = sourceModel()->index(source_row, KeyList::PrettyName, source_parent);
194
195 const KeyListModelInterface *const klm = dynamic_cast<KeyListModelInterface *>(sourceModel());
196 Q_ASSERT(klm);
197 const Key key = klm->key(nameIndex);
198 const auto userID = nameIndex.data(KeyList::UserIDRole).value<UserID>();
199 const KeyGroup group = klm->group(nameIndex);
200 Q_ASSERT(!key.isNull() || !group.isNull());
201
202 if (col) {
203 const QModelIndex colIdx = sourceModel()->index(source_row, col, source_parent);
204 const QString content = colIdx.data(role).toString();
205 if (!content.contains(rx)) {
206 return false;
207 }
208 } else if (!key.isNull()) {
209 // By default match against the full uid data (name / email / comment / dn)
210 bool match = false;
211
212 if (userID.isNull()) {
213 for (const auto &uid : key.userIDs()) {
214 const auto id = QString::fromUtf8(uid.id());
215 if (id.contains(rx)) {
216 match = true;
217 break;
218 }
219 }
220 } else {
221 const auto id = QString::fromUtf8(userID.id());
222 if (id.contains(rx)) {
223 match = true;
224 }
225 }
226 if (!match) {
227 // Also match against remarks (search tags)
228 const auto alm = dynamic_cast<AbstractKeyListModel *>(sourceModel());
229 if (alm) {
230 const auto remarks = alm->data(alm->index(key, KeyList::Remarks));
231 if (!remarks.isNull() && remarks.toString().contains(rx)) {
232 match = true;
233 }
234 }
235 // Also match against fingerprints
236 for (const auto &subkey : key.subkeys()) {
237 const auto fpr = QString::fromLatin1(subkey.fingerprint());
238 if (fpr.contains(rx)) {
239 match = true;
240 break;
241 }
242 }
243
244 if (!match) {
245 return false;
246 }
247 }
248 } else if (!group.isNull()) {
249 if (!group.name().contains(rx)) {
250 return false;
251 }
252 } else {
253 return false;
254 }
255
256 //
257 // 2. For keys check that key filters match (if any are defined)
258 // For groups check that at least one key matches the key filter
259 //
260 if (d->keyFilter) { // avoid artifacts when no filters are defined
261 if (!userID.isNull()) {
262 return d->keyFilter->matches(userID, KeyFilter::Filtering);
263 } else if (!key.isNull()) {
264 return d->keyFilter->matches(key, KeyFilter::Filtering);
265 } else if (!group.isNull()) {
266 return Kleo::any_of(group.keys(), [this](const auto &key) {
267 return d->keyFilter->matches(key, KeyFilter::Filtering);
268 });
269 }
270 }
271
272 // 3. match by default:
273 return true;
274}
275
276#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 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 Fri Dec 6 2024 12:02:18 by doxygen 1.12.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.