diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 94d7975f5..78fc84e93 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,409 +1,410 @@ # SPDX-FileCopyrightText: none # SPDX-License-Identifier: BSD-3-Clause add_subdirectory(icons) add_subdirectory(mimetypes) include_directories(${CMAKE_CURRENT_BINARY_DIR}) include_directories(${CMAKE_CURRENT_SOURCE_DIR}) if (NOT DISABLE_KWATCHGNUPG) add_subdirectory(kwatchgnupg) endif() add_subdirectory(libkleopatraclient) add_subdirectory(conf) add_subdirectory(kconf_update) if(WIN32) set(_kleopatra_extra_uiserver_SRCS uiserver/uiserver_win.cpp) set(_kleopatra_extra_SRCS utils/gnupg-registry.c selftest/registrycheck.cpp utils/windowsprocessdevice.cpp utils/userinfo_win.cpp ) else() set(_kleopatra_extra_uiserver_SRCS uiserver/uiserver_unix.cpp) set(_kleopatra_extra_SRCS) endif() set(_kleopatra_uiserver_SRCS uiserver/sessiondata.cpp uiserver/uiserver.cpp ${_kleopatra_extra_uiserver_SRCS} uiserver/assuanserverconnection.cpp uiserver/echocommand.cpp uiserver/decryptverifycommandemailbase.cpp uiserver/decryptverifycommandfilesbase.cpp uiserver/signcommand.cpp uiserver/signencryptfilescommand.cpp uiserver/prepencryptcommand.cpp uiserver/prepsigncommand.cpp uiserver/encryptcommand.cpp uiserver/selectcertificatecommand.cpp uiserver/importfilescommand.cpp uiserver/createchecksumscommand.cpp uiserver/verifychecksumscommand.cpp selftest/uiservercheck.cpp ) if(ASSUAN2_FOUND) include_directories(${ASSUAN2_INCLUDES}) set(_kleopatra_uiserver_extra_libs ${ASSUAN2_LIBRARIES}) else() include_directories(${ASSUAN_INCLUDES}) if(WIN32) set(_kleopatra_uiserver_extra_libs ${ASSUAN_VANILLA_LIBRARIES}) else() set(_kleopatra_uiserver_extra_libs ${ASSUAN_PTHREAD_LIBRARIES}) endif() endif() if(HAVE_GPG_ERR_SOURCE_KLEO) add_definitions(-DGPG_ERR_SOURCE_DEFAULT=GPG_ERR_SOURCE_KLEO) add_definitions(-DGPGMEPP_ERR_SOURCE_DEFAULT=GPG_ERR_SOURCE_KLEO) else() add_definitions(-DGPG_ERR_SOURCE_DEFAULT=GPG_ERR_SOURCE_USER_1) add_definitions(-DGPGMEPP_ERR_SOURCE_DEFAULT=GPG_ERR_SOURCE_USER_1) endif() if(KF5IdentityManagement_FOUND AND KF5MailTransport_FOUND AND KF5MailTransportAkonadi_FOUND) set(_kleopatra_mail_libs KF5::IdentityManagement # Export OpenPGP keys using WKS KF5::MailTransport KF5::MailTransportAkonadi ) add_definitions(-DMAILAKONADI_ENABLED) endif() ki18n_wrap_ui(_kleopatra_uiserver_SRCS crypto/gui/signingcertificateselectionwidget.ui) set(_kleopatra_SRCS utils/accessibility.cpp utils/gui-helper.cpp utils/filedialog.cpp utils/kdpipeiodevice.cpp utils/headerview.cpp utils/scrollarea.cpp utils/dragqueen.cpp utils/multivalidator.cpp utils/systemtrayicon.cpp utils/path-helper.cpp utils/input.cpp utils/output.cpp utils/validation.cpp utils/wsastarter.cpp utils/iodevicelogger.cpp utils/log.cpp utils/action_data.cpp utils/types.cpp utils/archivedefinition.cpp utils/auditlog.cpp utils/clipboardmenu.cpp utils/kuniqueservice.cpp utils/tags.cpp utils/writecertassuantransaction.cpp utils/keyparameters.cpp utils/userinfo.cpp utils/keys.cpp selftest/selftest.cpp selftest/enginecheck.cpp selftest/gpgconfcheck.cpp selftest/gpgagentcheck.cpp selftest/libkleopatrarccheck.cpp selftest/compliancecheck.cpp ${_kleopatra_extra_SRCS} view/errorlabel.cpp view/formtextinput.cpp view/htmllabel.cpp view/keylistcontroller.cpp view/keytreeview.cpp view/searchbar.cpp view/smartcardwidget.cpp view/openpgpkeycardwidget.cpp view/padwidget.cpp view/pgpcardwidget.cpp view/pivcardwidget.cpp view/p15cardwidget.cpp view/netkeywidget.cpp view/nullpinwidget.cpp view/tabwidget.cpp view/keycacheoverlay.cpp view/urllabel.cpp view/waitwidget.cpp view/welcomewidget.cpp dialogs/certificateselectiondialog.cpp dialogs/certifywidget.cpp dialogs/expirydialog.cpp dialogs/lookupcertificatesdialog.cpp dialogs/ownertrustdialog.cpp dialogs/selftestdialog.cpp dialogs/certifycertificatedialog.cpp dialogs/revokecertificationwidget.cpp dialogs/revokecertificationdialog.cpp dialogs/adduseriddialog.cpp dialogs/deletecertificatesdialog.cpp dialogs/setinitialpindialog.cpp dialogs/certificatedetailsdialog.cpp dialogs/certificatedetailswidget.cpp dialogs/trustchainwidget.cpp dialogs/weboftrustwidget.cpp dialogs/weboftrustdialog.cpp dialogs/exportdialog.cpp dialogs/subkeyswidget.cpp dialogs/gencardkeydialog.cpp dialogs/updatenotification.cpp dialogs/pivcardapplicationadministrationkeyinputdialog.cpp dialogs/certificatedetailsinputwidget.cpp dialogs/createcsrforcardkeydialog.cpp dialogs/groupdetailsdialog.cpp dialogs/editgroupdialog.cpp dialogs/revokekeydialog.cpp + dialogs/nameandemailwidget.cpp crypto/controller.cpp crypto/certificateresolver.cpp crypto/sender.cpp crypto/recipient.cpp crypto/task.cpp crypto/taskcollection.cpp crypto/decryptverifytask.cpp crypto/decryptverifyemailcontroller.cpp crypto/decryptverifyfilescontroller.cpp crypto/autodecryptverifyfilescontroller.cpp crypto/encryptemailtask.cpp crypto/encryptemailcontroller.cpp crypto/newsignencryptemailcontroller.cpp crypto/signencrypttask.cpp crypto/signencryptfilescontroller.cpp crypto/signemailtask.cpp crypto/signemailcontroller.cpp crypto/createchecksumscontroller.cpp crypto/verifychecksumscontroller.cpp crypto/checksumsutils_p.cpp crypto/gui/wizard.cpp crypto/gui/wizardpage.cpp crypto/gui/certificateselectionline.cpp crypto/gui/certificatelineedit.cpp crypto/gui/signingcertificateselectionwidget.cpp crypto/gui/signingcertificateselectiondialog.cpp crypto/gui/resultitemwidget.cpp crypto/gui/resultlistwidget.cpp crypto/gui/resultpage.cpp crypto/gui/newresultpage.cpp crypto/gui/signencryptfileswizard.cpp crypto/gui/signencryptemailconflictdialog.cpp crypto/gui/decryptverifyoperationwidget.cpp crypto/gui/decryptverifyfileswizard.cpp crypto/gui/decryptverifyfilesdialog.cpp crypto/gui/objectspage.cpp crypto/gui/resolverecipientspage.cpp crypto/gui/signerresolvepage.cpp crypto/gui/encryptemailwizard.cpp crypto/gui/signemailwizard.cpp crypto/gui/signencryptwidget.cpp crypto/gui/signencryptwizard.cpp crypto/gui/unknownrecipientwidget.cpp crypto/gui/verifychecksumsdialog.cpp commands/command.cpp commands/gnupgprocesscommand.cpp commands/detailscommand.cpp commands/exportcertificatecommand.cpp commands/exportgroupscommand.cpp commands/importcertificatescommand.cpp commands/importcertificatefromfilecommand.cpp commands/importcertificatefromclipboardcommand.cpp commands/importcertificatefromdatacommand.cpp commands/importcertificatefromkeyservercommand.cpp commands/lookupcertificatescommand.cpp commands/reloadkeyscommand.cpp commands/refreshcertificatecommand.cpp commands/refreshx509certscommand.cpp commands/refreshopenpgpcertscommand.cpp commands/deletecertificatescommand.cpp commands/decryptverifyfilescommand.cpp commands/signencryptfilescommand.cpp commands/signencryptfoldercommand.cpp commands/encryptclipboardcommand.cpp commands/signclipboardcommand.cpp commands/decryptverifyclipboardcommand.cpp commands/clearcrlcachecommand.cpp commands/dumpcrlcachecommand.cpp commands/dumpcertificatecommand.cpp commands/importcrlcommand.cpp commands/changeexpirycommand.cpp commands/changeownertrustcommand.cpp commands/changeroottrustcommand.cpp commands/changepassphrasecommand.cpp commands/certifycertificatecommand.cpp commands/revokecertificationcommand.cpp commands/selftestcommand.cpp commands/exportsecretkeycommand.cpp commands/exportsecretkeycommand_old.cpp commands/exportsecretsubkeycommand.cpp commands/exportopenpgpcertstoservercommand.cpp commands/exportopenpgpcerttoprovidercommand.cpp commands/adduseridcommand.cpp commands/newcertificatecommand.cpp commands/setinitialpincommand.cpp commands/learncardkeyscommand.cpp commands/checksumcreatefilescommand.cpp commands/checksumverifyfilescommand.cpp commands/exportpaperkeycommand.cpp commands/importpaperkeycommand.cpp commands/genrevokecommand.cpp commands/keytocardcommand.cpp commands/cardcommand.cpp commands/pivgeneratecardkeycommand.cpp commands/changepincommand.cpp commands/authenticatepivcardapplicationcommand.cpp commands/setpivcardapplicationadministrationkeycommand.cpp commands/certificatetopivcardcommand.cpp commands/importcertificatefrompivcardcommand.cpp commands/createopenpgpkeyfromcardkeyscommand.cpp commands/createcsrforcardkeycommand.cpp commands/revokekeycommand.cpp commands/revokeuseridcommand.cpp ${_kleopatra_uiserver_files} conf/configuredialog.cpp conf/groupsconfigdialog.cpp conf/groupsconfigpage.cpp conf/groupsconfigwidget.cpp newcertificatewizard/advancedsettingsdialog.cpp newcertificatewizard/chooseprotocolpage.cpp newcertificatewizard/enterdetailspage.cpp newcertificatewizard/keyalgo.cpp newcertificatewizard/keycreationpage.cpp newcertificatewizard/listwidget.cpp newcertificatewizard/newcertificatewizard.cpp newcertificatewizard/resultpage.cpp newcertificatewizard/wizardpage.cpp smartcard/readerstatus.cpp smartcard/card.cpp smartcard/openpgpcard.cpp smartcard/netkeycard.cpp smartcard/pivcard.cpp smartcard/p15card.cpp smartcard/keypairinfo.cpp smartcard/utils.cpp smartcard/deviceinfowatcher.cpp accessibility/accessiblerichtextlabel.cpp accessibility/accessiblewidgetfactory.cpp aboutdata.cpp systrayicon.cpp kleopatraapplication.cpp mainwindow.cpp main.cpp kleopatra.qrc ) if(WIN32) configure_file (versioninfo.rc.in versioninfo.rc) set(_kleopatra_SRCS ${CMAKE_CURRENT_BINARY_DIR}/versioninfo.rc ${_kleopatra_SRCS}) endif() set (_kleopatra_SRCS conf/kleopageconfigdialog.cpp ${_kleopatra_SRCS}) ecm_qt_declare_logging_category(_kleopatra_SRCS HEADER kleopatra_debug.h IDENTIFIER KLEOPATRA_LOG CATEGORY_NAME org.kde.pim.kleopatra DESCRIPTION "kleopatra (kleopatra)" OLD_CATEGORY_NAMES log_kleopatra EXPORT KLEOPATRA ) if(KLEO_MODEL_TEST) add_definitions(-DKLEO_MODEL_TEST) set(_kleopatra_SRCS ${_kleopatra_SRCS} models/modeltest.cpp) endif() ki18n_wrap_ui(_kleopatra_SRCS dialogs/ownertrustdialog.ui dialogs/selectchecklevelwidget.ui dialogs/selftestdialog.ui dialogs/setinitialpindialog.ui dialogs/trustchainwidget.ui dialogs/subkeyswidget.ui newcertificatewizard/listwidget.ui ) kconfig_add_kcfg_files(_kleopatra_SRCS kcfg/tooltippreferences.kcfgc kcfg/emailoperationspreferences.kcfgc kcfg/fileoperationspreferences.kcfgc kcfg/smimevalidationpreferences.kcfgc kcfg/tagspreferences.kcfgc kcfg/settings.kcfgc ) file(GLOB ICONS_SRCS "${CMAKE_CURRENT_SOURCE_DIR}/icons/*-apps-kleopatra.png") ecm_add_app_icon(_kleopatra_SRCS ICONS ${ICONS_SRCS}) add_executable(kleopatra_bin ${_kleopatra_SRCS} ${_kleopatra_uiserver_SRCS}) # For the ConfigureDialog & KCMs target_link_libraries(kleopatra_bin kcm_kleopatra_static) #if (COMPILE_WITH_UNITY_CMAKE_SUPPORT) # set_target_properties(kleopatra_bin PROPERTIES UNITY_BUILD ON) #endif() set_target_properties(kleopatra_bin PROPERTIES OUTPUT_NAME kleopatra) if (WIN32) set(_kleopatra_platform_libs "secur32") endif () target_link_libraries(kleopatra_bin Gpgmepp QGpgme ${_kleopatra_extra_libs} KF5::Libkleo KF5::Mime KF5::I18n KF5::XmlGui KF5::IconThemes KF5::WindowSystem KF5::CoreAddons KF5::ItemModels KF5::Crash ${_kleopatra_mail_libs} Qt${QT_MAJOR_VERSION}::Network Qt${QT_MAJOR_VERSION}::PrintSupport # Printing secret keys ${_kleopatra_uiserver_extra_libs} ${_kleopatra_dbusaddons_libs} kleopatraclientcore ${_kleopatra_platform_libs} ) install(TARGETS kleopatra_bin ${KDE_INSTALL_TARGETS_DEFAULT_ARGS}) install( PROGRAMS data/org.kde.kleopatra.desktop data/kleopatra_import.desktop DESTINATION ${KDE_INSTALL_APPDIR} ) install(FILES data/org.kde.kleopatra.appdata.xml DESTINATION ${KDE_INSTALL_METAINFODIR}) install( PROGRAMS data/kleopatra_signencryptfiles.desktop data/kleopatra_signencryptfolders.desktop data/kleopatra_decryptverifyfiles.desktop data/kleopatra_decryptverifyfolders.desktop DESTINATION ${KDE_INSTALL_DATADIR}/kio/servicemenus ) diff --git a/src/dialogs/adduseriddialog.cpp b/src/dialogs/adduseriddialog.cpp index dd9d7c1fa..620b416b3 100644 --- a/src/dialogs/adduseriddialog.cpp +++ b/src/dialogs/adduseriddialog.cpp @@ -1,268 +1,184 @@ /* -*- mode: c++; c-basic-offset:4 -*- dialogs/adduseriddialog.cpp 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 SPDX-License-Identifier: GPL-2.0-or-later */ #include #include "adduseriddialog.h" +#include "nameandemailwidget.h" + #include "utils/accessibility.h" #include "utils/scrollarea.h" -#include "view/errorlabel.h" -#include "view/formtextinput.h" #include "view/htmllabel.h" -#include - #include #include #include #include #include #include -#include #include -#include -#include #include #include "kleopatra_debug.h" using namespace Kleo; -namespace -{ -QString buildUserId(const QString &name, const QString &email) -{ - if (name.isEmpty()) { - return email; - } else if (email.isEmpty()) { - return name; - } else { - return QStringLiteral("%1 <%2>").arg(name, email); - } -} -} - class AddUserIDDialog::Private { friend class ::Kleo::AddUserIDDialog; AddUserIDDialog *const q; struct { ScrollArea *scrollArea; - std::unique_ptr> nameInput; - std::unique_ptr> emailInput; + NameAndEmailWidget *nameAndEmail; HtmlLabel *resultLabel; QDialogButtonBox *buttonBox; } ui; LabelHelper labelHelper; public: explicit Private(AddUserIDDialog *qq) : q{qq} { q->setWindowTitle(i18nc("title:window", "Add User ID")); const KConfigGroup config{KSharedConfig::openConfig(), "CertificateCreationWizard"}; const auto attrOrder = config.readEntry("OpenPGPAttributeOrder", QStringList{}); const auto nameIsRequired = attrOrder.contains(QLatin1String{"NAME!"}, Qt::CaseInsensitive); const auto emailIsRequired = attrOrder.contains(QLatin1String{"EMAIL!"}, Qt::CaseInsensitive); auto mainLayout = new QVBoxLayout{q}; { const auto infoText = nameIsRequired || emailIsRequired ? i18n("Enter a name and an email address to use for the user ID.") : i18n("Enter a name and/or an email address to use for the user ID."); auto label = new QLabel{infoText, q}; label->setWordWrap(true); mainLayout->addWidget(label); } mainLayout->addWidget(new KSeparator{Qt::Horizontal, q}); ui.scrollArea = new ScrollArea{q}; ui.scrollArea->setFocusPolicy(Qt::NoFocus); ui.scrollArea->setFrameStyle(QFrame::NoFrame); ui.scrollArea->setBackgroundRole(q->backgroundRole()); ui.scrollArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); ui.scrollArea->setSizeAdjustPolicy(QScrollArea::AdjustToContents); auto scrollAreaLayout = qobject_cast(ui.scrollArea->widget()->layout()); scrollAreaLayout->setContentsMargins(0, 0, 0, 0); - { - ui.nameInput = FormTextInput::create(q); - ui.nameInput->setLabelText(i18nc("@label", "Name")); - ui.nameInput->setIsRequired(nameIsRequired); - ui.nameInput->setValueRequiredErrorMessage(i18n("Enter a name.")); - const auto regexp = config.readEntry("NAME_regex"); - if (regexp.isEmpty()) { - 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.")); - ui.nameInput->setInvalidEntryErrorMessage( - i18n("The name must not include <, >, and @."), - i18nc("text for screen readers", - "The name must not include less-than sign, greater-than sign, and at sign.")); - } else { - 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", - "Must be in the format required by your organization and " - "must not include less-than sign, greater-than sign, and at sign.")); - ui.nameInput->setInvalidEntryErrorMessage( - i18n("The name must be in the format required by your organization and " - "it must not include <, >, and @."), - i18nc("text for screen readers", - "The name must be in the format required by your organization and " - "it must not include less-than sign, greater-than sign, and at sign.")); - } - - scrollAreaLayout->addWidget(ui.nameInput->label()); - scrollAreaLayout->addWidget(ui.nameInput->hintLabel()); - scrollAreaLayout->addWidget(ui.nameInput->errorLabel()); - scrollAreaLayout->addWidget(ui.nameInput->widget()); - } - connect(ui.nameInput->widget(), &QLineEdit::textChanged, - q, [this]() { updateResultLabel(); }); - - { - ui.emailInput = FormTextInput::create(q); - ui.emailInput->setLabelText(i18nc("@label", "Email address")); - ui.emailInput->setIsRequired(emailIsRequired); - ui.emailInput->setValueRequiredErrorMessage(i18n("Enter an email address.")); - const auto regexp = config.readEntry(QLatin1String("EMAIL_regex")); - if (regexp.isEmpty()) { - 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(Validation::email(regexp, Validation::Optional)); - ui.emailInput->setHint(i18n( - "Must be in the format required by your organization")); - ui.emailInput->setInvalidEntryErrorMessage(i18n( - "Enter an email address in the correct format required by your organization.")); - } - - scrollAreaLayout->addWidget(ui.emailInput->label()); - scrollAreaLayout->addWidget(ui.emailInput->hintLabel()); - scrollAreaLayout->addWidget(ui.emailInput->errorLabel()); - scrollAreaLayout->addWidget(ui.emailInput->widget()); - } - connect(ui.emailInput->widget(), &QLineEdit::textChanged, - q, [this]() { updateResultLabel(); }); + ui.nameAndEmail = new NameAndEmailWidget{q}; + ui.nameAndEmail->setNameIsRequired(nameIsRequired); + ui.nameAndEmail->setNamePattern(config.readEntry("NAME_regex")); + ui.nameAndEmail->setEmailIsRequired(emailIsRequired); + ui.nameAndEmail->setEmailPattern(config.readEntry("EMAIL_regex")); + scrollAreaLayout->addWidget(ui.nameAndEmail); scrollAreaLayout->addWidget(new KSeparator{Qt::Horizontal, q}); { ui.resultLabel = new HtmlLabel{q}; ui.resultLabel->setWordWrap(true); ui.resultLabel->setFocusPolicy(Qt::ClickFocus); labelHelper.addLabel(ui.resultLabel); scrollAreaLayout->addWidget(ui.resultLabel); } scrollAreaLayout->addStretch(1); mainLayout->addWidget(ui.scrollArea); mainLayout->addWidget(new KSeparator{Qt::Horizontal, q}); ui.buttonBox = new QDialogButtonBox{QDialogButtonBox::Ok | QDialogButtonBox::Cancel, q}; mainLayout->addWidget(ui.buttonBox); + connect(ui.nameAndEmail, &NameAndEmailWidget::userIDChanged, q, [this]() { + updateResultLabel(); + }); connect(ui.buttonBox, &QDialogButtonBox::accepted, q, [this]() { checkAccept(); }); connect(ui.buttonBox, &QDialogButtonBox::rejected, q, &QDialog::reject); updateResultLabel(); } - QString name() const - { - return ui.nameInput->widget()->text().trimmed(); - } - - QString email() const - { - return ui.emailInput->widget()->text().trimmed(); - } - private: void checkAccept() { QStringList errors; - if (q->userID().isEmpty() - && !ui.nameInput->isRequired() && !ui.emailInput->isRequired()) { + if (ui.nameAndEmail->userID().isEmpty() + && !ui.nameAndEmail->nameIsRequired() && !ui.nameAndEmail->emailIsRequired()) { errors.push_back(i18n("Enter a name or an email address.")); } - const auto nameError = ui.nameInput->currentError(); + const auto nameError = ui.nameAndEmail->nameError(); if (!nameError.isEmpty()) { errors.push_back(nameError); } - const auto emailError = ui.emailInput->currentError(); + const auto emailError = ui.nameAndEmail->emailError(); if (!emailError.isEmpty()) { errors.push_back(emailError); } if (errors.size() > 1) { KMessageBox::errorList(q, i18n("There is a problem."), errors); } else if (!errors.empty()) { KMessageBox::error(q, errors.first()); } else { q->accept(); } } void updateResultLabel() { ui.resultLabel->setHtml(i18nc("@info", "
This is how the new user ID will be stored in the certificate:
" "
%1
", - buildUserId(name(), email()).toHtmlEscaped())); + ui.nameAndEmail->userID().toHtmlEscaped())); } }; AddUserIDDialog::AddUserIDDialog(QWidget *parent, Qt::WindowFlags f) : QDialog{parent, f} , d(new Private{this}) { } AddUserIDDialog::~AddUserIDDialog() = default; void AddUserIDDialog::setName(const QString &name) { - d->ui.nameInput->widget()->setText(name); + d->ui.nameAndEmail->setName(name); } QString AddUserIDDialog::name() const { - return d->name(); + return d->ui.nameAndEmail->name(); } void AddUserIDDialog::setEmail(const QString &email) { - d->ui.emailInput->widget()->setText(email); + d->ui.nameAndEmail->setEmail(email); } QString AddUserIDDialog::email() const { - return d->email(); + return d->ui.nameAndEmail->email(); } QString AddUserIDDialog::userID() const { - return buildUserId(name(), email()); + return d->ui.nameAndEmail->userID(); } diff --git a/src/dialogs/nameandemailwidget.cpp b/src/dialogs/nameandemailwidget.cpp new file mode 100644 index 000000000..c1c8111f3 --- /dev/null +++ b/src/dialogs/nameandemailwidget.cpp @@ -0,0 +1,214 @@ +/* -*- mode: c++; c-basic-offset:4 -*- + dialogs/nameandemailwidget.cpp + + 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 + + SPDX-License-Identifier: GPL-2.0-or-later +*/ + +#include + +#include "nameandemailwidget.h" + +#include "view/errorlabel.h" +#include "view/formtextinput.h" + +#include + +#include + +#include +#include +#include + +#include "kleopatra_debug.h" + +using namespace Kleo; + +namespace +{ +QString buildUserId(const QString &name, const QString &email) +{ + if (name.isEmpty()) { + return email; + } else if (email.isEmpty()) { + return name; + } else { + return QStringLiteral("%1 <%2>").arg(name, email); + } +} +} + +class NameAndEmailWidget::Private +{ + NameAndEmailWidget *const q; + +public: + struct { + std::unique_ptr> nameInput; + std::unique_ptr> emailInput; + } ui; + + explicit Private(NameAndEmailWidget *qq) + : q{qq} + { + auto mainLayout = new QVBoxLayout{q}; + + { + ui.nameInput = FormTextInput::create(q); + ui.nameInput->setLabelText(i18nc("@label", "Name")); + ui.nameInput->setValueRequiredErrorMessage(i18n("Enter a name.")); + setNamePattern({}); + + mainLayout->addWidget(ui.nameInput->label()); + mainLayout->addWidget(ui.nameInput->hintLabel()); + mainLayout->addWidget(ui.nameInput->errorLabel()); + mainLayout->addWidget(ui.nameInput->widget()); + } + connect(ui.nameInput->widget(), &QLineEdit::textChanged, + q, [this]() { Q_EMIT q->userIDChanged(); }); + + { + ui.emailInput = FormTextInput::create(q); + ui.emailInput->setLabelText(i18nc("@label", "Email address")); + ui.emailInput->setValueRequiredErrorMessage(i18n("Enter an email address.")); + setEmailPattern({}); + + mainLayout->addWidget(ui.emailInput->label()); + mainLayout->addWidget(ui.emailInput->hintLabel()); + mainLayout->addWidget(ui.emailInput->errorLabel()); + mainLayout->addWidget(ui.emailInput->widget()); + } + connect(ui.emailInput->widget(), &QLineEdit::textChanged, + q, [this]() { Q_EMIT q->userIDChanged(); }); + } + + + void setNamePattern(const QString ®exp) + { + if (regexp.isEmpty()) { + 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.")); + ui.nameInput->setInvalidEntryErrorMessage( + i18n("The name must not include <, >, and @."), + i18nc("text for screen readers", + "The name must not include less-than sign, greater-than sign, and at sign.")); + } else { + 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", + "Must be in the format required by your organization and " + "must not include less-than sign, greater-than sign, and at sign.")); + ui.nameInput->setInvalidEntryErrorMessage( + i18n("The name must be in the format required by your organization and " + "it must not include <, >, and @."), + i18nc("text for screen readers", + "The name must be in the format required by your organization and " + "it must not include less-than sign, greater-than sign, and at sign.")); + } + } + + void setEmailPattern(const QString ®exp) + { + if (regexp.isEmpty()) { + 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(Validation::email(regexp, Validation::Optional)); + ui.emailInput->setHint(i18n( + "Must be in the format required by your organization")); + ui.emailInput->setInvalidEntryErrorMessage(i18n( + "Enter an email address in the correct format required by your organization.")); + } + } + + QString name() const + { + return ui.nameInput->widget()->text().trimmed(); + } + + QString email() const + { + return ui.emailInput->widget()->text().trimmed(); + } +}; + +NameAndEmailWidget::NameAndEmailWidget(QWidget *parent, Qt::WindowFlags f) + : QWidget{parent, f} + , d(new Private{this}) +{ +} + +NameAndEmailWidget::~NameAndEmailWidget() = default; + +void NameAndEmailWidget::setName(const QString &name) +{ + d->ui.nameInput->widget()->setText(name); +} + +QString NameAndEmailWidget::name() const +{ + return d->name(); +} + +void NameAndEmailWidget::setNameIsRequired(bool required) +{ + d->ui.nameInput->setIsRequired(required); +} + +bool NameAndEmailWidget::nameIsRequired() const +{ + return d->ui.nameInput->isRequired(); +} + +void NameAndEmailWidget::setNamePattern(const QString &pattern) +{ + d->setNamePattern(pattern); +} + +QString NameAndEmailWidget::nameError() const +{ + return d->ui.nameInput->currentError(); +} + +void NameAndEmailWidget::setEmail(const QString &email) +{ + d->ui.emailInput->widget()->setText(email); +} + +QString NameAndEmailWidget::email() const +{ + return d->email(); +} + +void NameAndEmailWidget::setEmailIsRequired(bool required) +{ + d->ui.emailInput->setIsRequired(required); +} + +bool NameAndEmailWidget::emailIsRequired() const +{ + return d->ui.emailInput->isRequired(); +} + +void NameAndEmailWidget::setEmailPattern(const QString &pattern) +{ + d->setEmailPattern(pattern); +} + +QString NameAndEmailWidget::emailError() const +{ + return d->ui.emailInput->currentError(); +} + +QString NameAndEmailWidget::userID() const +{ + return buildUserId(name(), email()); +} diff --git a/src/dialogs/nameandemailwidget.h b/src/dialogs/nameandemailwidget.h new file mode 100644 index 000000000..74f420110 --- /dev/null +++ b/src/dialogs/nameandemailwidget.h @@ -0,0 +1,55 @@ +/* -*- mode: c++; c-basic-offset:4 -*- + dialogs/nameandemailwidget.h + + 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 + + SPDX-License-Identifier: GPL-2.0-or-later +*/ + +#pragma once + +#include + +#include + +namespace Kleo +{ + +class NameAndEmailWidget : public QWidget +{ + Q_OBJECT +public: + explicit NameAndEmailWidget(QWidget *parent = nullptr, Qt::WindowFlags f = {}); + ~NameAndEmailWidget() override; + + void setName(const QString &name); + QString name() const; + void setNameIsRequired(bool required); + bool nameIsRequired() const; + void setNamePattern(const QString &pattern); + QString nameError() const; + + void setEmail(const QString &email); + QString email() const; + void setEmailIsRequired(bool required); + bool emailIsRequired() const; + void setEmailPattern(const QString &pattern); + QString emailError() const; + + /** + * Returns the user ID built from the entered name and/or email address. + */ + QString userID() const; + +Q_SIGNALS: + void userIDChanged() const; + +private: + class Private; + const std::unique_ptr d; +}; + +} // namespace Kleo