tdf#130857 qt weld: Implement QtInstanceWidget::strip_mnemonic
[LibreOffice.git] / accessibility / source / standard / vclxaccessiblelist.cxx
blob674b500b87037fed381163a8ad088502a4a5c3da
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 <standard/vclxaccessiblelist.hxx>
21 #include <standard/vclxaccessiblelistitem.hxx>
22 #include <helper/listboxhelper.hxx>
24 #include <unotools/accessiblerelationsethelper.hxx>
25 #include <com/sun/star/accessibility/AccessibleStateType.hpp>
26 #include <com/sun/star/accessibility/AccessibleEventId.hpp>
27 #include <com/sun/star/accessibility/AccessibleRelationType.hpp>
28 #include <com/sun/star/accessibility/AccessibleRole.hpp>
29 #include <com/sun/star/lang/IndexOutOfBoundsException.hpp>
30 #include <comphelper/sequence.hxx>
31 #include <comphelper/types.hxx>
32 #include <o3tl/safeint.hxx>
33 #include <vcl/svapp.hxx>
34 #include <vcl/toolkit/combobox.hxx>
35 #include <vcl/toolkit/lstbox.hxx>
36 #include <vcl/unohelp.hxx>
38 using namespace ::com::sun::star;
39 using namespace ::com::sun::star::uno;
40 using namespace ::com::sun::star::lang;
41 using namespace ::com::sun::star::accessibility;
42 using namespace ::accessibility;
44 namespace
46 /// @throws css::lang::IndexOutOfBoundsException
47 void checkSelection_Impl( sal_Int64 _nIndex, const IComboListBoxHelper& _rListBox, bool bSelected )
49 sal_Int32 nCount = bSelected ? _rListBox.GetSelectedEntryCount()
50 : _rListBox.GetEntryCount();
51 if ( _nIndex < 0 || _nIndex >= nCount )
52 throw css::lang::IndexOutOfBoundsException();
56 VCLXAccessibleList::VCLXAccessibleList(vcl::Window* pWindow, BoxType aBoxType,
57 const Reference< XAccessible >& _xParent)
58 : ImplInheritanceHelper (pWindow),
59 m_aBoxType (aBoxType),
60 m_nVisibleLineCount (0),
61 m_nIndexInParent (DEFAULT_INDEX_IN_PARENT),
62 m_nLastTopEntry ( 0 ),
63 m_nLastSelectedPos ( LISTBOX_ENTRY_NOTFOUND ),
64 m_bDisableProcessEvent ( false ),
65 m_bVisible ( true ),
66 m_nCurSelectedPos ( LISTBOX_ENTRY_NOTFOUND ),
67 m_xParent ( _xParent )
69 // Because combo boxes and list boxes don't have a common interface for
70 // methods with identical signature we have to write down twice the
71 // same code.
72 switch (m_aBoxType)
74 case COMBOBOX:
76 VclPtr< ComboBox > pBox = GetAs< ComboBox >();
77 if ( pBox )
78 m_pListBoxHelper.reset( new VCLListBoxHelper<ComboBox> (*pBox) );
79 break;
82 case LISTBOX:
84 VclPtr< ListBox > pBox = GetAs< ListBox >();
85 if ( pBox )
86 m_pListBoxHelper.reset( new VCLListBoxHelper<ListBox> (*pBox) );
87 break;
90 UpdateVisibleLineCount();
91 if(m_pListBoxHelper)
93 m_nCurSelectedPos=m_pListBoxHelper->GetSelectedEntryPos(0);
95 sal_uInt16 nCount = static_cast<sal_uInt16>(getAccessibleChildCount());
96 m_aAccessibleChildren.reserve(nCount);
100 void VCLXAccessibleList::SetIndexInParent (sal_Int32 nIndex)
102 m_nIndexInParent = nIndex;
106 void SAL_CALL VCLXAccessibleList::disposing()
108 VCLXAccessibleComponent::disposing();
110 disposeChildren();
111 m_pListBoxHelper.reset();
114 void VCLXAccessibleList::disposeChildren()
116 // Dispose all items in the list.
117 for (rtl::Reference<VCLXAccessibleListItem>& rxChild : m_aAccessibleChildren)
119 if (rxChild.is())
120 rxChild->dispose();
123 m_aAccessibleChildren.clear();
127 void VCLXAccessibleList::FillAccessibleStateSet (sal_Int64& rStateSet)
129 SolarMutexGuard aSolarGuard;
131 VCLXAccessibleComponent::FillAccessibleStateSet( rStateSet );
132 // check if our list should be visible
133 if ( m_pListBoxHelper
134 && (m_pListBoxHelper->GetStyle() & WB_DROPDOWN ) == WB_DROPDOWN
135 && !m_pListBoxHelper->IsInDropDown() )
137 rStateSet &= ~AccessibleStateType::VISIBLE;
138 rStateSet &= ~AccessibleStateType::SHOWING;
139 m_bVisible = false;
142 // Both the combo box and list box are handled identical in the
143 // following but for some reason they don't have a common interface for
144 // the methods used.
145 if ( m_pListBoxHelper )
147 if ( m_pListBoxHelper->IsMultiSelectionEnabled() )
148 rStateSet |= AccessibleStateType::MULTI_SELECTABLE;
149 rStateSet |= AccessibleStateType::FOCUSABLE;
150 // All children are transient.
151 rStateSet |= AccessibleStateType::MANAGES_DESCENDANTS;
155 void VCLXAccessibleList::notifyVisibleStates(bool _bSetNew )
157 m_bVisible = _bSetNew;
158 Any aOldValue, aNewValue;
159 (_bSetNew ? aNewValue : aOldValue ) <<= AccessibleStateType::VISIBLE;
160 NotifyAccessibleEvent( AccessibleEventId::STATE_CHANGED, aOldValue, aNewValue );
161 (_bSetNew ? aNewValue : aOldValue ) <<= AccessibleStateType::SHOWING;
162 NotifyAccessibleEvent( AccessibleEventId::STATE_CHANGED, aOldValue, aNewValue );
164 auto aIter = m_aAccessibleChildren.begin();
165 UpdateVisibleLineCount();
166 // adjust the index inside the VCLXAccessibleListItem
167 for ( ; aIter != m_aAccessibleChildren.end(); )
169 rtl::Reference<VCLXAccessibleListItem> xChild = *aIter;
170 if (!xChild.is())
172 aIter = m_aAccessibleChildren.erase(aIter);
174 else
176 const sal_Int32 nTopEntry = m_pListBoxHelper ? m_pListBoxHelper->GetTopEntry() : 0;
177 const sal_Int32 nPos = static_cast<sal_Int32>(aIter - m_aAccessibleChildren.begin());
178 bool bVisible = ( nPos>=nTopEntry && nPos<( nTopEntry + m_nVisibleLineCount ) );
179 xChild->SetVisible(m_bVisible && bVisible);
180 ++aIter;
186 void VCLXAccessibleList::UpdateSelection_Acc (std::u16string_view /*sTextOfSelectedItem*/, bool b_IsDropDownList)
188 if ( m_aBoxType != COMBOBOX )
189 return;
191 /* FIXME: is there something missing here? nIndex is unused. Looks like
192 * copy-paste from VCLXAccessibleList::UpdateSelection() */
193 // VclPtr< ComboBox > pBox = GetAs< ComboBox >();
194 // if ( pBox )
195 // {
196 // // Find the index of the selected item inside the VCL control...
197 // sal_Int32 nIndex = pBox->GetEntryPos(sTextOfSelectedItem);
198 // // ...and then find the associated accessibility object.
199 // if ( nIndex == LISTBOX_ENTRY_NOTFOUND )
200 // nIndex = 0;
201 UpdateSelection_Impl_Acc(b_IsDropDownList);
202 // }
206 void VCLXAccessibleList::UpdateSelection_Impl_Acc(bool bHasDropDownList)
208 uno::Any aOldValue, aNewValue;
211 SolarMutexGuard aSolarGuard;
212 ::osl::Guard< ::osl::Mutex > aGuard( GetMutex() );
213 Reference< XAccessible > xNewAcc;
214 if ( m_pListBoxHelper )
216 sal_Int32 i=0;
217 m_nCurSelectedPos = LISTBOX_ENTRY_NOTFOUND;
218 for (const rtl::Reference<VCLXAccessibleListItem>& rxChild : m_aAccessibleChildren)
220 if (rxChild.is())
222 // Retrieve the item's index from the list entry.
223 bool bNowSelected = m_pListBoxHelper->IsEntryPosSelected (i);
224 if (bNowSelected)
225 m_nCurSelectedPos = i;
227 if (bNowSelected && !rxChild->IsSelected())
229 xNewAcc = rxChild;
230 aNewValue <<= xNewAcc;
232 else if (rxChild->IsSelected())
233 m_nLastSelectedPos = i;
235 rxChild->SetSelected(bNowSelected);
237 else
238 { // it could happen that a child was not created before
239 checkEntrySelected(i,aNewValue,xNewAcc);
241 ++i;
243 const sal_Int32 nCount = m_pListBoxHelper->GetEntryCount();
244 if ( i < nCount ) // here we have to check the if any other listbox entry is selected
246 for (; i < nCount && !checkEntrySelected(i,aNewValue,xNewAcc) ;++i )
249 if ( xNewAcc.is() && GetWindow()->HasFocus() )
251 if ( m_nLastSelectedPos != LISTBOX_ENTRY_NOTFOUND )
252 aOldValue <<= getAccessibleChild( m_nLastSelectedPos );
253 aNewValue <<= xNewAcc;
258 // since an active descendant is the UI element with keyboard focus, only send
259 // ACTIVE_DESCENDANT_CHANGED if the listbox/combobox has focus
260 vcl::Window* pWindow = GetWindow();
261 assert(pWindow);
262 const bool bFocused = pWindow->HasChildPathFocus();
264 if (m_aBoxType == COMBOBOX)
266 //VCLXAccessibleDropDownComboBox
267 //when in list is dropped down, xText = NULL
268 if (bHasDropDownList && m_pListBoxHelper && m_pListBoxHelper->IsInDropDown())
270 if ( aNewValue.hasValue() || aOldValue.hasValue() )
272 if (bFocused)
274 NotifyAccessibleEvent(
275 AccessibleEventId::ACTIVE_DESCENDANT_CHANGED,
276 aOldValue,
277 aNewValue );
280 NotifyListItem(aNewValue);
283 else
285 //VCLXAccessibleComboBox
286 NotifyAccessibleEvent( AccessibleEventId::SELECTION_CHANGED, uno::Any(), uno::Any() );
289 else if (m_aBoxType == LISTBOX)
291 if ( aNewValue.hasValue() || aOldValue.hasValue() )
293 if (bFocused)
295 NotifyAccessibleEvent(
296 AccessibleEventId::ACTIVE_DESCENDANT_CHANGED,
297 aOldValue,
298 aNewValue );
301 NotifyListItem(aNewValue);
306 void VCLXAccessibleList::NotifyListItem(css::uno::Any const & val)
308 Reference< XAccessible > xCurItem;
309 val >>= xCurItem;
310 if (xCurItem.is())
312 VCLXAccessibleListItem* pCurItem = static_cast< VCLXAccessibleListItem* >(xCurItem.get());
313 if (pCurItem)
315 pCurItem->NotifyAccessibleEvent(AccessibleEventId::SELECTION_CHANGED,Any(),Any());
320 void VCLXAccessibleList::ProcessWindowEvent (const VclWindowEvent& rVclWindowEvent, bool b_IsDropDownList)
322 switch ( rVclWindowEvent.GetId() )
324 case VclEventId::DropdownSelect:
325 case VclEventId::ListboxSelect:
326 if ( !m_bDisableProcessEvent )
327 UpdateSelection_Impl_Acc(b_IsDropDownList);
328 break;
329 case VclEventId::WindowGetFocus:
330 break;
331 case VclEventId::ControlGetFocus:
333 VCLXAccessibleComponent::ProcessWindowEvent (rVclWindowEvent);
334 if (m_aBoxType == COMBOBOX && b_IsDropDownList)
336 //VCLXAccessibleDropDownComboBox
338 else if (m_aBoxType == LISTBOX && b_IsDropDownList)
341 else if ( m_aBoxType == LISTBOX && !b_IsDropDownList)
343 if ( m_pListBoxHelper )
345 uno::Any aOldValue,
346 aNewValue;
347 sal_Int32 nPos = m_nCurSelectedPos; //m_pListBoxHelper->GetSelectedEntryPos();
349 if ( nPos == LISTBOX_ENTRY_NOTFOUND )
350 nPos = m_pListBoxHelper->GetTopEntry();
351 if ( nPos != LISTBOX_ENTRY_NOTFOUND )
352 aNewValue <<= uno::Reference<XAccessible>(CreateChild(nPos));
353 NotifyAccessibleEvent( AccessibleEventId::ACTIVE_DESCENDANT_CHANGED,
354 aOldValue,
355 aNewValue );
359 break;
360 default:
361 break;
366 void VCLXAccessibleList::ProcessWindowEvent (const VclWindowEvent& rVclWindowEvent)
368 // Create a reference to this object to prevent an early release of the
369 // listbox (VclEventId::ObjectDying).
370 Reference< XAccessible > xHoldAlive = this;
372 switch ( rVclWindowEvent.GetId() )
374 case VclEventId::DropdownOpen:
375 notifyVisibleStates(true);
376 break;
377 case VclEventId::DropdownClose:
378 notifyVisibleStates(false);
379 break;
380 case VclEventId::ListboxScrolled:
381 UpdateEntryRange_Impl();
382 break;
384 // The selection events VclEventId::ComboboxSelect and
385 // VclEventId::ComboboxDeselect are not handled here because here we
386 // have no access to the edit field. Its text is necessary to
387 // identify the currently selected item.
389 case VclEventId::ObjectDying:
391 dispose();
393 VCLXAccessibleComponent::ProcessWindowEvent (rVclWindowEvent);
394 break;
397 case VclEventId::ListboxItemRemoved:
398 case VclEventId::ComboboxItemRemoved:
399 case VclEventId::ListboxItemAdded:
400 case VclEventId::ComboboxItemAdded:
401 HandleChangedItemList();
402 break;
403 case VclEventId::ControlGetFocus:
405 VCLXAccessibleComponent::ProcessWindowEvent (rVclWindowEvent);
406 // Added by IBM Symphony Acc team to handle the list item focus when List control get focus
407 bool b_IsDropDownList = true;
408 if (m_pListBoxHelper)
409 b_IsDropDownList = ((m_pListBoxHelper->GetStyle() & WB_DROPDOWN ) == WB_DROPDOWN);
410 if ( m_aBoxType == LISTBOX && !b_IsDropDownList )
412 if ( m_pListBoxHelper )
414 uno::Any aOldValue,
415 aNewValue;
416 sal_Int32 nPos = m_nCurSelectedPos;
418 if ( nPos == LISTBOX_ENTRY_NOTFOUND )
419 nPos = m_pListBoxHelper->GetTopEntry();
420 if ( nPos != LISTBOX_ENTRY_NOTFOUND )
421 aNewValue <<= Reference<XAccessible>(CreateChild(nPos));
422 NotifyAccessibleEvent( AccessibleEventId::ACTIVE_DESCENDANT_CHANGED,
423 aOldValue,
424 aNewValue );
428 break;
430 default:
431 VCLXAccessibleComponent::ProcessWindowEvent (rVclWindowEvent);
435 void VCLXAccessibleList::FillAccessibleRelationSet( utl::AccessibleRelationSetHelper& rRelationSet )
437 VclPtr< ListBox > pBox = GetAs< ListBox >();
438 if( m_aBoxType == LISTBOX )
440 if (m_pListBoxHelper && (m_pListBoxHelper->GetStyle() & WB_DROPDOWN ) != WB_DROPDOWN)
442 uno::Sequence<uno::Reference<css::accessibility::XAccessible>> aSequence { pBox->GetAccessible() };
443 rRelationSet.AddRelation( css::accessibility::AccessibleRelation( css::accessibility::AccessibleRelationType_MEMBER_OF, aSequence ) );
446 else
448 VCLXAccessibleComponent::FillAccessibleRelationSet(rRelationSet);
453 /** To find out which item is currently selected and to update the SELECTED
454 state of the associated accessibility objects accordingly we exploit the
455 fact that the
457 void VCLXAccessibleList::UpdateSelection (std::u16string_view sTextOfSelectedItem)
459 if ( m_aBoxType != COMBOBOX )
460 return;
462 VclPtr< ComboBox > pBox = GetAs< ComboBox >();
463 if ( pBox )
465 // Find the index of the selected item inside the VCL control...
466 sal_Int32 nIndex = pBox->GetEntryPos(sTextOfSelectedItem);
467 // ...and then find the associated accessibility object.
468 if ( nIndex == LISTBOX_ENTRY_NOTFOUND )
469 nIndex = 0;
470 UpdateSelection_Impl(nIndex);
475 rtl::Reference<VCLXAccessibleListItem> VCLXAccessibleList::CreateChild(sal_Int32 nPos)
477 rtl::Reference<VCLXAccessibleListItem> xChild;
479 if ( o3tl::make_unsigned(nPos) >= m_aAccessibleChildren.size() )
481 m_aAccessibleChildren.resize(nPos + 1);
483 // insert into the container
484 xChild = new VCLXAccessibleListItem(nPos, this);
485 m_aAccessibleChildren[nPos] = xChild;
487 else
489 xChild = m_aAccessibleChildren[nPos];
490 // check if position is empty and can be used else we have to adjust all entries behind this
491 if (!xChild.is())
493 xChild = new VCLXAccessibleListItem(nPos, this);
494 m_aAccessibleChildren[nPos] = xChild;
498 if ( xChild.is() )
500 // Just add the SELECTED state.
501 bool bNowSelected = false;
502 if ( m_pListBoxHelper )
503 bNowSelected = m_pListBoxHelper->IsEntryPosSelected(nPos);
504 if (bNowSelected)
505 m_nCurSelectedPos = nPos;
506 xChild->SetSelected(bNowSelected);
508 // Set the child's VISIBLE state.
509 UpdateVisibleLineCount();
510 const sal_Int32 nTopEntry = m_pListBoxHelper ? m_pListBoxHelper->GetTopEntry() : 0;
511 bool bVisible = ( nPos>=nTopEntry && nPos<( nTopEntry + m_nVisibleLineCount ) );
512 xChild->SetVisible(m_bVisible && bVisible);
515 return xChild;
519 void VCLXAccessibleList::HandleChangedItemList()
521 disposeChildren();
522 NotifyAccessibleEvent (
523 AccessibleEventId::INVALIDATE_ALL_CHILDREN,
524 Any(), Any());
527 // XAccessible
529 Reference<XAccessibleContext> SAL_CALL
530 VCLXAccessibleList::getAccessibleContext()
532 return this;
536 // XAccessibleContext
538 sal_Int64 SAL_CALL VCLXAccessibleList::getAccessibleChildCount()
540 SolarMutexGuard aSolarGuard;
541 ::osl::Guard< ::osl::Mutex > aGuard( GetMutex() );
542 return implGetAccessibleChildCount();
545 sal_Int64 VCLXAccessibleList::implGetAccessibleChildCount()
547 sal_Int32 nCount = 0;
548 if ( m_pListBoxHelper )
549 nCount = m_pListBoxHelper->GetEntryCount();
551 return nCount;
554 Reference<XAccessible> SAL_CALL VCLXAccessibleList::getAccessibleChild (sal_Int64 i)
556 SolarMutexGuard aSolarGuard;
557 ::osl::Guard< ::osl::Mutex > aGuard( GetMutex() );
559 if ( i < 0 || i >= getAccessibleChildCount() )
560 throw IndexOutOfBoundsException();
562 Reference< XAccessible > xChild;
563 // search for the child
564 if ( o3tl::make_unsigned(i) >= m_aAccessibleChildren.size() )
565 xChild = CreateChild (i);
566 else
568 xChild = m_aAccessibleChildren[i];
569 if ( !xChild.is() )
570 xChild = CreateChild (i);
572 OSL_ENSURE( xChild.is(), "VCLXAccessibleList::getAccessibleChild: returning empty child!" );
573 return xChild;
576 Reference< XAccessible > SAL_CALL VCLXAccessibleList::getAccessibleParent( )
578 ::osl::Guard< ::osl::Mutex > aGuard( GetMutex() );
580 return m_xParent;
583 sal_Int64 SAL_CALL VCLXAccessibleList::getAccessibleIndexInParent()
585 if (m_nIndexInParent != DEFAULT_INDEX_IN_PARENT)
586 return m_nIndexInParent;
587 else
588 return VCLXAccessibleComponent::getAccessibleIndexInParent();
591 sal_Int16 SAL_CALL VCLXAccessibleList::getAccessibleRole()
593 return AccessibleRole::LIST;
596 // XServiceInfo
597 OUString VCLXAccessibleList::getImplementationName()
599 return u"com.sun.star.comp.toolkit.AccessibleList"_ustr;
602 Sequence< OUString > VCLXAccessibleList::getSupportedServiceNames()
604 return comphelper::concatSequences(VCLXAccessibleComponent::getSupportedServiceNames(),
605 std::initializer_list<OUString>{u"com.sun.star.accessibility.AccessibleList"_ustr});
608 void VCLXAccessibleList::UpdateVisibleLineCount()
610 if ( m_pListBoxHelper )
612 if ( (m_pListBoxHelper->GetStyle() & WB_DROPDOWN ) == WB_DROPDOWN )
613 m_nVisibleLineCount = m_pListBoxHelper->GetDisplayLineCount();
614 else
616 sal_uInt16 nCols = 0,
617 nLines = 0;
618 m_pListBoxHelper->GetMaxVisColumnsAndLines (nCols, nLines);
619 m_nVisibleLineCount = nLines;
624 void VCLXAccessibleList::UpdateEntryRange_Impl()
626 SolarMutexGuard aSolarGuard;
627 ::osl::Guard< ::osl::Mutex > aGuard( GetMutex() );
629 sal_Int32 nTop = m_nLastTopEntry;
631 if ( m_pListBoxHelper )
632 nTop = m_pListBoxHelper->GetTopEntry();
633 if ( nTop != m_nLastTopEntry )
635 UpdateVisibleLineCount();
636 sal_Int32 nBegin = std::min( m_nLastTopEntry, nTop );
637 sal_Int32 nEnd = std::max( m_nLastTopEntry + m_nVisibleLineCount, nTop + m_nVisibleLineCount );
638 for (sal_Int32 i = nBegin; (i <= nEnd); ++i)
640 bool bVisible = ( i >= nTop && i < ( nTop + m_nVisibleLineCount ) );
641 rtl::Reference<VCLXAccessibleListItem> xChild;
642 if ( o3tl::make_unsigned(i) < m_aAccessibleChildren.size() )
643 xChild = m_aAccessibleChildren[i];
644 else if ( bVisible )
645 xChild = CreateChild(i);
647 if (xChild.is())
648 xChild->SetVisible(m_bVisible && bVisible);
652 m_nLastTopEntry = nTop;
655 bool VCLXAccessibleList::checkEntrySelected(sal_Int32 _nPos,Any& _rNewValue,Reference< XAccessible >& _rxNewAcc)
657 OSL_ENSURE(m_pListBoxHelper,"Helper is not valid!");
658 bool bNowSelected = false;
659 if ( m_pListBoxHelper )
661 bNowSelected = m_pListBoxHelper->IsEntryPosSelected (_nPos);
662 if ( bNowSelected )
664 _rxNewAcc = CreateChild(_nPos);
665 _rNewValue <<= _rxNewAcc;
668 return bNowSelected;
672 void VCLXAccessibleList::UpdateSelection_Impl(sal_Int32)
674 uno::Any aOldValue, aNewValue;
677 SolarMutexGuard aSolarGuard;
678 ::osl::Guard< ::osl::Mutex > aGuard( GetMutex() );
679 Reference< XAccessible > xNewAcc;
681 if ( m_pListBoxHelper )
683 sal_Int32 i=0;
684 m_nCurSelectedPos = LISTBOX_ENTRY_NOTFOUND;
685 for (const rtl::Reference<VCLXAccessibleListItem>& rxChild : m_aAccessibleChildren)
687 if (rxChild.is())
689 // Retrieve the item's index from the list entry.
690 bool bNowSelected = m_pListBoxHelper->IsEntryPosSelected (i);
691 if (bNowSelected)
692 m_nCurSelectedPos = i;
694 if (bNowSelected && !rxChild->IsSelected())
696 xNewAcc = rxChild;
697 aNewValue <<= xNewAcc;
699 else if (rxChild->IsSelected())
700 m_nLastSelectedPos = i;
702 rxChild->SetSelected(bNowSelected);
704 else
705 { // it could happen that a child was not created before
706 checkEntrySelected(i,aNewValue,xNewAcc);
708 ++i;
710 const sal_Int32 nCount = m_pListBoxHelper->GetEntryCount();
711 if ( i < nCount ) // here we have to check the if any other listbox entry is selected
713 for (; i < nCount && !checkEntrySelected(i,aNewValue,xNewAcc) ;++i )
716 if ( xNewAcc.is() && GetWindow()->HasFocus() )
718 if ( m_nLastSelectedPos != LISTBOX_ENTRY_NOTFOUND )
719 aOldValue <<= getAccessibleChild( m_nLastSelectedPos );
720 aNewValue <<= xNewAcc;
722 if (m_pListBoxHelper->IsInDropDown())
724 if ( aNewValue.hasValue() || aOldValue.hasValue() )
725 NotifyAccessibleEvent(
726 AccessibleEventId::ACTIVE_DESCENDANT_CHANGED,
727 aOldValue,
728 aNewValue );
729 //the SELECTION_CHANGED is not necessary
730 //NotifyAccessibleEvent( AccessibleEventId::SELECTION_CHANGED, Any(), Any() );
737 // XAccessibleSelection
739 void SAL_CALL VCLXAccessibleList::selectAccessibleChild( sal_Int64 nChildIndex )
741 bool bNotify = false;
744 SolarMutexGuard aSolarGuard;
745 ::osl::Guard< ::osl::Mutex > aGuard( GetMutex() );
747 if ( m_pListBoxHelper )
749 checkSelection_Impl(nChildIndex,*m_pListBoxHelper,false);
751 m_pListBoxHelper->SelectEntryPos( static_cast<sal_uInt16>(nChildIndex) );
752 // call the select handler, don't handle events in this time
753 m_bDisableProcessEvent = true;
754 m_pListBoxHelper->Select();
755 m_bDisableProcessEvent = false;
756 bNotify = true;
760 if ( bNotify )
761 UpdateSelection_Impl();
764 sal_Bool SAL_CALL VCLXAccessibleList::isAccessibleChildSelected( sal_Int64 nChildIndex )
766 SolarMutexGuard aSolarGuard;
767 ::osl::Guard< ::osl::Mutex > aGuard( GetMutex() );
769 bool bRet = false;
770 if ( m_pListBoxHelper )
772 checkSelection_Impl(nChildIndex,*m_pListBoxHelper,false);
774 bRet = m_pListBoxHelper->IsEntryPosSelected( static_cast<sal_uInt16>(nChildIndex) );
776 return bRet;
779 void SAL_CALL VCLXAccessibleList::clearAccessibleSelection( )
781 bool bNotify = false;
784 SolarMutexGuard aSolarGuard;
785 ::osl::Guard< ::osl::Mutex > aGuard( GetMutex() );
787 if ( m_pListBoxHelper )
789 m_pListBoxHelper->SetNoSelection();
790 bNotify = true;
794 if ( bNotify )
795 UpdateSelection_Impl();
798 void SAL_CALL VCLXAccessibleList::selectAllAccessibleChildren( )
800 bool bNotify = false;
803 SolarMutexGuard aSolarGuard;
804 ::osl::Guard< ::osl::Mutex > aGuard( GetMutex() );
806 if ( m_pListBoxHelper )
808 const sal_Int32 nCount = m_pListBoxHelper->GetEntryCount();
809 for ( sal_Int32 i = 0; i < nCount; ++i )
810 m_pListBoxHelper->SelectEntryPos( i );
811 // call the select handler, don't handle events in this time
812 m_bDisableProcessEvent = true;
813 m_pListBoxHelper->Select();
814 m_bDisableProcessEvent = false;
815 bNotify = true;
819 if ( bNotify )
820 UpdateSelection_Impl();
823 sal_Int64 SAL_CALL VCLXAccessibleList::getSelectedAccessibleChildCount( )
825 SolarMutexGuard aSolarGuard;
826 ::osl::Guard< ::osl::Mutex > aGuard( GetMutex() );
828 sal_Int64 nCount = 0;
829 if ( m_pListBoxHelper )
830 nCount = m_pListBoxHelper->GetSelectedEntryCount();
831 return nCount;
834 Reference< XAccessible > SAL_CALL VCLXAccessibleList::getSelectedAccessibleChild( sal_Int64 nSelectedChildIndex )
836 SolarMutexGuard aSolarGuard;
837 ::osl::Guard< ::osl::Mutex > aGuard( GetMutex() );
839 if ( m_pListBoxHelper )
841 checkSelection_Impl(nSelectedChildIndex,*m_pListBoxHelper,true);
842 return getAccessibleChild( m_pListBoxHelper->GetSelectedEntryPos( static_cast<sal_uInt16>(nSelectedChildIndex) ) );
845 return nullptr;
848 void SAL_CALL VCLXAccessibleList::deselectAccessibleChild( sal_Int64 nSelectedChildIndex )
850 bool bNotify = false;
853 SolarMutexGuard aSolarGuard;
854 ::osl::Guard< ::osl::Mutex > aGuard( GetMutex() );
856 if ( m_pListBoxHelper )
858 checkSelection_Impl(nSelectedChildIndex,*m_pListBoxHelper,false);
860 m_pListBoxHelper->SelectEntryPos( static_cast<sal_uInt16>(nSelectedChildIndex), false );
861 // call the select handler, don't handle events in this time
862 m_bDisableProcessEvent = true;
863 m_pListBoxHelper->Select();
864 m_bDisableProcessEvent = false;
865 bNotify = true;
869 if ( bNotify )
870 UpdateSelection_Impl();
873 awt::Rectangle VCLXAccessibleList::implGetBounds()
875 awt::Rectangle aBounds ( 0, 0, 0, 0 );
876 if ( m_pListBoxHelper
877 && (m_pListBoxHelper->GetStyle() & WB_DROPDOWN ) == WB_DROPDOWN )
879 if ( m_pListBoxHelper->IsInDropDown() )
880 aBounds = vcl::unohelper::ConvertToAWTRect(m_pListBoxHelper->GetDropDownPosSizePixel());
882 else
884 // a list has the same bounds as his parent but starts at (0,0)
885 aBounds = VCLXAccessibleComponent::implGetBounds();
886 aBounds.X = 0;
887 aBounds.Y = 0;
888 if ( m_aBoxType == COMBOBOX )
890 VclPtr< ComboBox > pBox = GetAs< ComboBox >();
891 if ( pBox )
893 Size aSize = pBox->GetSubEdit()->GetSizePixel();
894 aBounds.Y += aSize.Height();
895 aBounds.Height -= aSize.Height();
899 return aBounds;
903 awt::Point VCLXAccessibleList::getLocationOnScreen( )
905 SolarMutexGuard aSolarGuard;
906 ::osl::Guard< ::osl::Mutex > aGuard( GetMutex() );
908 awt::Point aPos;
909 if ( m_pListBoxHelper
910 && (m_pListBoxHelper->GetStyle() & WB_DROPDOWN ) == WB_DROPDOWN )
912 if ( m_pListBoxHelper->IsInDropDown() )
913 aPos = vcl::unohelper::ConvertToAWTPoint(
914 m_pListBoxHelper->GetDropDownPosSizePixel().TopLeft());
916 else
918 aPos = VCLXAccessibleComponent::getLocationOnScreen();
919 if ( m_aBoxType == COMBOBOX )
921 VclPtr< ComboBox > pBox = GetAs< ComboBox >();
922 if ( pBox )
924 aPos.Y += pBox->GetSubEdit()->GetSizePixel().Height();
928 return aPos;
932 bool VCLXAccessibleList::IsInDropDown() const
934 return m_pListBoxHelper->IsInDropDown();
938 void VCLXAccessibleList::HandleDropOpen()
940 if ( !m_bDisableProcessEvent )
941 UpdateSelection_Impl();
942 if (m_nCurSelectedPos != LISTBOX_ENTRY_NOTFOUND &&
943 m_nLastSelectedPos != LISTBOX_ENTRY_NOTFOUND)
945 Reference< XAccessible > xChild = getAccessibleChild(m_nCurSelectedPos);
946 if(xChild.is())
948 uno::Any aNewValue;
949 aNewValue <<= xChild;
950 NotifyAccessibleEvent(AccessibleEventId::ACTIVE_DESCENDANT_CHANGED, uno::Any(), aNewValue );
955 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */