From ed5640d8b587fbcfed7dd7967f3de04b37a76f26 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sun, 7 Apr 2024 11:06:44 +0200 Subject: Adding upstream version 4:7.4.7. Signed-off-by: Daniel Baumann --- .../source/extended/accessiblelistboxentry.cxx | 1194 ++++++++++++++++++++ 1 file changed, 1194 insertions(+) create mode 100644 accessibility/source/extended/accessiblelistboxentry.cxx (limited to 'accessibility/source/extended/accessiblelistboxentry.cxx') diff --git a/accessibility/source/extended/accessiblelistboxentry.cxx b/accessibility/source/extended/accessiblelistboxentry.cxx new file mode 100644 index 000000000..2fff77b03 --- /dev/null +++ b/accessibility/source/extended/accessiblelistboxentry.cxx @@ -0,0 +1,1194 @@ +/* -*- 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define ACCESSIBLE_ACTION_COUNT 1 + +namespace +{ + /// @throws css::lang::IndexOutOfBoundsException + void checkActionIndex_Impl( sal_Int32 _nIndex ) + { + if ( _nIndex < 0 || _nIndex >= ACCESSIBLE_ACTION_COUNT ) + // only three actions + throw css::lang::IndexOutOfBoundsException(); + } +} + + +namespace accessibility +{ + // class AccessibleListBoxEntry ----------------------------------------------------- + + using namespace ::com::sun::star::accessibility; + using namespace ::com::sun::star::uno; + using namespace ::com::sun::star::lang; + using namespace ::com::sun::star; + using namespace ::comphelper; + + + // Ctor() and Dtor() + + AccessibleListBoxEntry::AccessibleListBoxEntry( SvTreeListBox& _rListBox, + SvTreeListEntry& rEntry, + AccessibleListBox & rListBox) + : AccessibleListBoxEntry_BASE( m_aMutex ) + + , m_pTreeListBox( &_rListBox ) + , m_pSvLBoxEntry(&rEntry) + , m_nClientId( 0 ) + , m_wListBox(&rListBox) + , m_rListBox(rListBox) + { + m_pTreeListBox->AddEventListener( LINK( this, AccessibleListBoxEntry, WindowEventListener ) ); + _rListBox.FillEntryPath( m_pSvLBoxEntry, m_aEntryPath ); + } + + AccessibleListBoxEntry::~AccessibleListBoxEntry() + { + if ( IsAlive_Impl() ) + { + // increment ref count to prevent double call of Dtor + osl_atomic_increment( &m_refCount ); + dispose(); + } + } + + IMPL_LINK( AccessibleListBoxEntry, WindowEventListener, VclWindowEvent&, rEvent, void ) + { + OSL_ENSURE( rEvent.GetWindow() , "AccessibleListBoxEntry::WindowEventListener: no event window!" ); + OSL_ENSURE( rEvent.GetWindow() == m_pTreeListBox, "AccessibleListBoxEntry::WindowEventListener: where did this come from?" ); + + if ( m_pTreeListBox == nullptr ) + return; + + switch ( rEvent.GetId() ) + { + case VclEventId::ObjectDying : + { + if ( m_pTreeListBox ) + m_pTreeListBox->RemoveEventListener( LINK( this, AccessibleListBoxEntry, WindowEventListener ) ); + m_pTreeListBox = nullptr; + dispose(); + break; + } + default: break; + } + } + + void AccessibleListBoxEntry::NotifyAccessibleEvent( sal_Int16 _nEventId, + const css::uno::Any& _aOldValue, + const css::uno::Any& _aNewValue ) + { + Reference< uno::XInterface > xSource( *this ); + AccessibleEventObject aEventObj( xSource, _nEventId, _aNewValue, _aOldValue ); + + if (m_nClientId) + comphelper::AccessibleEventNotifier::addEvent( m_nClientId, aEventObj ); + } + + + tools::Rectangle AccessibleListBoxEntry::GetBoundingBox_Impl() const + { + tools::Rectangle aRect; + SvTreeListEntry* pEntry = m_pTreeListBox->GetEntryFromPath( m_aEntryPath ); + if ( pEntry ) + { + aRect = m_pTreeListBox->GetBoundingRect( pEntry ); + SvTreeListEntry* pParent = m_pTreeListBox->GetParent( pEntry ); + if ( pParent ) + { + // position relative to parent entry + Point aTopLeft = aRect.TopLeft(); + aTopLeft -= m_pTreeListBox->GetBoundingRect( pParent ).TopLeft(); + aRect = tools::Rectangle( aTopLeft, aRect.GetSize() ); + } + } + + return aRect; + } + + tools::Rectangle AccessibleListBoxEntry::GetBoundingBoxOnScreen_Impl() const + { + tools::Rectangle aRect; + SvTreeListEntry* pEntry = m_pTreeListBox->GetEntryFromPath( m_aEntryPath ); + if ( pEntry ) + { + aRect = m_pTreeListBox->GetBoundingRect( pEntry ); + Point aTopLeft = aRect.TopLeft(); + aTopLeft += m_pTreeListBox->GetWindowExtentsRelative( nullptr ).TopLeft(); + aRect = tools::Rectangle( aTopLeft, aRect.GetSize() ); + } + + return aRect; + } + + bool AccessibleListBoxEntry::IsAlive_Impl() const + { + return !rBHelper.bDisposed && !rBHelper.bInDispose && (m_pTreeListBox != nullptr); + } + + bool AccessibleListBoxEntry::IsShowing_Impl() const + { + Reference< XAccessible > xParent = implGetParentAccessible( ); + + bool bShowing = false; + Reference< XAccessibleContext > xParentContext = + xParent.is() ? xParent->getAccessibleContext() : Reference< XAccessibleContext >(); + if( xParentContext.is() ) + { + Reference< XAccessibleComponent > xParentComp( xParentContext, uno::UNO_QUERY ); + if( xParentComp.is() ) + bShowing = GetBoundingBox_Impl().Overlaps( VCLRectangle( xParentComp->getBounds() ) ); + } + + return bShowing; + } + + tools::Rectangle AccessibleListBoxEntry::GetBoundingBox() + { + SolarMutexGuard aSolarGuard; + ::osl::MutexGuard aGuard( m_aMutex ); + + EnsureIsAlive(); + return GetBoundingBox_Impl(); + } + + tools::Rectangle AccessibleListBoxEntry::GetBoundingBoxOnScreen() + { + SolarMutexGuard aSolarGuard; + ::osl::MutexGuard aGuard( m_aMutex ); + + EnsureIsAlive(); + return GetBoundingBoxOnScreen_Impl(); + } + + void AccessibleListBoxEntry::EnsureIsAlive() const + { + if ( !IsAlive_Impl() ) + throw lang::DisposedException(); + } + + OUString AccessibleListBoxEntry::implGetText() + { + OUString sRet; + SvTreeListEntry* pEntry = m_pTreeListBox->GetEntryFromPath( m_aEntryPath ); + if ( pEntry ) + sRet = SvTreeListBox::SearchEntryTextWithHeadTitle( pEntry ); + return sRet; + } + + Locale AccessibleListBoxEntry::implGetLocale() + { + return Application::GetSettings().GetUILanguageTag().getLocale(); + } + void AccessibleListBoxEntry::implGetSelection( sal_Int32& nStartIndex, sal_Int32& nEndIndex ) + { + nStartIndex = 0; + nEndIndex = 0; + } + + // XTypeProvider + + + Sequence< sal_Int8 > AccessibleListBoxEntry::getImplementationId() + { + return css::uno::Sequence(); + } + + + // XComponent + + void SAL_CALL AccessibleListBoxEntry::disposing() + { + SolarMutexGuard aSolarGuard; + ::osl::MutexGuard aGuard( m_aMutex ); + + Reference< XAccessible > xKeepAlive( this ); + + // Send a disposing to all listeners. + if ( m_nClientId ) + { + ::comphelper::AccessibleEventNotifier::TClientId nId = m_nClientId; + m_nClientId = 0; + ::comphelper::AccessibleEventNotifier::revokeClientNotifyDisposing( nId, *this ); + } + + // clean up + m_wListBox.clear(); + + if ( m_pTreeListBox ) + m_pTreeListBox->RemoveEventListener( LINK( this, AccessibleListBoxEntry, WindowEventListener ) ); + m_pTreeListBox = nullptr; + } + + // XServiceInfo + + OUString SAL_CALL AccessibleListBoxEntry::getImplementationName() + { + return "com.sun.star.comp.svtools.AccessibleTreeListBoxEntry"; + } + + Sequence< OUString > SAL_CALL AccessibleListBoxEntry::getSupportedServiceNames() + { + return {"com.sun.star.accessibility.AccessibleContext", + "com.sun.star.accessibility.AccessibleComponent", + "com.sun.star.awt.AccessibleTreeListBoxEntry"}; + } + + sal_Bool SAL_CALL AccessibleListBoxEntry::supportsService( const OUString& _rServiceName ) + { + return cppu::supportsService(this, _rServiceName); + } + + // XAccessible + + Reference< XAccessibleContext > SAL_CALL AccessibleListBoxEntry::getAccessibleContext( ) + { + EnsureIsAlive(); + return this; + } + + // XAccessibleContext + + sal_Int32 SAL_CALL AccessibleListBoxEntry::getAccessibleChildCount( ) + { + SolarMutexGuard aSolarGuard; + ::osl::MutexGuard aGuard( m_aMutex ); + + EnsureIsAlive(); + SvTreeListEntry* pEntry = m_pTreeListBox->GetEntryFromPath( m_aEntryPath ); + sal_Int32 nCount = 0; + if ( pEntry ) + nCount = m_pTreeListBox->GetLevelChildCount( pEntry ); + + return nCount; + } + + Reference< XAccessible > SAL_CALL AccessibleListBoxEntry::getAccessibleChild( sal_Int32 i ) + { + SolarMutexGuard aSolarGuard; + ::osl::MutexGuard aGuard( m_aMutex ); + EnsureIsAlive(); + + SvTreeListEntry* pEntry = GetRealChild(i); + if ( !pEntry ) + throw IndexOutOfBoundsException(); + + uno::Reference xListBox(m_wListBox); + assert(xListBox.is()); + + return m_rListBox.implGetAccessible(*pEntry); + } + + Reference< XAccessible > AccessibleListBoxEntry::implGetParentAccessible( ) const + { + Reference< XAccessible > xParent; + if ( !xParent.is() ) + { + OSL_ENSURE( m_aEntryPath.size(), "AccessibleListBoxEntry::getAccessibleParent: invalid path!" ); + if ( m_aEntryPath.size() == 1 ) + { // we're a top level entry + // -> our parent is the tree listbox itself + if ( m_pTreeListBox ) + xParent = m_pTreeListBox->GetAccessible( ); + } + else + { // we have an entry as parent -> get its accessible + + // shorten our access path by one + std::deque< sal_Int32 > aParentPath( m_aEntryPath ); + aParentPath.pop_back(); + + // get the entry for this shortened access path + SvTreeListEntry* pParentEntry = m_pTreeListBox->GetEntryFromPath( aParentPath ); + OSL_ENSURE( pParentEntry, "AccessibleListBoxEntry::implGetParentAccessible: could not obtain a parent entry!" ); + + if ( pParentEntry ) + pParentEntry = m_pTreeListBox->GetParent(pParentEntry); + if ( pParentEntry ) + { + uno::Reference xListBox(m_wListBox); + assert(xListBox.is()); + return m_rListBox.implGetAccessible(*pParentEntry); + // the AccessibleListBoxEntry class will create its parent + // when needed + } + } + } + + return xParent; + } + + + Reference< XAccessible > SAL_CALL AccessibleListBoxEntry::getAccessibleParent( ) + { + SolarMutexGuard aSolarGuard; + ::osl::MutexGuard aGuard( m_aMutex ); + EnsureIsAlive(); + + return implGetParentAccessible( ); + } + + sal_Int32 SAL_CALL AccessibleListBoxEntry::getAccessibleIndexInParent( ) + { + ::osl::MutexGuard aGuard( m_aMutex ); + + OSL_ENSURE( !m_aEntryPath.empty(), "empty path" ); + return m_aEntryPath.empty() ? -1 : m_aEntryPath.back(); + } + + sal_Int32 AccessibleListBoxEntry::GetRoleType() const + { + sal_Int32 nCase = 0; + SvTreeListEntry* pEntry = m_pTreeListBox->GetEntry(0); + if ( pEntry ) + { + if( pEntry->HasChildrenOnDemand() || m_pTreeListBox->GetChildCount(pEntry) > 0 ) + { + nCase = 1; + return nCase; + } + } + + bool bHasButtons = (m_pTreeListBox->GetStyle() & WB_HASBUTTONS)!=0; + if( !(m_pTreeListBox->GetTreeFlags() & SvTreeFlags::CHKBTN) ) + { + if( bHasButtons ) + nCase = 1; + } + else + { + if( bHasButtons ) + nCase = 2; + else + nCase = 3; + } + return nCase; + } + + sal_Int16 SAL_CALL AccessibleListBoxEntry::getAccessibleRole( ) + { + SolarMutexGuard aSolarGuard; + ::osl::MutexGuard aGuard( m_aMutex ); + + SvTreeListBox* pBox = m_pTreeListBox; + if(!pBox) + return AccessibleRole::UNKNOWN; + + SvTreeFlags treeFlag = pBox->GetTreeFlags(); + if(treeFlag & SvTreeFlags::CHKBTN ) + { + SvTreeListEntry* pEntry = pBox->GetEntryFromPath( m_aEntryPath ); + SvButtonState eState = pBox->GetCheckButtonState( pEntry ); + switch( eState ) + { + case SvButtonState::Checked: + case SvButtonState::Unchecked: + return AccessibleRole::CHECK_BOX; + case SvButtonState::Tristate: + default: + return AccessibleRole::LABEL; + } + } + if (GetRoleType() == 0) + return AccessibleRole::LIST_ITEM; + else + //o is: return AccessibleRole::LABEL; + return AccessibleRole::TREE_ITEM; + } + + OUString SAL_CALL AccessibleListBoxEntry::getAccessibleDescription( ) + { + SolarMutexGuard aSolarGuard; + ::osl::MutexGuard aGuard( m_aMutex ); + + if( getAccessibleRole() == AccessibleRole::TREE_ITEM ) + { + return OUString(); + } + return m_pTreeListBox->GetEntryAccessibleDescription( + m_pTreeListBox->GetEntryFromPath(m_aEntryPath)); + } + + OUString SAL_CALL AccessibleListBoxEntry::getAccessibleName( ) + { + ::osl::MutexGuard aGuard( m_aMutex ); + + EnsureIsAlive(); + + return implGetText(); + } + + Reference< XAccessibleRelationSet > SAL_CALL AccessibleListBoxEntry::getAccessibleRelationSet( ) + { + Reference< XAccessibleRelationSet > xRelSet; + Reference< XAccessible > xParent; + if ( m_aEntryPath.size() > 1 ) // not a root entry + xParent = implGetParentAccessible(); + if ( xParent.is() ) + { + rtl::Reference pRelationSetHelper = new utl::AccessibleRelationSetHelper; + Sequence< Reference< XInterface > > aSequence { xParent }; + pRelationSetHelper->AddRelation( + AccessibleRelation( AccessibleRelationType::NODE_CHILD_OF, aSequence ) ); + xRelSet = pRelationSetHelper; + } + return xRelSet; + } + + Reference< XAccessibleStateSet > SAL_CALL AccessibleListBoxEntry::getAccessibleStateSet( ) + { + ::osl::MutexGuard aGuard( m_aMutex ); + + rtl::Reference pStateSetHelper = new utl::AccessibleStateSetHelper; + + if ( IsAlive_Impl() ) + { + switch(getAccessibleRole()) + { + case AccessibleRole::LABEL: + pStateSetHelper->AddState( AccessibleStateType::TRANSIENT ); + pStateSetHelper->AddState( AccessibleStateType::SELECTABLE ); + pStateSetHelper->AddState( AccessibleStateType::ENABLED ); + if (m_pTreeListBox->IsInplaceEditingEnabled()) + pStateSetHelper->AddState( AccessibleStateType::EDITABLE ); + if (IsShowing_Impl()) + pStateSetHelper->AddState( AccessibleStateType::SHOWING ); + break; + case AccessibleRole::CHECK_BOX: + pStateSetHelper->AddState( AccessibleStateType::TRANSIENT ); + pStateSetHelper->AddState( AccessibleStateType::SELECTABLE ); + pStateSetHelper->AddState( AccessibleStateType::ENABLED ); + if (IsShowing_Impl()) + pStateSetHelper->AddState( AccessibleStateType::SHOWING ); + break; + } + SvTreeListEntry *pEntry = m_pTreeListBox->GetEntryFromPath(m_aEntryPath); + if (pEntry) + m_pTreeListBox->FillAccessibleEntryStateSet(pEntry, *pStateSetHelper); + } + else + pStateSetHelper->AddState( AccessibleStateType::DEFUNC ); + + return pStateSetHelper; + } + + Locale SAL_CALL AccessibleListBoxEntry::getLocale( ) + { + SolarMutexGuard aSolarGuard; + ::osl::MutexGuard aGuard( m_aMutex ); + + return implGetLocale(); + } + + // XAccessibleComponent + + sal_Bool SAL_CALL AccessibleListBoxEntry::containsPoint( const awt::Point& rPoint ) + { + return tools::Rectangle( Point(), GetBoundingBox().GetSize() ).Contains( VCLPoint( rPoint ) ); + } + + Reference< XAccessible > SAL_CALL AccessibleListBoxEntry::getAccessibleAtPoint( const awt::Point& _aPoint ) + { + SolarMutexGuard aSolarGuard; + ::osl::MutexGuard aGuard( m_aMutex ); + + EnsureIsAlive(); + SvTreeListEntry* pEntry = m_pTreeListBox->GetEntry( VCLPoint( _aPoint ) ); + if ( !pEntry ) + throw RuntimeException("AccessibleListBoxEntry::getAccessibleAtPoint - pEntry cannot be empty!"); + + Reference< XAccessible > xAcc; + uno::Reference xListBox(m_wListBox); + assert(xListBox.is()); + auto pAccEntry = m_rListBox.implGetAccessible(*pEntry); + tools::Rectangle aRect = pAccEntry->GetBoundingBox_Impl(); + if ( aRect.Contains( VCLPoint( _aPoint ) ) ) + xAcc = pAccEntry.get(); + return xAcc; + } + + awt::Rectangle SAL_CALL AccessibleListBoxEntry::getBounds( ) + { + return AWTRectangle( GetBoundingBox() ); + } + + awt::Point SAL_CALL AccessibleListBoxEntry::getLocation( ) + { + return AWTPoint( GetBoundingBox().TopLeft() ); + } + + awt::Point SAL_CALL AccessibleListBoxEntry::getLocationOnScreen( ) + { + return AWTPoint( GetBoundingBoxOnScreen().TopLeft() ); + } + + awt::Size SAL_CALL AccessibleListBoxEntry::getSize( ) + { + return AWTSize( GetBoundingBox().GetSize() ); + } + + void SAL_CALL AccessibleListBoxEntry::grabFocus( ) + { + // do nothing, because no focus for each item + } + + sal_Int32 AccessibleListBoxEntry::getForeground( ) + { + SolarMutexGuard aSolarGuard; + ::osl::MutexGuard aGuard( m_aMutex ); + + sal_Int32 nColor = 0; + Reference< XAccessible > xParent = getAccessibleParent(); + if ( xParent.is() ) + { + Reference< XAccessibleComponent > xParentComp( xParent->getAccessibleContext(), UNO_QUERY ); + if ( xParentComp.is() ) + nColor = xParentComp->getForeground(); + } + + return nColor; + } + + sal_Int32 AccessibleListBoxEntry::getBackground( ) + { + SolarMutexGuard aSolarGuard; + ::osl::MutexGuard aGuard( m_aMutex ); + + sal_Int32 nColor = 0; + Reference< XAccessible > xParent = getAccessibleParent(); + if ( xParent.is() ) + { + Reference< XAccessibleComponent > xParentComp( xParent->getAccessibleContext(), UNO_QUERY ); + if ( xParentComp.is() ) + nColor = xParentComp->getBackground(); + } + + return nColor; + } + + // XAccessibleText + + + awt::Rectangle SAL_CALL AccessibleListBoxEntry::getCharacterBounds( sal_Int32 nIndex ) + { + SolarMutexGuard aSolarGuard; + ::osl::MutexGuard aGuard( m_aMutex ); + + EnsureIsAlive(); + + if ( !implIsValidIndex( nIndex, implGetText().getLength() ) ) + throw IndexOutOfBoundsException(); + + awt::Rectangle aBounds( 0, 0, 0, 0 ); + SvTreeListEntry* pEntry = m_pTreeListBox->GetEntryFromPath( m_aEntryPath ); + if ( pEntry ) + { + vcl::ControlLayoutData aLayoutData; + tools::Rectangle aItemRect = GetBoundingBox(); + m_pTreeListBox->RecordLayoutData( &aLayoutData, aItemRect ); + tools::Rectangle aCharRect = aLayoutData.GetCharacterBounds( nIndex ); + aCharRect.Move( -aItemRect.Left(), -aItemRect.Top() ); + aBounds = AWTRectangle( aCharRect ); + } + + return aBounds; + } + + sal_Int32 SAL_CALL AccessibleListBoxEntry::getIndexAtPoint( const awt::Point& aPoint ) + { + SolarMutexGuard aSolarGuard; + ::osl::MutexGuard aGuard( m_aMutex ); + EnsureIsAlive(); + if(aPoint.X==0 && aPoint.Y==0) return 0; + + sal_Int32 nIndex = -1; + SvTreeListEntry* pEntry = m_pTreeListBox->GetEntryFromPath( m_aEntryPath ); + if ( pEntry ) + { + vcl::ControlLayoutData aLayoutData; + tools::Rectangle aItemRect = GetBoundingBox(); + m_pTreeListBox->RecordLayoutData( &aLayoutData, aItemRect ); + Point aPnt( VCLPoint( aPoint ) ); + aPnt += aItemRect.TopLeft(); + nIndex = aLayoutData.GetIndexForPoint( aPnt ); + } + + return nIndex; + } + + sal_Bool SAL_CALL AccessibleListBoxEntry::copyText( sal_Int32 nStartIndex, sal_Int32 nEndIndex ) + { + SolarMutexGuard aSolarGuard; + ::osl::MutexGuard aGuard( m_aMutex ); + EnsureIsAlive(); + + OUString sText = implGetText(); + if ( ( 0 > nStartIndex ) || ( sText.getLength() <= nStartIndex ) + || ( 0 > nEndIndex ) || ( sText.getLength() <= nEndIndex ) ) + throw IndexOutOfBoundsException(); + + sal_Int32 nLen = nEndIndex - nStartIndex + 1; + ::svt::OStringTransfer::CopyString( sText.copy( nStartIndex, nLen ), m_pTreeListBox ); + + return true; + } + + sal_Bool SAL_CALL AccessibleListBoxEntry::scrollSubstringTo( sal_Int32, sal_Int32, AccessibleScrollType ) + { + return false; + } + + // XAccessibleEventBroadcaster + + void SAL_CALL AccessibleListBoxEntry::addAccessibleEventListener( const Reference< XAccessibleEventListener >& xListener ) + { + if (xListener.is()) + { + ::osl::MutexGuard aGuard( m_aMutex ); + if (!m_nClientId) + m_nClientId = comphelper::AccessibleEventNotifier::registerClient( ); + comphelper::AccessibleEventNotifier::addEventListener( m_nClientId, xListener ); + } + } + + void SAL_CALL AccessibleListBoxEntry::removeAccessibleEventListener( const Reference< XAccessibleEventListener >& xListener ) + { + if (!xListener.is()) + return; + + ::osl::MutexGuard aGuard( m_aMutex ); + + sal_Int32 nListenerCount = comphelper::AccessibleEventNotifier::removeEventListener( m_nClientId, xListener ); + if ( !nListenerCount ) + { + // no listeners anymore + // -> 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 + sal_Int32 nId = m_nClientId; + m_nClientId = 0; + comphelper::AccessibleEventNotifier::revokeClient( nId ); + + } + } + + // XAccessibleAction + + sal_Int32 SAL_CALL AccessibleListBoxEntry::getAccessibleActionCount( ) + { + ::osl::MutexGuard aGuard( m_aMutex ); + + // three actions supported + SvTreeFlags treeFlag = m_pTreeListBox->GetTreeFlags(); + bool bHasButtons = (m_pTreeListBox->GetStyle() & WB_HASBUTTONS)!=0; + if( (treeFlag & SvTreeFlags::CHKBTN) && !bHasButtons) + { + sal_Int16 role = getAccessibleRole(); + if ( role == AccessibleRole::CHECK_BOX ) + return 2; + else if ( role == AccessibleRole::LABEL ) + return 0; + } + else + return ACCESSIBLE_ACTION_COUNT; + return 0; + } + + sal_Bool SAL_CALL AccessibleListBoxEntry::doAccessibleAction( sal_Int32 nIndex ) + { + SolarMutexGuard aSolarGuard; + ::osl::MutexGuard aGuard( m_aMutex ); + + bool bRet = false; + checkActionIndex_Impl( nIndex ); + EnsureIsAlive(); + + SvTreeFlags treeFlag = m_pTreeListBox->GetTreeFlags(); + if( nIndex == 0 && (treeFlag & SvTreeFlags::CHKBTN) ) + { + if(getAccessibleRole() == AccessibleRole::CHECK_BOX) + { + SvTreeListEntry* pEntry = m_pTreeListBox->GetEntryFromPath( m_aEntryPath ); + SvButtonState state = m_pTreeListBox->GetCheckButtonState( pEntry ); + if ( state == SvButtonState::Checked ) + m_pTreeListBox->SetCheckButtonState(pEntry, SvButtonState::Unchecked); + else if (state == SvButtonState::Unchecked) + m_pTreeListBox->SetCheckButtonState(pEntry, SvButtonState::Checked); + } + } + else if( (nIndex == 1 && (treeFlag & SvTreeFlags::CHKBTN) ) || (nIndex == 0) ) + { + SvTreeListEntry* pEntry = m_pTreeListBox->GetEntryFromPath( m_aEntryPath ); + if ( pEntry ) + { + if ( m_pTreeListBox->IsExpanded( pEntry ) ) + m_pTreeListBox->Collapse( pEntry ); + else + m_pTreeListBox->Expand( pEntry ); + bRet = true; + } + } + + return bRet; + } + + OUString SAL_CALL AccessibleListBoxEntry::getAccessibleActionDescription( sal_Int32 nIndex ) + { + SolarMutexGuard aSolarGuard; + ::osl::MutexGuard aGuard( m_aMutex ); + + checkActionIndex_Impl( nIndex ); + EnsureIsAlive(); + + SvTreeListEntry* pEntry = m_pTreeListBox->GetEntryFromPath( m_aEntryPath ); + SvButtonState state = m_pTreeListBox->GetCheckButtonState( pEntry ); + SvTreeFlags treeFlag = m_pTreeListBox->GetTreeFlags(); + if(nIndex == 0 && (treeFlag & SvTreeFlags::CHKBTN)) + { + if(getAccessibleRole() == AccessibleRole::CHECK_BOX) + { + if ( state == SvButtonState::Checked ) + return "UnCheck"; + else if (state == SvButtonState::Unchecked) + return "Check"; + } + else + { + //Sometimes, a List or Tree may have both checkbox and label at the same time + return OUString(); + } + }else if( (nIndex == 1 && (treeFlag & SvTreeFlags::CHKBTN)) || nIndex == 0 ) + { + if( pEntry->HasChildren() || pEntry->HasChildrenOnDemand() ) + return m_pTreeListBox->IsExpanded( pEntry ) ? + AccResId(STR_SVT_ACC_ACTION_COLLAPSE) : + AccResId(STR_SVT_ACC_ACTION_EXPAND); + return OUString(); + + } + throw IndexOutOfBoundsException(); + } + + Reference< XAccessibleKeyBinding > AccessibleListBoxEntry::getAccessibleActionKeyBinding( sal_Int32 nIndex ) + { + ::osl::MutexGuard aGuard( m_aMutex ); + + Reference< XAccessibleKeyBinding > xRet; + checkActionIndex_Impl( nIndex ); + // ... which key? + return xRet; + } + + // XAccessibleSelection + + void SAL_CALL AccessibleListBoxEntry::selectAccessibleChild( sal_Int32 nChildIndex ) + { + SolarMutexGuard aSolarGuard; + ::osl::MutexGuard aGuard( m_aMutex ); + + EnsureIsAlive(); + + SvTreeListEntry* pEntry = GetRealChild(nChildIndex); + if ( !pEntry ) + throw IndexOutOfBoundsException(); + + m_pTreeListBox->Select( pEntry ); + } + + sal_Bool SAL_CALL AccessibleListBoxEntry::isAccessibleChildSelected( sal_Int32 nChildIndex ) + { + SolarMutexGuard aSolarGuard; + ::osl::MutexGuard aGuard( m_aMutex ); + + EnsureIsAlive(); + + SvTreeListEntry* pParent = m_pTreeListBox->GetEntryFromPath( m_aEntryPath ); + SvTreeListEntry* pEntry = m_pTreeListBox->GetEntry( pParent, nChildIndex ); + if ( !pEntry ) + throw IndexOutOfBoundsException(); + + return m_pTreeListBox->IsSelected( pEntry ); + } + + void SAL_CALL AccessibleListBoxEntry::clearAccessibleSelection( ) + { + SolarMutexGuard aSolarGuard; + ::osl::MutexGuard aGuard( m_aMutex ); + + EnsureIsAlive(); + + SvTreeListEntry* pParent = m_pTreeListBox->GetEntryFromPath( m_aEntryPath ); + if ( !pParent ) + throw RuntimeException("AccessibleListBoxEntry::clearAccessibleSelection - pParent cannot be empty!"); + sal_Int32 nCount = m_pTreeListBox->GetLevelChildCount( pParent ); + for ( sal_Int32 i = 0; i < nCount; ++i ) + { + SvTreeListEntry* pEntry = m_pTreeListBox->GetEntry( pParent, i ); + if ( m_pTreeListBox->IsSelected( pEntry ) ) + m_pTreeListBox->Select( pEntry, false ); + } + } + + void SAL_CALL AccessibleListBoxEntry::selectAllAccessibleChildren( ) + { + SolarMutexGuard aSolarGuard; + ::osl::MutexGuard aGuard( m_aMutex ); + + EnsureIsAlive(); + + SvTreeListEntry* pParent = m_pTreeListBox->GetEntryFromPath( m_aEntryPath ); + if ( !pParent ) + throw RuntimeException("AccessibleListBoxEntry::selectAllAccessibleChildren - pParent cannot be empty!"); + sal_Int32 nCount = m_pTreeListBox->GetLevelChildCount( pParent ); + for ( sal_Int32 i = 0; i < nCount; ++i ) + { + SvTreeListEntry* pEntry = m_pTreeListBox->GetEntry( pParent, i ); + if ( !m_pTreeListBox->IsSelected( pEntry ) ) + m_pTreeListBox->Select( pEntry ); + } + } + + sal_Int32 SAL_CALL AccessibleListBoxEntry::getSelectedAccessibleChildCount( ) + { + SolarMutexGuard aSolarGuard; + ::osl::MutexGuard aGuard( m_aMutex ); + + EnsureIsAlive(); + + sal_Int32 i, nSelCount = 0, nCount = 0; + + SvTreeListEntry* pParent = m_pTreeListBox->GetEntryFromPath( m_aEntryPath ); + if ( !pParent ) + throw RuntimeException("AccessibleListBoxEntry::getSelectedAccessibleChildCount - pParent cannot be empty!"); + nCount = m_pTreeListBox->GetLevelChildCount( pParent ); + for ( i = 0; i < nCount; ++i ) + { + SvTreeListEntry* pEntry = m_pTreeListBox->GetEntry( pParent, i ); + if ( m_pTreeListBox->IsSelected( pEntry ) ) + ++nSelCount; + } + + return nSelCount; + } + + Reference< XAccessible > SAL_CALL AccessibleListBoxEntry::getSelectedAccessibleChild( sal_Int32 nSelectedChildIndex ) + { + SolarMutexGuard aSolarGuard; + ::osl::MutexGuard aGuard( m_aMutex ); + + EnsureIsAlive(); + + if ( nSelectedChildIndex < 0 || nSelectedChildIndex >= getSelectedAccessibleChildCount() ) + throw IndexOutOfBoundsException(); + + Reference< XAccessible > xChild; + sal_Int32 i, nSelCount = 0, nCount = 0; + + SvTreeListEntry* pParent = m_pTreeListBox->GetEntryFromPath( m_aEntryPath ); + if ( !pParent ) + throw RuntimeException("AccessibleListBoxEntry::getSelectedAccessibleChild - pParent cannot be empty!"); + nCount = m_pTreeListBox->GetLevelChildCount( pParent ); + for ( i = 0; i < nCount; ++i ) + { + SvTreeListEntry* pEntry = m_pTreeListBox->GetEntry( pParent, i ); + if ( m_pTreeListBox->IsSelected( pEntry ) ) + ++nSelCount; + + if ( nSelCount == ( nSelectedChildIndex + 1 ) ) + { + uno::Reference xListBox(m_wListBox); + assert(xListBox.is()); + xChild = m_rListBox.implGetAccessible(*pEntry).get(); + break; + } + } + + return xChild; + } + + void SAL_CALL AccessibleListBoxEntry::deselectAccessibleChild( sal_Int32 nSelectedChildIndex ) + { + SolarMutexGuard aSolarGuard; + ::osl::MutexGuard aGuard( m_aMutex ); + + EnsureIsAlive(); + + SvTreeListEntry* pParent = m_pTreeListBox->GetEntryFromPath( m_aEntryPath ); + SvTreeListEntry* pEntry = m_pTreeListBox->GetEntry( pParent, nSelectedChildIndex ); + if ( !pEntry ) + throw IndexOutOfBoundsException(); + + m_pTreeListBox->Select( pEntry, false ); + } + sal_Int32 SAL_CALL AccessibleListBoxEntry::getCaretPosition( ) + { + return -1; + } + sal_Bool SAL_CALL AccessibleListBoxEntry::setCaretPosition ( sal_Int32 nIndex ) + { + SolarMutexGuard aSolarGuard; + ::osl::MutexGuard aGuard( m_aMutex ); + EnsureIsAlive(); + + if ( !implIsValidRange( nIndex, nIndex, implGetText().getLength() ) ) + throw IndexOutOfBoundsException(); + + return false; + } + sal_Unicode SAL_CALL AccessibleListBoxEntry::getCharacter( sal_Int32 nIndex ) + { + SolarMutexGuard aSolarGuard; + ::osl::MutexGuard aGuard( m_aMutex ); + EnsureIsAlive(); + return OCommonAccessibleText::implGetCharacter( implGetText(), nIndex ); + } + css::uno::Sequence< css::beans::PropertyValue > SAL_CALL AccessibleListBoxEntry::getCharacterAttributes( sal_Int32 nIndex, const css::uno::Sequence< OUString >& ) + { + SolarMutexGuard aSolarGuard; + ::osl::MutexGuard aGuard( m_aMutex ); + EnsureIsAlive(); + + OUString sText( implGetText() ); + + if ( !implIsValidIndex( nIndex, sText.getLength() ) ) + throw IndexOutOfBoundsException(); + + return css::uno::Sequence< css::beans::PropertyValue >(); + } + sal_Int32 SAL_CALL AccessibleListBoxEntry::getCharacterCount( ) + { + SolarMutexGuard aSolarGuard; + ::osl::MutexGuard aGuard( m_aMutex ); + EnsureIsAlive(); + return implGetText().getLength(); + } + + OUString SAL_CALL AccessibleListBoxEntry::getSelectedText( ) + { + SolarMutexGuard aSolarGuard; + ::osl::MutexGuard aGuard( m_aMutex ); + EnsureIsAlive(); + return OUString(); + } + sal_Int32 SAL_CALL AccessibleListBoxEntry::getSelectionStart( ) + { + SolarMutexGuard aSolarGuard; + ::osl::MutexGuard aGuard( m_aMutex ); + EnsureIsAlive(); + return 0; + } + sal_Int32 SAL_CALL AccessibleListBoxEntry::getSelectionEnd( ) + { + SolarMutexGuard aSolarGuard; + ::osl::MutexGuard aGuard( m_aMutex ); + EnsureIsAlive(); + return 0; + } + sal_Bool SAL_CALL AccessibleListBoxEntry::setSelection( sal_Int32 nStartIndex, sal_Int32 nEndIndex ) + { + SolarMutexGuard aSolarGuard; + ::osl::MutexGuard aGuard( m_aMutex ); + EnsureIsAlive(); + + if ( !implIsValidRange( nStartIndex, nEndIndex, implGetText().getLength() ) ) + throw IndexOutOfBoundsException(); + + return false; + } + OUString SAL_CALL AccessibleListBoxEntry::getText( ) + { + SolarMutexGuard aSolarGuard; + ::osl::MutexGuard aGuard( m_aMutex ); + EnsureIsAlive(); + return implGetText( ); + } + OUString SAL_CALL AccessibleListBoxEntry::getTextRange( sal_Int32 nStartIndex, sal_Int32 nEndIndex ) + { + SolarMutexGuard aSolarGuard; + ::osl::MutexGuard aGuard( m_aMutex ); + EnsureIsAlive(); + return OCommonAccessibleText::implGetTextRange( implGetText(), nStartIndex, nEndIndex ); + } + css::accessibility::TextSegment SAL_CALL AccessibleListBoxEntry::getTextAtIndex( sal_Int32 nIndex, sal_Int16 aTextType ) + { + SolarMutexGuard aSolarGuard; + ::osl::MutexGuard aGuard( m_aMutex ); + EnsureIsAlive(); + return OCommonAccessibleText::getTextAtIndex( nIndex ,aTextType); + } + css::accessibility::TextSegment SAL_CALL AccessibleListBoxEntry::getTextBeforeIndex( sal_Int32 nIndex, sal_Int16 aTextType ) + { + SolarMutexGuard aSolarGuard; + ::osl::MutexGuard aGuard( m_aMutex ); + EnsureIsAlive(); + return OCommonAccessibleText::getTextBeforeIndex( nIndex ,aTextType); + } + css::accessibility::TextSegment SAL_CALL AccessibleListBoxEntry::getTextBehindIndex( sal_Int32 nIndex, sal_Int16 aTextType ) + { + SolarMutexGuard aSolarGuard; + ::osl::MutexGuard aGuard( m_aMutex ); + EnsureIsAlive(); + + return OCommonAccessibleText::getTextBehindIndex( nIndex ,aTextType); + } + + // XAccessibleValue + + + Any AccessibleListBoxEntry::getCurrentValue( ) + { + ::osl::MutexGuard aGuard( m_aMutex ); + Any aValue; + sal_Int32 level = static_cast(m_aEntryPath.size()) - 1; + level = level < 0 ? 0: level; + aValue <<= level; + return aValue; + } + + + sal_Bool AccessibleListBoxEntry::setCurrentValue( const Any& aNumber ) + { + ::osl::MutexGuard aGuard( m_aMutex ); + + + bool bReturn = false; + SvTreeListBox* pBox = m_pTreeListBox; + if(getAccessibleRole() == AccessibleRole::CHECK_BOX) + { + SvTreeListEntry* pEntry = pBox->GetEntryFromPath( m_aEntryPath ); + if ( pEntry ) + { + sal_Int32 nValue(0), nValueMin(0), nValueMax(0); + aNumber >>= nValue; + getMinimumValue() >>= nValueMin; + getMaximumValue() >>= nValueMax; + + if ( nValue < nValueMin ) + nValue = nValueMin; + else if ( nValue > nValueMax ) + nValue = nValueMax; + + pBox->SetCheckButtonState(pEntry, static_cast(nValue) ); + bReturn = true; + } + } + + return bReturn; + } + + + Any AccessibleListBoxEntry::getMaximumValue( ) + { + ::osl::MutexGuard aGuard( m_aMutex ); + + Any aValue; + // SvTreeListBox* pBox = m_pTreeListBox; + switch(getAccessibleRole()) + { + case AccessibleRole::CHECK_BOX: + aValue <<= sal_Int32(1); + break; + case AccessibleRole::LABEL: + default: + break; + } + + return aValue; + } + + + Any AccessibleListBoxEntry::getMinimumValue( ) + { + ::osl::MutexGuard aGuard( m_aMutex ); + + Any aValue; + // SvTreeListBox* pBox = m_pTreeListBox; + switch(getAccessibleRole()) + { + case AccessibleRole::CHECK_BOX: + aValue <<= sal_Int32(0); + break; + case AccessibleRole::LABEL: + default: + break; + } + + return aValue; + } + + Any AccessibleListBoxEntry::getMinimumIncrement( ) + { + ::osl::MutexGuard aGuard( m_aMutex ); + + Any aValue; + switch(getAccessibleRole()) + { + case AccessibleRole::CHECK_BOX: + aValue <<= sal_Int32(1); + break; + case AccessibleRole::LABEL: + default: + break; + } + + return aValue; + } + + SvTreeListEntry* AccessibleListBoxEntry::GetRealChild(sal_Int32 nIndex) + { + SvTreeListEntry* pEntry = nullptr; + SvTreeListEntry* pParent = m_pTreeListBox->GetEntryFromPath( m_aEntryPath ); + if (pParent) + { + pEntry = m_pTreeListBox->GetEntry( pParent, nIndex ); + if ( !pEntry && getAccessibleChildCount() > 0 ) + { + m_pTreeListBox->RequestingChildren(pParent); + pEntry = m_pTreeListBox->GetEntry( pParent, nIndex ); + } + } + return pEntry; + } + +}// namespace accessibility + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ -- cgit v1.2.3