diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index e17f1488d..ddff82de7 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,620 +1,622 @@ # SPDX-FileCopyrightText: none # SPDX-License-Identifier: BSD-3-Clause add_subdirectory(icons) add_subdirectory(mimetypes) include_directories(${CMAKE_CURRENT_BINARY_DIR}) include_directories(${CMAKE_CURRENT_SOURCE_DIR}) if (NOT DISABLE_KWATCHGNUPG) add_subdirectory(kwatchgnupg) endif() add_subdirectory(libkleopatraclient) add_subdirectory(conf) add_subdirectory(kconf_update) if(WIN32) set(_kleopatra_extra_uiserver_SRCS uiserver/uiserver_win.cpp) set(_kleopatra_extra_SRCS selftest/registrycheck.cpp utils/gnupg-registry.c utils/userinfo_win.cpp utils/windowsprocessdevice.cpp ) 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 uiserver/assuanserverconnection.cpp uiserver/createchecksumscommand.cpp uiserver/decryptverifycommandemailbase.cpp uiserver/decryptverifycommandfilesbase.cpp uiserver/echocommand.cpp uiserver/encryptcommand.cpp uiserver/importfilescommand.cpp uiserver/prepencryptcommand.cpp uiserver/prepsigncommand.cpp uiserver/selectcertificatecommand.cpp uiserver/sessiondata.cpp uiserver/signcommand.cpp uiserver/signencryptfilescommand.cpp uiserver/uiserver.cpp uiserver/verifychecksumscommand.cpp ) if(ASSUAN2_FOUND) include_directories(${ASSUAN2_INCLUDES}) set(_kleopatra_uiserver_extra_libs ${ASSUAN2_LIBRARIES}) else() include_directories(${ASSUAN_INCLUDES}) if(WIN32) set(_kleopatra_uiserver_extra_libs ${ASSUAN_VANILLA_LIBRARIES}) else() set(_kleopatra_uiserver_extra_libs ${ASSUAN_PTHREAD_LIBRARIES}) endif() endif() if(HAVE_GPG_ERR_SOURCE_KLEO) add_definitions(-DGPG_ERR_SOURCE_DEFAULT=GPG_ERR_SOURCE_KLEO) add_definitions(-DGPGMEPP_ERR_SOURCE_DEFAULT=GPG_ERR_SOURCE_KLEO) else() add_definitions(-DGPG_ERR_SOURCE_DEFAULT=GPG_ERR_SOURCE_USER_1) add_definitions(-DGPGMEPP_ERR_SOURCE_DEFAULT=GPG_ERR_SOURCE_USER_1) endif() if(KF5IdentityManagement_FOUND AND KF5MailTransport_FOUND AND KF5MailTransportAkonadi_FOUND) set(_kleopatra_mail_libs KF5::IdentityManagement # Export OpenPGP keys using WKS KF5::MailTransport KF5::MailTransportAkonadi ) add_definitions(-DMAILAKONADI_ENABLED) endif() ki18n_wrap_ui(_kleopatra_uiserver_SRCS crypto/gui/signingcertificateselectionwidget.ui) set(_kleopatra_SRCS ${_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/adduseridcommand.cpp commands/adduseridcommand.h commands/authenticatepivcardapplicationcommand.cpp commands/authenticatepivcardapplicationcommand.h commands/cardcommand.cpp commands/cardcommand.h commands/certificatetopivcardcommand.cpp commands/certificatetopivcardcommand.h commands/certifycertificatecommand.cpp commands/certifycertificatecommand.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/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/exportsecretkeycommand_old.cpp commands/exportsecretkeycommand_old.h commands/exportsecretsubkeycommand.cpp commands/exportsecretsubkeycommand.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/learncardkeyscommand.cpp commands/learncardkeyscommand.h commands/lookupcertificatescommand.cpp commands/lookupcertificatescommand.h commands/newcertificatesigningrequestcommand.cpp commands/newcertificatesigningrequestcommand.h commands/newopenpgpcertificatecommand.cpp commands/newopenpgpcertificatecommand.h commands/pivgeneratecardkeycommand.cpp commands/pivgeneratecardkeycommand.h commands/refreshcertificatecommand.cpp commands/refreshcertificatecommand.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 conf/configuredialog.cpp conf/configuredialog.h conf/groupsconfigdialog.cpp conf/groupsconfigdialog.h conf/groupsconfigpage.cpp conf/groupsconfigpage.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/signencryptfileswizard.cpp crypto/gui/signencryptfileswizard.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/adduseriddialog.cpp dialogs/adduseriddialog.h dialogs/certificatedetailsdialog.cpp dialogs/certificatedetailsdialog.h dialogs/certificatedetailsinputwidget.cpp dialogs/certificatedetailsinputwidget.h dialogs/certificatedetailswidget.cpp dialogs/certificatedetailswidget.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/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/nameandemailwidget.cpp dialogs/nameandemailwidget.h dialogs/newopenpgpcertificatedetailsdialog.cpp dialogs/newopenpgpcertificatedetailsdialog.h dialogs/ownertrustdialog.cpp dialogs/ownertrustdialog.h dialogs/pivcardapplicationadministrationkeyinputdialog.cpp dialogs/pivcardapplicationadministrationkeyinputdialog.h dialogs/revokekeydialog.cpp dialogs/revokekeydialog.h dialogs/selftestdialog.cpp dialogs/selftestdialog.h dialogs/setinitialpindialog.cpp dialogs/setinitialpindialog.h dialogs/subkeyswidget.cpp dialogs/subkeyswidget.h dialogs/trustchainwidget.cpp dialogs/trustchainwidget.h dialogs/updatenotification.cpp dialogs/updatenotification.h dialogs/weboftrustdialog.cpp dialogs/weboftrustdialog.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/keyalgo.cpp newcertificatewizard/keyalgo_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/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/auditlog.cpp utils/auditlog.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/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/keyparameters.cpp utils/keyparameters.h utils/keys.cpp utils/keys.h utils/kuniqueservice.cpp utils/kuniqueservice.h utils/log.cpp utils/log.h utils/multivalidator.cpp utils/multivalidator.h utils/output.cpp utils/output.h utils/path-helper.cpp utils/path-helper.h utils/scrollarea.cpp utils/scrollarea.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/validation.cpp utils/validation.h utils/writecertassuantransaction.cpp utils/writecertassuantransaction.h utils/wsastarter.cpp utils/wsastarter.h view/anchorcache.cpp view/anchorcache_p.h view/errorlabel.cpp view/errorlabel.h view/formtextinput.cpp view/formtextinput.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/nullpinwidget.cpp view/nullpinwidget.h view/openpgpkeycardwidget.cpp view/openpgpkeycardwidget.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/searchbar.cpp view/searchbar.h view/smartcardwidget.cpp view/smartcardwidget.h view/tabwidget.cpp view/tabwidget.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 ) if(WIN32) configure_file (versioninfo.rc.in versioninfo.rc) set(_kleopatra_SRCS ${CMAKE_CURRENT_BINARY_DIR}/versioninfo.rc ${_kleopatra_SRCS}) endif() set (_kleopatra_SRCS conf/kleopageconfigdialog.cpp ${_kleopatra_SRCS}) ecm_qt_declare_logging_category(_kleopatra_SRCS HEADER kleopatra_debug.h IDENTIFIER KLEOPATRA_LOG CATEGORY_NAME org.kde.pim.kleopatra DESCRIPTION "kleopatra (kleopatra)" OLD_CATEGORY_NAMES log_kleopatra EXPORT KLEOPATRA ) if(KLEO_MODEL_TEST) add_definitions(-DKLEO_MODEL_TEST) set(_kleopatra_SRCS ${_kleopatra_SRCS} models/modeltest.cpp) endif() ki18n_wrap_ui(_kleopatra_SRCS dialogs/ownertrustdialog.ui dialogs/selectchecklevelwidget.ui dialogs/setinitialpindialog.ui dialogs/trustchainwidget.ui newcertificatewizard/listwidget.ui ) kconfig_add_kcfg_files(_kleopatra_SRCS kcfg/emailoperationspreferences.kcfgc kcfg/fileoperationspreferences.kcfgc kcfg/settings.kcfgc kcfg/smimevalidationpreferences.kcfgc kcfg/tagspreferences.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 ${_kleopatra_extra_libs} KF5::Libkleo KF5::Mime KF5::I18n KF5::XmlGui KF5::IconThemes KF5::WindowSystem KF5::CoreAddons KF5::ItemModels KF5::Crash ${_kleopatra_mail_libs} Qt::Network Qt::PrintSupport # Printing secret keys ${_kleopatra_uiserver_extra_libs} ${_kleopatra_dbusaddons_libs} kleopatraclientcore ${_kleopatra_platform_libs} ) if (QT_MAJOR_VERSION STREQUAL "6") target_link_libraries(kleopatra_bin QGpgmeQt6) else() target_link_libraries(kleopatra_bin QGpgme) endif() install(TARGETS kleopatra_bin ${KDE_INSTALL_TARGETS_DEFAULT_ARGS}) install( PROGRAMS data/org.kde.kleopatra.desktop data/kleopatra_import.desktop DESTINATION ${KDE_INSTALL_APPDIR} ) install(FILES data/org.kde.kleopatra.appdata.xml DESTINATION ${KDE_INSTALL_METAINFODIR}) install( PROGRAMS data/kleopatra_signencryptfiles.desktop data/kleopatra_signencryptfolders.desktop data/kleopatra_decryptverifyfiles.desktop data/kleopatra_decryptverifyfolders.desktop DESTINATION ${KDE_INSTALL_DATADIR}/kio/servicemenus ) diff --git a/src/accessibility/accessiblevaluelabel.cpp b/src/accessibility/accessiblevaluelabel.cpp new file mode 100644 index 000000000..09433924e --- /dev/null +++ b/src/accessibility/accessiblevaluelabel.cpp @@ -0,0 +1,59 @@ +/* + accessibility/accessiblevaluelabel.cpp + + This file is part of Kleopatra, the KDE keymanager + SPDX-FileCopyrightText: 2022 g10 Code GmbH + SPDX-FileContributor: Ingo Klöcker + + SPDX-License-Identifier: GPL-2.0-or-later +*/ + +#include + +#include "accessiblevaluelabel_p.h" + +#include "utils/accessibility.h" + +#include + +using namespace Kleo; + +static constexpr QAccessible::Role ValueRole = static_cast(QAccessible::UserRole + 1); + +AccessibleValueLabel::AccessibleValueLabel(QWidget *w) + : QAccessibleWidget{w, ValueRole} +{ + Q_ASSERT(qobject_cast(w)); +} + +QAccessible::State AccessibleValueLabel::state() const +{ + auto state = QAccessibleWidget::state(); + state.readOnly = true; + return state; +} + +QString AccessibleValueLabel::text(QAccessible::Text t) const +{ + QString str; + switch (t) { + case QAccessible::Value: { + str = Kleo::getAccessibleValue(widget()); + if (str.isEmpty()) { + str = label()->text(); + } + break; + } + default: + break; + } + if (str.isEmpty()) { + str = QAccessibleWidget::text(t); + } + return str; +} + +QLabel *AccessibleValueLabel::label() const +{ + return qobject_cast(object()); +} diff --git a/src/accessibility/accessiblevaluelabel_p.h b/src/accessibility/accessiblevaluelabel_p.h new file mode 100644 index 000000000..7b20d606d --- /dev/null +++ b/src/accessibility/accessiblevaluelabel_p.h @@ -0,0 +1,32 @@ +/* + accessibility/accessiblevaluelabel_p.h + + This file is part of Kleopatra, the KDE keymanager + SPDX-FileCopyrightText: 2022 g10 Code GmbH + SPDX-FileContributor: Ingo Klöcker + + SPDX-License-Identifier: GPL-2.0-or-later +*/ + +#pragma once + +#include + +class QLabel; + +namespace Kleo +{ + +class AccessibleValueLabel : public QAccessibleWidget +{ +public: + explicit AccessibleValueLabel(QWidget *w); + + QAccessible::State state() const override; + QString text(QAccessible::Text t) const override; + +private: + QLabel *label() const; +}; + +} diff --git a/src/accessibility/accessiblewidgetfactory.cpp b/src/accessibility/accessiblewidgetfactory.cpp index 4959216a9..bc11274dd 100644 --- a/src/accessibility/accessiblewidgetfactory.cpp +++ b/src/accessibility/accessiblewidgetfactory.cpp @@ -1,31 +1,36 @@ /* accessibility/accessiblewidgetfactory.cpp This file is part of Kleopatra, the KDE keymanager - SPDX-FileCopyrightText: 2021 g10 Code GmbH + SPDX-FileCopyrightText: 2021, 2022 g10 Code GmbH SPDX-FileContributor: Ingo Klöcker SPDX-License-Identifier: GPL-2.0-or-later */ #include "accessiblewidgetfactory.h" #include "accessiblerichtextlabel_p.h" +#include "accessiblevaluelabel_p.h" + +#include "utils/accessibility.h" #include "view/htmllabel.h" #include "view/urllabel.h" QAccessibleInterface *Kleo::accessibleWidgetFactory(const QString &classname, QObject *object) { QAccessibleInterface *iface = nullptr; if (!object || !object->isWidgetType()) return iface; QWidget *widget = static_cast(object); if (classname == QString::fromLatin1(Kleo::HtmlLabel::staticMetaObject.className()) || classname == QString::fromLatin1(Kleo::UrlLabel::staticMetaObject.className())) { iface = new AccessibleRichTextLabel{widget}; + } else if (classname == QLatin1String("QLabel") && Kleo::representAsAccessibleValueWidget(widget)) { + iface = new AccessibleValueLabel{widget}; } return iface; } diff --git a/src/utils/accessibility.cpp b/src/utils/accessibility.cpp index ae988a923..c6930dbbd 100644 --- a/src/utils/accessibility.cpp +++ b/src/utils/accessibility.cpp @@ -1,165 +1,188 @@ /* utils/accessibility.cpp This file is part of Kleopatra, the KDE keymanager SPDX-FileCopyrightText: 2022 g10 Code GmbH SPDX-FileContributor: Ingo Klöcker SPDX-License-Identifier: GPL-2.0-or-later */ #include #include "accessibility.h" #include #include #ifdef Q_OS_WIN32 #include #include #endif #include #include #include #include #include #include #include "kleopatra_debug.h" using namespace Kleo; static const char *accessibleNameProperty = "_kleo_accessibleName"; +static const char *accessibleValueProperty = "_kleo_accessibleValue"; + +static const char *useAccessibleValueLabelProperty = "_kleo_useAccessibleValueLabel"; namespace { QString getAccessibleText(QWidget *widget, QAccessible::Text t) { QString name; if (const auto *const iface = QAccessible::queryAccessibleInterface(widget)) { name = iface->text(t); } return name; } } QString Kleo::getAccessibleName(QWidget *widget) { return getAccessibleText(widget, QAccessible::Name); } QString Kleo::getAccessibleDescription(QWidget *widget) { return getAccessibleText(widget, QAccessible::Description); } void Kleo::setAccessibleName(QAction *action, const QString &name) { action->setProperty(accessibleNameProperty, name); } QString Kleo::getAccessibleName(const QAction *action) { return action->property(accessibleNameProperty).toString(); } +void Kleo::setAccessibleValue(QWidget *widget, const QString &value) +{ + widget->setProperty(accessibleValueProperty, value); +} + +QString Kleo::getAccessibleValue(const QWidget *widget) +{ + return widget->property(accessibleValueProperty).toString(); +} + +void Kleo::setRepresentAsAccessibleValueWidget(QWidget *widget, bool flag) +{ + widget->setProperty(useAccessibleValueLabelProperty, flag ? flag : QVariant{}); +} + +bool Kleo::representAsAccessibleValueWidget(const QWidget *widget) +{ + return widget->property(useAccessibleValueLabelProperty).toBool(); +} + QString Kleo::invalidEntryText() { return i18nc("text for screen readers to indicate that the associated object, " "such as a form field, has an error", "invalid entry"); } QString Kleo::requiredText() { return i18nc("text for screen readers to indicate that the associated object, " "such as a form field must be filled out", "required"); } void Kleo::selectLabelText(QLabel *label) { if (!label || label->text().isEmpty()) { return; } if (label->textFormat() == Qt::PlainText) { label->setSelection(0, label->text().size()); } else if (label->textFormat() == Qt::RichText) { // unfortunately, there is no selectAll(); therefore, we need // to determine the "visual" length of the text by stripping // the label's text of all formatting information QTextDocument temp; temp.setHtml(label->text()); label->setSelection(0, temp.toRawText().size()); } else { qCDebug(KLEOPATRA_LOG) << "Label with unsupported text format" << label->textFormat() << "got focus"; } } namespace { static void notifyAccessibilityClientsAboutToolTip(const QPoint &pos, QWidget *parent) { #ifdef Q_OS_WIN32 // On Windows, the tool tip's parent widget is a desktop screen widget (see implementation of QToolTip::showText) QT_WARNING_PUSH QT_WARNING_DISABLE_DEPRECATED const auto desktop = QApplication::desktop(); const int screenNumber = desktop->isVirtualDesktop() ? desktop->screenNumber(pos) : desktop->screenNumber(parent); parent = desktop->screen(screenNumber); QT_WARNING_POP #else Q_UNUSED(pos); #endif if (!parent) { return; } if (auto toolTipLabel = parent->findChild(QStringLiteral("qtooltip_label"))) { // Qt explicitly does not notify accessibility clients about the tool tip being shown because // "Tooltips are read aloud twice in MS narrator." // The problem is that they are not read out by orca (on Linux) if the notification is omitted. // Therefore, we take care of notifying the accessibility clients. #ifndef QT_NO_ACCESSIBILITY QAccessibleEvent event(toolTipLabel, QAccessible::ObjectShow); QAccessible::updateAccessibility(&event); #endif } } } void Kleo::showToolTip(const QPoint &pos, const QString &text, QWidget *w) { using namespace std::chrono_literals; static const std::chrono::milliseconds timeout = 24h; QToolTip::showText(pos, text, w, {}, timeout.count()); notifyAccessibilityClientsAboutToolTip(pos, w); } LabelHelper::LabelHelper() { QAccessible::installActivationObserver(this); } LabelHelper::~LabelHelper() { QAccessible::removeActivationObserver(this); } void LabelHelper::addLabel(QLabel *label) { mLabels.push_back(label); accessibilityActiveChanged(QAccessible::isActive()); } void LabelHelper::accessibilityActiveChanged(bool active) { // Allow text labels to get focus if accessibility is active const auto focusPolicy = active ? Qt::StrongFocus : Qt::ClickFocus; std::for_each(std::cbegin(mLabels), std::cend(mLabels), [focusPolicy](const auto &label) { if (label) { label->setFocusPolicy(focusPolicy); } }); } diff --git a/src/utils/accessibility.h b/src/utils/accessibility.h index 70eaa721d..eb7b3b056 100644 --- a/src/utils/accessibility.h +++ b/src/utils/accessibility.h @@ -1,73 +1,109 @@ /* utils/accessibility.h This file is part of Kleopatra, the KDE keymanager SPDX-FileCopyrightText: 2022 g10 Code GmbH SPDX-FileContributor: Ingo Klöcker SPDX-License-Identifier: GPL-2.0-or-later */ #pragma once #include #include +#include class QAction; class QLabel; class QObject; class QString; namespace Kleo { QString getAccessibleName(QWidget *widget); QString getAccessibleDescription(QWidget *widget); /** * Sets the accessible name of the action \p action. * * \note Qt does not provide an accessible object for a QAction. Therefore, * we store the accessible name as custom property of the action. * \sa getAccessibleName */ void setAccessibleName(QAction *action, const QString &name); /** * Returns the accessible name of the action \p action. * \sa setAccessibleName */ QString getAccessibleName(const QAction *action); + /** + * Sets \p value as accessible value of \p widget. + * + * Stores the string \p value as custom property of the widget \p widget + * for retrieval by a QAccessibleWidget. + * + * \sa getAccessibleValue + */ + void setAccessibleValue(QWidget *widget, const QString &value); + /** + * Returns the accessible value of \p widget. + * + * \sa setAccessibleValue + */ + QString getAccessibleValue(const QWidget *widget); + + /** + * Mark \p widget as being represented as AccessibleValueWidget. + * + * This is useful, if you want Windows UI Automation to treat the widget + * as labelled value, i.e. a custom widget with a value and a name. + * + * \note: Don't use this on other platforms than Windows, unless you made + * sure that it works as expected. + * \sa representAsAccessibleValueWidget + */ + void setRepresentAsAccessibleValueWidget(QWidget *widget, bool); + /** + * Returns whether \p widget is marked as being represented as + * AccessibleValueWidget. + * + * \sa setRepresentAsAccessibleValueWidget + */ + bool representAsAccessibleValueWidget(const QWidget *widget); + QString invalidEntryText(); QString requiredText(); /** * Selects the text displayed by the label. Only \ref QLabel with text format * \c Qt::PlainText or \c Qt::RichText are supported. */ void selectLabelText(QLabel *label); /** * Shows \p text as a tool tip, with the global position \p pos as the point of interest. * Additionally to QToolTip::showText, it takes care of notifying accessibility clients * about the tool tip. * \sa QToolTip::showText */ void showToolTip(const QPoint &pos, const QString &text, QWidget *w); /** * Simple helper that sets the focus policy of the associated labels * to \c Qt::StrongFocus if an assistive tool is active. */ class LabelHelper: public QAccessible::ActivationObserver { public: LabelHelper(); ~LabelHelper() override; Q_DISABLE_COPY_MOVE(LabelHelper) void addLabel(QLabel *label); private: void accessibilityActiveChanged(bool active) override; std::vector> mLabels; }; } diff --git a/src/view/infofield.cpp b/src/view/infofield.cpp index 3960f88b4..33559b3c0 100644 --- a/src/view/infofield.cpp +++ b/src/view/infofield.cpp @@ -1,130 +1,142 @@ /* view/infofield.cpp This file is part of Kleopatra, the KDE keymanager SPDX-FileCopyrightText: 2022 g10 Code GmbH SPDX-FileContributor: Ingo Klöcker SPDX-License-Identifier: GPL-2.0-or-later */ #include #include "infofield.h" #include "utils/accessibility.h" #include #include #include #include #include #include #include using namespace Kleo; InfoField::InfoField(const QString &label, QWidget *parent) : mLabel{new QLabel{label, parent}} , mLayout{new QHBoxLayout} , mIcon{new QLabel{parent}} , mValue{new QLabel{parent}} , mButton{new QPushButton{parent}} { + mLabel->setObjectName(QStringLiteral("InfoField.label")); + mIcon->setObjectName(QStringLiteral("InfoField.icon")); + mValue->setObjectName(QStringLiteral("InfoField.value")); + mButton->setObjectName(QStringLiteral("InfoField.button")); + mLabel->setBuddy(mValue); mLabel->setTextInteractionFlags(Qt::TextSelectableByMouse); mIcon->setVisible(false); mLayout->addWidget(mIcon); mValue->setTextInteractionFlags(Qt::TextSelectableByMouse); mValue->setFocusPolicy(Qt::TabFocus); +#ifdef Q_OS_WIN + Kleo::setRepresentAsAccessibleValueWidget(mValue, true); +#endif mLayout->addWidget(mValue); mButton->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); mButton->setVisible(false); mLayout->addWidget(mButton); mLayout->addStretch(); } QLabel *InfoField::label() const { return mLabel; } QLayout *InfoField::layout() const { return mLayout; } void InfoField::setValue(const QString &value, const QString &accessibleValue) { mValue->setText(value); +#ifdef Q_OS_WIN + Kleo::setAccessibleValue(mValue, accessibleValue); +#else mValue->setAccessibleName(accessibleValue); +#endif } QString InfoField::value() const { return mValue->text(); } void InfoField::setIcon(const QIcon &icon) { if (!icon.isNull()) { const int iconSize = mIcon->style()->pixelMetric(QStyle::PM_SmallIconSize, nullptr, mIcon); mIcon->setPixmap(icon.pixmap(iconSize)); mIcon->setVisible(true); } else { mIcon->setVisible(false); mIcon->clear(); } } void InfoField::setAction(const QAction *action) { if (action == mAction) { return; } if (mAction) { QObject::disconnect(mButton, {}, mAction, {}); QObject::disconnect(mAction, {}, mButton, {}); } mAction = action; if (mAction) { QObject::connect(mButton, &QPushButton::clicked, action, &QAction::trigger); QObject::connect(mAction, &QAction::changed, mButton, [this]() { onActionChanged(); }); onActionChanged(); mButton->setAccessibleName(getAccessibleName(mAction)); mButton->setVisible(true); } else { mButton->setVisible(false); mButton->setText({}); mButton->setIcon({}); } } void InfoField::setToolTip(const QString &toolTip) { mValue->setToolTip(toolTip); } void InfoField::setVisible(bool visible) { mLabel->setVisible(visible); mIcon->setVisible(visible && !mIcon->pixmap(Qt::ReturnByValue).isNull()); mValue->setVisible(visible); mButton->setVisible(visible && mAction); } void InfoField::onActionChanged() { if (!mAction) { return; } if (mAction->text() != mButton->text()) { mButton->setText(mAction->text()); } mButton->setIcon(mAction->icon()); if (mAction->toolTip() != mButton->toolTip()) { mButton->setToolTip(mAction->toolTip()); } if (mAction->isEnabled() != mButton->isEnabled()) { mButton->setEnabled(mAction->isEnabled()); } }