Branch libreoffice-5-0-4
[LibreOffice.git] / accessibility / source / standard / vclxaccessiblelist.cxx
blob86272805a4d7c8904193a9837687666c4b326cb4
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/standard/vclxaccessiblelist.hxx>
21 #include <accessibility/standard/vclxaccessiblelistitem.hxx>
22 #include <accessibility/helper/listboxhelper.hxx>
24 #include <unotools/accessiblerelationsethelper.hxx>
25 #include <unotools/accessiblestatesethelper.hxx>
26 #include <com/sun/star/accessibility/AccessibleStateType.hpp>
27 #include <com/sun/star/accessibility/AccessibleEventId.hpp>
28 #include <com/sun/star/accessibility/AccessibleRelationType.hpp>
29 #include <com/sun/star/accessibility/AccessibleRole.hpp>
30 #include <vcl/svapp.hxx>
31 #include <vcl/combobox.hxx>
32 #include <vcl/lstbox.hxx>
33 #include <toolkit/helper/convert.hxx>
35 using namespace ::com::sun::star;
36 using namespace ::com::sun::star::uno;
37 using namespace ::com::sun::star::lang;
38 using namespace ::com::sun::star::beans;
39 using namespace ::com::sun::star::accessibility;
40 using namespace ::accessibility;
42 namespace
44 void checkSelection_Impl( sal_Int32 _nIndex, const IComboListBoxHelper& _rListBox, bool bSelected )
45 throw (::com::sun::star::lang::IndexOutOfBoundsException)
47 sal_Int32 nCount = bSelected ? (sal_Int32)_rListBox.GetSelectEntryCount()
48 : (sal_Int32)_rListBox.GetEntryCount();
49 if ( _nIndex < 0 || _nIndex >= nCount )
50 throw ::com::sun::star::lang::IndexOutOfBoundsException();
54 VCLXAccessibleList::VCLXAccessibleList (VCLXWindow* pVCLWindow, BoxType aBoxType,
55 const Reference< XAccessible >& _xParent)
56 : VCLXAccessibleComponent (pVCLWindow),
57 m_aBoxType (aBoxType),
58 m_pListBoxHelper (0),
59 m_nVisibleLineCount (0),
60 m_nIndexInParent (DEFAULT_INDEX_IN_PARENT),
61 m_nLastTopEntry ( 0 ),
62 m_nLastSelectedPos ( LISTBOX_ENTRY_NOTFOUND ),
63 m_bDisableProcessEvent ( false ),
64 m_bVisible ( true ),
65 m_nCurSelectedPos ( LISTBOX_ENTRY_NOTFOUND ),
66 m_xParent ( _xParent )
68 // Because combo boxes and list boxes don't have a common interface for
69 // methods with identical signature we have to write down twice the
70 // same code.
71 switch (m_aBoxType)
73 case COMBOBOX:
75 VclPtr< ComboBox > pBox = GetAs< ComboBox >();
76 if ( pBox )
77 m_pListBoxHelper = new VCLListBoxHelper<ComboBox> (*pBox);
78 break;
81 case LISTBOX:
83 VclPtr< ListBox > pBox = GetAs< ListBox >();
84 if ( pBox )
85 m_pListBoxHelper = new VCLListBoxHelper<ListBox> (*pBox);
86 break;
89 UpdateVisibleLineCount();
90 if(m_pListBoxHelper)
92 m_nCurSelectedPos=m_pListBoxHelper->GetSelectEntryPos();
94 sal_uInt16 nCount = static_cast<sal_uInt16>(getAccessibleChildCount());
95 m_aAccessibleChildren.reserve(nCount);
99 VCLXAccessibleList::~VCLXAccessibleList()
101 delete m_pListBoxHelper;
105 void VCLXAccessibleList::SetIndexInParent (sal_Int32 nIndex)
107 m_nIndexInParent = nIndex;
111 void SAL_CALL VCLXAccessibleList::disposing()
113 VCLXAccessibleComponent::disposing();
115 // Dispose all items in the list.
116 clearItems();
118 delete m_pListBoxHelper;
119 m_pListBoxHelper = NULL;
123 void VCLXAccessibleList::clearItems()
125 // Clear the list itself and delete all the rest.
126 ListItems().swap(m_aAccessibleChildren); // clear and minimize
130 void VCLXAccessibleList::FillAccessibleStateSet (utl::AccessibleStateSetHelper& rStateSet)
132 SolarMutexGuard aSolarGuard;
134 VCLXAccessibleComponent::FillAccessibleStateSet( rStateSet );
135 // check if our list should be visible
136 if ( m_pListBoxHelper
137 && (m_pListBoxHelper->GetStyle() & WB_DROPDOWN ) == WB_DROPDOWN
138 && !m_pListBoxHelper->IsInDropDown() )
140 rStateSet.RemoveState (AccessibleStateType::VISIBLE);
141 rStateSet.RemoveState (AccessibleStateType::SHOWING);
142 m_bVisible = false;
145 // Both the combo box and list box are handled identical in the
146 // following but for some reason they don't have a common interface for
147 // the methods used.
148 if ( m_pListBoxHelper )
150 if ( m_pListBoxHelper->IsMultiSelectionEnabled() )
151 rStateSet.AddState( AccessibleStateType::MULTI_SELECTABLE);
152 rStateSet.AddState (AccessibleStateType::FOCUSABLE);
153 // All children are transient.
154 rStateSet.AddState (AccessibleStateType::MANAGES_DESCENDANTS);
158 void VCLXAccessibleList::notifyVisibleStates(bool _bSetNew )
160 m_bVisible = _bSetNew;
161 Any aOldValue, aNewValue;
162 (_bSetNew ? aNewValue : aOldValue ) <<= AccessibleStateType::VISIBLE;
163 NotifyAccessibleEvent( AccessibleEventId::STATE_CHANGED, aOldValue, aNewValue );
164 (_bSetNew ? aNewValue : aOldValue ) <<= AccessibleStateType::SHOWING;
165 NotifyAccessibleEvent( AccessibleEventId::STATE_CHANGED, aOldValue, aNewValue );
167 ListItems::iterator aIter = m_aAccessibleChildren.begin();
168 ListItems::iterator aEnd = m_aAccessibleChildren.end();
169 UpdateVisibleLineCount();
170 // adjust the index inside the VCLXAccessibleListItem
171 for (;aIter != aEnd ; ++aIter)
173 Reference< XAccessible > xHold = *aIter;
174 VCLXAccessibleListItem* pItem = static_cast<VCLXAccessibleListItem*>(xHold.get());
175 if ( pItem )
177 sal_uInt16 nTopEntry = 0;
178 if ( m_pListBoxHelper )
179 nTopEntry = m_pListBoxHelper->GetTopEntry();
180 sal_uInt16 nPos = (sal_uInt16)(aIter - m_aAccessibleChildren.begin());
181 bool bVisible = ( nPos>=nTopEntry && nPos<( nTopEntry + m_nVisibleLineCount ) );
182 pItem->SetVisible( m_bVisible && bVisible );
188 void VCLXAccessibleList::UpdateSelection_Acc (const ::rtl::OUString& sTextOfSelectedItem, bool b_IsDropDownList)
190 if ( m_aBoxType == COMBOBOX )
192 VclPtr< ComboBox > pBox = GetAs< ComboBox >();
193 if ( pBox )
195 // Find the index of the selected item inside the VCL control...
196 sal_Int32 nIndex = pBox->GetEntryPos(sTextOfSelectedItem);
197 // ...and then find the associated accessibility object.
198 if ( nIndex == LISTBOX_ENTRY_NOTFOUND )
199 nIndex = 0;
200 /* FIXME: is there something missing here? nIndex is unused. Looks
201 * like copy-paste from VCLXAccessibleList::UpdateSelection() */
202 UpdateSelection_Impl_Acc(b_IsDropDownList);
208 void VCLXAccessibleList::UpdateSelection_Impl_Acc(bool bHasDropDownList)
210 uno::Any aOldValue, aNewValue;
213 SolarMutexGuard aSolarGuard;
214 ::osl::Guard< ::osl::Mutex > aGuard( GetMutex() );
215 Reference< XAccessible > xNewAcc;
216 if ( m_pListBoxHelper )
218 sal_uInt32 i=0;
219 m_nCurSelectedPos = LISTBOX_ENTRY_NOTFOUND;
220 for ( ListItems::iterator aIter = m_aAccessibleChildren.begin();
221 aIter != m_aAccessibleChildren.end(); ++aIter,++i)
223 Reference< XAccessible > xHold = *aIter;
224 if ( xHold.is() )
226 VCLXAccessibleListItem* pItem = static_cast< VCLXAccessibleListItem* >( xHold.get() );
227 // Retrieve the item's index from the list entry.
228 bool bNowSelected = m_pListBoxHelper->IsEntryPosSelected (i);
229 if (bNowSelected)
230 m_nCurSelectedPos = i;
232 if ( bNowSelected && !pItem->IsSelected() )
234 xNewAcc = *aIter;
235 aNewValue <<= xNewAcc;
237 else if ( pItem->IsSelected() )
238 m_nLastSelectedPos = i;
240 pItem->SetSelected( bNowSelected );
242 else
243 { // it could happen that a child was not created before
244 checkEntrySelected(i,aNewValue,xNewAcc);
247 sal_uInt16 nCount = m_pListBoxHelper->GetEntryCount();
248 if ( i < nCount ) // here we have to check the if any other listbox entry is selected
250 for (; i < nCount && !checkEntrySelected(i,aNewValue,xNewAcc) ;++i )
253 if ( xNewAcc.is() && GetWindow()->HasFocus() )
255 if ( m_nLastSelectedPos != LISTBOX_ENTRY_NOTFOUND )
256 aOldValue <<= getAccessibleChild( (sal_Int32)m_nLastSelectedPos );
257 aNewValue <<= xNewAcc;
262 if (m_aBoxType == COMBOBOX)
264 //VCLXAccessibleDropDownComboBox
265 //when in list is dropped down, xText = NULL
266 if (bHasDropDownList && m_pListBoxHelper && m_pListBoxHelper->IsInDropDown())
268 if ( aNewValue.hasValue() || aOldValue.hasValue() )
270 NotifyAccessibleEvent(
271 AccessibleEventId::ACTIVE_DESCENDANT_CHANGED,
272 aOldValue,
273 aNewValue );
275 NotifyListItem(aNewValue);
278 else
280 //VCLXAccessibleComboBox
281 NotifyAccessibleEvent( AccessibleEventId::SELECTION_CHANGED, uno::Any(), uno::Any() );
284 else if (m_aBoxType == LISTBOX)
286 if ( aNewValue.hasValue() || aOldValue.hasValue() )
288 NotifyAccessibleEvent(
289 AccessibleEventId::ACTIVE_DESCENDANT_CHANGED,
290 aOldValue,
291 aNewValue );
293 NotifyListItem(aNewValue);
298 void VCLXAccessibleList::NotifyListItem(::com::sun::star::uno::Any& val)
300 Reference< XAccessible > xCurItem;
301 val >>= xCurItem;
302 if (xCurItem.is())
304 VCLXAccessibleListItem* pCurItem = static_cast< VCLXAccessibleListItem* >(xCurItem.get());
305 if (pCurItem)
307 pCurItem->NotifyAccessibleEvent(AccessibleEventId::SELECTION_CHANGED,Any(),Any());
312 void VCLXAccessibleList::UpdateFocus_Impl_Acc (sal_uInt16 nPos ,bool b_IsDropDownList)
314 if (!(m_aBoxType == LISTBOX && !b_IsDropDownList))
316 return ;
318 Reference<XAccessible> xChild= CreateChild(nPos);
319 if ( !xChild.is() )
321 return ;
323 m_nCurSelectedPos = nPos;
324 uno::Any aOldValue, aNewValue;
325 aNewValue <<= xChild;
327 NotifyAccessibleEvent(
328 AccessibleEventId::ACTIVE_DESCENDANT_CHANGED,
329 aOldValue,
330 aNewValue );
334 void VCLXAccessibleList::ProcessWindowEvent (const VclWindowEvent& rVclWindowEvent, bool b_IsDropDownList)
336 switch ( rVclWindowEvent.GetId() )
338 case VCLEVENT_DROPDOWN_SELECT:
339 case VCLEVENT_LISTBOX_SELECT:
340 if ( !m_bDisableProcessEvent )
341 UpdateSelection_Impl_Acc(b_IsDropDownList);
342 break;
343 case VCLEVENT_LISTBOX_FOCUSITEMCHANGED:
344 if ( !m_bDisableProcessEvent )
345 UpdateFocus_Impl_Acc((sal_uInt16)reinterpret_cast<sal_uIntPtr>(rVclWindowEvent.GetData()),b_IsDropDownList);
346 break;
347 case VCLEVENT_WINDOW_GETFOCUS:
348 break;
349 case VCLEVENT_CONTROL_GETFOCUS:
351 VCLXAccessibleComponent::ProcessWindowEvent (rVclWindowEvent);
352 if (m_aBoxType == COMBOBOX && b_IsDropDownList)
354 //VCLXAccessibleDropDownComboBox
356 else if (m_aBoxType == LISTBOX && b_IsDropDownList)
359 else if ( m_aBoxType == LISTBOX && !b_IsDropDownList)
361 if ( m_pListBoxHelper )
363 uno::Any aOldValue,
364 aNewValue;
365 sal_Int32 nPos = m_nCurSelectedPos; //m_pListBoxHelper->GetSelectEntryPos();
367 if ( nPos == LISTBOX_ENTRY_NOTFOUND )
368 nPos = m_pListBoxHelper->GetTopEntry();
369 if ( nPos != LISTBOX_ENTRY_NOTFOUND )
370 aNewValue <<= CreateChild(nPos);
371 NotifyAccessibleEvent( AccessibleEventId::ACTIVE_DESCENDANT_CHANGED,
372 aOldValue,
373 aNewValue );
377 break;
378 default:
379 break;
384 void VCLXAccessibleList::ProcessWindowEvent (const VclWindowEvent& rVclWindowEvent)
386 // Create a reference to this object to prevent an early release of the
387 // listbox (VCLEVENT_OBJECT_DYING).
388 Reference< XAccessible > xTemp = this;
390 switch ( rVclWindowEvent.GetId() )
392 case VCLEVENT_DROPDOWN_OPEN:
393 notifyVisibleStates(true);
394 break;
395 case VCLEVENT_DROPDOWN_CLOSE:
396 notifyVisibleStates(false);
397 break;
398 case VCLEVENT_LISTBOX_SCROLLED:
399 case VCLEVENT_COMBOBOX_SCROLLED:
400 UpdateEntryRange_Impl();
401 break;
403 // The selection events VCLEVENT_COMBOBOX_SELECT and
404 // VCLEVENT_COMBOBOX_DESELECT are not handled here because here we
405 // have no access to the edit field. Its text is necessary to
406 // identify the currently selected item.
408 case VCLEVENT_OBJECT_DYING:
410 dispose();
412 VCLXAccessibleComponent::ProcessWindowEvent (rVclWindowEvent);
413 break;
416 case VCLEVENT_LISTBOX_ITEMREMOVED:
417 case VCLEVENT_COMBOBOX_ITEMREMOVED:
418 HandleChangedItemList (false, reinterpret_cast<sal_IntPtr>(
419 rVclWindowEvent.GetData()));
420 break;
422 case VCLEVENT_LISTBOX_ITEMADDED:
423 case VCLEVENT_COMBOBOX_ITEMADDED:
424 HandleChangedItemList (true, reinterpret_cast<sal_IntPtr>(
425 rVclWindowEvent.GetData()));
426 break;
427 case VCLEVENT_CONTROL_GETFOCUS:
429 VCLXAccessibleComponent::ProcessWindowEvent (rVclWindowEvent);
430 // Added by IBM Symphony Acc team to handle the list item focus when List control get focus
431 bool b_IsDropDownList = true;
432 if (m_pListBoxHelper)
433 b_IsDropDownList = ((m_pListBoxHelper->GetStyle() & WB_DROPDOWN ) == WB_DROPDOWN);
434 if ( m_aBoxType == LISTBOX && !b_IsDropDownList )
436 if ( m_pListBoxHelper )
438 uno::Any aOldValue,
439 aNewValue;
440 sal_Int32 nPos = m_nCurSelectedPos;
442 if ( nPos == LISTBOX_ENTRY_NOTFOUND )
443 nPos = m_pListBoxHelper->GetTopEntry();
444 if ( nPos != LISTBOX_ENTRY_NOTFOUND )
445 aNewValue <<= CreateChild(nPos);
446 NotifyAccessibleEvent( AccessibleEventId::ACTIVE_DESCENDANT_CHANGED,
447 aOldValue,
448 aNewValue );
452 break;
454 default:
455 VCLXAccessibleComponent::ProcessWindowEvent (rVclWindowEvent);
459 void VCLXAccessibleList::FillAccessibleRelationSet( utl::AccessibleRelationSetHelper& rRelationSet )
461 VclPtr< ListBox > pBox = GetAs< ListBox >();
462 if( m_aBoxType == LISTBOX )
464 if (m_pListBoxHelper && (m_pListBoxHelper->GetStyle() & WB_DROPDOWN ) != WB_DROPDOWN)
466 uno::Sequence< uno::Reference< uno::XInterface > > aSequence(1);
467 aSequence[0] = pBox->GetAccessible();
468 rRelationSet.AddRelation( com::sun::star::accessibility::AccessibleRelation( com::sun::star::accessibility::AccessibleRelationType::MEMBER_OF, aSequence ) );
471 else
473 VCLXAccessibleComponent::FillAccessibleRelationSet(rRelationSet);
478 /** To find out which item is currently selected and to update the SELECTED
479 state of the associated accessibility objects accordingly we exploit the
480 fact that the
482 void VCLXAccessibleList::UpdateSelection (const OUString& sTextOfSelectedItem)
484 if ( m_aBoxType == COMBOBOX )
486 VclPtr< ComboBox > pBox = GetAs< ComboBox >();
487 if ( pBox )
489 // Find the index of the selected item inside the VCL control...
490 sal_Int32 nIndex = pBox->GetEntryPos(sTextOfSelectedItem);
491 // ...and then find the associated accessibility object.
492 if ( nIndex == LISTBOX_ENTRY_NOTFOUND )
493 nIndex = 0;
494 UpdateSelection_Impl(nIndex);
501 Reference<XAccessible> VCLXAccessibleList::CreateChild (sal_Int32 i)
503 Reference<XAccessible> xChild;
505 sal_uInt16 nPos = static_cast<sal_uInt16>(i);
506 if ( nPos >= m_aAccessibleChildren.size() )
508 m_aAccessibleChildren.resize(nPos + 1);
510 // insert into the container
511 xChild = new VCLXAccessibleListItem(m_pListBoxHelper, i, this);
512 m_aAccessibleChildren[nPos] = xChild;
514 else
516 xChild = m_aAccessibleChildren[nPos];
517 // check if position is empty and can be used else we have to adjust all entries behind this
518 if (!xChild.is())
520 xChild = new VCLXAccessibleListItem(m_pListBoxHelper, i, this);
521 m_aAccessibleChildren[nPos] = xChild;
525 if ( xChild.is() )
527 // Just add the SELECTED state.
528 bool bNowSelected = false;
529 if ( m_pListBoxHelper )
530 bNowSelected = m_pListBoxHelper->IsEntryPosSelected ((sal_uInt16)i);
531 if (bNowSelected)
532 m_nCurSelectedPos = sal_uInt16(i);
533 VCLXAccessibleListItem* pItem = static_cast< VCLXAccessibleListItem* >(xChild.get());
534 pItem->SetSelected( bNowSelected );
536 // Set the child's VISIBLE state.
537 UpdateVisibleLineCount();
538 sal_uInt16 nTopEntry = 0;
539 if ( m_pListBoxHelper )
540 nTopEntry = m_pListBoxHelper->GetTopEntry();
541 bool bVisible = ( nPos>=nTopEntry && nPos<( nTopEntry + m_nVisibleLineCount ) );
542 pItem->SetVisible( m_bVisible && bVisible );
545 return xChild;
549 void VCLXAccessibleList::HandleChangedItemList (bool /*bItemInserted*/, sal_Int32 /*nIndex*/)
551 clearItems();
552 NotifyAccessibleEvent (
553 AccessibleEventId::INVALIDATE_ALL_CHILDREN,
554 Any(), Any());
558 IMPLEMENT_FORWARD_XINTERFACE2(VCLXAccessibleList, VCLXAccessibleComponent, VCLXAccessibleList_BASE)
559 IMPLEMENT_FORWARD_XTYPEPROVIDER2(VCLXAccessibleList, VCLXAccessibleComponent, VCLXAccessibleList_BASE)
561 // XAccessible
563 Reference<XAccessibleContext> SAL_CALL
564 VCLXAccessibleList::getAccessibleContext()
565 throw (RuntimeException, std::exception)
567 return this;
571 // XAccessibleContext
573 sal_Int32 SAL_CALL VCLXAccessibleList::getAccessibleChildCount()
574 throw (RuntimeException, std::exception)
576 SolarMutexGuard aSolarGuard;
577 ::osl::Guard< ::osl::Mutex > aGuard( GetMutex() );
579 sal_Int32 nCount = 0;
580 if ( m_pListBoxHelper )
581 nCount = m_pListBoxHelper->GetEntryCount();
583 return nCount;
586 Reference<XAccessible> SAL_CALL VCLXAccessibleList::getAccessibleChild (sal_Int32 i)
587 throw (IndexOutOfBoundsException, RuntimeException, std::exception)
589 SolarMutexGuard aSolarGuard;
590 ::osl::Guard< ::osl::Mutex > aGuard( GetMutex() );
592 if ( i < 0 || i >= getAccessibleChildCount() )
593 throw IndexOutOfBoundsException();
595 Reference< XAccessible > xChild;
596 // search for the child
597 if ( i >= static_cast<sal_Int32>(m_aAccessibleChildren.size()) )
598 xChild = CreateChild (i);
599 else
601 xChild = m_aAccessibleChildren[i];
602 if ( !xChild.is() )
603 xChild = CreateChild (i);
605 OSL_ENSURE( xChild.is(), "VCLXAccessibleList::getAccessibleChild: returning empty child!" );
606 return xChild;
609 Reference< XAccessible > SAL_CALL VCLXAccessibleList::getAccessibleParent( )
610 throw (RuntimeException, std::exception)
612 ::osl::Guard< ::osl::Mutex > aGuard( GetMutex() );
614 return m_xParent;
617 sal_Int32 SAL_CALL VCLXAccessibleList::getAccessibleIndexInParent()
618 throw (::com::sun::star::uno::RuntimeException, std::exception)
620 if (m_nIndexInParent != DEFAULT_INDEX_IN_PARENT)
621 return m_nIndexInParent;
622 else
623 return VCLXAccessibleComponent::getAccessibleIndexInParent();
626 sal_Int16 SAL_CALL VCLXAccessibleList::getAccessibleRole()
627 throw (RuntimeException, std::exception)
629 return AccessibleRole::LIST;
632 // XServiceInfo
633 OUString VCLXAccessibleList::getImplementationName()
634 throw (RuntimeException, std::exception)
636 return OUString( "com.sun.star.comp.toolkit.AccessibleList" );
639 Sequence< OUString > VCLXAccessibleList::getSupportedServiceNames()
640 throw (RuntimeException, std::exception)
642 Sequence< OUString > aNames = VCLXAccessibleComponent::getSupportedServiceNames();
643 sal_Int32 nLength = aNames.getLength();
644 aNames.realloc( nLength + 1 );
645 aNames[nLength] = "com.sun.star.accessibility.AccessibleList";
646 return aNames;
649 void VCLXAccessibleList::UpdateVisibleLineCount()
651 if ( m_pListBoxHelper )
653 if ( (m_pListBoxHelper->GetStyle() & WB_DROPDOWN ) == WB_DROPDOWN )
654 m_nVisibleLineCount = m_pListBoxHelper->GetDisplayLineCount();
655 else
657 sal_uInt16 nCols = 0,
658 nLines = 0;
659 m_pListBoxHelper->GetMaxVisColumnsAndLines (nCols, nLines);
660 m_nVisibleLineCount = nLines;
665 void VCLXAccessibleList::UpdateEntryRange_Impl()
667 SolarMutexGuard aSolarGuard;
668 ::osl::Guard< ::osl::Mutex > aGuard( GetMutex() );
670 sal_Int32 nTop = m_nLastTopEntry;
672 if ( m_pListBoxHelper )
673 nTop = m_pListBoxHelper->GetTopEntry();
674 if ( nTop != m_nLastTopEntry )
676 UpdateVisibleLineCount();
677 sal_Int32 nBegin = std::min( m_nLastTopEntry, nTop );
678 sal_Int32 nEnd = std::max( m_nLastTopEntry + m_nVisibleLineCount, nTop + m_nVisibleLineCount );
679 for (sal_uInt16 i = static_cast<sal_uInt16>(nBegin); (i <= static_cast<sal_uInt16>(nEnd)); ++i)
681 bool bVisible = ( i >= nTop && i < ( nTop + m_nVisibleLineCount ) );
682 Reference< XAccessible > xHold;
683 if ( i < m_aAccessibleChildren.size() )
684 xHold = m_aAccessibleChildren[i];
685 else if ( bVisible )
686 xHold = CreateChild(i);
688 if ( xHold.is() )
689 static_cast< VCLXAccessibleListItem* >( xHold.get() )->SetVisible( m_bVisible && bVisible );
693 m_nLastTopEntry = nTop;
696 bool VCLXAccessibleList::checkEntrySelected(sal_uInt16 _nPos,Any& _rNewValue,Reference< XAccessible >& _rxNewAcc)
698 OSL_ENSURE(m_pListBoxHelper,"Helper is not valid!");
699 bool bNowSelected = false;
700 if ( m_pListBoxHelper )
702 bNowSelected = m_pListBoxHelper->IsEntryPosSelected (_nPos);
703 if ( bNowSelected )
705 _rxNewAcc = CreateChild(_nPos);
706 _rNewValue <<= _rxNewAcc;
709 return bNowSelected;
713 void VCLXAccessibleList::UpdateSelection_Impl(sal_uInt16)
715 uno::Any aOldValue, aNewValue;
718 SolarMutexGuard aSolarGuard;
719 ::osl::Guard< ::osl::Mutex > aGuard( GetMutex() );
720 Reference< XAccessible > xNewAcc;
722 if ( m_pListBoxHelper )
724 sal_uInt16 i=0;
725 m_nCurSelectedPos = LISTBOX_ENTRY_NOTFOUND;
726 for ( ListItems::iterator aIter = m_aAccessibleChildren.begin();
727 aIter != m_aAccessibleChildren.end(); ++aIter,++i)
729 Reference< XAccessible > xHold = *aIter;
730 if ( xHold.is() )
732 VCLXAccessibleListItem* pItem = static_cast< VCLXAccessibleListItem* >( xHold.get() );
733 // Retrieve the item's index from the list entry.
734 bool bNowSelected = m_pListBoxHelper->IsEntryPosSelected (i);
735 if (bNowSelected)
736 m_nCurSelectedPos = i;
738 if ( bNowSelected && !pItem->IsSelected() )
740 xNewAcc = *aIter;
741 aNewValue <<= xNewAcc;
743 else if ( pItem->IsSelected() )
744 m_nLastSelectedPos = i;
746 pItem->SetSelected( bNowSelected );
748 else
749 { // it could happen that a child was not created before
750 checkEntrySelected(i,aNewValue,xNewAcc);
753 sal_uInt16 nCount = m_pListBoxHelper->GetEntryCount();
754 if ( i < nCount ) // here we have to check the if any other listbox entry is selected
756 for (; i < nCount && !checkEntrySelected(i,aNewValue,xNewAcc) ;++i )
759 if ( xNewAcc.is() && GetWindow()->HasFocus() )
761 if ( m_nLastSelectedPos != LISTBOX_ENTRY_NOTFOUND )
762 aOldValue <<= getAccessibleChild( (sal_Int32)m_nLastSelectedPos );
763 aNewValue <<= xNewAcc;
765 if (m_pListBoxHelper->IsInDropDown())
767 if ( aNewValue.hasValue() || aOldValue.hasValue() )
768 NotifyAccessibleEvent(
769 AccessibleEventId::ACTIVE_DESCENDANT_CHANGED,
770 aOldValue,
771 aNewValue );
772 //the SELECTION_CHANGED is not necessary
773 //NotifyAccessibleEvent( AccessibleEventId::SELECTION_CHANGED, Any(), Any() );
780 // XAccessibleSelection
782 void SAL_CALL VCLXAccessibleList::selectAccessibleChild( sal_Int32 nChildIndex ) throw (IndexOutOfBoundsException, RuntimeException, std::exception)
784 bool bNotify = false;
787 SolarMutexGuard aSolarGuard;
788 ::osl::Guard< ::osl::Mutex > aGuard( GetMutex() );
790 if ( m_pListBoxHelper )
792 checkSelection_Impl(nChildIndex,*m_pListBoxHelper,false);
794 m_pListBoxHelper->SelectEntryPos( (sal_uInt16)nChildIndex, true );
795 // call the select handler, don't handle events in this time
796 m_bDisableProcessEvent = true;
797 m_pListBoxHelper->Select();
798 m_bDisableProcessEvent = false;
799 bNotify = true;
803 if ( bNotify )
804 UpdateSelection_Impl();
807 sal_Bool SAL_CALL VCLXAccessibleList::isAccessibleChildSelected( sal_Int32 nChildIndex ) throw (IndexOutOfBoundsException, RuntimeException, std::exception)
809 SolarMutexGuard aSolarGuard;
810 ::osl::Guard< ::osl::Mutex > aGuard( GetMutex() );
812 bool bRet = false;
813 if ( m_pListBoxHelper )
815 checkSelection_Impl(nChildIndex,*m_pListBoxHelper,false);
817 bRet = m_pListBoxHelper->IsEntryPosSelected( (sal_uInt16)nChildIndex );
819 return bRet;
822 void SAL_CALL VCLXAccessibleList::clearAccessibleSelection( ) throw (RuntimeException, std::exception)
824 bool bNotify = false;
827 SolarMutexGuard aSolarGuard;
828 ::osl::Guard< ::osl::Mutex > aGuard( GetMutex() );
830 if ( m_pListBoxHelper )
832 m_pListBoxHelper->SetNoSelection();
833 bNotify = true;
837 if ( bNotify )
838 UpdateSelection_Impl();
841 void SAL_CALL VCLXAccessibleList::selectAllAccessibleChildren( ) throw (RuntimeException, std::exception)
843 bool bNotify = false;
846 SolarMutexGuard aSolarGuard;
847 ::osl::Guard< ::osl::Mutex > aGuard( GetMutex() );
849 if ( m_pListBoxHelper )
851 sal_uInt16 nCount = m_pListBoxHelper->GetEntryCount();
852 for ( sal_uInt16 i = 0; i < nCount; ++i )
853 m_pListBoxHelper->SelectEntryPos( i, true );
854 // call the select handler, don't handle events in this time
855 m_bDisableProcessEvent = true;
856 m_pListBoxHelper->Select();
857 m_bDisableProcessEvent = false;
858 bNotify = true;
862 if ( bNotify )
863 UpdateSelection_Impl();
866 sal_Int32 SAL_CALL VCLXAccessibleList::getSelectedAccessibleChildCount( ) throw (RuntimeException, std::exception)
868 SolarMutexGuard aSolarGuard;
869 ::osl::Guard< ::osl::Mutex > aGuard( GetMutex() );
871 sal_Int32 nCount = 0;
872 if ( m_pListBoxHelper )
873 nCount = m_pListBoxHelper->GetSelectEntryCount();
874 return nCount;
877 Reference< XAccessible > SAL_CALL VCLXAccessibleList::getSelectedAccessibleChild( sal_Int32 nSelectedChildIndex ) throw (IndexOutOfBoundsException, RuntimeException, std::exception)
879 SolarMutexGuard aSolarGuard;
880 ::osl::Guard< ::osl::Mutex > aGuard( GetMutex() );
882 if ( m_pListBoxHelper )
884 checkSelection_Impl(nSelectedChildIndex,*m_pListBoxHelper,true);
885 return getAccessibleChild( (sal_Int32)m_pListBoxHelper->GetSelectEntryPos( (sal_uInt16)nSelectedChildIndex ) );
888 return NULL;
891 void SAL_CALL VCLXAccessibleList::deselectAccessibleChild( sal_Int32 nSelectedChildIndex ) throw (IndexOutOfBoundsException, RuntimeException, std::exception)
893 bool bNotify = false;
896 SolarMutexGuard aSolarGuard;
897 ::osl::Guard< ::osl::Mutex > aGuard( GetMutex() );
899 if ( m_pListBoxHelper )
901 checkSelection_Impl(nSelectedChildIndex,*m_pListBoxHelper,false);
903 m_pListBoxHelper->SelectEntryPos( (sal_uInt16)nSelectedChildIndex, false );
904 // call the select handler, don't handle events in this time
905 m_bDisableProcessEvent = true;
906 m_pListBoxHelper->Select();
907 m_bDisableProcessEvent = false;
908 bNotify = true;
912 if ( bNotify )
913 UpdateSelection_Impl();
916 awt::Rectangle VCLXAccessibleList::implGetBounds() throw (uno::RuntimeException)
918 awt::Rectangle aBounds ( 0, 0, 0, 0 );
919 if ( m_pListBoxHelper
920 && (m_pListBoxHelper->GetStyle() & WB_DROPDOWN ) == WB_DROPDOWN )
922 if ( m_pListBoxHelper->IsInDropDown() )
923 aBounds = AWTRectangle(m_pListBoxHelper->GetDropDownPosSizePixel());
925 else
927 // a list has the same bounds as his parent but starts at (0,0)
928 aBounds = VCLXAccessibleComponent::implGetBounds();
929 aBounds.X = 0;
930 aBounds.Y = 0;
931 if ( m_aBoxType == COMBOBOX )
933 VclPtr< ComboBox > pBox = GetAs< ComboBox >();
934 if ( pBox )
936 Size aSize = pBox->GetSubEdit()->GetSizePixel();
937 aBounds.Y += aSize.Height();
938 aBounds.Height -= aSize.Height();
942 return aBounds;
946 awt::Point VCLXAccessibleList::getLocationOnScreen( ) throw (uno::RuntimeException, std::exception)
948 SolarMutexGuard aSolarGuard;
949 ::osl::Guard< ::osl::Mutex > aGuard( GetMutex() );
951 awt::Point aPos;
952 if ( m_pListBoxHelper
953 && (m_pListBoxHelper->GetStyle() & WB_DROPDOWN ) == WB_DROPDOWN )
955 if ( m_pListBoxHelper->IsInDropDown() )
956 aPos = AWTPoint(m_pListBoxHelper->GetDropDownPosSizePixel().TopLeft());
958 else
960 aPos = VCLXAccessibleComponent::getLocationOnScreen();
961 if ( m_aBoxType == COMBOBOX )
963 VclPtr< ComboBox > pBox = GetAs< ComboBox >();
964 if ( pBox )
966 aPos.Y += pBox->GetSubEdit()->GetSizePixel().Height();
970 return aPos;
975 bool VCLXAccessibleList::IsInDropDown()
977 return m_pListBoxHelper->IsInDropDown();
982 void VCLXAccessibleList::HandleDropOpen()
984 if ( !m_bDisableProcessEvent )
985 UpdateSelection_Impl();
986 if (m_nCurSelectedPos != LISTBOX_ENTRY_NOTFOUND &&
987 m_nLastSelectedPos != LISTBOX_ENTRY_NOTFOUND)
989 Reference< XAccessible > xChild = getAccessibleChild(m_nCurSelectedPos);
990 if(xChild.is())
992 uno::Any aNewValue;
993 aNewValue <<= xChild;
994 NotifyAccessibleEvent(AccessibleEventId::ACTIVE_DESCENDANT_CHANGED, uno::Any(), aNewValue );
999 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */