Version 7.6.3.2-android, tag libreoffice-7.6.3.2-android
[LibreOffice.git] / accessibility / source / extended / accessiblelistbox.cxx
blob5561fa232dfcd1a4617cbbff526c3da74ab85be4
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <extended/accessiblelistbox.hxx>
21 #include <extended/accessiblelistboxentry.hxx>
22 #include <vcl/toolkit/treelistbox.hxx>
23 #include <vcl/toolkit/treelistentry.hxx>
24 #include <com/sun/star/accessibility/AccessibleEventId.hpp>
25 #include <com/sun/star/accessibility/AccessibleRole.hpp>
26 #include <com/sun/star/accessibility/AccessibleStateType.hpp>
27 #include <com/sun/star/lang/IndexOutOfBoundsException.hpp>
28 #include <comphelper/accessiblecontexthelper.hxx>
29 #include <cppuhelper/supportsservice.hxx>
32 namespace accessibility
36 // class AccessibleListBox -----------------------------------------------------
38 using namespace ::com::sun::star::accessibility;
39 using namespace ::com::sun::star::uno;
40 using namespace ::com::sun::star::lang;
41 using namespace ::com::sun::star;
44 // Ctor() and Dtor()
46 AccessibleListBox::AccessibleListBox( SvTreeListBox const & _rListBox, const Reference< XAccessible >& _xParent ) :
48 ImplInheritanceHelper( _rListBox.GetWindowPeer() ),
49 m_xParent( _xParent )
53 AccessibleListBox::~AccessibleListBox()
55 if ( isAlive() )
57 // increment ref count to prevent double call of Dtor
58 osl_atomic_increment( &m_refCount );
59 dispose();
63 void AccessibleListBox::ProcessWindowEvent( const VclWindowEvent& rVclWindowEvent )
65 if ( !isAlive() )
66 return;
68 switch ( rVclWindowEvent.GetId() )
70 case VclEventId::CheckboxToggle :
72 if ( !getListBox() || !getListBox()->HasFocus() )
74 return;
76 AccessibleListBoxEntry* pCurOpEntry = GetCurEventEntry(rVclWindowEvent);
77 if(!pCurOpEntry)
79 return ;
81 uno::Any aValue;
82 aValue <<= AccessibleStateType::CHECKED;
84 if ( getListBox()->GetCheckButtonState( pCurOpEntry->GetSvLBoxEntry() ) == SvButtonState::Checked )
86 pCurOpEntry->NotifyAccessibleEvent( AccessibleEventId::STATE_CHANGED, uno::Any(), aValue );
88 else
90 pCurOpEntry->NotifyAccessibleEvent( AccessibleEventId::STATE_CHANGED, aValue,uno::Any() );
92 break;
95 case VclEventId::ListboxSelect :
97 OSL_FAIL("Debug: Treelist shouldn't use VclEventId::ListboxSelect");
98 break;
101 case VclEventId::ListboxTreeSelect:
103 if ( getListBox() && getListBox()->HasFocus() )
105 AccessibleListBoxEntry* pEntry =static_cast< AccessibleListBoxEntry* >(m_xFocusedChild.get());
106 if (pEntry)
108 pEntry->NotifyAccessibleEvent( AccessibleEventId::SELECTION_CHANGED, Any(), Any() );
112 break;
113 case VclEventId::ListboxTreeFocus:
115 VclPtr<SvTreeListBox> pBox = getListBox();
116 if( pBox && pBox->HasFocus() )
118 uno::Any aNewValue;
119 SvTreeListEntry* pEntry = static_cast< SvTreeListEntry* >( rVclWindowEvent.GetData() );
120 if ( pEntry )
122 AccessibleListBoxEntry* pEntryFocus =static_cast< AccessibleListBoxEntry* >(m_xFocusedChild.get());
123 if (pEntryFocus && pEntryFocus->GetSvLBoxEntry() == pEntry)
125 aNewValue <<= m_xFocusedChild;
126 NotifyAccessibleEvent( AccessibleEventId::ACTIVE_DESCENDANT_CHANGED, uno::Any(), aNewValue );
127 return ;
130 uno::Any aOldValue;
131 aOldValue <<= m_xFocusedChild;
133 m_xFocusedChild.set(implGetAccessible(*pEntry));
135 aNewValue <<= m_xFocusedChild;
136 NotifyAccessibleEvent( AccessibleEventId::ACTIVE_DESCENDANT_CHANGED, aOldValue, aNewValue );
138 else
140 aNewValue <<= AccessibleStateType::FOCUSED;
141 NotifyAccessibleEvent( AccessibleEventId::STATE_CHANGED, uno::Any(), aNewValue );
145 break;
146 case VclEventId::ListboxItemRemoved:
148 SvTreeListEntry* pEntry = static_cast< SvTreeListEntry* >( rVclWindowEvent.GetData() );
149 if ( pEntry )
151 RemoveChildEntries(pEntry);
153 else
155 // NULL means Clear()
156 for (auto const& entry : m_mapEntry)
158 uno::Any aNewValue;
159 uno::Any aOldValue;
160 aOldValue <<= uno::Reference<XAccessible>(entry.second);
161 NotifyAccessibleEvent( AccessibleEventId::CHILD, aOldValue, aNewValue );
163 for (auto const& entry : m_mapEntry)
164 { // release references ...
165 entry.second->dispose();
167 m_mapEntry.clear();
170 break;
172 // #i92103#
173 case VclEventId::ItemExpanded :
174 case VclEventId::ItemCollapsed :
176 SvTreeListEntry* pEntry = static_cast< SvTreeListEntry* >( rVclWindowEvent.GetData() );
177 if ( pEntry )
179 Reference<XAccessible> const xChild(implGetAccessible(*pEntry));
180 const short nAccEvent =
181 ( rVclWindowEvent.GetId() == VclEventId::ItemExpanded )
182 ? AccessibleEventId::LISTBOX_ENTRY_EXPANDED
183 : AccessibleEventId::LISTBOX_ENTRY_COLLAPSED;
184 uno::Any aListBoxEntry;
185 aListBoxEntry <<= xChild;
186 NotifyAccessibleEvent( nAccEvent, Any(), aListBoxEntry );
187 if ( getListBox() && getListBox()->HasFocus() )
189 NotifyAccessibleEvent( AccessibleEventId::ACTIVE_DESCENDANT_CHANGED, Any(), aListBoxEntry );
193 break;
194 default:
195 VCLXAccessibleComponent::ProcessWindowEvent (rVclWindowEvent);
199 AccessibleListBoxEntry* AccessibleListBox::GetCurEventEntry( const VclWindowEvent& rVclWindowEvent )
201 SvTreeListEntry* pEntry = static_cast< SvTreeListEntry* >( rVclWindowEvent.GetData() );
202 if ( !pEntry )
203 pEntry = getListBox()->GetCurEntry();
205 AccessibleListBoxEntry* pEntryFocus =static_cast< AccessibleListBoxEntry* >(m_xFocusedChild.get());
206 if (pEntryFocus && pEntry && pEntry != pEntryFocus->GetSvLBoxEntry())
208 AccessibleListBoxEntry *const pAccCurOptionEntry = implGetAccessible(*pEntry).get();
209 uno::Any aNewValue;
210 aNewValue <<= uno::Reference<XAccessible>(pAccCurOptionEntry);
211 NotifyAccessibleEvent( AccessibleEventId::CHILD, uno::Any(), aNewValue );//Add
213 return pAccCurOptionEntry;
215 else
217 return pEntryFocus;
221 void AccessibleListBox::RemoveChildEntries(SvTreeListEntry* pEntry)
223 MAP_ENTRY::iterator mi = m_mapEntry.find(pEntry);
224 if ( mi != m_mapEntry.end() )
226 uno::Any aNewValue;
227 uno::Any aOldValue;
228 aOldValue <<= uno::Reference<XAccessible>(mi->second);
229 NotifyAccessibleEvent( AccessibleEventId::CHILD, aOldValue, aNewValue );
231 m_mapEntry.erase(mi);
234 VclPtr<SvTreeListBox> pBox = getListBox();
235 SvTreeListEntry* pEntryChild = pBox->FirstChild(pEntry);
236 while (pEntryChild)
238 RemoveChildEntries(pEntryChild);
239 pEntryChild = pEntryChild->NextSibling();
244 void AccessibleListBox::ProcessWindowChildEvent( const VclWindowEvent& rVclWindowEvent )
246 switch ( rVclWindowEvent.GetId() )
248 case VclEventId::WindowShow:
249 case VclEventId::WindowHide:
252 break;
253 default:
255 VCLXAccessibleComponent::ProcessWindowChildEvent( rVclWindowEvent );
257 break;
262 // XComponent
264 void SAL_CALL AccessibleListBox::disposing()
266 ::osl::MutexGuard aGuard( m_aMutex );
268 m_mapEntry.clear();
269 VCLXAccessibleComponent::disposing();
270 m_xParent = nullptr;
273 // XServiceInfo
275 OUString SAL_CALL AccessibleListBox::getImplementationName()
277 return "com.sun.star.comp.svtools.AccessibleTreeListBox";
280 Sequence< OUString > SAL_CALL AccessibleListBox::getSupportedServiceNames()
282 return {"com.sun.star.accessibility.AccessibleContext",
283 "com.sun.star.accessibility.AccessibleComponent",
284 "com.sun.star.awt.AccessibleTreeListBox"};
287 sal_Bool SAL_CALL AccessibleListBox::supportsService( const OUString& _rServiceName )
289 return cppu::supportsService(this, _rServiceName);
292 // XAccessible
294 Reference< XAccessibleContext > SAL_CALL AccessibleListBox::getAccessibleContext( )
296 ensureAlive();
297 return this;
300 // XAccessibleContext
302 sal_Int64 SAL_CALL AccessibleListBox::getAccessibleChildCount( )
304 ::comphelper::OExternalLockGuard aGuard( this );
306 sal_Int32 nCount = 0;
307 VclPtr<SvTreeListBox> pSvTreeListBox = getListBox();
308 if ( pSvTreeListBox )
309 nCount = pSvTreeListBox->GetLevelChildCount( nullptr );
311 return nCount;
314 Reference< XAccessible > SAL_CALL AccessibleListBox::getAccessibleChild( sal_Int64 i )
316 ::comphelper::OExternalLockGuard aGuard( this );
318 SvTreeListEntry* pEntry = getListBox()->GetEntry(i);
319 if ( !pEntry )
320 throw IndexOutOfBoundsException();
322 // Solution: Set the parameter of the parent to null to let entry determine the parent by itself
323 //return new AccessibleListBoxEntry( *getListBox(), pEntry, this );
324 //return new AccessibleListBoxEntry( *getListBox(), pEntry, nullptr );
325 return implGetAccessible(*pEntry);
328 Reference< XAccessible > SAL_CALL AccessibleListBox::getAccessibleParent( )
330 ::osl::MutexGuard aGuard( m_aMutex );
332 ensureAlive();
333 return m_xParent;
336 sal_Int32 AccessibleListBox::GetRoleType() const
338 sal_Int32 nCase = 0;
339 SvTreeListEntry* pEntry = getListBox()->GetEntry(0);
340 if ( pEntry )
342 if( pEntry->HasChildrenOnDemand() || getListBox()->GetChildCount(pEntry) > 0 )
344 nCase = 1;
345 return nCase;
349 bool bHasButtons = (getListBox()->GetStyle() & WB_HASBUTTONS)!=0;
350 if( !(getListBox()->GetTreeFlags() & SvTreeFlags::CHKBTN) )
352 if( bHasButtons )
353 nCase = 1;
355 else
357 if( bHasButtons )
358 nCase = 2;
359 else
360 nCase = 3;
362 return nCase;
365 sal_Int16 SAL_CALL AccessibleListBox::getAccessibleRole()
367 ::comphelper::OExternalLockGuard aGuard( this );
369 //o is: return AccessibleRole::TREE;
370 bool bHasButtons = (getListBox()->GetStyle() & WB_HASBUTTONS)!=0;
371 if(!bHasButtons && (getListBox()->GetTreeFlags() & SvTreeFlags::CHKBTN))
372 return AccessibleRole::LIST;
373 else
374 if (GetRoleType() == 0)
375 return AccessibleRole::LIST;
376 else
377 return AccessibleRole::TREE;
380 OUString SAL_CALL AccessibleListBox::getAccessibleDescription( )
382 ::comphelper::OExternalLockGuard aGuard( this );
384 return getListBox()->GetAccessibleDescription();
387 OUString SAL_CALL AccessibleListBox::getAccessibleName( )
389 ::comphelper::OExternalLockGuard aGuard( this );
391 return getListBox()->GetAccessibleName();
394 // XAccessibleSelection
396 void SAL_CALL AccessibleListBox::selectAccessibleChild( sal_Int64 nChildIndex )
398 ::comphelper::OExternalLockGuard aGuard( this );
400 SvTreeListEntry* pEntry = getListBox()->GetEntry( nChildIndex );
401 if ( !pEntry )
402 throw IndexOutOfBoundsException();
404 getListBox()->Select( pEntry );
407 sal_Bool SAL_CALL AccessibleListBox::isAccessibleChildSelected( sal_Int64 nChildIndex )
409 ::comphelper::OExternalLockGuard aGuard( this );
411 if (nChildIndex < 0 || nChildIndex >= getAccessibleChildCount())
412 throw IndexOutOfBoundsException();
414 SvTreeListEntry* pEntry = getListBox()->GetEntry( nChildIndex );
415 if ( !pEntry )
416 throw IndexOutOfBoundsException();
418 return getListBox()->IsSelected( pEntry );
421 void SAL_CALL AccessibleListBox::clearAccessibleSelection( )
423 ::comphelper::OExternalLockGuard aGuard( this );
425 sal_Int32 nCount = getListBox()->GetLevelChildCount( nullptr );
426 for ( sal_Int32 i = 0; i < nCount; ++i )
428 SvTreeListEntry* pEntry = getListBox()->GetEntry( i );
429 if ( getListBox()->IsSelected( pEntry ) )
430 getListBox()->Select( pEntry, false );
434 void SAL_CALL AccessibleListBox::selectAllAccessibleChildren( )
436 ::comphelper::OExternalLockGuard aGuard( this );
438 sal_Int32 nCount = getListBox()->GetLevelChildCount( nullptr );
439 for ( sal_Int32 i = 0; i < nCount; ++i )
441 SvTreeListEntry* pEntry = getListBox()->GetEntry( i );
442 if ( !getListBox()->IsSelected( pEntry ) )
443 getListBox()->Select( pEntry );
447 sal_Int64 SAL_CALL AccessibleListBox::getSelectedAccessibleChildCount( )
449 ::comphelper::OExternalLockGuard aGuard( this );
451 return getListBox()->GetSelectionCount();
454 Reference< XAccessible > SAL_CALL AccessibleListBox::getSelectedAccessibleChild( sal_Int64 nSelectedChildIndex )
456 ::comphelper::OExternalLockGuard aGuard( this );
458 if ( nSelectedChildIndex < 0 || nSelectedChildIndex >= getSelectedAccessibleChildCount() )
459 throw IndexOutOfBoundsException();
461 Reference< XAccessible > xChild;
462 sal_Int64 nSelCount= 0;
463 sal_Int32 nCount = getListBox()->GetLevelChildCount( nullptr );
464 for ( sal_Int32 i = 0; i < nCount; ++i )
466 SvTreeListEntry* pEntry = getListBox()->GetEntry( i );
467 if ( getListBox()->IsSelected( pEntry ) )
468 ++nSelCount;
470 if ( nSelCount == ( nSelectedChildIndex + 1 ) )
472 // Solution: Set the parameter of the parent to null to let entry determine the parent by itself
473 //xChild = new AccessibleListBoxEntry( *getListBox(), pEntry, this );
474 //xChild = new AccessibleListBoxEntry( *getListBox(), pEntry, nullptr );
475 xChild = implGetAccessible(*pEntry).get();
476 break;
480 return xChild;
483 void SAL_CALL AccessibleListBox::deselectAccessibleChild( sal_Int64 nSelectedChildIndex )
485 ::comphelper::OExternalLockGuard aGuard( this );
487 SvTreeListEntry* pEntry = getListBox()->GetEntry( nSelectedChildIndex );
488 if ( !pEntry )
489 throw IndexOutOfBoundsException();
491 getListBox()->Select( pEntry, false );
494 void AccessibleListBox::FillAccessibleStateSet( sal_Int64& rStateSet )
496 VCLXAccessibleComponent::FillAccessibleStateSet( rStateSet );
497 if ( getListBox() && isAlive() )
499 rStateSet |= AccessibleStateType::FOCUSABLE;
500 rStateSet |= AccessibleStateType::MANAGES_DESCENDANTS;
501 if ( getListBox()->GetSelectionMode() == SelectionMode::Multiple )
502 rStateSet |= AccessibleStateType::MULTI_SELECTABLE;
506 rtl::Reference<AccessibleListBoxEntry> AccessibleListBox::implGetAccessible(SvTreeListEntry & rEntry)
508 rtl::Reference<AccessibleListBoxEntry> pAccessible;
509 auto const it = m_mapEntry.find(&rEntry);
510 if (it != m_mapEntry.end())
512 pAccessible = it->second;
514 else
516 pAccessible = new AccessibleListBoxEntry(*getListBox(), rEntry, *this);
517 m_mapEntry.emplace(&rEntry, pAccessible);
519 assert(pAccessible.is());
520 return pAccessible;
523 VclPtr< SvTreeListBox > AccessibleListBox::getListBox() const
525 return GetAs< SvTreeListBox >();
528 }// namespace accessibility
531 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */