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