diff --git a/src/kleo/keyfiltermanager.cpp b/src/kleo/keyfiltermanager.cpp
index 9be56d99..d9f42bbd 100644
--- a/src/kleo/keyfiltermanager.cpp
+++ b/src/kleo/keyfiltermanager.cpp
@@ -1,481 +1,489 @@
 /*
     keyfiltermanager.cpp
 
     This file is part of libkleopatra, the KDE keymanagement library
     SPDX-FileCopyrightText: 2004 Klarälvdalens Datakonsult AB
 
     SPDX-License-Identifier: GPL-2.0-or-later
 */
 
 #include <config-libkleo.h>
 
 #include "keyfiltermanager.h"
 
 #include "defaultkeyfilter.h"
 #include "kconfigbasedkeyfilter.h"
 #include "stl_util.h"
 
 #include <libkleo/algorithm.h>
 #include <libkleo/compliance.h>
 #include <libkleo/gnupg.h>
 #include <libkleo/keyhelpers.h>
 
 #include <libkleo_debug.h>
 
 #include <KConfig>
 #include <KConfigGroup>
 #include <KLocalizedString>
 #include <KSharedConfig>
 
 #include <QAbstractListModel>
 #include <QCoreApplication>
 #include <QIcon>
 #include <QModelIndex>
 #include <QRegularExpression>
 #include <QStringList>
 
 #include <algorithm>
 #include <climits>
 #include <functional>
 
 using namespace Kleo;
 using namespace GpgME;
 
 namespace
 {
 
 class Model : public QAbstractListModel
 {
     KeyFilterManager::Private *m_keyFilterManagerPrivate;
 
 public:
     explicit Model(KeyFilterManager::Private *p)
         : QAbstractListModel(nullptr)
         , m_keyFilterManagerPrivate(p)
     {
     }
 
     int rowCount(const QModelIndex &) const override;
     QVariant data(const QModelIndex &idx, int role) const override;
     /* upgrade to public */ using QAbstractListModel::beginResetModel;
     /* upgrade to public */ using QAbstractListModel::endResetModel;
 };
 
 class AllCertificatesKeyFilter : public DefaultKeyFilter
 {
 public:
     AllCertificatesKeyFilter()
         : DefaultKeyFilter()
     {
         setSpecificity(UINT_MAX); // overly high for ordering
         setName(i18n("All Certificates"));
         setId(QStringLiteral("all-certificates"));
         setMatchContexts(Filtering);
     }
 };
 
 class MyCertificatesKeyFilter : public DefaultKeyFilter
 {
 public:
     MyCertificatesKeyFilter()
         : DefaultKeyFilter()
     {
         setHasSecret(Set);
         setSpecificity(UINT_MAX - 1); // overly high for ordering
 
         setName(i18n("My Certificates"));
         setId(QStringLiteral("my-certificates"));
         setMatchContexts(AnyMatchContext);
         setBold(true);
     }
 };
 
 class TrustedCertificatesKeyFilter : public DefaultKeyFilter
 {
 public:
     TrustedCertificatesKeyFilter()
         : DefaultKeyFilter()
     {
         setRevoked(NotSet);
         setValidity(IsAtLeast);
         setValidityReferenceLevel(UserID::Marginal);
         setSpecificity(UINT_MAX - 2); // overly high for ordering
 
         setName(i18n("Trusted Certificates"));
         setId(QStringLiteral("trusted-certificates"));
         setMatchContexts(Filtering);
     }
 };
 
 class FullCertificatesKeyFilter : public DefaultKeyFilter
 {
 public:
     FullCertificatesKeyFilter()
         : DefaultKeyFilter()
     {
         setRevoked(NotSet);
         setValidity(IsAtLeast);
         setValidityReferenceLevel(UserID::Full);
         setSpecificity(UINT_MAX - 3);
 
         setName(i18n("Fully Trusted Certificates"));
         setId(QStringLiteral("full-certificates"));
         setMatchContexts(Filtering);
     }
 };
 
 class OtherCertificatesKeyFilter : public DefaultKeyFilter
 {
 public:
     OtherCertificatesKeyFilter()
         : DefaultKeyFilter()
     {
         setHasSecret(NotSet);
         setValidity(IsAtMost);
         setValidityReferenceLevel(UserID::Never);
         setSpecificity(UINT_MAX - 4); // overly high for ordering
 
         setName(i18n("Other Certificates"));
         setId(QStringLiteral("other-certificates"));
         setMatchContexts(Filtering);
     }
 };
 
 /* This filter selects uncertified OpenPGP keys, i.e. "good" OpenPGP keys with
  * unrevoked user IDs that are not fully valid. */
 class UncertifiedOpenPGPKeysFilter : public DefaultKeyFilter
 {
 public:
     UncertifiedOpenPGPKeysFilter()
         : DefaultKeyFilter()
     {
         setSpecificity(UINT_MAX - 6); // overly high for ordering
         setName(i18n("Not Certified Certificates"));
         setId(QStringLiteral("not-certified-certificates"));
 
         setMatchContexts(Filtering);
         setIsOpenPGP(Set);
         setIsBad(NotSet);
     }
     bool matches(const Key &key, MatchContexts contexts) const override
     {
         return DefaultKeyFilter::matches(key, contexts) && !Kleo::allUserIDsHaveFullValidity(key);
     }
+    bool matches(const UserID &userID, MatchContexts contexts) const override
+    {
+        return DefaultKeyFilter::matches(userID.parent(), contexts) && userID.validity() < UserID::Full;
+    }
 };
 
 /* This filter selects only invalid keys (i.e. those where not all
  * UIDs are at least fully valid).  */
 class KeyNotValidFilter : public DefaultKeyFilter
 {
 public:
     KeyNotValidFilter()
         : DefaultKeyFilter()
     {
         setSpecificity(UINT_MAX - 7); // overly high for ordering
 
         setName(i18n("Not Validated Certificates"));
         setId(QStringLiteral("not-validated-certificates"));
         setMatchContexts(Filtering);
     }
     bool matches(const Key &key, MatchContexts contexts) const override
     {
         return DefaultKeyFilter::matches(key, contexts) && !Kleo::allUserIDsHaveFullValidity(key);
     }
+    bool matches(const UserID &userID, MatchContexts contexts) const override
+    {
+        return DefaultKeyFilter::matches(userID.parent(), contexts) && userID.validity() < UserID::Full;
+    }
 };
 
 }
 
 static std::vector<std::shared_ptr<KeyFilter>> defaultFilters()
 {
     std::vector<std::shared_ptr<KeyFilter>> result;
     result.reserve(6);
     result.push_back(std::shared_ptr<KeyFilter>(new MyCertificatesKeyFilter));
     result.push_back(std::shared_ptr<KeyFilter>(new TrustedCertificatesKeyFilter));
     result.push_back(std::shared_ptr<KeyFilter>(new FullCertificatesKeyFilter));
     result.push_back(std::shared_ptr<KeyFilter>(new OtherCertificatesKeyFilter));
     result.push_back(std::shared_ptr<KeyFilter>(new AllCertificatesKeyFilter));
     result.push_back(std::shared_ptr<KeyFilter>(new UncertifiedOpenPGPKeysFilter));
     result.push_back(std::shared_ptr<KeyFilter>(new KeyNotValidFilter));
     return result;
 }
 
 class KeyFilterManager::Private
 {
 public:
     Private()
         : filters()
         , model(this)
     {
     }
     void clear()
     {
         model.beginResetModel();
         filters.clear();
         model.endResetModel();
     }
 
     std::vector<std::shared_ptr<KeyFilter>> filters;
     Model model;
     GpgME::Protocol protocol = GpgME::UnknownProtocol;
 };
 
 KeyFilterManager *KeyFilterManager::mSelf = nullptr;
 
 KeyFilterManager::KeyFilterManager(QObject *parent)
     : QObject(parent)
     , d(new Private)
 {
     mSelf = this;
     // ### DF: doesn't a KStaticDeleter work more reliably?
     if (QCoreApplication *app = QCoreApplication::instance()) {
         connect(app, &QCoreApplication::aboutToQuit, this, &QObject::deleteLater);
     }
     reload();
 }
 
 KeyFilterManager::~KeyFilterManager()
 {
     mSelf = nullptr;
     if (d) {
         d->clear();
     }
 }
 
 KeyFilterManager *KeyFilterManager::instance()
 {
     if (!mSelf) {
         mSelf = new KeyFilterManager();
     }
     return mSelf;
 }
 
 void KeyFilterManager::alwaysFilterByProtocol(GpgME::Protocol protocol)
 {
     if (protocol != d->protocol) {
         d->protocol = protocol;
         reload();
     }
 }
 
 const std::shared_ptr<KeyFilter> &KeyFilterManager::filterMatching(const Key &key, KeyFilter::MatchContexts contexts) const
 {
     const auto it = std::find_if(d->filters.cbegin(), d->filters.cend(), [&key, contexts](const std::shared_ptr<KeyFilter> &filter) {
         return filter->matches(key, contexts);
     });
     if (it != d->filters.cend()) {
         return *it;
     }
     static const std::shared_ptr<KeyFilter> null;
     return null;
 }
 
 std::vector<std::shared_ptr<KeyFilter>> KeyFilterManager::filtersMatching(const Key &key, KeyFilter::MatchContexts contexts) const
 {
     std::vector<std::shared_ptr<KeyFilter>> result;
     result.reserve(d->filters.size());
     std::remove_copy_if(d->filters.begin(), d->filters.end(), std::back_inserter(result), [&key, contexts](const std::shared_ptr<KeyFilter> &filter) {
         return !filter->matches(key, contexts);
     });
     return result;
 }
 
 namespace
 {
 static const auto byDecreasingSpecificity = [](const std::shared_ptr<KeyFilter> &lhs, const std::shared_ptr<KeyFilter> &rhs) {
     return lhs->specificity() > rhs->specificity();
 };
 }
 
 void KeyFilterManager::reload()
 {
     d->clear();
 
     d->filters = defaultFilters();
     KSharedConfigPtr config = KSharedConfig::openConfig(QStringLiteral("libkleopatrarc"));
 
     const QStringList groups = config->groupList().filter(QRegularExpression(QStringLiteral("^Key Filter #\\d+$")));
     const bool ignoreDeVs = !DeVSCompliance::isCompliant();
     for (QStringList::const_iterator it = groups.begin(); it != groups.end(); ++it) {
         const KConfigGroup cfg(config, *it);
         if (cfg.hasKey("is-de-vs") && ignoreDeVs) {
             /* Don't show de-vs filters in other compliance modes */
             continue;
         }
         d->filters.push_back(std::shared_ptr<KeyFilter>(new KConfigBasedKeyFilter(cfg)));
     }
     std::stable_sort(d->filters.begin(), d->filters.end(), byDecreasingSpecificity);
 
     if (d->protocol != GpgME::UnknownProtocol) {
         // remove filters with conflicting isOpenPGP rule
         const auto conflictingValue = (d->protocol == GpgME::OpenPGP) ? DefaultKeyFilter::NotSet : DefaultKeyFilter::Set;
         Kleo::erase_if(d->filters, [conflictingValue](const auto &f) {
             const auto filter = std::dynamic_pointer_cast<DefaultKeyFilter>(f);
             Q_ASSERT(filter);
             return filter->isOpenPGP() == conflictingValue;
         });
         // add isOpenPGP rule to all filters
         const auto isOpenPGPValue = (d->protocol == GpgME::OpenPGP) ? DefaultKeyFilter::Set : DefaultKeyFilter::NotSet;
         std::for_each(std::begin(d->filters), std::end(d->filters), [isOpenPGPValue](auto &f) {
             const auto filter = std::dynamic_pointer_cast<DefaultKeyFilter>(f);
             Q_ASSERT(filter);
             return filter->setIsOpenPGP(isOpenPGPValue);
         });
     }
     qCDebug(LIBKLEO_LOG) << "KeyFilterManager::" << __func__ << "final filter count is" << d->filters.size();
 }
 
 QAbstractItemModel *KeyFilterManager::model() const
 {
     return &d->model;
 }
 
 const std::shared_ptr<KeyFilter> &KeyFilterManager::keyFilterByID(const QString &id) const
 {
     const auto it = std::find_if(d->filters.begin(), d->filters.end(), [id](const std::shared_ptr<KeyFilter> &filter) {
         return filter->id() == id;
     });
     if (it != d->filters.end()) {
         return *it;
     }
     static const std::shared_ptr<KeyFilter> null;
     return null;
 }
 
 const std::shared_ptr<KeyFilter> &KeyFilterManager::fromModelIndex(const QModelIndex &idx) const
 {
     if (!idx.isValid() || idx.model() != &d->model || idx.row() < 0 || static_cast<unsigned>(idx.row()) >= d->filters.size()) {
         static const std::shared_ptr<KeyFilter> null;
         return null;
     }
     return d->filters[idx.row()];
 }
 
 QModelIndex KeyFilterManager::toModelIndex(const std::shared_ptr<KeyFilter> &kf) const
 {
     if (!kf) {
         return {};
     }
     const auto pair = std::equal_range(d->filters.cbegin(), d->filters.cend(), kf, byDecreasingSpecificity);
     const auto it = std::find(pair.first, pair.second, kf);
     if (it != pair.second) {
         return d->model.index(it - d->filters.begin());
     } else {
         return QModelIndex();
     }
 }
 
 int Model::rowCount(const QModelIndex &) const
 {
     return m_keyFilterManagerPrivate->filters.size();
 }
 
 QVariant Model::data(const QModelIndex &idx, int role) const
 {
     if (!idx.isValid() || idx.model() != this || idx.row() < 0 || static_cast<unsigned>(idx.row()) > m_keyFilterManagerPrivate->filters.size()) {
         return QVariant();
     }
 
     const auto filter = m_keyFilterManagerPrivate->filters[idx.row()];
     switch (role) {
     case Qt::DecorationRole:
         return filter->icon();
 
     case Qt::DisplayRole:
     case Qt::EditRole:
     case Qt::ToolTipRole: /* Most useless tooltip ever.  */
         return filter->name();
 
     case KeyFilterManager::FilterIdRole:
         return filter->id();
 
     case KeyFilterManager::FilterMatchContextsRole:
         return QVariant::fromValue(filter->availableMatchContexts());
 
     default:
         return QVariant();
     }
 }
 
 static KeyFilter::FontDescription
 get_fontdescription(const std::vector<std::shared_ptr<KeyFilter>> &filters, const Key &key, const KeyFilter::FontDescription &initial)
 {
     return kdtools::accumulate_if(
         filters.begin(),
         filters.end(),
         [&key](const std::shared_ptr<KeyFilter> &filter) {
             return filter->matches(key, KeyFilter::Appearance);
         },
         initial,
         [](const KeyFilter::FontDescription &lhs, const std::shared_ptr<KeyFilter> &rhs) {
             return lhs.resolve(rhs->fontDescription());
         });
 }
 
 QFont KeyFilterManager::font(const Key &key, const QFont &baseFont) const
 {
     const KeyFilter::FontDescription fd = get_fontdescription(d->filters, key, KeyFilter::FontDescription());
 
     return fd.font(baseFont);
 }
 
 static QColor get_color(const std::vector<std::shared_ptr<KeyFilter>> &filters, const Key &key, QColor (KeyFilter::*fun)() const)
 {
     const auto it = std::find_if(filters.cbegin(), filters.cend(), [&fun, &key](const std::shared_ptr<KeyFilter> &filter) {
         return filter->matches(key, KeyFilter::Appearance) && (filter.get()->*fun)().isValid();
     });
     if (it == filters.cend()) {
         return {};
     } else {
         return (it->get()->*fun)();
     }
 }
 
 static QColor get_color(const std::vector<std::shared_ptr<KeyFilter>> &filters, const UserID &userID, QColor (KeyFilter::*fun)() const)
 {
     const auto it = std::find_if(filters.cbegin(), filters.cend(), [&fun, &userID](const std::shared_ptr<KeyFilter> &filter) {
         return filter->matches(userID, KeyFilter::Appearance) && (filter.get()->*fun)().isValid();
     });
     if (it == filters.cend()) {
         return {};
     } else {
         return (it->get()->*fun)();
     }
 }
 
 static QString get_string(const std::vector<std::shared_ptr<KeyFilter>> &filters, const Key &key, QString (KeyFilter::*fun)() const)
 {
     const auto it = std::find_if(filters.cbegin(), filters.cend(), [&fun, &key](const std::shared_ptr<KeyFilter> &filter) {
         return filter->matches(key, KeyFilter::Appearance) && !(filter.get()->*fun)().isEmpty();
     });
     if (it == filters.cend()) {
         return QString();
     } else {
         return (*it)->icon();
     }
 }
 
 QColor KeyFilterManager::bgColor(const Key &key) const
 {
     return get_color(d->filters, key, &KeyFilter::bgColor);
 }
 
 QColor KeyFilterManager::fgColor(const Key &key) const
 {
     return get_color(d->filters, key, &KeyFilter::fgColor);
 }
 
 QColor KeyFilterManager::bgColor(const UserID &userID) const
 {
     return get_color(d->filters, userID, &KeyFilter::bgColor);
 }
 
 QColor KeyFilterManager::fgColor(const UserID &userID) const
 {
     return get_color(d->filters, userID, &KeyFilter::fgColor);
 }
 
 QIcon KeyFilterManager::icon(const Key &key) const
 {
     const QString icon = get_string(d->filters, key, &KeyFilter::icon);
     return icon.isEmpty() ? QIcon() : QIcon::fromTheme(icon);
 }
