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