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