Page Menu
Home
GnuPG
Search
Configure Global Search
Log In
Files
F34751988
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Size
173 KB
Subscribers
None
View Options
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
Details
Attached
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
Attached To
rKLEOPATRA Kleopatra
Event Timeline
Log In to Comment