Page MenuHome GnuPG

No OneTemporary

diff --git a/src/ui/useridselectioncombo.cpp b/src/ui/useridselectioncombo.cpp
index 7b83901d..3243d787 100644
--- a/src/ui/useridselectioncombo.cpp
+++ b/src/ui/useridselectioncombo.cpp
@@ -1,742 +1,769 @@
/* This file is part of Kleopatra, the KDE keymanager
SPDX-FileCopyrightText: 2016 Klarälvdalens Datakonsult AB
SPDX-License-Identifier: GPL-2.0-or-later
*/
#include <config-libkleo.h>
#include "useridselectioncombo.h"
#include "progressbar.h"
#include <libkleo/defaultkeyfilter.h>
#include <libkleo/dn.h>
#include <libkleo/formatting.h>
#include <libkleo/keycache.h>
#include <libkleo/keylist.h>
#include <libkleo/keylistmodel.h>
#include <libkleo/keylistsortfilterproxymodel.h>
#include <libkleo/useridproxymodel.h>
#include <kleo_ui_debug.h>
#include <KLocalizedString>
+#include <QHBoxLayout>
#include <QList>
#include <QSortFilterProxyModel>
#include <QTimer>
+#include <QToolButton>
#include <gpgme++/key.h>
using namespace Kleo;
#if !UNITY_BUILD
Q_DECLARE_METATYPE(GpgME::Key)
#endif
namespace
{
class SortFilterProxyModel : public KeyListSortFilterProxyModel
{
Q_OBJECT
public:
using KeyListSortFilterProxyModel::KeyListSortFilterProxyModel;
void setAlwaysAcceptedKey(const QString &fingerprint)
{
if (fingerprint == mFingerprint) {
return;
}
mFingerprint = fingerprint;
invalidate();
}
protected:
bool filterAcceptsRow(int source_row, const QModelIndex &source_parent) const override
{
if (!mFingerprint.isEmpty()) {
const QModelIndex index = sourceModel()->index(source_row, 0, source_parent);
const auto fingerprint = sourceModel()->data(index, KeyList::FingerprintRole).toString();
if (fingerprint == mFingerprint) {
return true;
}
}
return KeyListSortFilterProxyModel::filterAcceptsRow(source_row, source_parent);
}
private:
QString mFingerprint;
};
static QString formatUserID(const GpgME::UserID &userID)
{
QString name;
QString email;
if (userID.parent().protocol() == GpgME::OpenPGP) {
name = QString::fromUtf8(userID.name());
email = QString::fromUtf8(userID.email());
} else {
const Kleo::DN dn(userID.id());
name = dn[QStringLiteral("CN")];
email = dn[QStringLiteral("EMAIL")];
if (name.isEmpty()) {
name = Kleo::DN(userID.parent().userID(0).id())[QStringLiteral("CN")];
}
}
return email.isEmpty() ? name : name.isEmpty() ? email : i18nc("Name <email>", "%1 <%2>", name, email);
}
class SortAndFormatCertificatesProxyModel : public QSortFilterProxyModel
{
Q_OBJECT
public:
SortAndFormatCertificatesProxyModel(KeyUsage::Flags usageFlags, QObject *parent = nullptr)
: QSortFilterProxyModel{parent}
, mIconProvider{usageFlags}
{
}
private:
bool lessThan(const QModelIndex &left, const QModelIndex &right) const override
{
const auto leftUserId = sourceModel()->data(left, KeyList::UserIDRole).value<GpgME::UserID>();
const auto rightUserId = sourceModel()->data(right, KeyList::UserIDRole).value<GpgME::UserID>();
if (leftUserId.isNull()) {
return false;
}
if (rightUserId.isNull()) {
return true;
}
const auto leftNameAndEmail = formatUserID(leftUserId);
const auto rightNameAndEmail = formatUserID(rightUserId);
const int cmp = QString::localeAwareCompare(leftNameAndEmail, rightNameAndEmail);
if (cmp) {
return cmp < 0;
}
if (leftUserId.validity() != rightUserId.validity()) {
return leftUserId.validity() > rightUserId.validity();
}
/* Both have the same validity, check which one is newer. */
time_t leftTime = 0;
for (const GpgME::Subkey &s : leftUserId.parent().subkeys()) {
if (s.isBad()) {
continue;
}
if (s.creationTime() > leftTime) {
leftTime = s.creationTime();
}
}
time_t rightTime = 0;
for (const GpgME::Subkey &s : rightUserId.parent().subkeys()) {
if (s.isBad()) {
continue;
}
if (s.creationTime() > rightTime) {
rightTime = s.creationTime();
}
}
if (rightTime != leftTime) {
return leftTime > rightTime;
}
// as final resort we compare the fingerprints
return strcmp(leftUserId.parent().primaryFingerprint(), rightUserId.parent().primaryFingerprint()) < 0;
}
protected:
QVariant data(const QModelIndex &index, int role) const override
{
if (!index.isValid()) {
return QVariant();
}
const auto userId = QSortFilterProxyModel::data(index, KeyList::UserIDRole).value<GpgME::UserID>();
Q_ASSERT(!userId.isNull());
if (userId.isNull()) {
return QVariant();
}
switch (role) {
case Qt::DisplayRole:
case Qt::AccessibleTextRole: {
const auto nameAndEmail = formatUserID(userId);
if (Kleo::KeyCache::instance()->pgpOnly()) {
return i18nc("Name <email> (validity, created: date)",
"%1 (%2, created: %3)",
nameAndEmail,
Kleo::Formatting::complianceStringShort(userId),
Kleo::Formatting::creationDateString(userId.parent()));
} else {
return i18nc("Name <email> (validity, type, created: date)",
"%1 (%2, %3, created: %4)",
nameAndEmail,
Kleo::Formatting::complianceStringShort(userId),
Formatting::displayName(userId.parent().protocol()),
Kleo::Formatting::creationDateString(userId.parent()));
}
}
case Qt::ToolTipRole: {
using namespace Kleo::Formatting;
return Kleo::Formatting::toolTip(userId, Validity | Issuer | Subject | Fingerprint | ExpiryDates | UserIDs);
}
case Qt::DecorationRole: {
return mIconProvider.icon(userId.parent());
}
default:
return QSortFilterProxyModel::data(index, role);
}
}
private:
Formatting::IconProvider mIconProvider;
};
class CustomItemsProxyModel : public QSortFilterProxyModel
{
Q_OBJECT
private:
struct CustomItem {
QIcon icon;
QString text;
QVariant data;
QString toolTip;
};
public:
CustomItemsProxyModel(QObject *parent = nullptr)
: QSortFilterProxyModel(parent)
{
}
~CustomItemsProxyModel() override
{
qDeleteAll(mFrontItems);
qDeleteAll(mBackItems);
}
bool isCustomItem(const int row) const
{
return row < mFrontItems.count() || row >= mFrontItems.count() + QSortFilterProxyModel::rowCount();
}
void prependItem(const QIcon &icon, const QString &text, const QVariant &data, const QString &toolTip)
{
beginInsertRows(QModelIndex(), 0, 0);
mFrontItems.push_front(new CustomItem{icon, text, data, toolTip});
endInsertRows();
}
void appendItem(const QIcon &icon, const QString &text, const QVariant &data, const QString &toolTip)
{
beginInsertRows(QModelIndex(), rowCount(), rowCount());
mBackItems.push_back(new CustomItem{icon, text, data, toolTip});
endInsertRows();
}
void removeCustomItem(const QVariant &data)
{
for (int i = 0; i < mFrontItems.count(); ++i) {
if (mFrontItems[i]->data == data) {
beginRemoveRows(QModelIndex(), i, i);
delete mFrontItems.takeAt(i);
endRemoveRows();
return;
}
}
for (int i = 0; i < mBackItems.count(); ++i) {
if (mBackItems[i]->data == data) {
const int index = mFrontItems.count() + QSortFilterProxyModel::rowCount() + i;
beginRemoveRows(QModelIndex(), index, index);
delete mBackItems.takeAt(i);
endRemoveRows();
return;
}
}
}
int rowCount(const QModelIndex &parent = QModelIndex()) const override
{
return mFrontItems.count() + QSortFilterProxyModel::rowCount(parent) + mBackItems.count();
}
int columnCount(const QModelIndex &parent = QModelIndex()) const override
{
Q_UNUSED(parent)
// pretend that there is only one column to workaround a bug in
// QAccessibleTable which provides the accessibility interface for the
// pop-up of the combo box
return 1;
}
QModelIndex mapToSource(const QModelIndex &index) const override
{
if (!index.isValid()) {
return {};
}
if (!isCustomItem(index.row())) {
const int sourceRow = index.row() - mFrontItems.count();
return QSortFilterProxyModel::mapToSource(createIndex(sourceRow, index.column(), index.internalPointer()));
}
return {};
}
QModelIndex mapFromSource(const QModelIndex &source_index) const override
{
const QModelIndex idx = QSortFilterProxyModel::mapFromSource(source_index);
return createIndex(mFrontItems.count() + idx.row(), idx.column(), idx.internalPointer());
}
QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const override
{
if (row < 0 || row >= rowCount()) {
return {};
}
if (row < mFrontItems.count()) {
return createIndex(row, column, mFrontItems[row]);
} else if (row >= mFrontItems.count() + QSortFilterProxyModel::rowCount()) {
return createIndex(row, column, mBackItems[row - mFrontItems.count() - QSortFilterProxyModel::rowCount()]);
} else {
const QModelIndex mi = QSortFilterProxyModel::index(row - mFrontItems.count(), column, parent);
return createIndex(row, column, mi.internalPointer());
}
}
Qt::ItemFlags flags(const QModelIndex &index) const override
{
Q_UNUSED(index)
return Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemNeverHasChildren;
}
QModelIndex parent(const QModelIndex &) const override
{
// Flat list
return {};
}
QVariant data(const QModelIndex &index, int role) const override
{
if (!index.isValid()) {
return QVariant();
}
if (isCustomItem(index.row())) {
Q_ASSERT(!mFrontItems.isEmpty() || !mBackItems.isEmpty());
auto ci = static_cast<CustomItem *>(index.internalPointer());
switch (role) {
case Qt::DisplayRole:
return ci->text;
case Qt::DecorationRole:
return ci->icon;
case Qt::UserRole:
+ case KeyList::UserIDRole:
return ci->data;
case Qt::ToolTipRole:
return ci->toolTip;
default:
return QVariant();
}
}
return QSortFilterProxyModel::data(index, role);
}
private:
QList<CustomItem *> mFrontItems;
QList<CustomItem *> mBackItems;
};
} // anonymous namespace
namespace Kleo
{
class UserIDSelectionComboPrivate
{
public:
UserIDSelectionComboPrivate(UserIDSelectionCombo *parent, bool secretOnly_, KeyUsage::Flags usage)
: wasEnabled(true)
, secretOnly{secretOnly_}
, usageFlags{usage}
, q{parent}
{
}
/* Selects the first key with a UID addrSpec that matches
* the mPerfectMatchMbox variable.
*
* The idea here is that if there are keys like:
*
* tom-store@abc.com
* susi-store@abc.com
* store@abc.com
*
* And the user wants to send a mail to "store@abc.com"
* the filter should still show tom and susi (because they
* both are part of store) but the key for "store" should
* be preselected.
*
* Returns true if one was selected. False otherwise. */
bool selectPerfectIdMatch() const
{
if (mPerfectMatchMbox.isEmpty()) {
return false;
}
for (int i = 0; i < proxyModel->rowCount(); ++i) {
const auto idx = proxyModel->index(i, 0, QModelIndex());
const auto userID = idx.data(KeyList::UserIDRole).value<GpgME::UserID>();
if (userID.isNull()) {
// WTF?
continue;
}
if (QString::fromStdString(userID.addrSpec()) == mPerfectMatchMbox) {
- q->setCurrentIndex(i);
+ combo->setCurrentIndex(i);
return true;
}
}
return false;
}
/* Updates the current key with the default key if the key matches
* the current key filter. */
void updateWithDefaultKey()
{
GpgME::Protocol filterProto = GpgME::UnknownProtocol;
const auto filter = dynamic_cast<const DefaultKeyFilter *>(sortFilterProxy->keyFilter().get());
if (filter && filter->isOpenPGP() == DefaultKeyFilter::Set) {
filterProto = GpgME::OpenPGP;
} else if (filter && filter->isOpenPGP() == DefaultKeyFilter::NotSet) {
filterProto = GpgME::CMS;
}
QString defaultKey = defaultKeys.value(filterProto);
if (defaultKey.isEmpty()) {
// Fallback to unknown protocol
defaultKey = defaultKeys.value(GpgME::UnknownProtocol);
}
// make sure that the default key is not filtered out unless it has the wrong protocol
if (filterProto == GpgME::UnknownProtocol) {
sortFilterProxy->setAlwaysAcceptedKey(defaultKey);
} else {
const auto key = KeyCache::instance()->findByFingerprint(defaultKey.toLatin1().constData());
if (!key.isNull() && key.protocol() == filterProto) {
sortFilterProxy->setAlwaysAcceptedKey(defaultKey);
} else {
sortFilterProxy->setAlwaysAcceptedKey({});
}
}
q->setCurrentKey(defaultKey);
}
void storeCurrentSelectionBeforeModelChange()
{
userIDBeforeModelChange = q->currentUserID();
- customItemBeforeModelChange = q->currentData();
+ customItemBeforeModelChange = combo->currentData();
}
void restoreCurrentSelectionAfterModelChange()
{
if (!userIDBeforeModelChange.isNull()) {
q->setCurrentUserID(userIDBeforeModelChange);
} else if (customItemBeforeModelChange.isValid()) {
- const auto index = q->findData(customItemBeforeModelChange);
+ const auto index = combo->findData(customItemBeforeModelChange);
if (index != -1) {
- q->setCurrentIndex(index);
+ combo->setCurrentIndex(index);
} else {
updateWithDefaultKey();
}
}
}
Kleo::AbstractKeyListModel *model = nullptr;
UserIDProxyModel *userIdProxy = nullptr;
SortFilterProxyModel *sortFilterProxy = nullptr;
SortAndFormatCertificatesProxyModel *sortAndFormatProxy = nullptr;
CustomItemsProxyModel *proxyModel = nullptr;
+ QComboBox *combo = nullptr;
+ QToolButton *button = nullptr;
+ QHBoxLayout *layout = nullptr;
std::shared_ptr<Kleo::KeyCache> cache;
QMap<GpgME::Protocol, QString> defaultKeys;
bool wasEnabled = false;
bool useWasEnabled = false;
bool secretOnly = false;
bool initialKeyListingDone = false;
QString mPerfectMatchMbox;
GpgME::UserID userIDBeforeModelChange;
QVariant customItemBeforeModelChange;
KeyUsage::Flags usageFlags;
private:
UserIDSelectionCombo *const q;
};
}
using namespace Kleo;
UserIDSelectionCombo::UserIDSelectionCombo(QWidget *parent)
: UserIDSelectionCombo(true, KeyUsage::None, parent)
{
}
UserIDSelectionCombo::UserIDSelectionCombo(bool secretOnly, QWidget *parent)
: UserIDSelectionCombo(secretOnly, KeyUsage::None, parent)
{
}
UserIDSelectionCombo::UserIDSelectionCombo(KeyUsage::Flags usage, QWidget *parent)
: UserIDSelectionCombo{false, usage, parent}
{
}
UserIDSelectionCombo::UserIDSelectionCombo(KeyUsage::Flag usage, QWidget *parent)
: UserIDSelectionCombo{false, usage, parent}
{
}
UserIDSelectionCombo::UserIDSelectionCombo(bool secretOnly, KeyUsage::Flags usage, QWidget *parent)
- : QComboBox(parent)
+ : QWidget(parent)
, d(new UserIDSelectionComboPrivate(this, secretOnly, usage))
{
// set a non-empty string as accessible description to prevent screen readers
// from reading the tool tip which isn't meant for screen readers
setAccessibleDescription(QStringLiteral(" "));
d->model = Kleo::AbstractKeyListModel::createFlatKeyListModel(this);
d->userIdProxy = new UserIDProxyModel(this);
d->userIdProxy->setSourceModel(d->model);
d->sortFilterProxy = new SortFilterProxyModel(this);
d->sortFilterProxy->setSourceModel(d->userIdProxy);
d->sortAndFormatProxy = new SortAndFormatCertificatesProxyModel{usage, this};
d->sortAndFormatProxy->setSourceModel(d->sortFilterProxy);
// initialize dynamic sorting
d->sortAndFormatProxy->sort(0);
d->proxyModel = new CustomItemsProxyModel{this};
d->proxyModel->setSourceModel(d->sortAndFormatProxy);
- setModel(d->proxyModel);
- connect(this, &QComboBox::currentIndexChanged, this, [this](int row) {
+ d->layout = new QHBoxLayout();
+ d->layout->setContentsMargins(0, 0, 0, 0);
+ setLayout(d->layout);
+
+ d->combo = new QComboBox();
+ d->layout->addWidget(d->combo);
+
+ d->button = new QToolButton();
+ d->button->setIcon(QIcon::fromTheme(QStringLiteral("resource-group-new")));
+ d->button->setToolTip(i18nc("@info:tooltip", "Show certificate list"));
+ d->button->setAccessibleName(i18n("Show certificate list"));
+ d->layout->addWidget(d->button);
+
+ connect(d->button, &QToolButton::clicked, this, &UserIDSelectionCombo::certificateSelectionRequested);
+
+ d->combo->setModel(d->proxyModel);
+ connect(d->combo, &QComboBox::currentIndexChanged, this, [this](int row) {
if (row >= 0 && row < d->proxyModel->rowCount()) {
if (d->proxyModel->isCustomItem(row)) {
- Q_EMIT customItemSelected(currentData(Qt::UserRole));
+ Q_EMIT customItemSelected(d->combo->currentData(Qt::UserRole));
} else {
Q_EMIT currentKeyChanged(currentKey());
}
}
});
d->cache = Kleo::KeyCache::mutableInstance();
- connect(model(), &QAbstractItemModel::rowsAboutToBeInserted, this, [this]() {
+ connect(d->combo->model(), &QAbstractItemModel::rowsAboutToBeInserted, this, [this]() {
d->storeCurrentSelectionBeforeModelChange();
});
- connect(model(), &QAbstractItemModel::rowsInserted, this, [this]() {
+ connect(d->combo->model(), &QAbstractItemModel::rowsInserted, this, [this]() {
d->restoreCurrentSelectionAfterModelChange();
});
- connect(model(), &QAbstractItemModel::rowsAboutToBeRemoved, this, [this]() {
+ connect(d->combo->model(), &QAbstractItemModel::rowsAboutToBeRemoved, this, [this]() {
d->storeCurrentSelectionBeforeModelChange();
});
- connect(model(), &QAbstractItemModel::rowsRemoved, this, [this]() {
+ connect(d->combo->model(), &QAbstractItemModel::rowsRemoved, this, [this]() {
d->restoreCurrentSelectionAfterModelChange();
});
- connect(model(), &QAbstractItemModel::modelAboutToBeReset, this, [this]() {
+ connect(d->combo->model(), &QAbstractItemModel::modelAboutToBeReset, this, [this]() {
d->storeCurrentSelectionBeforeModelChange();
});
- connect(model(), &QAbstractItemModel::modelReset, this, [this]() {
+ connect(d->combo->model(), &QAbstractItemModel::modelReset, this, [this]() {
d->restoreCurrentSelectionAfterModelChange();
});
QTimer::singleShot(0, this, &UserIDSelectionCombo::init);
}
UserIDSelectionCombo::~UserIDSelectionCombo() = default;
void UserIDSelectionCombo::init()
{
connect(d->cache.get(), &Kleo::KeyCache::keyListingDone, this, [this]() {
// Set useKeyCache ensures that the cache is populated
// so this can be a blocking call if the cache is not initialized
if (!d->initialKeyListingDone) {
d->model->useKeyCache(true, d->secretOnly ? KeyList::SecretKeysOnly : KeyList::AllKeys);
}
d->proxyModel->removeCustomItem(QStringLiteral("-libkleo-loading-keys"));
// We use the useWasEnabled state variable to decide if we should
// change the enable / disable state based on the keylist done signal.
// If we triggered the refresh useWasEnabled is true and we want to
// enable / disable again after our refresh, as the refresh disabled it.
//
// But if a keyListingDone signal comes from just a generic refresh
// triggered by someone else we don't want to change the enable / disable
// state.
if (d->useWasEnabled) {
setEnabled(d->wasEnabled);
d->useWasEnabled = false;
}
Q_EMIT keyListingFinished();
});
connect(this, &UserIDSelectionCombo::keyListingFinished, this, [this]() {
if (!d->initialKeyListingDone) {
d->updateWithDefaultKey();
d->initialKeyListingDone = true;
}
});
if (!d->cache->initialized()) {
refreshKeys();
} else {
d->model->useKeyCache(true, d->secretOnly ? KeyList::SecretKeysOnly : KeyList::AllKeys);
Q_EMIT keyListingFinished();
}
- connect(this, &QComboBox::currentIndexChanged, this, [this]() {
- setToolTip(currentData(Qt::ToolTipRole).toString());
+ connect(d->combo, &QComboBox::currentIndexChanged, this, [this]() {
+ setToolTip(d->combo->currentData(Qt::ToolTipRole).toString());
});
}
void UserIDSelectionCombo::setKeyFilter(const std::shared_ptr<const KeyFilter> &kf)
{
d->sortFilterProxy->setKeyFilter(kf);
d->updateWithDefaultKey();
}
std::shared_ptr<const KeyFilter> UserIDSelectionCombo::keyFilter() const
{
return d->sortFilterProxy->keyFilter();
}
void UserIDSelectionCombo::setIdFilter(const QString &id)
{
d->sortFilterProxy->setFilterRegularExpression(id);
d->mPerfectMatchMbox = id;
d->updateWithDefaultKey();
}
QString UserIDSelectionCombo::idFilter() const
{
return d->sortFilterProxy->filterRegularExpression().pattern();
}
GpgME::Key Kleo::UserIDSelectionCombo::currentKey() const
{
- return currentData(KeyList::KeyRole).value<GpgME::Key>();
+ return d->combo->currentData(KeyList::KeyRole).value<GpgME::Key>();
}
void Kleo::UserIDSelectionCombo::setCurrentKey(const GpgME::Key &key)
{
- const int idx = findData(QString::fromLatin1(key.primaryFingerprint()), KeyList::FingerprintRole, Qt::MatchExactly);
+ const int idx = d->combo->findData(QString::fromLatin1(key.primaryFingerprint()), KeyList::FingerprintRole, Qt::MatchExactly);
if (idx > -1) {
- setCurrentIndex(idx);
+ d->combo->setCurrentIndex(idx);
} else if (!d->selectPerfectIdMatch()) {
d->updateWithDefaultKey();
}
- setToolTip(currentData(Qt::ToolTipRole).toString());
+ setToolTip(d->combo->currentData(Qt::ToolTipRole).toString());
}
void Kleo::UserIDSelectionCombo::setCurrentKey(const QString &fingerprint)
{
const auto cur = currentKey();
if (!cur.isNull() && !fingerprint.isEmpty() && fingerprint == QLatin1StringView(cur.primaryFingerprint())) {
// already set; still emit a changed signal because the current key may
// have become the item at the current index by changes in the underlying model
Q_EMIT currentKeyChanged(cur);
return;
}
- const int idx = findData(fingerprint, KeyList::FingerprintRole, Qt::MatchExactly);
+ const int idx = d->combo->findData(fingerprint, KeyList::FingerprintRole, Qt::MatchExactly);
if (idx > -1) {
- setCurrentIndex(idx);
+ d->combo->setCurrentIndex(idx);
} else if (!d->selectPerfectIdMatch()) {
- setCurrentIndex(0);
+ d->combo->setCurrentIndex(0);
}
- setToolTip(currentData(Qt::ToolTipRole).toString());
+ setToolTip(d->combo->currentData(Qt::ToolTipRole).toString());
}
GpgME::UserID Kleo::UserIDSelectionCombo::currentUserID() const
{
- return currentData(KeyList::UserIDRole).value<GpgME::UserID>();
+ return d->combo->currentData(KeyList::UserIDRole).value<GpgME::UserID>();
}
void Kleo::UserIDSelectionCombo::setCurrentUserID(const GpgME::UserID &userID)
{
- for (auto i = 0; i < count(); i++) {
- const auto &other = itemData(i, KeyList::UserIDRole).value<GpgME::UserID>();
+ for (auto i = 0; i < d->combo->count(); i++) {
+ const auto &other = d->combo->itemData(i, KeyList::UserIDRole).value<GpgME::UserID>();
if (!qstrcmp(userID.id(), other.id()) && !qstrcmp(userID.parent().primaryFingerprint(), other.parent().primaryFingerprint())) {
- setCurrentIndex(i);
- setToolTip(currentData(Qt::ToolTipRole).toString());
+ d->combo->setCurrentIndex(i);
+ setToolTip(d->combo->currentData(Qt::ToolTipRole).toString());
return;
}
}
if (!d->selectPerfectIdMatch()) {
d->updateWithDefaultKey();
- setToolTip(currentData(Qt::ToolTipRole).toString());
+ setToolTip(d->combo->currentData(Qt::ToolTipRole).toString());
}
}
void UserIDSelectionCombo::refreshKeys()
{
d->wasEnabled = isEnabled();
d->useWasEnabled = true;
setEnabled(false);
const bool wasBlocked = blockSignals(true);
prependCustomItem(QIcon(), i18n("Loading keys ..."), QStringLiteral("-libkleo-loading-keys"));
- setCurrentIndex(0);
+ d->combo->setCurrentIndex(0);
blockSignals(wasBlocked);
d->cache->startKeyListing();
}
void UserIDSelectionCombo::appendCustomItem(const QIcon &icon, const QString &text, const QVariant &data, const QString &toolTip)
{
d->proxyModel->appendItem(icon, text, data, toolTip);
}
void UserIDSelectionCombo::appendCustomItem(const QIcon &icon, const QString &text, const QVariant &data)
{
appendCustomItem(icon, text, data, QString());
}
void UserIDSelectionCombo::prependCustomItem(const QIcon &icon, const QString &text, const QVariant &data, const QString &toolTip)
{
d->proxyModel->prependItem(icon, text, data, toolTip);
}
void UserIDSelectionCombo::prependCustomItem(const QIcon &icon, const QString &text, const QVariant &data)
{
prependCustomItem(icon, text, data, QString());
}
void UserIDSelectionCombo::removeCustomItem(const QVariant &data)
{
d->proxyModel->removeCustomItem(data);
}
void Kleo::UserIDSelectionCombo::setDefaultKey(const QString &fingerprint, GpgME::Protocol proto)
{
d->defaultKeys.insert(proto, fingerprint);
d->updateWithDefaultKey();
}
void Kleo::UserIDSelectionCombo::setDefaultKey(const QString &fingerprint)
{
setDefaultKey(fingerprint, GpgME::UnknownProtocol);
}
QString Kleo::UserIDSelectionCombo::defaultKey(GpgME::Protocol proto) const
{
return d->defaultKeys.value(proto);
}
QString Kleo::UserIDSelectionCombo::defaultKey() const
{
return defaultKey(GpgME::UnknownProtocol);
}
+
+QComboBox *Kleo::UserIDSelectionCombo::combo() const
+{
+ return d->combo;
+}
+
#include "useridselectioncombo.moc"
#include "moc_useridselectioncombo.cpp"
diff --git a/src/ui/useridselectioncombo.h b/src/ui/useridselectioncombo.h
index 59438a80..1f5819cd 100644
--- a/src/ui/useridselectioncombo.h
+++ b/src/ui/useridselectioncombo.h
@@ -1,94 +1,97 @@
/* This file is part of Kleopatra, the KDE keymanager
SPDX-FileCopyrightText: 2016 Klarälvdalens Datakonsult AB
SPDX-License-Identifier: GPL-2.0-or-later
*/
#pragma once
#include "kleo_export.h"
#include <libkleo/enum.h>
#include <libkleo/keyusage.h>
#include <QComboBox>
#include <gpgme++/global.h>
#include <memory>
namespace GpgME
{
class Key;
}
namespace Kleo
{
class KeyFilter;
class UserIDSelectionComboPrivate;
-class KLEO_EXPORT UserIDSelectionCombo : public QComboBox
+class KLEO_EXPORT UserIDSelectionCombo : public QWidget
{
Q_OBJECT
public:
explicit UserIDSelectionCombo(QWidget *parent = nullptr);
explicit UserIDSelectionCombo(bool secretOnly, QWidget *parent = nullptr);
/**
* @param usage the desired usage of the certificate
*
* \a usage is used to mark certificates that cannot be used for the desired
* usage with an appropriate icon. This is useful in combination with a suitable
* key filter.
* For example, the key filter could filter out any certificates without
* encryption subkeys and the usage flags would mark certificates with expired
* encryption subkeys as unusable, so that the users see that there is a
* certificate, but that it cannot be used.
*/
explicit UserIDSelectionCombo(KeyUsage::Flags usage, QWidget *parent = nullptr);
/* Overload to help the compiler choose the correct overload if a KeyUsage::Flag is passed as first argument.
* Without this overload the compiler tries to use the bool-overload instead of the KeyUsage::Flags-overload
* and throws an error. */
explicit UserIDSelectionCombo(KeyUsage::Flag usage, QWidget *parent = nullptr);
UserIDSelectionCombo(bool secretOnly, KeyUsage::Flags usage, QWidget *parent = nullptr);
~UserIDSelectionCombo() override;
void setKeyFilter(const std::shared_ptr<const KeyFilter> &kf);
std::shared_ptr<const KeyFilter> keyFilter() const;
void setIdFilter(const QString &id);
QString idFilter() const;
void refreshKeys();
GpgME::Key currentKey() const;
void setCurrentKey(const GpgME::Key &key);
void setCurrentKey(const QString &fingerprint);
GpgME::UserID currentUserID() const;
void setCurrentUserID(const GpgME::UserID &userID);
void setDefaultKey(const QString &fingerprint);
void setDefaultKey(const QString &fingerprint, GpgME::Protocol proto);
QString defaultKey() const;
QString defaultKey(GpgME::Protocol proto) const;
void prependCustomItem(const QIcon &icon, const QString &text, const QVariant &data);
void appendCustomItem(const QIcon &icon, const QString &text, const QVariant &data);
void prependCustomItem(const QIcon &icon, const QString &text, const QVariant &data, const QString &toolTip);
void appendCustomItem(const QIcon &icon, const QString &text, const QVariant &data, const QString &toolTip);
void removeCustomItem(const QVariant &data);
+ QComboBox *combo() const;
+
Q_SIGNALS:
void customItemSelected(const QVariant &data);
void currentKeyChanged(const GpgME::Key &key);
void keyListingFinished();
+ void certificateSelectionRequested();
protected:
virtual void init();
private:
std::unique_ptr<UserIDSelectionComboPrivate> const d;
};
}

File Metadata

Mime Type
text/x-diff
Expires
Sat, May 10, 8:45 AM (1 d, 21 h)
Storage Engine
local-disk
Storage Format
Raw Data
Storage Handle
f7/71/a9546b818660ff3dd3eae30f1085

Event Timeline