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