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