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