Libkleo

useridproxymodel.cpp
1/*
2 SPDX-FileCopyrightText: 2024 g10 Code GmbH
3 SPDX-FileContributor: Tobias Fella <tobias.fella@gnupg.com>
4 SPDX-License-Identifier: GPL-2.0-or-later
5*/
6
7#include "useridproxymodel.h"
8
9#include "keylist.h"
10#include "keylistmodel.h"
11#include "kleo/keyfiltermanager.h"
12#include "utils/algorithm.h"
13#include "utils/formatting.h"
14#include "utils/systeminfo.h"
15
16#include <gpgme++/global.h>
17
18#include <QColor>
19
20#include <variant>
21
22using namespace Kleo;
23
24class UserIDProxyModel::Private
25{
26public:
27 Private(UserIDProxyModel *qq);
28 void loadUserIDs();
30 QAbstractItemModel *oldSourceModel = nullptr;
31 UserIDProxyModel *q;
32};
33
34void UserIDProxyModel::Private::loadUserIDs()
35{
36 q->beginResetModel();
37 mIds.clear();
38 mIds.reserve(q->sourceModel()->rowCount());
39 for (auto i = 0; i < q->sourceModel()->rowCount(); ++i) {
40 const auto key = q->sourceModel()->index(i, 0).data(KeyList::KeyRole).value<GpgME::Key>();
42 if (key.isNull()) {
43 mIds += q->sourceModel()->index(i, 0).data(KeyList::GroupRole).value<KeyGroup>();
44 } else if (key.protocol() == GpgME::OpenPGP) {
45 for (const auto &userID : key.userIDs()) {
46 mIds += userID;
47 }
48 } else {
50 for (const auto &userID : key.userIDs()) {
51 const auto exists = Kleo::contains_if(ids, [userID](const auto &other) {
52 return !qstrcmp(std::get<GpgME::UserID>(other).email(), userID.email());
53 });
54 if (!exists && userID.email() && *userID.email()) {
55 ids += userID;
56 }
57 }
58 if (ids.count() > 0) {
59 mIds.append(ids);
60 } else {
61 mIds.append(key.userID(0));
62 }
63 }
64 }
65 q->endResetModel();
66}
67
68UserIDProxyModel::Private::Private(UserIDProxyModel *qq)
69 : q(qq)
70{
71 connect(q, &UserIDProxyModel::sourceModelChanged, q, [this]() {
72 if (oldSourceModel) {
73 disconnect(oldSourceModel, nullptr, q, nullptr);
74 }
75 connect(q->sourceModel(), &QAbstractItemModel::dataChanged, q, [this]() {
76 loadUserIDs();
77 });
78 connect(q->sourceModel(), &QAbstractItemModel::rowsInserted, q, [this]() {
79 loadUserIDs();
80 });
81 connect(q->sourceModel(), &QAbstractItemModel::modelReset, q, [this]() {
82 loadUserIDs();
83 });
84 oldSourceModel = q->sourceModel();
85 loadUserIDs();
86 });
87}
88
89UserIDProxyModel::UserIDProxyModel(QObject *parent)
90 : AbstractKeyListSortFilterProxyModel(parent)
91 , d{new Private(this)}
92{
93}
94
95UserIDProxyModel::~UserIDProxyModel() = default;
96
97static QVariant returnIfValid(const QColor &t)
98{
99 if (t.isValid()) {
100 return t;
101 } else {
102 return QVariant();
103 }
104}
105
106QModelIndex UserIDProxyModel::mapFromSource(const QModelIndex &sourceIndex) const
107{
108 if (!sourceIndex.isValid()) {
109 return {};
110 }
111 const auto &sourceKey = sourceIndex.data(KeyList::KeyRole).value<GpgME::Key>();
112 if (sourceKey.isNull()) {
113 const auto &sourceKeyGroup = sourceIndex.data(KeyList::GroupRole).value<KeyGroup>();
114 for (int i = 0; i < d->mIds.count(); ++i) {
115 if (std::holds_alternative<KeyGroup>(d->mIds[i]) && std::get<KeyGroup>(d->mIds[i]).id() == sourceKeyGroup.id()) {
116 return index(i, sourceIndex.column(), {});
117 }
118 }
119 } else {
120 const auto &fingerprint = sourceKey.primaryFingerprint();
121 for (int i = 0; i < d->mIds.count(); ++i) {
122 if (std::holds_alternative<GpgME::UserID>(d->mIds[i]) && !qstrcmp(fingerprint, std::get<GpgME::UserID>(d->mIds[i]).parent().primaryFingerprint())) {
123 return index(i, sourceIndex.column(), {});
124 }
125 }
126 }
127
128 return {};
129}
130
131QModelIndex UserIDProxyModel::mapToSource(const QModelIndex &proxyIndex) const
132{
133 if (!proxyIndex.isValid()) {
134 return {};
135 }
136 const auto &entry = d->mIds[proxyIndex.row()];
137
138 if (std::holds_alternative<KeyGroup>(entry)) {
139 const auto &id = std::get<KeyGroup>(entry).id();
140 for (int i = 0; i < sourceModel()->rowCount(); ++i) {
141 if (sourceModel()->index(i, 0).data(KeyList::GroupRole).value<KeyGroup>().id() == id) {
142 return sourceModel()->index(i, proxyIndex.column());
143 }
144 }
145 } else {
146 const auto &fingerprint = std::get<GpgME::UserID>(entry).parent().primaryFingerprint();
147 for (int i = 0; i < sourceModel()->rowCount(); ++i) {
148 if (!qstrcmp(sourceModel()->index(i, 0).data(KeyList::KeyRole).value<GpgME::Key>().primaryFingerprint(), fingerprint)) {
149 return sourceModel()->index(i, proxyIndex.column());
150 }
151 }
152 }
153
154 return {};
155}
156
157int UserIDProxyModel::rowCount(const QModelIndex &parent) const
158{
159 if (parent.isValid()) {
160 return 0;
161 }
162 return d->mIds.count();
163}
164
165QModelIndex UserIDProxyModel::index(int row, int column, const QModelIndex &parent) const
166{
167 if (parent.isValid()) {
168 return {};
169 }
170 return createIndex(row, column, nullptr);
171}
172
174{
175 return {};
176}
177
178int UserIDProxyModel::columnCount(const QModelIndex &index) const
179{
180 if (!sourceModel()) {
181 return 0;
182 }
183 return sourceModel()->columnCount(mapToSource(index));
184}
185
186QVariant UserIDProxyModel::data(const QModelIndex &index, int role) const
187{
188 const auto &entry = d->mIds[index.row()];
189 if (std::holds_alternative<KeyGroup>(entry)) {
191 }
192 const auto &userId = std::get<GpgME::UserID>(entry);
193 const auto &key = userId.parent();
194 if (role == KeyList::UserIDRole) {
195 return QVariant::fromValue(userId);
196 }
197 if ((role == Qt::DisplayRole || role == Qt::EditRole || role == Qt::AccessibleTextRole || role == Kleo::ClipboardRole)) {
198 if (index.column() == KeyList::Columns::PrettyName) {
199 if (key.protocol() == GpgME::OpenPGP) {
200 return Formatting::prettyName(userId);
201 } else {
202 return Formatting::prettyName(key);
203 }
204 }
205 if (index.column() == KeyList::Columns::PrettyEMail) {
206 return Formatting::prettyEMail(userId);
207 }
208 if (index.column() == KeyList::Columns::Validity) {
209 return Formatting::complianceStringShort(userId);
210 }
211 if (index.column() == KeyList::Columns::Summary) {
212 return Formatting::summaryLine(userId);
213 }
214 if (index.column() == KeyList::Columns::Origin) {
215 return Formatting::origin(userId.origin());
216 }
217 if (index.column() == KeyList::Columns::LastUpdate) {
218 if (role == Qt::AccessibleTextRole) {
219 return Formatting::accessibleDate(userId.lastUpdate());
220 } else {
221 return Formatting::dateString(userId.lastUpdate());
222 }
223 }
224 }
225 if (role == Qt::BackgroundRole) {
226 if (!SystemInfo::isHighContrastModeActive()) {
227 return returnIfValid(KeyFilterManager::instance()->bgColor(userId));
228 }
229 } else if (role == Qt::ForegroundRole) {
230 if (!SystemInfo::isHighContrastModeActive()) {
231 return returnIfValid(KeyFilterManager::instance()->fgColor(userId));
232 }
233 }
235}
236
237UserIDProxyModel *UserIDProxyModel::clone() const
238{
239 auto model = new UserIDProxyModel(QObject::parent());
240 model->setSourceModel(sourceModel());
241 return model;
242}
243
244QModelIndex UserIDProxyModel::index(const KeyGroup &group) const
245{
246 Q_UNUSED(group);
247 return {};
248}
249
250QModelIndex UserIDProxyModel::index(const GpgME::Key &key) const
251{
252 Q_UNUSED(key);
253 return {};
254}
255
256#include "moc_useridproxymodel.cpp"
QModelIndex createIndex(int row, int column, const void *ptr) const const
virtual QVariant data(const QModelIndex &index, int role) const const=0
void dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight, const QList< int > &roles)
void rowsInserted(const QModelIndex &parent, int first, int last)
bool isValid() const const
void append(QList< T > &&value)
void clear()
qsizetype count() const const
void reserve(qsizetype size)
int column() const const
QVariant data(int role) const const
bool isValid() const const
int row() const const
QObject * parent() const const
DisplayRole
QFuture< ArgsType< Signal > > connect(Sender *sender, Signal signal)
QVariant fromValue(T &&value)
T value() const const
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Mon Nov 18 2024 12:09:14 by doxygen 1.12.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.