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