include/svtools/editbrowsebox.hxx | 2 include/svtools/strings.hrc | 3 include/vcl/accessibility/accessibleeditbrowseboxcell.hxx | 127 ------- solenv/clang-format/excludelist | 4 svtools/Library_svt.mk | 1 svtools/source/brwbox/accessibleeditbrowseboxcell.cxx | 63 +++ svtools/source/brwbox/accessibleeditbrowseboxcell.hxx | 46 ++ svtools/source/brwbox/ebbcontrols.cxx | 7 svtools/source/brwbox/editbrowsebox2.cxx | 34 -- svtools/source/brwbox/editbrowseboximpl.hxx | 5 vcl/Library_vcl.mk | 1 vcl/inc/strings.hrc | 2 vcl/source/accessibility/accessibleeditbrowseboxcell.cxx | 237 -------------- 13 files changed, 141 insertions(+), 391 deletions(-)
New commits: commit 8a919d023c1cb1397228a185ff3a6216448b5f90 Author: Michael Weghorn <m.wegh...@posteo.de> AuthorDate: Fri Feb 7 17:09:22 2025 +0100 Commit: Michael Weghorn <m.wegh...@posteo.de> CommitDate: Fri Feb 7 21:00:11 2025 +0100 browsebox a11y: Completely rework EditBrowseBoxTableCell So far the logic to implement accessibility for the currently active control to edit a cell in a BrowseBox (an EditBrowseBox) was as follows: There were two classes: EditBrowseBoxTableCellAccess implemented the XAccessible interface and created an EditBrowseBoxTableCell object in its XAccessible::getAccessibleContext implementation. EditBrowseBoxTableCell was the XAccessibleContext implementation that derived from AccessibleBrowseBoxCell and wrapped the accessible of the control window (svt::ControlBase) using comphelper::OAccessibleContextWrapperHelper (that it also subclassed). Change that as follows: 1) Let EditBrowseBoxTableCell implement both, the XAccessible and the XAccessibleContext interfaces at the same time. 2) No longer derive from AccessibleBrowseBoxCell as almost none of the the base class logic from that subclass was used (mostly storing and retrieving the current row + column index to generate an accessible name based on that), but was instead using comphelper::OAccessibleContextWrapperHelper functionality to use the logic of the wrapped accessible instead. 3) No longer use comphelper::OAccessibleContextWrapperHelper to wrap the accessible object of the svt::ControlBase, but let EditBrowseBoxTableCell be the svt::ControlBase's accessible itself (created in ControlBase::CreateAccessible). 4) Derive from VCLXAccessibleComponent, which is the default implementation for vcl::Window's XAccessible and is what was used for the svt::ControlBase before. The base class already does most of the things as needed. Only override what needs to be adjusted. 5) Move existing logic to generate an accessible name based on the cell's address from EditBrowseBoxTableCell::getAccessibleName to EditBrowseBox::implCreateActiveAccessible and set it via vcl::Window::SetAccessibleName. This also takes care of sending the necessary events about name changes if the accessible name of the existing accessible is changed. (Since the ControlBase's accessible is used now, the lifetime of the accessible is tied to the lifetime of the ControlBase/vcl::Window, too, and apparently that control gets reused e.g. for comboboxes in multiple rows, but this way, the name gets updated as needed on the a11y layer.) 6) No longer let EditBrowseBox dispose the accessible object. As described in 5), it is no longer the owner, but the ControlBase is (so the "normal" vcl::Window logic applies regarding lifecycle of the accessible and the vcl::Window disposes the accessible). 7) Implement EditBrowseBoxTableCell::getAccessibleParent to override the default VCLXAccessibleComponent implementation and return the BrowseBox's accessible as the a11y parent. In the vcl::Window hierarchy, there is a BrowserDataWin in between, but as the BrowseBox's accessible implementation, AccessibleBrowseBox, reports the EditBrowseBoxTableCell as a direct child, also report the parent accordingly the other way around. (This was previously handled by OAccessibleContextWrapperHelper.) To test: 1) Start Base, create a new database 2) With the "Tables" section enabled, click on "Create Table in Design View..." 3) In the window that opens, edit cells ("Field Name", "Field Type", "Description") in multiple rows. 4) Inspect a11y tree using Accerciser. 5) Use a screen reader while doing the previous steps and observe what gets announced. Besides simplifying code, this commit also improves/fixes the following aspects seen during testing: 1) With the qt6 VCL plugin, hen clicking on the accessible object implemented by EditBrowseBoxTableCell in Accerciser's treeview of the a11y hierarchy (shown e.g. with an accessible name of "Column 2, Row 2" as a child of the "BrowseBox" object), the correct area is highlighted on screen now, while it was slightly off before. 2) The object now reports the correct child index (index in parent) which matches the position in the parent as shown in Accerciser (index 3, after the "ColumnHeaderBar", "RowHeaderBar", "Table"). Before: In [3]: acc.get_index_in_parent() Out[3]: -1 Now: In [2]: acc.get_index_in_parent() Out[2]: 3 (This is now handled correctly by OCommonAccessibleComponent::getAccessibleIndexInParent via the new VCLXAccessibleComponent base class hierarchy.) 3) When testing with the NVDA screen reader running on Windows, this works OK now when testing for a while, while LibreOffice would previously freeze/deadlock quite quickly (somehow related to the comphelper::OAccessibleContextWrapperHelper base class hierarchy). Sample backtrace: 1 NtWaitForAlertByThreadId ntdll 0x7ffb0c5b0f24 2 RtlWaitOnAddress ntdll 0x7ffb0c574d6d 3 RtlWaitOnAddress ntdll 0x7ffb0c574c22 4 RtlWaitOnAddress ntdll 0x7ffb0c574a3d 5 RtlEnterCriticalSection ntdll 0x7ffb0c53fcb4 6 RtlEnterCriticalSection ntdll 0x7ffb0c53fae2 7 osl_acquireMutex mutex.cxx 65 0x7ffaf6aa7328 8 osl::Mutex::acquire mutex.hxx 63 0x7ffaf8814620 9 osl::Guard<osl::Mutex>::Guard<osl::Mutex> mutex.hxx 144 0x7ffaf88122a1 10 `anonymous namespace'::AffineBridge::v_callOut_v AffineBridge.cxx 272 0x7ffaf88163fd 11 Enterable_call_callOut_v Enterable.hxx 75 0x7ffaf8816890 12 cppu::Enterable::callOut_v Enterable.hxx 58 0x7ffaf4993ebd 13 `anonymous namespace'::Base::v_callOut_v helper_purpenv_Environment.cxx 505 0x7ffaf49955e6 14 Enterable_call_callOut_v Enterable.hxx 75 0x7ffaf49957b0 15 cppu::Enterable::callOut_v Enterable.hxx 58 0x7ffaf3e6fa9d 16 s_callOut_v EnvStack.cxx 251 0x7ffaf3e70385 17 s_callOut EnvStack.cxx 263 0x7ffaf3e7032f 18 s_environment_invoke_v EnvStack.cxx 286 0x7ffaf3e7044f 19 uno_Environment_invoke_v EnvStack.cxx 310 0x7ffaf3e710c8 20 uno_Environment_invoke EnvStack.cxx 319 0x7ffaf3e7107f 21 computeObjectIdentifier component.cxx 112 0x7ffaf63db115 22 defenv_getObjectIdentifier lbenv.cxx 446 0x7ffaf3e82535 23 `anonymous namespace'::ProxyRoot::queryAggregation proxyfac.cxx 298 0x7ffaf9336b13 24 comphelper::OProxyAggregation::queryAggregation proxyaggregation.cxx 70 0x7ffae10a99a7 25 comphelper::OComponentProxyAggregationHelper::queryInterface proxyaggregation.cxx 129 0x7ffae10a9c11 26 comphelper::OAccessibleContextWrapperHelper::queryInterface accessiblewrapper.cxx 381 0x7ffae100dd4b 27 comphelper::OAccessibleContextWrapper::queryInterface accessiblewrapper.cxx 475 0x7ffae100dc81 28 com::sun::star::uno::BaseReference::iquery Reference.hxx 59 0x7ffadedf85f2 29 com::sun::star::uno::Reference<com::sun::star::accessibility::XAccessibleHypertext>::iquery Reference.hxx 75 0x7ffadee02596 30 com::sun::star::uno::Reference<com::sun::star::accessibility::XAccessibleHypertext>::Reference<com::sun::star::accessibility::XAccessibleHypertext> Reference.hxx 179 0x7ffadee010fe 31 CMAccessible::get_accState MAccessible.cxx 568 0x7ffadee24a88 32 DllGetClassObject OLEACC 0x7ffaee454bd2 33 UiaReturnRawElementProvider uiautomationcore 0x7ffaf46c3abd 34 UiaReturnRawElementProvider uiautomationcore 0x7ffaf46c2cb1 35 UiaReturnRawElementProvider uiautomationcore 0x7ffaf46c4d5e 36 UiaReturnRawElementProvider uiautomationcore 0x7ffaf46d68d5 37 UiaReturnRawElementProvider uiautomationcore 0x7ffaf46d63fc 38 DllCanUnloadNow uiautomationcore 0x7ffaf46a55de 39 UiaClientsAreListening uiautomationcore 0x7ffaf46ed629 40 UiaRaiseAutomationEvent uiautomationcore 0x7ffaf46e7ca8 41 uiautomationcore 0x7ffaf4693abb 42 uiautomationcore 0x7ffaf4697300 43 uiautomationcore 0x7ffaf4693c9c 44 DllCanUnloadNow uiautomationcore 0x7ffaf46a55de 45 DllCanUnloadNow uiautomationcore 0x7ffaf46abe77 46 DllCanUnloadNow uiautomationcore 0x7ffaf46ab5c9 47 uiautomationcore 0x7ffaf469acf7 48 UiaReturnRawElementProvider uiautomationcore 0x7ffaf46ccfe5 49 UiaReturnRawElementProvider uiautomationcore 0x7ffaf46ccca7 50 Ordinal2712 USER32 0x7ffb0c21e442 51 SendMessageTimeoutW USER32 0x7ffb0c2210c3 52 KiUserCallbackDispatcher ntdll 0x7ffb0c5b1374 53 NtUserPeekMessage win32u 0x7ffb09bb1064 54 PeekMessageW USER32 0x7ffb0c20a333 55 PeekMessageW USER32 0x7ffb0c20a293 56 Ordinal87 combase 0x7ffb0b3f9403 57 Ordinal87 combase 0x7ffb0b3f936d 58 Ordinal88 combase 0x7ffb0b3f9c3e 59 Ordinal88 combase 0x7ffb0b3f969b 60 Ordinal87 combase 0x7ffb0b3f7d8a 61 CoWaitForMultipleObjects combase 0x7ffb0b3f4aa5 62 CoWaitForMultipleHandles combase 0x7ffb0b3f1736 63 sal::systools::WaitForMultipleObjects_COMDispatch wait_for_multiple_objects.hxx 26 0x7ffaf6a91a1e 64 osl_waitCondition conditn.cxx 79 0x7ffaf6a91d1a 65 osl::Condition::wait conditn.hxx 124 0x7ffaf88167aa 66 `anonymous namespace'::AffineBridge::outerDispatch AffineBridge.cxx 183 0x7ffaf8815167 67 `anonymous namespace'::AffineBridge::v_callInto_v AffineBridge.cxx 262 0x7ffaf8816353 68 Enterable_call_callInto_v Enterable.hxx 73 0x7ffaf8816840 69 cppu::Enterable::callInto_v Enterable.hxx 57 0x7ffaf4993e6d 70 `anonymous namespace'::Base::v_callInto_v helper_purpenv_Environment.cxx 500 0x7ffaf4995596 71 Enterable_call_callInto_v Enterable.hxx 73 0x7ffaf4995760 72 cppu::Enterable::callInto_v Enterable.hxx 57 0x7ffaf3e6fa4d 73 cppu::Enterable::callInto Enterable.hxx 95 0x7ffaf3e6f9ff 74 s_callInto_v EnvStack.cxx 232 0x7ffaf3e702cc 75 s_callInto EnvStack.cxx 244 0x7ffaf3e7026f 76 s_environment_invoke_v EnvStack.cxx 300 0x7ffaf3e704d8 77 uno_Environment_invoke_v EnvStack.cxx 310 0x7ffaf3e710c8 78 uno_Environment_invoke EnvStack.cxx 319 0x7ffaf3e7107f 79 Proxy::dispatch helper_purpenv_Proxy.cxx 432 0x7ffaf49992b5 80 s_Proxy_dispatch helper_purpenv_Proxy.cxx 151 0x7ffaf4999efd 81 cpp2uno_call cpp2uno.cxx 149 0x7ffaf63e52ef 82 cpp_mediate cpp2uno.cxx 336 0x7ffaf63e6c88 83 cpp_vtable_call cpp2uno.cxx 52 0x7ffaf63d2506 84 privateSnippetExecutor mscx_uno 0x7ffaf63ecdee 85 dbaui::OFieldDescControl::ActivateAggregate FieldDescControl.cxx 419 0x7ffac81839ee 86 dbaui::OTableFieldControl::ActivateAggregate TableFieldControl.cxx 90 0x7ffac839ba3e 87 dbaui::OFieldDescControl::DisplayData FieldDescControl.cxx 892 0x7ffac81889b4 88 dbaui::OTableFieldDescWin::DisplayData TableFieldDescWin.cxx 67 0x7ffac839cc4c 89 dbaui::OTableEditorCtrl::SwitchType TEditControl.cxx 1654 0x7ffac83ad160 90 dbaui::OTableEditorCtrl::resetType TEditControl.cxx 693 0x7ffac83ae1aa 91 dbaui::OTableEditorCtrl::CellModified TEditControl.cxx 676 0x7ffac83a4a92 92 dbaui::OTableEditorCtrl::CellModified TEditControl.cxx 700 0x7ffac83a4205 93 svt::EditBrowseBox::CellModifiedHdl editbrowsebox.cxx 1074 0x7ffadd8dc04a 94 svt::EditBrowseBox::LinkStubCellModifiedHdl editbrowsebox.cxx 1071 0x7ffadd8de116 95 Link<void *,void>::Call link.hxx 105 0x7ffacc1dfd43 96 ImplHandleUserEvent winproc.cxx 2285 0x7ffacc1e8ec7 97 ImplWindowFrameProc winproc.cxx 2849 0x7ffacc1ea6a4 98 SalFrame::CallCallback salframe.hxx 311 0x7ffacbfc8036 99 ImplHandleUserEvent salframe.cxx 4539 0x7ffac9a58f8b 100 SalFrameWndProc salframe.cxx 6123 0x7ffac9a5e5ed 101 SalFrameWndProcW salframe.cxx 6229 0x7ffac9a5ebf0 102 CallWindowProcW USER32 0x7ffb0c20ef5c 103 DispatchMessageW USER32 0x7ffb0c20e684 104 ImplSalDispatchMessage salinst.cxx 443 0x7ffac99bc4f8 105 ImplSalYield salinst.cxx 474 0x7ffac99bc5fb 106 WinSalInstance::DoYield salinst.cxx 549 0x7ffac99bc1c1 107 ImplYield svapp.cxx 385 0x7ffacc7eb309 108 Application::Yield svapp.cxx 488 0x7ffacc7ef0a9 109 Application::Execute svapp.cxx 361 0x7ffacc7e89ec 110 desktop::Desktop::Main app.cxx 1679 0x7ffaf31d8d4d 111 ImplSVMain svmain.cxx 230 0x7ffacc800245 112 SVMain svmain.cxx 249 0x7ffacc800a42 113 soffice_main sofficemain.cxx 122 0x7ffaf32291da 114 sal_main main.c 51 0x7ff702321013 115 main main.c 49 0x7ff70232105a 116 __scrt_common_main_seh exe_common.inl 288 0x7ff702321344 117 BaseThreadInitThunk KERNEL32 0x7ffb0b9c7374 118 RtlUserThreadStart ntdll 0x7ffb0c55cc91 Change-Id: I5dfd2554d919babb3400967f8ffc0df5df3af53a Reviewed-on: https://gerrit.libreoffice.org/c/core/+/181268 Reviewed-by: Michael Weghorn <m.wegh...@posteo.de> Tested-by: Jenkins diff --git a/include/svtools/editbrowsebox.hxx b/include/svtools/editbrowsebox.hxx index 67e101fcf409..c82b39dd852c 100644 --- a/include/svtools/editbrowsebox.hxx +++ b/include/svtools/editbrowsebox.hxx @@ -210,6 +210,8 @@ namespace svt m_aKeyReleaseHdl = rHdl; } + css::uno::Reference<css::accessibility::XAccessible> CreateAccessible() override; + protected: DECL_DLLPRIVATE_LINK(KeyInputHdl, const KeyEvent&, bool); DECL_DLLPRIVATE_LINK(KeyReleaseHdl, const KeyEvent&, bool); diff --git a/svtools/source/brwbox/accessibleeditbrowseboxcell.cxx b/svtools/source/brwbox/accessibleeditbrowseboxcell.cxx index b3a185481956..3fa822edc834 100644 --- a/svtools/source/brwbox/accessibleeditbrowseboxcell.cxx +++ b/svtools/source/brwbox/accessibleeditbrowseboxcell.cxx @@ -19,38 +19,24 @@ #include "accessibleeditbrowseboxcell.hxx" -#include <comphelper/processfactory.hxx> -#include <comphelper/diagnose_ex.hxx> -#include <svtools/strings.hrc> -#include <svtools/svtresid.hxx> +#include <comphelper/accessiblecontexthelper.hxx> using namespace com::sun::star::accessibility; using namespace ::com::sun::star::uno; -using namespace ::com::sun::star::lang; using namespace ::com::sun::star::awt; using namespace ::comphelper; -EditBrowseBoxTableCell::EditBrowseBoxTableCell( - const css::uno::Reference< css::accessibility::XAccessible >& _rxParent, - const css::uno::Reference< css::accessibility::XAccessible >& _rxOwningAccessible, - const css::uno::Reference< css::accessibility::XAccessibleContext >& _xControlChild, - ::vcl::IAccessibleTableProvider& _rBrowseBox, - const css::uno::Reference< css::awt::XWindow >& _xFocusWindow, - sal_Int32 _nRowPos, - sal_uInt16 _nColPos) - :AccessibleBrowseBoxCell( _rxParent, _rBrowseBox, _xFocusWindow, _nRowPos, _nColPos ) - ,OAccessibleContextWrapperHelper( ::comphelper::getProcessComponentContext(), rBHelper, _xControlChild, _rxOwningAccessible, _rxParent ) +EditBrowseBoxTableCell::EditBrowseBoxTableCell(svt::ControlBase* pControl) + : ImplInheritanceHelper(pControl) { - aggregateProxy( m_refCount, *this ); } -EditBrowseBoxTableCell::~EditBrowseBoxTableCell() +Reference<css::accessibility::XAccessibleContext> + SAL_CALL EditBrowseBoxTableCell::getAccessibleContext() { - if ( !rBHelper.bDisposed ) - { - acquire(); // to prevent duplicate dtor calls - dispose(); - } + OExternalLockGuard aGuard(this); + ensureAlive(); + return this; } OUString SAL_CALL EditBrowseBoxTableCell::getImplementationName() @@ -58,179 +44,20 @@ OUString SAL_CALL EditBrowseBoxTableCell::getImplementationName() return u"com.sun.star.comp.svtools.TableCellProxy"_ustr; } -IMPLEMENT_FORWARD_XINTERFACE2( EditBrowseBoxTableCell, AccessibleBrowseBoxCell, OAccessibleContextWrapperHelper ) - -IMPLEMENT_FORWARD_XTYPEPROVIDER2( EditBrowseBoxTableCell, AccessibleBrowseBoxCell, OAccessibleContextWrapperHelper ) - -void EditBrowseBoxTableCell::notifyTranslatedEvent( const AccessibleEventObject& _rEvent ) -{ - commitEvent( _rEvent.EventId, _rEvent.NewValue, _rEvent.OldValue ); -} - -// css::accessibility::XAccessibleComponent -sal_Int32 SAL_CALL EditBrowseBoxTableCell::getForeground( ) -{ - SolarMethodGuard aGuard(getMutex()); - ensureIsAlive(); - - css::uno::Reference< css::accessibility::XAccessibleComponent > xAccComp( m_xInnerContext, UNO_QUERY ); - if ( xAccComp.is() ) - return xAccComp->getForeground(); - return 0; -} - -sal_Int32 SAL_CALL EditBrowseBoxTableCell::getBackground( ) -{ - SolarMethodGuard aGuard(getMutex()); - ensureIsAlive(); - - css::uno::Reference< css::accessibility::XAccessibleComponent > xAccComp( m_xInnerContext, UNO_QUERY ); - if ( xAccComp.is() ) - return xAccComp->getBackground(); - return 0; -} - -css::uno::Reference< css::accessibility::XAccessible > SAL_CALL EditBrowseBoxTableCell::getAccessibleParent( ) -{ - return m_xParentAccessible; -} - -OUString SAL_CALL EditBrowseBoxTableCell::getAccessibleDescription() -{ - SolarMethodGuard aGuard(getMutex()); - ensureIsAlive(); - - return m_xInnerContext->getAccessibleDescription(); -} - -OUString SAL_CALL EditBrowseBoxTableCell::getAccessibleName() -{ - SolarMethodGuard aGuard(getMutex()); - ensureIsAlive(); - - return SvtResId(STR_ACC_COLUMN_NUM).replaceAll("%COLUMNNUMBER", OUString::number(getColumnPos()-1)) + ", " - + SvtResId(STR_ACC_ROW_NUM).replaceAll("%ROWNUMBER", OUString::number(getRowPos())); -} - -css::uno::Reference< css::accessibility::XAccessibleRelationSet > SAL_CALL EditBrowseBoxTableCell::getAccessibleRelationSet() -{ - SolarMethodGuard aGuard(getMutex()); - ensureIsAlive(); - - return baseGetAccessibleRelationSet( ); -} - -sal_Int64 SAL_CALL EditBrowseBoxTableCell::getAccessibleStateSet() -{ - SolarMethodGuard aGuard(getMutex()); - ensureIsAlive(); - - return m_xInnerContext->getAccessibleStateSet(); - // TODO: shouldn't we add an ACTIVE here? Isn't the EditBrowseBoxTableCell always ACTIVE? -} - -sal_Int64 SAL_CALL EditBrowseBoxTableCell::getAccessibleChildCount( ) +css::uno::Reference<css::accessibility::XAccessible> + SAL_CALL EditBrowseBoxTableCell::getAccessibleParent() { - SolarMethodGuard aGuard(getMutex()); - ensureIsAlive(); + OExternalLockGuard aGuard(this); - return baseGetAccessibleChildCount(); -} - -css::uno::Reference< css::accessibility::XAccessible > SAL_CALL EditBrowseBoxTableCell::getAccessibleChild( sal_Int64 i ) -{ - SolarMethodGuard aGuard(getMutex()); - ensureIsAlive(); - - return baseGetAccessibleChild( i ); -} - -sal_Int16 SAL_CALL EditBrowseBoxTableCell::getAccessibleRole() -{ - SolarMethodGuard aGuard(getMutex()); - ensureIsAlive(); - - return m_xInnerContext->getAccessibleRole( ); -} - -void SAL_CALL EditBrowseBoxTableCell::dispose() -{ - // simply disambiguate. Note that the OComponentHelper base in AccessibleBrowseBoxCell - // will call our "disposing()", which will call "dispose()" on the OAccessibleContextWrapperHelper - // so there is no need to do this here. - AccessibleBrowseBoxCell::dispose(); -} - -void SAL_CALL EditBrowseBoxTableCell::disposing( const css::lang::EventObject& _rSource ) -{ - AccessibleBrowseBoxCell::disposing( _rSource ); - OAccessibleContextWrapperHelper::disposing( _rSource ); -} - -void SAL_CALL EditBrowseBoxTableCell::disposing() -{ - SolarMethodGuard aGuard(getMutex()); - - OAccessibleContextWrapperHelper::dispose(); - // TODO: do we need to dispose our inner object? The base class does this, but is it a good idea? - AccessibleBrowseBoxCell::disposing(); -} - -// EditBrowseBoxTableCell -EditBrowseBoxTableCellAccess::EditBrowseBoxTableCellAccess( - css::uno::Reference< css::accessibility::XAccessible > _xParent, css::uno::Reference< css::accessibility::XAccessible > _xControlAccessible, - css::uno::Reference< css::awt::XWindow > _xFocusWindow, - ::vcl::IAccessibleTableProvider& _rBrowseBox, sal_Int32 _nRowPos, sal_uInt16 _nColPos ) - :m_xParent(std::move( _xParent )) - ,m_xControlAccessible(std::move( _xControlAccessible )) - ,m_xFocusWindow(std::move( _xFocusWindow )) - ,m_pBrowseBox( &_rBrowseBox ) - ,m_nRowPos( _nRowPos ) - ,m_nColPos( _nColPos ) -{ -} - -EditBrowseBoxTableCellAccess::~EditBrowseBoxTableCellAccess( ) -{ -} - -css::uno::Reference< css::accessibility::XAccessibleContext > SAL_CALL EditBrowseBoxTableCellAccess::getAccessibleContext( ) -{ - if ( !m_pBrowseBox || !m_xControlAccessible.is() ) - throw DisposedException(); - css::uno::Reference< css::accessibility::XAccessibleContext > xMyContext( m_aContext ); - if ( !xMyContext.is() ) - { - css::uno::Reference< css::accessibility::XAccessibleContext > xInnerContext = m_xControlAccessible->getAccessibleContext(); - css::uno::Reference< css::accessibility::XAccessible > xMe( this ); - - xMyContext = new EditBrowseBoxTableCell(m_xParent, xMe, xInnerContext, *m_pBrowseBox, m_xFocusWindow, m_nRowPos, m_nColPos); - m_aContext = xMyContext; - } - return xMyContext; -} - -void EditBrowseBoxTableCellAccess::disposing(std::unique_lock<std::mutex>&) -{ - // dispose our context, if it still alive - css::uno::Reference< XComponent > xMyContext( m_aContext.get(), UNO_QUERY ); - if ( xMyContext.is() ) - { - try - { - xMyContext->dispose(); - } - catch( const Exception& ) - { - TOOLS_WARN_EXCEPTION( "accessibility", "EditBrowseBoxTableCellAccess::disposing: caught an exception while disposing the context!" ); - } - } + // AccessibleBrowseBox reports this as direct child (s. AccessibleBrowseBox::getAccessibleChild), + // so report BrowseBox's accessible object as parent as well - m_pBrowseBox = nullptr; - m_xControlAccessible.clear(); - m_aContext.clear(); - // NO dispose of the inner object there: it is the css::accessibility::XAccessible of a window, and disposing - // it would delete the respective VCL window + // The control's parent is a BrowserDataWin (see ControlBase ctor) + BrowserDataWin* pBrowserDataWin = dynamic_cast<BrowserDataWin*>(GetWindow()->GetParent()); + assert(pBrowserDataWin); + BrowseBox* pBrowseBox = pBrowserDataWin->GetParent(); + assert(pBrowseBox); + return pBrowseBox->GetAccessible(); } /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/svtools/source/brwbox/accessibleeditbrowseboxcell.hxx b/svtools/source/brwbox/accessibleeditbrowseboxcell.hxx index 5a74a3873cb1..b3efbe63f46b 100644 --- a/svtools/source/brwbox/accessibleeditbrowseboxcell.hxx +++ b/svtools/source/brwbox/accessibleeditbrowseboxcell.hxx @@ -18,110 +18,29 @@ */ #pragma once -#include <com/sun/star/accessibility/XAccessibleRelationSet.hpp> -#include <comphelper/compbase.hxx> -#include <comphelper/accessiblewrapper.hxx> -#include <vcl/accessibility/AccessibleBrowseBoxCell.hxx> +#include <cppuhelper/implbase.hxx> +#include <svtools/editbrowsebox.hxx> +#include <vcl/accessibility/vclxaccessiblecomponent.hxx> - -// = EditBrowseBoxTableCell - -class EditBrowseBoxTableCell final : public AccessibleBrowseBoxCell - ,public ::comphelper::OAccessibleContextWrapperHelper +class EditBrowseBoxTableCell final + : public cppu::ImplInheritanceHelper<VCLXAccessibleComponent, css::accessibility::XAccessible> { public: - EditBrowseBoxTableCell( - const css::uno::Reference< css::accessibility::XAccessible >& _rxParent, - const css::uno::Reference< css::accessibility::XAccessible >& _rxOwningAccessible, - const css::uno::Reference< css::accessibility::XAccessibleContext >& _xControlChild, - ::vcl::IAccessibleTableProvider& _rBrowseBox, - const css::uno::Reference< css::awt::XWindow >& _xFocusWindow, - sal_Int32 _nRowPos, - sal_uInt16 _nColPos - ); - -private: - virtual ~EditBrowseBoxTableCell() override; + EditBrowseBoxTableCell(svt::ControlBase* pControl); - // XAccessibleComponent - virtual sal_Int32 SAL_CALL getForeground( ) override ; - virtual sal_Int32 SAL_CALL getBackground( ) override ; + // XAccessible + css::uno::Reference<css::accessibility::XAccessibleContext> + SAL_CALL getAccessibleContext() override; // XServiceInfo virtual OUString SAL_CALL getImplementationName() override; - // XInterface - DECLARE_XINTERFACE( ) - // XTypeProvider - DECLARE_XTYPEPROVIDER( ) - // XAccessibleContext - virtual css::uno::Reference< css::accessibility::XAccessible > SAL_CALL getAccessibleParent( ) override; - virtual OUString SAL_CALL getAccessibleDescription( ) override; - virtual OUString SAL_CALL getAccessibleName( ) override; - virtual css::uno::Reference< css::accessibility::XAccessibleRelationSet > SAL_CALL getAccessibleRelationSet( ) override; - virtual sal_Int64 SAL_CALL getAccessibleStateSet( ) override; - - sal_Int16 SAL_CALL getAccessibleRole() override; - - virtual sal_Int64 SAL_CALL getAccessibleChildCount( ) override; - virtual css::uno::Reference< css::accessibility::XAccessible > SAL_CALL getAccessibleChild( sal_Int64 i ) override; - - virtual void SAL_CALL disposing( const css::lang::EventObject& Source ) override; - - // OComponentHelper - virtual void SAL_CALL disposing() override; - - // XComponent/OComponentProxyAggregationHelper (needs to be disambiguated) - virtual void SAL_CALL dispose() final override; - - // OAccessibleContextWrapperHelper(); - void notifyTranslatedEvent( const css::accessibility::AccessibleEventObject& _rEvent ) override; + virtual css::uno::Reference<css::accessibility::XAccessible> + SAL_CALL getAccessibleParent() override; EditBrowseBoxTableCell( const EditBrowseBoxTableCell& ) = delete; EditBrowseBoxTableCell& operator=( const EditBrowseBoxTableCell& ) = delete; }; - -// = EditBrowseBoxTableCell - -// XAccessible providing an EditBrowseBoxTableCell -class EditBrowseBoxTableCellAccess final - : public comphelper::WeakComponentImplHelper<css::accessibility::XAccessible> -{ - css::uno::WeakReference< css::accessibility::XAccessibleContext > - m_aContext; - css::uno::Reference< css::accessibility::XAccessible > - m_xParent; - css::uno::Reference< css::accessibility::XAccessible > - m_xControlAccessible; - css::uno::Reference< css::awt::XWindow > - m_xFocusWindow; - ::vcl::IAccessibleTableProvider* m_pBrowseBox; - sal_Int32 m_nRowPos; - sal_uInt16 m_nColPos; - -public: - EditBrowseBoxTableCellAccess( - css::uno::Reference< css::accessibility::XAccessible > _xParent, - css::uno::Reference< css::accessibility::XAccessible > _xControlAccessible, - css::uno::Reference< css::awt::XWindow > _xFocusWindow, - ::vcl::IAccessibleTableProvider& _rBrowseBox, - sal_Int32 _nRowPos, - sal_uInt16 _nColPos - ); - -private: - virtual ~EditBrowseBoxTableCellAccess() override; - - // XAccessible - virtual css::uno::Reference< css::accessibility::XAccessibleContext > SAL_CALL getAccessibleContext( ) override; - - // XComponent/WeakComponentImplHelper - virtual void disposing(std::unique_lock<std::mutex>&) override; - - EditBrowseBoxTableCellAccess( const EditBrowseBoxTableCellAccess& ) = delete; - EditBrowseBoxTableCellAccess& operator=( const EditBrowseBoxTableCellAccess& ) = delete; -}; - /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/svtools/source/brwbox/ebbcontrols.cxx b/svtools/source/brwbox/ebbcontrols.cxx index 71fc13dde91f..1c568dc89b42 100644 --- a/svtools/source/brwbox/ebbcontrols.cxx +++ b/svtools/source/brwbox/ebbcontrols.cxx @@ -16,6 +16,8 @@ * the License at http://www.apache.org/licenses/LICENSE-2.0 . */ +#include "accessibleeditbrowseboxcell.hxx" + #include <svtools/editbrowsebox.hxx> #include <vcl/svapp.hxx> @@ -379,6 +381,11 @@ namespace svt return static_cast<BrowserDataWin*>(GetParent())->GetParent()->ProcessKey(rKEvt); } + css::uno::Reference<css::accessibility::XAccessible> ControlBase::CreateAccessible() + { + return new EditBrowseBoxTableCell(this); + } + IMPL_LINK(ControlBase, KeyInputHdl, const KeyEvent&, rKEvt, bool) { m_aKeyInputHdl.Call(rKEvt); diff --git a/svtools/source/brwbox/editbrowsebox2.cxx b/svtools/source/brwbox/editbrowsebox2.cxx index 1d97e1283a58..064c13e78c30 100644 --- a/svtools/source/brwbox/editbrowsebox2.cxx +++ b/svtools/source/brwbox/editbrowsebox2.cxx @@ -22,6 +22,8 @@ #include <com/sun/star/accessibility/AccessibleEventId.hpp> #include "editbrowseboximpl.hxx" #include <comphelper/types.hxx> +#include <svtools/strings.hrc> +#include <svtools/svtresid.hxx> #include <toolkit/helper/vclunohelper.hxx> #include <vcl/accessibility/AccessibleBrowseBoxCheckBoxCell.hxx> #include <vcl/accessiblefactory.hxx> @@ -65,20 +67,19 @@ void EditBrowseBox::implCreateActiveAccessible( ) if ( m_aImpl->m_xActiveCell.is() || !IsEditing() ) return; - Reference< XAccessible > xCont = aController->GetWindow().GetAccessible(); - Reference< XAccessible > xMy = GetAccessible(); - if ( !(xMy.is() && xCont.is()) ) - return; + ControlBase& rControl = aController->GetWindow(); + + // set accessible name based on current cell (which is the one that is being edited) + const sal_uInt16 nCol = GetColumnPos(GetCurColumnId()); + const sal_Int32 nRow = GetCurRow(); + OUString sAccName + = SvtResId(STR_ACC_COLUMN_NUM).replaceAll("%COLUMNNUMBER", OUString::number(nCol - 1)) + + ", " + SvtResId(STR_ACC_ROW_NUM).replaceAll("%ROWNUMBER", OUString::number(nRow)); + rControl.SetAccessibleName(sAccName); - m_aImpl->m_xActiveCell = new EditBrowseBoxTableCellAccess( - xMy, // parent accessible - xCont, // control accessible - VCLUnoHelper::GetInterface(&aController->GetWindow()), // focus window (for notifications) - *this, // the browse box - GetCurRow(), GetColumnPos(GetCurColumnId())); + m_aImpl->m_xActiveCell = rControl.GetAccessible(); - css::uno::Reference<css::accessibility::XAccessible> xCell = m_aImpl->m_xActiveCell; - commitBrowseBoxEvent(CHILD, Any(xCell), Any()); + commitBrowseBoxEvent(CHILD, Any(m_aImpl->m_xActiveCell), Any()); } @@ -95,13 +96,7 @@ Reference< XAccessible > EditBrowseBox::CreateAccessibleControl( sal_Int32 _nInd return m_aImpl->m_xActiveCell; } -void EditBrowseBoxImpl::clearActiveCell() -{ - if (m_xActiveCell) - m_xActiveCell->dispose(); - - m_xActiveCell.clear(); -} +void EditBrowseBoxImpl::clearActiveCell() { m_xActiveCell.clear(); } void EditBrowseBox::GrabTableFocus() { diff --git a/svtools/source/brwbox/editbrowseboximpl.hxx b/svtools/source/brwbox/editbrowseboximpl.hxx index 50a58886f199..2add89544aa0 100644 --- a/svtools/source/brwbox/editbrowseboximpl.hxx +++ b/svtools/source/brwbox/editbrowseboximpl.hxx @@ -18,7 +18,8 @@ */ #pragma once -#include "accessibleeditbrowseboxcell.hxx" +#include <com/sun/star/accessibility/XAccessible.hpp> +#include <com/sun/star/uno/Reference.hxx> namespace svt { @@ -26,7 +27,7 @@ namespace svt class EditBrowseBoxImpl { public: - rtl::Reference<EditBrowseBoxTableCellAccess> m_xActiveCell; + css::uno::Reference<css::accessibility::XAccessible> m_xActiveCell; void clearActiveCell(); }; commit 1df8f5979a818f10c3654a2a9bcb5c1184c53278 Author: Michael Weghorn <m.wegh...@posteo.de> AuthorDate: Fri Feb 7 13:16:32 2025 +0100 Commit: Michael Weghorn <m.wegh...@posteo.de> CommitDate: Fri Feb 7 21:00:02 2025 +0100 a11y: Move EditBrowseBoxTableCell to svtools While the AccessibleBrowseBoxCell base class and other AccessibleBrowseBox* classes are used for both, SvHeaderTabListBox (in vcl) and BrowseBox (in svtools), EditBrowseBoxTableCell is only used for the latter, in order to make the currently active edit control accessible. Therefore, move the class to the svtools library, where BrowseBox is located as well. This is also in preparation of reworking how accessibility for BrowseBox's currently active control is implemented. Change-Id: Ia290df4b497baa66f98c1065c2425a0e2e079d13 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/181267 Tested-by: Jenkins Reviewed-by: Michael Weghorn <m.wegh...@posteo.de> diff --git a/include/svtools/strings.hrc b/include/svtools/strings.hrc index faa3e7cd4b2a..a4f5873ed0af 100644 --- a/include/svtools/strings.hrc +++ b/include/svtools/strings.hrc @@ -278,6 +278,9 @@ #define STR_WARNING_INVALIDJAVASETTINGS_TITLE NC_("STR_WARNING_INVALIDJAVASETTINGS_TITLE", "Select JRE") #define STR_ERROR_JVMCREATIONFAILED_TITLE NC_("STR_ERROR_JVMCREATIONFAILED_TITLE", "JRE is Defective") +#define STR_ACC_COLUMN_NUM NC_("STR_ACC_COLUMN_NUM", "Column %COLUMNNUMBER") +#define STR_ACC_ROW_NUM NC_("STR_ACC_ROW_NUM", "Row %ROWNUMBER") + // accessibility descriptions that use %PRODUCTNAME, we set these explicitly because querying a11y descs // in order to change %PRODUCTNAME at runtime is expensive, so limit doing that as much as possible. #define STR_A11Y_DESC_OPTIONS NC_("printersetupdialog|extended_tip|options", "Opens the Printer Options dialog where you can override the global printer options set on the Tools - Options - %PRODUCTNAME Writer/Web - Print panel for the current document.") diff --git a/solenv/clang-format/excludelist b/solenv/clang-format/excludelist index 72ee3d33a11d..3b7235aecfee 100644 --- a/solenv/clang-format/excludelist +++ b/solenv/clang-format/excludelist @@ -6118,7 +6118,6 @@ include/vcl/accessibility/AccessibleBrowseBoxObjType.hxx include/vcl/accessibility/AccessibleBrowseBoxTable.hxx include/vcl/accessibility/AccessibleBrowseBoxTableBase.hxx include/vcl/accessibility/AccessibleBrowseBoxTableCell.hxx -include/vcl/accessibility/accessibleeditbrowseboxcell.hxx include/vcl/BitmapBuffer.hxx include/vcl/BitmapColor.hxx include/vcl/BitmapPalette.hxx @@ -10932,6 +10931,8 @@ svl/unx/source/svdde/ddedummy.cxx svtools/inc/strings.hxx svtools/inc/framestatuslistener.hxx svtools/langsupport/langsupport.cxx +svtools/source/brwbox/accessibleeditbrowseboxcell.cxx +svtools/source/brwbox/accessibleeditbrowseboxcell.hxx svtools/source/brwbox/brwbox1.cxx svtools/source/brwbox/brwbox2.cxx svtools/source/brwbox/brwbox3.cxx @@ -14125,7 +14126,6 @@ vcl/source/accessibility/AccessibleBrowseBoxTableBase.cxx vcl/source/accessibility/AccessibleBrowseBoxTableCell.cxx vcl/source/accessibility/acc_factory.cxx vcl/source/accessibility/accessiblebrowseboxcell.cxx -vcl/source/accessibility/accessibleeditbrowseboxcell.cxx vcl/source/accessibility/accessibleiconchoicectrl.cxx vcl/source/accessibility/accessibleiconchoicectrlentry.cxx vcl/source/accessibility/accessiblelistbox.cxx diff --git a/svtools/Library_svt.mk b/svtools/Library_svt.mk index 5782d70261ac..3fbae7468957 100644 --- a/svtools/Library_svt.mk +++ b/svtools/Library_svt.mk @@ -68,6 +68,7 @@ $(eval $(call gb_Library_use_externals,svt,\ )) $(eval $(call gb_Library_add_exception_objects,svt,\ + svtools/source/brwbox/accessibleeditbrowseboxcell \ svtools/source/brwbox/brwbox1 \ svtools/source/brwbox/brwbox2 \ svtools/source/brwbox/brwbox3 \ diff --git a/vcl/source/accessibility/accessibleeditbrowseboxcell.cxx b/svtools/source/brwbox/accessibleeditbrowseboxcell.cxx similarity index 95% rename from vcl/source/accessibility/accessibleeditbrowseboxcell.cxx rename to svtools/source/brwbox/accessibleeditbrowseboxcell.cxx index 6d6a99e12ed0..b3a185481956 100644 --- a/vcl/source/accessibility/accessibleeditbrowseboxcell.cxx +++ b/svtools/source/brwbox/accessibleeditbrowseboxcell.cxx @@ -17,13 +17,12 @@ * the License at http://www.apache.org/licenses/LICENSE-2.0 . */ -#include <svdata.hxx> -#include <strings.hrc> +#include "accessibleeditbrowseboxcell.hxx" #include <comphelper/processfactory.hxx> -#include <utility> #include <comphelper/diagnose_ex.hxx> -#include <vcl/accessibility/accessibleeditbrowseboxcell.hxx> +#include <svtools/strings.hrc> +#include <svtools/svtresid.hxx> using namespace com::sun::star::accessibility; using namespace ::com::sun::star::uno; @@ -109,8 +108,8 @@ OUString SAL_CALL EditBrowseBoxTableCell::getAccessibleName() SolarMethodGuard aGuard(getMutex()); ensureIsAlive(); - return VclResId(RID_STR_ACC_COLUMN_NUM).replaceAll("%COLUMNNUMBER", OUString::number(getColumnPos()-1)) + ", " - + VclResId(RID_STR_ACC_ROW_NUM).replaceAll("%ROWNUMBER", OUString::number(getRowPos())); + return SvtResId(STR_ACC_COLUMN_NUM).replaceAll("%COLUMNNUMBER", OUString::number(getColumnPos()-1)) + ", " + + SvtResId(STR_ACC_ROW_NUM).replaceAll("%ROWNUMBER", OUString::number(getRowPos())); } css::uno::Reference< css::accessibility::XAccessibleRelationSet > SAL_CALL EditBrowseBoxTableCell::getAccessibleRelationSet() diff --git a/include/vcl/accessibility/accessibleeditbrowseboxcell.hxx b/svtools/source/brwbox/accessibleeditbrowseboxcell.hxx similarity index 98% rename from include/vcl/accessibility/accessibleeditbrowseboxcell.hxx rename to svtools/source/brwbox/accessibleeditbrowseboxcell.hxx index 0c40aa7d2cf8..5a74a3873cb1 100644 --- a/include/vcl/accessibility/accessibleeditbrowseboxcell.hxx +++ b/svtools/source/brwbox/accessibleeditbrowseboxcell.hxx @@ -86,7 +86,7 @@ private: // = EditBrowseBoxTableCell // XAccessible providing an EditBrowseBoxTableCell -class VCL_DLLPUBLIC EditBrowseBoxTableCellAccess final +class EditBrowseBoxTableCellAccess final : public comphelper::WeakComponentImplHelper<css::accessibility::XAccessible> { css::uno::WeakReference< css::accessibility::XAccessibleContext > diff --git a/svtools/source/brwbox/editbrowsebox2.cxx b/svtools/source/brwbox/editbrowsebox2.cxx index 0c089650ac09..1d97e1283a58 100644 --- a/svtools/source/brwbox/editbrowsebox2.cxx +++ b/svtools/source/brwbox/editbrowsebox2.cxx @@ -24,7 +24,6 @@ #include <comphelper/types.hxx> #include <toolkit/helper/vclunohelper.hxx> #include <vcl/accessibility/AccessibleBrowseBoxCheckBoxCell.hxx> -#include <vcl/accessibility/accessibleeditbrowseboxcell.hxx> #include <vcl/accessiblefactory.hxx> #include <vcl/svapp.hxx> #include <tools/debug.hxx> diff --git a/svtools/source/brwbox/editbrowseboximpl.hxx b/svtools/source/brwbox/editbrowseboximpl.hxx index b2780124833a..50a58886f199 100644 --- a/svtools/source/brwbox/editbrowseboximpl.hxx +++ b/svtools/source/brwbox/editbrowseboximpl.hxx @@ -18,7 +18,7 @@ */ #pragma once -#include <vcl/accessibility/accessibleeditbrowseboxcell.hxx> +#include "accessibleeditbrowseboxcell.hxx" namespace svt { diff --git a/vcl/Library_vcl.mk b/vcl/Library_vcl.mk index b9fa3e21c996..08d4e550505c 100644 --- a/vcl/Library_vcl.mk +++ b/vcl/Library_vcl.mk @@ -108,7 +108,6 @@ $(eval $(call gb_Library_add_exception_objects,vcl,\ vcl/source/accessibility/AccessibleTextAttributeHelper \ vcl/source/accessibility/acc_factory \ vcl/source/accessibility/accessiblebrowseboxcell \ - vcl/source/accessibility/accessibleeditbrowseboxcell \ vcl/source/accessibility/accessibleiconchoicectrl \ vcl/source/accessibility/accessibleiconchoicectrlentry \ vcl/source/accessibility/AccessibleIconView \ diff --git a/vcl/inc/strings.hrc b/vcl/inc/strings.hrc index cdd231e842a4..c4f173fc0f40 100644 --- a/vcl/inc/strings.hrc +++ b/vcl/inc/strings.hrc @@ -135,8 +135,6 @@ #define RID_STR_ACC_SCROLLBAR_NAME_VERTICAL NC_("RID_STR_ACC_SCROLLBAR_NAME_VERTICAL", "Vertical scroll bar") #define RID_STR_ACC_SCROLLBAR_NAME_HORIZONTAL NC_("RID_STR_ACC_SCROLLBAR_NAME_HORIZONTAL", "Horizontal scroll bar") #define RID_STR_ACC_PANEL_DESCRIPTION NC_("RID_STR_ACC_PANEL_DESCRIPTION", "Please press enter to go into child control for more operations") -#define RID_STR_ACC_COLUMN_NUM NC_("RID_STR_ACC_COLUMN_NUM", "Column %COLUMNNUMBER") -#define RID_STR_ACC_ROW_NUM NC_("RID_STR_ACC_ROW_NUM", "Row %ROWNUMBER") #endif // INCLUDED_VCL_INC_STRINGS_HRC