Libkleo

useridlistmodel.cpp
1/* -*- mode: c++; c-basic-offset:4 -*-
2 models/useridlistmodel.cpp
3
4 This file is part of Kleopatra, the KDE keymanager
5 SPDX-FileCopyrightText: 2007 Klarälvdalens Datakonsult AB
6 SPDX-FileCopyrightText: 2016 Andre Heinecke <aheinecke@gnupg.org>
7 SPDX-FileCopyrightText: 2021 g10 Code GmbH
8 SPDX-FileContributor: Ingo Klöcker <dev@ingo-kloecker.de>
9
10 SPDX-License-Identifier: GPL-2.0-or-later
11*/
12
13#include <config-libkleo.h>
14
15#include "useridlistmodel.h"
16
17#include "keycache.h"
18
19#include <libkleo/formatting.h>
20
21#include <KLocalizedString>
22
23#include <QDate>
24#include <QIcon>
25#include <QVariant>
26
27#include <gpgme++/key.h>
28
29using namespace GpgME;
30using namespace Kleo;
31
32class UIDModelItem
33{
34 // A uid model item can either be a UserID::Signature or a UserID.
35 // you can find out which it is if the uid or the signature return
36 // null values. (Not null but isNull)
37 //
38public:
39 explicit UIDModelItem(const UserID::Signature &sig, UIDModelItem *parentItem, bool showRemarks)
40 : mParentItem{parentItem}
41 , mSig{sig}
42 {
43 const auto name = Formatting::prettyName(sig);
44 const auto email = Formatting::prettyEMail(sig);
45 mItemData = {
46 Formatting::prettyID(sig.signerKeyID()),
47 name,
48 email,
49 Formatting::creationDateString(sig),
50 Formatting::expirationDateString(sig),
51 Formatting::validityShort(sig),
52 sig.isExportable() ? QStringLiteral("✓") : QString{},
53 };
54
55 QString lastNotation;
56 if (showRemarks && parentItem) {
57 for (const auto &notation : sig.notations()) {
58 if (notation.name() && !strcmp(notation.name(), "rem@gnupg.org")) {
59 lastNotation = QString::fromUtf8(notation.value());
60 }
61 }
62 }
63 mItemData.push_back(lastNotation);
64
65 const auto trustSignatureDomain = Formatting::trustSignatureDomain(sig);
66 mItemData.push_back(trustSignatureDomain);
67 mAccessibleText = {
68 Formatting::accessibleHexID(sig.signerKeyID()),
69 name.isEmpty() ? i18nc("text for screen readers for an empty name", "no name") : QVariant{},
70 email.isEmpty() ? i18nc("text for screen readers for an empty email address", "no email") : QVariant{},
71 Formatting::accessibleDate(Formatting::creationDate(sig)),
72 Formatting::accessibleExpirationDate(sig),
73 {}, // display text is always okay
74 sig.isExportable() ? i18nc("yes, is exportable", "yes") : i18nc("no, is not exportable", "no"),
75 lastNotation.isEmpty() ? i18nc("accessible text for empty list of tags", "none") : QVariant{},
76 trustSignatureDomain.isEmpty() ? i18n("not applicable") : QVariant{},
77 };
78 Q_ASSERT(mAccessibleText.size() == mItemData.size());
79 }
80
81 explicit UIDModelItem(const UserID &uid, UIDModelItem *parentItem)
82 : mParentItem{parentItem}
83 , mUid{uid}
84 {
85 mItemData = {Formatting::prettyUserID(uid)};
86 // for the empty cells of the user ID rows we announce "User ID"
87 mAccessibleText = {
88 {}, // use displayed user ID
89 i18n("User ID"),
90 i18n("User ID"),
91 i18n("User ID"),
92 i18n("User ID"),
93 i18n("User ID"),
94 i18n("User ID"),
95 i18n("User ID"),
96 i18n("User ID"),
97 };
98 }
99
100 // The root item
101 UIDModelItem()
102 {
103 mItemData = {
104 i18n("User ID / Certification Key ID"),
105 i18n("Name"),
106 i18n("E-Mail"),
107 i18n("Valid From"),
108 i18n("Valid Until"),
109 i18n("Status"),
110 i18n("Exportable"),
111 i18n("Tags"),
112 i18n("Trust Signature For"),
113 };
114 // mAccessibleText is explicitly left empty
115 }
116
117 ~UIDModelItem()
118 {
119 qDeleteAll(mChildItems);
120 }
121
122 void appendChild(UIDModelItem *child)
123 {
124 mChildItems << child;
125 }
126
127 UIDModelItem *child(int row) const
128 {
129 return mChildItems.value(row);
130 }
131
132 const UIDModelItem *constChild(int row) const
133 {
134 return mChildItems.value(row);
135 }
136
137 int childCount() const
138 {
139 return mChildItems.count();
140 }
141
142 int columnCount() const
143 {
144 if (childCount()) {
145 // We take the value from the first child
146 // as we are likely a UID and our children
147 // are UID Signatures.
148 return constChild(0)->columnCount();
149 }
150 return mItemData.count();
151 }
152
153 QVariant data(int column) const
154 {
155 return mItemData.value(column);
156 }
157
158 QVariant accessibleText(int column) const
159 {
160 return mAccessibleText.value(column);
161 }
162
163 QVariant toolTip(int column) const
164 {
165 if (!mSig.isNull()) {
166 if (column == static_cast<int>(UserIDListModel::Column::TrustSignatureDomain)) {
167 return Formatting::trustSignature(mSig);
168 }
169 }
170 return mItemData.value(column);
171 }
172
173 QVariant icon(int column) const
174 {
175 if (!mSig.isNull() && column == static_cast<int>(UserIDListModel::Column::Status)) {
176 return Formatting::validityIcon(mSig);
177 }
178 return {};
179 }
180
181 int row() const
182 {
183 if (mParentItem) {
184 return mParentItem->mChildItems.indexOf(const_cast<UIDModelItem *>(this));
185 }
186 return 0;
187 }
188
189 UIDModelItem *parentItem() const
190 {
191 return mParentItem;
192 }
193
194 UserID::Signature signature() const
195 {
196 return mSig;
197 }
198
199 UserID uid() const
200 {
201 return mUid;
202 }
203
204 const char *signerKeyId() const
205 {
206 return mSig.signerKeyID();
207 }
208
209private:
210 QList<UIDModelItem *> mChildItems;
211 QList<QVariant> mItemData;
212 QList<QVariant> mAccessibleText;
213 UIDModelItem *mParentItem = nullptr;
214 UserID::Signature mSig;
215 UserID mUid;
216};
217
218UserIDListModel::UserIDListModel(QObject *p)
220{
221}
222
223UserIDListModel::~UserIDListModel() = default;
224
225Key UserIDListModel::key() const
226{
227 return mKey;
228}
229
230void UserIDListModel::setKey(const Key &key)
231{
233 mKey = key;
234
235 mRootItem.reset(new UIDModelItem);
236 for (int i = 0, ids = key.numUserIDs(); i < ids; ++i) {
237 UserID uid = key.userID(i);
238 auto uidItem = new UIDModelItem(uid, mRootItem.get());
239 mRootItem->appendChild(uidItem);
240 std::vector<UserID::Signature> sigs = uid.signatures();
241 std::sort(sigs.begin(), sigs.end());
242 for (const auto &sig : sigs) {
243 auto sigItem = new UIDModelItem(sig, uidItem, mRemarksEnabled);
244 uidItem->appendChild(sigItem);
245 }
246 }
247
249}
250
251int UserIDListModel::columnCount(const QModelIndex &parent) const
252{
253 if (parent.isValid()) {
254 return static_cast<UIDModelItem *>(parent.internalPointer())->columnCount();
255 }
256
257 if (!mRootItem) {
258 return 0;
259 }
260
261 return mRootItem->columnCount();
262}
263
264int UserIDListModel::rowCount(const QModelIndex &parent) const
265{
266 if (parent.column() > 0 || !mRootItem) {
267 return 0;
268 }
269
270 const UIDModelItem *const parentItem = !parent.isValid() ? mRootItem.get() : static_cast<UIDModelItem *>(parent.internalPointer());
271 return parentItem->childCount();
272}
273
274QModelIndex UserIDListModel::index(int row, int column, const QModelIndex &parent) const
275{
276 if (!hasIndex(row, column, parent)) {
277 return {};
278 }
279
280 const UIDModelItem *const parentItem = !parent.isValid() ? mRootItem.get() : static_cast<UIDModelItem *>(parent.internalPointer());
281 UIDModelItem *const childItem = parentItem->child(row);
282 if (childItem) {
283 return createIndex(row, column, childItem);
284 } else {
285 return QModelIndex();
286 }
287}
288
290{
291 if (!index.isValid()) {
292 return {};
293 }
294 auto childItem = static_cast<UIDModelItem *>(index.internalPointer());
295 UIDModelItem *parentItem = childItem->parentItem();
296
297 if (parentItem == mRootItem.get()) {
298 return QModelIndex();
299 }
300
301 return createIndex(parentItem->row(), 0, parentItem);
302}
303
304QVariant UserIDListModel::headerData(int section, Qt::Orientation o, int role) const
305{
306 if (o == Qt::Horizontal && mRootItem) {
307 if (role == Qt::DisplayRole || role == Qt::EditRole || role == Qt::ToolTipRole) {
308 return mRootItem->data(section);
309 } else if (role == Qt::AccessibleTextRole) {
310 return mRootItem->accessibleText(section);
311 }
312 }
313 return QVariant();
314}
315
316QVariant UserIDListModel::data(const QModelIndex &index, int role) const
317{
318 if (!index.isValid()) {
319 return QVariant();
320 }
321
322 auto item = static_cast<UIDModelItem *>(index.internalPointer());
323
324 switch (role) {
325 case Qt::DisplayRole:
326 case Qt::EditRole:
327 return item->data(index.column());
329 return item->accessibleText(index.column());
330 case Qt::ToolTipRole:
331 return item->toolTip(index.column());
333 return item->icon(index.column());
334 case UserIDListModel::SignerKeyIdRole:
335 return QVariant::fromValue(item->signerKeyId());
336 default:;
337 }
338
339 return {};
340}
341
342UserID UserIDListModel::userID(const QModelIndex &index) const
343{
344 if (!index.isValid()) {
345 return UserID();
346 }
347 UIDModelItem *item = static_cast<UIDModelItem *>(index.internalPointer());
348 return item->uid();
349}
350
351QList<UserID> UserIDListModel::userIDs(const QModelIndexList &indexes) const
352{
354 for (const QModelIndex &idx : indexes) {
355 if (!idx.isValid()) {
356 continue;
357 }
358 auto item = static_cast<UIDModelItem *>(idx.internalPointer());
359 if (!item->uid().isNull()) {
360 ret << item->uid();
361 }
362 }
363 return ret;
364}
365
366UserID::Signature UserIDListModel::signature(const QModelIndex &index) const
367{
368 if (!index.isValid()) {
369 return UserID::Signature();
370 }
371 UIDModelItem *item = static_cast<UIDModelItem *>(index.internalPointer());
372 return item->signature();
373}
374
375QList<UserID::Signature> UserIDListModel::signatures(const QModelIndexList &indexes) const
376{
378 for (const QModelIndex &idx : indexes) {
379 if (!idx.isValid()) {
380 continue;
381 }
382 auto item = static_cast<UIDModelItem *>(idx.internalPointer());
383 if (!item->signature().isNull()) {
384 ret << item->signature();
385 }
386 }
387 return ret;
388}
389
390void UserIDListModel::enableRemarks(bool value)
391{
392 mRemarksEnabled = value;
393}
394
395#include "moc_useridlistmodel.cpp"
QString i18nc(const char *context, const char *text, const TYPE &arg...)
QString i18n(const char *text, const TYPE &arg...)
QModelIndex createIndex(int row, int column, const void *ptr) const const
bool hasIndex(int row, int column, const QModelIndex &parent) const const
qsizetype count() const const
qsizetype indexOf(const AT &value, qsizetype from) const const
void push_back(parameter_type value)
qsizetype size() const const
T value(qsizetype i) const const
int column() const const
void * internalPointer() const const
bool isValid() const const
QObject * parent() const const
QString fromUtf8(QByteArrayView str)
DisplayRole
Orientation
QVariant fromValue(T &&value)
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Fri Jul 26 2024 11:50:31 by doxygen 1.11.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.