Commit b11dfc5f authored by Ingo Klöcker's avatar Ingo Klöcker Committed by Ingo Klöcker
Browse files

Make InfoField work as intended with Windows UI Automation

Representing the value widget of an InfoField as AccessibleValueLabel
with a custom role makes Windows UI Automation treat the value widget
as a custom widget providing a value instead of as static text. This
way the text of the label widget is used as accessible name and the
text of the value widget is used as accessible value as intended.

For Linux we keep the old behavior which works with orca/AT-SPI.

GnuPG-bug-id: 6149, 5843
parent 005e3f52
Pipeline #227427 passed with stage
in 4 minutes and 40 seconds
......@@ -85,6 +85,8 @@ set(_kleopatra_SRCS
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
......
/*
accessibility/accessiblevaluelabel.cpp
This file is part of Kleopatra, the KDE keymanager
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 "accessiblevaluelabel_p.h"
#include "utils/accessibility.h"
#include <QLabel>
using namespace Kleo;
static constexpr QAccessible::Role ValueRole = static_cast<QAccessible::Role>(QAccessible::UserRole + 1);
AccessibleValueLabel::AccessibleValueLabel(QWidget *w)
: QAccessibleWidget{w, ValueRole}
{
Q_ASSERT(qobject_cast<QLabel *>(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<QLabel*>(object());
}
/*
accessibility/accessiblevaluelabel_p.h
This file is part of Kleopatra, the KDE keymanager
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 <QAccessibleWidget>
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;
};
}
......@@ -2,7 +2,7 @@
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 <dev@ingo-kloecker.de>
SPDX-License-Identifier: GPL-2.0-or-later
......@@ -11,6 +11,9 @@
#include "accessiblewidgetfactory.h"
#include "accessiblerichtextlabel_p.h"
#include "accessiblevaluelabel_p.h"
#include "utils/accessibility.h"
#include "view/htmllabel.h"
#include "view/urllabel.h"
......@@ -25,6 +28,8 @@ QAccessibleInterface *Kleo::accessibleWidgetFactory(const QString &classname, QO
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;
......
......@@ -31,6 +31,9 @@
using namespace Kleo;
static const char *accessibleNameProperty = "_kleo_accessibleName";
static const char *accessibleValueProperty = "_kleo_accessibleValue";
static const char *useAccessibleValueLabelProperty = "_kleo_useAccessibleValueLabel";
namespace
{
......@@ -64,6 +67,26 @@ 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, "
......
......@@ -10,6 +10,7 @@
#include <QAccessible>
#include <QPointer>
#include <QtGlobal>
class QAction;
class QLabel;
......@@ -35,6 +36,41 @@ namespace Kleo
*/
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();
......
......@@ -30,12 +30,20 @@ InfoField::InfoField(const QString &label, QWidget *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);
......@@ -54,7 +62,11 @@ QLayout *InfoField::layout() const {
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
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment