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/accessiblestatesethelper.hxx>
25 : #include <com/sun/star/accessibility/AccessibleStateType.hpp>
26 : #include <com/sun/star/accessibility/AccessibleEventId.hpp>
27 : #include <com/sun/star/accessibility/AccessibleRole.hpp>
28 : #include <vcl/svapp.hxx>
29 : #include <vcl/combobox.hxx>
30 : #include <vcl/lstbox.hxx>
31 : #include <toolkit/helper/convert.hxx>
32 :
33 : using namespace ::com::sun::star;
34 : using namespace ::com::sun::star::uno;
35 : using namespace ::com::sun::star::lang;
36 : using namespace ::com::sun::star::beans;
37 : using namespace ::com::sun::star::accessibility;
38 : using namespace ::accessibility;
39 :
40 : namespace
41 : {
42 0 : void checkSelection_Impl( sal_Int32 _nIndex, const IComboListBoxHelper& _rListBox, sal_Bool bSelected )
43 : throw (::com::sun::star::lang::IndexOutOfBoundsException)
44 : {
45 0 : sal_Int32 nCount = bSelected ? (sal_Int32)_rListBox.GetSelectEntryCount()
46 0 : : (sal_Int32)_rListBox.GetEntryCount();
47 0 : if ( _nIndex < 0 || _nIndex >= nCount )
48 0 : throw ::com::sun::star::lang::IndexOutOfBoundsException();
49 0 : }
50 : }
51 :
52 10 : VCLXAccessibleList::VCLXAccessibleList (VCLXWindow* pVCLWindow, BoxType aBoxType,
53 : const Reference< XAccessible >& _xParent)
54 : : VCLXAccessibleComponent (pVCLWindow),
55 : m_aBoxType (aBoxType),
56 : m_pListBoxHelper (0),
57 : m_nVisibleLineCount (0),
58 : m_nIndexInParent (DEFAULT_INDEX_IN_PARENT),
59 : m_nLastTopEntry ( 0 ),
60 : m_nLastSelectedPos ( LISTBOX_ENTRY_NOTFOUND ),
61 : m_bDisableProcessEvent ( false ),
62 : m_bVisible ( true ),
63 10 : m_xParent ( _xParent )
64 : {
65 : // Because combo boxes and list boxes don't have a common interface for
66 : // methods with identical signature we have to write down twice the
67 : // same code.
68 10 : switch (m_aBoxType)
69 : {
70 : case COMBOBOX:
71 : {
72 5 : ComboBox* pBox = static_cast<ComboBox*>(GetWindow());
73 5 : if ( pBox != NULL )
74 5 : m_pListBoxHelper = new VCLListBoxHelper<ComboBox> (*pBox);
75 5 : break;
76 : }
77 :
78 : case LISTBOX:
79 : {
80 5 : ListBox* pBox = static_cast<ListBox*>(GetWindow());
81 5 : if ( pBox != NULL )
82 5 : m_pListBoxHelper = new VCLListBoxHelper<ListBox> (*pBox);
83 5 : break;
84 : }
85 : }
86 10 : UpdateVisibleLineCount();
87 :
88 10 : sal_uInt16 nCount = static_cast<sal_uInt16>(getAccessibleChildCount());
89 10 : m_aAccessibleChildren.reserve(nCount);
90 10 : }
91 : // -----------------------------------------------------------------------------
92 :
93 0 : VCLXAccessibleList::~VCLXAccessibleList (void)
94 : {
95 0 : delete m_pListBoxHelper;
96 0 : }
97 : // -----------------------------------------------------------------------------
98 :
99 10 : void VCLXAccessibleList::SetIndexInParent (sal_Int32 nIndex)
100 : {
101 10 : m_nIndexInParent = nIndex;
102 10 : }
103 : // -----------------------------------------------------------------------------
104 :
105 10 : void SAL_CALL VCLXAccessibleList::disposing (void)
106 : {
107 10 : VCLXAccessibleComponent::disposing();
108 :
109 : // Dispose all items in the list.
110 10 : clearItems();
111 :
112 10 : delete m_pListBoxHelper;
113 10 : m_pListBoxHelper = NULL;
114 10 : }
115 : // -----------------------------------------------------------------------------
116 :
117 10 : void VCLXAccessibleList::clearItems()
118 : {
119 : // Clear the list itself and delete all the rest.
120 10 : ListItems().swap(m_aAccessibleChildren); // clear and minimize
121 10 : }
122 : // -----------------------------------------------------------------------------
123 :
124 13 : void VCLXAccessibleList::FillAccessibleStateSet (utl::AccessibleStateSetHelper& rStateSet)
125 : {
126 13 : SolarMutexGuard aSolarGuard;
127 :
128 13 : VCLXAccessibleComponent::FillAccessibleStateSet( rStateSet );
129 : // check if our list should be visible
130 13 : if ( m_pListBoxHelper
131 13 : && (m_pListBoxHelper->GetStyle() & WB_DROPDOWN ) == WB_DROPDOWN
132 26 : && !m_pListBoxHelper->IsInDropDown() )
133 : {
134 13 : rStateSet.RemoveState (AccessibleStateType::VISIBLE);
135 13 : rStateSet.RemoveState (AccessibleStateType::SHOWING);
136 13 : m_bVisible = false;
137 : }
138 :
139 : // Both the combo box and list box are handled identical in the
140 : // following but for some reason they don't have a common interface for
141 : // the methods used.
142 13 : if ( m_pListBoxHelper )
143 : {
144 13 : if ( m_pListBoxHelper->IsMultiSelectionEnabled() )
145 0 : rStateSet.AddState( AccessibleStateType::MULTI_SELECTABLE);
146 13 : rStateSet.AddState (AccessibleStateType::FOCUSABLE);
147 : // All children are transient.
148 13 : rStateSet.AddState (AccessibleStateType::MANAGES_DESCENDANTS);
149 13 : }
150 13 : }
151 : // -----------------------------------------------------------------------------
152 6 : void VCLXAccessibleList::notifyVisibleStates(sal_Bool _bSetNew )
153 : {
154 6 : m_bVisible = _bSetNew ? true : false;
155 12 : Any aOldValue, aNewValue;
156 6 : (_bSetNew ? aNewValue : aOldValue ) <<= AccessibleStateType::VISIBLE;
157 6 : NotifyAccessibleEvent( AccessibleEventId::STATE_CHANGED, aOldValue, aNewValue );
158 6 : (_bSetNew ? aNewValue : aOldValue ) <<= AccessibleStateType::SHOWING;
159 6 : NotifyAccessibleEvent( AccessibleEventId::STATE_CHANGED, aOldValue, aNewValue );
160 :
161 6 : ListItems::iterator aIter = m_aAccessibleChildren.begin();
162 6 : ListItems::iterator aEnd = m_aAccessibleChildren.end();
163 6 : UpdateVisibleLineCount();
164 : // adjust the index inside the VCLXAccessibleListItem
165 6 : for (;aIter != aEnd ; ++aIter)
166 : {
167 0 : Reference< XAccessible > xHold = *aIter;
168 0 : VCLXAccessibleListItem* pItem = static_cast<VCLXAccessibleListItem*>(xHold.get());
169 0 : if ( pItem )
170 : {
171 0 : sal_uInt16 nTopEntry = 0;
172 0 : if ( m_pListBoxHelper )
173 0 : nTopEntry = m_pListBoxHelper->GetTopEntry();
174 0 : sal_uInt16 nPos = (sal_uInt16)(aIter - m_aAccessibleChildren.begin());
175 0 : sal_Bool bVisible = ( nPos>=nTopEntry && nPos<( nTopEntry + m_nVisibleLineCount ) );
176 0 : pItem->SetVisible( m_bVisible && bVisible );
177 : }
178 :
179 6 : }
180 6 : }
181 : // -----------------------------------------------------------------------------
182 35 : void VCLXAccessibleList::ProcessWindowEvent (const VclWindowEvent& rVclWindowEvent)
183 : {
184 : // Create a reference to this object to prevent an early release of the
185 : // listbox (VCLEVENT_OBJECT_DYING).
186 35 : Reference< XAccessible > xTemp = this;
187 :
188 35 : switch ( rVclWindowEvent.GetId() )
189 : {
190 : case VCLEVENT_DROPDOWN_OPEN:
191 4 : notifyVisibleStates(sal_True);
192 4 : break;
193 : case VCLEVENT_DROPDOWN_CLOSE:
194 2 : notifyVisibleStates(sal_False);
195 2 : break;
196 : case VCLEVENT_LISTBOX_SCROLLED:
197 : case VCLEVENT_COMBOBOX_SCROLLED:
198 0 : UpdateEntryRange_Impl();
199 0 : break;
200 :
201 : case VCLEVENT_LISTBOX_SELECT:
202 0 : if ( !m_bDisableProcessEvent )
203 0 : UpdateSelection_Impl();
204 0 : break;
205 : // The selection events VCLEVENT_COMBOBOX_SELECT and
206 : // VCLEVENT_COMBOBOX_DESELECT are not handled here because here we
207 : // have no access to the edit field. Its text is necessary to
208 : // identify the currently selected item.
209 :
210 : case VCLEVENT_OBJECT_DYING:
211 : {
212 10 : dispose();
213 :
214 10 : VCLXAccessibleComponent::ProcessWindowEvent (rVclWindowEvent);
215 10 : break;
216 : }
217 :
218 : case VCLEVENT_LISTBOX_ITEMREMOVED:
219 : case VCLEVENT_COMBOBOX_ITEMREMOVED:
220 : HandleChangedItemList (false, reinterpret_cast<sal_IntPtr>(
221 0 : rVclWindowEvent.GetData()));
222 0 : break;
223 :
224 : case VCLEVENT_LISTBOX_ITEMADDED:
225 : case VCLEVENT_COMBOBOX_ITEMADDED:
226 : HandleChangedItemList (true, reinterpret_cast<sal_IntPtr>(
227 0 : rVclWindowEvent.GetData()));
228 0 : break;
229 : case VCLEVENT_CONTROL_GETFOCUS:
230 0 : VCLXAccessibleComponent::ProcessWindowEvent (rVclWindowEvent);
231 0 : if ( m_pListBoxHelper )
232 : {
233 0 : uno::Any aOldValue,
234 0 : aNewValue;
235 0 : sal_uInt16 nPos = m_pListBoxHelper->GetSelectEntryPos();
236 0 : if ( nPos == LISTBOX_ENTRY_NOTFOUND )
237 0 : nPos = m_pListBoxHelper->GetTopEntry();
238 0 : if ( nPos != LISTBOX_ENTRY_NOTFOUND )
239 0 : aNewValue <<= CreateChild(nPos);
240 :
241 : NotifyAccessibleEvent( AccessibleEventId::ACTIVE_DESCENDANT_CHANGED,
242 : aOldValue,
243 0 : aNewValue );
244 : }
245 0 : break;
246 :
247 : default:
248 19 : VCLXAccessibleComponent::ProcessWindowEvent (rVclWindowEvent);
249 35 : }
250 35 : }
251 : // -----------------------------------------------------------------------------
252 :
253 : /** To find out which item is currently selected and to update the SELECTED
254 : state of the associated accessibility objects accordingly we exploit the
255 : fact that the
256 : */
257 0 : void VCLXAccessibleList::UpdateSelection (OUString sTextOfSelectedItem)
258 : {
259 0 : if ( m_aBoxType == COMBOBOX )
260 : {
261 0 : ComboBox* pBox = static_cast<ComboBox*>(GetWindow());
262 0 : if ( pBox != NULL )
263 : {
264 : // Find the index of the selected item inside the VCL control...
265 0 : sal_uInt16 nIndex = pBox->GetEntryPos(sTextOfSelectedItem);
266 : // ...and then find the associated accessibility object.
267 0 : if ( nIndex == LISTBOX_ENTRY_NOTFOUND )
268 0 : nIndex = 0;
269 0 : UpdateSelection_Impl(nIndex);
270 : }
271 : }
272 0 : }
273 : // -----------------------------------------------------------------------------
274 :
275 0 : void VCLXAccessibleList::adjustEntriesIndexInParent(ListItems::iterator& _aBegin,::std::mem_fun_t<bool,VCLXAccessibleListItem>& _rMemFun)
276 : {
277 0 : ListItems::iterator aIter = _aBegin;
278 0 : ListItems::iterator aEnd = m_aAccessibleChildren.end();
279 : // adjust the index inside the VCLXAccessibleListItem
280 0 : for (;aIter != aEnd ; ++aIter)
281 : {
282 0 : Reference< XAccessible > xHold = *aIter;
283 0 : VCLXAccessibleListItem* pItem = static_cast<VCLXAccessibleListItem*>(xHold.get());
284 0 : if ( pItem )
285 0 : _rMemFun(pItem);
286 0 : }
287 0 : }
288 : // -----------------------------------------------------------------------------
289 :
290 142 : Reference<XAccessible> VCLXAccessibleList::CreateChild (sal_Int32 i)
291 : {
292 142 : Reference<XAccessible> xChild;
293 :
294 142 : sal_uInt16 nPos = static_cast<sal_uInt16>(i);
295 142 : if ( nPos >= m_aAccessibleChildren.size() )
296 : {
297 142 : m_aAccessibleChildren.resize(nPos + 1);
298 :
299 : // insert into the container
300 142 : xChild = new VCLXAccessibleListItem(m_pListBoxHelper, i, this);
301 142 : m_aAccessibleChildren[nPos] = xChild;
302 : }
303 : else
304 : {
305 0 : xChild = m_aAccessibleChildren[nPos];
306 : // check if position is empty and can be used else we have to adjust all entries behind this
307 0 : if ( xChild.is() )
308 : {
309 0 : ListItems::iterator aIter = m_aAccessibleChildren.begin() + nPos;
310 0 : ::std::mem_fun_t<bool, VCLXAccessibleListItem> aTemp(&VCLXAccessibleListItem::IncrementIndexInParent);
311 0 : adjustEntriesIndexInParent( aIter, aTemp);
312 : }
313 : else
314 : {
315 0 : xChild = new VCLXAccessibleListItem(m_pListBoxHelper, i, this);
316 0 : m_aAccessibleChildren[nPos] = xChild;
317 : }
318 : }
319 :
320 142 : if ( xChild.is() )
321 : {
322 : // Just add the SELECTED state.
323 142 : bool bNowSelected = false;
324 142 : if ( m_pListBoxHelper )
325 142 : bNowSelected = m_pListBoxHelper->IsEntryPosSelected ((sal_uInt16)i);
326 142 : VCLXAccessibleListItem* pItem = static_cast< VCLXAccessibleListItem* >(xChild.get());
327 142 : pItem->SetSelected( bNowSelected );
328 :
329 : // Set the child's VISIBLE state.
330 142 : UpdateVisibleLineCount();
331 142 : sal_uInt16 nTopEntry = 0;
332 142 : if ( m_pListBoxHelper )
333 142 : nTopEntry = m_pListBoxHelper->GetTopEntry();
334 142 : bool bVisible = ( nPos>=nTopEntry && nPos<( nTopEntry + m_nVisibleLineCount ) );
335 142 : pItem->SetVisible( m_bVisible && bVisible );
336 : }
337 :
338 142 : return xChild;
339 : }
340 : // -----------------------------------------------------------------------------
341 :
342 0 : void VCLXAccessibleList::HandleChangedItemList (bool bItemInserted, sal_Int32 nIndex)
343 : {
344 0 : if ( !bItemInserted )
345 : {
346 0 : if ( nIndex == -1 ) // special handling here
347 : {
348 0 : clearItems();
349 : }
350 : else
351 : {
352 0 : if ( nIndex >= 0 && static_cast<sal_uInt16>(nIndex) < m_aAccessibleChildren.size() )
353 : {
354 0 : ListItems::iterator aIter = m_aAccessibleChildren.erase(m_aAccessibleChildren.begin()+nIndex);
355 0 : ::std::mem_fun_t<bool, VCLXAccessibleListItem> aTemp(&VCLXAccessibleListItem::DecrementIndexInParent);
356 0 : adjustEntriesIndexInParent( aIter, aTemp );
357 : }
358 : }
359 : }
360 : else
361 0 : getAccessibleChild(nIndex);
362 :
363 : NotifyAccessibleEvent (
364 : AccessibleEventId::INVALIDATE_ALL_CHILDREN,
365 0 : Any(), Any());
366 0 : }
367 : // -----------------------------------------------------------------------------
368 :
369 1914 : IMPLEMENT_FORWARD_XINTERFACE2(VCLXAccessibleList, VCLXAccessibleComponent, VCLXAccessibleList_BASE)
370 0 : IMPLEMENT_FORWARD_XTYPEPROVIDER2(VCLXAccessibleList, VCLXAccessibleComponent, VCLXAccessibleList_BASE)
371 :
372 : //===== XAccessible =========================================================
373 :
374 : Reference<XAccessibleContext> SAL_CALL
375 155 : VCLXAccessibleList::getAccessibleContext (void)
376 : throw (RuntimeException)
377 : {
378 155 : return this;
379 : }
380 : // -----------------------------------------------------------------------------
381 :
382 : //===== XAccessibleContext ==================================================
383 :
384 164 : sal_Int32 SAL_CALL VCLXAccessibleList::getAccessibleChildCount (void)
385 : throw (RuntimeException)
386 : {
387 164 : SolarMutexGuard aSolarGuard;
388 328 : ::osl::Guard< ::osl::Mutex > aGuard( GetMutex() );
389 :
390 164 : sal_Int32 nCount = 0;
391 164 : if ( m_pListBoxHelper )
392 164 : nCount = m_pListBoxHelper->GetEntryCount();
393 :
394 328 : return nCount;
395 : }
396 : // -----------------------------------------------------------------------------
397 :
398 142 : Reference<XAccessible> SAL_CALL VCLXAccessibleList::getAccessibleChild (sal_Int32 i)
399 : throw (IndexOutOfBoundsException, RuntimeException)
400 : {
401 142 : SolarMutexGuard aSolarGuard;
402 284 : ::osl::Guard< ::osl::Mutex > aGuard( GetMutex() );
403 :
404 142 : if ( i < 0 || i >= getAccessibleChildCount() )
405 0 : throw IndexOutOfBoundsException();
406 :
407 142 : Reference< XAccessible > xChild;
408 : // search for the child
409 142 : if ( static_cast<sal_uInt16>(i) >= m_aAccessibleChildren.size() )
410 142 : xChild = CreateChild (i);
411 : else
412 : {
413 0 : xChild = m_aAccessibleChildren[i];
414 0 : if ( !xChild.is() )
415 0 : xChild = CreateChild (i);
416 : }
417 : OSL_ENSURE( xChild.is(), "VCLXAccessibleList::getAccessibleChild: returning empty child!" );
418 284 : return xChild;
419 : }
420 : // -----------------------------------------------------------------------------
421 :
422 1 : Reference< XAccessible > SAL_CALL VCLXAccessibleList::getAccessibleParent( )
423 : throw (RuntimeException)
424 : {
425 1 : ::osl::Guard< ::osl::Mutex > aGuard( GetMutex() );
426 :
427 1 : return m_xParent;
428 : }
429 : // -----------------------------------------------------------------------------
430 :
431 2 : sal_Int32 SAL_CALL VCLXAccessibleList::getAccessibleIndexInParent (void)
432 : throw (::com::sun::star::uno::RuntimeException)
433 : {
434 2 : if (m_nIndexInParent != DEFAULT_INDEX_IN_PARENT)
435 2 : return m_nIndexInParent;
436 : else
437 0 : return VCLXAccessibleComponent::getAccessibleIndexInParent();
438 : }
439 : // -----------------------------------------------------------------------------
440 :
441 22 : sal_Int16 SAL_CALL VCLXAccessibleList::getAccessibleRole (void)
442 : throw (RuntimeException)
443 : {
444 22 : return AccessibleRole::LIST;
445 : }
446 : // -----------------------------------------------------------------------------
447 :
448 : //===== XAccessibleComponent ================================================
449 :
450 0 : sal_Bool SAL_CALL VCLXAccessibleList::contains( const awt::Point& rPoint ) throw (RuntimeException)
451 : {
452 0 : SolarMutexGuard aSolarGuard;
453 0 : ::osl::Guard< ::osl::Mutex > aGuard( GetMutex() );
454 :
455 0 : sal_Bool bInside = sal_False;
456 :
457 0 : Window* pListBox = GetWindow();
458 0 : if ( pListBox )
459 : {
460 0 : Rectangle aRect( Point(0,0), pListBox->GetSizePixel() );
461 0 : bInside = aRect.IsInside( VCLPoint( rPoint ) );
462 : }
463 :
464 0 : return bInside;
465 : }
466 : // -----------------------------------------------------------------------------
467 :
468 0 : Reference< XAccessible > SAL_CALL VCLXAccessibleList::getAccessibleAt( const awt::Point& rPoint )
469 : throw (RuntimeException)
470 : {
471 0 : SolarMutexGuard aSolarGuard;
472 0 : ::osl::Guard< ::osl::Mutex > aGuard( GetMutex() );
473 :
474 0 : Reference< XAccessible > xChild;
475 0 : if ( m_pListBoxHelper )
476 : {
477 0 : UpdateVisibleLineCount();
478 0 : if ( contains( rPoint ) && m_nVisibleLineCount > 0 )
479 : {
480 0 : Point aPos = VCLPoint( rPoint );
481 0 : sal_uInt16 nEndPos = m_pListBoxHelper->GetTopEntry() + (sal_uInt16)m_nVisibleLineCount;
482 0 : for ( sal_uInt16 i = m_pListBoxHelper->GetTopEntry(); i < nEndPos; ++i )
483 : {
484 0 : if ( m_pListBoxHelper->GetBoundingRectangle(i).IsInside( aPos ) )
485 : {
486 0 : xChild = getAccessibleChild(i);
487 0 : break;
488 : }
489 : }
490 : }
491 : }
492 :
493 0 : return xChild;
494 : }
495 : // -----------------------------------------------------------------------------
496 :
497 : //===== XServiceInfo ==========================================================
498 :
499 2 : OUString VCLXAccessibleList::getImplementationName (void)
500 : throw (RuntimeException)
501 : {
502 2 : return OUString( "com.sun.star.comp.toolkit.AccessibleList" );
503 : }
504 : // -----------------------------------------------------------------------------
505 :
506 0 : Sequence< OUString > VCLXAccessibleList::getSupportedServiceNames (void)
507 : throw (RuntimeException)
508 : {
509 0 : Sequence< OUString > aNames = VCLXAccessibleComponent::getSupportedServiceNames();
510 0 : sal_Int32 nLength = aNames.getLength();
511 0 : aNames.realloc( nLength + 1 );
512 0 : aNames[nLength] = "com.sun.star.accessibility.AccessibleList";
513 0 : return aNames;
514 : }
515 : // -----------------------------------------------------------------------------
516 :
517 158 : void VCLXAccessibleList::UpdateVisibleLineCount()
518 : {
519 158 : if ( m_pListBoxHelper )
520 : {
521 158 : if ( (m_pListBoxHelper->GetStyle() & WB_DROPDOWN ) == WB_DROPDOWN )
522 158 : m_nVisibleLineCount = m_pListBoxHelper->GetDisplayLineCount();
523 : else
524 : {
525 0 : sal_uInt16 nCols = 0,
526 0 : nLines = 0;
527 0 : m_pListBoxHelper->GetMaxVisColumnsAndLines (nCols, nLines);
528 0 : m_nVisibleLineCount = nLines;
529 : }
530 : }
531 158 : }
532 :
533 : // -----------------------------------------------------------------------------
534 0 : void VCLXAccessibleList::UpdateEntryRange_Impl()
535 : {
536 0 : SolarMutexGuard aSolarGuard;
537 0 : ::osl::Guard< ::osl::Mutex > aGuard( GetMutex() );
538 :
539 0 : sal_Int32 nTop = m_nLastTopEntry;
540 :
541 0 : if ( m_pListBoxHelper )
542 0 : nTop = m_pListBoxHelper->GetTopEntry();
543 0 : if ( nTop != m_nLastTopEntry )
544 : {
545 0 : UpdateVisibleLineCount();
546 0 : sal_Int32 nBegin = std::min( m_nLastTopEntry, nTop );
547 0 : sal_Int32 nEnd = std::max( m_nLastTopEntry + m_nVisibleLineCount, nTop + m_nVisibleLineCount );
548 0 : for (sal_uInt16 i = static_cast<sal_uInt16>(nBegin); (i <= static_cast<sal_uInt16>(nEnd)); ++i)
549 : {
550 0 : sal_Bool bVisible = ( i >= nTop && i < ( nTop + m_nVisibleLineCount ) );
551 0 : Reference< XAccessible > xHold;
552 0 : if ( i < m_aAccessibleChildren.size() )
553 0 : xHold = m_aAccessibleChildren[i];
554 0 : else if ( bVisible )
555 0 : xHold = CreateChild(i);
556 :
557 0 : if ( xHold.is() )
558 0 : static_cast< VCLXAccessibleListItem* >( xHold.get() )->SetVisible( m_bVisible && bVisible );
559 0 : }
560 : }
561 :
562 0 : m_nLastTopEntry = nTop;
563 0 : }
564 : // -----------------------------------------------------------------------------
565 0 : sal_Bool VCLXAccessibleList::checkEntrySelected(sal_uInt16 _nPos,Any& _rNewValue,Reference< XAccessible >& _rxNewAcc)
566 : {
567 : OSL_ENSURE(m_pListBoxHelper,"Helper is not valid!");
568 0 : sal_Bool bNowSelected = sal_False;
569 0 : if ( m_pListBoxHelper )
570 : {
571 0 : bNowSelected = m_pListBoxHelper->IsEntryPosSelected (_nPos);
572 0 : if ( bNowSelected )
573 : {
574 0 : _rxNewAcc = CreateChild(_nPos);
575 0 : _rNewValue <<= _rxNewAcc;
576 : }
577 : }
578 0 : return bNowSelected;
579 : }
580 : // -----------------------------------------------------------------------------
581 :
582 0 : void VCLXAccessibleList::UpdateSelection_Impl(sal_uInt16)
583 : {
584 0 : uno::Any aOldValue, aNewValue;
585 :
586 : {
587 0 : SolarMutexGuard aSolarGuard;
588 0 : ::osl::Guard< ::osl::Mutex > aGuard( GetMutex() );
589 0 : Reference< XAccessible > xNewAcc;
590 :
591 0 : if ( m_pListBoxHelper )
592 : {
593 0 : sal_uInt16 i=0;
594 0 : for ( ListItems::iterator aIter = m_aAccessibleChildren.begin();
595 0 : aIter != m_aAccessibleChildren.end(); ++aIter,++i)
596 : {
597 0 : Reference< XAccessible > xHold = *aIter;
598 0 : if ( xHold.is() )
599 : {
600 0 : VCLXAccessibleListItem* pItem = static_cast< VCLXAccessibleListItem* >( xHold.get() );
601 : // Retrieve the item's index from the list entry.
602 0 : sal_Bool bNowSelected = m_pListBoxHelper->IsEntryPosSelected (i);
603 :
604 0 : if ( bNowSelected && !pItem->IsSelected() )
605 : {
606 0 : xNewAcc = *aIter;
607 0 : aNewValue <<= xNewAcc;
608 : }
609 0 : else if ( pItem->IsSelected() )
610 0 : m_nLastSelectedPos = i;
611 :
612 0 : pItem->SetSelected( bNowSelected );
613 : }
614 : else
615 : { // it could happen that a child was not created before
616 0 : checkEntrySelected(i,aNewValue,xNewAcc);
617 : }
618 0 : }
619 0 : sal_uInt16 nCount = m_pListBoxHelper->GetEntryCount();
620 0 : if ( i < nCount ) // here we have to check the if any other listbox entry is selected
621 : {
622 0 : for (; i < nCount && !checkEntrySelected(i,aNewValue,xNewAcc) ;++i )
623 : ;
624 : }
625 0 : if ( xNewAcc.is() && GetWindow()->HasFocus() )
626 : {
627 0 : if ( m_nLastSelectedPos != LISTBOX_ENTRY_NOTFOUND )
628 0 : aOldValue <<= getAccessibleChild( (sal_Int32)m_nLastSelectedPos );
629 0 : aNewValue <<= xNewAcc;
630 : }
631 0 : }
632 : }
633 :
634 0 : if ( aNewValue.hasValue() || aOldValue.hasValue() )
635 : NotifyAccessibleEvent(
636 : AccessibleEventId::ACTIVE_DESCENDANT_CHANGED,
637 : aOldValue,
638 0 : aNewValue );
639 :
640 0 : NotifyAccessibleEvent( AccessibleEventId::SELECTION_CHANGED, Any(), Any() );
641 0 : }
642 :
643 : // -----------------------------------------------------------------------------
644 : // XAccessibleSelection
645 : // -----------------------------------------------------------------------------
646 0 : void SAL_CALL VCLXAccessibleList::selectAccessibleChild( sal_Int32 nChildIndex ) throw (IndexOutOfBoundsException, RuntimeException)
647 : {
648 0 : sal_Bool bNotify = sal_False;
649 :
650 : {
651 0 : SolarMutexGuard aSolarGuard;
652 0 : ::osl::Guard< ::osl::Mutex > aGuard( GetMutex() );
653 :
654 0 : if ( m_pListBoxHelper )
655 : {
656 0 : checkSelection_Impl(nChildIndex,*m_pListBoxHelper,sal_False);
657 :
658 0 : m_pListBoxHelper->SelectEntryPos( (sal_uInt16)nChildIndex, sal_True );
659 : // call the select handler, don't handle events in this time
660 0 : m_bDisableProcessEvent = true;
661 0 : m_pListBoxHelper->Select();
662 0 : m_bDisableProcessEvent = false;
663 0 : bNotify = sal_True;
664 0 : }
665 : }
666 :
667 0 : if ( bNotify )
668 0 : UpdateSelection_Impl();
669 0 : }
670 : // -----------------------------------------------------------------------------
671 0 : sal_Bool SAL_CALL VCLXAccessibleList::isAccessibleChildSelected( sal_Int32 nChildIndex ) throw (IndexOutOfBoundsException, RuntimeException)
672 : {
673 0 : SolarMutexGuard aSolarGuard;
674 0 : ::osl::Guard< ::osl::Mutex > aGuard( GetMutex() );
675 :
676 0 : sal_Bool bRet = sal_False;
677 0 : if ( m_pListBoxHelper )
678 : {
679 0 : checkSelection_Impl(nChildIndex,*m_pListBoxHelper,sal_False);
680 :
681 0 : bRet = m_pListBoxHelper->IsEntryPosSelected( (sal_uInt16)nChildIndex );
682 : }
683 0 : return bRet;
684 : }
685 : // -----------------------------------------------------------------------------
686 0 : void SAL_CALL VCLXAccessibleList::clearAccessibleSelection( ) throw (RuntimeException)
687 : {
688 0 : sal_Bool bNotify = sal_False;
689 :
690 : {
691 0 : SolarMutexGuard aSolarGuard;
692 0 : ::osl::Guard< ::osl::Mutex > aGuard( GetMutex() );
693 :
694 0 : if ( m_pListBoxHelper )
695 : {
696 0 : m_pListBoxHelper->SetNoSelection();
697 0 : bNotify = sal_True;
698 0 : }
699 : }
700 :
701 0 : if ( bNotify )
702 0 : UpdateSelection_Impl();
703 0 : }
704 : // -----------------------------------------------------------------------------
705 0 : void SAL_CALL VCLXAccessibleList::selectAllAccessibleChildren( ) throw (RuntimeException)
706 : {
707 0 : sal_Bool bNotify = sal_False;
708 :
709 : {
710 0 : SolarMutexGuard aSolarGuard;
711 0 : ::osl::Guard< ::osl::Mutex > aGuard( GetMutex() );
712 :
713 0 : if ( m_pListBoxHelper )
714 : {
715 0 : sal_uInt16 nCount = m_pListBoxHelper->GetEntryCount();
716 0 : for ( sal_uInt16 i = 0; i < nCount; ++i )
717 0 : m_pListBoxHelper->SelectEntryPos( i, sal_True );
718 : // call the select handler, don't handle events in this time
719 0 : m_bDisableProcessEvent = true;
720 0 : m_pListBoxHelper->Select();
721 0 : m_bDisableProcessEvent = false;
722 0 : bNotify = sal_True;
723 0 : }
724 : }
725 :
726 0 : if ( bNotify )
727 0 : UpdateSelection_Impl();
728 0 : }
729 : // -----------------------------------------------------------------------------
730 0 : sal_Int32 SAL_CALL VCLXAccessibleList::getSelectedAccessibleChildCount( ) throw (RuntimeException)
731 : {
732 0 : SolarMutexGuard aSolarGuard;
733 0 : ::osl::Guard< ::osl::Mutex > aGuard( GetMutex() );
734 :
735 0 : sal_Int32 nCount = 0;
736 0 : if ( m_pListBoxHelper )
737 0 : nCount = m_pListBoxHelper->GetSelectEntryCount();
738 0 : return nCount;
739 : }
740 : // -----------------------------------------------------------------------------
741 0 : Reference< XAccessible > SAL_CALL VCLXAccessibleList::getSelectedAccessibleChild( sal_Int32 nSelectedChildIndex ) throw (IndexOutOfBoundsException, RuntimeException)
742 : {
743 0 : SolarMutexGuard aSolarGuard;
744 0 : ::osl::Guard< ::osl::Mutex > aGuard( GetMutex() );
745 :
746 0 : if ( m_pListBoxHelper )
747 : {
748 0 : checkSelection_Impl(nSelectedChildIndex,*m_pListBoxHelper,sal_True);
749 0 : return getAccessibleChild( (sal_Int32)m_pListBoxHelper->GetSelectEntryPos( (sal_uInt16)nSelectedChildIndex ) );
750 : }
751 :
752 0 : return NULL;
753 : }
754 : // -----------------------------------------------------------------------------
755 0 : void SAL_CALL VCLXAccessibleList::deselectAccessibleChild( sal_Int32 nSelectedChildIndex ) throw (IndexOutOfBoundsException, RuntimeException)
756 : {
757 0 : sal_Bool bNotify = sal_False;
758 :
759 : {
760 0 : SolarMutexGuard aSolarGuard;
761 0 : ::osl::Guard< ::osl::Mutex > aGuard( GetMutex() );
762 :
763 0 : if ( m_pListBoxHelper )
764 : {
765 0 : checkSelection_Impl(nSelectedChildIndex,*m_pListBoxHelper,sal_False);
766 :
767 0 : m_pListBoxHelper->SelectEntryPos( (sal_uInt16)nSelectedChildIndex, sal_False );
768 : // call the select handler, don't handle events in this time
769 0 : m_bDisableProcessEvent = true;
770 0 : m_pListBoxHelper->Select();
771 0 : m_bDisableProcessEvent = false;
772 0 : bNotify = sal_True;
773 0 : }
774 : }
775 :
776 0 : if ( bNotify )
777 0 : UpdateSelection_Impl();
778 0 : }
779 : // -----------------------------------------------------------------------------
780 4 : awt::Rectangle VCLXAccessibleList::implGetBounds() throw (uno::RuntimeException)
781 : {
782 4 : awt::Rectangle aBounds ( 0, 0, 0, 0 );
783 4 : if ( m_pListBoxHelper
784 4 : && (m_pListBoxHelper->GetStyle() & WB_DROPDOWN ) == WB_DROPDOWN )
785 : {
786 4 : if ( m_pListBoxHelper->IsInDropDown() )
787 0 : aBounds = AWTRectangle(m_pListBoxHelper->GetDropDownPosSizePixel());
788 : }
789 : else
790 : {
791 : // a list has the same bounds as his parent but starts at (0,0)
792 0 : aBounds = VCLXAccessibleComponent::implGetBounds();
793 0 : aBounds.X = 0;
794 0 : aBounds.Y = 0;
795 0 : if ( m_aBoxType == COMBOBOX )
796 : {
797 0 : ComboBox* pBox = static_cast<ComboBox*>(GetWindow());
798 0 : if ( pBox )
799 : {
800 0 : Size aSize = pBox->GetSubEdit()->GetSizePixel();
801 0 : aBounds.X += aSize.Height();
802 0 : aBounds.Y += aSize.Width();
803 0 : aBounds.Height -= aSize.Height();
804 0 : aBounds.Width -= aSize.Width();
805 : }
806 : }
807 : }
808 4 : return aBounds;
809 : }
810 : // -----------------------------------------------------------------------------
811 :
812 0 : awt::Point VCLXAccessibleList::getLocationOnScreen( ) throw (uno::RuntimeException)
813 : {
814 0 : SolarMutexGuard aSolarGuard;
815 0 : ::osl::Guard< ::osl::Mutex > aGuard( GetMutex() );
816 :
817 0 : awt::Point aPos;
818 0 : if ( m_pListBoxHelper
819 0 : && (m_pListBoxHelper->GetStyle() & WB_DROPDOWN ) == WB_DROPDOWN )
820 : {
821 0 : if ( m_pListBoxHelper->IsInDropDown() )
822 0 : aPos = AWTPoint(m_pListBoxHelper->GetDropDownPosSizePixel().TopLeft());
823 : }
824 : else
825 : {
826 0 : aPos = VCLXAccessibleComponent::getLocationOnScreen();
827 0 : if ( m_aBoxType == COMBOBOX )
828 : {
829 0 : ComboBox* pBox = static_cast<ComboBox*>(GetWindow());
830 0 : if ( pBox )
831 : {
832 0 : aPos.X += pBox->GetSubEdit()->GetSizePixel().Height();
833 0 : aPos.Y += pBox->GetSubEdit()->GetSizePixel().Width();
834 : }
835 : }
836 : }
837 0 : return aPos;
838 30 : }
839 : // -----------------------------------------------------------------------------
840 :
841 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|