diff --git a/src/models/useridproxymodel.cpp b/src/models/useridproxymodel.cpp
index 3b7efd05..31bf9deb 100644
--- a/src/models/useridproxymodel.cpp
+++ b/src/models/useridproxymodel.cpp
@@ -1,189 +1,201 @@
 /*
     SPDX-FileCopyrightText: 2024 g10 Code GmbH
     SPDX-FileContributor: Tobias Fella <tobias.fella@gnupg.com>
     SPDX-License-Identifier: GPL-2.0-or-later
 */
 
 #include "useridproxymodel.h"
 
 #include "keylist.h"
 #include "keylistmodel.h"
 #include "kleo/keyfiltermanager.h"
 #include "utils/formatting.h"
 #include "utils/systeminfo.h"
 
 #include <global.h>
 
 #include <QColor>
 
 using namespace Kleo;
 
 UserIDProxyModel::UserIDProxyModel(QObject *parent)
     : AbstractKeyListSortFilterProxyModel(parent)
 {
 }
 
 static QVariant returnIfValid(const QColor &t)
 {
     if (t.isValid()) {
         return t;
     } else {
         return QVariant();
     }
 }
 
 QModelIndex UserIDProxyModel::mapFromSource(const QModelIndex &sourceIndex) const
 {
     if (!sourceIndex.isValid()) {
         return {};
     }
     int row = 0;
     for (int i = 0; i < sourceIndex.row(); i++) {
         row += userIDsOfSourceRow(i);
     }
     return index(row, sourceIndex.column(), {});
 }
 
 QModelIndex UserIDProxyModel::mapToSource(const QModelIndex &proxyIndex) const
 {
     if (!proxyIndex.isValid()) {
         return {};
     }
     return sourceModel()->index(sourceRowForProxyIndex(proxyIndex), proxyIndex.column(), {});
 }
 
 int UserIDProxyModel::rowCount(const QModelIndex &parent) const
 {
     if (parent.isValid()) {
         return 0;
     }
     int sum = 0;
     for (int i = 0; i < sourceModel()->rowCount(); i++) {
         sum += userIDsOfSourceRow(i);
     }
     return sum;
 }
 
 QModelIndex UserIDProxyModel::index(int row, int column, const QModelIndex &parent) const
 {
     if (parent.isValid()) {
         return {};
     }
     return createIndex(row, column, nullptr);
 }
 
 QModelIndex UserIDProxyModel::parent(const QModelIndex &) const
 {
     return {};
 }
 
 int UserIDProxyModel::columnCount(const QModelIndex &index) const
 {
     return sourceModel()->columnCount(mapToSource(index));
 }
 
 QVariant UserIDProxyModel::data(const QModelIndex &index, int role) const
 {
     const auto row = sourceRowForProxyIndex(index);
     const auto offset = sourceOffsetForProxyIndex(index);
     const auto model = dynamic_cast<AbstractKeyListModel *>(sourceModel());
     const auto key = model->key(model->index(row, 0));
     if (key.isNull()) {
         return AbstractKeyListSortFilterProxyModel::data(index, role);
     }
     const auto userId = key.userID(offset);
     if ((role == Qt::DisplayRole || role == Qt::EditRole || role == Qt::AccessibleTextRole)) {
         if (index.column() == KeyList::Columns::PrettyName) {
             auto name = QString::fromUtf8(userId.name());
             if (name.isEmpty()) {
                 return AbstractKeyListSortFilterProxyModel::data(index, role);
             }
             return name;
         }
         if (index.column() == KeyList::Columns::PrettyEMail) {
             return QString::fromUtf8(userId.email());
         }
         if (index.column() == KeyList::Columns::Validity) {
             return Formatting::complianceStringShort(userId);
         }
         if (index.column() == KeyList::Columns::Summary) {
             return Formatting::summaryLine(userId);
         }
         if (index.column() == KeyList::Columns::Origin) {
             return Formatting::origin(userId.origin());
         }
         if (index.column() == KeyList::Columns::LastUpdate) {
             if (role == Qt::AccessibleTextRole) {
                 return Formatting::accessibleDate(userId.lastUpdate());
             } else {
                 return Formatting::dateString(userId.lastUpdate());
             }
         }
     }
     if (role == Qt::BackgroundRole) {
         if (!SystemInfo::isHighContrastModeActive()) {
             return returnIfValid(KeyFilterManager::instance()->bgColor(userId));
         }
     } else if (role == Qt::ForegroundRole) {
         if (!SystemInfo::isHighContrastModeActive()) {
             return returnIfValid(KeyFilterManager::instance()->fgColor(userId));
         }
     }
     return AbstractKeyListSortFilterProxyModel::data(index, role);
 }
 
 int UserIDProxyModel::sourceRowForProxyIndex(const QModelIndex &index) const
 {
     int row = index.row();
     int i;
     for (i = 0; row >= userIDsOfSourceRow(i); i++) {
         row -= userIDsOfSourceRow(i);
     }
     return i;
 }
 
 int UserIDProxyModel::sourceOffsetForProxyIndex(const QModelIndex &index) const
 {
     int row = index.row();
     int i;
     for (i = 0; row >= userIDsOfSourceRow(i); i++) {
         row -= userIDsOfSourceRow(i);
     }
     auto model = dynamic_cast<AbstractKeyListModel *>(sourceModel());
     auto key = model->key(model->index(sourceRowForProxyIndex(index), 0));
     int tmp = row;
     for (int j = 0; j <= tmp; j++) {
         // account for filtered out S/MIME user IDs
         if (key.protocol() == GpgME::Protocol::CMS && !key.userID(j).email()) {
             row++;
         }
     }
     return row;
 }
 
 int UserIDProxyModel::userIDsOfSourceRow(int sourceRow) const
 {
     auto model = dynamic_cast<AbstractKeyListModel *>(sourceModel());
     auto key = model->key(model->index(sourceRow, 0));
 
     if (key.protocol() == GpgME::OpenPGP) {
         return key.numUserIDs();
     }
     // Try to filter out some useless SMIME user ids
     int count = 0;
     const auto &uids = key.userIDs();
     for (auto it = uids.begin(); it != uids.end(); ++it) {
         const auto &uid = *it;
         if (uid.email()) {
             count++;
         }
     }
     return count;
 }
 
 UserIDProxyModel *UserIDProxyModel::clone() const
 {
     auto model = new UserIDProxyModel(QObject::parent());
     model->setSourceModel(sourceModel());
     return model;
 }
