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 <accessibility/extended/accessiblelistbox.hxx>
21 #include <accessibility/extended/accessiblelistboxentry.hxx>
22 #include <svtools/treelistbox.hxx>
23 #include <svtools/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 <cppuhelper/supportsservice.hxx>
31 #include <vcl/svapp.hxx>
32 #include <toolkit/awt/vclxwindow.hxx>
33 #include <toolkit/helper/convert.hxx>
34 #include <unotools/accessiblestatesethelper.hxx>
37 namespace accessibility
41 // class AccessibleListBox -----------------------------------------------------
43 using namespace ::com::sun::star::accessibility
;
44 using namespace ::com::sun::star::uno
;
45 using namespace ::com::sun::star::lang
;
46 using namespace ::com::sun::star
;
51 AccessibleListBox::AccessibleListBox( SvTreeListBox
& _rListBox
, const Reference
< XAccessible
>& _xParent
) :
53 VCLXAccessibleComponent( _rListBox
.GetWindowPeer() ),
58 AccessibleListBox::~AccessibleListBox()
62 // increment ref count to prevent double call of Dtor
63 osl_atomic_increment( &m_refCount
);
67 IMPLEMENT_FORWARD_XINTERFACE2(AccessibleListBox
, VCLXAccessibleComponent
, AccessibleListBox_BASE
)
68 IMPLEMENT_FORWARD_XTYPEPROVIDER2(AccessibleListBox
, VCLXAccessibleComponent
, AccessibleListBox_BASE
)
70 void AccessibleListBox::ProcessWindowEvent( const VclWindowEvent
& rVclWindowEvent
)
74 switch ( rVclWindowEvent
.GetId() )
76 case VCLEVENT_CHECKBOX_TOGGLE
:
78 if ( !getListBox() || !getListBox()->HasFocus() )
82 AccessibleListBoxEntry
* pCurOpEntry
= GetCurEventEntry(rVclWindowEvent
);
88 aValue
<<= AccessibleStateType::CHECKED
;
90 if ( getListBox()->GetCheckButtonState( pCurOpEntry
->GetSvLBoxEntry() ) == SV_BUTTON_CHECKED
)
92 pCurOpEntry
->NotifyAccessibleEvent( AccessibleEventId::STATE_CHANGED
, uno::Any(), aValue
);
96 pCurOpEntry
->NotifyAccessibleEvent( AccessibleEventId::STATE_CHANGED
, aValue
,uno::Any() );
101 case VCLEVENT_LISTBOX_SELECT
:
103 OSL_FAIL("Debug: Treelist shouldn't use VCLEVENT_LISTBOX_SELECT");
107 case VCLEVENT_LISTBOX_TREESELECT
:
109 if ( getListBox() && getListBox()->HasFocus() )
111 AccessibleListBoxEntry
* pEntry
=static_cast< AccessibleListBoxEntry
* >(m_xFocusedChild
.get());
114 pEntry
->NotifyAccessibleEvent( AccessibleEventId::SELECTION_CHANGED
, Any(), Any() );
119 case VCLEVENT_LISTBOX_TREEFOCUS
:
121 SvTreeListBox
* pBox
= getListBox();
122 bool bNeedFocus
= false;
125 vcl::Window
* pParent
= ((vcl::Window
*)pBox
)->GetParent();
126 if (pParent
&& pParent
->GetType() == WINDOW_FLOATINGWINDOW
)
128 // MT: ImplGetAppSVData shouldn't be exported from VCL.
129 // In which scenario is this needed?
130 // If needed, we need to find an other solution
132 ImplSVData* pSVData = ImplGetAppSVData();
133 if (pSVData && pSVData->maWinData.mpFirstFloat == (FloatingWindow*)pParent)
138 if( pBox
&& (pBox
->HasFocus() || bNeedFocus
) )
140 uno::Any aOldValue
, aNewValue
;
141 SvTreeListEntry
* pEntry
= static_cast< SvTreeListEntry
* >( rVclWindowEvent
.GetData() );
144 AccessibleListBoxEntry
* pEntryFocus
=static_cast< AccessibleListBoxEntry
* >(m_xFocusedChild
.get());
145 if (pEntryFocus
&& pEntryFocus
->GetSvLBoxEntry() == pEntry
)
147 aOldValue
<<= uno::Any();
148 aNewValue
<<= m_xFocusedChild
;
149 NotifyAccessibleEvent( AccessibleEventId::ACTIVE_DESCENDANT_CHANGED
, aOldValue
, aNewValue
);
153 aOldValue
<<= m_xFocusedChild
;
155 MAP_ENTRY::iterator mi
= m_mapEntry
.find(pEntry
);
156 if(mi
!= m_mapEntry
.end())
158 OSL_ASSERT(mi
->second
.get() != NULL
);
159 m_xFocusedChild
= mi
->second
;
163 AccessibleListBoxEntry
*pEntNew
= new AccessibleListBoxEntry( *getListBox(), pEntry
, NULL
);
164 m_xFocusedChild
= pEntNew
;
165 m_mapEntry
.insert(MAP_ENTRY::value_type(pEntry
,pEntNew
));
168 aNewValue
<<= m_xFocusedChild
;
169 NotifyAccessibleEvent( AccessibleEventId::ACTIVE_DESCENDANT_CHANGED
, aOldValue
, aNewValue
);
173 aOldValue
<<= uno::Any();
174 aNewValue
<<= AccessibleStateType::FOCUSED
;
175 NotifyAccessibleEvent( AccessibleEventId::STATE_CHANGED
, aOldValue
, aNewValue
);
180 case VCLEVENT_LISTBOX_ITEMREMOVED
:
182 SvTreeListEntry
* pEntry
= static_cast< SvTreeListEntry
* >( rVclWindowEvent
.GetData() );
185 RemoveChildEntries(pEntry
);
189 // NULL means Clear()
190 MAP_ENTRY::iterator mi
= m_mapEntry
.begin();
191 for ( ; mi
!= m_mapEntry
.end() ; ++mi
)
195 aOldValue
<<= mi
->second
;
196 NotifyAccessibleEvent( AccessibleEventId::CHILD
, aOldValue
, aNewValue
);
204 case VCLEVENT_ITEM_EXPANDED
:
205 case VCLEVENT_ITEM_COLLAPSED
:
207 SvTreeListEntry
* pEntry
= static_cast< SvTreeListEntry
* >( rVclWindowEvent
.GetData() );
210 AccessibleListBoxEntry
* pAccListBoxEntry
=
211 new AccessibleListBoxEntry( *getListBox(), pEntry
, this );
212 Reference
< XAccessible
> xChild
= pAccListBoxEntry
;
213 const short nAccEvent
=
214 ( rVclWindowEvent
.GetId() == VCLEVENT_ITEM_EXPANDED
)
215 ? AccessibleEventId::LISTBOX_ENTRY_EXPANDED
216 : AccessibleEventId::LISTBOX_ENTRY_COLLAPSED
;
217 uno::Any aListBoxEntry
;
218 aListBoxEntry
<<= xChild
;
219 NotifyAccessibleEvent( nAccEvent
, Any(), aListBoxEntry
);
220 if ( getListBox() && getListBox()->HasFocus() )
222 NotifyAccessibleEvent( AccessibleEventId::ACTIVE_DESCENDANT_CHANGED
, Any(), aListBoxEntry
);
228 VCLXAccessibleComponent::ProcessWindowEvent (rVclWindowEvent
);
233 AccessibleListBoxEntry
* AccessibleListBox::GetCurEventEntry( const VclWindowEvent
& rVclWindowEvent
)
235 SvTreeListEntry
* pEntry
= static_cast< SvTreeListEntry
* >( rVclWindowEvent
.GetData() );
237 pEntry
= getListBox()->GetCurEntry();
239 AccessibleListBoxEntry
* pEntryFocus
=static_cast< AccessibleListBoxEntry
* >(m_xFocusedChild
.get());
240 if (pEntryFocus
&& pEntry
&& pEntry
!= pEntryFocus
->GetSvLBoxEntry())
242 AccessibleListBoxEntry
*pAccCurOptionEntry
=NULL
;
243 MAP_ENTRY::iterator mi
= m_mapEntry
.find(pEntry
);
244 if (mi
!= m_mapEntry
.end())
246 pAccCurOptionEntry
= static_cast< AccessibleListBoxEntry
* >(mi
->second
.get());
250 pAccCurOptionEntry
=new AccessibleListBoxEntry( *getListBox(), pEntry
, NULL
);
251 std::pair
<MAP_ENTRY::iterator
, bool> pairMi
= m_mapEntry
.insert(MAP_ENTRY::value_type(pAccCurOptionEntry
->GetSvLBoxEntry(),pAccCurOptionEntry
));
256 aNewValue
<<= mi
->second
;//xAcc
257 NotifyAccessibleEvent( AccessibleEventId::CHILD
, uno::Any(), aNewValue
);//Add
259 return pAccCurOptionEntry
;
267 void AccessibleListBox::RemoveChildEntries(SvTreeListEntry
* pEntry
)
269 MAP_ENTRY::iterator mi
= m_mapEntry
.find(pEntry
);
270 if ( mi
!= m_mapEntry
.end() )
274 aOldValue
<<= mi
->second
;
275 NotifyAccessibleEvent( AccessibleEventId::CHILD
, aOldValue
, aNewValue
);
277 m_mapEntry
.erase(mi
);
280 SvTreeListBox
* pBox
= getListBox();
281 SvTreeListEntry
* pEntryChild
= pBox
->FirstChild(pEntry
);
284 RemoveChildEntries(pEntryChild
);
285 pEntryChild
= SvTreeListBox::NextSibling(pEntryChild
);
290 void AccessibleListBox::ProcessWindowChildEvent( const VclWindowEvent
& rVclWindowEvent
)
292 switch ( rVclWindowEvent
.GetId() )
294 case VCLEVENT_WINDOW_SHOW
:
295 case VCLEVENT_WINDOW_HIDE
:
301 VCLXAccessibleComponent::ProcessWindowChildEvent( rVclWindowEvent
);
310 void SAL_CALL
AccessibleListBox::disposing()
312 ::osl::MutexGuard
aGuard( m_aMutex
);
315 VCLXAccessibleComponent::disposing();
321 OUString SAL_CALL
AccessibleListBox::getImplementationName() throw(RuntimeException
, std::exception
)
323 return getImplementationName_Static();
326 Sequence
< OUString
> SAL_CALL
AccessibleListBox::getSupportedServiceNames() throw(RuntimeException
, std::exception
)
328 return getSupportedServiceNames_Static();
331 sal_Bool SAL_CALL
AccessibleListBox::supportsService( const OUString
& _rServiceName
) throw (RuntimeException
, std::exception
)
333 return cppu::supportsService(this, _rServiceName
);
336 // XServiceInfo - static methods
338 Sequence
< OUString
> AccessibleListBox::getSupportedServiceNames_Static() throw( RuntimeException
)
340 Sequence
< OUString
> aSupported(3);
341 aSupported
[0] = "com.sun.star.accessibility.AccessibleContext";
342 aSupported
[1] = "com.sun.star.accessibility.AccessibleComponent";
343 aSupported
[2] = "com.sun.star.awt.AccessibleTreeListBox";
347 OUString
AccessibleListBox::getImplementationName_Static() throw( RuntimeException
)
349 return OUString( "com.sun.star.comp.svtools.AccessibleTreeListBox" );
354 Reference
< XAccessibleContext
> SAL_CALL
AccessibleListBox::getAccessibleContext( ) throw (RuntimeException
, std::exception
)
360 // XAccessibleContext
362 sal_Int32 SAL_CALL
AccessibleListBox::getAccessibleChildCount( ) throw (RuntimeException
, std::exception
)
364 ::comphelper::OExternalLockGuard
aGuard( this );
368 sal_Int32 nCount
= 0;
369 SvTreeListBox
* pSvTreeListBox
= getListBox();
370 if ( pSvTreeListBox
)
371 nCount
= pSvTreeListBox
->GetLevelChildCount( NULL
);
376 Reference
< XAccessible
> SAL_CALL
AccessibleListBox::getAccessibleChild( sal_Int32 i
) throw (IndexOutOfBoundsException
,RuntimeException
, std::exception
)
378 ::comphelper::OExternalLockGuard
aGuard( this );
381 SvTreeListEntry
* pEntry
= getListBox()->GetEntry(i
);
383 throw IndexOutOfBoundsException();
385 // Solution: Set the parameter of the parent to null to let entry determine the parent by itself
386 //return new AccessibleListBoxEntry( *getListBox(), pEntry, this );
387 return new AccessibleListBoxEntry( *getListBox(), pEntry
, NULL
);
390 Reference
< XAccessible
> SAL_CALL
AccessibleListBox::getAccessibleParent( ) throw (RuntimeException
, std::exception
)
392 ::osl::MutexGuard
aGuard( m_aMutex
);
398 sal_Int32
AccessibleListBox::GetRoleType()
401 SvTreeListEntry
* pEntry
= getListBox()->GetEntry(0);
404 if( pEntry
->HasChildrenOnDemand() || getListBox()->GetChildCount(pEntry
) > 0 )
411 bool bHasButtons
= (getListBox()->GetStyle() & WB_HASBUTTONS
)!=0;
412 if( !(getListBox()->GetTreeFlags() & SvTreeFlags::CHKBTN
) )
427 sal_Int16 SAL_CALL
AccessibleListBox::getAccessibleRole()
428 throw (RuntimeException
, std::exception
)
430 ::comphelper::OExternalLockGuard
aGuard( this );
434 SvTreeAccRoleType nType
= getListBox()->GetAllEntriesAccessibleRoleType();
435 if( nType
== SvTreeAccRoleType::TREE
)
436 return AccessibleRole::TREE
;
437 else if( nType
== SvTreeAccRoleType::LIST
)
438 return AccessibleRole::LIST
;
441 //o is: return AccessibleRole::TREE;
442 bool bHasButtons
= (getListBox()->GetStyle() & WB_HASBUTTONS
)!=0;
443 if(!bHasButtons
&& (getListBox()->GetTreeFlags() & SvTreeFlags::CHKBTN
))
444 return AccessibleRole::LIST
;
446 if (GetRoleType() == 0)
447 return AccessibleRole::LIST
;
449 return AccessibleRole::TREE
;
452 OUString SAL_CALL
AccessibleListBox::getAccessibleDescription( ) throw (RuntimeException
, std::exception
)
454 ::comphelper::OExternalLockGuard
aGuard( this );
457 return getListBox()->GetAccessibleDescription();
460 OUString SAL_CALL
AccessibleListBox::getAccessibleName( ) throw (RuntimeException
, std::exception
)
462 ::comphelper::OExternalLockGuard
aGuard( this );
465 return getListBox()->GetAccessibleName();
468 // XAccessibleSelection
470 void SAL_CALL
AccessibleListBox::selectAccessibleChild( sal_Int32 nChildIndex
) throw (IndexOutOfBoundsException
, RuntimeException
, std::exception
)
472 ::comphelper::OExternalLockGuard
aGuard( this );
476 SvTreeListEntry
* pEntry
= getListBox()->GetEntry( nChildIndex
);
478 throw IndexOutOfBoundsException();
480 getListBox()->Select( pEntry
, true );
483 sal_Bool SAL_CALL
AccessibleListBox::isAccessibleChildSelected( sal_Int32 nChildIndex
) throw (IndexOutOfBoundsException
, RuntimeException
, std::exception
)
485 ::comphelper::OExternalLockGuard
aGuard( this );
489 SvTreeListEntry
* pEntry
= getListBox()->GetEntry( nChildIndex
);
491 throw IndexOutOfBoundsException();
493 return getListBox()->IsSelected( pEntry
);
496 void SAL_CALL
AccessibleListBox::clearAccessibleSelection( ) throw (RuntimeException
, std::exception
)
498 ::comphelper::OExternalLockGuard
aGuard( this );
502 sal_Int32 nCount
= getListBox()->GetLevelChildCount( NULL
);
503 for ( sal_Int32 i
= 0; i
< nCount
; ++i
)
505 SvTreeListEntry
* pEntry
= getListBox()->GetEntry( i
);
506 if ( getListBox()->IsSelected( pEntry
) )
507 getListBox()->Select( pEntry
, false );
511 void SAL_CALL
AccessibleListBox::selectAllAccessibleChildren( ) throw (RuntimeException
, std::exception
)
513 ::comphelper::OExternalLockGuard
aGuard( this );
517 sal_Int32 nCount
= getListBox()->GetLevelChildCount( NULL
);
518 for ( sal_Int32 i
= 0; i
< nCount
; ++i
)
520 SvTreeListEntry
* pEntry
= getListBox()->GetEntry( i
);
521 if ( !getListBox()->IsSelected( pEntry
) )
522 getListBox()->Select( pEntry
, true );
526 sal_Int32 SAL_CALL
AccessibleListBox::getSelectedAccessibleChildCount( ) throw (RuntimeException
, std::exception
)
528 ::comphelper::OExternalLockGuard
aGuard( this );
532 return getListBox()->GetSelectionCount();
535 Reference
< XAccessible
> SAL_CALL
AccessibleListBox::getSelectedAccessibleChild( sal_Int32 nSelectedChildIndex
) throw (IndexOutOfBoundsException
, RuntimeException
, std::exception
)
537 ::comphelper::OExternalLockGuard
aGuard( this );
541 if ( nSelectedChildIndex
< 0 || nSelectedChildIndex
>= getSelectedAccessibleChildCount() )
542 throw IndexOutOfBoundsException();
544 Reference
< XAccessible
> xChild
;
545 sal_Int32 nSelCount
= 0;
546 sal_Int32 nCount
= getListBox()->GetLevelChildCount( NULL
);
547 for ( sal_Int32 i
= 0; i
< nCount
; ++i
)
549 SvTreeListEntry
* pEntry
= getListBox()->GetEntry( i
);
550 if ( getListBox()->IsSelected( pEntry
) )
553 if ( nSelCount
== ( nSelectedChildIndex
+ 1 ) )
555 // Solution: Set the parameter of the parent to null to let entry determine the parent by itself
556 //xChild = new AccessibleListBoxEntry( *getListBox(), pEntry, this );
557 xChild
= new AccessibleListBoxEntry( *getListBox(), pEntry
, NULL
);
565 void SAL_CALL
AccessibleListBox::deselectAccessibleChild( sal_Int32 nSelectedChildIndex
) throw (IndexOutOfBoundsException
, RuntimeException
, std::exception
)
567 ::comphelper::OExternalLockGuard
aGuard( this );
571 SvTreeListEntry
* pEntry
= getListBox()->GetEntry( nSelectedChildIndex
);
573 throw IndexOutOfBoundsException();
575 getListBox()->Select( pEntry
, false );
578 void AccessibleListBox::FillAccessibleStateSet( utl::AccessibleStateSetHelper
& rStateSet
)
580 VCLXAccessibleComponent::FillAccessibleStateSet( rStateSet
);
581 if ( getListBox() && isAlive() )
583 rStateSet
.AddState( AccessibleStateType::FOCUSABLE
);
584 rStateSet
.AddState( AccessibleStateType::MANAGES_DESCENDANTS
);
585 if ( getListBox()->GetSelectionMode() == MULTIPLE_SELECTION
)
586 rStateSet
.AddState( AccessibleStateType::MULTI_SELECTABLE
);
590 VclPtr
< SvTreeListBox
> AccessibleListBox::getListBox() const
592 return GetAs
< SvTreeListBox
>();
595 }// namespace accessibility
598 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */