xref: /trunk/main/accessibility/source/standard/vclxaccessiblelist.cxx (revision 91144cd0085a7583d2099b982122deb2184ab956)
1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_accessibility.hxx"
26 #include <accessibility/standard/vclxaccessiblelist.hxx>
27 #include <accessibility/standard/vclxaccessiblelistitem.hxx>
28 #include <accessibility/helper/listboxhelper.hxx>
29 
30 #include <unotools/accessiblestatesethelper.hxx>
31 #include <com/sun/star/accessibility/AccessibleStateType.hpp>
32 #include <com/sun/star/accessibility/AccessibleEventId.hpp>
33 #include <com/sun/star/accessibility/AccessibleRole.hpp>
34 #include <vcl/svapp.hxx>
35 #include <vcl/combobox.hxx>
36 #include <vcl/lstbox.hxx>
37 #include <toolkit/helper/convert.hxx>
38 
39 #ifndef _UTL_ACCESSIBLERELATIONSETHELPER_HXX_
40 #include <unotools/accessiblerelationsethelper.hxx>
41 #endif
42 #ifndef _COM_SUN_STAR_ACCESSIBILITY_ACCESSIBLERELATIONTYPE_HPP_
43 #include <com/sun/star/accessibility/AccessibleRelationType.hpp>
44 #endif
45 using namespace ::com::sun::star;
46 using namespace ::com::sun::star::uno;
47 using namespace ::com::sun::star::lang;
48 using namespace ::com::sun::star::beans;
49 using namespace ::com::sun::star::accessibility;
50 using namespace ::accessibility;
51 
52 namespace
53 {
checkSelection_Impl(sal_Int32 _nIndex,const IComboListBoxHelper & _rListBox,sal_Bool bSelected)54     void checkSelection_Impl( sal_Int32 _nIndex, const IComboListBoxHelper& _rListBox, sal_Bool bSelected )
55     {
56         sal_Int32 nCount = bSelected ? (sal_Int32)_rListBox.GetSelectEntryCount()
57                                      : (sal_Int32)_rListBox.GetEntryCount();
58         if ( _nIndex < 0 || _nIndex >= nCount )
59             throw ::com::sun::star::lang::IndexOutOfBoundsException();
60     }
61 }
62 
VCLXAccessibleList(VCLXWindow * pVCLWindow,BoxType aBoxType,const Reference<XAccessible> & _xParent)63 VCLXAccessibleList::VCLXAccessibleList (VCLXWindow* pVCLWindow, BoxType aBoxType,
64                                         const Reference< XAccessible >& _xParent)
65     : VCLXAccessibleComponent   (pVCLWindow),
66       m_aBoxType                (aBoxType),
67       m_nVisibleLineCount       (0),
68       m_nIndexInParent          (DEFAULT_INDEX_IN_PARENT),
69       m_nLastTopEntry           ( 0 ),
70       m_nLastSelectedPos        ( LISTBOX_ENTRY_NOTFOUND ),
71       m_bDisableProcessEvent    ( false ),
72       m_bVisible                ( true ),
73       m_nCurSelectedPos         ( LISTBOX_ENTRY_NOTFOUND ),
74       m_xParent                 ( _xParent )
75 {
76     // Because combo boxes and list boxes have the no common interface for
77     // methods with identical signature we have to write down twice the
78     // same code.
79     switch (m_aBoxType)
80     {
81         case COMBOBOX:
82         {
83             ComboBox* pBox = static_cast<ComboBox*>(GetWindow());
84             if ( pBox != NULL )
85                 m_pListBoxHelper = new VCLListBoxHelper<ComboBox> (*pBox);
86             break;
87         }
88 
89         case LISTBOX:
90         {
91             ListBox* pBox = static_cast<ListBox*>(GetWindow());
92             if ( pBox != NULL )
93                 m_pListBoxHelper = new VCLListBoxHelper<ListBox> (*pBox);
94             break;
95         }
96     }
97     UpdateVisibleLineCount();
98     m_nCurSelectedPos=m_pListBoxHelper->GetSelectEntryPos();
99 
100     sal_uInt16 nCount = static_cast<sal_uInt16>(getAccessibleChildCount());
101     m_aAccessibleChildren.reserve(nCount);
102 }
103 // -----------------------------------------------------------------------------
104 
~VCLXAccessibleList(void)105 VCLXAccessibleList::~VCLXAccessibleList (void)
106 {
107     delete m_pListBoxHelper;
108 }
109 // -----------------------------------------------------------------------------
110 
SetIndexInParent(sal_Int32 nIndex)111 void VCLXAccessibleList::SetIndexInParent (sal_Int32 nIndex)
112 {
113     m_nIndexInParent = nIndex;
114 }
115 // -----------------------------------------------------------------------------
116 
disposing(void)117 void SAL_CALL VCLXAccessibleList::disposing (void)
118 {
119     VCLXAccessibleComponent::disposing();
120 
121     // Dispose all items in the list.
122     clearItems();
123 
124     delete m_pListBoxHelper;
125     m_pListBoxHelper = NULL;
126 }
127 // -----------------------------------------------------------------------------
128 
clearItems()129 void VCLXAccessibleList::clearItems()
130 {
131 //  ListItems::iterator aEnd = m_aAccessibleChildren.end();
132 //  for (ListItems::iterator aIter = m_aAccessibleChildren.begin(); aIter != aEnd; ++aIter)
133 //      ::comphelper::disposeComponent(*aIter);
134 
135     // Clear the list itself and delete all the rest.
136     ListItems().swap(m_aAccessibleChildren); // clear and minimize
137 }
138 // -----------------------------------------------------------------------------
139 
FillAccessibleStateSet(utl::AccessibleStateSetHelper & rStateSet)140 void VCLXAccessibleList::FillAccessibleStateSet (utl::AccessibleStateSetHelper& rStateSet)
141 {
142     vos::OGuard aSolarGuard( Application::GetSolarMutex() );
143 
144     VCLXAccessibleComponent::FillAccessibleStateSet( rStateSet );
145     // check if our list should be visible
146     if (    m_pListBoxHelper
147         && (m_pListBoxHelper->GetStyle() & WB_DROPDOWN ) == WB_DROPDOWN
148         && !m_pListBoxHelper->IsInDropDown() )
149     {
150         rStateSet.RemoveState (AccessibleStateType::VISIBLE);
151         rStateSet.RemoveState (AccessibleStateType::SHOWING);
152         m_bVisible = false;
153     }
154 
155     // Both the combo box and list box are handled identical in the
156     // following but for some reason they don't have a common interface for
157     // the methods used.
158     if ( m_pListBoxHelper )
159     {
160         if ( m_pListBoxHelper->IsMultiSelectionEnabled() )
161             rStateSet.AddState( AccessibleStateType::MULTI_SELECTABLE);
162         rStateSet.AddState (AccessibleStateType::FOCUSABLE);
163         // All children are transient.
164         rStateSet.AddState (AccessibleStateType::MANAGES_DESCENDANTS);
165     }
166 }
167 // -----------------------------------------------------------------------------
notifyVisibleStates(sal_Bool _bSetNew)168 void VCLXAccessibleList::notifyVisibleStates(sal_Bool _bSetNew )
169 {
170     m_bVisible = _bSetNew ? true : false;
171     Any aOldValue, aNewValue;
172     (_bSetNew ? aNewValue : aOldValue ) <<= AccessibleStateType::VISIBLE;
173     NotifyAccessibleEvent( AccessibleEventId::STATE_CHANGED, aOldValue, aNewValue );
174     (_bSetNew ? aNewValue : aOldValue ) <<= AccessibleStateType::SHOWING;
175     NotifyAccessibleEvent( AccessibleEventId::STATE_CHANGED, aOldValue, aNewValue );
176 
177     ListItems::iterator aIter = m_aAccessibleChildren.begin();
178     ListItems::iterator aEnd = m_aAccessibleChildren.end();
179     UpdateVisibleLineCount();
180     // adjust the index inside the VCLXAccessibleListItem
181     for (;aIter != aEnd ; ++aIter)
182     {
183         Reference< XAccessible > xHold = *aIter;
184         VCLXAccessibleListItem* pItem = static_cast<VCLXAccessibleListItem*>(xHold.get());
185         if ( pItem )
186         {
187             sal_uInt16 nTopEntry = 0;
188             if ( m_pListBoxHelper )
189                 nTopEntry = m_pListBoxHelper->GetTopEntry();
190             sal_uInt16 nPos = (sal_uInt16)(aIter - m_aAccessibleChildren.begin());
191             sal_Bool bVisible = ( nPos>=nTopEntry && nPos<( nTopEntry + m_nVisibleLineCount ) );
192             pItem->SetVisible( m_bVisible && bVisible );
193         }
194 
195     }
196 }
197 // -----------------------------------------------------------------------------
UpdateSelection_Acc(::rtl::OUString sTextOfSelectedItem,bool b_IsDropDownList)198 void VCLXAccessibleList::UpdateSelection_Acc (::rtl::OUString sTextOfSelectedItem, bool b_IsDropDownList)
199 {
200     if ( m_aBoxType == COMBOBOX )
201     {
202         ComboBox* pBox = static_cast<ComboBox*>(GetWindow());
203         if ( pBox != NULL )
204         {
205         // Find the index of the selected item inside the VCL control...
206         sal_uInt16 nIndex = pBox->GetEntryPos (XubString(sTextOfSelectedItem));
207         // ...and then find the associated accessibility object.
208         if ( nIndex == LISTBOX_ENTRY_NOTFOUND )
209             nIndex = 0;
210         UpdateSelection_Impl_Acc(b_IsDropDownList);
211         }
212     }
213 }
214 
215 // -----------------------------------------------------------------------------
UpdateSelection_Impl_Acc(bool b_IsDropDownList)216 void VCLXAccessibleList::UpdateSelection_Impl_Acc(bool b_IsDropDownList)
217 {
218     uno::Any aOldValue, aNewValue;
219     VCLXAccessibleListItem* pCurItem =NULL;
220 
221     {
222         vos::OGuard aSolarGuard( Application::GetSolarMutex() );
223         ::osl::Guard< ::osl::Mutex > aGuard( GetMutex() );
224             Reference< XAccessible > xNewAcc;
225         if ( m_pListBoxHelper )
226         {
227             sal_uInt16 i=0;
228             m_nCurSelectedPos = LISTBOX_ENTRY_NOTFOUND;
229             for ( ListItems::iterator aIter = m_aAccessibleChildren.begin();
230                   aIter != m_aAccessibleChildren.end(); ++aIter,++i)
231             {
232                 Reference< XAccessible > xHold = *aIter;
233                 if ( xHold.is() )
234                 {
235                     VCLXAccessibleListItem* pItem = static_cast< VCLXAccessibleListItem* >( xHold.get() );
236                     // Retrieve the item's index from the list entry.
237                     sal_Bool bNowSelected = m_pListBoxHelper->IsEntryPosSelected (i);
238                     if (bNowSelected)
239                         m_nCurSelectedPos = i;
240 
241                     if ( bNowSelected && !pItem->IsSelected() )
242                     {
243                         xNewAcc = *aIter;
244                         aNewValue <<= xNewAcc;
245 
246                         pCurItem = pItem;
247 
248                     }
249                     else if ( pItem->IsSelected() )
250                         m_nLastSelectedPos = i;
251 
252                     pItem->SetSelected( bNowSelected );
253                 }
254                 else
255                 { // it could happen that a child was not created before
256                     checkEntrySelected(i,aNewValue,xNewAcc);
257                 }
258             }
259             sal_uInt16 nCount = m_pListBoxHelper->GetEntryCount();
260             if ( i < nCount ) // here we have to check the if any other listbox entry is selected
261             {
262                 for (; i < nCount && !checkEntrySelected(i,aNewValue,xNewAcc) ;++i )
263                     ;
264             }
265             if ( xNewAcc.is() && GetWindow()->HasFocus() )
266             {
267                 if ( m_nLastSelectedPos != LISTBOX_ENTRY_NOTFOUND )
268                     aOldValue <<= getAccessibleChild( (sal_Int32)m_nLastSelectedPos );
269                 aNewValue <<= xNewAcc;
270             }
271         }
272     }
273     if (m_aBoxType == COMBOBOX && b_IsDropDownList)
274     {
275         //VCLXAccessibleDropDownComboBox
276         //when in list is dropped down, xText = NULL
277         if (m_pListBoxHelper->IsInDropDown())
278         {
279             if ( aNewValue.hasValue() || aOldValue.hasValue() )
280             {
281                 NotifyAccessibleEvent(
282                     AccessibleEventId::ACTIVE_DESCENDANT_CHANGED,
283                     aOldValue,
284                     aNewValue );
285 
286                 NotifyListItem(aNewValue);
287 
288             }
289         }
290     }
291     else if (m_aBoxType == COMBOBOX && !b_IsDropDownList)
292     {
293         //VCLXAccessibleComboBox
294         NotifyAccessibleEvent( AccessibleEventId::SELECTION_CHANGED, uno::Any(), uno::Any() );
295     }
296     else if (m_aBoxType == LISTBOX && b_IsDropDownList)
297     {
298         //VCLXAccessibleDropdownListBox
299         //when in list is dropped down, xText = NULL
300         if (m_pListBoxHelper->IsInDropDown())
301         {
302             if ( aNewValue.hasValue() || aOldValue.hasValue() )
303             {
304                 NotifyAccessibleEvent(
305                     AccessibleEventId::ACTIVE_DESCENDANT_CHANGED,
306                     aOldValue,
307                     aNewValue );
308 
309                 NotifyListItem(aNewValue);
310             }
311         }
312     }
313     else if (m_aBoxType == LISTBOX && !b_IsDropDownList)
314     {
315         //VCLXAccessibleListBox, xText = NULL.
316 
317 
318         if ( aNewValue.hasValue())
319         {
320             NotifyListItem(aNewValue);
321         }
322     }
323 }
NotifyListItem(::com::sun::star::uno::Any & val)324 void VCLXAccessibleList::NotifyListItem(::com::sun::star::uno::Any& val)
325 {
326     Reference< XAccessible > xCurItem;
327     val >>= xCurItem;
328     if (xCurItem.is())
329     {
330         VCLXAccessibleListItem* pCurItem = static_cast< VCLXAccessibleListItem* >(xCurItem.get());
331         if (pCurItem)
332         {
333             pCurItem->NotifyAccessibleEvent(AccessibleEventId::SELECTION_CHANGED,Any(),Any());
334         }
335     }
336 }
337 
338 
UpdateFocus_Impl_Acc(sal_uInt16 nPos,bool b_IsDropDownList)339 void VCLXAccessibleList::UpdateFocus_Impl_Acc (sal_uInt16 nPos ,bool b_IsDropDownList)
340 {
341     if (!(m_aBoxType == LISTBOX && !b_IsDropDownList))
342     {
343         return ;
344     }
345     Reference<XAccessible> xChild= CreateChild(nPos);
346     if ( !xChild.is() )
347     {
348         return ;
349     }
350     m_nCurSelectedPos = nPos;
351     uno::Any aOldValue, aNewValue;
352     aNewValue <<= xChild;
353 
354     NotifyAccessibleEvent(
355             AccessibleEventId::ACTIVE_DESCENDANT_CHANGED,
356             aOldValue,
357             aNewValue );
358 }
359 
360 // -----------------------------------------------------------------------------
ProcessWindowEvent(const VclWindowEvent & rVclWindowEvent,bool b_IsDropDownList)361 void VCLXAccessibleList::ProcessWindowEvent (const VclWindowEvent& rVclWindowEvent, bool b_IsDropDownList)
362 {
363     switch ( rVclWindowEvent.GetId() )
364     {
365         case VCLEVENT_DROPDOWN_SELECT:
366         case VCLEVENT_LISTBOX_SELECT:
367             if ( !m_bDisableProcessEvent )
368                 UpdateSelection_Impl_Acc(b_IsDropDownList);
369             break;
370         case VCLEVENT_LISTBOX_FOCUSITEMCHANGED:
371             if ( !m_bDisableProcessEvent )
372                 UpdateFocus_Impl_Acc((sal_uInt16)reinterpret_cast<sal_uIntPtr>(rVclWindowEvent.GetData()),b_IsDropDownList);
373             break;
374         case VCLEVENT_WINDOW_GETFOCUS:
375             break;
376         case VCLEVENT_CONTROL_GETFOCUS:
377             {
378                 VCLXAccessibleComponent::ProcessWindowEvent (rVclWindowEvent);
379                 if (m_aBoxType == COMBOBOX && b_IsDropDownList)
380                 {
381                     //VCLXAccessibleDropDownComboBox
382                 }
383                 else if (m_aBoxType == LISTBOX && b_IsDropDownList)
384                 {
385                 }
386                 else if ( m_aBoxType == LISTBOX && !b_IsDropDownList)
387                 {
388                     if ( m_pListBoxHelper )
389                     {
390                         uno::Any    aOldValue,
391                                     aNewValue;
392                         sal_uInt16 nPos = m_nCurSelectedPos; //m_pListBoxHelper->GetSelectEntryPos();
393 
394                         if ( nPos == LISTBOX_ENTRY_NOTFOUND )
395                             nPos = m_pListBoxHelper->GetTopEntry();
396                         if ( nPos != LISTBOX_ENTRY_NOTFOUND )
397                             aNewValue <<= CreateChild(nPos);
398                         NotifyAccessibleEvent(  AccessibleEventId::ACTIVE_DESCENDANT_CHANGED,
399                                                 aOldValue,
400                                                 aNewValue );
401                     }
402                 }
403             }
404             break;
405         default:
406             break;
407     }
408 
409 }
410 // -----------------------------------------------------------------------------
ProcessWindowEvent(const VclWindowEvent & rVclWindowEvent)411 void VCLXAccessibleList::ProcessWindowEvent (const VclWindowEvent& rVclWindowEvent)
412 {
413     // Create a reference to this object to prevent an early release of the
414     // listbox (VCLEVENT_OBJECT_DYING).
415     Reference< XAccessible > xTemp = this;
416 
417     switch ( rVclWindowEvent.GetId() )
418     {
419         case VCLEVENT_DROPDOWN_OPEN:
420             notifyVisibleStates(sal_True);
421             break;
422         case VCLEVENT_DROPDOWN_CLOSE:
423             notifyVisibleStates(sal_False);
424             break;
425         case VCLEVENT_LISTBOX_SCROLLED:
426         case VCLEVENT_COMBOBOX_SCROLLED:
427             UpdateEntryRange_Impl();
428             break;
429 
430         // The selection events VCLEVENT_COMBOBOX_SELECT and
431         // VCLEVENT_COMBOBOX_DESELECT are not handled here because here we
432         // have no access to the edit field. Its text is necessary to
433         // identify the currently selected item.
434 
435         case VCLEVENT_OBJECT_DYING:
436         {
437             dispose();
438 
439             VCLXAccessibleComponent::ProcessWindowEvent (rVclWindowEvent);
440             break;
441         }
442 
443         case VCLEVENT_LISTBOX_ITEMREMOVED:
444         case VCLEVENT_COMBOBOX_ITEMREMOVED:
445             HandleChangedItemList (false, reinterpret_cast<sal_IntPtr>(
446                 rVclWindowEvent.GetData()));
447             break;
448 
449         case VCLEVENT_LISTBOX_ITEMADDED:
450         case VCLEVENT_COMBOBOX_ITEMADDED:
451             HandleChangedItemList (true, reinterpret_cast<sal_IntPtr>(
452                 rVclWindowEvent.GetData()));
453             break;
454         case VCLEVENT_CONTROL_GETFOCUS:
455             {
456                 VCLXAccessibleComponent::ProcessWindowEvent (rVclWindowEvent);
457                 // Added by IBM Symphony Acc team to handle the list item focus when List control get focus
458                 sal_Bool b_IsDropDownList = sal_True;
459                 if (m_pListBoxHelper)
460                     b_IsDropDownList = ((m_pListBoxHelper->GetStyle() & WB_DROPDOWN ) == WB_DROPDOWN);
461                 if ( m_aBoxType == LISTBOX && !b_IsDropDownList )
462                 {
463                     if ( m_pListBoxHelper )
464                     {
465                         uno::Any    aOldValue,
466                                     aNewValue;
467                         sal_uInt16 nPos = m_nCurSelectedPos;
468 
469                         if ( nPos == LISTBOX_ENTRY_NOTFOUND )
470                             nPos = m_pListBoxHelper->GetTopEntry();
471                         if ( nPos != LISTBOX_ENTRY_NOTFOUND )
472                             aNewValue <<= CreateChild(nPos);
473                         NotifyAccessibleEvent(  AccessibleEventId::ACTIVE_DESCENDANT_CHANGED,
474                                                 aOldValue,
475                                                 aNewValue );
476                     }
477                 }
478             }
479             break;
480 
481         default:
482             VCLXAccessibleComponent::ProcessWindowEvent (rVclWindowEvent);
483     }
484 }
485 
FillAccessibleRelationSet(utl::AccessibleRelationSetHelper & rRelationSet)486  void VCLXAccessibleList::FillAccessibleRelationSet( utl::AccessibleRelationSetHelper& rRelationSet )
487 {
488     ListBox* pBox = static_cast<ListBox*>(GetWindow());
489     if( m_aBoxType == LISTBOX )
490     {
491         if (m_pListBoxHelper && (m_pListBoxHelper->GetStyle() & WB_DROPDOWN ) != WB_DROPDOWN)
492         {
493             uno::Sequence< uno::Reference< uno::XInterface > > aSequence(1);
494             aSequence[0] = pBox->GetAccessible();
495             rRelationSet.AddRelation( com::sun::star::accessibility::AccessibleRelation( com::sun::star::accessibility::AccessibleRelationType::MEMBER_OF, aSequence ) );
496         }
497     }
498     else
499     {
500         VCLXAccessibleComponent::FillAccessibleRelationSet(rRelationSet);
501     }
502 }
503 // -----------------------------------------------------------------------------
504 
505 /** To find out which item is currently selected and to update the SELECTED
506     state of the associated accessibility objects accordingly we exploit the
507     fact that the
508 */
UpdateSelection(::rtl::OUString sTextOfSelectedItem)509 void VCLXAccessibleList::UpdateSelection (::rtl::OUString sTextOfSelectedItem)
510 {
511     if ( m_aBoxType == COMBOBOX )
512     {
513         ComboBox* pBox = static_cast<ComboBox*>(GetWindow());
514         if ( pBox != NULL )
515         {
516             // Find the index of the selected item inside the VCL control...
517             sal_uInt16 nIndex = pBox->GetEntryPos (XubString(sTextOfSelectedItem));
518             // ...and then find the associated accessibility object.
519             if ( nIndex == LISTBOX_ENTRY_NOTFOUND )
520                 nIndex = 0;
521             UpdateSelection_Impl(nIndex);
522         }
523     }
524 }
525 // -----------------------------------------------------------------------------
526 
adjustEntriesIndexInParent(ListItems::iterator & _aBegin,::std::mem_fun_t<bool,VCLXAccessibleListItem> & _rMemFun)527 void VCLXAccessibleList::adjustEntriesIndexInParent(ListItems::iterator& _aBegin,::std::mem_fun_t<bool,VCLXAccessibleListItem>& _rMemFun)
528 {
529     ListItems::iterator aIter = _aBegin;
530     ListItems::iterator aEnd = m_aAccessibleChildren.end();
531     // adjust the index inside the VCLXAccessibleListItem
532     for (;aIter != aEnd ; ++aIter)
533     {
534         Reference< XAccessible > xHold = *aIter;
535         VCLXAccessibleListItem* pItem = static_cast<VCLXAccessibleListItem*>(xHold.get());
536         if ( pItem )
537             _rMemFun(pItem);
538     }
539 }
540 // -----------------------------------------------------------------------------
541 
CreateChild(sal_Int32 i)542 Reference<XAccessible> VCLXAccessibleList::CreateChild (sal_Int32 i)
543 {
544     Reference<XAccessible> xChild;
545 
546     sal_uInt16 nPos = static_cast<sal_uInt16>(i);
547     if ( nPos >= m_aAccessibleChildren.size() )
548     {
549         m_aAccessibleChildren.resize(nPos + 1);
550 
551         // insert into the container
552         xChild = new VCLXAccessibleListItem(m_pListBoxHelper, i, this);
553         m_aAccessibleChildren[nPos] = xChild;
554     }
555     else
556     {
557         xChild = m_aAccessibleChildren[nPos];
558         // check if position is empty and can be used else we have to adjust all entries behind this
559         if ( !xChild.is() )
560         {
561             xChild = new VCLXAccessibleListItem(m_pListBoxHelper, i, this);
562             m_aAccessibleChildren[nPos] = xChild;
563         }
564     }
565 
566     if ( xChild.is() )
567     {
568         // Just add the SELECTED state.
569         sal_Bool bNowSelected = sal_False;
570         if ( m_pListBoxHelper )
571             bNowSelected = m_pListBoxHelper->IsEntryPosSelected ((sal_uInt16)i);
572         if (bNowSelected)
573             m_nCurSelectedPos = sal_uInt16(i);
574         VCLXAccessibleListItem* pItem = static_cast< VCLXAccessibleListItem* >(xChild.get());
575         pItem->SetSelected( bNowSelected );
576 
577         // Set the child's VISIBLE state.
578         UpdateVisibleLineCount();
579         sal_uInt16 nTopEntry = 0;
580         if ( m_pListBoxHelper )
581             nTopEntry = m_pListBoxHelper->GetTopEntry();
582         sal_Bool bVisible = ( nPos>=nTopEntry && nPos<( nTopEntry + m_nVisibleLineCount ) );
583         pItem->SetVisible( m_bVisible && bVisible );
584     }
585 
586     return xChild;
587 }
588 // -----------------------------------------------------------------------------
589 
HandleChangedItemList(bool bItemInserted,sal_Int32 nIndex)590 void VCLXAccessibleList::HandleChangedItemList (bool bItemInserted, sal_Int32 nIndex)
591 {
592     clearItems();
593     NotifyAccessibleEvent (
594         AccessibleEventId::INVALIDATE_ALL_CHILDREN,
595         Any(), Any());
596 }
597 // -----------------------------------------------------------------------------
598 
IMPLEMENT_FORWARD_XINTERFACE2(VCLXAccessibleList,VCLXAccessibleComponent,VCLXAccessibleList_BASE)599 IMPLEMENT_FORWARD_XINTERFACE2(VCLXAccessibleList, VCLXAccessibleComponent, VCLXAccessibleList_BASE)
600 IMPLEMENT_FORWARD_XTYPEPROVIDER2(VCLXAccessibleList, VCLXAccessibleComponent, VCLXAccessibleList_BASE)
601 
602 //=====  XAccessible  =========================================================
603 
604 Reference<XAccessibleContext> SAL_CALL
605     VCLXAccessibleList::getAccessibleContext (void)
606 {
607     return this;
608 }
609 // -----------------------------------------------------------------------------
610 
611 //=====  XAccessibleContext  ==================================================
612 
getAccessibleChildCount(void)613 sal_Int32 SAL_CALL VCLXAccessibleList::getAccessibleChildCount (void)
614 {
615     vos::OGuard aSolarGuard( Application::GetSolarMutex() );
616     ::osl::Guard< ::osl::Mutex > aGuard( GetMutex() );
617 
618     sal_Int32 nCount = 0;
619     if ( m_pListBoxHelper )
620         nCount = m_pListBoxHelper->GetEntryCount();
621 
622     return nCount;
623 }
624 // -----------------------------------------------------------------------------
625 
getAccessibleChild(sal_Int32 i)626 Reference<XAccessible> SAL_CALL VCLXAccessibleList::getAccessibleChild (sal_Int32 i)
627 {
628     vos::OGuard aSolarGuard( Application::GetSolarMutex() );
629     ::osl::Guard< ::osl::Mutex > aGuard( GetMutex() );
630 
631     if ( i < 0 || i >= getAccessibleChildCount() )
632         throw IndexOutOfBoundsException();
633 
634     Reference< XAccessible > xChild;
635     // search for the child
636     if ( i >= static_cast<sal_Int32>(m_aAccessibleChildren.size()) )
637         xChild = CreateChild (i);
638     else
639     {
640         xChild = m_aAccessibleChildren[i];
641         if ( !xChild.is() )
642             xChild = CreateChild (i);
643     }
644     OSL_ENSURE( xChild.is(), "VCLXAccessibleList::getAccessibleChild: returning empty child!" );
645     return xChild;
646 }
647 // -----------------------------------------------------------------------------
648 
getAccessibleParent()649 Reference< XAccessible > SAL_CALL VCLXAccessibleList::getAccessibleParent(  )
650 {
651     ::osl::Guard< ::osl::Mutex > aGuard( GetMutex() );
652 
653     return m_xParent;
654 }
655 // -----------------------------------------------------------------------------
656 
getAccessibleIndexInParent(void)657 sal_Int32 SAL_CALL VCLXAccessibleList::getAccessibleIndexInParent (void)
658 {
659     if (m_nIndexInParent != DEFAULT_INDEX_IN_PARENT)
660         return m_nIndexInParent;
661     else
662         return VCLXAccessibleComponent::getAccessibleIndexInParent();
663 }
664 // -----------------------------------------------------------------------------
665 
getAccessibleRole(void)666 sal_Int16 SAL_CALL VCLXAccessibleList::getAccessibleRole (void)
667 {
668     return AccessibleRole::LIST;
669 }
670 // -----------------------------------------------------------------------------
671 
672 //=====  XAccessibleComponent  ================================================
673 
contains(const awt::Point & rPoint)674 sal_Bool SAL_CALL VCLXAccessibleList::contains( const awt::Point& rPoint )
675 {
676     vos::OGuard aSolarGuard( Application::GetSolarMutex() );
677     ::osl::Guard< ::osl::Mutex > aGuard( GetMutex() );
678 
679     sal_Bool bInside = sal_False;
680 
681     Window* pListBox = GetWindow();
682     if ( pListBox )
683     {
684         Rectangle aRect( Point(0,0), pListBox->GetSizePixel() );
685         bInside = aRect.IsInside( VCLPoint( rPoint ) );
686     }
687 
688     return bInside;
689 }
690 // -----------------------------------------------------------------------------
691 
getAccessibleAt(const awt::Point & rPoint)692 Reference< XAccessible > SAL_CALL VCLXAccessibleList::getAccessibleAt( const awt::Point& rPoint )
693 {
694     vos::OGuard aSolarGuard( Application::GetSolarMutex() );
695     ::osl::Guard< ::osl::Mutex > aGuard( GetMutex() );
696 
697     Reference< XAccessible > xChild;
698     if ( m_pListBoxHelper )
699     {
700         UpdateVisibleLineCount();
701         if ( contains( rPoint ) && m_nVisibleLineCount > 0 )
702         {
703             Point aPos = VCLPoint( rPoint );
704             sal_uInt16 nEndPos = m_pListBoxHelper->GetTopEntry() + (sal_uInt16)m_nVisibleLineCount;
705             for ( sal_uInt16 i = m_pListBoxHelper->GetTopEntry(); i < nEndPos; ++i )
706             {
707                 if ( m_pListBoxHelper->GetBoundingRectangle(i).IsInside( aPos ) )
708                 {
709                     xChild = getAccessibleChild(i);
710                     break;
711                 }
712             }
713         }
714     }
715 
716     return xChild;
717 }
718 // -----------------------------------------------------------------------------
719 
720 //===== XServiceInfo ==========================================================
721 
getImplementationName(void)722 ::rtl::OUString VCLXAccessibleList::getImplementationName (void)
723 {
724     return ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.comp.toolkit.AccessibleList"));
725 }
726 // -----------------------------------------------------------------------------
727 
getSupportedServiceNames(void)728 Sequence< ::rtl::OUString > VCLXAccessibleList::getSupportedServiceNames (void)
729 {
730     Sequence< ::rtl::OUString > aNames = VCLXAccessibleComponent::getSupportedServiceNames();
731     sal_Int32 nLength = aNames.getLength();
732     aNames.realloc( nLength + 1 );
733     aNames[nLength] = ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.accessibility.AccessibleList"));
734     return aNames;
735 }
736 // -----------------------------------------------------------------------------
737 
UpdateVisibleLineCount()738 void VCLXAccessibleList::UpdateVisibleLineCount()
739 {
740     if ( m_pListBoxHelper )
741     {
742         if ( (m_pListBoxHelper->GetStyle() & WB_DROPDOWN ) == WB_DROPDOWN )
743             m_nVisibleLineCount = m_pListBoxHelper->GetDisplayLineCount();
744         else
745         {
746             sal_uInt16 nCols = 0,
747                 nLines = 0;
748             m_pListBoxHelper->GetMaxVisColumnsAndLines (nCols, nLines);
749             m_nVisibleLineCount = nLines;
750         }
751     }
752 }
753 
754 // -----------------------------------------------------------------------------
UpdateEntryRange_Impl()755 void VCLXAccessibleList::UpdateEntryRange_Impl()
756 {
757     vos::OGuard aSolarGuard( Application::GetSolarMutex() );
758     ::osl::Guard< ::osl::Mutex > aGuard( GetMutex() );
759 
760     sal_Int32 nTop = m_nLastTopEntry;
761 
762     if ( m_pListBoxHelper )
763         nTop = m_pListBoxHelper->GetTopEntry();
764     if ( nTop != m_nLastTopEntry )
765     {
766         UpdateVisibleLineCount();
767         sal_Int32 nBegin = Min( m_nLastTopEntry, nTop );
768         sal_Int32 nEnd = Max( m_nLastTopEntry + m_nVisibleLineCount, nTop + m_nVisibleLineCount );
769         for (sal_uInt16 i = static_cast<sal_uInt16>(nBegin); (i <= static_cast<sal_uInt16>(nEnd)); ++i)
770         {
771             sal_Bool bVisible = ( i >= nTop && i < ( nTop + m_nVisibleLineCount ) );
772             Reference< XAccessible > xHold;
773             if ( i < m_aAccessibleChildren.size() )
774                 xHold = m_aAccessibleChildren[i];
775             else if ( bVisible )
776                 xHold = CreateChild(i);
777 
778             if ( xHold.is() )
779                 static_cast< VCLXAccessibleListItem* >( xHold.get() )->SetVisible( m_bVisible && bVisible );
780         }
781     }
782 
783     m_nLastTopEntry = nTop;
784 }
785 // -----------------------------------------------------------------------------
checkEntrySelected(sal_uInt16 _nPos,Any & _rNewValue,Reference<XAccessible> & _rxNewAcc)786 sal_Bool VCLXAccessibleList::checkEntrySelected(sal_uInt16 _nPos,Any& _rNewValue,Reference< XAccessible >& _rxNewAcc)
787 {
788     OSL_ENSURE(m_pListBoxHelper,"Helper is not valid!");
789     sal_Bool bNowSelected = sal_False;
790     if ( m_pListBoxHelper )
791     {
792         bNowSelected = m_pListBoxHelper->IsEntryPosSelected (_nPos);
793         if ( bNowSelected )
794         {
795             _rxNewAcc = CreateChild(_nPos);
796             _rNewValue <<= _rxNewAcc;
797         }
798     }
799     return bNowSelected;
800 }
801 // -----------------------------------------------------------------------------
802 
UpdateSelection_Impl(sal_uInt16)803 void VCLXAccessibleList::UpdateSelection_Impl(sal_uInt16)
804 {
805     uno::Any aOldValue, aNewValue;
806 
807     {
808         vos::OGuard aSolarGuard( Application::GetSolarMutex() );
809         ::osl::Guard< ::osl::Mutex > aGuard( GetMutex() );
810         Reference< XAccessible > xNewAcc;
811 
812         if ( m_pListBoxHelper )
813         {
814             sal_uInt16 i=0;
815             m_nCurSelectedPos = LISTBOX_ENTRY_NOTFOUND;
816             for ( ListItems::iterator aIter = m_aAccessibleChildren.begin();
817                   aIter != m_aAccessibleChildren.end(); ++aIter,++i)
818             {
819                 Reference< XAccessible > xHold = *aIter;
820                 if ( xHold.is() )
821                 {
822                     VCLXAccessibleListItem* pItem = static_cast< VCLXAccessibleListItem* >( xHold.get() );
823                     // Retrieve the item's index from the list entry.
824                     sal_Bool bNowSelected = m_pListBoxHelper->IsEntryPosSelected (i);
825                     if (bNowSelected)
826                         m_nCurSelectedPos = i;
827 
828                     if ( bNowSelected && !pItem->IsSelected() )
829                     {
830                         xNewAcc = *aIter;
831                         aNewValue <<= xNewAcc;
832                     }
833                     else if ( pItem->IsSelected() )
834                         m_nLastSelectedPos = i;
835 
836                     pItem->SetSelected( bNowSelected );
837                 }
838                 else
839                 { // it could happen that a child was not created before
840                     checkEntrySelected(i,aNewValue,xNewAcc);
841                 }
842             }
843             sal_uInt16 nCount = m_pListBoxHelper->GetEntryCount();
844             if ( i < nCount ) // here we have to check the if any other listbox entry is selected
845             {
846                 for (; i < nCount && !checkEntrySelected(i,aNewValue,xNewAcc) ;++i )
847                     ;
848             }
849             if ( xNewAcc.is() && GetWindow()->HasFocus() )
850             {
851                 if ( m_nLastSelectedPos != LISTBOX_ENTRY_NOTFOUND )
852                     aOldValue <<= getAccessibleChild( (sal_Int32)m_nLastSelectedPos );
853                 aNewValue <<= xNewAcc;
854             }
855         }
856     }
857     if (!m_pListBoxHelper->IsInDropDown())
858     {
859     }
860     else
861     {
862         if ( aNewValue.hasValue() || aOldValue.hasValue() )
863             NotifyAccessibleEvent(
864                 AccessibleEventId::ACTIVE_DESCENDANT_CHANGED,
865                 aOldValue,
866                 aNewValue );
867         //the SELECTION_CHANGED is not necessary
868         //NotifyAccessibleEvent( AccessibleEventId::SELECTION_CHANGED, Any(), Any() );
869     }
870 }
871 
872 // -----------------------------------------------------------------------------
873 // XAccessibleSelection
874 // -----------------------------------------------------------------------------
selectAccessibleChild(sal_Int32 nChildIndex)875 void SAL_CALL VCLXAccessibleList::selectAccessibleChild( sal_Int32 nChildIndex )
876 {
877     sal_Bool bNotify = sal_False;
878 
879     {
880         vos::OGuard aSolarGuard( Application::GetSolarMutex() );
881         ::osl::Guard< ::osl::Mutex > aGuard( GetMutex() );
882 
883         if ( m_pListBoxHelper )
884         {
885             checkSelection_Impl(nChildIndex,*m_pListBoxHelper,sal_False);
886 
887             m_pListBoxHelper->SelectEntryPos( (sal_uInt16)nChildIndex, sal_True );
888             // call the select handler, don't handle events in this time
889             m_bDisableProcessEvent = true;
890             m_pListBoxHelper->Select();
891             m_bDisableProcessEvent = false;
892             bNotify = sal_True;
893         }
894     }
895 
896     if ( bNotify )
897         UpdateSelection_Impl();
898 }
899 // -----------------------------------------------------------------------------
isAccessibleChildSelected(sal_Int32 nChildIndex)900 sal_Bool SAL_CALL VCLXAccessibleList::isAccessibleChildSelected( sal_Int32 nChildIndex )
901 {
902     vos::OGuard aSolarGuard( Application::GetSolarMutex() );
903     ::osl::Guard< ::osl::Mutex > aGuard( GetMutex() );
904 
905     sal_Bool bRet = sal_False;
906     if ( m_pListBoxHelper )
907     {
908         checkSelection_Impl(nChildIndex,*m_pListBoxHelper,sal_False);
909 
910         bRet = m_pListBoxHelper->IsEntryPosSelected( (sal_uInt16)nChildIndex );
911     }
912     return bRet;
913 }
914 // -----------------------------------------------------------------------------
clearAccessibleSelection()915 void SAL_CALL VCLXAccessibleList::clearAccessibleSelection(  )
916 {
917     sal_Bool bNotify = sal_False;
918 
919     {
920         vos::OGuard aSolarGuard( Application::GetSolarMutex() );
921         ::osl::Guard< ::osl::Mutex > aGuard( GetMutex() );
922 
923         if ( m_pListBoxHelper )
924         {
925             m_pListBoxHelper->SetNoSelection();
926             bNotify = sal_True;
927         }
928     }
929 
930     if ( bNotify )
931         UpdateSelection_Impl();
932 }
933 // -----------------------------------------------------------------------------
selectAllAccessibleChildren()934 void SAL_CALL VCLXAccessibleList::selectAllAccessibleChildren(  )
935 {
936     sal_Bool bNotify = sal_False;
937 
938     {
939         vos::OGuard aSolarGuard( Application::GetSolarMutex() );
940         ::osl::Guard< ::osl::Mutex > aGuard( GetMutex() );
941 
942         if ( m_pListBoxHelper )
943         {
944             sal_uInt16 nCount = m_pListBoxHelper->GetEntryCount();
945             for ( sal_uInt16 i = 0; i < nCount; ++i )
946                 m_pListBoxHelper->SelectEntryPos( i, sal_True );
947             // call the select handler, don't handle events in this time
948             m_bDisableProcessEvent = true;
949             m_pListBoxHelper->Select();
950             m_bDisableProcessEvent = false;
951             bNotify = sal_True;
952         }
953     }
954 
955     if ( bNotify )
956         UpdateSelection_Impl();
957 }
958 // -----------------------------------------------------------------------------
getSelectedAccessibleChildCount()959 sal_Int32 SAL_CALL VCLXAccessibleList::getSelectedAccessibleChildCount(  )
960 {
961     vos::OGuard aSolarGuard( Application::GetSolarMutex() );
962     ::osl::Guard< ::osl::Mutex > aGuard( GetMutex() );
963 
964     sal_Int32 nCount = 0;
965     if ( m_pListBoxHelper )
966         nCount = m_pListBoxHelper->GetSelectEntryCount();
967     return nCount;
968 }
969 // -----------------------------------------------------------------------------
getSelectedAccessibleChild(sal_Int32 nSelectedChildIndex)970 Reference< XAccessible > SAL_CALL VCLXAccessibleList::getSelectedAccessibleChild( sal_Int32 nSelectedChildIndex )
971 {
972     vos::OGuard aSolarGuard( Application::GetSolarMutex() );
973     ::osl::Guard< ::osl::Mutex > aGuard( GetMutex() );
974 
975     if ( m_pListBoxHelper )
976     {
977         checkSelection_Impl(nSelectedChildIndex,*m_pListBoxHelper,sal_True);
978         return getAccessibleChild( (sal_Int32)m_pListBoxHelper->GetSelectEntryPos( (sal_uInt16)nSelectedChildIndex ) );
979     }
980 
981     return NULL;
982 }
983 // -----------------------------------------------------------------------------
deselectAccessibleChild(sal_Int32 nSelectedChildIndex)984 void SAL_CALL VCLXAccessibleList::deselectAccessibleChild( sal_Int32 nSelectedChildIndex )
985 {
986     sal_Bool bNotify = sal_False;
987 
988     {
989         vos::OGuard aSolarGuard( Application::GetSolarMutex() );
990         ::osl::Guard< ::osl::Mutex > aGuard( GetMutex() );
991 
992         if ( m_pListBoxHelper )
993         {
994             checkSelection_Impl(nSelectedChildIndex,*m_pListBoxHelper,sal_False);
995 
996             m_pListBoxHelper->SelectEntryPos( (sal_uInt16)nSelectedChildIndex, sal_False );
997             // call the select handler, don't handle events in this time
998             m_bDisableProcessEvent = true;
999             m_pListBoxHelper->Select();
1000             m_bDisableProcessEvent = false;
1001             bNotify = sal_True;
1002         }
1003     }
1004 
1005     if ( bNotify )
1006         UpdateSelection_Impl();
1007 }
1008 // -----------------------------------------------------------------------------
1009 // accessibility::XAccessibleComponent
implGetBounds()1010 awt::Rectangle VCLXAccessibleList::implGetBounds()
1011 {
1012     awt::Rectangle aBounds ( 0, 0, 0, 0 );
1013     if ( m_pListBoxHelper
1014         && (m_pListBoxHelper->GetStyle() & WB_DROPDOWN ) == WB_DROPDOWN )
1015     {
1016         if ( m_pListBoxHelper->IsInDropDown() )
1017             aBounds = AWTRectangle(m_pListBoxHelper->GetDropDownPosSizePixel());
1018     }
1019     else
1020     {
1021         // a list has the same bounds as his parent but starts at (0,0)
1022         aBounds = VCLXAccessibleComponent::implGetBounds();
1023         aBounds.X = 0;
1024         aBounds.Y = 0;
1025         if ( m_aBoxType == COMBOBOX )
1026         {
1027             ComboBox* pBox = static_cast<ComboBox*>(GetWindow());
1028             if ( pBox )
1029             {
1030                 Size aSize = pBox->GetSubEdit()->GetSizePixel();
1031                 aBounds.Y += aSize.Height();
1032                 aBounds.Height -= aSize.Height();
1033             }
1034         }
1035     }
1036     return aBounds;
1037 }
1038 // -----------------------------------------------------------------------------
1039 
getLocationOnScreen()1040 awt::Point VCLXAccessibleList::getLocationOnScreen(  )
1041 {
1042     vos::OGuard aSolarGuard( Application::GetSolarMutex() );
1043     ::osl::Guard< ::osl::Mutex > aGuard( GetMutex() );
1044 
1045     awt::Point aPos;
1046     if ( m_pListBoxHelper
1047         && (m_pListBoxHelper->GetStyle() & WB_DROPDOWN ) == WB_DROPDOWN )
1048     {
1049         if ( m_pListBoxHelper->IsInDropDown() )
1050             aPos = AWTPoint(m_pListBoxHelper->GetDropDownPosSizePixel().TopLeft());
1051     }
1052     else
1053     {
1054         aPos = VCLXAccessibleComponent::getLocationOnScreen();
1055         if ( m_aBoxType == COMBOBOX )
1056         {
1057             ComboBox* pBox = static_cast<ComboBox*>(GetWindow());
1058             if ( pBox )
1059             {
1060                 aPos.Y += pBox->GetSubEdit()->GetSizePixel().Height();
1061             }
1062         }
1063     }
1064     return aPos;
1065 }
1066 // -----------------------------------------------------------------------------
IsInDropDown()1067 sal_Bool    VCLXAccessibleList::IsInDropDown()
1068 {
1069     return m_pListBoxHelper->IsInDropDown();
1070 }
1071 // -----------------------------------------------------------------------------
HandleDropOpen()1072 void VCLXAccessibleList::HandleDropOpen()
1073 {
1074     if ( !m_bDisableProcessEvent )
1075         UpdateSelection_Impl();
1076     if (m_nCurSelectedPos != LISTBOX_ENTRY_NOTFOUND &&
1077         m_nLastSelectedPos != LISTBOX_ENTRY_NOTFOUND)
1078     {
1079         Reference< XAccessible > xChild = getAccessibleChild(m_nCurSelectedPos);
1080         if(xChild.is())
1081         {
1082             uno::Any aNewValue;
1083             aNewValue <<= xChild;
1084             NotifyAccessibleEvent(AccessibleEventId::ACTIVE_DESCENDANT_CHANGED, uno::Any(), aNewValue );
1085         }
1086     }
1087 }
1088