Commit 04d95345 authored by Ingo Klöcker's avatar Ingo Klöcker
Browse files

Manage lifetime of validators with shared pointers

... instead of relying on a mix of QObject's lifetime management and
manual deletion.

GnuPG-bug-id: 5832
parent 0e35efa3
Pipeline #178548 passed with stage
in 3 minutes and 42 seconds
......@@ -107,7 +107,7 @@ public:
ui.nameInput->setValueRequiredErrorMessage(i18n("Enter a name."));
const auto regexp = config.readEntry("NAME_regex");
if (regexp.isEmpty()) {
ui.nameInput->setValidator(std::shared_ptr<QValidator>{Validation::simpleName(Validation::Optional)});
ui.nameInput->setValidator(Validation::simpleName(Validation::Optional));
ui.nameInput->setHint(i18n("Must not include <, >, and @."),
i18nc("text for screen readers",
"Must not include less-than sign, greater-than sign, and at sign."));
......@@ -116,7 +116,7 @@ public:
i18nc("text for screen readers",
"The name must not include less-than sign, greater-than sign, and at sign."));
} else {
ui.nameInput->setValidator(std::shared_ptr<QValidator>{Validation::simpleName(regexp, Validation::Optional)});
ui.nameInput->setValidator(Validation::simpleName(regexp, Validation::Optional));
ui.nameInput->setHint(i18n("Must be in the format required by your organization and "
"must not include <, >, and @."),
i18nc("text for screen readers",
......@@ -145,11 +145,11 @@ public:
ui.emailInput->setValueRequiredErrorMessage(i18n("Enter an email address."));
const auto regexp = config.readEntry(QLatin1String("EMAIL_regex"));
if (regexp.isEmpty()) {
ui.emailInput->setValidator(std::shared_ptr<QValidator>{Validation::email(Validation::Optional)});
ui.emailInput->setValidator(Validation::email(Validation::Optional));
ui.emailInput->setInvalidEntryErrorMessage(i18n(
"Enter an email address in the correct format, like name@example.com."));
} else {
ui.emailInput->setValidator(std::shared_ptr<QValidator>{Validation::email(regexp, Validation::Optional)});
ui.emailInput->setValidator(Validation::email(regexp, Validation::Optional));
ui.emailInput->setHint(i18n(
"Must be in the format required by your organization"));
ui.emailInput->setInvalidEntryErrorMessage(i18n(
......
......@@ -40,6 +40,7 @@ namespace
QString label;
QString regex;
QLineEdit *edit;
std::shared_ptr<QValidator> validator;
bool required;
};
......@@ -62,7 +63,7 @@ namespace
}
}
QLineEdit * addRow(QGridLayout *l, const QString &label, const QString &preset, QValidator *validator, bool readonly, bool required)
QLineEdit * addRow(QGridLayout *l, const QString &label, const QString &preset, const std::shared_ptr<QValidator> &validator, bool readonly, bool required)
{
Q_ASSERT(l);
......@@ -71,12 +72,8 @@ namespace
auto le = new QLineEdit(l->parentWidget());
le->setText(preset);
delete le->validator();
if (validator) {
if (!validator->parent()) {
validator->setParent(le);
}
le->setValidator(validator);
le->setValidator(validator.get());
}
le->setReadOnly(readonly && le->hasAcceptableInput());
......@@ -244,16 +241,16 @@ public:
attributeLabel(attr));
const QString regex = config.readEntry(attr + QLatin1String("_regex"));
QValidator *validator = nullptr;
std::shared_ptr<QValidator> validator;
if (attr == QLatin1String("EMAIL")) {
validator = regex.isEmpty() ? Validation::email() : Validation::email(regex);
} else if (!regex.isEmpty()) {
validator = new QRegularExpressionValidator{QRegularExpression{regex}, nullptr};
validator = std::make_shared<QRegularExpressionValidator>(QRegularExpression{regex});
}
QLineEdit *le = addRow(ui.gridLayout, label, preset, validator, readonly, required);
const Line line = { attr, label, regex, le, required };
const Line line = { attr, label, regex, le, validator, required };
ui.lines.push_back(line);
if (attr != QLatin1String("EMAIL")) {
......
......@@ -301,7 +301,7 @@ static int row_index_of(QWidget *w, QGridLayout *l)
return r;
}
static QLineEdit *adjust_row(QGridLayout *l, int row, const QString &label, const QString &preset, QValidator *validator, bool readonly, bool required)
static QLineEdit *adjust_row(QGridLayout *l, int row, const QString &label, const QString &preset, const std::shared_ptr<QValidator> &validator, bool readonly, bool required)
{
Q_ASSERT(l);
Q_ASSERT(row >= 0);
......@@ -318,12 +318,8 @@ static QLineEdit *adjust_row(QGridLayout *l, int row, const QString &label, cons
lb->setText(i18nc("interpunctation for labels", "%1:", label));
le->setText(preset);
reqLB->setText(required ? i18n("(required)") : i18n("(optional)"));
delete le->validator();
if (validator) {
if (!validator->parent()) {
validator->setParent(le);
}
le->setValidator(validator);
le->setValidator(validator.get());
}
le->setReadOnly(readonly && le->hasAcceptableInput());
......@@ -389,7 +385,7 @@ void EnterDetailsPage::updateForm()
int row;
bool known = true;
QValidator *validator = nullptr;
std::shared_ptr<QValidator> validator;
if (attr == QLatin1String("EMAIL")) {
row = row_index_of(ui->emailLE, ui->gridLayout);
validator = regex.isEmpty() ? Validation::email() : Validation::email(regex);
......@@ -406,13 +402,13 @@ void EnterDetailsPage::updateForm()
row = add_row(ui->gridLayout, &dynamicWidgets);
}
if (!validator && !regex.isEmpty()) {
validator = new QRegularExpressionValidator{QRegularExpression{regex}, nullptr};
validator = std::make_shared<QRegularExpressionValidator>(QRegularExpression{regex});
}
QLineEdit *le = adjust_row(ui->gridLayout, row, label, preset, validator, readonly, required);
le->setPlaceholderText(placeholder);
const Line line = { key, label, regex, le };
const Line line = { key, label, regex, le, validator };
lines[row] = line;
if (!known) {
......
......@@ -17,6 +17,7 @@
class AdvancedSettingsDialog;
class QLineEdit;
class QValidator;
class EnterDetailsPage : public Kleo::NewCertificateUi::WizardPage
{
......@@ -28,6 +29,7 @@ public:
QString label;
QString regex;
QLineEdit *edit;
std::shared_ptr<QValidator> validator;
};
explicit EnterDetailsPage(QWidget *parent = nullptr);
......
......@@ -3,6 +3,8 @@
This file is part of Kleopatra, the KDE keymanager
SPDX-FileCopyrightText: 2008 Klarälvdalens Datakonsult AB
SPDX-FileCopyrightText: 2022 g10 Code GmbH
SPDX-FileContributor: Ingo Klöcker <dev@ingo-kloecker.de>
SPDX-License-Identifier: GPL-2.0-or-later
*/
......@@ -11,81 +13,55 @@
#include "multivalidator.h"
#include <Libkleo/Stl_Util>
#include <vector>
#include <algorithm>
#include <iterator>
using namespace Kleo;
MultiValidator::~MultiValidator() {}
void MultiValidator::addValidator(QValidator *vali)
MultiValidator::MultiValidator(const std::vector<std::shared_ptr<QValidator>> &validators)
: QValidator{}
, m_validators{validators}
{
if (!vali) {
return;
}
if (!vali->parent()) {
vali->setParent(this);
}
connect(vali, &QObject::destroyed, this, &MultiValidator::_kdmv_slotDestroyed);
m_validators.push_back(vali);
}
void MultiValidator::addValidators(const QList<QValidator *> &valis)
// static
std::shared_ptr<QValidator> Kleo::MultiValidator::create(const std::vector<std::shared_ptr<QValidator>> &validators)
{
std::for_each(valis.cbegin(), valis.cend(),
[this](QValidator *val) { addValidator(val); });
}
Q_ASSERT(std::all_of(std::begin(validators), std::end(validators), [](const auto &v) {
return v && !v->parent();
}));
void MultiValidator::removeValidator(QValidator *vali)
{
if (!vali) {
return;
}
_kdmv_slotDestroyed(vali);
if (vali->parent() == this) {
delete vali;
} else {
disconnect(vali, &QObject::destroyed, this, &MultiValidator::_kdmv_slotDestroyed);
}
return std::shared_ptr<MultiValidator>{new MultiValidator{validators}};
}
void MultiValidator::removeValidators(const QList<QValidator *> &valis)
{
std::for_each(valis.cbegin(), valis.cend(),
[this](QValidator *val) { removeValidator(val); });
}
MultiValidator::~MultiValidator() = default;
void MultiValidator::fixup(QString &str) const
{
std::for_each(m_validators.begin(), m_validators.end(),
[&str](QValidator *val) { val->fixup(str); });
std::for_each(std::cbegin(m_validators), std::cend(m_validators), [&str](const auto &val) {
val->fixup(str);
});
}
QValidator::State MultiValidator::validate(QString &str, int &pos) const
{
std::vector<State> states;
states.reserve(m_validators.size());
std::transform(m_validators.begin(), m_validators.end(),
std::transform(std::cbegin(m_validators), std::cend(m_validators),
std::back_inserter(states),
[&str, &pos](QValidator *val) {
[&str, &pos](const auto &val) {
return val->validate(str, pos);
});
if (std::any_of(states.cbegin(), states.cend(),
if (std::any_of(std::cbegin(states), std::cend(states),
[](State state) { return state == Invalid; })) {
return Invalid;
}
if (std::all_of(states.cbegin(), states.cend(),
if (std::all_of(std::cbegin(states), std::cend(states),
[](State state) { return state == Acceptable; })) {
return Acceptable;
}
return Intermediate;
}
void MultiValidator::_kdmv_slotDestroyed(QObject *o)
{
m_validators.erase(std::remove(m_validators.begin(), m_validators.end(), o),
m_validators.end());
return Intermediate;
}
......@@ -3,6 +3,8 @@
This file is part of Kleopatra, the KDE keymanager
SPDX-FileCopyrightText: 2008 Klarälvdalens Datakonsult AB
SPDX-FileCopyrightText: 2022 g10 Code GmbH
SPDX-FileContributor: Ingo Klöcker <dev@ingo-kloecker.de>
SPDX-License-Identifier: GPL-2.0-or-later
*/
......@@ -10,7 +12,9 @@
#pragma once
#include <QValidator>
#include <QList>
#include <memory>
#include <vector>
namespace Kleo
{
......@@ -18,37 +22,24 @@ namespace Kleo
class MultiValidator : public QValidator
{
Q_OBJECT
public:
explicit MultiValidator(QObject *parent = nullptr)
: QValidator(parent) {}
explicit MultiValidator(QValidator *validator1, QValidator *validator2 = nullptr, QObject *parent = nullptr)
: QValidator(parent)
{
addValidator(validator1);
addValidator(validator2);
}
explicit MultiValidator(const QList<QValidator *> &validators, QObject *parent = nullptr)
: QValidator(parent)
{
addValidators(validators);
}
~MultiValidator() override;
void addValidator(QValidator *validator);
void addValidators(const QList<QValidator *> &validators);
explicit MultiValidator(const std::vector<std::shared_ptr<QValidator>> &validators);
public:
/**
* Creates a combined validator from the \p validators.
*
* The validators must not be null and they must not have a parent.
*/
static std::shared_ptr<QValidator> create(const std::vector<std::shared_ptr<QValidator>> &validators);
void removeValidator(QValidator *validator);
void removeValidators(const QList<QValidator *> &validators);
~MultiValidator() override;
void fixup(QString &str) const override;
State validate(QString &str, int &pos) const override;
private Q_SLOTS:
void _kdmv_slotDestroyed(QObject *);
private:
QList<QValidator *> m_validators;
std::vector<std::shared_ptr<QValidator>> m_validators;
};
}
......@@ -3,6 +3,8 @@
This file is part of Kleopatra, the KDE keymanager
SPDX-FileCopyrightText: 2008 Klarälvdalens Datakonsult AB
SPDX-FileCopyrightText: 2022 g10 Code GmbH
SPDX-FileContributor: Ingo Klöcker <dev@ingo-kloecker.de>
SPDX-License-Identifier: GPL-2.0-or-later
*/
......@@ -57,7 +59,7 @@ public:
class EMailValidator : public QValidator
{
public:
explicit EMailValidator(QObject *parent = nullptr) : QValidator(parent) {}
EMailValidator() : QValidator{} {}
State validate(QString &str, int &pos) const override
{
......@@ -69,50 +71,50 @@ public:
}
};
QValidator *regularExpressionValidator(Validation::Flags flags, const QString &regexp, QObject *parent)
std::shared_ptr<QValidator> regularExpressionValidator(Validation::Flags flags, const QString &regexp)
{
if (flags & Validation::Required) {
return new TrimmingValidator<QRegularExpressionValidator>{QRegularExpression{regexp}, parent};
return std::make_shared<TrimmingValidator<QRegularExpressionValidator>>(QRegularExpression{regexp});
} else {
return new TrimmingValidator<EmptyIsAcceptableValidator<QRegularExpressionValidator>>{QRegularExpression{regexp}, parent};
return std::make_shared<TrimmingValidator<EmptyIsAcceptableValidator<QRegularExpressionValidator>>>(QRegularExpression{regexp});
}
}
}
QValidator *Validation::email(Flags flags, QObject *parent)
std::shared_ptr<QValidator> Validation::email(Flags flags)
{
if (flags & Required) {
return new TrimmingValidator<EMailValidator>{parent};
return std::make_shared<TrimmingValidator<EMailValidator>>();
} else {
return new TrimmingValidator<EmptyIsAcceptableValidator<EMailValidator>>{parent};
return std::make_shared<TrimmingValidator<EmptyIsAcceptableValidator<EMailValidator>>>();
}
}
QValidator *Validation::email(const QString &addRX, Flags flags, QObject *parent)
std::shared_ptr<QValidator> Validation::email(const QString &addRX, Flags flags)
{
return new MultiValidator{email(flags), regularExpressionValidator(flags, addRX, nullptr), parent};
return MultiValidator::create({email(flags), regularExpressionValidator(flags, addRX)});
}
QValidator *Validation::pgpName(Flags flags, QObject *parent)
std::shared_ptr<QValidator> Validation::pgpName(Flags flags)
{
// this regular expression is modeled after gnupg/g10/keygen.c:ask_user_id:
static const QString name_rx{QLatin1String{"[^0-9<>][^<>@]{4,}"}};
return regularExpressionValidator(flags, name_rx, parent);
return regularExpressionValidator(flags, name_rx);
}
QValidator *Validation::pgpName(const QString &addRX, Flags flags, QObject *parent)
std::shared_ptr<QValidator> Validation::pgpName(const QString &addRX, Flags flags)
{
return new MultiValidator{pgpName(flags), regularExpressionValidator(flags, addRX, nullptr), parent};
return MultiValidator::create({pgpName(flags), regularExpressionValidator(flags, addRX)});
}
QValidator *Validation::simpleName(Flags flags, QObject *parent)
std::shared_ptr<QValidator> Validation::simpleName(Flags flags)
{
static const QString name_rx{QLatin1String{"[^<>@]*"}};
return regularExpressionValidator(flags, name_rx, parent);
return std::shared_ptr<QValidator>{regularExpressionValidator(flags, name_rx)};
}
QValidator *Validation::simpleName(const QString &additionalRegExp, Flags flags, QObject *parent)
std::shared_ptr<QValidator> Validation::simpleName(const QString &additionalRegExp, Flags flags)
{
return new MultiValidator{simpleName(flags), regularExpressionValidator(flags, additionalRegExp, nullptr), parent};
return MultiValidator::create({simpleName(flags), regularExpressionValidator(flags, additionalRegExp)});
}
......@@ -3,13 +3,16 @@
This file is part of Kleopatra, the KDE keymanager
SPDX-FileCopyrightText: 2008 Klarälvdalens Datakonsult AB
SPDX-FileCopyrightText: 2022 g10 Code GmbH
SPDX-FileContributor: Ingo Klöcker <dev@ingo-kloecker.de>
SPDX-License-Identifier: GPL-2.0-or-later
*/
#pragma once
class QObject;
#include <memory>
class QString;
class QValidator;
......@@ -23,31 +26,31 @@ enum Flags {
Required
};
QValidator *email(Flags flags = Required, QObject *parent = nullptr);
std::shared_ptr<QValidator> email(Flags flags = Required);
/**
* Creates a validator for the name part of the user ID of an OpenPGP key with
* restrictions that are necessary for usage with the edit-key interface.
*/
QValidator *pgpName(Flags flags = Required, QObject *parent = nullptr);
std::shared_ptr<QValidator> pgpName(Flags flags = Required);
/**
* Creates a validator for the name part of the user ID of an OpenPGP key with
* less restrictions than \ref pgpName.
*/
QValidator *simpleName(Flags flags = Required, QObject *parent = nullptr);
std::shared_ptr<QValidator> simpleName(Flags flags = Required);
QValidator *email(const QString &additionalRegExp, Flags flags = Required, QObject *parent = nullptr);
std::shared_ptr<QValidator> email(const QString &additionalRegExp, Flags flags = Required);
/**
* Creates a validator for the name part of the user ID of an OpenPGP key with
* restrictions that are necessary for usage with the edit-key interface, and
* with additional restrictions imposed by \p additionalRegExp.
*/
QValidator *pgpName(const QString &additionalRegExp, Flags flags = Required, QObject *parent = nullptr);
std::shared_ptr<QValidator> pgpName(const QString &additionalRegExp, Flags flags = Required);
/**
* Creates a validator for the name part of the user ID of an OpenPGP key with
* less restrictions than \ref pgpName, but with additional restrictions imposed
* by \p additionalRegExp.
*/
QValidator *simpleName(const QString &additionalRegExp, Flags flags = Required, QObject *parent = nullptr);
std::shared_ptr<QValidator> simpleName(const QString &additionalRegExp, Flags flags = Required);
}
}
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment