Branch libreoffice-5-0-4
[LibreOffice.git] / accessibility / source / extended / accessiblelistbox.cxx
blob22cc0202e7bbdb06542c6a2ab7f2352108a7eeeb
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 <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;
49 // Ctor() and Dtor()
51 AccessibleListBox::AccessibleListBox( SvTreeListBox& _rListBox, const Reference< XAccessible >& _xParent ) :
53 VCLXAccessibleComponent( _rListBox.GetWindowPeer() ),
54 m_xParent( _xParent )
58 AccessibleListBox::~AccessibleListBox()
60 if ( isAlive() )
62 // increment ref count to prevent double call of Dtor
63 osl_atomic_increment( &m_refCount );
64 dispose();
67 IMPLEMENT_FORWARD_XINTERFACE2(AccessibleListBox, VCLXAccessibleComponent, AccessibleListBox_BASE)
68 IMPLEMENT_FORWARD_XTYPEPROVIDER2(AccessibleListBox, VCLXAccessibleComponent, AccessibleListBox_BASE)
70 void AccessibleListBox::ProcessWindowEvent( const VclWindowEvent& rVclWindowEvent )
72 if ( isAlive() )
74 switch ( rVclWindowEvent.GetId() )
76 case VCLEVENT_CHECKBOX_TOGGLE :
78 if ( !getListBox() || !getListBox()->HasFocus() )
80 return;
82 AccessibleListBoxEntry* pCurOpEntry = GetCurEventEntry(rVclWindowEvent);
83 if(!pCurOpEntry)
85 return ;
87 uno::Any aValue;
88 aValue <<= AccessibleStateType::CHECKED;
90 if ( getListBox()->GetCheckButtonState( pCurOpEntry->GetSvLBoxEntry() ) == SV_BUTTON_CHECKED )
92 pCurOpEntry->NotifyAccessibleEvent( AccessibleEventId::STATE_CHANGED, uno::Any(), aValue );
94 else
96 pCurOpEntry->NotifyAccessibleEvent( AccessibleEventId::STATE_CHANGED, aValue,uno::Any() );
98 break;
101 case VCLEVENT_LISTBOX_SELECT :
103 OSL_FAIL("Debug: Treelist shouldn't use VCLEVENT_LISTBOX_SELECT");
104 break;
107 case VCLEVENT_LISTBOX_TREESELECT:
109 if ( getListBox() && getListBox()->HasFocus() )
111 AccessibleListBoxEntry* pEntry =static_cast< AccessibleListBoxEntry* >(m_xFocusedChild.get());
112 if (pEntry)
114 pEntry->NotifyAccessibleEvent( AccessibleEventId::SELECTION_CHANGED, Any(), Any() );
118 break;
119 case VCLEVENT_LISTBOX_TREEFOCUS:
121 SvTreeListBox* pBox = getListBox();
122 bool bNeedFocus = false;
123 if (pBox)
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)
134 bNeedFocus = true;
138 if( pBox && (pBox->HasFocus() || bNeedFocus) )
140 uno::Any aOldValue, aNewValue;
141 SvTreeListEntry* pEntry = static_cast< SvTreeListEntry* >( rVclWindowEvent.GetData() );
142 if ( pEntry )
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 );
150 return ;
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;
161 else
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 );
171 else
173 aOldValue <<= uno::Any();
174 aNewValue <<= AccessibleStateType::FOCUSED;
175 NotifyAccessibleEvent( AccessibleEventId::STATE_CHANGED, aOldValue, aNewValue );
179 break;
180 case VCLEVENT_LISTBOX_ITEMREMOVED:
182 SvTreeListEntry* pEntry = static_cast< SvTreeListEntry* >( rVclWindowEvent.GetData() );
183 if ( pEntry )
185 RemoveChildEntries(pEntry);
187 else
189 // NULL means Clear()
190 MAP_ENTRY::iterator mi = m_mapEntry.begin();
191 for ( ; mi != m_mapEntry.end() ; ++mi)
193 uno::Any aNewValue;
194 uno::Any aOldValue;
195 aOldValue <<= mi->second;
196 NotifyAccessibleEvent( AccessibleEventId::CHILD, aOldValue, aNewValue );
198 m_mapEntry.clear();
201 break;
203 // #i92103#
204 case VCLEVENT_ITEM_EXPANDED :
205 case VCLEVENT_ITEM_COLLAPSED :
207 SvTreeListEntry* pEntry = static_cast< SvTreeListEntry* >( rVclWindowEvent.GetData() );
208 if ( pEntry )
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 );
226 break;
227 default:
228 VCLXAccessibleComponent::ProcessWindowEvent (rVclWindowEvent);
233 AccessibleListBoxEntry* AccessibleListBox::GetCurEventEntry( const VclWindowEvent& rVclWindowEvent )
235 SvTreeListEntry* pEntry = static_cast< SvTreeListEntry* >( rVclWindowEvent.GetData() );
236 if ( !pEntry )
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());
248 else
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));
252 mi = pairMi.first;
255 uno::Any aNewValue;
256 aNewValue <<= mi->second;//xAcc
257 NotifyAccessibleEvent( AccessibleEventId::CHILD, uno::Any(), aNewValue );//Add
259 return pAccCurOptionEntry;
261 else
263 return pEntryFocus;
267 void AccessibleListBox::RemoveChildEntries(SvTreeListEntry* pEntry)
269 MAP_ENTRY::iterator mi = m_mapEntry.find(pEntry);
270 if ( mi != m_mapEntry.end() )
272 uno::Any aNewValue;
273 uno::Any aOldValue;
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);
282 while (pEntryChild)
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:
298 break;
299 default:
301 VCLXAccessibleComponent::ProcessWindowChildEvent( rVclWindowEvent );
303 break;
308 // XComponent
310 void SAL_CALL AccessibleListBox::disposing()
312 ::osl::MutexGuard aGuard( m_aMutex );
314 m_mapEntry.clear();
315 VCLXAccessibleComponent::disposing();
316 m_xParent = NULL;
319 // XServiceInfo
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";
344 return aSupported;
347 OUString AccessibleListBox::getImplementationName_Static() throw( RuntimeException )
349 return OUString( "com.sun.star.comp.svtools.AccessibleTreeListBox" );
352 // XAccessible
354 Reference< XAccessibleContext > SAL_CALL AccessibleListBox::getAccessibleContext( ) throw (RuntimeException, std::exception)
356 ensureAlive();
357 return this;
360 // XAccessibleContext
362 sal_Int32 SAL_CALL AccessibleListBox::getAccessibleChildCount( ) throw (RuntimeException, std::exception)
364 ::comphelper::OExternalLockGuard aGuard( this );
366 ensureAlive();
368 sal_Int32 nCount = 0;
369 SvTreeListBox* pSvTreeListBox = getListBox();
370 if ( pSvTreeListBox )
371 nCount = pSvTreeListBox->GetLevelChildCount( NULL );
373 return nCount;
376 Reference< XAccessible > SAL_CALL AccessibleListBox::getAccessibleChild( sal_Int32 i ) throw (IndexOutOfBoundsException,RuntimeException, std::exception)
378 ::comphelper::OExternalLockGuard aGuard( this );
380 ensureAlive();
381 SvTreeListEntry* pEntry = getListBox()->GetEntry(i);
382 if ( !pEntry )
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 );
394 ensureAlive();
395 return m_xParent;
398 sal_Int32 AccessibleListBox::GetRoleType()
400 sal_Int32 nCase = 0;
401 SvTreeListEntry* pEntry = getListBox()->GetEntry(0);
402 if ( pEntry )
404 if( pEntry->HasChildrenOnDemand() || getListBox()->GetChildCount(pEntry) > 0 )
406 nCase = 1;
407 return nCase;
411 bool bHasButtons = (getListBox()->GetStyle() & WB_HASBUTTONS)!=0;
412 if( !(getListBox()->GetTreeFlags() & SvTreeFlags::CHKBTN) )
414 if( bHasButtons )
415 nCase = 1;
417 else
419 if( bHasButtons )
420 nCase = 2;
421 else
422 nCase = 3;
424 return nCase;
427 sal_Int16 SAL_CALL AccessibleListBox::getAccessibleRole()
428 throw (RuntimeException, std::exception)
430 ::comphelper::OExternalLockGuard aGuard( this );
432 if(getListBox())
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;
445 else
446 if (GetRoleType() == 0)
447 return AccessibleRole::LIST;
448 else
449 return AccessibleRole::TREE;
452 OUString SAL_CALL AccessibleListBox::getAccessibleDescription( ) throw (RuntimeException, std::exception)
454 ::comphelper::OExternalLockGuard aGuard( this );
456 ensureAlive();
457 return getListBox()->GetAccessibleDescription();
460 OUString SAL_CALL AccessibleListBox::getAccessibleName( ) throw (RuntimeException, std::exception)
462 ::comphelper::OExternalLockGuard aGuard( this );
464 ensureAlive();
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 );
474 ensureAlive();
476 SvTreeListEntry* pEntry = getListBox()->GetEntry( nChildIndex );
477 if ( !pEntry )
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 );
487 ensureAlive();
489 SvTreeListEntry* pEntry = getListBox()->GetEntry( nChildIndex );
490 if ( !pEntry )
491 throw IndexOutOfBoundsException();
493 return getListBox()->IsSelected( pEntry );
496 void SAL_CALL AccessibleListBox::clearAccessibleSelection( ) throw (RuntimeException, std::exception)
498 ::comphelper::OExternalLockGuard aGuard( this );
500 ensureAlive();
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 );
515 ensureAlive();
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 );
530 ensureAlive();
532 return getListBox()->GetSelectionCount();
535 Reference< XAccessible > SAL_CALL AccessibleListBox::getSelectedAccessibleChild( sal_Int32 nSelectedChildIndex ) throw (IndexOutOfBoundsException, RuntimeException, std::exception)
537 ::comphelper::OExternalLockGuard aGuard( this );
539 ensureAlive();
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 ) )
551 ++nSelCount;
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 );
558 break;
562 return xChild;
565 void SAL_CALL AccessibleListBox::deselectAccessibleChild( sal_Int32 nSelectedChildIndex ) throw (IndexOutOfBoundsException, RuntimeException, std::exception)
567 ::comphelper::OExternalLockGuard aGuard( this );
569 ensureAlive();
571 SvTreeListEntry* pEntry = getListBox()->GetEntry( nSelectedChildIndex );
572 if ( !pEntry )
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: */