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

0001 /* -*- mode: c++; c-basic-offset:4 -*-
0002     models/subkeylistmodel.cpp
0003 
0004     This file is part of Kleopatra, the KDE keymanager
0005     SPDX-FileCopyrightText: 2007 Klarälvdalens Datakonsult AB
0006 
0007     SPDX-License-Identifier: GPL-2.0-or-later
0008 */
0009 
0010 #include <config-libkleo.h>
0011 
0012 #include "subkeylistmodel.h"
0013 
0014 #include <libkleo/formatting.h>
0015 
0016 #include <KLocalizedString>
0017 
0018 #include <QDate>
0019 #include <QVariant>
0020 
0021 #include <gpgme++/key.h>
0022 
0023 #include <algorithm>
0024 #include <iterator>
0025 
0026 using namespace GpgME;
0027 using namespace Kleo;
0028 
0029 class SubkeyListModel::Private
0030 {
0031     friend class ::Kleo::SubkeyListModel;
0032     SubkeyListModel *const q;
0033 
0034 public:
0035     explicit Private(SubkeyListModel *qq)
0036         : q(qq)
0037         , key()
0038     {
0039     }
0040 
0041 private:
0042     Key key;
0043 };
0044 
0045 SubkeyListModel::SubkeyListModel(QObject *p)
0046     : QAbstractTableModel(p)
0047     , d(new Private(this))
0048 {
0049 }
0050 
0051 SubkeyListModel::~SubkeyListModel()
0052 {
0053 }
0054 
0055 Key SubkeyListModel::key() const
0056 {
0057     return d->key;
0058 }
0059 
0060 // slot
0061 void SubkeyListModel::setKey(const Key &key)
0062 {
0063     const Key oldKey = d->key;
0064 
0065     if (qstricmp(key.primaryFingerprint(), oldKey.primaryFingerprint()) != 0) {
0066         // different key -> reset
0067         beginResetModel();
0068         d->key = key;
0069         endResetModel();
0070         return;
0071     }
0072 
0073     d->key = key;
0074 
0075     // ### diff them, and signal more fine-grained than this:
0076 
0077     if (key.numSubkeys() > 0 && oldKey.numSubkeys() == key.numSubkeys()) {
0078         Q_EMIT dataChanged(index(0, 0), index(key.numSubkeys() - 1, NumColumns - 1));
0079     } else {
0080         Q_EMIT layoutAboutToBeChanged();
0081         Q_EMIT layoutChanged();
0082     }
0083 }
0084 
0085 Subkey SubkeyListModel::subkey(const QModelIndex &idx) const
0086 {
0087     if (idx.isValid()) {
0088         return d->key.subkey(idx.row());
0089     } else {
0090         return Subkey();
0091     }
0092 }
0093 
0094 std::vector<Subkey> SubkeyListModel::subkeys(const QList<QModelIndex> &indexes) const
0095 {
0096     std::vector<Subkey> result;
0097     result.reserve(indexes.size());
0098     std::transform(indexes.begin(), //
0099                    indexes.end(),
0100                    std::back_inserter(result),
0101                    [this](const QModelIndex &idx) {
0102                        return subkey(idx);
0103                    });
0104     return result;
0105 }
0106 
0107 QModelIndex SubkeyListModel::index(const Subkey &subkey, int col) const
0108 {
0109     // O(N), but not sorted, so no better way...
0110     for (unsigned int row = 0, end = d->key.numSubkeys(); row != end; ++row) {
0111         if (qstricmp(subkey.keyID(), d->key.subkey(row).keyID()) == 0) {
0112             return index(row, col);
0113         }
0114     }
0115     return {};
0116 }
0117 
0118 QList<QModelIndex> SubkeyListModel::indexes(const std::vector<Subkey> &subkeys) const
0119 {
0120     QList<QModelIndex> result;
0121     result.reserve(subkeys.size());
0122     // O(N*M), but who cares...?
0123     std::transform(subkeys.begin(), //
0124                    subkeys.end(),
0125                    std::back_inserter(result),
0126                    [this](const Subkey &key) {
0127                        return index(key);
0128                    });
0129     return result;
0130 }
0131 
0132 void SubkeyListModel::clear()
0133 {
0134     beginResetModel();
0135     d->key = Key::null;
0136     endResetModel();
0137 }
0138 
0139 int SubkeyListModel::columnCount(const QModelIndex &) const
0140 {
0141     return NumColumns;
0142 }
0143 
0144 int SubkeyListModel::rowCount(const QModelIndex &pidx) const
0145 {
0146     return pidx.isValid() ? 0 : d->key.numSubkeys();
0147 }
0148 
0149 QVariant SubkeyListModel::headerData(int section, Qt::Orientation o, int role) const
0150 {
0151     if (o == Qt::Horizontal) {
0152         if (role == Qt::DisplayRole || role == Qt::EditRole || role == Qt::ToolTipRole) {
0153             switch (section) {
0154             case ID:
0155                 return i18n("ID");
0156             case Type:
0157                 return i18n("Type");
0158             case ValidFrom:
0159                 return i18n("Valid From");
0160             case ValidUntil:
0161                 return i18n("Valid Until");
0162             case Status:
0163                 return i18n("Status");
0164             case Strength:
0165                 return i18n("Strength");
0166             case Usage:
0167                 return i18n("Usage");
0168             case NumColumns:;
0169             }
0170         }
0171     }
0172     return QVariant();
0173 }
0174 
0175 QVariant SubkeyListModel::data(const QModelIndex &idx, int role) const
0176 {
0177     if (role != Qt::DisplayRole && role != Qt::EditRole && role != Qt::ToolTipRole) {
0178         return QVariant();
0179     }
0180 
0181     const Subkey subkey = this->subkey(idx);
0182     if (subkey.isNull()) {
0183         return QVariant();
0184     }
0185 
0186     switch (idx.column()) {
0187     case ID:
0188         return QString::fromLatin1(subkey.keyID());
0189     case Type:
0190         return Formatting::type(subkey);
0191     case ValidFrom:
0192         if (role == Qt::EditRole) {
0193             return Formatting::creationDate(subkey);
0194         } else {
0195             return Formatting::creationDateString(subkey);
0196         }
0197     case ValidUntil:
0198         if (role == Qt::EditRole) {
0199             return Formatting::expirationDate(subkey);
0200         } else {
0201             return Formatting::expirationDateString(subkey);
0202         }
0203     case Status:
0204         return Formatting::validityShort(subkey);
0205     case Usage:
0206         return Formatting::usageString(subkey);
0207     case Strength:
0208         const QString algName = QString::fromStdString(subkey.algoName());
0209         // For ECC keys the algo name is something like bp512 and directly
0210         // indicated the "strength"
0211         return algName.isEmpty() ? QVariant(subkey.length()) : algName;
0212     }
0213 
0214     return QVariant();
0215 }
0216 
0217 #include "moc_subkeylistmodel.cpp"