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