Page MenuHome GnuPG

No OneTemporary

diff --git a/src/dialogs/certifywidget.cpp b/src/dialogs/certifywidget.cpp
index 4daba9594..2b8b08aa1 100644
--- a/src/dialogs/certifywidget.cpp
+++ b/src/dialogs/certifywidget.cpp
@@ -1,752 +1,760 @@
/* dialogs/certifywidget.cpp
This file is part of Kleopatra, the KDE keymanager
SPDX-FileCopyrightText: 2019, 2021 g10 Code GmbH
SPDX-FileContributor: Ingo Klöcker <dev@ingo-kloecker.de>
SPDX-License-Identifier: GPL-2.0-or-later
*/
#include <config-kleopatra.h>
#include "certifywidget.h"
#include "view/infofield.h"
#include <utils/accessibility.h>
#include <utils/expiration.h>
#include <utils/keys.h>
#include <settings.h>
#include "kleopatra_debug.h"
#include <KConfigGroup>
#include <KDateComboBox>
#include <KLocalizedString>
#include <KMessageBox>
#include <KMessageWidget>
#include <KSeparator>
#include <KSharedConfig>
#include <Libkleo/Algorithm>
#include <Libkleo/DefaultKeyFilter>
#include <Libkleo/Formatting>
#include <Libkleo/KeyCache>
#include <Libkleo/KeySelectionCombo>
#include <Libkleo/NavigatableTreeWidget>
#include <Libkleo/Predicates>
#include <QGpgME/ChangeOwnerTrustJob>
#include <QGpgME/Protocol>
#include <QAction>
#include <QCheckBox>
#include <QHBoxLayout>
#include <QIcon>
#include <QLabel>
#include <QLineEdit>
#include <QParallelAnimationGroup>
#include <QPropertyAnimation>
#include <QPushButton>
#include <QScrollArea>
#include <QToolButton>
#include <QVBoxLayout>
#include <gpgme++/key.h>
Q_DECLARE_METATYPE(GpgME::UserID)
using namespace Kleo;
using namespace GpgME;
static QDebug operator<<(QDebug s, const GpgME::UserID &userID)
{
return s << Formatting::prettyUserID(userID);
}
namespace
{
// Maybe move this in its own file
// based on code from StackOverflow
class AnimatedExpander : public QWidget
{
Q_OBJECT
public:
explicit AnimatedExpander(const QString &title, const QString &accessibleTitle = {}, QWidget *parent = nullptr);
void setContentLayout(QLayout *contentLayout);
private:
QGridLayout mainLayout;
QToolButton toggleButton;
QFrame headerLine;
QParallelAnimationGroup toggleAnimation;
QWidget contentArea;
int animationDuration{300};
};
AnimatedExpander::AnimatedExpander(const QString &title, const QString &accessibleTitle, QWidget *parent)
: QWidget{parent}
{
#ifdef Q_OS_WIN
// draw dotted focus frame if button has focus; otherwise, draw invisible frame using background color
toggleButton.setStyleSheet(
QStringLiteral("QToolButton { border: 1px solid palette(window); }"
"QToolButton:focus { border: 1px dotted palette(window-text); }"));
#else
// this works with Breeze style because Breeze draws the focus frame when drawing CE_ToolButtonLabel
// while the Windows styles (and Qt's common base style) draw the focus frame before drawing CE_ToolButtonLabel
toggleButton.setStyleSheet(QStringLiteral("QToolButton { border: none; }"));
#endif
toggleButton.setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
toggleButton.setArrowType(Qt::ArrowType::RightArrow);
toggleButton.setText(title);
if (!accessibleTitle.isEmpty()) {
toggleButton.setAccessibleName(accessibleTitle);
}
toggleButton.setCheckable(true);
toggleButton.setChecked(false);
headerLine.setFrameShape(QFrame::HLine);
headerLine.setFrameShadow(QFrame::Sunken);
headerLine.setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Maximum);
contentArea.setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
// start out collapsed
contentArea.setMaximumHeight(0);
contentArea.setMinimumHeight(0);
contentArea.setVisible(false);
// let the entire widget grow and shrink with its content
toggleAnimation.addAnimation(new QPropertyAnimation(this, "minimumHeight"));
toggleAnimation.addAnimation(new QPropertyAnimation(this, "maximumHeight"));
toggleAnimation.addAnimation(new QPropertyAnimation(&contentArea, "maximumHeight"));
mainLayout.setVerticalSpacing(0);
mainLayout.setContentsMargins(0, 0, 0, 0);
int row = 0;
mainLayout.addWidget(&toggleButton, row, 0, 1, 1, Qt::AlignLeft);
mainLayout.addWidget(&headerLine, row++, 2, 1, 1);
mainLayout.addWidget(&contentArea, row, 0, 1, 3);
setLayout(&mainLayout);
QObject::connect(&toggleButton, &QToolButton::clicked, [this](const bool checked) {
if (checked) {
// make the content visible when expanding starts
contentArea.setVisible(true);
}
toggleButton.setArrowType(checked ? Qt::ArrowType::DownArrow : Qt::ArrowType::RightArrow);
toggleAnimation.setDirection(checked ? QAbstractAnimation::Forward : QAbstractAnimation::Backward);
toggleAnimation.start();
});
connect(&toggleAnimation, &QAbstractAnimation::finished, [this]() {
// hide the content area when it is fully collapsed
if (!toggleButton.isChecked()) {
contentArea.setVisible(false);
}
});
}
void AnimatedExpander::setContentLayout(QLayout *contentLayout)
{
delete contentArea.layout();
contentArea.setLayout(contentLayout);
const auto collapsedHeight = sizeHint().height() - contentArea.maximumHeight();
auto contentHeight = contentLayout->sizeHint().height();
for (int i = 0; i < toggleAnimation.animationCount() - 1; ++i) {
auto expanderAnimation = static_cast<QPropertyAnimation *>(toggleAnimation.animationAt(i));
expanderAnimation->setDuration(animationDuration);
expanderAnimation->setStartValue(collapsedHeight);
expanderAnimation->setEndValue(collapsedHeight + contentHeight);
}
auto contentAnimation = static_cast<QPropertyAnimation *>(toggleAnimation.animationAt(toggleAnimation.animationCount() - 1));
contentAnimation->setDuration(animationDuration);
contentAnimation->setStartValue(0);
contentAnimation->setEndValue(contentHeight);
}
class SecKeyFilter : public DefaultKeyFilter
{
public:
SecKeyFilter()
: DefaultKeyFilter()
{
setRevoked(DefaultKeyFilter::NotSet);
setExpired(DefaultKeyFilter::NotSet);
setHasSecret(DefaultKeyFilter::Set);
setCanCertify(DefaultKeyFilter::Set);
setIsOpenPGP(DefaultKeyFilter::Set);
}
bool matches(const GpgME::Key &key, Kleo::KeyFilter::MatchContexts contexts) const override
{
if (!(availableMatchContexts() & contexts)) {
return false;
}
if (_detail::ByFingerprint<std::equal_to>()(key, mExcludedKey)) {
return false;
}
return DefaultKeyFilter::matches(key, contexts);
}
void setExcludedKey(const GpgME::Key &key)
{
mExcludedKey = key;
}
private:
GpgME::Key mExcludedKey;
};
auto checkBoxSize(const QCheckBox *checkBox)
{
QStyleOptionButton opt;
return checkBox->style()->sizeFromContents(QStyle::CT_CheckBox, &opt, QSize(), checkBox);
}
class TreeWidget : public NavigatableTreeWidget
{
Q_OBJECT
public:
using NavigatableTreeWidget::NavigatableTreeWidget;
protected:
void focusInEvent(QFocusEvent *event) override
{
NavigatableTreeWidget::focusInEvent(event);
// queue the invokation, so that it happens after the widget itself got focus
QMetaObject::invokeMethod(this, &TreeWidget::forceAccessibleFocusEventForCurrentItem, Qt::QueuedConnection);
}
private:
void forceAccessibleFocusEventForCurrentItem()
{
// force Qt to send a focus event for the current item to accessibility
// tools; otherwise, the user has no idea which item is selected when the
// list gets keyboard input focus
const auto current = currentIndex();
setCurrentIndex({});
setCurrentIndex(current);
}
};
}
class CertifyWidget::Private
{
enum Role { UserIdRole = Qt::UserRole };
public:
Private(CertifyWidget *qq)
: q{qq}
{
auto mainLay = new QVBoxLayout{q};
{
auto label = new QLabel{i18n("Verify the fingerprint, mark the user IDs you want to certify, "
"and select the key you want to certify the user IDs with.<br>"
"<i>Note: Only the fingerprint clearly identifies the key and its owner.</i>"),
q};
label->setWordWrap(true);
labelHelper.addLabel(label);
mainLay->addWidget(label);
}
mainLay->addWidget(new KSeparator{Qt::Horizontal, q});
{
auto grid = new QGridLayout;
grid->setColumnStretch(1, 1);
int row = -1;
row++;
mFprField = std::make_unique<InfoField>(i18n("Fingerprint:"), q);
grid->addWidget(mFprField->label(), row, 0);
grid->addLayout(mFprField->layout(), row, 1);
row++;
auto label = new QLabel{i18n("Certify with:"), q};
mSecKeySelect = new KeySelectionCombo{/* secretOnly= */ true, q};
mSecKeySelect->setKeyFilter(std::make_shared<SecKeyFilter>());
label->setBuddy(mSecKeySelect);
grid->addWidget(label, row, 0);
grid->addWidget(mSecKeySelect);
mainLay->addLayout(grid);
}
mMissingOwnerTrustInfo = new KMessageWidget{q};
mSetOwnerTrustAction = new QAction{q};
mSetOwnerTrustAction->setText(i18nc("@action:button", "Set Owner Trust"));
mSetOwnerTrustAction->setToolTip(i18nc("@info:tooltip",
"Click to set the trust level of the selected certification key to ultimate trust. "
"This is what you usually want to do for your own keys."));
connect(mSetOwnerTrustAction, &QAction::triggered, q, [this]() {
setOwnerTrust();
});
mMissingOwnerTrustInfo->addAction(mSetOwnerTrustAction);
mMissingOwnerTrustInfo->setVisible(false);
mainLay->addWidget(mMissingOwnerTrustInfo);
mainLay->addWidget(new KSeparator{Qt::Horizontal, q});
userIdListView = new TreeWidget{q};
userIdListView->setAccessibleName(i18n("User IDs"));
userIdListView->setEditTriggers(QAbstractItemView::NoEditTriggers);
userIdListView->setSelectionMode(QAbstractItemView::SingleSelection);
userIdListView->setRootIsDecorated(false);
userIdListView->setUniformRowHeights(true);
userIdListView->setAllColumnsShowFocus(false);
userIdListView->setHeaderHidden(true);
userIdListView->setHeaderLabels({i18nc("@title:column", "User ID")});
mainLay->addWidget(userIdListView, 1);
// Setup the advanced area
auto expander = new AnimatedExpander{i18n("Advanced"), i18n("Show advanced options"), q};
mainLay->addWidget(expander);
auto advLay = new QVBoxLayout;
mExportCB = new QCheckBox{q};
mExportCB->setText(i18n("Certify for everyone to see (exportable)"));
advLay->addWidget(mExportCB);
{
auto layout = new QHBoxLayout;
mPublishCB = new QCheckBox{q};
mPublishCB->setText(i18n("Publish on keyserver afterwards"));
mPublishCB->setEnabled(mExportCB->isChecked());
layout->addSpacing(checkBoxSize(mExportCB).width());
layout->addWidget(mPublishCB);
advLay->addLayout(layout);
}
{
auto tagsLay = new QHBoxLayout;
auto label = new QLabel{i18n("Tags:"), q};
mTagsLE = new QLineEdit{q};
label->setBuddy(mTagsLE);
const auto tooltip = i18n("You can use this to add additional info to a certification.") + QStringLiteral("<br/><br/>")
+ i18n("Tags created by anyone with full certification trust "
"are shown in the keylist and can be searched.");
label->setToolTip(tooltip);
mTagsLE->setToolTip(tooltip);
tagsLay->addWidget(label);
tagsLay->addWidget(mTagsLE, 1);
advLay->addLayout(tagsLay);
}
{
auto layout = new QHBoxLayout;
mExpirationCheckBox = new QCheckBox{q};
mExpirationCheckBox->setText(i18n("Expiration:"));
mExpirationDateEdit = new KDateComboBox{q};
Kleo::setUpExpirationDateComboBox(mExpirationDateEdit, {QDate::currentDate().addDays(1), QDate{}});
mExpirationDateEdit->setDate(Kleo::defaultExpirationDate(ExpirationOnUnlimitedValidity::InternalDefaultExpiration));
mExpirationDateEdit->setEnabled(mExpirationCheckBox->isChecked());
const auto tooltip = i18n("You can use this to set an expiration date for a certification.") + QStringLiteral("<br/><br/>")
+ i18n("By setting an expiration date, you can limit the validity of "
"your certification to a certain amount of time. Once the expiration "
"date has passed, your certification is no longer valid.");
mExpirationCheckBox->setToolTip(tooltip);
mExpirationDateEdit->setToolTip(tooltip);
layout->addWidget(mExpirationCheckBox);
layout->addWidget(mExpirationDateEdit, 1);
advLay->addLayout(layout);
}
{
mTrustSignatureCB = new QCheckBox{q};
mTrustSignatureCB->setText(i18n("Certify as trusted introducer"));
const auto tooltip = i18n("You can use this to certify a trusted introducer for a domain.") + QStringLiteral("<br/><br/>")
+ i18n("All certificates with email addresses belonging to the domain "
"that have been certified by the trusted introducer are treated "
"as certified, i.e. a trusted introducer acts as a kind of "
"intermediate CA for a domain.");
mTrustSignatureCB->setToolTip(tooltip);
advLay->addWidget(mTrustSignatureCB);
}
{
auto layout = new QHBoxLayout;
auto label = new QLabel{i18n("Domain:"), q};
mTrustSignatureDomainLE = new QLineEdit{q};
mTrustSignatureDomainLE->setEnabled(mTrustSignatureCB->isChecked());
label->setBuddy(mTrustSignatureDomainLE);
layout->addSpacing(checkBoxSize(mTrustSignatureCB).width());
layout->addWidget(label);
layout->addWidget(mTrustSignatureDomainLE);
advLay->addLayout(layout);
}
expander->setContentLayout(advLay);
connect(userIdListView, &QTreeWidget::itemChanged, q, [this](auto item, auto) {
onItemChanged(item);
});
connect(mExportCB, &QCheckBox::toggled, [this](bool on) {
mPublishCB->setEnabled(on);
});
connect(mSecKeySelect, &KeySelectionCombo::currentKeyChanged, [this](const GpgME::Key &) {
updateTags();
checkOwnerTrust();
Q_EMIT q->changed();
});
connect(mExpirationCheckBox, &QCheckBox::toggled, q, [this](bool checked) {
mExpirationDateEdit->setEnabled(checked);
Q_EMIT q->changed();
});
connect(mExpirationDateEdit, &KDateComboBox::dateChanged, q, &CertifyWidget::changed);
connect(mTrustSignatureCB, &QCheckBox::toggled, q, [this](bool on) {
mTrustSignatureDomainLE->setEnabled(on);
Q_EMIT q->changed();
});
connect(mTrustSignatureDomainLE, &QLineEdit::textChanged, q, &CertifyWidget::changed);
loadConfig();
}
~Private() = default;
void loadConfig()
{
const Settings settings;
mExpirationCheckBox->setChecked(settings.certificationValidityInDays() > 0);
if (settings.certificationValidityInDays() > 0) {
const QDate expirationDate = QDate::currentDate().addDays(settings.certificationValidityInDays());
mExpirationDateEdit->setDate(expirationDate > mExpirationDateEdit->maximumDate() //
? mExpirationDateEdit->maximumDate() //
: expirationDate);
}
const KConfigGroup conf(KSharedConfig::openConfig(), "CertifySettings");
mSecKeySelect->setDefaultKey(conf.readEntry("LastKey", QString()));
mExportCB->setChecked(conf.readEntry("ExportCheckState", false));
mPublishCB->setChecked(conf.readEntry("PublishCheckState", false));
}
void setUpUserIdList(const std::vector<GpgME::UserID> &uids)
{
userIdListView->clear();
for (const auto &uid : uids) {
if (uid.isInvalid() || Kleo::isRevokedOrExpired(uid)) {
// Skip user IDs that cannot really be certified.
continue;
}
auto item = new QTreeWidgetItem;
item->setData(0, UserIdRole, QVariant::fromValue(uid));
item->setData(0, Qt::DisplayRole, Kleo::Formatting::prettyUserID(uid));
item->setFlags(Qt::ItemIsSelectable | Qt::ItemIsUserCheckable | Qt::ItemIsEnabled);
item->setCheckState(0, Qt::Checked);
userIdListView->addTopLevelItem(item);
}
}
void updateTags()
{
+ struct ItemAndRemark {
+ QTreeWidgetItem *item;
+ QString remark;
+ };
+
if (mTagsLE->isModified()) {
return;
}
GpgME::Key remarkKey = mSecKeySelect->currentKey();
if (!remarkKey.isNull()) {
- std::vector<GpgME::UserID> uidsWithRemark;
+ std::vector<ItemAndRemark> itemsAndRemarks;
+ // first choose the remark we want to prefill the Tags field with
QString remark;
for (int i = 0, end = userIdListView->topLevelItemCount(); i < end; ++i) {
- const auto uid = getUserId(userIdListView->topLevelItem(i));
+ const auto item = userIdListView->topLevelItem(i);
+ const auto uid = getUserId(item);
GpgME::Error err;
const char *c_remark = uid.remark(remarkKey, err);
- if (!err && c_remark) {
- const QString candidate = QString::fromUtf8(c_remark);
- if (candidate != remark) {
- if (!remark.isEmpty()) {
- qCDebug(KLEOPATRA_LOG) << "Different remarks on user IDs. Taking last.";
- }
- remark = candidate;
- uidsWithRemark.clear();
+ const QString itemRemark = (!err && c_remark) ? QString::fromUtf8(c_remark) : QString{};
+ if (!itemRemark.isEmpty() && (itemRemark != remark)) {
+ if (!remark.isEmpty()) {
+ qCDebug(KLEOPATRA_LOG) << "Different remarks on user IDs. Taking last.";
}
- uidsWithRemark.push_back(uid);
+ remark = itemRemark;
}
+ itemsAndRemarks.push_back({item, itemRemark});
}
- // Only select the user IDs with the correct remark
+ // then select the user IDs with the chosen remark; this prevents overwriting existing
+ // different remarks on the other user IDs (as long as the user doesn't select any of
+ // the unselected user IDs with a different remark)
if (!remark.isEmpty()) {
- selectUserIDs(uidsWithRemark);
+ for (const auto &[item, itemRemark] : itemsAndRemarks) {
+ item->setCheckState(0, itemRemark == remark ? Qt::Checked : Qt::Unchecked);
+ }
}
mTagsLE->setText(remark);
}
}
void updateTrustSignatureDomain()
{
if (mTrustSignatureDomainLE->text().isEmpty() && mTarget.numUserIDs() == 1) {
// try to guess the domain to use for the trust signature
const auto address = mTarget.userID(0).addrSpec();
const auto atPos = address.find('@');
if (atPos != std::string::npos) {
const auto domain = address.substr(atPos + 1);
mTrustSignatureDomainLE->setText(QString::fromUtf8(domain.c_str(), domain.size()));
}
}
}
void setTarget(const GpgME::Key &key, const std::vector<GpgME::UserID> &uids)
{
mFprField->setValue(QStringLiteral("<b>") + Formatting::prettyID(key.primaryFingerprint()) + QStringLiteral("</b>"),
Formatting::accessibleHexID(key.primaryFingerprint()));
mTarget = key;
setUpUserIdList(uids.empty() ? mTarget.userIDs() : uids);
auto keyFilter = std::make_shared<SecKeyFilter>();
keyFilter->setExcludedKey(mTarget);
mSecKeySelect->setKeyFilter(keyFilter);
updateTags();
updateTrustSignatureDomain();
}
GpgME::Key secKey() const
{
return mSecKeySelect->currentKey();
}
GpgME::UserID getUserId(const QTreeWidgetItem *item) const
{
return item ? item->data(0, UserIdRole).value<UserID>() : UserID{};
}
void selectUserIDs(const std::vector<GpgME::UserID> &uids)
{
for (int i = 0, end = userIdListView->topLevelItemCount(); i < end; ++i) {
const auto uidItem = userIdListView->topLevelItem(i);
const auto itemUserId = getUserId(uidItem);
const bool userIdIsInList = Kleo::any_of(uids, [itemUserId](const auto &uid) {
return Kleo::userIDsAreEqual(itemUserId, uid);
});
uidItem->setCheckState(0, userIdIsInList ? Qt::Checked : Qt::Unchecked);
}
}
std::vector<GpgME::UserID> selectedUserIDs() const
{
std::vector<GpgME::UserID> userIds;
userIds.reserve(userIdListView->topLevelItemCount());
for (int i = 0, end = userIdListView->topLevelItemCount(); i < end; ++i) {
const auto *const uidItem = userIdListView->topLevelItem(i);
if (uidItem->checkState(0) == Qt::Checked) {
userIds.push_back(getUserId(uidItem));
}
}
qCDebug(KLEOPATRA_LOG) << "Checked user IDs:" << userIds;
return userIds;
}
bool exportableSelected() const
{
return mExportCB->isChecked();
}
bool publishSelected() const
{
return mPublishCB->isChecked();
}
QString tags() const
{
return mTagsLE->text().trimmed();
}
GpgME::Key target() const
{
return mTarget;
}
bool isValid() const
{
static const QRegularExpression domainNameRegExp{QStringLiteral(R"(^\s*((xn--)?[a-z0-9]+(-[a-z0-9]+)*\.)+[a-z]{2,}\s*$)"),
QRegularExpression::CaseInsensitiveOption};
// do not accept null keys
if (mTarget.isNull() || mSecKeySelect->currentKey().isNull()) {
return false;
}
// do not accept empty list of user IDs
if (selectedUserIDs().empty()) {
return false;
}
// do not accept if the key to certify is selected as certification key;
// this shouldn't happen because the key to certify is excluded from the choice, but better safe than sorry
if (_detail::ByFingerprint<std::equal_to>()(mTarget, mSecKeySelect->currentKey())) {
return false;
}
if (mExpirationCheckBox->isChecked() && !mExpirationDateEdit->isValid()) {
return false;
}
if (mTrustSignatureCB->isChecked() && !domainNameRegExp.match(mTrustSignatureDomainLE->text()).hasMatch()) {
return false;
}
return true;
}
void checkOwnerTrust()
{
const auto secretKey = secKey();
if (secretKey.ownerTrust() != GpgME::Key::Ultimate) {
mMissingOwnerTrustInfo->setMessageType(KMessageWidget::Information);
mMissingOwnerTrustInfo->setIcon(QIcon::fromTheme(QStringLiteral("question")));
mMissingOwnerTrustInfo->setText(i18n("Is this your own key?"));
mSetOwnerTrustAction->setEnabled(true);
mMissingOwnerTrustInfo->animatedShow();
} else {
mMissingOwnerTrustInfo->animatedHide();
}
}
void setOwnerTrust()
{
mSetOwnerTrustAction->setEnabled(false);
QGpgME::ChangeOwnerTrustJob *const j = QGpgME::openpgp()->changeOwnerTrustJob();
connect(j, &QGpgME::ChangeOwnerTrustJob::result, q, [this](const GpgME::Error &err) {
if (err) {
KMessageBox::error(q,
i18n("<p>Changing the certification trust of the key <b>%1</b> failed:</p><p>%2</p>",
Formatting::formatForComboBox(secKey()),
Formatting::errorAsString(err)),
i18n("Certification Trust Change Failed"));
}
if (err || err.isCanceled()) {
mSetOwnerTrustAction->setEnabled(true);
} else {
mMissingOwnerTrustInfo->setMessageType(KMessageWidget::Positive);
mMissingOwnerTrustInfo->setIcon(QIcon::fromTheme(QStringLiteral("checkmark")));
mMissingOwnerTrustInfo->setText(i18n("Owner trust set successfully."));
}
});
j->start(secKey(), GpgME::Key::Ultimate);
}
void onItemChanged(QTreeWidgetItem *item)
{
Q_EMIT q->changed();
#ifndef QT_NO_ACCESSIBILITY
if (item) {
// assume that the checked state changed
QAccessible::State st;
st.checked = true;
QAccessibleStateChangeEvent e(userIdListView, st);
e.setChild(userIdListView->indexOfTopLevelItem(item));
QAccessible::updateAccessibility(&e);
}
#endif
}
public:
CertifyWidget *const q;
std::unique_ptr<InfoField> mFprField;
KeySelectionCombo *mSecKeySelect = nullptr;
KMessageWidget *mMissingOwnerTrustInfo = nullptr;
NavigatableTreeWidget *userIdListView = nullptr;
QCheckBox *mExportCB = nullptr;
QCheckBox *mPublishCB = nullptr;
QLineEdit *mTagsLE = nullptr;
QCheckBox *mTrustSignatureCB = nullptr;
QLineEdit *mTrustSignatureDomainLE = nullptr;
QCheckBox *mExpirationCheckBox = nullptr;
KDateComboBox *mExpirationDateEdit = nullptr;
QAction *mSetOwnerTrustAction = nullptr;
LabelHelper labelHelper;
GpgME::Key mTarget;
};
CertifyWidget::CertifyWidget(QWidget *parent)
: QWidget{parent}
, d{std::make_unique<Private>(this)}
{
}
Kleo::CertifyWidget::~CertifyWidget() = default;
void CertifyWidget::setTarget(const GpgME::Key &key, const std::vector<GpgME::UserID> &uids)
{
d->setTarget(key, uids);
}
GpgME::Key CertifyWidget::target() const
{
return d->target();
}
void CertifyWidget::selectUserIDs(const std::vector<GpgME::UserID> &uids)
{
d->selectUserIDs(uids);
}
std::vector<GpgME::UserID> CertifyWidget::selectedUserIDs() const
{
return d->selectedUserIDs();
}
GpgME::Key CertifyWidget::secKey() const
{
return d->secKey();
}
bool CertifyWidget::exportableSelected() const
{
return d->exportableSelected();
}
QString CertifyWidget::tags() const
{
return d->tags();
}
bool CertifyWidget::publishSelected() const
{
return d->publishSelected();
}
bool CertifyWidget::trustSignatureSelected() const
{
return d->mTrustSignatureCB->isChecked();
}
QString CertifyWidget::trustSignatureDomain() const
{
return d->mTrustSignatureDomainLE->text().trimmed();
}
QDate CertifyWidget::expirationDate() const
{
return d->mExpirationCheckBox->isChecked() ? d->mExpirationDateEdit->date() : QDate{};
}
bool CertifyWidget::isValid() const
{
return d->isValid();
}
// For UserID model
#include "certifywidget.moc"

File Metadata

Mime Type
text/x-diff
Expires
Mon, Dec 29, 7:08 AM (13 h, 22 m)
Storage Engine
local-disk
Storage Format
Raw Data
Storage Handle
72/8c/a984690d6b9f6e28e9a72995eeb3

Event Timeline