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 DBG_ASSERT( rBound.startPos <= nPos, "start pos too high" ); 762 DBG_ASSERT( rBound.endPos >= nPos, "end pos too low" ); 763 } 764 else 765 { 766 // no break Iterator -> no glyph 767 rBound.startPos = nPos; 768 rBound.endPos = nPos; 769 } 770 771 return bRet; 772 } 773 774 775 sal_Bool SwAccessibleParagraph::GetTextBoundary( 776 i18n::Boundary& rBound, 777 const ::rtl::OUString& rText, 778 sal_Int32 nPos, 779 sal_Int16 nTextType ) 780 throw ( 781 lang::IndexOutOfBoundsException, 782 lang::IllegalArgumentException, 783 uno::RuntimeException) 784 { 785 // error checking 786 if( !( AccessibleTextType::LINE == nTextType 787 ? IsValidPosition( nPos, rText.getLength() ) 788 : IsValidChar( nPos, rText.getLength() ) ) ) 789 throw lang::IndexOutOfBoundsException(); 790 791 sal_Bool bRet; 792 793 switch( nTextType ) 794 { 795 case AccessibleTextType::WORD: 796 bRet = GetWordBoundary( rBound, rText, nPos ); 797 break; 798 799 case AccessibleTextType::SENTENCE: 800 bRet = GetSentenceBoundary( rBound, rText, nPos ); 801 break; 802 803 case AccessibleTextType::PARAGRAPH: 804 bRet = GetParagraphBoundary( rBound, rText, nPos ); 805 break; 806 807 case AccessibleTextType::CHARACTER: 808 bRet = GetCharBoundary( rBound, rText, nPos ); 809 break; 810 811 case AccessibleTextType::LINE: 812 bRet = GetLineBoundary( rBound, rText, nPos ); 813 break; 814 815 case AccessibleTextType::ATTRIBUTE_RUN: 816 bRet = GetAttributeBoundary( rBound, rText, nPos ); 817 break; 818 819 case AccessibleTextType::GLYPH: 820 bRet = GetGlyphBoundary( rBound, rText, nPos ); 821 break; 822 823 default: 824 throw lang::IllegalArgumentException( ); 825 } 826 827 return bRet; 828 } 829 830 ::rtl::OUString SAL_CALL SwAccessibleParagraph::getAccessibleDescription (void) 831 throw (uno::RuntimeException) 832 { 833 vos::OGuard aGuard(Application::GetSolarMutex()); 834 835 CHECK_FOR_DEFUNC( XAccessibleContext ); 836 837 vos::OGuard aGuard2( aMutex ); 838 if( !sDesc.getLength() ) 839 sDesc = GetDescription(); 840 841 return sDesc; 842 } 843 844 lang::Locale SAL_CALL SwAccessibleParagraph::getLocale (void) 845 throw (IllegalAccessibleComponentStateException, uno::RuntimeException) 846 { 847 vos::OGuard aGuard(Application::GetSolarMutex()); 848 849 SwTxtFrm *pTxtFrm = PTR_CAST( SwTxtFrm, GetFrm() ); 850 if( !pTxtFrm ) 851 { 852 THROW_RUNTIME_EXCEPTION( XAccessibleContext, "internal error (no text frame)" ); 853 } 854 855 const SwTxtNode *pTxtNd = pTxtFrm->GetTxtNode(); 856 lang::Locale aLoc( pBreakIt->GetLocale( pTxtNd->GetLang( 0 ) ) ); 857 858 return aLoc; 859 } 860 861 /** paragraphs are in relation CONTENT_FLOWS_FROM and/or CONTENT_FLOWS_TO 862 863 OD 2005-12-02 #i27138# 864 865 @author OD 866 */ 867 uno::Reference<XAccessibleRelationSet> SAL_CALL SwAccessibleParagraph::getAccessibleRelationSet() 868 throw ( uno::RuntimeException ) 869 { 870 vos::OGuard aGuard(Application::GetSolarMutex()); 871 CHECK_FOR_DEFUNC( XAccessibleContext ); 872 873 utl::AccessibleRelationSetHelper* pHelper = new utl::AccessibleRelationSetHelper(); 874 875 const SwTxtFrm* pTxtFrm = dynamic_cast<const SwTxtFrm*>(GetFrm()); 876 ASSERT( pTxtFrm, 877 "<SwAccessibleParagraph::getAccessibleRelationSet()> - missing text frame"); 878 if ( pTxtFrm ) 879 { 880 const SwCntntFrm* pPrevCntFrm( pTxtFrm->FindPrevCnt( true ) ); 881 if ( pPrevCntFrm ) 882 { 883 uno::Sequence< uno::Reference<XInterface> > aSequence(1); 884 aSequence[0] = GetMap()->GetContext( pPrevCntFrm ); 885 AccessibleRelation aAccRel( AccessibleRelationType::CONTENT_FLOWS_FROM, 886 aSequence ); 887 pHelper->AddRelation( aAccRel ); 888 } 889 890 const SwCntntFrm* pNextCntFrm( pTxtFrm->FindNextCnt( true ) ); 891 if ( pNextCntFrm ) 892 { 893 uno::Sequence< uno::Reference<XInterface> > aSequence(1); 894 aSequence[0] = GetMap()->GetContext( pNextCntFrm ); 895 AccessibleRelation aAccRel( AccessibleRelationType::CONTENT_FLOWS_TO, 896 aSequence ); 897 pHelper->AddRelation( aAccRel ); 898 } 899 } 900 901 return pHelper; 902 } 903 904 void SAL_CALL SwAccessibleParagraph::grabFocus() 905 throw (uno::RuntimeException) 906 { 907 vos::OGuard aGuard(Application::GetSolarMutex()); 908 909 CHECK_FOR_DEFUNC( XAccessibleContext ); 910 911 // get cursor shell 912 SwCrsrShell *pCrsrSh = GetCrsrShell(); 913 // --> OD 2005-12-20 #i27301# - consider new method signature 914 SwPaM *pCrsr = GetCursor( false ); 915 // <-- 916 const SwTxtFrm *pTxtFrm = static_cast<const SwTxtFrm*>( GetFrm() ); 917 const SwTxtNode* pTxtNd = pTxtFrm->GetTxtNode(); 918 919 if( pCrsrSh != 0 && pTxtNd != 0 && 920 ( pCrsr == 0 || 921 pCrsr->GetPoint()->nNode.GetIndex() != pTxtNd->GetIndex() || 922 !pTxtFrm->IsInside( pCrsr->GetPoint()->nContent.GetIndex()) ) ) 923 { 924 // create pam for selection 925 SwIndex aIndex( const_cast< SwTxtNode * >( pTxtNd ), 926 pTxtFrm->GetOfst() ); 927 SwPosition aStartPos( *pTxtNd, aIndex ); 928 SwPaM aPaM( aStartPos ); 929 930 // set PaM at cursor shell 931 Select( aPaM ); 932 933 934 } 935 936 /* ->#i13955# */ 937 Window * pWindow = GetWindow(); 938 939 if (pWindow != NULL) 940 pWindow->GrabFocus(); 941 /* <-#i13955# */ 942 } 943 944 // --> OD 2007-01-17 #i71385# 945 bool lcl_GetBackgroundColor( Color & rColor, 946 const SwFrm* pFrm, 947 SwCrsrShell* pCrsrSh ) 948 { 949 const SvxBrushItem* pBackgrdBrush = 0; 950 const Color* pSectionTOXColor = 0; 951 SwRect aDummyRect; 952 if ( pFrm && 953 pFrm->GetBackgroundBrush( pBackgrdBrush, pSectionTOXColor, aDummyRect, false ) ) 954 { 955 if ( pSectionTOXColor ) 956 { 957 rColor = *pSectionTOXColor; 958 return true; 959 } 960 else 961 { 962 rColor = pBackgrdBrush->GetColor(); 963 return true; 964 } 965 } 966 else if ( pCrsrSh ) 967 { 968 rColor = pCrsrSh->Imp()->GetRetoucheColor(); 969 return true; 970 } 971 972 return false; 973 } 974 975 sal_Int32 SAL_CALL SwAccessibleParagraph::getForeground() 976 throw (uno::RuntimeException) 977 { 978 Color aBackgroundCol; 979 980 if ( lcl_GetBackgroundColor( aBackgroundCol, GetFrm(), GetCrsrShell() ) ) 981 { 982 if ( aBackgroundCol.IsDark() ) 983 { 984 return COL_WHITE; 985 } 986 else 987 { 988 return COL_BLACK; 989 } 990 } 991 992 return SwAccessibleContext::getForeground(); 993 } 994 995 sal_Int32 SAL_CALL SwAccessibleParagraph::getBackground() 996 throw (uno::RuntimeException) 997 { 998 Color aBackgroundCol; 999 1000 if ( lcl_GetBackgroundColor( aBackgroundCol, GetFrm(), GetCrsrShell() ) ) 1001 { 1002 return aBackgroundCol.GetColor(); 1003 } 1004 1005 return SwAccessibleContext::getBackground(); 1006 } 1007 // <-- 1008 1009 ::rtl::OUString SAL_CALL SwAccessibleParagraph::getImplementationName() 1010 throw( uno::RuntimeException ) 1011 { 1012 return ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(sImplementationName)); 1013 } 1014 1015 sal_Bool SAL_CALL SwAccessibleParagraph::supportsService( 1016 const ::rtl::OUString& sTestServiceName) 1017 throw (uno::RuntimeException) 1018 { 1019 return sTestServiceName.equalsAsciiL( sServiceName, 1020 sizeof(sServiceName)-1 ) || 1021 sTestServiceName.equalsAsciiL( sAccessibleServiceName, 1022 sizeof(sAccessibleServiceName)-1 ); 1023 } 1024 1025 uno::Sequence< ::rtl::OUString > SAL_CALL SwAccessibleParagraph::getSupportedServiceNames() 1026 throw( uno::RuntimeException ) 1027 { 1028 uno::Sequence< ::rtl::OUString > aRet(2); 1029 ::rtl::OUString* pArray = aRet.getArray(); 1030 pArray[0] = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(sServiceName) ); 1031 pArray[1] = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(sAccessibleServiceName) ); 1032 return aRet; 1033 } 1034 1035 // 1036 //===== XInterface ======================================================= 1037 // 1038 1039 uno::Any SwAccessibleParagraph::queryInterface( const uno::Type& rType ) 1040 throw (uno::RuntimeException) 1041 { 1042 uno::Any aRet; 1043 if ( rType == ::getCppuType((uno::Reference<XAccessibleText> *)0) ) 1044 { 1045 uno::Reference<XAccessibleText> aAccText = (XAccessibleText *) *this; // resolve ambiguity 1046 aRet <<= aAccText; 1047 } 1048 else if ( rType == ::getCppuType((uno::Reference<XAccessibleEditableText> *)0) ) 1049 { 1050 uno::Reference<XAccessibleEditableText> aAccEditText = this; 1051 aRet <<= aAccEditText; 1052 } 1053 else if ( rType == ::getCppuType((uno::Reference<XAccessibleSelection> *)0) ) 1054 { 1055 uno::Reference<XAccessibleSelection> aAccSel = this; 1056 aRet <<= aAccSel; 1057 } 1058 else if ( rType == ::getCppuType((uno::Reference<XAccessibleHypertext> *)0) ) 1059 { 1060 uno::Reference<XAccessibleHypertext> aAccHyp = this; 1061 aRet <<= aAccHyp; 1062 } 1063 // --> OD 2006-07-13 #i63870# 1064 // add interface com::sun:star:accessibility::XAccessibleTextAttributes 1065 else if ( rType == ::getCppuType((uno::Reference<XAccessibleTextAttributes> *)0) ) 1066 { 1067 uno::Reference<XAccessibleTextAttributes> aAccTextAttr = this; 1068 aRet <<= aAccTextAttr; 1069 } 1070 // <-- 1071 // --> OD 2008-06-10 #i89175# 1072 // add interface com::sun:star:accessibility::XAccessibleTextMarkup 1073 else if ( rType == ::getCppuType((uno::Reference<XAccessibleTextMarkup> *)0) ) 1074 { 1075 uno::Reference<XAccessibleTextMarkup> aAccTextMarkup = this; 1076 aRet <<= aAccTextMarkup; 1077 } 1078 // add interface com::sun:star:accessibility::XAccessibleMultiLineText 1079 else if ( rType == ::getCppuType((uno::Reference<XAccessibleMultiLineText> *)0) ) 1080 { 1081 uno::Reference<XAccessibleMultiLineText> aAccMultiLineText = this; 1082 aRet <<= aAccMultiLineText; 1083 } 1084 // <-- 1085 else 1086 { 1087 aRet = SwAccessibleContext::queryInterface(rType); 1088 } 1089 1090 return aRet; 1091 } 1092 1093 //====== XTypeProvider ==================================================== 1094 uno::Sequence< uno::Type > SAL_CALL SwAccessibleParagraph::getTypes() throw(uno::RuntimeException) 1095 { 1096 uno::Sequence< uno::Type > aTypes( SwAccessibleContext::getTypes() ); 1097 1098 sal_Int32 nIndex = aTypes.getLength(); 1099 // --> OD 2006-07-13 #i63870# 1100 // add type accessibility::XAccessibleTextAttributes 1101 // --> OD 2008-06-10 #i89175# 1102 // add type accessibility::XAccessibleTextMarkup and accessibility::XAccessibleMultiLineText 1103 aTypes.realloc( nIndex + 6 ); 1104 1105 uno::Type* pTypes = aTypes.getArray(); 1106 pTypes[nIndex++] = ::getCppuType( static_cast< uno::Reference< XAccessibleEditableText > * >( 0 ) ); 1107 pTypes[nIndex++] = ::getCppuType( static_cast< uno::Reference< XAccessibleTextAttributes > * >( 0 ) ); 1108 pTypes[nIndex++] = ::getCppuType( static_cast< uno::Reference< XAccessibleSelection > * >( 0 ) ); 1109 pTypes[nIndex++] = ::getCppuType( static_cast< uno::Reference< XAccessibleTextMarkup > * >( 0 ) ); 1110 pTypes[nIndex++] = ::getCppuType( static_cast< uno::Reference< XAccessibleMultiLineText > * >( 0 ) ); 1111 pTypes[nIndex] = ::getCppuType( static_cast< uno::Reference< XAccessibleHypertext > * >( 0 ) ); 1112 // <-- 1113 1114 return aTypes; 1115 } 1116 1117 uno::Sequence< sal_Int8 > SAL_CALL SwAccessibleParagraph::getImplementationId() 1118 throw(uno::RuntimeException) 1119 { 1120 vos::OGuard aGuard(Application::GetSolarMutex()); 1121 static uno::Sequence< sal_Int8 > aId( 16 ); 1122 static sal_Bool bInit = sal_False; 1123 if(!bInit) 1124 { 1125 rtl_createUuid( (sal_uInt8 *)(aId.getArray() ), 0, sal_True ); 1126 bInit = sal_True; 1127 } 1128 return aId; 1129 } 1130 1131 1132 // 1133 //===== XAccesibleText =================================================== 1134 // 1135 1136 sal_Int32 SwAccessibleParagraph::getCaretPosition() 1137 throw (uno::RuntimeException) 1138 { 1139 vos::OGuard aGuard(Application::GetSolarMutex()); 1140 1141 CHECK_FOR_DEFUNC_THIS( XAccessibleText, *this ); 1142 1143 sal_Int32 nRet = GetCaretPos(); 1144 { 1145 vos::OGuard aOldCaretPosGuard( aMutex ); 1146 ASSERT( nRet == nOldCaretPos, "caret pos out of sync" ); 1147 nOldCaretPos = nRet; 1148 } 1149 if( -1 != nRet ) 1150 { 1151 ::vos::ORef < SwAccessibleContext > xThis( this ); 1152 GetMap()->SetCursorContext( xThis ); 1153 } 1154 1155 return nRet; 1156 } 1157 1158 sal_Bool SAL_CALL SwAccessibleParagraph::setCaretPosition( sal_Int32 nIndex ) 1159 throw (lang::IndexOutOfBoundsException, uno::RuntimeException) 1160 { 1161 vos::OGuard aGuard(Application::GetSolarMutex()); 1162 1163 CHECK_FOR_DEFUNC_THIS( XAccessibleText, *this ); 1164 1165 // parameter checking 1166 sal_Int32 nLength = GetString().getLength(); 1167 if ( ! IsValidPosition( nIndex, nLength ) ) 1168 { 1169 throw lang::IndexOutOfBoundsException(); 1170 } 1171 1172 sal_Bool bRet = sal_False; 1173 1174 // get cursor shell 1175 SwCrsrShell* pCrsrShell = GetCrsrShell(); 1176 if( pCrsrShell != NULL ) 1177 { 1178 // create pam for selection 1179 SwTxtNode* pNode = const_cast<SwTxtNode*>( GetTxtNode() ); 1180 SwIndex aIndex( pNode, GetPortionData().GetModelPosition(nIndex)); 1181 SwPosition aStartPos( *pNode, aIndex ); 1182 SwPaM aPaM( aStartPos ); 1183 1184 // set PaM at cursor shell 1185 bRet = Select( aPaM ); 1186 } 1187 1188 return bRet; 1189 } 1190 1191 sal_Unicode SwAccessibleParagraph::getCharacter( sal_Int32 nIndex ) 1192 throw (lang::IndexOutOfBoundsException, uno::RuntimeException) 1193 { 1194 vos::OGuard aGuard(Application::GetSolarMutex()); 1195 1196 CHECK_FOR_DEFUNC_THIS( XAccessibleText, *this ); 1197 1198 ::rtl::OUString sText( GetString() ); 1199 1200 // return character (if valid) 1201 if( IsValidChar(nIndex, sText.getLength() ) ) 1202 { 1203 return sText.getStr()[nIndex]; 1204 } 1205 else 1206 throw lang::IndexOutOfBoundsException(); 1207 } 1208 1209 // --> OD 2006-07-20 #i63870# 1210 // re-implement method on behalf of methods <_getDefaultAttributesImpl(..)> and 1211 // <_getRunAttributesImpl(..)> 1212 uno::Sequence<PropertyValue> SwAccessibleParagraph::getCharacterAttributes( 1213 sal_Int32 nIndex, 1214 const uno::Sequence< ::rtl::OUString >& aRequestedAttributes ) 1215 throw (lang::IndexOutOfBoundsException, uno::RuntimeException) 1216 { 1217 1218 vos::OGuard aGuard(Application::GetSolarMutex()); 1219 CHECK_FOR_DEFUNC_THIS( XAccessibleText, *this ); 1220 1221 const ::rtl::OUString& rText = GetString(); 1222 1223 if( ! IsValidChar( nIndex, rText.getLength() ) ) 1224 throw lang::IndexOutOfBoundsException(); 1225 1226 // retrieve default character attributes 1227 tAccParaPropValMap aDefAttrSeq; 1228 _getDefaultAttributesImpl( aRequestedAttributes, aDefAttrSeq, true ); 1229 1230 // retrieved run character attributes 1231 tAccParaPropValMap aRunAttrSeq; 1232 _getRunAttributesImpl( nIndex, aRequestedAttributes, aRunAttrSeq ); 1233 1234 // merge default and run attributes 1235 uno::Sequence< PropertyValue > aValues( aDefAttrSeq.size() ); 1236 PropertyValue* pValues = aValues.getArray(); 1237 sal_Int32 i = 0; 1238 for ( tAccParaPropValMap::const_iterator aDefIter = aDefAttrSeq.begin(); 1239 aDefIter != aDefAttrSeq.end(); 1240 ++aDefIter ) 1241 { 1242 tAccParaPropValMap::const_iterator aRunIter = 1243 aRunAttrSeq.find( aDefIter->first ); 1244 if ( aRunIter != aRunAttrSeq.end() ) 1245 { 1246 pValues[i] = aRunIter->second; 1247 } 1248 else 1249 { 1250 pValues[i] = aDefIter->second; 1251 } 1252 ++i; 1253 } 1254 1255 // // create a (dummy) text portion for the sole purpose of calling 1256 // // getPropertyValues on it 1257 // Reference<XMultiPropertySet> xPortion = CreateUnoPortion( nIndex, nIndex + 1 ); 1258 1259 // // get values 1260 // Sequence<OUString> aNames = getAttributeNames(); 1261 // sal_Int32 nLength = aNames.getLength(); 1262 // Sequence<Any> aAnys( nLength ); 1263 // aAnys = xPortion->getPropertyValues( aNames ); 1264 1265 // // copy names + anys into return sequence 1266 // Sequence<PropertyValue> aValues( aNames.getLength() ); 1267 // const OUString* pNames = aNames.getConstArray(); 1268 // const Any* pAnys = aAnys.getConstArray(); 1269 // PropertyValue* pValues = aValues.getArray(); 1270 // for( sal_Int32 i = 0; i < nLength; i++ ) 1271 // { 1272 // PropertyValue& rValue = pValues[i]; 1273 // rValue.Name = pNames[i]; 1274 // rValue.Value = pAnys[i]; 1275 // rValue.Handle = -1; // handle not supported 1276 // rValue.State = PropertyState_DIRECT_VALUE; // states not supported 1277 // } 1278 1279 // // adjust background color if we're in a gray portion 1280 // DBG_ASSERT( pValues[CHAR_BACK_COLOR_POS].Name. 1281 // equalsAsciiL(RTL_CONSTASCII_STRINGPARAM("CharBackColor")), 1282 // "Please adjust CHAR_BACK_COLOR_POS constant." ); 1283 // if( GetPortionData().IsInGrayPortion( nIndex ) ) 1284 // pValues[CHAR_BACK_COLOR_POS].Value <<= SwViewOption::GetFieldShadingsColor().GetColor(); 1285 1286 return aValues; 1287 } 1288 1289 // --> OD 2006-07-11 #i63870# 1290 void SwAccessibleParagraph::_getDefaultAttributesImpl( 1291 const uno::Sequence< ::rtl::OUString >& aRequestedAttributes, 1292 tAccParaPropValMap& rDefAttrSeq, 1293 const bool bOnlyCharAttrs ) 1294 { 1295 // retrieve default attributes 1296 const SwTxtNode* pTxtNode( GetTxtNode() ); 1297 ::boost::scoped_ptr<SfxItemSet> pSet; 1298 if ( !bOnlyCharAttrs ) 1299 { 1300 pSet.reset( new SfxItemSet( const_cast<SwAttrPool&>(pTxtNode->GetDoc()->GetAttrPool()), 1301 RES_CHRATR_BEGIN, RES_CHRATR_END - 1, 1302 RES_PARATR_BEGIN, RES_PARATR_END - 1, 1303 RES_FRMATR_BEGIN, RES_FRMATR_END - 1, 1304 0 ) ); 1305 } 1306 else 1307 { 1308 pSet.reset( new SfxItemSet( const_cast<SwAttrPool&>(pTxtNode->GetDoc()->GetAttrPool()), 1309 RES_CHRATR_BEGIN, RES_CHRATR_END - 1, 1310 0 ) ); 1311 } 1312 // --> OD 2007-11-12 #i82637# 1313 // From the perspective of the a11y API the default character attributes 1314 // are the character attributes, which are set at the paragraph style 1315 // of the paragraph. The character attributes set at the automatic paragraph 1316 // style of the paragraph are treated as run attributes. 1317 // pTxtNode->SwCntntNode::GetAttr( *pSet ); 1318 // get default paragraph attributes, if needed, and merge these into <pSet> 1319 if ( !bOnlyCharAttrs ) 1320 { 1321 SfxItemSet aParaSet( const_cast<SwAttrPool&>(pTxtNode->GetDoc()->GetAttrPool()), 1322 RES_PARATR_BEGIN, RES_PARATR_END - 1, 1323 RES_FRMATR_BEGIN, RES_FRMATR_END - 1, 1324 0 ); 1325 pTxtNode->SwCntntNode::GetAttr( aParaSet ); 1326 pSet->Put( aParaSet ); 1327 } 1328 // get default character attributes and merge these into <pSet> 1329 ASSERT( pTxtNode->GetTxtColl(), 1330 "<SwAccessibleParagraph::_getDefaultAttributesImpl(..)> - missing paragraph style. Serious defect, please inform OD!" ); 1331 if ( pTxtNode->GetTxtColl() ) 1332 { 1333 SfxItemSet aCharSet( const_cast<SwAttrPool&>(pTxtNode->GetDoc()->GetAttrPool()), 1334 RES_CHRATR_BEGIN, RES_CHRATR_END - 1, 1335 0 ); 1336 aCharSet.Put( pTxtNode->GetTxtColl()->GetAttrSet() ); 1337 pSet->Put( aCharSet ); 1338 } 1339 // <-- 1340 1341 // build-up sequence containing the run attributes <rDefAttrSeq> 1342 tAccParaPropValMap aDefAttrSeq; 1343 { 1344 const SfxItemPropertyMap* pPropMap = 1345 aSwMapProvider.GetPropertySet( PROPERTY_MAP_TEXT_CURSOR )->getPropertyMap(); 1346 PropertyEntryVector_t aPropertyEntries = pPropMap->getPropertyEntries(); 1347 PropertyEntryVector_t::const_iterator aPropIt = aPropertyEntries.begin(); 1348 while ( aPropIt != aPropertyEntries.end() ) 1349 { 1350 const SfxPoolItem* pItem = pSet->GetItem( aPropIt->nWID ); 1351 if ( pItem ) 1352 { 1353 uno::Any aVal; 1354 pItem->QueryValue( aVal, aPropIt->nMemberId ); 1355 1356 PropertyValue rPropVal; 1357 rPropVal.Name = aPropIt->sName; 1358 rPropVal.Value = aVal; 1359 rPropVal.Handle = -1; 1360 rPropVal.State = beans::PropertyState_DEFAULT_VALUE; 1361 1362 aDefAttrSeq[rPropVal.Name] = rPropVal; 1363 } 1364 ++aPropIt; 1365 } 1366 1367 // --> OD 2007-01-15 #i72800# 1368 // add property value entry for the paragraph style 1369 if ( !bOnlyCharAttrs && pTxtNode->GetTxtColl() ) 1370 { 1371 const ::rtl::OUString sParaStyleName = 1372 ::rtl::OUString::createFromAscii( 1373 GetPropName( UNO_NAME_PARA_STYLE_NAME ).pName ); 1374 if ( aDefAttrSeq.find( sParaStyleName ) == aDefAttrSeq.end() ) 1375 { 1376 PropertyValue rPropVal; 1377 rPropVal.Name = sParaStyleName; 1378 uno::Any aVal( uno::makeAny( ::rtl::OUString( pTxtNode->GetTxtColl()->GetName() ) ) ); 1379 rPropVal.Value = aVal; 1380 rPropVal.Handle = -1; 1381 rPropVal.State = beans::PropertyState_DEFAULT_VALUE; 1382 1383 aDefAttrSeq[rPropVal.Name] = rPropVal; 1384 } 1385 } 1386 // <-- 1387 1388 // --> OD 2007-01-15 #i73371# 1389 // resolve value text::WritingMode2::PAGE of property value entry WritingMode 1390 if ( !bOnlyCharAttrs && GetFrm() ) 1391 { 1392 const ::rtl::OUString sWritingMode = 1393 ::rtl::OUString::createFromAscii( 1394 GetPropName( UNO_NAME_WRITING_MODE ).pName ); 1395 tAccParaPropValMap::iterator aIter = aDefAttrSeq.find( sWritingMode ); 1396 if ( aIter != aDefAttrSeq.end() ) 1397 { 1398 PropertyValue rPropVal( aIter->second ); 1399 sal_Int16 nVal = rPropVal.Value.get<sal_Int16>(); 1400 if ( nVal == text::WritingMode2::PAGE ) 1401 { 1402 const SwFrm* pUpperFrm( GetFrm()->GetUpper() ); 1403 while ( pUpperFrm ) 1404 { 1405 if ( pUpperFrm->GetType() & 1406 ( FRM_PAGE | FRM_FLY | FRM_SECTION | FRM_TAB | FRM_CELL ) ) 1407 { 1408 if ( pUpperFrm->IsVertical() ) 1409 { 1410 nVal = text::WritingMode2::TB_RL; 1411 } 1412 else if ( pUpperFrm->IsRightToLeft() ) 1413 { 1414 nVal = text::WritingMode2::RL_TB; 1415 } 1416 else 1417 { 1418 nVal = text::WritingMode2::LR_TB; 1419 } 1420 rPropVal.Value <<= nVal; 1421 aDefAttrSeq[rPropVal.Name] = rPropVal; 1422 break; 1423 } 1424 1425 if ( dynamic_cast<const SwFlyFrm*>(pUpperFrm) ) 1426 { 1427 pUpperFrm = dynamic_cast<const SwFlyFrm*>(pUpperFrm)->GetAnchorFrm(); 1428 } 1429 else 1430 { 1431 pUpperFrm = pUpperFrm->GetUpper(); 1432 } 1433 } 1434 } 1435 } 1436 } 1437 // <-- 1438 } 1439 1440 if ( aRequestedAttributes.getLength() == 0 ) 1441 { 1442 rDefAttrSeq = aDefAttrSeq; 1443 } 1444 else 1445 { 1446 const ::rtl::OUString* pReqAttrs = aRequestedAttributes.getConstArray(); 1447 const sal_Int32 nLength = aRequestedAttributes.getLength(); 1448 for( sal_Int32 i = 0; i < nLength; ++i ) 1449 { 1450 tAccParaPropValMap::const_iterator const aIter = aDefAttrSeq.find( pReqAttrs[i] ); 1451 if ( aIter != aDefAttrSeq.end() ) 1452 { 1453 rDefAttrSeq[ aIter->first ] = aIter->second; 1454 } 1455 } 1456 } 1457 } 1458 1459 uno::Sequence< PropertyValue > SwAccessibleParagraph::getDefaultAttributes( 1460 const uno::Sequence< ::rtl::OUString >& aRequestedAttributes ) 1461 throw ( uno::RuntimeException ) 1462 { 1463 vos::OGuard aGuard(Application::GetSolarMutex()); 1464 CHECK_FOR_DEFUNC_THIS( XAccessibleText, *this ); 1465 1466 tAccParaPropValMap aDefAttrSeq; 1467 _getDefaultAttributesImpl( aRequestedAttributes, aDefAttrSeq ); 1468 1469 // --> OD 2010-03-08 #i92233# 1470 static rtl::OUString sMMToPixelRatio( rtl::OUString::createFromAscii( "MMToPixelRatio" ) ); 1471 bool bProvideMMToPixelRatio( false ); 1472 { 1473 if ( aRequestedAttributes.getLength() == 0 ) 1474 { 1475 bProvideMMToPixelRatio = true; 1476 } 1477 else 1478 { 1479 const rtl::OUString* aRequestedAttrIter = 1480 ::std::find( ::comphelper::stl_begin( aRequestedAttributes ), 1481 ::comphelper::stl_end( aRequestedAttributes ), 1482 sMMToPixelRatio ); 1483 if ( aRequestedAttrIter != ::comphelper::stl_end( aRequestedAttributes ) ) 1484 { 1485 bProvideMMToPixelRatio = true; 1486 } 1487 } 1488 } 1489 // <-- 1490 1491 uno::Sequence< PropertyValue > aValues( aDefAttrSeq.size() + 1492 ( bProvideMMToPixelRatio ? 1 : 0 ) ); 1493 PropertyValue* pValues = aValues.getArray(); 1494 sal_Int32 i = 0; 1495 for ( tAccParaPropValMap::const_iterator aIter = aDefAttrSeq.begin(); 1496 aIter != aDefAttrSeq.end(); 1497 ++aIter ) 1498 { 1499 pValues[i] = aIter->second; 1500 ++i; 1501 } 1502 1503 // --> OD 2010-03-08 #i92233# 1504 if ( bProvideMMToPixelRatio ) 1505 { 1506 PropertyValue rPropVal; 1507 rPropVal.Name = sMMToPixelRatio; 1508 const Size a100thMMSize( 1000, 1000 ); 1509 const Size aPixelSize = GetMap()->LogicToPixel( a100thMMSize ); 1510 const float fRatio = ((float)a100thMMSize.Width()/100)/aPixelSize.Width(); 1511 rPropVal.Value = uno::makeAny( fRatio ); 1512 rPropVal.Handle = -1; 1513 rPropVal.State = beans::PropertyState_DEFAULT_VALUE; 1514 pValues[ aValues.getLength() - 1 ] = rPropVal; 1515 } 1516 // <-- 1517 1518 return aValues; 1519 } 1520 1521 void SwAccessibleParagraph::_getRunAttributesImpl( 1522 const sal_Int32 nIndex, 1523 const uno::Sequence< ::rtl::OUString >& aRequestedAttributes, 1524 tAccParaPropValMap& rRunAttrSeq ) 1525 { 1526 // create PaM for character at position <nIndex> 1527 SwPaM* pPaM( 0 ); 1528 { 1529 const SwTxtNode* pTxtNode( GetTxtNode() ); 1530 SwPosition* pStartPos = new SwPosition( *pTxtNode ); 1531 pStartPos->nContent.Assign( const_cast<SwTxtNode*>(pTxtNode), static_cast<sal_uInt16>(nIndex) ); 1532 SwPosition* pEndPos = new SwPosition( *pTxtNode ); 1533 pEndPos->nContent.Assign( const_cast<SwTxtNode*>(pTxtNode), static_cast<sal_uInt16>(nIndex+1) ); 1534 1535 pPaM = new SwPaM( *pStartPos, *pEndPos ); 1536 1537 delete pStartPos; 1538 delete pEndPos; 1539 } 1540 1541 // retrieve character attributes for the created PaM <pPaM> 1542 SfxItemSet aSet( pPaM->GetDoc()->GetAttrPool(), 1543 RES_CHRATR_BEGIN, RES_CHRATR_END -1, 1544 0 ); 1545 // --> OD 2007-11-12 #i82637# 1546 // From the perspective of the a11y API the character attributes, which 1547 // are set at the automatic paragraph style of the paragraph are treated 1548 // as run attributes. 1549 // SwXTextCursor::GetCrsrAttr( *pPaM, aSet, sal_True, sal_True ); 1550 // get character attributes from automatic paragraph style and merge these into <aSet> 1551 { 1552 const SwTxtNode* pTxtNode( GetTxtNode() ); 1553 if ( pTxtNode->HasSwAttrSet() ) 1554 { 1555 SfxItemSet aAutomaticParaStyleCharAttrs( pPaM->GetDoc()->GetAttrPool(), 1556 RES_CHRATR_BEGIN, RES_CHRATR_END -1, 1557 0 ); 1558 aAutomaticParaStyleCharAttrs.Put( *(pTxtNode->GetpSwAttrSet()), sal_False ); 1559 aSet.Put( aAutomaticParaStyleCharAttrs ); 1560 } 1561 } 1562 // get character attributes at <pPaM> and merge these into <aSet> 1563 { 1564 SfxItemSet aCharAttrsAtPaM( pPaM->GetDoc()->GetAttrPool(), 1565 RES_CHRATR_BEGIN, RES_CHRATR_END -1, 1566 0 ); 1567 SwUnoCursorHelper::GetCrsrAttr(*pPaM, aCharAttrsAtPaM, sal_True, sal_True); 1568 aSet.Put( aCharAttrsAtPaM ); 1569 } 1570 // <-- 1571 1572 // build-up sequence containing the run attributes <rRunAttrSeq> 1573 { 1574 tAccParaPropValMap aRunAttrSeq; 1575 { 1576 // --> OD 2007-11-12 #i82637# 1577 tAccParaPropValMap aDefAttrSeq; 1578 uno::Sequence< ::rtl::OUString > aDummy; 1579 _getDefaultAttributesImpl( aDummy, aDefAttrSeq, true ); 1580 // <-- 1581 1582 const SfxItemPropertyMap* pPropMap = 1583 aSwMapProvider.GetPropertySet( PROPERTY_MAP_TEXT_CURSOR )->getPropertyMap(); 1584 PropertyEntryVector_t aPropertyEntries = pPropMap->getPropertyEntries(); 1585 PropertyEntryVector_t::const_iterator aPropIt = aPropertyEntries.begin(); 1586 while ( aPropIt != aPropertyEntries.end() ) 1587 { 1588 const SfxPoolItem* pItem( 0 ); 1589 // --> OD 2007-11-12 #i82637# 1590 // Found character attributes, whose value equals the value of 1591 // the corresponding default character attributes, are excluded. 1592 if ( aSet.GetItemState( aPropIt->nWID, sal_True, &pItem ) == SFX_ITEM_SET ) 1593 { 1594 uno::Any aVal; 1595 pItem->QueryValue( aVal, aPropIt->nMemberId ); 1596 1597 PropertyValue rPropVal; 1598 rPropVal.Name = aPropIt->sName; 1599 rPropVal.Value = aVal; 1600 rPropVal.Handle = -1; 1601 rPropVal.State = PropertyState_DIRECT_VALUE; 1602 1603 tAccParaPropValMap::const_iterator aDefIter = 1604 aDefAttrSeq.find( rPropVal.Name ); 1605 if ( aDefIter == aDefAttrSeq.end() || 1606 rPropVal.Value != aDefIter->second.Value ) 1607 { 1608 aRunAttrSeq[rPropVal.Name] = rPropVal; 1609 } 1610 } 1611 1612 ++aPropIt; 1613 } 1614 } 1615 1616 if ( aRequestedAttributes.getLength() == 0 ) 1617 { 1618 rRunAttrSeq = aRunAttrSeq; 1619 } 1620 else 1621 { 1622 const ::rtl::OUString* pReqAttrs = aRequestedAttributes.getConstArray(); 1623 const sal_Int32 nLength = aRequestedAttributes.getLength(); 1624 for( sal_Int32 i = 0; i < nLength; ++i ) 1625 { 1626 tAccParaPropValMap::iterator aIter = aRunAttrSeq.find( pReqAttrs[i] ); 1627 if ( aIter != aRunAttrSeq.end() ) 1628 { 1629 rRunAttrSeq[ (*aIter).first ] = (*aIter).second; 1630 } 1631 } 1632 } 1633 } 1634 1635 delete pPaM; 1636 } 1637 1638 uno::Sequence< PropertyValue > SwAccessibleParagraph::getRunAttributes( 1639 sal_Int32 nIndex, 1640 const uno::Sequence< ::rtl::OUString >& aRequestedAttributes ) 1641 throw ( lang::IndexOutOfBoundsException, 1642 uno::RuntimeException ) 1643 { 1644 vos::OGuard aGuard(Application::GetSolarMutex()); 1645 CHECK_FOR_DEFUNC_THIS( XAccessibleText, *this ); 1646 1647 { 1648 const ::rtl::OUString& rText = GetString(); 1649 if ( !IsValidChar( nIndex, rText.getLength() ) ) 1650 { 1651 throw lang::IndexOutOfBoundsException(); 1652 } 1653 } 1654 1655 tAccParaPropValMap aRunAttrSeq; 1656 _getRunAttributesImpl( nIndex, aRequestedAttributes, aRunAttrSeq ); 1657 1658 uno::Sequence< PropertyValue > aValues( aRunAttrSeq.size() ); 1659 PropertyValue* pValues = aValues.getArray(); 1660 sal_Int32 i = 0; 1661 for ( tAccParaPropValMap::const_iterator aIter = aRunAttrSeq.begin(); 1662 aIter != aRunAttrSeq.end(); 1663 ++aIter ) 1664 { 1665 pValues[i] = aIter->second; 1666 ++i; 1667 } 1668 1669 return aValues; 1670 } 1671 // <-- 1672 1673 awt::Rectangle SwAccessibleParagraph::getCharacterBounds( 1674 sal_Int32 nIndex ) 1675 throw (lang::IndexOutOfBoundsException, uno::RuntimeException) 1676 { 1677 vos::OGuard aGuard(Application::GetSolarMutex()); 1678 1679 CHECK_FOR_DEFUNC_THIS( XAccessibleText, *this ); 1680 1681 1682 /* #i12332# The position after the string needs special treatment. 1683 IsValidChar -> IsValidPosition 1684 */ 1685 if( ! (IsValidPosition( nIndex, GetString().getLength() ) ) ) 1686 throw lang::IndexOutOfBoundsException(); 1687 1688 /* #i12332# */ 1689 sal_Bool bBehindText = sal_False; 1690 if ( nIndex == GetString().getLength() ) 1691 bBehindText = sal_True; 1692 1693 // get model position & prepare GetCharRect() arguments 1694 SwCrsrMoveState aMoveState; 1695 aMoveState.bRealHeight = sal_True; 1696 aMoveState.bRealWidth = sal_True; 1697 SwSpecialPos aSpecialPos; 1698 SwTxtNode* pNode = const_cast<SwTxtNode*>( GetTxtNode() ); 1699 1700 sal_uInt16 nPos = 0; 1701 1702 /* #i12332# FillSpecialPos does not accept nIndex == 1703 GetString().getLength(). In that case nPos is set to the 1704 length of the string in the core. This way GetCharRect 1705 returns the rectangle for a cursor at the end of the 1706 paragraph. */ 1707 if (bBehindText) 1708 { 1709 nPos = pNode->GetTxt().Len(); 1710 } 1711 else 1712 nPos = GetPortionData().FillSpecialPos 1713 (nIndex, aSpecialPos, aMoveState.pSpecialPos ); 1714 1715 // call GetCharRect 1716 SwRect aCoreRect; 1717 SwIndex aIndex( pNode, nPos ); 1718 SwPosition aPosition( *pNode, aIndex ); 1719 GetFrm()->GetCharRect( aCoreRect, aPosition, &aMoveState ); 1720 1721 // translate core coordinates into accessibility coordinates 1722 Window *pWin = GetWindow(); 1723 CHECK_FOR_WINDOW( XAccessibleComponent, pWin ); 1724 1725 Rectangle aScreenRect( GetMap()->CoreToPixel( aCoreRect.SVRect() )); 1726 SwRect aFrmLogBounds( GetBounds( *(GetMap()) ) ); // twip rel to doc root 1727 1728 Point aFrmPixPos( GetMap()->CoreToPixel( aFrmLogBounds.SVRect() ).TopLeft() ); 1729 aScreenRect.Move( -aFrmPixPos.X(), -aFrmPixPos.Y() ); 1730 1731 // convert into AWT Rectangle 1732 return awt::Rectangle( 1733 aScreenRect.Left(), aScreenRect.Top(), 1734 aScreenRect.GetWidth(), aScreenRect.GetHeight() ); 1735 } 1736 1737 sal_Int32 SwAccessibleParagraph::getCharacterCount() 1738 throw (uno::RuntimeException) 1739 { 1740 vos::OGuard aGuard(Application::GetSolarMutex()); 1741 1742 CHECK_FOR_DEFUNC_THIS( XAccessibleText, *this ); 1743 1744 return GetString().getLength(); 1745 } 1746 1747 sal_Int32 SwAccessibleParagraph::getIndexAtPoint( const awt::Point& rPoint ) 1748 throw (uno::RuntimeException) 1749 { 1750 vos::OGuard aGuard(Application::GetSolarMutex()); 1751 1752 1753 CHECK_FOR_DEFUNC_THIS( XAccessibleText, *this ); 1754 1755 // construct SwPosition (where GetCrsrOfst() will put the result into) 1756 SwTxtNode* pNode = const_cast<SwTxtNode*>( GetTxtNode() ); 1757 SwIndex aIndex( pNode, 0); 1758 SwPosition aPos( *pNode, aIndex ); 1759 1760 // construct Point (translate into layout coordinates) 1761 Window *pWin = GetWindow(); 1762 CHECK_FOR_WINDOW( XAccessibleComponent, pWin ); 1763 Point aPoint( rPoint.X, rPoint.Y ); 1764 SwRect aLogBounds( GetBounds( *(GetMap()), GetFrm() ) ); // twip rel to doc root 1765 Point aPixPos( GetMap()->CoreToPixel( aLogBounds.SVRect() ).TopLeft() ); 1766 aPoint.X() += aPixPos.X(); 1767 aPoint.Y() += aPixPos.Y(); 1768 MapMode aMapMode = pWin->GetMapMode(); 1769 Point aCorePoint( GetMap()->PixelToCore( aPoint ) ); 1770 if( !aLogBounds.IsInside( aCorePoint ) ) 1771 { 1772 /* #i12332# rPoint is may also be in rectangle returned by 1773 getCharacterBounds(getCharacterCount() */ 1774 1775 awt::Rectangle aRectEndPos = 1776 getCharacterBounds(getCharacterCount()); 1777 1778 if (rPoint.X - aRectEndPos.X >= 0 && 1779 rPoint.X - aRectEndPos.X < aRectEndPos.Width && 1780 rPoint.Y - aRectEndPos.Y >= 0 && 1781 rPoint.Y - aRectEndPos.Y < aRectEndPos.Height) 1782 return getCharacterCount(); 1783 1784 return -1; 1785 } 1786 1787 // ask core for position 1788 DBG_ASSERT( GetFrm() != NULL, "The text frame has vanished!" ); 1789 DBG_ASSERT( GetFrm()->IsTxtFrm(), "The text frame has mutated!" ); 1790 const SwTxtFrm* pFrm = static_cast<const SwTxtFrm*>( GetFrm() ); 1791 SwCrsrMoveState aMoveState; 1792 aMoveState.bPosMatchesBounds = sal_True; 1793 sal_Bool bSuccess = pFrm->GetCrsrOfst( &aPos, aCorePoint, &aMoveState ); 1794 1795 SwIndex aCntntIdx = aPos.nContent; 1796 const xub_StrLen nIndex = aCntntIdx.GetIndex(); 1797 if ( nIndex > 0 ) 1798 { 1799 SwRect aResultRect; 1800 pFrm->GetCharRect( aResultRect, aPos ); 1801 bool bVert = pFrm->IsVertical(); 1802 bool bR2L = pFrm->IsRightToLeft(); 1803 1804 if ( (!bVert && aResultRect.Pos().X() > aCorePoint.X()) || 1805 ( bVert && aResultRect.Pos().Y() > aCorePoint.Y()) || 1806 ( bR2L && aResultRect.Right() < aCorePoint.X()) ) 1807 { 1808 SwIndex aIdxPrev( pNode, nIndex - 1); 1809 SwPosition aPosPrev( *pNode, aIdxPrev ); 1810 SwRect aResultRectPrev; 1811 pFrm->GetCharRect( aResultRectPrev, aPosPrev ); 1812 if ( (!bVert && aResultRectPrev.Pos().X() < aCorePoint.X() && aResultRect.Pos().Y() == aResultRectPrev.Pos().Y()) || 1813 ( bVert && aResultRectPrev.Pos().Y() < aCorePoint.Y() && aResultRect.Pos().X() == aResultRectPrev.Pos().X()) || 1814 ( bR2L && aResultRectPrev.Right() > aCorePoint.X() && aResultRect.Pos().Y() == aResultRectPrev.Pos().Y()) ) 1815 aPos = aPosPrev; 1816 } 1817 } 1818 1819 return bSuccess ? 1820 GetPortionData().GetAccessiblePosition( aPos.nContent.GetIndex() ) 1821 : -1L; 1822 } 1823 1824 ::rtl::OUString SwAccessibleParagraph::getSelectedText() 1825 throw (uno::RuntimeException) 1826 { 1827 vos::OGuard aGuard(Application::GetSolarMutex()); 1828 1829 CHECK_FOR_DEFUNC_THIS( XAccessibleText, *this ); 1830 1831 sal_Int32 nStart, nEnd; 1832 sal_Bool bSelected = GetSelection( nStart, nEnd ); 1833 return bSelected 1834 ? GetString().copy( nStart, nEnd - nStart ) 1835 : ::rtl::OUString(); 1836 } 1837 1838 sal_Int32 SwAccessibleParagraph::getSelectionStart() 1839 throw (uno::RuntimeException) 1840 { 1841 vos::OGuard aGuard(Application::GetSolarMutex()); 1842 1843 CHECK_FOR_DEFUNC_THIS( XAccessibleText, *this ); 1844 1845 sal_Int32 nStart, nEnd; 1846 GetSelection( nStart, nEnd ); 1847 return nStart; 1848 } 1849 1850 sal_Int32 SwAccessibleParagraph::getSelectionEnd() 1851 throw (uno::RuntimeException) 1852 { 1853 vos::OGuard aGuard(Application::GetSolarMutex()); 1854 1855 CHECK_FOR_DEFUNC_THIS( XAccessibleText, *this ); 1856 1857 sal_Int32 nStart, nEnd; 1858 GetSelection( nStart, nEnd ); 1859 return nEnd; 1860 } 1861 1862 sal_Bool SwAccessibleParagraph::setSelection( sal_Int32 nStartIndex, sal_Int32 nEndIndex ) 1863 throw (lang::IndexOutOfBoundsException, uno::RuntimeException) 1864 { 1865 vos::OGuard aGuard(Application::GetSolarMutex()); 1866 1867 CHECK_FOR_DEFUNC_THIS( XAccessibleText, *this ); 1868 1869 // parameter checking 1870 sal_Int32 nLength = GetString().getLength(); 1871 if ( ! IsValidRange( nStartIndex, nEndIndex, nLength ) ) 1872 { 1873 throw lang::IndexOutOfBoundsException(); 1874 } 1875 1876 sal_Bool bRet = sal_False; 1877 1878 // get cursor shell 1879 SwCrsrShell* pCrsrShell = GetCrsrShell(); 1880 if( pCrsrShell != NULL ) 1881 { 1882 // create pam for selection 1883 SwTxtNode* pNode = const_cast<SwTxtNode*>( GetTxtNode() ); 1884 SwIndex aIndex( pNode, GetPortionData().GetModelPosition(nStartIndex)); 1885 SwPosition aStartPos( *pNode, aIndex ); 1886 SwPaM aPaM( aStartPos ); 1887 aPaM.SetMark(); 1888 aPaM.GetPoint()->nContent = 1889 GetPortionData().GetModelPosition(nEndIndex); 1890 1891 // set PaM at cursor shell 1892 bRet = Select( aPaM ); 1893 } 1894 1895 return bRet; 1896 } 1897 1898 ::rtl::OUString SwAccessibleParagraph::getText() 1899 throw (uno::RuntimeException) 1900 { 1901 vos::OGuard aGuard(Application::GetSolarMutex()); 1902 1903 CHECK_FOR_DEFUNC_THIS( XAccessibleText, *this ); 1904 1905 return GetString(); 1906 } 1907 1908 ::rtl::OUString SwAccessibleParagraph::getTextRange( 1909 sal_Int32 nStartIndex, sal_Int32 nEndIndex ) 1910 throw (lang::IndexOutOfBoundsException, uno::RuntimeException) 1911 { 1912 vos::OGuard aGuard(Application::GetSolarMutex()); 1913 1914 CHECK_FOR_DEFUNC_THIS( XAccessibleText, *this ); 1915 1916 ::rtl::OUString sText( GetString() ); 1917 1918 if ( IsValidRange( nStartIndex, nEndIndex, sText.getLength() ) ) 1919 { 1920 OrderRange( nStartIndex, nEndIndex ); 1921 return sText.copy(nStartIndex, nEndIndex-nStartIndex ); 1922 } 1923 else 1924 throw lang::IndexOutOfBoundsException(); 1925 } 1926 1927 /*accessibility::*/TextSegment SwAccessibleParagraph::getTextAtIndex( sal_Int32 nIndex, sal_Int16 nTextType ) throw (lang::IndexOutOfBoundsException, lang::IllegalArgumentException, uno::RuntimeException) 1928 { 1929 vos::OGuard aGuard(Application::GetSolarMutex()); 1930 1931 CHECK_FOR_DEFUNC_THIS( XAccessibleText, *this ); 1932 1933 /*accessibility::*/TextSegment aResult; 1934 aResult.SegmentStart = -1; 1935 aResult.SegmentEnd = -1; 1936 1937 const ::rtl::OUString rText = GetString(); 1938 // implement the silly specification that first position after 1939 // text must return an empty string, rather than throwing an 1940 // IndexOutOfBoundsException, except for LINE, where the last 1941 // line is returned 1942 if( nIndex == rText.getLength() && AccessibleTextType::LINE != nTextType ) 1943 return aResult; 1944 1945 // with error checking 1946 i18n::Boundary aBound; 1947 sal_Bool bWord = GetTextBoundary( aBound, rText, nIndex, nTextType ); 1948 1949 DBG_ASSERT( aBound.startPos >= 0, "illegal boundary" ); 1950 DBG_ASSERT( aBound.startPos <= aBound.endPos, "illegal boundary" ); 1951 1952 // return word (if present) 1953 if ( bWord ) 1954 { 1955 aResult.SegmentText = rText.copy( aBound.startPos, aBound.endPos - aBound.startPos ); 1956 aResult.SegmentStart = aBound.startPos; 1957 aResult.SegmentEnd = aBound.endPos; 1958 } 1959 1960 return aResult; 1961 } 1962 1963 /*accessibility::*/TextSegment SwAccessibleParagraph::getTextBeforeIndex( sal_Int32 nIndex, sal_Int16 nTextType ) throw (lang::IndexOutOfBoundsException, lang::IllegalArgumentException, uno::RuntimeException) 1964 { 1965 vos::OGuard aGuard(Application::GetSolarMutex()); 1966 1967 CHECK_FOR_DEFUNC_THIS( XAccessibleText, *this ); 1968 1969 const ::rtl::OUString rText = GetString(); 1970 1971 /*accessibility::*/TextSegment aResult; 1972 aResult.SegmentStart = -1; 1973 aResult.SegmentEnd = -1; 1974 1975 // get starting pos 1976 i18n::Boundary aBound; 1977 if (nIndex == rText.getLength()) 1978 aBound.startPos = aBound.endPos = nIndex; 1979 else 1980 { 1981 sal_Bool bTmp = GetTextBoundary( aBound, rText, nIndex, nTextType ); 1982 1983 if ( ! bTmp ) 1984 aBound.startPos = aBound.endPos = nIndex; 1985 } 1986 1987 // now skip to previous word 1988 sal_Bool bWord = sal_False; 1989 while( !bWord ) 1990 { 1991 nIndex = min( nIndex, aBound.startPos ) - 1; 1992 if( nIndex >= 0 ) 1993 bWord = GetTextBoundary( aBound, rText, nIndex, nTextType ); 1994 else 1995 break; // exit if beginning of string is reached 1996 } 1997 1998 if ( bWord ) 1999 { 2000 aResult.SegmentText = rText.copy( aBound.startPos, aBound.endPos - aBound.startPos ); 2001 aResult.SegmentStart = aBound.startPos; 2002 aResult.SegmentEnd = aBound.endPos; 2003 }; 2004 return aResult; 2005 } 2006 2007 /*accessibility::*/TextSegment SwAccessibleParagraph::getTextBehindIndex( sal_Int32 nIndex, sal_Int16 nTextType ) throw (lang::IndexOutOfBoundsException, lang::IllegalArgumentException, uno::RuntimeException) 2008 { 2009 vos::OGuard aGuard(Application::GetSolarMutex()); 2010 2011 CHECK_FOR_DEFUNC_THIS( XAccessibleText, *this ); 2012 2013 /*accessibility::*/TextSegment aResult; 2014 aResult.SegmentStart = -1; 2015 aResult.SegmentEnd = -1; 2016 const ::rtl::OUString rText = GetString(); 2017 2018 // implement the silly specification that first position after 2019 // text must return an empty string, rather than throwing an 2020 // IndexOutOfBoundsException 2021 if( nIndex == rText.getLength() ) 2022 return aResult; 2023 2024 2025 // get first word, then skip to next word 2026 i18n::Boundary aBound; 2027 GetTextBoundary( aBound, rText, nIndex, nTextType ); 2028 sal_Bool bWord = sal_False; 2029 while( !bWord ) 2030 { 2031 nIndex = max( sal_Int32(nIndex+1), aBound.endPos ); 2032 if( nIndex < rText.getLength() ) 2033 bWord = GetTextBoundary( aBound, rText, nIndex, nTextType ); 2034 else 2035 break; // exit if end of string is reached 2036 } 2037 2038 if ( bWord ) 2039 { 2040 aResult.SegmentText = rText.copy( aBound.startPos, aBound.endPos - aBound.startPos ); 2041 aResult.SegmentStart = aBound.startPos; 2042 aResult.SegmentEnd = aBound.endPos; 2043 } 2044 return aResult; 2045 } 2046 2047 sal_Bool SwAccessibleParagraph::copyText( sal_Int32 nStartIndex, sal_Int32 nEndIndex ) 2048 throw (lang::IndexOutOfBoundsException, uno::RuntimeException) 2049 { 2050 CHECK_FOR_DEFUNC_THIS( XAccessibleText, *this ); 2051 vos::OGuard aGuard(Application::GetSolarMutex()); 2052 2053 // select and copy (through dispatch mechanism) 2054 setSelection( nStartIndex, nEndIndex ); 2055 ExecuteAtViewShell( SID_COPY ); 2056 return sal_True; 2057 } 2058 2059 2060 // 2061 //===== XAccesibleEditableText ========================================== 2062 // 2063 2064 sal_Bool SwAccessibleParagraph::cutText( sal_Int32 nStartIndex, sal_Int32 nEndIndex ) 2065 throw (lang::IndexOutOfBoundsException, uno::RuntimeException) 2066 { 2067 CHECK_FOR_DEFUNC( XAccessibleEditableText ); 2068 vos::OGuard aGuard(Application::GetSolarMutex()); 2069 2070 if( !IsEditableState() ) 2071 return sal_False; 2072 2073 // select and cut (through dispatch mechanism) 2074 setSelection( nStartIndex, nEndIndex ); 2075 ExecuteAtViewShell( SID_CUT ); 2076 return sal_True; 2077 } 2078 2079 sal_Bool SwAccessibleParagraph::pasteText( sal_Int32 nIndex ) 2080 throw (lang::IndexOutOfBoundsException, uno::RuntimeException) 2081 { 2082 CHECK_FOR_DEFUNC( XAccessibleEditableText ); 2083 vos::OGuard aGuard(Application::GetSolarMutex()); 2084 2085 if( !IsEditableState() ) 2086 return sal_False; 2087 2088 // select and paste (through dispatch mechanism) 2089 setSelection( nIndex, nIndex ); 2090 ExecuteAtViewShell( SID_PASTE ); 2091 return sal_True; 2092 } 2093 2094 sal_Bool SwAccessibleParagraph::deleteText( sal_Int32 nStartIndex, sal_Int32 nEndIndex ) 2095 throw (lang::IndexOutOfBoundsException, uno::RuntimeException) 2096 { 2097 return replaceText( nStartIndex, nEndIndex, ::rtl::OUString() ); 2098 } 2099 2100 sal_Bool SwAccessibleParagraph::insertText( const ::rtl::OUString& sText, sal_Int32 nIndex ) 2101 throw (lang::IndexOutOfBoundsException, uno::RuntimeException) 2102 { 2103 return replaceText( nIndex, nIndex, sText ); 2104 } 2105 2106 sal_Bool SwAccessibleParagraph::replaceText( 2107 sal_Int32 nStartIndex, sal_Int32 nEndIndex, 2108 const ::rtl::OUString& sReplacement ) 2109 throw (lang::IndexOutOfBoundsException, uno::RuntimeException) 2110 { 2111 vos::OGuard aGuard(Application::GetSolarMutex()); 2112 2113 CHECK_FOR_DEFUNC( XAccessibleEditableText ); 2114 2115 const ::rtl::OUString& rText = GetString(); 2116 2117 if( IsValidRange( nStartIndex, nEndIndex, rText.getLength() ) ) 2118 { 2119 if( !IsEditableState() ) 2120 return sal_False; 2121 2122 SwTxtNode* pNode = const_cast<SwTxtNode*>( GetTxtNode() ); 2123 2124 // translate positions 2125 sal_uInt16 nStart, nEnd; 2126 sal_Bool bSuccess = GetPortionData().GetEditableRange( 2127 nStartIndex, nEndIndex, nStart, nEnd ); 2128 2129 // edit only if the range is editable 2130 if( bSuccess ) 2131 { 2132 // create SwPosition for nStartIndex 2133 SwIndex aIndex( pNode, nStart ); 2134 SwPosition aStartPos( *pNode, aIndex ); 2135 2136 // create SwPosition for nEndIndex 2137 SwPosition aEndPos( aStartPos ); 2138 aEndPos.nContent = nEnd; 2139 2140 // now create XTextRange as helper and set string 2141 const uno::Reference<text::XTextRange> xRange( 2142 SwXTextRange::CreateXTextRange( 2143 *pNode->GetDoc(), aStartPos, &aEndPos)); 2144 xRange->setString(sReplacement); 2145 2146 // delete portion data 2147 ClearPortionData(); 2148 } 2149 2150 return bSuccess; 2151 } 2152 else 2153 throw lang::IndexOutOfBoundsException(); 2154 } 2155 2156 struct IndexCompare 2157 { 2158 const PropertyValue* pValues; 2159 IndexCompare( const PropertyValue* pVals ) : pValues(pVals) {} 2160 bool operator() ( const sal_Int32& a, const sal_Int32& b ) const 2161 { 2162 return (pValues[a].Name < pValues[b].Name) ? true : false; 2163 } 2164 }; 2165 2166 2167 sal_Bool SwAccessibleParagraph::setAttributes( 2168 sal_Int32 nStartIndex, 2169 sal_Int32 nEndIndex, 2170 const uno::Sequence<PropertyValue>& rAttributeSet ) 2171 throw (lang::IndexOutOfBoundsException, uno::RuntimeException) 2172 { 2173 vos::OGuard aGuard(Application::GetSolarMutex()); 2174 CHECK_FOR_DEFUNC( XAccessibleEditableText ); 2175 2176 const ::rtl::OUString& rText = GetString(); 2177 2178 if( ! IsValidRange( nStartIndex, nEndIndex, rText.getLength() ) ) 2179 throw lang::IndexOutOfBoundsException(); 2180 2181 if( !IsEditableState() ) 2182 return sal_False; 2183 2184 2185 // create a (dummy) text portion for the sole purpose of calling 2186 // setPropertyValue on it 2187 uno::Reference<XMultiPropertySet> xPortion = CreateUnoPortion( nStartIndex, 2188 nEndIndex ); 2189 2190 // build sorted index array 2191 sal_Int32 nLength = rAttributeSet.getLength(); 2192 const PropertyValue* pPairs = rAttributeSet.getConstArray(); 2193 sal_Int32* pIndices = new sal_Int32[nLength]; 2194 sal_Int32 i; 2195 for( i = 0; i < nLength; i++ ) 2196 pIndices[i] = i; 2197 sort( &pIndices[0], &pIndices[nLength], IndexCompare(pPairs) ); 2198 2199 // create sorted sequences accoring to index array 2200 uno::Sequence< ::rtl::OUString > aNames( nLength ); 2201 ::rtl::OUString* pNames = aNames.getArray(); 2202 uno::Sequence< uno::Any > aValues( nLength ); 2203 uno::Any* pValues = aValues.getArray(); 2204 for( i = 0; i < nLength; i++ ) 2205 { 2206 const PropertyValue& rVal = pPairs[pIndices[i]]; 2207 pNames[i] = rVal.Name; 2208 pValues[i] = rVal.Value; 2209 } 2210 delete[] pIndices; 2211 2212 // now set the values 2213 sal_Bool bRet = sal_True; 2214 try 2215 { 2216 xPortion->setPropertyValues( aNames, aValues ); 2217 } 2218 catch( UnknownPropertyException e ) 2219 { 2220 // error handling through return code! 2221 bRet = sal_False; 2222 } 2223 2224 return bRet; 2225 } 2226 2227 sal_Bool SwAccessibleParagraph::setText( const ::rtl::OUString& sText ) 2228 throw (uno::RuntimeException) 2229 { 2230 return replaceText(0, GetString().getLength(), sText); 2231 } 2232 2233 //===== XAccessibleSelection ============================================ 2234 2235 void SwAccessibleParagraph::selectAccessibleChild( 2236 sal_Int32 nChildIndex ) 2237 throw ( lang::IndexOutOfBoundsException, 2238 uno::RuntimeException ) 2239 { 2240 CHECK_FOR_DEFUNC( XAccessibleSelection ); 2241 2242 aSelectionHelper.selectAccessibleChild(nChildIndex); 2243 } 2244 2245 sal_Bool SwAccessibleParagraph::isAccessibleChildSelected( 2246 sal_Int32 nChildIndex ) 2247 throw ( lang::IndexOutOfBoundsException, 2248 uno::RuntimeException ) 2249 { 2250 CHECK_FOR_DEFUNC( XAccessibleSelection ); 2251 2252 return aSelectionHelper.isAccessibleChildSelected(nChildIndex); 2253 } 2254 2255 void SwAccessibleParagraph::clearAccessibleSelection( ) 2256 throw ( uno::RuntimeException ) 2257 { 2258 CHECK_FOR_DEFUNC( XAccessibleSelection ); 2259 2260 aSelectionHelper.clearAccessibleSelection(); 2261 } 2262 2263 void SwAccessibleParagraph::selectAllAccessibleChildren( ) 2264 throw ( uno::RuntimeException ) 2265 { 2266 CHECK_FOR_DEFUNC( XAccessibleSelection ); 2267 2268 aSelectionHelper.selectAllAccessibleChildren(); 2269 } 2270 2271 sal_Int32 SwAccessibleParagraph::getSelectedAccessibleChildCount( ) 2272 throw ( uno::RuntimeException ) 2273 { 2274 CHECK_FOR_DEFUNC( XAccessibleSelection ); 2275 2276 return aSelectionHelper.getSelectedAccessibleChildCount(); 2277 } 2278 2279 uno::Reference<XAccessible> SwAccessibleParagraph::getSelectedAccessibleChild( 2280 sal_Int32 nSelectedChildIndex ) 2281 throw ( lang::IndexOutOfBoundsException, 2282 uno::RuntimeException) 2283 { 2284 CHECK_FOR_DEFUNC( XAccessibleSelection ); 2285 2286 return aSelectionHelper.getSelectedAccessibleChild(nSelectedChildIndex); 2287 } 2288 2289 // --> OD 2004-11-16 #111714# - index has to be treated as global child index. 2290 void SwAccessibleParagraph::deselectAccessibleChild( 2291 sal_Int32 nChildIndex ) 2292 throw ( lang::IndexOutOfBoundsException, 2293 uno::RuntimeException ) 2294 { 2295 CHECK_FOR_DEFUNC( XAccessibleSelection ); 2296 2297 aSelectionHelper.deselectAccessibleChild( nChildIndex ); 2298 } 2299 2300 //===== XAccessibleHypertext ============================================ 2301 2302 class SwHyperlinkIter_Impl 2303 { 2304 const SwpHints *pHints; 2305 xub_StrLen nStt; 2306 xub_StrLen nEnd; 2307 sal_uInt16 nPos; 2308 2309 public: 2310 SwHyperlinkIter_Impl( const SwTxtFrm *pTxtFrm ); 2311 const SwTxtAttr *next(); 2312 sal_uInt16 getCurrHintPos() const { return nPos-1; } 2313 2314 xub_StrLen startIdx() const { return nStt; } 2315 xub_StrLen endIdx() const { return nEnd; } 2316 }; 2317 2318 SwHyperlinkIter_Impl::SwHyperlinkIter_Impl( const SwTxtFrm *pTxtFrm ) : 2319 pHints( pTxtFrm->GetTxtNode()->GetpSwpHints() ), 2320 nStt( pTxtFrm->GetOfst() ), 2321 nPos( 0 ) 2322 { 2323 const SwTxtFrm *pFollFrm = pTxtFrm->GetFollow(); 2324 nEnd = pFollFrm ? pFollFrm->GetOfst() : pTxtFrm->GetTxtNode()->Len(); 2325 } 2326 2327 const SwTxtAttr *SwHyperlinkIter_Impl::next() 2328 { 2329 const SwTxtAttr *pAttr = 0; 2330 if( pHints ) 2331 { 2332 while( !pAttr && nPos < pHints->Count() ) 2333 { 2334 const SwTxtAttr *pHt = (*pHints)[nPos]; 2335 if( RES_TXTATR_INETFMT == pHt->Which() ) 2336 { 2337 xub_StrLen nHtStt = *pHt->GetStart(); 2338 xub_StrLen nHtEnd = *pHt->GetAnyEnd(); 2339 if( nHtEnd > nHtStt && 2340 ( (nHtStt >= nStt && nHtStt < nEnd) || 2341 (nHtEnd > nStt && nHtEnd <= nEnd) ) ) 2342 { 2343 pAttr = pHt; 2344 } 2345 } 2346 ++nPos; 2347 } 2348 } 2349 2350 return pAttr; 2351 }; 2352 2353 sal_Int32 SAL_CALL SwAccessibleParagraph::getHyperLinkCount() 2354 throw (uno::RuntimeException) 2355 { 2356 vos::OGuard aGuard(Application::GetSolarMutex()); 2357 2358 CHECK_FOR_DEFUNC( XAccessibleHypertext ); 2359 2360 sal_Int32 nCount = 0; 2361 // --> OD 2007-06-27 #i77108# - provide hyperlinks also in editable documents. 2362 // if( !IsEditableState() ) 2363 // <-- 2364 { 2365 const SwTxtFrm *pTxtFrm = static_cast<const SwTxtFrm*>( GetFrm() ); 2366 SwHyperlinkIter_Impl aIter( pTxtFrm ); 2367 while( aIter.next() ) 2368 nCount++; 2369 } 2370 2371 return nCount; 2372 } 2373 2374 uno::Reference< XAccessibleHyperlink > SAL_CALL 2375 SwAccessibleParagraph::getHyperLink( sal_Int32 nLinkIndex ) 2376 throw (lang::IndexOutOfBoundsException, uno::RuntimeException) 2377 { 2378 vos::OGuard aGuard(Application::GetSolarMutex()); 2379 CHECK_FOR_DEFUNC( XAccessibleHypertext ); 2380 2381 uno::Reference< XAccessibleHyperlink > xRet; 2382 2383 // --> OD 2007-06-27 #i77108# - provide hyperlinks also in editable documents. 2384 // if( !IsEditableState() ) 2385 // <-- 2386 { 2387 const SwTxtFrm *pTxtFrm = static_cast<const SwTxtFrm*>( GetFrm() ); 2388 SwHyperlinkIter_Impl aHIter( pTxtFrm ); 2389 while( nLinkIndex-- ) 2390 aHIter.next(); 2391 2392 const SwTxtAttr *pHt = aHIter.next(); 2393 if( pHt ) 2394 { 2395 if( !pHyperTextData ) 2396 pHyperTextData = new SwAccessibleHyperTextData; 2397 SwAccessibleHyperTextData::iterator aIter = 2398 pHyperTextData ->find( pHt ); 2399 if( aIter != pHyperTextData->end() ) 2400 { 2401 xRet = (*aIter).second; 2402 } 2403 if( !xRet.is() ) 2404 { 2405 sal_Int32 nHStt= GetPortionData().GetAccessiblePosition( 2406 max( aHIter.startIdx(), *pHt->GetStart() ) ); 2407 sal_Int32 nHEnd= GetPortionData().GetAccessiblePosition( 2408 min( aHIter.endIdx(), *pHt->GetAnyEnd() ) ); 2409 xRet = new SwAccessibleHyperlink( aHIter.getCurrHintPos(), 2410 this, nHStt, nHEnd ); 2411 if( aIter != pHyperTextData->end() ) 2412 { 2413 (*aIter).second = xRet; 2414 } 2415 else 2416 { 2417 SwAccessibleHyperTextData::value_type aEntry( pHt, xRet ); 2418 pHyperTextData->insert( aEntry ); 2419 } 2420 } 2421 } 2422 } 2423 2424 if( !xRet.is() ) 2425 throw lang::IndexOutOfBoundsException(); 2426 2427 return xRet; 2428 } 2429 2430 sal_Int32 SAL_CALL SwAccessibleParagraph::getHyperLinkIndex( sal_Int32 nCharIndex ) 2431 throw (lang::IndexOutOfBoundsException, uno::RuntimeException) 2432 { 2433 vos::OGuard aGuard(Application::GetSolarMutex()); 2434 CHECK_FOR_DEFUNC( XAccessibleHypertext ); 2435 2436 // parameter checking 2437 sal_Int32 nLength = GetString().getLength(); 2438 if ( ! IsValidPosition( nCharIndex, nLength ) ) 2439 { 2440 throw lang::IndexOutOfBoundsException(); 2441 } 2442 2443 sal_Int32 nRet = -1; 2444 // --> OD 2007-06-27 #i77108# - provide hyperlinks also in editable documents. 2445 // if( !IsEditableState() ) 2446 // <-- 2447 { 2448 const SwTxtFrm *pTxtFrm = static_cast<const SwTxtFrm*>( GetFrm() ); 2449 SwHyperlinkIter_Impl aHIter( pTxtFrm ); 2450 2451 xub_StrLen nIdx = GetPortionData().GetModelPosition( nCharIndex ); 2452 sal_Int32 nPos = 0; 2453 const SwTxtAttr *pHt = aHIter.next(); 2454 while( pHt && !(nIdx >= *pHt->GetStart() && nIdx < *pHt->GetAnyEnd()) ) 2455 { 2456 pHt = aHIter.next(); 2457 nPos++; 2458 } 2459 2460 if( pHt ) 2461 nRet = nPos; 2462 2463 } 2464 2465 return nRet; 2466 } 2467 2468 // --> OD 2008-05-26 #i71360# 2469 // --> OD 2010-02-22 #i108125# - adjustments for change tracking text markup 2470 sal_Int32 SAL_CALL SwAccessibleParagraph::getTextMarkupCount( sal_Int32 nTextMarkupType ) 2471 throw (lang::IllegalArgumentException, 2472 uno::RuntimeException) 2473 { 2474 std::auto_ptr<SwTextMarkupHelper> pTextMarkupHelper; 2475 switch ( nTextMarkupType ) 2476 { 2477 case text::TextMarkupType::TRACK_CHANGE_INSERTION: 2478 case text::TextMarkupType::TRACK_CHANGE_DELETION: 2479 case text::TextMarkupType::TRACK_CHANGE_FORMATCHANGE: 2480 { 2481 pTextMarkupHelper.reset( new SwTextMarkupHelper( 2482 GetPortionData(), 2483 *(mpParaChangeTrackInfo->getChangeTrackingTextMarkupList( nTextMarkupType ) )) ); 2484 } 2485 break; 2486 default: 2487 { 2488 pTextMarkupHelper.reset( new SwTextMarkupHelper( GetPortionData(), *GetTxtNode() ) ); 2489 } 2490 } 2491 2492 return pTextMarkupHelper->getTextMarkupCount( nTextMarkupType ); 2493 } 2494 2495 /*accessibility::*/TextSegment SAL_CALL 2496 SwAccessibleParagraph::getTextMarkup( sal_Int32 nTextMarkupIndex, 2497 sal_Int32 nTextMarkupType ) 2498 throw (lang::IndexOutOfBoundsException, 2499 lang::IllegalArgumentException, 2500 uno::RuntimeException) 2501 { 2502 std::auto_ptr<SwTextMarkupHelper> pTextMarkupHelper; 2503 switch ( nTextMarkupType ) 2504 { 2505 case text::TextMarkupType::TRACK_CHANGE_INSERTION: 2506 case text::TextMarkupType::TRACK_CHANGE_DELETION: 2507 case text::TextMarkupType::TRACK_CHANGE_FORMATCHANGE: 2508 { 2509 pTextMarkupHelper.reset( new SwTextMarkupHelper( 2510 GetPortionData(), 2511 *(mpParaChangeTrackInfo->getChangeTrackingTextMarkupList( nTextMarkupType ) )) ); 2512 } 2513 break; 2514 default: 2515 { 2516 pTextMarkupHelper.reset( new SwTextMarkupHelper( GetPortionData(), *GetTxtNode() ) ); 2517 } 2518 } 2519 2520 return pTextMarkupHelper->getTextMarkup( nTextMarkupIndex, nTextMarkupType ); 2521 } 2522 2523 uno::Sequence< /*accessibility::*/TextSegment > SAL_CALL 2524 SwAccessibleParagraph::getTextMarkupAtIndex( sal_Int32 nCharIndex, 2525 sal_Int32 nTextMarkupType ) 2526 throw (lang::IndexOutOfBoundsException, 2527 lang::IllegalArgumentException, 2528 uno::RuntimeException) 2529 { 2530 // parameter checking 2531 const sal_Int32 nLength = GetString().getLength(); 2532 if ( ! IsValidPosition( nCharIndex, nLength ) ) 2533 { 2534 throw lang::IndexOutOfBoundsException(); 2535 } 2536 2537 std::auto_ptr<SwTextMarkupHelper> pTextMarkupHelper; 2538 switch ( nTextMarkupType ) 2539 { 2540 case text::TextMarkupType::TRACK_CHANGE_INSERTION: 2541 case text::TextMarkupType::TRACK_CHANGE_DELETION: 2542 case text::TextMarkupType::TRACK_CHANGE_FORMATCHANGE: 2543 { 2544 pTextMarkupHelper.reset( new SwTextMarkupHelper( 2545 GetPortionData(), 2546 *(mpParaChangeTrackInfo->getChangeTrackingTextMarkupList( nTextMarkupType ) )) ); 2547 } 2548 break; 2549 default: 2550 { 2551 pTextMarkupHelper.reset( new SwTextMarkupHelper( GetPortionData(), *GetTxtNode() ) ); 2552 } 2553 } 2554 2555 return pTextMarkupHelper->getTextMarkupAtIndex( nCharIndex, nTextMarkupType ); 2556 } 2557 // <-- 2558 2559 // --> OD 2008-05-29 #i89175# 2560 sal_Int32 SAL_CALL SwAccessibleParagraph::getLineNumberAtIndex( sal_Int32 nIndex ) 2561 throw (lang::IndexOutOfBoundsException, 2562 uno::RuntimeException) 2563 { 2564 // parameter checking 2565 const sal_Int32 nLength = GetString().getLength(); 2566 if ( ! IsValidPosition( nIndex, nLength ) ) 2567 { 2568 throw lang::IndexOutOfBoundsException(); 2569 } 2570 2571 const sal_Int32 nLineNo = GetPortionData().GetLineNo( nIndex ); 2572 return nLineNo; 2573 } 2574 2575 /*accessibility::*/TextSegment SAL_CALL 2576 SwAccessibleParagraph::getTextAtLineNumber( sal_Int32 nLineNo ) 2577 throw (lang::IndexOutOfBoundsException, 2578 uno::RuntimeException) 2579 { 2580 // parameter checking 2581 if ( nLineNo < 0 || 2582 nLineNo >= GetPortionData().GetLineCount() ) 2583 { 2584 throw lang::IndexOutOfBoundsException(); 2585 } 2586 2587 i18n::Boundary aLineBound; 2588 GetPortionData().GetBoundaryOfLine( nLineNo, aLineBound ); 2589 2590 /*accessibility::*/TextSegment aTextAtLine; 2591 const ::rtl::OUString rText = GetString(); 2592 aTextAtLine.SegmentText = rText.copy( aLineBound.startPos, 2593 aLineBound.endPos - aLineBound.startPos ); 2594 aTextAtLine.SegmentStart = aLineBound.startPos; 2595 aTextAtLine.SegmentEnd = aLineBound.endPos; 2596 2597 return aTextAtLine; 2598 } 2599 2600 /*accessibility::*/TextSegment SAL_CALL SwAccessibleParagraph::getTextAtLineWithCaret() 2601 throw (uno::RuntimeException) 2602 { 2603 const sal_Int32 nLineNoOfCaret = getNumberOfLineWithCaret(); 2604 2605 if ( nLineNoOfCaret >= 0 && 2606 nLineNoOfCaret < GetPortionData().GetLineCount() ) 2607 { 2608 return getTextAtLineNumber( nLineNoOfCaret ); 2609 } 2610 2611 return /*accessibility::*/TextSegment(); 2612 } 2613 2614 sal_Int32 SAL_CALL SwAccessibleParagraph::getNumberOfLineWithCaret() 2615 throw (uno::RuntimeException) 2616 { 2617 const sal_Int32 nCaretPos = getCaretPosition(); 2618 const sal_Int32 nLength = GetString().getLength(); 2619 if ( !IsValidPosition( nCaretPos, nLength ) ) 2620 { 2621 return -1; 2622 } 2623 2624 sal_Int32 nLineNo = GetPortionData().GetLineNo( nCaretPos ); 2625 2626 // special handling for cursor positioned at end of text line via End key 2627 if ( nCaretPos != 0 ) 2628 { 2629 i18n::Boundary aLineBound; 2630 GetPortionData().GetBoundaryOfLine( nLineNo, aLineBound ); 2631 if ( nCaretPos == aLineBound.startPos ) 2632 { 2633 SwCrsrShell* pCrsrShell = SwAccessibleParagraph::GetCrsrShell(); 2634 if ( pCrsrShell != 0 ) 2635 { 2636 const awt::Rectangle aCharRect = getCharacterBounds( nCaretPos ); 2637 2638 const SwRect& aCursorCoreRect = pCrsrShell->GetCharRect(); 2639 // translate core coordinates into accessibility coordinates 2640 Window *pWin = GetWindow(); 2641 CHECK_FOR_WINDOW( XAccessibleComponent, pWin ); 2642 2643 Rectangle aScreenRect( GetMap()->CoreToPixel( aCursorCoreRect.SVRect() )); 2644 2645 SwRect aFrmLogBounds( GetBounds( *(GetMap()) ) ); // twip rel to doc root 2646 Point aFrmPixPos( GetMap()->CoreToPixel( aFrmLogBounds.SVRect() ).TopLeft() ); 2647 aScreenRect.Move( -aFrmPixPos.X(), -aFrmPixPos.Y() ); 2648 2649 // convert into AWT Rectangle 2650 const awt::Rectangle aCursorRect( aScreenRect.Left(), 2651 aScreenRect.Top(), 2652 aScreenRect.GetWidth(), 2653 aScreenRect.GetHeight() ); 2654 2655 if ( aCharRect.X != aCursorRect.X || 2656 aCharRect.Y != aCursorRect.Y ) 2657 { 2658 --nLineNo; 2659 } 2660 } 2661 } 2662 } 2663 2664 return nLineNo; 2665 } 2666 2667 // --> OD 2010-02-19 #i108125# 2668 void SwAccessibleParagraph::Modify( const SfxPoolItem* pOld, const SfxPoolItem* pNew ) 2669 { 2670 mpParaChangeTrackInfo->reset(); 2671 2672 CheckRegistration( pOld, pNew ); 2673 } 2674 // <-- 2675