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_sw.hxx" 26 27 #include <txtfrm.hxx> 28 #include <flyfrm.hxx> 29 #include <ndtxt.hxx> 30 #include <pam.hxx> 31 #include <unotextrange.hxx> 32 #include <unocrsrhelper.hxx> 33 #include <crstate.hxx> 34 #include <accmap.hxx> 35 #include <fesh.hxx> 36 #include <viewopt.hxx> 37 #include <vos/mutex.hxx> 38 #include <vcl/svapp.hxx> 39 #include <vcl/window.hxx> 40 #include <rtl/ustrbuf.hxx> 41 #include <com/sun/star/accessibility/AccessibleRole.hpp> 42 #include <com/sun/star/accessibility/AccessibleStateType.hpp> 43 #include <com/sun/star/accessibility/AccessibleTextType.hpp> 44 #include <com/sun/star/accessibility/AccessibleEventId.hpp> 45 #include <unotools/accessiblestatesethelper.hxx> 46 #include <com/sun/star/i18n/CharacterIteratorMode.hpp> 47 #include <com/sun/star/i18n/WordType.hpp> 48 #include <com/sun/star/i18n/XBreakIterator.hpp> 49 #include <com/sun/star/beans/UnknownPropertyException.hpp> 50 #include <breakit.hxx> 51 #include <accpara.hxx> 52 #include <access.hrc> 53 #include <accportions.hxx> 54 #include <sfx2/viewsh.hxx> // for ExecuteAtViewShell(...) 55 #include <sfx2/viewfrm.hxx> // for ExecuteAtViewShell(...) 56 #include <sfx2/dispatch.hxx> // for ExecuteAtViewShell(...) 57 #include <unotools/charclass.hxx> // for GetWordBoundary 58 // for get/setCharacterAttribute(...) 59 #include <unocrsr.hxx> 60 //#include <unoobj.hxx> 61 #include <unoport.hxx> 62 #include <doc.hxx> 63 #include <crsskip.hxx> 64 #include <txtatr.hxx> 65 #include <acchyperlink.hxx> 66 #include <acchypertextdata.hxx> 67 #include <unotools/accessiblerelationsethelper.hxx> 68 #include <com/sun/star/accessibility/AccessibleRelationType.hpp> 69 #include <comphelper/accessibletexthelper.hxx> 70 #include <unomap.hxx> 71 #include <unoprnms.hxx> 72 #include <com/sun/star/text/WritingMode2.hpp> 73 #include <editeng/brshitem.hxx> 74 #include <viewimp.hxx> 75 #include <boost/scoped_ptr.hpp> 76 #include <textmarkuphelper.hxx> 77 // --> OD 2010-02-22 #i10825# 78 #include <parachangetrackinginfo.hxx> 79 #include <com/sun/star/text/TextMarkupType.hpp> 80 // <-- 81 // --> OD 2010-03-08 #i92233# 82 #include <comphelper/stlunosequence.hxx> 83 // <-- 84 85 #include <algorithm> 86 87 using namespace ::com::sun::star; 88 using namespace ::com::sun::star::accessibility; 89 90 using beans::PropertyValue; 91 using beans::XMultiPropertySet; 92 using beans::UnknownPropertyException; 93 using beans::PropertyState_DIRECT_VALUE; 94 95 using std::max; 96 using std::min; 97 using std::sort; 98 99 namespace com { namespace sun { namespace star { 100 namespace text { 101 class XText; 102 } 103 } } } 104 105 106 const sal_Char sServiceName[] = "com.sun.star.text.AccessibleParagraphView"; 107 const sal_Char sImplementationName[] = "com.sun.star.comp.Writer.SwAccessibleParagraphView"; 108 const xub_StrLen MAX_DESC_TEXT_LEN = 40; 109 const SwTxtNode* SwAccessibleParagraph::GetTxtNode() const 110 { 111 const SwFrm* pFrm = GetFrm(); 112 DBG_ASSERT( pFrm->IsTxtFrm(), "The text frame has mutated!" ); 113 114 const SwTxtNode* pNode = static_cast<const SwTxtFrm*>(pFrm)->GetTxtNode(); 115 DBG_ASSERT( pNode != NULL, "A text frame without a text node." ); 116 117 return pNode; 118 } 119 120 ::rtl::OUString SwAccessibleParagraph::GetString() 121 { 122 return GetPortionData().GetAccessibleString(); 123 } 124 125 ::rtl::OUString SwAccessibleParagraph::GetDescription() 126 { 127 // --> OD 2004-09-29 #117933# - provide empty description for paragraphs 128 return ::rtl::OUString(); 129 // <-- 130 } 131 132 sal_Int32 SwAccessibleParagraph::GetCaretPos() 133 { 134 sal_Int32 nRet = -1; 135 136 // get the selection's point, and test whether it's in our node 137 // --> OD 2005-12-20 #i27301# - consider adjusted method signature 138 SwPaM* pCaret = GetCursor( false ); // caret is first PaM in PaM-ring 139 // <-- 140 if( pCaret != NULL ) 141 { 142 const SwTxtNode* pNode = GetTxtNode(); 143 144 // check whether the point points into 'our' node 145 SwPosition* pPoint = pCaret->GetPoint(); 146 if( pNode->GetIndex() == pPoint->nNode.GetIndex() ) 147 { 148 // same node? Then check whether it's also within 'our' part 149 // of the paragraph 150 sal_uInt16 nIndex = pPoint->nContent.GetIndex(); 151 if( GetPortionData().IsValidCorePosition( nIndex ) ) 152 { 153 // Yes, it's us! 154 // --> OD 2006-10-19 #70538# 155 // consider that cursor/caret is in front of the list label 156 if ( pCaret->IsInFrontOfLabel() ) 157 { 158 nRet = 0; 159 } 160 else 161 { 162 nRet = GetPortionData().GetAccessiblePosition( nIndex ); 163 } 164 // <-- 165 166 DBG_ASSERT( nRet >= 0, "invalid cursor?" ); 167 DBG_ASSERT( nRet <= GetPortionData().GetAccessibleString(). 168 getLength(), "invalid cursor?" ); 169 } 170 // else: in this paragraph, but in different frame 171 } 172 // else: not in this paragraph 173 } 174 // else: no cursor -> no caret 175 176 return nRet; 177 } 178 179 sal_Bool SwAccessibleParagraph::GetSelection( 180 sal_Int32& nStart, sal_Int32& nEnd) 181 { 182 sal_Bool bRet = sal_False; 183 nStart = -1; 184 nEnd = -1; 185 186 // get the selection, and test whether it affects our text node 187 // --> OD 2005-12-20 #i27301# - consider adjusted method signature 188 SwPaM* pCrsr = GetCursor( true ); 189 // <-- 190 if( pCrsr != NULL ) 191 { 192 // get SwPosition for my node 193 const SwTxtNode* pNode = GetTxtNode(); 194 sal_uLong nHere = pNode->GetIndex(); 195 196 // iterate over ring 197 SwPaM* pRingStart = pCrsr; 198 do 199 { 200 // ignore, if no mark 201 if( pCrsr->HasMark() ) 202 { 203 // check whether nHere is 'inside' pCrsr 204 SwPosition* pStart = pCrsr->Start(); 205 sal_uLong nStartIndex = pStart->nNode.GetIndex(); 206 SwPosition* pEnd = pCrsr->End(); 207 sal_uLong nEndIndex = pEnd->nNode.GetIndex(); 208 if( ( nHere >= nStartIndex ) && 209 ( nHere <= nEndIndex ) ) 210 { 211 // translate start and end positions 212 213 // start position 214 sal_Int32 nLocalStart = -1; 215 if( nHere > nStartIndex ) 216 { 217 // selection starts in previous node: 218 // then our local selection starts with the paragraph 219 nLocalStart = 0; 220 } 221 else 222 { 223 DBG_ASSERT( nHere == nStartIndex, 224 "miscalculated index" ); 225 226 // selection starts in this node: 227 // then check whether it's before or inside our part of 228 // the paragraph, and if so, get the proper position 229 sal_uInt16 nCoreStart = pStart->nContent.GetIndex(); 230 if( nCoreStart < 231 GetPortionData().GetFirstValidCorePosition() ) 232 { 233 nLocalStart = 0; 234 } 235 else if( nCoreStart <= 236 GetPortionData().GetLastValidCorePosition() ) 237 { 238 DBG_ASSERT( 239 GetPortionData().IsValidCorePosition( 240 nCoreStart ), 241 "problem determining valid core position" ); 242 243 nLocalStart = 244 GetPortionData().GetAccessiblePosition( 245 nCoreStart ); 246 } 247 } 248 249 // end position 250 sal_Int32 nLocalEnd = -1; 251 if( nHere < nEndIndex ) 252 { 253 // selection ends in following node: 254 // then our local selection extends to the end 255 nLocalEnd = GetPortionData().GetAccessibleString(). 256 getLength(); 257 } 258 else 259 { 260 DBG_ASSERT( nHere == nEndIndex, 261 "miscalculated index" ); 262 263 // selection ends in this node: then select everything 264 // before our part of the node 265 sal_uInt16 nCoreEnd = pEnd->nContent.GetIndex(); 266 if( nCoreEnd > 267 GetPortionData().GetLastValidCorePosition() ) 268 { 269 // selection extends beyond out part of this para 270 nLocalEnd = GetPortionData().GetAccessibleString(). 271 getLength(); 272 } 273 else if( nCoreEnd >= 274 GetPortionData().GetFirstValidCorePosition() ) 275 { 276 // selection is inside our part of this para 277 DBG_ASSERT( 278 GetPortionData().IsValidCorePosition( 279 nCoreEnd ), 280 "problem determining valid core position" ); 281 282 nLocalEnd = GetPortionData().GetAccessiblePosition( 283 nCoreEnd ); 284 } 285 } 286 287 if( ( nLocalStart != -1 ) && ( nLocalEnd != -1 ) ) 288 { 289 nStart = nLocalStart; 290 nEnd = nLocalEnd; 291 bRet = sal_True; 292 } 293 } 294 // else: this PaM doesn't point to this paragraph 295 } 296 // else: this PaM is collapsed and doesn't select anything 297 298 // next PaM in ring 299 pCrsr = static_cast<SwPaM*>( pCrsr->GetNext() ); 300 } 301 while( !bRet && (pCrsr != pRingStart) ); 302 } 303 // else: nocursor -> no selection 304 305 return bRet; 306 } 307 308 // --> OD 2005-12-20 #i27301# - new parameter <_bForSelection> 309 SwPaM* SwAccessibleParagraph::GetCursor( const bool _bForSelection ) 310 { 311 // get the cursor shell; if we don't have any, we don't have a 312 // cursor/selection either 313 SwPaM* pCrsr = NULL; 314 SwCrsrShell* pCrsrShell = SwAccessibleParagraph::GetCrsrShell(); 315 // --> OD 2005-12-20 #i27301# 316 // - if cursor is retrieved for selection, the cursors for a table selection 317 // has to be returned. 318 if ( pCrsrShell != NULL && 319 ( _bForSelection || !pCrsrShell->IsTableMode() ) ) 320 // <-- 321 { 322 SwFEShell *pFESh = pCrsrShell->ISA( SwFEShell ) 323 ? static_cast< SwFEShell * >( pCrsrShell ) : 0; 324 if( !pFESh || 325 !(pFESh->IsFrmSelected() || pFESh->IsObjSelected() > 0) ) 326 { 327 // get the selection, and test whether it affects our text node 328 pCrsr = pCrsrShell->GetCrsr( sal_False /* ??? */ ); 329 } 330 } 331 332 return pCrsr; 333 } 334 335 sal_Bool SwAccessibleParagraph::IsHeading() const 336 { 337 const SwTxtNode *pTxtNd = GetTxtNode(); 338 return pTxtNd->IsOutline(); 339 } 340 341 void SwAccessibleParagraph::GetStates( 342 ::utl::AccessibleStateSetHelper& rStateSet ) 343 { 344 SwAccessibleContext::GetStates( rStateSet ); 345 346 // MULTILINE 347 rStateSet.AddState( AccessibleStateType::MULTI_LINE ); 348 349 // MULTISELECTABLE 350 SwCrsrShell *pCrsrSh = GetCrsrShell(); 351 if( pCrsrSh ) 352 rStateSet.AddState( AccessibleStateType::MULTI_SELECTABLE ); 353 354 // FOCUSABLE 355 if( pCrsrSh ) 356 rStateSet.AddState( AccessibleStateType::FOCUSABLE ); 357 358 // FOCUSED (simulates node index of cursor) 359 // --> OD 2005-12-20 #i27301# - consider adjusted method signature 360 SwPaM* pCaret = GetCursor( false ); 361 // <-- 362 const SwTxtNode* pTxtNd = GetTxtNode(); 363 if( pCaret != 0 && pTxtNd != 0 && 364 pTxtNd->GetIndex() == pCaret->GetPoint()->nNode.GetIndex() && 365 nOldCaretPos != -1) 366 { 367 Window *pWin = GetWindow(); 368 if( pWin && pWin->HasFocus() ) 369 rStateSet.AddState( AccessibleStateType::FOCUSED ); 370 ::vos::ORef < SwAccessibleContext > xThis( this ); 371 GetMap()->SetCursorContext( xThis ); 372 } 373 } 374 375 void SwAccessibleParagraph::_InvalidateContent( sal_Bool bVisibleDataFired ) 376 { 377 ::rtl::OUString sOldText( GetString() ); 378 379 ClearPortionData(); 380 381 const ::rtl::OUString& rText = GetString(); 382 383 if( rText != sOldText ) 384 { 385 // The text is changed 386 AccessibleEventObject aEvent; 387 aEvent.EventId = AccessibleEventId::TEXT_CHANGED; 388 389 // determine exact changes between sOldText and rText 390 comphelper::OCommonAccessibleText::implInitTextChangedEvent( 391 sOldText, rText, 392 aEvent.OldValue, aEvent.NewValue ); 393 394 FireAccessibleEvent( aEvent ); 395 } 396 else if( !bVisibleDataFired ) 397 { 398 FireVisibleDataEvent(); 399 } 400 401 sal_Bool bNewIsHeading = IsHeading(); 402 sal_Bool bOldIsHeading; 403 { 404 vos::OGuard aGuard( aMutex ); 405 bOldIsHeading = bIsHeading; 406 if( bIsHeading != bNewIsHeading ) 407 bIsHeading = bNewIsHeading; 408 } 409 410 411 if( bNewIsHeading != bOldIsHeading || rText != sOldText ) 412 { 413 ::rtl::OUString sNewDesc( GetDescription() ); 414 ::rtl::OUString sOldDesc; 415 { 416 vos::OGuard aGuard( aMutex ); 417 sOldDesc = sDesc; 418 if( sDesc != sNewDesc ) 419 sDesc = sNewDesc; 420 } 421 422 if( sNewDesc != sOldDesc ) 423 { 424 // The text is changed 425 AccessibleEventObject aEvent; 426 aEvent.EventId = AccessibleEventId::DESCRIPTION_CHANGED; 427 aEvent.OldValue <<= sOldDesc; 428 aEvent.NewValue <<= sNewDesc; 429 430 FireAccessibleEvent( aEvent ); 431 } 432 } 433 } 434 435 void SwAccessibleParagraph::_InvalidateCursorPos() 436 { 437 // The text is changed 438 sal_Int32 nNew = GetCaretPos(); 439 sal_Int32 nOld; 440 { 441 vos::OGuard aGuard( aMutex ); 442 nOld = nOldCaretPos; 443 nOldCaretPos = nNew; 444 } 445 if( -1 != nNew ) 446 { 447 // remember that object as the one that has the caret. This is 448 // neccessary to notify that object if the cursor leaves it. 449 ::vos::ORef < SwAccessibleContext > xThis( this ); 450 GetMap()->SetCursorContext( xThis ); 451 } 452 453 Window *pWin = GetWindow(); 454 if( nOld != nNew ) 455 { 456 // The cursor's node position is sumilated by the focus! 457 if( pWin && pWin->HasFocus() && -1 == nOld ) 458 FireStateChangedEvent( AccessibleStateType::FOCUSED, sal_True ); 459 460 461 AccessibleEventObject aEvent; 462 aEvent.EventId = AccessibleEventId::CARET_CHANGED; 463 aEvent.OldValue <<= nOld; 464 aEvent.NewValue <<= nNew; 465 466 FireAccessibleEvent( aEvent ); 467 468 if( pWin && pWin->HasFocus() && -1 == nNew ) 469 FireStateChangedEvent( AccessibleStateType::FOCUSED, sal_False ); 470 } 471 } 472 473 void SwAccessibleParagraph::_InvalidateFocus() 474 { 475 Window *pWin = GetWindow(); 476 if( pWin ) 477 { 478 sal_Int32 nPos; 479 { 480 vos::OGuard aGuard( aMutex ); 481 nPos = nOldCaretPos; 482 } 483 ASSERT( nPos != -1, "focus object should be selected" ); 484 485 FireStateChangedEvent( AccessibleStateType::FOCUSED, 486 pWin->HasFocus() && nPos != -1 ); 487 } 488 } 489 490 SwAccessibleParagraph::SwAccessibleParagraph( 491 SwAccessibleMap& rInitMap, 492 const SwTxtFrm& rTxtFrm ) 493 // --> OD 2010-02-24 #i108125# 494 : SwClient( const_cast<SwTxtNode*>(rTxtFrm.GetTxtNode()) ) 495 // <-- 496 , SwAccessibleContext( &rInitMap, AccessibleRole::PARAGRAPH, &rTxtFrm ) 497 , sDesc() 498 , pPortionData( NULL ) 499 , pHyperTextData( NULL ) 500 , nOldCaretPos( -1 ) 501 , bIsHeading( sal_False ) 502 , aSelectionHelper( *this ) 503 // --> OD 2010-02-19 #i108125# 504 , mpParaChangeTrackInfo( new SwParaChangeTrackingInfo( rTxtFrm ) ) 505 // <-- 506 { 507 vos::OGuard aGuard(Application::GetSolarMutex()); 508 509 bIsHeading = IsHeading(); 510 // --> OD 2004-09-27 #117970# - set an empty accessibility name for paragraphs 511 SetName( ::rtl::OUString() ); 512 // <-- 513 514 // If this object has the focus, then it is remembered by the map itself. 515 nOldCaretPos = GetCaretPos(); 516 } 517 518 SwAccessibleParagraph::~SwAccessibleParagraph() 519 { 520 vos::OGuard aGuard(Application::GetSolarMutex()); 521 522 delete pPortionData; 523 delete pHyperTextData; 524 // --> OD 2010-02-22 #i108125# 525 delete mpParaChangeTrackInfo; 526 // <-- 527 } 528 529 sal_Bool SwAccessibleParagraph::HasCursor() 530 { 531 vos::OGuard aGuard( aMutex ); 532 return nOldCaretPos != -1; 533 } 534 535 void SwAccessibleParagraph::UpdatePortionData() 536 throw( uno::RuntimeException ) 537 { 538 // obtain the text frame 539 DBG_ASSERT( GetFrm() != NULL, "The text frame has vanished!" ); 540 DBG_ASSERT( GetFrm()->IsTxtFrm(), "The text frame has mutated!" ); 541 const SwTxtFrm* pFrm = static_cast<const SwTxtFrm*>( GetFrm() ); 542 543 // build new portion data 544 delete pPortionData; 545 pPortionData = new SwAccessiblePortionData( 546 pFrm->GetTxtNode(), GetMap()->GetShell()->GetViewOptions() ); 547 pFrm->VisitPortions( *pPortionData ); 548 549 DBG_ASSERT( pPortionData != NULL, "UpdatePortionData() failed" ); 550 } 551 552 void SwAccessibleParagraph::ClearPortionData() 553 { 554 delete pPortionData; 555 pPortionData = NULL; 556 557 delete pHyperTextData; 558 pHyperTextData = 0; 559 } 560 561 562 void SwAccessibleParagraph::ExecuteAtViewShell( sal_uInt16 nSlot ) 563 { 564 DBG_ASSERT( GetMap() != NULL, "no map?" ); 565 ViewShell* pViewShell = GetMap()->GetShell(); 566 567 DBG_ASSERT( pViewShell != NULL, "View shell exptected!" ); 568 SfxViewShell* pSfxShell = pViewShell->GetSfxViewShell(); 569 570 DBG_ASSERT( pSfxShell != NULL, "SfxViewShell shell exptected!" ); 571 if( !pSfxShell ) 572 return; 573 574 SfxViewFrame *pFrame = pSfxShell->GetViewFrame(); 575 DBG_ASSERT( pFrame != NULL, "View frame exptected!" ); 576 if( !pFrame ) 577 return; 578 579 SfxDispatcher *pDispatcher = pFrame->GetDispatcher(); 580 DBG_ASSERT( pDispatcher != NULL, "Dispatcher exptected!" ); 581 if( !pDispatcher ) 582 return; 583 584 pDispatcher->Execute( nSlot ); 585 } 586 587 SwXTextPortion* SwAccessibleParagraph::CreateUnoPortion( 588 sal_Int32 nStartIndex, 589 sal_Int32 nEndIndex ) 590 { 591 DBG_ASSERT( (IsValidChar(nStartIndex, GetString().getLength()) && 592 (nEndIndex == -1)) || 593 IsValidRange(nStartIndex, nEndIndex, GetString().getLength()), 594 "please check parameters before calling this method" ); 595 596 sal_uInt16 nStart = GetPortionData().GetModelPosition( nStartIndex ); 597 sal_uInt16 nEnd = (nEndIndex == -1) ? (nStart + 1) : 598 GetPortionData().GetModelPosition( nEndIndex ); 599 600 // create UNO cursor 601 SwTxtNode* pTxtNode = const_cast<SwTxtNode*>( GetTxtNode() ); 602 SwIndex aIndex( pTxtNode, nStart ); 603 SwPosition aStartPos( *pTxtNode, aIndex ); 604 SwUnoCrsr* pUnoCursor = pTxtNode->GetDoc()->CreateUnoCrsr( aStartPos ); 605 pUnoCursor->SetMark(); 606 pUnoCursor->GetMark()->nContent = nEnd; 607 608 // create a (dummy) text portion to be returned 609 uno::Reference<text::XText> aEmpty; 610 SwXTextPortion* pPortion = 611 new SwXTextPortion ( pUnoCursor, aEmpty, PORTION_TEXT); 612 delete pUnoCursor; 613 614 return pPortion; 615 } 616 617 618 // 619 // range checking for parameter 620 // 621 622 sal_Bool SwAccessibleParagraph::IsValidChar( 623 sal_Int32 nPos, sal_Int32 nLength) 624 { 625 return (nPos >= 0) && (nPos < nLength); 626 } 627 628 sal_Bool SwAccessibleParagraph::IsValidPosition( 629 sal_Int32 nPos, sal_Int32 nLength) 630 { 631 return (nPos >= 0) && (nPos <= nLength); 632 } 633 634 sal_Bool SwAccessibleParagraph::IsValidRange( 635 sal_Int32 nBegin, sal_Int32 nEnd, sal_Int32 nLength) 636 { 637 return IsValidPosition(nBegin, nLength) && IsValidPosition(nEnd, nLength); 638 } 639 640 641 // 642 // text boundaries 643 // 644 645 646 sal_Bool SwAccessibleParagraph::GetCharBoundary( 647 i18n::Boundary& rBound, 648 const ::rtl::OUString&, 649 sal_Int32 nPos ) 650 { 651 rBound.startPos = nPos; 652 rBound.endPos = nPos+1; 653 return sal_True; 654 } 655 656 sal_Bool SwAccessibleParagraph::GetWordBoundary( 657 i18n::Boundary& rBound, 658 const ::rtl::OUString& rText, 659 sal_Int32 nPos ) 660 { 661 sal_Bool bRet = sal_False; 662 663 // now ask the Break-Iterator for the word 664 DBG_ASSERT( pBreakIt != NULL, "We always need a break." ); 665 DBG_ASSERT( pBreakIt->GetBreakIter().is(), "No break-iterator." ); 666 if( pBreakIt->GetBreakIter().is() ) 667 { 668 // get locale for this position 669 sal_uInt16 nModelPos = GetPortionData().GetModelPosition( nPos ); 670 lang::Locale aLocale = pBreakIt->GetLocale( 671 GetTxtNode()->GetLang( nModelPos ) ); 672 673 // which type of word are we interested in? 674 // (DICTIONARY_WORD includes punctuation, ANY_WORD doesn't.) 675 const sal_uInt16 nWordType = i18n::WordType::ANY_WORD; 676 677 // get word boundary, as the Break-Iterator sees fit. 678 rBound = pBreakIt->GetBreakIter()->getWordBoundary( 679 rText, nPos, aLocale, nWordType, sal_True ); 680 681 // It's a word if the first character is an alpha-numeric character. 682 bRet = GetAppCharClass().isLetterNumeric( 683 rText.getStr()[ rBound.startPos ] ); 684 } 685 else 686 { 687 // no break Iterator -> no word 688 rBound.startPos = nPos; 689 rBound.endPos = nPos; 690 } 691 692 return bRet; 693 } 694 695 sal_Bool SwAccessibleParagraph::GetSentenceBoundary( 696 i18n::Boundary& rBound, 697 const ::rtl::OUString&, 698 sal_Int32 nPos ) 699 { 700 GetPortionData().GetSentenceBoundary( rBound, nPos ); 701 return sal_True; 702 } 703 704 sal_Bool SwAccessibleParagraph::GetLineBoundary( 705 i18n::Boundary& rBound, 706 const ::rtl::OUString& rText, 707 sal_Int32 nPos ) 708 { 709 if( rText.getLength() == nPos ) 710 GetPortionData().GetLastLineBoundary( rBound ); 711 else 712 GetPortionData().GetLineBoundary( rBound, nPos ); 713 return sal_True; 714 } 715 716 sal_Bool SwAccessibleParagraph::GetParagraphBoundary( 717 i18n::Boundary& rBound, 718 const ::rtl::OUString& rText, 719 sal_Int32 ) 720 { 721 rBound.startPos = 0; 722 rBound.endPos = rText.getLength(); 723 return sal_True; 724 } 725 726 sal_Bool SwAccessibleParagraph::GetAttributeBoundary( 727 i18n::Boundary& rBound, 728 const ::rtl::OUString&, 729 sal_Int32 nPos ) 730 { 731 GetPortionData().GetAttributeBoundary( rBound, nPos ); 732 return sal_True; 733 } 734 735 sal_Bool SwAccessibleParagraph::GetGlyphBoundary( 736 i18n::Boundary& rBound, 737 const ::rtl::OUString& rText, 738 sal_Int32 nPos ) 739 { 740 sal_Bool bRet = sal_False; 741 742 // ask the Break-Iterator for the glyph by moving one cell 743 // forward, and then one cell back 744 DBG_ASSERT( pBreakIt != NULL, "We always need a break." ); 745 DBG_ASSERT( pBreakIt->GetBreakIter().is(), "No break-iterator." ); 746 if( pBreakIt->GetBreakIter().is() ) 747 { 748 // get locale for this position 749 sal_uInt16 nModelPos = GetPortionData().GetModelPosition( nPos ); 750 lang::Locale aLocale = pBreakIt->GetLocale( 751 GetTxtNode()->GetLang( nModelPos ) ); 752 753 // get word boundary, as the Break-Iterator sees fit. 754 const sal_uInt16 nIterMode = i18n::CharacterIteratorMode::SKIPCELL; 755 sal_Int32 nDone = 0; 756 rBound.endPos = pBreakIt->GetBreakIter()->nextCharacters( 757 rText, nPos, aLocale, nIterMode, 1, nDone ); 758 rBound.startPos = pBreakIt->GetBreakIter()->previousCharacters( 759 rText, rBound.endPos, aLocale, nIterMode, 1, nDone ); 760 761 bRet = ((rBound.startPos <= nPos) && (nPos <= rBound.endPos)); 762 DBG_ASSERT( rBound.startPos <= nPos, "start pos too high" ); 763 DBG_ASSERT( rBound.endPos >= nPos, "end pos too low" ); 764 } 765 else 766 { 767 // no break Iterator -> no glyph 768 rBound.startPos = nPos; 769 rBound.endPos = nPos; 770 } 771 772 return bRet; 773 } 774 775 776 sal_Bool SwAccessibleParagraph::GetTextBoundary( 777 i18n::Boundary& rBound, 778 const ::rtl::OUString& rText, 779 sal_Int32 nPos, 780 sal_Int16 nTextType ) 781 throw ( 782 lang::IndexOutOfBoundsException, 783 lang::IllegalArgumentException, 784 uno::RuntimeException) 785 { 786 // error checking 787 if( !( AccessibleTextType::LINE == nTextType 788 ? IsValidPosition( nPos, rText.getLength() ) 789 : IsValidChar( nPos, rText.getLength() ) ) ) 790 throw lang::IndexOutOfBoundsException(); 791 792 sal_Bool bRet; 793 794 switch( nTextType ) 795 { 796 case AccessibleTextType::WORD: 797 bRet = GetWordBoundary( rBound, rText, nPos ); 798 break; 799 800 case AccessibleTextType::SENTENCE: 801 bRet = GetSentenceBoundary( rBound, rText, nPos ); 802 break; 803 804 case AccessibleTextType::PARAGRAPH: 805 bRet = GetParagraphBoundary( rBound, rText, nPos ); 806 break; 807 808 case AccessibleTextType::CHARACTER: 809 bRet = GetCharBoundary( rBound, rText, nPos ); 810 break; 811 812 case AccessibleTextType::LINE: 813 bRet = GetLineBoundary( rBound, rText, nPos ); 814 break; 815 816 case AccessibleTextType::ATTRIBUTE_RUN: 817 bRet = GetAttributeBoundary( rBound, rText, nPos ); 818 break; 819 820 case AccessibleTextType::GLYPH: 821 bRet = GetGlyphBoundary( rBound, rText, nPos ); 822 break; 823 824 default: 825 throw lang::IllegalArgumentException( ); 826 } 827 828 return bRet; 829 } 830 831 ::rtl::OUString SAL_CALL SwAccessibleParagraph::getAccessibleDescription (void) 832 throw (uno::RuntimeException) 833 { 834 vos::OGuard aGuard(Application::GetSolarMutex()); 835 836 CHECK_FOR_DEFUNC( XAccessibleContext ); 837 838 vos::OGuard aGuard2( aMutex ); 839 if( !sDesc.getLength() ) 840 sDesc = GetDescription(); 841 842 return sDesc; 843 } 844 845 lang::Locale SAL_CALL SwAccessibleParagraph::getLocale (void) 846 throw (IllegalAccessibleComponentStateException, uno::RuntimeException) 847 { 848 vos::OGuard aGuard(Application::GetSolarMutex()); 849 850 SwTxtFrm *pTxtFrm = PTR_CAST( SwTxtFrm, GetFrm() ); 851 if( !pTxtFrm ) 852 { 853 THROW_RUNTIME_EXCEPTION( XAccessibleContext, "internal error (no text frame)" ); 854 } 855 856 const SwTxtNode *pTxtNd = pTxtFrm->GetTxtNode(); 857 lang::Locale aLoc( pBreakIt->GetLocale( pTxtNd->GetLang( 0 ) ) ); 858 859 return aLoc; 860 } 861 862 /** paragraphs are in relation CONTENT_FLOWS_FROM and/or CONTENT_FLOWS_TO 863 864 OD 2005-12-02 #i27138# 865 866 @author OD 867 */ 868 uno::Reference<XAccessibleRelationSet> SAL_CALL SwAccessibleParagraph::getAccessibleRelationSet() 869 throw ( uno::RuntimeException ) 870 { 871 vos::OGuard aGuard(Application::GetSolarMutex()); 872 CHECK_FOR_DEFUNC( XAccessibleContext ); 873 874 utl::AccessibleRelationSetHelper* pHelper = new utl::AccessibleRelationSetHelper(); 875 876 const SwTxtFrm* pTxtFrm = dynamic_cast<const SwTxtFrm*>(GetFrm()); 877 ASSERT( pTxtFrm, 878 "<SwAccessibleParagraph::getAccessibleRelationSet()> - missing text frame"); 879 if ( pTxtFrm ) 880 { 881 const SwCntntFrm* pPrevCntFrm( pTxtFrm->FindPrevCnt( true ) ); 882 if ( pPrevCntFrm ) 883 { 884 uno::Sequence< uno::Reference<XInterface> > aSequence(1); 885 aSequence[0] = GetMap()->GetContext( pPrevCntFrm ); 886 AccessibleRelation aAccRel( AccessibleRelationType::CONTENT_FLOWS_FROM, 887 aSequence ); 888 pHelper->AddRelation( aAccRel ); 889 } 890 891 const SwCntntFrm* pNextCntFrm( pTxtFrm->FindNextCnt( true ) ); 892 if ( pNextCntFrm ) 893 { 894 uno::Sequence< uno::Reference<XInterface> > aSequence(1); 895 aSequence[0] = GetMap()->GetContext( pNextCntFrm ); 896 AccessibleRelation aAccRel( AccessibleRelationType::CONTENT_FLOWS_TO, 897 aSequence ); 898 pHelper->AddRelation( aAccRel ); 899 } 900 } 901 902 return pHelper; 903 } 904 905 void SAL_CALL SwAccessibleParagraph::grabFocus() 906 throw (uno::RuntimeException) 907 { 908 vos::OGuard aGuard(Application::GetSolarMutex()); 909 910 CHECK_FOR_DEFUNC( XAccessibleContext ); 911 912 // get cursor shell 913 SwCrsrShell *pCrsrSh = GetCrsrShell(); 914 // --> OD 2005-12-20 #i27301# - consider new method signature 915 SwPaM *pCrsr = GetCursor( false ); 916 // <-- 917 const SwTxtFrm *pTxtFrm = static_cast<const SwTxtFrm*>( GetFrm() ); 918 const SwTxtNode* pTxtNd = pTxtFrm->GetTxtNode(); 919 920 if( pCrsrSh != 0 && pTxtNd != 0 && 921 ( pCrsr == 0 || 922 pCrsr->GetPoint()->nNode.GetIndex() != pTxtNd->GetIndex() || 923 !pTxtFrm->IsInside( pCrsr->GetPoint()->nContent.GetIndex()) ) ) 924 { 925 // create pam for selection 926 SwIndex aIndex( const_cast< SwTxtNode * >( pTxtNd ), 927 pTxtFrm->GetOfst() ); 928 SwPosition aStartPos( *pTxtNd, aIndex ); 929 SwPaM aPaM( aStartPos ); 930 931 // set PaM at cursor shell 932 Select( aPaM ); 933 934 935 } 936 937 /* ->#i13955# */ 938 Window * pWindow = GetWindow(); 939 940 if (pWindow != NULL) 941 pWindow->GrabFocus(); 942 /* <-#i13955# */ 943 } 944 945 // --> OD 2007-01-17 #i71385# 946 bool lcl_GetBackgroundColor( Color & rColor, 947 const SwFrm* pFrm, 948 SwCrsrShell* pCrsrSh ) 949 { 950 const SvxBrushItem* pBackgrdBrush = 0; 951 const Color* pSectionTOXColor = 0; 952 SwRect aDummyRect; 953 if ( pFrm && 954 pFrm->GetBackgroundBrush( pBackgrdBrush, pSectionTOXColor, aDummyRect, false ) ) 955 { 956 if ( pSectionTOXColor ) 957 { 958 rColor = *pSectionTOXColor; 959 return true; 960 } 961 else 962 { 963 rColor = pBackgrdBrush->GetColor(); 964 return true; 965 } 966 } 967 else if ( pCrsrSh ) 968 { 969 rColor = pCrsrSh->Imp()->GetRetoucheColor(); 970 return true; 971 } 972 973 return false; 974 } 975 976 sal_Int32 SAL_CALL SwAccessibleParagraph::getForeground() 977 throw (uno::RuntimeException) 978 { 979 Color aBackgroundCol; 980 981 if ( lcl_GetBackgroundColor( aBackgroundCol, GetFrm(), GetCrsrShell() ) ) 982 { 983 if ( aBackgroundCol.IsDark() ) 984 { 985 return COL_WHITE; 986 } 987 else 988 { 989 return COL_BLACK; 990 } 991 } 992 993 return SwAccessibleContext::getForeground(); 994 } 995 996 sal_Int32 SAL_CALL SwAccessibleParagraph::getBackground() 997 throw (uno::RuntimeException) 998 { 999 Color aBackgroundCol; 1000 1001 if ( lcl_GetBackgroundColor( aBackgroundCol, GetFrm(), GetCrsrShell() ) ) 1002 { 1003 return aBackgroundCol.GetColor(); 1004 } 1005 1006 return SwAccessibleContext::getBackground(); 1007 } 1008 // <-- 1009 1010 ::rtl::OUString SAL_CALL SwAccessibleParagraph::getImplementationName() 1011 throw( uno::RuntimeException ) 1012 { 1013 return ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(sImplementationName)); 1014 } 1015 1016 sal_Bool SAL_CALL SwAccessibleParagraph::supportsService( 1017 const ::rtl::OUString& sTestServiceName) 1018 throw (uno::RuntimeException) 1019 { 1020 return sTestServiceName.equalsAsciiL( sServiceName, 1021 sizeof(sServiceName)-1 ) || 1022 sTestServiceName.equalsAsciiL( sAccessibleServiceName, 1023 sizeof(sAccessibleServiceName)-1 ); 1024 } 1025 1026 uno::Sequence< ::rtl::OUString > SAL_CALL SwAccessibleParagraph::getSupportedServiceNames() 1027 throw( uno::RuntimeException ) 1028 { 1029 uno::Sequence< ::rtl::OUString > aRet(2); 1030 ::rtl::OUString* pArray = aRet.getArray(); 1031 pArray[0] = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(sServiceName) ); 1032 pArray[1] = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(sAccessibleServiceName) ); 1033 return aRet; 1034 } 1035 1036 // 1037 //===== XInterface ======================================================= 1038 // 1039 1040 uno::Any SwAccessibleParagraph::queryInterface( const uno::Type& rType ) 1041 throw (uno::RuntimeException) 1042 { 1043 uno::Any aRet; 1044 if ( rType == ::getCppuType((uno::Reference<XAccessibleText> *)0) ) 1045 { 1046 uno::Reference<XAccessibleText> aAccText = (XAccessibleText *) *this; // resolve ambiguity 1047 aRet <<= aAccText; 1048 } 1049 else if ( rType == ::getCppuType((uno::Reference<XAccessibleEditableText> *)0) ) 1050 { 1051 uno::Reference<XAccessibleEditableText> aAccEditText = this; 1052 aRet <<= aAccEditText; 1053 } 1054 else if ( rType == ::getCppuType((uno::Reference<XAccessibleSelection> *)0) ) 1055 { 1056 uno::Reference<XAccessibleSelection> aAccSel = this; 1057 aRet <<= aAccSel; 1058 } 1059 else if ( rType == ::getCppuType((uno::Reference<XAccessibleHypertext> *)0) ) 1060 { 1061 uno::Reference<XAccessibleHypertext> aAccHyp = this; 1062 aRet <<= aAccHyp; 1063 } 1064 // --> OD 2006-07-13 #i63870# 1065 // add interface com::sun:star:accessibility::XAccessibleTextAttributes 1066 else if ( rType == ::getCppuType((uno::Reference<XAccessibleTextAttributes> *)0) ) 1067 { 1068 uno::Reference<XAccessibleTextAttributes> aAccTextAttr = this; 1069 aRet <<= aAccTextAttr; 1070 } 1071 // <-- 1072 // --> OD 2008-06-10 #i89175# 1073 // add interface com::sun:star:accessibility::XAccessibleTextMarkup 1074 else if ( rType == ::getCppuType((uno::Reference<XAccessibleTextMarkup> *)0) ) 1075 { 1076 uno::Reference<XAccessibleTextMarkup> aAccTextMarkup = this; 1077 aRet <<= aAccTextMarkup; 1078 } 1079 // add interface com::sun:star:accessibility::XAccessibleMultiLineText 1080 else if ( rType == ::getCppuType((uno::Reference<XAccessibleMultiLineText> *)0) ) 1081 { 1082 uno::Reference<XAccessibleMultiLineText> aAccMultiLineText = this; 1083 aRet <<= aAccMultiLineText; 1084 } 1085 // <-- 1086 else 1087 { 1088 aRet = SwAccessibleContext::queryInterface(rType); 1089 } 1090 1091 return aRet; 1092 } 1093 1094 //====== XTypeProvider ==================================================== 1095 uno::Sequence< uno::Type > SAL_CALL SwAccessibleParagraph::getTypes() throw(uno::RuntimeException) 1096 { 1097 uno::Sequence< uno::Type > aTypes( SwAccessibleContext::getTypes() ); 1098 1099 sal_Int32 nIndex = aTypes.getLength(); 1100 // --> OD 2006-07-13 #i63870# 1101 // add type accessibility::XAccessibleTextAttributes 1102 // --> OD 2008-06-10 #i89175# 1103 // add type accessibility::XAccessibleTextMarkup and accessibility::XAccessibleMultiLineText 1104 aTypes.realloc( nIndex + 6 ); 1105 1106 uno::Type* pTypes = aTypes.getArray(); 1107 pTypes[nIndex++] = ::getCppuType( static_cast< uno::Reference< XAccessibleEditableText > * >( 0 ) ); 1108 pTypes[nIndex++] = ::getCppuType( static_cast< uno::Reference< XAccessibleTextAttributes > * >( 0 ) ); 1109 pTypes[nIndex++] = ::getCppuType( static_cast< uno::Reference< XAccessibleSelection > * >( 0 ) ); 1110 pTypes[nIndex++] = ::getCppuType( static_cast< uno::Reference< XAccessibleTextMarkup > * >( 0 ) ); 1111 pTypes[nIndex++] = ::getCppuType( static_cast< uno::Reference< XAccessibleMultiLineText > * >( 0 ) ); 1112 pTypes[nIndex] = ::getCppuType( static_cast< uno::Reference< XAccessibleHypertext > * >( 0 ) ); 1113 // <-- 1114 1115 return aTypes; 1116 } 1117 1118 uno::Sequence< sal_Int8 > SAL_CALL SwAccessibleParagraph::getImplementationId() 1119 throw(uno::RuntimeException) 1120 { 1121 vos::OGuard aGuard(Application::GetSolarMutex()); 1122 static uno::Sequence< sal_Int8 > aId( 16 ); 1123 static sal_Bool bInit = sal_False; 1124 if(!bInit) 1125 { 1126 rtl_createUuid( (sal_uInt8 *)(aId.getArray() ), 0, sal_True ); 1127 bInit = sal_True; 1128 } 1129 return aId; 1130 } 1131 1132 1133 // 1134 //===== XAccesibleText =================================================== 1135 // 1136 1137 sal_Int32 SwAccessibleParagraph::getCaretPosition() 1138 throw (uno::RuntimeException) 1139 { 1140 vos::OGuard aGuard(Application::GetSolarMutex()); 1141 1142 CHECK_FOR_DEFUNC_THIS( XAccessibleText, *this ); 1143 1144 sal_Int32 nRet = GetCaretPos(); 1145 { 1146 vos::OGuard aOldCaretPosGuard( aMutex ); 1147 ASSERT( nRet == nOldCaretPos, "caret pos out of sync" ); 1148 nOldCaretPos = nRet; 1149 } 1150 if( -1 != nRet ) 1151 { 1152 ::vos::ORef < SwAccessibleContext > xThis( this ); 1153 GetMap()->SetCursorContext( xThis ); 1154 } 1155 1156 return nRet; 1157 } 1158 1159 sal_Bool SAL_CALL SwAccessibleParagraph::setCaretPosition( sal_Int32 nIndex ) 1160 throw (lang::IndexOutOfBoundsException, uno::RuntimeException) 1161 { 1162 vos::OGuard aGuard(Application::GetSolarMutex()); 1163 1164 CHECK_FOR_DEFUNC_THIS( XAccessibleText, *this ); 1165 1166 // parameter checking 1167 sal_Int32 nLength = GetString().getLength(); 1168 if ( ! IsValidPosition( nIndex, nLength ) ) 1169 { 1170 throw lang::IndexOutOfBoundsException(); 1171 } 1172 1173 sal_Bool bRet = sal_False; 1174 1175 // get cursor shell 1176 SwCrsrShell* pCrsrShell = GetCrsrShell(); 1177 if( pCrsrShell != NULL ) 1178 { 1179 // create pam for selection 1180 SwTxtNode* pNode = const_cast<SwTxtNode*>( GetTxtNode() ); 1181 SwIndex aIndex( pNode, GetPortionData().GetModelPosition(nIndex)); 1182 SwPosition aStartPos( *pNode, aIndex ); 1183 SwPaM aPaM( aStartPos ); 1184 1185 // set PaM at cursor shell 1186 bRet = Select( aPaM ); 1187 } 1188 1189 return bRet; 1190 } 1191 1192 sal_Unicode SwAccessibleParagraph::getCharacter( sal_Int32 nIndex ) 1193 throw (lang::IndexOutOfBoundsException, uno::RuntimeException) 1194 { 1195 vos::OGuard aGuard(Application::GetSolarMutex()); 1196 1197 CHECK_FOR_DEFUNC_THIS( XAccessibleText, *this ); 1198 1199 ::rtl::OUString sText( GetString() ); 1200 1201 // return character (if valid) 1202 if( IsValidChar(nIndex, sText.getLength() ) ) 1203 { 1204 return sText.getStr()[nIndex]; 1205 } 1206 else 1207 throw lang::IndexOutOfBoundsException(); 1208 } 1209 1210 // --> OD 2006-07-20 #i63870# 1211 // re-implement method on behalf of methods <_getDefaultAttributesImpl(..)> and 1212 // <_getRunAttributesImpl(..)> 1213 uno::Sequence<PropertyValue> SwAccessibleParagraph::getCharacterAttributes( 1214 sal_Int32 nIndex, 1215 const uno::Sequence< ::rtl::OUString >& aRequestedAttributes ) 1216 throw (lang::IndexOutOfBoundsException, uno::RuntimeException) 1217 { 1218 1219 vos::OGuard aGuard(Application::GetSolarMutex()); 1220 CHECK_FOR_DEFUNC_THIS( XAccessibleText, *this ); 1221 1222 const ::rtl::OUString& rText = GetString(); 1223 1224 if( ! IsValidChar( nIndex, rText.getLength() ) ) 1225 throw lang::IndexOutOfBoundsException(); 1226 1227 // retrieve default character attributes 1228 tAccParaPropValMap aDefAttrSeq; 1229 _getDefaultAttributesImpl( aRequestedAttributes, aDefAttrSeq, true ); 1230 1231 // retrieved run character attributes 1232 tAccParaPropValMap aRunAttrSeq; 1233 _getRunAttributesImpl( nIndex, aRequestedAttributes, aRunAttrSeq ); 1234 1235 // merge default and run attributes 1236 uno::Sequence< PropertyValue > aValues( aDefAttrSeq.size() ); 1237 PropertyValue* pValues = aValues.getArray(); 1238 sal_Int32 i = 0; 1239 for ( tAccParaPropValMap::const_iterator aDefIter = aDefAttrSeq.begin(); 1240 aDefIter != aDefAttrSeq.end(); 1241 ++aDefIter ) 1242 { 1243 tAccParaPropValMap::const_iterator aRunIter = 1244 aRunAttrSeq.find( aDefIter->first ); 1245 if ( aRunIter != aRunAttrSeq.end() ) 1246 { 1247 pValues[i] = aRunIter->second; 1248 } 1249 else 1250 { 1251 pValues[i] = aDefIter->second; 1252 } 1253 ++i; 1254 } 1255 1256 // // create a (dummy) text portion for the sole purpose of calling 1257 // // getPropertyValues on it 1258 // Reference<XMultiPropertySet> xPortion = CreateUnoPortion( nIndex, nIndex + 1 ); 1259 1260 // // get values 1261 // Sequence<OUString> aNames = getAttributeNames(); 1262 // sal_Int32 nLength = aNames.getLength(); 1263 // Sequence<Any> aAnys( nLength ); 1264 // aAnys = xPortion->getPropertyValues( aNames ); 1265 1266 // // copy names + anys into return sequence 1267 // Sequence<PropertyValue> aValues( aNames.getLength() ); 1268 // const OUString* pNames = aNames.getConstArray(); 1269 // const Any* pAnys = aAnys.getConstArray(); 1270 // PropertyValue* pValues = aValues.getArray(); 1271 // for( sal_Int32 i = 0; i < nLength; i++ ) 1272 // { 1273 // PropertyValue& rValue = pValues[i]; 1274 // rValue.Name = pNames[i]; 1275 // rValue.Value = pAnys[i]; 1276 // rValue.Handle = -1; // handle not supported 1277 // rValue.State = PropertyState_DIRECT_VALUE; // states not supported 1278 // } 1279 1280 // // adjust background color if we're in a gray portion 1281 // DBG_ASSERT( pValues[CHAR_BACK_COLOR_POS].Name. 1282 // equalsAsciiL(RTL_CONSTASCII_STRINGPARAM("CharBackColor")), 1283 // "Please adjust CHAR_BACK_COLOR_POS constant." ); 1284 // if( GetPortionData().IsInGrayPortion( nIndex ) ) 1285 // pValues[CHAR_BACK_COLOR_POS].Value <<= SwViewOption::GetFieldShadingsColor().GetColor(); 1286 1287 return aValues; 1288 } 1289 1290 // --> OD 2006-07-11 #i63870# 1291 void SwAccessibleParagraph::_getDefaultAttributesImpl( 1292 const uno::Sequence< ::rtl::OUString >& aRequestedAttributes, 1293 tAccParaPropValMap& rDefAttrSeq, 1294 const bool bOnlyCharAttrs ) 1295 { 1296 // retrieve default attributes 1297 const SwTxtNode* pTxtNode( GetTxtNode() ); 1298 ::boost::scoped_ptr<SfxItemSet> pSet; 1299 if ( !bOnlyCharAttrs ) 1300 { 1301 pSet.reset( new SfxItemSet( const_cast<SwAttrPool&>(pTxtNode->GetDoc()->GetAttrPool()), 1302 RES_CHRATR_BEGIN, RES_CHRATR_END - 1, 1303 RES_PARATR_BEGIN, RES_PARATR_END - 1, 1304 RES_FRMATR_BEGIN, RES_FRMATR_END - 1, 1305 0 ) ); 1306 } 1307 else 1308 { 1309 pSet.reset( new SfxItemSet( const_cast<SwAttrPool&>(pTxtNode->GetDoc()->GetAttrPool()), 1310 RES_CHRATR_BEGIN, RES_CHRATR_END - 1, 1311 0 ) ); 1312 } 1313 // --> OD 2007-11-12 #i82637# 1314 // From the perspective of the a11y API the default character attributes 1315 // are the character attributes, which are set at the paragraph style 1316 // of the paragraph. The character attributes set at the automatic paragraph 1317 // style of the paragraph are treated as run attributes. 1318 // pTxtNode->SwCntntNode::GetAttr( *pSet ); 1319 // get default paragraph attributes, if needed, and merge these into <pSet> 1320 if ( !bOnlyCharAttrs ) 1321 { 1322 SfxItemSet aParaSet( const_cast<SwAttrPool&>(pTxtNode->GetDoc()->GetAttrPool()), 1323 RES_PARATR_BEGIN, RES_PARATR_END - 1, 1324 RES_FRMATR_BEGIN, RES_FRMATR_END - 1, 1325 0 ); 1326 pTxtNode->SwCntntNode::GetAttr( aParaSet ); 1327 pSet->Put( aParaSet ); 1328 } 1329 // get default character attributes and merge these into <pSet> 1330 ASSERT( pTxtNode->GetTxtColl(), 1331 "<SwAccessibleParagraph::_getDefaultAttributesImpl(..)> - missing paragraph style. Serious defect, please inform OD!" ); 1332 if ( pTxtNode->GetTxtColl() ) 1333 { 1334 SfxItemSet aCharSet( const_cast<SwAttrPool&>(pTxtNode->GetDoc()->GetAttrPool()), 1335 RES_CHRATR_BEGIN, RES_CHRATR_END - 1, 1336 0 ); 1337 aCharSet.Put( pTxtNode->GetTxtColl()->GetAttrSet() ); 1338 pSet->Put( aCharSet ); 1339 } 1340 // <-- 1341 1342 // build-up sequence containing the run attributes <rDefAttrSeq> 1343 tAccParaPropValMap aDefAttrSeq; 1344 { 1345 const SfxItemPropertyMap* pPropMap = 1346 aSwMapProvider.GetPropertySet( PROPERTY_MAP_TEXT_CURSOR )->getPropertyMap(); 1347 PropertyEntryVector_t aPropertyEntries = pPropMap->getPropertyEntries(); 1348 PropertyEntryVector_t::const_iterator aPropIt = aPropertyEntries.begin(); 1349 while ( aPropIt != aPropertyEntries.end() ) 1350 { 1351 const SfxPoolItem* pItem = pSet->GetItem( aPropIt->nWID ); 1352 if ( pItem ) 1353 { 1354 uno::Any aVal; 1355 pItem->QueryValue( aVal, aPropIt->nMemberId ); 1356 1357 PropertyValue rPropVal; 1358 rPropVal.Name = aPropIt->sName; 1359 rPropVal.Value = aVal; 1360 rPropVal.Handle = -1; 1361 rPropVal.State = beans::PropertyState_DEFAULT_VALUE; 1362 1363 aDefAttrSeq[rPropVal.Name] = rPropVal; 1364 } 1365 ++aPropIt; 1366 } 1367 1368 // --> OD 2007-01-15 #i72800# 1369 // add property value entry for the paragraph style 1370 if ( !bOnlyCharAttrs && pTxtNode->GetTxtColl() ) 1371 { 1372 const ::rtl::OUString sParaStyleName = 1373 ::rtl::OUString::createFromAscii( 1374 GetPropName( UNO_NAME_PARA_STYLE_NAME ).pName ); 1375 if ( aDefAttrSeq.find( sParaStyleName ) == aDefAttrSeq.end() ) 1376 { 1377 PropertyValue rPropVal; 1378 rPropVal.Name = sParaStyleName; 1379 uno::Any aVal( uno::makeAny( ::rtl::OUString( pTxtNode->GetTxtColl()->GetName() ) ) ); 1380 rPropVal.Value = aVal; 1381 rPropVal.Handle = -1; 1382 rPropVal.State = beans::PropertyState_DEFAULT_VALUE; 1383 1384 aDefAttrSeq[rPropVal.Name] = rPropVal; 1385 } 1386 } 1387 // <-- 1388 1389 // --> OD 2007-01-15 #i73371# 1390 // resolve value text::WritingMode2::PAGE of property value entry WritingMode 1391 if ( !bOnlyCharAttrs && GetFrm() ) 1392 { 1393 const ::rtl::OUString sWritingMode = 1394 ::rtl::OUString::createFromAscii( 1395 GetPropName( UNO_NAME_WRITING_MODE ).pName ); 1396 tAccParaPropValMap::iterator aIter = aDefAttrSeq.find( sWritingMode ); 1397 if ( aIter != aDefAttrSeq.end() ) 1398 { 1399 PropertyValue rPropVal( aIter->second ); 1400 sal_Int16 nVal = rPropVal.Value.get<sal_Int16>(); 1401 if ( nVal == text::WritingMode2::PAGE ) 1402 { 1403 const SwFrm* pUpperFrm( GetFrm()->GetUpper() ); 1404 while ( pUpperFrm ) 1405 { 1406 if ( pUpperFrm->GetType() & 1407 ( FRM_PAGE | FRM_FLY | FRM_SECTION | FRM_TAB | FRM_CELL ) ) 1408 { 1409 if ( pUpperFrm->IsVertical() ) 1410 { 1411 nVal = text::WritingMode2::TB_RL; 1412 } 1413 else if ( pUpperFrm->IsRightToLeft() ) 1414 { 1415 nVal = text::WritingMode2::RL_TB; 1416 } 1417 else 1418 { 1419 nVal = text::WritingMode2::LR_TB; 1420 } 1421 rPropVal.Value <<= nVal; 1422 aDefAttrSeq[rPropVal.Name] = rPropVal; 1423 break; 1424 } 1425 1426 if ( dynamic_cast<const SwFlyFrm*>(pUpperFrm) ) 1427 { 1428 pUpperFrm = dynamic_cast<const SwFlyFrm*>(pUpperFrm)->GetAnchorFrm(); 1429 } 1430 else 1431 { 1432 pUpperFrm = pUpperFrm->GetUpper(); 1433 } 1434 } 1435 } 1436 } 1437 } 1438 // <-- 1439 } 1440 1441 if ( aRequestedAttributes.getLength() == 0 ) 1442 { 1443 rDefAttrSeq = aDefAttrSeq; 1444 } 1445 else 1446 { 1447 const ::rtl::OUString* pReqAttrs = aRequestedAttributes.getConstArray(); 1448 const sal_Int32 nLength = aRequestedAttributes.getLength(); 1449 for( sal_Int32 i = 0; i < nLength; ++i ) 1450 { 1451 tAccParaPropValMap::const_iterator const aIter = aDefAttrSeq.find( pReqAttrs[i] ); 1452 if ( aIter != aDefAttrSeq.end() ) 1453 { 1454 rDefAttrSeq[ aIter->first ] = aIter->second; 1455 } 1456 } 1457 } 1458 } 1459 1460 uno::Sequence< PropertyValue > SwAccessibleParagraph::getDefaultAttributes( 1461 const uno::Sequence< ::rtl::OUString >& aRequestedAttributes ) 1462 throw ( uno::RuntimeException ) 1463 { 1464 vos::OGuard aGuard(Application::GetSolarMutex()); 1465 CHECK_FOR_DEFUNC_THIS( XAccessibleText, *this ); 1466 1467 tAccParaPropValMap aDefAttrSeq; 1468 _getDefaultAttributesImpl( aRequestedAttributes, aDefAttrSeq ); 1469 1470 // --> OD 2010-03-08 #i92233# 1471 static rtl::OUString sMMToPixelRatio( rtl::OUString::createFromAscii( "MMToPixelRatio" ) ); 1472 bool bProvideMMToPixelRatio( false ); 1473 { 1474 if ( aRequestedAttributes.getLength() == 0 ) 1475 { 1476 bProvideMMToPixelRatio = true; 1477 } 1478 else 1479 { 1480 const rtl::OUString* aRequestedAttrIter = 1481 ::std::find( ::comphelper::stl_begin( aRequestedAttributes ), 1482 ::comphelper::stl_end( aRequestedAttributes ), 1483 sMMToPixelRatio ); 1484 if ( aRequestedAttrIter != ::comphelper::stl_end( aRequestedAttributes ) ) 1485 { 1486 bProvideMMToPixelRatio = true; 1487 } 1488 } 1489 } 1490 // <-- 1491 1492 uno::Sequence< PropertyValue > aValues( aDefAttrSeq.size() + 1493 ( bProvideMMToPixelRatio ? 1 : 0 ) ); 1494 PropertyValue* pValues = aValues.getArray(); 1495 sal_Int32 i = 0; 1496 for ( tAccParaPropValMap::const_iterator aIter = aDefAttrSeq.begin(); 1497 aIter != aDefAttrSeq.end(); 1498 ++aIter ) 1499 { 1500 pValues[i] = aIter->second; 1501 ++i; 1502 } 1503 1504 // --> OD 2010-03-08 #i92233# 1505 if ( bProvideMMToPixelRatio ) 1506 { 1507 PropertyValue rPropVal; 1508 rPropVal.Name = sMMToPixelRatio; 1509 const Size a100thMMSize( 1000, 1000 ); 1510 const Size aPixelSize = GetMap()->LogicToPixel( a100thMMSize ); 1511 const float fRatio = ((float)a100thMMSize.Width()/100)/aPixelSize.Width(); 1512 rPropVal.Value = uno::makeAny( fRatio ); 1513 rPropVal.Handle = -1; 1514 rPropVal.State = beans::PropertyState_DEFAULT_VALUE; 1515 pValues[ aValues.getLength() - 1 ] = rPropVal; 1516 } 1517 // <-- 1518 1519 return aValues; 1520 } 1521 1522 void SwAccessibleParagraph::_getRunAttributesImpl( 1523 const sal_Int32 nIndex, 1524 const uno::Sequence< ::rtl::OUString >& aRequestedAttributes, 1525 tAccParaPropValMap& rRunAttrSeq ) 1526 { 1527 // create PaM for character at position <nIndex> 1528 SwPaM* pPaM( 0 ); 1529 { 1530 const SwTxtNode* pTxtNode( GetTxtNode() ); 1531 SwPosition* pStartPos = new SwPosition( *pTxtNode ); 1532 pStartPos->nContent.Assign( const_cast<SwTxtNode*>(pTxtNode), static_cast<sal_uInt16>(nIndex) ); 1533 SwPosition* pEndPos = new SwPosition( *pTxtNode ); 1534 pEndPos->nContent.Assign( const_cast<SwTxtNode*>(pTxtNode), static_cast<sal_uInt16>(nIndex+1) ); 1535 1536 pPaM = new SwPaM( *pStartPos, *pEndPos ); 1537 1538 delete pStartPos; 1539 delete pEndPos; 1540 } 1541 1542 // retrieve character attributes for the created PaM <pPaM> 1543 SfxItemSet aSet( pPaM->GetDoc()->GetAttrPool(), 1544 RES_CHRATR_BEGIN, RES_CHRATR_END -1, 1545 0 ); 1546 // --> OD 2007-11-12 #i82637# 1547 // From the perspective of the a11y API the character attributes, which 1548 // are set at the automatic paragraph style of the paragraph are treated 1549 // as run attributes. 1550 // SwXTextCursor::GetCrsrAttr( *pPaM, aSet, sal_True, sal_True ); 1551 // get character attributes from automatic paragraph style and merge these into <aSet> 1552 { 1553 const SwTxtNode* pTxtNode( GetTxtNode() ); 1554 if ( pTxtNode->HasSwAttrSet() ) 1555 { 1556 SfxItemSet aAutomaticParaStyleCharAttrs( pPaM->GetDoc()->GetAttrPool(), 1557 RES_CHRATR_BEGIN, RES_CHRATR_END -1, 1558 0 ); 1559 aAutomaticParaStyleCharAttrs.Put( *(pTxtNode->GetpSwAttrSet()), sal_False ); 1560 aSet.Put( aAutomaticParaStyleCharAttrs ); 1561 } 1562 } 1563 // get character attributes at <pPaM> and merge these into <aSet> 1564 { 1565 SfxItemSet aCharAttrsAtPaM( pPaM->GetDoc()->GetAttrPool(), 1566 RES_CHRATR_BEGIN, RES_CHRATR_END -1, 1567 0 ); 1568 SwUnoCursorHelper::GetCrsrAttr(*pPaM, aCharAttrsAtPaM, sal_True, sal_True); 1569 aSet.Put( aCharAttrsAtPaM ); 1570 } 1571 // <-- 1572 1573 // build-up sequence containing the run attributes <rRunAttrSeq> 1574 { 1575 tAccParaPropValMap aRunAttrSeq; 1576 { 1577 // --> OD 2007-11-12 #i82637# 1578 tAccParaPropValMap aDefAttrSeq; 1579 uno::Sequence< ::rtl::OUString > aDummy; 1580 _getDefaultAttributesImpl( aDummy, aDefAttrSeq, true ); 1581 // <-- 1582 1583 const SfxItemPropertyMap* pPropMap = 1584 aSwMapProvider.GetPropertySet( PROPERTY_MAP_TEXT_CURSOR )->getPropertyMap(); 1585 PropertyEntryVector_t aPropertyEntries = pPropMap->getPropertyEntries(); 1586 PropertyEntryVector_t::const_iterator aPropIt = aPropertyEntries.begin(); 1587 while ( aPropIt != aPropertyEntries.end() ) 1588 { 1589 const SfxPoolItem* pItem( 0 ); 1590 // --> OD 2007-11-12 #i82637# 1591 // Found character attributes, whose value equals the value of 1592 // the corresponding default character attributes, are excluded. 1593 if ( aSet.GetItemState( aPropIt->nWID, sal_True, &pItem ) == SFX_ITEM_SET ) 1594 { 1595 uno::Any aVal; 1596 pItem->QueryValue( aVal, aPropIt->nMemberId ); 1597 1598 PropertyValue rPropVal; 1599 rPropVal.Name = aPropIt->sName; 1600 rPropVal.Value = aVal; 1601 rPropVal.Handle = -1; 1602 rPropVal.State = PropertyState_DIRECT_VALUE; 1603 1604 tAccParaPropValMap::const_iterator aDefIter = 1605 aDefAttrSeq.find( rPropVal.Name ); 1606 if ( aDefIter == aDefAttrSeq.end() || 1607 rPropVal.Value != aDefIter->second.Value ) 1608 { 1609 aRunAttrSeq[rPropVal.Name] = rPropVal; 1610 } 1611 } 1612 1613 ++aPropIt; 1614 } 1615 } 1616 1617 if ( aRequestedAttributes.getLength() == 0 ) 1618 { 1619 rRunAttrSeq = aRunAttrSeq; 1620 } 1621 else 1622 { 1623 const ::rtl::OUString* pReqAttrs = aRequestedAttributes.getConstArray(); 1624 const sal_Int32 nLength = aRequestedAttributes.getLength(); 1625 for( sal_Int32 i = 0; i < nLength; ++i ) 1626 { 1627 tAccParaPropValMap::iterator aIter = aRunAttrSeq.find( pReqAttrs[i] ); 1628 if ( aIter != aRunAttrSeq.end() ) 1629 { 1630 rRunAttrSeq[ (*aIter).first ] = (*aIter).second; 1631 } 1632 } 1633 } 1634 } 1635 1636 delete pPaM; 1637 } 1638 1639 uno::Sequence< PropertyValue > SwAccessibleParagraph::getRunAttributes( 1640 sal_Int32 nIndex, 1641 const uno::Sequence< ::rtl::OUString >& aRequestedAttributes ) 1642 throw ( lang::IndexOutOfBoundsException, 1643 uno::RuntimeException ) 1644 { 1645 vos::OGuard aGuard(Application::GetSolarMutex()); 1646 CHECK_FOR_DEFUNC_THIS( XAccessibleText, *this ); 1647 1648 { 1649 const ::rtl::OUString& rText = GetString(); 1650 if ( !IsValidChar( nIndex, rText.getLength() ) ) 1651 { 1652 throw lang::IndexOutOfBoundsException(); 1653 } 1654 } 1655 1656 tAccParaPropValMap aRunAttrSeq; 1657 _getRunAttributesImpl( nIndex, aRequestedAttributes, aRunAttrSeq ); 1658 1659 uno::Sequence< PropertyValue > aValues( aRunAttrSeq.size() ); 1660 PropertyValue* pValues = aValues.getArray(); 1661 sal_Int32 i = 0; 1662 for ( tAccParaPropValMap::const_iterator aIter = aRunAttrSeq.begin(); 1663 aIter != aRunAttrSeq.end(); 1664 ++aIter ) 1665 { 1666 pValues[i] = aIter->second; 1667 ++i; 1668 } 1669 1670 return aValues; 1671 } 1672 // <-- 1673 1674 awt::Rectangle SwAccessibleParagraph::getCharacterBounds( 1675 sal_Int32 nIndex ) 1676 throw (lang::IndexOutOfBoundsException, uno::RuntimeException) 1677 { 1678 vos::OGuard aGuard(Application::GetSolarMutex()); 1679 1680 CHECK_FOR_DEFUNC_THIS( XAccessibleText, *this ); 1681 1682 1683 /* #i12332# The position after the string needs special treatment. 1684 IsValidChar -> IsValidPosition 1685 */ 1686 if( ! (IsValidPosition( nIndex, GetString().getLength() ) ) ) 1687 throw lang::IndexOutOfBoundsException(); 1688 1689 /* #i12332# */ 1690 sal_Bool bBehindText = sal_False; 1691 if ( nIndex == GetString().getLength() ) 1692 bBehindText = sal_True; 1693 1694 // get model position & prepare GetCharRect() arguments 1695 SwCrsrMoveState aMoveState; 1696 aMoveState.bRealHeight = sal_True; 1697 aMoveState.bRealWidth = sal_True; 1698 SwSpecialPos aSpecialPos; 1699 SwTxtNode* pNode = const_cast<SwTxtNode*>( GetTxtNode() ); 1700 1701 sal_uInt16 nPos = 0; 1702 1703 /* #i12332# FillSpecialPos does not accept nIndex == 1704 GetString().getLength(). In that case nPos is set to the 1705 length of the string in the core. This way GetCharRect 1706 returns the rectangle for a cursor at the end of the 1707 paragraph. */ 1708 if (bBehindText) 1709 { 1710 nPos = pNode->GetTxt().Len(); 1711 } 1712 else 1713 nPos = GetPortionData().FillSpecialPos 1714 (nIndex, aSpecialPos, aMoveState.pSpecialPos ); 1715 1716 // call GetCharRect 1717 SwRect aCoreRect; 1718 SwIndex aIndex( pNode, nPos ); 1719 SwPosition aPosition( *pNode, aIndex ); 1720 GetFrm()->GetCharRect( aCoreRect, aPosition, &aMoveState ); 1721 1722 // translate core coordinates into accessibility coordinates 1723 Window *pWin = GetWindow(); 1724 CHECK_FOR_WINDOW( XAccessibleComponent, pWin ); 1725 1726 Rectangle aScreenRect( GetMap()->CoreToPixel( aCoreRect.SVRect() )); 1727 SwRect aFrmLogBounds( GetBounds( *(GetMap()) ) ); // twip rel to doc root 1728 1729 Point aFrmPixPos( GetMap()->CoreToPixel( aFrmLogBounds.SVRect() ).TopLeft() ); 1730 aScreenRect.Move( -aFrmPixPos.X(), -aFrmPixPos.Y() ); 1731 1732 // convert into AWT Rectangle 1733 return awt::Rectangle( 1734 aScreenRect.Left(), aScreenRect.Top(), 1735 aScreenRect.GetWidth(), aScreenRect.GetHeight() ); 1736 } 1737 1738 sal_Int32 SwAccessibleParagraph::getCharacterCount() 1739 throw (uno::RuntimeException) 1740 { 1741 vos::OGuard aGuard(Application::GetSolarMutex()); 1742 1743 CHECK_FOR_DEFUNC_THIS( XAccessibleText, *this ); 1744 1745 return GetString().getLength(); 1746 } 1747 1748 sal_Int32 SwAccessibleParagraph::getIndexAtPoint( const awt::Point& rPoint ) 1749 throw (uno::RuntimeException) 1750 { 1751 vos::OGuard aGuard(Application::GetSolarMutex()); 1752 1753 1754 CHECK_FOR_DEFUNC_THIS( XAccessibleText, *this ); 1755 1756 // construct SwPosition (where GetCrsrOfst() will put the result into) 1757 SwTxtNode* pNode = const_cast<SwTxtNode*>( GetTxtNode() ); 1758 SwIndex aIndex( pNode, 0); 1759 SwPosition aPos( *pNode, aIndex ); 1760 1761 // construct Point (translate into layout coordinates) 1762 Window *pWin = GetWindow(); 1763 CHECK_FOR_WINDOW( XAccessibleComponent, pWin ); 1764 Point aPoint( rPoint.X, rPoint.Y ); 1765 SwRect aLogBounds( GetBounds( *(GetMap()), GetFrm() ) ); // twip rel to doc root 1766 Point aPixPos( GetMap()->CoreToPixel( aLogBounds.SVRect() ).TopLeft() ); 1767 aPoint.X() += aPixPos.X(); 1768 aPoint.Y() += aPixPos.Y(); 1769 MapMode aMapMode = pWin->GetMapMode(); 1770 Point aCorePoint( GetMap()->PixelToCore( aPoint ) ); 1771 if( !aLogBounds.IsInside( aCorePoint ) ) 1772 { 1773 /* #i12332# rPoint is may also be in rectangle returned by 1774 getCharacterBounds(getCharacterCount() */ 1775 1776 awt::Rectangle aRectEndPos = 1777 getCharacterBounds(getCharacterCount()); 1778 1779 if (rPoint.X - aRectEndPos.X >= 0 && 1780 rPoint.X - aRectEndPos.X < aRectEndPos.Width && 1781 rPoint.Y - aRectEndPos.Y >= 0 && 1782 rPoint.Y - aRectEndPos.Y < aRectEndPos.Height) 1783 return getCharacterCount(); 1784 1785 return -1; 1786 } 1787 1788 // ask core for position 1789 DBG_ASSERT( GetFrm() != NULL, "The text frame has vanished!" ); 1790 DBG_ASSERT( GetFrm()->IsTxtFrm(), "The text frame has mutated!" ); 1791 const SwTxtFrm* pFrm = static_cast<const SwTxtFrm*>( GetFrm() ); 1792 SwCrsrMoveState aMoveState; 1793 aMoveState.bPosMatchesBounds = sal_True; 1794 sal_Bool bSuccess = pFrm->GetCrsrOfst( &aPos, aCorePoint, &aMoveState ); 1795 1796 SwIndex aCntntIdx = aPos.nContent; 1797 const xub_StrLen nIndex = aCntntIdx.GetIndex(); 1798 if ( nIndex > 0 ) 1799 { 1800 SwRect aResultRect; 1801 pFrm->GetCharRect( aResultRect, aPos ); 1802 bool bVert = pFrm->IsVertical(); 1803 bool bR2L = pFrm->IsRightToLeft(); 1804 1805 if ( (!bVert && aResultRect.Pos().X() > aCorePoint.X()) || 1806 ( bVert && aResultRect.Pos().Y() > aCorePoint.Y()) || 1807 ( bR2L && aResultRect.Right() < aCorePoint.X()) ) 1808 { 1809 SwIndex aIdxPrev( pNode, nIndex - 1); 1810 SwPosition aPosPrev( *pNode, aIdxPrev ); 1811 SwRect aResultRectPrev; 1812 pFrm->GetCharRect( aResultRectPrev, aPosPrev ); 1813 if ( (!bVert && aResultRectPrev.Pos().X() < aCorePoint.X() && aResultRect.Pos().Y() == aResultRectPrev.Pos().Y()) || 1814 ( bVert && aResultRectPrev.Pos().Y() < aCorePoint.Y() && aResultRect.Pos().X() == aResultRectPrev.Pos().X()) || 1815 ( bR2L && aResultRectPrev.Right() > aCorePoint.X() && aResultRect.Pos().Y() == aResultRectPrev.Pos().Y()) ) 1816 aPos = aPosPrev; 1817 } 1818 } 1819 1820 return bSuccess ? 1821 GetPortionData().GetAccessiblePosition( aPos.nContent.GetIndex() ) 1822 : -1L; 1823 } 1824 1825 ::rtl::OUString SwAccessibleParagraph::getSelectedText() 1826 throw (uno::RuntimeException) 1827 { 1828 vos::OGuard aGuard(Application::GetSolarMutex()); 1829 1830 CHECK_FOR_DEFUNC_THIS( XAccessibleText, *this ); 1831 1832 sal_Int32 nStart, nEnd; 1833 sal_Bool bSelected = GetSelection( nStart, nEnd ); 1834 return bSelected 1835 ? GetString().copy( nStart, nEnd - nStart ) 1836 : ::rtl::OUString(); 1837 } 1838 1839 sal_Int32 SwAccessibleParagraph::getSelectionStart() 1840 throw (uno::RuntimeException) 1841 { 1842 vos::OGuard aGuard(Application::GetSolarMutex()); 1843 1844 CHECK_FOR_DEFUNC_THIS( XAccessibleText, *this ); 1845 1846 sal_Int32 nStart, nEnd; 1847 GetSelection( nStart, nEnd ); 1848 return nStart; 1849 } 1850 1851 sal_Int32 SwAccessibleParagraph::getSelectionEnd() 1852 throw (uno::RuntimeException) 1853 { 1854 vos::OGuard aGuard(Application::GetSolarMutex()); 1855 1856 CHECK_FOR_DEFUNC_THIS( XAccessibleText, *this ); 1857 1858 sal_Int32 nStart, nEnd; 1859 GetSelection( nStart, nEnd ); 1860 return nEnd; 1861 } 1862 1863 sal_Bool SwAccessibleParagraph::setSelection( sal_Int32 nStartIndex, sal_Int32 nEndIndex ) 1864 throw (lang::IndexOutOfBoundsException, uno::RuntimeException) 1865 { 1866 vos::OGuard aGuard(Application::GetSolarMutex()); 1867 1868 CHECK_FOR_DEFUNC_THIS( XAccessibleText, *this ); 1869 1870 // parameter checking 1871 sal_Int32 nLength = GetString().getLength(); 1872 if ( ! IsValidRange( nStartIndex, nEndIndex, nLength ) ) 1873 { 1874 throw lang::IndexOutOfBoundsException(); 1875 } 1876 1877 sal_Bool bRet = sal_False; 1878 1879 // get cursor shell 1880 SwCrsrShell* pCrsrShell = GetCrsrShell(); 1881 if( pCrsrShell != NULL ) 1882 { 1883 // create pam for selection 1884 SwTxtNode* pNode = const_cast<SwTxtNode*>( GetTxtNode() ); 1885 SwIndex aIndex( pNode, GetPortionData().GetModelPosition(nStartIndex)); 1886 SwPosition aStartPos( *pNode, aIndex ); 1887 SwPaM aPaM( aStartPos ); 1888 aPaM.SetMark(); 1889 aPaM.GetPoint()->nContent = 1890 GetPortionData().GetModelPosition(nEndIndex); 1891 1892 // set PaM at cursor shell 1893 bRet = Select( aPaM ); 1894 } 1895 1896 return bRet; 1897 } 1898 1899 ::rtl::OUString SwAccessibleParagraph::getText() 1900 throw (uno::RuntimeException) 1901 { 1902 vos::OGuard aGuard(Application::GetSolarMutex()); 1903 1904 CHECK_FOR_DEFUNC_THIS( XAccessibleText, *this ); 1905 1906 return GetString(); 1907 } 1908 1909 ::rtl::OUString SwAccessibleParagraph::getTextRange( 1910 sal_Int32 nStartIndex, sal_Int32 nEndIndex ) 1911 throw (lang::IndexOutOfBoundsException, uno::RuntimeException) 1912 { 1913 vos::OGuard aGuard(Application::GetSolarMutex()); 1914 1915 CHECK_FOR_DEFUNC_THIS( XAccessibleText, *this ); 1916 1917 ::rtl::OUString sText( GetString() ); 1918 1919 if ( IsValidRange( nStartIndex, nEndIndex, sText.getLength() ) ) 1920 { 1921 OrderRange( nStartIndex, nEndIndex ); 1922 return sText.copy(nStartIndex, nEndIndex-nStartIndex ); 1923 } 1924 else 1925 throw lang::IndexOutOfBoundsException(); 1926 } 1927 1928 /*accessibility::*/TextSegment SwAccessibleParagraph::getTextAtIndex( sal_Int32 nIndex, sal_Int16 nTextType ) throw (lang::IndexOutOfBoundsException, lang::IllegalArgumentException, uno::RuntimeException) 1929 { 1930 vos::OGuard aGuard(Application::GetSolarMutex()); 1931 1932 CHECK_FOR_DEFUNC_THIS( XAccessibleText, *this ); 1933 1934 /*accessibility::*/TextSegment aResult; 1935 aResult.SegmentStart = -1; 1936 aResult.SegmentEnd = -1; 1937 1938 const ::rtl::OUString rText = GetString(); 1939 // implement the silly specification that first position after 1940 // text must return an empty string, rather than throwing an 1941 // IndexOutOfBoundsException, except for LINE, where the last 1942 // line is returned 1943 if( nIndex == rText.getLength() && AccessibleTextType::LINE != nTextType ) 1944 return aResult; 1945 1946 // with error checking 1947 i18n::Boundary aBound; 1948 sal_Bool bWord = GetTextBoundary( aBound, rText, nIndex, nTextType ); 1949 1950 DBG_ASSERT( aBound.startPos >= 0, "illegal boundary" ); 1951 DBG_ASSERT( aBound.startPos <= aBound.endPos, "illegal boundary" ); 1952 1953 // return word (if present) 1954 if ( bWord ) 1955 { 1956 aResult.SegmentText = rText.copy( aBound.startPos, aBound.endPos - aBound.startPos ); 1957 aResult.SegmentStart = aBound.startPos; 1958 aResult.SegmentEnd = aBound.endPos; 1959 } 1960 1961 return aResult; 1962 } 1963 1964 /*accessibility::*/TextSegment SwAccessibleParagraph::getTextBeforeIndex( sal_Int32 nIndex, sal_Int16 nTextType ) throw (lang::IndexOutOfBoundsException, lang::IllegalArgumentException, uno::RuntimeException) 1965 { 1966 vos::OGuard aGuard(Application::GetSolarMutex()); 1967 1968 CHECK_FOR_DEFUNC_THIS( XAccessibleText, *this ); 1969 1970 const ::rtl::OUString rText = GetString(); 1971 1972 /*accessibility::*/TextSegment aResult; 1973 aResult.SegmentStart = -1; 1974 aResult.SegmentEnd = -1; 1975 1976 // get starting pos 1977 i18n::Boundary aBound; 1978 if (nIndex == rText.getLength()) 1979 aBound.startPos = aBound.endPos = nIndex; 1980 else 1981 { 1982 sal_Bool bTmp = GetTextBoundary( aBound, rText, nIndex, nTextType ); 1983 1984 if ( ! bTmp ) 1985 aBound.startPos = aBound.endPos = nIndex; 1986 } 1987 1988 // now skip to previous word 1989 sal_Bool bWord = sal_False; 1990 while( !bWord ) 1991 { 1992 nIndex = min( nIndex, aBound.startPos ) - 1; 1993 if( nIndex >= 0 ) 1994 bWord = GetTextBoundary( aBound, rText, nIndex, nTextType ); 1995 else 1996 break; // exit if beginning of string is reached 1997 } 1998 1999 if ( bWord ) 2000 { 2001 aResult.SegmentText = rText.copy( aBound.startPos, aBound.endPos - aBound.startPos ); 2002 aResult.SegmentStart = aBound.startPos; 2003 aResult.SegmentEnd = aBound.endPos; 2004 }; 2005 return aResult; 2006 } 2007 2008 /*accessibility::*/TextSegment SwAccessibleParagraph::getTextBehindIndex( sal_Int32 nIndex, sal_Int16 nTextType ) throw (lang::IndexOutOfBoundsException, lang::IllegalArgumentException, uno::RuntimeException) 2009 { 2010 vos::OGuard aGuard(Application::GetSolarMutex()); 2011 2012 CHECK_FOR_DEFUNC_THIS( XAccessibleText, *this ); 2013 2014 /*accessibility::*/TextSegment aResult; 2015 aResult.SegmentStart = -1; 2016 aResult.SegmentEnd = -1; 2017 const ::rtl::OUString rText = GetString(); 2018 2019 // implement the silly specification that first position after 2020 // text must return an empty string, rather than throwing an 2021 // IndexOutOfBoundsException 2022 if( nIndex == rText.getLength() ) 2023 return aResult; 2024 2025 2026 // get first word, then skip to next word 2027 i18n::Boundary aBound; 2028 GetTextBoundary( aBound, rText, nIndex, nTextType ); 2029 sal_Bool bWord = sal_False; 2030 while( !bWord ) 2031 { 2032 nIndex = max( sal_Int32(nIndex+1), aBound.endPos ); 2033 if( nIndex < rText.getLength() ) 2034 bWord = GetTextBoundary( aBound, rText, nIndex, nTextType ); 2035 else 2036 break; // exit if end of string is reached 2037 } 2038 2039 if ( bWord ) 2040 { 2041 aResult.SegmentText = rText.copy( aBound.startPos, aBound.endPos - aBound.startPos ); 2042 aResult.SegmentStart = aBound.startPos; 2043 aResult.SegmentEnd = aBound.endPos; 2044 } 2045 return aResult; 2046 } 2047 2048 sal_Bool SwAccessibleParagraph::copyText( sal_Int32 nStartIndex, sal_Int32 nEndIndex ) 2049 throw (lang::IndexOutOfBoundsException, uno::RuntimeException) 2050 { 2051 CHECK_FOR_DEFUNC_THIS( XAccessibleText, *this ); 2052 vos::OGuard aGuard(Application::GetSolarMutex()); 2053 2054 // select and copy (through dispatch mechanism) 2055 setSelection( nStartIndex, nEndIndex ); 2056 ExecuteAtViewShell( SID_COPY ); 2057 return sal_True; 2058 } 2059 2060 2061 // 2062 //===== XAccesibleEditableText ========================================== 2063 // 2064 2065 sal_Bool SwAccessibleParagraph::cutText( sal_Int32 nStartIndex, sal_Int32 nEndIndex ) 2066 throw (lang::IndexOutOfBoundsException, uno::RuntimeException) 2067 { 2068 CHECK_FOR_DEFUNC( XAccessibleEditableText ); 2069 vos::OGuard aGuard(Application::GetSolarMutex()); 2070 2071 if( !IsEditableState() ) 2072 return sal_False; 2073 2074 // select and cut (through dispatch mechanism) 2075 setSelection( nStartIndex, nEndIndex ); 2076 ExecuteAtViewShell( SID_CUT ); 2077 return sal_True; 2078 } 2079 2080 sal_Bool SwAccessibleParagraph::pasteText( sal_Int32 nIndex ) 2081 throw (lang::IndexOutOfBoundsException, uno::RuntimeException) 2082 { 2083 CHECK_FOR_DEFUNC( XAccessibleEditableText ); 2084 vos::OGuard aGuard(Application::GetSolarMutex()); 2085 2086 if( !IsEditableState() ) 2087 return sal_False; 2088 2089 // select and paste (through dispatch mechanism) 2090 setSelection( nIndex, nIndex ); 2091 ExecuteAtViewShell( SID_PASTE ); 2092 return sal_True; 2093 } 2094 2095 sal_Bool SwAccessibleParagraph::deleteText( sal_Int32 nStartIndex, sal_Int32 nEndIndex ) 2096 throw (lang::IndexOutOfBoundsException, uno::RuntimeException) 2097 { 2098 return replaceText( nStartIndex, nEndIndex, ::rtl::OUString() ); 2099 } 2100 2101 sal_Bool SwAccessibleParagraph::insertText( const ::rtl::OUString& sText, sal_Int32 nIndex ) 2102 throw (lang::IndexOutOfBoundsException, uno::RuntimeException) 2103 { 2104 return replaceText( nIndex, nIndex, sText ); 2105 } 2106 2107 sal_Bool SwAccessibleParagraph::replaceText( 2108 sal_Int32 nStartIndex, sal_Int32 nEndIndex, 2109 const ::rtl::OUString& sReplacement ) 2110 throw (lang::IndexOutOfBoundsException, uno::RuntimeException) 2111 { 2112 vos::OGuard aGuard(Application::GetSolarMutex()); 2113 2114 CHECK_FOR_DEFUNC( XAccessibleEditableText ); 2115 2116 const ::rtl::OUString& rText = GetString(); 2117 2118 if( IsValidRange( nStartIndex, nEndIndex, rText.getLength() ) ) 2119 { 2120 if( !IsEditableState() ) 2121 return sal_False; 2122 2123 SwTxtNode* pNode = const_cast<SwTxtNode*>( GetTxtNode() ); 2124 2125 // translate positions 2126 sal_uInt16 nStart, nEnd; 2127 sal_Bool bSuccess = GetPortionData().GetEditableRange( 2128 nStartIndex, nEndIndex, nStart, nEnd ); 2129 2130 // edit only if the range is editable 2131 if( bSuccess ) 2132 { 2133 // create SwPosition for nStartIndex 2134 SwIndex aIndex( pNode, nStart ); 2135 SwPosition aStartPos( *pNode, aIndex ); 2136 2137 // create SwPosition for nEndIndex 2138 SwPosition aEndPos( aStartPos ); 2139 aEndPos.nContent = nEnd; 2140 2141 // now create XTextRange as helper and set string 2142 const uno::Reference<text::XTextRange> xRange( 2143 SwXTextRange::CreateXTextRange( 2144 *pNode->GetDoc(), aStartPos, &aEndPos)); 2145 xRange->setString(sReplacement); 2146 2147 // delete portion data 2148 ClearPortionData(); 2149 } 2150 2151 return bSuccess; 2152 } 2153 else 2154 throw lang::IndexOutOfBoundsException(); 2155 } 2156 2157 struct IndexCompare 2158 { 2159 const PropertyValue* pValues; 2160 IndexCompare( const PropertyValue* pVals ) : pValues(pVals) {} 2161 bool operator() ( const sal_Int32& a, const sal_Int32& b ) const 2162 { 2163 return (pValues[a].Name < pValues[b].Name) ? true : false; 2164 } 2165 }; 2166 2167 2168 sal_Bool SwAccessibleParagraph::setAttributes( 2169 sal_Int32 nStartIndex, 2170 sal_Int32 nEndIndex, 2171 const uno::Sequence<PropertyValue>& rAttributeSet ) 2172 throw (lang::IndexOutOfBoundsException, uno::RuntimeException) 2173 { 2174 vos::OGuard aGuard(Application::GetSolarMutex()); 2175 CHECK_FOR_DEFUNC( XAccessibleEditableText ); 2176 2177 const ::rtl::OUString& rText = GetString(); 2178 2179 if( ! IsValidRange( nStartIndex, nEndIndex, rText.getLength() ) ) 2180 throw lang::IndexOutOfBoundsException(); 2181 2182 if( !IsEditableState() ) 2183 return sal_False; 2184 2185 2186 // create a (dummy) text portion for the sole purpose of calling 2187 // setPropertyValue on it 2188 uno::Reference<XMultiPropertySet> xPortion = CreateUnoPortion( nStartIndex, 2189 nEndIndex ); 2190 2191 // build sorted index array 2192 sal_Int32 nLength = rAttributeSet.getLength(); 2193 const PropertyValue* pPairs = rAttributeSet.getConstArray(); 2194 sal_Int32* pIndices = new sal_Int32[nLength]; 2195 sal_Int32 i; 2196 for( i = 0; i < nLength; i++ ) 2197 pIndices[i] = i; 2198 sort( &pIndices[0], &pIndices[nLength], IndexCompare(pPairs) ); 2199 2200 // create sorted sequences accoring to index array 2201 uno::Sequence< ::rtl::OUString > aNames( nLength ); 2202 ::rtl::OUString* pNames = aNames.getArray(); 2203 uno::Sequence< uno::Any > aValues( nLength ); 2204 uno::Any* pValues = aValues.getArray(); 2205 for( i = 0; i < nLength; i++ ) 2206 { 2207 const PropertyValue& rVal = pPairs[pIndices[i]]; 2208 pNames[i] = rVal.Name; 2209 pValues[i] = rVal.Value; 2210 } 2211 delete[] pIndices; 2212 2213 // now set the values 2214 sal_Bool bRet = sal_True; 2215 try 2216 { 2217 xPortion->setPropertyValues( aNames, aValues ); 2218 } 2219 catch( UnknownPropertyException e ) 2220 { 2221 // error handling through return code! 2222 bRet = sal_False; 2223 } 2224 2225 return bRet; 2226 } 2227 2228 sal_Bool SwAccessibleParagraph::setText( const ::rtl::OUString& sText ) 2229 throw (uno::RuntimeException) 2230 { 2231 return replaceText(0, GetString().getLength(), sText); 2232 } 2233 2234 //===== XAccessibleSelection ============================================ 2235 2236 void SwAccessibleParagraph::selectAccessibleChild( 2237 sal_Int32 nChildIndex ) 2238 throw ( lang::IndexOutOfBoundsException, 2239 uno::RuntimeException ) 2240 { 2241 CHECK_FOR_DEFUNC( XAccessibleSelection ); 2242 2243 aSelectionHelper.selectAccessibleChild(nChildIndex); 2244 } 2245 2246 sal_Bool SwAccessibleParagraph::isAccessibleChildSelected( 2247 sal_Int32 nChildIndex ) 2248 throw ( lang::IndexOutOfBoundsException, 2249 uno::RuntimeException ) 2250 { 2251 CHECK_FOR_DEFUNC( XAccessibleSelection ); 2252 2253 return aSelectionHelper.isAccessibleChildSelected(nChildIndex); 2254 } 2255 2256 void SwAccessibleParagraph::clearAccessibleSelection( ) 2257 throw ( uno::RuntimeException ) 2258 { 2259 CHECK_FOR_DEFUNC( XAccessibleSelection ); 2260 2261 aSelectionHelper.clearAccessibleSelection(); 2262 } 2263 2264 void SwAccessibleParagraph::selectAllAccessibleChildren( ) 2265 throw ( uno::RuntimeException ) 2266 { 2267 CHECK_FOR_DEFUNC( XAccessibleSelection ); 2268 2269 aSelectionHelper.selectAllAccessibleChildren(); 2270 } 2271 2272 sal_Int32 SwAccessibleParagraph::getSelectedAccessibleChildCount( ) 2273 throw ( uno::RuntimeException ) 2274 { 2275 CHECK_FOR_DEFUNC( XAccessibleSelection ); 2276 2277 return aSelectionHelper.getSelectedAccessibleChildCount(); 2278 } 2279 2280 uno::Reference<XAccessible> SwAccessibleParagraph::getSelectedAccessibleChild( 2281 sal_Int32 nSelectedChildIndex ) 2282 throw ( lang::IndexOutOfBoundsException, 2283 uno::RuntimeException) 2284 { 2285 CHECK_FOR_DEFUNC( XAccessibleSelection ); 2286 2287 return aSelectionHelper.getSelectedAccessibleChild(nSelectedChildIndex); 2288 } 2289 2290 // --> OD 2004-11-16 #111714# - index has to be treated as global child index. 2291 void SwAccessibleParagraph::deselectAccessibleChild( 2292 sal_Int32 nChildIndex ) 2293 throw ( lang::IndexOutOfBoundsException, 2294 uno::RuntimeException ) 2295 { 2296 CHECK_FOR_DEFUNC( XAccessibleSelection ); 2297 2298 aSelectionHelper.deselectAccessibleChild( nChildIndex ); 2299 } 2300 2301 //===== XAccessibleHypertext ============================================ 2302 2303 class SwHyperlinkIter_Impl 2304 { 2305 const SwpHints *pHints; 2306 xub_StrLen nStt; 2307 xub_StrLen nEnd; 2308 sal_uInt16 nPos; 2309 2310 public: 2311 SwHyperlinkIter_Impl( const SwTxtFrm *pTxtFrm ); 2312 const SwTxtAttr *next(); 2313 sal_uInt16 getCurrHintPos() const { return nPos-1; } 2314 2315 xub_StrLen startIdx() const { return nStt; } 2316 xub_StrLen endIdx() const { return nEnd; } 2317 }; 2318 2319 SwHyperlinkIter_Impl::SwHyperlinkIter_Impl( const SwTxtFrm *pTxtFrm ) : 2320 pHints( pTxtFrm->GetTxtNode()->GetpSwpHints() ), 2321 nStt( pTxtFrm->GetOfst() ), 2322 nPos( 0 ) 2323 { 2324 const SwTxtFrm *pFollFrm = pTxtFrm->GetFollow(); 2325 nEnd = pFollFrm ? pFollFrm->GetOfst() : pTxtFrm->GetTxtNode()->Len(); 2326 } 2327 2328 const SwTxtAttr *SwHyperlinkIter_Impl::next() 2329 { 2330 const SwTxtAttr *pAttr = 0; 2331 if( pHints ) 2332 { 2333 while( !pAttr && nPos < pHints->Count() ) 2334 { 2335 const SwTxtAttr *pHt = (*pHints)[nPos]; 2336 if( RES_TXTATR_INETFMT == pHt->Which() ) 2337 { 2338 xub_StrLen nHtStt = *pHt->GetStart(); 2339 xub_StrLen nHtEnd = *pHt->GetAnyEnd(); 2340 if( nHtEnd > nHtStt && 2341 ( (nHtStt >= nStt && nHtStt < nEnd) || 2342 (nHtEnd > nStt && nHtEnd <= nEnd) ) ) 2343 { 2344 pAttr = pHt; 2345 } 2346 } 2347 ++nPos; 2348 } 2349 } 2350 2351 return pAttr; 2352 }; 2353 2354 sal_Int32 SAL_CALL SwAccessibleParagraph::getHyperLinkCount() 2355 throw (uno::RuntimeException) 2356 { 2357 vos::OGuard aGuard(Application::GetSolarMutex()); 2358 2359 CHECK_FOR_DEFUNC( XAccessibleHypertext ); 2360 2361 sal_Int32 nCount = 0; 2362 // --> OD 2007-06-27 #i77108# - provide hyperlinks also in editable documents. 2363 // if( !IsEditableState() ) 2364 // <-- 2365 { 2366 const SwTxtFrm *pTxtFrm = static_cast<const SwTxtFrm*>( GetFrm() ); 2367 SwHyperlinkIter_Impl aIter( pTxtFrm ); 2368 while( aIter.next() ) 2369 nCount++; 2370 } 2371 2372 return nCount; 2373 } 2374 2375 uno::Reference< XAccessibleHyperlink > SAL_CALL 2376 SwAccessibleParagraph::getHyperLink( sal_Int32 nLinkIndex ) 2377 throw (lang::IndexOutOfBoundsException, uno::RuntimeException) 2378 { 2379 vos::OGuard aGuard(Application::GetSolarMutex()); 2380 CHECK_FOR_DEFUNC( XAccessibleHypertext ); 2381 2382 uno::Reference< XAccessibleHyperlink > xRet; 2383 2384 // --> OD 2007-06-27 #i77108# - provide hyperlinks also in editable documents. 2385 // if( !IsEditableState() ) 2386 // <-- 2387 { 2388 const SwTxtFrm *pTxtFrm = static_cast<const SwTxtFrm*>( GetFrm() ); 2389 SwHyperlinkIter_Impl aHIter( pTxtFrm ); 2390 while( nLinkIndex-- ) 2391 aHIter.next(); 2392 2393 const SwTxtAttr *pHt = aHIter.next(); 2394 if( pHt ) 2395 { 2396 if( !pHyperTextData ) 2397 pHyperTextData = new SwAccessibleHyperTextData; 2398 SwAccessibleHyperTextData::iterator aIter = 2399 pHyperTextData ->find( pHt ); 2400 if( aIter != pHyperTextData->end() ) 2401 { 2402 xRet = (*aIter).second; 2403 } 2404 if( !xRet.is() ) 2405 { 2406 sal_Int32 nHStt= GetPortionData().GetAccessiblePosition( 2407 max( aHIter.startIdx(), *pHt->GetStart() ) ); 2408 sal_Int32 nHEnd= GetPortionData().GetAccessiblePosition( 2409 min( aHIter.endIdx(), *pHt->GetAnyEnd() ) ); 2410 xRet = new SwAccessibleHyperlink( aHIter.getCurrHintPos(), 2411 this, nHStt, nHEnd ); 2412 if( aIter != pHyperTextData->end() ) 2413 { 2414 (*aIter).second = xRet; 2415 } 2416 else 2417 { 2418 SwAccessibleHyperTextData::value_type aEntry( pHt, xRet ); 2419 pHyperTextData->insert( aEntry ); 2420 } 2421 } 2422 } 2423 } 2424 2425 if( !xRet.is() ) 2426 throw lang::IndexOutOfBoundsException(); 2427 2428 return xRet; 2429 } 2430 2431 sal_Int32 SAL_CALL SwAccessibleParagraph::getHyperLinkIndex( sal_Int32 nCharIndex ) 2432 throw (lang::IndexOutOfBoundsException, uno::RuntimeException) 2433 { 2434 vos::OGuard aGuard(Application::GetSolarMutex()); 2435 CHECK_FOR_DEFUNC( XAccessibleHypertext ); 2436 2437 // parameter checking 2438 sal_Int32 nLength = GetString().getLength(); 2439 if ( ! IsValidPosition( nCharIndex, nLength ) ) 2440 { 2441 throw lang::IndexOutOfBoundsException(); 2442 } 2443 2444 sal_Int32 nRet = -1; 2445 // --> OD 2007-06-27 #i77108# - provide hyperlinks also in editable documents. 2446 // if( !IsEditableState() ) 2447 // <-- 2448 { 2449 const SwTxtFrm *pTxtFrm = static_cast<const SwTxtFrm*>( GetFrm() ); 2450 SwHyperlinkIter_Impl aHIter( pTxtFrm ); 2451 2452 xub_StrLen nIdx = GetPortionData().GetModelPosition( nCharIndex ); 2453 sal_Int32 nPos = 0; 2454 const SwTxtAttr *pHt = aHIter.next(); 2455 while( pHt && !(nIdx >= *pHt->GetStart() && nIdx < *pHt->GetAnyEnd()) ) 2456 { 2457 pHt = aHIter.next(); 2458 nPos++; 2459 } 2460 2461 if( pHt ) 2462 nRet = nPos; 2463 2464 } 2465 2466 return nRet; 2467 } 2468 2469 // --> OD 2008-05-26 #i71360# 2470 // --> OD 2010-02-22 #i108125# - adjustments for change tracking text markup 2471 sal_Int32 SAL_CALL SwAccessibleParagraph::getTextMarkupCount( sal_Int32 nTextMarkupType ) 2472 throw (lang::IllegalArgumentException, 2473 uno::RuntimeException) 2474 { 2475 std::auto_ptr<SwTextMarkupHelper> pTextMarkupHelper; 2476 switch ( nTextMarkupType ) 2477 { 2478 case text::TextMarkupType::TRACK_CHANGE_INSERTION: 2479 case text::TextMarkupType::TRACK_CHANGE_DELETION: 2480 case text::TextMarkupType::TRACK_CHANGE_FORMATCHANGE: 2481 { 2482 pTextMarkupHelper.reset( new SwTextMarkupHelper( 2483 GetPortionData(), 2484 *(mpParaChangeTrackInfo->getChangeTrackingTextMarkupList( nTextMarkupType ) )) ); 2485 } 2486 break; 2487 default: 2488 { 2489 pTextMarkupHelper.reset( new SwTextMarkupHelper( GetPortionData(), *GetTxtNode() ) ); 2490 } 2491 } 2492 2493 return pTextMarkupHelper->getTextMarkupCount( nTextMarkupType ); 2494 } 2495 2496 /*accessibility::*/TextSegment SAL_CALL 2497 SwAccessibleParagraph::getTextMarkup( sal_Int32 nTextMarkupIndex, 2498 sal_Int32 nTextMarkupType ) 2499 throw (lang::IndexOutOfBoundsException, 2500 lang::IllegalArgumentException, 2501 uno::RuntimeException) 2502 { 2503 std::auto_ptr<SwTextMarkupHelper> pTextMarkupHelper; 2504 switch ( nTextMarkupType ) 2505 { 2506 case text::TextMarkupType::TRACK_CHANGE_INSERTION: 2507 case text::TextMarkupType::TRACK_CHANGE_DELETION: 2508 case text::TextMarkupType::TRACK_CHANGE_FORMATCHANGE: 2509 { 2510 pTextMarkupHelper.reset( new SwTextMarkupHelper( 2511 GetPortionData(), 2512 *(mpParaChangeTrackInfo->getChangeTrackingTextMarkupList( nTextMarkupType ) )) ); 2513 } 2514 break; 2515 default: 2516 { 2517 pTextMarkupHelper.reset( new SwTextMarkupHelper( GetPortionData(), *GetTxtNode() ) ); 2518 } 2519 } 2520 2521 return pTextMarkupHelper->getTextMarkup( nTextMarkupIndex, nTextMarkupType ); 2522 } 2523 2524 uno::Sequence< /*accessibility::*/TextSegment > SAL_CALL 2525 SwAccessibleParagraph::getTextMarkupAtIndex( sal_Int32 nCharIndex, 2526 sal_Int32 nTextMarkupType ) 2527 throw (lang::IndexOutOfBoundsException, 2528 lang::IllegalArgumentException, 2529 uno::RuntimeException) 2530 { 2531 // parameter checking 2532 const sal_Int32 nLength = GetString().getLength(); 2533 if ( ! IsValidPosition( nCharIndex, nLength ) ) 2534 { 2535 throw lang::IndexOutOfBoundsException(); 2536 } 2537 2538 std::auto_ptr<SwTextMarkupHelper> pTextMarkupHelper; 2539 switch ( nTextMarkupType ) 2540 { 2541 case text::TextMarkupType::TRACK_CHANGE_INSERTION: 2542 case text::TextMarkupType::TRACK_CHANGE_DELETION: 2543 case text::TextMarkupType::TRACK_CHANGE_FORMATCHANGE: 2544 { 2545 pTextMarkupHelper.reset( new SwTextMarkupHelper( 2546 GetPortionData(), 2547 *(mpParaChangeTrackInfo->getChangeTrackingTextMarkupList( nTextMarkupType ) )) ); 2548 } 2549 break; 2550 default: 2551 { 2552 pTextMarkupHelper.reset( new SwTextMarkupHelper( GetPortionData(), *GetTxtNode() ) ); 2553 } 2554 } 2555 2556 return pTextMarkupHelper->getTextMarkupAtIndex( nCharIndex, nTextMarkupType ); 2557 } 2558 // <-- 2559 2560 // --> OD 2008-05-29 #i89175# 2561 sal_Int32 SAL_CALL SwAccessibleParagraph::getLineNumberAtIndex( sal_Int32 nIndex ) 2562 throw (lang::IndexOutOfBoundsException, 2563 uno::RuntimeException) 2564 { 2565 // parameter checking 2566 const sal_Int32 nLength = GetString().getLength(); 2567 if ( ! IsValidPosition( nIndex, nLength ) ) 2568 { 2569 throw lang::IndexOutOfBoundsException(); 2570 } 2571 2572 const sal_Int32 nLineNo = GetPortionData().GetLineNo( nIndex ); 2573 return nLineNo; 2574 } 2575 2576 /*accessibility::*/TextSegment SAL_CALL 2577 SwAccessibleParagraph::getTextAtLineNumber( sal_Int32 nLineNo ) 2578 throw (lang::IndexOutOfBoundsException, 2579 uno::RuntimeException) 2580 { 2581 // parameter checking 2582 if ( nLineNo < 0 || 2583 nLineNo >= GetPortionData().GetLineCount() ) 2584 { 2585 throw lang::IndexOutOfBoundsException(); 2586 } 2587 2588 i18n::Boundary aLineBound; 2589 GetPortionData().GetBoundaryOfLine( nLineNo, aLineBound ); 2590 2591 /*accessibility::*/TextSegment aTextAtLine; 2592 const ::rtl::OUString rText = GetString(); 2593 aTextAtLine.SegmentText = rText.copy( aLineBound.startPos, 2594 aLineBound.endPos - aLineBound.startPos ); 2595 aTextAtLine.SegmentStart = aLineBound.startPos; 2596 aTextAtLine.SegmentEnd = aLineBound.endPos; 2597 2598 return aTextAtLine; 2599 } 2600 2601 /*accessibility::*/TextSegment SAL_CALL SwAccessibleParagraph::getTextAtLineWithCaret() 2602 throw (uno::RuntimeException) 2603 { 2604 const sal_Int32 nLineNoOfCaret = getNumberOfLineWithCaret(); 2605 2606 if ( nLineNoOfCaret >= 0 && 2607 nLineNoOfCaret < GetPortionData().GetLineCount() ) 2608 { 2609 return getTextAtLineNumber( nLineNoOfCaret ); 2610 } 2611 2612 return /*accessibility::*/TextSegment(); 2613 } 2614 2615 sal_Int32 SAL_CALL SwAccessibleParagraph::getNumberOfLineWithCaret() 2616 throw (uno::RuntimeException) 2617 { 2618 const sal_Int32 nCaretPos = getCaretPosition(); 2619 const sal_Int32 nLength = GetString().getLength(); 2620 if ( !IsValidPosition( nCaretPos, nLength ) ) 2621 { 2622 return -1; 2623 } 2624 2625 sal_Int32 nLineNo = GetPortionData().GetLineNo( nCaretPos ); 2626 2627 // special handling for cursor positioned at end of text line via End key 2628 if ( nCaretPos != 0 ) 2629 { 2630 i18n::Boundary aLineBound; 2631 GetPortionData().GetBoundaryOfLine( nLineNo, aLineBound ); 2632 if ( nCaretPos == aLineBound.startPos ) 2633 { 2634 SwCrsrShell* pCrsrShell = SwAccessibleParagraph::GetCrsrShell(); 2635 if ( pCrsrShell != 0 ) 2636 { 2637 const awt::Rectangle aCharRect = getCharacterBounds( nCaretPos ); 2638 2639 const SwRect& aCursorCoreRect = pCrsrShell->GetCharRect(); 2640 // translate core coordinates into accessibility coordinates 2641 Window *pWin = GetWindow(); 2642 CHECK_FOR_WINDOW( XAccessibleComponent, pWin ); 2643 2644 Rectangle aScreenRect( GetMap()->CoreToPixel( aCursorCoreRect.SVRect() )); 2645 2646 SwRect aFrmLogBounds( GetBounds( *(GetMap()) ) ); // twip rel to doc root 2647 Point aFrmPixPos( GetMap()->CoreToPixel( aFrmLogBounds.SVRect() ).TopLeft() ); 2648 aScreenRect.Move( -aFrmPixPos.X(), -aFrmPixPos.Y() ); 2649 2650 // convert into AWT Rectangle 2651 const awt::Rectangle aCursorRect( aScreenRect.Left(), 2652 aScreenRect.Top(), 2653 aScreenRect.GetWidth(), 2654 aScreenRect.GetHeight() ); 2655 2656 if ( aCharRect.X != aCursorRect.X || 2657 aCharRect.Y != aCursorRect.Y ) 2658 { 2659 --nLineNo; 2660 } 2661 } 2662 } 2663 } 2664 2665 return nLineNo; 2666 } 2667 2668 // --> OD 2010-02-19 #i108125# 2669 void SwAccessibleParagraph::Modify( const SfxPoolItem* pOld, const SfxPoolItem* pNew ) 2670 { 2671 mpParaChangeTrackInfo->reset(); 2672 2673 CheckRegistration( pOld, pNew ); 2674 } 2675 // <-- 2676