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_svx.hxx" 30 31 //------------------------------------------------------------------------ 32 // 33 // Global header 34 // 35 //------------------------------------------------------------------------ 36 37 #include <limits.h> 38 #include <memory> 39 #include <algorithm> 40 #include <deque> 41 #include <vos/mutex.hxx> 42 #include <com/sun/star/uno/Any.hxx> 43 #include <com/sun/star/uno/Reference.hxx> 44 #include <cppuhelper/weakref.hxx> 45 #include <com/sun/star/awt/Point.hpp> 46 #include <com/sun/star/awt/Rectangle.hpp> 47 #include <com/sun/star/lang/DisposedException.hpp> 48 #include <com/sun/star/accessibility/AccessibleEventId.hpp> 49 #include <com/sun/star/accessibility/XAccessible.hpp> 50 #include <com/sun/star/accessibility/XAccessibleContext.hpp> 51 #include <com/sun/star/accessibility/XAccessibleComponent.hpp> 52 #include <com/sun/star/accessibility/AccessibleStateType.hpp> 53 #include <comphelper/accessibleeventnotifier.hxx> 54 #include <unotools/accessiblestatesethelper.hxx> 55 #include <vcl/unohelp.hxx> 56 #include <vcl/svapp.hxx> 57 58 //------------------------------------------------------------------------ 59 // 60 // Project-local header 61 // 62 //------------------------------------------------------------------------ 63 #include "AccessibleTextEventQueue.hxx" 64 #include <svx/AccessibleTextHelper.hxx> 65 #include <svx/unoshape.hxx> 66 #include "editeng/unolingu.hxx" 67 #include <editeng/unotext.hxx> 68 69 #include "editeng/unoedhlp.hxx" 70 #include "editeng/unopracc.hxx" 71 #include "editeng/AccessibleParaManager.hxx" 72 #include "editeng/AccessibleEditableTextPara.hxx" 73 #include <svx/svdmodel.hxx> 74 #include <svx/svdpntv.hxx> 75 #include <editeng/editdata.hxx> 76 #include <editeng/editeng.hxx> 77 #include <editeng/editview.hxx> 78 79 using namespace ::com::sun::star; 80 using namespace ::com::sun::star::accessibility; 81 82 namespace accessibility 83 { 84 85 //------------------------------------------------------------------------ 86 // 87 // AccessibleTextHelper_Impl declaration 88 // 89 //------------------------------------------------------------------------ 90 91 DBG_NAME( AccessibleTextHelper_Impl ) 92 93 template < typename first_type, typename second_type > 94 ::std::pair< first_type, second_type > makeSortedPair( first_type first, 95 second_type second ) 96 { 97 if( first > second ) 98 return ::std::make_pair( second, first ); 99 else 100 return ::std::make_pair( first, second ); 101 } 102 103 class AccessibleTextHelper_Impl : public SfxListener 104 { 105 106 public: 107 typedef ::std::vector< sal_Int16 > VectorOfStates; 108 109 // receive pointer to our frontend class and view window 110 AccessibleTextHelper_Impl(); 111 ~AccessibleTextHelper_Impl(); 112 113 // XAccessibleContext child handling methods 114 sal_Int32 SAL_CALL getAccessibleChildCount() SAL_THROW((uno::RuntimeException)); 115 uno::Reference< XAccessible > SAL_CALL getAccessibleChild( sal_Int32 i ) SAL_THROW((lang::IndexOutOfBoundsException, uno::RuntimeException)); 116 117 // XAccessibleEventBroadcaster child related methods 118 void SAL_CALL addEventListener( const uno::Reference< XAccessibleEventListener >& xListener ) SAL_THROW((uno::RuntimeException)); 119 void SAL_CALL removeEventListener( const uno::Reference< XAccessibleEventListener >& xListener ) SAL_THROW((uno::RuntimeException)); 120 121 // XAccessibleComponent child related methods 122 uno::Reference< XAccessible > SAL_CALL getAccessibleAtPoint( const awt::Point& aPoint ) SAL_THROW((uno::RuntimeException)); 123 124 SvxEditSourceAdapter& GetEditSource() const SAL_THROW((uno::RuntimeException)); 125 void SetEditSource( ::std::auto_ptr< SvxEditSource > pEditSource ) SAL_THROW((uno::RuntimeException)); 126 127 void SetEventSource( const uno::Reference< XAccessible >& rInterface ) 128 { 129 DBG_CHKTHIS( AccessibleTextHelper_Impl, NULL ); 130 mxFrontEnd = rInterface; 131 } 132 uno::Reference< XAccessible > GetEventSource() const 133 { 134 DBG_CHKTHIS( AccessibleTextHelper_Impl, NULL ); 135 return mxFrontEnd; 136 } 137 138 void SetOffset( const Point& ); 139 Point GetOffset() const 140 { 141 DBG_CHKTHIS( AccessibleTextHelper_Impl, NULL ); 142 ::osl::MutexGuard aGuard( maMutex ); Point aPoint( maOffset ); 143 return aPoint; 144 } 145 146 void SetStartIndex( sal_Int32 nOffset ); 147 sal_Int32 GetStartIndex() const 148 { 149 DBG_CHKTHIS( AccessibleTextHelper_Impl, NULL ); 150 // Strictly correct only with locked solar mutex, // but 151 // here we rely on the fact that sal_Int32 access is 152 // atomic 153 return mnStartIndex; 154 } 155 156 void SetAdditionalChildStates( const VectorOfStates& rChildStates ); 157 const VectorOfStates& GetAdditionalChildStates() const; 158 159 sal_Bool IsSelected() const; 160 161 void Dispose(); 162 163 // do NOT hold object mutex when calling this! Danger of deadlock 164 void FireEvent( const sal_Int16 nEventId, const uno::Any& rNewValue = uno::Any(), const uno::Any& rOldValue = uno::Any() ) const; 165 void FireEvent( const AccessibleEventObject& rEvent ) const; 166 167 void SetFocus( sal_Bool bHaveFocus ) SAL_THROW((::com::sun::star::uno::RuntimeException)); 168 sal_Bool HaveFocus() SAL_THROW((::com::sun::star::uno::RuntimeException)); 169 void SetChildFocus( sal_Int32 nChild, sal_Bool bHaveFocus ) SAL_THROW((::com::sun::star::uno::RuntimeException)); 170 void SetShapeFocus( sal_Bool bHaveFocus ) SAL_THROW((::com::sun::star::uno::RuntimeException)); 171 void ChangeChildFocus( sal_Int32 nNewChild ) SAL_THROW((::com::sun::star::uno::RuntimeException)); 172 173 #ifdef DBG_UTIL 174 void CheckInvariants() const; 175 #endif 176 177 // checks all children for visibility, throws away invisible ones 178 void UpdateVisibleChildren( bool bBroadcastEvents=true ); 179 180 // check all children for changes in posit�on and size 181 void UpdateBoundRect(); 182 183 // calls SetSelection on the forwarder and updates maLastSelection 184 // cache. 185 void UpdateSelection(); 186 187 private: 188 189 // Process event queue 190 void ProcessQueue(); 191 192 // syntactic sugar for FireEvent 193 void GotPropertyEvent( const uno::Any& rNewValue, const sal_Int16 nEventId ) const { FireEvent( nEventId, rNewValue ); } 194 void LostPropertyEvent( const uno::Any& rOldValue, const sal_Int16 nEventId ) const { FireEvent( nEventId, uno::Any(), rOldValue ); } 195 196 // shutdown usage of current edit source on myself and the children. 197 void ShutdownEditSource() SAL_THROW((uno::RuntimeException)); 198 199 void ParagraphsMoved( sal_Int32 nFirst, sal_Int32 nMiddle, sal_Int32 nLast ); 200 201 virtual void Notify( SfxBroadcaster& rBC, const SfxHint& rHint ); 202 203 int getNotifierClientId() const { return mnNotifierClientId; } 204 205 // lock solar mutex before 206 SvxTextForwarder& GetTextForwarder() const SAL_THROW((uno::RuntimeException)); 207 // lock solar mutex before 208 SvxViewForwarder& GetViewForwarder() const SAL_THROW((uno::RuntimeException)); 209 // lock solar mutex before 210 SvxEditViewForwarder& GetEditViewForwarder( sal_Bool bCreate = sal_False ) const SAL_THROW((uno::RuntimeException)); 211 212 // are we in edit mode? 213 sal_Bool IsActive() const SAL_THROW((uno::RuntimeException)); 214 215 // our frontend class (the one implementing the actual 216 // interface). That's not necessarily the one containing the impl 217 // pointer! 218 uno::Reference< XAccessible > mxFrontEnd; 219 220 // a wrapper for the text forwarders (guarded by solar mutex) 221 mutable SvxEditSourceAdapter maEditSource; 222 223 // store last selection (to correctly report selection changes, guarded by solar mutex) 224 ESelection maLastSelection; 225 226 // cache range of visible children (guarded by solar mutex) 227 sal_Int32 mnFirstVisibleChild; 228 sal_Int32 mnLastVisibleChild; 229 230 // offset to add to all our children (unguarded, relying on 231 // the fact that sal_Int32 access is atomic) 232 sal_Int32 mnStartIndex; 233 234 // the object handling our children (guarded by solar mutex) 235 ::accessibility::AccessibleParaManager maParaManager; 236 237 // number of not-yet-closed event frames (BEGIN/END sequences) (guarded by solar mutex) 238 sal_Int32 maEventOpenFrames; 239 240 // Queued events from Notify() (guarded by solar mutex) 241 AccessibleTextEventQueue maEventQueue; 242 243 // spin lock to prevent notify in notify (guarded by solar mutex) 244 sal_Bool mbInNotify; 245 246 // whether the object or it's children has the focus set (guarded by solar mutex) 247 sal_Bool mbGroupHasFocus; 248 249 // whether we (this object) has the focus set (guarded by solar mutex) 250 sal_Bool mbThisHasFocus; 251 252 mutable ::osl::Mutex maMutex; 253 254 /// our current offset to the containing shape/cell (guarded by maMutex) 255 Point maOffset; 256 257 /// client Id from AccessibleEventNotifier 258 int mnNotifierClientId; 259 }; 260 261 //------------------------------------------------------------------------ 262 // 263 // AccessibleTextHelper_Impl implementation 264 // 265 //------------------------------------------------------------------------ 266 267 AccessibleTextHelper_Impl::AccessibleTextHelper_Impl() : 268 mxFrontEnd( NULL ), 269 maLastSelection( EE_PARA_NOT_FOUND,EE_PARA_NOT_FOUND,EE_PARA_NOT_FOUND,EE_PARA_NOT_FOUND ), 270 mnFirstVisibleChild( -1 ), 271 mnLastVisibleChild( -2 ), 272 mnStartIndex( 0 ), 273 maEventOpenFrames( 0 ), 274 mbInNotify( sal_False ), 275 mbGroupHasFocus( sal_False ), 276 mbThisHasFocus( sal_False ), 277 maOffset(0,0), 278 // well, that's strictly exception safe, though not really 279 // robust. We rely on the fact that this member is constructed 280 // last, and that the constructor body is empty, thus no 281 // chance for exceptions once the Id is fetched. Nevertheless, 282 // normally should employ RAII here... 283 mnNotifierClientId(::comphelper::AccessibleEventNotifier::registerClient()) 284 { 285 DBG_CTOR( AccessibleTextHelper_Impl, NULL ); 286 287 #ifdef DBG_UTIL 288 OSL_TRACE( "AccessibleTextHelper_Impl received ID: %d", mnNotifierClientId ); 289 #endif 290 } 291 292 AccessibleTextHelper_Impl::~AccessibleTextHelper_Impl() 293 { 294 DBG_DTOR( AccessibleTextHelper_Impl, NULL ); 295 296 ::vos::OGuard aGuard( Application::GetSolarMutex() ); 297 298 try 299 { 300 // call Dispose here, too, since we've some resources not 301 // automatically freed otherwise 302 Dispose(); 303 } 304 catch( const uno::Exception& ) {} 305 } 306 307 SvxTextForwarder& AccessibleTextHelper_Impl::GetTextForwarder() const SAL_THROW((uno::RuntimeException)) 308 { 309 DBG_CHKTHIS( AccessibleTextHelper_Impl, NULL ); 310 311 if( !maEditSource.IsValid() ) 312 throw uno::RuntimeException(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("Unknown edit source")), mxFrontEnd); 313 314 SvxTextForwarder* pTextForwarder = maEditSource.GetTextForwarder(); 315 316 if( !pTextForwarder ) 317 throw uno::RuntimeException(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("Unable to fetch text forwarder, model might be dead")), mxFrontEnd); 318 319 if( pTextForwarder->IsValid() ) 320 return *pTextForwarder; 321 else 322 throw uno::RuntimeException(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("Text forwarder is invalid, model might be dead")), mxFrontEnd); 323 } 324 325 SvxViewForwarder& AccessibleTextHelper_Impl::GetViewForwarder() const SAL_THROW((uno::RuntimeException)) 326 { 327 DBG_CHKTHIS( AccessibleTextHelper_Impl, NULL ); 328 329 if( !maEditSource.IsValid() ) 330 throw uno::RuntimeException(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("Unknown edit source")), mxFrontEnd); 331 332 SvxViewForwarder* pViewForwarder = maEditSource.GetViewForwarder(); 333 334 if( !pViewForwarder ) 335 throw uno::RuntimeException(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("Unable to fetch view forwarder, model might be dead")), mxFrontEnd); 336 337 if( pViewForwarder->IsValid() ) 338 return *pViewForwarder; 339 else 340 throw uno::RuntimeException(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("View forwarder is invalid, model might be dead")), mxFrontEnd); 341 } 342 343 SvxEditViewForwarder& AccessibleTextHelper_Impl::GetEditViewForwarder( sal_Bool bCreate ) const SAL_THROW((uno::RuntimeException)) 344 { 345 DBG_CHKTHIS( AccessibleTextHelper_Impl, NULL ); 346 347 if( !maEditSource.IsValid() ) 348 throw uno::RuntimeException(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("Unknown edit source")), mxFrontEnd); 349 350 SvxEditViewForwarder* pViewForwarder = maEditSource.GetEditViewForwarder( bCreate ); 351 352 if( !pViewForwarder ) 353 { 354 if( bCreate ) 355 throw uno::RuntimeException(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("Unable to fetch edit view forwarder, model might be dead")), mxFrontEnd); 356 else 357 throw uno::RuntimeException(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("No edit view forwarder, object not in edit mode")), mxFrontEnd); 358 } 359 360 if( pViewForwarder->IsValid() ) 361 return *pViewForwarder; 362 else 363 { 364 if( bCreate ) 365 throw uno::RuntimeException(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("View forwarder is invalid, model might be dead")), mxFrontEnd); 366 else 367 throw uno::RuntimeException(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("View forwarder is invalid, object not in edit mode")), mxFrontEnd); 368 } 369 } 370 371 SvxEditSourceAdapter& AccessibleTextHelper_Impl::GetEditSource() const SAL_THROW((uno::RuntimeException)) 372 { 373 DBG_CHKTHIS( AccessibleTextHelper_Impl, NULL ); 374 375 if( maEditSource.IsValid() ) 376 return maEditSource; 377 else 378 throw uno::RuntimeException(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("AccessibleTextHelper_Impl::GetEditSource: no edit source")), mxFrontEnd ); 379 } 380 381 sal_Bool AccessibleTextHelper_Impl::IsSelected() const 382 { 383 DBG_CHKTHIS( AccessibleTextHelper_Impl, NULL ); 384 385 sal_Bool bRet = sal_False; 386 387 try 388 { 389 ESelection aSelection; 390 bRet = GetEditViewForwarder().GetSelection( aSelection ); 391 } 392 catch( const uno::Exception& ) {} 393 394 return bRet; 395 } 396 397 // functor for sending child events (no stand-alone function, they are maybe not inlined) 398 class AccessibleTextHelper_OffsetChildIndex : public ::std::unary_function< ::accessibility::AccessibleEditableTextPara&, void > 399 { 400 public: 401 AccessibleTextHelper_OffsetChildIndex( sal_Int32 nDifference ) : mnDifference(nDifference) {} 402 void operator()( ::accessibility::AccessibleEditableTextPara& rPara ) 403 { 404 rPara.SetIndexInParent( rPara.GetIndexInParent() + mnDifference ); 405 } 406 407 private: 408 const sal_Int32 mnDifference; 409 }; 410 411 void AccessibleTextHelper_Impl::SetStartIndex( sal_Int32 nOffset ) 412 { 413 DBG_CHKTHIS( AccessibleTextHelper_Impl, NULL ); 414 415 sal_Int32 nOldOffset( mnStartIndex ); 416 417 mnStartIndex = nOffset; 418 419 if( nOldOffset != nOffset ) 420 { 421 // update children 422 AccessibleTextHelper_OffsetChildIndex aFunctor( nOffset - nOldOffset ); 423 424 ::std::for_each( maParaManager.begin(), maParaManager.end(), 425 AccessibleParaManager::WeakChildAdapter< AccessibleTextHelper_OffsetChildIndex > (aFunctor) ); 426 } 427 } 428 429 void AccessibleTextHelper_Impl::SetAdditionalChildStates( const VectorOfStates& rChildStates ) 430 { 431 maParaManager.SetAdditionalChildStates( rChildStates ); 432 } 433 434 const AccessibleTextHelper_Impl::VectorOfStates& AccessibleTextHelper_Impl::GetAdditionalChildStates() const 435 { 436 return maParaManager.GetAdditionalChildStates(); 437 } 438 439 void AccessibleTextHelper_Impl::SetChildFocus( sal_Int32 nChild, sal_Bool bHaveFocus ) SAL_THROW((::com::sun::star::uno::RuntimeException)) 440 { 441 DBG_CHKTHIS( AccessibleTextHelper_Impl, NULL ); 442 443 if( bHaveFocus ) 444 { 445 if( mbThisHasFocus ) 446 SetShapeFocus( sal_False ); 447 448 maParaManager.SetFocus( nChild ); 449 450 // we just received the focus, also send caret event then 451 UpdateSelection(); 452 453 DBG_TRACE1("AccessibleTextHelper_Impl::SetChildFocus(): Paragraph %d received focus", nChild ); 454 } 455 else 456 { 457 maParaManager.SetFocus( -1 ); 458 459 DBG_TRACE1("AccessibleTextHelper_Impl::SetChildFocus(): Paragraph %d lost focus", nChild ); 460 461 if( mbGroupHasFocus ) 462 SetShapeFocus( sal_True ); 463 } 464 } 465 466 void AccessibleTextHelper_Impl::ChangeChildFocus( sal_Int32 nNewChild ) SAL_THROW((::com::sun::star::uno::RuntimeException)) 467 { 468 DBG_CHKTHIS( AccessibleTextHelper_Impl, NULL ); 469 470 if( mbThisHasFocus ) 471 SetShapeFocus( sal_False ); 472 473 mbGroupHasFocus = sal_True; 474 maParaManager.SetFocus( nNewChild ); 475 476 DBG_TRACE1("AccessibleTextHelper_Impl::ChangeChildFocus(): Paragraph %d received focus", nNewChild ); 477 } 478 479 void AccessibleTextHelper_Impl::SetShapeFocus( sal_Bool bHaveFocus ) SAL_THROW((::com::sun::star::uno::RuntimeException)) 480 { 481 DBG_CHKTHIS( AccessibleTextHelper_Impl, NULL ); 482 483 sal_Bool bOldFocus( mbThisHasFocus ); 484 485 mbThisHasFocus = bHaveFocus; 486 487 if( bOldFocus != bHaveFocus ) 488 { 489 if( bHaveFocus ) 490 { 491 GotPropertyEvent( uno::makeAny(AccessibleStateType::FOCUSED), AccessibleEventId::STATE_CHANGED ); 492 DBG_TRACE("AccessibleTextHelper_Impl::SetShapeFocus(): Parent object received focus" ); 493 } 494 else 495 { 496 LostPropertyEvent( uno::makeAny(AccessibleStateType::FOCUSED), AccessibleEventId::STATE_CHANGED ); 497 DBG_TRACE("AccessibleTextHelper_Impl::SetShapeFocus(): Parent object lost focus" ); 498 } 499 } 500 } 501 502 void AccessibleTextHelper_Impl::SetFocus( sal_Bool bHaveFocus ) SAL_THROW((::com::sun::star::uno::RuntimeException)) 503 { 504 DBG_CHKTHIS( AccessibleTextHelper_Impl, NULL ); 505 506 sal_Bool bOldFocus( mbGroupHasFocus ); 507 508 mbGroupHasFocus = bHaveFocus; 509 510 if( IsActive() ) 511 { 512 try 513 { 514 // find the one with the cursor and get/set focus accordingly 515 ESelection aSelection; 516 if( GetEditViewForwarder().GetSelection( aSelection ) ) 517 SetChildFocus( aSelection.nEndPara, bHaveFocus ); 518 } 519 catch( const uno::Exception& ) {} 520 } 521 else if( bOldFocus != bHaveFocus ) 522 { 523 SetShapeFocus( bHaveFocus ); 524 } 525 526 DBG_TRACE2("AccessibleTextHelper_Impl::SetFocus: focus changed, Object %d, state: %s", this, bHaveFocus ? "focused" : "not focused"); 527 } 528 529 sal_Bool AccessibleTextHelper_Impl::HaveFocus() SAL_THROW((::com::sun::star::uno::RuntimeException)) 530 { 531 DBG_CHKTHIS( AccessibleTextHelper_Impl, NULL ); 532 533 // No locking of solar mutex here, since we rely on the fact 534 // that sal_Bool access is atomic 535 return mbThisHasFocus; 536 } 537 538 sal_Bool AccessibleTextHelper_Impl::IsActive() const SAL_THROW((uno::RuntimeException)) 539 { 540 DBG_CHKTHIS( AccessibleTextHelper_Impl, NULL ); 541 542 try 543 { 544 SvxEditSource& rEditSource = GetEditSource(); 545 SvxEditViewForwarder* pViewForwarder = rEditSource.GetEditViewForwarder(); 546 547 if( !pViewForwarder ) 548 return sal_False; 549 550 if( pViewForwarder->IsValid() ) 551 return sal_True; 552 else 553 return sal_False; 554 } 555 catch( const uno::RuntimeException& ) 556 { 557 return sal_False; 558 } 559 } 560 561 void AccessibleTextHelper_Impl::UpdateSelection() 562 { 563 DBG_CHKTHIS( AccessibleTextHelper_Impl, NULL ); 564 565 try 566 { 567 ESelection aSelection; 568 if( GetEditViewForwarder().GetSelection( aSelection ) ) 569 { 570 if( !maLastSelection.IsEqual( aSelection ) && 571 aSelection.nEndPara < maParaManager.GetNum() ) 572 { 573 // #103998# Not that important, changed from assertion to trace 574 if( mbThisHasFocus ) 575 { 576 DBG_TRACE("AccessibleTextHelper_Impl::UpdateSelection(): Parent has focus!"); 577 } 578 579 sal_uInt16 nMaxValidParaIndex( static_cast< sal_uInt16 >( GetTextForwarder().GetParagraphCount() ) - 1 ); 580 581 // notify all affected paragraphs (TODO: may be suboptimal, 582 // since some paragraphs might stay selected) 583 if( maLastSelection.nStartPara != EE_PARA_NOT_FOUND ) 584 { 585 // Did the caret move from one paragraph to another? 586 // #100530# no caret events if not focused. 587 if( mbGroupHasFocus && 588 maLastSelection.nEndPara != aSelection.nEndPara ) 589 { 590 if( maLastSelection.nEndPara < maParaManager.GetNum() ) 591 { 592 maParaManager.FireEvent( ::std::min( maLastSelection.nEndPara, nMaxValidParaIndex ), 593 ::std::min( maLastSelection.nEndPara, nMaxValidParaIndex )+1, 594 AccessibleEventId::CARET_CHANGED, 595 uno::makeAny(static_cast<sal_Int32>(-1)), 596 uno::makeAny(static_cast<sal_Int32>(maLastSelection.nEndPos)) ); 597 } 598 599 ChangeChildFocus( aSelection.nEndPara ); 600 601 DBG_TRACE3("AccessibleTextHelper_Impl::UpdateSelection(): focus changed, Object: %d, Paragraph: %d, Last paragraph: %d", 602 this, aSelection.nEndPara, maLastSelection.nEndPara); 603 } 604 } 605 606 // #100530# no caret events if not focused. 607 if( mbGroupHasFocus ) 608 { 609 uno::Any aOldCursor; 610 611 // #i13705# The old cursor can only contain valid 612 // values if it's the same paragraph! 613 if( maLastSelection.nStartPara != EE_PARA_NOT_FOUND && 614 maLastSelection.nEndPara == aSelection.nEndPara ) 615 { 616 aOldCursor <<= static_cast<sal_Int32>(maLastSelection.nEndPos); 617 } 618 else 619 { 620 aOldCursor <<= static_cast<sal_Int32>(-1); 621 } 622 623 maParaManager.FireEvent( aSelection.nEndPara, 624 aSelection.nEndPara+1, 625 AccessibleEventId::CARET_CHANGED, 626 uno::makeAny(static_cast<sal_Int32>(aSelection.nEndPos)), 627 aOldCursor ); 628 } 629 630 DBG_TRACE5("AccessibleTextHelper_Impl::UpdateSelection(): caret changed, Object: %d, New pos: %d, Old pos: %d, New para: %d, Old para: %d", 631 this, aSelection.nEndPos, maLastSelection.nEndPos, aSelection.nEndPara, maLastSelection.nEndPara); 632 633 // #108947# Sort new range before calling FireEvent 634 ::std::pair< xub_StrLen, xub_StrLen > sortedSelection( 635 makeSortedPair(::std::min( aSelection.nStartPara, nMaxValidParaIndex ), 636 ::std::min( aSelection.nEndPara, nMaxValidParaIndex ) ) ); 637 638 // #108947# Sort last range before calling FireEvent 639 ::std::pair< xub_StrLen, xub_StrLen > sortedLastSelection( 640 makeSortedPair(::std::min( maLastSelection.nStartPara, nMaxValidParaIndex ), 641 ::std::min( maLastSelection.nEndPara, nMaxValidParaIndex ) ) ); 642 643 // --> OD 2005-12-15 #i27299# 644 // event TEXT_SELECTION_CHANGED has to be submitted. 645 const sal_Int16 nTextSelChgEventId = 646 AccessibleEventId::TEXT_SELECTION_CHANGED; 647 // <-- 648 // #107037# notify selection change 649 if( maLastSelection.nStartPara == EE_PARA_NOT_FOUND ) 650 { 651 // last selection is undefined 652 // --> OD 2005-12-15 #i27299# - use method <ESelection::HasRange()> 653 if ( aSelection.HasRange() ) 654 // <-- 655 { 656 // selection was undefined, now is on 657 maParaManager.FireEvent( sortedSelection.first, 658 sortedSelection.second+1, 659 nTextSelChgEventId ); 660 } 661 } 662 else 663 { 664 // last selection is valid 665 // --> OD 2005-12-15 #i27299# - use method <ESelection::HasRange()> 666 if ( maLastSelection.HasRange() && 667 !aSelection.HasRange() ) 668 // <-- 669 { 670 // selection was on, now is empty 671 maParaManager.FireEvent( sortedLastSelection.first, 672 sortedLastSelection.second+1, 673 nTextSelChgEventId ); 674 } 675 // --> OD 2005-12-15 #i27299# - use method <ESelection::HasRange()> 676 else if( !maLastSelection.HasRange() && 677 aSelection.HasRange() ) 678 // <-- 679 { 680 // selection was empty, now is on 681 maParaManager.FireEvent( sortedSelection.first, 682 sortedSelection.second+1, 683 nTextSelChgEventId ); 684 } 685 // --> OD 2005-12-15 #i27299# 686 // - no event TEXT_SELECTION_CHANGED event, if new and 687 // last selection are empty. 688 else if ( maLastSelection.HasRange() && 689 aSelection.HasRange() ) 690 // <-- 691 { 692 // --> OD 2005-12-16 #i27299# 693 // - send event TEXT_SELECTION_CHANGED for difference 694 // between last and new selection. 695 // // selection was on, now is different: take union of ranges 696 // maParaManager.FireEvent( ::std::min(sortedSelection.first, 697 // sortedLastSelection.second), 698 // ::std::max(sortedSelection.first, 699 // sortedLastSelection.second)+1, 700 // nTextSelChgEventId ); 701 // use sorted last and new selection 702 ESelection aTmpLastSel( maLastSelection ); 703 aTmpLastSel.Adjust(); 704 ESelection aTmpSel( aSelection ); 705 aTmpSel.Adjust(); 706 // first submit event for new and changed selection 707 sal_uInt32 nPara = aTmpSel.nStartPara; 708 for ( ; nPara <= aTmpSel.nEndPara; ++nPara ) 709 { 710 if ( nPara < aTmpLastSel.nStartPara || 711 nPara > aTmpLastSel.nEndPara ) 712 { 713 // new selection on paragraph <nPara> 714 maParaManager.FireEvent( nPara, 715 nTextSelChgEventId ); 716 } 717 else 718 { 719 // check for changed selection on paragraph <nPara> 720 const xub_StrLen nParaStartPos = 721 nPara == aTmpSel.nStartPara 722 ? aTmpSel.nStartPos : 0; 723 const xub_StrLen nParaEndPos = 724 nPara == aTmpSel.nEndPara 725 ? aTmpSel.nEndPos : STRING_LEN; 726 const xub_StrLen nLastParaStartPos = 727 nPara == aTmpLastSel.nStartPara 728 ? aTmpLastSel.nStartPos : 0; 729 const xub_StrLen nLastParaEndPos = 730 nPara == aTmpLastSel.nEndPara 731 ? aTmpLastSel.nEndPos : STRING_LEN; 732 if ( nParaStartPos != nLastParaStartPos || 733 nParaEndPos != nLastParaEndPos ) 734 { 735 maParaManager.FireEvent( 736 nPara, nTextSelChgEventId ); 737 } 738 } 739 } 740 // second submit event for 'old' selections 741 nPara = aTmpLastSel.nStartPara; 742 for ( ; nPara <= aTmpLastSel.nEndPara; ++nPara ) 743 { 744 if ( nPara < aTmpSel.nStartPara || 745 nPara > aTmpSel.nEndPara ) 746 { 747 maParaManager.FireEvent( nPara, 748 nTextSelChgEventId ); 749 } 750 } 751 } 752 } 753 754 maLastSelection = aSelection; 755 } 756 } 757 } 758 // no selection? no update actions 759 catch( const uno::RuntimeException& ) {} 760 } 761 762 void AccessibleTextHelper_Impl::ShutdownEditSource() SAL_THROW((uno::RuntimeException)) 763 { 764 DBG_CHKTHIS( AccessibleTextHelper_Impl, NULL ); 765 766 // This should only be called with solar mutex locked, i.e. from the main office thread 767 768 // This here is somewhat clumsy: As soon as our children have 769 // a NULL EditSource (maParaManager.SetEditSource()), they 770 // enter the disposed state and cannot be reanimated. Thus, it 771 // is unavoidable and a hard requirement to let go and create 772 // from scratch each and every child. 773 774 // invalidate children 775 maParaManager.Dispose(); 776 maParaManager.SetNum(0); 777 778 // lost all children 779 if( mxFrontEnd.is() ) 780 FireEvent(AccessibleEventId::INVALIDATE_ALL_CHILDREN); 781 782 // quit listen on stale edit source 783 if( maEditSource.IsValid() ) 784 EndListening( maEditSource.GetBroadcaster() ); 785 786 maEditSource.SetEditSource( ::std::auto_ptr< SvxEditSource >(NULL) ); 787 } 788 789 void AccessibleTextHelper_Impl::SetEditSource( ::std::auto_ptr< SvxEditSource > pEditSource ) SAL_THROW((uno::RuntimeException)) 790 { 791 DBG_CHKTHIS( AccessibleTextHelper_Impl, NULL ); 792 793 // This should only be called with solar mutex locked, i.e. from the main office thread 794 795 // shutdown old edit source 796 ShutdownEditSource(); 797 798 // set new edit source 799 maEditSource.SetEditSource( pEditSource ); 800 801 // init child vector to the current child count 802 if( maEditSource.IsValid() ) 803 { 804 maParaManager.SetNum( GetTextForwarder().GetParagraphCount() ); 805 806 // listen on new edit source 807 StartListening( maEditSource.GetBroadcaster() ); 808 809 UpdateVisibleChildren(); 810 } 811 } 812 813 void AccessibleTextHelper_Impl::SetOffset( const Point& rPoint ) 814 { 815 DBG_CHKTHIS( AccessibleTextHelper_Impl, NULL ); 816 817 // guard against non-atomic access to maOffset data structure 818 { 819 ::osl::MutexGuard aGuard( maMutex ); 820 maOffset = rPoint; 821 } 822 823 maParaManager.SetEEOffset( rPoint ); 824 825 // in all cases, check visibility afterwards. 826 UpdateVisibleChildren(); 827 UpdateBoundRect(); 828 } 829 830 void AccessibleTextHelper_Impl::UpdateVisibleChildren( bool bBroadcastEvents ) 831 { 832 DBG_CHKTHIS( AccessibleTextHelper_Impl, NULL ); 833 834 try 835 { 836 SvxTextForwarder& rCacheTF = GetTextForwarder(); 837 SvxViewForwarder& rCacheVF = GetViewForwarder(); 838 839 Rectangle aViewArea = rCacheVF.GetVisArea(); 840 841 if( IsActive() ) 842 { 843 // maybe the edit view scrolls, adapt aViewArea 844 Rectangle aEditViewArea = GetEditViewForwarder().GetVisArea(); 845 aViewArea += aEditViewArea.TopLeft(); 846 847 // now determine intersection 848 aViewArea.Intersection( aEditViewArea ); 849 } 850 851 Rectangle aTmpBB, aParaBB; 852 sal_Bool bFirstChild = sal_True; 853 sal_Int32 nCurrPara; 854 sal_Int32 nParas=rCacheTF.GetParagraphCount(); 855 856 mnFirstVisibleChild = -1; 857 mnLastVisibleChild = -2; 858 859 for( nCurrPara=0; nCurrPara<nParas; ++nCurrPara ) 860 { 861 DBG_ASSERT(nCurrPara >= 0 && nCurrPara <= USHRT_MAX, 862 "AccessibleTextHelper_Impl::UpdateVisibleChildren: index value overflow"); 863 864 aTmpBB = rCacheTF.GetParaBounds( static_cast< sal_uInt16 >( nCurrPara ) ); 865 866 // convert to screen coordinates 867 aParaBB = ::accessibility::AccessibleEditableTextPara::LogicToPixel( aTmpBB, rCacheTF.GetMapMode(), rCacheVF ); 868 869 if( aParaBB.IsOver( aViewArea ) ) 870 { 871 // at least partially visible 872 if( bFirstChild ) 873 { 874 bFirstChild = sal_False; 875 mnFirstVisibleChild = nCurrPara; 876 } 877 878 mnLastVisibleChild = nCurrPara; 879 880 // child not yet created? 881 ::accessibility::AccessibleParaManager::WeakChild aChild( maParaManager.GetChild(nCurrPara) ); 882 if( aChild.second.Width == 0 && 883 aChild.second.Height == 0 && 884 mxFrontEnd.is() && 885 bBroadcastEvents ) 886 { 887 GotPropertyEvent( uno::makeAny( maParaManager.CreateChild( nCurrPara - mnFirstVisibleChild, 888 mxFrontEnd, GetEditSource(), nCurrPara ).first ), 889 AccessibleEventId::CHILD ); 890 } 891 } 892 else 893 { 894 // not or no longer visible 895 if( maParaManager.IsReferencable( nCurrPara ) ) 896 { 897 if( bBroadcastEvents ) 898 LostPropertyEvent( uno::makeAny( maParaManager.GetChild( nCurrPara ).first.get().getRef() ), 899 AccessibleEventId::CHILD ); 900 901 // clear reference 902 maParaManager.Release( nCurrPara ); 903 } 904 } 905 } 906 } 907 catch( const uno::Exception& ) 908 { 909 DBG_ERROR("AccessibleTextHelper_Impl::UpdateVisibleChildren error while determining visible children"); 910 911 // something failed - currently no children 912 mnFirstVisibleChild = -1; 913 mnLastVisibleChild = -2; 914 maParaManager.SetNum(0); 915 916 // lost all children 917 if( bBroadcastEvents ) 918 FireEvent(AccessibleEventId::INVALIDATE_ALL_CHILDREN); 919 } 920 } 921 922 // functor for checking changes in paragraph bounding boxes (no stand-alone function, maybe not inlined) 923 class AccessibleTextHelper_UpdateChildBounds : public ::std::unary_function< const ::accessibility::AccessibleParaManager::WeakChild&, 924 ::accessibility::AccessibleParaManager::WeakChild > 925 { 926 public: 927 AccessibleTextHelper_UpdateChildBounds( AccessibleTextHelper_Impl& rImpl ) : mrImpl(rImpl) {} 928 ::accessibility::AccessibleParaManager::WeakChild operator()( const ::accessibility::AccessibleParaManager::WeakChild& rChild ) 929 { 930 // retrieve hard reference from weak one 931 ::accessibility::AccessibleParaManager::WeakPara::HardRefType aHardRef( rChild.first.get() ); 932 933 if( aHardRef.is() ) 934 { 935 awt::Rectangle aNewRect = aHardRef->getBounds(); 936 const awt::Rectangle& aOldRect = rChild.second; 937 938 if( aNewRect.X != aOldRect.X || 939 aNewRect.Y != aOldRect.Y || 940 aNewRect.Width != aOldRect.Width || 941 aNewRect.Height != aOldRect.Height ) 942 { 943 // visible data changed 944 aHardRef->FireEvent( AccessibleEventId::BOUNDRECT_CHANGED ); 945 946 // update internal bounds 947 return ::accessibility::AccessibleParaManager::WeakChild( rChild.first, aNewRect ); 948 } 949 } 950 951 // identity transform 952 return rChild; 953 } 954 955 private: 956 AccessibleTextHelper_Impl& mrImpl; 957 }; 958 959 void AccessibleTextHelper_Impl::UpdateBoundRect() 960 { 961 DBG_CHKTHIS( AccessibleTextHelper_Impl, NULL ); 962 963 // send BOUNDRECT_CHANGED to affected children 964 AccessibleTextHelper_UpdateChildBounds aFunctor( *this ); 965 ::std::transform( maParaManager.begin(), maParaManager.end(), maParaManager.begin(), aFunctor ); 966 } 967 968 #ifdef DBG_UTIL 969 void AccessibleTextHelper_Impl::CheckInvariants() const 970 { 971 if( mnFirstVisibleChild >= 0 && 972 mnFirstVisibleChild > mnLastVisibleChild ) 973 { 974 DBG_ERROR( "AccessibleTextHelper: range invalid" ); 975 } 976 } 977 #endif 978 979 // functor for sending child events (no stand-alone function, they are maybe not inlined) 980 class AccessibleTextHelper_LostChildEvent : public ::std::unary_function< const ::accessibility::AccessibleParaManager::WeakChild&, void > 981 { 982 public: 983 AccessibleTextHelper_LostChildEvent( AccessibleTextHelper_Impl& rImpl ) : mrImpl(rImpl) {} 984 void operator()( const ::accessibility::AccessibleParaManager::WeakChild& rPara ) 985 { 986 // retrieve hard reference from weak one 987 ::accessibility::AccessibleParaManager::WeakPara::HardRefType aHardRef( rPara.first.get() ); 988 989 if( aHardRef.is() ) 990 mrImpl.FireEvent(AccessibleEventId::CHILD, uno::Any(), uno::makeAny( aHardRef.getRef() ) ); 991 } 992 993 private: 994 AccessibleTextHelper_Impl& mrImpl; 995 }; 996 997 void AccessibleTextHelper_Impl::ParagraphsMoved( sal_Int32 nFirst, sal_Int32 nMiddle, sal_Int32 nLast ) 998 { 999 DBG_CHKTHIS( AccessibleTextHelper_Impl, NULL ); 1000 1001 const sal_Int32 nParas = GetTextForwarder().GetParagraphCount(); 1002 1003 /* rotate paragraphs 1004 * ================= 1005 * 1006 * Three cases: 1007 * 1008 * 1. 1009 * ... nParagraph ... nParam1 ... nParam2 ... 1010 * |______________[xxxxxxxxxxx] 1011 * becomes 1012 * [xxxxxxxxxxx]|______________ 1013 * 1014 * tail is 0 1015 * 1016 * 2. 1017 * ... nParam1 ... nParagraph ... nParam2 ... 1018 * [xxxxxxxxxxx|xxxxxxxxxxxxxx]____________ 1019 * becomes 1020 * ____________[xxxxxxxxxxx|xxxxxxxxxxxxxx] 1021 * 1022 * tail is nParagraph - nParam1 1023 * 1024 * 3. 1025 * ... nParam1 ... nParam2 ... nParagraph ... 1026 * [xxxxxxxxxxx]___________|____________ 1027 * becomes 1028 * ___________|____________[xxxxxxxxxxx] 1029 * 1030 * tail is nParam2 - nParam1 1031 */ 1032 1033 // sort nParagraph, nParam1 and nParam2 in ascending order, calc range 1034 if( nMiddle < nFirst ) 1035 { 1036 ::std::swap(nFirst, nMiddle); 1037 } 1038 else if( nMiddle < nLast ) 1039 { 1040 nLast = nLast + nMiddle - nFirst; 1041 } 1042 else 1043 { 1044 ::std::swap(nMiddle, nLast); 1045 nLast = nLast + nMiddle - nFirst; 1046 } 1047 1048 if( nFirst < nParas && nMiddle < nParas && nLast < nParas ) 1049 { 1050 // since we have no "paragraph index 1051 // changed" event on UAA, remove 1052 // [first,last] and insert again later (in 1053 // UpdateVisibleChildren) 1054 1055 // maParaManager.Rotate( nFirst, nMiddle, nLast ); 1056 1057 // send CHILD_EVENT to affected children 1058 ::accessibility::AccessibleParaManager::VectorOfChildren::const_iterator begin = maParaManager.begin(); 1059 ::accessibility::AccessibleParaManager::VectorOfChildren::const_iterator end = begin; 1060 1061 ::std::advance( begin, nFirst ); 1062 ::std::advance( end, nLast+1 ); 1063 1064 // TODO: maybe optimize here in the following way. If the 1065 // number of removed children exceeds a certain threshold, 1066 // use INVALIDATE_CHILDREN 1067 AccessibleTextHelper_LostChildEvent aFunctor( *this ); 1068 1069 ::std::for_each( begin, end, aFunctor ); 1070 1071 maParaManager.Release(nFirst, nLast+1); 1072 // should be no need for UpdateBoundRect, since all affected children are cleared. 1073 } 1074 } 1075 1076 // functor for sending child events (no stand-alone function, they are maybe not inlined) 1077 class AccessibleTextHelper_ChildrenTextChanged : public ::std::unary_function< ::accessibility::AccessibleEditableTextPara&, void > 1078 { 1079 public: 1080 void operator()( ::accessibility::AccessibleEditableTextPara& rPara ) 1081 { 1082 rPara.TextChanged(); 1083 } 1084 }; 1085 1086 /** functor processing queue events 1087 1088 Reacts on TEXT_HINT_PARAINSERTED/REMOVED events and stores 1089 their content 1090 */ 1091 class AccessibleTextHelper_QueueFunctor : public ::std::unary_function< const SfxHint*, void > 1092 { 1093 public: 1094 AccessibleTextHelper_QueueFunctor() : 1095 mnParasChanged( 0 ), 1096 mnParaIndex(-1), 1097 mnHintId(-1) 1098 {} 1099 void operator()( const SfxHint* pEvent ) 1100 { 1101 if( pEvent && 1102 mnParasChanged != -1 ) 1103 { 1104 // determine hint type 1105 const TextHint* pTextHint = PTR_CAST( TextHint, pEvent ); 1106 const SvxEditSourceHint* pEditSourceHint = PTR_CAST( SvxEditSourceHint, pEvent ); 1107 1108 if( !pEditSourceHint && pTextHint && 1109 (pTextHint->GetId() == TEXT_HINT_PARAINSERTED || 1110 pTextHint->GetId() == TEXT_HINT_PARAREMOVED ) ) 1111 { 1112 if( pTextHint->GetValue() == EE_PARA_ALL ) 1113 { 1114 mnParasChanged = -1; 1115 } 1116 else 1117 { 1118 mnHintId = pTextHint->GetId(); 1119 mnParaIndex = pTextHint->GetValue(); 1120 ++mnParasChanged; 1121 } 1122 } 1123 } 1124 } 1125 1126 /** Query number of paragraphs changed during queue processing. 1127 1128 @return number of changed paragraphs, -1 for 1129 "every paragraph changed" 1130 */ 1131 int GetNumberOfParasChanged() { return mnParasChanged; } 1132 /** Query index of last added/removed paragraph 1133 1134 @return index of lastly added paragraphs, -1 for none 1135 added so far. 1136 */ 1137 int GetParaIndex() { return mnParaIndex; } 1138 /** Query hint id of last interesting event 1139 1140 @return hint id of last interesting event (REMOVED/INSERTED). 1141 */ 1142 int GetHintId() { return mnHintId; } 1143 1144 private: 1145 /** number of paragraphs changed during queue processing. -1 for 1146 "every paragraph changed" 1147 */ 1148 int mnParasChanged; 1149 /// index of paragraph added/removed last 1150 int mnParaIndex; 1151 /// TextHint ID (removed/inserted) of last interesting event 1152 int mnHintId; 1153 }; 1154 1155 void AccessibleTextHelper_Impl::ProcessQueue() 1156 { 1157 DBG_CHKTHIS( AccessibleTextHelper_Impl, NULL ); 1158 1159 // inspect queue for paragraph insert/remove events. If there 1160 // is exactly _one_ of those in the queue, and the number of 1161 // paragraphs has changed by exactly one, use that event to 1162 // determine a priori which paragraph was added/removed. This 1163 // is necessary, since I must sync right here with the 1164 // EditEngine state (number of paragraphs etc.), since I'm 1165 // potentially sending listener events right away. 1166 AccessibleTextHelper_QueueFunctor aFunctor; 1167 maEventQueue.ForEach( aFunctor ); 1168 1169 const sal_Int32 nNewParas( GetTextForwarder().GetParagraphCount() ); 1170 const sal_Int32 nCurrParas( maParaManager.GetNum() ); 1171 1172 // whether every paragraph already is updated (no need to 1173 // repeat that later on, e.g. for PARA_MOVED events) 1174 bool bEverythingUpdated( false ); 1175 1176 if( labs( nNewParas - nCurrParas ) == 1 && 1177 aFunctor.GetNumberOfParasChanged() == 1 ) 1178 { 1179 // #103483# Exactly one paragraph added/removed. This is 1180 // the normal case, optimize event handling here. 1181 1182 if( aFunctor.GetHintId() == TEXT_HINT_PARAINSERTED ) 1183 { 1184 // update num of paras 1185 maParaManager.SetNum( nNewParas ); 1186 1187 // release everything from the insertion position until the end 1188 maParaManager.Release(aFunctor.GetParaIndex(), nCurrParas); 1189 1190 // TODO: Clarify whether this behaviour _really_ saves 1191 // anybody anything! 1192 // update children, _don't_ broadcast 1193 UpdateVisibleChildren( false ); 1194 UpdateBoundRect(); 1195 1196 // send insert event 1197 // #109864# Enforce creation of this paragraph 1198 try 1199 { 1200 GotPropertyEvent( uno::makeAny( getAccessibleChild( aFunctor.GetParaIndex() - 1201 mnFirstVisibleChild + GetStartIndex() ) ), 1202 AccessibleEventId::CHILD ); 1203 } 1204 catch( const uno::Exception& ) 1205 { 1206 DBG_ERROR("AccessibleTextHelper_Impl::ProcessQueue: could not create new paragraph"); 1207 } 1208 } 1209 else if( aFunctor.GetHintId() == TEXT_HINT_PARAREMOVED ) 1210 { 1211 ::accessibility::AccessibleParaManager::VectorOfChildren::const_iterator begin = maParaManager.begin(); 1212 ::std::advance( begin, aFunctor.GetParaIndex() ); 1213 ::accessibility::AccessibleParaManager::VectorOfChildren::const_iterator end = begin; 1214 ::std::advance( end, 1 ); 1215 1216 // #i61812# remember para to be removed for later notification 1217 // AFTER the new state is applied (that after the para got removed) 1218 ::uno::Reference< XAccessible > xPara; 1219 ::accessibility::AccessibleParaManager::WeakPara::HardRefType aHardRef( begin->first.get() ); 1220 if( aHardRef.is() ) 1221 xPara = ::uno::Reference< XAccessible >( aHardRef.getRef(), ::uno::UNO_QUERY ); 1222 1223 // release everything from the remove position until the end 1224 maParaManager.Release(aFunctor.GetParaIndex(), nCurrParas); 1225 1226 // update num of paras 1227 maParaManager.SetNum( nNewParas ); 1228 1229 // TODO: Clarify whether this behaviour _really_ saves 1230 // anybody anything! 1231 // update children, _don't_ broadcast 1232 UpdateVisibleChildren( false ); 1233 UpdateBoundRect(); 1234 1235 // #i61812# notification for removed para 1236 if (xPara.is()) 1237 FireEvent(AccessibleEventId::CHILD, uno::Any(), uno::makeAny( xPara) ); 1238 } 1239 #ifdef DBG_UTIL 1240 else 1241 DBG_ERROR("AccessibleTextHelper_Impl::ProcessQueue() invalid hint id"); 1242 #endif 1243 } 1244 else if( nNewParas != nCurrParas ) 1245 { 1246 // release all paras 1247 maParaManager.Release(0, nCurrParas); 1248 1249 // update num of paras 1250 maParaManager.SetNum( nNewParas ); 1251 1252 // #109864# create from scratch, don't broadcast 1253 UpdateVisibleChildren( false ); 1254 UpdateBoundRect(); 1255 1256 // number of paragraphs somehow changed - but we have no 1257 // chance determining how. Thus, throw away everything and 1258 // create from scratch. 1259 // (child events should be broadcast after the changes are done...) 1260 FireEvent(AccessibleEventId::INVALIDATE_ALL_CHILDREN); 1261 1262 // no need for further updates later on 1263 bEverythingUpdated = true; 1264 } 1265 1266 while( !maEventQueue.IsEmpty() ) 1267 { 1268 ::std::auto_ptr< SfxHint > pHint( maEventQueue.PopFront() ); 1269 if( pHint.get() ) 1270 { 1271 const SfxHint& rHint = *(pHint.get()); 1272 1273 // determine hint type 1274 const SdrHint* pSdrHint = PTR_CAST( SdrHint, &rHint ); 1275 const SfxSimpleHint* pSimpleHint = PTR_CAST( SfxSimpleHint, &rHint ); 1276 const TextHint* pTextHint = PTR_CAST( TextHint, &rHint ); 1277 const SvxViewHint* pViewHint = PTR_CAST( SvxViewHint, &rHint ); 1278 const SvxEditSourceHint* pEditSourceHint = PTR_CAST( SvxEditSourceHint, &rHint ); 1279 1280 try 1281 { 1282 const sal_Int32 nParas = GetTextForwarder().GetParagraphCount(); 1283 1284 if( pEditSourceHint ) 1285 { 1286 switch( pEditSourceHint->GetId() ) 1287 { 1288 case EDITSOURCE_HINT_PARASMOVED: 1289 { 1290 DBG_ASSERT( pEditSourceHint->GetStartValue() < GetTextForwarder().GetParagraphCount() && 1291 pEditSourceHint->GetEndValue() < GetTextForwarder().GetParagraphCount(), 1292 "AccessibleTextHelper_Impl::NotifyHdl: Invalid notification"); 1293 1294 if( !bEverythingUpdated ) 1295 { 1296 ParagraphsMoved(pEditSourceHint->GetStartValue(), 1297 pEditSourceHint->GetValue(), 1298 pEditSourceHint->GetEndValue()); 1299 1300 // in all cases, check visibility afterwards. 1301 UpdateVisibleChildren(); 1302 } 1303 break; 1304 } 1305 1306 case EDITSOURCE_HINT_SELECTIONCHANGED: 1307 // notify listeners 1308 try 1309 { 1310 UpdateSelection(); 1311 } 1312 // maybe we're not in edit mode (this is not an error) 1313 catch( const uno::Exception& ) {} 1314 break; 1315 } 1316 } 1317 else if( pTextHint ) 1318 { 1319 switch( pTextHint->GetId() ) 1320 { 1321 case TEXT_HINT_MODIFIED: 1322 { 1323 // notify listeners 1324 sal_Int32 nPara( pTextHint->GetValue() ); 1325 1326 // #108900# Delegate change event to children 1327 AccessibleTextHelper_ChildrenTextChanged aNotifyChildrenFunctor; 1328 1329 if( nPara == static_cast<sal_Int32>(EE_PARA_ALL) ) 1330 { 1331 // #108900# Call every child 1332 ::std::for_each( maParaManager.begin(), maParaManager.end(), 1333 AccessibleParaManager::WeakChildAdapter< AccessibleTextHelper_ChildrenTextChanged > (aNotifyChildrenFunctor) ); 1334 } 1335 else 1336 if( nPara < nParas ) 1337 { 1338 // #108900# Call child at index nPara 1339 ::std::for_each( maParaManager.begin()+nPara, maParaManager.begin()+nPara+1, 1340 AccessibleParaManager::WeakChildAdapter< AccessibleTextHelper_ChildrenTextChanged > (aNotifyChildrenFunctor) ); 1341 } 1342 break; 1343 } 1344 1345 case TEXT_HINT_PARAINSERTED: 1346 // already happened above 1347 break; 1348 1349 case TEXT_HINT_PARAREMOVED: 1350 // already happened above 1351 break; 1352 1353 case TEXT_HINT_TEXTHEIGHTCHANGED: 1354 // visibility changed, done below 1355 break; 1356 1357 case TEXT_HINT_VIEWSCROLLED: 1358 // visibility changed, done below 1359 break; 1360 } 1361 1362 // in all cases, check visibility afterwards. 1363 UpdateVisibleChildren(); 1364 UpdateBoundRect(); 1365 } 1366 else if( pViewHint ) 1367 { 1368 switch( pViewHint->GetHintType() ) 1369 { 1370 case SvxViewHint::SVX_HINT_VIEWCHANGED: 1371 // just check visibility 1372 UpdateVisibleChildren(); 1373 UpdateBoundRect(); 1374 break; 1375 } 1376 } 1377 else if( pSdrHint ) 1378 { 1379 switch( pSdrHint->GetKind() ) 1380 { 1381 case HINT_BEGEDIT: 1382 { 1383 // change children state 1384 maParaManager.SetActive(); 1385 1386 // per definition, edit mode text has the focus 1387 SetFocus( sal_True ); 1388 break; 1389 } 1390 1391 case HINT_ENDEDIT: 1392 { 1393 // focused child now looses focus 1394 ESelection aSelection; 1395 if( GetEditViewForwarder().GetSelection( aSelection ) ) 1396 SetChildFocus( aSelection.nEndPara, sal_False ); 1397 1398 // change children state 1399 maParaManager.SetActive( sal_False ); 1400 1401 maLastSelection = ESelection( EE_PARA_NOT_FOUND, EE_PARA_NOT_FOUND, 1402 EE_PARA_NOT_FOUND, EE_PARA_NOT_FOUND); 1403 break; 1404 } 1405 default: 1406 break; 1407 } 1408 } 1409 // it's VITAL to keep the SfxSimpleHint last! It's the base of some classes above! 1410 else if( pSimpleHint ) 1411 { 1412 switch( pSimpleHint->GetId() ) 1413 { 1414 case SFX_HINT_DYING: 1415 // edit source is dying under us, become defunc then 1416 try 1417 { 1418 // make edit source inaccessible 1419 // Note: cannot destroy it here, since we're called from there! 1420 ShutdownEditSource(); 1421 } 1422 catch( const uno::Exception& ) {} 1423 1424 break; 1425 } 1426 } 1427 } 1428 catch( const uno::Exception& ) 1429 { 1430 #ifdef DBG_UTIL 1431 OSL_TRACE("AccessibleTextHelper_Impl::ProcessQueue: Unhandled exception."); 1432 #endif 1433 } 1434 } 1435 } 1436 } 1437 1438 void AccessibleTextHelper_Impl::Notify( SfxBroadcaster& /*rBC*/, const SfxHint& rHint ) 1439 { 1440 DBG_CHKTHIS( AccessibleTextHelper_Impl, NULL ); 1441 1442 // precondition: solar mutex locked 1443 DBG_TESTSOLARMUTEX(); 1444 1445 // precondition: not in a recursion 1446 if( mbInNotify ) 1447 return; 1448 1449 mbInNotify = sal_True; 1450 1451 // determine hint type 1452 const SdrHint* pSdrHint = PTR_CAST( SdrHint, &rHint ); 1453 const SfxSimpleHint* pSimpleHint = PTR_CAST( SfxSimpleHint, &rHint ); 1454 const TextHint* pTextHint = PTR_CAST( TextHint, &rHint ); 1455 const SvxViewHint* pViewHint = PTR_CAST( SvxViewHint, &rHint ); 1456 const SvxEditSourceHint* pEditSourceHint = PTR_CAST( SvxEditSourceHint, &rHint ); 1457 1458 try 1459 { 1460 // Process notification event 1461 if( pEditSourceHint ) 1462 { 1463 maEventQueue.Append( *pEditSourceHint ); 1464 // --> OD 2005-12-19 #i27299# 1465 if( maEventOpenFrames == 0 ) 1466 ProcessQueue(); 1467 // <-- 1468 } 1469 else if( pTextHint ) 1470 { 1471 switch( pTextHint->GetId() ) 1472 { 1473 case TEXT_HINT_BLOCKNOTIFICATION_END: 1474 case TEXT_HINT_INPUT_END: 1475 --maEventOpenFrames; 1476 1477 if( maEventOpenFrames == 0 ) 1478 { 1479 // #103483# 1480 /* All information should have arrived 1481 * now, process queue. As stated in the 1482 * above bug, we can often avoid throwing 1483 * away all paragraphs by looking forward 1484 * in the event queue (searching for 1485 * PARAINSERT/REMOVE events). Furthermore, 1486 * processing the event queue only at the 1487 * end of an interaction cycle, ensures 1488 * that the EditEngine state and the 1489 * AccessibleText state are the same 1490 * (well, mostly. If there are _multiple_ 1491 * interaction cycles in the EE queues, it 1492 * can still happen that EE state is 1493 * different. That's so to say broken by 1494 * design with that delayed EE event 1495 * concept). 1496 */ 1497 ProcessQueue(); 1498 } 1499 break; 1500 1501 case TEXT_HINT_BLOCKNOTIFICATION_START: 1502 case TEXT_HINT_INPUT_START: 1503 ++maEventOpenFrames; 1504 // --> OD 2005-12-19 #i27299# - no FALLTROUGH 1505 // reason: event will not be processes, thus appending 1506 // the event isn't necessary. 1507 break; 1508 // <-- 1509 default: 1510 maEventQueue.Append( *pTextHint ); 1511 // --> OD 2005-12-19 #i27299# 1512 if( maEventOpenFrames == 0 ) 1513 ProcessQueue(); 1514 // <-- 1515 break; 1516 } 1517 } 1518 else if( pViewHint ) 1519 { 1520 maEventQueue.Append( *pViewHint ); 1521 1522 // process visibility right away, if not within an 1523 // open EE notification frame. Otherwise, event 1524 // processing would be delayed until next EE 1525 // notification sequence. 1526 if( maEventOpenFrames == 0 ) 1527 ProcessQueue(); 1528 } 1529 else if( pSdrHint ) 1530 { 1531 maEventQueue.Append( *pSdrHint ); 1532 1533 // process drawing layer events right away, if not 1534 // within an open EE notification frame. Otherwise, 1535 // event processing would be delayed until next EE 1536 // notification sequence. 1537 if( maEventOpenFrames == 0 ) 1538 ProcessQueue(); 1539 } 1540 // it's VITAL to keep the SfxSimpleHint last! It's the base of some classes above! 1541 else if( pSimpleHint ) 1542 { 1543 // handle this event _at once_, because after that, objects are invalid 1544 switch( pSimpleHint->GetId() ) 1545 { 1546 case SFX_HINT_DYING: 1547 // edit source is dying under us, become defunc then 1548 maEventQueue.Clear(); 1549 try 1550 { 1551 // make edit source inaccessible 1552 // Note: cannot destroy it here, since we're called from there! 1553 ShutdownEditSource(); 1554 } 1555 catch( const uno::Exception& ) {} 1556 1557 break; 1558 } 1559 } 1560 } 1561 catch( const uno::Exception& ) 1562 { 1563 #ifdef DBG_UTIL 1564 OSL_TRACE("AccessibleTextHelper_Impl::Notify: Unhandled exception."); 1565 #endif 1566 mbInNotify = sal_False; 1567 } 1568 1569 mbInNotify = sal_False; 1570 } 1571 1572 void AccessibleTextHelper_Impl::Dispose() 1573 { 1574 DBG_CHKTHIS( AccessibleTextHelper_Impl, NULL ); 1575 1576 if( getNotifierClientId() != -1 ) 1577 { 1578 try 1579 { 1580 // #106234# Unregister from EventNotifier 1581 ::comphelper::AccessibleEventNotifier::revokeClient( getNotifierClientId() ); 1582 #ifdef DBG_UTIL 1583 OSL_TRACE( "AccessibleTextHelper_Impl disposed ID: %d", mnNotifierClientId ); 1584 #endif 1585 } 1586 catch( const uno::Exception& ) {} 1587 1588 mnNotifierClientId = -1; 1589 } 1590 1591 try 1592 { 1593 // dispose children 1594 maParaManager.Dispose(); 1595 } 1596 catch( const uno::Exception& ) {} 1597 1598 // quit listen on stale edit source 1599 if( maEditSource.IsValid() ) 1600 EndListening( maEditSource.GetBroadcaster() ); 1601 1602 // clear references 1603 maEditSource.SetEditSource( ::std::auto_ptr< SvxEditSource >(NULL) ); 1604 mxFrontEnd = NULL; 1605 } 1606 1607 void AccessibleTextHelper_Impl::FireEvent( const sal_Int16 nEventId, const uno::Any& rNewValue, const uno::Any& rOldValue ) const 1608 { 1609 DBG_CHKTHIS( AccessibleTextHelper_Impl, NULL ); 1610 1611 // -- object locked -- 1612 ::osl::ClearableMutexGuard aGuard( maMutex ); 1613 1614 AccessibleEventObject aEvent; 1615 1616 DBG_ASSERT(mxFrontEnd.is(), "AccessibleTextHelper::FireEvent: no event source set" ); 1617 1618 if( mxFrontEnd.is() ) 1619 aEvent = AccessibleEventObject(mxFrontEnd->getAccessibleContext(), nEventId, rNewValue, rOldValue); 1620 else 1621 aEvent = AccessibleEventObject(uno::Reference< uno::XInterface >(), nEventId, rNewValue, rOldValue); 1622 1623 // no locking necessary, FireEvent internally copies listeners 1624 // if someone removes/adds in between Further locking, 1625 // actually, might lead to deadlocks, since we're calling out 1626 // of this object 1627 aGuard.clear(); 1628 // -- until here -- 1629 1630 FireEvent(aEvent); 1631 } 1632 1633 void AccessibleTextHelper_Impl::FireEvent( const AccessibleEventObject& rEvent ) const 1634 { 1635 DBG_CHKTHIS( AccessibleTextHelper_Impl, NULL ); 1636 1637 // #102261# Call global queue for focus events 1638 if( rEvent.EventId == AccessibleStateType::FOCUSED ) 1639 vcl::unohelper::NotifyAccessibleStateEventGlobally( rEvent ); 1640 1641 // #106234# Delegate to EventNotifier 1642 ::comphelper::AccessibleEventNotifier::addEvent( getNotifierClientId(), 1643 rEvent ); 1644 } 1645 1646 // XAccessibleContext 1647 sal_Int32 SAL_CALL AccessibleTextHelper_Impl::getAccessibleChildCount() SAL_THROW((uno::RuntimeException)) 1648 { 1649 DBG_CHKTHIS( AccessibleTextHelper_Impl, NULL ); 1650 1651 return mnLastVisibleChild - mnFirstVisibleChild + 1; 1652 } 1653 1654 uno::Reference< XAccessible > SAL_CALL AccessibleTextHelper_Impl::getAccessibleChild( sal_Int32 i ) SAL_THROW((lang::IndexOutOfBoundsException, uno::RuntimeException)) 1655 { 1656 DBG_CHKTHIS( AccessibleTextHelper_Impl, NULL ); 1657 1658 i -= GetStartIndex(); 1659 1660 if( 0 > i || i >= getAccessibleChildCount() || 1661 GetTextForwarder().GetParagraphCount() <= i ) 1662 { 1663 throw lang::IndexOutOfBoundsException(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("Invalid child index")), mxFrontEnd); 1664 } 1665 1666 DBG_ASSERT(mxFrontEnd.is(), "AccessibleTextHelper_Impl::UpdateVisibleChildren: no frontend set"); 1667 1668 if( mxFrontEnd.is() ) 1669 return maParaManager.CreateChild( i, mxFrontEnd, GetEditSource(), mnFirstVisibleChild + i ).first; 1670 else 1671 return NULL; 1672 } 1673 1674 void SAL_CALL AccessibleTextHelper_Impl::addEventListener( const uno::Reference< XAccessibleEventListener >& xListener ) SAL_THROW((uno::RuntimeException)) 1675 { 1676 DBG_CHKTHIS( AccessibleTextHelper_Impl, NULL ); 1677 1678 if( getNotifierClientId() != -1 ) 1679 ::comphelper::AccessibleEventNotifier::addEventListener( getNotifierClientId(), xListener ); 1680 } 1681 1682 void SAL_CALL AccessibleTextHelper_Impl::removeEventListener( const uno::Reference< XAccessibleEventListener >& xListener ) SAL_THROW((uno::RuntimeException)) 1683 { 1684 DBG_CHKTHIS( AccessibleTextHelper_Impl, NULL ); 1685 1686 if( getNotifierClientId() != -1 ) 1687 ::comphelper::AccessibleEventNotifier::removeEventListener( getNotifierClientId(), xListener ); 1688 } 1689 1690 uno::Reference< XAccessible > SAL_CALL AccessibleTextHelper_Impl::getAccessibleAtPoint( const awt::Point& _aPoint ) SAL_THROW((uno::RuntimeException)) 1691 { 1692 DBG_CHKTHIS( AccessibleTextHelper_Impl, NULL ); 1693 1694 // make given position relative 1695 if( !mxFrontEnd.is() ) 1696 throw uno::RuntimeException(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("AccessibleTextHelper_Impl::getAccessibleAt: frontend invalid")), mxFrontEnd ); 1697 1698 uno::Reference< XAccessibleContext > xFrontEndContext = mxFrontEnd->getAccessibleContext(); 1699 1700 if( !xFrontEndContext.is() ) 1701 throw uno::RuntimeException(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("AccessibleTextHelper_Impl::getAccessibleAt: frontend invalid")), mxFrontEnd ); 1702 1703 uno::Reference< XAccessibleComponent > xFrontEndComponent( xFrontEndContext, uno::UNO_QUERY ); 1704 1705 if( !xFrontEndComponent.is() ) 1706 throw uno::RuntimeException(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("AccessibleTextHelper_Impl::getAccessibleAt: frontend is no XAccessibleComponent")), 1707 mxFrontEnd ); 1708 1709 // #103862# No longer need to make given position relative 1710 Point aPoint( _aPoint.X, _aPoint.Y ); 1711 1712 // respect EditEngine offset to surrounding shape/cell 1713 aPoint -= GetOffset(); 1714 1715 // convert to EditEngine coordinate system 1716 SvxTextForwarder& rCacheTF = GetTextForwarder(); 1717 Point aLogPoint( GetViewForwarder().PixelToLogic( aPoint, rCacheTF.GetMapMode() ) ); 1718 1719 // iterate over all visible children (including those not yet created) 1720 sal_Int32 nChild; 1721 for( nChild=mnFirstVisibleChild; nChild <= mnLastVisibleChild; ++nChild ) 1722 { 1723 DBG_ASSERT(nChild >= 0 && nChild <= USHRT_MAX, 1724 "AccessibleTextHelper_Impl::getAccessibleAt: index value overflow"); 1725 1726 Rectangle aParaBounds( rCacheTF.GetParaBounds( static_cast< sal_uInt16 > (nChild) ) ); 1727 1728 if( aParaBounds.IsInside( aLogPoint ) ) 1729 return getAccessibleChild( nChild - mnFirstVisibleChild + GetStartIndex() ); 1730 } 1731 1732 // found none 1733 return NULL; 1734 } 1735 1736 //------------------------------------------------------------------------ 1737 // 1738 // AccessibleTextHelper implementation (simply forwards to impl) 1739 // 1740 //------------------------------------------------------------------------ 1741 1742 AccessibleTextHelper::AccessibleTextHelper( ::std::auto_ptr< SvxEditSource > pEditSource ) : 1743 mpImpl( new AccessibleTextHelper_Impl() ) 1744 { 1745 ::vos::OGuard aGuard( Application::GetSolarMutex() ); 1746 1747 SetEditSource( pEditSource ); 1748 } 1749 1750 AccessibleTextHelper::~AccessibleTextHelper() 1751 { 1752 } 1753 1754 const SvxEditSource& AccessibleTextHelper::GetEditSource() const SAL_THROW((uno::RuntimeException)) 1755 { 1756 #ifdef DBG_UTIL 1757 mpImpl->CheckInvariants(); 1758 1759 const SvxEditSource& aEditSource = mpImpl->GetEditSource(); 1760 1761 mpImpl->CheckInvariants(); 1762 1763 return aEditSource; 1764 #else 1765 return mpImpl->GetEditSource(); 1766 #endif 1767 } 1768 1769 void AccessibleTextHelper::SetEditSource( ::std::auto_ptr< SvxEditSource > pEditSource ) SAL_THROW((uno::RuntimeException)) 1770 { 1771 #ifdef DBG_UTIL 1772 // precondition: solar mutex locked 1773 DBG_TESTSOLARMUTEX(); 1774 1775 mpImpl->CheckInvariants(); 1776 #endif 1777 1778 mpImpl->SetEditSource( pEditSource ); 1779 1780 #ifdef DBG_UTIL 1781 mpImpl->CheckInvariants(); 1782 #endif 1783 } 1784 1785 void AccessibleTextHelper::SetEventSource( const uno::Reference< XAccessible >& rInterface ) 1786 { 1787 #ifdef DBG_UTIL 1788 mpImpl->CheckInvariants(); 1789 #endif 1790 1791 mpImpl->SetEventSource( rInterface ); 1792 1793 #ifdef DBG_UTIL 1794 mpImpl->CheckInvariants(); 1795 #endif 1796 } 1797 1798 uno::Reference< XAccessible > AccessibleTextHelper::GetEventSource() const 1799 { 1800 #ifdef DBG_UTIL 1801 mpImpl->CheckInvariants(); 1802 1803 uno::Reference< XAccessible > xRet( mpImpl->GetEventSource() ); 1804 1805 mpImpl->CheckInvariants(); 1806 1807 return xRet; 1808 #else 1809 return mpImpl->GetEventSource(); 1810 #endif 1811 } 1812 1813 void AccessibleTextHelper::SetFocus( sal_Bool bHaveFocus ) SAL_THROW((::com::sun::star::uno::RuntimeException)) 1814 { 1815 #ifdef DBG_UTIL 1816 // precondition: solar mutex locked 1817 DBG_TESTSOLARMUTEX(); 1818 1819 mpImpl->CheckInvariants(); 1820 #endif 1821 1822 mpImpl->SetFocus( bHaveFocus ); 1823 1824 #ifdef DBG_UTIL 1825 mpImpl->CheckInvariants(); 1826 #endif 1827 } 1828 1829 sal_Bool AccessibleTextHelper::HaveFocus() SAL_THROW((::com::sun::star::uno::RuntimeException)) 1830 { 1831 #ifdef DBG_UTIL 1832 mpImpl->CheckInvariants(); 1833 1834 sal_Bool bRet( mpImpl->HaveFocus() ); 1835 1836 mpImpl->CheckInvariants(); 1837 1838 return bRet; 1839 #else 1840 return mpImpl->HaveFocus(); 1841 #endif 1842 } 1843 1844 void AccessibleTextHelper::FireEvent( const sal_Int16 nEventId, const uno::Any& rNewValue, const uno::Any& rOldValue ) const 1845 { 1846 #ifdef DBG_UTIL 1847 mpImpl->CheckInvariants(); 1848 #endif 1849 1850 mpImpl->FireEvent( nEventId, rNewValue, rOldValue ); 1851 1852 #ifdef DBG_UTIL 1853 mpImpl->CheckInvariants(); 1854 #endif 1855 } 1856 1857 void AccessibleTextHelper::FireEvent( const AccessibleEventObject& rEvent ) const 1858 { 1859 #ifdef DBG_UTIL 1860 mpImpl->CheckInvariants(); 1861 #endif 1862 1863 mpImpl->FireEvent( rEvent ); 1864 1865 #ifdef DBG_UTIL 1866 mpImpl->CheckInvariants(); 1867 #endif 1868 } 1869 1870 void AccessibleTextHelper::SetOffset( const Point& rPoint ) 1871 { 1872 #ifdef DBG_UTIL 1873 // precondition: solar mutex locked 1874 DBG_TESTSOLARMUTEX(); 1875 1876 mpImpl->CheckInvariants(); 1877 #endif 1878 1879 mpImpl->SetOffset( rPoint ); 1880 1881 #ifdef DBG_UTIL 1882 mpImpl->CheckInvariants(); 1883 #endif 1884 } 1885 1886 Point AccessibleTextHelper::GetOffset() const 1887 { 1888 #ifdef DBG_UTIL 1889 mpImpl->CheckInvariants(); 1890 1891 Point aPoint( mpImpl->GetOffset() ); 1892 1893 mpImpl->CheckInvariants(); 1894 1895 return aPoint; 1896 #else 1897 return mpImpl->GetOffset(); 1898 #endif 1899 } 1900 1901 void AccessibleTextHelper::SetStartIndex( sal_Int32 nOffset ) 1902 { 1903 #ifdef DBG_UTIL 1904 // precondition: solar mutex locked 1905 DBG_TESTSOLARMUTEX(); 1906 1907 mpImpl->CheckInvariants(); 1908 #endif 1909 1910 mpImpl->SetStartIndex( nOffset ); 1911 1912 #ifdef DBG_UTIL 1913 mpImpl->CheckInvariants(); 1914 #endif 1915 } 1916 1917 sal_Int32 AccessibleTextHelper::GetStartIndex() const 1918 { 1919 #ifdef DBG_UTIL 1920 mpImpl->CheckInvariants(); 1921 1922 sal_Int32 nOffset = mpImpl->GetStartIndex(); 1923 1924 mpImpl->CheckInvariants(); 1925 1926 return nOffset; 1927 #else 1928 return mpImpl->GetStartIndex(); 1929 #endif 1930 } 1931 1932 void AccessibleTextHelper::SetAdditionalChildStates( const VectorOfStates& rChildStates ) 1933 { 1934 mpImpl->SetAdditionalChildStates( rChildStates ); 1935 } 1936 1937 const AccessibleTextHelper::VectorOfStates& AccessibleTextHelper::GetAdditionalChildStates() const 1938 { 1939 return mpImpl->GetAdditionalChildStates(); 1940 } 1941 1942 void AccessibleTextHelper::UpdateChildren() SAL_THROW((::com::sun::star::uno::RuntimeException)) 1943 { 1944 #ifdef DBG_UTIL 1945 // precondition: solar mutex locked 1946 DBG_TESTSOLARMUTEX(); 1947 1948 mpImpl->CheckInvariants(); 1949 #endif 1950 1951 mpImpl->UpdateVisibleChildren(); 1952 mpImpl->UpdateBoundRect(); 1953 1954 mpImpl->UpdateSelection(); 1955 1956 #ifdef DBG_UTIL 1957 mpImpl->CheckInvariants(); 1958 #endif 1959 } 1960 1961 void AccessibleTextHelper::Dispose() 1962 { 1963 // As Dispose calls ShutdownEditSource, which in turn 1964 // deregisters as listener on the edit source, have to lock 1965 // here 1966 ::vos::OGuard aGuard( Application::GetSolarMutex() ); 1967 1968 #ifdef DBG_UTIL 1969 mpImpl->CheckInvariants(); 1970 #endif 1971 1972 mpImpl->Dispose(); 1973 1974 #ifdef DBG_UTIL 1975 mpImpl->CheckInvariants(); 1976 #endif 1977 } 1978 1979 sal_Bool AccessibleTextHelper::IsSelected() const 1980 { 1981 ::vos::OGuard aGuard( Application::GetSolarMutex() ); 1982 1983 #ifdef DBG_UTIL 1984 mpImpl->CheckInvariants(); 1985 1986 sal_Bool aRet = mpImpl->IsSelected(); 1987 1988 mpImpl->CheckInvariants(); 1989 1990 return aRet; 1991 #else 1992 return mpImpl->IsSelected(); 1993 #endif 1994 } 1995 1996 // XAccessibleContext 1997 sal_Int32 AccessibleTextHelper::GetChildCount() SAL_THROW((uno::RuntimeException)) 1998 { 1999 ::vos::OGuard aGuard( Application::GetSolarMutex() ); 2000 2001 #ifdef DBG_UTIL 2002 mpImpl->CheckInvariants(); 2003 2004 sal_Int32 nRet = mpImpl->getAccessibleChildCount(); 2005 2006 mpImpl->CheckInvariants(); 2007 2008 return nRet; 2009 #else 2010 return mpImpl->getAccessibleChildCount(); 2011 #endif 2012 } 2013 2014 uno::Reference< XAccessible > AccessibleTextHelper::GetChild( sal_Int32 i ) SAL_THROW((lang::IndexOutOfBoundsException, uno::RuntimeException)) 2015 { 2016 ::vos::OGuard aGuard( Application::GetSolarMutex() ); 2017 2018 #ifdef DBG_UTIL 2019 mpImpl->CheckInvariants(); 2020 2021 uno::Reference< XAccessible > xRet = mpImpl->getAccessibleChild( i ); 2022 2023 mpImpl->CheckInvariants(); 2024 2025 return xRet; 2026 #else 2027 return mpImpl->getAccessibleChild( i ); 2028 #endif 2029 } 2030 2031 void AccessibleTextHelper::AddEventListener( const uno::Reference< XAccessibleEventListener >& xListener ) SAL_THROW((uno::RuntimeException)) 2032 { 2033 #ifdef DBG_UTIL 2034 mpImpl->CheckInvariants(); 2035 2036 mpImpl->addEventListener( xListener ); 2037 2038 mpImpl->CheckInvariants(); 2039 #else 2040 mpImpl->addEventListener( xListener ); 2041 #endif 2042 } 2043 2044 void AccessibleTextHelper::RemoveEventListener( const uno::Reference< XAccessibleEventListener >& xListener ) SAL_THROW((uno::RuntimeException)) 2045 { 2046 #ifdef DBG_UTIL 2047 mpImpl->CheckInvariants(); 2048 2049 mpImpl->removeEventListener( xListener ); 2050 2051 mpImpl->CheckInvariants(); 2052 #else 2053 mpImpl->removeEventListener( xListener ); 2054 #endif 2055 } 2056 2057 // XAccessibleComponent 2058 uno::Reference< XAccessible > AccessibleTextHelper::GetAt( const awt::Point& aPoint ) SAL_THROW((uno::RuntimeException)) 2059 { 2060 ::vos::OGuard aGuard( Application::GetSolarMutex() ); 2061 2062 #ifdef DBG_UTIL 2063 mpImpl->CheckInvariants(); 2064 2065 uno::Reference< XAccessible > xChild = mpImpl->getAccessibleAtPoint( aPoint ); 2066 2067 mpImpl->CheckInvariants(); 2068 2069 return xChild; 2070 #else 2071 return mpImpl->getAccessibleAtPoint( aPoint ); 2072 #endif 2073 } 2074 2075 } // end of namespace accessibility 2076 2077 //------------------------------------------------------------------------ 2078