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 
26 using namespace Kleo;
27 using namespace GpgME;
28 
29 AbstractKeyListSortFilterProxyModel::AbstractKeyListSortFilterProxyModel(QObject *p)
31  , KeyListModelInterface()
32 {
33  init();
34 }
35 
36 AbstractKeyListSortFilterProxyModel::AbstractKeyListSortFilterProxyModel(const AbstractKeyListSortFilterProxyModel &other)
38  , KeyListModelInterface()
39 {
40  Q_UNUSED(other)
41  init();
42 }
43 
44 void AbstractKeyListSortFilterProxyModel::init()
45 {
46  setDynamicSortFilter(true);
47  setSortRole(Qt::EditRole); // EditRole can be expected to be in a less formatted way, better for sorting
48  setFilterRole(Qt::DisplayRole);
49  setFilterCaseSensitivity(Qt::CaseInsensitive);
50 }
51 
52 AbstractKeyListSortFilterProxyModel::~AbstractKeyListSortFilterProxyModel()
53 {
54 }
55 
56 Key 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 
66 std::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 
83 KeyGroup 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 
91 QModelIndex 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 
99 QList<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 
116 QModelIndex 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 
124 class KeyListSortFilterProxyModel::Private
125 {
126  friend class ::Kleo::KeyListSortFilterProxyModel;
127 
128 public:
129  explicit Private()
130  : keyFilter()
131  {
132  }
133  ~Private()
134  {
135  }
136 
137 private:
138  std::shared_ptr<const KeyFilter> keyFilter;
139 };
140 
141 KeyListSortFilterProxyModel::KeyListSortFilterProxyModel(QObject *p)
142  : AbstractKeyListSortFilterProxyModel(p)
143  , d(new Private)
144 {
145 }
146 
147 KeyListSortFilterProxyModel::KeyListSortFilterProxyModel(const KeyListSortFilterProxyModel &other)
148  : AbstractKeyListSortFilterProxyModel(other)
149  , d(new Private(*other.d))
150 {
151 }
152 
153 KeyListSortFilterProxyModel::~KeyListSortFilterProxyModel()
154 {
155 }
156 
157 KeyListSortFilterProxyModel *KeyListSortFilterProxyModel::clone() const
158 {
159  return new KeyListSortFilterProxyModel(*this);
160 }
161 
162 std::shared_ptr<const KeyFilter> KeyListSortFilterProxyModel::keyFilter() const
163 {
164  return d->keyFilter;
165 }
166 
167 void 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 
176 bool 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();
193  const QRegularExpression rx = filterRegularExpression();
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"
EditRole
QString fromUtf8(const char *str, int size)
CaseInsensitive
T value() const const
QFuture< typename QtPrivate::MapResultType< void, MapFunctor >::ResultType > mapped(const Sequence &sequence, MapFunctor function)
QVariant data(int role) const const
int size() const const
void init(KXmlGuiWindow *window, KGameDifficulty *difficulty=nullptr)
QString fromLatin1(const char *str, int size)
KCOREADDONS_EXPORT Result match(QStringView pattern, QStringView str)
QList::iterator begin()
bool contains(QChar ch, Qt::CaseSensitivity cs) const const
QList::iterator end()
const QList< QKeySequence > & end()
QString toString() const const
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Thu Feb 15 2024 03:56:14 by doxygen 1.8.17 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.