lok: vcl: fix multiple floatwin removal case more robustly.
[LibreOffice.git] / accessibility / source / extended / accessiblelistbox.cxx
blob63f7ff87ac10c374a2d05aee21da46e131e6685f
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/treelistbox.hxx>
23 #include <vcl/treelistentry.hxx>
24 #include <com/sun/star/awt/Point.hpp>
25 #include <com/sun/star/awt/Rectangle.hpp>
26 #include <com/sun/star/awt/Size.hpp>
27 #include <com/sun/star/accessibility/AccessibleEventId.hpp>
28 #include <com/sun/star/accessibility/AccessibleRole.hpp>
29 #include <com/sun/star/accessibility/AccessibleStateType.hpp>
30 #include <com/sun/star/lang/IndexOutOfBoundsException.hpp>
31 #include <cppuhelper/supportsservice.hxx>
32 #include <vcl/svapp.hxx>
33 #include <toolkit/awt/vclxwindow.hxx>
34 #include <toolkit/helper/convert.hxx>
35 #include <unotools/accessiblestatesethelper.hxx>
38 namespace accessibility
42 // class AccessibleListBox -----------------------------------------------------
44 using namespace ::com::sun::star::accessibility;
45 using namespace ::com::sun::star::uno;
46 using namespace ::com::sun::star::lang;
47 using namespace ::com::sun::star;
50 // Ctor() and Dtor()
52 AccessibleListBox::AccessibleListBox( SvTreeListBox const & _rListBox, const Reference< XAccessible >& _xParent ) :
54 VCLXAccessibleComponent( _rListBox.GetWindowPeer() ),
55 m_xParent( _xParent )
59 AccessibleListBox::~AccessibleListBox()
61 if ( isAlive() )
63 // increment ref count to prevent double call of Dtor
64 osl_atomic_increment( &m_refCount );
65 dispose();
68 IMPLEMENT_FORWARD_XINTERFACE2(AccessibleListBox, VCLXAccessibleComponent, ImplHelper2)
69 IMPLEMENT_FORWARD_XTYPEPROVIDER2(AccessibleListBox, VCLXAccessibleComponent, ImplHelper2)
71 void AccessibleListBox::ProcessWindowEvent( const VclWindowEvent& rVclWindowEvent )
73 if ( isAlive() )
75 switch ( rVclWindowEvent.GetId() )
77 case VclEventId::CheckboxToggle :
79 if ( !getListBox() || !getListBox()->HasFocus() )
81 return;
83 AccessibleListBoxEntry* pCurOpEntry = GetCurEventEntry(rVclWindowEvent);
84 if(!pCurOpEntry)
86 return ;
88 uno::Any aValue;
89 aValue <<= AccessibleStateType::CHECKED;
91 if ( getListBox()->GetCheckButtonState( pCurOpEntry->GetSvLBoxEntry() ) == SvButtonState::Checked )
93 pCurOpEntry->NotifyAccessibleEvent( AccessibleEventId::STATE_CHANGED, uno::Any(), aValue );
95 else
97 pCurOpEntry->NotifyAccessibleEvent( AccessibleEventId::STATE_CHANGED, aValue,uno::Any() );
99 break;
102 case VclEventId::ListboxSelect :
104 OSL_FAIL("Debug: Treelist shouldn't use VclEventId::ListboxSelect");
105 break;
108 case VclEventId::ListboxTreeSelect:
110 if ( getListBox() && getListBox()->HasFocus() )
112 AccessibleListBoxEntry* pEntry =static_cast< AccessibleListBoxEntry* >(m_xFocusedChild.get());
113 if (pEntry)
115 pEntry->NotifyAccessibleEvent( AccessibleEventId::SELECTION_CHANGED, Any(), Any() );
119 break;
120 case VclEventId::ListboxTreeFocus:
122 VclPtr<SvTreeListBox> pBox = getListBox();
123 if( pBox && pBox->HasFocus() )
125 uno::Any aNewValue;
126 SvTreeListEntry* pEntry = static_cast< SvTreeListEntry* >( rVclWindowEvent.GetData() );
127 if ( pEntry )
129 AccessibleListBoxEntry* pEntryFocus =static_cast< AccessibleListBoxEntry* >(m_xFocusedChild.get());
130 if (pEntryFocus && pEntryFocus->GetSvLBoxEntry() == pEntry)
132 aNewValue <<= m_xFocusedChild;
133 NotifyAccessibleEvent( AccessibleEventId::ACTIVE_DESCENDANT_CHANGED, uno::Any(), aNewValue );
134 return ;
137 uno::Any aOldValue;
138 aOldValue <<= m_xFocusedChild;
140 MAP_ENTRY::iterator mi = m_mapEntry.find(pEntry);
141 if(mi != m_mapEntry.end())
143 OSL_ASSERT(mi->second.get() != nullptr);
144 m_xFocusedChild = mi->second;
146 else
148 AccessibleListBoxEntry *pEntNew = new AccessibleListBoxEntry( *getListBox(), pEntry, nullptr );
149 m_xFocusedChild = pEntNew;
150 m_mapEntry.emplace(pEntry,pEntNew);
153 aNewValue <<= m_xFocusedChild;
154 NotifyAccessibleEvent( AccessibleEventId::ACTIVE_DESCENDANT_CHANGED, aOldValue, aNewValue );
156 else
158 aNewValue <<= AccessibleStateType::FOCUSED;
159 NotifyAccessibleEvent( AccessibleEventId::STATE_CHANGED, uno::Any(), aNewValue );
163 break;
164 case VclEventId::ListboxItemRemoved:
166 SvTreeListEntry* pEntry = static_cast< SvTreeListEntry* >( rVclWindowEvent.GetData() );
167 if ( pEntry )
169 RemoveChildEntries(pEntry);
171 else
173 // NULL means Clear()
174 for (auto const& entry : m_mapEntry)
176 uno::Any aNewValue;
177 uno::Any aOldValue;
178 aOldValue <<= entry.second;
179 NotifyAccessibleEvent( AccessibleEventId::CHILD, aOldValue, aNewValue );
181 m_mapEntry.clear();
184 break;
186 // #i92103#
187 case VclEventId::ItemExpanded :
188 case VclEventId::ItemCollapsed :
190 SvTreeListEntry* pEntry = static_cast< SvTreeListEntry* >( rVclWindowEvent.GetData() );
191 if ( pEntry )
193 AccessibleListBoxEntry* pAccListBoxEntry =
194 new AccessibleListBoxEntry( *getListBox(), pEntry, this );
195 Reference< XAccessible > xChild = pAccListBoxEntry;
196 const short nAccEvent =
197 ( rVclWindowEvent.GetId() == VclEventId::ItemExpanded )
198 ? AccessibleEventId::LISTBOX_ENTRY_EXPANDED
199 : AccessibleEventId::LISTBOX_ENTRY_COLLAPSED;
200 uno::Any aListBoxEntry;
201 aListBoxEntry <<= xChild;
202 NotifyAccessibleEvent( nAccEvent, Any(), aListBoxEntry );
203 if ( getListBox() && getListBox()->HasFocus() )
205 NotifyAccessibleEvent( AccessibleEventId::ACTIVE_DESCENDANT_CHANGED, Any(), aListBoxEntry );
209 break;
210 default:
211 VCLXAccessibleComponent::ProcessWindowEvent (rVclWindowEvent);
216 AccessibleListBoxEntry* AccessibleListBox::GetCurEventEntry( const VclWindowEvent& rVclWindowEvent )
218 SvTreeListEntry* pEntry = static_cast< SvTreeListEntry* >( rVclWindowEvent.GetData() );
219 if ( !pEntry )
220 pEntry = getListBox()->GetCurEntry();
222 AccessibleListBoxEntry* pEntryFocus =static_cast< AccessibleListBoxEntry* >(m_xFocusedChild.get());
223 if (pEntryFocus && pEntry && pEntry != pEntryFocus->GetSvLBoxEntry())
225 AccessibleListBoxEntry *pAccCurOptionEntry =nullptr;
226 MAP_ENTRY::iterator mi = m_mapEntry.find(pEntry);
227 if (mi != m_mapEntry.end())
229 pAccCurOptionEntry= static_cast< AccessibleListBoxEntry* >(mi->second.get());
231 else
233 pAccCurOptionEntry =new AccessibleListBoxEntry( *getListBox(), pEntry, nullptr );
234 std::pair<MAP_ENTRY::iterator, bool> pairMi = m_mapEntry.emplace(pAccCurOptionEntry->GetSvLBoxEntry(), pAccCurOptionEntry);
235 mi = pairMi.first;
238 uno::Any aNewValue;
239 aNewValue <<= mi->second;//xAcc
240 NotifyAccessibleEvent( AccessibleEventId::CHILD, uno::Any(), aNewValue );//Add
242 return pAccCurOptionEntry;
244 else
246 return pEntryFocus;
250 void AccessibleListBox::RemoveChildEntries(SvTreeListEntry* pEntry)
252 MAP_ENTRY::iterator mi = m_mapEntry.find(pEntry);
253 if ( mi != m_mapEntry.end() )
255 uno::Any aNewValue;
256 uno::Any aOldValue;
257 aOldValue <<= mi->second;
258 NotifyAccessibleEvent( AccessibleEventId::CHILD, aOldValue, aNewValue );
260 m_mapEntry.erase(mi);
263 VclPtr<SvTreeListBox> pBox = getListBox();
264 SvTreeListEntry* pEntryChild = pBox->FirstChild(pEntry);
265 while (pEntryChild)
267 RemoveChildEntries(pEntryChild);
268 pEntryChild = pEntryChild->NextSibling();
273 void AccessibleListBox::ProcessWindowChildEvent( const VclWindowEvent& rVclWindowEvent )
275 switch ( rVclWindowEvent.GetId() )
277 case VclEventId::WindowShow:
278 case VclEventId::WindowHide:
281 break;
282 default:
284 VCLXAccessibleComponent::ProcessWindowChildEvent( rVclWindowEvent );
286 break;
291 // XComponent
293 void SAL_CALL AccessibleListBox::disposing()
295 ::osl::MutexGuard aGuard( m_aMutex );
297 m_mapEntry.clear();
298 VCLXAccessibleComponent::disposing();
299 m_xParent = nullptr;
302 // XServiceInfo
304 OUString SAL_CALL AccessibleListBox::getImplementationName()
306 return OUString( "com.sun.star.comp.svtools.AccessibleTreeListBox" );
309 Sequence< OUString > SAL_CALL AccessibleListBox::getSupportedServiceNames()
311 return {"com.sun.star.accessibility.AccessibleContext",
312 "com.sun.star.accessibility.AccessibleComponent",
313 "com.sun.star.awt.AccessibleTreeListBox"};
316 sal_Bool SAL_CALL AccessibleListBox::supportsService( const OUString& _rServiceName )
318 return cppu::supportsService(this, _rServiceName);
321 // XAccessible
323 Reference< XAccessibleContext > SAL_CALL AccessibleListBox::getAccessibleContext( )
325 ensureAlive();
326 return this;
329 // XAccessibleContext
331 sal_Int32 SAL_CALL AccessibleListBox::getAccessibleChildCount( )
333 ::comphelper::OExternalLockGuard aGuard( this );
335 sal_Int32 nCount = 0;
336 VclPtr<SvTreeListBox> pSvTreeListBox = getListBox();
337 if ( pSvTreeListBox )
338 nCount = pSvTreeListBox->GetLevelChildCount( nullptr );
340 return nCount;
343 Reference< XAccessible > SAL_CALL AccessibleListBox::getAccessibleChild( sal_Int32 i )
345 ::comphelper::OExternalLockGuard aGuard( this );
347 SvTreeListEntry* pEntry = getListBox()->GetEntry(i);
348 if ( !pEntry )
349 throw IndexOutOfBoundsException();
351 // Solution: Set the parameter of the parent to null to let entry determine the parent by itself
352 //return new AccessibleListBoxEntry( *getListBox(), pEntry, this );
353 return new AccessibleListBoxEntry( *getListBox(), pEntry, nullptr );
356 Reference< XAccessible > SAL_CALL AccessibleListBox::getAccessibleParent( )
358 ::osl::MutexGuard aGuard( m_aMutex );
360 ensureAlive();
361 return m_xParent;
364 sal_Int32 AccessibleListBox::GetRoleType()
366 sal_Int32 nCase = 0;
367 SvTreeListEntry* pEntry = getListBox()->GetEntry(0);
368 if ( pEntry )
370 if( pEntry->HasChildrenOnDemand() || getListBox()->GetChildCount(pEntry) > 0 )
372 nCase = 1;
373 return nCase;
377 bool bHasButtons = (getListBox()->GetStyle() & WB_HASBUTTONS)!=0;
378 if( !(getListBox()->GetTreeFlags() & SvTreeFlags::CHKBTN) )
380 if( bHasButtons )
381 nCase = 1;
383 else
385 if( bHasButtons )
386 nCase = 2;
387 else
388 nCase = 3;
390 return nCase;
393 sal_Int16 SAL_CALL AccessibleListBox::getAccessibleRole()
395 ::comphelper::OExternalLockGuard aGuard( this );
397 if(getListBox())
399 SvTreeAccRoleType nType = getListBox()->GetAllEntriesAccessibleRoleType();
400 if( nType == SvTreeAccRoleType::TREE)
401 return AccessibleRole::TREE;
404 //o is: return AccessibleRole::TREE;
405 bool bHasButtons = (getListBox()->GetStyle() & WB_HASBUTTONS)!=0;
406 if(!bHasButtons && (getListBox()->GetTreeFlags() & SvTreeFlags::CHKBTN))
407 return AccessibleRole::LIST;
408 else
409 if (GetRoleType() == 0)
410 return AccessibleRole::LIST;
411 else
412 return AccessibleRole::TREE;
415 OUString SAL_CALL AccessibleListBox::getAccessibleDescription( )
417 ::comphelper::OExternalLockGuard aGuard( this );
419 return getListBox()->GetAccessibleDescription();
422 OUString SAL_CALL AccessibleListBox::getAccessibleName( )
424 ::comphelper::OExternalLockGuard aGuard( this );
426 return getListBox()->GetAccessibleName();
429 // XAccessibleSelection
431 void SAL_CALL AccessibleListBox::selectAccessibleChild( sal_Int32 nChildIndex )
433 ::comphelper::OExternalLockGuard aGuard( this );
435 SvTreeListEntry* pEntry = getListBox()->GetEntry( nChildIndex );
436 if ( !pEntry )
437 throw IndexOutOfBoundsException();
439 getListBox()->Select( pEntry );
442 sal_Bool SAL_CALL AccessibleListBox::isAccessibleChildSelected( sal_Int32 nChildIndex )
444 ::comphelper::OExternalLockGuard aGuard( this );
446 SvTreeListEntry* pEntry = getListBox()->GetEntry( nChildIndex );
447 if ( !pEntry )
448 throw IndexOutOfBoundsException();
450 return getListBox()->IsSelected( pEntry );
453 void SAL_CALL AccessibleListBox::clearAccessibleSelection( )
455 ::comphelper::OExternalLockGuard aGuard( this );
457 sal_Int32 nCount = getListBox()->GetLevelChildCount( nullptr );
458 for ( sal_Int32 i = 0; i < nCount; ++i )
460 SvTreeListEntry* pEntry = getListBox()->GetEntry( i );
461 if ( getListBox()->IsSelected( pEntry ) )
462 getListBox()->Select( pEntry, false );
466 void SAL_CALL AccessibleListBox::selectAllAccessibleChildren( )
468 ::comphelper::OExternalLockGuard aGuard( this );
470 sal_Int32 nCount = getListBox()->GetLevelChildCount( nullptr );
471 for ( sal_Int32 i = 0; i < nCount; ++i )
473 SvTreeListEntry* pEntry = getListBox()->GetEntry( i );
474 if ( !getListBox()->IsSelected( pEntry ) )
475 getListBox()->Select( pEntry );
479 sal_Int32 SAL_CALL AccessibleListBox::getSelectedAccessibleChildCount( )
481 ::comphelper::OExternalLockGuard aGuard( this );
483 return getListBox()->GetSelectionCount();
486 Reference< XAccessible > SAL_CALL AccessibleListBox::getSelectedAccessibleChild( sal_Int32 nSelectedChildIndex )
488 ::comphelper::OExternalLockGuard aGuard( this );
490 if ( nSelectedChildIndex < 0 || nSelectedChildIndex >= getSelectedAccessibleChildCount() )
491 throw IndexOutOfBoundsException();
493 Reference< XAccessible > xChild;
494 sal_Int32 nSelCount= 0;
495 sal_Int32 nCount = getListBox()->GetLevelChildCount( nullptr );
496 for ( sal_Int32 i = 0; i < nCount; ++i )
498 SvTreeListEntry* pEntry = getListBox()->GetEntry( i );
499 if ( getListBox()->IsSelected( pEntry ) )
500 ++nSelCount;
502 if ( nSelCount == ( nSelectedChildIndex + 1 ) )
504 // Solution: Set the parameter of the parent to null to let entry determine the parent by itself
505 //xChild = new AccessibleListBoxEntry( *getListBox(), pEntry, this );
506 xChild = new AccessibleListBoxEntry( *getListBox(), pEntry, nullptr );
507 break;
511 return xChild;
514 void SAL_CALL AccessibleListBox::deselectAccessibleChild( sal_Int32 nSelectedChildIndex )
516 ::comphelper::OExternalLockGuard aGuard( this );
518 SvTreeListEntry* pEntry = getListBox()->GetEntry( nSelectedChildIndex );
519 if ( !pEntry )
520 throw IndexOutOfBoundsException();
522 getListBox()->Select( pEntry, false );
525 void AccessibleListBox::FillAccessibleStateSet( utl::AccessibleStateSetHelper& rStateSet )
527 VCLXAccessibleComponent::FillAccessibleStateSet( rStateSet );
528 if ( getListBox() && isAlive() )
530 rStateSet.AddState( AccessibleStateType::FOCUSABLE );
531 rStateSet.AddState( AccessibleStateType::MANAGES_DESCENDANTS );
532 if ( getListBox()->GetSelectionMode() == SelectionMode::Multiple )
533 rStateSet.AddState( AccessibleStateType::MULTI_SELECTABLE );
537 VclPtr< SvTreeListBox > AccessibleListBox::getListBox() const
539 return GetAs< SvTreeListBox >();
542 }// namespace accessibility
545 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */