Page MenuHome GnuPG

No OneTemporary

diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index f11662766..7b444b140 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -1,646 +1,644 @@
# 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)
if(WIN32)
set(_kleopatra_extra_uiserver_SRCS uiserver/uiserver_win.cpp)
set(_kleopatra_extra_SRCS
pics/gpg4win.qrc
selftest/registrycheck.cpp selftest/registrycheck.h
utils/gnupg-registry.c
utils/userinfo_win.cpp
utils/winapi-helpers.cpp utils/winapi-helpers.h
utils/windowsprocessdevice.cpp utils/windowsprocessdevice.h
versioninfo.rc kleopatra.w32-manifest
)
else()
set(_kleopatra_extra_uiserver_SRCS uiserver/uiserver_unix.cpp)
set(_kleopatra_extra_SRCS)
endif()
set(_kleopatra_uiserver_SRCS
${_kleopatra_extra_uiserver_SRCS}
selftest/uiservercheck.cpp selftest/uiservercheck.h
uiserver/assuanserverconnection.cpp uiserver/assuanserverconnection.h
uiserver/createchecksumscommand.cpp uiserver/createchecksumscommand.h
uiserver/decryptverifycommandemailbase.cpp uiserver/decryptverifycommandemailbase.h
uiserver/decryptverifycommandfilesbase.cpp uiserver/decryptverifycommandfilesbase.h
uiserver/echocommand.cpp uiserver/echocommand.h
uiserver/encryptcommand.cpp uiserver/encryptcommand.h
uiserver/importfilescommand.cpp uiserver/importfilescommand.h
uiserver/prepencryptcommand.cpp uiserver/prepencryptcommand.h
uiserver/prepsigncommand.cpp uiserver/prepsigncommand.h
uiserver/selectcertificatecommand.cpp
uiserver/sessiondata.cpp uiserver/sessiondata.h
uiserver/signcommand.cpp uiserver/signcommand.h
uiserver/signencryptfilescommand.cpp
uiserver/uiserver.cpp
uiserver/verifychecksumscommand.cpp uiserver/verifychecksumscommand.h
)
set(_kleopatra_uiserver_extra_libs LibAssuan::LibAssuan LibGpgError::LibGpgError)
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(KPim6IdentityManagementCore_FOUND AND KPim6MailTransport_FOUND AND KPim6AkonadiMime_FOUND)
set(_kleopatra_mail_libs
KPim6::IdentityManagementCore # Export OpenPGP keys using WKS
KPim6::MailTransport
KPim6::AkonadiMime
)
add_definitions(-DMAILAKONADI_ENABLED)
endif()
ki18n_wrap_ui(_kleopatra_uiserver_SRCS crypto/gui/signingcertificateselectionwidget.ui)
set(_kleopatra_SRCS
${_kleopatra_extra_SRCS}
accessibility/accessiblelink.cpp
accessibility/accessiblelink_p.h
accessibility/accessiblerichtextlabel.cpp
accessibility/accessiblerichtextlabel_p.h
accessibility/accessiblevaluelabel.cpp
accessibility/accessiblevaluelabel_p.h
accessibility/accessiblewidgetfactory.cpp
accessibility/accessiblewidgetfactory.h
commands/addadskcommand.cpp
commands/addadskcommand.h
commands/addsubkeycommand.cpp
commands/addsubkeycommand.h
commands/adduseridcommand.cpp
commands/adduseridcommand.h
commands/authenticatepivcardapplicationcommand.cpp
commands/authenticatepivcardapplicationcommand.h
commands/cardcommand.cpp
commands/cardcommand.h
commands/certificatetocardcommand.cpp
commands/certificatetocardcommand.h
commands/certificatetopivcardcommand.cpp
commands/certificatetopivcardcommand.h
commands/certifycertificatecommand.cpp
commands/certifycertificatecommand.h
commands/certifygroupcommand.cpp
commands/certifygroupcommand.h
commands/changeexpirycommand.cpp
commands/changeexpirycommand.h
commands/changeownertrustcommand.cpp
commands/changeownertrustcommand.h
commands/changepassphrasecommand.cpp
commands/changepassphrasecommand.h
commands/changepincommand.cpp
commands/changepincommand.h
commands/changeroottrustcommand.cpp
commands/changeroottrustcommand.h
commands/checksumcreatefilescommand.cpp
commands/checksumcreatefilescommand.h
commands/checksumverifyfilescommand.cpp
commands/checksumverifyfilescommand.h
commands/clearcrlcachecommand.cpp
commands/clearcrlcachecommand.h
commands/command.cpp
commands/command.h
commands/createcsrforcardkeycommand.cpp
commands/createcsrforcardkeycommand.h
commands/creategroupcommand.cpp
commands/creategroupcommand.h
commands/createopenpgpkeyfromcardkeyscommand.cpp
commands/createopenpgpkeyfromcardkeyscommand.h
commands/decryptverifyclipboardcommand.cpp
commands/decryptverifyclipboardcommand.h
commands/decryptverifyfilescommand.cpp
commands/decryptverifyfilescommand.h
commands/deletecertificatescommand.cpp
commands/deletecertificatescommand.h
commands/detailscommand.cpp
commands/detailscommand.h
commands/dumpcertificatecommand.cpp
commands/dumpcertificatecommand.h
commands/dumpcrlcachecommand.cpp
commands/dumpcrlcachecommand.h
commands/encryptclipboardcommand.cpp
commands/encryptclipboardcommand.h
commands/exportcertificatecommand.cpp
commands/exportcertificatecommand.h
commands/exportgroupscommand.cpp
commands/exportgroupscommand.h
commands/exportopenpgpcertstoservercommand.cpp
commands/exportopenpgpcertstoservercommand.h
commands/exportopenpgpcerttoprovidercommand.cpp
commands/exportopenpgpcerttoprovidercommand.h
commands/exportpaperkeycommand.cpp
commands/exportpaperkeycommand.h
commands/exportsecretkeycommand.cpp
commands/exportsecretkeycommand.h
commands/exportsecretsubkeycommand.cpp
commands/exportsecretsubkeycommand.h
commands/generateopenpgpcardkeysandcertificatecommand.cpp
commands/generateopenpgpcardkeysandcertificatecommand.h
commands/genrevokecommand.cpp
commands/genrevokecommand.h
commands/gnupgprocesscommand.cpp
commands/gnupgprocesscommand.h
commands/importcertificatefromclipboardcommand.cpp
commands/importcertificatefromclipboardcommand.h
commands/importcertificatefromdatacommand.cpp
commands/importcertificatefromdatacommand.h
commands/importcertificatefromfilecommand.cpp
commands/importcertificatefromfilecommand.h
commands/importcertificatefromkeyservercommand.cpp
commands/importcertificatefromkeyservercommand.h
commands/importcertificatefrompivcardcommand.cpp
commands/importcertificatefrompivcardcommand.h
commands/importcertificatescommand.cpp
commands/importcertificatescommand.h
commands/importcrlcommand.cpp
commands/importcrlcommand.h
commands/importpaperkeycommand.cpp
commands/importpaperkeycommand.h
commands/keytocardcommand.cpp
commands/keytocardcommand.h
commands/lookupcertificatescommand.cpp
commands/lookupcertificatescommand.h
commands/newcertificatesigningrequestcommand.cpp
commands/newcertificatesigningrequestcommand.h
commands/newopenpgpcertificatecommand.cpp
commands/newopenpgpcertificatecommand.h
commands/openpgpgeneratecardkeycommand.cpp
commands/openpgpgeneratecardkeycommand.h
commands/pivgeneratecardkeycommand.cpp
commands/pivgeneratecardkeycommand.h
commands/refreshcertificatescommand.cpp
commands/refreshcertificatescommand.h
commands/refreshopenpgpcertscommand.cpp
commands/refreshopenpgpcertscommand.h
commands/refreshx509certscommand.cpp
commands/refreshx509certscommand.h
commands/reloadkeyscommand.cpp
commands/reloadkeyscommand.h
commands/revokecertificationcommand.cpp
commands/revokecertificationcommand.h
commands/revokekeycommand.cpp
commands/revokekeycommand.h
commands/revokeuseridcommand.cpp
commands/revokeuseridcommand.h
commands/selftestcommand.cpp
commands/selftestcommand.h
commands/setinitialpincommand.cpp
commands/setinitialpincommand.h
commands/setpivcardapplicationadministrationkeycommand.cpp
commands/setpivcardapplicationadministrationkeycommand.h
commands/setprimaryuseridcommand.cpp
commands/setprimaryuseridcommand.h
commands/signclipboardcommand.cpp
commands/signclipboardcommand.h
commands/signencryptfilescommand.cpp
commands/signencryptfilescommand.h
commands/signencryptfoldercommand.cpp
commands/signencryptfoldercommand.h
commands/togglecertificateenabledcommand.cpp
commands/togglecertificateenabledcommand.h
commands/viewemailfilescommand.cpp
commands/viewemailfilescommand.h
conf/configuredialog.cpp
conf/configuredialog.h
conf/groupsconfigdialog.cpp
conf/groupsconfigdialog.h
conf/groupsconfigwidget.cpp
conf/groupsconfigwidget.h
crypto/autodecryptverifyfilescontroller.cpp
crypto/autodecryptverifyfilescontroller.h
crypto/certificateresolver.cpp
crypto/certificateresolver.h
crypto/checksumsutils_p.cpp
crypto/checksumsutils_p.h
crypto/controller.cpp
crypto/controller.h
crypto/createchecksumscontroller.cpp
crypto/createchecksumscontroller.h
crypto/decryptverifyemailcontroller.cpp
crypto/decryptverifyemailcontroller.h
crypto/decryptverifyfilescontroller.cpp
crypto/decryptverifyfilescontroller.h
crypto/decryptverifytask.cpp
crypto/decryptverifytask.h
crypto/encryptemailcontroller.cpp
crypto/encryptemailcontroller.h
crypto/encryptemailtask.cpp
crypto/encryptemailtask.h
crypto/gui/certificatelineedit.cpp
crypto/gui/certificatelineedit.h
crypto/gui/certificateselectionline.cpp
crypto/gui/certificateselectionline.h
crypto/gui/decryptverifyfilesdialog.cpp
crypto/gui/decryptverifyfilesdialog.h
crypto/gui/decryptverifyfileswizard.cpp
crypto/gui/decryptverifyfileswizard.h
crypto/gui/decryptverifyoperationwidget.cpp
crypto/gui/decryptverifyoperationwidget.h
crypto/gui/encryptemailwizard.cpp
crypto/gui/encryptemailwizard.h
crypto/gui/newresultpage.cpp
crypto/gui/newresultpage.h
crypto/gui/objectspage.cpp
crypto/gui/objectspage.h
crypto/gui/resolverecipientspage.cpp
crypto/gui/resolverecipientspage.h
crypto/gui/resultitemwidget.cpp
crypto/gui/resultitemwidget.h
crypto/gui/resultlistwidget.cpp
crypto/gui/resultlistwidget.h
crypto/gui/resultpage.cpp
crypto/gui/resultpage.h
crypto/gui/signemailwizard.cpp
crypto/gui/signemailwizard.h
crypto/gui/signencryptemailconflictdialog.cpp
crypto/gui/signencryptemailconflictdialog.h
crypto/gui/signencryptfilesdialog.cpp
crypto/gui/signencryptfilesdialog.h
crypto/gui/signencryptwidget.cpp
crypto/gui/signencryptwidget.h
crypto/gui/signencryptwizard.cpp
crypto/gui/signencryptwizard.h
crypto/gui/signerresolvepage.cpp
crypto/gui/signerresolvepage.h
crypto/gui/signingcertificateselectiondialog.cpp
crypto/gui/signingcertificateselectiondialog.h
crypto/gui/signingcertificateselectionwidget.cpp
crypto/gui/signingcertificateselectionwidget.h
crypto/gui/unknownrecipientwidget.cpp
crypto/gui/unknownrecipientwidget.h
crypto/gui/verifychecksumsdialog.cpp
crypto/gui/verifychecksumsdialog.h
crypto/gui/wizard.cpp
crypto/gui/wizard.h
crypto/gui/wizardpage.cpp
crypto/gui/wizardpage.h
crypto/newsignencryptemailcontroller.cpp
crypto/newsignencryptemailcontroller.h
crypto/recipient.cpp
crypto/recipient.h
crypto/sender.cpp
crypto/sender.h
crypto/signemailcontroller.cpp
crypto/signemailcontroller.h
crypto/signemailtask.cpp
crypto/signemailtask.h
crypto/signencryptfilescontroller.cpp
crypto/signencryptfilescontroller.h
crypto/signencrypttask.cpp
crypto/signencrypttask.h
crypto/task.cpp
crypto/task.h
crypto/taskcollection.cpp
crypto/taskcollection.h
crypto/verifychecksumscontroller.cpp
crypto/verifychecksumscontroller.h
dialogs/addsubkeydialog.cpp
dialogs/addsubkeydialog.h
dialogs/adduseriddialog.cpp
dialogs/adduseriddialog.h
dialogs/animatedexpander.cpp
dialogs/animatedexpander.h
dialogs/certificatedetailsdialog.cpp
dialogs/certificatedetailsdialog.h
dialogs/certificatedetailsinputwidget.cpp
dialogs/certificatedetailsinputwidget.h
dialogs/certificatedetailswidget.cpp
dialogs/certificatedetailswidget.h
dialogs/certificatedumpwidget.cpp
dialogs/certificatedumpwidget.h
dialogs/certificateselectiondialog.cpp
dialogs/certificateselectiondialog.h
dialogs/certifycertificatedialog.cpp
dialogs/certifycertificatedialog.h
dialogs/certifywidget.cpp
dialogs/certifywidget.h
dialogs/createcsrforcardkeydialog.cpp
dialogs/createcsrforcardkeydialog.h
dialogs/copytosmartcarddialog.cpp
dialogs/copytosmartcarddialog.h
dialogs/debugdialog.cpp
dialogs/debugdialog.h
dialogs/deletecertificatesdialog.cpp
dialogs/deletecertificatesdialog.h
dialogs/editgroupdialog.cpp
dialogs/editgroupdialog.h
dialogs/expirydialog.cpp
dialogs/expirydialog.h
dialogs/exportdialog.cpp
dialogs/exportdialog.h
dialogs/gencardkeydialog.cpp
dialogs/gencardkeydialog.h
dialogs/groupdetailsdialog.cpp
dialogs/groupdetailsdialog.h
dialogs/lookupcertificatesdialog.cpp
dialogs/lookupcertificatesdialog.h
dialogs/pivcardapplicationadministrationkeyinputdialog.cpp
dialogs/pivcardapplicationadministrationkeyinputdialog.h
dialogs/revokekeydialog.cpp
dialogs/revokekeydialog.h
dialogs/revokerswidget.cpp
dialogs/revokerswidget.h
dialogs/selftestdialog.cpp
dialogs/selftestdialog.h
dialogs/setinitialpindialog.cpp
dialogs/setinitialpindialog.h
dialogs/smartcardwindow.cpp
dialogs/smartcardwindow.h
dialogs/subkeyswidget.cpp
dialogs/subkeyswidget.h
dialogs/trustchainwidget.cpp
dialogs/trustchainwidget.h
dialogs/updatenotification.cpp
dialogs/updatenotification.h
dialogs/useridswidget.cpp
dialogs/useridswidget.h
dialogs/weboftrustwidget.cpp
dialogs/weboftrustwidget.h
interfaces/anchorprovider.h
interfaces/focusfirstchild.h
newcertificatewizard/advancedsettingsdialog.cpp
newcertificatewizard/advancedsettingsdialog_p.h
newcertificatewizard/enterdetailspage.cpp
newcertificatewizard/enterdetailspage_p.h
newcertificatewizard/keycreationpage.cpp
newcertificatewizard/keycreationpage_p.h
newcertificatewizard/listwidget.cpp
newcertificatewizard/listwidget.h
newcertificatewizard/newcertificatewizard.cpp
newcertificatewizard/newcertificatewizard.h
newcertificatewizard/resultpage.cpp
newcertificatewizard/resultpage_p.h
newcertificatewizard/wizardpage.cpp
newcertificatewizard/wizardpage_p.h
selftest/compliancecheck.cpp
selftest/compliancecheck.h
selftest/enginecheck.cpp
selftest/enginecheck.h
selftest/gpgagentcheck.cpp
selftest/gpgagentcheck.h
selftest/gpgconfcheck.cpp
selftest/gpgconfcheck.h
selftest/libkleopatrarccheck.cpp
selftest/libkleopatrarccheck.h
selftest/selftest.cpp
selftest/selftest.h
smartcard/algorithminfo.h
smartcard/card.cpp
smartcard/card.h
smartcard/deviceinfowatcher.cpp
smartcard/deviceinfowatcher.h
smartcard/keypairinfo.cpp
smartcard/keypairinfo.h
smartcard/netkeycard.cpp
smartcard/netkeycard.h
smartcard/openpgpcard.cpp
smartcard/openpgpcard.h
smartcard/p15card.cpp
smartcard/p15card.h
smartcard/pivcard.cpp
smartcard/pivcard.h
smartcard/readerstatus.cpp
smartcard/readerstatus.h
smartcard/utils.cpp
smartcard/utils.h
utils/accessibility.cpp
utils/accessibility.h
utils/action_data.cpp
utils/action_data.h
utils/applicationstate.cpp
utils/applicationstate.h
utils/archivedefinition.cpp
utils/archivedefinition.h
utils/certificatepair.h
utils/clipboardmenu.cpp
utils/clipboardmenu.h
utils/debug-helpers.cpp
utils/debug-helpers.h
utils/dragqueen.cpp
utils/dragqueen.h
utils/email.cpp
utils/email.h
utils/emptypassphraseprovider.cpp
utils/emptypassphraseprovider.h
utils/filedialog.cpp
utils/filedialog.h
utils/fileutils.cpp
utils/fileutils.h
utils/gui-helper.cpp
utils/gui-helper.h
utils/headerview.cpp
utils/headerview.h
utils/input.cpp
utils/input.h
utils/iodevicelogger.cpp
utils/iodevicelogger.h
utils/kdpipeiodevice.cpp
utils/kdpipeiodevice.h
utils/keyexportdraghandler.cpp
utils/keyexportdraghandler.h
utils/kuniqueservice.cpp
utils/kuniqueservice.h
utils/log.cpp
utils/log.h
utils/memory-helpers.h
utils/migration.cpp
utils/migration.h
utils/output.cpp
utils/output.h
utils/overwritedialog.cpp
utils/overwritedialog.h
utils/path-helper.cpp
utils/path-helper.h
- utils/scrollarea.cpp
- utils/scrollarea.h
utils/statusmessage.cpp
utils/statusmessage.h
utils/systemtrayicon.cpp
utils/systemtrayicon.h
utils/tags.cpp
utils/tags.h
utils/types.cpp
utils/types.h
utils/userinfo.cpp
utils/userinfo.h
utils/writecertassuantransaction.cpp
utils/writecertassuantransaction.h
utils/wsastarter.cpp
utils/wsastarter.h
view/anchorcache.cpp
view/anchorcache_p.h
view/cardkeysview.cpp
view/cardkeysview.h
view/htmllabel.cpp
view/htmllabel.h
view/infofield.cpp
view/infofield.h
view/keycacheoverlay.cpp
view/keycacheoverlay.h
view/keylistcontroller.cpp
view/keylistcontroller.h
view/keytreeview.cpp
view/keytreeview.h
view/netkeywidget.cpp
view/netkeywidget.h
view/overlaywidget.cpp
view/overlaywidget.h
view/p15cardwidget.cpp
view/p15cardwidget.h
view/padwidget.cpp
view/padwidget.h
view/pgpcardwidget.cpp
view/pgpcardwidget.h
view/pivcardwidget.cpp
view/pivcardwidget.h
view/progressoverlay.cpp
view/progressoverlay.h
view/searchbar.cpp
view/searchbar.h
view/smartcardactions.cpp
view/smartcardactions.h
view/smartcardswidget.cpp
view/smartcardswidget.h
view/smartcardwidget.cpp
view/smartcardwidget.h
view/tabwidget.cpp
view/tabwidget.h
view/textoverlay.cpp
view/textoverlay.h
view/urllabel.cpp
view/urllabel.h
view/waitwidget.cpp
view/waitwidget.h
view/welcomewidget.cpp
view/welcomewidget.h
aboutdata.cpp
aboutdata.h
kleopatra.qrc
kleopatraapplication.cpp
kleopatraapplication.h
main.cpp
mainwindow.cpp
mainwindow.h
systrayicon.cpp
systrayicon.h
kleopatra_options.h
)
if(WIN32)
configure_file (versioninfo.rc.in versioninfo.rc)
configure_file (kleopatra.w32-manifest.in kleopatra.w32-manifest)
set(_kleopatra_SRCS
${CMAKE_CURRENT_BINARY_DIR}/kleopatra.w32-manifest
${CMAKE_CURRENT_BINARY_DIR}/versioninfo.rc
conf/kmessageboxdontaskagainstorage.cpp
conf/kmessageboxdontaskagainstorage.h
${_kleopatra_SRCS}
)
endif()
set (_kleopatra_SRCS conf/kleopageconfigdialog.cpp conf/kleopageconfigdialog.h ${_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/setinitialpindialog.ui
newcertificatewizard/listwidget.ui
)
kconfig_add_kcfg_files(_kleopatra_SRCS
kcfg/emailoperationspreferences.kcfgc
kcfg/fileoperationspreferences.kcfgc
kcfg/settings.kcfgc
kcfg/smimevalidationpreferences.kcfgc
kcfg/tooltippreferences.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
KPim6::Libkleo
KPim6::Mime
KPim6::MimeTreeParserWidgets
KF6::Codecs
KF6::CoreAddons
KF6::Crash
KF6::I18n
KF6::IconThemes
KF6::ItemModels
KF6::KIOCore
KF6::KIOWidgets
KF6::WindowSystem
KF6::XmlGui
Qt::Network
Qt::PrintSupport # Printing secret keys
kleopatraclientcore
${_kleopatra_extra_libs}
${_kleopatra_mail_libs}
${_kleopatra_uiserver_extra_libs}
${_kleopatra_dbusaddons_libs}
${_kleopatra_platform_libs}
)
target_link_libraries(kleopatra_bin QGpgmeQt6)
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(FILES data/kleopatra-mime.xml DESTINATION ${KDE_INSTALL_MIMEDIR})
install(
PROGRAMS data/kleopatra_signencryptfiles.desktop
data/kleopatra_signencryptfolders.desktop
data/kleopatra_decryptverifyfiles.desktop
data/kleopatra_decryptverifyfolders.desktop
DESTINATION ${KDE_INSTALL_DATADIR}/kio/servicemenus
)
install(FILES kleopatradebugcommandsrc DESTINATION ${KDE_INSTALL_CONFDIR})
diff --git a/src/conf/groupsconfigdialog.cpp b/src/conf/groupsconfigdialog.cpp
index e59baf946..099b36c72 100644
--- a/src/conf/groupsconfigdialog.cpp
+++ b/src/conf/groupsconfigdialog.cpp
@@ -1,168 +1,170 @@
/*
conf/groupsconfigdialog.cpp
This file is part of Kleopatra, the KDE keymanager
SPDX-FileCopyrightText: 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 "groupsconfigdialog.h"
#include "groupsconfigwidget.h"
#include <kleopatra_debug.h>
#include <utils/gui-helper.h>
-#include <utils/scrollarea.h>
#include <Libkleo/DocAction>
#include <Libkleo/KeyCache>
#include <Libkleo/KeyGroup>
+#include <KAdjustingScrollArea>
#include <KConfigGroup>
#include <KLocalizedString>
#include <KSharedConfig>
#include <QDialogButtonBox>
#include <QPushButton>
#include <QVBoxLayout>
using namespace Kleo;
class GroupsConfigDialog::Private
{
friend class ::GroupsConfigDialog;
GroupsConfigDialog *const q;
public:
Private(GroupsConfigDialog *qq)
: q(qq)
{
}
private:
void saveLayout();
void restoreLayout(const QSize &defaultSize = {});
void loadGroups();
void saveGroups();
void onKeysMayHaveChanged();
private:
GroupsConfigWidget *configWidget = nullptr;
bool savingChanges = false;
};
void GroupsConfigDialog::Private::saveLayout()
{
KConfigGroup configGroup(KSharedConfig::openStateConfig(), QLatin1StringView("GroupsConfigDialog"));
configGroup.writeEntry("Size", q->size());
configGroup.sync();
}
void GroupsConfigDialog::Private::restoreLayout(const QSize &defaultSize)
{
const KConfigGroup configGroup(KSharedConfig::openStateConfig(), QLatin1StringView("GroupsConfigDialog"));
const QSize size = configGroup.readEntry("Size", defaultSize);
if (size.isValid()) {
q->resize(size);
}
}
void GroupsConfigDialog::Private::loadGroups()
{
qCDebug(KLEOPATRA_LOG) << q << __func__;
configWidget->setGroups(KeyCache::instance()->configurableGroups());
}
void GroupsConfigDialog::Private::saveGroups()
{
qCDebug(KLEOPATRA_LOG) << q << __func__;
savingChanges = true;
KeyCache::mutableInstance()->saveConfigurableGroups(configWidget->groups());
savingChanges = false;
// reload after saving to ensure that the groups reflect the saved groups (e.g. in case of immutable entries)
loadGroups();
}
void GroupsConfigDialog::Private::onKeysMayHaveChanged()
{
if (savingChanges) {
qCDebug(KLEOPATRA_LOG) << __func__ << "ignoring changes caused by ourselves";
return;
}
qCDebug(KLEOPATRA_LOG) << "Reloading groups";
loadGroups();
}
GroupsConfigDialog::GroupsConfigDialog(QWidget *parent)
: QDialog(parent)
, d(new Private(this))
{
setWindowTitle(i18nc("@title:window", "Configure Groups"));
auto mainLayout = new QVBoxLayout{this};
- auto scrollArea = new ScrollArea{this};
+ auto scrollArea = new KAdjustingScrollArea{this};
scrollArea->setFocusPolicy(Qt::NoFocus);
scrollArea->setFrameStyle(QFrame::NoFrame);
scrollArea->setBackgroundRole(backgroundRole());
scrollArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
scrollArea->setSizeAdjustPolicy(QScrollArea::AdjustToContents);
- auto scrollAreaLayout = qobject_cast<QBoxLayout *>(scrollArea->widget()->layout());
+ auto widget = new QWidget;
+ scrollArea->setWidget(widget);
+ auto scrollAreaLayout = new QVBoxLayout(widget);
scrollAreaLayout->setContentsMargins({});
d->configWidget = new GroupsConfigWidget{this};
d->configWidget->setContentsMargins({});
scrollAreaLayout->addWidget(d->configWidget);
mainLayout->addWidget(scrollArea);
auto buttonBox = new QDialogButtonBox{QDialogButtonBox::Close, this};
mainLayout->addWidget(buttonBox);
auto helpAction = std::make_unique<Kleo::DocAction>(
QIcon::fromTheme(QStringLiteral("help")),
i18n("Help"),
i18nc("Only available in German and English. Leave to English for other languages.", "handout_group-feature_gnupg_en.pdf"),
QStringLiteral("../share/doc/gnupg-vsd"),
QUrl(),
this);
if (helpAction->isEnabled()) {
auto helpButton = buttonBox->addButton(QDialogButtonBox::Help);
disconnect(helpButton, &QAbstractButton::clicked, nullptr, nullptr);
connect(helpButton, &QAbstractButton::clicked, helpAction.get(), &QAction::trigger);
helpAction.release();
}
// prevent accidental closing of dialog when pressing Enter while the search field has focus
Kleo::unsetAutoDefaultButtons(this);
// Close button (defined with RejectRole) should close the dialog
connect(buttonBox, &QDialogButtonBox::rejected, this, &QDialog::accept);
connect(d->configWidget, &GroupsConfigWidget::changed, this, [this]() {
d->saveGroups();
});
connect(KeyCache::instance().get(), &KeyCache::keysMayHaveChanged, this, [this]() {
d->onKeysMayHaveChanged();
});
d->restoreLayout();
d->loadGroups();
}
GroupsConfigDialog::~GroupsConfigDialog()
{
d->saveLayout();
}
#include "moc_groupsconfigdialog.cpp"
diff --git a/src/crypto/gui/decryptverifyfileswizard.cpp b/src/crypto/gui/decryptverifyfileswizard.cpp
index c128de305..2a54e7083 100644
--- a/src/crypto/gui/decryptverifyfileswizard.cpp
+++ b/src/crypto/gui/decryptverifyfileswizard.cpp
@@ -1,283 +1,283 @@
/* -*- mode: c++; c-basic-offset:4 -*-
crypto/gui/decryptverifywizard.cpp
This file is part of Kleopatra, the KDE keymanager
SPDX-FileCopyrightText: 2007 Klarälvdalens Datakonsult AB
SPDX-License-Identifier: GPL-2.0-or-later
*/
#include <config-kleopatra.h>
#include "decryptverifyfileswizard.h"
#include "decryptverifyoperationwidget.h"
#include "utils/fileutils.h"
#include <crypto/gui/resultpage.h>
#include <crypto/gui/wizardpage.h>
#include <crypto/task.h>
#include <crypto/taskcollection.h>
#include <utils/kleo_assert.h>
-#include <utils/scrollarea.h>
#include <Libkleo/FileNameRequester>
#include <Libkleo/Stl_Util>
+#include <KAdjustingScrollArea>
#include <KGuiItem>
#include <KLocalizedString>
#include <QBoxLayout>
#include <QCheckBox>
#include <QLabel>
#include <QTimer>
#include <QTreeView>
#include <vector>
using namespace Kleo;
using namespace Kleo::Crypto;
using namespace Kleo::Crypto::Gui;
namespace
{
class HLine : public QFrame
{
Q_OBJECT
public:
explicit HLine(QWidget *p = nullptr, Qt::WindowFlags f = {})
: QFrame(p, f)
{
setFrameStyle(static_cast<int>(QFrame::HLine) | static_cast<int>(QFrame::Sunken));
}
};
class OperationsWidget : public WizardPage
{
Q_OBJECT
public:
explicit OperationsWidget(QWidget *p = nullptr);
~OperationsWidget() override;
void setOutputDirectory(const QString &dir)
{
m_ui.outputDirectoryFNR.setFileName(dir);
}
QString outputDirectory() const
{
return m_ui.outputDirectoryFNR.fileName();
}
bool useOutputDirectory() const
{
return m_ui.useOutputDirectoryCB.isChecked();
}
void ensureIndexAvailable(unsigned int idx);
DecryptVerifyOperationWidget *widget(unsigned int idx)
{
return m_widgets.at(idx);
}
bool isComplete() const override
{
return std::all_of(m_widgets.cbegin(), m_widgets.cend(), [](const auto &w) {
switch (w->mode()) {
case DecryptVerifyOperationWidget::VerifyDetachedWithSignature:
case DecryptVerifyOperationWidget::VerifyDetachedWithSignedData: {
const QString sigFileName = w->inputFileName();
const QString dataFileName = w->signedDataFileName();
return !sigFileName.isEmpty() && !dataFileName.isEmpty() && QFile::exists(sigFileName) && QFile::exists(dataFileName);
}
case DecryptVerifyOperationWidget::DecryptVerifyOpaque:;
}
return true;
});
}
bool onNext() override
{
return Kleo::ensureOutputDirectoryExists(outputDirectory(), this);
}
private:
std::vector<DecryptVerifyOperationWidget *> m_widgets;
struct UI {
QCheckBox useOutputDirectoryCB;
QLabel outputDirectoryLB;
FileNameRequester outputDirectoryFNR;
- ScrollArea scrollArea; // ### replace with KDScrollArea when done
+ KAdjustingScrollArea scrollArea;
QVBoxLayout vlay;
QHBoxLayout hlay;
explicit UI(OperationsWidget *q);
} m_ui;
};
}
class DecryptVerifyFilesWizard::Private
{
friend class ::Kleo::Crypto::Gui::DecryptVerifyFilesWizard;
DecryptVerifyFilesWizard *const q;
public:
Private(DecryptVerifyFilesWizard *qq);
~Private();
void ensureIndexAvailable(unsigned int idx)
{
operationsPage.ensureIndexAvailable(idx);
}
private:
OperationsWidget operationsPage;
Gui::ResultPage resultPage;
};
DecryptVerifyFilesWizard::DecryptVerifyFilesWizard(QWidget *p, Qt::WindowFlags f)
: Wizard(p, f)
, d(new Private(this))
{
}
DecryptVerifyFilesWizard::~DecryptVerifyFilesWizard()
{
}
void DecryptVerifyFilesWizard::setOutputDirectory(const QString &dir)
{
d->operationsPage.setOutputDirectory(dir);
}
QString DecryptVerifyFilesWizard::outputDirectory() const
{
return d->operationsPage.outputDirectory();
}
bool DecryptVerifyFilesWizard::useOutputDirectory() const
{
return d->operationsPage.useOutputDirectory();
}
DecryptVerifyOperationWidget *DecryptVerifyFilesWizard::operationWidget(unsigned int idx)
{
d->ensureIndexAvailable(idx);
return d->operationsPage.widget(idx);
}
void DecryptVerifyFilesWizard::onNext(int id)
{
if (id == OperationsPage) {
QTimer::singleShot(0, this, &DecryptVerifyFilesWizard::operationPrepared);
}
Wizard::onNext(id);
}
void DecryptVerifyFilesWizard::setTaskCollection(const std::shared_ptr<TaskCollection> &coll)
{
kleo_assert(coll);
d->resultPage.setTaskCollection(coll);
}
DecryptVerifyFilesWizard::Private::Private(DecryptVerifyFilesWizard *qq)
: q(qq)
, operationsPage(q)
, resultPage(q)
{
q->setPage(DecryptVerifyFilesWizard::OperationsPage, &operationsPage);
q->setPage(DecryptVerifyFilesWizard::ResultPage, &resultPage);
std::vector<int> order;
order.push_back(DecryptVerifyFilesWizard::OperationsPage);
order.push_back(DecryptVerifyFilesWizard::ResultPage);
q->setPageOrder(order);
operationsPage.setCommitPage(true);
}
DecryptVerifyFilesWizard::Private::~Private()
{
}
OperationsWidget::OperationsWidget(QWidget *p)
: WizardPage(p)
, m_widgets()
, m_ui(this)
{
setTitle(i18n("<b>Choose operations to be performed</b>"));
setSubTitle(
i18n("Here you can check and, if needed, override "
"the operations Kleopatra detected for the input given."));
setCommitPage(true);
setCustomNextButton(KGuiItem(i18nc("@action:button", "&Decrypt/Verify")));
}
OperationsWidget::~OperationsWidget()
{
}
OperationsWidget::UI::UI(OperationsWidget *q)
: useOutputDirectoryCB(i18n("Create all output files in a single folder"), q)
, outputDirectoryLB(i18n("&Output folder:"), q)
, outputDirectoryFNR(q)
, scrollArea(q)
, vlay(q)
, hlay()
{
Q_SET_OBJECT_NAME(useOutputDirectoryCB);
Q_SET_OBJECT_NAME(outputDirectoryLB);
Q_SET_OBJECT_NAME(outputDirectoryFNR);
Q_SET_OBJECT_NAME(scrollArea);
Q_SET_OBJECT_NAME(vlay);
Q_SET_OBJECT_NAME(hlay);
outputDirectoryFNR.setFilter(QDir::Dirs);
useOutputDirectoryCB.setChecked(true);
connect(&useOutputDirectoryCB, &QCheckBox::toggled, &outputDirectoryLB, &QLabel::setEnabled);
connect(&useOutputDirectoryCB, &QCheckBox::toggled, &outputDirectoryFNR, &FileNameRequester::setEnabled);
Q_ASSERT(qobject_cast<QBoxLayout *>(scrollArea.widget()->layout()));
static_cast<QBoxLayout *>(scrollArea.widget()->layout())->addStretch(1);
outputDirectoryLB.setBuddy(&outputDirectoryFNR);
hlay.setContentsMargins(0, 0, 0, 0);
vlay.addWidget(&scrollArea, 1);
vlay.addWidget(&useOutputDirectoryCB);
vlay.addLayout(&hlay);
hlay.addWidget(&outputDirectoryLB);
hlay.addWidget(&outputDirectoryFNR);
}
void OperationsWidget::ensureIndexAvailable(unsigned int idx)
{
if (idx < m_widgets.size()) {
return;
}
Q_ASSERT(m_ui.scrollArea.widget());
Q_ASSERT(qobject_cast<QBoxLayout *>(m_ui.scrollArea.widget()->layout()));
QBoxLayout &blay = *static_cast<QBoxLayout *>(m_ui.scrollArea.widget()->layout());
for (unsigned int i = m_widgets.size(); i < idx + 1; ++i) {
if (i) {
blay.insertWidget(blay.count() - 1, new HLine(m_ui.scrollArea.widget()));
}
auto w = new DecryptVerifyOperationWidget(m_ui.scrollArea.widget());
blay.insertWidget(blay.count() - 1, w);
w->show();
connect(w, &DecryptVerifyOperationWidget::changed, this, &WizardPage::completeChanged);
m_widgets.push_back(w);
}
}
#include "decryptverifyfileswizard.moc"
#include "moc_decryptverifyfileswizard.cpp"
diff --git a/src/crypto/gui/resultlistwidget.cpp b/src/crypto/gui/resultlistwidget.cpp
index 11fc0f291..3b2a849f3 100644
--- a/src/crypto/gui/resultlistwidget.cpp
+++ b/src/crypto/gui/resultlistwidget.cpp
@@ -1,224 +1,224 @@
/* -*- mode: c++; c-basic-offset:4 -*-
crypto/gui/resultlistwidget.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 "resultlistwidget.h"
#include "emailoperationspreferences.h"
#include <crypto/decryptverifytask.h>
#include <crypto/gui/resultitemwidget.h>
#include <utils/gui-helper.h>
-#include <utils/scrollarea.h>
#include <Libkleo/Stl_Util>
+#include <KAdjustingScrollArea>
+#include <KGuiItem>
#include <KLocalizedString>
#include <KStandardGuiItem>
-#include <QPushButton>
#include <QLabel>
+#include <QPushButton>
#include <QVBoxLayout>
-#include <KGuiItem>
-
using namespace Kleo;
using namespace Kleo::Crypto;
using namespace Kleo::Crypto::Gui;
class ResultListWidget::Private
{
ResultListWidget *const q;
public:
explicit Private(ResultListWidget *qq);
void result(const std::shared_ptr<const Task::Result> &result);
void started(const std::shared_ptr<Task> &task);
void allTasksDone();
void addResultWidget(ResultItemWidget *widget);
void resizeIfStandalone();
std::vector<std::shared_ptr<TaskCollection>> m_collections;
bool m_standaloneMode = false;
int m_lastErrorItemIndex = 0;
- ScrollArea *m_scrollArea = nullptr;
+ KAdjustingScrollArea *m_scrollArea = nullptr;
QPushButton *m_closeButton = nullptr;
QVBoxLayout *m_layout = nullptr;
QLabel *m_progressLabel = nullptr;
};
ResultListWidget::Private::Private(ResultListWidget *qq)
: q(qq)
, m_collections()
{
m_layout = new QVBoxLayout(q);
m_layout->setContentsMargins(0, 0, 0, 0);
m_layout->setSpacing(0);
- m_scrollArea = new ScrollArea;
+ m_scrollArea = new KAdjustingScrollArea;
m_scrollArea->setFocusPolicy(Qt::NoFocus);
- auto scrollAreaLayout = qobject_cast<QBoxLayout *>(m_scrollArea->widget()->layout());
- Q_ASSERT(scrollAreaLayout);
+ auto widget = new QWidget;
+ m_scrollArea->setWidget(widget);
+ auto scrollAreaLayout = new QVBoxLayout(widget);
scrollAreaLayout->setContentsMargins(0, 0, 0, 0);
scrollAreaLayout->setSpacing(2);
scrollAreaLayout->addStretch();
m_layout->addWidget(m_scrollArea);
m_progressLabel = new QLabel;
m_progressLabel->setWordWrap(true);
m_layout->addWidget(m_progressLabel);
m_progressLabel->setVisible(false);
m_closeButton = new QPushButton;
KGuiItem::assign(m_closeButton, KStandardGuiItem::close());
q->connect(m_closeButton, &QPushButton::clicked, q, &ResultListWidget::close);
m_layout->addWidget(m_closeButton);
m_closeButton->setVisible(false);
m_closeButton->setEnabled(false);
}
ResultListWidget::ResultListWidget(QWidget *parent, Qt::WindowFlags f)
: QWidget(parent, f)
, d(new Private(this))
{
}
ResultListWidget::~ResultListWidget()
{
if (!d->m_standaloneMode) {
return;
}
EMailOperationsPreferences prefs;
prefs.setDecryptVerifyPopupGeometry(geometry());
prefs.save();
}
void ResultListWidget::Private::resizeIfStandalone()
{
if (m_standaloneMode) {
q->resize(q->size().expandedTo(q->sizeHint()));
}
}
void ResultListWidget::Private::addResultWidget(ResultItemWidget *widget)
{
Q_ASSERT(widget);
Q_ASSERT(std::any_of(m_collections.cbegin(), m_collections.cend(), [](const std::shared_ptr<TaskCollection> &t) {
return !t->isEmpty();
}));
Q_ASSERT(m_scrollArea);
Q_ASSERT(m_scrollArea->widget());
auto scrollAreaLayout = qobject_cast<QBoxLayout *>(m_scrollArea->widget()->layout());
Q_ASSERT(scrollAreaLayout);
// insert new widget after last widget showing error or before the trailing stretch
const auto insertIndex = widget->hasErrorResult() ? m_lastErrorItemIndex++ : scrollAreaLayout->count() - 1;
scrollAreaLayout->insertWidget(insertIndex, widget);
if (insertIndex == 0) {
forceSetTabOrder(m_scrollArea->widget(), widget);
} else {
auto previousResultWidget = qobject_cast<ResultItemWidget *>(scrollAreaLayout->itemAt(insertIndex - 1)->widget());
QWidget::setTabOrder(previousResultWidget, widget);
}
widget->show();
resizeIfStandalone();
}
void ResultListWidget::Private::allTasksDone()
{
if (!q->isComplete()) {
return;
}
m_progressLabel->setVisible(false);
resizeIfStandalone();
Q_EMIT q->completeChanged();
}
void ResultListWidget::Private::result(const std::shared_ptr<const Task::Result> &result)
{
Q_ASSERT(result);
Q_ASSERT(std::any_of(m_collections.cbegin(), m_collections.cend(), [](const std::shared_ptr<TaskCollection> &t) {
return !t->isEmpty();
}));
auto wid = new ResultItemWidget(result);
q->connect(wid, &ResultItemWidget::linkActivated, q, &ResultListWidget::linkActivated);
q->connect(wid, &ResultItemWidget::closeButtonClicked, q, &ResultListWidget::close);
const auto viewableContentType = result->viewableContentType();
if (viewableContentType == Task::Result::ContentType::Mime || viewableContentType == Task::Result::ContentType::Mbox) {
wid->setShowButton(i18nc("@action:button", "Show Email"), true);
q->connect(wid, &ResultItemWidget::showButtonClicked, q, [this, result] {
Q_EMIT q->showButtonClicked(result);
});
}
addResultWidget(wid);
}
bool ResultListWidget::isComplete() const
{
return std::all_of(d->m_collections.cbegin(), d->m_collections.cend(), std::mem_fn(&TaskCollection::allTasksCompleted));
}
unsigned int ResultListWidget::totalNumberOfTasks() const
{
return kdtools::accumulate_transform(d->m_collections.cbegin(), d->m_collections.cend(), std::mem_fn(&TaskCollection::size), 0U);
}
unsigned int ResultListWidget::numberOfCompletedTasks() const
{
return kdtools::accumulate_transform(d->m_collections.cbegin(), d->m_collections.cend(), std::mem_fn(&TaskCollection::numberOfCompletedTasks), 0U);
}
void ResultListWidget::setTaskCollection(const std::shared_ptr<TaskCollection> &coll)
{
// clear(); ### PENDING(marc) implement
addTaskCollection(coll);
}
void ResultListWidget::addTaskCollection(const std::shared_ptr<TaskCollection> &coll)
{
Q_ASSERT(coll);
Q_ASSERT(!coll->isEmpty());
d->m_collections.push_back(coll);
connect(coll.get(),
SIGNAL(result(std::shared_ptr<const Kleo::Crypto::Task::Result>)),
this,
SLOT(result(std::shared_ptr<const Kleo::Crypto::Task::Result>)));
connect(coll.get(), SIGNAL(started(std::shared_ptr<Kleo::Crypto::Task>)), this, SLOT(started(std::shared_ptr<Kleo::Crypto::Task>)));
connect(coll.get(), SIGNAL(done()), this, SLOT(allTasksDone()));
setStandaloneMode(d->m_standaloneMode);
}
void ResultListWidget::Private::started(const std::shared_ptr<Task> &task)
{
Q_ASSERT(task);
Q_ASSERT(m_progressLabel);
m_progressLabel->setText(i18nc("number, operation description", "Operation %1: %2", q->numberOfCompletedTasks() + 1, task->label()));
resizeIfStandalone();
}
void ResultListWidget::setStandaloneMode(bool standalone)
{
d->m_standaloneMode = standalone;
if (totalNumberOfTasks() == 0) {
return;
}
d->m_closeButton->setVisible(standalone);
d->m_closeButton->setEnabled(standalone);
d->m_progressLabel->setVisible(standalone);
}
#include "moc_resultlistwidget.cpp"
diff --git a/src/crypto/gui/resultpage.cpp b/src/crypto/gui/resultpage.cpp
index 9025916a8..bdfc0cefe 100644
--- a/src/crypto/gui/resultpage.cpp
+++ b/src/crypto/gui/resultpage.cpp
@@ -1,179 +1,177 @@
/* -*- mode: c++; c-basic-offset:4 -*-
crypto/gui/resultpage.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 "resultitemwidget.h"
#include "resultlistwidget.h"
#include "resultpage.h"
#include <crypto/taskcollection.h>
-#include <utils/scrollarea.h>
-
#include <KLocalizedString>
#include <QCheckBox>
#include <QHash>
#include <QLabel>
#include <QProgressBar>
#include <QVBoxLayout>
using namespace Kleo;
using namespace Kleo::Crypto;
using namespace Kleo::Crypto::Gui;
class ResultPage::Private
{
ResultPage *const q;
public:
explicit Private(ResultPage *qq);
void progress(int progress, int total);
void result(const std::shared_ptr<const Task::Result> &result);
void started(const std::shared_ptr<Task> &result);
void allDone();
QLabel *labelForTag(const QString &tag);
std::shared_ptr<TaskCollection> m_tasks;
QProgressBar *m_progressBar;
QHash<QString, QLabel *> m_progressLabelByTag;
QVBoxLayout *m_progressLabelLayout;
int m_lastErrorItemIndex = 0;
ResultListWidget *m_resultList;
QCheckBox *m_keepOpenCB;
};
ResultPage::Private::Private(ResultPage *qq)
: q(qq)
{
QBoxLayout *const layout = new QVBoxLayout(q);
auto const labels = new QWidget;
m_progressLabelLayout = new QVBoxLayout(labels);
layout->addWidget(labels);
m_progressBar = new QProgressBar;
layout->addWidget(m_progressBar);
m_resultList = new ResultListWidget;
layout->addWidget(m_resultList);
m_keepOpenCB = new QCheckBox;
m_keepOpenCB->setText(i18n("Keep open after operation completed"));
m_keepOpenCB->setChecked(true);
layout->addWidget(m_keepOpenCB);
}
void ResultPage::Private::progress(int progress, int total)
{
Q_ASSERT(progress >= 0);
Q_ASSERT(total >= 0);
m_progressBar->setRange(0, total);
m_progressBar->setValue(progress);
}
void ResultPage::Private::allDone()
{
Q_ASSERT(m_tasks);
q->setAutoAdvance(!m_keepOpenCB->isChecked() && !m_tasks->errorOccurred());
m_progressBar->setRange(0, 100);
m_progressBar->setValue(100);
m_tasks.reset();
const auto progressLabelByTagKeys{m_progressLabelByTag.keys()};
for (const QString &i : progressLabelByTagKeys) {
if (!i.isEmpty()) {
m_progressLabelByTag.value(i)->setText(i18n("%1: All operations completed.", i));
} else {
m_progressLabelByTag.value(i)->setText(i18n("All operations completed."));
}
}
Q_EMIT q->completeChanged();
}
void ResultPage::Private::result(const std::shared_ptr<const Task::Result> &)
{
}
void ResultPage::Private::started(const std::shared_ptr<Task> &task)
{
Q_ASSERT(task);
const QString tag = task->tag();
QLabel *const label = labelForTag(tag);
Q_ASSERT(label);
if (tag.isEmpty()) {
label->setText(i18nc("number, operation description", "Operation %1: %2", m_tasks->numberOfCompletedTasks() + 1, task->label()));
} else {
label->setText(i18nc(R"(tag( "OpenPGP" or "CMS"), operation description)", "%1: %2", tag, task->label()));
}
}
ResultPage::ResultPage(QWidget *parent, Qt::WindowFlags flags)
: WizardPage(parent, flags)
, d(new Private(this))
{
setTitle(i18n("<b>Results</b>"));
}
ResultPage::~ResultPage()
{
}
bool ResultPage::keepOpenWhenDone() const
{
return d->m_keepOpenCB->isChecked();
}
void ResultPage::setKeepOpenWhenDone(bool keep)
{
d->m_keepOpenCB->setChecked(keep);
}
void ResultPage::setTaskCollection(const std::shared_ptr<TaskCollection> &coll)
{
Q_ASSERT(!d->m_tasks);
if (d->m_tasks == coll) {
return;
}
d->m_tasks = coll;
Q_ASSERT(d->m_tasks);
d->m_resultList->setTaskCollection(coll);
connect(d->m_tasks.get(), &TaskCollection::progress, this, [this](int current, int total) {
d->progress(current, total);
});
connect(d->m_tasks.get(), SIGNAL(done()), this, SLOT(allDone()));
connect(d->m_tasks.get(),
SIGNAL(result(std::shared_ptr<const Kleo::Crypto::Task::Result>)),
this,
SLOT(result(std::shared_ptr<const Kleo::Crypto::Task::Result>)));
connect(d->m_tasks.get(), SIGNAL(started(std::shared_ptr<Kleo::Crypto::Task>)), this, SLOT(started(std::shared_ptr<Kleo::Crypto::Task>)));
for (const std::shared_ptr<Task> &i : d->m_tasks->tasks()) { // create labels for all tags in collection
Q_ASSERT(i && d->labelForTag(i->tag()));
Q_UNUSED(i)
}
Q_EMIT completeChanged();
}
QLabel *ResultPage::Private::labelForTag(const QString &tag)
{
if (QLabel *const label = m_progressLabelByTag.value(tag)) {
return label;
}
auto label = new QLabel;
label->setTextFormat(Qt::RichText);
label->setWordWrap(true);
m_progressLabelLayout->addWidget(label);
m_progressLabelByTag.insert(tag, label);
return label;
}
bool ResultPage::isComplete() const
{
return d->m_tasks ? d->m_tasks->allTasksCompleted() : true;
}
#include "moc_resultpage.cpp"
diff --git a/src/crypto/gui/signencryptfilesdialog.cpp b/src/crypto/gui/signencryptfilesdialog.cpp
index b976e06ab..3957ed5f3 100644
--- a/src/crypto/gui/signencryptfilesdialog.cpp
+++ b/src/crypto/gui/signencryptfilesdialog.cpp
@@ -1,688 +1,688 @@
/* crypto/gui/signencryptfileswizard.cpp
This file is part of Kleopatra, the KDE keymanager
SPDX-FileCopyrightText: 2009 Klarälvdalens Datakonsult AB
SPDX-FileCopyrightText: 2016 Bundesamt für Sicherheit in der Informationstechnik
SPDX-FileContributor: Intevation GmbH
SPDX-License-Identifier: GPL-2.0-or-later
*/
#include <config-kleopatra.h>
#include "kleopatra_debug.h"
#include "signencryptfilesdialog.h"
#include "signencryptwidget.h"
#include "resultpage.h"
-#include "utils/scrollarea.h"
#include <fileoperationspreferences.h>
#include <settings.h>
+#include <KAdjustingScrollArea>
#include <KColorScheme>
#include <KConfigGroup>
#include <KLocalizedString>
#include <KMessageBox>
#include <KMessageWidget>
#include <KSeparator>
#include <KSharedConfig>
#include <KTitleWidget>
#include <Libkleo/Compliance>
#include <Libkleo/FileNameRequester>
#include <Libkleo/Formatting>
#include <Libkleo/GnuPG>
#include <Libkleo/SystemInfo>
#include <QCheckBox>
#include <QGroupBox>
#include <QIcon>
#include <QLabel>
#include <QPushButton>
#include <QStackedLayout>
#include <QStyle>
#include <QVBoxLayout>
#include <QWindow>
#include <gpgme++/key.h>
#include <array>
using namespace GpgME;
using namespace Kleo;
using namespace Kleo::Crypto::Gui;
class FileNameRequesterWithIcon : public QWidget
{
Q_OBJECT
public:
explicit FileNameRequesterWithIcon(QDir::Filters filter, QWidget *parent = nullptr)
: QWidget(parent)
{
auto layout = new QHBoxLayout{this};
layout->setContentsMargins(0, 0, 0, 0);
mIconLabel = new QLabel{this};
mRequester = new FileNameRequester{filter, this};
mRequester->setExistingOnly(false);
layout->addWidget(mIconLabel);
layout->addWidget(mRequester);
setFocusPolicy(mRequester->focusPolicy());
setFocusProxy(mRequester);
connect(mRequester, &FileNameRequester::fileNameChanged, this, &FileNameRequesterWithIcon::fileNameChanged);
}
void setIcon(const QIcon &icon)
{
mIconLabel->setPixmap(icon.pixmap(32, 32));
}
void setFileName(const QString &name)
{
mRequester->setFileName(name);
}
QString fileName() const
{
return mRequester->fileName();
}
void setNameFilter(const QString &nameFilter)
{
mRequester->setNameFilter(nameFilter);
}
QString nameFilter() const
{
return mRequester->nameFilter();
}
FileNameRequester *requester()
{
return mRequester;
}
Q_SIGNALS:
void fileNameChanged(const QString &filename);
protected:
bool event(QEvent *e) override
{
if (e->type() == QEvent::ToolTipChange) {
mRequester->setToolTip(toolTip());
}
return QWidget::event(e);
}
private:
QLabel *mIconLabel;
FileNameRequester *mRequester;
};
class SigEncPage : public QWidget
{
Q_OBJECT
public:
explicit SigEncPage(QWidget *parent = nullptr)
: QWidget(parent)
, mWidget(new SignEncryptWidget)
, mOutLayout(new QVBoxLayout)
, mOutputLabel{nullptr}
, mArchive(false)
, mUseOutputDir(false)
, mSingleFile{true}
{
auto mainLayout = new QVBoxLayout(this);
mainLayout->setContentsMargins({});
- auto scrollArea = new Kleo::ScrollArea;
+ auto scrollArea = new KAdjustingScrollArea;
mainLayout->addWidget(scrollArea);
auto wrapper = new QWidget;
scrollArea->setWidget(wrapper);
scrollArea->setFrameStyle(0);
auto vLay = new QVBoxLayout(wrapper);
vLay->setContentsMargins({});
if (!Settings{}.cmsEnabled()) {
mWidget->setProtocol(GpgME::OpenPGP);
}
mWidget->setSignAsText(i18nc("@option:check on SignEncryptPage", "&Sign as:"));
mWidget->setEncryptForMeText(i18nc("@option:check on SignEncryptPage", "Encrypt for &me:"));
mWidget->setEncryptForOthersText(i18nc("@label on SignEncryptPage", "Encrypt for &others:"));
mWidget->setEncryptWithPasswordText(i18nc("@option:check on SignEncryptPage", "Encrypt with &password:"));
vLay->addWidget(mWidget);
connect(mWidget, &SignEncryptWidget::operationChanged, this, &SigEncPage::checkReady);
connect(mWidget, &SignEncryptWidget::keysChanged, this, &SigEncPage::updateFileWidgets);
vLay->addSpacing(style()->pixelMetric(QStyle::PM_LayoutVerticalSpacing) * 3);
vLay->addLayout(mOutLayout);
mPlaceholderWidget = new QLabel(i18nc("@label:textbox", "Please select an action."));
mOutLayout->addWidget(mPlaceholderWidget);
mOutputLabel = new QLabel(i18nc("@label on SignEncryptPage", "Output &files/folder:"));
auto font = mOutputLabel->font();
font.setWeight(QFont::DemiBold);
mOutputLabel->setFont(font);
mOutLayout->addWidget(mOutputLabel);
createRequesters(mOutLayout);
mUseOutputDirChk = new QCheckBox(i18nc("@option:check on SignEncryptPage", "Encrypt / Sign &each file separately."));
mUseOutputDirChk->setToolTip(i18nc("@info:tooltip", "Keep each file separate instead of creating an archive for all."));
mOutLayout->addWidget(mUseOutputDirChk);
connect(mUseOutputDirChk, &QCheckBox::toggled, this, [this](bool state) {
mUseOutputDir = state;
mArchive = !mUseOutputDir && !mSingleFile;
updateFileWidgets();
});
auto messageWidget = new KMessageWidget;
messageWidget->setMessageType(KMessageWidget::Error);
messageWidget->setIcon(style()->standardIcon(QStyle::SP_MessageBoxCritical, nullptr, this));
messageWidget->setText(i18n("Invalid compliance settings for signing and encrypting files."));
messageWidget->setToolTip(xi18nc("@info %1 is a placeholder for the name of a compliance mode. E.g. NATO RESTRICTED compliant or VS-NfD compliant",
"<para>You cannot use <application>Kleopatra</application> for signing or encrypting files "
"because the <application>GnuPG</application> system used by <application>Kleopatra</application> is not %1.</para>",
DeVSCompliance::name(true)));
messageWidget->setCloseButtonVisible(false);
messageWidget->setVisible(DeVSCompliance::isActive() && !DeVSCompliance::isCompliant());
vLay->addWidget(messageWidget);
setMinimumHeight(300);
vLay->addStretch();
}
void setEncryptionPreset(bool value)
{
mWidget->setEncryptionChecked(value);
}
void setSigningPreset(bool value)
{
mWidget->setSigningChecked(value);
}
void setArchiveForced(bool archive)
{
mArchive = archive;
setArchiveMutable(!archive);
}
void setArchiveMutable(bool archive)
{
mUseOutputDirChk->setVisible(archive);
if (archive) {
const KConfigGroup archCfg(KSharedConfig::openConfig(), QStringLiteral("SignEncryptFilesWizard"));
mUseOutputDirChk->setChecked(archCfg.readEntry("LastUseOutputDir", false));
} else {
mUseOutputDirChk->setChecked(false);
}
}
void setSingleFile(bool singleFile)
{
mSingleFile = singleFile;
mArchive = !mUseOutputDir && !mSingleFile;
}
bool validatePage()
{
if (DeVSCompliance::isActive() && !DeVSCompliance::isCompliant()) {
return false;
}
return mWidget->isComplete();
}
std::vector<Key> recipients() const
{
return mWidget->recipients();
}
/* In the future we might find a usecase for multiple
* signers */
std::vector<Key> signers() const
{
const Key k = mWidget->signUserId().parent();
if (!k.isNull()) {
return {k};
}
return {};
}
void done()
{
mWidget->saveOwnKeys();
if (mUseOutputDirChk->isVisible()) {
KConfigGroup archCfg(KSharedConfig::openConfig(), QStringLiteral("SignEncryptFilesDialog"));
archCfg.writeEntry("LastUseOutputDir", mUseOutputDir);
}
auto sign = !mWidget->signUserId().isNull();
auto encrypt = !mWidget->selfUserId().isNull() || !mWidget->recipients().empty();
if (!mWidget->validate()) {
return;
}
if (DeVSCompliance::isActive() && !DeVSCompliance::isCompliant()) {
KMessageBox::error(topLevelWidget(),
xi18nc("@info %1 is a placeholder for the name of a compliance mode. E.g. NATO RESTRICTED compliant or VS-NfD compliant",
"<para>Sorry! You cannot use <application>Kleopatra</application> for signing or encrypting files "
"because the <application>GnuPG</application> system used by <application>Kleopatra</application> is not %1.</para>",
DeVSCompliance::name(true)));
return;
}
if (sign && !encrypt && mArchive) {
auto status = KMessageBox::warningContinueCancel(
this,
xi18nc("@info",
"<para>Archiving in combination with sign-only currently requires what are known as opaque signatures - "
"unlike detached ones, these embed the content in the signature.</para>"
"<para>This format is rather unusual. You might want to archive the files separately, "
"and then sign the archive as one file with Kleopatra.</para>"
"<para>Future versions of Kleopatra are expected to also support detached signatures in this case.</para>"),
i18nc("@title:window", "Unusual Signature Warning"),
KStandardGuiItem::cont(),
KStandardGuiItem::cancel(),
QStringLiteral("signencryptfileswizard-archive+sign-only-warning"));
if (status != KMessageBox::Continue) {
return;
}
}
if (encrypt && !mWidget->encryptSymmetric() && std::ranges::none_of(recipients(), [](const auto &k) {
return k.hasSecret();
})) {
if (KMessageBox::warningContinueCancel(this,
xi18nc("@info",
"<para>None of the recipients you are encrypting to seems to be your own.</para>"
"<para>This means that you will not be able to decrypt the data anymore, once encrypted.</para>"
"<para>Do you want to continue, or cancel to change the recipient selection?</para>"),
i18nc("@title:window", "Encrypt-To-Self Warning"),
KStandardGuiItem::cont(),
KStandardGuiItem::cancel(),
QStringLiteral("warn-encrypt-to-non-self"),
KMessageBox::Notify | KMessageBox::Dangerous)
== KMessageBox::Cancel) {
return;
}
}
Q_EMIT finished();
}
bool isDeVsAndValid() const
{
return mWidget->isDeVsAndValid();
}
private:
struct RequesterInfo {
SignEncryptFilesDialog::KindNames id;
QString icon;
QString toolTip;
QString accessibleName;
QString nameFilterBinary;
QString nameFilterAscii;
};
void createRequesters(QBoxLayout *lay)
{
static const std::array<RequesterInfo, 6> requestersInfo = {{
{
SignEncryptFilesDialog::SignatureCMS,
QStringLiteral("document-sign"),
i18nc("@info:tooltip", "This is the filename of the S/MIME signature."),
i18nc("Lineedit accessible name", "S/MIME signature file"),
i18nc("Name filter binary", "S/MIME Signatures (*.p7s)"),
i18nc("Name filter ASCII", "S/MIME Signatures (*.p7s *.pem)"),
},
{
SignEncryptFilesDialog::SignaturePGP,
QStringLiteral("document-sign"),
i18nc("@info:tooltip", "This is the filename of the detached OpenPGP signature."),
i18nc("Lineedit accessible name", "OpenPGP signature file"),
i18nc("Name filter binary", "OpenPGP Signatures (*.sig *.pgp)"),
i18nc("Name filter ASCII", "OpenPGP Signatures (*.asc *.sig)"),
},
{
SignEncryptFilesDialog::CombinedPGP,
QStringLiteral("document-edit-sign-encrypt"),
i18nc("@info:tooltip", "This is the filename of the OpenPGP-signed and encrypted file."),
i18nc("Lineedit accessible name", "OpenPGP signed and encrypted file"),
i18nc("Name filter binary", "OpenPGP Files (*.gpg *.pgp)"),
i18nc("Name filter ASCII", "OpenPGP Files (*.asc)"),
},
{
SignEncryptFilesDialog::EncryptedPGP,
QStringLiteral("document-encrypt"),
i18nc("@info:tooltip", "This is the filename of the OpenPGP encrypted file."),
i18nc("Lineedit accessible name", "OpenPGP encrypted file"),
i18nc("Name filter binary", "OpenPGP Files (*.gpg *.pgp)"),
i18nc("Name filter ASCII", "OpenPGP Files (*.asc)"),
},
{
SignEncryptFilesDialog::EncryptedCMS,
QStringLiteral("document-encrypt"),
i18nc("@info:tooltip", "This is the filename of the S/MIME encrypted file."),
i18nc("Lineedit accessible name", "S/MIME encrypted file"),
i18nc("Name filter binary", "S/MIME Files (*.p7m)"),
i18nc("Name filter ASCII", "S/MIME Files (*.p7m *.pem)"),
},
{
SignEncryptFilesDialog::Directory,
QStringLiteral("folder"),
i18nc("@info:tooltip", "The resulting files are written to this directory."),
i18nc("Lineedit accessible name", "Output directory"),
{},
{},
},
}};
if (!mRequesters.empty()) {
return;
}
const bool isAscii = FileOperationsPreferences().addASCIIArmor();
for (const auto &requester : requestersInfo) {
const auto id = requester.id;
auto requesterWithIcon = new FileNameRequesterWithIcon{id == SignEncryptFilesDialog::Directory ? QDir::Dirs : QDir::Files, this};
requesterWithIcon->setIcon(QIcon::fromTheme(requester.icon));
requesterWithIcon->setToolTip(requester.toolTip);
requesterWithIcon->requester()->setAccessibleNameOfLineEdit(requester.accessibleName);
requesterWithIcon->setNameFilter(isAscii ? requester.nameFilterAscii : requester.nameFilterBinary);
lay->addWidget(requesterWithIcon);
connect(requesterWithIcon, &FileNameRequesterWithIcon::fileNameChanged, this, [this, id](const QString &newName) {
mOutNames[id] = newName;
});
mRequesters.insert(id, requesterWithIcon);
}
}
public:
void setOutputNames(const QMap<int, QString> &names)
{
Q_ASSERT(mOutNames.isEmpty());
for (auto it = std::begin(names); it != std::end(names); ++it) {
mRequesters.value(it.key())->setFileName(it.value());
}
mOutNames = names;
updateFileWidgets();
}
QMap<int, QString> outputNames() const
{
if (!mUseOutputDir) {
auto ret = mOutNames;
ret.remove(SignEncryptFilesDialog::Directory);
return ret;
}
return mOutNames;
}
bool encryptSymmetric() const
{
return mWidget->encryptSymmetric();
}
private Q_SLOTS:
void updateFileWidgets()
{
if (mRequesters.isEmpty()) {
return;
}
const std::vector<Key> recipients = mWidget->recipients();
const Key sigKey = mWidget->signUserId().parent();
const bool pgp = mWidget->encryptSymmetric() || std::any_of(std::cbegin(recipients), std::cend(recipients), [](const auto &k) {
return k.protocol() == Protocol::OpenPGP;
});
const bool cms = std::any_of(std::cbegin(recipients), std::cend(recipients), [](const auto &k) {
return k.protocol() == Protocol::CMS;
});
mOutLayout->setEnabled(false);
if (cms || pgp || !sigKey.isNull()) {
mPlaceholderWidget->setVisible(false);
mOutputLabel->setVisible(true);
mRequesters[SignEncryptFilesDialog::SignatureCMS]->setVisible(!mUseOutputDir && sigKey.protocol() == Protocol::CMS);
mRequesters[SignEncryptFilesDialog::EncryptedCMS]->setVisible(!mUseOutputDir && cms);
mRequesters[SignEncryptFilesDialog::CombinedPGP]->setVisible(!mUseOutputDir && sigKey.protocol() == Protocol::OpenPGP && pgp);
mRequesters[SignEncryptFilesDialog::EncryptedPGP]->setVisible(!mUseOutputDir && sigKey.protocol() != Protocol::OpenPGP && pgp);
mRequesters[SignEncryptFilesDialog::SignaturePGP]->setVisible(!mUseOutputDir && sigKey.protocol() == Protocol::OpenPGP && !pgp);
mRequesters[SignEncryptFilesDialog::Directory]->setVisible(mUseOutputDir);
auto firstNotHidden = std::find_if(std::cbegin(mRequesters), std::cend(mRequesters), [](auto w) {
return !w->isHidden();
});
mOutputLabel->setBuddy(*firstNotHidden);
} else {
mPlaceholderWidget->setVisible(true);
mOutputLabel->setVisible(false);
std::for_each(std::cbegin(mRequesters), std::cend(mRequesters), [](auto w) {
w->setVisible(false);
});
mOutputLabel->setBuddy(nullptr);
}
mOutLayout->setEnabled(true);
Q_EMIT checkReady(mWidget->currentOp());
}
Q_SIGNALS:
void finished();
void checkReady(SignEncryptWidget::Operations op);
private:
SignEncryptWidget *mWidget;
QMap<int, QString> mOutNames;
QMap<int, FileNameRequesterWithIcon *> mRequesters;
QVBoxLayout *mOutLayout;
QWidget *mPlaceholderWidget;
QCheckBox *mUseOutputDirChk;
QLabel *mOutputLabel;
bool mArchive;
bool mUseOutputDir;
bool mSingleFile;
};
class SignEncryptResultPage : public Kleo::Crypto::Gui::ResultPage
{
Q_OBJECT
public:
explicit SignEncryptResultPage(QWidget *parent = nullptr)
: ResultPage(parent)
{
setTitle(i18nc("@title", "Results"));
setSubTitle(i18nc("@title", "Status and progress of the crypto operations is shown here."));
}
};
SignEncryptFilesDialog::SignEncryptFilesDialog(QWidget *parent, Qt::WindowFlags f)
: QDialog(parent, f)
{
readConfig();
setWindowTitle(i18nc("@title", "Sign / Encrypt Files"));
mSigEncPage = new SigEncPage;
mResultPage = new SignEncryptResultPage(this);
mResultPage->setVisible(false);
auto layout = new QVBoxLayout(this);
auto title = new KTitleWidget;
title->setText(i18nc("@title:dialog", "Sign / Encrypt Files"));
layout->addWidget(title);
auto stackedLayout = new QStackedLayout;
stackedLayout->addWidget(mSigEncPage);
stackedLayout->addWidget(mResultPage);
layout->addLayout(stackedLayout);
auto buttons = new QDialogButtonBox;
QPushButton *labelButton = nullptr;
if (DeVSCompliance::isActive()) {
/* We use a custom button to display a label next to the
buttons. */
labelButton = buttons->addButton(QString(), QDialogButtonBox::ActionRole);
/* We style the button so that it looks and acts like a
label. */
labelButton->setStyleSheet(QStringLiteral("border: none"));
labelButton->setFocusPolicy(Qt::NoFocus);
}
auto okButton = buttons->addButton(i18nc("@action:button", "Continue"), QDialogButtonBox::ActionRole);
auto cancelButton = buttons->addButton(QDialogButtonBox::Cancel);
connect(cancelButton, &QPushButton::clicked, this, &QDialog::reject);
connect(okButton, &QPushButton::clicked, this, [this]() {
mSigEncPage->done();
});
connect(mSigEncPage, &SigEncPage::finished, this, [this, title, okButton, stackedLayout]() {
if (stackedLayout->currentIndex() == 0) {
stackedLayout->setCurrentIndex(1);
Q_EMIT operationPrepared();
title->setText(i18nc("@title:dialog", "Results"));
okButton->setText(i18nc("@action:button", "Finish"));
} else {
accept();
}
});
connect(mSigEncPage, &SigEncPage::checkReady, this, [this, okButton, labelButton](const auto op) {
QString label;
switch (op) {
case SignEncryptWidget::Sign:
label = i18nc("@action:button", "Sign");
break;
case SignEncryptWidget::Encrypt:
label = i18nc("@action:button", "Encrypt");
break;
case SignEncryptWidget::SignAndEncrypt:
label = i18nc("@action:button", "Sign / Encrypt");
break;
default:;
};
if (!label.isEmpty()) {
okButton->setText(label);
if (DeVSCompliance::isActive()) {
const bool de_vs = DeVSCompliance::isCompliant() && mSigEncPage->isDeVsAndValid();
DeVSCompliance::decorate(okButton, de_vs);
okButton->setToolTip(DeVSCompliance::name(de_vs));
labelButton->setText(DeVSCompliance::name(de_vs));
}
} else {
okButton->setText(i18nc("@action:button", "Next"));
okButton->setIcon(QIcon());
okButton->setStyleSheet(QString());
}
okButton->setEnabled(mSigEncPage->validatePage());
});
layout->addWidget(buttons);
}
SignEncryptFilesDialog::~SignEncryptFilesDialog()
{
qCDebug(KLEOPATRA_LOG) << this << __func__;
writeConfig();
}
void SignEncryptFilesDialog::setSigningPreset(bool preset)
{
mSigEncPage->setSigningPreset(preset);
}
void SignEncryptFilesDialog::setSigningUserMutable(bool mut)
{
if (mut == mSigningUserMutable) {
return;
}
mSigningUserMutable = mut;
}
void SignEncryptFilesDialog::setEncryptionPreset(bool preset)
{
mSigEncPage->setEncryptionPreset(preset);
}
void SignEncryptFilesDialog::setEncryptionUserMutable(bool mut)
{
if (mut == mEncryptionUserMutable) {
return;
}
mEncryptionUserMutable = mut;
}
void SignEncryptFilesDialog::setArchiveForced(bool archive)
{
mSigEncPage->setArchiveForced(archive);
}
void SignEncryptFilesDialog::setArchiveMutable(bool archive)
{
mSigEncPage->setArchiveMutable(archive);
}
void SignEncryptFilesDialog::setSingleFile(bool singleFile)
{
mSigEncPage->setSingleFile(singleFile);
}
std::vector<Key> SignEncryptFilesDialog::resolvedRecipients() const
{
return mSigEncPage->recipients();
}
std::vector<Key> SignEncryptFilesDialog::resolvedSigners() const
{
return mSigEncPage->signers();
}
void SignEncryptFilesDialog::setTaskCollection(const std::shared_ptr<Kleo::Crypto::TaskCollection> &coll)
{
mResultPage->setTaskCollection(coll);
}
void SignEncryptFilesDialog::setOutputNames(const QMap<int, QString> &map) const
{
mSigEncPage->setOutputNames(map);
}
QMap<int, QString> SignEncryptFilesDialog::outputNames() const
{
return mSigEncPage->outputNames();
}
bool SignEncryptFilesDialog::encryptSymmetric() const
{
return mSigEncPage->encryptSymmetric();
}
void SignEncryptFilesDialog::readConfig()
{
KConfigGroup dialog(KSharedConfig::openStateConfig(), QStringLiteral("SignEncryptFilesWizard"));
const QSize size = dialog.readEntry("Size", QSize(640, 480));
if (size.isValid()) {
resize(size);
}
}
void SignEncryptFilesDialog::writeConfig()
{
KConfigGroup dialog(KSharedConfig::openStateConfig(), QStringLiteral("SignEncryptFilesWizard"));
dialog.writeEntry("Size", size());
dialog.sync();
}
#include "signencryptfilesdialog.moc"
#include "moc_signencryptfilesdialog.cpp"
diff --git a/src/dialogs/addsubkeydialog.cpp b/src/dialogs/addsubkeydialog.cpp
index e1e16bfaf..d6fa6ce7a 100644
--- a/src/dialogs/addsubkeydialog.cpp
+++ b/src/dialogs/addsubkeydialog.cpp
@@ -1,272 +1,274 @@
/* -*- mode: c++; c-basic-offset:4 -*-
This file is part of Kleopatra, the KDE keymanager
SPDX-FileCopyrightText: 2008 Klarälvdalens Datakonsult AB
SPDX-FileCopyrightText: 2021-2023 g10 Code GmbH
SPDX-FileContributor: Ingo Klöcker <dev@ingo-kloecker.de>
SPDX-FileContributor: Tobias Fella <tobias.fella@gnupg.com>
SPDX-License-Identifier: GPL-2.0-or-later
*/
#include "addsubkeydialog.h"
#include "utils/gui-helper.h"
-#include "utils/scrollarea.h"
#include <Libkleo/Compat>
#include <Libkleo/Compliance>
#include <Libkleo/Expiration>
#include <Libkleo/Formatting>
#include <Libkleo/GnuPG>
+#include <KAdjustingScrollArea>
#include <KConfigGroup>
#include <KDateComboBox>
#include <KLocalizedString>
#include <KMessageBox>
#include <KSharedConfig>
#include <KStandardGuiItem>
#include <QGpgME/CryptoConfig>
#include <QGpgME/Protocol>
#include <QCheckBox>
#include <QDate>
#include <QDialogButtonBox>
#include <QFormLayout>
#include <QGroupBox>
#include <QHBoxLayout>
#include <QLabel>
#include <QPushButton>
#include <QRadioButton>
#include <QVBoxLayout>
#include <gpgme++/key.h>
using namespace Kleo;
using namespace Kleo::Dialogs;
using namespace GpgME;
class AddSubkeyDialog::Private
{
AddSubkeyDialog *const q;
public:
Private(AddSubkeyDialog *qq)
: q{qq}
, ui{qq}
{
}
struct UI {
QComboBox *keyAlgoCB = nullptr;
QRadioButton *signingCB = nullptr;
QRadioButton *encryptionCB = nullptr;
QRadioButton *authenticationCB = nullptr;
QCheckBox *expiryCB = nullptr;
KDateComboBox *expiryDE = nullptr;
QLabel *primaryKeyExpiration = nullptr;
QDialogButtonBox *buttonBox = nullptr;
UI(QDialog *parent)
{
parent->setWindowTitle(i18nc("@title:window", "Advanced Settings"));
const auto mainLayout = new QVBoxLayout{parent};
- const auto scrollArea = new ScrollArea{parent};
+ const auto scrollArea = new KAdjustingScrollArea{parent};
{
scrollArea->setFocusPolicy(Qt::NoFocus);
scrollArea->setFrameStyle(QFrame::NoFrame);
scrollArea->setBackgroundRole(parent->backgroundRole());
scrollArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
scrollArea->setSizeAdjustPolicy(QScrollArea::AdjustToContents);
- const auto scrollLayout = qobject_cast<QVBoxLayout *>(scrollArea->widget()->layout());
+ auto widget = new QWidget;
+ scrollArea->setWidget(widget);
+ auto scrollLayout = new QVBoxLayout(widget);
{
const auto groupBox = new QGroupBox{i18nc("@title:group", "Key Material"), scrollArea};
const auto formLayout = new QFormLayout(groupBox);
keyAlgoCB = new QComboBox(groupBox);
formLayout->addRow(i18n("Algorithm:"), keyAlgoCB);
scrollLayout->addWidget(groupBox);
}
{
const auto groupBox = new QGroupBox{i18nc("@title:group", "Certificate Usage"), scrollArea};
const auto usageLayout = new QVBoxLayout;
signingCB = new QRadioButton{i18nc("@option:check", "Signing"), groupBox};
usageLayout->addWidget(signingCB);
encryptionCB = new QRadioButton{i18nc("@option:check", "Encryption"), groupBox};
encryptionCB->setChecked(true);
usageLayout->addWidget(encryptionCB);
authenticationCB = new QRadioButton{i18nc("@option:check", "Authentication"), groupBox};
usageLayout->addWidget(authenticationCB);
{
const auto hbox = new QHBoxLayout;
expiryCB = new QCheckBox{i18nc("@option:check", "Valid until:"), groupBox};
expiryCB->setChecked(true);
hbox->addWidget(expiryCB);
expiryDE = new KDateComboBox(groupBox);
hbox->addWidget(expiryDE, 1);
connect(expiryCB, &QCheckBox::toggled, expiryDE, &KDateComboBox::setEnabled);
usageLayout->addLayout(hbox);
}
primaryKeyExpiration = new QLabel(groupBox);
primaryKeyExpiration->setVisible(false);
usageLayout->addWidget(primaryKeyExpiration);
groupBox->setLayout(usageLayout);
scrollLayout->addWidget(groupBox);
}
scrollLayout->addStretch(1);
}
mainLayout->addWidget(scrollArea);
buttonBox = new QDialogButtonBox{parent};
buttonBox->setStandardButtons(QDialogButtonBox::Cancel | QDialogButtonBox::Ok);
mainLayout->addWidget(buttonBox);
}
} ui;
};
AddSubkeyDialog::AddSubkeyDialog(const GpgME::Key &parent, QWidget *p)
: QDialog{p}
, d{new Private{this}}
{
setWindowTitle(i18nc("@title:window", "Add Subkey"));
d->ui.expiryCB->setEnabled(unlimitedValidityIsAllowed());
if (!parent.subkey(0).neverExpires()) {
d->ui.expiryDE->setMaximumDate(Kleo::Formatting::expirationDate(parent));
d->ui.primaryKeyExpiration->setText(i18n("Expiration of primary key: %1", Kleo::Formatting::expirationDateString(parent)));
d->ui.primaryKeyExpiration->setVisible(true);
}
d->ui.expiryDE->setMinimumDate(QDate::currentDate());
loadDefaults();
connect(d->ui.buttonBox, &QDialogButtonBox::accepted, this, &AddSubkeyDialog::accept);
connect(d->ui.buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject);
}
AddSubkeyDialog::~AddSubkeyDialog() = default;
bool AddSubkeyDialog::unlimitedValidityIsAllowed() const
{
return !Expiration::maximumExpirationDate().isValid();
}
void AddSubkeyDialog::setKeyType(const QString &algorithm)
{
const auto index = d->ui.keyAlgoCB->findData(algorithm);
if (index != -1) {
d->ui.keyAlgoCB->setCurrentIndex(index);
}
}
void AddSubkeyDialog::loadDefaults()
{
setExpiryDate(defaultExpirationDate(unlimitedValidityIsAllowed() ? Expiration::ExpirationOnUnlimitedValidity::NoExpiration
: Expiration::ExpirationOnUnlimitedValidity::InternalDefaultExpiration));
loadAlgorithms();
loadDefaultKeyType();
}
void AddSubkeyDialog::replaceEntry(const QString &before, const QString &after)
{
const auto currentIndex = d->ui.keyAlgoCB->currentIndex();
const auto index = d->ui.keyAlgoCB->findData(before);
if (index != -1) {
d->ui.keyAlgoCB->removeItem(index);
d->ui.keyAlgoCB->insertItem(index, after, after);
d->ui.keyAlgoCB->setCurrentIndex(currentIndex);
}
}
void AddSubkeyDialog::loadDefaultKeyType()
{
if (DeVSCompliance::isActive()) {
for (const auto &algorithm : DeVSCompliance::preferredCompliantAlgorithms()) {
if (d->ui.keyAlgoCB->findData(QString::fromStdString(algorithm)) != -1) {
setKeyType(QString::fromStdString(algorithm));
break;
}
}
return;
}
}
QDate AddSubkeyDialog::forceDateIntoAllowedRange(QDate date) const
{
const auto minDate = d->ui.expiryDE->minimumDate();
if (minDate.isValid() && date < minDate) {
date = minDate;
}
const auto maxDate = d->ui.expiryDE->maximumDate();
if (maxDate.isValid() && date > maxDate) {
date = maxDate;
}
return date;
}
void AddSubkeyDialog::setExpiryDate(QDate date)
{
if (date.isValid()) {
d->ui.expiryDE->setDate(forceDateIntoAllowedRange(date));
} else {
if (unlimitedValidityIsAllowed()) {
d->ui.expiryDE->setDate(date);
}
}
if (d->ui.expiryCB->isEnabled()) {
d->ui.expiryCB->setChecked(d->ui.expiryDE->isValid());
}
}
KeyUsage AddSubkeyDialog::usage() const
{
if (d->ui.signingCB->isChecked()) {
return KeyUsage(KeyUsage::Sign);
}
if (d->ui.encryptionCB->isChecked()) {
return KeyUsage(KeyUsage::Encrypt);
}
return KeyUsage(KeyUsage::Authenticate);
}
QString AddSubkeyDialog::algo() const
{
return d->ui.keyAlgoCB->currentData().toString();
}
QDate AddSubkeyDialog::expires() const
{
return d->ui.expiryCB->isChecked() ? d->ui.expiryDE->date() : QDate();
}
void AddSubkeyDialog::loadAlgorithms()
{
if (!DeVSCompliance::isActive()) {
d->ui.keyAlgoCB->addItem(i18nc("Default Algorithm", "Default"), QLatin1StringView("default"));
}
for (const auto &algorithm : DeVSCompliance::isActive() ? DeVSCompliance::compliantAlgorithms() : availableAlgorithms()) {
d->ui.keyAlgoCB->addItem(Formatting::prettyAlgorithmName(algorithm), QString::fromStdString(algorithm));
}
d->ui.keyAlgoCB->setCurrentIndex(0);
}
#include "moc_addsubkeydialog.cpp"
diff --git a/src/dialogs/adduseriddialog.cpp b/src/dialogs/adduseriddialog.cpp
index d45bc0c56..24a8dd5a6 100644
--- a/src/dialogs/adduseriddialog.cpp
+++ b/src/dialogs/adduseriddialog.cpp
@@ -1,192 +1,194 @@
/* -*- 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 <dev@ingo-kloecker.de>
SPDX-License-Identifier: GPL-2.0-or-later
*/
#include <config-kleopatra.h>
#include "adduseriddialog.h"
#include "utils/accessibility.h"
-#include "utils/scrollarea.h"
#include "view/htmllabel.h"
#include <Libkleo/NameAndEmailWidget>
+#include <KAdjustingScrollArea>
#include <KConfigGroup>
#include <KLocalizedString>
#include <KMessageBox>
#include <KSeparator>
#include <KSharedConfig>
#include <QDialogButtonBox>
#include <QLabel>
#include <QVBoxLayout>
#include "kleopatra_debug.h"
using namespace Kleo;
class AddUserIDDialog::Private
{
friend class ::Kleo::AddUserIDDialog;
AddUserIDDialog *const q;
struct {
- ScrollArea *scrollArea;
+ KAdjustingScrollArea *scrollArea;
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(), QLatin1StringView("CertificateCreationWizard")};
const auto attrOrder = config.readEntry("OpenPGPAttributeOrder", QStringList{});
const auto nameIsRequired = attrOrder.contains(QLatin1StringView{"NAME!"}, Qt::CaseInsensitive);
const auto emailIsRequired = attrOrder.contains(QLatin1StringView{"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 = new KAdjustingScrollArea{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<QBoxLayout *>(ui.scrollArea->widget()->layout());
+ auto widget = new QWidget;
+ ui.scrollArea->setWidget(widget);
+ auto scrollAreaLayout = new QVBoxLayout(widget);
scrollAreaLayout->setContentsMargins(0, 0, 0, 0);
ui.nameAndEmail = new NameAndEmailWidget{q};
ui.nameAndEmail->layout()->setContentsMargins(0, 0, 0, 0);
ui.nameAndEmail->setNameIsRequired(nameIsRequired);
ui.nameAndEmail->setNameLabel(config.readEntry("NAME_label"));
ui.nameAndEmail->setNameHint(config.readEntry("NAME_hint", config.readEntry("NAME_placeholder")));
ui.nameAndEmail->setNamePattern(config.readEntry("NAME_regex"));
ui.nameAndEmail->setEmailIsRequired(emailIsRequired);
ui.nameAndEmail->setEmailLabel(config.readEntry("EMAIL_label"));
ui.nameAndEmail->setEmailHint(config.readEntry("EMAIL_hint", config.readEntry("EMAIL_placeholder")));
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();
}
private:
void checkAccept()
{
QStringList errors;
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.nameAndEmail->nameError();
if (!nameError.isEmpty()) {
errors.push_back(nameError);
}
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",
"<div>This is how the new user ID will be stored in the certificate:</div>"
"<center><strong>%1</strong></center>",
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.nameAndEmail->setName(name);
}
QString AddUserIDDialog::name() const
{
return d->ui.nameAndEmail->name();
}
void AddUserIDDialog::setEmail(const QString &email)
{
d->ui.nameAndEmail->setEmail(email);
}
QString AddUserIDDialog::email() const
{
return d->ui.nameAndEmail->email();
}
QString AddUserIDDialog::userID() const
{
return d->ui.nameAndEmail->userID();
}
#include "moc_adduseriddialog.cpp"
diff --git a/src/dialogs/selftestdialog.cpp b/src/dialogs/selftestdialog.cpp
index 834779f1b..ed4bd2211 100644
--- a/src/dialogs/selftestdialog.cpp
+++ b/src/dialogs/selftestdialog.cpp
@@ -1,491 +1,495 @@
/* -*- mode: c++; c-basic-offset:4 -*-
dialogs/selftestdialog.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 "selftestdialog.h"
#include <selftest/selftest.h>
#include <utils/accessibility.h>
-#include <utils/scrollarea.h>
#include <Libkleo/SystemInfo>
#include <Libkleo/TreeView>
+#include <KAdjustingScrollArea>
#include <KColorScheme>
#include <KLocalizedString>
#include <QAbstractTableModel>
#include <QApplication>
#include <QCheckBox>
#include <QDialogButtonBox>
#include <QGroupBox>
#include <QHBoxLayout>
#include <QHeaderView>
#include <QLabel>
#include <QPushButton>
#include <QSortFilterProxyModel>
#include <QSplitter>
#include <QVBoxLayout>
#include "kleopatra_debug.h"
using namespace Kleo;
using namespace Kleo::Dialogs;
namespace
{
class Model : public QAbstractTableModel
{
Q_OBJECT
public:
explicit Model(QObject *parent = nullptr)
: QAbstractTableModel(parent)
, m_tests()
{
}
enum Column {
TestName,
TestResult,
NumColumns
};
const std::shared_ptr<SelfTest> &fromModelIndex(const QModelIndex &idx) const
{
const unsigned int row = idx.row();
if (row < m_tests.size()) {
return m_tests[row];
}
static const std::shared_ptr<SelfTest> null;
return null;
}
int rowCount(const QModelIndex &idx) const override
{
return idx.isValid() ? 0 : m_tests.size();
}
int columnCount(const QModelIndex &) const override
{
return NumColumns;
}
QVariant data(const QModelIndex &idx, int role) const override
{
const unsigned int row = idx.row();
if (idx.isValid() && row < m_tests.size())
switch (role) {
case Qt::DisplayRole:
case Qt::ToolTipRole:
switch (idx.column()) {
case TestName:
return m_tests[row]->name();
case TestResult:
return m_tests[row]->skipped() ? i18n("Skipped") //
: m_tests[row]->passed() ? i18n("Passed")
: m_tests[row]->shortError();
}
break;
case Qt::BackgroundRole:
if (!SystemInfo::isHighContrastModeActive()) {
KColorScheme scheme(qApp->palette().currentColorGroup());
return (m_tests[row]->skipped() ? scheme.background(KColorScheme::NeutralBackground)
: m_tests[row]->passed() ? scheme.background(KColorScheme::PositiveBackground)
: scheme.background(KColorScheme::NegativeBackground))
.color();
}
}
return QVariant();
}
QVariant headerData(int section, Qt::Orientation o, int role) const override
{
if (o == Qt::Horizontal && section >= 0 && section < NumColumns && role == Qt::DisplayRole)
switch (section) {
case TestName:
return i18n("Test Name");
case TestResult:
return i18n("Result");
}
return QVariant();
}
void clear()
{
if (m_tests.empty()) {
return;
}
beginRemoveRows(QModelIndex(), 0, m_tests.size() - 1);
m_tests.clear();
endRemoveRows();
}
void append(const std::vector<std::shared_ptr<SelfTest>> &tests)
{
if (tests.empty()) {
return;
}
beginInsertRows(QModelIndex(), m_tests.size(), m_tests.size() + tests.size());
m_tests.insert(m_tests.end(), tests.begin(), tests.end());
endInsertRows();
}
void reloadData()
{
if (!m_tests.empty()) {
Q_EMIT dataChanged(index(0, 0), index(m_tests.size() - 1, NumColumns - 1));
}
}
const std::shared_ptr<SelfTest> &at(unsigned int idx) const
{
return m_tests.at(idx);
}
private:
std::vector<std::shared_ptr<SelfTest>> m_tests;
};
class Proxy : public QSortFilterProxyModel
{
Q_OBJECT
public:
explicit Proxy(QObject *parent = nullptr)
: QSortFilterProxyModel(parent)
, m_showAll(true)
{
}
bool showAll() const
{
return m_showAll;
}
Q_SIGNALS:
void showAllChanged(bool);
public Q_SLOTS:
void setShowAll(bool on)
{
if (on == m_showAll) {
return;
}
m_showAll = on;
invalidateFilter();
Q_EMIT showAllChanged(on);
}
private:
bool filterAcceptsRow(int src_row, const QModelIndex &src_parent) const override
{
if (m_showAll) {
return true;
}
if (const Model *const model = qobject_cast<Model *>(sourceModel())) {
if (!src_parent.isValid() && src_row >= 0 && src_row < model->rowCount(src_parent)) {
if (const std::shared_ptr<SelfTest> &t = model->at(src_row)) {
return !t->passed();
} else {
qCWarning(KLEOPATRA_LOG) << "NULL test??";
}
} else {
if (src_parent.isValid()) {
qCWarning(KLEOPATRA_LOG) << "view asks for subitems!";
} else {
qCWarning(KLEOPATRA_LOG) << "index " << src_row << " is out of range [" << 0 << "," << model->rowCount(src_parent) << "]";
}
}
} else {
qCWarning(KLEOPATRA_LOG) << "expected a ::Model, got ";
if (!sourceModel()) {
qCWarning(KLEOPATRA_LOG) << "a null pointer";
} else {
qCWarning(KLEOPATRA_LOG) << sourceModel()->metaObject()->className();
}
}
return false;
}
private:
bool m_showAll;
};
}
class SelfTestDialog::Private
{
friend class ::Kleo::Dialogs::SelfTestDialog;
SelfTestDialog *const q;
public:
explicit Private(SelfTestDialog *qq)
: q(qq)
, model(q)
, proxy(q)
, ui(q)
{
proxy.setSourceModel(&model);
ui.resultsTV->setModel(&proxy);
ui.detailsGB->hide();
ui.proposedCorrectiveActionGB->hide();
connect(ui.buttonBox, &QDialogButtonBox::accepted, q, &QDialog::accept);
connect(ui.buttonBox, &QDialogButtonBox::rejected, q, &QDialog::reject);
connect(ui.doItPB, &QAbstractButton::clicked, q, [this]() {
slotDoItClicked();
});
connect(ui.rerunPB, &QAbstractButton::clicked, q, &SelfTestDialog::updateRequested);
connect(ui.resultsTV->selectionModel(), &QItemSelectionModel::selectionChanged, q, [this]() {
slotSelectionChanged();
});
connect(ui.showAllCB, &QAbstractButton::toggled, q, [this](bool checked) {
proxy.setShowAll(checked);
if (checked) {
updateColumnSizes();
}
ensureCurrentItemIsVisible();
});
proxy.setShowAll(ui.showAllCB->isChecked());
ui.resultsTV->setFocus();
}
private:
void slotSelectionChanged()
{
const int row = selectedRowIndex();
if (row < 0) {
ui.detailsLB->setText(i18n("(select test first)"));
ui.detailsGB->hide();
ui.proposedCorrectiveActionGB->hide();
} else {
const std::shared_ptr<SelfTest> &t = model.at(row);
ui.detailsLB->setText(t->longError());
ui.detailsGB->setVisible(!t->passed());
const QString action = t->proposedFix();
ui.proposedCorrectiveActionGB->setVisible(!t->passed() && !action.isEmpty());
ui.proposedCorrectiveActionLB->setText(action);
ui.doItPB->setVisible(!t->passed() && t->canFixAutomatically());
QMetaObject::invokeMethod(
q,
[this]() {
ensureCurrentItemIsVisible();
},
Qt::QueuedConnection);
}
}
void slotDoItClicked()
{
if (const std::shared_ptr<SelfTest> st = model.fromModelIndex(selectedRow()))
if (st->fix()) {
model.reloadData();
}
}
private:
void ensureCurrentItemIsVisible()
{
ui.resultsTV->scrollTo(ui.resultsTV->currentIndex());
}
void updateColumnSizes()
{
ui.resultsTV->resizeToContentsLimited();
}
private:
QModelIndex selectedRow() const
{
const QItemSelectionModel *const ism = ui.resultsTV->selectionModel();
if (!ism) {
return QModelIndex();
}
const QModelIndexList mil = ism->selectedRows();
return mil.empty() ? QModelIndex() : proxy.mapToSource(mil.front());
}
int selectedRowIndex() const
{
return selectedRow().row();
}
private:
Model model;
Proxy proxy;
struct UI {
TreeView *resultsTV = nullptr;
QCheckBox *showAllCB = nullptr;
QGroupBox *detailsGB = nullptr;
QLabel *detailsLB = nullptr;
QGroupBox *proposedCorrectiveActionGB = nullptr;
QLabel *proposedCorrectiveActionLB = nullptr;
QPushButton *doItPB = nullptr;
QCheckBox *runAtStartUpCB;
QDialogButtonBox *buttonBox;
QPushButton *rerunPB = nullptr;
LabelHelper labelHelper;
explicit UI(SelfTestDialog *qq)
{
auto mainLayout = new QVBoxLayout{qq};
{
auto label = new QLabel{xi18nc("@info",
"<para>These are the results of the Kleopatra self-test suite. Click on a test for details.</para>"
"<para>Note that all but the first failure might be due to prior tests failing.</para>"),
qq};
label->setWordWrap(true);
labelHelper.addLabel(label);
mainLayout->addWidget(label);
}
auto splitter = new QSplitter{qq};
splitter->setOrientation(Qt::Vertical);
{
auto widget = new QWidget{qq};
auto vbox = new QVBoxLayout{widget};
vbox->setContentsMargins(0, 0, 0, 0);
resultsTV = new TreeView{qq};
resultsTV->setAccessibleName(i18n("test results"));
QSizePolicy sizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
sizePolicy.setHorizontalStretch(0);
sizePolicy.setVerticalStretch(1);
sizePolicy.setHeightForWidth(resultsTV->sizePolicy().hasHeightForWidth());
resultsTV->setSizePolicy(sizePolicy);
resultsTV->setMinimumHeight(100);
resultsTV->setRootIsDecorated(false);
resultsTV->setAllColumnsShowFocus(true);
vbox->addWidget(resultsTV);
splitter->addWidget(widget);
}
{
detailsGB = new QGroupBox{i18nc("@title:group", "Details"), qq};
auto groupBoxLayout = new QVBoxLayout{detailsGB};
- auto scrollArea = new Kleo::ScrollArea{qq};
+ auto scrollArea = new KAdjustingScrollArea{qq};
scrollArea->setFocusPolicy(Qt::NoFocus);
scrollArea->setMinimumHeight(100);
scrollArea->setFrameShape(QFrame::NoFrame);
scrollArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
- auto scrollAreaLayout = qobject_cast<QBoxLayout *>(scrollArea->widget()->layout());
+ auto widget = new QWidget;
+ scrollArea->setWidget(widget);
+ auto scrollAreaLayout = new QVBoxLayout(widget);
detailsLB = new QLabel{qq};
detailsLB->setTextFormat(Qt::RichText);
detailsLB->setTextInteractionFlags(Qt::TextSelectableByMouse);
detailsLB->setWordWrap(true);
labelHelper.addLabel(detailsLB);
scrollAreaLayout->addWidget(detailsLB);
scrollAreaLayout->addStretch();
groupBoxLayout->addWidget(scrollArea);
splitter->addWidget(detailsGB);
}
{
proposedCorrectiveActionGB = new QGroupBox{i18nc("@title:group", "Proposed Corrective Action"), qq};
auto groupBoxLayout = new QVBoxLayout{proposedCorrectiveActionGB};
- auto scrollArea = new Kleo::ScrollArea{qq};
+ auto scrollArea = new KAdjustingScrollArea{qq};
scrollArea->setFocusPolicy(Qt::NoFocus);
scrollArea->setMinimumHeight(100);
scrollArea->setFrameShape(QFrame::NoFrame);
scrollArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
- auto scrollAreaLayout = qobject_cast<QBoxLayout *>(scrollArea->widget()->layout());
+ auto widget = new QWidget;
+ scrollArea->setWidget(widget);
+ auto scrollAreaLayout = new QVBoxLayout(widget);
proposedCorrectiveActionLB = new QLabel{qq};
proposedCorrectiveActionLB->setTextFormat(Qt::RichText);
proposedCorrectiveActionLB->setTextInteractionFlags(Qt::TextSelectableByMouse);
proposedCorrectiveActionLB->setWordWrap(true);
labelHelper.addLabel(proposedCorrectiveActionLB);
scrollAreaLayout->addWidget(proposedCorrectiveActionLB);
scrollAreaLayout->addStretch();
groupBoxLayout->addWidget(scrollArea);
{
auto hbox = new QHBoxLayout;
hbox->addStretch();
doItPB = new QPushButton{i18nc("@action:button", "Do It"), qq};
doItPB->setEnabled(false);
hbox->addWidget(doItPB);
groupBoxLayout->addLayout(hbox);
}
splitter->addWidget(proposedCorrectiveActionGB);
}
mainLayout->addWidget(splitter);
showAllCB = new QCheckBox{i18nc("@option:check", "Show all test results"), qq};
showAllCB->setChecked(true);
mainLayout->addWidget(showAllCB);
runAtStartUpCB = new QCheckBox{i18nc("@option:check", "Run these tests at startup"), qq};
runAtStartUpCB->setChecked(true);
mainLayout->addWidget(runAtStartUpCB);
buttonBox = new QDialogButtonBox{qq};
buttonBox->setStandardButtons(QDialogButtonBox::Cancel | QDialogButtonBox::Close | QDialogButtonBox::Ok);
buttonBox->button(QDialogButtonBox::Ok)->setText(i18nc("@action:button", "Continue"));
rerunPB = buttonBox->addButton(i18nc("@action:button", "Rerun Tests"), QDialogButtonBox::ActionRole);
mainLayout->addWidget(buttonBox);
}
} ui;
};
SelfTestDialog::SelfTestDialog(QWidget *p, Qt::WindowFlags f)
: QDialog(p, f)
, d(new Private(this))
{
setWindowTitle(i18nc("@title:window", "Self Test"));
resize(448, 610);
setAutomaticMode(false);
}
SelfTestDialog::~SelfTestDialog() = default;
void SelfTestDialog::setTests(const std::vector<std::shared_ptr<SelfTest>> &tests)
{
d->model.clear();
d->model.append(tests);
d->updateColumnSizes();
}
void SelfTestDialog::setRunAtStartUp(bool on)
{
d->ui.runAtStartUpCB->setChecked(on);
}
bool SelfTestDialog::runAtStartUp() const
{
return d->ui.runAtStartUpCB->isChecked();
}
void SelfTestDialog::setAutomaticMode(bool automatic)
{
d->ui.showAllCB->setChecked(!automatic);
d->ui.buttonBox->button(QDialogButtonBox::Ok)->setVisible(automatic);
d->ui.buttonBox->button(QDialogButtonBox::Cancel)->setVisible(automatic);
d->ui.buttonBox->button(QDialogButtonBox::Close)->setVisible(!automatic);
}
#include "moc_selftestdialog.cpp"
#include "selftestdialog.moc"
diff --git a/src/newcertificatewizard/advancedsettingsdialog.cpp b/src/newcertificatewizard/advancedsettingsdialog.cpp
index aad747844..74fdf38e7 100644
--- a/src/newcertificatewizard/advancedsettingsdialog.cpp
+++ b/src/newcertificatewizard/advancedsettingsdialog.cpp
@@ -1,439 +1,439 @@
/* -*- mode: c++; c-basic-offset:4 -*-
newcertificatewizard/advancedsettingsdialog.cpp
This file is part of Kleopatra, the KDE keymanager
SPDX-FileCopyrightText: 2008 Klarälvdalens Datakonsult AB
SPDX-FileCopyrightText: 2016, 2017 Bundesamt für Sicherheit in der Informationstechnik
SPDX-FileContributor: Intevation GmbH
SPDX-FileCopyrightText: 2022 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 "advancedsettingsdialog_p.h"
#include "listwidget.h"
#include "utils/gui-helper.h"
-#include "utils/scrollarea.h"
#include <settings.h>
#include <Libkleo/Compat>
#include <Libkleo/Compliance>
#include <Libkleo/GnuPG>
+#include <KAdjustingScrollArea>
#include <KLocalizedString>
#include <QGpgME/CryptoConfig>
#include <QGpgME/Protocol>
#include <QCheckBox>
#include <QComboBox>
#include <QDialogButtonBox>
#include <QGridLayout>
#include <QGroupBox>
#include <QHBoxLayout>
#include <QLabel>
#include <QPushButton>
#include <QTabWidget>
#include <QVBoxLayout>
#include "kleopatra_debug.h"
using namespace Kleo;
using namespace Kleo::NewCertificateUi;
using namespace GpgME;
static const char RSA_KEYSIZES_ENTRY[] = "RSAKeySizes";
static const char RSA_KEYSIZE_LABELS_ENTRY[] = "RSAKeySizeLabels";
static const char CMS_KEY_TYPE_ENTRY[] = "CMSKeyType";
namespace
{
static void set_keysize(QComboBox *cb, unsigned int strength)
{
if (!cb) {
return;
}
const int idx = cb->findData(static_cast<int>(strength));
if (idx >= 0) {
cb->setCurrentIndex(idx);
}
}
static unsigned int get_keysize(const QComboBox *cb)
{
if (!cb) {
return 0;
}
const int idx = cb->currentIndex();
if (idx < 0) {
return 0;
}
return cb->itemData(idx).toInt();
}
static int parseSize(const QString &algoString)
{
const auto split = algoString.split(QLatin1Char('/'));
const auto lowered = split[0].toLower().remove(QLatin1Char('-'));
bool ok;
auto size = lowered.right(lowered.size() - 3).toInt(&ok);
if (ok) {
return size;
}
qCWarning(KLEOPATRA_LOG) << "Could not extract size from: " << lowered;
return 3072;
}
}
struct AdvancedSettingsDialog::UI {
QTabWidget *tabWidget = nullptr;
QComboBox *rsaKeyStrengthCB = nullptr;
QCheckBox *signingCB = nullptr;
QCheckBox *encryptionCB = nullptr;
- ScrollArea *personalTab = nullptr;
+ KAdjustingScrollArea *personalTab = nullptr;
QGroupBox *emailGB = nullptr;
Kleo::NewCertificateUi::ListWidget *emailLW = nullptr;
QGroupBox *dnsGB = nullptr;
Kleo::NewCertificateUi::ListWidget *dnsLW = nullptr;
QGroupBox *uriGB = nullptr;
Kleo::NewCertificateUi::ListWidget *uriLW = nullptr;
QDialogButtonBox *buttonBox = nullptr;
UI(QDialog *parent)
{
parent->setWindowTitle(i18nc("@title:window", "Advanced Settings"));
auto mainLayout = new QVBoxLayout{parent};
tabWidget = new QTabWidget{parent};
tabWidget->setDocumentMode(true);
{
- auto technicalTab = new ScrollArea{tabWidget};
+ auto technicalTab = new KAdjustingScrollArea{tabWidget};
technicalTab->setFocusPolicy(Qt::NoFocus);
technicalTab->setFrameStyle(QFrame::NoFrame);
technicalTab->setBackgroundRole(parent->backgroundRole());
technicalTab->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
technicalTab->setSizeAdjustPolicy(QScrollArea::AdjustToContents);
auto tabLayout = qobject_cast<QVBoxLayout *>(technicalTab->widget()->layout());
{
auto groupBox = new QGroupBox{i18nc("@title:group", "Key Material"), technicalTab};
auto groupBoxGrid = new QGridLayout{groupBox};
int row = 0;
auto label = new QLabel(i18nc("@info:label", "RSA key strength:"));
groupBoxGrid->addWidget(label, row, 0, 1, 1);
rsaKeyStrengthCB = new QComboBox{groupBox};
rsaKeyStrengthCB->setEnabled(true);
groupBoxGrid->addWidget(rsaKeyStrengthCB, row, 2, 1, 1);
row++;
auto subKeyIndentation = new QSpacerItem(13, 13, QSizePolicy::Fixed, QSizePolicy::Minimum);
groupBoxGrid->addItem(subKeyIndentation, row, 0, 1, 1);
groupBoxGrid->setColumnStretch(3, 1);
tabLayout->addWidget(groupBox);
}
{
auto groupBox = new QGroupBox{i18nc("@title:group", "Certificate Usage"), technicalTab};
auto groupBoxGrid = new QGridLayout{groupBox};
int row = 0;
signingCB = new QCheckBox{i18nc("@option:check", "Signing"), groupBox};
signingCB->setChecked(true);
groupBoxGrid->addWidget(signingCB, row, 0, 1, 1);
row++;
encryptionCB = new QCheckBox{i18nc("@option:check", "Encryption"), groupBox};
encryptionCB->setChecked(true);
groupBoxGrid->addWidget(encryptionCB, row, 0, 1, 1);
row++;
{
auto hbox = new QHBoxLayout;
groupBoxGrid->addLayout(hbox, row, 0, 1, 2);
}
tabLayout->addWidget(groupBox);
}
tabLayout->addStretch(1);
tabWidget->addTab(technicalTab, i18nc("@title:tab", "Technical Details"));
}
{
- personalTab = new ScrollArea{tabWidget};
+ personalTab = new KAdjustingScrollArea{tabWidget};
personalTab->setFocusPolicy(Qt::NoFocus);
personalTab->setFrameStyle(QFrame::NoFrame);
personalTab->setBackgroundRole(parent->backgroundRole());
personalTab->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
personalTab->setSizeAdjustPolicy(QScrollArea::AdjustToContents);
auto scrollAreaLayout = qobject_cast<QVBoxLayout *>(personalTab->widget()->layout());
auto tabGrid = new QGridLayout;
emailGB = new QGroupBox{i18nc("@title:group", "EMail Addresses"), personalTab};
{
auto layout = new QVBoxLayout{emailGB};
emailLW = new Kleo::NewCertificateUi::ListWidget{emailGB};
layout->addWidget(emailLW);
}
tabGrid->addWidget(emailGB, 2, 0, 2, 1);
dnsGB = new QGroupBox{i18nc("@title:group", "DNS Names"), personalTab};
{
auto layout = new QVBoxLayout{dnsGB};
dnsLW = new Kleo::NewCertificateUi::ListWidget{dnsGB};
layout->addWidget(dnsLW);
}
tabGrid->addWidget(dnsGB, 2, 1, 1, 1);
uriGB = new QGroupBox{i18nc("@title:group", "URIs"), personalTab};
{
auto layout = new QVBoxLayout{uriGB};
uriLW = new Kleo::NewCertificateUi::ListWidget{uriGB};
layout->addWidget(uriLW);
}
tabGrid->addWidget(uriGB, 3, 1, 1, 1);
scrollAreaLayout->addLayout(tabGrid);
tabWidget->addTab(personalTab, i18nc("@title:tab", "Personal Details"));
}
mainLayout->addWidget(tabWidget);
buttonBox = new QDialogButtonBox{parent};
buttonBox->setStandardButtons(QDialogButtonBox::Cancel | QDialogButtonBox::Ok);
mainLayout->addWidget(buttonBox);
}
};
AdvancedSettingsDialog::AdvancedSettingsDialog(QWidget *parent)
: QDialog{parent}
, ui{new UI{this}}
{
qRegisterMetaType<Subkey::PubkeyAlgo>("Subkey::PubkeyAlgo");
ui->emailLW->setDefaultValue(i18n("new email"));
ui->dnsLW->setDefaultValue(i18n("new dns name"));
ui->uriLW->setDefaultValue(i18n("new uri"));
fillKeySizeComboBoxen();
connect(ui->signingCB, &QAbstractButton::toggled, this, &AdvancedSettingsDialog::slotSigningAllowedToggled);
connect(ui->encryptionCB, &QAbstractButton::toggled, this, &AdvancedSettingsDialog::slotEncryptionAllowedToggled);
connect(ui->buttonBox, &QDialogButtonBox::accepted, this, &AdvancedSettingsDialog::accept);
connect(ui->buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject);
loadDefaults();
}
AdvancedSettingsDialog::~AdvancedSettingsDialog() = default;
void AdvancedSettingsDialog::setAdditionalEMailAddresses(const QStringList &items)
{
ui->emailLW->setItems(items);
}
QStringList AdvancedSettingsDialog::additionalEMailAddresses() const
{
return ui->emailLW->items();
}
void AdvancedSettingsDialog::setDnsNames(const QStringList &items)
{
ui->dnsLW->setItems(items);
}
QStringList AdvancedSettingsDialog::dnsNames() const
{
return ui->dnsLW->items();
}
void AdvancedSettingsDialog::setUris(const QStringList &items)
{
ui->uriLW->setItems(items);
}
QStringList AdvancedSettingsDialog::uris() const
{
return ui->uriLW->items();
}
void AdvancedSettingsDialog::setKeyStrength(unsigned int strength)
{
set_keysize(ui->rsaKeyStrengthCB, strength);
}
unsigned int AdvancedSettingsDialog::keyStrength() const
{
return get_keysize(ui->rsaKeyStrengthCB);
}
Subkey::PubkeyAlgo AdvancedSettingsDialog::keyType() const
{
return Subkey::AlgoRSA;
}
void AdvancedSettingsDialog::setSigningAllowed(bool on)
{
ui->signingCB->setChecked(on);
}
bool AdvancedSettingsDialog::signingAllowed() const
{
return ui->signingCB->isChecked();
}
void AdvancedSettingsDialog::setEncryptionAllowed(bool on)
{
ui->encryptionCB->setChecked(on);
}
bool AdvancedSettingsDialog::encryptionAllowed() const
{
return ui->encryptionCB->isChecked();
}
void AdvancedSettingsDialog::slotSigningAllowedToggled(bool on)
{
if (!on && !encryptionAllowed()) {
setEncryptionAllowed(true);
}
}
void AdvancedSettingsDialog::slotEncryptionAllowedToggled(bool on)
{
if (!on && !signingAllowed()) {
setSigningAllowed(true);
}
}
static void fill_combobox(QComboBox &cb, const QList<int> &sizes, const QStringList &labels)
{
cb.clear();
for (int i = 0, end = sizes.size(); i != end; ++i) {
const int size = std::abs(sizes[i]);
/* As we respect the defaults configurable in GnuPG, and we also have configurable
* defaults in Kleopatra its difficult to print out "default" here. To avoid confusion
* about that its better not to show any default indication. */
cb.addItem(i < labels.size() && !labels[i].trimmed().isEmpty()
? i18ncp("%2: some admin-supplied text, %1: key size in bits", "%2 (1 bit)", "%2 (%1 bits)", size, labels[i].trimmed())
: i18ncp("%1: key size in bits", "1 bit", "%1 bits", size),
size);
if (sizes[i] < 0) {
cb.setCurrentIndex(cb.count() - 1);
}
}
}
void AdvancedSettingsDialog::fillKeySizeComboBoxen()
{
const KConfigGroup config(KSharedConfig::openConfig(), QStringLiteral("CertificateCreationWizard"));
QList<int> rsaKeySizes = config.readEntry(RSA_KEYSIZES_ENTRY, QList<int>() << 2048 << -3072 << 4096);
if (DeVSCompliance::isActive()) {
rsaKeySizes = config.readEntry(RSA_KEYSIZES_ENTRY, QList<int>() << -3072 << 4096);
}
const QStringList rsaKeySizeLabels = config.readEntry(RSA_KEYSIZE_LABELS_ENTRY, QStringList());
fill_combobox(*ui->rsaKeyStrengthCB, rsaKeySizes, rsaKeySizeLabels);
}
// Try to load the default key type from GnuPG
void AdvancedSettingsDialog::loadDefaultGnuPGKeyType()
{
const auto conf = QGpgME::cryptoConfig();
if (!conf) {
qCWarning(KLEOPATRA_LOG) << "Failed to obtain cryptoConfig.";
return;
}
const auto entry = getCryptoConfigEntry(conf, "gpgsm", "default_pubkey_algo");
if (!entry) {
qCDebug(KLEOPATRA_LOG) << "GnuPG does not have default key type. Fallback to RSA";
return;
}
qCDebug(KLEOPATRA_LOG) << "Have default key type: " << entry->stringValue();
// Format is <primarytype>[/usage]+<subkeytype>[/usage]
const auto split = entry->stringValue().split(QLatin1Char('+'));
setKeyStrength(parseSize(split[0]));
}
void AdvancedSettingsDialog::loadDefaultKeyType()
{
const KConfigGroup config(KSharedConfig::openConfig(), QStringLiteral("CertificateCreationWizard"));
const QString entry = QLatin1StringView(CMS_KEY_TYPE_ENTRY);
const QString keyType = config.readEntry(entry).trimmed().toUpper();
if (keyType.isEmpty() && engineIsVersion(2, 1, 17)) {
loadDefaultGnuPGKeyType();
} else {
if (!keyType.isEmpty() && keyType != QLatin1StringView("RSA"))
qCWarning(KLEOPATRA_LOG) << "invalid value \"" << qPrintable(keyType) << "\" for entry \"[CertificateCreationWizard]" << qPrintable(entry) << "\"";
}
keyTypeImmutable = config.isEntryImmutable(entry);
}
void AdvancedSettingsDialog::loadDefaults()
{
loadDefaultKeyType();
updateWidgetVisibility();
}
void AdvancedSettingsDialog::updateWidgetVisibility()
{
if (keyTypeImmutable) {
// force usage if key type is forced
ui->signingCB->setEnabled(false);
ui->encryptionCB->setEnabled(false);
} else {
ui->encryptionCB->setEnabled(true);
}
}
void AdvancedSettingsDialog::setInitialFocus()
{
// then try the usage check boxes and the expiration check box
if (focusFirstEnabledButton({ui->signingCB, ui->encryptionCB})) {
return;
}
// finally, focus the OK button
ui->buttonBox->button(QDialogButtonBox::Ok)->setFocus();
}
void AdvancedSettingsDialog::accept()
{
QDialog::accept();
}
void AdvancedSettingsDialog::showEvent(QShowEvent *event)
{
if (isFirstShowEvent) {
setInitialFocus();
isFirstShowEvent = false;
}
QDialog::showEvent(event);
}
#include "moc_advancedsettingsdialog_p.cpp"
diff --git a/src/newcertificatewizard/enterdetailspage.cpp b/src/newcertificatewizard/enterdetailspage.cpp
index 41d0a47d9..ba2519dd1 100644
--- a/src/newcertificatewizard/enterdetailspage.cpp
+++ b/src/newcertificatewizard/enterdetailspage.cpp
@@ -1,530 +1,532 @@
/* -*- mode: c++; c-basic-offset:4 -*-
newcertificatewizard/enterdetailspage.cpp
This file is part of Kleopatra, the KDE keymanager
SPDX-FileCopyrightText: 2008 Klarälvdalens Datakonsult AB
SPDX-FileCopyrightText: 2016, 2017 Bundesamt für Sicherheit in der Informationstechnik
SPDX-FileContributor: Intevation GmbH
SPDX-FileCopyrightText: 2022 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 "enterdetailspage_p.h"
#include "advancedsettingsdialog_p.h"
-#include "utils/scrollarea.h"
#include "utils/userinfo.h"
#include <settings.h>
#include <Libkleo/Compat>
#include <Libkleo/Dn>
#include <Libkleo/Formatting>
#include <Libkleo/OidMap>
#include <Libkleo/Stl_Util>
#include <Libkleo/Validation>
+#include <KAdjustingScrollArea>
#include <KLocalizedString>
#include <QGpgME/CryptoConfig>
#include <QGpgME/Protocol>
#include <QCheckBox>
#include <QHBoxLayout>
#include <QLabel>
#include <QLineEdit>
#include <QMetaProperty>
#include <QPushButton>
#include <QSpacerItem>
#include <QVBoxLayout>
#include <QValidator>
#include "kleopatra_debug.h"
using namespace Kleo;
using namespace Kleo::NewCertificateUi;
using namespace GpgME;
static void set_tab_order(const QList<QWidget *> &wl)
{
kdtools::for_each_adjacent_pair(wl.begin(), wl.end(), [](QWidget *w1, QWidget *w2) {
QWidget::setTabOrder(w1, w2);
});
}
static QString pgpLabel(const QString &attr)
{
if (attr == QLatin1StringView("NAME")) {
return i18n("Name");
}
if (attr == QLatin1StringView("EMAIL")) {
return i18n("EMail");
}
return QString();
}
static QString attributeLabel(const QString &attr, bool pgp)
{
if (attr.isEmpty()) {
return QString();
}
const QString label = pgp ? pgpLabel(attr) : Kleo::DN::attributeNameToLabel(attr);
if (!label.isEmpty())
if (pgp) {
return label;
} else
return i18nc("Format string for the labels in the \"Your Personal Data\" page", "%1 (%2)", label, attr);
else {
return attr;
}
}
static QString attributeFromKey(QString key)
{
return key.remove(QLatin1Char('!'));
}
struct EnterDetailsPage::UI {
QGridLayout *gridLayout = nullptr;
QLabel *nameLB = nullptr;
QLineEdit *nameLE = nullptr;
QLabel *nameRequiredLB = nullptr;
QLabel *emailLB = nullptr;
QLineEdit *emailLE = nullptr;
QLabel *emailRequiredLB = nullptr;
QCheckBox *withPassCB = nullptr;
QLineEdit *resultLE = nullptr;
QLabel *errorLB = nullptr;
QPushButton *advancedPB = nullptr;
UI(QWizardPage *parent)
{
parent->setTitle(i18nc("@title", "Enter Details"));
auto mainLayout = new QVBoxLayout{parent};
const auto margins = mainLayout->contentsMargins();
mainLayout->setContentsMargins(margins.left(), 0, margins.right(), 0);
- auto scrollArea = new ScrollArea{parent};
+ auto scrollArea = new KAdjustingScrollArea{parent};
scrollArea->setFocusPolicy(Qt::NoFocus);
scrollArea->setFrameStyle(QFrame::NoFrame);
scrollArea->setBackgroundRole(parent->backgroundRole());
scrollArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
scrollArea->setSizeAdjustPolicy(QScrollArea::AdjustToContents);
- auto scrollAreaLayout = qobject_cast<QBoxLayout *>(scrollArea->widget()->layout());
+ auto widget = new QWidget;
+ scrollArea->setWidget(widget);
+ auto scrollAreaLayout = new QVBoxLayout(widget);
scrollAreaLayout->setContentsMargins(0, margins.top(), 0, margins.bottom());
gridLayout = new QGridLayout;
int row = 0;
nameLB = new QLabel{i18n("Real name:"), parent};
nameLE = new QLineEdit{parent};
nameRequiredLB = new QLabel{i18n("(required)"), parent};
gridLayout->addWidget(nameLB, row, 0, 1, 1);
gridLayout->addWidget(nameLE, row, 1, 1, 1);
gridLayout->addWidget(nameRequiredLB, row, 2, 1, 1);
row++;
emailLB = new QLabel{i18n("EMail address:"), parent};
emailLE = new QLineEdit{parent};
emailRequiredLB = new QLabel{i18n("(required)"), parent};
gridLayout->addWidget(emailLB, row, 0, 1, 1);
gridLayout->addWidget(emailLE, row, 1, 1, 1);
gridLayout->addWidget(emailRequiredLB, row, 2, 1, 1);
row++;
withPassCB = new QCheckBox{i18n("Protect the generated key with a passphrase."), parent};
withPassCB->setToolTip(
i18nc("@info:tooltip", "Encrypts the secret key with an unrecoverable passphrase. You will be asked for the passphrase during key generation."));
gridLayout->addWidget(withPassCB, row, 1, 1, 2);
scrollAreaLayout->addLayout(gridLayout);
auto verticalSpacer = new QSpacerItem{20, 40, QSizePolicy::Minimum, QSizePolicy::Expanding};
scrollAreaLayout->addItem(verticalSpacer);
resultLE = new QLineEdit{parent};
resultLE->setFrame(false);
resultLE->setAlignment(Qt::AlignCenter);
resultLE->setReadOnly(true);
scrollAreaLayout->addWidget(resultLE);
auto horizontalLayout = new QHBoxLayout;
errorLB = new QLabel{parent};
QSizePolicy sizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Preferred);
sizePolicy.setHorizontalStretch(0);
sizePolicy.setVerticalStretch(0);
sizePolicy.setHeightForWidth(errorLB->sizePolicy().hasHeightForWidth());
errorLB->setSizePolicy(sizePolicy);
QPalette palette;
QBrush brush(QColor(255, 0, 0, 255));
brush.setStyle(Qt::SolidPattern);
palette.setBrush(QPalette::Active, QPalette::WindowText, brush);
palette.setBrush(QPalette::Inactive, QPalette::WindowText, brush);
QBrush brush1(QColor(114, 114, 114, 255));
brush1.setStyle(Qt::SolidPattern);
palette.setBrush(QPalette::Disabled, QPalette::WindowText, brush1);
errorLB->setPalette(palette);
errorLB->setTextFormat(Qt::RichText);
horizontalLayout->addWidget(errorLB);
advancedPB = new QPushButton{i18n("Advanced Settings..."), parent};
advancedPB->setAutoDefault(false);
horizontalLayout->addWidget(advancedPB);
scrollAreaLayout->addLayout(horizontalLayout);
mainLayout->addWidget(scrollArea);
}
};
EnterDetailsPage::EnterDetailsPage(QWidget *p)
: WizardPage{p}
, ui{new UI{this}}
, dialog{new AdvancedSettingsDialog{this}}
{
setObjectName(QLatin1StringView("Kleo__NewCertificateUi__EnterDetailsPage"));
Settings settings;
if (settings.hideAdvanced()) {
setSubTitle(i18n("Please enter your personal details below."));
} else {
setSubTitle(i18n("Please enter your personal details below. If you want more control over the parameters, click on the Advanced Settings button."));
}
ui->advancedPB->setVisible(!settings.hideAdvanced());
ui->resultLE->setFocusPolicy(Qt::NoFocus);
// set errorLB to have a fixed height of two lines:
ui->errorLB->setText(QStringLiteral("2<br>1"));
ui->errorLB->setFixedHeight(ui->errorLB->minimumSizeHint().height());
ui->errorLB->clear();
connect(ui->advancedPB, &QPushButton::clicked, this, &EnterDetailsPage::slotAdvancedSettingsClicked);
connect(ui->resultLE, &QLineEdit::textChanged, this, &QWizardPage::completeChanged);
// The email doesn't necessarily show up in ui->resultLE:
connect(ui->emailLE, &QLineEdit::textChanged, this, &QWizardPage::completeChanged);
registerDialogPropertiesAsFields();
registerField(QStringLiteral("dn"), ui->resultLE);
registerField(QStringLiteral("name"), ui->nameLE);
registerField(QStringLiteral("email"), ui->emailLE);
registerField(QStringLiteral("protectedKey"), ui->withPassCB);
setCommitPage(true);
setButtonText(QWizard::CommitButton, i18nc("@action", "Create"));
const auto conf = QGpgME::cryptoConfig();
if (!conf) {
qCWarning(KLEOPATRA_LOG) << "Failed to obtain cryptoConfig.";
return;
}
const auto entry = getCryptoConfigEntry(conf, "gpg-agent", "enforce-passphrase-constraints");
if (entry && entry->boolValue()) {
qCDebug(KLEOPATRA_LOG) << "Disabling passphrace cb because of agent config.";
ui->withPassCB->setEnabled(false);
ui->withPassCB->setChecked(true);
} else {
const KConfigGroup config(KSharedConfig::openConfig(), QStringLiteral("CertificateCreationWizard"));
ui->withPassCB->setChecked(config.readEntry("WithPassphrase", false));
ui->withPassCB->setEnabled(!config.isEntryImmutable("WithPassphrase"));
}
}
EnterDetailsPage::~EnterDetailsPage() = default;
void EnterDetailsPage::initializePage()
{
updateForm();
ui->withPassCB->setVisible(false);
}
void EnterDetailsPage::cleanupPage()
{
saveValues();
}
void EnterDetailsPage::registerDialogPropertiesAsFields()
{
const QMetaObject *const mo = dialog->metaObject();
for (unsigned int i = mo->propertyOffset(), end = i + mo->propertyCount(); i != end; ++i) {
const QMetaProperty mp = mo->property(i);
if (mp.isValid()) {
registerField(QLatin1StringView(mp.name()), dialog, mp.name(), SIGNAL(accepted()));
}
}
}
void EnterDetailsPage::saveValues()
{
for (const Line &line : std::as_const(lineList)) {
savedValues[attributeFromKey(line.attr)] = line.edit->text().trimmed();
}
}
void EnterDetailsPage::clearForm()
{
qDeleteAll(dynamicWidgets);
dynamicWidgets.clear();
lineList.clear();
ui->nameLE->hide();
ui->nameLE->clear();
ui->nameLB->hide();
ui->nameRequiredLB->hide();
ui->emailLE->hide();
ui->emailLE->clear();
ui->emailLB->hide();
ui->emailRequiredLB->hide();
}
static int row_index_of(QWidget *w, QGridLayout *l)
{
const int idx = l->indexOf(w);
int r, c, rs, cs;
l->getItemPosition(idx, &r, &c, &rs, &cs);
return r;
}
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);
Q_ASSERT(row < l->rowCount());
auto lb = qobject_cast<QLabel *>(l->itemAtPosition(row, 0)->widget());
Q_ASSERT(lb);
auto le = qobject_cast<QLineEdit *>(l->itemAtPosition(row, 1)->widget());
Q_ASSERT(le);
lb->setBuddy(le); // For better accessibility
auto reqLB = qobject_cast<QLabel *>(l->itemAtPosition(row, 2)->widget());
Q_ASSERT(reqLB);
lb->setText(i18nc("interpunctation for labels", "%1:", label));
le->setText(preset);
reqLB->setText(required ? i18n("(required)") : i18n("(optional)"));
if (validator) {
le->setValidator(validator.get());
}
le->setReadOnly(readonly && le->hasAcceptableInput());
lb->show();
le->show();
reqLB->show();
return le;
}
static int add_row(QGridLayout *l, QList<QWidget *> *wl)
{
Q_ASSERT(l);
Q_ASSERT(wl);
const int row = l->rowCount();
QWidget *w1, *w2, *w3;
l->addWidget(w1 = new QLabel(l->parentWidget()), row, 0);
l->addWidget(w2 = new QLineEdit(l->parentWidget()), row, 1);
l->addWidget(w3 = new QLabel(l->parentWidget()), row, 2);
wl->push_back(w1);
wl->push_back(w2);
wl->push_back(w3);
return row;
}
void EnterDetailsPage::updateForm()
{
clearForm();
const auto settings = Kleo::Settings{};
const KConfigGroup config(KSharedConfig::openConfig(), QStringLiteral("CertificateCreationWizard"));
QStringList attrOrder = config.readEntry("DNAttributeOrder", QStringList());
if (attrOrder.empty()) {
attrOrder << QStringLiteral("CN!") << QStringLiteral("L") << QStringLiteral("OU") << QStringLiteral("O") << QStringLiteral("C")
<< QStringLiteral("EMAIL!");
}
QList<QWidget *> widgets;
widgets.push_back(ui->nameLE);
widgets.push_back(ui->emailLE);
QMap<int, Line> lines;
for (const QString &rawKey : std::as_const(attrOrder)) {
const QString key = rawKey.trimmed().toUpper();
const QString attr = attributeFromKey(key);
if (attr.isEmpty()) {
continue;
}
const QString preset = savedValues.value(attr, config.readEntry(attr, QString()));
const bool required = key.endsWith(QLatin1Char('!'));
const bool readonly = config.isEntryImmutable(attr);
const QString label = config.readEntry(attr + QLatin1StringView("_label"), attributeLabel(attr, false));
const QString regex = config.readEntry(attr + QLatin1StringView("_regex"));
const QString placeholder = config.readEntry(attr + QLatin1StringView{"_placeholder"});
int row;
bool known = true;
std::shared_ptr<QValidator> validator;
if (attr == QLatin1StringView("EMAIL")) {
row = row_index_of(ui->emailLE, ui->gridLayout);
validator = regex.isEmpty() ? Validation::email() : Validation::email(regex);
} else if (attr == QLatin1StringView("NAME") || attr == QLatin1StringView("CN")) {
if (attr == QLatin1StringView("NAME")) {
continue;
}
row = row_index_of(ui->nameLE, ui->gridLayout);
} else {
known = false;
row = add_row(ui->gridLayout, &dynamicWidgets);
}
if (!validator && !regex.isEmpty()) {
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, validator};
lines[row] = line;
if (!known) {
widgets.push_back(le);
}
// don't connect twice:
disconnect(le, &QLineEdit::textChanged, this, &EnterDetailsPage::slotUpdateResultLabel);
connect(le, &QLineEdit::textChanged, this, &EnterDetailsPage::slotUpdateResultLabel);
}
// create lineList in visual order, so requirementsAreMet()
// complains from top to bottom:
lineList.reserve(lines.count());
std::copy(lines.cbegin(), lines.cend(), std::back_inserter(lineList));
widgets.push_back(ui->withPassCB);
widgets.push_back(ui->advancedPB);
if (ui->nameLE->text().isEmpty() && settings.prefillCN()) {
ui->nameLE->setText(userFullName());
}
if (ui->emailLE->text().isEmpty() && settings.prefillEmail()) {
ui->emailLE->setText(userEmailAddress());
}
slotUpdateResultLabel();
set_tab_order(widgets);
}
QString EnterDetailsPage::cmsDN() const
{
DN dn;
for (QList<Line>::const_iterator it = lineList.begin(), end = lineList.end(); it != end; ++it) {
const QString text = it->edit->text().trimmed();
if (text.isEmpty()) {
continue;
}
QString attr = attributeFromKey(it->attr);
if (attr == QLatin1StringView("EMAIL")) {
continue;
}
if (const char *const oid = oidForAttributeName(attr)) {
attr = QString::fromUtf8(oid);
}
dn.append(DN::Attribute(attr, text));
}
return dn.dn();
}
QString EnterDetailsPage::pgpUserID() const
{
return Formatting::prettyNameAndEMail(OpenPGP, QString(), ui->nameLE->text().trimmed(), ui->emailLE->text().trimmed(), QString());
}
static bool has_intermediate_input(const QLineEdit *le)
{
QString text = le->text();
int pos = le->cursorPosition();
const QValidator *const v = le->validator();
return v && v->validate(text, pos) == QValidator::Intermediate;
}
static bool requirementsAreMet(const QList<EnterDetailsPage::Line> &list, QString &error)
{
bool allEmpty = true;
for (const auto &line : list) {
const QLineEdit *le = line.edit;
if (!le) {
continue;
}
const QString key = line.attr;
qCDebug(KLEOPATRA_LOG) << "requirementsAreMet(): checking" << key << "against" << le->text() << ":";
if (le->text().trimmed().isEmpty()) {
if (key.endsWith(QLatin1Char('!'))) {
if (line.regex.isEmpty()) {
error = xi18nc("@info", "<interface>%1</interface> is required, but empty.", line.label);
} else
error = xi18nc("@info",
"<interface>%1</interface> is required, but empty.<nl/>"
"Local Admin rule: <icode>%2</icode>",
line.label,
line.regex);
return false;
}
} else if (has_intermediate_input(le)) {
if (line.regex.isEmpty()) {
error = xi18nc("@info", "<interface>%1</interface> is incomplete.", line.label);
} else
error = xi18nc("@info",
"<interface>%1</interface> is incomplete.<nl/>"
"Local Admin rule: <icode>%2</icode>",
line.label,
line.regex);
return false;
} else if (!le->hasAcceptableInput()) {
if (line.regex.isEmpty()) {
error = xi18nc("@info", "<interface>%1</interface> is invalid.", line.label);
} else
error = xi18nc("@info",
"<interface>%1</interface> is invalid.<nl/>"
"Local Admin rule: <icode>%2</icode>",
line.label,
line.regex);
return false;
} else {
allEmpty = false;
}
}
// Ensure that at least one value is acceptable
return !allEmpty;
}
bool EnterDetailsPage::isComplete() const
{
QString error;
const bool ok = requirementsAreMet(lineList, error);
ui->errorLB->setText(error);
return ok;
}
void EnterDetailsPage::slotAdvancedSettingsClicked()
{
dialog->exec();
}
void EnterDetailsPage::slotUpdateResultLabel()
{
ui->resultLE->setText(cmsDN());
}
#include "moc_enterdetailspage_p.cpp"
diff --git a/src/newcertificatewizard/resultpage.cpp b/src/newcertificatewizard/resultpage.cpp
index ef87474d8..3a6705666 100644
--- a/src/newcertificatewizard/resultpage.cpp
+++ b/src/newcertificatewizard/resultpage.cpp
@@ -1,286 +1,288 @@
/* -*- mode: c++; c-basic-offset:4 -*-
newcertificatewizard/resultpage.cpp
This file is part of Kleopatra, the KDE keymanager
SPDX-FileCopyrightText: 2008 Klarälvdalens Datakonsult AB
SPDX-FileCopyrightText: 2016, 2017 Bundesamt für Sicherheit in der Informationstechnik
SPDX-FileContributor: Intevation GmbH
SPDX-FileCopyrightText: 2022 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 "resultpage_p.h"
#include "commands/exportcertificatecommand.h"
#include "commands/exportopenpgpcertstoservercommand.h"
#include "commands/exportsecretkeycommand.h"
#include "utils/dragqueen.h"
#include "utils/email.h"
#include "utils/filedialog.h"
-#include "utils/scrollarea.h"
#include <Libkleo/KeyCache>
+#include <KAdjustingScrollArea>
#include <KConfigGroup>
#include <KLocalizedString>
#include <KMessageBox>
#include <KSharedConfig>
#include <QGroupBox>
#include <QHBoxLayout>
#include <QLineEdit>
#include <QPushButton>
#include <QTextBrowser>
#include <QVBoxLayout>
#include <gpgme++/key.h>
#include "kleopatra_debug.h"
using namespace Kleo;
using namespace Kleo::Commands;
using namespace Kleo::NewCertificateUi;
using namespace GpgME;
struct ResultPage::UI {
QTextBrowser *resultTB = nullptr;
QTextBrowser *errorTB = nullptr;
DragQueen *dragQueen = nullptr;
QPushButton *restartWizardPB = nullptr;
QGroupBox *nextStepsGB = nullptr;
QPushButton *saveRequestToFilePB = nullptr;
QPushButton *sendRequestByEMailPB = nullptr;
QPushButton *createSigningCertificatePB = nullptr;
QPushButton *createEncryptionCertificatePB = nullptr;
UI(QWizardPage *parent)
{
auto mainLayout = new QVBoxLayout{parent};
const auto margins = mainLayout->contentsMargins();
mainLayout->setContentsMargins(margins.left(), 0, margins.right(), 0);
- auto scrollArea = new ScrollArea{parent};
+ auto scrollArea = new KAdjustingScrollArea{parent};
scrollArea->setFocusPolicy(Qt::NoFocus);
scrollArea->setFrameStyle(QFrame::NoFrame);
scrollArea->setBackgroundRole(parent->backgroundRole());
scrollArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
scrollArea->setSizeAdjustPolicy(QScrollArea::AdjustToContents);
- auto scrollAreaLayout = qobject_cast<QBoxLayout *>(scrollArea->widget()->layout());
+ auto widget = new QWidget;
+ scrollArea->setWidget(widget);
+ auto scrollAreaLayout = new QVBoxLayout(widget);
scrollAreaLayout->setContentsMargins(0, margins.top(), 0, margins.bottom());
auto resultGB = new QGroupBox{i18nc("@title:group", "Result"), parent};
auto resultGBLayout = new QHBoxLayout{resultGB};
resultTB = new QTextBrowser{resultGB};
resultGBLayout->addWidget(resultTB);
errorTB = new QTextBrowser{resultGB};
resultGBLayout->addWidget(errorTB);
dragQueen = new Kleo::DragQueen{resultGB};
dragQueen->setToolTip(i18nc("@info:tooltip", "Drag this icon to your mail application's composer to attach the request to a mail."));
dragQueen->setAlignment(Qt::AlignCenter);
resultGBLayout->addWidget(dragQueen);
scrollAreaLayout->addWidget(resultGB);
restartWizardPB = new QPushButton{i18n("Restart This Wizard (Keeps Your Parameters)"), parent};
scrollAreaLayout->addWidget(restartWizardPB);
nextStepsGB = new QGroupBox{i18nc("@title:group", "Next Steps"), parent};
auto nextStepsGBLayout = new QVBoxLayout{nextStepsGB};
saveRequestToFilePB = new QPushButton{i18n("Save Certificate Request To File..."), nextStepsGB};
nextStepsGBLayout->addWidget(saveRequestToFilePB);
sendRequestByEMailPB = new QPushButton{i18n("Send Certificate Request By EMail..."), nextStepsGB};
nextStepsGBLayout->addWidget(sendRequestByEMailPB);
createSigningCertificatePB = new QPushButton{i18n("Create Signing Certificate With Same Parameters"), nextStepsGB};
nextStepsGBLayout->addWidget(createSigningCertificatePB);
createEncryptionCertificatePB = new QPushButton{i18n("Create Encryption Certificate With Same Parameters"), nextStepsGB};
nextStepsGBLayout->addWidget(createEncryptionCertificatePB);
scrollAreaLayout->addWidget(nextStepsGB);
mainLayout->addWidget(scrollArea);
}
};
ResultPage::ResultPage(QWidget *p)
: WizardPage{p}
, ui{new UI{this}}
, initialized{false}
, successfullyCreatedSigningCertificate{false}
, successfullyCreatedEncryptionCertificate{false}
{
setObjectName(QString::fromUtf8("Kleo__NewCertificateUi__ResultPage"));
connect(ui->saveRequestToFilePB, &QPushButton::clicked, this, &ResultPage::slotSaveRequestToFile);
connect(ui->sendRequestByEMailPB, &QPushButton::clicked, this, &ResultPage::slotSendRequestByEMail);
connect(ui->createSigningCertificatePB, &QPushButton::clicked, this, &ResultPage::slotCreateSigningCertificate);
connect(ui->createEncryptionCertificatePB, &QPushButton::clicked, this, &ResultPage::slotCreateEncryptionCertificate);
ui->dragQueen->setPixmap(QIcon::fromTheme(QStringLiteral("kleopatra")).pixmap(64, 64));
registerField(QStringLiteral("error"), ui->errorTB, "plainText");
registerField(QStringLiteral("result"), ui->resultTB, "plainText");
registerField(QStringLiteral("url"), ui->dragQueen, "url");
// hidden field, since QWizard can't deal with non-widget-backed fields...
auto le = new QLineEdit(this);
le->hide();
registerField(QStringLiteral("fingerprint"), le);
}
ResultPage::~ResultPage() = default;
void ResultPage::initializePage()
{
const bool error = isError();
if (error) {
setTitle(i18nc("@title", "Key Creation Failed"));
setSubTitle(i18n("Key pair creation failed. Please find details about the failure below."));
} else {
setTitle(i18nc("@title", "Key Pair Successfully Created"));
setSubTitle(i18n("Your new key pair was created successfully. Please find details on the result and some suggested next steps below."));
}
ui->resultTB->setVisible(!error);
ui->errorTB->setVisible(error);
ui->dragQueen->setVisible(!error);
ui->restartWizardPB->setVisible(error);
ui->nextStepsGB->setVisible(!error);
ui->saveRequestToFilePB->setVisible(true);
ui->sendRequestByEMailPB->setVisible(true);
if (!error) {
if (signingAllowed() && !encryptionAllowed()) {
successfullyCreatedSigningCertificate = true;
} else if (!signingAllowed() && encryptionAllowed()) {
successfullyCreatedEncryptionCertificate = true;
} else {
successfullyCreatedEncryptionCertificate = successfullyCreatedSigningCertificate = true;
}
}
ui->createSigningCertificatePB->setVisible(successfullyCreatedEncryptionCertificate && !successfullyCreatedSigningCertificate);
ui->createEncryptionCertificatePB->setVisible(successfullyCreatedSigningCertificate && !successfullyCreatedEncryptionCertificate);
if (error) {
wizard()->setOptions(wizard()->options() & ~QWizard::NoCancelButtonOnLastPage);
} else {
wizard()->setOptions(wizard()->options() | QWizard::NoCancelButtonOnLastPage);
}
if (!initialized) {
connect(ui->restartWizardPB, &QAbstractButton::clicked, this, [this]() {
restartAtEnterDetailsPage();
});
}
initialized = true;
}
bool ResultPage::isError() const
{
return !ui->errorTB->document()->isEmpty();
}
bool ResultPage::isComplete() const
{
return !isError();
}
Key ResultPage::key() const
{
return KeyCache::instance()->findByFingerprint(fingerprint().toLatin1().constData());
}
void ResultPage::slotSaveRequestToFile()
{
QString fileName = FileDialog::getSaveFileName(this, i18nc("@title", "Save Request"), QStringLiteral("imp"), i18n("PKCS#10 Requests (*.p10)"));
if (fileName.isEmpty()) {
return;
}
if (!fileName.endsWith(QLatin1StringView(".p10"), Qt::CaseInsensitive)) {
fileName += QLatin1StringView(".p10");
}
QFile src(QUrl(url()).toLocalFile());
if (!src.copy(fileName))
KMessageBox::error(this,
xi18nc("@info",
"Could not copy temporary file <filename>%1</filename> "
"to file <filename>%2</filename>: <message>%3</message>",
src.fileName(),
fileName,
src.errorString()),
i18nc("@title", "Error Saving Request"));
else
KMessageBox::information(this,
xi18nc("@info",
"<para>Successfully wrote request to <filename>%1</filename>.</para>"
"<para>You should now send the request to the Certification Authority (CA).</para>",
fileName),
i18nc("@title", "Request Saved"));
}
void ResultPage::slotSendRequestByEMail()
{
const KConfigGroup config(KSharedConfig::openConfig(), QStringLiteral("CertificateCreationWizard"));
invokeMailer(config.readEntry("CAEmailAddress"), // to
i18n("Please process this certificate."), // subject
i18n("Please process this certificate and inform the sender about the location to fetch the resulting certificate.\n\nThanks,\n"), // body
QFileInfo{QUrl(url()).toLocalFile()}); // attachment
KMessageBox::information(this,
xi18nc("@info",
"<para><application>Kleopatra</application> tried to send a mail via your default mail client.</para>"
"<para>Some mail clients are known not to support attachments when invoked this way.</para>"
"<para>If your mail client does not have an attachment, then drag the <application>Kleopatra</application> icon and drop "
"it on the message compose window of your mail client.</para>"
"<para>If that does not work, either, save the request to a file, and then attach that.</para>"),
i18nc("@title", "Sending Mail"),
QStringLiteral("newcertificatewizard-mailto-troubles"));
}
void ResultPage::slotCreateSigningCertificate()
{
if (successfullyCreatedSigningCertificate) {
return;
}
toggleSignEncryptAndRestart();
}
void ResultPage::slotCreateEncryptionCertificate()
{
if (successfullyCreatedEncryptionCertificate) {
return;
}
toggleSignEncryptAndRestart();
}
void ResultPage::toggleSignEncryptAndRestart()
{
if (!wizard()) {
return;
}
if (KMessageBox::warningContinueCancel(this,
i18nc("@info",
"This operation will delete the certification request. "
"Please make sure that you have sent or saved it before proceeding."),
i18nc("@title", "Certification Request About To Be Deleted"))
!= KMessageBox::Continue) {
return;
}
const bool sign = signingAllowed();
const bool encr = encryptionAllowed();
setField(QStringLiteral("signingAllowed"), !sign);
setField(QStringLiteral("encryptionAllowed"), !encr);
restartAtEnterDetailsPage();
}
#include "moc_resultpage_p.cpp"
diff --git a/src/utils/scrollarea.cpp b/src/utils/scrollarea.cpp
deleted file mode 100644
index 4fe7d05e7..000000000
--- a/src/utils/scrollarea.cpp
+++ /dev/null
@@ -1,103 +0,0 @@
-/* -*- mode: c++; c-basic-offset:4 -*-
- utils/scrollarea.cpp
-
- This file is part of Kleopatra, the KDE keymanager
- SPDX-FileCopyrightText: 2007 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
-*/
-
-#include <config-kleopatra.h>
-
-#include "scrollarea.h"
-
-#include <QApplication>
-#include <QResizeEvent>
-#include <QScreen>
-#include <QScrollBar>
-#include <QVBoxLayout>
-
-using namespace Kleo;
-
-ScrollArea::ScrollArea(QWidget *parent)
- : QScrollArea{parent}
-{
- auto w = new QWidget;
- w->setObjectName(QLatin1StringView("scrollarea_widget"));
- new QVBoxLayout{w};
- setWidget(w);
- setWidgetResizable(true);
- w->installEventFilter(this);
-
- connect(qApp, &QApplication::focusChanged, this, [this](QWidget *old, QWidget *now) {
- Q_UNUSED(old);
- ensureWidgetVisible(now);
- });
-}
-
-ScrollArea::~ScrollArea()
-{
- widget()->removeEventFilter(this);
-}
-
-QSize ScrollArea::minimumSizeHint() const
-{
- const int fw = frameWidth();
- QSize sz{2 * fw, 2 * fw};
- sz += {widget()->minimumSizeHint().width(), 0};
- if (verticalScrollBarPolicy() != Qt::ScrollBarAlwaysOff) {
- sz.setWidth(sz.width() + verticalScrollBar()->sizeHint().width());
- }
- if (horizontalScrollBarPolicy() != Qt::ScrollBarAlwaysOff) {
- sz.setHeight(sz.height() + horizontalScrollBar()->sizeHint().height());
- }
- return QScrollArea::minimumSizeHint().expandedTo(sz);
-}
-
-QSize ScrollArea::sizeHint() const
-{
- const int fw = frameWidth();
- QSize sz{2 * fw, 2 * fw};
- sz += viewportSizeHint();
- if (verticalScrollBarPolicy() != Qt::ScrollBarAlwaysOff) {
- sz.setWidth(sz.width() + verticalScrollBar()->sizeHint().width());
- }
- if (horizontalScrollBarPolicy() != Qt::ScrollBarAlwaysOff) {
- sz.setHeight(sz.height() + horizontalScrollBar()->sizeHint().height());
- }
- sz = QScrollArea::sizeHint().expandedTo(sz);
- return sz;
-}
-
-void ScrollArea::adjustSizeOfWindowBy(const QSize &extent)
-{
- if (auto w = window()) {
- const auto currentSize = w->size();
- // we limit the automatic size adjustment to 2/3 of the screen's size
- const auto maxWindowSize = screen()->geometry().size() * 2 / 3;
- const auto newWindowSize = currentSize.expandedTo((currentSize + extent).boundedTo(maxWindowSize));
- if (newWindowSize != currentSize) {
- w->resize(newWindowSize);
- }
- }
-}
-
-bool ScrollArea::eventFilter(QObject *obj, QEvent *ev)
-{
- if (ev->type() == QEvent::Resize && obj == widget() && sizeAdjustPolicy() == AdjustToContents) {
- const auto *const event = static_cast<QResizeEvent *>(ev);
- if (event->size().height() > event->oldSize().height()) {
- const auto currentViewportHeight = viewport()->height();
- const auto wantedViewportHeight = event->size().height();
- const auto wantedAdditionalHeight = wantedViewportHeight - currentViewportHeight;
- if (wantedAdditionalHeight > 0) {
- adjustSizeOfWindowBy(QSize{0, wantedAdditionalHeight});
- }
- }
- }
- return QScrollArea::eventFilter(obj, ev);
-}
-
-#include "moc_scrollarea.cpp"
diff --git a/src/utils/scrollarea.h b/src/utils/scrollarea.h
deleted file mode 100644
index 084b9add0..000000000
--- a/src/utils/scrollarea.h
+++ /dev/null
@@ -1,56 +0,0 @@
-/* -*- mode: c++; c-basic-offset:4 -*-
- utils/scrollarea.h
-
- This file is part of Kleopatra, the KDE keymanager
- SPDX-FileCopyrightText: 2007 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
-
-#include <QScrollArea>
-
-namespace Kleo
-{
-
-/**
- * This class improves a few aspects of QScrollArea for usage by us, in
- * particular, for vertically scrollable widgets.
- *
- * If sizeAdjustPolicy is set to QAbstractScrollArea::AdjustToContents,
- * then the scroll area will (try to) adjust its size to the widget to avoid
- * scroll bars as much as possible.
- */
-class ScrollArea : public QScrollArea
-{
- Q_OBJECT
-
-public:
- /**
- * Creates a scroll area with a QWidget with QVBoxLayout that is flagged
- * as resizable.
- */
- explicit ScrollArea(QWidget *parent = nullptr);
- ~ScrollArea() override;
-
- /**
- * Reimplemented to add the minimum size hint of the widget.
- */
- QSize minimumSizeHint() const override;
-
- /**
- * Reimplemented to remove the caching of the size/size hint of the
- * widget and to add the horizontal size hint of the vertical scroll bar
- * unless it is explicitly turned off.
- */
- QSize sizeHint() const override;
-
-private:
- void adjustSizeOfWindowBy(const QSize &extent);
- bool eventFilter(QObject *obj, QEvent *ev) override;
-};
-
-}
diff --git a/src/view/padwidget.cpp b/src/view/padwidget.cpp
index 1595f268b..9d02ec76c 100644
--- a/src/view/padwidget.cpp
+++ b/src/view/padwidget.cpp
@@ -1,513 +1,513 @@
/* -*- mode: c++; c-basic-offset:4 -*-
padwidget.cpp
This file is part of Kleopatra, the KDE keymanager
SPDX-FileCopyrightText: 2018 Intevation GmbH
SPDX-License-Identifier: GPL-2.0-or-later
*/
#include "padwidget.h"
#include "kleopatra_debug.h"
#include <settings.h>
#include <Libkleo/Classify>
#include <Libkleo/Compliance>
#include <Libkleo/Formatting>
#include <Libkleo/GnuPG>
#include <Libkleo/KeyCache>
#include <Libkleo/KleoException>
#include <Libkleo/SystemInfo>
#include "commands/importcertificatefromdatacommand.h"
#include "crypto/decryptverifytask.h"
#include "crypto/gui/resultitemwidget.h"
#include "crypto/gui/signencryptwidget.h"
#include "crypto/signencrypttask.h"
#include "utils/gui-helper.h"
#include "utils/input.h"
#include "utils/output.h"
-#include "utils/scrollarea.h"
#include <gpgme++/data.h>
#include <gpgme++/decryptionresult.h>
#include <QGpgME/DataProvider>
#include <QAccessible>
#include <QButtonGroup>
#include <QFontMetrics>
#include <QFrame>
#include <QLabel>
#include <QProgressBar>
#include <QPushButton>
#include <QRadioButton>
#include <QSplitter>
#include <QStyle>
#include <QTextEdit>
#include <QVBoxLayout>
+#include <KAdjustingScrollArea>
#include <KColorScheme>
#include <KConfigGroup>
#include <KLocalizedString>
#include <KMessageBox>
#include <KMessageWidget>
#include <KSeparator>
#include <KSharedConfig>
using namespace Kleo;
using namespace Kleo::Crypto;
using namespace Kleo::Crypto::Gui;
static GpgME::Protocol getProtocol(const std::shared_ptr<const Kleo::Crypto::Task::Result> &result)
{
const auto dvResult = dynamic_cast<const Kleo::Crypto::DecryptVerifyResult *>(result.get());
if (dvResult) {
for (const auto &key : KeyCache::instance()->findRecipients(dvResult->decryptionResult())) {
return key.protocol();
}
for (const auto &key : KeyCache::instance()->findSigners(dvResult->verificationResult())) {
return key.protocol();
}
}
return GpgME::UnknownProtocol;
}
class PadWidget::Private
{
friend class ::Kleo::PadWidget;
public:
Private(PadWidget *qq)
: q(qq)
, mEdit(new QTextEdit)
, mCryptBtn(new QPushButton(QIcon::fromTheme(QStringLiteral("document-edit-sign-encrypt")), i18n("Sign / Encrypt Notepad")))
, mDecryptBtn(new QPushButton(QIcon::fromTheme(QStringLiteral("document-edit-decrypt-verify")), i18n("Decrypt / Verify Notepad")))
, mImportBtn(new QPushButton(QIcon::fromTheme(QStringLiteral("view-certificate-import")), i18n("Import Notepad")))
, mRevertBtn(new QPushButton(QIcon::fromTheme(QStringLiteral("edit-undo")), i18n("Revert")))
, mMessageWidget{new KMessageWidget}
, mAdditionalInfoLabel(new QLabel)
, mSigEncWidget(nullptr)
, mProgressBar(new QProgressBar)
, mProgressLabel(new QLabel)
, mLastResultWidget(nullptr)
, mImportProto(GpgME::UnknownProtocol)
{
auto vLay = new QVBoxLayout(q);
vLay->setContentsMargins({});
vLay->setSpacing(0);
mMessageWidget->setMessageType(KMessageWidget::Warning);
mMessageWidget->setIcon(q->style()->standardIcon(QStyle::SP_MessageBoxWarning, nullptr, q));
mMessageWidget->setText(i18n("Signing and encryption is not possible."));
mMessageWidget->setToolTip(xi18nc("@info %1 is a placeholder for the name of a compliance mode. E.g. NATO RESTRICTED compliant or VS-NfD compliant",
"<para>You cannot use <application>Kleopatra</application> for signing or encryption "
"because the <application>GnuPG</application> system used by <application>Kleopatra</application> is not %1.</para>",
DeVSCompliance::name(true)));
mMessageWidget->setCloseButtonVisible(false);
mMessageWidget->setVisible(false);
mMessageWidget->setPosition(KMessageWidget::Position::Header);
vLay->addWidget(mMessageWidget);
auto btnLay = new QHBoxLayout;
btnLay->setSpacing(q->style()->pixelMetric(QStyle::PM_LayoutHorizontalSpacing));
btnLay->setContentsMargins(q->style()->pixelMetric(QStyle::PM_LayoutLeftMargin),
q->style()->pixelMetric(QStyle::PM_LayoutTopMargin),
q->style()->pixelMetric(QStyle::PM_LayoutRightMargin),
q->style()->pixelMetric(QStyle::PM_LayoutBottomMargin));
vLay->addLayout(btnLay);
btnLay->addWidget(mCryptBtn);
btnLay->addWidget(mDecryptBtn);
btnLay->addWidget(mImportBtn);
btnLay->addWidget(mRevertBtn);
auto separator = new KSeparator(Qt::Horizontal, q);
vLay->addWidget(separator);
mRevertBtn->setVisible(false);
btnLay->addWidget(mAdditionalInfoLabel);
btnLay->addStretch(-1);
mProgressBar->setRange(0, 0);
mProgressBar->setVisible(false);
mProgressLabel->setVisible(false);
auto progLay = new QHBoxLayout;
progLay->addWidget(mProgressLabel);
progLay->addWidget(mProgressBar);
mStatusLay = new QVBoxLayout;
mStatusLay->addLayout(progLay);
vLay->addLayout(mStatusLay, 0);
auto splitterWidget = new QSplitter;
splitterWidget->setChildrenCollapsible(false);
vLay->addWidget(splitterWidget, 1);
splitterWidget->addWidget(mEdit);
splitterWidget->setStretchFactor(0, 1);
// The recipients area
- auto scrollArea = new Kleo::ScrollArea;
+ auto scrollArea = new KAdjustingScrollArea;
scrollArea->setFocusPolicy(Qt::NoFocus);
auto recipientsWidget = new QWidget;
scrollArea->setWidget(recipientsWidget);
auto recipientsVLay = new QVBoxLayout(recipientsWidget);
mSigEncWidget = new SignEncryptWidget(nullptr, true);
recipientsVLay->addWidget(mSigEncWidget);
mCryptBtn->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Maximum);
auto hLay = new QHBoxLayout;
hLay->addStretch();
hLay->addWidget(mCryptBtn);
recipientsVLay->addLayout(hLay);
splitterWidget->addWidget(scrollArea);
mEdit->setPlaceholderText(i18nc("@info:placeholder", "Enter a message to encrypt or decrypt..."));
auto fixedFont = QFont(QStringLiteral("Monospace"));
fixedFont.setStyleHint(QFont::TypeWriter);
mEdit->setFont(fixedFont);
mEdit->setAcceptRichText(false);
mEdit->setMinimumWidth(QFontMetrics(fixedFont).averageCharWidth() * 70);
updateButtons();
connect(mEdit, &QTextEdit::textChanged, q, [this]() {
updateButtons();
});
connect(mCryptBtn, &QPushButton::clicked, q, [this]() {
doEncryptSign();
});
connect(mSigEncWidget, &SignEncryptWidget::operationChanged, q, [this]() {
updateButtons();
});
connect(mDecryptBtn, &QPushButton::clicked, q, [this]() {
doDecryptVerify();
});
connect(mImportBtn, &QPushButton::clicked, q, [this]() {
doImport();
});
connect(mRevertBtn, &QPushButton::clicked, q, [this]() {
revert();
});
}
void revert()
{
mEdit->setPlainText(QString::fromUtf8(mInputData));
mRevertBtn->setVisible(false);
}
void updateRecipientsFromResult(const Kleo::Crypto::DecryptVerifyResult &result)
{
const auto decResult = result.decryptionResult();
for (const auto &recipient : decResult.recipients()) {
if (!recipient.keyID()) {
continue;
}
GpgME::Key key = KeyCache::instance()->findByKeyIDOrFingerprint(recipient.keyID());
if (key.isNull()) {
std::vector<std::string> subids;
subids.push_back(std::string(recipient.keyID()));
for (const auto &subkey : KeyCache::instance()->findSubkeysByKeyID(subids)) {
key = subkey.parent();
break;
}
}
if (key.isNull()) {
qCDebug(KLEOPATRA_LOG) << "Unknown key" << recipient.keyID();
mSigEncWidget->addUnknownRecipient(recipient.keyID());
continue;
}
bool keyFound = false;
for (const auto &existingKey : mSigEncWidget->recipients()) {
if (existingKey.primaryFingerprint() && key.primaryFingerprint() && !strcmp(existingKey.primaryFingerprint(), key.primaryFingerprint())) {
keyFound = true;
break;
}
}
if (!keyFound) {
mSigEncWidget->addRecipient(key);
}
}
}
void cryptDone(const std::shared_ptr<const Kleo::Crypto::Task::Result> &result)
{
updateButtons();
mProgressBar->setVisible(false);
mProgressLabel->setVisible(false);
if (!result->error().isCanceled()) {
mLastResultWidget = new ResultItemWidget(result);
mLastResultWidget->showCloseButton(true);
mStatusLay->addWidget(mLastResultWidget);
connect(mLastResultWidget, &ResultItemWidget::closeButtonClicked, q, [this]() {
removeLastResultItem();
});
}
const auto protocol = getProtocol(result);
if (protocol != GpgME::Protocol::UnknownProtocol) {
mSigEncWidget->setProtocol(protocol);
}
if (result->error()) {
if (!result->errorString().isEmpty()) {
KMessageBox::error(q, result->errorString());
}
} else if (!result->error().isCanceled()) {
mEdit->setPlainText(QString::fromUtf8(mOutputData));
mOutputData.clear();
mRevertBtn->setVisible(true);
const auto decryptVerifyResult = dynamic_cast<const Kleo::Crypto::DecryptVerifyResult *>(result.get());
if (decryptVerifyResult) {
updateRecipientsFromResult(*decryptVerifyResult);
}
}
}
void doDecryptVerify()
{
doCryptoCommon();
mSigEncWidget->clearAddedRecipients();
mProgressLabel->setText(i18n("Decrypt / Verify") + QStringLiteral("..."));
auto input = Input::createFromByteArray(&mInputData, i18n("Notepad"));
auto output = Output::createFromByteArray(&mOutputData, i18n("Notepad"));
AbstractDecryptVerifyTask *task;
auto classification = input->classification();
if (classification & Class::OpaqueSignature || classification & Class::ClearsignedMessage) {
auto verifyTask = new VerifyOpaqueTask();
verifyTask->setInput(input);
verifyTask->setOutput(output);
task = verifyTask;
} else {
auto decTask = new DecryptVerifyTask();
decTask->setInput(input);
decTask->setOutput(output);
task = decTask;
}
try {
task->autodetectProtocolFromInput();
} catch (const Kleo::Exception &e) {
KMessageBox::error(q, e.message());
updateButtons();
mProgressBar->setVisible(false);
mProgressLabel->setVisible(false);
return;
}
task->setDataSource(Task::Notepad);
connect(task, &Task::result, q, [this, task](const std::shared_ptr<const Kleo::Crypto::Task::Result> &result) {
qCDebug(KLEOPATRA_LOG) << "Decrypt / Verify done. Err:" << result->error().code();
task->deleteLater();
cryptDone(result);
});
task->start();
}
void removeLastResultItem()
{
if (mLastResultWidget) {
mStatusLay->removeWidget(mLastResultWidget);
delete mLastResultWidget;
mLastResultWidget = nullptr;
}
}
void doCryptoCommon()
{
mCryptBtn->setEnabled(false);
mDecryptBtn->setEnabled(false);
mImportBtn->setEnabled(false);
mProgressBar->setVisible(true);
mProgressLabel->setVisible(true);
mInputData = mEdit->toPlainText().toUtf8();
removeLastResultItem();
}
void doEncryptSign()
{
if (DeVSCompliance::isActive() && !DeVSCompliance::isCompliant()) {
KMessageBox::error(q->topLevelWidget(),
xi18nc("@info %1 is a placeholder for the name of a compliance mode. E.g. NATO RESTRICTED compliant or VS-NfD compliant",
"<para>Sorry! You cannot use <application>Kleopatra</application> for signing or encryption "
"because the <application>GnuPG</application> system used by <application>Kleopatra</application> is not %1.</para>",
DeVSCompliance::name(true)));
return;
}
mSigEncWidget->saveOwnKeys();
doCryptoCommon();
switch (mSigEncWidget->currentOp()) {
case SignEncryptWidget::Sign:
mProgressLabel->setText(i18nc("@info:progress", "Signing notepad..."));
break;
case SignEncryptWidget::Encrypt:
mProgressLabel->setText(i18nc("@info:progress", "Encrypting notepad..."));
break;
case SignEncryptWidget::SignAndEncrypt:
mProgressLabel->setText(i18nc("@info:progress", "Signing and encrypting notepad..."));
break;
default:;
};
auto input = Input::createFromByteArray(&mInputData, i18n("Notepad"));
auto output = Output::createFromByteArray(&mOutputData, i18n("Notepad"));
auto task = new SignEncryptTask();
task->setInput(input);
task->setOutput(output);
task->setDataSource(Task::Notepad);
const auto sigKey = mSigEncWidget->signUserId().parent();
const std::vector<GpgME::Key> recipients = mSigEncWidget->recipients();
const bool encrypt = mSigEncWidget->encryptSymmetric() || !recipients.empty();
const bool sign = !sigKey.isNull();
if (sign) {
task->setSign(true);
std::vector<GpgME::Key> signVector;
signVector.push_back(sigKey);
task->setSigners(signVector);
} else {
task->setSign(false);
}
task->setEncrypt(encrypt);
task->setRecipients(recipients);
task->setEncryptSymmetric(mSigEncWidget->encryptSymmetric());
task->setAsciiArmor(true);
if (sign && !encrypt && sigKey.protocol() == GpgME::OpenPGP) {
task->setClearsign(true);
}
connect(task, &Task::result, q, [this, task](const std::shared_ptr<const Kleo::Crypto::Task::Result> &result) {
qCDebug(KLEOPATRA_LOG) << "Encrypt / Sign done. Err:" << result->error().code();
task->deleteLater();
cryptDone(result);
});
task->start();
}
void doImport()
{
doCryptoCommon();
mProgressLabel->setText(i18n("Importing..."));
auto cmd = new Kleo::ImportCertificateFromDataCommand(mInputData, mImportProto);
connect(cmd, &Kleo::ImportCertificatesCommand::finished, q, [this]() {
updateButtons();
mProgressBar->setVisible(false);
mProgressLabel->setVisible(false);
mRevertBtn->setVisible(true);
mEdit->setPlainText(QString());
});
cmd->start();
}
void checkImportProtocol()
{
QGpgME::QByteArrayDataProvider dp(mEdit->toPlainText().toUtf8());
GpgME::Data data(&dp);
auto type = data.type();
if (type == GpgME::Data::PGPKey) {
mImportProto = GpgME::OpenPGP;
} else if (type == GpgME::Data::X509Cert || type == GpgME::Data::PKCS12) {
mImportProto = GpgME::CMS;
} else {
mImportProto = GpgME::UnknownProtocol;
}
}
void updateButtons()
{
mAdditionalInfoLabel->setVisible(false);
mDecryptBtn->setEnabled(mEdit->document() && !mEdit->document()->isEmpty());
checkImportProtocol();
mImportBtn->setEnabled(mImportProto != GpgME::UnknownProtocol);
mCryptBtn->setEnabled(mSigEncWidget->currentOp() != SignEncryptWidget::NoOperation);
switch (mSigEncWidget->currentOp()) {
case SignEncryptWidget::Sign:
mCryptBtn->setText(i18nc("@action:button", "Sign Notepad"));
break;
case SignEncryptWidget::Encrypt:
mCryptBtn->setText(i18nc("@action:button", "Encrypt Notepad"));
break;
case SignEncryptWidget::SignAndEncrypt:
default:
mCryptBtn->setText(i18nc("@action:button", "Sign / Encrypt Notepad"));
};
if (!mSigEncWidget->isComplete()) {
mCryptBtn->setEnabled(false);
}
if (DeVSCompliance::isActive()) {
const bool de_vs = DeVSCompliance::isCompliant() && mSigEncWidget->isDeVsAndValid();
DeVSCompliance::decorate(mCryptBtn, de_vs);
mAdditionalInfoLabel->setText(DeVSCompliance::name(de_vs));
mAdditionalInfoLabel->setVisible(true);
if (!DeVSCompliance::isCompliant()) {
mCryptBtn->setEnabled(false);
}
mMessageWidget->setVisible(!DeVSCompliance::isCompliant());
if (mMessageWidget->isVisible() && QAccessible::isActive()) {
mMessageWidget->setFocus();
}
}
}
private:
PadWidget *const q;
QTextEdit *mEdit;
QPushButton *mCryptBtn;
QPushButton *mDecryptBtn;
QPushButton *mImportBtn;
QPushButton *mRevertBtn;
KMessageWidget *mMessageWidget;
QLabel *mAdditionalInfoLabel;
QByteArray mInputData;
QByteArray mOutputData;
SignEncryptWidget *mSigEncWidget;
QProgressBar *mProgressBar;
QLabel *mProgressLabel;
QVBoxLayout *mStatusLay;
ResultItemWidget *mLastResultWidget;
QList<GpgME::Key> mAutoAddedKeys;
GpgME::Protocol mImportProto;
};
PadWidget::PadWidget(QWidget *parent)
: QWidget(parent)
, d(new Private(this))
{
}
void PadWidget::focusFirstChild(Qt::FocusReason reason)
{
d->mEdit->setFocus(reason);
}
#include "moc_padwidget.cpp"

File Metadata

Mime Type
text/x-diff
Expires
Sat, Jan 24, 11:27 PM (7 h, 3 m)
Storage Engine
local-disk
Storage Format
Raw Data
Storage Handle
1b/b9/7dd17c57a16a1b4d1c121ef2f3ea

Event Timeline