diff --git a/src/dialogs/certificateselectiondialog.cpp b/src/dialogs/certificateselectiondialog.cpp index 60cb7f7d4..d8e80e486 100644 --- a/src/dialogs/certificateselectiondialog.cpp +++ b/src/dialogs/certificateselectiondialog.cpp @@ -1,374 +1,386 @@ /* -*- mode: c++; c-basic-offset:4 -*- dialogs/certificateselectiondialog.cpp This file is part of Kleopatra, the KDE keymanager SPDX-FileCopyrightText: 2008 Klarälvdalens Datakonsult AB SPDX-License-Identifier: GPL-2.0-or-later */ #include #include "certificateselectiondialog.h" #include #include +#include "utils/tags.h" + #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include +#include +#if GPGMEPP_VERSION >= 0x10E00 // 1.14.0 +# define GPGME_HAS_REMARKS +#endif + using namespace Kleo; using namespace Kleo::Dialogs; using namespace Kleo::Commands; using namespace GpgME; class CertificateSelectionDialog::Private { friend class ::Kleo::Dialogs::CertificateSelectionDialog; CertificateSelectionDialog *const q; public: explicit Private(CertificateSelectionDialog *qq); private: void reload() { Command *const cmd = new ReloadKeysCommand(nullptr); cmd->setParentWidget(q); cmd->start(); } void create() { NewCertificateCommand *cmd = new NewCertificateCommand(nullptr); cmd->setParentWidget(q); if ((options & AnyFormat) != AnyFormat) { cmd->setProtocol((options & OpenPGPFormat) ? OpenPGP : CMS); } cmd->start(); } void lookup() { Command *const cmd = new LookupCertificatesCommand(nullptr); cmd->setParentWidget(q); cmd->start(); } void slotKeysMayHaveChanged(); void slotCurrentViewChanged(QAbstractItemView *newView); void slotSelectionChanged(); void slotDoubleClicked(const QModelIndex &idx); private: bool acceptable(const std::vector &keys) { return !keys.empty(); } void updateLabelText() { ui.label.setText(!customLabelText.isEmpty() ? customLabelText : (options & MultiSelection) ? i18n("Please select one or more of the following certificates:") : i18n("Please select one of the following certificates:")); } private: QPointer lastView; QString customLabelText; Options options; struct UI { QLabel label; SearchBar searchBar; TabWidget tabWidget; QDialogButtonBox buttonBox; QVBoxLayout vlay; explicit UI(CertificateSelectionDialog *q) : label(q), searchBar(q), tabWidget(q), buttonBox(q), vlay(q) { KDAB_SET_OBJECT_NAME(label); KDAB_SET_OBJECT_NAME(searchBar); KDAB_SET_OBJECT_NAME(tabWidget); KDAB_SET_OBJECT_NAME(buttonBox); KDAB_SET_OBJECT_NAME(vlay); vlay.addWidget(&label); vlay.addWidget(&searchBar); vlay.addWidget(&tabWidget, 1); vlay.addWidget(&buttonBox); QPushButton *const ok = buttonBox.addButton(QDialogButtonBox::Ok); ok->setEnabled(false); QPushButton *const cancel = buttonBox.addButton(QDialogButtonBox::Close); Q_UNUSED(cancel) QPushButton *const reload = buttonBox.addButton(i18n("Reload"), QDialogButtonBox::ActionRole); QPushButton *const import = buttonBox.addButton(i18n("Import..."), QDialogButtonBox::ActionRole); QPushButton *const lookup = buttonBox.addButton(i18n("Lookup..."), QDialogButtonBox::ActionRole); QPushButton *const create = buttonBox.addButton(i18n("New..."), QDialogButtonBox::ActionRole); import->setToolTip(i18nc("@info:tooltip", "Import certificate from file")); lookup->setToolTip(i18nc("@info:tooltip", "Lookup certificates on server")); reload->setToolTip(i18nc("@info:tooltip", "Refresh certificate list")); create->setToolTip(i18nc("@info:tooltip", "Create a new certificate")); connect(&buttonBox, &QDialogButtonBox::accepted, q, &CertificateSelectionDialog::accept); connect(&buttonBox, &QDialogButtonBox::rejected, q, &CertificateSelectionDialog::reject); connect(reload, SIGNAL(clicked()), q, SLOT(reload())); connect(lookup, SIGNAL(clicked()), q, SLOT(lookup())); connect(create, SIGNAL(clicked()), q, SLOT(create())); connect(KeyCache::instance().get(), SIGNAL(keysMayHaveChanged()), q, SLOT(slotKeysMayHaveChanged())); connect(import, &QPushButton::clicked, q, [import, q] () { import->setEnabled(false); auto cmd = new Kleo::ImportCertificateFromFileCommand(); connect(cmd, &Kleo::ImportCertificateFromFileCommand::finished, q, [import]() { import->setEnabled(true); }); cmd->setParentWidget(q); cmd->start(); }); } } ui; }; CertificateSelectionDialog::Private::Private(CertificateSelectionDialog *qq) : q(qq), ui(q) { ui.tabWidget.setFlatModel(AbstractKeyListModel::createFlatKeyListModel(q)); ui.tabWidget.setHierarchicalModel(AbstractKeyListModel::createHierarchicalKeyListModel(q)); +#ifdef GPGME_HAS_REMARKS + const auto tagKeys = Tags::tagKeys(); + ui.tabWidget.flatModel()->setRemarkKeys(tagKeys); + ui.tabWidget.hierarchicalModel()->setRemarkKeys(tagKeys); +#endif ui.tabWidget.connectSearchBar(&ui.searchBar); connect(&ui.tabWidget, SIGNAL(currentViewChanged(QAbstractItemView*)), q, SLOT(slotCurrentViewChanged(QAbstractItemView*))); updateLabelText(); q->setWindowTitle(i18nc("@title:window", "Certificate Selection")); } CertificateSelectionDialog::CertificateSelectionDialog(QWidget *parent) : QDialog(parent), d(new Private(this)) { const KSharedConfig::Ptr config = KSharedConfig::openConfig(QStringLiteral("kleopatracertificateselectiondialogrc")); d->ui.tabWidget.loadViews(config.data()); const KConfigGroup geometry(config, "Geometry"); resize(geometry.readEntry("size", size())); d->slotKeysMayHaveChanged(); } CertificateSelectionDialog::~CertificateSelectionDialog() {} void CertificateSelectionDialog::setCustomLabelText(const QString &txt) { if (txt == d->customLabelText) { return; } d->customLabelText = txt; d->updateLabelText(); } QString CertificateSelectionDialog::customLabelText() const { return d->customLabelText; } void CertificateSelectionDialog::setOptions(Options options) { if (d->options == options) { return; } d->options = options; d->ui.tabWidget.setMultiSelection(options & MultiSelection); d->slotKeysMayHaveChanged(); } CertificateSelectionDialog::Options CertificateSelectionDialog::options() const { return d->options; } void CertificateSelectionDialog::setStringFilter(const QString &filter) { d->ui.tabWidget.setStringFilter(filter); } void CertificateSelectionDialog::setKeyFilter(const std::shared_ptr &filter) { d->ui.tabWidget.setKeyFilter(filter); } void CertificateSelectionDialog::selectCertificates(const std::vector &keys) { const QAbstractItemView *const view = d->ui.tabWidget.currentView(); if (!view) { return; } const auto *const model = d->ui.tabWidget.currentModel(); Q_ASSERT(model); QItemSelectionModel *const sm = view->selectionModel(); Q_ASSERT(sm); Q_FOREACH (const QModelIndex &idx, model->indexes(keys)) if (idx.isValid()) { sm->select(idx, QItemSelectionModel::Select | QItemSelectionModel::Rows); } } void CertificateSelectionDialog::selectCertificate(const Key &key) { selectCertificates(std::vector(1, key)); } std::vector CertificateSelectionDialog::selectedCertificates() const { const QAbstractItemView *const view = d->ui.tabWidget.currentView(); if (!view) { return std::vector(); } const auto *const model = d->ui.tabWidget.currentModel(); Q_ASSERT(model); const QItemSelectionModel *const sm = view->selectionModel(); Q_ASSERT(sm); return model->keys(sm->selectedRows()); } Key CertificateSelectionDialog::selectedCertificate() const { const std::vector keys = selectedCertificates(); return keys.empty() ? Key() : keys.front(); } void CertificateSelectionDialog::hideEvent(QHideEvent *e) { KSharedConfig::Ptr config = KSharedConfig::openConfig(QStringLiteral("kleopatracertificateselectiondialogrc")); d->ui.tabWidget.saveViews(config.data()); KConfigGroup geometry(config, "Geometry"); geometry.writeEntry("size", size()); QDialog::hideEvent(e); } void CertificateSelectionDialog::Private::slotKeysMayHaveChanged() { q->setEnabled(true); std::vector keys = (options & SecretKeys) ? KeyCache::instance()->secretKeys() : KeyCache::instance()->keys(); q->filterAllowedKeys(keys, options); const std::vector selected = q->selectedCertificates(); if (AbstractKeyListModel *const model = ui.tabWidget.flatModel()) { model->setKeys(keys); } if (AbstractKeyListModel *const model = ui.tabWidget.hierarchicalModel()) { model->setKeys(keys); } q->selectCertificates(selected); } void CertificateSelectionDialog::filterAllowedKeys(std::vector &keys, int options) { std::vector::iterator end = keys.end(); switch (options & AnyFormat) { case OpenPGPFormat: end = std::remove_if(keys.begin(), end, [](const Key &key) { return key.protocol() != OpenPGP; }); break; case CMSFormat: end = std::remove_if(keys.begin(), end, [](const Key &key) { return key.protocol() != CMS; }); break; default: case AnyFormat: ; } switch (options & AnyCertificate) { case SignOnly: end = std::remove_if(keys.begin(), end, [](const Key &key) { return !key.canReallySign(); }); break; case EncryptOnly: end = std::remove_if(keys.begin(), end, [](const Key &key) { return !key.canEncrypt(); }); break; default: case AnyCertificate: ; } if (options & SecretKeys) { end = std::remove_if(keys.begin(), end, [](const Key &key) { return !key.hasSecret(); }); } keys.erase(end, keys.end()); } void CertificateSelectionDialog::Private::slotCurrentViewChanged(QAbstractItemView *newView) { if (lastView) { disconnect(lastView, SIGNAL(doubleClicked(QModelIndex)), q, SLOT(slotDoubleClicked(QModelIndex))); Q_ASSERT(lastView->selectionModel()); disconnect(lastView->selectionModel(), SIGNAL(selectionChanged(QItemSelection,QItemSelection)), q, SLOT(slotSelectionChanged())); } lastView = newView; if (newView) { connect(newView, SIGNAL(doubleClicked(QModelIndex)), q, SLOT(slotDoubleClicked(QModelIndex))); Q_ASSERT(newView->selectionModel()); connect(newView->selectionModel(), SIGNAL(selectionChanged(QItemSelection,QItemSelection)), q, SLOT(slotSelectionChanged())); } slotSelectionChanged(); } void CertificateSelectionDialog::Private::slotSelectionChanged() { if (QPushButton *const pb = ui.buttonBox.button(QDialogButtonBox::Ok)) { pb->setEnabled(acceptable(q->selectedCertificates())); } } void CertificateSelectionDialog::Private::slotDoubleClicked(const QModelIndex &idx) { QAbstractItemView *const view = ui.tabWidget.currentView(); Q_ASSERT(view); const auto *const model = ui.tabWidget.currentModel(); Q_ASSERT(model); Q_UNUSED(model) QItemSelectionModel *const sm = view->selectionModel(); Q_ASSERT(sm); sm->select(idx, QItemSelectionModel::ClearAndSelect | QItemSelectionModel::Rows); QMetaObject::invokeMethod(q, [this]() {q->accept();}, Qt::QueuedConnection); } void CertificateSelectionDialog::accept() { if (d->acceptable(selectedCertificates())) { QDialog::accept(); } } #include "moc_certificateselectiondialog.cpp"