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