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