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