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