summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorVolker Hilsheimer <volker.hilsheimer@qt.io>2022-06-13 20:50:22 +0200
committerVolker Hilsheimer <volker.hilsheimer@qt.io>2022-06-16 19:29:36 +0200
commit56d6a360206c7bd93e6503a63daf1517ff40a1d4 (patch)
treec266ba049da735c5318d45caa5bc60d1cba04846
parent4d25429746dd1d71aac373c5ecd3d56756ce4d80 (diff)
Implement a dedicated QAccessibleInterface for QMessageBox
QMessageBox has text values that an accessible client should be able to read directly without having to navigate through the text labels. Add test coverage. Windows Narrator is inconsistent in reading the contents of a message box. It might skip them completely, even though the text property is read through the interface. Task-number: QTBUG-101585 Change-Id: I639c2210a627733c093743790c6a6b83f4bb80d0 Reviewed-by: Jan Arve Sæther <jan-arve.saether@qt.io>
-rw-r--r--src/widgets/accessible/qaccessiblewidgetfactory.cpp2
-rw-r--r--src/widgets/accessible/simplewidgets.cpp43
-rw-r--r--src/widgets/accessible/simplewidgets_p.h11
-rw-r--r--tests/auto/other/qaccessibility/tst_qaccessibility.cpp104
4 files changed, 159 insertions, 1 deletions
diff --git a/src/widgets/accessible/qaccessiblewidgetfactory.cpp b/src/widgets/accessible/qaccessiblewidgetfactory.cpp
index c0a025e048..01ada3a5c5 100644
--- a/src/widgets/accessible/qaccessiblewidgetfactory.cpp
+++ b/src/widgets/accessible/qaccessiblewidgetfactory.cpp
@@ -85,7 +85,7 @@ QAccessibleInterface *qAccessibleFactory(const QString &classname, QObject *obje
} else if (classname == "QDialog"_L1) {
iface = new QAccessibleWidget(widget, QAccessible::Dialog);
} else if (classname == "QMessageBox"_L1) {
- iface = new QAccessibleWidget(widget, QAccessible::AlertMessage);
+ iface = new QAccessibleMessageBox(widget);
#if QT_CONFIG(mainwindow)
} else if (classname == "QMainWindow"_L1) {
iface = new QAccessibleMainWindow(widget);
diff --git a/src/widgets/accessible/simplewidgets.cpp b/src/widgets/accessible/simplewidgets.cpp
index f149bad170..bb0f8401d3 100644
--- a/src/widgets/accessible/simplewidgets.cpp
+++ b/src/widgets/accessible/simplewidgets.cpp
@@ -43,6 +43,8 @@
#ifndef QT_NO_PICTURE
#include <QtGui/qpicture.h>
#endif
+#include <qmessagebox.h>
+#include <qdialogbuttonbox.h>
#include <qstyle.h>
#include <qstyleoption.h>
#include <qtextdocument.h>
@@ -951,6 +953,47 @@ QWindowContainer *QAccessibleWindowContainer::container() const
return static_cast<QWindowContainer *>(widget());
}
+/*!
+ \internal
+ Implements QAccessibleWidget for QMessageBox
+*/
+QAccessibleMessageBox::QAccessibleMessageBox(QWidget *widget)
+ : QAccessibleWidget(widget, QAccessible::AlertMessage)
+{
+ Q_ASSERT(qobject_cast<QMessageBox *>(widget));
+}
+
+QMessageBox *QAccessibleMessageBox::messageBox() const
+{
+ return static_cast<QMessageBox *>(widget());
+}
+
+QString QAccessibleMessageBox::text(QAccessible::Text t) const
+{
+ QString str;
+
+ switch (t) {
+ case QAccessible::Name:
+ str = QAccessibleWidget::text(t);
+ if (str.isEmpty()) // implies no title text is set
+ str = messageBox()->text();
+ break;
+ case QAccessible::Description:
+ str = widget()->accessibleDescription();
+ break;
+ case QAccessible::Value:
+ str = messageBox()->text();
+ break;
+ case QAccessible::Help:
+ str = messageBox()->informativeText();
+ break;
+ default:
+ break;
+ }
+
+ return str;
+}
+
#endif // QT_CONFIG(accessibility)
QT_END_NAMESPACE
diff --git a/src/widgets/accessible/simplewidgets_p.h b/src/widgets/accessible/simplewidgets_p.h
index 3d0a76c078..027d3c7bbc 100644
--- a/src/widgets/accessible/simplewidgets_p.h
+++ b/src/widgets/accessible/simplewidgets_p.h
@@ -27,6 +27,7 @@ class QAbstractButton;
class QLineEdit;
class QToolButton;
class QGroupBox;
+class QMessageBox;
class QProgressBar;
#if QT_CONFIG(abstractbutton)
@@ -189,6 +190,16 @@ private:
QWindowContainer *container() const;
};
+class QAccessibleMessageBox : public QAccessibleWidget
+{
+public:
+ explicit QAccessibleMessageBox(QWidget *widget);
+
+ QString text(QAccessible::Text t) const override;
+
+ QMessageBox *messageBox() const;
+};
+
#endif // QT_CONFIG(accessibility)
QT_END_NAMESPACE
diff --git a/tests/auto/other/qaccessibility/tst_qaccessibility.cpp b/tests/auto/other/qaccessibility/tst_qaccessibility.cpp
index 779e5021e1..de0942ba08 100644
--- a/tests/auto/other/qaccessibility/tst_qaccessibility.cpp
+++ b/tests/auto/other/qaccessibility/tst_qaccessibility.cpp
@@ -21,6 +21,8 @@
#include <QtGui/private/qguiapplication_p.h>
#include <QtGui/private/qhighdpiscaling_p.h>
+#include <QtWidgets/private/qdialog_p.h>
+
#if defined(Q_OS_WIN) && defined(interface)
# undef interface
#endif
@@ -219,6 +221,9 @@ private slots:
void bridgeTest();
void focusChild();
+ void messageBoxTest_data();
+ void messageBoxTest();
+
protected slots:
void onClicked();
private:
@@ -4196,6 +4201,105 @@ void tst_QAccessibility::focusChild()
}
}
+void tst_QAccessibility::messageBoxTest_data()
+{
+ QTest::addColumn<QMessageBox::Icon>("icon");
+ QTest::addColumn<QMessageBox::StandardButtons>("buttons");
+ QTest::addColumn<QString>("title");
+ QTest::addColumn<QString>("text");
+ QTest::addColumn<QString>("infoText");
+ QTest::addColumn<QString>("details");
+ QTest::addColumn<bool>("checkbox");
+ QTest::addColumn<bool>("textInteractive");
+
+ QTest::addRow("Information") << QMessageBox::Information
+ << QMessageBox::StandardButtons(QMessageBox::Ok)
+ << "Information"
+ << "Here, have some information."
+ << QString()
+ << QString()
+ << false
+ << false;
+
+ QTest::addRow("Warning") << QMessageBox::Warning
+ << QMessageBox::StandardButtons(QMessageBox::Ok | QMessageBox::Cancel)
+ << "Warning"
+ << "This is a dangerous operation!"
+ << "Ok or Cancel?"
+ << QString()
+ << true
+ << false;
+
+ QTest::addRow("Error") << QMessageBox::Critical
+ << QMessageBox::StandardButtons(QMessageBox::Abort | QMessageBox::Retry | QMessageBox::Ignore)
+ << "Error"
+ << "Operation failed for http://example.com"
+ << "You have to decide what to do"
+ << "Detailed log output"
+ << false
+ << true;
+}
+
+void tst_QAccessibility::messageBoxTest()
+{
+ QFETCH(QMessageBox::Icon, icon);
+ QFETCH(QMessageBox::StandardButtons, buttons);
+ QFETCH(QString, title);
+ QFETCH(QString, text);
+ QFETCH(QString, infoText);
+ QFETCH(QString, details);
+ QFETCH(bool, checkbox);
+ QFETCH(bool, textInteractive);
+
+ QMessageBox box(icon, title, text, buttons);
+
+ QAccessibleInterface *iface = QAccessible::queryAccessibleInterface(&box);
+ QVERIFY(iface);
+ QCOMPARE(iface->role(), QAccessible::AlertMessage);
+#ifndef Q_OS_DARWIN // macOS message boxes show no title
+ QCOMPARE(iface->text(QAccessible::Name), title);
+#endif
+ QCOMPARE(iface->text(QAccessible::Value), text);
+
+ int expectedChildCount = 3;
+ QCOMPARE(iface->childCount(), expectedChildCount);
+
+ if (textInteractive)
+ box.setTextInteractionFlags(Qt::TextBrowserInteraction);
+
+ if (!infoText.isEmpty()) {
+ box.setInformativeText(infoText);
+ QCOMPARE(iface->childCount(), ++expectedChildCount);
+ }
+ QCOMPARE(iface->text(QAccessible::Help), infoText);
+
+ if (!details.isEmpty()) {
+ box.setDetailedText(details);
+ QCOMPARE(iface->childCount(), ++expectedChildCount);
+ }
+ if (checkbox) {
+ box.setCheckBox(new QCheckBox("Don't show again"));
+ QCOMPARE(iface->childCount(), ++expectedChildCount);
+ }
+
+ QTestAccessibility::clearEvents();
+
+ QDialogPrivate *boxPrivate = static_cast<QDialogPrivate *>(QDialogPrivate::get(&box));
+ if (!boxPrivate->canBeNativeDialog()) {
+ // platforms that use a native message box will not emit accessibility events
+ box.show();
+
+ QAccessibleEvent showEvent(&box, QAccessible::DialogStart);
+ QVERIFY(QTestAccessibility::containsEvent(&showEvent));
+
+ box.hide();
+
+ QAccessibleEvent hideEvent(&box, QAccessible::DialogEnd);
+ QVERIFY(QTestAccessibility::containsEvent(&hideEvent));
+ }
+
+ QTestAccessibility::clearEvents();
+}
QTEST_MAIN(tst_QAccessibility)
#include "tst_qaccessibility.moc"