1 /************************************************************************* 2 * 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * Copyright 2000, 2010 Oracle and/or its affiliates. 6 * 7 * OpenOffice.org - a multi-platform office productivity suite 8 * 9 * This file is part of OpenOffice.org. 10 * 11 * OpenOffice.org is free software: you can redistribute it and/or modify 12 * it under the terms of the GNU Lesser General Public License version 3 13 * only, as published by the Free Software Foundation. 14 * 15 * OpenOffice.org is distributed in the hope that it will be useful, 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 * GNU Lesser General Public License version 3 for more details 19 * (a copy is included in the LICENSE file that accompanied this code). 20 * 21 * You should have received a copy of the GNU Lesser General Public License 22 * version 3 along with OpenOffice.org. If not, see 23 * <http://www.openoffice.org/license.html> 24 * for a copy of the LGPLv3 License. 25 * 26 ************************************************************************/ 27 28 // MARKER(update_precomp.py): autogen include statement, do not remove 29 #include "precompiled_editeng.hxx" 30 31 //------------------------------------------------------------------------ 32 // 33 // Global header 34 // 35 //------------------------------------------------------------------------ 36 37 #include <limits.h> 38 #include <vector> 39 #include <algorithm> 40 #include <boost/bind.hpp> 41 #include <vos/mutex.hxx> 42 #include <vcl/window.hxx> 43 #include <vcl/svapp.hxx> 44 #include <comphelper/sequenceasvector.hxx> 45 #include <com/sun/star/uno/Any.hxx> 46 #include <com/sun/star/uno/Reference.hxx> 47 #include <com/sun/star/awt/Point.hpp> 48 #include <com/sun/star/awt/Rectangle.hpp> 49 #include <com/sun/star/accessibility/AccessibleTextType.hpp> 50 51 //------------------------------------------------------------------------ 52 // 53 // Project-local header 54 // 55 //------------------------------------------------------------------------ 56 57 #include <editeng/editdata.hxx> 58 #include <editeng/unopracc.hxx> 59 #include "editeng/unoedprx.hxx" 60 #include <editeng/AccessibleStaticTextBase.hxx> 61 #include "editeng/AccessibleEditableTextPara.hxx" 62 63 64 using namespace ::com::sun::star; 65 using namespace ::com::sun::star::accessibility; 66 67 /* TODO: 68 ===== 69 70 - separate adapter functionality from AccessibleStaticText class 71 72 - refactor common loops into templates, using mem_fun 73 74 */ 75 76 namespace accessibility 77 { 78 typedef ::comphelper::SequenceAsVector< beans::PropertyValue > PropertyValueVector; 79 80 class PropertyValueEqualFunctor : public ::std::binary_function< beans::PropertyValue, beans::PropertyValue, bool > 81 { 82 public: 83 PropertyValueEqualFunctor() 84 {} 85 bool operator() ( const beans::PropertyValue& lhs, const beans::PropertyValue& rhs ) const 86 { 87 return ( lhs.Name == rhs.Name && lhs.Value == rhs.Value ); 88 } 89 }; 90 91 //------------------------------------------------------------------------ 92 // 93 // Static Helper 94 // 95 //------------------------------------------------------------------------ 96 ESelection MakeSelection( sal_Int32 nStartPara, sal_Int32 nStartIndex, 97 sal_Int32 nEndPara, sal_Int32 nEndIndex ) 98 { 99 DBG_ASSERT(nStartPara >= 0 && nStartPara <= USHRT_MAX && 100 nStartIndex >= 0 && nStartIndex <= USHRT_MAX && 101 nEndPara >= 0 && nEndPara <= USHRT_MAX && 102 nEndIndex >= 0 && nEndIndex <= USHRT_MAX , 103 "AccessibleStaticTextBase_Impl::MakeSelection: index value overflow"); 104 105 return ESelection( static_cast< sal_uInt16 >(nStartPara), static_cast< sal_uInt16 >(nStartIndex), 106 static_cast< sal_uInt16 >(nEndPara), static_cast< sal_uInt16 >(nEndIndex) ); 107 } 108 109 //------------------------------------------------------------------------ 110 // 111 // AccessibleStaticTextBase_Impl declaration 112 // 113 //------------------------------------------------------------------------ 114 115 DBG_NAME( AccessibleStaticTextBase_Impl ); 116 117 /** AccessibleStaticTextBase_Impl 118 119 This class implements the AccessibleStaticTextBase 120 functionality, mainly by forwarding the calls to an aggregated 121 AccessibleEditableTextPara. As this is a therefore non-trivial 122 adapter, factoring out the common functionality from 123 AccessibleEditableTextPara might be a profitable future task. 124 */ 125 class AccessibleStaticTextBase_Impl 126 { 127 128 public: 129 130 // receive pointer to our frontend class and view window 131 AccessibleStaticTextBase_Impl(); 132 ~AccessibleStaticTextBase_Impl(); 133 134 SvxEditSourceAdapter& GetEditSource() const SAL_THROW((uno::RuntimeException)) 135 { 136 DBG_CHKTHIS( AccessibleStaticTextBase_Impl, NULL ); 137 138 return maEditSource; 139 } 140 void SetEditSource( ::std::auto_ptr< SvxEditSource > pEditSource ) SAL_THROW((uno::RuntimeException)); 141 142 void SetEventSource( const uno::Reference< XAccessible >& rInterface ) 143 { 144 DBG_CHKTHIS( AccessibleStaticTextBase_Impl, NULL ); 145 146 mxThis = rInterface; 147 } 148 uno::Reference< XAccessible > GetEventSource() const 149 { 150 DBG_CHKTHIS( AccessibleStaticTextBase_Impl, NULL ); 151 152 return mxThis; 153 } 154 155 void SetOffset( const Point& ); 156 Point GetOffset() const 157 { 158 DBG_CHKTHIS( AccessibleStaticTextBase_Impl, NULL ); 159 160 ::osl::MutexGuard aGuard( maMutex ); Point aPoint( maOffset ); 161 return aPoint; 162 } 163 164 void UpdateChildren(); 165 void Dispose(); 166 167 #ifdef DBG_UTIL 168 void CheckInvariants() const; 169 #endif 170 171 AccessibleEditableTextPara& GetParagraph( sal_Int32 nPara ) const; 172 sal_Int32 GetParagraphCount() const; 173 sal_Int32 GetParagraphIndex() const; 174 sal_Int32 GetLineCount( sal_Int32 nParagraph ) const; 175 176 EPosition Index2Internal( sal_Int32 nFlatIndex ) const 177 { 178 DBG_CHKTHIS( AccessibleStaticTextBase_Impl, NULL ); 179 180 return ImpCalcInternal( nFlatIndex, false ); 181 } 182 183 EPosition Range2Internal( sal_Int32 nFlatIndex ) const 184 { 185 DBG_CHKTHIS( AccessibleStaticTextBase_Impl, NULL ); 186 187 return ImpCalcInternal( nFlatIndex, true ); 188 } 189 190 sal_Int32 Internal2Index( EPosition nEEIndex ) const; 191 192 void CorrectTextSegment( TextSegment& aTextSegment, 193 int nPara ) const; 194 195 sal_Bool SetSelection( sal_Int32 nStartPara, sal_Int32 nStartIndex, 196 sal_Int32 nEndPara, sal_Int32 nEndIndex ); 197 sal_Bool CopyText( sal_Int32 nStartPara, sal_Int32 nStartIndex, 198 sal_Int32 nEndPara, sal_Int32 nEndIndex ); 199 200 Rectangle GetParagraphBoundingBox() const; 201 202 private: 203 204 EPosition ImpCalcInternal( sal_Int32 nFlatIndex, bool bExclusive ) const; 205 206 // our frontend class (the one implementing the actual 207 // interface). That's not necessarily the one containing the impl 208 // pointer 209 uno::Reference< XAccessible > mxThis; 210 211 // implements our functionality, we're just an adapter (guarded by solar mutex) 212 mutable AccessibleEditableTextPara* mpTextParagraph; 213 214 uno::Reference< XAccessible > mxParagraph; 215 216 // a wrapper for the text forwarders (guarded by solar mutex) 217 mutable SvxEditSourceAdapter maEditSource; 218 219 // guard for maOffset 220 mutable ::osl::Mutex maMutex; 221 222 /// our current offset to the containing shape/cell (guarded by maMutex) 223 Point maOffset; 224 225 }; 226 227 //------------------------------------------------------------------------ 228 // 229 // AccessibleStaticTextBase_Impl implementation 230 // 231 //------------------------------------------------------------------------ 232 233 AccessibleStaticTextBase_Impl::AccessibleStaticTextBase_Impl() : 234 mxThis( NULL ), 235 mpTextParagraph( new AccessibleEditableTextPara(NULL) ), 236 mxParagraph( mpTextParagraph ), 237 maEditSource(), 238 maMutex(), 239 maOffset(0,0) 240 { 241 DBG_CTOR( AccessibleStaticTextBase_Impl, NULL ); 242 243 // TODO: this is still somewhat of a hack, all the more since 244 // now the maTextParagraph has an empty parent reference set 245 } 246 247 AccessibleStaticTextBase_Impl::~AccessibleStaticTextBase_Impl() 248 { 249 DBG_DTOR( AccessibleStaticTextBase_Impl, NULL ); 250 } 251 252 void AccessibleStaticTextBase_Impl::SetEditSource( ::std::auto_ptr< SvxEditSource > pEditSource ) SAL_THROW((uno::RuntimeException)) 253 { 254 DBG_CHKTHIS( AccessibleStaticTextBase_Impl, NULL ); 255 256 maEditSource.SetEditSource( pEditSource ); 257 if( mpTextParagraph ) 258 mpTextParagraph->SetEditSource( &maEditSource ); 259 } 260 261 void AccessibleStaticTextBase_Impl::SetOffset( const Point& rPoint ) 262 { 263 DBG_CHKTHIS( AccessibleStaticTextBase_Impl, NULL ); 264 265 // guard against non-atomic access to maOffset data structure 266 { 267 ::osl::MutexGuard aGuard( maMutex ); 268 maOffset = rPoint; 269 } 270 271 if( mpTextParagraph ) 272 mpTextParagraph->SetEEOffset( rPoint ); 273 274 // in all cases, check visibility afterwards. 275 UpdateChildren(); 276 } 277 278 void AccessibleStaticTextBase_Impl::UpdateChildren() 279 { 280 DBG_CHKTHIS( AccessibleStaticTextBase_Impl, NULL ); 281 282 // currently no children 283 } 284 285 void AccessibleStaticTextBase_Impl::Dispose() 286 { 287 DBG_CHKTHIS( AccessibleStaticTextBase_Impl, NULL ); 288 289 // we're the owner of the paragraph, so destroy it, too 290 if( mpTextParagraph ) 291 mpTextParagraph->Dispose(); 292 293 // drop references 294 mxParagraph = NULL; 295 mxThis = NULL; 296 mpTextParagraph = NULL; 297 } 298 299 #ifdef DBG_UTIL 300 void AccessibleStaticTextBase_Impl::CheckInvariants() const 301 { 302 // TODO 303 } 304 #endif 305 306 AccessibleEditableTextPara& AccessibleStaticTextBase_Impl::GetParagraph( sal_Int32 nPara ) const 307 { 308 DBG_CHKTHIS( AccessibleStaticTextBase_Impl, NULL ); 309 310 if( !mpTextParagraph ) 311 throw lang::DisposedException ( 312 ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("object has been already disposed")), mxThis ); 313 314 // TODO: Have a differnt method on AccessibleEditableTextPara 315 // that does not care about state changes 316 mpTextParagraph->SetParagraphIndex( nPara ); 317 318 return *mpTextParagraph; 319 } 320 321 sal_Int32 AccessibleStaticTextBase_Impl::GetParagraphCount() const 322 { 323 DBG_CHKTHIS( AccessibleStaticTextBase_Impl, NULL ); 324 325 if( !mpTextParagraph ) 326 return 0; 327 else 328 return mpTextParagraph->GetTextForwarder().GetParagraphCount(); 329 } 330 331 sal_Int32 AccessibleStaticTextBase_Impl::GetParagraphIndex() const 332 { 333 DBG_CHKTHIS( AccessibleStaticTextBase_Impl, NULL ); 334 335 sal_Int32 nIndex = -1; 336 if( mpTextParagraph ) 337 nIndex = mpTextParagraph->GetParagraphIndex(); 338 return nIndex; 339 } 340 341 sal_Int32 AccessibleStaticTextBase_Impl::GetLineCount( sal_Int32 nParagraph ) const 342 { 343 DBG_CHKTHIS( AccessibleStaticTextBase_Impl, NULL ); 344 345 sal_Int32 nIndex = 0; 346 if( mpTextParagraph ) 347 nIndex = mpTextParagraph->GetTextForwarder().GetLineCount( static_cast< sal_uInt16 >(nParagraph) ); 348 return nIndex; 349 } 350 351 sal_Int32 AccessibleStaticTextBase_Impl::Internal2Index( EPosition nEEIndex ) const 352 { 353 sal_Int32 aRes(0); 354 int i; 355 for(i=0; i<nEEIndex.nPara; ++i) 356 aRes += GetParagraph(i).getCharacterCount(); 357 358 return aRes + nEEIndex.nIndex; 359 } 360 361 void AccessibleStaticTextBase_Impl::CorrectTextSegment( TextSegment& aTextSegment, 362 int nPara ) const 363 { 364 // Keep 'invalid' values at the TextSegment 365 if( aTextSegment.SegmentStart != -1 && 366 aTextSegment.SegmentStart != -1 ) 367 { 368 // #112814# Correct TextSegment by paragraph offset 369 sal_Int32 nOffset(0); 370 int i; 371 for(i=0; i<nPara; ++i) 372 nOffset += GetParagraph(i).getCharacterCount(); 373 374 aTextSegment.SegmentStart += nOffset; 375 aTextSegment.SegmentEnd += nOffset; 376 } 377 } 378 379 EPosition AccessibleStaticTextBase_Impl::ImpCalcInternal( sal_Int32 nFlatIndex, bool bExclusive ) const 380 { 381 DBG_CHKTHIS( AccessibleStaticTextBase_Impl, NULL ); 382 383 if( nFlatIndex < 0 ) 384 throw lang::IndexOutOfBoundsException(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("AccessibleStaticTextBase_Impl::Index2Internal: character index out of bounds")), 385 mxThis); 386 // gratuitously accepting larger indices here, AccessibleEditableTextPara will throw eventually 387 388 sal_Int32 nCurrPara, nCurrIndex, nParas, nCurrCount; 389 for( nCurrPara=0, nParas=GetParagraphCount(), nCurrCount=0, nCurrIndex=0; nCurrPara<nParas; ++nCurrPara ) 390 { 391 nCurrCount = GetParagraph( nCurrPara ).getCharacterCount(); 392 nCurrIndex += nCurrCount; 393 394 if( nCurrIndex > nFlatIndex ) 395 { 396 // check overflow 397 DBG_ASSERT(nCurrPara >= 0 && nCurrPara <= USHRT_MAX && 398 nFlatIndex - nCurrIndex + nCurrCount >= 0 && nFlatIndex - nCurrIndex + nCurrCount <= USHRT_MAX , 399 "AccessibleStaticTextBase_Impl::Index2Internal: index value overflow"); 400 401 return EPosition( static_cast< sal_uInt16 >(nCurrPara), static_cast< sal_uInt16 >(nFlatIndex - nCurrIndex + nCurrCount) ); 402 } 403 } 404 405 // #102170# Allow one-past the end for ranges 406 if( bExclusive && nCurrIndex == nFlatIndex ) 407 { 408 // check overflow 409 DBG_ASSERT(nCurrPara >= 0 && nCurrPara <= USHRT_MAX && 410 nFlatIndex - nCurrIndex + nCurrCount >= 0 && nFlatIndex - nCurrIndex + nCurrCount <= USHRT_MAX , 411 "AccessibleStaticTextBase_Impl::Index2Internal: index value overflow"); 412 413 return EPosition( static_cast< sal_uInt16 >(nCurrPara-1), static_cast< sal_uInt16 >(nFlatIndex - nCurrIndex + nCurrCount) ); 414 } 415 416 // not found? Out of bounds 417 throw lang::IndexOutOfBoundsException(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("AccessibleStaticTextBase_Impl::Index2Internal: character index out of bounds")), 418 mxThis); 419 } 420 421 sal_Bool AccessibleStaticTextBase_Impl::SetSelection( sal_Int32 nStartPara, sal_Int32 nStartIndex, 422 sal_Int32 nEndPara, sal_Int32 nEndIndex ) 423 { 424 DBG_CHKTHIS( AccessibleStaticTextBase_Impl, NULL ); 425 426 if( !mpTextParagraph ) 427 return sal_False; 428 429 try 430 { 431 SvxEditViewForwarder& rCacheVF = mpTextParagraph->GetEditViewForwarder( sal_True ); 432 return rCacheVF.SetSelection( MakeSelection(nStartPara, nStartIndex, nEndPara, nEndIndex) ); 433 } 434 catch( const uno::RuntimeException& ) 435 { 436 return sal_False; 437 } 438 } 439 440 sal_Bool AccessibleStaticTextBase_Impl::CopyText( sal_Int32 nStartPara, sal_Int32 nStartIndex, 441 sal_Int32 nEndPara, sal_Int32 nEndIndex ) 442 { 443 DBG_CHKTHIS( AccessibleStaticTextBase_Impl, NULL ); 444 445 if( !mpTextParagraph ) 446 return sal_False; 447 448 try 449 { 450 SvxEditViewForwarder& rCacheVF = mpTextParagraph->GetEditViewForwarder( sal_True ); 451 mpTextParagraph->GetTextForwarder(); // MUST be after GetEditViewForwarder(), see method docs 452 sal_Bool aRetVal; 453 454 // save current selection 455 ESelection aOldSelection; 456 457 rCacheVF.GetSelection( aOldSelection ); 458 rCacheVF.SetSelection( MakeSelection(nStartPara, nStartIndex, nEndPara, nEndIndex) ); 459 aRetVal = rCacheVF.Copy(); 460 rCacheVF.SetSelection( aOldSelection ); // restore 461 462 return aRetVal; 463 } 464 catch( const uno::RuntimeException& ) 465 { 466 return sal_False; 467 } 468 } 469 470 Rectangle AccessibleStaticTextBase_Impl::GetParagraphBoundingBox() const 471 { 472 Rectangle aRect; 473 if( mpTextParagraph ) 474 { 475 awt::Rectangle aAwtRect = mpTextParagraph->getBounds(); 476 aRect = Rectangle( Point( aAwtRect.X, aAwtRect.Y ), Size( aAwtRect.Width, aAwtRect.Height ) ); 477 } 478 else 479 { 480 aRect.SetEmpty(); 481 } 482 return aRect; 483 } 484 485 //------------------------------------------------------------------------ 486 // 487 // AccessibleStaticTextBase implementation 488 // 489 //------------------------------------------------------------------------ 490 491 AccessibleStaticTextBase::AccessibleStaticTextBase( ::std::auto_ptr< SvxEditSource > pEditSource ) : 492 mpImpl( new AccessibleStaticTextBase_Impl() ) 493 { 494 ::vos::OGuard aGuard( Application::GetSolarMutex() ); 495 496 SetEditSource( pEditSource ); 497 } 498 499 AccessibleStaticTextBase::~AccessibleStaticTextBase() 500 { 501 } 502 503 const SvxEditSource& AccessibleStaticTextBase::GetEditSource() const SAL_THROW((::com::sun::star::uno::RuntimeException)) 504 { 505 #ifdef DBG_UTIL 506 mpImpl->CheckInvariants(); 507 508 const SvxEditSource& aEditSource = mpImpl->GetEditSource(); 509 510 mpImpl->CheckInvariants(); 511 512 return aEditSource; 513 #else 514 return mpImpl->GetEditSource(); 515 #endif 516 } 517 518 void AccessibleStaticTextBase::SetEditSource( ::std::auto_ptr< SvxEditSource > pEditSource ) SAL_THROW((::com::sun::star::uno::RuntimeException)) 519 { 520 #ifdef DBG_UTIL 521 // precondition: solar mutex locked 522 DBG_TESTSOLARMUTEX(); 523 524 mpImpl->CheckInvariants(); 525 526 mpImpl->SetEditSource( pEditSource ); 527 528 mpImpl->CheckInvariants(); 529 #else 530 mpImpl->SetEditSource( pEditSource ); 531 #endif 532 } 533 534 void AccessibleStaticTextBase::SetEventSource( const uno::Reference< XAccessible >& rInterface ) 535 { 536 #ifdef DBG_UTIL 537 mpImpl->CheckInvariants(); 538 #endif 539 540 mpImpl->SetEventSource( rInterface ); 541 542 #ifdef DBG_UTIL 543 mpImpl->CheckInvariants(); 544 #endif 545 } 546 547 uno::Reference< XAccessible > AccessibleStaticTextBase::GetEventSource() const 548 { 549 #ifdef DBG_UTIL 550 mpImpl->CheckInvariants(); 551 552 uno::Reference< XAccessible > xRet( mpImpl->GetEventSource() ); 553 554 mpImpl->CheckInvariants(); 555 556 return xRet; 557 #else 558 return mpImpl->GetEventSource(); 559 #endif 560 } 561 562 void AccessibleStaticTextBase::SetOffset( const Point& rPoint ) 563 { 564 #ifdef DBG_UTIL 565 // precondition: solar mutex locked 566 DBG_TESTSOLARMUTEX(); 567 568 mpImpl->CheckInvariants(); 569 570 mpImpl->SetOffset( rPoint ); 571 572 mpImpl->CheckInvariants(); 573 #else 574 mpImpl->SetOffset( rPoint ); 575 #endif 576 } 577 578 Point AccessibleStaticTextBase::GetOffset() const 579 { 580 #ifdef DBG_UTIL 581 mpImpl->CheckInvariants(); 582 583 Point aPoint( mpImpl->GetOffset() ); 584 585 mpImpl->CheckInvariants(); 586 587 return aPoint; 588 #else 589 return mpImpl->GetOffset(); 590 #endif 591 } 592 593 void AccessibleStaticTextBase::UpdateChildren() SAL_THROW((::com::sun::star::uno::RuntimeException)) 594 { 595 #ifdef DBG_UTIL 596 // precondition: solar mutex locked 597 DBG_TESTSOLARMUTEX(); 598 599 mpImpl->CheckInvariants(); 600 601 mpImpl->UpdateChildren(); 602 603 mpImpl->CheckInvariants(); 604 #else 605 mpImpl->UpdateChildren(); 606 #endif 607 } 608 609 void AccessibleStaticTextBase::Dispose() 610 { 611 #ifdef DBG_UTIL 612 mpImpl->CheckInvariants(); 613 #endif 614 615 mpImpl->Dispose(); 616 617 #ifdef DBG_UTIL 618 mpImpl->CheckInvariants(); 619 #endif 620 } 621 622 // XAccessibleContext 623 sal_Int32 SAL_CALL AccessibleStaticTextBase::getAccessibleChildCount() throw (uno::RuntimeException) 624 { 625 // no children at all 626 return 0; 627 } 628 629 uno::Reference< XAccessible > SAL_CALL AccessibleStaticTextBase::getAccessibleChild( sal_Int32 /*i*/ ) throw (lang::IndexOutOfBoundsException, uno::RuntimeException) 630 { 631 // no children at all 632 return uno::Reference< XAccessible >(); 633 } 634 635 uno::Reference< XAccessible > SAL_CALL AccessibleStaticTextBase::getAccessibleAtPoint( const awt::Point& /*_aPoint*/ ) throw (uno::RuntimeException) 636 { 637 // no children at all 638 return uno::Reference< XAccessible >(); 639 } 640 641 // XAccessibleText 642 sal_Int32 SAL_CALL AccessibleStaticTextBase::getCaretPosition() throw (uno::RuntimeException) 643 { 644 ::vos::OGuard aGuard( Application::GetSolarMutex() ); 645 646 sal_Int32 i, nPos, nParas; 647 for( i=0, nPos=-1, nParas=mpImpl->GetParagraphCount(); i<nParas; ++i ) 648 { 649 if( (nPos=mpImpl->GetParagraph(i).getCaretPosition()) != -1 ) 650 return nPos; 651 } 652 653 return nPos; 654 } 655 656 sal_Bool SAL_CALL AccessibleStaticTextBase::setCaretPosition( sal_Int32 nIndex ) throw (lang::IndexOutOfBoundsException, uno::RuntimeException) 657 { 658 return setSelection(nIndex, nIndex); 659 } 660 661 sal_Unicode SAL_CALL AccessibleStaticTextBase::getCharacter( sal_Int32 nIndex ) throw (lang::IndexOutOfBoundsException, uno::RuntimeException) 662 { 663 ::vos::OGuard aGuard( Application::GetSolarMutex() ); 664 665 EPosition aPos( mpImpl->Index2Internal(nIndex) ); 666 667 return mpImpl->GetParagraph( aPos.nPara ).getCharacter( aPos.nIndex ); 668 } 669 670 uno::Sequence< beans::PropertyValue > SAL_CALL AccessibleStaticTextBase::getCharacterAttributes( sal_Int32 nIndex, const ::com::sun::star::uno::Sequence< ::rtl::OUString >& aRequestedAttributes ) throw (lang::IndexOutOfBoundsException, uno::RuntimeException) 671 { 672 ::vos::OGuard aGuard( Application::GetSolarMutex() ); 673 674 EPosition aPos( mpImpl->Index2Internal(nIndex) ); 675 676 return mpImpl->GetParagraph( aPos.nPara ).getCharacterAttributes( aPos.nIndex, aRequestedAttributes ); 677 } 678 679 awt::Rectangle SAL_CALL AccessibleStaticTextBase::getCharacterBounds( sal_Int32 nIndex ) throw (lang::IndexOutOfBoundsException, uno::RuntimeException) 680 { 681 ::vos::OGuard aGuard( Application::GetSolarMutex() ); 682 683 // #108900# Allow ranges for nIndex, as one-past-the-end 684 // values are now legal, too. 685 EPosition aPos( mpImpl->Range2Internal(nIndex) ); 686 687 // #i70916# Text in spread sheet cells return the wrong extents 688 AccessibleEditableTextPara& rPara = mpImpl->GetParagraph( aPos.nPara ); 689 awt::Rectangle aParaBounds( rPara.getBounds() ); 690 awt::Rectangle aBounds( rPara.getCharacterBounds( aPos.nIndex ) ); 691 aBounds.X += aParaBounds.X; 692 aBounds.Y += aParaBounds.Y; 693 694 return aBounds; 695 } 696 697 sal_Int32 SAL_CALL AccessibleStaticTextBase::getCharacterCount() throw (uno::RuntimeException) 698 { 699 ::vos::OGuard aGuard( Application::GetSolarMutex() ); 700 701 sal_Int32 i, nCount, nParas; 702 for( i=0, nCount=0, nParas=mpImpl->GetParagraphCount(); i<nParas; ++i ) 703 nCount += mpImpl->GetParagraph(i).getCharacterCount(); 704 705 return nCount; 706 } 707 708 sal_Int32 SAL_CALL AccessibleStaticTextBase::getIndexAtPoint( const awt::Point& rPoint ) throw (uno::RuntimeException) 709 { 710 ::vos::OGuard aGuard( Application::GetSolarMutex() ); 711 712 const sal_Int32 nParas( mpImpl->GetParagraphCount() ); 713 sal_Int32 nIndex; 714 int i; 715 for( i=0; i<nParas; ++i ) 716 { 717 // TODO: maybe exploit the fact that paragraphs are 718 // ordered vertically for early exit 719 720 // #i70916# Text in spread sheet cells return the wrong extents 721 AccessibleEditableTextPara& rPara = mpImpl->GetParagraph( i ); 722 awt::Rectangle aParaBounds( rPara.getBounds() ); 723 awt::Point aPoint( rPoint ); 724 aPoint.X -= aParaBounds.X; 725 aPoint.Y -= aParaBounds.Y; 726 727 // #112814# Use correct index offset 728 if ( ( nIndex = rPara.getIndexAtPoint( aPoint ) ) != -1 ) 729 return mpImpl->Internal2Index( EPosition(sal::static_int_cast<sal_uInt16>(i), 730 sal::static_int_cast<sal_uInt16>(nIndex)) ); 731 } 732 733 return -1; 734 } 735 736 ::rtl::OUString SAL_CALL AccessibleStaticTextBase::getSelectedText() throw (uno::RuntimeException) 737 { 738 ::vos::OGuard aGuard( Application::GetSolarMutex() ); 739 740 sal_Int32 nStart( getSelectionStart() ); 741 sal_Int32 nEnd( getSelectionEnd() ); 742 743 // #104481# Return the empty string for 'no selection' 744 if( nStart < 0 || nEnd < 0 ) 745 return ::rtl::OUString(); 746 747 return getTextRange( nStart, nEnd ); 748 } 749 750 sal_Int32 SAL_CALL AccessibleStaticTextBase::getSelectionStart() throw (uno::RuntimeException) 751 { 752 ::vos::OGuard aGuard( Application::GetSolarMutex() ); 753 754 sal_Int32 i, nPos, nParas; 755 for( i=0, nPos=-1, nParas=mpImpl->GetParagraphCount(); i<nParas; ++i ) 756 { 757 if( (nPos=mpImpl->GetParagraph(i).getSelectionStart()) != -1 ) 758 return nPos; 759 } 760 761 return nPos; 762 } 763 764 sal_Int32 SAL_CALL AccessibleStaticTextBase::getSelectionEnd() throw (uno::RuntimeException) 765 { 766 ::vos::OGuard aGuard( Application::GetSolarMutex() ); 767 768 sal_Int32 i, nPos, nParas; 769 for( i=0, nPos=-1, nParas=mpImpl->GetParagraphCount(); i<nParas; ++i ) 770 { 771 if( (nPos=mpImpl->GetParagraph(i).getSelectionEnd()) != -1 ) 772 return nPos; 773 } 774 775 return nPos; 776 } 777 778 sal_Bool SAL_CALL AccessibleStaticTextBase::setSelection( sal_Int32 nStartIndex, sal_Int32 nEndIndex ) throw (lang::IndexOutOfBoundsException, uno::RuntimeException) 779 { 780 ::vos::OGuard aGuard( Application::GetSolarMutex() ); 781 782 EPosition aStartIndex( mpImpl->Range2Internal(nStartIndex) ); 783 EPosition aEndIndex( mpImpl->Range2Internal(nEndIndex) ); 784 785 return mpImpl->SetSelection( aStartIndex.nPara, aStartIndex.nIndex, 786 aEndIndex.nPara, aEndIndex.nIndex ); 787 } 788 789 ::rtl::OUString SAL_CALL AccessibleStaticTextBase::getText() throw (uno::RuntimeException) 790 { 791 ::vos::OGuard aGuard( Application::GetSolarMutex() ); 792 793 sal_Int32 i, nParas; 794 ::rtl::OUString aRes; 795 for( i=0, nParas=mpImpl->GetParagraphCount(); i<nParas; ++i ) 796 aRes += mpImpl->GetParagraph(i).getText(); 797 798 return aRes; 799 } 800 801 ::rtl::OUString SAL_CALL AccessibleStaticTextBase::getTextRange( sal_Int32 nStartIndex, sal_Int32 nEndIndex ) throw (lang::IndexOutOfBoundsException, uno::RuntimeException) 802 { 803 ::vos::OGuard aGuard( Application::GetSolarMutex() ); 804 805 if( nStartIndex > nEndIndex ) 806 ::std::swap(nStartIndex, nEndIndex); 807 808 EPosition aStartIndex( mpImpl->Range2Internal(nStartIndex) ); 809 EPosition aEndIndex( mpImpl->Range2Internal(nEndIndex) ); 810 811 // #102170# Special case: start and end paragraph are identical 812 if( aStartIndex.nPara == aEndIndex.nPara ) 813 { 814 return mpImpl->GetParagraph( aStartIndex.nPara ).getTextRange( aStartIndex.nIndex, aEndIndex.nIndex ); 815 } 816 else 817 { 818 sal_Int32 i( aStartIndex.nPara ); 819 ::rtl::OUString aRes( mpImpl->GetParagraph(i).getTextRange( aStartIndex.nIndex, 820 mpImpl->GetParagraph(i).getCharacterCount()-1) ); 821 ++i; 822 823 // paragraphs inbetween are fully included 824 for( ; i<aEndIndex.nPara; ++i ) 825 aRes += mpImpl->GetParagraph(i).getText(); 826 827 if( i<=aEndIndex.nPara ) 828 aRes += mpImpl->GetParagraph(i).getTextRange( 0, aEndIndex.nIndex ); 829 830 return aRes; 831 } 832 } 833 834 ::com::sun::star::accessibility::TextSegment SAL_CALL AccessibleStaticTextBase::getTextAtIndex( sal_Int32 nIndex, sal_Int16 aTextType ) throw (::com::sun::star::lang::IndexOutOfBoundsException, ::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::uno::RuntimeException) 835 { 836 ::vos::OGuard aGuard( Application::GetSolarMutex() ); 837 838 EPosition aPos( mpImpl->Range2Internal(nIndex) ); 839 840 ::com::sun::star::accessibility::TextSegment aResult; 841 842 if( AccessibleTextType::PARAGRAPH == aTextType ) 843 { 844 // #106393# Special casing one behind last paragraph is 845 // not necessary, since then, we return the content and 846 // boundary of that last paragraph. Range2Internal is 847 // tolerant against that, and returns the last paragraph 848 // in aPos.nPara. 849 850 // retrieve full text of the paragraph 851 aResult.SegmentText = mpImpl->GetParagraph( aPos.nPara ).getText(); 852 853 // #112814# Adapt the start index with the paragraph offset 854 aResult.SegmentStart = mpImpl->Internal2Index( EPosition( aPos.nPara, 0 ) ); 855 aResult.SegmentEnd = aResult.SegmentStart + aResult.SegmentText.getLength(); 856 } 857 else 858 { 859 // No special handling required, forward to wrapped class 860 aResult = mpImpl->GetParagraph( aPos.nPara ).getTextAtIndex( aPos.nIndex, aTextType ); 861 862 // #112814# Adapt the start index with the paragraph offset 863 mpImpl->CorrectTextSegment( aResult, aPos.nPara ); 864 } 865 866 return aResult; 867 } 868 869 ::com::sun::star::accessibility::TextSegment SAL_CALL AccessibleStaticTextBase::getTextBeforeIndex( sal_Int32 nIndex, sal_Int16 aTextType ) throw (::com::sun::star::lang::IndexOutOfBoundsException, ::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::uno::RuntimeException) 870 { 871 ::vos::OGuard aGuard( Application::GetSolarMutex() ); 872 873 EPosition aPos( mpImpl->Range2Internal(nIndex) ); 874 875 ::com::sun::star::accessibility::TextSegment aResult; 876 877 if( AccessibleTextType::PARAGRAPH == aTextType ) 878 { 879 if( aPos.nIndex == mpImpl->GetParagraph( aPos.nPara ).getCharacterCount() ) 880 { 881 // #103589# Special casing one behind the last paragraph 882 aResult.SegmentText = mpImpl->GetParagraph( aPos.nPara ).getText(); 883 884 // #112814# Adapt the start index with the paragraph offset 885 aResult.SegmentStart = mpImpl->Internal2Index( EPosition( aPos.nPara, 0 ) ); 886 } 887 else if( aPos.nPara > 0 ) 888 { 889 aResult.SegmentText = mpImpl->GetParagraph( aPos.nPara - 1 ).getText(); 890 891 // #112814# Adapt the start index with the paragraph offset 892 aResult.SegmentStart = mpImpl->Internal2Index( EPosition( aPos.nPara - 1, 0 ) ); 893 } 894 895 aResult.SegmentEnd = aResult.SegmentStart + aResult.SegmentText.getLength(); 896 } 897 else 898 { 899 // No special handling required, forward to wrapped class 900 aResult = mpImpl->GetParagraph( aPos.nPara ).getTextBeforeIndex( aPos.nIndex, aTextType ); 901 902 // #112814# Adapt the start index with the paragraph offset 903 mpImpl->CorrectTextSegment( aResult, aPos.nPara ); 904 } 905 906 return aResult; 907 } 908 909 ::com::sun::star::accessibility::TextSegment SAL_CALL AccessibleStaticTextBase::getTextBehindIndex( sal_Int32 nIndex, sal_Int16 aTextType ) throw (::com::sun::star::lang::IndexOutOfBoundsException, ::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::uno::RuntimeException) 910 { 911 ::vos::OGuard aGuard( Application::GetSolarMutex() ); 912 913 EPosition aPos( mpImpl->Range2Internal(nIndex) ); 914 915 ::com::sun::star::accessibility::TextSegment aResult; 916 917 if( AccessibleTextType::PARAGRAPH == aTextType ) 918 { 919 // Special casing one behind the last paragraph is not 920 // necessary, this case is invalid here for 921 // getTextBehindIndex 922 if( aPos.nPara + 1 < mpImpl->GetParagraphCount() ) 923 { 924 aResult.SegmentText = mpImpl->GetParagraph( aPos.nPara + 1 ).getText(); 925 926 // #112814# Adapt the start index with the paragraph offset 927 aResult.SegmentStart = mpImpl->Internal2Index( EPosition( aPos.nPara + 1, 0 ) ); 928 aResult.SegmentEnd = aResult.SegmentStart + aResult.SegmentText.getLength(); 929 } 930 } 931 else 932 { 933 // No special handling required, forward to wrapped class 934 aResult = mpImpl->GetParagraph( aPos.nPara ).getTextBehindIndex( aPos.nIndex, aTextType ); 935 936 // #112814# Adapt the start index with the paragraph offset 937 mpImpl->CorrectTextSegment( aResult, aPos.nPara ); 938 } 939 940 return aResult; 941 } 942 943 sal_Bool SAL_CALL AccessibleStaticTextBase::copyText( sal_Int32 nStartIndex, sal_Int32 nEndIndex ) throw (lang::IndexOutOfBoundsException, uno::RuntimeException) 944 { 945 ::vos::OGuard aGuard( Application::GetSolarMutex() ); 946 947 if( nStartIndex > nEndIndex ) 948 ::std::swap(nStartIndex, nEndIndex); 949 950 EPosition aStartIndex( mpImpl->Range2Internal(nStartIndex) ); 951 EPosition aEndIndex( mpImpl->Range2Internal(nEndIndex) ); 952 953 return mpImpl->CopyText( aStartIndex.nPara, aStartIndex.nIndex, 954 aEndIndex.nPara, aEndIndex.nIndex ); 955 } 956 957 // XAccessibleTextAttributes 958 uno::Sequence< beans::PropertyValue > AccessibleStaticTextBase::getDefaultAttributes( const uno::Sequence< ::rtl::OUString >& RequestedAttributes ) throw (uno::RuntimeException) 959 { 960 // get the intersection of the default attributes of all paragraphs 961 962 ::vos::OGuard aGuard( Application::GetSolarMutex() ); 963 964 PropertyValueVector aDefAttrVec( mpImpl->GetParagraph( 0 ).getDefaultAttributes( RequestedAttributes ) ); 965 966 const sal_Int32 nParaCount = mpImpl->GetParagraphCount(); 967 for ( sal_Int32 nPara = 1; nPara < nParaCount; ++nPara ) 968 { 969 uno::Sequence< beans::PropertyValue > aSeq = mpImpl->GetParagraph( nPara ).getDefaultAttributes( RequestedAttributes ); 970 PropertyValueVector aIntersectionVec; 971 972 PropertyValueVector::const_iterator aEnd = aDefAttrVec.end(); 973 for ( PropertyValueVector::const_iterator aItr = aDefAttrVec.begin(); aItr != aEnd; ++aItr ) 974 { 975 const beans::PropertyValue* pItr = aSeq.getConstArray(); 976 const beans::PropertyValue* pEnd = pItr + aSeq.getLength(); 977 const beans::PropertyValue* pFind = ::std::find_if( pItr, pEnd, ::std::bind2nd( PropertyValueEqualFunctor(), boost::cref( *aItr ) ) ); 978 if ( pFind != pEnd ) 979 { 980 aIntersectionVec.push_back( *pFind ); 981 } 982 } 983 984 aDefAttrVec.swap( aIntersectionVec ); 985 986 if ( aDefAttrVec.empty() ) 987 { 988 break; 989 } 990 } 991 992 return aDefAttrVec.getAsConstList(); 993 } 994 995 uno::Sequence< beans::PropertyValue > SAL_CALL AccessibleStaticTextBase::getRunAttributes( sal_Int32 nIndex, const uno::Sequence< ::rtl::OUString >& RequestedAttributes ) throw (lang::IndexOutOfBoundsException, uno::RuntimeException) 996 { 997 // get those default attributes of the paragraph, which are not part 998 // of the intersection of all paragraphs and add them to the run attributes 999 1000 ::vos::OGuard aGuard( Application::GetSolarMutex() ); 1001 1002 EPosition aPos( mpImpl->Index2Internal( nIndex ) ); 1003 AccessibleEditableTextPara& rPara = mpImpl->GetParagraph( aPos.nPara ); 1004 uno::Sequence< beans::PropertyValue > aDefAttrSeq = rPara.getDefaultAttributes( RequestedAttributes ); 1005 uno::Sequence< beans::PropertyValue > aRunAttrSeq = rPara.getRunAttributes( aPos.nIndex, RequestedAttributes ); 1006 uno::Sequence< beans::PropertyValue > aIntersectionSeq = getDefaultAttributes( RequestedAttributes ); 1007 PropertyValueVector aDiffVec; 1008 1009 const beans::PropertyValue* pDefAttr = aDefAttrSeq.getConstArray(); 1010 const sal_Int32 nLength = aDefAttrSeq.getLength(); 1011 for ( sal_Int32 i = 0; i < nLength; ++i ) 1012 { 1013 const beans::PropertyValue* pItr = aIntersectionSeq.getConstArray(); 1014 const beans::PropertyValue* pEnd = pItr + aIntersectionSeq.getLength(); 1015 const beans::PropertyValue* pFind = ::std::find_if( pItr, pEnd, ::std::bind2nd( PropertyValueEqualFunctor(), boost::cref( pDefAttr[i] ) ) ); 1016 if ( pFind == pEnd && pDefAttr[i].Handle != 0) 1017 { 1018 aDiffVec.push_back( pDefAttr[i] ); 1019 } 1020 } 1021 1022 return ::comphelper::concatSequences( aRunAttrSeq, aDiffVec.getAsConstList() ); 1023 } 1024 1025 Rectangle AccessibleStaticTextBase::GetParagraphBoundingBox() const 1026 { 1027 return mpImpl->GetParagraphBoundingBox(); 1028 } 1029 1030 sal_Int32 AccessibleStaticTextBase::GetParagraphIndex() const 1031 { 1032 return mpImpl->GetParagraphIndex(); 1033 } 1034 1035 sal_Int32 AccessibleStaticTextBase::GetParagraphCount() const 1036 { 1037 return mpImpl->GetParagraphCount(); 1038 } 1039 1040 sal_Int32 AccessibleStaticTextBase::GetLineCount( sal_Int32 nParagraph ) const 1041 { 1042 return mpImpl->GetLineCount( nParagraph ); 1043 } 1044 1045 } // end of namespace accessibility 1046 1047 //------------------------------------------------------------------------ 1048