1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ 2 /* 3 * This file is part of the LibreOffice project. 4 * 5 * This Source Code Form is subject to the terms of the Mozilla Public 6 * License, v. 2.0. If a copy of the MPL was not distributed with this 7 * file, You can obtain one at http://mozilla.org/MPL/2.0/. 8 * 9 * This file incorporates work covered by the following license notice: 10 * 11 * Licensed to the Apache Software Foundation (ASF) under one or more 12 * contributor license agreements. See the NOTICE file distributed 13 * with this work for additional information regarding copyright 14 * ownership. The ASF licenses this file to you under the Apache 15 * License, Version 2.0 (the "License"); you may not use this file 16 * except in compliance with the License. You may obtain a copy of 17 * the License at http://www.apache.org/licenses/LICENSE-2.0 . 18 */ 19 20 #include <comphelper/accessibletexthelper.hxx> 21 #include <com/sun/star/accessibility/AccessibleTextType.hpp> 22 #include <com/sun/star/i18n/BreakIterator.hpp> 23 #include <com/sun/star/i18n/CharacterIteratorMode.hpp> 24 #include <com/sun/star/i18n/CharacterClassification.hpp> 25 #include <com/sun/star/i18n/WordType.hpp> 26 #include <com/sun/star/i18n/KCharacterType.hpp> 27 #include <com/sun/star/lang/IndexOutOfBoundsException.hpp> 28 #include <comphelper/processfactory.hxx> 29 #include <com/sun/star/accessibility/TextSegment.hpp> 30 31 #include <algorithm> 32 33 34 namespace comphelper 35 { 36 37 38 using namespace ::com::sun::star; 39 using namespace ::com::sun::star::uno; 40 using namespace ::com::sun::star::lang; 41 using namespace ::com::sun::star::beans; 42 using namespace ::com::sun::star::accessibility; 43 44 45 // OCommonAccessibleText 46 47 OCommonAccessibleText()48 OCommonAccessibleText::OCommonAccessibleText() 49 { 50 } 51 52 ~OCommonAccessibleText()53 OCommonAccessibleText::~OCommonAccessibleText() 54 { 55 } 56 57 implGetBreakIterator()58 Reference < i18n::XBreakIterator > const & OCommonAccessibleText::implGetBreakIterator() 59 { 60 if ( !m_xBreakIter.is() ) 61 { 62 Reference< uno::XComponentContext > xContext = ::comphelper::getProcessComponentContext(); 63 m_xBreakIter = i18n::BreakIterator::create(xContext); 64 } 65 66 return m_xBreakIter; 67 } 68 69 implGetCharacterClassification()70 Reference < i18n::XCharacterClassification > const & OCommonAccessibleText::implGetCharacterClassification() 71 { 72 if ( !m_xCharClass.is() ) 73 { 74 m_xCharClass = i18n::CharacterClassification::create( ::comphelper::getProcessComponentContext() ); 75 } 76 77 return m_xCharClass; 78 } 79 80 implIsValidBoundary(i18n::Boundary const & rBoundary,sal_Int32 nLength)81 bool OCommonAccessibleText::implIsValidBoundary( i18n::Boundary const & rBoundary, sal_Int32 nLength ) 82 { 83 return ( rBoundary.startPos >= 0 ) && ( rBoundary.startPos < nLength ) && ( rBoundary.endPos >= 0 ) && ( rBoundary.endPos <= nLength ); 84 } 85 86 implIsValidIndex(sal_Int32 nIndex,sal_Int32 nLength)87 bool OCommonAccessibleText::implIsValidIndex( sal_Int32 nIndex, sal_Int32 nLength ) 88 { 89 return ( nIndex >= 0 ) && ( nIndex < nLength ); 90 } 91 92 implIsValidRange(sal_Int32 nStartIndex,sal_Int32 nEndIndex,sal_Int32 nLength)93 bool OCommonAccessibleText::implIsValidRange( sal_Int32 nStartIndex, sal_Int32 nEndIndex, sal_Int32 nLength ) 94 { 95 return ( nStartIndex >= 0 ) && ( nStartIndex <= nLength ) && ( nEndIndex >= 0 ) && ( nEndIndex <= nLength ); 96 } 97 98 implGetGlyphBoundary(const OUString & rText,i18n::Boundary & rBoundary,sal_Int32 nIndex)99 void OCommonAccessibleText::implGetGlyphBoundary( const OUString& rText, i18n::Boundary& rBoundary, sal_Int32 nIndex ) 100 { 101 if ( implIsValidIndex( nIndex, rText.getLength() ) ) 102 { 103 Reference < i18n::XBreakIterator > xBreakIter = implGetBreakIterator(); 104 if ( xBreakIter.is() ) 105 { 106 sal_Int32 nCount = 1; 107 sal_Int32 nDone; 108 sal_Int32 nStartIndex = xBreakIter->previousCharacters( rText, nIndex, implGetLocale(), i18n::CharacterIteratorMode::SKIPCELL, nCount, nDone ); 109 if ( nDone != 0 ) 110 nStartIndex = xBreakIter->nextCharacters( rText, nStartIndex, implGetLocale(), i18n::CharacterIteratorMode::SKIPCELL, nCount, nDone ); 111 sal_Int32 nEndIndex = xBreakIter->nextCharacters( rText, nStartIndex, implGetLocale(), i18n::CharacterIteratorMode::SKIPCELL, nCount, nDone ); 112 if ( nDone != 0 ) 113 { 114 rBoundary.startPos = nStartIndex; 115 rBoundary.endPos = nEndIndex; 116 } 117 } 118 } 119 else 120 { 121 rBoundary.startPos = nIndex; 122 rBoundary.endPos = nIndex; 123 } 124 } 125 126 implGetWordBoundary(const OUString & rText,i18n::Boundary & rBoundary,sal_Int32 nIndex)127 bool OCommonAccessibleText::implGetWordBoundary( const OUString& rText, i18n::Boundary& rBoundary, sal_Int32 nIndex ) 128 { 129 bool bWord = false; 130 131 if ( implIsValidIndex( nIndex, rText.getLength() ) ) 132 { 133 Reference < i18n::XBreakIterator > xBreakIter = implGetBreakIterator(); 134 if ( xBreakIter.is() ) 135 { 136 rBoundary = xBreakIter->getWordBoundary( rText, nIndex, implGetLocale(), i18n::WordType::ANY_WORD, true ); 137 138 // it's a word, if the first character is an alpha-numeric character 139 Reference< i18n::XCharacterClassification > xCharClass = implGetCharacterClassification(); 140 if ( xCharClass.is() ) 141 { 142 sal_Int32 nType = xCharClass->getCharacterType( rText, rBoundary.startPos, implGetLocale() ); 143 if ( ( nType & ( i18n::KCharacterType::LETTER | i18n::KCharacterType::DIGIT ) ) != 0 ) 144 bWord = true; 145 } 146 } 147 } 148 else 149 { 150 rBoundary.startPos = nIndex; 151 rBoundary.endPos = nIndex; 152 } 153 154 return bWord; 155 } 156 157 implGetSentenceBoundary(const OUString & rText,i18n::Boundary & rBoundary,sal_Int32 nIndex)158 void OCommonAccessibleText::implGetSentenceBoundary( const OUString& rText, i18n::Boundary& rBoundary, sal_Int32 nIndex ) 159 { 160 if ( implIsValidIndex( nIndex, rText.getLength() ) ) 161 { 162 Locale aLocale = implGetLocale(); 163 Reference < i18n::XBreakIterator > xBreakIter = implGetBreakIterator(); 164 if ( xBreakIter.is() ) 165 { 166 rBoundary.endPos = xBreakIter->endOfSentence( rText, nIndex, aLocale ); 167 rBoundary.startPos = xBreakIter->beginOfSentence( rText, rBoundary.endPos, aLocale ); 168 } 169 } 170 else 171 { 172 rBoundary.startPos = nIndex; 173 rBoundary.endPos = nIndex; 174 } 175 } 176 177 implGetParagraphBoundary(const OUString & rText,i18n::Boundary & rBoundary,sal_Int32 nIndex)178 void OCommonAccessibleText::implGetParagraphBoundary( const OUString& rText, i18n::Boundary& rBoundary, sal_Int32 nIndex ) 179 { 180 if ( implIsValidIndex( nIndex, rText.getLength() ) ) 181 { 182 rBoundary.startPos = 0; 183 rBoundary.endPos = rText.getLength(); 184 185 sal_Int32 nFound = rText.lastIndexOf( '\n', nIndex ); 186 if ( nFound != -1 ) 187 rBoundary.startPos = nFound + 1; 188 189 nFound = rText.indexOf( '\n', nIndex ); 190 if ( nFound != -1 ) 191 rBoundary.endPos = nFound + 1; 192 } 193 else 194 { 195 rBoundary.startPos = nIndex; 196 rBoundary.endPos = nIndex; 197 } 198 } 199 200 implGetLineBoundary(const OUString & rText,i18n::Boundary & rBoundary,sal_Int32 nIndex)201 void OCommonAccessibleText::implGetLineBoundary( const OUString& rText, i18n::Boundary& rBoundary, sal_Int32 nIndex ) 202 { 203 sal_Int32 nLength = rText.getLength(); 204 205 if ( implIsValidIndex( nIndex, nLength ) || nIndex == nLength ) 206 { 207 rBoundary.startPos = 0; 208 rBoundary.endPos = nLength; 209 } 210 else 211 { 212 rBoundary.startPos = nIndex; 213 rBoundary.endPos = nIndex; 214 } 215 } 216 217 implGetCharacter(const OUString & rText,sal_Int32 nIndex)218 sal_Unicode OCommonAccessibleText::implGetCharacter( const OUString& rText, sal_Int32 nIndex ) 219 { 220 if ( !implIsValidIndex( nIndex, rText.getLength() ) ) 221 throw IndexOutOfBoundsException(); 222 223 return rText[nIndex]; 224 } 225 getSelectedText()226 OUString OCommonAccessibleText::getSelectedText() 227 { 228 OUString sText; 229 sal_Int32 nStartIndex; 230 sal_Int32 nEndIndex; 231 232 implGetSelection( nStartIndex, nEndIndex ); 233 234 try 235 { 236 sText = implGetTextRange( implGetText(), nStartIndex, nEndIndex ); 237 } 238 catch ( IndexOutOfBoundsException& ) 239 { 240 } 241 242 return sText; 243 } 244 245 getSelectionStart()246 sal_Int32 OCommonAccessibleText::getSelectionStart() 247 { 248 sal_Int32 nStartIndex; 249 sal_Int32 nEndIndex; 250 251 implGetSelection( nStartIndex, nEndIndex ); 252 253 return nStartIndex; 254 } 255 256 getSelectionEnd()257 sal_Int32 OCommonAccessibleText::getSelectionEnd() 258 { 259 sal_Int32 nStartIndex; 260 sal_Int32 nEndIndex; 261 262 implGetSelection( nStartIndex, nEndIndex ); 263 264 return nEndIndex; 265 } 266 267 implGetTextRange(const OUString & rText,sal_Int32 nStartIndex,sal_Int32 nEndIndex)268 OUString OCommonAccessibleText::implGetTextRange( const OUString& rText, sal_Int32 nStartIndex, sal_Int32 nEndIndex ) 269 { 270 271 if ( !implIsValidRange( nStartIndex, nEndIndex, rText.getLength() ) ) 272 throw IndexOutOfBoundsException(); 273 274 sal_Int32 nMinIndex = std::min( nStartIndex, nEndIndex ); 275 sal_Int32 nMaxIndex = std::max( nStartIndex, nEndIndex ); 276 277 return rText.copy( nMinIndex, nMaxIndex - nMinIndex ); 278 } 279 getTextAtIndex(sal_Int32 nIndex,sal_Int16 aTextType)280 TextSegment OCommonAccessibleText::getTextAtIndex( sal_Int32 nIndex, sal_Int16 aTextType ) 281 { 282 OUString sText( implGetText() ); 283 sal_Int32 nLength = sText.getLength(); 284 285 if ( !implIsValidIndex( nIndex, nLength ) && nIndex != nLength ) 286 throw IndexOutOfBoundsException(); 287 288 i18n::Boundary aBoundary; 289 TextSegment aResult; 290 aResult.SegmentStart = -1; 291 aResult.SegmentEnd = -1; 292 293 switch ( aTextType ) 294 { 295 case AccessibleTextType::CHARACTER: 296 { 297 if ( implIsValidIndex( nIndex, nLength ) ) 298 { 299 aResult.SegmentText = sText.copy( nIndex, 1 ); 300 aResult.SegmentStart = nIndex; 301 aResult.SegmentEnd = nIndex+1; 302 } 303 } 304 break; 305 case AccessibleTextType::GLYPH: 306 { 307 // get glyph at index 308 implGetGlyphBoundary( sText, aBoundary, nIndex ); 309 if ( implIsValidBoundary( aBoundary, nLength ) ) 310 { 311 aResult.SegmentText = sText.copy( aBoundary.startPos, aBoundary.endPos - aBoundary.startPos ); 312 aResult.SegmentStart = aBoundary.startPos; 313 aResult.SegmentEnd = aBoundary.endPos; 314 } 315 } 316 break; 317 case AccessibleTextType::WORD: 318 { 319 // get word at index 320 bool bWord = implGetWordBoundary( sText, aBoundary, nIndex ); 321 if ( bWord && implIsValidBoundary( aBoundary, nLength ) ) 322 { 323 aResult.SegmentText = sText.copy( aBoundary.startPos, aBoundary.endPos - aBoundary.startPos ); 324 aResult.SegmentStart = aBoundary.startPos; 325 aResult.SegmentEnd = aBoundary.endPos; 326 } 327 } 328 break; 329 case AccessibleTextType::SENTENCE: 330 { 331 // get sentence at index 332 implGetSentenceBoundary( sText, aBoundary, nIndex ); 333 if ( implIsValidBoundary( aBoundary, nLength ) ) 334 { 335 aResult.SegmentText = sText.copy( aBoundary.startPos, aBoundary.endPos - aBoundary.startPos ); 336 aResult.SegmentStart = aBoundary.startPos; 337 aResult.SegmentEnd = aBoundary.endPos; 338 } 339 } 340 break; 341 case AccessibleTextType::PARAGRAPH: 342 { 343 // get paragraph at index 344 implGetParagraphBoundary( sText, aBoundary, nIndex ); 345 if ( implIsValidBoundary( aBoundary, nLength ) ) 346 { 347 aResult.SegmentText = sText.copy( aBoundary.startPos, aBoundary.endPos - aBoundary.startPos ); 348 aResult.SegmentStart = aBoundary.startPos; 349 aResult.SegmentEnd = aBoundary.endPos; 350 } 351 } 352 break; 353 case AccessibleTextType::LINE: 354 { 355 // get line at index 356 implGetLineBoundary( sText, aBoundary, nIndex ); 357 if ( implIsValidBoundary( aBoundary, nLength ) ) 358 { 359 aResult.SegmentText = sText.copy( aBoundary.startPos, aBoundary.endPos - aBoundary.startPos ); 360 aResult.SegmentStart = aBoundary.startPos; 361 aResult.SegmentEnd = aBoundary.endPos; 362 } 363 } 364 break; 365 case AccessibleTextType::ATTRIBUTE_RUN: 366 { 367 // TODO: implGetAttributeRunBoundary() (incompatible!) 368 369 aResult.SegmentText = sText; 370 aResult.SegmentStart = 0; 371 aResult.SegmentEnd = nLength; 372 } 373 break; 374 default: 375 { 376 // unknown text type 377 } 378 } 379 380 return aResult; 381 } 382 383 getTextBeforeIndex(sal_Int32 nIndex,sal_Int16 aTextType)384 TextSegment OCommonAccessibleText::getTextBeforeIndex( sal_Int32 nIndex, sal_Int16 aTextType ) 385 { 386 OUString sText( implGetText() ); 387 sal_Int32 nLength = sText.getLength(); 388 389 if ( !implIsValidIndex( nIndex, nLength ) && nIndex != nLength ) 390 throw IndexOutOfBoundsException(); 391 392 i18n::Boundary aBoundary; 393 TextSegment aResult; 394 aResult.SegmentStart = -1; 395 aResult.SegmentEnd = -1; 396 397 switch ( aTextType ) 398 { 399 case AccessibleTextType::CHARACTER: 400 { 401 if ( implIsValidIndex( nIndex - 1, nLength ) ) 402 { 403 aResult.SegmentText = sText.copy( nIndex - 1, 1 ); 404 aResult.SegmentStart = nIndex-1; 405 aResult.SegmentEnd = nIndex; 406 } 407 } 408 break; 409 case AccessibleTextType::GLYPH: 410 { 411 // get glyph at index 412 implGetGlyphBoundary( sText, aBoundary, nIndex ); 413 // get previous glyph 414 if ( aBoundary.startPos > 0 ) 415 { 416 implGetGlyphBoundary( sText, aBoundary, aBoundary.startPos - 1 ); 417 if ( implIsValidBoundary( aBoundary, nLength ) ) 418 { 419 aResult.SegmentText = sText.copy( aBoundary.startPos, aBoundary.endPos - aBoundary.startPos ); 420 aResult.SegmentStart = aBoundary.startPos; 421 aResult.SegmentEnd = aBoundary.endPos; 422 } 423 } 424 } 425 break; 426 case AccessibleTextType::WORD: 427 { 428 // get word at index 429 implGetWordBoundary( sText, aBoundary, nIndex ); 430 // get previous word 431 bool bWord = false; 432 while ( !bWord && aBoundary.startPos > 0 ) 433 bWord = implGetWordBoundary( sText, aBoundary, aBoundary.startPos - 1 ); 434 if ( bWord && implIsValidBoundary( aBoundary, nLength ) ) 435 { 436 aResult.SegmentText = sText.copy( aBoundary.startPos, aBoundary.endPos - aBoundary.startPos ); 437 aResult.SegmentStart = aBoundary.startPos; 438 aResult.SegmentEnd = aBoundary.endPos; 439 } 440 } 441 break; 442 case AccessibleTextType::SENTENCE: 443 { 444 // get sentence at index 445 implGetSentenceBoundary( sText, aBoundary, nIndex ); 446 // get previous sentence 447 if ( aBoundary.startPos > 0 ) 448 { 449 implGetSentenceBoundary( sText, aBoundary, aBoundary.startPos - 1 ); 450 if ( implIsValidBoundary( aBoundary, nLength ) ) 451 { 452 aResult.SegmentText = sText.copy( aBoundary.startPos, aBoundary.endPos - aBoundary.startPos ); 453 aResult.SegmentStart = aBoundary.startPos; 454 aResult.SegmentEnd = aBoundary.endPos; 455 } 456 } 457 } 458 break; 459 case AccessibleTextType::PARAGRAPH: 460 { 461 // get paragraph at index 462 implGetParagraphBoundary( sText, aBoundary, nIndex ); 463 // get previous paragraph 464 if ( aBoundary.startPos > 0 ) 465 { 466 implGetParagraphBoundary( sText, aBoundary, aBoundary.startPos - 1 ); 467 if ( implIsValidBoundary( aBoundary, nLength ) ) 468 { 469 aResult.SegmentText = sText.copy( aBoundary.startPos, aBoundary.endPos - aBoundary.startPos ); 470 aResult.SegmentStart = aBoundary.startPos; 471 aResult.SegmentEnd = aBoundary.endPos; 472 } 473 } 474 } 475 break; 476 case AccessibleTextType::LINE: 477 { 478 // get line at index 479 implGetLineBoundary( sText, aBoundary, nIndex ); 480 // get previous line 481 if ( aBoundary.startPos > 0 ) 482 { 483 implGetLineBoundary( sText, aBoundary, aBoundary.startPos - 1 ); 484 if ( implIsValidBoundary( aBoundary, nLength ) ) 485 { 486 aResult.SegmentText = sText.copy( aBoundary.startPos, aBoundary.endPos - aBoundary.startPos ); 487 aResult.SegmentStart = aBoundary.startPos; 488 aResult.SegmentEnd = aBoundary.endPos; 489 } 490 } 491 } 492 break; 493 case AccessibleTextType::ATTRIBUTE_RUN: 494 { 495 // TODO: implGetAttributeRunBoundary() (incompatible!) 496 } 497 break; 498 default: 499 { 500 // unknown text type 501 } 502 } 503 504 return aResult; 505 } 506 507 getTextBehindIndex(sal_Int32 nIndex,sal_Int16 aTextType)508 TextSegment OCommonAccessibleText::getTextBehindIndex( sal_Int32 nIndex, sal_Int16 aTextType ) 509 { 510 OUString sText( implGetText() ); 511 sal_Int32 nLength = sText.getLength(); 512 513 if ( !implIsValidIndex( nIndex, nLength ) && nIndex != nLength ) 514 throw IndexOutOfBoundsException(); 515 516 i18n::Boundary aBoundary; 517 TextSegment aResult; 518 aResult.SegmentStart = -1; 519 aResult.SegmentEnd = -1; 520 521 switch ( aTextType ) 522 { 523 case AccessibleTextType::CHARACTER: 524 { 525 if ( implIsValidIndex( nIndex + 1, nLength ) ) 526 { 527 aResult.SegmentText = sText.copy( nIndex + 1, 1 ); 528 aResult.SegmentStart = nIndex+1; 529 aResult.SegmentEnd = nIndex+2; 530 } 531 } 532 break; 533 case AccessibleTextType::GLYPH: 534 { 535 // get glyph at index 536 implGetGlyphBoundary( sText, aBoundary, nIndex ); 537 // get next glyph 538 if ( aBoundary.endPos < nLength ) 539 { 540 implGetGlyphBoundary( sText, aBoundary, aBoundary.endPos ); 541 if ( implIsValidBoundary( aBoundary, nLength ) ) 542 { 543 aResult.SegmentText = sText.copy( aBoundary.startPos, aBoundary.endPos - aBoundary.startPos ); 544 aResult.SegmentStart = aBoundary.startPos; 545 aResult.SegmentEnd = aBoundary.endPos; 546 } 547 } 548 } 549 break; 550 case AccessibleTextType::WORD: 551 { 552 // get word at index 553 implGetWordBoundary( sText, aBoundary, nIndex ); 554 // get next word 555 bool bWord = false; 556 while ( !bWord && aBoundary.endPos < nLength ) 557 bWord = implGetWordBoundary( sText, aBoundary, aBoundary.endPos ); 558 if ( bWord && implIsValidBoundary( aBoundary, nLength ) ) 559 { 560 aResult.SegmentText = sText.copy( aBoundary.startPos, aBoundary.endPos - aBoundary.startPos ); 561 aResult.SegmentStart = aBoundary.startPos; 562 aResult.SegmentEnd = aBoundary.endPos; 563 } 564 } 565 break; 566 case AccessibleTextType::SENTENCE: 567 { 568 // get sentence at index 569 implGetSentenceBoundary( sText, aBoundary, nIndex ); 570 // get next sentence 571 sal_Int32 nEnd = aBoundary.endPos; 572 sal_Int32 nI = aBoundary.endPos; 573 bool bFound = false; 574 while ( !bFound && ++nI < nLength ) 575 { 576 implGetSentenceBoundary( sText, aBoundary, nI ); 577 bFound = ( aBoundary.endPos > nEnd ); 578 } 579 if ( bFound && implIsValidBoundary( aBoundary, nLength ) ) 580 { 581 aResult.SegmentText = sText.copy( aBoundary.startPos, aBoundary.endPos - aBoundary.startPos ); 582 aResult.SegmentStart = aBoundary.startPos; 583 aResult.SegmentEnd = aBoundary.endPos; 584 } 585 } 586 break; 587 case AccessibleTextType::PARAGRAPH: 588 { 589 // get paragraph at index 590 implGetParagraphBoundary( sText, aBoundary, nIndex ); 591 // get next paragraph 592 if ( aBoundary.endPos < nLength ) 593 { 594 implGetParagraphBoundary( sText, aBoundary, aBoundary.endPos ); 595 if ( implIsValidBoundary( aBoundary, nLength ) ) 596 { 597 aResult.SegmentText = sText.copy( aBoundary.startPos, aBoundary.endPos - aBoundary.startPos ); 598 aResult.SegmentStart = aBoundary.startPos; 599 aResult.SegmentEnd = aBoundary.endPos; 600 } 601 } 602 } 603 break; 604 case AccessibleTextType::LINE: 605 { 606 // get line at index 607 implGetLineBoundary( sText, aBoundary, nIndex ); 608 // get next line 609 if ( aBoundary.endPos < nLength ) 610 { 611 implGetLineBoundary( sText, aBoundary, aBoundary.endPos ); 612 if ( implIsValidBoundary( aBoundary, nLength ) ) 613 { 614 aResult.SegmentText = sText.copy( aBoundary.startPos, aBoundary.endPos - aBoundary.startPos ); 615 aResult.SegmentStart = aBoundary.startPos; 616 aResult.SegmentEnd = aBoundary.endPos; 617 } 618 } 619 } 620 break; 621 case AccessibleTextType::ATTRIBUTE_RUN: 622 { 623 // TODO: implGetAttributeRunBoundary() (incompatible!) 624 } 625 break; 626 default: 627 { 628 // unknown text type 629 } 630 } 631 632 return aResult; 633 } 634 635 implInitTextChangedEvent(const OUString & rOldString,const OUString & rNewString,css::uno::Any & rDeleted,css::uno::Any & rInserted)636 bool OCommonAccessibleText::implInitTextChangedEvent( 637 const OUString& rOldString, 638 const OUString& rNewString, 639 css::uno::Any& rDeleted, 640 css::uno::Any& rInserted) // throw() 641 { 642 sal_uInt32 nLenOld = rOldString.getLength(); 643 sal_uInt32 nLenNew = rNewString.getLength(); 644 645 // equal 646 if ((0 == nLenOld) && (0 == nLenNew)) 647 return false; 648 649 TextSegment aDeletedText; 650 TextSegment aInsertedText; 651 652 aDeletedText.SegmentStart = -1; 653 aDeletedText.SegmentEnd = -1; 654 aInsertedText.SegmentStart = -1; 655 aInsertedText.SegmentEnd = -1; 656 657 // insert only 658 if ((0 == nLenOld) && (nLenNew > 0)) 659 { 660 aInsertedText.SegmentStart = 0; 661 aInsertedText.SegmentEnd = nLenNew; 662 aInsertedText.SegmentText = rNewString.copy( aInsertedText.SegmentStart, aInsertedText.SegmentEnd - aInsertedText.SegmentStart ); 663 664 rInserted <<= aInsertedText; 665 return true; 666 } 667 668 // delete only 669 if ((nLenOld > 0) && (0 == nLenNew)) 670 { 671 aDeletedText.SegmentStart = 0; 672 aDeletedText.SegmentEnd = nLenOld; 673 aDeletedText.SegmentText = rOldString.copy( aDeletedText.SegmentStart, aDeletedText.SegmentEnd - aDeletedText.SegmentStart ); 674 675 rDeleted <<= aDeletedText; 676 return true; 677 } 678 679 const sal_Unicode* pFirstDiffOld = rOldString.getStr(); 680 const sal_Unicode* pLastDiffOld = rOldString.getStr() + nLenOld; 681 const sal_Unicode* pFirstDiffNew = rNewString.getStr(); 682 const sal_Unicode* pLastDiffNew = rNewString.getStr() + nLenNew; 683 684 // find first difference 685 while ((*pFirstDiffOld == *pFirstDiffNew) && 686 (pFirstDiffOld < pLastDiffOld) && 687 (pFirstDiffNew < pLastDiffNew)) 688 { 689 pFirstDiffOld++; 690 pFirstDiffNew++; 691 } 692 693 // equality test 694 if ((0 == *pFirstDiffOld) && (0 == *pFirstDiffNew)) 695 return false; 696 697 // find last difference 698 while ( ( pLastDiffOld > pFirstDiffOld) && 699 ( pLastDiffNew > pFirstDiffNew) && 700 (pLastDiffOld[-1] == pLastDiffNew[-1])) 701 { 702 pLastDiffOld--; 703 pLastDiffNew--; 704 } 705 706 if (pFirstDiffOld < pLastDiffOld) 707 { 708 aDeletedText.SegmentStart = pFirstDiffOld - rOldString.getStr(); 709 aDeletedText.SegmentEnd = pLastDiffOld - rOldString.getStr(); 710 aDeletedText.SegmentText = rOldString.copy( aDeletedText.SegmentStart, aDeletedText.SegmentEnd - aDeletedText.SegmentStart ); 711 712 rDeleted <<= aDeletedText; 713 } 714 715 if (pFirstDiffNew < pLastDiffNew) 716 { 717 aInsertedText.SegmentStart = pFirstDiffNew - rNewString.getStr(); 718 aInsertedText.SegmentEnd = pLastDiffNew - rNewString.getStr(); 719 aInsertedText.SegmentText = rNewString.copy( aInsertedText.SegmentStart, aInsertedText.SegmentEnd - aInsertedText.SegmentStart ); 720 721 rInserted <<= aInsertedText; 722 } 723 return true; 724 } 725 726 727 // OAccessibleTextHelper 728 729 OAccessibleTextHelper()730 OAccessibleTextHelper::OAccessibleTextHelper( ) 731 { 732 } 733 734 735 // XInterface 736 737 IMPLEMENT_FORWARD_XINTERFACE2(OAccessibleTextHelper,OAccessibleExtendedComponentHelper,OAccessibleTextHelper_Base)738 IMPLEMENT_FORWARD_XINTERFACE2( OAccessibleTextHelper, OAccessibleExtendedComponentHelper, OAccessibleTextHelper_Base ) 739 740 741 // XTypeProvider 742 743 744 IMPLEMENT_FORWARD_XTYPEPROVIDER2( OAccessibleTextHelper, OAccessibleExtendedComponentHelper, OAccessibleTextHelper_Base ) 745 746 747 // XAccessibleText 748 749 750 OUString OAccessibleTextHelper::getSelectedText() 751 { 752 OExternalLockGuard aGuard( this ); 753 754 return OCommonAccessibleText::getSelectedText(); 755 } 756 757 getSelectionStart()758 sal_Int32 OAccessibleTextHelper::getSelectionStart() 759 { 760 OExternalLockGuard aGuard( this ); 761 762 return OCommonAccessibleText::getSelectionStart(); 763 } 764 765 getSelectionEnd()766 sal_Int32 OAccessibleTextHelper::getSelectionEnd() 767 { 768 OExternalLockGuard aGuard( this ); 769 770 return OCommonAccessibleText::getSelectionEnd(); 771 } 772 773 getTextAtIndex(sal_Int32 nIndex,sal_Int16 aTextType)774 TextSegment OAccessibleTextHelper::getTextAtIndex( sal_Int32 nIndex, sal_Int16 aTextType ) 775 { 776 OExternalLockGuard aGuard( this ); 777 778 return OCommonAccessibleText::getTextAtIndex( nIndex, aTextType ); 779 } 780 781 getTextBeforeIndex(sal_Int32 nIndex,sal_Int16 aTextType)782 TextSegment OAccessibleTextHelper::getTextBeforeIndex( sal_Int32 nIndex, sal_Int16 aTextType ) 783 { 784 OExternalLockGuard aGuard( this ); 785 786 return OCommonAccessibleText::getTextBeforeIndex( nIndex, aTextType ); 787 } 788 789 getTextBehindIndex(sal_Int32 nIndex,sal_Int16 aTextType)790 TextSegment OAccessibleTextHelper::getTextBehindIndex( sal_Int32 nIndex, sal_Int16 aTextType ) 791 { 792 OExternalLockGuard aGuard( this ); 793 794 return OCommonAccessibleText::getTextBehindIndex( nIndex, aTextType ); 795 } 796 797 798 } // namespace comphelper 799 800 801 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ 802