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