1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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 <cppuhelper/supportsservice.hxx>
29 #include <unotools/accessiblestatesethelper.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
;
46 AccessibleListBox::AccessibleListBox( SvTreeListBox
const & _rListBox
, const Reference
< XAccessible
>& _xParent
) :
48 VCLXAccessibleComponent( _rListBox
.GetWindowPeer() ),
53 AccessibleListBox::~AccessibleListBox()
57 // increment ref count to prevent double call of Dtor
58 osl_atomic_increment( &m_refCount
);
62 IMPLEMENT_FORWARD_XINTERFACE2(AccessibleListBox
, VCLXAccessibleComponent
, ImplHelper2
)
63 IMPLEMENT_FORWARD_XTYPEPROVIDER2(AccessibleListBox
, VCLXAccessibleComponent
, ImplHelper2
)
65 void AccessibleListBox::ProcessWindowEvent( const VclWindowEvent
& rVclWindowEvent
)
70 switch ( rVclWindowEvent
.GetId() )
72 case VclEventId::CheckboxToggle
:
74 if ( !getListBox() || !getListBox()->HasFocus() )
78 AccessibleListBoxEntry
* pCurOpEntry
= GetCurEventEntry(rVclWindowEvent
);
84 aValue
<<= AccessibleStateType::CHECKED
;
86 if ( getListBox()->GetCheckButtonState( pCurOpEntry
->GetSvLBoxEntry() ) == SvButtonState::Checked
)
88 pCurOpEntry
->NotifyAccessibleEvent( AccessibleEventId::STATE_CHANGED
, uno::Any(), aValue
);
92 pCurOpEntry
->NotifyAccessibleEvent( AccessibleEventId::STATE_CHANGED
, aValue
,uno::Any() );
97 case VclEventId::ListboxSelect
:
99 OSL_FAIL("Debug: Treelist shouldn't use VclEventId::ListboxSelect");
103 case VclEventId::ListboxTreeSelect
:
105 if ( getListBox() && getListBox()->HasFocus() )
107 AccessibleListBoxEntry
* pEntry
=static_cast< AccessibleListBoxEntry
* >(m_xFocusedChild
.get());
110 pEntry
->NotifyAccessibleEvent( AccessibleEventId::SELECTION_CHANGED
, Any(), Any() );
115 case VclEventId::ListboxTreeFocus
:
117 VclPtr
<SvTreeListBox
> pBox
= getListBox();
118 if( pBox
&& pBox
->HasFocus() )
121 SvTreeListEntry
* pEntry
= static_cast< SvTreeListEntry
* >( rVclWindowEvent
.GetData() );
124 AccessibleListBoxEntry
* pEntryFocus
=static_cast< AccessibleListBoxEntry
* >(m_xFocusedChild
.get());
125 if (pEntryFocus
&& pEntryFocus
->GetSvLBoxEntry() == pEntry
)
127 aNewValue
<<= m_xFocusedChild
;
128 NotifyAccessibleEvent( AccessibleEventId::ACTIVE_DESCENDANT_CHANGED
, uno::Any(), aNewValue
);
133 aOldValue
<<= m_xFocusedChild
;
135 m_xFocusedChild
.set(implGetAccessible(*pEntry
));
137 aNewValue
<<= m_xFocusedChild
;
138 NotifyAccessibleEvent( AccessibleEventId::ACTIVE_DESCENDANT_CHANGED
, aOldValue
, aNewValue
);
142 aNewValue
<<= AccessibleStateType::FOCUSED
;
143 NotifyAccessibleEvent( AccessibleEventId::STATE_CHANGED
, uno::Any(), aNewValue
);
148 case VclEventId::ListboxItemRemoved
:
150 SvTreeListEntry
* pEntry
= static_cast< SvTreeListEntry
* >( rVclWindowEvent
.GetData() );
153 RemoveChildEntries(pEntry
);
157 // NULL means Clear()
158 for (auto const& entry
: m_mapEntry
)
162 aOldValue
<<= uno::Reference
<XAccessible
>(entry
.second
);
163 NotifyAccessibleEvent( AccessibleEventId::CHILD
, aOldValue
, aNewValue
);
165 for (auto const& entry
: m_mapEntry
)
166 { // release references ...
167 entry
.second
->dispose();
175 case VclEventId::ItemExpanded
:
176 case VclEventId::ItemCollapsed
:
178 SvTreeListEntry
* pEntry
= static_cast< SvTreeListEntry
* >( rVclWindowEvent
.GetData() );
181 Reference
<XAccessible
> const xChild(implGetAccessible(*pEntry
));
182 const short nAccEvent
=
183 ( rVclWindowEvent
.GetId() == VclEventId::ItemExpanded
)
184 ? AccessibleEventId::LISTBOX_ENTRY_EXPANDED
185 : AccessibleEventId::LISTBOX_ENTRY_COLLAPSED
;
186 uno::Any aListBoxEntry
;
187 aListBoxEntry
<<= xChild
;
188 NotifyAccessibleEvent( nAccEvent
, Any(), aListBoxEntry
);
189 if ( getListBox() && getListBox()->HasFocus() )
191 NotifyAccessibleEvent( AccessibleEventId::ACTIVE_DESCENDANT_CHANGED
, Any(), aListBoxEntry
);
197 VCLXAccessibleComponent::ProcessWindowEvent (rVclWindowEvent
);
201 AccessibleListBoxEntry
* AccessibleListBox::GetCurEventEntry( const VclWindowEvent
& rVclWindowEvent
)
203 SvTreeListEntry
* pEntry
= static_cast< SvTreeListEntry
* >( rVclWindowEvent
.GetData() );
205 pEntry
= getListBox()->GetCurEntry();
207 AccessibleListBoxEntry
* pEntryFocus
=static_cast< AccessibleListBoxEntry
* >(m_xFocusedChild
.get());
208 if (pEntryFocus
&& pEntry
&& pEntry
!= pEntryFocus
->GetSvLBoxEntry())
210 AccessibleListBoxEntry
*const pAccCurOptionEntry
= implGetAccessible(*pEntry
).get();
212 aNewValue
<<= uno::Reference
<XAccessible
>(pAccCurOptionEntry
);
213 NotifyAccessibleEvent( AccessibleEventId::CHILD
, uno::Any(), aNewValue
);//Add
215 return pAccCurOptionEntry
;
223 void AccessibleListBox::RemoveChildEntries(SvTreeListEntry
* pEntry
)
225 MAP_ENTRY::iterator mi
= m_mapEntry
.find(pEntry
);
226 if ( mi
!= m_mapEntry
.end() )
230 aOldValue
<<= uno::Reference
<XAccessible
>(mi
->second
);
231 NotifyAccessibleEvent( AccessibleEventId::CHILD
, aOldValue
, aNewValue
);
233 m_mapEntry
.erase(mi
);
236 VclPtr
<SvTreeListBox
> pBox
= getListBox();
237 SvTreeListEntry
* pEntryChild
= pBox
->FirstChild(pEntry
);
240 RemoveChildEntries(pEntryChild
);
241 pEntryChild
= pEntryChild
->NextSibling();
246 void AccessibleListBox::ProcessWindowChildEvent( const VclWindowEvent
& rVclWindowEvent
)
248 switch ( rVclWindowEvent
.GetId() )
250 case VclEventId::WindowShow
:
251 case VclEventId::WindowHide
:
257 VCLXAccessibleComponent::ProcessWindowChildEvent( rVclWindowEvent
);
266 void SAL_CALL
AccessibleListBox::disposing()
268 ::osl::MutexGuard
aGuard( m_aMutex
);
271 VCLXAccessibleComponent::disposing();
277 OUString SAL_CALL
AccessibleListBox::getImplementationName()
279 return "com.sun.star.comp.svtools.AccessibleTreeListBox";
282 Sequence
< OUString
> SAL_CALL
AccessibleListBox::getSupportedServiceNames()
284 return {"com.sun.star.accessibility.AccessibleContext",
285 "com.sun.star.accessibility.AccessibleComponent",
286 "com.sun.star.awt.AccessibleTreeListBox"};
289 sal_Bool SAL_CALL
AccessibleListBox::supportsService( const OUString
& _rServiceName
)
291 return cppu::supportsService(this, _rServiceName
);
296 Reference
< XAccessibleContext
> SAL_CALL
AccessibleListBox::getAccessibleContext( )
302 // XAccessibleContext
304 sal_Int32 SAL_CALL
AccessibleListBox::getAccessibleChildCount( )
306 ::comphelper::OExternalLockGuard
aGuard( this );
308 sal_Int32 nCount
= 0;
309 VclPtr
<SvTreeListBox
> pSvTreeListBox
= getListBox();
310 if ( pSvTreeListBox
)
311 nCount
= pSvTreeListBox
->GetLevelChildCount( nullptr );
316 Reference
< XAccessible
> SAL_CALL
AccessibleListBox::getAccessibleChild( sal_Int32 i
)
318 ::comphelper::OExternalLockGuard
aGuard( this );
320 SvTreeListEntry
* pEntry
= getListBox()->GetEntry(i
);
322 throw IndexOutOfBoundsException();
324 // Solution: Set the parameter of the parent to null to let entry determine the parent by itself
325 //return new AccessibleListBoxEntry( *getListBox(), pEntry, this );
326 //return new AccessibleListBoxEntry( *getListBox(), pEntry, nullptr );
327 return implGetAccessible(*pEntry
);
330 Reference
< XAccessible
> SAL_CALL
AccessibleListBox::getAccessibleParent( )
332 ::osl::MutexGuard
aGuard( m_aMutex
);
338 sal_Int32
AccessibleListBox::GetRoleType() const
341 SvTreeListEntry
* pEntry
= getListBox()->GetEntry(0);
344 if( pEntry
->HasChildrenOnDemand() || getListBox()->GetChildCount(pEntry
) > 0 )
351 bool bHasButtons
= (getListBox()->GetStyle() & WB_HASBUTTONS
)!=0;
352 if( !(getListBox()->GetTreeFlags() & SvTreeFlags::CHKBTN
) )
367 sal_Int16 SAL_CALL
AccessibleListBox::getAccessibleRole()
369 ::comphelper::OExternalLockGuard
aGuard( this );
371 //o is: return AccessibleRole::TREE;
372 bool bHasButtons
= (getListBox()->GetStyle() & WB_HASBUTTONS
)!=0;
373 if(!bHasButtons
&& (getListBox()->GetTreeFlags() & SvTreeFlags::CHKBTN
))
374 return AccessibleRole::LIST
;
376 if (GetRoleType() == 0)
377 return AccessibleRole::LIST
;
379 return AccessibleRole::TREE
;
382 OUString SAL_CALL
AccessibleListBox::getAccessibleDescription( )
384 ::comphelper::OExternalLockGuard
aGuard( this );
386 return getListBox()->GetAccessibleDescription();
389 OUString SAL_CALL
AccessibleListBox::getAccessibleName( )
391 ::comphelper::OExternalLockGuard
aGuard( this );
393 return getListBox()->GetAccessibleName();
396 // XAccessibleSelection
398 void SAL_CALL
AccessibleListBox::selectAccessibleChild( sal_Int32 nChildIndex
)
400 ::comphelper::OExternalLockGuard
aGuard( this );
402 SvTreeListEntry
* pEntry
= getListBox()->GetEntry( nChildIndex
);
404 throw IndexOutOfBoundsException();
406 getListBox()->Select( pEntry
);
409 sal_Bool SAL_CALL
AccessibleListBox::isAccessibleChildSelected( sal_Int32 nChildIndex
)
411 ::comphelper::OExternalLockGuard
aGuard( this );
413 SvTreeListEntry
* pEntry
= getListBox()->GetEntry( nChildIndex
);
415 throw IndexOutOfBoundsException();
417 return getListBox()->IsSelected( pEntry
);
420 void SAL_CALL
AccessibleListBox::clearAccessibleSelection( )
422 ::comphelper::OExternalLockGuard
aGuard( this );
424 sal_Int32 nCount
= getListBox()->GetLevelChildCount( nullptr );
425 for ( sal_Int32 i
= 0; i
< nCount
; ++i
)
427 SvTreeListEntry
* pEntry
= getListBox()->GetEntry( i
);
428 if ( getListBox()->IsSelected( pEntry
) )
429 getListBox()->Select( pEntry
, false );
433 void SAL_CALL
AccessibleListBox::selectAllAccessibleChildren( )
435 ::comphelper::OExternalLockGuard
aGuard( this );
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 getListBox()->Select( pEntry
);
446 sal_Int32 SAL_CALL
AccessibleListBox::getSelectedAccessibleChildCount( )
448 ::comphelper::OExternalLockGuard
aGuard( this );
450 return getListBox()->GetSelectionCount();
453 Reference
< XAccessible
> SAL_CALL
AccessibleListBox::getSelectedAccessibleChild( sal_Int32 nSelectedChildIndex
)
455 ::comphelper::OExternalLockGuard
aGuard( this );
457 if ( nSelectedChildIndex
< 0 || nSelectedChildIndex
>= getSelectedAccessibleChildCount() )
458 throw IndexOutOfBoundsException();
460 Reference
< XAccessible
> xChild
;
461 sal_Int32 nSelCount
= 0;
462 sal_Int32 nCount
= getListBox()->GetLevelChildCount( nullptr );
463 for ( sal_Int32 i
= 0; i
< nCount
; ++i
)
465 SvTreeListEntry
* pEntry
= getListBox()->GetEntry( i
);
466 if ( getListBox()->IsSelected( pEntry
) )
469 if ( nSelCount
== ( nSelectedChildIndex
+ 1 ) )
471 // Solution: Set the parameter of the parent to null to let entry determine the parent by itself
472 //xChild = new AccessibleListBoxEntry( *getListBox(), pEntry, this );
473 //xChild = new AccessibleListBoxEntry( *getListBox(), pEntry, nullptr );
474 xChild
= implGetAccessible(*pEntry
).get();
482 void SAL_CALL
AccessibleListBox::deselectAccessibleChild( sal_Int32 nSelectedChildIndex
)
484 ::comphelper::OExternalLockGuard
aGuard( this );
486 SvTreeListEntry
* pEntry
= getListBox()->GetEntry( nSelectedChildIndex
);
488 throw IndexOutOfBoundsException();
490 getListBox()->Select( pEntry
, false );
493 void AccessibleListBox::FillAccessibleStateSet( utl::AccessibleStateSetHelper
& rStateSet
)
495 VCLXAccessibleComponent::FillAccessibleStateSet( rStateSet
);
496 if ( getListBox() && isAlive() )
498 rStateSet
.AddState( AccessibleStateType::FOCUSABLE
);
499 rStateSet
.AddState( AccessibleStateType::MANAGES_DESCENDANTS
);
500 if ( getListBox()->GetSelectionMode() == SelectionMode::Multiple
)
501 rStateSet
.AddState( AccessibleStateType::MULTI_SELECTABLE
);
505 rtl::Reference
<AccessibleListBoxEntry
> AccessibleListBox::implGetAccessible(SvTreeListEntry
& rEntry
)
507 rtl::Reference
<AccessibleListBoxEntry
> pAccessible
;
508 auto const it
= m_mapEntry
.find(&rEntry
);
509 if (it
!= m_mapEntry
.end())
511 pAccessible
= it
->second
;
515 pAccessible
= new AccessibleListBoxEntry(*getListBox(), rEntry
, *this);
516 m_mapEntry
.emplace(&rEntry
, pAccessible
);
518 assert(pAccessible
.is());
522 VclPtr
< SvTreeListBox
> AccessibleListBox::getListBox() const
524 return GetAs
< SvTreeListBox
>();
527 }// namespace accessibility
530 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */