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