diff options
Diffstat (limited to 'accessibility/source/standard/vclxaccessiblelist.cxx')
-rw-r--r-- | accessibility/source/standard/vclxaccessiblelist.cxx | 942 |
1 files changed, 942 insertions, 0 deletions
diff --git a/accessibility/source/standard/vclxaccessiblelist.cxx b/accessibility/source/standard/vclxaccessiblelist.cxx new file mode 100644 index 000000000..e405b30fb --- /dev/null +++ b/accessibility/source/standard/vclxaccessiblelist.cxx @@ -0,0 +1,942 @@ +/* -*- 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 <standard/vclxaccessiblelist.hxx> +#include <standard/vclxaccessiblelistitem.hxx> +#include <helper/listboxhelper.hxx> + +#include <unotools/accessiblerelationsethelper.hxx> +#include <unotools/accessiblestatesethelper.hxx> +#include <com/sun/star/accessibility/AccessibleStateType.hpp> +#include <com/sun/star/accessibility/AccessibleEventId.hpp> +#include <com/sun/star/accessibility/AccessibleRelationType.hpp> +#include <com/sun/star/accessibility/AccessibleRole.hpp> +#include <com/sun/star/lang/IndexOutOfBoundsException.hpp> +#include <o3tl/safeint.hxx> +#include <vcl/svapp.hxx> +#include <vcl/toolkit/combobox.hxx> +#include <vcl/lstbox.hxx> +#include <toolkit/helper/convert.hxx> + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::accessibility; +using namespace ::accessibility; + +namespace +{ + /// @throws css::lang::IndexOutOfBoundsException + void checkSelection_Impl( sal_Int32 _nIndex, const IComboListBoxHelper& _rListBox, bool bSelected ) + { + sal_Int32 nCount = bSelected ? _rListBox.GetSelectedEntryCount() + : _rListBox.GetEntryCount(); + if ( _nIndex < 0 || _nIndex >= nCount ) + throw css::lang::IndexOutOfBoundsException(); + } +} + +VCLXAccessibleList::VCLXAccessibleList (VCLXWindow* pVCLWindow, BoxType aBoxType, + const Reference< XAccessible >& _xParent) + : VCLXAccessibleComponent (pVCLWindow), + m_aBoxType (aBoxType), + m_nVisibleLineCount (0), + m_nIndexInParent (DEFAULT_INDEX_IN_PARENT), + m_nLastTopEntry ( 0 ), + m_nLastSelectedPos ( LISTBOX_ENTRY_NOTFOUND ), + m_bDisableProcessEvent ( false ), + m_bVisible ( true ), + m_nCurSelectedPos ( LISTBOX_ENTRY_NOTFOUND ), + m_xParent ( _xParent ) +{ + // Because combo boxes and list boxes don't have a common interface for + // methods with identical signature we have to write down twice the + // same code. + switch (m_aBoxType) + { + case COMBOBOX: + { + VclPtr< ComboBox > pBox = GetAs< ComboBox >(); + if ( pBox ) + m_pListBoxHelper.reset( new VCLListBoxHelper<ComboBox> (*pBox) ); + break; + } + + case LISTBOX: + { + VclPtr< ListBox > pBox = GetAs< ListBox >(); + if ( pBox ) + m_pListBoxHelper.reset( new VCLListBoxHelper<ListBox> (*pBox) ); + break; + } + } + UpdateVisibleLineCount(); + if(m_pListBoxHelper) + { + m_nCurSelectedPos=m_pListBoxHelper->GetSelectedEntryPos(0); + } + sal_uInt16 nCount = static_cast<sal_uInt16>(getAccessibleChildCount()); + m_aAccessibleChildren.reserve(nCount); +} + + +void VCLXAccessibleList::SetIndexInParent (sal_Int32 nIndex) +{ + m_nIndexInParent = nIndex; +} + + +void SAL_CALL VCLXAccessibleList::disposing() +{ + VCLXAccessibleComponent::disposing(); + + // Dispose all items in the list. + m_aAccessibleChildren.clear(); + + m_pListBoxHelper.reset(); +} + + +void VCLXAccessibleList::FillAccessibleStateSet (utl::AccessibleStateSetHelper& rStateSet) +{ + SolarMutexGuard aSolarGuard; + + VCLXAccessibleComponent::FillAccessibleStateSet( rStateSet ); + // check if our list should be visible + if ( m_pListBoxHelper + && (m_pListBoxHelper->GetStyle() & WB_DROPDOWN ) == WB_DROPDOWN + && !m_pListBoxHelper->IsInDropDown() ) + { + rStateSet.RemoveState (AccessibleStateType::VISIBLE); + rStateSet.RemoveState (AccessibleStateType::SHOWING); + m_bVisible = false; + } + + // Both the combo box and list box are handled identical in the + // following but for some reason they don't have a common interface for + // the methods used. + if ( m_pListBoxHelper ) + { + if ( m_pListBoxHelper->IsMultiSelectionEnabled() ) + rStateSet.AddState( AccessibleStateType::MULTI_SELECTABLE); + rStateSet.AddState (AccessibleStateType::FOCUSABLE); + // All children are transient. + rStateSet.AddState (AccessibleStateType::MANAGES_DESCENDANTS); + } +} + +void VCLXAccessibleList::notifyVisibleStates(bool _bSetNew ) +{ + m_bVisible = _bSetNew; + Any aOldValue, aNewValue; + (_bSetNew ? aNewValue : aOldValue ) <<= AccessibleStateType::VISIBLE; + NotifyAccessibleEvent( AccessibleEventId::STATE_CHANGED, aOldValue, aNewValue ); + (_bSetNew ? aNewValue : aOldValue ) <<= AccessibleStateType::SHOWING; + NotifyAccessibleEvent( AccessibleEventId::STATE_CHANGED, aOldValue, aNewValue ); + + ListItems::iterator aIter = m_aAccessibleChildren.begin(); + UpdateVisibleLineCount(); + // adjust the index inside the VCLXAccessibleListItem + for ( ; aIter != m_aAccessibleChildren.end(); ) + { + Reference< XAccessible > xHold = *aIter; + if (!xHold.is()) + { + aIter = m_aAccessibleChildren.erase(aIter); + } + else + { + VCLXAccessibleListItem* pItem = static_cast<VCLXAccessibleListItem*>(xHold.get()); + const sal_Int32 nTopEntry = m_pListBoxHelper ? m_pListBoxHelper->GetTopEntry() : 0; + const sal_Int32 nPos = static_cast<sal_Int32>(aIter - m_aAccessibleChildren.begin()); + bool bVisible = ( nPos>=nTopEntry && nPos<( nTopEntry + m_nVisibleLineCount ) ); + pItem->SetVisible( m_bVisible && bVisible ); + ++aIter; + } + + } +} + +void VCLXAccessibleList::UpdateSelection_Acc (const OUString& /*sTextOfSelectedItem*/, bool b_IsDropDownList) +{ + if ( m_aBoxType != COMBOBOX ) + return; + + /* FIXME: is there something missing here? nIndex is unused. Looks like + * copy-paste from VCLXAccessibleList::UpdateSelection() */ + // VclPtr< ComboBox > pBox = GetAs< ComboBox >(); + // if ( pBox ) + // { + // // Find the index of the selected item inside the VCL control... + // sal_Int32 nIndex = pBox->GetEntryPos(sTextOfSelectedItem); + // // ...and then find the associated accessibility object. + // if ( nIndex == LISTBOX_ENTRY_NOTFOUND ) + // nIndex = 0; + UpdateSelection_Impl_Acc(b_IsDropDownList); + // } +} + + +void VCLXAccessibleList::UpdateSelection_Impl_Acc(bool bHasDropDownList) +{ + uno::Any aOldValue, aNewValue; + + { + SolarMutexGuard aSolarGuard; + ::osl::Guard< ::osl::Mutex > aGuard( GetMutex() ); + Reference< XAccessible > xNewAcc; + if ( m_pListBoxHelper ) + { + sal_Int32 i=0; + m_nCurSelectedPos = LISTBOX_ENTRY_NOTFOUND; + for ( const auto& rChild : m_aAccessibleChildren ) + { + Reference< XAccessible > xHold = rChild; + if ( xHold.is() ) + { + VCLXAccessibleListItem* pItem = static_cast< VCLXAccessibleListItem* >( xHold.get() ); + // Retrieve the item's index from the list entry. + bool bNowSelected = m_pListBoxHelper->IsEntryPosSelected (i); + if (bNowSelected) + m_nCurSelectedPos = i; + + if ( bNowSelected && !pItem->IsSelected() ) + { + xNewAcc = rChild; + aNewValue <<= xNewAcc; + } + else if ( pItem->IsSelected() ) + m_nLastSelectedPos = i; + + pItem->SetSelected( bNowSelected ); + } + else + { // it could happen that a child was not created before + checkEntrySelected(i,aNewValue,xNewAcc); + } + ++i; + } + const sal_Int32 nCount = m_pListBoxHelper->GetEntryCount(); + if ( i < nCount ) // here we have to check the if any other listbox entry is selected + { + for (; i < nCount && !checkEntrySelected(i,aNewValue,xNewAcc) ;++i ) + ; + } + if ( xNewAcc.is() && GetWindow()->HasFocus() ) + { + if ( m_nLastSelectedPos != LISTBOX_ENTRY_NOTFOUND ) + aOldValue <<= getAccessibleChild( m_nLastSelectedPos ); + aNewValue <<= xNewAcc; + } + } + } + + if (m_aBoxType == COMBOBOX) + { + //VCLXAccessibleDropDownComboBox + //when in list is dropped down, xText = NULL + if (bHasDropDownList && m_pListBoxHelper && m_pListBoxHelper->IsInDropDown()) + { + if ( aNewValue.hasValue() || aOldValue.hasValue() ) + { + NotifyAccessibleEvent( + AccessibleEventId::ACTIVE_DESCENDANT_CHANGED, + aOldValue, + aNewValue ); + + NotifyListItem(aNewValue); + } + } + else + { + //VCLXAccessibleComboBox + NotifyAccessibleEvent( AccessibleEventId::SELECTION_CHANGED, uno::Any(), uno::Any() ); + } + } + else if (m_aBoxType == LISTBOX) + { + if ( aNewValue.hasValue() || aOldValue.hasValue() ) + { + NotifyAccessibleEvent( + AccessibleEventId::ACTIVE_DESCENDANT_CHANGED, + aOldValue, + aNewValue ); + + NotifyListItem(aNewValue); + } + } +} + +void VCLXAccessibleList::NotifyListItem(css::uno::Any const & val) +{ + Reference< XAccessible > xCurItem; + val >>= xCurItem; + if (xCurItem.is()) + { + VCLXAccessibleListItem* pCurItem = static_cast< VCLXAccessibleListItem* >(xCurItem.get()); + if (pCurItem) + { + pCurItem->NotifyAccessibleEvent(AccessibleEventId::SELECTION_CHANGED,Any(),Any()); + } + } +} + +void VCLXAccessibleList::ProcessWindowEvent (const VclWindowEvent& rVclWindowEvent, bool b_IsDropDownList) +{ + switch ( rVclWindowEvent.GetId() ) + { + case VclEventId::DropdownSelect: + case VclEventId::ListboxSelect: + if ( !m_bDisableProcessEvent ) + UpdateSelection_Impl_Acc(b_IsDropDownList); + break; + case VclEventId::WindowGetFocus: + break; + case VclEventId::ControlGetFocus: + { + VCLXAccessibleComponent::ProcessWindowEvent (rVclWindowEvent); + if (m_aBoxType == COMBOBOX && b_IsDropDownList) + { + //VCLXAccessibleDropDownComboBox + } + else if (m_aBoxType == LISTBOX && b_IsDropDownList) + { + } + else if ( m_aBoxType == LISTBOX && !b_IsDropDownList) + { + if ( m_pListBoxHelper ) + { + uno::Any aOldValue, + aNewValue; + sal_Int32 nPos = m_nCurSelectedPos; //m_pListBoxHelper->GetSelectedEntryPos(); + + if ( nPos == LISTBOX_ENTRY_NOTFOUND ) + nPos = m_pListBoxHelper->GetTopEntry(); + if ( nPos != LISTBOX_ENTRY_NOTFOUND ) + aNewValue <<= CreateChild(nPos); + NotifyAccessibleEvent( AccessibleEventId::ACTIVE_DESCENDANT_CHANGED, + aOldValue, + aNewValue ); + } + } + } + break; + default: + break; + } + +} + +void VCLXAccessibleList::ProcessWindowEvent (const VclWindowEvent& rVclWindowEvent) +{ + // Create a reference to this object to prevent an early release of the + // listbox (VclEventId::ObjectDying). + Reference< XAccessible > xHoldAlive = this; + + switch ( rVclWindowEvent.GetId() ) + { + case VclEventId::DropdownOpen: + notifyVisibleStates(true); + break; + case VclEventId::DropdownClose: + notifyVisibleStates(false); + break; + case VclEventId::ListboxScrolled: + UpdateEntryRange_Impl(); + break; + + // The selection events VclEventId::ComboboxSelect and + // VclEventId::ComboboxDeselect are not handled here because here we + // have no access to the edit field. Its text is necessary to + // identify the currently selected item. + + case VclEventId::ObjectDying: + { + dispose(); + + VCLXAccessibleComponent::ProcessWindowEvent (rVclWindowEvent); + break; + } + + case VclEventId::ListboxItemRemoved: + case VclEventId::ComboboxItemRemoved: + case VclEventId::ListboxItemAdded: + case VclEventId::ComboboxItemAdded: + HandleChangedItemList(); + break; + case VclEventId::ControlGetFocus: + { + VCLXAccessibleComponent::ProcessWindowEvent (rVclWindowEvent); + // Added by IBM Symphony Acc team to handle the list item focus when List control get focus + bool b_IsDropDownList = true; + if (m_pListBoxHelper) + b_IsDropDownList = ((m_pListBoxHelper->GetStyle() & WB_DROPDOWN ) == WB_DROPDOWN); + if ( m_aBoxType == LISTBOX && !b_IsDropDownList ) + { + if ( m_pListBoxHelper ) + { + uno::Any aOldValue, + aNewValue; + sal_Int32 nPos = m_nCurSelectedPos; + + if ( nPos == LISTBOX_ENTRY_NOTFOUND ) + nPos = m_pListBoxHelper->GetTopEntry(); + if ( nPos != LISTBOX_ENTRY_NOTFOUND ) + aNewValue <<= CreateChild(nPos); + NotifyAccessibleEvent( AccessibleEventId::ACTIVE_DESCENDANT_CHANGED, + aOldValue, + aNewValue ); + } + } + } + break; + + default: + VCLXAccessibleComponent::ProcessWindowEvent (rVclWindowEvent); + } +} + + void VCLXAccessibleList::FillAccessibleRelationSet( utl::AccessibleRelationSetHelper& rRelationSet ) +{ + VclPtr< ListBox > pBox = GetAs< ListBox >(); + if( m_aBoxType == LISTBOX ) + { + if (m_pListBoxHelper && (m_pListBoxHelper->GetStyle() & WB_DROPDOWN ) != WB_DROPDOWN) + { + uno::Sequence< uno::Reference< uno::XInterface > > aSequence { pBox->GetAccessible() }; + rRelationSet.AddRelation( com::sun::star::accessibility::AccessibleRelation( com::sun::star::accessibility::AccessibleRelationType::MEMBER_OF, aSequence ) ); + } + } + else + { + VCLXAccessibleComponent::FillAccessibleRelationSet(rRelationSet); + } +} + + +/** To find out which item is currently selected and to update the SELECTED + state of the associated accessibility objects accordingly we exploit the + fact that the +*/ +void VCLXAccessibleList::UpdateSelection (const OUString& sTextOfSelectedItem) +{ + if ( m_aBoxType != COMBOBOX ) + return; + + VclPtr< ComboBox > pBox = GetAs< ComboBox >(); + if ( pBox ) + { + // Find the index of the selected item inside the VCL control... + sal_Int32 nIndex = pBox->GetEntryPos(sTextOfSelectedItem); + // ...and then find the associated accessibility object. + if ( nIndex == LISTBOX_ENTRY_NOTFOUND ) + nIndex = 0; + UpdateSelection_Impl(nIndex); + } +} + + +Reference<XAccessible> VCLXAccessibleList::CreateChild (sal_Int32 nPos) +{ + Reference<XAccessible> xChild; + + if ( o3tl::make_unsigned(nPos) >= m_aAccessibleChildren.size() ) + { + m_aAccessibleChildren.resize(nPos + 1); + + // insert into the container + xChild = new VCLXAccessibleListItem(nPos, this); + m_aAccessibleChildren[nPos] = xChild; + } + else + { + xChild = m_aAccessibleChildren[nPos]; + // check if position is empty and can be used else we have to adjust all entries behind this + if (!xChild.is()) + { + xChild = new VCLXAccessibleListItem(nPos, this); + m_aAccessibleChildren[nPos] = xChild; + } + } + + if ( xChild.is() ) + { + // Just add the SELECTED state. + bool bNowSelected = false; + if ( m_pListBoxHelper ) + bNowSelected = m_pListBoxHelper->IsEntryPosSelected(nPos); + if (bNowSelected) + m_nCurSelectedPos = nPos; + VCLXAccessibleListItem* pItem = static_cast< VCLXAccessibleListItem* >(xChild.get()); + pItem->SetSelected( bNowSelected ); + + // Set the child's VISIBLE state. + UpdateVisibleLineCount(); + const sal_Int32 nTopEntry = m_pListBoxHelper ? m_pListBoxHelper->GetTopEntry() : 0; + bool bVisible = ( nPos>=nTopEntry && nPos<( nTopEntry + m_nVisibleLineCount ) ); + pItem->SetVisible( m_bVisible && bVisible ); + } + + return xChild; +} + + +void VCLXAccessibleList::HandleChangedItemList() +{ + m_aAccessibleChildren.clear(); + NotifyAccessibleEvent ( + AccessibleEventId::INVALIDATE_ALL_CHILDREN, + Any(), Any()); +} + + +IMPLEMENT_FORWARD_XINTERFACE2(VCLXAccessibleList, VCLXAccessibleComponent, VCLXAccessibleList_BASE) +IMPLEMENT_FORWARD_XTYPEPROVIDER2(VCLXAccessibleList, VCLXAccessibleComponent, VCLXAccessibleList_BASE) + +// XAccessible + +Reference<XAccessibleContext> SAL_CALL + VCLXAccessibleList::getAccessibleContext() +{ + return this; +} + + +// XAccessibleContext + +sal_Int32 SAL_CALL VCLXAccessibleList::getAccessibleChildCount() +{ + SolarMutexGuard aSolarGuard; + ::osl::Guard< ::osl::Mutex > aGuard( GetMutex() ); + return implGetAccessibleChildCount(); +} + +sal_Int32 VCLXAccessibleList::implGetAccessibleChildCount() +{ + sal_Int32 nCount = 0; + if ( m_pListBoxHelper ) + nCount = m_pListBoxHelper->GetEntryCount(); + + return nCount; +} + +Reference<XAccessible> SAL_CALL VCLXAccessibleList::getAccessibleChild (sal_Int32 i) +{ + SolarMutexGuard aSolarGuard; + ::osl::Guard< ::osl::Mutex > aGuard( GetMutex() ); + + if ( i < 0 || i >= getAccessibleChildCount() ) + throw IndexOutOfBoundsException(); + + Reference< XAccessible > xChild; + // search for the child + if ( i >= static_cast<sal_Int32>(m_aAccessibleChildren.size()) ) + xChild = CreateChild (i); + else + { + xChild = m_aAccessibleChildren[i]; + if ( !xChild.is() ) + xChild = CreateChild (i); + } + OSL_ENSURE( xChild.is(), "VCLXAccessibleList::getAccessibleChild: returning empty child!" ); + return xChild; +} + +Reference< XAccessible > SAL_CALL VCLXAccessibleList::getAccessibleParent( ) +{ + ::osl::Guard< ::osl::Mutex > aGuard( GetMutex() ); + + return m_xParent; +} + +sal_Int32 SAL_CALL VCLXAccessibleList::getAccessibleIndexInParent() +{ + if (m_nIndexInParent != DEFAULT_INDEX_IN_PARENT) + return m_nIndexInParent; + else + return VCLXAccessibleComponent::getAccessibleIndexInParent(); +} + +sal_Int16 SAL_CALL VCLXAccessibleList::getAccessibleRole() +{ + return AccessibleRole::LIST; +} + +// XServiceInfo +OUString VCLXAccessibleList::getImplementationName() +{ + return "com.sun.star.comp.toolkit.AccessibleList"; +} + +Sequence< OUString > VCLXAccessibleList::getSupportedServiceNames() +{ + return comphelper::concatSequences(VCLXAccessibleComponent::getSupportedServiceNames(), + Sequence<OUString>{"com.sun.star.accessibility.AccessibleList"}); +} + +void VCLXAccessibleList::UpdateVisibleLineCount() +{ + if ( m_pListBoxHelper ) + { + if ( (m_pListBoxHelper->GetStyle() & WB_DROPDOWN ) == WB_DROPDOWN ) + m_nVisibleLineCount = m_pListBoxHelper->GetDisplayLineCount(); + else + { + sal_uInt16 nCols = 0, + nLines = 0; + m_pListBoxHelper->GetMaxVisColumnsAndLines (nCols, nLines); + m_nVisibleLineCount = nLines; + } + } +} + +void VCLXAccessibleList::UpdateEntryRange_Impl() +{ + SolarMutexGuard aSolarGuard; + ::osl::Guard< ::osl::Mutex > aGuard( GetMutex() ); + + sal_Int32 nTop = m_nLastTopEntry; + + if ( m_pListBoxHelper ) + nTop = m_pListBoxHelper->GetTopEntry(); + if ( nTop != m_nLastTopEntry ) + { + UpdateVisibleLineCount(); + sal_Int32 nBegin = std::min( m_nLastTopEntry, nTop ); + sal_Int32 nEnd = std::max( m_nLastTopEntry + m_nVisibleLineCount, nTop + m_nVisibleLineCount ); + for (sal_Int32 i = nBegin; (i <= nEnd); ++i) + { + bool bVisible = ( i >= nTop && i < ( nTop + m_nVisibleLineCount ) ); + Reference< XAccessible > xHold; + if ( o3tl::make_unsigned(i) < m_aAccessibleChildren.size() ) + xHold = m_aAccessibleChildren[i]; + else if ( bVisible ) + xHold = CreateChild(i); + + if ( xHold.is() ) + static_cast< VCLXAccessibleListItem* >( xHold.get() )->SetVisible( m_bVisible && bVisible ); + } + } + + m_nLastTopEntry = nTop; +} + +bool VCLXAccessibleList::checkEntrySelected(sal_Int32 _nPos,Any& _rNewValue,Reference< XAccessible >& _rxNewAcc) +{ + OSL_ENSURE(m_pListBoxHelper,"Helper is not valid!"); + bool bNowSelected = false; + if ( m_pListBoxHelper ) + { + bNowSelected = m_pListBoxHelper->IsEntryPosSelected (_nPos); + if ( bNowSelected ) + { + _rxNewAcc = CreateChild(_nPos); + _rNewValue <<= _rxNewAcc; + } + } + return bNowSelected; +} + + +void VCLXAccessibleList::UpdateSelection_Impl(sal_Int32) +{ + uno::Any aOldValue, aNewValue; + + { + SolarMutexGuard aSolarGuard; + ::osl::Guard< ::osl::Mutex > aGuard( GetMutex() ); + Reference< XAccessible > xNewAcc; + + if ( m_pListBoxHelper ) + { + sal_Int32 i=0; + m_nCurSelectedPos = LISTBOX_ENTRY_NOTFOUND; + for ( const auto& rChild : m_aAccessibleChildren ) + { + Reference< XAccessible > xHold = rChild; + if ( xHold.is() ) + { + VCLXAccessibleListItem* pItem = static_cast< VCLXAccessibleListItem* >( xHold.get() ); + // Retrieve the item's index from the list entry. + bool bNowSelected = m_pListBoxHelper->IsEntryPosSelected (i); + if (bNowSelected) + m_nCurSelectedPos = i; + + if ( bNowSelected && !pItem->IsSelected() ) + { + xNewAcc = rChild; + aNewValue <<= xNewAcc; + } + else if ( pItem->IsSelected() ) + m_nLastSelectedPos = i; + + pItem->SetSelected( bNowSelected ); + } + else + { // it could happen that a child was not created before + checkEntrySelected(i,aNewValue,xNewAcc); + } + ++i; + } + const sal_Int32 nCount = m_pListBoxHelper->GetEntryCount(); + if ( i < nCount ) // here we have to check the if any other listbox entry is selected + { + for (; i < nCount && !checkEntrySelected(i,aNewValue,xNewAcc) ;++i ) + ; + } + if ( xNewAcc.is() && GetWindow()->HasFocus() ) + { + if ( m_nLastSelectedPos != LISTBOX_ENTRY_NOTFOUND ) + aOldValue <<= getAccessibleChild( m_nLastSelectedPos ); + aNewValue <<= xNewAcc; + } + if (m_pListBoxHelper->IsInDropDown()) + { + if ( aNewValue.hasValue() || aOldValue.hasValue() ) + NotifyAccessibleEvent( + AccessibleEventId::ACTIVE_DESCENDANT_CHANGED, + aOldValue, + aNewValue ); + //the SELECTION_CHANGED is not necessary + //NotifyAccessibleEvent( AccessibleEventId::SELECTION_CHANGED, Any(), Any() ); + } + } + } +} + + +// XAccessibleSelection + +void SAL_CALL VCLXAccessibleList::selectAccessibleChild( sal_Int32 nChildIndex ) +{ + bool bNotify = false; + + { + SolarMutexGuard aSolarGuard; + ::osl::Guard< ::osl::Mutex > aGuard( GetMutex() ); + + if ( m_pListBoxHelper ) + { + checkSelection_Impl(nChildIndex,*m_pListBoxHelper,false); + + m_pListBoxHelper->SelectEntryPos( static_cast<sal_uInt16>(nChildIndex) ); + // call the select handler, don't handle events in this time + m_bDisableProcessEvent = true; + m_pListBoxHelper->Select(); + m_bDisableProcessEvent = false; + bNotify = true; + } + } + + if ( bNotify ) + UpdateSelection_Impl(); +} + +sal_Bool SAL_CALL VCLXAccessibleList::isAccessibleChildSelected( sal_Int32 nChildIndex ) +{ + SolarMutexGuard aSolarGuard; + ::osl::Guard< ::osl::Mutex > aGuard( GetMutex() ); + + bool bRet = false; + if ( m_pListBoxHelper ) + { + checkSelection_Impl(nChildIndex,*m_pListBoxHelper,false); + + bRet = m_pListBoxHelper->IsEntryPosSelected( static_cast<sal_uInt16>(nChildIndex) ); + } + return bRet; +} + +void SAL_CALL VCLXAccessibleList::clearAccessibleSelection( ) +{ + bool bNotify = false; + + { + SolarMutexGuard aSolarGuard; + ::osl::Guard< ::osl::Mutex > aGuard( GetMutex() ); + + if ( m_pListBoxHelper ) + { + m_pListBoxHelper->SetNoSelection(); + bNotify = true; + } + } + + if ( bNotify ) + UpdateSelection_Impl(); +} + +void SAL_CALL VCLXAccessibleList::selectAllAccessibleChildren( ) +{ + bool bNotify = false; + + { + SolarMutexGuard aSolarGuard; + ::osl::Guard< ::osl::Mutex > aGuard( GetMutex() ); + + if ( m_pListBoxHelper ) + { + const sal_Int32 nCount = m_pListBoxHelper->GetEntryCount(); + for ( sal_Int32 i = 0; i < nCount; ++i ) + m_pListBoxHelper->SelectEntryPos( i ); + // call the select handler, don't handle events in this time + m_bDisableProcessEvent = true; + m_pListBoxHelper->Select(); + m_bDisableProcessEvent = false; + bNotify = true; + } + } + + if ( bNotify ) + UpdateSelection_Impl(); +} + +sal_Int32 SAL_CALL VCLXAccessibleList::getSelectedAccessibleChildCount( ) +{ + SolarMutexGuard aSolarGuard; + ::osl::Guard< ::osl::Mutex > aGuard( GetMutex() ); + + sal_Int32 nCount = 0; + if ( m_pListBoxHelper ) + nCount = m_pListBoxHelper->GetSelectedEntryCount(); + return nCount; +} + +Reference< XAccessible > SAL_CALL VCLXAccessibleList::getSelectedAccessibleChild( sal_Int32 nSelectedChildIndex ) +{ + SolarMutexGuard aSolarGuard; + ::osl::Guard< ::osl::Mutex > aGuard( GetMutex() ); + + if ( m_pListBoxHelper ) + { + checkSelection_Impl(nSelectedChildIndex,*m_pListBoxHelper,true); + return getAccessibleChild( m_pListBoxHelper->GetSelectedEntryPos( static_cast<sal_uInt16>(nSelectedChildIndex) ) ); + } + + return nullptr; +} + +void SAL_CALL VCLXAccessibleList::deselectAccessibleChild( sal_Int32 nSelectedChildIndex ) +{ + bool bNotify = false; + + { + SolarMutexGuard aSolarGuard; + ::osl::Guard< ::osl::Mutex > aGuard( GetMutex() ); + + if ( m_pListBoxHelper ) + { + checkSelection_Impl(nSelectedChildIndex,*m_pListBoxHelper,false); + + m_pListBoxHelper->SelectEntryPos( static_cast<sal_uInt16>(nSelectedChildIndex), false ); + // call the select handler, don't handle events in this time + m_bDisableProcessEvent = true; + m_pListBoxHelper->Select(); + m_bDisableProcessEvent = false; + bNotify = true; + } + } + + if ( bNotify ) + UpdateSelection_Impl(); +} + +awt::Rectangle VCLXAccessibleList::implGetBounds() +{ + awt::Rectangle aBounds ( 0, 0, 0, 0 ); + if ( m_pListBoxHelper + && (m_pListBoxHelper->GetStyle() & WB_DROPDOWN ) == WB_DROPDOWN ) + { + if ( m_pListBoxHelper->IsInDropDown() ) + aBounds = AWTRectangle(m_pListBoxHelper->GetDropDownPosSizePixel()); + } + else + { + // a list has the same bounds as his parent but starts at (0,0) + aBounds = VCLXAccessibleComponent::implGetBounds(); + aBounds.X = 0; + aBounds.Y = 0; + if ( m_aBoxType == COMBOBOX ) + { + VclPtr< ComboBox > pBox = GetAs< ComboBox >(); + if ( pBox ) + { + Size aSize = pBox->GetSubEdit()->GetSizePixel(); + aBounds.Y += aSize.Height(); + aBounds.Height -= aSize.Height(); + } + } + } + return aBounds; +} + + +awt::Point VCLXAccessibleList::getLocationOnScreen( ) +{ + SolarMutexGuard aSolarGuard; + ::osl::Guard< ::osl::Mutex > aGuard( GetMutex() ); + + awt::Point aPos; + if ( m_pListBoxHelper + && (m_pListBoxHelper->GetStyle() & WB_DROPDOWN ) == WB_DROPDOWN ) + { + if ( m_pListBoxHelper->IsInDropDown() ) + aPos = AWTPoint(m_pListBoxHelper->GetDropDownPosSizePixel().TopLeft()); + } + else + { + aPos = VCLXAccessibleComponent::getLocationOnScreen(); + if ( m_aBoxType == COMBOBOX ) + { + VclPtr< ComboBox > pBox = GetAs< ComboBox >(); + if ( pBox ) + { + aPos.Y += pBox->GetSubEdit()->GetSizePixel().Height(); + } + } + } + return aPos; +} + + +bool VCLXAccessibleList::IsInDropDown() const +{ + return m_pListBoxHelper->IsInDropDown(); +} + + +void VCLXAccessibleList::HandleDropOpen() +{ + if ( !m_bDisableProcessEvent ) + UpdateSelection_Impl(); + if (m_nCurSelectedPos != LISTBOX_ENTRY_NOTFOUND && + m_nLastSelectedPos != LISTBOX_ENTRY_NOTFOUND) + { + Reference< XAccessible > xChild = getAccessibleChild(m_nCurSelectedPos); + if(xChild.is()) + { + uno::Any aNewValue; + aNewValue <<= xChild; + NotifyAccessibleEvent(AccessibleEventId::ACTIVE_DESCENDANT_CHANGED, uno::Any(), aNewValue ); + } + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |