office-gobmx/accessibility/source/extended/accessiblelistbox.cxx
Michael Weghorn c24db71bc5 tdf#160971 a11y: Add null check in AccessibleListBox::getAccessibleRole
Add a null check in `AccessibleListBox::getAccessibleRole`.

Otherwise, LO Writer crashes on exit when using the qt6 VCL
plugin with Orca running for this scenario:

1) start Writer with the qt6 VCL plugin
2) press F6 until focus is in the formatting toolbar
3) use tab key to get to the editable comboboxes
4) use up/down keys to change entries
5) use Alt+Down to expand combobox
6) switch between entries using up/down keys
7) close Writer

The reason is that the window gets unset when when
`SvTreeListBox::dispose` emits the
`VclEventId::ObjectDying` event, see
`VCLXAccessibleComponent::ProcessWindowEvent`.

But then, Qt's AT-SPI adaptor wants to query the accessible
role when the `AccessibleEventId::CHILD` event is forwarded
in our Qt a11y bridge, which previously resulted in a
nullptr dereference with the below backtrace.

Just return `AccessibleRole::LIST` for the null case.

Backtrace:

    1  std::__uniq_ptr_impl<WindowImpl, std::default_delete<WindowImpl>>::_M_ptr                         unique_ptr.h                  199  0x7f0c1ee0b055
    2  std::unique_ptr<WindowImpl, std::default_delete<WindowImpl>>::get                                 unique_ptr.h                  470  0x7f0c1ee0b035
    3  std::unique_ptr<WindowImpl, std::default_delete<WindowImpl>>::operator bool                       unique_ptr.h                  487  0x7f0c1ee4abc5
    4  vcl::Window::GetStyle                                                                             window2.cxx                   989  0x7f0c1f0e594d
    5  accessibility::AccessibleListBox::getAccessibleRole                                               accessiblelistbox.cxx         347  0x7f0be055205a
    6  QtAccessibleWidget::role                                                                          QtAccessibleWidget.cxx        380  0x7f0c151cc242
    7  AtSpiAdaptor::pathForInterface                                                                    atspiadaptor.cpp              1771 0x7f0c13a8b112
    8  AtSpiAdaptor::notifyAboutDestruction                                                              atspiadaptor.cpp              1419 0x7f0c13a86e81
    9  AtSpiAdaptor::notify                                                                              atspiadaptor.cpp              988  0x7f0c13a8246b
    10 QSpiAccessibleBridge::notifyAccessibilityUpdate                                                   qspiaccessiblebridge.cpp      85   0x7f0c13ad9bf2
    11 QAccessible::updateAccessibility                                                                  qaccessible.cpp               940  0x7f0c13a603aa
    12 QtAccessibleEventListener::notifyEvent                                                            QtAccessibleEventListener.cxx 232  0x7f0c151c1363
    13 comphelper::AccessibleEventNotifier::addEvent                                                     accessibleeventnotifier.cxx   256  0x7f0c270ee1b7
    14 comphelper::OCommonAccessibleComponent::NotifyAccessibleEvent                                     accessiblecomponenthelper.cxx 127  0x7f0c270e95b1
    15 VCLXAccessibleComponent::ProcessWindowEvent                                                       vclxaccessiblecomponent.cxx   229  0x7f0c20e80720
    16 VCLXAccessibleComponent::WindowEventListener                                                      vclxaccessiblecomponent.cxx   109  0x7f0c20e7fbbe
    17 VCLXAccessibleComponent::LinkStubWindowEventListener                                              vclxaccessiblecomponent.cxx   98   0x7f0c20e7f58d
    18 Link<VclWindowEvent&, void>::Call                                                                 link.hxx                      111  0x7f0c1efa2898
    19 vcl::Window::CallEventListeners                                                                   event.cxx                     262  0x7f0c1ef9f62e
    20 vcl::Window::dispose                                                                              window.cxx                    163  0x7f0c1f0f6513
    21 Control::dispose                                                                                  ctrl.cxx                      65   0x7f0c1f177a06
    22 SvTreeListBox::dispose                                                                            treelistbox.cxx               1340 0x7f0c1f464d1b
    23 SvTabListBox::dispose                                                                             svtabbx.cxx                   243  0x7f0c1f407a09
    24 VclReferenceBase::disposeOnce                                                                     vclreferencebase.cxx          38   0x7f0c1f3a957a
    25 VclPtr<vcl::Window>::disposeAndClear                                                              vclptr.hxx                    207  0x7f0c1eebfb19
    26 VclBuilder::disposeBuilder                                                                        builder.cxx                   814  0x7f0c1ee96f91
    27 VclBuilder::~VclBuilder                                                                           builder.cxx                   806  0x7f0c1ee96df9
    28 std::default_delete<VclBuilder>::operator()                                                       unique_ptr.h                  99   0x7f0c1ef6375b
    29 std::__uniq_ptr_impl<VclBuilder, std::default_delete<VclBuilder>>::reset                          unique_ptr.h                  211  0x7f0c1ef9da3c
    30 std::unique_ptr<VclBuilder, std::default_delete<VclBuilder>>::reset                               unique_ptr.h                  509  0x7f0c1ef9cfcd
    31 SalInstanceBuilder::~SalInstanceBuilder                                                           salvtables.cxx                7436 0x7f0c1f900b3e
    32 SalInstanceBuilder::~SalInstanceBuilder                                                           salvtables.cxx                7431 0x7f0c1f900ba9
    33 std::default_delete<weld::Builder>::operator()                                                    unique_ptr.h                  99   0x7f0c2490445f
    34 std::__uniq_ptr_impl<weld::Builder, std::default_delete<weld::Builder>>::reset                    unique_ptr.h                  211  0x7f0c2490438c
    35 std::unique_ptr<weld::Builder, std::default_delete<weld::Builder>>::reset                         unique_ptr.h                  509  0x7f0c24900e5d
    36 PanelLayout::~PanelLayout                                                                         PanelLayout.cxx               76   0x7f0c24f71c06
    37 SfxTemplatePanelControl::~SfxTemplatePanelControl                                                 templdlg.cxx                  163  0x7f0c24bd3d51
    38 SfxTemplatePanelControl::~SfxTemplatePanelControl                                                 templdlg.cxx                  160  0x7f0c24bd3d99
    39 std::default_delete<PanelLayout>::operator()                                                      unique_ptr.h                  99   0x7f0c24f1bedc
    40 std::__uniq_ptr_impl<PanelLayout, std::default_delete<PanelLayout>>::reset                        unique_ptr.h                  211  0x7f0c24f1bfdc
    41 std::unique_ptr<PanelLayout, std::default_delete<PanelLayout>>::reset                             unique_ptr.h                  509  0x7f0c24f1b06d
    42 sfx2::sidebar::SidebarPanelBase::disposing                                                        SidebarPanelBase.cxx          86   0x7f0c24f1a1df
    43 comphelper::WeakComponentImplHelperBase::dispose                                                  compbase.cxx                  26   0x7f0c2715c7a4
    44 comphelper::WeakComponentImplHelper<com::sun::ui::XContextChangeEventListener, com::sun::ui::XUIElement, com::sun::ui::XToolPanel, com::sun::ui::XSidebarPanel, com::sun::ui::XUpdateModel>::dispose compbase.hxx        75   0x7f0c24f1b235
    45 sfx2::sidebar::Panel::~Panel                                                                      Panel.cxx                     124  0x7f0c24f6fa51
    46 std::destroy_at<sfx2::sidebar::Panel>                                                             stl_construct.h               88   0x7f0c24f17315
    47 std::_Destroy<sfx2::sidebar::Panel>                                                               stl_construct.h               149  0x7f0c24f172f5
    48 std::allocator_traits<std::allocator<void>>::destroy<sfx2::sidebar::Panel>                        alloc_traits.h                675  0x7f0c24f170ff
    49 std::_Sp_counted_ptr_inplace<sfx2::sidebar::Panel, std::allocator<void>, (__gnu_cxx::_Lock_policy)2>::_M_dispose                                                       shared_ptr_base.h             613  0x7f0c24f170ff
    50 std::_Sp_counted_base<(__gnu_cxx::_Lock_policy)2>::_M_release                                     shared_ptr_base.h             346  0x7f0c2481f0ce
    51 std::__shared_count<(__gnu_cxx::_Lock_policy)2>::~__shared_count                                  shared_ptr_base.h             1071 0x7f0c2481f04a
    52 std::__shared_ptr<sfx2::sidebar::Panel, (__gnu_cxx::_Lock_policy)2>::~__shared_ptr                shared_ptr_base.h             1524 0x7f0c24f15469
    53 std::__shared_ptr<sfx2::sidebar::Panel, (__gnu_cxx::_Lock_policy)2>::reset                        shared_ptr_base.h             1642 0x7f0c24f0cc84
    54 sfx2::sidebar::Deck::dispose                                                                      Deck.cxx                      93   0x7f0c24f5842b
    55 VclReferenceBase::disposeOnce                                                                     vclreferencebase.cxx          38   0x7f0c1f3a957a
    56 VclPtr<sfx2::sidebar::Deck>::disposeAndClear                                                      vclptr.hxx                    207  0x7f0c24f0bc96
    57 sfx2::sidebar::ResourceManager::disposeDecks                                                      ResourceManager.cxx           800  0x7f0c24f79791
    58 sfx2::sidebar::SidebarController::disposeDecks                                                    SidebarController.cxx         250  0x7f0c24efde01
    59 sfx2::sidebar::SidebarController::unregisterSidebarForFrame                                       SidebarController.cxx         212  0x7f0c24efd7e3
    60 sfx2::sidebar::SidebarController::frameAction                                                     SidebarController.cxx         1619 0x7f0c24f07542
    61 (anonymous namespace)::XFrameImpl::implts_sendFrameActionEvent                                    frame.cxx                     2960 0x7f0c25e25207
    62 (anonymous namespace)::XFrameImpl::setComponent                                                   frame.cxx                     1457 0x7f0c25e1d8b2
    63 (anonymous namespace)::XFrameImpl::close                                                          frame.cxx                     1706 0x7f0c25e20158
    64 framework::Desktop::impl_closeFrames                                                              desktop.cxx                   1699 0x7f0c25e03be4
    65 framework::Desktop::terminate                                                                     desktop.cxx                   205  0x7f0c25e0315b
    66 framework::CloseDispatcher::implts_terminateApplication                                           closedispatcher.cxx           552  0x7f0c25c33510
    67 framework::CloseDispatcher::impl_asyncCallback                                                    closedispatcher.cxx           406  0x7f0c25c326af
    68 framework::CloseDispatcher::LinkStubimpl_asyncCallback                                            closedispatcher.cxx           246  0x7f0c25c30b7d
    69 Link<LinkParamNone *, void>::Call                                                                 link.hxx                      111  0x7f0c1ee22718
    70 vcl::EventPoster::DoEvent_Impl                                                                    evntpost.cxx                  52   0x7f0c1f8a1485
    71 vcl::EventPoster::LinkStubDoEvent_Impl                                                            evntpost.cxx                  48   0x7f0c1f8a143d
    72 Link<void *, void>::Call                                                                          link.hxx                      111  0x7f0c1f12d138
    73 ImplHandleUserEvent                                                                               winproc.cxx                   2287 0x7f0c1f128e19
    74 ImplWindowFrameProc                                                                               winproc.cxx                   2851 0x7f0c1f1257d0
    75 SalFrame::CallCallback                                                                            salframe.hxx                  312  0x7f0c15240b90
    76 QtInstance::ProcessEvent                                                                          QtInstance.cxx                516  0x7f0c15263e3f
    77 SalUserEventList::DispatchUserEvents(bool)::$_0::operator()() const                               salusereventlist.cxx          119  0x7f0c1f8b585d
    78 SalUserEventList::DispatchUserEvents                                                              salusereventlist.cxx          120  0x7f0c1f8b5704
    79 QtInstance::ImplYield                                                                             QtInstance.cxx                442  0x7f0c15260541
    80 QtInstance::DoYield                                                                               QtInstance.cxx                464  0x7f0c15263945
    81 ImplYield                                                                                         svapp.cxx                     378  0x7f0c1f995c9c
    82 Application::Yield                                                                                svapp.cxx                     466  0x7f0c1f9955ab
    83 Application::Execute                                                                              svapp.cxx                     353  0x7f0c1f995342
    84 desktop::Desktop::Main                                                                            app.cxx                       1615 0x7f0c28b275a9
    85 ImplSVMain                                                                                        svmain.cxx                    229  0x7f0c1f9b84ae
    86 SVMain                                                                                            svmain.cxx                    261  0x7f0c1f9ba4f9
    87 soffice_main                                                                                      sofficemain.cxx               93   0x7f0c28bab36c
    88 sal_main                                                                                          main.c                        51   0x5644eb5ffa5d
    89 main                                                                                              main.c                        49   0x5644eb5ffa37

