File indexing completed on 2025-01-05 04:55:46
0001 /* -*- mode: c++; c-basic-offset:4 -*- 0002 models/useridlistmodel.cpp 0003 0004 This file is part of Kleopatra, the KDE keymanager 0005 SPDX-FileCopyrightText: 2007 Klarälvdalens Datakonsult AB 0006 SPDX-FileCopyrightText: 2016 Andre Heinecke <aheinecke@gnupg.org> 0007 SPDX-FileCopyrightText: 2021 g10 Code GmbH 0008 SPDX-FileContributor: Ingo Klöcker <dev@ingo-kloecker.de> 0009 0010 SPDX-License-Identifier: GPL-2.0-or-later 0011 */ 0012 0013 #include <config-libkleo.h> 0014 0015 #include "useridlistmodel.h" 0016 0017 #include "keycache.h" 0018 0019 #include <libkleo/formatting.h> 0020 0021 #include <KLocalizedString> 0022 0023 #include <QDate> 0024 #include <QIcon> 0025 #include <QVariant> 0026 0027 #include <gpgme++/key.h> 0028 0029 using namespace GpgME; 0030 using namespace Kleo; 0031 0032 class UIDModelItem 0033 { 0034 // A uid model item can either be a UserID::Signature or a UserID. 0035 // you can find out which it is if the uid or the signature return 0036 // null values. (Not null but isNull) 0037 // 0038 public: 0039 explicit UIDModelItem(const UserID::Signature &sig, UIDModelItem *parentItem, bool showRemarks) 0040 : mParentItem{parentItem} 0041 , mSig{sig} 0042 { 0043 const auto name = Formatting::prettyName(sig); 0044 const auto email = Formatting::prettyEMail(sig); 0045 mItemData = { 0046 Formatting::prettyID(sig.signerKeyID()), 0047 name, 0048 email, 0049 Formatting::creationDateString(sig), 0050 Formatting::expirationDateString(sig), 0051 Formatting::validityShort(sig), 0052 sig.isExportable() ? QStringLiteral("✓") : QString{}, 0053 }; 0054 0055 QString lastNotation; 0056 if (showRemarks && parentItem) { 0057 for (const auto ¬ation : sig.notations()) { 0058 if (notation.name() && !strcmp(notation.name(), "rem@gnupg.org")) { 0059 lastNotation = QString::fromUtf8(notation.value()); 0060 } 0061 } 0062 } 0063 mItemData.push_back(lastNotation); 0064 0065 const auto trustSignatureDomain = Formatting::trustSignatureDomain(sig); 0066 mItemData.push_back(trustSignatureDomain); 0067 mAccessibleText = { 0068 Formatting::accessibleHexID(sig.signerKeyID()), 0069 name.isEmpty() ? i18nc("text for screen readers for an empty name", "no name") : QVariant{}, 0070 email.isEmpty() ? i18nc("text for screen readers for an empty email address", "no email") : QVariant{}, 0071 Formatting::accessibleDate(Formatting::creationDate(sig)), 0072 Formatting::accessibleExpirationDate(sig), 0073 {}, // display text is always okay 0074 sig.isExportable() ? i18nc("yes, is exportable", "yes") : i18nc("no, is not exportable", "no"), 0075 lastNotation.isEmpty() ? i18nc("accessible text for empty list of tags", "none") : QVariant{}, 0076 trustSignatureDomain.isEmpty() ? i18n("not applicable") : QVariant{}, 0077 }; 0078 Q_ASSERT(mAccessibleText.size() == mItemData.size()); 0079 } 0080 0081 explicit UIDModelItem(const UserID &uid, UIDModelItem *parentItem) 0082 : mParentItem{parentItem} 0083 , mUid{uid} 0084 { 0085 mItemData = {Formatting::prettyUserID(uid)}; 0086 // for the empty cells of the user ID rows we announce "User ID" 0087 mAccessibleText = { 0088 {}, // use displayed user ID 0089 i18n("User ID"), 0090 i18n("User ID"), 0091 i18n("User ID"), 0092 i18n("User ID"), 0093 i18n("User ID"), 0094 i18n("User ID"), 0095 i18n("User ID"), 0096 i18n("User ID"), 0097 }; 0098 } 0099 0100 // The root item 0101 UIDModelItem() 0102 { 0103 mItemData = { 0104 i18n("User ID / Certification Key ID"), 0105 i18n("Name"), 0106 i18n("E-Mail"), 0107 i18n("Valid From"), 0108 i18n("Valid Until"), 0109 i18n("Status"), 0110 i18n("Exportable"), 0111 i18n("Tags"), 0112 i18n("Trust Signature For"), 0113 }; 0114 // mAccessibleText is explicitly left empty 0115 } 0116 0117 ~UIDModelItem() 0118 { 0119 qDeleteAll(mChildItems); 0120 } 0121 0122 void appendChild(UIDModelItem *child) 0123 { 0124 mChildItems << child; 0125 } 0126 0127 UIDModelItem *child(int row) const 0128 { 0129 return mChildItems.value(row); 0130 } 0131 0132 const UIDModelItem *constChild(int row) const 0133 { 0134 return mChildItems.value(row); 0135 } 0136 0137 int childCount() const 0138 { 0139 return mChildItems.count(); 0140 } 0141 0142 int columnCount() const 0143 { 0144 if (childCount()) { 0145 // We take the value from the first child 0146 // as we are likely a UID and our children 0147 // are UID Signatures. 0148 return constChild(0)->columnCount(); 0149 } 0150 return mItemData.count(); 0151 } 0152 0153 QVariant data(int column) const 0154 { 0155 return mItemData.value(column); 0156 } 0157 0158 QVariant accessibleText(int column) const 0159 { 0160 return mAccessibleText.value(column); 0161 } 0162 0163 QVariant toolTip(int column) const 0164 { 0165 if (!mSig.isNull()) { 0166 if (column == static_cast<int>(UserIDListModel::Column::Status)) { 0167 return i18n("class %1", mSig.certClass()); 0168 } else if (column == static_cast<int>(UserIDListModel::Column::TrustSignatureDomain)) { 0169 return Formatting::trustSignature(mSig); 0170 } 0171 } 0172 return mItemData.value(column); 0173 } 0174 0175 QVariant icon(int column) const 0176 { 0177 if (!mSig.isNull() && column == static_cast<int>(UserIDListModel::Column::Status)) { 0178 return Formatting::validityIcon(mSig); 0179 } 0180 return {}; 0181 } 0182 0183 int row() const 0184 { 0185 if (mParentItem) { 0186 return mParentItem->mChildItems.indexOf(const_cast<UIDModelItem *>(this)); 0187 } 0188 return 0; 0189 } 0190 0191 UIDModelItem *parentItem() const 0192 { 0193 return mParentItem; 0194 } 0195 0196 UserID::Signature signature() const 0197 { 0198 return mSig; 0199 } 0200 0201 UserID uid() const 0202 { 0203 return mUid; 0204 } 0205 0206 private: 0207 QList<UIDModelItem *> mChildItems; 0208 QList<QVariant> mItemData; 0209 QList<QVariant> mAccessibleText; 0210 UIDModelItem *mParentItem = nullptr; 0211 UserID::Signature mSig; 0212 UserID mUid; 0213 }; 0214 0215 UserIDListModel::UserIDListModel(QObject *p) 0216 : QAbstractItemModel{p} 0217 { 0218 } 0219 0220 UserIDListModel::~UserIDListModel() = default; 0221 0222 Key UserIDListModel::key() const 0223 { 0224 return mKey; 0225 } 0226 0227 void UserIDListModel::setKey(const Key &key) 0228 { 0229 beginResetModel(); 0230 mKey = key; 0231 0232 mRootItem.reset(new UIDModelItem); 0233 for (int i = 0, ids = key.numUserIDs(); i < ids; ++i) { 0234 UserID uid = key.userID(i); 0235 auto uidItem = new UIDModelItem(uid, mRootItem.get()); 0236 mRootItem->appendChild(uidItem); 0237 std::vector<UserID::Signature> sigs = uid.signatures(); 0238 std::sort(sigs.begin(), sigs.end()); 0239 for (const auto &sig : sigs) { 0240 auto sigItem = new UIDModelItem(sig, uidItem, mRemarksEnabled); 0241 uidItem->appendChild(sigItem); 0242 } 0243 } 0244 0245 endResetModel(); 0246 } 0247 0248 int UserIDListModel::columnCount(const QModelIndex &parent) const 0249 { 0250 if (parent.isValid()) { 0251 return static_cast<UIDModelItem *>(parent.internalPointer())->columnCount(); 0252 } 0253 0254 if (!mRootItem) { 0255 return 0; 0256 } 0257 0258 return mRootItem->columnCount(); 0259 } 0260 0261 int UserIDListModel::rowCount(const QModelIndex &parent) const 0262 { 0263 if (parent.column() > 0 || !mRootItem) { 0264 return 0; 0265 } 0266 0267 const UIDModelItem *const parentItem = !parent.isValid() ? mRootItem.get() : static_cast<UIDModelItem *>(parent.internalPointer()); 0268 return parentItem->childCount(); 0269 } 0270 0271 QModelIndex UserIDListModel::index(int row, int column, const QModelIndex &parent) const 0272 { 0273 if (!hasIndex(row, column, parent)) { 0274 return {}; 0275 } 0276 0277 const UIDModelItem *const parentItem = !parent.isValid() ? mRootItem.get() : static_cast<UIDModelItem *>(parent.internalPointer()); 0278 UIDModelItem *const childItem = parentItem->child(row); 0279 if (childItem) { 0280 return createIndex(row, column, childItem); 0281 } else { 0282 return QModelIndex(); 0283 } 0284 } 0285 0286 QModelIndex UserIDListModel::parent(const QModelIndex &index) const 0287 { 0288 if (!index.isValid()) { 0289 return {}; 0290 } 0291 auto childItem = static_cast<UIDModelItem *>(index.internalPointer()); 0292 UIDModelItem *parentItem = childItem->parentItem(); 0293 0294 if (parentItem == mRootItem.get()) { 0295 return QModelIndex(); 0296 } 0297 0298 return createIndex(parentItem->row(), 0, parentItem); 0299 } 0300 0301 QVariant UserIDListModel::headerData(int section, Qt::Orientation o, int role) const 0302 { 0303 if (o == Qt::Horizontal && mRootItem) { 0304 if (role == Qt::DisplayRole || role == Qt::EditRole || role == Qt::ToolTipRole) { 0305 return mRootItem->data(section); 0306 } else if (role == Qt::AccessibleTextRole) { 0307 return mRootItem->accessibleText(section); 0308 } 0309 } 0310 return QVariant(); 0311 } 0312 0313 QVariant UserIDListModel::data(const QModelIndex &index, int role) const 0314 { 0315 if (!index.isValid()) { 0316 return QVariant(); 0317 } 0318 0319 auto item = static_cast<UIDModelItem *>(index.internalPointer()); 0320 0321 switch (role) { 0322 case Qt::DisplayRole: 0323 case Qt::EditRole: 0324 return item->data(index.column()); 0325 case Qt::AccessibleTextRole: 0326 return item->accessibleText(index.column()); 0327 case Qt::ToolTipRole: 0328 return item->toolTip(index.column()); 0329 case Qt::DecorationRole: 0330 return item->icon(index.column()); 0331 default:; 0332 } 0333 0334 return {}; 0335 } 0336 0337 UserID UserIDListModel::userID(const QModelIndex &index) const 0338 { 0339 if (!index.isValid()) { 0340 return UserID(); 0341 } 0342 UIDModelItem *item = static_cast<UIDModelItem *>(index.internalPointer()); 0343 return item->uid(); 0344 } 0345 0346 QList<UserID> UserIDListModel::userIDs(const QModelIndexList &indexes) const 0347 { 0348 QList<GpgME::UserID> ret; 0349 for (const QModelIndex &idx : indexes) { 0350 if (!idx.isValid()) { 0351 continue; 0352 } 0353 auto item = static_cast<UIDModelItem *>(idx.internalPointer()); 0354 if (!item->uid().isNull()) { 0355 ret << item->uid(); 0356 } 0357 } 0358 return ret; 0359 } 0360 0361 UserID::Signature UserIDListModel::signature(const QModelIndex &index) const 0362 { 0363 if (!index.isValid()) { 0364 return UserID::Signature(); 0365 } 0366 UIDModelItem *item = static_cast<UIDModelItem *>(index.internalPointer()); 0367 return item->signature(); 0368 } 0369 0370 QList<UserID::Signature> UserIDListModel::signatures(const QModelIndexList &indexes) const 0371 { 0372 QList<GpgME::UserID::Signature> ret; 0373 for (const QModelIndex &idx : indexes) { 0374 if (!idx.isValid()) { 0375 continue; 0376 } 0377 auto item = static_cast<UIDModelItem *>(idx.internalPointer()); 0378 if (!item->signature().isNull()) { 0379 ret << item->signature(); 0380 } 0381 } 0382 return ret; 0383 } 0384 0385 void UserIDListModel::enableRemarks(bool value) 0386 { 0387 mRemarksEnabled = value; 0388 } 0389 0390 #include "moc_useridlistmodel.cpp"