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