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