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