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 
29 using namespace GpgME;
30 using namespace Kleo;
31 
32 class 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  //
38 public:
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::Status)) {
167  return i18n("class %1", mSig.certClass());
168  } else if (column == static_cast<int>(UserIDListModel::Column::TrustSignatureDomain)) {
169  return Formatting::trustSignature(mSig);
170  }
171  }
172  return mItemData.value(column);
173  }
174 
175  QVariant icon(int column) const
176  {
177  if (!mSig.isNull() && column == static_cast<int>(UserIDListModel::Column::Status)) {
178  return Formatting::validityIcon(mSig);
179  }
180  return {};
181  }
182 
183  int row() const
184  {
185  if (mParentItem) {
186  return mParentItem->mChildItems.indexOf(const_cast<UIDModelItem *>(this));
187  }
188  return 0;
189  }
190 
191  UIDModelItem *parentItem() const
192  {
193  return mParentItem;
194  }
195 
196  UserID::Signature signature() const
197  {
198  return mSig;
199  }
200 
201  UserID uid() const
202  {
203  return mUid;
204  }
205 
206 private:
207  QList<UIDModelItem *> mChildItems;
208  QList<QVariant> mItemData;
209  QList<QVariant> mAccessibleText;
210  UIDModelItem *mParentItem = nullptr;
211  UserID::Signature mSig;
212  UserID mUid;
213 };
214 
215 UserIDListModel::UserIDListModel(QObject *p)
216  : QAbstractItemModel{p}
217 {
218 }
219 
220 UserIDListModel::~UserIDListModel() = default;
221 
222 Key UserIDListModel::key() const
223 {
224  return mKey;
225 }
226 
227 void UserIDListModel::setKey(const Key &key)
228 {
229  beginResetModel();
230  mKey = key;
231 
232  mRootItem.reset(new UIDModelItem);
233  for (int i = 0, ids = key.numUserIDs(); i < ids; ++i) {
234  UserID uid = key.userID(i);
235  auto uidItem = new UIDModelItem(uid, mRootItem.get());
236  mRootItem->appendChild(uidItem);
237  std::vector<UserID::Signature> sigs = uid.signatures();
238  std::sort(sigs.begin(), sigs.end());
239  for (const auto &sig : sigs) {
240  auto sigItem = new UIDModelItem(sig, uidItem, mRemarksEnabled);
241  uidItem->appendChild(sigItem);
242  }
243  }
244 
245  endResetModel();
246 }
247 
248 int UserIDListModel::columnCount(const QModelIndex &parent) const
249 {
250  if (parent.isValid()) {
251  return static_cast<UIDModelItem *>(parent.internalPointer())->columnCount();
252  }
253 
254  if (!mRootItem) {
255  return 0;
256  }
257 
258  return mRootItem->columnCount();
259 }
260 
261 int UserIDListModel::rowCount(const QModelIndex &parent) const
262 {
263  if (parent.column() > 0 || !mRootItem) {
264  return 0;
265  }
266 
267  const UIDModelItem *const parentItem = !parent.isValid() ? mRootItem.get() : static_cast<UIDModelItem *>(parent.internalPointer());
268  return parentItem->childCount();
269 }
270 
271 QModelIndex UserIDListModel::index(int row, int column, const QModelIndex &parent) const
272 {
273  if (!hasIndex(row, column, parent)) {
274  return {};
275  }
276 
277  const UIDModelItem *const parentItem = !parent.isValid() ? mRootItem.get() : static_cast<UIDModelItem *>(parent.internalPointer());
278  UIDModelItem *const childItem = parentItem->child(row);
279  if (childItem) {
280  return createIndex(row, column, childItem);
281  } else {
282  return QModelIndex();
283  }
284 }
285 
286 QModelIndex UserIDListModel::parent(const QModelIndex &index) const
287 {
288  if (!index.isValid()) {
289  return {};
290  }
291  auto childItem = static_cast<UIDModelItem *>(index.internalPointer());
292  UIDModelItem *parentItem = childItem->parentItem();
293 
294  if (parentItem == mRootItem.get()) {
295  return QModelIndex();
296  }
297 
298  return createIndex(parentItem->row(), 0, parentItem);
299 }
300 
301 QVariant UserIDListModel::headerData(int section, Qt::Orientation o, int role) const
302 {
303  if (o == Qt::Horizontal && mRootItem) {
304  if (role == Qt::DisplayRole || role == Qt::EditRole || role == Qt::ToolTipRole) {
305  return mRootItem->data(section);
306  } else if (role == Qt::AccessibleTextRole) {
307  return mRootItem->accessibleText(section);
308  }
309  }
310  return QVariant();
311 }
312 
313 QVariant UserIDListModel::data(const QModelIndex &index, int role) const
314 {
315  if (!index.isValid()) {
316  return QVariant();
317  }
318 
319  auto item = static_cast<UIDModelItem *>(index.internalPointer());
320 
321  switch (role) {
322  case Qt::DisplayRole:
323  case Qt::EditRole:
324  return item->data(index.column());
326  return item->accessibleText(index.column());
327  case Qt::ToolTipRole:
328  return item->toolTip(index.column());
329  case Qt::DecorationRole:
330  return item->icon(index.column());
331  default:;
332  }
333 
334  return {};
335 }
336 
337 UserID UserIDListModel::userID(const QModelIndex &index) const
338 {
339  if (!index.isValid()) {
340  return UserID();
341  }
342  UIDModelItem *item = static_cast<UIDModelItem *>(index.internalPointer());
343  return item->uid();
344 }
345 
346 QList<UserID> UserIDListModel::userIDs(const QModelIndexList &indexes) const
347 {
349  for (const QModelIndex &idx : indexes) {
350  if (!idx.isValid()) {
351  continue;
352  }
353  auto item = static_cast<UIDModelItem *>(idx.internalPointer());
354  if (!item->uid().isNull()) {
355  ret << item->uid();
356  }
357  }
358  return ret;
359 }
360 
361 UserID::Signature UserIDListModel::signature(const QModelIndex &index) const
362 {
363  if (!index.isValid()) {
364  return UserID::Signature();
365  }
366  UIDModelItem *item = static_cast<UIDModelItem *>(index.internalPointer());
367  return item->signature();
368 }
369 
370 QList<UserID::Signature> UserIDListModel::signatures(const QModelIndexList &indexes) const
371 {
373  for (const QModelIndex &idx : indexes) {
374  if (!idx.isValid()) {
375  continue;
376  }
377  auto item = static_cast<UIDModelItem *>(idx.internalPointer());
378  if (!item->signature().isNull()) {
379  ret << item->signature();
380  }
381  }
382  return ret;
383 }
384 
385 void UserIDListModel::enableRemarks(bool value)
386 {
387  mRemarksEnabled = value;
388 }
389 
390 #include "moc_useridlistmodel.cpp"
DisplayRole
QString fromUtf8(const char *str, int size)
void * internalPointer() const const
int column() const const
T value() const const
QString i18n(const char *text, const TYPE &arg...)
Orientation
bool isEmpty() const const
bool isValid() const const
QString i18nc(const char *context, const char *text, const TYPE &arg...)
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.