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 <com/sun/star/linguistic2/ProofreadingResult.hpp> 32 #include <com/sun/star/linguistic2/XProofreader.hpp> 33 #include <com/sun/star/linguistic2/XProofreadingIterator.hpp> 34 #include <com/sun/star/text/XFlatParagraph.hpp> 35 36 #include <unoflatpara.hxx> 37 38 #include <comcore.hrc> 39 #include <hintids.hxx> 40 #include <linguistic/lngprops.hxx> 41 #include <vcl/msgbox.hxx> 42 #include <editeng/unolingu.hxx> 43 #include <editeng/svxacorr.hxx> 44 #include <editeng/langitem.hxx> 45 #include <editeng/SpellPortions.hxx> 46 #include <editeng/scripttypeitem.hxx> 47 #include <charatr.hxx> 48 #include <editsh.hxx> 49 #include <doc.hxx> 50 #include <IDocumentUndoRedo.hxx> 51 #include <rootfrm.hxx> // SwRootFrm 52 #include <pam.hxx> 53 #include <swundo.hxx> // fuer die UndoIds 54 #include <ndtxt.hxx> // AdjHyphPos 55 #include <viewopt.hxx> // HyphStart/End 56 #include <viscrs.hxx> // SwShellCrsr 57 #include <SwGrammarMarkUp.hxx> // SwWrongList 58 #include <mdiexp.hxx> // Statusanzeige 59 #include <statstr.hrc> // StatLine-String 60 #include <cntfrm.hxx> 61 #include <crsskip.hxx> 62 #include <splargs.hxx> 63 #include <redline.hxx> // SwRedline 64 #include <docary.hxx> // SwRedlineTbl 65 #include <docsh.hxx> 66 #include <txatbase.hxx> 67 #include <txtfrm.hxx> 68 69 using namespace ::svx; 70 using namespace ::com::sun::star; 71 using namespace ::com::sun::star::uno; 72 using namespace ::com::sun::star::beans; 73 using namespace ::com::sun::star::linguistic2; 74 75 #define C2U(cChar) rtl::OUString::createFromAscii(cChar) 76 77 /************************************************************************* 78 * class SwLinguIter 79 *************************************************************************/ 80 81 class SwLinguIter 82 { 83 SwEditShell *pSh; 84 SwPosition *pStart; 85 SwPosition *pEnd; 86 SwPosition *pCurr; 87 SwPosition *pCurrX; 88 sal_uInt16 nCrsrCnt; 89 public: 90 SwLinguIter(); 91 92 inline SwEditShell *GetSh() { return pSh; } 93 inline const SwEditShell *GetSh() const { return pSh; } 94 95 inline const SwPosition *GetEnd() const { return pEnd; } 96 inline void SetEnd( SwPosition* pNew ){ delete pEnd; pEnd = pNew; } 97 98 inline const SwPosition *GetStart() const { return pStart; } 99 inline void SetStart( SwPosition* pNew ){ delete pStart; pStart = pNew; } 100 101 inline const SwPosition *GetCurr() const { return pCurr; } 102 inline void SetCurr( SwPosition* pNew ){ delete pCurr; pCurr = pNew; } 103 104 inline const SwPosition *GetCurrX() const { return pCurrX; } 105 inline void SetCurrX( SwPosition* pNew ){ delete pCurrX; pCurrX = pNew; } 106 107 inline sal_uInt16& GetCrsrCnt(){ return nCrsrCnt; } 108 109 // Der UI-Bauchladen: 110 void _Start( SwEditShell *pSh, SwDocPositions eStart, 111 SwDocPositions eEnd ); 112 void _End(bool bRestoreSelection = true); 113 }; 114 115 /************************************************************************* 116 * class SwSpellIter 117 *************************************************************************/ 118 119 // #i18881# to be able to identify the postions of the changed words 120 // the content positions of each portion need to be saved 121 struct SpellContentPosition 122 { 123 sal_uInt16 nLeft; 124 sal_uInt16 nRight; 125 }; 126 typedef std::vector<SpellContentPosition> SpellContentPositions; 127 class SwSpellIter : public SwLinguIter 128 { 129 uno::Reference< XSpellChecker1 > xSpeller; 130 ::svx::SpellPortions aLastPortions; 131 132 SpellContentPositions aLastPositions; 133 bool bBackToStartOfSentence; 134 bool bMoveToEndOfSentence; 135 136 137 void CreatePortion(uno::Reference< XSpellAlternatives > xAlt, 138 linguistic2::ProofreadingResult* pGrammarResult, 139 bool bIsField, bool bIsHidden); 140 141 void AddPortion(uno::Reference< XSpellAlternatives > xAlt, 142 linguistic2::ProofreadingResult* pGrammarResult, 143 const SpellContentPositions& rDeletedRedlines); 144 public: 145 SwSpellIter() : 146 bBackToStartOfSentence(false), bMoveToEndOfSentence(false) {} 147 148 void Start( SwEditShell *pSh, SwDocPositions eStart, SwDocPositions eEnd ); 149 150 uno::Any Continue( sal_uInt16* pPageCnt, sal_uInt16* pPageSt ); 151 152 bool SpellSentence(::svx::SpellPortions& rPortions, bool bIsGrammarCheck); 153 void ToSentenceStart(); 154 const ::svx::SpellPortions GetLastPortions(){ return aLastPortions;} 155 SpellContentPositions GetLastPositions() {return aLastPositions;} 156 void ContinueAfterThisSentence() { bMoveToEndOfSentence = true; } 157 }; 158 159 /************************************************************************* 160 * class SwConvIter 161 * used for text conversion 162 *************************************************************************/ 163 164 class SwConvIter : public SwLinguIter 165 { 166 SwConversionArgs &rArgs; 167 public: 168 SwConvIter( SwConversionArgs &rConvArgs ) : 169 rArgs( rConvArgs ) 170 {} 171 172 void Start( SwEditShell *pSh, SwDocPositions eStart, SwDocPositions eEnd ); 173 174 uno::Any Continue( sal_uInt16* pPageCnt, sal_uInt16* pPageSt ); 175 }; 176 177 /************************************************************************* 178 * class SwHyphIter 179 *************************************************************************/ 180 181 class SwHyphIter : public SwLinguIter 182 { 183 sal_Bool bOldIdle; 184 void DelSoftHyph( SwPaM &rPam ); 185 186 public: 187 SwHyphIter() : bOldIdle(sal_False) {} 188 189 void Start( SwEditShell *pSh, SwDocPositions eStart, SwDocPositions eEnd ); 190 void End(); 191 192 void Ignore(); 193 194 uno::Any Continue( sal_uInt16* pPageCnt, sal_uInt16* pPageSt ); 195 196 sal_Bool IsAuto(); 197 void InsertSoftHyph( const xub_StrLen nHyphPos ); 198 void ShowSelection(); 199 }; 200 201 static SwSpellIter* pSpellIter = 0; 202 static SwConvIter* pConvIter = 0; 203 static SwHyphIter* pHyphIter = 0; 204 205 // Wir ersparen uns in Hyphenate ein GetFrm() 206 // Achtung: in txtedt.cxx stehen extern-Deklarationen auf diese Pointer! 207 const SwTxtNode *pLinguNode; 208 SwTxtFrm *pLinguFrm; 209 210 /************************************************************************* 211 * SwLinguIter::SwLinguIter 212 *************************************************************************/ 213 214 SwLinguIter::SwLinguIter() 215 : pSh( 0 ), pStart( 0 ), pEnd( 0 ), pCurr( 0 ), pCurrX( 0 ) 216 { 217 // @@@ es fehlt: Sicherstellen der Reentrance, ASSERTs etc. 218 } 219 220 /************************************************************************* 221 * SwLinguIter::Start 222 *************************************************************************/ 223 224 225 226 void SwLinguIter::_Start( SwEditShell *pShell, SwDocPositions eStart, 227 SwDocPositions eEnd ) 228 { 229 // es fehlt: Sicherstellen der Reentrance, Locking 230 if( pSh ) 231 return; 232 233 sal_Bool bSetCurr; 234 235 pSh = pShell; 236 237 SET_CURR_SHELL( pSh ); 238 239 ASSERT( !pEnd, "LinguStart ohne End?"); 240 241 SwPaM *pCrsr = pSh->GetCrsr(); 242 243 // pStk->SetCurCrsr(); 244 // if( pCrsr->HasMark() || pCrsr != pCrsr->GetNext() ) 245 if( pShell->HasSelection() || pCrsr != pCrsr->GetNext() ) 246 { 247 bSetCurr = 0 != GetCurr(); 248 nCrsrCnt = pSh->GetCrsrCnt(); 249 if( pSh->IsTableMode() ) 250 pSh->TblCrsrToCursor(); 251 252 pSh->Push(); 253 sal_uInt16 n; 254 for( n = 0; n < nCrsrCnt; ++n ) 255 { 256 pSh->Push(); 257 pSh->DestroyCrsr(); 258 } 259 pSh->Pop( sal_False ); 260 } 261 else 262 { 263 bSetCurr = sal_False; 264 nCrsrCnt = 1; 265 pSh->Push(); 266 pSh->SetLinguRange( eStart, eEnd ); 267 } 268 269 pCrsr = pSh->GetCrsr(); 270 if ( *pCrsr->GetPoint() > *pCrsr->GetMark() ) 271 pCrsr->Exchange(); 272 273 pStart = new SwPosition( *pCrsr->GetPoint() ); 274 pEnd = new SwPosition( *pCrsr->GetMark() ); 275 if( bSetCurr ) 276 { 277 SwPosition* pNew = new SwPosition( *GetStart() ); 278 SetCurr( pNew ); 279 pNew = new SwPosition( *pNew ); 280 SetCurrX( pNew ); 281 } 282 283 pCrsr->SetMark(); 284 285 pLinguFrm = 0; 286 pLinguNode = 0; 287 } 288 289 /************************************************************************* 290 * SwLinguIter::End 291 *************************************************************************/ 292 293 294 295 void SwLinguIter::_End(bool bRestoreSelection) 296 { 297 if( !pSh ) 298 return; 299 300 ASSERT( pEnd, "SwEditShell::SpellEnd() ohne Start?"); 301 if(bRestoreSelection) 302 { 303 while( nCrsrCnt-- ) 304 pSh->Pop( sal_False ); 305 306 pSh->KillPams(); 307 pSh->ClearMark(); 308 } 309 DELETEZ(pStart); 310 DELETEZ(pEnd); 311 DELETEZ(pCurr); 312 DELETEZ(pCurrX); 313 314 pSh = 0; 315 316 #ifdef LINGU_STATISTIK 317 aSwLinguStat.Flush(); 318 #endif 319 } 320 321 /************************************************************************* 322 * virtual SwSpellIter::Start() 323 *************************************************************************/ 324 325 326 327 void SwSpellIter::Start( SwEditShell *pShell, SwDocPositions eStart, 328 SwDocPositions eEnd ) 329 { 330 if( GetSh() ) 331 return; 332 333 uno::Reference< beans::XPropertySet > xProp( ::GetLinguPropertySet() ); 334 xSpeller = ::GetSpellChecker(); 335 if ( xSpeller.is() ) 336 _Start( pShell, eStart, eEnd ); 337 aLastPortions.clear(); 338 aLastPositions.clear(); 339 } 340 341 /************************************************************************* 342 * SwSpellIter::Continue 343 *************************************************************************/ 344 345 // SwSpellIter::Continue ist das alte Original von 346 // SwEditShell::SpellContinue() 347 348 uno::Any SwSpellIter::Continue( sal_uInt16* pPageCnt, sal_uInt16* pPageSt ) 349 { 350 //!! 351 //!! Please check SwConvIter also when modifying this 352 //!! 353 354 uno::Any aSpellRet; 355 SwEditShell *pMySh = GetSh(); 356 if( !pMySh ) 357 return aSpellRet; 358 359 // const SwPosition *pEnd = GetEnd(); 360 361 ASSERT( GetEnd(), "SwEditShell::SpellContinue() ohne Start?"); 362 363 uno::Reference< uno::XInterface > xSpellRet; 364 sal_Bool bGoOn = sal_True; 365 do { 366 SwPaM *pCrsr = pMySh->GetCrsr(); 367 if ( !pCrsr->HasMark() ) 368 pCrsr->SetMark(); 369 370 uno::Reference< beans::XPropertySet > xProp( GetLinguPropertySet() ); 371 *pMySh->GetCrsr()->GetPoint() = *GetCurr(); 372 *pMySh->GetCrsr()->GetMark() = *GetEnd(); 373 pMySh->GetDoc()->Spell(*pMySh->GetCrsr(), 374 xSpeller, pPageCnt, pPageSt, false ) >>= xSpellRet; 375 bGoOn = GetCrsrCnt() > 1; 376 if( xSpellRet.is() ) 377 { 378 bGoOn = sal_False; 379 SwPosition* pNewPoint = new SwPosition( *pCrsr->GetPoint() ); 380 SwPosition* pNewMark = new SwPosition( *pCrsr->GetMark() ); 381 SetCurr( pNewPoint ); 382 SetCurrX( pNewMark ); 383 } 384 if( bGoOn ) 385 { 386 pMySh->Pop( sal_False ); 387 pCrsr = pMySh->GetCrsr(); 388 if ( *pCrsr->GetPoint() > *pCrsr->GetMark() ) 389 pCrsr->Exchange(); 390 SwPosition* pNew = new SwPosition( *pCrsr->GetPoint() ); 391 SetStart( pNew ); 392 pNew = new SwPosition( *pCrsr->GetMark() ); 393 SetEnd( pNew ); 394 pNew = new SwPosition( *GetStart() ); 395 SetCurr( pNew ); 396 pNew = new SwPosition( *pNew ); 397 SetCurrX( pNew ); 398 pCrsr->SetMark(); 399 --GetCrsrCnt(); 400 } 401 }while ( bGoOn ); 402 aSpellRet <<= xSpellRet; 403 return aSpellRet; 404 } 405 406 /************************************************************************* 407 * virtual SwConvIter::Start() 408 *************************************************************************/ 409 410 411 412 void SwConvIter::Start( SwEditShell *pShell, SwDocPositions eStart, 413 SwDocPositions eEnd ) 414 { 415 if( GetSh() ) 416 return; 417 _Start( pShell, eStart, eEnd ); 418 } 419 420 /************************************************************************* 421 * SwConvIter::Continue 422 *************************************************************************/ 423 424 uno::Any SwConvIter::Continue( sal_uInt16* pPageCnt, sal_uInt16* pPageSt ) 425 { 426 //!! 427 //!! Please check SwSpellIter also when modifying this 428 //!! 429 430 uno::Any aConvRet( makeAny( rtl::OUString() ) ); 431 SwEditShell *pMySh = GetSh(); 432 if( !pMySh ) 433 return aConvRet; 434 435 // const SwPosition *pEnd = GetEnd(); 436 437 ASSERT( GetEnd(), "SwConvIter::Continue() ohne Start?"); 438 439 rtl::OUString aConvText; 440 sal_Bool bGoOn = sal_True; 441 do { 442 SwPaM *pCrsr = pMySh->GetCrsr(); 443 if ( !pCrsr->HasMark() ) 444 pCrsr->SetMark(); 445 446 *pMySh->GetCrsr()->GetPoint() = *GetCurr(); 447 *pMySh->GetCrsr()->GetMark() = *GetEnd(); 448 449 // call function to find next text portion to be converted 450 uno::Reference< linguistic2::XSpellChecker1 > xEmpty; 451 pMySh->GetDoc()->Spell( *pMySh->GetCrsr(), 452 xEmpty, pPageCnt, pPageSt, false, &rArgs ) >>= aConvText; 453 454 bGoOn = GetCrsrCnt() > 1; 455 if( aConvText.getLength() ) 456 { 457 bGoOn = sal_False; 458 SwPosition* pNewPoint = new SwPosition( *pCrsr->GetPoint() ); 459 SwPosition* pNewMark = new SwPosition( *pCrsr->GetMark() ); 460 461 SetCurr( pNewPoint ); 462 SetCurrX( pNewMark ); 463 } 464 if( bGoOn ) 465 { 466 pMySh->Pop( sal_False ); 467 pCrsr = pMySh->GetCrsr(); 468 if ( *pCrsr->GetPoint() > *pCrsr->GetMark() ) 469 pCrsr->Exchange(); 470 SwPosition* pNew = new SwPosition( *pCrsr->GetPoint() ); 471 SetStart( pNew ); 472 pNew = new SwPosition( *pCrsr->GetMark() ); 473 SetEnd( pNew ); 474 pNew = new SwPosition( *GetStart() ); 475 SetCurr( pNew ); 476 pNew = new SwPosition( *pNew ); 477 SetCurrX( pNew ); 478 pCrsr->SetMark(); 479 --GetCrsrCnt(); 480 } 481 }while ( bGoOn ); 482 return makeAny( aConvText ); 483 } 484 485 486 /************************************************************************* 487 * SwHyphIter 488 *************************************************************************/ 489 490 491 sal_Bool SwHyphIter::IsAuto() 492 { 493 uno::Reference< beans::XPropertySet > xProp( ::GetLinguPropertySet() ); 494 return xProp.is() ? *(sal_Bool*)xProp->getPropertyValue( 495 C2U(UPN_IS_HYPH_AUTO) ).getValue() 496 : sal_False; 497 } 498 499 500 void SwHyphIter::ShowSelection() 501 { 502 SwEditShell *pMySh = GetSh(); 503 if( pMySh ) 504 { 505 pMySh->StartAction(); 506 // Ganz fatal: durch das EndAction() werden Formatierungen 507 // angeregt, die dazu fuehren koennen, dass im Hyphenator 508 // neue Worte eingestellt werden. Deswegen sichern! 509 pMySh->EndAction(); 510 } 511 } 512 513 /************************************************************************* 514 * virtual SwHyphIter::Start() 515 *************************************************************************/ 516 517 518 519 void SwHyphIter::Start( SwEditShell *pShell, SwDocPositions eStart, SwDocPositions eEnd ) 520 { 521 // robust 522 if( GetSh() || GetEnd() ) 523 { 524 ASSERT( !GetSh(), "+SwEditShell::HyphStart: missing HyphEnd()" ); 525 return; 526 } 527 528 // nothing to be done (at least not in the way as in the "else" part) 529 bOldIdle = pShell->GetViewOptions()->IsIdle(); 530 ((SwViewOption*)pShell->GetViewOptions())->SetIdle( sal_False ); 531 _Start( pShell, eStart, eEnd ); 532 } 533 534 /************************************************************************* 535 * virtual SwHyphIter::End 536 *************************************************************************/ 537 538 // Selektionen wiederherstellen 539 540 541 542 void SwHyphIter::End() 543 { 544 if( !GetSh() ) 545 return; 546 ((SwViewOption*)GetSh()->GetViewOptions())->SetIdle( bOldIdle ); 547 _End(); 548 } 549 550 /************************************************************************* 551 * SwHyphIter::Continue 552 *************************************************************************/ 553 554 uno::Any SwHyphIter::Continue( sal_uInt16* pPageCnt, sal_uInt16* pPageSt ) 555 { 556 uno::Any aHyphRet; 557 SwEditShell *pMySh = GetSh(); 558 if( !pMySh ) 559 return aHyphRet; 560 561 const sal_Bool bAuto = IsAuto(); 562 uno::Reference< XHyphenatedWord > xHyphWord; 563 sal_uInt16 nRet; 564 sal_Bool bGoOn = sal_False; 565 do { 566 SwPaM *pCrsr; 567 do { 568 ASSERT( GetEnd(), "SwEditShell::SpellContinue() ohne Start?" ); 569 pCrsr = pMySh->GetCrsr(); 570 if ( !pCrsr->HasMark() ) 571 pCrsr->SetMark(); 572 if ( *pCrsr->GetPoint() < *pCrsr->GetMark() ) 573 { 574 pCrsr->Exchange(); 575 pCrsr->SetMark(); 576 } 577 578 // geraten BUG: 579 if ( *pCrsr->End() > *GetEnd() ) 580 nRet = 0; 581 else 582 { 583 *pCrsr->GetMark() = *GetEnd(); 584 585 // Muss an der aktuellen Cursorpos das Wort getrennt werden ? 586 const Point aCrsrPos( pMySh->GetCharRect().Pos() ); 587 xHyphWord = pMySh->GetDoc()->Hyphenate( pCrsr, aCrsrPos, 588 pPageCnt, pPageSt ); 589 } 590 591 if( bAuto && xHyphWord.is() ) 592 { 593 pMySh->InsertSoftHyph( xHyphWord->getHyphenationPos() + 1); 594 } 595 } while( bAuto && xHyphWord.is() ); //end of do-while 596 bGoOn = !xHyphWord.is() && GetCrsrCnt() > 1; 597 598 if( bGoOn ) 599 { 600 pMySh->Pop( sal_False ); 601 pCrsr = pMySh->GetCrsr(); 602 if ( *pCrsr->GetPoint() > *pCrsr->GetMark() ) 603 pCrsr->Exchange(); 604 SwPosition* pNew = new SwPosition(*pCrsr->End()); 605 SetEnd( pNew ); 606 pCrsr->SetMark(); 607 --GetCrsrCnt(); 608 } 609 } while ( bGoOn ); 610 aHyphRet <<= xHyphWord; 611 return aHyphRet; 612 } 613 614 /************************************************************************* 615 * SwHyphIter::HyphIgnore 616 *************************************************************************/ 617 618 // Beschreibung: Trennstelle ignorieren 619 620 void SwHyphIter::Ignore() 621 { 622 SwEditShell *pMySh = GetSh(); 623 SwPaM *pCrsr = pMySh->GetCrsr(); 624 625 // Alten SoftHyphen loeschen 626 DelSoftHyph( *pCrsr ); 627 628 // und weiter 629 pCrsr->Start()->nContent = pCrsr->End()->nContent; 630 pCrsr->SetMark(); 631 } 632 633 /************************************************************************* 634 * SwHyphIter::DelSoftHyph 635 *************************************************************************/ 636 637 void SwHyphIter::DelSoftHyph( SwPaM &rPam ) 638 { 639 const SwPosition* pStt = rPam.Start(); 640 const xub_StrLen nStart = pStt->nContent.GetIndex(); 641 const xub_StrLen nEnd = rPam.End()->nContent.GetIndex(); 642 SwTxtNode *pNode = pStt->nNode.GetNode().GetTxtNode(); 643 pNode->DelSoftHyph( nStart, nEnd ); 644 } 645 646 /************************************************************************* 647 * SwHyphIter::InsertSoftHyph 648 *************************************************************************/ 649 650 651 void SwHyphIter::InsertSoftHyph( const xub_StrLen nHyphPos ) 652 { 653 SwEditShell *pMySh = GetSh(); 654 ASSERT( pMySh, "+SwEditShell::InsertSoftHyph: missing HyphStart()"); 655 if( !pMySh ) 656 return; 657 658 SwPaM *pCrsr = pMySh->GetCrsr(); 659 SwPosition* pSttPos = pCrsr->Start(); 660 SwPosition* pEndPos = pCrsr->End(); 661 662 xub_StrLen nLastHyphLen = GetEnd()->nContent.GetIndex() - 663 pSttPos->nContent.GetIndex(); 664 665 if( pSttPos->nNode != pEndPos->nNode || !nLastHyphLen ) 666 { 667 ASSERT( pSttPos->nNode == pEndPos->nNode, 668 "+SwEditShell::InsertSoftHyph: node warp during hyphenation" ); 669 ASSERT(nLastHyphLen, "+SwEditShell::InsertSoftHyph: missing HyphContinue()"); 670 *pSttPos = *pEndPos; 671 return; 672 } 673 674 pMySh->StartAction(); 675 { 676 SwDoc *pDoc = pMySh->GetDoc(); 677 DelSoftHyph( *pCrsr ); 678 pSttPos->nContent += nHyphPos; 679 SwPaM aRg( *pSttPos ); 680 pDoc->InsertString( aRg, CHAR_SOFTHYPHEN ); 681 // Durch das Einfuegen des SoftHyphs ist ein Zeichen hinzugekommen 682 //JP 18.07.95: warum, ist doch ein SwIndex, dieser wird doch mitverschoben !! 683 // pSttPos->nContent++; 684 } 685 // Die Selektion wird wieder aufgehoben 686 pCrsr->DeleteMark(); 687 pMySh->EndAction(); 688 pCrsr->SetMark(); 689 } 690 691 // --------------------- Methoden der SwEditShell ------------------------ 692 693 bool SwEditShell::HasLastSentenceGotGrammarChecked() const 694 { 695 bool bTextWasGrammarChecked = false; 696 if (pSpellIter) 697 { 698 ::svx::SpellPortions aLastPortions( pSpellIter->GetLastPortions() ); 699 for (size_t i = 0; i < aLastPortions.size() && !bTextWasGrammarChecked; ++i) 700 { 701 // bIsGrammarError is also true if the text was only checked but no 702 // grammar error was found. (That is if a ProofreadingResult was obtained in 703 // SwDoc::Spell and in turn bIsGrammarError was set in SwSpellIter::CreatePortion) 704 if (aLastPortions[i].bIsGrammarError) 705 bTextWasGrammarChecked = true; 706 } 707 } 708 return bTextWasGrammarChecked; 709 } 710 711 /************************************************************************* 712 * SwEditShell::HasConvIter 713 *************************************************************************/ 714 715 sal_Bool SwEditShell::HasConvIter() const 716 { 717 return 0 != pConvIter; 718 } 719 720 /************************************************************************* 721 * SwEditShell::HasHyphIter 722 *************************************************************************/ 723 724 sal_Bool SwEditShell::HasHyphIter() const 725 { 726 return 0 != pHyphIter; 727 } 728 729 /************************************************************************* 730 * SwEditShell::SetFindRange 731 *************************************************************************/ 732 733 void SwEditShell::SetLinguRange( SwDocPositions eStart, SwDocPositions eEnd ) 734 { 735 SwPaM *pCrsr = GetCrsr(); 736 MakeFindRange( static_cast<sal_uInt16>(eStart), static_cast<sal_uInt16>(eEnd), pCrsr ); 737 if( *pCrsr->GetPoint() > *pCrsr->GetMark() ) 738 pCrsr->Exchange(); 739 } 740 741 /************************************************************************* 742 * SwEditShell::SpellStart 743 *************************************************************************/ 744 745 void SwEditShell::SpellStart( 746 SwDocPositions eStart, SwDocPositions eEnd, SwDocPositions eCurr, 747 SwConversionArgs *pConvArgs ) 748 { 749 SwLinguIter *pLinguIter = 0; 750 751 // do not spell if interactive spelling is active elsewhere 752 if (!pConvArgs && !pSpellIter) 753 { 754 ASSERT( !pSpellIter, "wer ist da schon am spellen?" ); 755 pSpellIter = new SwSpellIter; 756 pLinguIter = pSpellIter; 757 } 758 // do not do text conversion if it is active elsewhere 759 if (pConvArgs && !pConvIter) 760 { 761 ASSERT( !pConvIter, "text conversion already active!" ); 762 pConvIter = new SwConvIter( *pConvArgs ); 763 pLinguIter = pConvIter; 764 } 765 766 if (pLinguIter) 767 { 768 SwCursor* pSwCrsr = GetSwCrsr(); 769 770 SwPosition *pTmp = new SwPosition( *pSwCrsr->GetPoint() ); 771 pSwCrsr->FillFindPos( eCurr, *pTmp ); 772 pLinguIter->SetCurr( pTmp ); 773 774 pTmp = new SwPosition( *pTmp ); 775 pLinguIter->SetCurrX( pTmp ); 776 } 777 778 if (!pConvArgs && pSpellIter) 779 pSpellIter->Start( this, eStart, eEnd ); 780 if (pConvArgs && pConvIter) 781 pConvIter->Start( this, eStart, eEnd ); 782 } 783 784 /************************************************************************* 785 * SwEditShell::SpellEnd 786 *************************************************************************/ 787 788 void SwEditShell::SpellEnd( SwConversionArgs *pConvArgs, bool bRestoreSelection ) 789 { 790 if (!pConvArgs && pSpellIter && pSpellIter->GetSh() == this) 791 { 792 ASSERT( pSpellIter, "wo ist mein Iterator?" ); 793 pSpellIter->_End(bRestoreSelection); 794 delete pSpellIter, pSpellIter = 0; 795 } 796 if (pConvArgs && pConvIter && pConvIter->GetSh() == this) 797 { 798 ASSERT( pConvIter, "wo ist mein Iterator?" ); 799 pConvIter->_End(); 800 delete pConvIter, pConvIter = 0; 801 } 802 } 803 804 /************************************************************************* 805 * SwEditShell::SpellContinue 806 *************************************************************************/ 807 808 // liefert Rueckgabewerte entsprechend SPL_ in splchk.hxx 809 810 uno::Any SwEditShell::SpellContinue( 811 sal_uInt16* pPageCnt, sal_uInt16* pPageSt, 812 SwConversionArgs *pConvArgs ) 813 { 814 uno::Any aRes; 815 816 if ((!pConvArgs && pSpellIter->GetSh() != this) || 817 ( pConvArgs && pConvIter->GetSh() != this)) 818 return aRes; 819 820 if( pPageCnt && !*pPageCnt ) 821 { 822 sal_uInt16 nEndPage = GetLayout()->GetPageNum(); 823 nEndPage += nEndPage * 10 / 100; 824 *pPageCnt = nEndPage; 825 if( nEndPage ) 826 ::StartProgress( STR_STATSTR_SPELL, 0, nEndPage, GetDoc()->GetDocShell() ); 827 } 828 829 ASSERT( pConvArgs || pSpellIter, "SpellIter missing" ); 830 ASSERT( !pConvArgs || pConvIter, "ConvIter missing" ); 831 //JP 18.07.95: verhinder bei Fehlermeldungen die Anzeige der Selektionen 832 // KEIN StartAction, da damit auch die Paints abgeschaltet 833 // werden !!!!! 834 ++nStartAction; 835 rtl::OUString aRet; 836 uno::Reference< uno::XInterface > xRet; 837 if (pConvArgs) 838 { 839 pConvIter->Continue( pPageCnt, pPageSt ) >>= aRet; 840 aRes <<= aRet; 841 } 842 else 843 { 844 pSpellIter->Continue( pPageCnt, pPageSt ) >>= xRet; 845 aRes <<= xRet; 846 } 847 --nStartAction; 848 849 if( aRet.getLength() || xRet.is() ) 850 { 851 // dann die awt::Selection sichtbar machen 852 StartAction(); 853 EndAction(); 854 } 855 return aRes; 856 } 857 /************************************************************************* 858 * SwEditShell::HyphStart 859 *************************************************************************/ 860 861 /* Interaktive Trennung, BP 10.03.93 862 * 863 * 1) HyphStart 864 * - Aufheben aller Selektionen 865 * - Sichern des aktuellen Cursors 866 * - falls keine Selektion vorhanden: 867 * - neue Selektion bis zum Dokumentende 868 * 2) HyphContinue 869 * - nLastHyphLen wird auf den Selektionsstart addiert 870 * - iteriert ueber alle selektierten Bereiche 871 * - pDoc->Hyphenate() iteriert ueber alle Nodes der Selektion 872 * - pTxtNode->Hyphenate() ruft das SwTxtFrm::Hyphenate zur EditShell 873 * - SwTxtFrm:Hyphenate() iteriert ueber die Zeilen des Pams 874 * - LineIter::Hyphenate() stellt den Hyphenator 875 * und den Pam auf das zu trennende Wort ein. 876 * - Es gibt nur zwei Returnwerte sal_True, wenn eine Trennstelle anliegt 877 * und sal_False, wenn der Pam abgearbeitet wurde. 878 * - Bei sal_True wird das selektierte Wort zur Anzeige gebracht und 879 * nLastHyphLen gesetzt. 880 * - Bei sal_False wird die aktuelle Selektion geloescht und die naechste 881 * zur aktuellen gewaehlt. Return HYPH_OK, wenn keine mehr vorhanden. 882 * 3) InsertSoftHyph (wird ggf. von der UI gerufen) 883 * - Der aktuelle Cursor wird plaziert und das Attribut eingefuegt. 884 * 4) HyphEnd 885 * - Wiederherstellen des alten Cursors, EndAction 886 */ 887 888 889 890 void SwEditShell::HyphStart( SwDocPositions eStart, SwDocPositions eEnd ) 891 { 892 // do not hyphenate if interactive hyphenationg is active elsewhere 893 if (!pHyphIter) 894 { 895 ASSERT( !pHyphIter, "wer ist da schon am hyphinieren?" ); 896 pHyphIter = new SwHyphIter; 897 pHyphIter->Start( this, eStart, eEnd ); 898 } 899 } 900 901 /************************************************************************* 902 * SwEditShell::HyphEnd 903 *************************************************************************/ 904 905 // Selektionen wiederherstellen 906 907 908 909 void SwEditShell::HyphEnd() 910 { 911 if (pHyphIter->GetSh() == this) 912 { 913 ASSERT( pHyphIter, "wo ist mein Iterator?" ); 914 pHyphIter->End(); 915 delete pHyphIter, pHyphIter = 0; 916 } 917 } 918 919 /************************************************************************* 920 * SwEditShell::HyphContinue 921 *************************************************************************/ 922 923 // Returnwerte: (BP: ich wuerde es genau umdrehen, aber die UI wuenscht es so) 924 // HYPH_CONTINUE, wenn eine Trennstelle anliegt 925 // HYPH_OK, wenn der selektierte Bereich abgearbeitet wurde. 926 927 928 uno::Reference< uno::XInterface > 929 SwEditShell::HyphContinue( sal_uInt16* pPageCnt, sal_uInt16* pPageSt ) 930 { 931 if (pHyphIter->GetSh() != this) 932 return 0; 933 934 if( pPageCnt && !*pPageCnt && !*pPageSt ) 935 { 936 sal_uInt16 nEndPage = GetLayout()->GetPageNum(); 937 nEndPage += nEndPage * 10 / 100; 938 if( nEndPage > 14 ) 939 { 940 *pPageCnt = nEndPage; 941 ::StartProgress( STR_STATSTR_HYPHEN, 0, nEndPage, GetDoc()->GetDocShell()); 942 } 943 else // Hiermit unterdruecken wir ein fuer allemal 944 *pPageSt = 1; // das StatLineStartPercent 945 } 946 947 ASSERT( pHyphIter, "wo ist mein Iterator?" ); 948 //JP 18.07.95: verhinder bei Fehlermeldungen die Anzeige der Selektionen 949 // KEIN StartAction, da damit auch die Paints abgeschaltet 950 // werden !!!!! 951 ++nStartAction; 952 uno::Reference< uno::XInterface > xRet; 953 pHyphIter->Continue( pPageCnt, pPageSt ) >>= xRet; 954 --nStartAction; 955 956 if( xRet.is() ) 957 pHyphIter->ShowSelection(); 958 959 return xRet; 960 } 961 962 963 /************************************************************************* 964 * SwEditShell::InsertSoftHyph 965 *************************************************************************/ 966 967 // Zum Einfuegen des SoftHyphens, Position ist der Offset 968 // innerhalb des getrennten Wortes. 969 970 971 void SwEditShell::InsertSoftHyph( const xub_StrLen nHyphPos ) 972 { 973 ASSERT( pHyphIter, "wo ist mein Iterator?" ); 974 pHyphIter->InsertSoftHyph( nHyphPos ); 975 } 976 977 978 /************************************************************************* 979 * SwEditShell::HyphIgnore 980 *************************************************************************/ 981 982 // Beschreibung: Trennstelle ignorieren 983 984 void SwEditShell::HyphIgnore() 985 { 986 ASSERT( pHyphIter, "wo ist mein Iterator?" ); 987 //JP 18.07.95: verhinder bei Fehlermeldungen die Anzeige der Selektionen 988 // KEIN StartAction, da damit auch die Paints abgeschaltet 989 // werden !!!!! 990 ++nStartAction; 991 pHyphIter->Ignore(); 992 --nStartAction; 993 994 pHyphIter->ShowSelection(); 995 } 996 997 /************************************************************************* 998 * SwEditShell::GetCorrection() 999 * liefert eine Liste von Vorschlaegen fuer falsch geschriebene Worte, 1000 * ein NULL-Pointer signalisiert, dass das Wort richtig geschrieben ist, 1001 * eine leere Liste, dass das Wort zwar unbekannt ist, aber keine Alternativen 1002 * geliefert werden koennen. 1003 *************************************************************************/ 1004 1005 1006 uno::Reference< XSpellAlternatives > 1007 SwEditShell::GetCorrection( const Point* pPt, SwRect& rSelectRect ) 1008 { 1009 uno::Reference< XSpellAlternatives > xSpellAlt; 1010 1011 if( IsTableMode() ) 1012 return NULL; 1013 SwPaM* pCrsr = GetCrsr(); 1014 SwPosition aPos( *pCrsr->GetPoint() ); 1015 Point aPt( *pPt ); 1016 SwCrsrMoveState eTmpState( MV_SETONLYTEXT ); 1017 SwTxtNode *pNode; 1018 SwWrongList *pWrong; 1019 if( GetLayout()->GetCrsrOfst( &aPos, aPt, &eTmpState ) && 1020 0 != (pNode = aPos.nNode.GetNode().GetTxtNode()) && 1021 0 != (pWrong = pNode->GetWrong()) && 1022 !pNode->IsInProtectSect() ) 1023 { 1024 xub_StrLen nBegin = aPos.nContent.GetIndex(); 1025 xub_StrLen nLen = 1; 1026 if( pWrong->InWrongWord(nBegin,nLen) && !pNode->IsSymbol(nBegin) ) 1027 { 1028 String aText( pNode->GetTxt().Copy( nBegin, nLen ) ); 1029 String aWord( aText ); 1030 aWord.EraseAllChars( CH_TXTATR_BREAKWORD ).EraseAllChars( CH_TXTATR_INWORD ); 1031 1032 uno::Reference< XSpellChecker1 > xSpell( ::GetSpellChecker() ); 1033 if( xSpell.is() ) 1034 { 1035 LanguageType eActLang = (LanguageType)pNode->GetLang( nBegin, nLen ); 1036 if( xSpell->hasLanguage( eActLang )) 1037 { 1038 // restrict the maximal number of suggestions displayed 1039 // in the context menu. 1040 // Note: That could of course be done by clipping the 1041 // resulting sequence but the current third party 1042 // implementations result differs greatly if the number of 1043 // suggestions to be retuned gets changed. Statistically 1044 // it gets much better if told to return e.g. only 7 strings 1045 // than returning e.g. 16 suggestions and using only the 1046 // first 7. Thus we hand down the value to use to that 1047 // implementation here by providing an additional parameter. 1048 Sequence< PropertyValue > aPropVals(1); 1049 PropertyValue &rVal = aPropVals.getArray()[0]; 1050 rVal.Name = C2U( UPN_MAX_NUMBER_OF_SUGGESTIONS ); 1051 rVal.Value <<= (sal_Int16) 7; 1052 1053 xSpellAlt = xSpell->spell( aWord, eActLang, aPropVals ); 1054 } 1055 } 1056 1057 if ( xSpellAlt.is() ) // error found? 1058 { 1059 //save the start and end positons of the line and the starting point 1060 Push(); 1061 LeftMargin(); 1062 xub_StrLen nLineStart = GetCrsr()->GetPoint()->nContent.GetIndex(); 1063 RightMargin(); 1064 xub_StrLen nLineEnd = GetCrsr()->GetPoint()->nContent.GetIndex(); 1065 Pop(sal_False); 1066 1067 // make sure the selection build later from the 1068 // data below does not include footnotes and other 1069 // "in word" character to the left and right in order 1070 // to preserve those. Therefore count those "in words" 1071 // in order to modify the selection accordingly. 1072 const sal_Unicode* pChar = aText.GetBuffer(); 1073 xub_StrLen nLeft = 0; 1074 while (pChar && *pChar++ == CH_TXTATR_INWORD) 1075 ++nLeft; 1076 pChar = aText.Len() ? aText.GetBuffer() + aText.Len() - 1 : 0; 1077 xub_StrLen nRight = 0; 1078 while (pChar && *pChar-- == CH_TXTATR_INWORD) 1079 ++nRight; 1080 1081 aPos.nContent = nBegin + nLeft; 1082 pCrsr = GetCrsr(); 1083 *pCrsr->GetPoint() = aPos; 1084 pCrsr->SetMark(); 1085 ExtendSelection( sal_True, nLen - nLeft - nRight ); 1086 //no determine the rectangle in the current line 1087 xub_StrLen nWordStart = (nBegin + nLeft) < nLineStart ? nLineStart : nBegin + nLeft; 1088 //take one less than the line end - otherwise the next line would be calculated 1089 xub_StrLen nWordEnd = (nBegin + nLen - nLeft - nRight) > nLineEnd ? nLineEnd - 1: (nBegin + nLen - nLeft - nRight); 1090 Push(); 1091 pCrsr->DeleteMark(); 1092 SwIndex& rContent = GetCrsr()->GetPoint()->nContent; 1093 rContent = nWordStart; 1094 SwRect aStartRect; 1095 SwCrsrMoveState aState; 1096 aState.bRealWidth = sal_True; 1097 SwCntntNode* pCntntNode = pCrsr->GetCntntNode(); 1098 SwCntntFrm *pCntntFrame = pCntntNode->getLayoutFrm( GetLayout(), pPt, pCrsr->GetPoint(), sal_False); 1099 1100 pCntntFrame->GetCharRect( aStartRect, *pCrsr->GetPoint(), &aState ); 1101 rContent = nWordEnd; 1102 SwRect aEndRect; 1103 pCntntFrame->GetCharRect( aEndRect, *pCrsr->GetPoint(),&aState ); 1104 rSelectRect = aStartRect.Union( aEndRect ); 1105 Pop(sal_False); 1106 } 1107 } 1108 } 1109 return xSpellAlt; 1110 } 1111 1112 /*------------------------------------------------------------------------- 1113 1114 -----------------------------------------------------------------------*/ 1115 1116 bool SwEditShell::GetGrammarCorrection( 1117 linguistic2::ProofreadingResult /*out*/ &rResult, // the complete result 1118 sal_Int32 /*out*/ &rErrorPosInText, // offset of error position in string that was grammar checked... 1119 sal_Int32 /*out*/ &rErrorIndexInResult, // index of error in rResult.aGrammarErrors 1120 uno::Sequence< rtl::OUString > /*out*/ &rSuggestions, // suggestions to be used for the error found 1121 const Point *pPt, SwRect &rSelectRect ) 1122 { 1123 bool bRes = false; 1124 1125 if( IsTableMode() ) 1126 return bRes; 1127 1128 SwPaM* pCrsr = GetCrsr(); 1129 SwPosition aPos( *pCrsr->GetPoint() ); 1130 Point aPt( *pPt ); 1131 SwCrsrMoveState eTmpState( MV_SETONLYTEXT ); 1132 SwTxtNode *pNode; 1133 SwGrammarMarkUp *pWrong; 1134 if( GetLayout()->GetCrsrOfst( &aPos, aPt, &eTmpState ) && 1135 0 != (pNode = aPos.nNode.GetNode().GetTxtNode()) && 1136 0 != (pWrong = pNode->GetGrammarCheck()) && 1137 !pNode->IsInProtectSect() ) 1138 { 1139 xub_StrLen nBegin = aPos.nContent.GetIndex(); 1140 xub_StrLen nLen = 1; 1141 if (pWrong->InWrongWord(nBegin, nLen)) 1142 { 1143 String aText( pNode->GetTxt().Copy( nBegin, nLen ) ); 1144 String aWord( aText ); 1145 aWord.EraseAllChars( CH_TXTATR_BREAKWORD ).EraseAllChars( CH_TXTATR_INWORD ); 1146 1147 uno::Reference< linguistic2::XProofreadingIterator > xGCIterator( pDoc->GetGCIterator() ); 1148 if (xGCIterator.is()) 1149 { 1150 // LanguageType eActLang = (LanguageType)pNode->GetLang( nBegin, nLen ); 1151 uno::Reference< lang::XComponent > xDoc( pDoc->GetDocShell()->GetBaseModel(), uno::UNO_QUERY ); 1152 1153 // Expand the string: 1154 rtl::OUString aExpandText; 1155 const ModelToViewHelper::ConversionMap* pConversionMap = 1156 pNode->BuildConversionMap( aExpandText ); 1157 // get XFlatParagraph to use... 1158 uno::Reference< text::XFlatParagraph > xFlatPara = new SwXFlatParagraph( *pNode, aExpandText, pConversionMap ); 1159 1160 // get error position of cursor in XFlatParagraph 1161 rErrorPosInText = ModelToViewHelper::ConvertToViewPosition( pConversionMap, nBegin ); 1162 1163 sal_Int32 nStartOfSentence = ModelToViewHelper::ConvertToViewPosition( pConversionMap, pWrong->getSentenceStart( nBegin ) ); 1164 sal_Int32 nEndOfSentence = ModelToViewHelper::ConvertToViewPosition( pConversionMap, pWrong->getSentenceEnd( nBegin ) ); 1165 if( nEndOfSentence == STRING_LEN ) 1166 { 1167 /* if( nStartOfSentence == 0 ) 1168 { 1169 nStartOfSentence = -1; 1170 nEndOfSentence = -1; 1171 } 1172 else */ 1173 nEndOfSentence = aExpandText.getLength(); 1174 } 1175 1176 rResult = xGCIterator->checkSentenceAtPosition( 1177 xDoc, xFlatPara, aExpandText, lang::Locale(), nStartOfSentence, nEndOfSentence, rErrorPosInText ); 1178 bRes = true; 1179 1180 // get suggestions to use for the specific error position 1181 sal_Int32 nErrors = rResult.aErrors.getLength(); 1182 rSuggestions.realloc( 0 ); 1183 for (sal_Int32 i = 0; i < nErrors; ++i ) 1184 { 1185 // return suggestions for first error that includes the given error position 1186 const linguistic2::SingleProofreadingError &rError = rResult.aErrors[i]; 1187 if (rError.nErrorStart <= rErrorPosInText && 1188 rErrorPosInText < rError.nErrorStart + rError.nErrorLength) 1189 { 1190 rSuggestions = rError.aSuggestions; 1191 rErrorIndexInResult = i; 1192 break; 1193 } 1194 } 1195 } 1196 1197 if (rResult.aErrors.getLength() > 0) // error found? 1198 { 1199 //save the start and end positons of the line and the starting point 1200 Push(); 1201 LeftMargin(); 1202 xub_StrLen nLineStart = GetCrsr()->GetPoint()->nContent.GetIndex(); 1203 RightMargin(); 1204 xub_StrLen nLineEnd = GetCrsr()->GetPoint()->nContent.GetIndex(); 1205 Pop(sal_False); 1206 1207 #if OSL_DEBUG_LEVEL > 1 1208 // pNode->GetGrammarCheck()->Invalidate( 0, STRING_LEN ); 1209 // pNode->SetGrammarCheckDirty( true ); 1210 #endif 1211 // make sure the selection build later from the 1212 // data below does not include footnotes and other 1213 // "in word" character to the left and right in order 1214 // to preserve those. Therefore count those "in words" 1215 // in order to modify the selection accordingly. 1216 const sal_Unicode* pChar = aText.GetBuffer(); 1217 xub_StrLen nLeft = 0; 1218 while (pChar && *pChar++ == CH_TXTATR_INWORD) 1219 ++nLeft; 1220 pChar = aText.Len() ? aText.GetBuffer() + aText.Len() - 1 : 0; 1221 xub_StrLen nRight = 0; 1222 while (pChar && *pChar-- == CH_TXTATR_INWORD) 1223 ++nRight; 1224 1225 aPos.nContent = nBegin + nLeft; 1226 pCrsr = GetCrsr(); 1227 *pCrsr->GetPoint() = aPos; 1228 pCrsr->SetMark(); 1229 ExtendSelection( sal_True, nLen - nLeft - nRight ); 1230 //no determine the rectangle in the current line 1231 xub_StrLen nWordStart = (nBegin + nLeft) < nLineStart ? nLineStart : nBegin + nLeft; 1232 //take one less than the line end - otherwise the next line would be calculated 1233 xub_StrLen nWordEnd = (nBegin + nLen - nLeft - nRight) > nLineEnd ? nLineEnd - 1: (nBegin + nLen - nLeft - nRight); 1234 Push(); 1235 pCrsr->DeleteMark(); 1236 SwIndex& rContent = GetCrsr()->GetPoint()->nContent; 1237 rContent = nWordStart; 1238 SwRect aStartRect; 1239 SwCrsrMoveState aState; 1240 aState.bRealWidth = sal_True; 1241 SwCntntNode* pCntntNode = pCrsr->GetCntntNode(); 1242 SwCntntFrm *pCntntFrame = pCntntNode->getLayoutFrm( GetLayout(), pPt, pCrsr->GetPoint(), sal_False); 1243 1244 pCntntFrame->GetCharRect( aStartRect, *pCrsr->GetPoint(), &aState ); 1245 rContent = nWordEnd; 1246 SwRect aEndRect; 1247 pCntntFrame->GetCharRect( aEndRect, *pCrsr->GetPoint(),&aState ); 1248 rSelectRect = aStartRect.Union( aEndRect ); 1249 Pop(sal_False); 1250 } 1251 } 1252 } 1253 1254 return bRes; 1255 } 1256 1257 /*-- 18.09.2003 15:08:18--------------------------------------------------- 1258 1259 -----------------------------------------------------------------------*/ 1260 bool SwEditShell::SpellSentence(::svx::SpellPortions& rPortions, bool bIsGrammarCheck) 1261 { 1262 ASSERT( pSpellIter, "SpellIter missing" ); 1263 if(!pSpellIter) 1264 return false; 1265 bool bRet = pSpellIter->SpellSentence(rPortions, bIsGrammarCheck); 1266 1267 // make Selection visible - this should simply move the 1268 // cursor to the end of the sentence 1269 StartAction(); 1270 EndAction(); 1271 return bRet; 1272 } 1273 /*-- 08.09.2008 09:35:19--------------------------------------------------- 1274 make SpellIter start with the current sentence when called next time 1275 -----------------------------------------------------------------------*/ 1276 void SwEditShell::PutSpellingToSentenceStart() 1277 { 1278 ASSERT( pSpellIter, "SpellIter missing" ); 1279 if(!pSpellIter) 1280 return; 1281 pSpellIter->ToSentenceStart(); 1282 } 1283 /*-- 02.02.2005 14:34:41--------------------------------------------------- 1284 1285 -----------------------------------------------------------------------*/ 1286 sal_uInt32 lcl_CountRedlines( 1287 const ::svx::SpellPortions& rLastPortions) 1288 { 1289 sal_uInt32 nRet = 0; 1290 SpellPortions::const_iterator aIter = rLastPortions.begin(); 1291 for( ; aIter != rLastPortions.end(); ++aIter) 1292 { 1293 if( aIter->bIsHidden ) 1294 ++nRet; 1295 } 1296 return nRet; 1297 } 1298 /*-- 18.09.2003 15:08:20--------------------------------------------------- 1299 1300 -----------------------------------------------------------------------*/ 1301 1302 void SwEditShell::MoveContinuationPosToEndOfCheckedSentence() 1303 { 1304 // give hint that continuation position for spell/grammar checking is 1305 // at the end of this sentence 1306 if (pSpellIter) 1307 { 1308 pSpellIter->SetCurr( new SwPosition( *pSpellIter->GetCurrX() ) ); 1309 pSpellIter->ContinueAfterThisSentence(); 1310 } 1311 } 1312 1313 1314 void SwEditShell::ApplyChangedSentence(const ::svx::SpellPortions& rNewPortions, bool bRecheck) 1315 { 1316 // Note: rNewPortions.size() == 0 is valid and happens when the whole 1317 // sentence got removed in the dialog 1318 1319 ASSERT( pSpellIter, "SpellIter missing" ); 1320 if(pSpellIter && 1321 pSpellIter->GetLastPortions().size() > 0) // no portions -> no text to be changed 1322 { 1323 const SpellPortions& rLastPortions = pSpellIter->GetLastPortions(); 1324 const SpellContentPositions rLastPositions = pSpellIter->GetLastPositions(); 1325 ASSERT(rLastPortions.size() > 0 && 1326 rLastPortions.size() == rLastPositions.size(), 1327 "last vectors of spelling results are not set or not equal") 1328 1329 // iterate over the new portions, beginning at the end to take advantage of the previously 1330 // saved content positions 1331 1332 pDoc->GetIDocumentUndoRedo().StartUndo( UNDO_OVERWRITE, NULL ); 1333 StartAction(); 1334 1335 SwPaM *pCrsr = GetCrsr(); 1336 // save cursor position (which should be at the end of the current sentence) 1337 // for later restoration 1338 Push(); 1339 1340 sal_uInt32 nRedlinePortions = lcl_CountRedlines(rLastPortions); 1341 if((rLastPortions.size() - nRedlinePortions) == rNewPortions.size()) 1342 { 1343 DBG_ASSERT( rNewPortions.size() > 0, "rNewPortions should not be empty here" ); 1344 DBG_ASSERT( rLastPortions.size() > 0, "rLastPortions should not be empty here" ); 1345 DBG_ASSERT( rLastPositions.size() > 0, "rLastPositions should not be empty here" ); 1346 1347 //the simple case: the same number of elements on both sides 1348 //each changed element has to be applied to the corresponding source element 1349 svx::SpellPortions::const_iterator aCurrentNewPortion = rNewPortions.end(); 1350 SpellPortions::const_iterator aCurrentOldPortion = rLastPortions.end(); 1351 SpellContentPositions::const_iterator aCurrentOldPosition = rLastPositions.end(); 1352 do 1353 { 1354 --aCurrentNewPortion; 1355 --aCurrentOldPortion; 1356 --aCurrentOldPosition; 1357 //jump over redline portions 1358 while(aCurrentOldPortion->bIsHidden) 1359 { 1360 if (aCurrentOldPortion != rLastPortions.begin() && 1361 aCurrentOldPosition != rLastPositions.begin()) 1362 { 1363 --aCurrentOldPortion; 1364 --aCurrentOldPosition; 1365 } 1366 else 1367 { 1368 DBG_ASSERT( 0, "ApplyChangedSentence: iterator positions broken" ); 1369 break; 1370 } 1371 } 1372 if ( !pCrsr->HasMark() ) 1373 pCrsr->SetMark(); 1374 pCrsr->GetPoint()->nContent = aCurrentOldPosition->nLeft; 1375 pCrsr->GetMark()->nContent = aCurrentOldPosition->nRight; 1376 sal_uInt16 nScriptType = GetI18NScriptTypeOfLanguage( aCurrentNewPortion->eLanguage ); 1377 sal_uInt16 nLangWhichId = RES_CHRATR_LANGUAGE; 1378 switch(nScriptType) 1379 { 1380 case SCRIPTTYPE_ASIAN : nLangWhichId = RES_CHRATR_CJK_LANGUAGE; break; 1381 case SCRIPTTYPE_COMPLEX : nLangWhichId = RES_CHRATR_CTL_LANGUAGE; break; 1382 } 1383 if(aCurrentNewPortion->sText != aCurrentOldPortion->sText) 1384 { 1385 //change text ... 1386 pDoc->DeleteAndJoin(*pCrsr); 1387 // ... and apply language if necessary 1388 if(aCurrentNewPortion->eLanguage != aCurrentOldPortion->eLanguage) 1389 SetAttr( SvxLanguageItem(aCurrentNewPortion->eLanguage, nLangWhichId), nLangWhichId ); 1390 pDoc->InsertString(*pCrsr, aCurrentNewPortion->sText); 1391 } 1392 else if(aCurrentNewPortion->eLanguage != aCurrentOldPortion->eLanguage) 1393 { 1394 //apply language 1395 SetAttr( SvxLanguageItem(aCurrentNewPortion->eLanguage, nLangWhichId), nLangWhichId ); 1396 } 1397 else if( aCurrentNewPortion->bIgnoreThisError ) 1398 { 1399 //add the 'ignore' markup to the TextNode's grammar ignore markup list 1400 IgnoreGrammarErrorAt( *pCrsr ); 1401 DBG_ERROR("TODO: add ignore mark to text node"); 1402 } 1403 if(aCurrentNewPortion == rNewPortions.begin()) 1404 break; 1405 } 1406 while(aCurrentNewPortion != rNewPortions.begin()); 1407 } 1408 else 1409 { 1410 DBG_ASSERT( rLastPositions.size() > 0, "rLastPositions should not be empty here" ); 1411 1412 //select the complete sentence 1413 SpellContentPositions::const_iterator aCurrentEndPosition = rLastPositions.end(); 1414 --aCurrentEndPosition; 1415 SpellContentPositions::const_iterator aCurrentStartPosition = rLastPositions.begin(); 1416 pCrsr->GetPoint()->nContent = aCurrentStartPosition->nLeft; 1417 pCrsr->GetMark()->nContent = aCurrentEndPosition->nRight; 1418 1419 //delete the sentence completely 1420 pDoc->DeleteAndJoin(*pCrsr); 1421 svx::SpellPortions::const_iterator aCurrentNewPortion = rNewPortions.begin(); 1422 while(aCurrentNewPortion != rNewPortions.end()) 1423 { 1424 //set the language attribute 1425 sal_uInt16 nScriptType = GetScriptType(); 1426 sal_uInt16 nLangWhichId = RES_CHRATR_LANGUAGE; 1427 switch(nScriptType) 1428 { 1429 case SCRIPTTYPE_ASIAN : nLangWhichId = RES_CHRATR_CJK_LANGUAGE; break; 1430 case SCRIPTTYPE_COMPLEX : nLangWhichId = RES_CHRATR_CTL_LANGUAGE; break; 1431 } 1432 SfxItemSet aSet(GetAttrPool(), nLangWhichId, nLangWhichId, 0); 1433 GetCurAttr( aSet ); 1434 const SvxLanguageItem& rLang = static_cast<const SvxLanguageItem& >(aSet.Get(nLangWhichId)); 1435 if(rLang.GetLanguage() != aCurrentNewPortion->eLanguage) 1436 SetAttr( SvxLanguageItem(aCurrentNewPortion->eLanguage, nLangWhichId) ); 1437 //insert the new string 1438 pDoc->InsertString(*pCrsr, aCurrentNewPortion->sText); 1439 1440 //set the cursor to the end of the inserted string 1441 *pCrsr->Start() = *pCrsr->End(); 1442 ++aCurrentNewPortion; 1443 } 1444 } 1445 1446 // restore cursor to the end of the sentence 1447 // (will work also if the sentence length has changed, 1448 // since cursors get updated automatically!) 1449 Pop( sal_False ); 1450 1451 // collapse cursor to the end of the modified sentence 1452 *pCrsr->Start() = *pCrsr->End(); 1453 if (bRecheck) 1454 { 1455 //in grammar check the current sentence has to be checked again 1456 GoStartSentence(); 1457 } 1458 // set continuation position for spell/grammar checking to the end of this sentence 1459 pSpellIter->SetCurr( new SwPosition( *pCrsr->Start() ) ); 1460 1461 pDoc->GetIDocumentUndoRedo().EndUndo( UNDO_OVERWRITE, NULL ); 1462 EndAction(); 1463 } 1464 } 1465 /*-- 02.02.2005 10:46:45--------------------------------------------------- 1466 collect all deleted redlines of the current text node beginning at the 1467 start of the cursor position 1468 -----------------------------------------------------------------------*/ 1469 SpellContentPositions lcl_CollectDeletedRedlines(SwEditShell* pSh) 1470 { 1471 SpellContentPositions aRedlines; 1472 SwDoc* pDoc = pSh->GetDoc(); 1473 const bool bShowChg = IDocumentRedlineAccess::IsShowChanges( pDoc->GetRedlineMode() ); 1474 if ( bShowChg ) 1475 { 1476 SwPaM *pCrsr = pSh->GetCrsr(); 1477 const SwPosition* pStartPos = pCrsr->Start(); 1478 const SwTxtNode* pTxtNode = pCrsr->GetNode()->GetTxtNode(); 1479 1480 sal_uInt16 nAct = pDoc->GetRedlinePos( *pTxtNode, USHRT_MAX ); 1481 const xub_StrLen nStartIndex = pStartPos->nContent.GetIndex(); 1482 for ( ; nAct < pDoc->GetRedlineTbl().Count(); nAct++ ) 1483 { 1484 const SwRedline* pRed = pDoc->GetRedlineTbl()[ nAct ]; 1485 1486 if ( pRed->Start()->nNode > pTxtNode->GetIndex() ) 1487 break; 1488 1489 if( nsRedlineType_t::REDLINE_DELETE == pRed->GetType() ) 1490 { 1491 xub_StrLen nStart, nEnd; 1492 pRed->CalcStartEnd( pTxtNode->GetIndex(), nStart, nEnd ); 1493 if(nStart >= nStartIndex || nEnd >= nStartIndex) 1494 { 1495 SpellContentPosition aAdd; 1496 aAdd.nLeft = nStart; 1497 aAdd.nRight = nEnd; 1498 aRedlines.push_back(aAdd); 1499 } 1500 } 1501 } 1502 } 1503 return aRedlines; 1504 } 1505 /*-- 02.02.2005 11:06:12--------------------------------------------------- 1506 remove the redline positions after the current selection 1507 -----------------------------------------------------------------------*/ 1508 void lcl_CutRedlines( SpellContentPositions& aDeletedRedlines, SwEditShell* pSh ) 1509 { 1510 if(!aDeletedRedlines.empty()) 1511 { 1512 SwPaM *pCrsr = pSh->GetCrsr(); 1513 const SwPosition* pEndPos = pCrsr->End(); 1514 xub_StrLen nEnd = pEndPos->nContent.GetIndex(); 1515 while(!aDeletedRedlines.empty() && 1516 aDeletedRedlines.back().nLeft > nEnd) 1517 { 1518 aDeletedRedlines.pop_back(); 1519 } 1520 } 1521 } 1522 /*-- 02.02.2005 11:43:00--------------------------------------------------- 1523 1524 -----------------------------------------------------------------------*/ 1525 SpellContentPosition lcl_FindNextDeletedRedline( 1526 const SpellContentPositions& rDeletedRedlines, 1527 xub_StrLen nSearchFrom ) 1528 { 1529 SpellContentPosition aRet; 1530 aRet.nLeft = aRet.nRight = STRING_MAXLEN; 1531 if(!rDeletedRedlines.empty()) 1532 { 1533 SpellContentPositions::const_iterator aIter = rDeletedRedlines.begin(); 1534 for( ; aIter != rDeletedRedlines.end(); ++aIter) 1535 { 1536 if(aIter->nLeft < nSearchFrom) 1537 continue; 1538 aRet = *aIter; 1539 break; 1540 } 1541 } 1542 return aRet; 1543 } 1544 /*-- 18.09.2003 15:08:20--------------------------------------------------- 1545 1546 -----------------------------------------------------------------------*/ 1547 bool SwSpellIter::SpellSentence(::svx::SpellPortions& rPortions, bool bIsGrammarCheck) 1548 { 1549 bool bRet = false; 1550 aLastPortions.clear(); 1551 aLastPositions.clear(); 1552 1553 SwEditShell *pMySh = GetSh(); 1554 if( !pMySh ) 1555 return false; 1556 1557 ASSERT( GetEnd(), "SwEditShell::SpellSentence() ohne Start?"); 1558 1559 uno::Reference< XSpellAlternatives > xSpellRet; 1560 linguistic2::ProofreadingResult aGrammarResult; 1561 sal_Bool bGoOn = sal_True; 1562 bool bGrammarErrorFound = false; 1563 do { 1564 SwPaM *pCrsr = pMySh->GetCrsr(); 1565 if ( !pCrsr->HasMark() ) 1566 pCrsr->SetMark(); 1567 1568 *pCrsr->GetPoint() = *GetCurr(); 1569 *pCrsr->GetMark() = *GetEnd(); 1570 1571 if( bBackToStartOfSentence ) 1572 { 1573 pMySh->GoStartSentence(); 1574 bBackToStartOfSentence = false; 1575 } 1576 uno::Any aSpellRet = 1577 pMySh->GetDoc()->Spell(*pCrsr, 1578 xSpeller, 0, 0, bIsGrammarCheck ); 1579 aSpellRet >>= xSpellRet; 1580 aSpellRet >>= aGrammarResult; 1581 bGoOn = GetCrsrCnt() > 1; 1582 bGrammarErrorFound = aGrammarResult.aErrors.getLength() > 0; 1583 if( xSpellRet.is() || bGrammarErrorFound ) 1584 { 1585 bGoOn = sal_False; 1586 SwPosition* pNewPoint = new SwPosition( *pCrsr->GetPoint() ); 1587 SwPosition* pNewMark = new SwPosition( *pCrsr->GetMark() ); 1588 1589 SetCurr( pNewPoint ); 1590 SetCurrX( pNewMark ); 1591 } 1592 if( bGoOn ) 1593 { 1594 pMySh->Pop( sal_False ); 1595 pCrsr = pMySh->GetCrsr(); 1596 if ( *pCrsr->GetPoint() > *pCrsr->GetMark() ) 1597 pCrsr->Exchange(); 1598 SwPosition* pNew = new SwPosition( *pCrsr->GetPoint() ); 1599 SetStart( pNew ); 1600 pNew = new SwPosition( *pCrsr->GetMark() ); 1601 SetEnd( pNew ); 1602 pNew = new SwPosition( *GetStart() ); 1603 SetCurr( pNew ); 1604 pNew = new SwPosition( *pNew ); 1605 SetCurrX( pNew ); 1606 pCrsr->SetMark(); 1607 --GetCrsrCnt(); 1608 } 1609 } 1610 while ( bGoOn ); 1611 if(xSpellRet.is() || bGrammarErrorFound) 1612 { 1613 //an error has been found 1614 //To fill the spell portions the beginning of the sentence has to be found 1615 SwPaM *pCrsr = pMySh->GetCrsr(); 1616 //set the mark to the right if necessary 1617 if ( *pCrsr->GetPoint() > *pCrsr->GetMark() ) 1618 pCrsr->Exchange(); 1619 //the cursor has to be collapsed on the left to go to the start of the sentence - if sentence ends inside of the error 1620 pCrsr->DeleteMark(); 1621 pCrsr->SetMark(); 1622 sal_Bool bStartSent = 0 != pMySh->GoStartSentence(); 1623 SpellContentPositions aDeletedRedlines = lcl_CollectDeletedRedlines(pMySh); 1624 if(bStartSent) 1625 { 1626 //create a portion from the start part 1627 AddPortion(0, 0, aDeletedRedlines); 1628 } 1629 //Set the cursor to the error already found 1630 *pCrsr->GetPoint() = *GetCurrX(); 1631 *pCrsr->GetMark() = *GetCurr(); 1632 AddPortion(xSpellRet, &aGrammarResult, aDeletedRedlines); 1633 1634 1635 //save the end position of the error to continue from here 1636 SwPosition aSaveStartPos = *pCrsr->End(); 1637 //determine the end of the current sentence 1638 if ( *pCrsr->GetPoint() < *pCrsr->GetMark() ) 1639 pCrsr->Exchange(); 1640 //again collapse to start marking after the end of the error 1641 pCrsr->DeleteMark(); 1642 pCrsr->SetMark(); 1643 1644 pMySh->GoEndSentence(); 1645 if( bGrammarErrorFound ) 1646 { 1647 rtl::OUString aExpandText; 1648 const ModelToViewHelper::ConversionMap* pConversionMap = ((SwTxtNode*)pCrsr->GetNode())->BuildConversionMap( aExpandText ); 1649 xub_StrLen nSentenceEnd = (xub_StrLen)ModelToViewHelper::ConvertToViewPosition( pConversionMap, aGrammarResult.nBehindEndOfSentencePosition ); 1650 // remove trailing space 1651 if( aExpandText[nSentenceEnd - 1] == ' ' ) 1652 --nSentenceEnd; 1653 if( pCrsr->End()->nContent.GetIndex() < nSentenceEnd ) 1654 { 1655 pCrsr->End()->nContent.Assign( 1656 pCrsr->End()->nNode.GetNode().GetCntntNode(), nSentenceEnd); 1657 } 1658 } 1659 1660 lcl_CutRedlines( aDeletedRedlines, pMySh ); 1661 //save the 'global' end of the spellchecking 1662 const SwPosition aSaveEndPos = *GetEnd(); 1663 //set the sentence end as 'local' end 1664 SetEnd( new SwPosition( *pCrsr->End() )); 1665 1666 *pCrsr->GetPoint() = aSaveStartPos; 1667 *pCrsr->GetMark() = *GetEnd(); 1668 //now the rest of the sentence has to be searched for errors 1669 // for each error the non-error text between the current and the last error has 1670 // to be added to the portions - if necessary broken into same-language-portions 1671 if( !bGrammarErrorFound ) //in grammar check there's only one error returned 1672 { 1673 do 1674 { 1675 xSpellRet = 0; 1676 // don't search for grammar errors here anymore! 1677 pMySh->GetDoc()->Spell(*pCrsr, 1678 xSpeller, 0, 0, false ) >>= xSpellRet; 1679 if ( *pCrsr->GetPoint() > *pCrsr->GetMark() ) 1680 pCrsr->Exchange(); 1681 SetCurr( new SwPosition( *pCrsr->GetPoint() )); 1682 SetCurrX( new SwPosition( *pCrsr->GetMark() )); 1683 1684 //if an error has been found go back to the text 1685 //preceeding the error 1686 if(xSpellRet.is()) 1687 { 1688 *pCrsr->GetPoint() = aSaveStartPos; 1689 *pCrsr->GetMark() = *GetCurr(); 1690 } 1691 //add the portion 1692 AddPortion(0, 0, aDeletedRedlines); 1693 1694 if(xSpellRet.is()) 1695 { 1696 *pCrsr->GetPoint() = *GetCurr(); 1697 *pCrsr->GetMark() = *GetCurrX(); 1698 AddPortion(xSpellRet, 0, aDeletedRedlines); 1699 //move the cursor to the end of the error string 1700 *pCrsr->GetPoint() = *GetCurrX(); 1701 //and save the end of the error as new start position 1702 aSaveStartPos = *GetCurrX(); 1703 //and the end of the sentence 1704 *pCrsr->GetMark() = *GetEnd(); 1705 } 1706 // if the end of the sentence has already been reached then break here 1707 if(*GetCurrX() >= *GetEnd()) 1708 break; 1709 } 1710 while(xSpellRet.is()); 1711 } 1712 else 1713 { 1714 //go to the end of sentence as the grammar check returned it 1715 // at this time the Point is behind the grammar error 1716 // and the mark points to the sentence end as 1717 if ( *pCrsr->GetPoint() < *pCrsr->GetMark() ) 1718 pCrsr->Exchange(); 1719 } 1720 1721 // the part between the last error and the end of the sentence has to be added 1722 *pMySh->GetCrsr()->GetPoint() = *GetEnd(); 1723 if(*GetCurrX() < *GetEnd()) 1724 { 1725 AddPortion(0, 0, aDeletedRedlines); 1726 } 1727 //set the shell cursor to the end of the sentence to prevent a visible selection 1728 *pCrsr->GetMark() = *GetEnd(); 1729 if( !bIsGrammarCheck ) 1730 { 1731 //set the current position to the end of the sentence 1732 SetCurr( new SwPosition(*GetEnd()) ); 1733 } 1734 //restore the 'global' end 1735 SetEnd( new SwPosition(aSaveEndPos) ); 1736 rPortions = aLastPortions; 1737 bRet = true; 1738 } 1739 else 1740 { 1741 //if no error could be found the selection has to be corrected - at least if it's not in the body 1742 *pMySh->GetCrsr()->GetPoint() = *GetEnd(); 1743 pMySh->GetCrsr()->DeleteMark(); 1744 } 1745 1746 return bRet; 1747 } 1748 1749 /*-- 08.09.2008 09:37:15--------------------------------------------------- 1750 1751 -----------------------------------------------------------------------*/ 1752 void SwSpellIter::ToSentenceStart() 1753 { 1754 bBackToStartOfSentence = true; 1755 } 1756 /*-- 08.10.2003 08:49:56--------------------------------------------------- 1757 1758 -----------------------------------------------------------------------*/ 1759 LanguageType lcl_GetLanguage(SwEditShell& rSh) 1760 { 1761 sal_uInt16 nScriptType = rSh.GetScriptType(); 1762 sal_uInt16 nLangWhichId = RES_CHRATR_LANGUAGE; 1763 1764 switch(nScriptType) 1765 { 1766 case SCRIPTTYPE_ASIAN : nLangWhichId = RES_CHRATR_CJK_LANGUAGE; break; 1767 case SCRIPTTYPE_COMPLEX : nLangWhichId = RES_CHRATR_CTL_LANGUAGE; break; 1768 } 1769 SfxItemSet aSet(rSh.GetAttrPool(), nLangWhichId, nLangWhichId, 0); 1770 rSh.GetCurAttr( aSet ); 1771 const SvxLanguageItem& rLang = static_cast<const SvxLanguageItem& >(aSet.Get(nLangWhichId)); 1772 return rLang.GetLanguage(); 1773 } 1774 /*-- 08.10.2003 08:53:27--------------------------------------------------- 1775 create a text portion at the given position 1776 -----------------------------------------------------------------------*/ 1777 void SwSpellIter::CreatePortion(uno::Reference< XSpellAlternatives > xAlt, 1778 linguistic2::ProofreadingResult* pGrammarResult, 1779 bool bIsField, bool bIsHidden) 1780 { 1781 svx::SpellPortion aPortion; 1782 String sText; 1783 GetSh()->GetSelectedText( sText ); 1784 if(sText.Len()) 1785 { 1786 //in case of redlined deletions the selection of an error is not 1787 //the same as the _real_ word 1788 if(xAlt.is()) 1789 aPortion.sText = xAlt->getWord(); 1790 else if(pGrammarResult) 1791 { 1792 aPortion.bIsGrammarError = true; 1793 if(pGrammarResult->aErrors.getLength()) 1794 { 1795 aPortion.aGrammarError = pGrammarResult->aErrors[0]; 1796 aPortion.sText = pGrammarResult->aText.copy( aPortion.aGrammarError.nErrorStart, aPortion.aGrammarError.nErrorLength ); 1797 aPortion.xGrammarChecker = pGrammarResult->xProofreader; 1798 const beans::PropertyValue* pProperties = pGrammarResult->aProperties.getConstArray(); 1799 for( sal_Int32 nProp = 0; nProp < pGrammarResult->aProperties.getLength(); ++nProp ) 1800 { 1801 if( pProperties->Name.equalsAscii("DialogTitle") ) 1802 { 1803 pProperties->Value >>= aPortion.sDialogTitle; 1804 break; 1805 } 1806 } 1807 } 1808 } 1809 else 1810 aPortion.sText = sText; 1811 aPortion.eLanguage = lcl_GetLanguage(*GetSh()); 1812 aPortion.bIsField = bIsField; 1813 aPortion.bIsHidden = bIsHidden; 1814 aPortion.xAlternatives = xAlt; 1815 SpellContentPosition aPosition; 1816 SwPaM *pCrsr = GetSh()->GetCrsr(); 1817 aPosition.nLeft = pCrsr->Start()->nContent.GetIndex(); 1818 aPosition.nRight = pCrsr->End()->nContent.GetIndex(); 1819 aLastPortions.push_back(aPortion); 1820 aLastPositions.push_back(aPosition); 1821 } 1822 } 1823 /*-- 19.09.2003 13:05:43--------------------------------------------------- 1824 1825 -----------------------------------------------------------------------*/ 1826 void SwSpellIter::AddPortion(uno::Reference< XSpellAlternatives > xAlt, 1827 linguistic2::ProofreadingResult* pGrammarResult, 1828 const SpellContentPositions& rDeletedRedlines) 1829 { 1830 SwEditShell *pMySh = GetSh(); 1831 String sText; 1832 pMySh->GetSelectedText( sText ); 1833 if(sText.Len()) 1834 { 1835 if(xAlt.is() || pGrammarResult != 0) 1836 { 1837 CreatePortion(xAlt, pGrammarResult, false, false); 1838 } 1839 else 1840 { 1841 SwPaM *pCrsr = GetSh()->GetCrsr(); 1842 if ( *pCrsr->GetPoint() > *pCrsr->GetMark() ) 1843 pCrsr->Exchange(); 1844 //save the start and end positions 1845 SwPosition aStart(*pCrsr->GetPoint()); 1846 SwPosition aEnd(*pCrsr->GetMark()); 1847 //iterate over the text to find changes in language 1848 //set the mark equal to the point 1849 *pCrsr->GetMark() = aStart; 1850 SwTxtNode* pTxtNode = pCrsr->GetNode()->GetTxtNode(); 1851 LanguageType eStartLanguage = lcl_GetLanguage(*GetSh()); 1852 SpellContentPosition aNextRedline = lcl_FindNextDeletedRedline( 1853 rDeletedRedlines, aStart.nContent.GetIndex() ); 1854 if( aNextRedline.nLeft == aStart.nContent.GetIndex() ) 1855 { 1856 //select until the end of the current redline 1857 xub_StrLen nEnd = aEnd.nContent.GetIndex() < aNextRedline.nRight ? 1858 aEnd.nContent.GetIndex() : aNextRedline.nRight; 1859 pCrsr->GetPoint()->nContent.Assign( pTxtNode, nEnd ); 1860 CreatePortion(xAlt, pGrammarResult, false, true); 1861 aStart = *pCrsr->End(); 1862 //search for next redline 1863 aNextRedline = lcl_FindNextDeletedRedline( 1864 rDeletedRedlines, aStart.nContent.GetIndex() ); 1865 } 1866 while(*pCrsr->GetPoint() < aEnd) 1867 { 1868 //#125786 in table cell with fixed row height the cursor might not move forward 1869 if(!GetSh()->Right(1, CRSR_SKIP_CELLS)) 1870 break; 1871 1872 bool bField = false; 1873 //read the character at the current position to check if it's a field 1874 xub_Unicode cChar = pTxtNode->GetTxt().GetChar( pCrsr->GetMark()->nContent.GetIndex() ); 1875 if( CH_TXTATR_BREAKWORD == cChar || CH_TXTATR_INWORD == cChar) 1876 { 1877 const SwTxtAttr* pTxtAttr = pTxtNode->GetTxtAttrForCharAt( 1878 pCrsr->GetMark()->nContent.GetIndex() ); 1879 const sal_uInt16 nWhich = pTxtAttr 1880 ? pTxtAttr->Which() 1881 : static_cast<sal_uInt16>(RES_TXTATR_END); 1882 switch (nWhich) 1883 { 1884 case RES_TXTATR_FIELD: 1885 case RES_TXTATR_FTN: 1886 case RES_TXTATR_FLYCNT: 1887 bField = true; 1888 break; 1889 } 1890 } 1891 1892 LanguageType eCurLanguage = lcl_GetLanguage(*GetSh()); 1893 bool bRedline = aNextRedline.nLeft == pCrsr->GetPoint()->nContent.GetIndex(); 1894 // create a portion if the next character 1895 // - is a field, 1896 // - is at the beginning of a deleted redline 1897 // - has a different language 1898 if(bField || bRedline || eCurLanguage != eStartLanguage) 1899 { 1900 eStartLanguage = eCurLanguage; 1901 //go one step back - the cursor currently selects the first character 1902 //with a different language 1903 //in the case of redlining it's different 1904 if(eCurLanguage != eStartLanguage || bField) 1905 *pCrsr->GetPoint() = *pCrsr->GetMark(); 1906 //set to the last start 1907 *pCrsr->GetMark() = aStart; 1908 //create portion should only be called if a selection exists 1909 //there's no selection if there's a field at the beginning 1910 if(*pCrsr->Start() != *pCrsr->End()) 1911 CreatePortion(xAlt, pGrammarResult, false, false); 1912 aStart = *pCrsr->End(); 1913 //now export the field - if there is any 1914 if(bField) 1915 { 1916 *pCrsr->GetMark() = *pCrsr->GetPoint(); 1917 GetSh()->Right(1, CRSR_SKIP_CELLS); 1918 CreatePortion(xAlt, pGrammarResult, true, false); 1919 aStart = *pCrsr->End(); 1920 } 1921 } 1922 // if a redline start then create a portion for it 1923 if(bRedline) 1924 { 1925 *pCrsr->GetMark() = *pCrsr->GetPoint(); 1926 //select until the end of the current redline 1927 xub_StrLen nEnd = aEnd.nContent.GetIndex() < aNextRedline.nRight ? 1928 aEnd.nContent.GetIndex() : aNextRedline.nRight; 1929 pCrsr->GetPoint()->nContent.Assign( pTxtNode, nEnd ); 1930 CreatePortion(xAlt, pGrammarResult, false, true); 1931 aStart = *pCrsr->End(); 1932 //search for next redline 1933 aNextRedline = lcl_FindNextDeletedRedline( 1934 rDeletedRedlines, aStart.nContent.GetIndex() ); 1935 } 1936 *pCrsr->GetMark() = *pCrsr->GetPoint(); 1937 } 1938 pCrsr->SetMark(); 1939 *pCrsr->GetMark() = aStart; 1940 CreatePortion(xAlt, pGrammarResult, false, false); 1941 } 1942 } 1943 } 1944 /*-- 07.08.2008 15:01:25--------------------------------------------------- 1945 1946 -----------------------------------------------------------------------*/ 1947 void SwEditShell::IgnoreGrammarErrorAt( SwPaM& rErrorPosition ) 1948 { 1949 SwTxtNode *pNode; 1950 SwWrongList *pWrong; 1951 SwNodeIndex aIdx = rErrorPosition.Start()->nNode; 1952 SwNodeIndex aEndIdx = rErrorPosition.Start()->nNode; 1953 xub_StrLen nStart = rErrorPosition.Start()->nContent.GetIndex(); 1954 xub_StrLen nEnd = STRING_LEN; 1955 while( aIdx <= aEndIdx ) 1956 { 1957 pNode = aIdx.GetNode().GetTxtNode(); 1958 if( pNode ) { 1959 if( aIdx == aEndIdx ) 1960 nEnd = rErrorPosition.End()->nContent.GetIndex(); 1961 pWrong = pNode->GetGrammarCheck(); 1962 if( pWrong ) 1963 pWrong->RemoveEntry( nStart, nEnd ); 1964 pWrong = pNode->GetWrong(); 1965 if( pWrong ) 1966 pWrong->RemoveEntry( nStart, nEnd ); 1967 SwTxtFrm::repaintTextFrames( *pNode ); 1968 } 1969 ++aIdx; 1970 nStart = 0; 1971 } 1972 } 1973 1974 1975