diff --git a/src/utils/accessibility.cpp b/src/utils/accessibility.cpp index 7b5cb95d6..6adb5bb7b 100644 --- a/src/utils/accessibility.cpp +++ b/src/utils/accessibility.cpp @@ -1,85 +1,107 @@ /* 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 #include +#include #include +#include "kleopatra_debug.h" + using namespace Kleo; namespace { QString getAccessibleText(QObject *object, QAccessible::Text t) { QString name; if (const auto *const iface = QAccessible::queryAccessibleInterface(object)) { name = iface->text(t); } return name; } } QString Kleo::getAccessibleName(QObject *object) { return getAccessibleText(object, QAccessible::Name); } QString Kleo::getAccessibleDescription(QObject *object) { return getAccessibleText(object, QAccessible::Description); } 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"; + } +} + 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 9baebf4ee..d860fd680 100644 --- a/src/utils/accessibility.h +++ b/src/utils/accessibility.h @@ -1,43 +1,49 @@ /* 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 class QLabel; class QObject; class QString; namespace Kleo { QString getAccessibleName(QObject *object); QString getAccessibleDescription(QObject *object); 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); + /** * 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/htmllabel.cpp b/src/view/htmllabel.cpp index a79fe4a87..5d7a5f702 100644 --- a/src/view/htmllabel.cpp +++ b/src/view/htmllabel.cpp @@ -1,85 +1,101 @@ /* view/htmllabel.cpp This file is part of Kleopatra, the KDE keymanager SPDX-FileCopyrightText: 2021 g10 Code GmbH SPDX-FileContributor: Ingo Klöcker SPDX-License-Identifier: GPL-2.0-or-later */ #include #include "htmllabel.h" +#include "utils/accessibility.h" #include using namespace Kleo; class HtmlLabel::Private { HtmlLabel *q; public: Private(HtmlLabel *q) : q{q} {} void updateText(const QString &newText = {}); QColor linkColor; }; void HtmlLabel::Private::updateText(const QString &newText) { static const QString styleTemplate{QLatin1String{""}}; if (newText.isEmpty() && q->text().isEmpty()) { return; } const auto styleTag = styleTemplate.arg(linkColor.isValid() ? linkColor.name() : q->palette().link().color().name()); if (newText.isEmpty()) { q->setText(styleTag + q->text().mid(styleTag.size())); } else { q->setText(styleTag + newText); } } HtmlLabel::HtmlLabel(QWidget *parent) : HtmlLabel{{}, parent} { } HtmlLabel::HtmlLabel(const QString &html, QWidget *parent) : QLabel{parent} , d{new Private{this}} { setTextFormat(Qt::RichText); setTextInteractionFlags(Qt::TextBrowserInteraction); setHtml(html); } HtmlLabel::~HtmlLabel() = default; void HtmlLabel::setHtml(const QString &html) { if (html.isEmpty()) { clear(); return; } d->updateText(html); } void HtmlLabel::setLinkColor(const QColor &color) { d->linkColor = color; d->updateText(); } +void HtmlLabel::focusInEvent(QFocusEvent *ev) +{ + QLabel::focusInEvent(ev); + + // if the text label gets focus, then select its text; this is a workaround + // for missing focus indicators for labels in many Qt styles + const Qt::FocusReason reason = ev->reason(); + const auto isKeyboardFocusEvent = reason == Qt::TabFocusReason + || reason == Qt::BacktabFocusReason + || reason == Qt::ShortcutFocusReason; + if (!text().isEmpty() && isKeyboardFocusEvent) { + Kleo::selectLabelText(this); + } +} + bool HtmlLabel::focusNextPrevChild(bool next) { const bool result = QLabel::focusNextPrevChild(next); if (hasFocus() && hasSelectedText()) { QAccessibleTextSelectionEvent ev(this, selectionStart(), selectionStart() + selectedText().size()); QAccessible::updateAccessibility(&ev); } return result; } diff --git a/src/view/htmllabel.h b/src/view/htmllabel.h index 92dc1e985..ab5818663 100644 --- a/src/view/htmllabel.h +++ b/src/view/htmllabel.h @@ -1,43 +1,44 @@ /* view/htmllabel.h This file is part of Kleopatra, the KDE keymanager SPDX-FileCopyrightText: 2021 g10 Code GmbH SPDX-FileContributor: Ingo Klöcker SPDX-License-Identifier: GPL-2.0-or-later */ #pragma once #include #include namespace Kleo { class HtmlLabel : public QLabel { Q_OBJECT public: explicit HtmlLabel(QWidget *parent = nullptr); explicit HtmlLabel(const QString &html, QWidget *parent = nullptr); ~HtmlLabel() override; void setHtml(const QString &html); void setLinkColor(const QColor &color); protected: + void focusInEvent(QFocusEvent *ev) override; bool focusNextPrevChild(bool next) override; private: using QLabel::setText; private: class Private; std::unique_ptr d; }; }