Change-Id: I3fefaed31c6557620ecbe1627d265f2065fe9747
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/167475
Tested-by: Jenkins
Reviewed-by: Michael Weghorn <m.weghorn@posteo.de>
2024-05-10 16:24:12 +02:00

512 lines
17 KiB
C++

/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
* 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/.
*
* This file incorporates work covered by the following license notice:
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed
* with this work for additional information regarding copyright
* ownership. The ASF licenses this file to you under the Apache
* License, Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.apache.org/licenses/LICENSE-2.0 .
*/
#include <extended/accessiblelistbox.hxx>
#include <extended/accessiblelistboxentry.hxx>
#include <vcl/toolkit/treelistbox.hxx>
#include <vcl/toolkit/treelistentry.hxx>
#include <com/sun/star/accessibility/AccessibleEventId.hpp>
#include <com/sun/star/accessibility/AccessibleRole.hpp>
#include <com/sun/star/accessibility/AccessibleStateType.hpp>
#include <com/sun/star/lang/IndexOutOfBoundsException.hpp>
#include <comphelper/accessiblecontexthelper.hxx>
#include <cppuhelper/supportsservice.hxx>
namespace accessibility
{
// class AccessibleListBox -----------------------------------------------------
using namespace ::com::sun::star::accessibility;
using namespace ::com::sun::star::uno;
using namespace ::com::sun::star::lang;
using namespace ::com::sun::star;
// Ctor() and Dtor()
AccessibleListBox::AccessibleListBox( SvTreeListBox const & _rListBox, const Reference< XAccessible >& _xParent ) :
ImplInheritanceHelper( _rListBox.GetWindowPeer() ),
m_xParent( _xParent )
{
}
AccessibleListBox::~AccessibleListBox()
{
if ( isAlive() )
{
// increment ref count to prevent double call of Dtor
osl_atomic_increment( &m_refCount );
dispose();
}
}
void AccessibleListBox::ProcessWindowEvent( const VclWindowEvent& rVclWindowEvent )
{
if ( !isAlive() )
return;
switch ( rVclWindowEvent.GetId() )
{
case VclEventId::CheckboxToggle :
{
if ( !getListBox() || !getListBox()->HasFocus() )
{
return;
}
AccessibleListBoxEntry* pCurOpEntry = GetCurEventEntry(rVclWindowEvent);
if(!pCurOpEntry)
{
return ;
}
uno::Any aValue;
aValue <<= AccessibleStateType::CHECKED;
if ( getListBox()->GetCheckButtonState( pCurOpEntry->GetSvLBoxEntry() ) == SvButtonState::Checked )
{
pCurOpEntry->NotifyAccessibleEvent( AccessibleEventId::STATE_CHANGED, uno::Any(), aValue );
}
else
{
pCurOpEntry->NotifyAccessibleEvent( AccessibleEventId::STATE_CHANGED, aValue,uno::Any() );
}
break;
}
case VclEventId::ListboxSelect :
{
OSL_FAIL("Debug: Treelist shouldn't use VclEventId::ListboxSelect");
break;
}
case VclEventId::ListboxTreeSelect:
{
if ( getListBox() && getListBox()->HasFocus() )
{
if (m_xFocusedEntry.is())
{
m_xFocusedEntry->NotifyAccessibleEvent(AccessibleEventId::SELECTION_CHANGED, Any(), Any());
}
}
}
break;
case VclEventId::ListboxTreeFocus:
{
VclPtr<SvTreeListBox> pBox = getListBox();
if( pBox && pBox->HasFocus() )
{
uno::Any aNewValue;
SvTreeListEntry* pEntry = static_cast< SvTreeListEntry* >( rVclWindowEvent.GetData() );
if ( pEntry )
{
if (m_xFocusedEntry.is() && m_xFocusedEntry->GetSvLBoxEntry() == pEntry)
{
aNewValue <<= uno::Reference<XAccessible>(m_xFocusedEntry);;
NotifyAccessibleEvent( AccessibleEventId::ACTIVE_DESCENDANT_CHANGED, uno::Any(), aNewValue );
return ;
}
uno::Any aOldValue;
aOldValue <<= uno::Reference<XAccessible>(m_xFocusedEntry);;
m_xFocusedEntry = implGetAccessible(*pEntry);
aNewValue <<= uno::Reference<XAccessible>(m_xFocusedEntry);
NotifyAccessibleEvent( AccessibleEventId::ACTIVE_DESCENDANT_CHANGED, aOldValue, aNewValue );
}
else
{
aNewValue <<= AccessibleStateType::FOCUSED;
NotifyAccessibleEvent( AccessibleEventId::STATE_CHANGED, uno::Any(), aNewValue );
}
}
}
break;
case VclEventId::ListboxItemRemoved:
{
SvTreeListEntry* pEntry = static_cast< SvTreeListEntry* >( rVclWindowEvent.GetData() );
if ( pEntry )
{
RemoveChildEntries(pEntry);
}
else
{
// NULL means Clear()
for (auto const& entry : m_mapEntry)
{
uno::Any aNewValue;
uno::Any aOldValue;
aOldValue <<= uno::Reference<XAccessible>(entry.second);
NotifyAccessibleEvent( AccessibleEventId::CHILD, aOldValue, aNewValue );
}
for (auto const& entry : m_mapEntry)
{ // release references ...
entry.second->dispose();
}
m_mapEntry.clear();
}
}
break;
// #i92103#
case VclEventId::ItemExpanded :
case VclEventId::ItemCollapsed :
{
SvTreeListEntry* pEntry = static_cast< SvTreeListEntry* >( rVclWindowEvent.GetData() );
if ( pEntry )
{
Reference<XAccessible> const xChild(implGetAccessible(*pEntry));
const short nAccEvent =
( rVclWindowEvent.GetId() == VclEventId::ItemExpanded )
? AccessibleEventId::LISTBOX_ENTRY_EXPANDED
: AccessibleEventId::LISTBOX_ENTRY_COLLAPSED;
uno::Any aListBoxEntry;
aListBoxEntry <<= xChild;
NotifyAccessibleEvent( nAccEvent, Any(), aListBoxEntry );
if ( getListBox() && getListBox()->HasFocus() )
{
NotifyAccessibleEvent( AccessibleEventId::ACTIVE_DESCENDANT_CHANGED, Any(), aListBoxEntry );
}
}
}
break;
default:
VCLXAccessibleComponent::ProcessWindowEvent (rVclWindowEvent);
}
}
AccessibleListBoxEntry* AccessibleListBox::GetCurEventEntry( const VclWindowEvent& rVclWindowEvent )
{
SvTreeListEntry* pEntry = static_cast< SvTreeListEntry* >( rVclWindowEvent.GetData() );
if ( !pEntry )
pEntry = getListBox()->GetCurEntry();
if (m_xFocusedEntry.is() && pEntry && pEntry != m_xFocusedEntry->GetSvLBoxEntry())
{
AccessibleListBoxEntry *const pAccCurOptionEntry = implGetAccessible(*pEntry).get();
uno::Any aNewValue;
aNewValue <<= uno::Reference<XAccessible>(pAccCurOptionEntry);
NotifyAccessibleEvent( AccessibleEventId::CHILD, uno::Any(), aNewValue );//Add
return pAccCurOptionEntry;
}
else
{
return m_xFocusedEntry.get();
}
}
void AccessibleListBox::RemoveChildEntries(SvTreeListEntry* pEntry)
{
MAP_ENTRY::iterator mi = m_mapEntry.find(pEntry);
if ( mi != m_mapEntry.end() )
{
uno::Any aNewValue;
uno::Any aOldValue;
aOldValue <<= uno::Reference<XAccessible>(mi->second);
NotifyAccessibleEvent( AccessibleEventId::CHILD, aOldValue, aNewValue );
m_mapEntry.erase(mi);
}
VclPtr<SvTreeListBox> pBox = getListBox();
SvTreeListEntry* pEntryChild = pBox->FirstChild(pEntry);
while (pEntryChild)
{
RemoveChildEntries(pEntryChild);
pEntryChild = pEntryChild->NextSibling();
}
}
// XComponent
void SAL_CALL AccessibleListBox::disposing()
{
::osl::MutexGuard aGuard( m_aMutex );
m_mapEntry.clear();
VCLXAccessibleComponent::disposing();
m_xParent = nullptr;
}
// XServiceInfo
OUString SAL_CALL AccessibleListBox::getImplementationName()
{
return u"com.sun.star.comp.svtools.AccessibleTreeListBox"_ustr;
}
Sequence< OUString > SAL_CALL AccessibleListBox::getSupportedServiceNames()
{
return {u"com.sun.star.accessibility.AccessibleContext"_ustr,
u"com.sun.star.accessibility.AccessibleComponent"_ustr,
u"com.sun.star.awt.AccessibleTreeListBox"_ustr};
}
sal_Bool SAL_CALL AccessibleListBox::supportsService( const OUString& _rServiceName )
{
return cppu::supportsService(this, _rServiceName);
}
// XAccessible
Reference< XAccessibleContext > SAL_CALL AccessibleListBox::getAccessibleContext( )
{
ensureAlive();
return this;
}
// XAccessibleContext
sal_Int64 SAL_CALL AccessibleListBox::getAccessibleChildCount( )
{
::comphelper::OExternalLockGuard aGuard( this );
sal_Int32 nCount = 0;
VclPtr<SvTreeListBox> pSvTreeListBox = getListBox();
if ( pSvTreeListBox )
nCount = pSvTreeListBox->GetLevelChildCount( nullptr );
return nCount;
}
Reference< XAccessible > SAL_CALL AccessibleListBox::getAccessibleChild( sal_Int64 i )
{
::comphelper::OExternalLockGuard aGuard( this );
SvTreeListEntry* pEntry = getListBox()->GetEntry(i);
if ( !pEntry )
throw IndexOutOfBoundsException();
// Solution: Set the parameter of the parent to null to let entry determine the parent by itself
//return new AccessibleListBoxEntry( *getListBox(), pEntry, this );
//return new AccessibleListBoxEntry( *getListBox(), pEntry, nullptr );
return implGetAccessible(*pEntry);
}
Reference< XAccessible > SAL_CALL AccessibleListBox::getAccessibleParent( )
{
::osl::MutexGuard aGuard( m_aMutex );
ensureAlive();
return m_xParent;
}
sal_Int32 AccessibleListBox::GetRoleType() const
{
sal_Int32 nCase = 0;
SvTreeListEntry* pEntry = getListBox()->GetEntry(0);
if ( pEntry )
{
if( pEntry->HasChildrenOnDemand() || getListBox()->GetChildCount(pEntry) > 0 )
{
nCase = 1;
return nCase;
}
}
bool bHasButtons = (getListBox()->GetStyle() & WB_HASBUTTONS)!=0;
if( !(getListBox()->GetTreeFlags() & SvTreeFlags::CHKBTN) )
{
if( bHasButtons )
nCase = 1;
}
else
{
if( bHasButtons )
nCase = 2;
else
nCase = 3;
}
return nCase;
}
sal_Int16 SAL_CALL AccessibleListBox::getAccessibleRole()
{
::comphelper::OExternalLockGuard aGuard( this );
VclPtr<SvTreeListBox> pListBox = getListBox();
if (!pListBox)
return AccessibleRole::LIST;
//o is: return AccessibleRole::TREE;
bool bHasButtons = (pListBox->GetStyle() & WB_HASBUTTONS) != 0;
if (!bHasButtons && (pListBox->GetTreeFlags() & SvTreeFlags::CHKBTN))
return AccessibleRole::LIST;
else
if (GetRoleType() == 0)
return AccessibleRole::LIST;
else
return AccessibleRole::TREE;
}
OUString SAL_CALL AccessibleListBox::getAccessibleDescription( )
{
::comphelper::OExternalLockGuard aGuard( this );
return getListBox()->GetAccessibleDescription();
}
OUString SAL_CALL AccessibleListBox::getAccessibleName( )
{
::comphelper::OExternalLockGuard aGuard( this );
return getListBox()->GetAccessibleName();
}
// XAccessibleSelection
void SAL_CALL AccessibleListBox::selectAccessibleChild( sal_Int64 nChildIndex )
{
::comphelper::OExternalLockGuard aGuard( this );
SvTreeListEntry* pEntry = getListBox()->GetEntry( nChildIndex );
if ( !pEntry )
throw IndexOutOfBoundsException();
getListBox()->Select( pEntry );
}
sal_Bool SAL_CALL AccessibleListBox::isAccessibleChildSelected( sal_Int64 nChildIndex )
{
::comphelper::OExternalLockGuard aGuard( this );
if (nChildIndex < 0 || nChildIndex >= getAccessibleChildCount())
throw IndexOutOfBoundsException();
SvTreeListEntry* pEntry = getListBox()->GetEntry( nChildIndex );
if ( !pEntry )
throw IndexOutOfBoundsException();
return getListBox()->IsSelected( pEntry );
}
void SAL_CALL AccessibleListBox::clearAccessibleSelection( )
{
::comphelper::OExternalLockGuard aGuard( this );
sal_Int32 nCount = getListBox()->GetLevelChildCount( nullptr );
for ( sal_Int32 i = 0; i < nCount; ++i )
{
SvTreeListEntry* pEntry = getListBox()->GetEntry( i );
if ( getListBox()->IsSelected( pEntry ) )
getListBox()->Select( pEntry, false );
}
}
void SAL_CALL AccessibleListBox::selectAllAccessibleChildren( )
{
::comphelper::OExternalLockGuard aGuard( this );
sal_Int32 nCount = getListBox()->GetLevelChildCount( nullptr );
for ( sal_Int32 i = 0; i < nCount; ++i )
{
SvTreeListEntry* pEntry = getListBox()->GetEntry( i );
if ( !getListBox()->IsSelected( pEntry ) )
getListBox()->Select( pEntry );
}
}
sal_Int64 SAL_CALL AccessibleListBox::getSelectedAccessibleChildCount( )
{
::comphelper::OExternalLockGuard aGuard( this );
return getListBox()->GetSelectionCount();
}
Reference< XAccessible > SAL_CALL AccessibleListBox::getSelectedAccessibleChild( sal_Int64 nSelectedChildIndex )
{
::comphelper::OExternalLockGuard aGuard( this );
if ( nSelectedChildIndex < 0 || nSelectedChildIndex >= getSelectedAccessibleChildCount() )
throw IndexOutOfBoundsException();
Reference< XAccessible > xChild;
sal_Int64 nSelCount= 0;
sal_Int32 nCount = getListBox()->GetLevelChildCount( nullptr );
for ( sal_Int32 i = 0; i < nCount; ++i )
{
SvTreeListEntry* pEntry = getListBox()->GetEntry( i );
if ( getListBox()->IsSelected( pEntry ) )
++nSelCount;
if ( nSelCount == ( nSelectedChildIndex + 1 ) )
{
// Solution: Set the parameter of the parent to null to let entry determine the parent by itself
//xChild = new AccessibleListBoxEntry( *getListBox(), pEntry, this );
//xChild = new AccessibleListBoxEntry( *getListBox(), pEntry, nullptr );
xChild = implGetAccessible(*pEntry).get();
break;
}
}
return xChild;
}
void SAL_CALL AccessibleListBox::deselectAccessibleChild( sal_Int64 nSelectedChildIndex )
{
::comphelper::OExternalLockGuard aGuard( this );
SvTreeListEntry* pEntry = getListBox()->GetEntry( nSelectedChildIndex );
if ( !pEntry )
throw IndexOutOfBoundsException();
getListBox()->Select( pEntry, false );
}
void AccessibleListBox::FillAccessibleStateSet( sal_Int64& rStateSet )
{
VCLXAccessibleComponent::FillAccessibleStateSet( rStateSet );
if ( getListBox() && isAlive() )
{
rStateSet |= AccessibleStateType::FOCUSABLE;
rStateSet |= AccessibleStateType::MANAGES_DESCENDANTS;
if ( getListBox()->GetSelectionMode() == SelectionMode::Multiple )
rStateSet |= AccessibleStateType::MULTI_SELECTABLE;
}
}
rtl::Reference<AccessibleListBoxEntry> AccessibleListBox::implGetAccessible(SvTreeListEntry & rEntry)
{
rtl::Reference<AccessibleListBoxEntry> pAccessible;
auto const it = m_mapEntry.find(&rEntry);
if (it != m_mapEntry.end())
{
pAccessible = it->second;
}
else
{
pAccessible = new AccessibleListBoxEntry(*getListBox(), rEntry, *this);
m_mapEntry.emplace(&rEntry, pAccessible);
}
assert(pAccessible.is());
return pAccessible;
}
VclPtr< SvTreeListBox > AccessibleListBox::getListBox() const
{
return GetAs< SvTreeListBox >();
}
}// namespace accessibility
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */