cui/source/dialogs/SpellDialog.cxx | 2 - cui/uiconfig/ui/spellingdialog.ui | 6 +-- include/test/a11y/AccessibilityTools.hxx | 8 ++++ sc/qa/uitest/calc_tests8/tdf125051.py | 2 - sw/qa/extras/accessibility/dialogs.cxx | 55 ++++++++++++++++++++++++++++++ sw/qa/uitest/writer_tests4/spellDialog.py | 2 - test/source/a11y/AccessibilityTools.cxx | 17 +++++++++ 7 files changed, 86 insertions(+), 6 deletions(-)
New commits: commit 39b15dc8f0adec9e856a39cf319c7c8ae6750043 Author: Michael Weghorn <m.wegh...@posteo.de> AuthorDate: Fri Nov 8 13:56:08 2024 +0100 Commit: Michael Weghorn <m.wegh...@posteo.de> CommitDate: Fri Nov 8 16:55:08 2024 +0100 tdf#155447 a11y: Add test for accessible IDs expected by Orca Add a new AccessibilityTools::getAccessibleObjectForId helper that can be used in a11y tests to identify an object by its accessible ID. Add a test that checks that the accessible ID of the spelling dialog matches what Orca's logic expects in order to identify it, and that more UI elements with expected accessible IDs exist. This is to prevent breaking Orca logic without noticing. Any changes affecting this test should be discussed with the Orca maintainer first. See the comment above the newly added test for more details and a link to the corresponding Orca commits. The new test initially only checks that objects with corresponding IDs exist, could be extended to verify more of their properties as needed. Logic for checking availability of a dictionary, needed for spell check was taken over from the existing tdf155705 test in sw/qa/extras/accessibility/tdf155705.cxx, whose sample doc is also used. Change-Id: I0c5629272a89a4a570e080e62e99b6c105369cf9 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/176281 Tested-by: Jenkins Reviewed-by: Michael Weghorn <m.wegh...@posteo.de> diff --git a/include/test/a11y/AccessibilityTools.hxx b/include/test/a11y/AccessibilityTools.hxx index 10d67f2a5338..687275b097a7 100644 --- a/include/test/a11y/AccessibilityTools.hxx +++ b/include/test/a11y/AccessibilityTools.hxx @@ -52,6 +52,14 @@ public: const css::uno::Reference<css::accessibility::XAccessible>& xAcc, const std::function< bool(const css::uno::Reference<css::accessibility::XAccessibleContext>&)>& cPredicate); + + static css::uno::Reference<css::accessibility::XAccessibleContext> getAccessibleObjectForId( + const css::uno::Reference<css::accessibility::XAccessibleContext>& xCtx, + std::u16string_view sId); + static css::uno::Reference<css::accessibility::XAccessibleContext> + getAccessibleObjectForId(const css::uno::Reference<css::accessibility::XAccessible>& xacc, + std::u16string_view sId); + static css::uno::Reference<css::accessibility::XAccessibleContext> getAccessibleObjectForRole( const css::uno::Reference<css::accessibility::XAccessibleContext>& xCtx, sal_Int16 role); static css::uno::Reference<css::accessibility::XAccessibleContext> diff --git a/sw/qa/extras/accessibility/dialogs.cxx b/sw/qa/extras/accessibility/dialogs.cxx index 18662ce7cd9b..1072a2c47b1f 100644 --- a/sw/qa/extras/accessibility/dialogs.cxx +++ b/sw/qa/extras/accessibility/dialogs.cxx @@ -9,6 +9,10 @@ #include <com/sun/star/awt/Key.hpp> #include <com/sun/star/accessibility/AccessibleRole.hpp> +#include <com/sun/star/accessibility/XAccessibleContext2.hpp> +#include <com/sun/star/linguistic2/LinguServiceManager.hpp> +#include <com/sun/star/linguistic2/XLinguServiceManager2.hpp> +#include <com/sun/star/linguistic2/XSpellChecker1.hpp> #include <vcl/scheduler.hxx> @@ -16,6 +20,7 @@ #include <test/a11y/AccessibilityTools.hxx> using namespace css; +using namespace css::accessibility; // FIXME: dialog API doesn't work on macos yet #if !defined(MACOSX) @@ -190,6 +195,56 @@ CPPUNIT_TEST_FIXTURE(test::AccessibleTestBase, BasicTestFrameDialog) collectText()); } +/* Verify that UI elements in the spell check dialog have the accessible IDs + * set that that Orca screen reader's logic to identify them depends on, + * see tdf#155447 and following Orca commits: + * + * https://gitlab.gnome.org/GNOME/orca/-/commit/6221f4ecf542646a80e47ee7236380360f0e1a85 + * https://gitlab.gnome.org/GNOME/orca/-/commit/40a2d302eb52295433fd84e6c254a7dbe5108a24 + * + * (Changes should be discussed with the Orca maintainer first.) + * + * While the Orca logic depends only on case-insensitive name starting + * with a certain string, this test uses the full accessible ID + * (which matches the GtkBuilder ID in ./cui/uiconfig/ui/spellingdialog.ui) + * in order to identify the elements. + */ +CPPUNIT_TEST_FIXTURE(test::AccessibleTestBase, SpellingDialog) +{ + // spell check depends on dictionary being available, so skip test if unavailable + uno::Reference<linguistic2::XLinguServiceManager2> xLSM2 + = linguistic2::LinguServiceManager::create(m_xContext); + uno::Reference<linguistic2::XSpellChecker1> xSpell(xLSM2->getSpellChecker(), uno::UNO_QUERY); + if (!xSpell.is() || !xSpell->hasLanguage(static_cast<sal_uInt16>(LANGUAGE_ENGLISH_US))) + return; + + loadFromSrc(u"/sw/qa/extras/accessibility/testdocuments/tdf155705.fodt"_ustr); + + auto dialogWaiter = awaitDialog(u"Spelling: English (USA)", [](Dialog& dialog) { + uno::Reference<XAccessible> xDialogAcc = dialog.getAccessible(); + + uno::Reference<XAccessibleContext2> xDialogContext(xDialogAcc->getAccessibleContext(), + uno::UNO_QUERY); + CPPUNIT_ASSERT(xDialogContext.is()); + CPPUNIT_ASSERT_EQUAL(u"SpellingDialog"_ustr, xDialogContext->getAccessibleId()); + + uno::Reference<XAccessibleContext> xSentenceAcc + = AccessibilityTools::getAccessibleObjectForId(xDialogContext, u"errorsentence"); + CPPUNIT_ASSERT(xSentenceAcc.is()); + + uno::Reference<XAccessibleContext> xSuggestionsAcc + = AccessibilityTools::getAccessibleObjectForId(xDialogContext, u"suggestionslb"); + CPPUNIT_ASSERT(xSuggestionsAcc.is()); + + CPPUNIT_ASSERT(dialog.tabTo(accessibility::AccessibleRole::PUSH_BUTTON, u"Close")); + dialog.postKeyEventAsync(0, awt::Key::RETURN); + Scheduler::ProcessEventsToIdle(); + }); + + CPPUNIT_ASSERT(activateMenuItem(u"Tools", u"Spelling...")); + CPPUNIT_ASSERT(dialogWaiter->waitEndDialog()); +} + #endif //defined(MACOSX) /* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ diff --git a/test/source/a11y/AccessibilityTools.cxx b/test/source/a11y/AccessibilityTools.cxx index e972836198c7..b91d431db9b5 100644 --- a/test/source/a11y/AccessibilityTools.cxx +++ b/test/source/a11y/AccessibilityTools.cxx @@ -70,6 +70,23 @@ AccessibilityTools::getAccessibleObjectForPredicate( return getAccessibleObjectForPredicate(xAcc->getAccessibleContext(), cPredicate); } +uno::Reference<accessibility::XAccessibleContext> AccessibilityTools::getAccessibleObjectForId( + const uno::Reference<accessibility::XAccessibleContext>& xCtx, std::u16string_view sId) +{ + return getAccessibleObjectForPredicate( + xCtx, [&](const uno::Reference<accessibility::XAccessibleContext>& xObjCtx) { + uno::Reference<accessibility::XAccessibleContext2> xContext2(xObjCtx, uno::UNO_QUERY); + return (xContext2 && xContext2->getAccessibleId() == sId); + }); +} + +css::uno::Reference<css::accessibility::XAccessibleContext> +AccessibilityTools::getAccessibleObjectForId( + const css::uno::Reference<css::accessibility::XAccessible>& xacc, const std::u16string_view sId) +{ + return getAccessibleObjectForId(xacc->getAccessibleContext(), sId); +} + uno::Reference<accessibility::XAccessibleContext> AccessibilityTools::getAccessibleObjectForRole( const uno::Reference<accessibility::XAccessibleContext>& xCtx, sal_Int16 role) { commit 4b7316e2ff6e63bbf73e0bcf04f90b807d9829ad Author: Michael Weghorn <m.wegh...@posteo.de> AuthorDate: Fri Nov 8 11:34:11 2024 +0100 Commit: Michael Weghorn <m.wegh...@posteo.de> CommitDate: Fri Nov 8 16:55:01 2024 +0100 tdf#155447 a11y: Set accessible ID that Orca expects Orca commit [1] commit 40a2d302eb52295433fd84e6c254a7dbe5108a24 Author: Joanmarie Diggs <jdi...@igalia.com> Date: Thu Nov 7 14:15:07 2024 +0100 Spellcheck: Check for accessible id in more places Do the following case-insensitive checks: * If the object's accessible id starts with "suggestions" treat it as the suggestions list. * If the object's accessible id starts with "replacement" treat it as the object (likely entry) which contains the proposed replacement. * If the label's/widget's accessible id starts with "error" treat it as the container displaying the misspelled word. Note that the first of the three is based on what LO 25.2 currently exposes ("suggestionslb"). The other two are not in use yet, but adding them facilitates implementation in, and getting feedback from, apps and toolkits. Also modify the existing check for the window. We were doing an exact match on "SpellingDialog". Making that case insensitive and limiting to starts with "spelling" works with the current LO implementation and removes an implementation detail ("dialog"). introduced logic to identify more UI elements in the spelling dialog by their accessible ID. Adjust the GtkBuilder ID (which gets reported as accessible ID as well) of the drawing area that holds the misspelt text to match the expectations as mentioned in the commit message above. [1] https://gitlab.gnome.org/GNOME/orca/-/commit/40a2d302eb52295433fd84e6c254a7dbe5108a24 Change-Id: I0658de40a47e46a6b2451dfb4ee30d1457b9f9e3 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/176280 Reviewed-by: Michael Weghorn <m.wegh...@posteo.de> Tested-by: Jenkins diff --git a/cui/source/dialogs/SpellDialog.cxx b/cui/source/dialogs/SpellDialog.cxx index dd017cf3de15..0b2e1ad3c6df 100644 --- a/cui/source/dialogs/SpellDialog.cxx +++ b/cui/source/dialogs/SpellDialog.cxx @@ -190,7 +190,7 @@ SpellDialog::SpellDialog(SpellDialogChildWindow* pChildWindow, , m_xUndoPB(m_xBuilder->weld_button(u"undo"_ustr)) , m_xClosePB(m_xBuilder->weld_button(u"close"_ustr)) , m_xToolbar(m_xBuilder->weld_toolbar(u"toolbar"_ustr)) - , m_xSentenceEDWeld(new weld::CustomWeld(*m_xBuilder, u"sentence"_ustr, *m_xSentenceED)) + , m_xSentenceEDWeld(new weld::CustomWeld(*m_xBuilder, u"errorsentence"_ustr, *m_xSentenceED)) { m_xSentenceED->SetSpellDialog(this); m_xSentenceED->Init(m_xToolbar.get()); diff --git a/cui/uiconfig/ui/spellingdialog.ui b/cui/uiconfig/ui/spellingdialog.ui index 9aa0ae3145e7..80103891ba71 100644 --- a/cui/uiconfig/ui/spellingdialog.ui +++ b/cui/uiconfig/ui/spellingdialog.ui @@ -165,12 +165,12 @@ <property name="visible">True</property> <property name="can-focus">False</property> <child> - <object class="GtkDrawingArea" id="sentence"> + <object class="GtkDrawingArea" id="errorsentence"> <property name="visible">True</property> <property name="can-focus">True</property> <property name="events">GDK_BUTTON_MOTION_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK | GDK_FOCUS_CHANGE_MASK | GDK_STRUCTURE_MASK</property> <child internal-child="accessible"> - <object class="AtkObject" id="sentence-atkobject"> + <object class="AtkObject" id="errorsentence-atkobject"> <property name="AtkObject::accessible-description" translatable="yes" context="spellingdialog|extended_tip|sentence">Displays the sentence with the misspelled word highlighted. Edit the word or the sentence, or click one of the suggestions in the text box below.</property> </object> </child> @@ -275,7 +275,7 @@ <property name="hexpand">True</property> <property name="label" translatable="yes" context="spellingdialog|notindictft">_Not in Dictionary</property> <property name="use-underline">True</property> - <property name="mnemonic-widget">sentence</property> + <property name="mnemonic-widget">errorsentence</property> <property name="xalign">0</property> </object> <packing> diff --git a/sc/qa/uitest/calc_tests8/tdf125051.py b/sc/qa/uitest/calc_tests8/tdf125051.py index c099e2e3d368..abf9836e97f9 100644 --- a/sc/qa/uitest/calc_tests8/tdf125051.py +++ b/sc/qa/uitest/calc_tests8/tdf125051.py @@ -23,7 +23,7 @@ class tdf125051(UITestCase): enter_text_to_cell(gridwin, "A1", "teext") gridwin.executeAction("SELECT", mkPropertyValues({"CELL": "A1"})) with self.ui_test.execute_dialog_through_command(".uno:SpellDialog", close_button="close") as xDialog: - xSentence = xDialog.getChild("sentence") + xSentence = xDialog.getChild("errorsentence") self.assertEqual("teext", get_state_as_dict(xSentence)['Text']) xLanguagelb = xDialog.getChild("languagelb") diff --git a/sw/qa/uitest/writer_tests4/spellDialog.py b/sw/qa/uitest/writer_tests4/spellDialog.py index 17898c4dc5b7..c01e78e10593 100644 --- a/sw/qa/uitest/writer_tests4/spellDialog.py +++ b/sw/qa/uitest/writer_tests4/spellDialog.py @@ -189,7 +189,7 @@ frog, dogg, catt""" with self.ui_test.load_file(get_url_for_data_file("tdf157992.odt")) as document: with self.ui_test.execute_modeless_dialog_through_command(".uno:SpellingAndGrammarDialog", close_button="") as xDialog: - sentence = xDialog.getChild('sentence') + sentence = xDialog.getChild('errorsentence') sentence.executeAction('TYPE', mkPropertyValues({'KEYCODE':'RIGHT'})) sentence.executeAction('TYPE', mkPropertyValues({'KEYCODE':'DELETE'})) sentence.executeAction('TYPE', mkPropertyValues({'KEYCODE':'DELETE'}))