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