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