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>
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
;
45 AccessibleListBox::AccessibleListBox(SvTreeListBox
& _rListBox
, const Reference
< XAccessible
>& _xParent
)
46 : ImplInheritanceHelper(&_rListBox
),
51 AccessibleListBox::~AccessibleListBox()
55 // increment ref count to prevent double call of Dtor
56 osl_atomic_increment( &m_refCount
);
61 void AccessibleListBox::ProcessWindowEvent( const VclWindowEvent
& rVclWindowEvent
)
66 switch ( rVclWindowEvent
.GetId() )
68 case VclEventId::CheckboxToggle
:
70 if ( !getListBox() || !getListBox()->HasFocus() )
74 AccessibleListBoxEntry
* pCurOpEntry
= GetCurEventEntry(rVclWindowEvent
);
80 aValue
<<= AccessibleStateType::CHECKED
;
82 if ( getListBox()->GetCheckButtonState( pCurOpEntry
->GetSvLBoxEntry() ) == SvButtonState::Checked
)
84 pCurOpEntry
->NotifyAccessibleEvent( AccessibleEventId::STATE_CHANGED
, uno::Any(), aValue
);
88 pCurOpEntry
->NotifyAccessibleEvent( AccessibleEventId::STATE_CHANGED
, aValue
,uno::Any() );
93 case VclEventId::ListboxSelect
:
95 OSL_FAIL("Debug: Treelist shouldn't use VclEventId::ListboxSelect");
99 case VclEventId::ListboxTreeSelect
:
101 if ( getListBox() && getListBox()->HasFocus() )
103 if (m_xFocusedEntry
.is())
105 m_xFocusedEntry
->NotifyAccessibleEvent(AccessibleEventId::SELECTION_CHANGED
, Any(), Any());
110 case VclEventId::ListboxTreeFocus
:
112 VclPtr
<SvTreeListBox
> pBox
= getListBox();
113 if( pBox
&& pBox
->HasFocus() )
116 SvTreeListEntry
* pEntry
= static_cast< SvTreeListEntry
* >( rVclWindowEvent
.GetData() );
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
);
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
);
135 aNewValue
<<= AccessibleStateType::FOCUSED
;
136 NotifyAccessibleEvent( AccessibleEventId::STATE_CHANGED
, uno::Any(), aNewValue
);
141 case VclEventId::ListboxItemRemoved
:
143 SvTreeListEntry
* pEntry
= static_cast< SvTreeListEntry
* >( rVclWindowEvent
.GetData() );
146 RemoveChildEntries(pEntry
);
150 // NULL means Clear()
151 for (auto const& entry
: m_mapEntry
)
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();
168 case VclEventId::ItemExpanded
:
169 case VclEventId::ItemCollapsed
:
171 SvTreeListEntry
* pEntry
= static_cast< SvTreeListEntry
* >( rVclWindowEvent
.GetData() );
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
);
190 VCLXAccessibleComponent::ProcessWindowEvent (rVclWindowEvent
);
194 AccessibleListBoxEntry
* AccessibleListBox::GetCurEventEntry( const VclWindowEvent
& rVclWindowEvent
)
196 SvTreeListEntry
* pEntry
= static_cast< SvTreeListEntry
* >( rVclWindowEvent
.GetData() );
198 pEntry
= getListBox()->GetCurEntry();
200 if (m_xFocusedEntry
.is() && pEntry
&& pEntry
!= m_xFocusedEntry
->GetSvLBoxEntry())
202 AccessibleListBoxEntry
*const pAccCurOptionEntry
= implGetAccessible(*pEntry
).get();
204 aNewValue
<<= uno::Reference
<XAccessible
>(pAccCurOptionEntry
);
205 NotifyAccessibleEvent( AccessibleEventId::CHILD
, uno::Any(), aNewValue
);//Add
207 return pAccCurOptionEntry
;
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() )
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
);
232 RemoveChildEntries(pEntryChild
);
233 pEntryChild
= pEntryChild
->NextSibling();
239 void SAL_CALL
AccessibleListBox::disposing()
241 ::osl::MutexGuard
aGuard( m_aMutex
);
244 VCLXAccessibleComponent::disposing();
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
};
264 Reference
< XAccessibleContext
> SAL_CALL
AccessibleListBox::getAccessibleContext( )
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 );
284 Reference
< XAccessible
> SAL_CALL
AccessibleListBox::getAccessibleChild( sal_Int64 i
)
286 ::comphelper::OExternalLockGuard
aGuard( this );
288 SvTreeListEntry
* pEntry
= getListBox()->GetEntry(i
);
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
);
306 sal_Int32
AccessibleListBox::GetRoleType() const
309 SvTreeListEntry
* pEntry
= getListBox()->GetEntry(0);
312 if( pEntry
->HasChildrenOnDemand() || getListBox()->GetChildCount(pEntry
) > 0 )
319 bool bHasButtons
= (getListBox()->GetStyle() & WB_HASBUTTONS
)!=0;
320 if( !(getListBox()->GetTreeFlags() & SvTreeFlags::CHKBTN
) )
335 sal_Int16 SAL_CALL
AccessibleListBox::getAccessibleRole()
337 ::comphelper::OExternalLockGuard
aGuard( this );
339 VclPtr
<SvTreeListBox
> pListBox
= getListBox();
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
;
348 if (GetRoleType() == 0)
349 return AccessibleRole::LIST
;
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
);
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
);
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
) )
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();
457 void SAL_CALL
AccessibleListBox::deselectAccessibleChild( sal_Int64 nSelectedChildIndex
)
459 ::comphelper::OExternalLockGuard
aGuard( this );
461 SvTreeListEntry
* pEntry
= getListBox()->GetEntry( nSelectedChildIndex
);
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
;
490 pAccessible
= new AccessibleListBoxEntry(*getListBox(), rEntry
, *this);
491 m_mapEntry
.emplace(&rEntry
, pAccessible
);
493 assert(pAccessible
.is());
497 VclPtr
< SvTreeListBox
> AccessibleListBox::getListBox() const
499 return GetAs
< SvTreeListBox
>();
502 }// namespace accessibility
505 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */