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