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_comphelper.hxx" 30 31 // includes -------------------------------------------------------------- 32 #include <comphelper/accessibletexthelper.hxx> 33 #include <com/sun/star/accessibility/AccessibleTextType.hpp> 34 #include <com/sun/star/i18n/CharacterIteratorMode.hpp> 35 #ifndef _COM_SUN_STAR_TEXT_WORDTYPE_HPP_ 36 #include <com/sun/star/i18n/WordType.hpp> 37 #endif 38 #include <com/sun/star/i18n/KCharacterType.hpp> 39 #include <comphelper/processfactory.hxx> 40 #include <com/sun/star/accessibility/TextSegment.hpp> 41 42 #include <algorithm> 43 44 //.............................................................................. 45 namespace comphelper 46 { 47 //.............................................................................. 48 49 using namespace ::com::sun::star; 50 using namespace ::com::sun::star::uno; 51 using namespace ::com::sun::star::lang; 52 using namespace ::com::sun::star::beans; 53 using namespace ::com::sun::star::accessibility; 54 55 //============================================================================== 56 // OCommonAccessibleText 57 //============================================================================== 58 59 OCommonAccessibleText::OCommonAccessibleText() 60 { 61 } 62 63 // ----------------------------------------------------------------------------- 64 65 OCommonAccessibleText::~OCommonAccessibleText() 66 { 67 } 68 69 // ----------------------------------------------------------------------------- 70 71 Reference < i18n::XBreakIterator > OCommonAccessibleText::implGetBreakIterator() 72 { 73 if ( !m_xBreakIter.is() ) 74 { 75 Reference< lang::XMultiServiceFactory > xMSF = ::comphelper::getProcessServiceFactory(); 76 if ( xMSF.is() ) 77 { 78 m_xBreakIter = Reference< i18n::XBreakIterator > 79 ( xMSF->createInstance( ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.i18n.BreakIterator" ) ) ), UNO_QUERY ); 80 } 81 } 82 83 return m_xBreakIter; 84 } 85 86 // ----------------------------------------------------------------------------- 87 88 Reference < i18n::XCharacterClassification > OCommonAccessibleText::implGetCharacterClassification() 89 { 90 if ( !m_xCharClass.is() ) 91 { 92 Reference< lang::XMultiServiceFactory > xMSF = ::comphelper::getProcessServiceFactory(); 93 if ( xMSF.is() ) 94 { 95 m_xCharClass = Reference< i18n::XCharacterClassification > 96 ( xMSF->createInstance( ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.i18n.CharacterClassification" ) ) ), UNO_QUERY ); 97 } 98 } 99 100 return m_xCharClass; 101 } 102 103 // ----------------------------------------------------------------------------- 104 105 sal_Bool OCommonAccessibleText::implIsValidBoundary( i18n::Boundary& rBoundary, sal_Int32 nLength ) 106 { 107 return ( rBoundary.startPos >= 0 ) && ( rBoundary.startPos < nLength ) && ( rBoundary.endPos >= 0 ) && ( rBoundary.endPos <= nLength ); 108 } 109 110 // ----------------------------------------------------------------------------- 111 112 sal_Bool OCommonAccessibleText::implIsValidIndex( sal_Int32 nIndex, sal_Int32 nLength ) 113 { 114 return ( nIndex >= 0 ) && ( nIndex < nLength ); 115 } 116 117 // ----------------------------------------------------------------------------- 118 119 sal_Bool OCommonAccessibleText::implIsValidRange( sal_Int32 nStartIndex, sal_Int32 nEndIndex, sal_Int32 nLength ) 120 { 121 return ( nStartIndex >= 0 ) && ( nStartIndex <= nLength ) && ( nEndIndex >= 0 ) && ( nEndIndex <= nLength ); 122 } 123 124 // ----------------------------------------------------------------------------- 125 126 void OCommonAccessibleText::implGetGlyphBoundary( i18n::Boundary& rBoundary, sal_Int32 nIndex ) 127 { 128 ::rtl::OUString sText( implGetText() ); 129 130 if ( implIsValidIndex( nIndex, sText.getLength() ) ) 131 { 132 Reference < i18n::XBreakIterator > xBreakIter = implGetBreakIterator(); 133 if ( xBreakIter.is() ) 134 { 135 sal_Int32 nCount = 1; 136 sal_Int32 nDone; 137 sal_Int32 nStartIndex = xBreakIter->previousCharacters( sText, nIndex, implGetLocale(), i18n::CharacterIteratorMode::SKIPCELL, nCount, nDone ); 138 if ( nDone != 0 ) 139 nStartIndex = xBreakIter->nextCharacters( sText, nStartIndex, implGetLocale(), i18n::CharacterIteratorMode::SKIPCELL, nCount, nDone ); 140 sal_Int32 nEndIndex = xBreakIter->nextCharacters( sText, nStartIndex, implGetLocale(), i18n::CharacterIteratorMode::SKIPCELL, nCount, nDone ); 141 if ( nDone != 0 ) 142 { 143 rBoundary.startPos = nStartIndex; 144 rBoundary.endPos = nEndIndex; 145 } 146 } 147 } 148 else 149 { 150 rBoundary.startPos = nIndex; 151 rBoundary.endPos = nIndex; 152 } 153 } 154 155 // ----------------------------------------------------------------------------- 156 157 sal_Bool OCommonAccessibleText::implGetWordBoundary( i18n::Boundary& rBoundary, sal_Int32 nIndex ) 158 { 159 sal_Bool bWord = sal_False; 160 ::rtl::OUString sText( implGetText() ); 161 162 if ( implIsValidIndex( nIndex, sText.getLength() ) ) 163 { 164 Reference < i18n::XBreakIterator > xBreakIter = implGetBreakIterator(); 165 if ( xBreakIter.is() ) 166 { 167 rBoundary = xBreakIter->getWordBoundary( sText, nIndex, implGetLocale(), i18n::WordType::ANY_WORD, sal_True ); 168 169 // it's a word, if the first character is an alpha-numeric character 170 Reference< i18n::XCharacterClassification > xCharClass = implGetCharacterClassification(); 171 if ( xCharClass.is() ) 172 { 173 sal_Int32 nType = xCharClass->getCharacterType( sText, rBoundary.startPos, implGetLocale() ); 174 if ( ( nType & ( i18n::KCharacterType::LETTER | i18n::KCharacterType::DIGIT ) ) != 0 ) 175 bWord = sal_True; 176 } 177 } 178 } 179 else 180 { 181 rBoundary.startPos = nIndex; 182 rBoundary.endPos = nIndex; 183 } 184 185 return bWord; 186 } 187 188 // ----------------------------------------------------------------------------- 189 190 void OCommonAccessibleText::implGetSentenceBoundary( i18n::Boundary& rBoundary, sal_Int32 nIndex ) 191 { 192 ::rtl::OUString sText( implGetText() ); 193 194 if ( implIsValidIndex( nIndex, sText.getLength() ) ) 195 { 196 Locale aLocale = implGetLocale(); 197 Reference < i18n::XBreakIterator > xBreakIter = implGetBreakIterator(); 198 if ( xBreakIter.is() ) 199 { 200 rBoundary.endPos = xBreakIter->endOfSentence( sText, nIndex, aLocale ); 201 rBoundary.startPos = xBreakIter->beginOfSentence( sText, rBoundary.endPos, aLocale ); 202 } 203 } 204 else 205 { 206 rBoundary.startPos = nIndex; 207 rBoundary.endPos = nIndex; 208 } 209 } 210 211 // ----------------------------------------------------------------------------- 212 213 void OCommonAccessibleText::implGetParagraphBoundary( i18n::Boundary& rBoundary, sal_Int32 nIndex ) 214 { 215 ::rtl::OUString sText( implGetText() ); 216 217 if ( implIsValidIndex( nIndex, sText.getLength() ) ) 218 { 219 rBoundary.startPos = 0; 220 rBoundary.endPos = sText.getLength(); 221 222 sal_Int32 nFound = sText.lastIndexOf( (sal_Unicode)'\n', nIndex ); 223 if ( nFound != -1 ) 224 rBoundary.startPos = nFound + 1; 225 226 nFound = sText.indexOf( (sal_Unicode)'\n', nIndex ); 227 if ( nFound != -1 ) 228 rBoundary.endPos = nFound + 1; 229 } 230 else 231 { 232 rBoundary.startPos = nIndex; 233 rBoundary.endPos = nIndex; 234 } 235 } 236 237 // ----------------------------------------------------------------------------- 238 239 void OCommonAccessibleText::implGetLineBoundary( i18n::Boundary& rBoundary, sal_Int32 nIndex ) 240 { 241 ::rtl::OUString sText( implGetText() ); 242 sal_Int32 nLength = sText.getLength(); 243 244 if ( implIsValidIndex( nIndex, nLength ) || nIndex == nLength ) 245 { 246 rBoundary.startPos = 0; 247 rBoundary.endPos = nLength; 248 } 249 else 250 { 251 rBoundary.startPos = nIndex; 252 rBoundary.endPos = nIndex; 253 } 254 } 255 256 // ----------------------------------------------------------------------------- 257 258 sal_Unicode OCommonAccessibleText::getCharacter( sal_Int32 nIndex ) throw (IndexOutOfBoundsException, RuntimeException) 259 { 260 ::rtl::OUString sText( implGetText() ); 261 262 if ( !implIsValidIndex( nIndex, sText.getLength() ) ) 263 throw IndexOutOfBoundsException(); 264 265 return sText.getStr()[nIndex]; 266 } 267 268 // ----------------------------------------------------------------------------- 269 270 sal_Int32 OCommonAccessibleText::getCharacterCount() throw (RuntimeException) 271 { 272 return implGetText().getLength(); 273 } 274 275 // ----------------------------------------------------------------------------- 276 277 ::rtl::OUString OCommonAccessibleText::getSelectedText() throw (RuntimeException) 278 { 279 ::rtl::OUString sText; 280 sal_Int32 nStartIndex; 281 sal_Int32 nEndIndex; 282 283 implGetSelection( nStartIndex, nEndIndex ); 284 285 try 286 { 287 sText = getTextRange( nStartIndex, nEndIndex ); 288 } 289 catch ( IndexOutOfBoundsException& ) 290 { 291 } 292 293 return sText; 294 } 295 296 // ----------------------------------------------------------------------------- 297 298 sal_Int32 OCommonAccessibleText::getSelectionStart() throw (RuntimeException) 299 { 300 sal_Int32 nStartIndex; 301 sal_Int32 nEndIndex; 302 303 implGetSelection( nStartIndex, nEndIndex ); 304 305 return nStartIndex; 306 } 307 308 // ----------------------------------------------------------------------------- 309 310 sal_Int32 OCommonAccessibleText::getSelectionEnd() throw (RuntimeException) 311 { 312 sal_Int32 nStartIndex; 313 sal_Int32 nEndIndex; 314 315 implGetSelection( nStartIndex, nEndIndex ); 316 317 return nEndIndex; 318 } 319 320 // ----------------------------------------------------------------------------- 321 322 ::rtl::OUString OCommonAccessibleText::getText() throw (RuntimeException) 323 { 324 return implGetText(); 325 } 326 327 // ----------------------------------------------------------------------------- 328 329 ::rtl::OUString OCommonAccessibleText::getTextRange( sal_Int32 nStartIndex, sal_Int32 nEndIndex ) throw (IndexOutOfBoundsException, RuntimeException) 330 { 331 ::rtl::OUString sText( implGetText() ); 332 333 if ( !implIsValidRange( nStartIndex, nEndIndex, sText.getLength() ) ) 334 throw IndexOutOfBoundsException(); 335 336 sal_Int32 nMinIndex = ::std::min( nStartIndex, nEndIndex ); 337 sal_Int32 nMaxIndex = ::std::max( nStartIndex, nEndIndex ); 338 339 return sText.copy( nMinIndex, nMaxIndex - nMinIndex ); 340 } 341 342 // ----------------------------------------------------------------------------- 343 344 TextSegment OCommonAccessibleText::getTextAtIndex( sal_Int32 nIndex, sal_Int16 aTextType ) throw (IndexOutOfBoundsException, IllegalArgumentException, RuntimeException) 345 { 346 ::rtl::OUString sText( implGetText() ); 347 sal_Int32 nLength = sText.getLength(); 348 349 if ( !implIsValidIndex( nIndex, nLength ) && nIndex != nLength ) 350 throw IndexOutOfBoundsException(); 351 352 i18n::Boundary aBoundary; 353 TextSegment aResult; 354 aResult.SegmentStart = -1; 355 aResult.SegmentEnd = -1; 356 357 switch ( aTextType ) 358 { 359 case AccessibleTextType::CHARACTER: 360 { 361 if ( implIsValidIndex( nIndex, nLength ) ) 362 { 363 aResult.SegmentText = sText.copy( nIndex, 1 ); 364 aResult.SegmentStart = nIndex; 365 aResult.SegmentEnd = nIndex+1; 366 } 367 } 368 break; 369 case AccessibleTextType::GLYPH: 370 { 371 // get glyph at index 372 implGetGlyphBoundary( aBoundary, nIndex ); 373 if ( implIsValidBoundary( aBoundary, nLength ) ) 374 { 375 aResult.SegmentText = sText.copy( aBoundary.startPos, aBoundary.endPos - aBoundary.startPos ); 376 aResult.SegmentStart = aBoundary.startPos; 377 aResult.SegmentEnd = aBoundary.endPos; 378 } 379 } 380 break; 381 case AccessibleTextType::WORD: 382 { 383 // get word at index 384 sal_Bool bWord = implGetWordBoundary( aBoundary, nIndex ); 385 if ( bWord && implIsValidBoundary( aBoundary, nLength ) ) 386 { 387 aResult.SegmentText = sText.copy( aBoundary.startPos, aBoundary.endPos - aBoundary.startPos ); 388 aResult.SegmentStart = aBoundary.startPos; 389 aResult.SegmentEnd = aBoundary.endPos; 390 } 391 } 392 break; 393 case AccessibleTextType::SENTENCE: 394 { 395 // get sentence at index 396 implGetSentenceBoundary( aBoundary, nIndex ); 397 if ( implIsValidBoundary( aBoundary, nLength ) ) 398 { 399 aResult.SegmentText = sText.copy( aBoundary.startPos, aBoundary.endPos - aBoundary.startPos ); 400 aResult.SegmentStart = aBoundary.startPos; 401 aResult.SegmentEnd = aBoundary.endPos; 402 } 403 } 404 break; 405 case AccessibleTextType::PARAGRAPH: 406 { 407 // get paragraph at index 408 implGetParagraphBoundary( aBoundary, nIndex ); 409 if ( implIsValidBoundary( aBoundary, nLength ) ) 410 { 411 aResult.SegmentText = sText.copy( aBoundary.startPos, aBoundary.endPos - aBoundary.startPos ); 412 aResult.SegmentStart = aBoundary.startPos; 413 aResult.SegmentEnd = aBoundary.endPos; 414 } 415 } 416 break; 417 case AccessibleTextType::LINE: 418 { 419 // get line at index 420 implGetLineBoundary( aBoundary, nIndex ); 421 if ( implIsValidBoundary( aBoundary, nLength ) ) 422 { 423 aResult.SegmentText = sText.copy( aBoundary.startPos, aBoundary.endPos - aBoundary.startPos ); 424 aResult.SegmentStart = aBoundary.startPos; 425 aResult.SegmentEnd = aBoundary.endPos; 426 } 427 } 428 break; 429 case AccessibleTextType::ATTRIBUTE_RUN: 430 { 431 // TODO: implGetAttributeRunBoundary() (incompatible!) 432 433 aResult.SegmentText = sText; 434 aResult.SegmentStart = 0; 435 aResult.SegmentEnd = nLength; 436 } 437 break; 438 default: 439 { 440 // unknown text type 441 } 442 } 443 444 return aResult; 445 } 446 447 // ----------------------------------------------------------------------------- 448 449 TextSegment OCommonAccessibleText::getTextBeforeIndex( sal_Int32 nIndex, sal_Int16 aTextType ) throw (IndexOutOfBoundsException, IllegalArgumentException, RuntimeException) 450 { 451 ::rtl::OUString sText( implGetText() ); 452 sal_Int32 nLength = sText.getLength(); 453 454 if ( !implIsValidIndex( nIndex, nLength ) && nIndex != nLength ) 455 throw IndexOutOfBoundsException(); 456 457 i18n::Boundary aBoundary; 458 TextSegment aResult; 459 aResult.SegmentStart = -1; 460 aResult.SegmentEnd = -1; 461 462 switch ( aTextType ) 463 { 464 case AccessibleTextType::CHARACTER: 465 { 466 if ( implIsValidIndex( nIndex - 1, nLength ) ) 467 { 468 aResult.SegmentText = sText.copy( nIndex - 1, 1 ); 469 aResult.SegmentStart = nIndex-1; 470 aResult.SegmentEnd = nIndex; 471 } 472 } 473 break; 474 case AccessibleTextType::GLYPH: 475 { 476 // get glyph at index 477 implGetGlyphBoundary( aBoundary, nIndex ); 478 // get previous glyph 479 if ( aBoundary.startPos > 0 ) 480 { 481 implGetGlyphBoundary( aBoundary, aBoundary.startPos - 1 ); 482 if ( implIsValidBoundary( aBoundary, nLength ) ) 483 { 484 aResult.SegmentText = sText.copy( aBoundary.startPos, aBoundary.endPos - aBoundary.startPos ); 485 aResult.SegmentStart = aBoundary.startPos; 486 aResult.SegmentEnd = aBoundary.endPos; 487 } 488 } 489 } 490 break; 491 case AccessibleTextType::WORD: 492 { 493 // get word at index 494 implGetWordBoundary( aBoundary, nIndex ); 495 // get previous word 496 sal_Bool bWord = sal_False; 497 while ( !bWord && aBoundary.startPos > 0 ) 498 bWord = implGetWordBoundary( aBoundary, aBoundary.startPos - 1 ); 499 if ( bWord && implIsValidBoundary( aBoundary, nLength ) ) 500 { 501 aResult.SegmentText = sText.copy( aBoundary.startPos, aBoundary.endPos - aBoundary.startPos ); 502 aResult.SegmentStart = aBoundary.startPos; 503 aResult.SegmentEnd = aBoundary.endPos; 504 } 505 } 506 break; 507 case AccessibleTextType::SENTENCE: 508 { 509 // get sentence at index 510 implGetSentenceBoundary( aBoundary, nIndex ); 511 // get previous sentence 512 if ( aBoundary.startPos > 0 ) 513 { 514 implGetSentenceBoundary( aBoundary, aBoundary.startPos - 1 ); 515 if ( implIsValidBoundary( aBoundary, nLength ) ) 516 { 517 aResult.SegmentText = sText.copy( aBoundary.startPos, aBoundary.endPos - aBoundary.startPos ); 518 aResult.SegmentStart = aBoundary.startPos; 519 aResult.SegmentEnd = aBoundary.endPos; 520 } 521 } 522 } 523 break; 524 case AccessibleTextType::PARAGRAPH: 525 { 526 // get paragraph at index 527 implGetParagraphBoundary( aBoundary, nIndex ); 528 // get previous paragraph 529 if ( aBoundary.startPos > 0 ) 530 { 531 implGetParagraphBoundary( aBoundary, aBoundary.startPos - 1 ); 532 if ( implIsValidBoundary( aBoundary, nLength ) ) 533 { 534 aResult.SegmentText = sText.copy( aBoundary.startPos, aBoundary.endPos - aBoundary.startPos ); 535 aResult.SegmentStart = aBoundary.startPos; 536 aResult.SegmentEnd = aBoundary.endPos; 537 } 538 } 539 } 540 break; 541 case AccessibleTextType::LINE: 542 { 543 // get line at index 544 implGetLineBoundary( aBoundary, nIndex ); 545 // get previous line 546 if ( aBoundary.startPos > 0 ) 547 { 548 implGetLineBoundary( aBoundary, aBoundary.startPos - 1 ); 549 if ( implIsValidBoundary( aBoundary, nLength ) ) 550 { 551 aResult.SegmentText = sText.copy( aBoundary.startPos, aBoundary.endPos - aBoundary.startPos ); 552 aResult.SegmentStart = aBoundary.startPos; 553 aResult.SegmentEnd = aBoundary.endPos; 554 } 555 } 556 } 557 break; 558 case AccessibleTextType::ATTRIBUTE_RUN: 559 { 560 // TODO: implGetAttributeRunBoundary() (incompatible!) 561 } 562 break; 563 default: 564 { 565 // unknown text type 566 } 567 } 568 569 return aResult; 570 } 571 572 // ----------------------------------------------------------------------------- 573 574 TextSegment OCommonAccessibleText::getTextBehindIndex( sal_Int32 nIndex, sal_Int16 aTextType ) throw (IndexOutOfBoundsException, IllegalArgumentException, RuntimeException) 575 { 576 ::rtl::OUString sText( implGetText() ); 577 sal_Int32 nLength = sText.getLength(); 578 579 if ( !implIsValidIndex( nIndex, nLength ) && nIndex != nLength ) 580 throw IndexOutOfBoundsException(); 581 582 i18n::Boundary aBoundary; 583 TextSegment aResult; 584 aResult.SegmentStart = -1; 585 aResult.SegmentEnd = -1; 586 587 switch ( aTextType ) 588 { 589 case AccessibleTextType::CHARACTER: 590 { 591 if ( implIsValidIndex( nIndex + 1, nLength ) ) 592 { 593 aResult.SegmentText = sText.copy( nIndex + 1, 1 ); 594 aResult.SegmentStart = nIndex+1; 595 aResult.SegmentEnd = nIndex+2; 596 } 597 } 598 break; 599 case AccessibleTextType::GLYPH: 600 { 601 // get glyph at index 602 implGetGlyphBoundary( aBoundary, nIndex ); 603 // get next glyph 604 if ( aBoundary.endPos < nLength ) 605 { 606 implGetGlyphBoundary( aBoundary, aBoundary.endPos ); 607 if ( implIsValidBoundary( aBoundary, nLength ) ) 608 { 609 aResult.SegmentText = sText.copy( aBoundary.startPos, aBoundary.endPos - aBoundary.startPos ); 610 aResult.SegmentStart = aBoundary.startPos; 611 aResult.SegmentEnd = aBoundary.endPos; 612 } 613 } 614 } 615 break; 616 case AccessibleTextType::WORD: 617 { 618 // get word at index 619 implGetWordBoundary( aBoundary, nIndex ); 620 // get next word 621 sal_Bool bWord = sal_False; 622 while ( !bWord && aBoundary.endPos < nLength ) 623 bWord = implGetWordBoundary( aBoundary, aBoundary.endPos ); 624 if ( bWord && implIsValidBoundary( aBoundary, nLength ) ) 625 { 626 aResult.SegmentText = sText.copy( aBoundary.startPos, aBoundary.endPos - aBoundary.startPos ); 627 aResult.SegmentStart = aBoundary.startPos; 628 aResult.SegmentEnd = aBoundary.endPos; 629 } 630 } 631 break; 632 case AccessibleTextType::SENTENCE: 633 { 634 // get sentence at index 635 implGetSentenceBoundary( aBoundary, nIndex ); 636 // get next sentence 637 sal_Int32 nEnd = aBoundary.endPos; 638 sal_Int32 nI = aBoundary.endPos; 639 sal_Bool bFound = sal_False; 640 while ( !bFound && ++nI < nLength ) 641 { 642 implGetSentenceBoundary( aBoundary, nI ); 643 bFound = ( aBoundary.endPos > nEnd ); 644 } 645 if ( bFound && implIsValidBoundary( aBoundary, nLength ) ) 646 { 647 aResult.SegmentText = sText.copy( aBoundary.startPos, aBoundary.endPos - aBoundary.startPos ); 648 aResult.SegmentStart = aBoundary.startPos; 649 aResult.SegmentEnd = aBoundary.endPos; 650 } 651 } 652 break; 653 case AccessibleTextType::PARAGRAPH: 654 { 655 // get paragraph at index 656 implGetParagraphBoundary( aBoundary, nIndex ); 657 // get next paragraph 658 if ( aBoundary.endPos < nLength ) 659 { 660 implGetParagraphBoundary( aBoundary, aBoundary.endPos ); 661 if ( implIsValidBoundary( aBoundary, nLength ) ) 662 { 663 aResult.SegmentText = sText.copy( aBoundary.startPos, aBoundary.endPos - aBoundary.startPos ); 664 aResult.SegmentStart = aBoundary.startPos; 665 aResult.SegmentEnd = aBoundary.endPos; 666 } 667 } 668 } 669 break; 670 case AccessibleTextType::LINE: 671 { 672 // get line at index 673 implGetLineBoundary( aBoundary, nIndex ); 674 // get next line 675 if ( aBoundary.endPos < nLength ) 676 { 677 implGetLineBoundary( aBoundary, aBoundary.endPos ); 678 if ( implIsValidBoundary( aBoundary, nLength ) ) 679 { 680 aResult.SegmentText = sText.copy( aBoundary.startPos, aBoundary.endPos - aBoundary.startPos ); 681 aResult.SegmentStart = aBoundary.startPos; 682 aResult.SegmentEnd = aBoundary.endPos; 683 } 684 } 685 } 686 break; 687 case AccessibleTextType::ATTRIBUTE_RUN: 688 { 689 // TODO: implGetAttributeRunBoundary() (incompatible!) 690 } 691 break; 692 default: 693 { 694 // unknown text type 695 } 696 } 697 698 return aResult; 699 } 700 701 // ----------------------------------------------------------------------------- 702 bool OCommonAccessibleText::implInitTextChangedEvent( 703 const rtl::OUString& rOldString, 704 const rtl::OUString& rNewString, 705 ::com::sun::star::uno::Any& rDeleted, 706 ::com::sun::star::uno::Any& rInserted) // throw() 707 { 708 sal_uInt32 nLenOld = rOldString.getLength(); 709 sal_uInt32 nLenNew = rNewString.getLength(); 710 711 // equal 712 if ((0 == nLenOld) && (0 == nLenNew)) 713 return false; 714 715 TextSegment aDeletedText; 716 TextSegment aInsertedText; 717 718 aDeletedText.SegmentStart = -1; 719 aDeletedText.SegmentEnd = -1; 720 aInsertedText.SegmentStart = -1; 721 aInsertedText.SegmentEnd = -1; 722 723 // insert only 724 if ((0 == nLenOld) && (nLenNew > 0)) 725 { 726 aInsertedText.SegmentStart = 0; 727 aInsertedText.SegmentEnd = nLenNew; 728 aInsertedText.SegmentText = rNewString.copy( aInsertedText.SegmentStart, aInsertedText.SegmentEnd - aInsertedText.SegmentStart ); 729 730 rInserted <<= aInsertedText; 731 return true; 732 } 733 734 // delete only 735 if ((nLenOld > 0) && (0 == nLenNew)) 736 { 737 aDeletedText.SegmentStart = 0; 738 aDeletedText.SegmentEnd = nLenOld; 739 aDeletedText.SegmentText = rOldString.copy( aDeletedText.SegmentStart, aDeletedText.SegmentEnd - aDeletedText.SegmentStart ); 740 741 rDeleted <<= aDeletedText; 742 return true; 743 } 744 745 const sal_Unicode* pFirstDiffOld = rOldString.getStr(); 746 const sal_Unicode* pLastDiffOld = rOldString.getStr() + nLenOld; 747 const sal_Unicode* pFirstDiffNew = rNewString.getStr(); 748 const sal_Unicode* pLastDiffNew = rNewString.getStr() + nLenNew; 749 750 // find first difference 751 while ((*pFirstDiffOld == *pFirstDiffNew) && 752 (pFirstDiffOld < pLastDiffOld) && 753 (pFirstDiffNew < pLastDiffNew)) 754 { 755 pFirstDiffOld++; 756 pFirstDiffNew++; 757 } 758 759 // equality test 760 if ((0 == *pFirstDiffOld) && (0 == *pFirstDiffNew)) 761 return false; 762 763 // find last difference 764 while ( ( pLastDiffOld > pFirstDiffOld) && 765 ( pLastDiffNew > pFirstDiffNew) && 766 (pLastDiffOld[-1] == pLastDiffNew[-1])) 767 { 768 pLastDiffOld--; 769 pLastDiffNew--; 770 } 771 772 if (pFirstDiffOld < pLastDiffOld) 773 { 774 aDeletedText.SegmentStart = pFirstDiffOld - rOldString.getStr(); 775 aDeletedText.SegmentEnd = pLastDiffOld - rOldString.getStr(); 776 aDeletedText.SegmentText = rOldString.copy( aDeletedText.SegmentStart, aDeletedText.SegmentEnd - aDeletedText.SegmentStart ); 777 778 rDeleted <<= aDeletedText; 779 } 780 781 if (pFirstDiffNew < pLastDiffNew) 782 { 783 aInsertedText.SegmentStart = pFirstDiffNew - rNewString.getStr(); 784 aInsertedText.SegmentEnd = pLastDiffNew - rNewString.getStr(); 785 aInsertedText.SegmentText = rNewString.copy( aInsertedText.SegmentStart, aInsertedText.SegmentEnd - aInsertedText.SegmentStart ); 786 787 rInserted <<= aInsertedText; 788 } 789 return true; 790 } 791 792 //============================================================================== 793 // OAccessibleTextHelper 794 //============================================================================== 795 796 OAccessibleTextHelper::OAccessibleTextHelper() 797 { 798 } 799 800 // ----------------------------------------------------------------------------- 801 802 OAccessibleTextHelper::OAccessibleTextHelper( IMutex* _pExternalLock ) 803 :OAccessibleExtendedComponentHelper( _pExternalLock ) 804 { 805 } 806 807 // ----------------------------------------------------------------------------- 808 // XInterface 809 // ----------------------------------------------------------------------------- 810 811 IMPLEMENT_FORWARD_XINTERFACE2( OAccessibleTextHelper, OAccessibleExtendedComponentHelper, OAccessibleTextHelper_Base ) 812 813 // ----------------------------------------------------------------------------- 814 // XTypeProvider 815 // ----------------------------------------------------------------------------- 816 817 IMPLEMENT_FORWARD_XTYPEPROVIDER2( OAccessibleTextHelper, OAccessibleExtendedComponentHelper, OAccessibleTextHelper_Base ) 818 819 // ----------------------------------------------------------------------------- 820 // XAccessibleText 821 // ----------------------------------------------------------------------------- 822 823 sal_Unicode OAccessibleTextHelper::getCharacter( sal_Int32 nIndex ) throw (IndexOutOfBoundsException, RuntimeException) 824 { 825 OExternalLockGuard aGuard( this ); 826 827 return OCommonAccessibleText::getCharacter( nIndex ); 828 } 829 830 // ----------------------------------------------------------------------------- 831 832 sal_Int32 OAccessibleTextHelper::getCharacterCount() throw (RuntimeException) 833 { 834 OExternalLockGuard aGuard( this ); 835 836 return OCommonAccessibleText::getCharacterCount(); 837 } 838 839 // ----------------------------------------------------------------------------- 840 841 ::rtl::OUString OAccessibleTextHelper::getSelectedText() throw (RuntimeException) 842 { 843 OExternalLockGuard aGuard( this ); 844 845 return OCommonAccessibleText::getSelectedText(); 846 } 847 848 // ----------------------------------------------------------------------------- 849 850 sal_Int32 OAccessibleTextHelper::getSelectionStart() throw (RuntimeException) 851 { 852 OExternalLockGuard aGuard( this ); 853 854 return OCommonAccessibleText::getSelectionStart(); 855 } 856 857 // ----------------------------------------------------------------------------- 858 859 sal_Int32 OAccessibleTextHelper::getSelectionEnd() throw (RuntimeException) 860 { 861 OExternalLockGuard aGuard( this ); 862 863 return OCommonAccessibleText::getSelectionEnd(); 864 } 865 866 // ----------------------------------------------------------------------------- 867 868 ::rtl::OUString OAccessibleTextHelper::getText() throw (RuntimeException) 869 { 870 OExternalLockGuard aGuard( this ); 871 872 return OCommonAccessibleText::getText(); 873 } 874 875 // ----------------------------------------------------------------------------- 876 877 ::rtl::OUString OAccessibleTextHelper::getTextRange( sal_Int32 nStartIndex, sal_Int32 nEndIndex ) throw (IndexOutOfBoundsException, RuntimeException) 878 { 879 OExternalLockGuard aGuard( this ); 880 881 return OCommonAccessibleText::getTextRange( nStartIndex, nEndIndex ); 882 } 883 884 // ----------------------------------------------------------------------------- 885 886 TextSegment OAccessibleTextHelper::getTextAtIndex( sal_Int32 nIndex, sal_Int16 aTextType ) throw (IndexOutOfBoundsException, IllegalArgumentException, RuntimeException) 887 { 888 OExternalLockGuard aGuard( this ); 889 890 return OCommonAccessibleText::getTextAtIndex( nIndex, aTextType ); 891 } 892 893 // ----------------------------------------------------------------------------- 894 895 TextSegment OAccessibleTextHelper::getTextBeforeIndex( sal_Int32 nIndex, sal_Int16 aTextType ) throw (IndexOutOfBoundsException, IllegalArgumentException, RuntimeException) 896 { 897 OExternalLockGuard aGuard( this ); 898 899 return OCommonAccessibleText::getTextBeforeIndex( nIndex, aTextType ); 900 } 901 902 // ----------------------------------------------------------------------------- 903 904 TextSegment OAccessibleTextHelper::getTextBehindIndex( sal_Int32 nIndex, sal_Int16 aTextType ) throw (IndexOutOfBoundsException, IllegalArgumentException, RuntimeException) 905 { 906 OExternalLockGuard aGuard( this ); 907 908 return OCommonAccessibleText::getTextBehindIndex( nIndex, aTextType ); 909 } 910 911 // ----------------------------------------------------------------------------- 912 913 //.............................................................................. 914 } // namespace comphelper 915 //.............................................................................. 916