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