From 2a28ebeef5ea3e2b01d836a7233d2316b765bf38 Mon Sep 17 00:00:00 2001 From: Mike Kaganski Date: Wed, 1 Jun 2022 11:18:26 +0300 Subject: [PATCH] Accessibility for IconView Change-Id: I65ca9d43f70a50e2e95aabfc3b8ba1b15f9ff8be Reviewed-on: https://gerrit.libreoffice.org/c/core/+/135226 Tested-by: Jenkins Reviewed-by: Mike Kaganski --- accessibility/Library_acc.mk | 1 + .../inc/extended/AccessibleIconView.hxx | 30 +++++++++++ .../inc/extended/accessiblelistbox.hxx | 9 ++-- .../source/extended/AccessibleIconView.cxx | 53 +++++++++++++++++++ .../extended/accessiblelistboxentry.cxx | 25 +-------- accessibility/source/helper/acc_factory.cxx | 13 +++++ include/vcl/accessiblefactory.hxx | 5 ++ include/vcl/toolkit/treelistbox.hxx | 2 + include/vcl/weld.hxx | 5 +- starmath/source/accessibility.cxx | 6 +-- vcl/inc/iconview.hxx | 11 ++++ vcl/inc/salvtables.hxx | 1 + vcl/source/app/salvtables.cxx | 12 +++++ vcl/source/helper/svtaccessiblefactory.cxx | 9 ++++ vcl/source/treelist/iconview.cxx | 25 +++++++++ vcl/source/treelist/treelistbox.cxx | 27 ++++++++++ 16 files changed, 202 insertions(+), 32 deletions(-) create mode 100644 accessibility/inc/extended/AccessibleIconView.hxx create mode 100644 accessibility/source/extended/AccessibleIconView.cxx diff --git a/accessibility/Library_acc.mk b/accessibility/Library_acc.mk index 0926fee97e5d..34c4dc7eb0c5 100644 --- a/accessibility/Library_acc.mk +++ b/accessibility/Library_acc.mk @@ -62,6 +62,7 @@ $(eval $(call gb_Library_add_exception_objects,acc,\ accessibility/source/extended/accessibleeditbrowseboxcell \ accessibility/source/extended/accessibleiconchoicectrl \ accessibility/source/extended/accessibleiconchoicectrlentry \ + accessibility/source/extended/AccessibleIconView \ accessibility/source/extended/accessiblelistbox \ accessibility/source/extended/accessiblelistboxentry \ accessibility/source/extended/accessibletablistbox \ diff --git a/accessibility/inc/extended/AccessibleIconView.hxx b/accessibility/inc/extended/AccessibleIconView.hxx new file mode 100644 index 000000000000..d5ab5eafb198 --- /dev/null +++ b/accessibility/inc/extended/AccessibleIconView.hxx @@ -0,0 +1,30 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#pragma once + +#include + +#include "accessiblelistbox.hxx" + +namespace accessibility +{ +class AccessibleIconView final : public AccessibleListBox +{ +public: + AccessibleIconView(SvTreeListBox const& _rListBox, + const css::uno::Reference& _xParent); + +protected: + // VCLXAccessibleComponent + virtual void ProcessWindowEvent(const VclWindowEvent& rVclWindowEvent) override; +}; +} // namespace accessibility + +/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ diff --git a/accessibility/inc/extended/accessiblelistbox.hxx b/accessibility/inc/extended/accessiblelistbox.hxx index 4f4104701709..40b01ea180a5 100644 --- a/accessibility/inc/extended/accessiblelistbox.hxx +++ b/accessibility/inc/extended/accessiblelistbox.hxx @@ -37,7 +37,7 @@ namespace accessibility /** the class OAccessibleListBoxEntry represents the base class for an accessible object of a listbox entry */ - class AccessibleListBox final : + class AccessibleListBox : public cppu::ImplHelper2< css::accessibility::XAccessible, css::accessibility::XAccessibleSelection>, @@ -45,18 +45,17 @@ namespace accessibility { css::uno::Reference< css::accessibility::XAccessible > m_xParent; - - virtual ~AccessibleListBox() override; - // OComponentHelper overridables /** this function is called upon disposing the component */ virtual void SAL_CALL disposing() override; + protected: // VCLXAccessibleComponent virtual void ProcessWindowEvent( const VclWindowEvent& rVclWindowEvent ) override; virtual void ProcessWindowChildEvent( const VclWindowEvent& rVclWindowEvent ) override; virtual void FillAccessibleStateSet( utl::AccessibleStateSetHelper& rStateSet ) override; + private: VclPtr< SvTreeListBox > getListBox() const; void RemoveChildEntries(SvTreeListEntry*); @@ -73,6 +72,8 @@ namespace accessibility AccessibleListBox( SvTreeListBox const & _rListBox, const css::uno::Reference< css::accessibility::XAccessible >& _xParent ); + virtual ~AccessibleListBox() override; + rtl::Reference implGetAccessible(SvTreeListEntry & rEntry); // XTypeProvider diff --git a/accessibility/source/extended/AccessibleIconView.cxx b/accessibility/source/extended/AccessibleIconView.cxx new file mode 100644 index 000000000000..6bc5c99e9243 --- /dev/null +++ b/accessibility/source/extended/AccessibleIconView.cxx @@ -0,0 +1,53 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include + +#include + +#include +#include + +#include + +namespace accessibility +{ +AccessibleIconView::AccessibleIconView( + SvTreeListBox const& _rListBox, + const css::uno::Reference& _xParent) + : AccessibleListBox(_rListBox, _xParent) +{ +} + +void AccessibleIconView::ProcessWindowEvent(const VclWindowEvent& rVclWindowEvent) +{ + if (!isAlive()) + return; + + switch (rVclWindowEvent.GetId()) + { + case VclEventId::WindowMouseMove: + if (MouseEvent* pMouseEvt = static_cast(rVclWindowEvent.GetData())) + { + if (auto xChild = getAccessibleAtPoint(AWTPoint(pMouseEvt->GetPosPixel()))) + { + // Allow announcing the element on mouse hover + css::uno::Any aNew(xChild); + NotifyAccessibleEvent( + css::accessibility::AccessibleEventId::ACTIVE_DESCENDANT_CHANGED, {}, aNew); + } + } + break; + default: + AccessibleListBox::ProcessWindowEvent(rVclWindowEvent); + } +} +} // namespace accessibility + +/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ diff --git a/accessibility/source/extended/accessiblelistboxentry.cxx b/accessibility/source/extended/accessiblelistboxentry.cxx index a1e38012dfff..2fff77b03699 100644 --- a/accessibility/source/extended/accessiblelistboxentry.cxx +++ b/accessibility/source/extended/accessiblelistboxentry.cxx @@ -439,33 +439,12 @@ namespace accessibility SolarMutexGuard aSolarGuard; ::osl::MutexGuard aGuard( m_aMutex ); - SvTreeListEntry* pEntry = m_pTreeListBox->GetEntryFromPath( m_aEntryPath ); if( getAccessibleRole() == AccessibleRole::TREE_ITEM ) { return OUString(); } - //want to count the real column number in the list box. - sal_uInt16 iRealItemCount = 0; - sal_uInt16 iCount = 0; - sal_uInt16 iTotleItemCount = pEntry->ItemCount(); - while( iCount < iTotleItemCount ) - { - const SvLBoxItem& rItem = pEntry->GetItem( iCount ); - if ( rItem.GetType() == SvLBoxItemType::String && - !static_cast( rItem ).GetText().isEmpty() ) - { - iRealItemCount++; - } - iCount++; - } - if(iRealItemCount<=1 ) - { - return OUString(); - } - else - { - return SvTreeListBox::SearchEntryTextWithHeadTitle( pEntry ); - } + return m_pTreeListBox->GetEntryAccessibleDescription( + m_pTreeListBox->GetEntryFromPath(m_aEntryPath)); } OUString SAL_CALL AccessibleListBoxEntry::getAccessibleName( ) diff --git a/accessibility/source/helper/acc_factory.cxx b/accessibility/source/helper/acc_factory.cxx index 53ed173c15b2..10cc27f007c6 100644 --- a/accessibility/source/helper/acc_factory.cxx +++ b/accessibility/source/helper/acc_factory.cxx @@ -46,6 +46,7 @@ #include #include #include +#include #include #include #include @@ -155,6 +156,12 @@ public: const css::uno::Reference< css::accessibility::XAccessible >& _xParent ) const override; + virtual css::uno::Reference< css::accessibility::XAccessible > + createAccessibleIconView( + SvTreeListBox& _rListBox, + const css::uno::Reference< css::accessibility::XAccessible >& _xParent + ) const override; + virtual css::uno::Reference< css::accessibility::XAccessible > createAccessibleBrowseBoxHeaderBar( const css::uno::Reference< css::accessibility::XAccessible >& rxParent, @@ -407,6 +414,12 @@ Reference< XAccessible > AccessibleFactory::createAccessibleTreeListBox( return new AccessibleListBox( _rListBox, _xParent ); } +Reference< XAccessible > AccessibleFactory::createAccessibleIconView( + SvTreeListBox& _rListBox, const Reference< XAccessible >& _xParent ) const +{ + return new AccessibleIconView( _rListBox, _xParent ); +} + Reference< XAccessible > AccessibleFactory::createAccessibleBrowseBoxHeaderBar( const Reference< XAccessible >& rxParent, vcl::IAccessibleTableProvider& _rOwningTable, AccessibleBrowseBoxObjType _eObjType ) const diff --git a/include/vcl/accessiblefactory.hxx b/include/vcl/accessiblefactory.hxx index f0482392fb65..a13e4dabc135 100644 --- a/include/vcl/accessiblefactory.hxx +++ b/include/vcl/accessiblefactory.hxx @@ -82,6 +82,11 @@ namespace vcl SvTreeListBox& _rListBox, const css::uno::Reference< css::accessibility::XAccessible >& _xParent ) const = 0; + virtual css::uno::Reference< css::accessibility::XAccessible > + createAccessibleIconView( + SvTreeListBox& _rListBox, + const css::uno::Reference< css::accessibility::XAccessible >& _xParent + ) const = 0; virtual vcl::IAccessibleBrowseBox* createAccessibleBrowseBox( const css::uno::Reference< css::accessibility::XAccessible >& _rxParent, diff --git a/include/vcl/toolkit/treelistbox.hxx b/include/vcl/toolkit/treelistbox.hxx index 7e21dfda21e7..216ffd55d83c 100644 --- a/include/vcl/toolkit/treelistbox.hxx +++ b/include/vcl/toolkit/treelistbox.hxx @@ -456,6 +456,8 @@ public: /** Fills the StateSet of one entry. */ void FillAccessibleEntryStateSet( SvTreeListEntry* pEntry, ::utl::AccessibleStateSetHelper& rStateSet ) const; + virtual OUString GetEntryAccessibleDescription(SvTreeListEntry* pEntry) const; + /** Calculate and return the bounding rectangle of an entry. @param pEntry The entry. diff --git a/include/vcl/weld.hxx b/include/vcl/weld.hxx index 135378ec540f..83e68002ce6c 100644 --- a/include/vcl/weld.hxx +++ b/include/vcl/weld.hxx @@ -1348,7 +1348,10 @@ protected: void signal_selection_changed() { m_aSelectionChangeHdl.Call(*this); } bool signal_item_activated() { return m_aItemActivatedHdl.Call(*this); } - OUString signal_query_tooltip(const TreeIter& rIter) { return m_aQueryTooltipHdl.Call(rIter); } + OUString signal_query_tooltip(const TreeIter& rIter) const + { + return m_aQueryTooltipHdl.Call(rIter); + } public: virtual int get_item_width() const = 0; diff --git a/starmath/source/accessibility.cxx b/starmath/source/accessibility.cxx index 25fd9532c758..591bbeafbba5 100644 --- a/starmath/source/accessibility.cxx +++ b/starmath/source/accessibility.cxx @@ -84,8 +84,7 @@ void SmGraphicAccessible::ClearWin() if ( nClientId ) { - comphelper::AccessibleEventNotifier::revokeClientNotifyDisposing( nClientId, *this ); - nClientId = 0; + comphelper::AccessibleEventNotifier::revokeClientNotifyDisposing( std::exchange(nClientId, 0), *this ); } } @@ -391,8 +390,7 @@ void SAL_CALL SmGraphicAccessible::removeAccessibleEventListener( // -> revoke ourself. This may lead to the notifier thread dying (if we were the last client), // and at least to us not firing any events anymore, in case somebody calls // NotifyAccessibleEvent, again - comphelper::AccessibleEventNotifier::revokeClient( nClientId ); - nClientId = 0; + comphelper::AccessibleEventNotifier::revokeClient( std::exchange(nClientId, 0) ); } } diff --git a/vcl/inc/iconview.hxx b/vcl/inc/iconview.hxx index 971a638cc6ef..c5ece6d4aeb1 100644 --- a/vcl/inc/iconview.hxx +++ b/vcl/inc/iconview.hxx @@ -36,11 +36,22 @@ public: void PaintEntry(SvTreeListEntry&, tools::Long nX, tools::Long nY, vcl::RenderContext& rRenderContext); + virtual css::uno::Reference CreateAccessible() override; + + virtual OUString GetEntryAccessibleDescription(SvTreeListEntry* pEntry) const override; + void SetEntryAccessibleDescriptionHdl(const Link& rLink) + { + maEntryAccessibleDescriptionHdl = rLink; + } + virtual FactoryFunction GetUITestFactory() const override; virtual void DumpAsPropertyTree(tools::JsonWriter& rJsonWriter) override; protected: virtual void CalcEntryHeight(SvTreeListEntry const* pEntry) override; + +private: + Link maEntryAccessibleDescriptionHdl; }; #endif diff --git a/vcl/inc/salvtables.hxx b/vcl/inc/salvtables.hxx index 81e1d1f00d4f..4fab7dfe2bb9 100644 --- a/vcl/inc/salvtables.hxx +++ b/vcl/inc/salvtables.hxx @@ -1759,6 +1759,7 @@ private: DECL_LINK(DoubleClickHdl, SvTreeListBox*, bool); DECL_LINK(CommandHdl, const CommandEvent&, bool); DECL_LINK(TooltipHdl, const HelpEvent&, bool); + DECL_LINK(EntryAccessibleDescriptionHdl, SvTreeListEntry*, OUString); public: SalInstanceIconView(::IconView* pIconView, SalInstanceBuilder* pBuilder, bool bTakeOwnership); diff --git a/vcl/source/app/salvtables.cxx b/vcl/source/app/salvtables.cxx index 0a26b3ae49a4..f548fe152b4f 100644 --- a/vcl/source/app/salvtables.cxx +++ b/vcl/source/app/salvtables.cxx @@ -5317,6 +5317,10 @@ SalInstanceIconView::SalInstanceIconView(::IconView* pIconView, SalInstanceBuild m_xIconView->SetDeselectHdl(LINK(this, SalInstanceIconView, DeSelectHdl)); m_xIconView->SetDoubleClickHdl(LINK(this, SalInstanceIconView, DoubleClickHdl)); m_xIconView->SetPopupMenuHdl(LINK(this, SalInstanceIconView, CommandHdl)); + + m_xIconView->SetEntryAccessibleDescriptionHdl( + LINK(this, SalInstanceIconView, EntryAccessibleDescriptionHdl)); + m_xIconView->SetAccessible(m_xIconView->CreateAccessible()); } int SalInstanceIconView::get_item_width() const { return m_xIconView->GetEntryWidth(); } @@ -5457,6 +5461,14 @@ IMPL_LINK(SalInstanceIconView, TooltipHdl, const HelpEvent&, rHEvt, bool) return true; } +IMPL_LINK(SalInstanceIconView, EntryAccessibleDescriptionHdl, SvTreeListEntry*, pEntry, OUString) +{ + OUString s = SvTreeListBox::SearchEntryTextWithHeadTitle(pEntry); + if (s.isEmpty()) + s = signal_query_tooltip(SalInstanceTreeIter(pEntry)); + return s; +} + void SalInstanceIconView::connect_query_tooltip(const Link& rLink) { weld::IconView::connect_query_tooltip(rLink); diff --git a/vcl/source/helper/svtaccessiblefactory.cxx b/vcl/source/helper/svtaccessiblefactory.cxx index 82845ec041d9..f6728732a2e7 100644 --- a/vcl/source/helper/svtaccessiblefactory.cxx +++ b/vcl/source/helper/svtaccessiblefactory.cxx @@ -82,6 +82,15 @@ namespace vcl return nullptr; } + virtual css::uno::Reference< css::accessibility::XAccessible > + createAccessibleIconView( + SvTreeListBox& /*_rListBox*/, + const css::uno::Reference< css::accessibility::XAccessible >& /*_xParent*/ + ) const override + { + return nullptr; + } + virtual vcl::IAccessibleBrowseBox* createAccessibleBrowseBox( const css::uno::Reference< css::accessibility::XAccessible >& /*_rxParent*/, diff --git a/vcl/source/treelist/iconview.cxx b/vcl/source/treelist/iconview.cxx index 6b8a193fde11..7814810cb7dd 100644 --- a/vcl/source/treelist/iconview.cxx +++ b/vcl/source/treelist/iconview.cxx @@ -21,6 +21,7 @@ #include #include #include "iconviewimpl.hxx" +#include #include #include #include @@ -231,6 +232,30 @@ void IconView::PaintEntry(SvTreeListEntry& rEntry, tools::Long nX, tools::Long n } } +css::uno::Reference IconView::CreateAccessible() +{ + if (vcl::Window* pParent = GetAccessibleParentWindow()) + { + if (auto xAccParent = pParent->GetAccessible()) + { + // need to be done here to get the vclxwindow later on in the accessible + css::uno::Reference xHoldAlive(GetComponentInterface()); + return pImpl->m_aFactoryAccess.getFactory().createAccessibleIconView(*this, xAccParent); + } + } + return {}; +} + +OUString IconView::GetEntryAccessibleDescription(SvTreeListEntry* pEntry) const +{ + assert(pEntry); + + if (maEntryAccessibleDescriptionHdl.IsSet()) + return maEntryAccessibleDescriptionHdl.Call(pEntry); + + return SvTreeListBox::GetEntryAccessibleDescription(pEntry); +} + FactoryFunction IconView::GetUITestFactory() const { return IconViewUIObject::create; } static OUString extractPngString(const SvLBoxContextBmp* pBmpItem) diff --git a/vcl/source/treelist/treelistbox.cxx b/vcl/source/treelist/treelistbox.cxx index 962dd60cf53b..925900dc0e2d 100644 --- a/vcl/source/treelist/treelistbox.cxx +++ b/vcl/source/treelist/treelistbox.cxx @@ -3513,6 +3513,33 @@ void SvTreeListBox::FillAccessibleEntryStateSet( SvTreeListEntry* pEntry, ::utl: } } +OUString SvTreeListBox::GetEntryAccessibleDescription(SvTreeListEntry* pEntry) const +{ + assert(pEntry); + + //want to count the real column number in the list box. + sal_uInt16 iRealItemCount = 0; + for (size_t i = 0; i < pEntry->ItemCount(); ++i) + { + const SvLBoxItem& rItem = pEntry->GetItem(i); + if (rItem.GetType() == SvLBoxItemType::String && + !static_cast(rItem).GetText().isEmpty()) + { + iRealItemCount++; + } + } + // No idea why <= 1; that was in AccessibleListBoxEntry::getAccessibleDescription + // since the "Integrate branch of IAccessible2" commit + if (iRealItemCount <= 1) + { + return {}; + } + else + { + return SearchEntryTextWithHeadTitle(pEntry); + } +} + tools::Rectangle SvTreeListBox::GetBoundingRect(const SvTreeListEntry* pEntry) { Point aPos = GetEntryPosition( pEntry );