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