tdf#130857 qt weld: Implement QtInstanceWidget::strip_mnemonic
[LibreOffice.git] / accessibility / source / extended / accessiblelistbox.cxx
blob1b8535af1df5d70c5c6d216df8842f68d521d9d4
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>
31 namespace accessibility
35 // class AccessibleListBox -----------------------------------------------------
37 using namespace ::com::sun::star::accessibility;
38 using namespace ::com::sun::star::uno;
39 using namespace ::com::sun::star::lang;
40 using namespace ::com::sun::star;
43 // Ctor() and Dtor()
45 AccessibleListBox::AccessibleListBox(SvTreeListBox& _rListBox, const Reference< XAccessible >& _xParent)
46 : ImplInheritanceHelper(&_rListBox),
47 m_xParent( _xParent )
51 AccessibleListBox::~AccessibleListBox()
53 if ( isAlive() )
55 // increment ref count to prevent double call of Dtor
56 osl_atomic_increment( &m_refCount );
57 dispose();
61 void AccessibleListBox::ProcessWindowEvent( const VclWindowEvent& rVclWindowEvent )
63 if ( !isAlive() )
64 return;
66 switch ( rVclWindowEvent.GetId() )
68 case VclEventId::CheckboxToggle :
70 if ( !getListBox() || !getListBox()->HasFocus() )
72 return;
74 AccessibleListBoxEntry* pCurOpEntry = GetCurEventEntry(rVclWindowEvent);
75 if(!pCurOpEntry)
77 return ;
79 uno::Any aValue;
80 aValue <<= AccessibleStateType::CHECKED;
82 if ( getListBox()->GetCheckButtonState( pCurOpEntry->GetSvLBoxEntry() ) == SvButtonState::Checked )
84 pCurOpEntry->NotifyAccessibleEvent( AccessibleEventId::STATE_CHANGED, uno::Any(), aValue );
86 else
88 pCurOpEntry->NotifyAccessibleEvent( AccessibleEventId::STATE_CHANGED, aValue,uno::Any() );
90 break;
93 case VclEventId::ListboxSelect :
95 OSL_FAIL("Debug: Treelist shouldn't use VclEventId::ListboxSelect");
96 break;
99 case VclEventId::ListboxTreeSelect:
101 if ( getListBox() && getListBox()->HasFocus() )
103 if (m_xFocusedEntry.is())
105 m_xFocusedEntry->NotifyAccessibleEvent(AccessibleEventId::SELECTION_CHANGED, Any(), Any());
109 break;
110 case VclEventId::ListboxTreeFocus:
112 VclPtr<SvTreeListBox> pBox = getListBox();
113 if( pBox && pBox->HasFocus() )
115 uno::Any aNewValue;
116 SvTreeListEntry* pEntry = static_cast< SvTreeListEntry* >( rVclWindowEvent.GetData() );
117 if ( pEntry )
119 if (m_xFocusedEntry.is() && m_xFocusedEntry->GetSvLBoxEntry() == pEntry)
121 aNewValue <<= uno::Reference<XAccessible>(m_xFocusedEntry);;
122 NotifyAccessibleEvent( AccessibleEventId::ACTIVE_DESCENDANT_CHANGED, uno::Any(), aNewValue );
123 return ;
125 uno::Any aOldValue;
126 aOldValue <<= uno::Reference<XAccessible>(m_xFocusedEntry);;
128 m_xFocusedEntry = implGetAccessible(*pEntry);
130 aNewValue <<= uno::Reference<XAccessible>(m_xFocusedEntry);
131 NotifyAccessibleEvent( AccessibleEventId::ACTIVE_DESCENDANT_CHANGED, aOldValue, aNewValue );
133 else
135 aNewValue <<= AccessibleStateType::FOCUSED;
136 NotifyAccessibleEvent( AccessibleEventId::STATE_CHANGED, uno::Any(), aNewValue );
140 break;
141 case VclEventId::ListboxItemRemoved:
143 SvTreeListEntry* pEntry = static_cast< SvTreeListEntry* >( rVclWindowEvent.GetData() );
144 if ( pEntry )
146 RemoveChildEntries(pEntry);
148 else
150 // NULL means Clear()
151 for (auto const& entry : m_mapEntry)
153 uno::Any aNewValue;
154 uno::Any aOldValue;
155 aOldValue <<= uno::Reference<XAccessible>(entry.second);
156 NotifyAccessibleEvent( AccessibleEventId::CHILD, aOldValue, aNewValue );
158 for (auto const& entry : m_mapEntry)
159 { // release references ...
160 entry.second->dispose();
162 m_mapEntry.clear();
165 break;
167 // #i92103#
168 case VclEventId::ItemExpanded :
169 case VclEventId::ItemCollapsed :
171 SvTreeListEntry* pEntry = static_cast< SvTreeListEntry* >( rVclWindowEvent.GetData() );
172 if ( pEntry )
174 Reference<XAccessible> const xChild(implGetAccessible(*pEntry));
175 const short nAccEvent =
176 ( rVclWindowEvent.GetId() == VclEventId::ItemExpanded )
177 ? AccessibleEventId::LISTBOX_ENTRY_EXPANDED
178 : AccessibleEventId::LISTBOX_ENTRY_COLLAPSED;
179 uno::Any aListBoxEntry;
180 aListBoxEntry <<= xChild;
181 NotifyAccessibleEvent( nAccEvent, Any(), aListBoxEntry );
182 if ( getListBox() && getListBox()->HasFocus() )
184 NotifyAccessibleEvent( AccessibleEventId::ACTIVE_DESCENDANT_CHANGED, Any(), aListBoxEntry );
188 break;
189 default:
190 VCLXAccessibleComponent::ProcessWindowEvent (rVclWindowEvent);
194 AccessibleListBoxEntry* AccessibleListBox::GetCurEventEntry( const VclWindowEvent& rVclWindowEvent )
196 SvTreeListEntry* pEntry = static_cast< SvTreeListEntry* >( rVclWindowEvent.GetData() );
197 if ( !pEntry )
198 pEntry = getListBox()->GetCurEntry();
200 if (m_xFocusedEntry.is() && pEntry && pEntry != m_xFocusedEntry->GetSvLBoxEntry())
202 AccessibleListBoxEntry *const pAccCurOptionEntry = implGetAccessible(*pEntry).get();
203 uno::Any aNewValue;
204 aNewValue <<= uno::Reference<XAccessible>(pAccCurOptionEntry);
205 NotifyAccessibleEvent( AccessibleEventId::CHILD, uno::Any(), aNewValue );//Add
207 return pAccCurOptionEntry;
209 else
211 return m_xFocusedEntry.get();
215 void AccessibleListBox::RemoveChildEntries(SvTreeListEntry* pEntry)
217 MAP_ENTRY::iterator mi = m_mapEntry.find(pEntry);
218 if ( mi != m_mapEntry.end() )
220 uno::Any aNewValue;
221 uno::Any aOldValue;
222 aOldValue <<= uno::Reference<XAccessible>(mi->second);
223 NotifyAccessibleEvent( AccessibleEventId::CHILD, aOldValue, aNewValue );
225 m_mapEntry.erase(mi);
228 VclPtr<SvTreeListBox> pBox = getListBox();
229 SvTreeListEntry* pEntryChild = pBox->FirstChild(pEntry);
230 while (pEntryChild)
232 RemoveChildEntries(pEntryChild);
233 pEntryChild = pEntryChild->NextSibling();
237 // XComponent
239 void SAL_CALL AccessibleListBox::disposing()
241 ::osl::MutexGuard aGuard( m_aMutex );
243 m_mapEntry.clear();
244 VCLXAccessibleComponent::disposing();
245 m_xParent = nullptr;
248 // XServiceInfo
250 OUString SAL_CALL AccessibleListBox::getImplementationName()
252 return u"com.sun.star.comp.svtools.AccessibleTreeListBox"_ustr;
255 Sequence< OUString > SAL_CALL AccessibleListBox::getSupportedServiceNames()
257 return {u"com.sun.star.accessibility.AccessibleContext"_ustr,
258 u"com.sun.star.accessibility.AccessibleComponent"_ustr,
259 u"com.sun.star.awt.AccessibleTreeListBox"_ustr};
262 // XAccessible
264 Reference< XAccessibleContext > SAL_CALL AccessibleListBox::getAccessibleContext( )
266 ensureAlive();
267 return this;
270 // XAccessibleContext
272 sal_Int64 SAL_CALL AccessibleListBox::getAccessibleChildCount( )
274 ::comphelper::OExternalLockGuard aGuard( this );
276 sal_Int32 nCount = 0;
277 VclPtr<SvTreeListBox> pSvTreeListBox = getListBox();
278 if ( pSvTreeListBox )
279 nCount = pSvTreeListBox->GetLevelChildCount( nullptr );
281 return nCount;
284 Reference< XAccessible > SAL_CALL AccessibleListBox::getAccessibleChild( sal_Int64 i )
286 ::comphelper::OExternalLockGuard aGuard( this );
288 SvTreeListEntry* pEntry = getListBox()->GetEntry(i);
289 if ( !pEntry )
290 throw IndexOutOfBoundsException();
292 // Solution: Set the parameter of the parent to null to let entry determine the parent by itself
293 //return new AccessibleListBoxEntry( *getListBox(), pEntry, this );
294 //return new AccessibleListBoxEntry( *getListBox(), pEntry, nullptr );
295 return implGetAccessible(*pEntry);
298 Reference< XAccessible > SAL_CALL AccessibleListBox::getAccessibleParent( )
300 ::osl::MutexGuard aGuard( m_aMutex );
302 ensureAlive();
303 return m_xParent;
306 sal_Int32 AccessibleListBox::GetRoleType() const
308 sal_Int32 nCase = 0;
309 SvTreeListEntry* pEntry = getListBox()->GetEntry(0);
310 if ( pEntry )
312 if( pEntry->HasChildrenOnDemand() || getListBox()->GetChildCount(pEntry) > 0 )
314 nCase = 1;
315 return nCase;
319 bool bHasButtons = (getListBox()->GetStyle() & WB_HASBUTTONS)!=0;
320 if( !(getListBox()->GetTreeFlags() & SvTreeFlags::CHKBTN) )
322 if( bHasButtons )
323 nCase = 1;
325 else
327 if( bHasButtons )
328 nCase = 2;
329 else
330 nCase = 3;
332 return nCase;
335 sal_Int16 SAL_CALL AccessibleListBox::getAccessibleRole()
337 ::comphelper::OExternalLockGuard aGuard( this );
339 VclPtr<SvTreeListBox> pListBox = getListBox();
340 if (!pListBox)
341 return AccessibleRole::LIST;
343 //o is: return AccessibleRole::TREE;
344 bool bHasButtons = (pListBox->GetStyle() & WB_HASBUTTONS) != 0;
345 if (!bHasButtons && (pListBox->GetTreeFlags() & SvTreeFlags::CHKBTN))
346 return AccessibleRole::LIST;
347 else
348 if (GetRoleType() == 0)
349 return AccessibleRole::LIST;
350 else
351 return AccessibleRole::TREE;
354 OUString SAL_CALL AccessibleListBox::getAccessibleDescription( )
356 ::comphelper::OExternalLockGuard aGuard( this );
358 return getListBox()->GetAccessibleDescription();
361 OUString SAL_CALL AccessibleListBox::getAccessibleName( )
363 ::comphelper::OExternalLockGuard aGuard( this );
365 return getListBox()->GetAccessibleName();
368 // XAccessibleSelection
370 void SAL_CALL AccessibleListBox::selectAccessibleChild( sal_Int64 nChildIndex )
372 ::comphelper::OExternalLockGuard aGuard( this );
374 SvTreeListEntry* pEntry = getListBox()->GetEntry( nChildIndex );
375 if ( !pEntry )
376 throw IndexOutOfBoundsException();
378 getListBox()->Select( pEntry );
381 sal_Bool SAL_CALL AccessibleListBox::isAccessibleChildSelected( sal_Int64 nChildIndex )
383 ::comphelper::OExternalLockGuard aGuard( this );
385 if (nChildIndex < 0 || nChildIndex >= getAccessibleChildCount())
386 throw IndexOutOfBoundsException();
388 SvTreeListEntry* pEntry = getListBox()->GetEntry( nChildIndex );
389 if ( !pEntry )
390 throw IndexOutOfBoundsException();
392 return getListBox()->IsSelected( pEntry );
395 void SAL_CALL AccessibleListBox::clearAccessibleSelection( )
397 ::comphelper::OExternalLockGuard aGuard( this );
399 sal_Int32 nCount = getListBox()->GetLevelChildCount( nullptr );
400 for ( sal_Int32 i = 0; i < nCount; ++i )
402 SvTreeListEntry* pEntry = getListBox()->GetEntry( i );
403 if ( getListBox()->IsSelected( pEntry ) )
404 getListBox()->Select( pEntry, false );
408 void SAL_CALL AccessibleListBox::selectAllAccessibleChildren( )
410 ::comphelper::OExternalLockGuard aGuard( this );
412 sal_Int32 nCount = getListBox()->GetLevelChildCount( nullptr );
413 for ( sal_Int32 i = 0; i < nCount; ++i )
415 SvTreeListEntry* pEntry = getListBox()->GetEntry( i );
416 if ( !getListBox()->IsSelected( pEntry ) )
417 getListBox()->Select( pEntry );
421 sal_Int64 SAL_CALL AccessibleListBox::getSelectedAccessibleChildCount( )
423 ::comphelper::OExternalLockGuard aGuard( this );
425 return getListBox()->GetSelectionCount();
428 Reference< XAccessible > SAL_CALL AccessibleListBox::getSelectedAccessibleChild( sal_Int64 nSelectedChildIndex )
430 ::comphelper::OExternalLockGuard aGuard( this );
432 if ( nSelectedChildIndex < 0 || nSelectedChildIndex >= getSelectedAccessibleChildCount() )
433 throw IndexOutOfBoundsException();
435 Reference< XAccessible > xChild;
436 sal_Int64 nSelCount= 0;
437 sal_Int32 nCount = getListBox()->GetLevelChildCount( nullptr );
438 for ( sal_Int32 i = 0; i < nCount; ++i )
440 SvTreeListEntry* pEntry = getListBox()->GetEntry( i );
441 if ( getListBox()->IsSelected( pEntry ) )
442 ++nSelCount;
444 if ( nSelCount == ( nSelectedChildIndex + 1 ) )
446 // Solution: Set the parameter of the parent to null to let entry determine the parent by itself
447 //xChild = new AccessibleListBoxEntry( *getListBox(), pEntry, this );
448 //xChild = new AccessibleListBoxEntry( *getListBox(), pEntry, nullptr );
449 xChild = implGetAccessible(*pEntry).get();
450 break;
454 return xChild;
457 void SAL_CALL AccessibleListBox::deselectAccessibleChild( sal_Int64 nSelectedChildIndex )
459 ::comphelper::OExternalLockGuard aGuard( this );
461 SvTreeListEntry* pEntry = getListBox()->GetEntry( nSelectedChildIndex );
462 if ( !pEntry )
463 throw IndexOutOfBoundsException();
465 getListBox()->Select( pEntry, false );
468 void AccessibleListBox::FillAccessibleStateSet( sal_Int64& rStateSet )
470 VCLXAccessibleComponent::FillAccessibleStateSet( rStateSet );
471 if ( getListBox() && isAlive() )
473 rStateSet |= AccessibleStateType::FOCUSABLE;
474 rStateSet |= AccessibleStateType::MANAGES_DESCENDANTS;
475 if ( getListBox()->GetSelectionMode() == SelectionMode::Multiple )
476 rStateSet |= AccessibleStateType::MULTI_SELECTABLE;
480 rtl::Reference<AccessibleListBoxEntry> AccessibleListBox::implGetAccessible(SvTreeListEntry & rEntry)
482 rtl::Reference<AccessibleListBoxEntry> pAccessible;
483 auto const it = m_mapEntry.find(&rEntry);
484 if (it != m_mapEntry.end())
486 pAccessible = it->second;
488 else
490 pAccessible = new AccessibleListBoxEntry(*getListBox(), rEntry, *this);
491 m_mapEntry.emplace(&rEntry, pAccessible);
493 assert(pAccessible.is());
494 return pAccessible;
497 VclPtr< SvTreeListBox > AccessibleListBox::getListBox() const
499 return GetAs< SvTreeListBox >();
502 }// namespace accessibility
505 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */