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