+
+QModelIndex UserIDProxyModel::index(const KeyGroup &group) const
+{
+    Q_UNUSED(group);
+    return {};
+}
+
+QModelIndex UserIDProxyModel::index(const GpgME::Key &key) const
+{
+    Q_UNUSED(key);
+    return {};
+}
diff --git a/src/models/useridproxymodel.h b/src/models/useridproxymodel.h
index 213c68af..506d2798 100644
--- a/src/models/useridproxymodel.h
+++ b/src/models/useridproxymodel.h
@@ -1,34 +1,36 @@
 /*
     SPDX-FileCopyrightText: 2024 g10 Code GmbH
     SPDX-FileContributor: Tobias Fella <tobias.fella@gnupg.com>
     SPDX-License-Identifier: GPL-2.0-or-later
 */
 
 #pragma once
 
 #include "kleo_export.h"
 #include <Libkleo/KeyListSortFilterProxyModel>
 
 namespace Kleo
 {
 
 class KLEO_EXPORT UserIDProxyModel : public Kleo::AbstractKeyListSortFilterProxyModel
 {
     Q_OBJECT
 
 public:
     explicit UserIDProxyModel(QObject *parent = nullptr);
 
     QModelIndex mapFromSource(const QModelIndex &sourceIndex) const override;
     QModelIndex mapToSource(const QModelIndex &proxyIndex) const override;
     int rowCount(const QModelIndex &parent = {}) const override;
     QModelIndex index(int row, int column, const QModelIndex &parent) const override;
     virtual QModelIndex parent(const QModelIndex &) const override;
     int columnCount(const QModelIndex &) const override;
     QVariant data(const QModelIndex &index, int role) const override;
     int sourceRowForProxyIndex(const QModelIndex &index) const;
     int sourceOffsetForProxyIndex(const QModelIndex &index) const;
     int userIDsOfSourceRow(int sourceRow) const;
     UserIDProxyModel *clone() const override;
+    QModelIndex index(const KeyGroup &) const override;
+    QModelIndex index(const GpgME::Key &key) const override;
 };
 }