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 <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
;
46 AccessibleListBox::AccessibleListBox( SvTreeListBox
const & _rListBox
, const Reference
< XAccessible
>& _xParent
) :
48 ImplInheritanceHelper( _rListBox
.GetWindowPeer() ),
53 AccessibleListBox::~AccessibleListBox()
57 // increment ref count to prevent double call of Dtor
58 osl_atomic_increment( &m_refCount
);
63 void AccessibleListBox::ProcessWindowEvent( const VclWindowEvent
& rVclWindowEvent
)
68 switch ( rVclWindowEvent
.GetId() )
70 case VclEventId::CheckboxToggle
:
72 if ( !getListBox() || !getListBox()->HasFocus() )
76 AccessibleListBoxEntry
* pCurOpEntry
= GetCurEventEntry(rVclWindowEvent
);
82 aValue
<<= AccessibleStateType::CHECKED
;
84 if ( getListBox()->GetCheckButtonState( pCurOpEntry
->GetSvLBoxEntry() ) == SvButtonState::Checked
)
86 pCurOpEntry
->NotifyAccessibleEvent( AccessibleEventId::STATE_CHANGED
, uno::Any(), aValue
);
90 pCurOpEntry
->NotifyAccessibleEvent( AccessibleEventId::STATE_CHANGED
, aValue
,uno::Any() );
95 case VclEventId::ListboxSelect
:
97 OSL_FAIL("Debug: Treelist shouldn't use VclEventId::ListboxSelect");
101 case VclEventId::ListboxTreeSelect
:
103 if ( getListBox() && getListBox()->HasFocus() )
105 AccessibleListBoxEntry
* pEntry
=static_cast< AccessibleListBoxEntry
* >(m_xFocusedChild
.get());
108 pEntry
->NotifyAccessibleEvent( AccessibleEventId::SELECTION_CHANGED
, Any(), Any() );
113 case VclEventId::ListboxTreeFocus
:
115 VclPtr
<SvTreeListBox
> pBox
= getListBox();
116 if( pBox
&& pBox
->HasFocus() )
119 SvTreeListEntry
* pEntry
= static_cast< SvTreeListEntry
* >( rVclWindowEvent
.GetData() );
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
);
131 aOldValue
<<= m_xFocusedChild
;
133 m_xFocusedChild
.set(implGetAccessible(*pEntry
));
135 aNewValue
<<= m_xFocusedChild
;
136 NotifyAccessibleEvent( AccessibleEventId::ACTIVE_DESCENDANT_CHANGED
, aOldValue
, aNewValue
);
140 aNewValue
<<= AccessibleStateType::FOCUSED
;
141 NotifyAccessibleEvent( AccessibleEventId::STATE_CHANGED
, uno::Any(), aNewValue
);
146 case VclEventId::ListboxItemRemoved
:
148 SvTreeListEntry
* pEntry
= static_cast< SvTreeListEntry
* >( rVclWindowEvent
.GetData() );
151 RemoveChildEntries(pEntry
);
155 // NULL means Clear()
156 for (auto const& entry
: m_mapEntry
)
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();
173 case VclEventId::ItemExpanded
:
174 case VclEventId::ItemCollapsed
:
176 SvTreeListEntry
* pEntry
= static_cast< SvTreeListEntry
* >( rVclWindowEvent
.GetData() );
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
);
195 VCLXAccessibleComponent::ProcessWindowEvent (rVclWindowEvent
);
199 AccessibleListBoxEntry
* AccessibleListBox::GetCurEventEntry( const VclWindowEvent
& rVclWindowEvent
)
201 SvTreeListEntry
* pEntry
= static_cast< SvTreeListEntry
* >( rVclWindowEvent
.GetData() );
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();
210 aNewValue
<<= uno::Reference
<XAccessible
>(pAccCurOptionEntry
);
211 NotifyAccessibleEvent( AccessibleEventId::CHILD
, uno::Any(), aNewValue
);//Add
213 return pAccCurOptionEntry
;
221 void AccessibleListBox::RemoveChildEntries(SvTreeListEntry
* pEntry
)
223 MAP_ENTRY::iterator mi
= m_mapEntry
.find(pEntry
);
224 if ( mi
!= m_mapEntry
.end() )
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
);
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
:
255 VCLXAccessibleComponent::ProcessWindowChildEvent( rVclWindowEvent
);
264 void SAL_CALL
AccessibleListBox::disposing()
266 ::osl::MutexGuard
aGuard( m_aMutex
);
269 VCLXAccessibleComponent::disposing();
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
);
294 Reference
< XAccessibleContext
> SAL_CALL
AccessibleListBox::getAccessibleContext( )
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 );
314 Reference
< XAccessible
> SAL_CALL
AccessibleListBox::getAccessibleChild( sal_Int64 i
)
316 ::comphelper::OExternalLockGuard
aGuard( this );
318 SvTreeListEntry
* pEntry
= getListBox()->GetEntry(i
);
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
);
336 sal_Int32
AccessibleListBox::GetRoleType() const
339 SvTreeListEntry
* pEntry
= getListBox()->GetEntry(0);
342 if( pEntry
->HasChildrenOnDemand() || getListBox()->GetChildCount(pEntry
) > 0 )
349 bool bHasButtons
= (getListBox()->GetStyle() & WB_HASBUTTONS
)!=0;
350 if( !(getListBox()->GetTreeFlags() & SvTreeFlags::CHKBTN
) )
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
;
374 if (GetRoleType() == 0)
375 return AccessibleRole::LIST
;
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
);
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
);
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
) )
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();
483 void SAL_CALL
AccessibleListBox::deselectAccessibleChild( sal_Int64 nSelectedChildIndex
)
485 ::comphelper::OExternalLockGuard
aGuard( this );
487 SvTreeListEntry
* pEntry
= getListBox()->GetEntry( nSelectedChildIndex
);
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
;
516 pAccessible
= new AccessibleListBoxEntry(*getListBox(), rEntry
, *this);
517 m_mapEntry
.emplace(&rEntry
, pAccessible
);
519 assert(pAccessible
.is());
523 VclPtr
< SvTreeListBox
> AccessibleListBox::getListBox() const
525 return GetAs
< SvTreeListBox
>();
528 }// namespace accessibility
531 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */