c24db71bc5
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>
512 lines
17 KiB
C++
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: */
|