File indexing completed on 2025-01-05 04:55:46

0001 /*
0002     SPDX-FileCopyrightText: 2024 g10 Code GmbH
0003     SPDX-FileContributor: Tobias Fella <tobias.fella@gnupg.com>
0004     SPDX-License-Identifier: GPL-2.0-or-later
0005 */
0006 
0007 #include "useridproxymodel.h"
0008 
0009 #include "keylist.h"
0010 #include "keylistmodel.h"
0011 #include "kleo/keyfiltermanager.h"
0012 #include "utils/algorithm.h"
0013 #include "utils/formatting.h"
0014 #include "utils/systeminfo.h"
0015 
0016 #include <global.h>
0017 
0018 #include <QColor>
0019 
0020 #include <variant>
0021 
0022 using namespace Kleo;
0023 
0024 class UserIDProxyModel::Private
0025 {
0026 public:
0027     Private(UserIDProxyModel *qq);
0028     void loadUserIDs();
0029     QList<std::variant<GpgME::UserID, KeyGroup>> mIds;
0030     QAbstractItemModel *oldSourceModel = nullptr;
0031     UserIDProxyModel *q;
0032 };
0033 
0034 void UserIDProxyModel::Private::loadUserIDs()
0035 {
0036     q->beginResetModel();
0037     mIds.clear();
0038     mIds.reserve(q->sourceModel()->rowCount());
0039     for (auto i = 0; i < q->sourceModel()->rowCount(); ++i) {
0040         const auto key = q->sourceModel()->index(i, 0).data(KeyList::KeyRole).value<GpgME::Key>();
0041         QList<GpgME::UserID> ids;
0042         if (key.isNull()) {
0043             mIds += q->sourceModel()->index(i, 0).data(KeyList::GroupRole).value<KeyGroup>();
0044         } else if (key.protocol() == GpgME::OpenPGP) {
0045             for (const auto &userID : key.userIDs()) {
0046                 mIds += userID;
0047             }
0048         } else {
0049             QList<std::variant<GpgME::UserID, KeyGroup>> ids;
0050             for (const auto &userID : key.userIDs()) {
0051                 const auto exists = Kleo::contains_if(ids, [userID](const auto &other) {
0052                     return !qstrcmp(std::get<GpgME::UserID>(other).email(), userID.email());
0053                 });
0054                 if (!exists && userID.email() && *userID.email()) {
0055                     ids += userID;
0056                 }
0057             }
0058             if (ids.count() > 0) {
0059                 mIds.append(ids);
0060             } else {
0061                 mIds.append(key.userID(0));
0062             }
0063         }
0064     }
0065     q->endResetModel();
0066 }
0067 
0068 UserIDProxyModel::Private::Private(UserIDProxyModel *qq)
0069     : q(qq)
0070 {
0071     connect(q, &UserIDProxyModel::sourceModelChanged, q, [this]() {
0072         if (oldSourceModel) {
0073             disconnect(oldSourceModel, nullptr, q, nullptr);
0074         }
0075         connect(q->sourceModel(), &QAbstractItemModel::dataChanged, q, [this]() {
0076             loadUserIDs();
0077         });
0078         connect(q->sourceModel(), &QAbstractItemModel::rowsInserted, q, [this]() {
0079             loadUserIDs();
0080         });
0081         connect(q->sourceModel(), &QAbstractItemModel::modelReset, q, [this]() {
0082             loadUserIDs();
0083         });
0084         oldSourceModel = q->sourceModel();
0085         loadUserIDs();
0086     });
0087 }
0088 
0089 UserIDProxyModel::UserIDProxyModel(QObject *parent)
0090     : AbstractKeyListSortFilterProxyModel(parent)
0091     , d{new Private(this)}
0092 {
0093 }
0094 
0095 UserIDProxyModel::~UserIDProxyModel() = default;
0096 
0097 static QVariant returnIfValid(const QColor &t)
0098 {
0099     if (t.isValid()) {
0100         return t;
0101     } else {
0102         return QVariant();
0103     }
0104 }
0105 
0106 QModelIndex UserIDProxyModel::mapFromSource(const QModelIndex &sourceIndex) const
0107 {
0108     if (!sourceIndex.isValid()) {
0109         return {};
0110     }
0111     const auto &sourceKey = sourceIndex.data(KeyList::KeyRole).value<GpgME::Key>();
0112     if (sourceKey.isNull()) {
0113         const auto &sourceKeyGroup = sourceIndex.data(KeyList::GroupRole).value<KeyGroup>();
0114         for (int i = 0; i < d->mIds.count(); ++i) {
0115             if (std::holds_alternative<KeyGroup>(d->mIds[i]) && std::get<KeyGroup>(d->mIds[i]).id() == sourceKeyGroup.id()) {
0116                 return index(i, sourceIndex.column(), {});
0117             }
0118         }
0119     } else {
0120         const auto &fingerprint = sourceKey.primaryFingerprint();
0121         for (int i = 0; i < d->mIds.count(); ++i) {
0122             if (std::holds_alternative<GpgME::UserID>(d->mIds[i]) && !qstrcmp(fingerprint, std::get<GpgME::UserID>(d->mIds[i]).parent().primaryFingerprint())) {
0123                 return index(i, sourceIndex.column(), {});
0124             }
0125         }
0126     }
0127 
0128     return {};
0129 }
0130 
0131 QModelIndex UserIDProxyModel::mapToSource(const QModelIndex &proxyIndex) const
0132 {
0133     if (!proxyIndex.isValid()) {
0134         return {};
0135     }
0136     const auto &entry = d->mIds[proxyIndex.row()];
0137 
0138     if (std::holds_alternative<KeyGroup>(entry)) {
0139         const auto &id = std::get<KeyGroup>(entry).id();
0140         for (int i = 0; i < sourceModel()->rowCount(); ++i) {
0141             if (sourceModel()->index(i, 0).data(KeyList::GroupRole).value<KeyGroup>().id() == id) {
0142                 return sourceModel()->index(i, proxyIndex.column());
0143             }
0144         }
0145     } else {
0146         const auto &fingerprint = std::get<GpgME::UserID>(entry).parent().primaryFingerprint();
0147         for (int i = 0; i < sourceModel()->rowCount(); ++i) {
0148             if (!qstrcmp(sourceModel()->index(i, 0).data(KeyList::KeyRole).value<GpgME::Key>().primaryFingerprint(), fingerprint)) {
0149                 return sourceModel()->index(i, proxyIndex.column());
0150             }
0151         }
0152     }
0153 
0154     return {};
0155 }
0156 
0157 int UserIDProxyModel::rowCount(const QModelIndex &parent) const
0158 {
0159     if (parent.isValid()) {
0160         return 0;
0161     }
0162     return d->mIds.count();
0163 }
0164 
0165 QModelIndex UserIDProxyModel::index(int row, int column, const QModelIndex &parent) const
0166 {
0167     if (parent.isValid()) {
0168         return {};
0169     }
0170     return createIndex(row, column, nullptr);
0171 }
0172 
0173 QModelIndex UserIDProxyModel::parent(const QModelIndex &) const
0174 {
0175     return {};
0176 }
0177 
0178 int UserIDProxyModel::columnCount(const QModelIndex &index) const
0179 {
0180     if (!sourceModel()) {
0181         return 0;
0182     }
0183     return sourceModel()->columnCount(mapToSource(index));
0184 }
0185 
0186 QVariant UserIDProxyModel::data(const QModelIndex &index, int role) const
0187 {
0188     const auto &entry = d->mIds[index.row()];
0189     if (std::holds_alternative<KeyGroup>(entry)) {
0190         return AbstractKeyListSortFilterProxyModel::data(index, role);
0191     }
0192     const auto &userId = std::get<GpgME::UserID>(entry);
0193     const auto &key = userId.parent();
0194     if (role == KeyList::UserIDRole) {
0195         return QVariant::fromValue(userId);
0196     }
0197     if ((role == Qt::DisplayRole || role == Qt::EditRole || role == Qt::AccessibleTextRole)) {
0198         if (index.column() == KeyList::Columns::PrettyName) {
0199             if (key.protocol() == GpgME::OpenPGP) {
0200                 return Formatting::prettyName(userId);
0201             } else {
0202                 return Formatting::prettyName(key);
0203             }
0204         }
0205         if (index.column() == KeyList::Columns::PrettyEMail) {
0206             return Formatting::prettyEMail(userId);
0207         }
0208         if (index.column() == KeyList::Columns::Validity) {
0209             return Formatting::complianceStringShort(userId);
0210         }
0211         if (index.column() == KeyList::Columns::Summary) {
0212             return Formatting::summaryLine(userId);
0213         }
0214         if (index.column() == KeyList::Columns::Origin) {
0215             return Formatting::origin(userId.origin());
0216         }
0217         if (index.column() == KeyList::Columns::LastUpdate) {
0218             if (role == Qt::AccessibleTextRole) {
0219                 return Formatting::accessibleDate(userId.lastUpdate());
0220             } else {
0221                 return Formatting::dateString(userId.lastUpdate());
0222             }
0223         }
0224     }
0225     if (role == Qt::BackgroundRole) {
0226         if (!SystemInfo::isHighContrastModeActive()) {
0227             return returnIfValid(KeyFilterManager::instance()->bgColor(userId));
0228         }
0229     } else if (role == Qt::ForegroundRole) {
0230         if (!SystemInfo::isHighContrastModeActive()) {
0231             return returnIfValid(KeyFilterManager::instance()->fgColor(userId));
0232         }
0233     }
0234     return AbstractKeyListSortFilterProxyModel::data(index, role);
0235 }
0236 
0237 UserIDProxyModel *UserIDProxyModel::clone() const
0238 {
0239     auto model = new UserIDProxyModel(QObject::parent());
0240     model->setSourceModel(sourceModel());
0241     return model;
0242 }
0243 
0244 QModelIndex UserIDProxyModel::index(const KeyGroup &group) const
0245 {
0246     Q_UNUSED(group);
0247     return {};
0248 }
0249 
0250 QModelIndex UserIDProxyModel::index(const GpgME::Key &key) const
0251 {
0252     Q_UNUSED(key);
0253     return {};
0254 }