Branch data Line data Source code
1 : : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : : /*************************************************************************
3 : : *
4 : : * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 : : *
6 : : * Copyright 2000, 2010 Oracle and/or its affiliates.
7 : : *
8 : : * OpenOffice.org - a multi-platform office productivity suite
9 : : *
10 : : * This file is part of OpenOffice.org.
11 : : *
12 : : * OpenOffice.org is free software: you can redistribute it and/or modify
13 : : * it under the terms of the GNU Lesser General Public License version 3
14 : : * only, as published by the Free Software Foundation.
15 : : *
16 : : * OpenOffice.org is distributed in the hope that it will be useful,
17 : : * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 : : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 : : * GNU Lesser General Public License version 3 for more details
20 : : * (a copy is included in the LICENSE file that accompanied this code).
21 : : *
22 : : * You should have received a copy of the GNU Lesser General Public License
23 : : * version 3 along with OpenOffice.org. If not, see
24 : : * <http://www.openoffice.org/license.html>
25 : : * for a copy of the LGPLv3 License.
26 : : *
27 : : ************************************************************************/
28 : :
29 : :
30 : : #include "atkwrapper.hxx"
31 : : #include "atktextattributes.hxx"
32 : : #include <algorithm>
33 : :
34 : : #include <com/sun/star/accessibility/AccessibleTextType.hpp>
35 : : #include <com/sun/star/accessibility/TextSegment.hpp>
36 : : #include <com/sun/star/accessibility/XAccessibleMultiLineText.hpp>
37 : : #include <com/sun/star/accessibility/XAccessibleText.hpp>
38 : : #include <com/sun/star/accessibility/XAccessibleTextAttributes.hpp>
39 : : #include <com/sun/star/accessibility/XAccessibleTextMarkup.hpp>
40 : : #include <com/sun/star/text/TextMarkupType.hpp>
41 : :
42 : : // #define ENABLE_TRACING
43 : :
44 : : #ifdef ENABLE_TRACING
45 : : #include <stdio.h>
46 : : #endif
47 : :
48 : : using namespace ::com::sun::star;
49 : :
50 : : static sal_Int16
51 : 0 : text_type_from_boundary(AtkTextBoundary boundary_type)
52 : : {
53 : 0 : switch(boundary_type)
54 : : {
55 : : case ATK_TEXT_BOUNDARY_CHAR:
56 : 0 : return accessibility::AccessibleTextType::CHARACTER;
57 : : case ATK_TEXT_BOUNDARY_WORD_START:
58 : : case ATK_TEXT_BOUNDARY_WORD_END:
59 : 0 : return accessibility::AccessibleTextType::WORD;
60 : : case ATK_TEXT_BOUNDARY_SENTENCE_START:
61 : : case ATK_TEXT_BOUNDARY_SENTENCE_END:
62 : 0 : return accessibility::AccessibleTextType::SENTENCE;
63 : : case ATK_TEXT_BOUNDARY_LINE_START:
64 : : case ATK_TEXT_BOUNDARY_LINE_END:
65 : 0 : return accessibility::AccessibleTextType::LINE;
66 : : default:
67 : 0 : return -1;
68 : : }
69 : : }
70 : :
71 : : /*****************************************************************************/
72 : :
73 : : static gchar *
74 : 0 : adjust_boundaries( accessibility::XAccessibleText* pText,
75 : : accessibility::TextSegment& rTextSegment,
76 : : AtkTextBoundary boundary_type,
77 : : gint * start_offset, gint * end_offset )
78 : : {
79 : 0 : accessibility::TextSegment aTextSegment;
80 : 0 : rtl::OUString aString;
81 : 0 : gint start = 0, end = 0;
82 : :
83 : 0 : if( !rTextSegment.SegmentText.isEmpty() )
84 : : {
85 : 0 : switch(boundary_type)
86 : : {
87 : : case ATK_TEXT_BOUNDARY_CHAR:
88 : : case ATK_TEXT_BOUNDARY_LINE_START:
89 : : case ATK_TEXT_BOUNDARY_LINE_END:
90 : : case ATK_TEXT_BOUNDARY_SENTENCE_START:
91 : 0 : start = rTextSegment.SegmentStart;
92 : 0 : end = rTextSegment.SegmentEnd;
93 : 0 : aString = rTextSegment.SegmentText;
94 : 0 : break;
95 : :
96 : : // the OOo break iterator behaves as SENTENCE_START
97 : : case ATK_TEXT_BOUNDARY_SENTENCE_END:
98 : 0 : start = rTextSegment.SegmentStart;
99 : 0 : end = rTextSegment.SegmentEnd;
100 : :
101 : 0 : if( start > 0 )
102 : 0 : --start;
103 : 0 : if( end > 0 && end < pText->getCharacterCount() - 1 )
104 : 0 : --end;
105 : :
106 : 0 : aString = pText->getTextRange(start, end);
107 : 0 : break;
108 : :
109 : : case ATK_TEXT_BOUNDARY_WORD_START:
110 : 0 : start = rTextSegment.SegmentStart;
111 : :
112 : : // Determine the start index of the next segment
113 : : aTextSegment = pText->getTextBehindIndex(rTextSegment.SegmentEnd,
114 : 0 : text_type_from_boundary(boundary_type));
115 : 0 : if( !aTextSegment.SegmentText.isEmpty() )
116 : 0 : end = aTextSegment.SegmentStart;
117 : : else
118 : 0 : end = pText->getCharacterCount();
119 : :
120 : 0 : aString = pText->getTextRange(start, end);
121 : 0 : break;
122 : :
123 : : case ATK_TEXT_BOUNDARY_WORD_END:
124 : 0 : end = rTextSegment.SegmentEnd;
125 : :
126 : : // Determine the end index of the previous segment
127 : : aTextSegment = pText->getTextBeforeIndex(rTextSegment.SegmentStart,
128 : 0 : text_type_from_boundary(boundary_type));
129 : 0 : if( !aTextSegment.SegmentText.isEmpty() )
130 : 0 : start = aTextSegment.SegmentEnd;
131 : : else
132 : 0 : start = 0;
133 : :
134 : 0 : aString = pText->getTextRange(start, end);
135 : 0 : break;
136 : :
137 : : default:
138 : 0 : return NULL;
139 : : }
140 : : }
141 : :
142 : 0 : *start_offset = start;
143 : 0 : *end_offset = end;
144 : :
145 : : #ifdef ENABLE_TRACING
146 : : fprintf(stderr, "adjust_boundaries( %d, %d, %d ) returns %d, %d\n",
147 : : rTextSegment.SegmentStart, rTextSegment.SegmentEnd, boundary_type,
148 : : start, end);
149 : : #endif
150 : :
151 : 0 : return OUStringToGChar(aString);
152 : : }
153 : :
154 : : /*****************************************************************************/
155 : :
156 : : static accessibility::XAccessibleText*
157 : 0 : getText( AtkText *pText ) throw (uno::RuntimeException)
158 : : {
159 : 0 : AtkObjectWrapper *pWrap = ATK_OBJECT_WRAPPER( pText );
160 : 0 : if( pWrap )
161 : : {
162 : 0 : if( !pWrap->mpText && pWrap->mpContext )
163 : : {
164 : 0 : uno::Any any = pWrap->mpContext->queryInterface( accessibility::XAccessibleText::static_type(NULL) );
165 : 0 : pWrap->mpText = reinterpret_cast< accessibility::XAccessibleText * > (any.pReserved);
166 : 0 : pWrap->mpText->acquire();
167 : : }
168 : :
169 : 0 : return pWrap->mpText;
170 : : }
171 : :
172 : 0 : return NULL;
173 : : }
174 : :
175 : : /*****************************************************************************/
176 : :
177 : : static accessibility::XAccessibleTextMarkup*
178 : 0 : getTextMarkup( AtkText *pText ) throw (uno::RuntimeException)
179 : : {
180 : 0 : AtkObjectWrapper *pWrap = ATK_OBJECT_WRAPPER( pText );
181 : 0 : if( pWrap )
182 : : {
183 : 0 : if( !pWrap->mpTextMarkup && pWrap->mpContext )
184 : : {
185 : 0 : uno::Any any = pWrap->mpContext->queryInterface( accessibility::XAccessibleTextMarkup::static_type(NULL) );
186 : : /* Since this not a dedicated interface in Atk and thus has not
187 : : * been queried during wrapper initialization, we need to check
188 : : * the return value here.
189 : : */
190 : 0 : if( typelib_TypeClass_INTERFACE == any.pType->eTypeClass )
191 : : {
192 : 0 : pWrap->mpTextMarkup = reinterpret_cast< accessibility::XAccessibleTextMarkup * > (any.pReserved);
193 : 0 : if( pWrap->mpTextMarkup )
194 : 0 : pWrap->mpTextMarkup->acquire();
195 : 0 : }
196 : : }
197 : :
198 : 0 : return pWrap->mpTextMarkup;
199 : : }
200 : :
201 : 0 : return NULL;
202 : : }
203 : :
204 : : /*****************************************************************************/
205 : :
206 : : static accessibility::XAccessibleTextAttributes*
207 : 0 : getTextAttributes( AtkText *pText ) throw (uno::RuntimeException)
208 : : {
209 : 0 : AtkObjectWrapper *pWrap = ATK_OBJECT_WRAPPER( pText );
210 : 0 : if( pWrap )
211 : : {
212 : 0 : if( !pWrap->mpTextAttributes && pWrap->mpContext )
213 : : {
214 : 0 : uno::Any any = pWrap->mpContext->queryInterface( accessibility::XAccessibleTextAttributes::static_type(NULL) );
215 : : /* Since this not a dedicated interface in Atk and thus has not
216 : : * been queried during wrapper initialization, we need to check
217 : : * the return value here.
218 : : */
219 : 0 : if( typelib_TypeClass_INTERFACE == any.pType->eTypeClass )
220 : : {
221 : 0 : pWrap->mpTextAttributes = reinterpret_cast< accessibility::XAccessibleTextAttributes * > (any.pReserved);
222 : 0 : pWrap->mpTextAttributes->acquire();
223 : 0 : }
224 : : }
225 : :
226 : 0 : return pWrap->mpTextAttributes;
227 : : }
228 : :
229 : 0 : return NULL;
230 : : }
231 : :
232 : : /*****************************************************************************/
233 : :
234 : : static accessibility::XAccessibleMultiLineText*
235 : 0 : getMultiLineText( AtkText *pText ) throw (uno::RuntimeException)
236 : : {
237 : 0 : AtkObjectWrapper *pWrap = ATK_OBJECT_WRAPPER( pText );
238 : 0 : if( pWrap )
239 : : {
240 : 0 : if( !pWrap->mpMultiLineText && pWrap->mpContext )
241 : : {
242 : 0 : uno::Any any = pWrap->mpContext->queryInterface( accessibility::XAccessibleMultiLineText::static_type(NULL) );
243 : : /* Since this not a dedicated interface in Atk and thus has not
244 : : * been queried during wrapper initialization, we need to check
245 : : * the return value here.
246 : : */
247 : 0 : if( typelib_TypeClass_INTERFACE == any.pType->eTypeClass )
248 : : {
249 : 0 : pWrap->mpMultiLineText = reinterpret_cast< accessibility::XAccessibleMultiLineText * > (any.pReserved);
250 : 0 : pWrap->mpMultiLineText->acquire();
251 : 0 : }
252 : : }
253 : :
254 : 0 : return pWrap->mpMultiLineText;
255 : : }
256 : :
257 : 0 : return NULL;
258 : : }
259 : :
260 : : /*****************************************************************************/
261 : :
262 : : extern "C" {
263 : :
264 : : static gchar *
265 : 0 : text_wrapper_get_text (AtkText *text,
266 : : gint start_offset,
267 : : gint end_offset)
268 : : {
269 : 0 : gchar * ret = NULL;
270 : :
271 : 0 : g_return_val_if_fail( (end_offset == -1) || (end_offset >= start_offset), NULL );
272 : :
273 : : /* at-spi expects the delete event to be send before the deletion happened
274 : : * so we save the deleted string object in the UNO event notification and
275 : : * fool libatk-bridge.so here ..
276 : : */
277 : 0 : void * pData = g_object_get_data( G_OBJECT(text), "ooo::text_changed::delete" );
278 : 0 : if( pData != NULL )
279 : : {
280 : : accessibility::TextSegment * pTextSegment =
281 : 0 : reinterpret_cast <accessibility::TextSegment *> (pData);
282 : :
283 : 0 : if( pTextSegment->SegmentStart == start_offset &&
284 : : pTextSegment->SegmentEnd == end_offset )
285 : : {
286 : 0 : rtl::OString aUtf8 = rtl::OUStringToOString( pTextSegment->SegmentText, RTL_TEXTENCODING_UTF8 );
287 : 0 : return g_strdup( aUtf8.getStr() );
288 : : }
289 : : }
290 : :
291 : : try {
292 : 0 : accessibility::XAccessibleText* pText = getText( text );
293 : 0 : if( pText )
294 : : {
295 : 0 : rtl::OUString aText;
296 : 0 : sal_Int32 n = pText->getCharacterCount();
297 : :
298 : 0 : if( -1 == end_offset )
299 : 0 : aText = pText->getText();
300 : 0 : else if( start_offset < n )
301 : 0 : aText = pText->getTextRange(start_offset, end_offset);
302 : :
303 : 0 : ret = g_strdup( rtl::OUStringToOString(aText, RTL_TEXTENCODING_UTF8 ).getStr() );
304 : : }
305 : : }
306 : 0 : catch(const uno::Exception& e) {
307 : 0 : g_warning( "Exception in getText()" );
308 : : }
309 : :
310 : : #ifdef ENABLE_TRACING
311 : : fprintf(stderr, "text_wrapper_get_text( %d,%d ) returns %s\n", start_offset, end_offset, ret ? ret : "null" );
312 : : #endif
313 : 0 : return ret;
314 : : }
315 : :
316 : : static gchar *
317 : 0 : text_wrapper_get_text_after_offset (AtkText *text,
318 : : gint offset,
319 : : AtkTextBoundary boundary_type,
320 : : gint *start_offset,
321 : : gint *end_offset)
322 : : {
323 : : try {
324 : 0 : accessibility::XAccessibleText* pText = getText( text );
325 : 0 : if( pText )
326 : : {
327 : 0 : accessibility::TextSegment aTextSegment = pText->getTextBehindIndex(offset, text_type_from_boundary(boundary_type));
328 : 0 : return adjust_boundaries(pText, aTextSegment, boundary_type, start_offset, end_offset);
329 : : }
330 : : }
331 : 0 : catch(const uno::Exception& e) {
332 : 0 : g_warning( "Exception in get_text_after_offset()" );
333 : : }
334 : :
335 : 0 : return NULL;
336 : : }
337 : :
338 : : static gchar *
339 : 0 : text_wrapper_get_text_at_offset (AtkText *text,
340 : : gint offset,
341 : : AtkTextBoundary boundary_type,
342 : : gint *start_offset,
343 : : gint *end_offset)
344 : : {
345 : : try {
346 : 0 : accessibility::XAccessibleText* pText = getText( text );
347 : 0 : if( pText )
348 : : {
349 : : /* If the user presses the 'End' key, the caret will be placed behind the last character,
350 : : * which is the same index as the first character of the next line. In atk the magic offset
351 : : * '-2' is used to cover this special case.
352 : : */
353 : 0 : if (
354 : : -2 == offset &&
355 : : (ATK_TEXT_BOUNDARY_LINE_START == boundary_type ||
356 : : ATK_TEXT_BOUNDARY_LINE_END == boundary_type)
357 : : )
358 : : {
359 : 0 : accessibility::XAccessibleMultiLineText* pMultiLineText = getMultiLineText( text );
360 : 0 : if( pMultiLineText )
361 : : {
362 : 0 : accessibility::TextSegment aTextSegment = pMultiLineText->getTextAtLineWithCaret();
363 : 0 : return adjust_boundaries(pText, aTextSegment, boundary_type, start_offset, end_offset);
364 : : }
365 : : }
366 : :
367 : 0 : accessibility::TextSegment aTextSegment = pText->getTextAtIndex(offset, text_type_from_boundary(boundary_type));
368 : 0 : return adjust_boundaries(pText, aTextSegment, boundary_type, start_offset, end_offset);
369 : : }
370 : : }
371 : 0 : catch(const uno::Exception& e) {
372 : 0 : g_warning( "Exception in get_text_at_offset()" );
373 : : }
374 : :
375 : 0 : return NULL;
376 : : }
377 : :
378 : : static gunichar
379 : 0 : text_wrapper_get_character_at_offset (AtkText *text,
380 : : gint offset)
381 : : {
382 : : gint start, end;
383 : 0 : gunichar uc = 0;
384 : :
385 : : gchar * char_as_string =
386 : : text_wrapper_get_text_at_offset(text, offset, ATK_TEXT_BOUNDARY_CHAR,
387 : 0 : &start, &end);
388 : 0 : if( char_as_string )
389 : : {
390 : 0 : uc = g_utf8_get_char( char_as_string );
391 : 0 : g_free( char_as_string );
392 : : }
393 : :
394 : 0 : return uc;
395 : : }
396 : :
397 : : static gchar *
398 : 0 : text_wrapper_get_text_before_offset (AtkText *text,
399 : : gint offset,
400 : : AtkTextBoundary boundary_type,
401 : : gint *start_offset,
402 : : gint *end_offset)
403 : : {
404 : : try {
405 : 0 : accessibility::XAccessibleText* pText = getText( text );
406 : 0 : if( pText )
407 : : {
408 : 0 : accessibility::TextSegment aTextSegment = pText->getTextBeforeIndex(offset, text_type_from_boundary(boundary_type));
409 : 0 : return adjust_boundaries(pText, aTextSegment, boundary_type, start_offset, end_offset);
410 : : }
411 : : }
412 : 0 : catch(const uno::Exception& e) {
413 : 0 : g_warning( "Exception in text_before_offset()" );
414 : : }
415 : :
416 : 0 : return NULL;
417 : : }
418 : :
419 : : static gint
420 : 0 : text_wrapper_get_caret_offset (AtkText *text)
421 : : {
422 : 0 : gint offset = -1;
423 : :
424 : : try {
425 : 0 : accessibility::XAccessibleText* pText = getText( text );
426 : 0 : if( pText )
427 : 0 : offset = pText->getCaretPosition();
428 : : }
429 : 0 : catch(const uno::Exception& e) {
430 : 0 : g_warning( "Exception in getCaretPosition()" );
431 : : }
432 : :
433 : : #ifdef ENABLE_TRACING
434 : : fprintf(stderr, "get_caret_offset(%p) returns %d\n", text, offset);
435 : : #endif
436 : :
437 : 0 : return offset;
438 : : }
439 : :
440 : : static gboolean
441 : 0 : text_wrapper_set_caret_offset (AtkText *text,
442 : : gint offset)
443 : : {
444 : : try {
445 : 0 : accessibility::XAccessibleText* pText = getText( text );
446 : 0 : if( pText )
447 : 0 : return pText->setCaretPosition( offset );
448 : : }
449 : 0 : catch(const uno::Exception& e) {
450 : 0 : g_warning( "Exception in setCaretPosition()" );
451 : : }
452 : :
453 : 0 : return FALSE;
454 : : }
455 : :
456 : : // #i92232#
457 : : AtkAttributeSet*
458 : 0 : handle_text_markup_as_run_attribute( accessibility::XAccessibleTextMarkup* pTextMarkup,
459 : : const gint nTextMarkupType,
460 : : const gint offset,
461 : : AtkAttributeSet* pSet,
462 : : gint *start_offset,
463 : : gint *end_offset )
464 : : {
465 : 0 : const gint nTextMarkupCount( pTextMarkup->getTextMarkupCount( nTextMarkupType ) );
466 : 0 : if ( nTextMarkupCount > 0 )
467 : : {
468 : 0 : for ( gint nTextMarkupIndex = 0;
469 : : nTextMarkupIndex < nTextMarkupCount;
470 : : ++nTextMarkupIndex )
471 : : {
472 : : accessibility::TextSegment aTextSegment =
473 : 0 : pTextMarkup->getTextMarkup( nTextMarkupIndex, nTextMarkupType );
474 : 0 : const gint nStartOffsetTextMarkup = aTextSegment.SegmentStart;
475 : 0 : const gint nEndOffsetTextMarkup = aTextSegment.SegmentEnd;
476 : 0 : if ( nStartOffsetTextMarkup <= offset )
477 : : {
478 : 0 : if ( offset < nEndOffsetTextMarkup )
479 : : {
480 : : // text markup at <offset>
481 : : *start_offset = ::std::max( *start_offset,
482 : 0 : nStartOffsetTextMarkup );
483 : : *end_offset = ::std::min( *end_offset,
484 : 0 : nEndOffsetTextMarkup );
485 : 0 : switch ( nTextMarkupType )
486 : : {
487 : : case com::sun::star::text::TextMarkupType::SPELLCHECK:
488 : : {
489 : 0 : pSet = attribute_set_prepend_misspelled( pSet );
490 : : }
491 : 0 : break;
492 : : case com::sun::star::text::TextMarkupType::TRACK_CHANGE_INSERTION:
493 : : {
494 : 0 : pSet = attribute_set_prepend_tracked_change_insertion( pSet );
495 : : }
496 : 0 : break;
497 : : case com::sun::star::text::TextMarkupType::TRACK_CHANGE_DELETION:
498 : : {
499 : 0 : pSet = attribute_set_prepend_tracked_change_deletion( pSet );
500 : : }
501 : 0 : break;
502 : : case com::sun::star::text::TextMarkupType::TRACK_CHANGE_FORMATCHANGE:
503 : : {
504 : 0 : pSet = attribute_set_prepend_tracked_change_formatchange( pSet );
505 : : }
506 : 0 : break;
507 : : default:
508 : : {
509 : : OSL_ASSERT( false );
510 : : }
511 : : }
512 : : break; // no further iteration needed.
513 : : }
514 : : else
515 : : {
516 : : *start_offset = ::std::max( *start_offset,
517 : 0 : nEndOffsetTextMarkup );
518 : : // continue iteration.
519 : : }
520 : : }
521 : : else
522 : : {
523 : : *end_offset = ::std::min( *end_offset,
524 : 0 : nStartOffsetTextMarkup );
525 : : break; // no further iteration.
526 : : }
527 : 0 : } // eof iteration over text markups
528 : : }
529 : :
530 : 0 : return pSet;
531 : : }
532 : :
533 : : static AtkAttributeSet *
534 : 0 : text_wrapper_get_run_attributes( AtkText *text,
535 : : gint offset,
536 : : gint *start_offset,
537 : : gint *end_offset)
538 : : {
539 : 0 : AtkAttributeSet *pSet = NULL;
540 : :
541 : : try {
542 : 0 : bool bOffsetsAreValid = false;
543 : :
544 : 0 : accessibility::XAccessibleText* pText = getText( text );
545 : 0 : accessibility::XAccessibleTextAttributes* pTextAttributes = getTextAttributes( text );
546 : 0 : if( pText && pTextAttributes )
547 : : {
548 : : uno::Sequence< beans::PropertyValue > aAttributeList =
549 : 0 : pTextAttributes->getRunAttributes( offset, uno::Sequence< rtl::OUString > () );
550 : :
551 : 0 : pSet = attribute_set_new_from_property_values( aAttributeList, true, text );
552 : : // #i100938#
553 : : // - always provide start_offset and end_offset
554 : : {
555 : : accessibility::TextSegment aTextSegment =
556 : 0 : pText->getTextAtIndex(offset, accessibility::AccessibleTextType::ATTRIBUTE_RUN);
557 : :
558 : 0 : *start_offset = aTextSegment.SegmentStart;
559 : : // #i100938#
560 : : // Do _not_ increment the end_offset provide by <accessibility::TextSegment> instance
561 : 0 : *end_offset = aTextSegment.SegmentEnd;
562 : 0 : bOffsetsAreValid = true;
563 : 0 : }
564 : : }
565 : :
566 : : // Special handling for misspelled text
567 : : // #i92232#
568 : : // - add special handling for tracked changes and refactor the
569 : : // corresponding code for handling misspelled text.
570 : 0 : accessibility::XAccessibleTextMarkup* pTextMarkup = getTextMarkup( text );
571 : 0 : if( pTextMarkup )
572 : : {
573 : : // Get attribute run here if it hasn't been done before
574 : 0 : if( !bOffsetsAreValid )
575 : : {
576 : : accessibility::TextSegment aAttributeTextSegment =
577 : 0 : pText->getTextAtIndex(offset, accessibility::AccessibleTextType::ATTRIBUTE_RUN);
578 : 0 : *start_offset = aAttributeTextSegment.SegmentStart;
579 : 0 : *end_offset = aAttributeTextSegment.SegmentEnd;
580 : : }
581 : : // handle misspelled text
582 : : pSet = handle_text_markup_as_run_attribute(
583 : : pTextMarkup,
584 : : com::sun::star::text::TextMarkupType::SPELLCHECK,
585 : 0 : offset, pSet, start_offset, end_offset );
586 : : // handle tracked changes
587 : : pSet = handle_text_markup_as_run_attribute(
588 : : pTextMarkup,
589 : : com::sun::star::text::TextMarkupType::TRACK_CHANGE_INSERTION,
590 : 0 : offset, pSet, start_offset, end_offset );
591 : : pSet = handle_text_markup_as_run_attribute(
592 : : pTextMarkup,
593 : : com::sun::star::text::TextMarkupType::TRACK_CHANGE_DELETION,
594 : 0 : offset, pSet, start_offset, end_offset );
595 : : pSet = handle_text_markup_as_run_attribute(
596 : : pTextMarkup,
597 : : com::sun::star::text::TextMarkupType::TRACK_CHANGE_FORMATCHANGE,
598 : 0 : offset, pSet, start_offset, end_offset );
599 : : }
600 : : }
601 : 0 : catch(const uno::Exception& e){
602 : :
603 : 0 : g_warning( "Exception in get_run_attributes()" );
604 : :
605 : 0 : if( pSet )
606 : : {
607 : 0 : atk_attribute_set_free( pSet );
608 : 0 : pSet = NULL;
609 : : }
610 : : }
611 : :
612 : 0 : return pSet;
613 : : }
614 : :
615 : : /*****************************************************************************/
616 : :
617 : : static AtkAttributeSet *
618 : 0 : text_wrapper_get_default_attributes( AtkText *text )
619 : : {
620 : 0 : AtkAttributeSet *pSet = NULL;
621 : :
622 : : try {
623 : 0 : accessibility::XAccessibleTextAttributes* pTextAttributes = getTextAttributes( text );
624 : 0 : if( pTextAttributes )
625 : : {
626 : : uno::Sequence< beans::PropertyValue > aAttributeList =
627 : 0 : pTextAttributes->getDefaultAttributes( uno::Sequence< rtl::OUString > () );
628 : :
629 : 0 : pSet = attribute_set_new_from_property_values( aAttributeList, false, text );
630 : : }
631 : : }
632 : 0 : catch(const uno::Exception& e) {
633 : :
634 : 0 : g_warning( "Exception in get_default_attributes()" );
635 : :
636 : 0 : if( pSet )
637 : : {
638 : 0 : atk_attribute_set_free( pSet );
639 : 0 : pSet = NULL;
640 : : }
641 : : }
642 : :
643 : 0 : return pSet;
644 : : }
645 : :
646 : : /*****************************************************************************/
647 : :
648 : : static void
649 : 0 : text_wrapper_get_character_extents( AtkText *text,
650 : : gint offset,
651 : : gint *x,
652 : : gint *y,
653 : : gint *width,
654 : : gint *height,
655 : : AtkCoordType coords )
656 : : {
657 : : try {
658 : 0 : accessibility::XAccessibleText* pText = getText( text );
659 : 0 : if( pText )
660 : : {
661 : 0 : *x = *y = *width = *height = 0;
662 : 0 : awt::Rectangle aRect = pText->getCharacterBounds( offset );
663 : :
664 : 0 : gint origin_x = 0;
665 : 0 : gint origin_y = 0;
666 : :
667 : 0 : if( coords == ATK_XY_SCREEN )
668 : : {
669 : 0 : g_return_if_fail( ATK_IS_COMPONENT( text ) );
670 : 0 : atk_component_get_position( ATK_COMPONENT( text ), &origin_x, &origin_y, coords);
671 : : }
672 : :
673 : 0 : *x = aRect.X + origin_x;
674 : 0 : *y = aRect.Y + origin_y;
675 : 0 : *width = aRect.Width;
676 : 0 : *height = aRect.Height;
677 : :
678 : : #ifdef ENABLE_TRACING
679 : : fprintf(stderr, "get_character_extents(%d, %d) returns: %d,%d,%d,%d ",
680 : : offset, coords, *x, *y, *width, *height);
681 : : #endif
682 : : }
683 : : }
684 : 0 : catch(const uno::Exception& e) {
685 : 0 : g_warning( "Exception in getCharacterBounds" );
686 : : }
687 : : }
688 : :
689 : : static gint
690 : 0 : text_wrapper_get_character_count (AtkText *text)
691 : : {
692 : 0 : gint rv = 0;
693 : :
694 : : try {
695 : 0 : accessibility::XAccessibleText* pText = getText( text );
696 : 0 : if( pText )
697 : 0 : rv = pText->getCharacterCount();
698 : : }
699 : 0 : catch(const uno::Exception& e) {
700 : 0 : g_warning( "Exception in getCharacterCount" );
701 : : }
702 : :
703 : : #ifdef ENABLE_TRACING
704 : : fprintf(stderr, "get_character_count(%p) returns: %d\n", text, rv);
705 : : #endif
706 : :
707 : 0 : return rv;
708 : : }
709 : :
710 : : static gint
711 : 0 : text_wrapper_get_offset_at_point (AtkText *text,
712 : : gint x,
713 : : gint y,
714 : : AtkCoordType coords)
715 : : {
716 : : try {
717 : 0 : accessibility::XAccessibleText* pText = getText( text );
718 : 0 : if( pText )
719 : : {
720 : 0 : gint origin_x = 0;
721 : 0 : gint origin_y = 0;
722 : :
723 : 0 : if( coords == ATK_XY_SCREEN )
724 : : {
725 : 0 : g_return_val_if_fail( ATK_IS_COMPONENT( text ), -1 );
726 : 0 : atk_component_get_position( ATK_COMPONENT( text ), &origin_x, &origin_y, coords);
727 : : }
728 : :
729 : 0 : return pText->getIndexAtPoint( awt::Point(x - origin_x, y - origin_y) );
730 : : }
731 : : }
732 : 0 : catch(const uno::Exception& e) {
733 : 0 : g_warning( "Exception in getIndexAtPoint" );
734 : : }
735 : :
736 : 0 : return -1;
737 : : }
738 : :
739 : : // FIXME: the whole series of selections API is problematic ...
740 : :
741 : : static gint
742 : 0 : text_wrapper_get_n_selections (AtkText *text)
743 : : {
744 : 0 : gint rv = 0;
745 : :
746 : : try {
747 : 0 : accessibility::XAccessibleText* pText = getText( text );
748 : 0 : if( pText )
749 : 0 : rv = ( pText->getSelectionEnd() > pText->getSelectionStart() ) ? 1 : 0;
750 : : }
751 : 0 : catch(const uno::Exception& e) {
752 : 0 : g_warning( "Exception in getSelectionEnd() or getSelectionStart()" );
753 : : }
754 : :
755 : : #ifdef ENABLE_TRACING
756 : : fprintf(stderr, "get_n_selections(%p) returns %d\n", text, rv);
757 : : #endif
758 : :
759 : 0 : return rv;
760 : : }
761 : :
762 : : static gchar *
763 : 0 : text_wrapper_get_selection (AtkText *text,
764 : : gint selection_num,
765 : : gint *start_offset,
766 : : gint *end_offset)
767 : : {
768 : 0 : g_return_val_if_fail( selection_num == 0, FALSE );
769 : :
770 : : try {
771 : 0 : accessibility::XAccessibleText* pText = getText( text );
772 : 0 : if( pText )
773 : : {
774 : 0 : *start_offset = pText->getSelectionStart();
775 : 0 : *end_offset = pText->getSelectionEnd();
776 : :
777 : 0 : return OUStringToGChar( pText->getSelectedText() );
778 : : }
779 : : }
780 : 0 : catch(const uno::Exception& e) {
781 : 0 : g_warning( "Exception in getSelectionEnd(), getSelectionStart() or getSelectedText()" );
782 : : }
783 : :
784 : 0 : return NULL;
785 : : }
786 : :
787 : : static gboolean
788 : 0 : text_wrapper_add_selection (AtkText *text,
789 : : gint start_offset,
790 : : gint end_offset)
791 : : {
792 : : // FIXME: can we try to be more compatible by expanding an
793 : : // existing adjacent selection ?
794 : :
795 : : try {
796 : 0 : accessibility::XAccessibleText* pText = getText( text );
797 : 0 : if( pText )
798 : 0 : return pText->setSelection( start_offset, end_offset ); // ?
799 : : }
800 : 0 : catch(const uno::Exception& e) {
801 : 0 : g_warning( "Exception in setSelection()" );
802 : : }
803 : :
804 : 0 : return FALSE;
805 : : }
806 : :
807 : : static gboolean
808 : 0 : text_wrapper_remove_selection (AtkText *text,
809 : : gint selection_num)
810 : : {
811 : 0 : g_return_val_if_fail( selection_num == 0, FALSE );
812 : :
813 : : try {
814 : 0 : accessibility::XAccessibleText* pText = getText( text );
815 : 0 : if( pText )
816 : 0 : return pText->setSelection( 0, 0 ); // ?
817 : : }
818 : 0 : catch(const uno::Exception& e) {
819 : 0 : g_warning( "Exception in setSelection()" );
820 : : }
821 : :
822 : 0 : return FALSE;
823 : : }
824 : :
825 : : static gboolean
826 : 0 : text_wrapper_set_selection (AtkText *text,
827 : : gint selection_num,
828 : : gint start_offset,
829 : : gint end_offset)
830 : : {
831 : 0 : g_return_val_if_fail( selection_num == 0, FALSE );
832 : :
833 : : try {
834 : 0 : accessibility::XAccessibleText* pText = getText( text );
835 : 0 : if( pText )
836 : 0 : return pText->setSelection( start_offset, end_offset );
837 : : }
838 : 0 : catch(const uno::Exception& e) {
839 : 0 : g_warning( "Exception in setSelection()" );
840 : : }
841 : :
842 : 0 : return FALSE;
843 : : }
844 : :
845 : : } // extern "C"
846 : :
847 : : void
848 : 0 : textIfaceInit (AtkTextIface *iface)
849 : : {
850 : 0 : g_return_if_fail (iface != NULL);
851 : :
852 : 0 : iface->get_text = text_wrapper_get_text;
853 : 0 : iface->get_character_at_offset = text_wrapper_get_character_at_offset;
854 : 0 : iface->get_text_before_offset = text_wrapper_get_text_before_offset;
855 : 0 : iface->get_text_at_offset = text_wrapper_get_text_at_offset;
856 : 0 : iface->get_text_after_offset = text_wrapper_get_text_after_offset;
857 : 0 : iface->get_caret_offset = text_wrapper_get_caret_offset;
858 : 0 : iface->set_caret_offset = text_wrapper_set_caret_offset;
859 : 0 : iface->get_character_count = text_wrapper_get_character_count;
860 : 0 : iface->get_n_selections = text_wrapper_get_n_selections;
861 : 0 : iface->get_selection = text_wrapper_get_selection;
862 : 0 : iface->add_selection = text_wrapper_add_selection;
863 : 0 : iface->remove_selection = text_wrapper_remove_selection;
864 : 0 : iface->set_selection = text_wrapper_set_selection;
865 : 0 : iface->get_run_attributes = text_wrapper_get_run_attributes;
866 : 0 : iface->get_default_attributes = text_wrapper_get_default_attributes;
867 : 0 : iface->get_character_extents = text_wrapper_get_character_extents;
868 : 0 : iface->get_offset_at_point = text_wrapper_get_offset_at_point;
869 : : }
870 : :
871 : : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|