Page Menu
Home
GnuPG
Search
Configure Global Search
Log In
Files
F34381703
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Size
15 KB
Subscribers
None
View Options
diff --git a/src/dialogs/certificateselectiondialog.cpp b/src/dialogs/certificateselectiondialog.cpp
index 60bd8da28..2ffed30e0 100644
--- a/src/dialogs/certificateselectiondialog.cpp
+++ b/src/dialogs/certificateselectiondialog.cpp
@@ -1,449 +1,466 @@
/* -*- 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 <config-kleopatra.h>
#include "certificateselectiondialog.h"
+#include "conf/groupsconfigdialog.h"
+
#include <view/keytreeview.h>
#include <view/searchbar.h>
#include <view/tabwidget.h>
#include "utils/tags.h"
#include <Libkleo/KeyGroup>
#include <Libkleo/KeyListModel>
#include <Libkleo/KeyCache>
#include <commands/reloadkeyscommand.h>
#include <commands/lookupcertificatescommand.h>
#include <commands/newcertificatecommand.h>
#include <commands/importcertificatefromfilecommand.h>
#include <gpgme++/key.h>
#include <KLocalizedString>
+#include <KConfigDialog>
#include <KConfigGroup>
#include <KSharedConfig>
#include <QLabel>
#include <QPushButton>
#include <QDialogButtonBox>
#include <QItemSelectionModel>
#include <QAbstractItemView>
#include <QPointer>
#include <QVBoxLayout>
#include <algorithm>
#include <gpgme++/gpgmepp_version.h>
#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 manageGroups()
+ {
+ KConfigDialog *dialog = KConfigDialog::exists(GroupsConfigDialog::dialogName());
+ if (dialog) {
+ // reparent the dialog to ensure it's shown on top of the modal CertificateSelectionDialog
+ dialog->setParent(q, Qt::Dialog);
+ } else {
+ dialog = new GroupsConfigDialog(q);
+ }
+ dialog->show();
+ }
void slotKeysMayHaveChanged();
void slotCurrentViewChanged(QAbstractItemView *newView);
void slotSelectionChanged();
void slotDoubleClicked(const QModelIndex &idx);
private:
bool acceptable(const std::vector<Key> &keys, const std::vector<KeyGroup> &groups)
{
return !keys.empty() || !groups.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<QAbstractItemView> lastView;
QString customLabelText;
Options options;
struct UI {
QLabel label;
SearchBar searchBar;
TabWidget tabWidget;
QDialogButtonBox buttonBox;
} ui;
void setUpUI(CertificateSelectionDialog *q)
{
KDAB_SET_OBJECT_NAME(ui.label);
KDAB_SET_OBJECT_NAME(ui.searchBar);
KDAB_SET_OBJECT_NAME(ui.tabWidget);
KDAB_SET_OBJECT_NAME(ui.buttonBox);
auto *vlay = new QVBoxLayout(q);
vlay->addWidget(&ui.label);
vlay->addWidget(&ui.searchBar);
vlay->addWidget(&ui.tabWidget, 1);
vlay->addWidget(&ui.buttonBox);
QPushButton *const ok = ui.buttonBox.addButton(QDialogButtonBox::Ok);
ok->setEnabled(false);
QPushButton *const cancel = ui.buttonBox.addButton(QDialogButtonBox::Close);
Q_UNUSED(cancel)
QPushButton *const reload = ui.buttonBox.addButton(i18n("Reload"), QDialogButtonBox::ActionRole);
QPushButton *const import = ui.buttonBox.addButton(i18n("Import..."), QDialogButtonBox::ActionRole);
QPushButton *const lookup = ui.buttonBox.addButton(i18n("Lookup..."), QDialogButtonBox::ActionRole);
QPushButton *const create = ui.buttonBox.addButton(i18n("New..."), QDialogButtonBox::ActionRole);
+ QPushButton *const groups = ui.buttonBox.addButton(i18n("Groups..."), 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"));
+ groups->setToolTip(i18nc("@info:tooltip", "Manage certificate groups"));
connect(&ui.buttonBox, &QDialogButtonBox::accepted, q, &CertificateSelectionDialog::accept);
connect(&ui.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(groups, &QPushButton::clicked, q, [this] () { manageGroups(); });
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();
});
}
};
CertificateSelectionDialog::Private::Private(CertificateSelectionDialog *qq)
: q(qq)
{
setUpUI(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<KeyFilter> &filter)
{
d->ui.tabWidget.setKeyFilter(filter);
}
namespace
{
void selectRows(const QAbstractItemView *view, const QModelIndexList &indexes)
{
if (!view) {
return;
}
QItemSelectionModel *const sm = view->selectionModel();
Q_ASSERT(sm);
for (const QModelIndex &idx : qAsConst(indexes)) {
if (idx.isValid()) {
sm->select(idx, QItemSelectionModel::Select | QItemSelectionModel::Rows);
}
}
}
QModelIndexList getGroupIndexes(const KeyListModelInterface *model, const std::vector<KeyGroup> &groups)
{
QModelIndexList indexes;
indexes.reserve(groups.size());
std::transform(groups.begin(), groups.end(),
std::back_inserter(indexes),
[model] (const KeyGroup &group) {
return model->index(group);
});
indexes.erase(std::remove_if(indexes.begin(), indexes.end(),
[] (const QModelIndex &index) { return !index.isValid(); }),
indexes.end());
return indexes;
}
}
void CertificateSelectionDialog::selectCertificates(const std::vector<Key> &keys)
{
const auto *const model = d->ui.tabWidget.currentModel();
Q_ASSERT(model);
selectRows(d->ui.tabWidget.currentView(), model->indexes(keys));
}
void CertificateSelectionDialog::selectCertificate(const Key &key)
{
selectCertificates(std::vector<Key>(1, key));
}
void CertificateSelectionDialog::selectGroups(const std::vector<KeyGroup> &groups)
{
const auto *const model = d->ui.tabWidget.currentModel();
Q_ASSERT(model);
selectRows(d->ui.tabWidget.currentView(), getGroupIndexes(model, groups));
}
namespace
{
QModelIndexList getSelectedRows(const QAbstractItemView *view)
{
if (!view) {
return {};
}
const QItemSelectionModel *const sm = view->selectionModel();
Q_ASSERT(sm);
return sm->selectedRows();
}
std::vector<KeyGroup> getGroups(const KeyListModelInterface *model, const QModelIndexList &indexes)
{
std::vector<KeyGroup> groups;
groups.reserve(indexes.size());
std::transform(indexes.begin(), indexes.end(),
std::back_inserter(groups),
[model](const QModelIndex &idx) {
return model->group(idx);
});
groups.erase(std::remove_if(groups.begin(), groups.end(), std::mem_fn(&Kleo::KeyGroup::isNull)), groups.end());
return groups;
}
}
std::vector<Key> CertificateSelectionDialog::selectedCertificates() const
{
const KeyListModelInterface *const model = d->ui.tabWidget.currentModel();
Q_ASSERT(model);
return model->keys(getSelectedRows(d->ui.tabWidget.currentView()));
}
Key CertificateSelectionDialog::selectedCertificate() const
{
const std::vector<Key> keys = selectedCertificates();
return keys.empty() ? Key() : keys.front();
}
std::vector<KeyGroup> CertificateSelectionDialog::selectedGroups() const
{
const KeyListModelInterface *const model = d->ui.tabWidget.currentModel();
Q_ASSERT(model);
return getGroups(model, getSelectedRows(d->ui.tabWidget.currentView()));
}
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<Key> keys = (options & SecretKeys) ? KeyCache::instance()->secretKeys() : KeyCache::instance()->keys();
q->filterAllowedKeys(keys, options);
const std::vector<KeyGroup> groups = (options & IncludeGroups) ? KeyCache::instance()->groups() : std::vector<KeyGroup>();
const std::vector<Key> selectedKeys = q->selectedCertificates();
const std::vector<KeyGroup> selectedGroups = q->selectedGroups();
if (AbstractKeyListModel *const model = ui.tabWidget.flatModel()) {
model->setKeys(keys);
model->setGroups(groups);
}
if (AbstractKeyListModel *const model = ui.tabWidget.hierarchicalModel()) {
model->setKeys(keys);
model->setGroups(groups);
}
q->selectCertificates(selectedKeys);
q->selectGroups(selectedGroups);
}
void CertificateSelectionDialog::filterAllowedKeys(std::vector<Key> &keys, int options)
{
std::vector<Key>::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(), q->selectedGroups()));
}
}
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(), selectedGroups())) {
QDialog::accept();
}
}
#include "moc_certificateselectiondialog.cpp"
File Metadata
Details
Attached
Mime Type
text/x-diff
Expires
Sat, Jan 3, 11:44 PM (9 h, 36 m)
Storage Engine
local-disk
Storage Format
Raw Data
Storage Handle
0b/7c/c57ba49e59d1446dccca413f689c
Attached To
rKLEOPATRA Kleopatra
Event Timeline
Log In to Comment