merge the formfield patch from ooo-build
[ooovba.git] / sw / source / core / edit / edlingu.cxx
blobc10370979a6f1641b504e63671d6ffa6de30ef05
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: edlingu.cxx,v $
10 * $Revision: 1.31 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_sw.hxx"
34 #include <com/sun/star/linguistic2/ProofreadingResult.hpp>
35 #include <com/sun/star/linguistic2/XProofreader.hpp>
36 #include <com/sun/star/linguistic2/XProofreadingIterator.hpp>
37 #include <com/sun/star/text/XFlatParagraph.hpp>
39 #include <unoflatpara.hxx>
41 #ifndef _COMCORE_HRC
42 #include <comcore.hrc>
43 #endif
44 #include <hintids.hxx>
45 #include <linguistic/lngprops.hxx>
46 #include <vcl/msgbox.hxx>
47 #include <svx/unolingu.hxx>
48 #include <svx/svxacorr.hxx>
49 #include <svx/langitem.hxx>
50 #include <svx/SpellPortions.hxx>
51 #include <svx/scripttypeitem.hxx>
52 #include <charatr.hxx>
53 #include <editsh.hxx>
54 #include <doc.hxx>
55 #include <rootfrm.hxx> // SwRootFrm
56 #include <pam.hxx>
57 #include <swundo.hxx> // fuer die UndoIds
58 #include <ndtxt.hxx> // AdjHyphPos
59 #include <viewopt.hxx> // HyphStart/End
60 #include <viscrs.hxx> // SwShellCrsr
61 #include <SwGrammarMarkUp.hxx> // SwWrongList
62 #include <mdiexp.hxx> // Statusanzeige
63 #ifndef _STATSTR_HRC
64 #include <statstr.hrc> // StatLine-String
65 #endif
66 #include <cntfrm.hxx>
67 #include <crsskip.hxx>
68 #include <splargs.hxx>
69 #include <redline.hxx> // SwRedline
70 #include <docary.hxx> // SwRedlineTbl
71 #include <docsh.hxx>
72 #include <txatbase.hxx>
75 using namespace ::svx;
76 using namespace ::com::sun::star;
77 using namespace ::com::sun::star::uno;
78 using namespace ::com::sun::star::beans;
79 using namespace ::com::sun::star::linguistic2;
81 #define C2U(cChar) rtl::OUString::createFromAscii(cChar)
83 extern void repaintTextFrames( SwModify& rModify );
85 /*************************************************************************
86 * class SwLinguIter
87 *************************************************************************/
89 class SwLinguIter
91 SwEditShell *pSh;
92 SwPosition *pStart;
93 SwPosition *pEnd;
94 SwPosition *pCurr;
95 SwPosition *pCurrX;
96 sal_uInt16 nCrsrCnt;
97 public:
98 SwLinguIter();
100 inline SwEditShell *GetSh() { return pSh; }
101 inline const SwEditShell *GetSh() const { return pSh; }
103 inline const SwPosition *GetEnd() const { return pEnd; }
104 inline void SetEnd( SwPosition* pNew ){ delete pEnd; pEnd = pNew; }
106 inline const SwPosition *GetStart() const { return pStart; }
107 inline void SetStart( SwPosition* pNew ){ delete pStart; pStart = pNew; }
109 inline const SwPosition *GetCurr() const { return pCurr; }
110 inline void SetCurr( SwPosition* pNew ){ delete pCurr; pCurr = pNew; }
112 inline const SwPosition *GetCurrX() const { return pCurrX; }
113 inline void SetCurrX( SwPosition* pNew ){ delete pCurrX; pCurrX = pNew; }
115 inline sal_uInt16& GetCrsrCnt(){ return nCrsrCnt; }
117 // Der UI-Bauchladen:
118 void _Start( SwEditShell *pSh, SwDocPositions eStart,
119 SwDocPositions eEnd );
120 void _End(bool bRestoreSelection = true);
123 /*************************************************************************
124 * class SwSpellIter
125 *************************************************************************/
127 // #i18881# to be able to identify the postions of the changed words
128 // the content positions of each portion need to be saved
129 struct SpellContentPosition
131 USHORT nLeft;
132 USHORT nRight;
134 typedef std::vector<SpellContentPosition> SpellContentPositions;
135 class SwSpellIter : public SwLinguIter
137 uno::Reference< XSpellChecker1 > xSpeller;
138 ::svx::SpellPortions aLastPortions;
140 SpellContentPositions aLastPositions;
141 bool bBackToStartOfSentence;
144 void CreatePortion(uno::Reference< XSpellAlternatives > xAlt,
145 linguistic2::ProofreadingResult* pGrammarResult,
146 bool bIsField, bool bIsHidden);
148 void AddPortion(uno::Reference< XSpellAlternatives > xAlt,
149 linguistic2::ProofreadingResult* pGrammarResult,
150 const SpellContentPositions& rDeletedRedlines);
151 public:
152 SwSpellIter() :
153 bBackToStartOfSentence(false) {}
155 void Start( SwEditShell *pSh, SwDocPositions eStart, SwDocPositions eEnd );
157 uno::Any Continue( sal_uInt16* pPageCnt, sal_uInt16* pPageSt );
159 bool SpellSentence(::svx::SpellPortions& rPortions, bool bIsGrammarCheck);
160 void ToSentenceStart();
161 const ::svx::SpellPortions GetLastPortions(){ return aLastPortions;}
162 SpellContentPositions GetLastPositions() {return aLastPositions;}
165 /*************************************************************************
166 * class SwConvIter
167 * used for text conversion
168 *************************************************************************/
170 class SwConvIter : public SwLinguIter
172 SwConversionArgs &rArgs;
173 public:
174 SwConvIter( SwConversionArgs &rConvArgs ) :
175 rArgs( rConvArgs )
178 void Start( SwEditShell *pSh, SwDocPositions eStart, SwDocPositions eEnd );
180 uno::Any Continue( sal_uInt16* pPageCnt, sal_uInt16* pPageSt );
183 /*************************************************************************
184 * class SwHyphIter
185 *************************************************************************/
187 class SwHyphIter : public SwLinguIter
189 sal_Bool bOldIdle;
190 void DelSoftHyph( SwPaM &rPam );
192 public:
193 SwHyphIter() : bOldIdle(sal_False) {}
195 void Start( SwEditShell *pSh, SwDocPositions eStart, SwDocPositions eEnd );
196 void End();
198 void Ignore();
200 uno::Any Continue( sal_uInt16* pPageCnt, sal_uInt16* pPageSt );
202 sal_Bool IsAuto();
203 void InsertSoftHyph( const xub_StrLen nHyphPos );
204 void ShowSelection();
207 static SwSpellIter* pSpellIter = 0;
208 static SwConvIter* pConvIter = 0;
209 static SwHyphIter* pHyphIter = 0;
211 // Wir ersparen uns in Hyphenate ein GetFrm()
212 // Achtung: in txtedt.cxx stehen extern-Deklarationen auf diese Pointer!
213 const SwTxtNode *pLinguNode;
214 SwTxtFrm *pLinguFrm;
216 /*************************************************************************
217 * SwLinguIter::SwLinguIter
218 *************************************************************************/
220 SwLinguIter::SwLinguIter()
221 : pSh( 0 ), pStart( 0 ), pEnd( 0 ), pCurr( 0 ), pCurrX( 0 )
223 // @@@ es fehlt: Sicherstellen der Reentrance, ASSERTs etc.
226 /*************************************************************************
227 * SwLinguIter::Start
228 *************************************************************************/
232 void SwLinguIter::_Start( SwEditShell *pShell, SwDocPositions eStart,
233 SwDocPositions eEnd )
235 // es fehlt: Sicherstellen der Reentrance, Locking
236 if( pSh )
237 return;
239 sal_Bool bSetCurr;
241 pSh = pShell;
243 SET_CURR_SHELL( pSh );
245 ASSERT( !pEnd, "LinguStart ohne End?");
247 SwPaM *pCrsr = pSh->GetCrsr();
249 // pStk->SetCurCrsr();
250 // if( pCrsr->HasMark() || pCrsr != pCrsr->GetNext() )
251 if( pShell->HasSelection() || pCrsr != pCrsr->GetNext() )
253 bSetCurr = 0 != GetCurr();
254 nCrsrCnt = pSh->GetCrsrCnt();
255 if( pSh->IsTableMode() )
256 pSh->TblCrsrToCursor();
258 pSh->Push();
259 sal_uInt16 n;
260 for( n = 0; n < nCrsrCnt; ++n )
262 pSh->Push();
263 pSh->DestroyCrsr();
265 pSh->Pop( sal_False );
267 else
269 bSetCurr = sal_False;
270 nCrsrCnt = 1;
271 pSh->Push();
272 pSh->SetLinguRange( eStart, eEnd );
275 pCrsr = pSh->GetCrsr();
276 if ( *pCrsr->GetPoint() > *pCrsr->GetMark() )
277 pCrsr->Exchange();
279 pStart = new SwPosition( *pCrsr->GetPoint() );
280 pEnd = new SwPosition( *pCrsr->GetMark() );
281 if( bSetCurr )
283 SwPosition* pNew = new SwPosition( *GetStart() );
284 SetCurr( pNew );
285 pNew = new SwPosition( *pNew );
286 SetCurrX( pNew );
289 pCrsr->SetMark();
291 pLinguFrm = 0;
292 pLinguNode = 0;
295 /*************************************************************************
296 * SwLinguIter::End
297 *************************************************************************/
301 void SwLinguIter::_End(bool bRestoreSelection)
303 if( !pSh )
304 return;
306 ASSERT( pEnd, "SwEditShell::SpellEnd() ohne Start?");
307 if(bRestoreSelection)
309 while( nCrsrCnt-- )
310 pSh->Pop( sal_False );
312 pSh->KillPams();
313 pSh->ClearMark();
315 DELETEZ(pStart);
316 DELETEZ(pEnd);
317 DELETEZ(pCurr);
318 DELETEZ(pCurrX);
320 pSh = 0;
322 #ifdef LINGU_STATISTIK
323 aSwLinguStat.Flush();
324 #endif
327 /*************************************************************************
328 * virtual SwSpellIter::Start()
329 *************************************************************************/
333 void SwSpellIter::Start( SwEditShell *pShell, SwDocPositions eStart,
334 SwDocPositions eEnd )
336 if( GetSh() )
337 return;
339 uno::Reference< beans::XPropertySet > xProp( ::GetLinguPropertySet() );
340 xSpeller = ::GetSpellChecker();
341 if ( xSpeller.is() )
342 _Start( pShell, eStart, eEnd );
343 aLastPortions.clear();
344 aLastPositions.clear();
347 /*************************************************************************
348 * SwSpellIter::Continue
349 *************************************************************************/
351 // SwSpellIter::Continue ist das alte Original von
352 // SwEditShell::SpellContinue()
354 uno::Any SwSpellIter::Continue( sal_uInt16* pPageCnt, sal_uInt16* pPageSt )
356 //!!
357 //!! Please check SwConvIter also when modifying this
358 //!!
360 uno::Any aSpellRet;
361 SwEditShell *pMySh = GetSh();
362 if( !pMySh )
363 return aSpellRet;
365 // const SwPosition *pEnd = GetEnd();
367 ASSERT( GetEnd(), "SwEditShell::SpellContinue() ohne Start?");
369 uno::Reference< uno::XInterface > xSpellRet;
370 sal_Bool bGoOn = sal_True;
371 do {
372 SwPaM *pCrsr = pMySh->GetCrsr();
373 if ( !pCrsr->HasMark() )
374 pCrsr->SetMark();
376 uno::Reference< beans::XPropertySet > xProp( GetLinguPropertySet() );
377 *pMySh->GetCrsr()->GetPoint() = *GetCurr();
378 *pMySh->GetCrsr()->GetMark() = *GetEnd();
379 pMySh->GetDoc()->Spell(*pMySh->GetCrsr(),
380 xSpeller, pPageCnt, pPageSt, false ) >>= xSpellRet;
381 bGoOn = GetCrsrCnt() > 1;
382 if( xSpellRet.is() )
384 bGoOn = sal_False;
385 SwPosition* pNewPoint = new SwPosition( *pCrsr->GetPoint() );
386 SwPosition* pNewMark = new SwPosition( *pCrsr->GetMark() );
387 SetCurr( pNewPoint );
388 SetCurrX( pNewMark );
390 if( bGoOn )
392 pMySh->Pop( sal_False );
393 pCrsr = pMySh->GetCrsr();
394 if ( *pCrsr->GetPoint() > *pCrsr->GetMark() )
395 pCrsr->Exchange();
396 SwPosition* pNew = new SwPosition( *pCrsr->GetPoint() );
397 SetStart( pNew );
398 pNew = new SwPosition( *pCrsr->GetMark() );
399 SetEnd( pNew );
400 pNew = new SwPosition( *GetStart() );
401 SetCurr( pNew );
402 pNew = new SwPosition( *pNew );
403 SetCurrX( pNew );
404 pCrsr->SetMark();
405 --GetCrsrCnt();
407 }while ( bGoOn );
408 aSpellRet <<= xSpellRet;
409 return aSpellRet;
412 /*************************************************************************
413 * virtual SwConvIter::Start()
414 *************************************************************************/
418 void SwConvIter::Start( SwEditShell *pShell, SwDocPositions eStart,
419 SwDocPositions eEnd )
421 if( GetSh() )
422 return;
423 _Start( pShell, eStart, eEnd );
426 /*************************************************************************
427 * SwConvIter::Continue
428 *************************************************************************/
430 uno::Any SwConvIter::Continue( sal_uInt16* pPageCnt, sal_uInt16* pPageSt )
432 //!!
433 //!! Please check SwSpellIter also when modifying this
434 //!!
436 uno::Any aConvRet( makeAny( rtl::OUString() ) );
437 SwEditShell *pMySh = GetSh();
438 if( !pMySh )
439 return aConvRet;
441 // const SwPosition *pEnd = GetEnd();
443 ASSERT( GetEnd(), "SwConvIter::Continue() ohne Start?");
445 rtl::OUString aConvText;
446 sal_Bool bGoOn = sal_True;
447 do {
448 SwPaM *pCrsr = pMySh->GetCrsr();
449 if ( !pCrsr->HasMark() )
450 pCrsr->SetMark();
452 *pMySh->GetCrsr()->GetPoint() = *GetCurr();
453 *pMySh->GetCrsr()->GetMark() = *GetEnd();
455 // call function to find next text portion to be converted
456 uno::Reference< linguistic2::XSpellChecker1 > xEmpty;
457 pMySh->GetDoc()->Spell( *pMySh->GetCrsr(),
458 xEmpty, pPageCnt, pPageSt, false, &rArgs ) >>= aConvText;
460 bGoOn = GetCrsrCnt() > 1;
461 if( aConvText.getLength() )
463 bGoOn = sal_False;
464 SwPosition* pNewPoint = new SwPosition( *pCrsr->GetPoint() );
465 SwPosition* pNewMark = new SwPosition( *pCrsr->GetMark() );
467 SetCurr( pNewPoint );
468 SetCurrX( pNewMark );
470 if( bGoOn )
472 pMySh->Pop( sal_False );
473 pCrsr = pMySh->GetCrsr();
474 if ( *pCrsr->GetPoint() > *pCrsr->GetMark() )
475 pCrsr->Exchange();
476 SwPosition* pNew = new SwPosition( *pCrsr->GetPoint() );
477 SetStart( pNew );
478 pNew = new SwPosition( *pCrsr->GetMark() );
479 SetEnd( pNew );
480 pNew = new SwPosition( *GetStart() );
481 SetCurr( pNew );
482 pNew = new SwPosition( *pNew );
483 SetCurrX( pNew );
484 pCrsr->SetMark();
485 --GetCrsrCnt();
487 }while ( bGoOn );
488 return makeAny( aConvText );
492 /*************************************************************************
493 * SwHyphIter
494 *************************************************************************/
497 sal_Bool SwHyphIter::IsAuto()
499 uno::Reference< beans::XPropertySet > xProp( ::GetLinguPropertySet() );
500 return xProp.is() ? *(sal_Bool*)xProp->getPropertyValue(
501 C2U(UPN_IS_HYPH_AUTO) ).getValue()
502 : sal_False;
506 void SwHyphIter::ShowSelection()
508 SwEditShell *pMySh = GetSh();
509 if( pMySh )
511 pMySh->StartAction();
512 // Ganz fatal: durch das EndAction() werden Formatierungen
513 // angeregt, die dazu fuehren koennen, dass im Hyphenator
514 // neue Worte eingestellt werden. Deswegen sichern!
515 pMySh->EndAction();
519 /*************************************************************************
520 * virtual SwHyphIter::Start()
521 *************************************************************************/
525 void SwHyphIter::Start( SwEditShell *pShell, SwDocPositions eStart, SwDocPositions eEnd )
527 // robust
528 if( GetSh() || GetEnd() )
530 ASSERT( !GetSh(), "+SwEditShell::HyphStart: missing HyphEnd()" );
531 return;
534 // nothing to be done (at least not in the way as in the "else" part)
535 bOldIdle = pShell->GetViewOptions()->IsIdle();
536 ((SwViewOption*)pShell->GetViewOptions())->SetIdle( sal_False );
537 _Start( pShell, eStart, eEnd );
540 /*************************************************************************
541 * virtual SwHyphIter::End
542 *************************************************************************/
544 // Selektionen wiederherstellen
548 void SwHyphIter::End()
550 if( !GetSh() )
551 return;
552 ((SwViewOption*)GetSh()->GetViewOptions())->SetIdle( bOldIdle );
553 _End();
556 /*************************************************************************
557 * SwHyphIter::Continue
558 *************************************************************************/
560 uno::Any SwHyphIter::Continue( sal_uInt16* pPageCnt, sal_uInt16* pPageSt )
562 uno::Any aHyphRet;
563 SwEditShell *pMySh = GetSh();
564 if( !pMySh )
565 return aHyphRet;
567 const sal_Bool bAuto = IsAuto();
568 uno::Reference< XHyphenatedWord > xHyphWord;
569 sal_uInt16 nRet;
570 sal_Bool bGoOn = sal_False;
571 do {
572 SwPaM *pCrsr;
573 do {
574 ASSERT( GetEnd(), "SwEditShell::SpellContinue() ohne Start?" );
575 pCrsr = pMySh->GetCrsr();
576 if ( !pCrsr->HasMark() )
577 pCrsr->SetMark();
578 if ( *pCrsr->GetPoint() < *pCrsr->GetMark() )
580 pCrsr->Exchange();
581 pCrsr->SetMark();
584 // geraten BUG:
585 if ( *pCrsr->End() > *GetEnd() )
586 nRet = 0;
587 else
589 *pCrsr->GetMark() = *GetEnd();
591 // Muss an der aktuellen Cursorpos das Wort getrennt werden ?
592 const Point aCrsrPos( pMySh->GetCharRect().Pos() );
593 xHyphWord = pMySh->GetDoc()->Hyphenate( pCrsr, aCrsrPos,
594 pPageCnt, pPageSt );
597 if( bAuto && xHyphWord.is() )
599 pMySh->InsertSoftHyph( xHyphWord->getHyphenationPos() + 1);
601 } while( bAuto && xHyphWord.is() ); //end of do-while
602 bGoOn = !xHyphWord.is() && GetCrsrCnt() > 1;
604 if( bGoOn )
606 pMySh->Pop( sal_False );
607 pCrsr = pMySh->GetCrsr();
608 if ( *pCrsr->GetPoint() > *pCrsr->GetMark() )
609 pCrsr->Exchange();
610 SwPosition* pNew = new SwPosition(*pCrsr->End());
611 SetEnd( pNew );
612 pCrsr->SetMark();
613 --GetCrsrCnt();
615 } while ( bGoOn );
616 aHyphRet <<= xHyphWord;
617 return aHyphRet;
620 /*************************************************************************
621 * SwHyphIter::HyphIgnore
622 *************************************************************************/
624 // Beschreibung: Trennstelle ignorieren
626 void SwHyphIter::Ignore()
628 SwEditShell *pMySh = GetSh();
629 SwPaM *pCrsr = pMySh->GetCrsr();
631 // Alten SoftHyphen loeschen
632 DelSoftHyph( *pCrsr );
634 // und weiter
635 pCrsr->Start()->nContent = pCrsr->End()->nContent;
636 pCrsr->SetMark();
639 /*************************************************************************
640 * SwHyphIter::DelSoftHyph
641 *************************************************************************/
643 void SwHyphIter::DelSoftHyph( SwPaM &rPam )
645 const SwPosition* pStt = rPam.Start();
646 const xub_StrLen nStart = pStt->nContent.GetIndex();
647 const xub_StrLen nEnd = rPam.End()->nContent.GetIndex();
648 SwTxtNode *pNode = pStt->nNode.GetNode().GetTxtNode();
649 pNode->DelSoftHyph( nStart, nEnd );
652 /*************************************************************************
653 * SwHyphIter::InsertSoftHyph
654 *************************************************************************/
657 void SwHyphIter::InsertSoftHyph( const xub_StrLen nHyphPos )
659 SwEditShell *pMySh = GetSh();
660 ASSERT( pMySh, "+SwEditShell::InsertSoftHyph: missing HyphStart()");
661 if( !pMySh )
662 return;
664 SwPaM *pCrsr = pMySh->GetCrsr();
665 SwPosition* pSttPos = pCrsr->Start();
666 SwPosition* pEndPos = pCrsr->End();
668 xub_StrLen nLastHyphLen = GetEnd()->nContent.GetIndex() -
669 pSttPos->nContent.GetIndex();
671 if( pSttPos->nNode != pEndPos->nNode || !nLastHyphLen )
673 ASSERT( pSttPos->nNode == pEndPos->nNode,
674 "+SwEditShell::InsertSoftHyph: node warp during hyphenation" );
675 ASSERT(nLastHyphLen, "+SwEditShell::InsertSoftHyph: missing HyphContinue()");
676 *pSttPos = *pEndPos;
677 return;
680 pMySh->StartAction();
682 SwDoc *pDoc = pMySh->GetDoc();
683 DelSoftHyph( *pCrsr );
684 pSttPos->nContent += nHyphPos;
685 SwPaM aRg( *pSttPos );
686 pDoc->InsertString( aRg, CHAR_SOFTHYPHEN );
687 // Durch das Einfuegen des SoftHyphs ist ein Zeichen hinzugekommen
688 //JP 18.07.95: warum, ist doch ein SwIndex, dieser wird doch mitverschoben !!
689 // pSttPos->nContent++;
691 // Die Selektion wird wieder aufgehoben
692 pCrsr->DeleteMark();
693 pMySh->EndAction();
694 pCrsr->SetMark();
697 // --------------------- Methoden der SwEditShell ------------------------
699 /*************************************************************************
700 * SwEditShell::HasConvIter
701 *************************************************************************/
703 BOOL SwEditShell::HasConvIter() const
705 return 0 != pConvIter;
708 /*************************************************************************
709 * SwEditShell::HasHyphIter
710 *************************************************************************/
712 BOOL SwEditShell::HasHyphIter() const
714 return 0 != pHyphIter;
717 /*************************************************************************
718 * SwEditShell::SetFindRange
719 *************************************************************************/
721 void SwEditShell::SetLinguRange( SwDocPositions eStart, SwDocPositions eEnd )
723 SwPaM *pCrsr = GetCrsr();
724 MakeFindRange( static_cast<USHORT>(eStart), static_cast<USHORT>(eEnd), pCrsr );
725 if( *pCrsr->GetPoint() > *pCrsr->GetMark() )
726 pCrsr->Exchange();
729 /*************************************************************************
730 * SwEditShell::SpellStart
731 *************************************************************************/
733 void SwEditShell::SpellStart(
734 SwDocPositions eStart, SwDocPositions eEnd, SwDocPositions eCurr,
735 SwConversionArgs *pConvArgs )
737 SwLinguIter *pLinguIter = 0;
739 // do not spell if interactive spelling is active elsewhere
740 if (!pConvArgs && !pSpellIter)
742 ASSERT( !pSpellIter, "wer ist da schon am spellen?" );
743 pSpellIter = new SwSpellIter;
744 pLinguIter = pSpellIter;
746 // do not do text conversion if it is active elsewhere
747 if (pConvArgs && !pConvIter)
749 ASSERT( !pConvIter, "text conversion already active!" );
750 pConvIter = new SwConvIter( *pConvArgs );
751 pLinguIter = pConvIter;
754 if (pLinguIter)
756 SwCursor* pSwCrsr = GetSwCrsr();
758 SwPosition *pTmp = new SwPosition( *pSwCrsr->GetPoint() );
759 pSwCrsr->FillFindPos( eCurr, *pTmp );
760 pLinguIter->SetCurr( pTmp );
762 pTmp = new SwPosition( *pTmp );
763 pLinguIter->SetCurrX( pTmp );
766 if (!pConvArgs && pSpellIter)
767 pSpellIter->Start( this, eStart, eEnd );
768 if (pConvArgs && pConvIter)
769 pConvIter->Start( this, eStart, eEnd );
772 /*************************************************************************
773 * SwEditShell::SpellEnd
774 *************************************************************************/
776 void SwEditShell::SpellEnd( SwConversionArgs *pConvArgs, bool bRestoreSelection )
778 if (!pConvArgs && pSpellIter && pSpellIter->GetSh() == this)
780 ASSERT( pSpellIter, "wo ist mein Iterator?" );
781 pSpellIter->_End(bRestoreSelection);
782 delete pSpellIter, pSpellIter = 0;
784 if (pConvArgs && pConvIter && pConvIter->GetSh() == this)
786 ASSERT( pConvIter, "wo ist mein Iterator?" );
787 pConvIter->_End();
788 delete pConvIter, pConvIter = 0;
792 /*************************************************************************
793 * SwEditShell::SpellContinue
794 *************************************************************************/
796 // liefert Rueckgabewerte entsprechend SPL_ in splchk.hxx
798 uno::Any SwEditShell::SpellContinue(
799 sal_uInt16* pPageCnt, sal_uInt16* pPageSt,
800 SwConversionArgs *pConvArgs )
802 uno::Any aRes;
804 if ((!pConvArgs && pSpellIter->GetSh() != this) ||
805 ( pConvArgs && pConvIter->GetSh() != this))
806 return aRes;
808 if( pPageCnt && !*pPageCnt )
810 sal_uInt16 nEndPage = GetLayout()->GetPageNum();
811 nEndPage += nEndPage * 10 / 100;
812 *pPageCnt = nEndPage;
813 if( nEndPage )
814 ::StartProgress( STR_STATSTR_SPELL, 0, nEndPage, GetDoc()->GetDocShell() );
817 ASSERT( pConvArgs || pSpellIter, "SpellIter missing" );
818 ASSERT( !pConvArgs || pConvIter, "ConvIter missing" );
819 //JP 18.07.95: verhinder bei Fehlermeldungen die Anzeige der Selektionen
820 // KEIN StartAction, da damit auch die Paints abgeschaltet
821 // werden !!!!!
822 ++nStartAction;
823 rtl::OUString aRet;
824 uno::Reference< uno::XInterface > xRet;
825 if (pConvArgs)
827 pConvIter->Continue( pPageCnt, pPageSt ) >>= aRet;
828 aRes <<= aRet;
830 else
832 pSpellIter->Continue( pPageCnt, pPageSt ) >>= xRet;
833 aRes <<= xRet;
835 --nStartAction;
837 if( aRet.getLength() || xRet.is() )
839 // dann die awt::Selection sichtbar machen
840 StartAction();
841 EndAction();
843 return aRes;
845 /*************************************************************************
846 * SwEditShell::HyphStart
847 *************************************************************************/
849 /* Interaktive Trennung, BP 10.03.93
851 * 1) HyphStart
852 * - Aufheben aller Selektionen
853 * - Sichern des aktuellen Cursors
854 * - falls keine Selektion vorhanden:
855 * - neue Selektion bis zum Dokumentende
856 * 2) HyphContinue
857 * - nLastHyphLen wird auf den Selektionsstart addiert
858 * - iteriert ueber alle selektierten Bereiche
859 * - pDoc->Hyphenate() iteriert ueber alle Nodes der Selektion
860 * - pTxtNode->Hyphenate() ruft das SwTxtFrm::Hyphenate zur EditShell
861 * - SwTxtFrm:Hyphenate() iteriert ueber die Zeilen des Pams
862 * - LineIter::Hyphenate() stellt den Hyphenator
863 * und den Pam auf das zu trennende Wort ein.
864 * - Es gibt nur zwei Returnwerte sal_True, wenn eine Trennstelle anliegt
865 * und sal_False, wenn der Pam abgearbeitet wurde.
866 * - Bei sal_True wird das selektierte Wort zur Anzeige gebracht und
867 * nLastHyphLen gesetzt.
868 * - Bei sal_False wird die aktuelle Selektion geloescht und die naechste
869 * zur aktuellen gewaehlt. Return HYPH_OK, wenn keine mehr vorhanden.
870 * 3) InsertSoftHyph (wird ggf. von der UI gerufen)
871 * - Der aktuelle Cursor wird plaziert und das Attribut eingefuegt.
872 * 4) HyphEnd
873 * - Wiederherstellen des alten Cursors, EndAction
878 void SwEditShell::HyphStart( SwDocPositions eStart, SwDocPositions eEnd )
880 // do not hyphenate if interactive hyphenationg is active elsewhere
881 if (!pHyphIter)
883 ASSERT( !pHyphIter, "wer ist da schon am hyphinieren?" );
884 pHyphIter = new SwHyphIter;
885 pHyphIter->Start( this, eStart, eEnd );
889 /*************************************************************************
890 * SwEditShell::HyphEnd
891 *************************************************************************/
893 // Selektionen wiederherstellen
897 void SwEditShell::HyphEnd()
899 if (pHyphIter->GetSh() == this)
901 ASSERT( pHyphIter, "wo ist mein Iterator?" );
902 pHyphIter->End();
903 delete pHyphIter, pHyphIter = 0;
907 /*************************************************************************
908 * SwEditShell::HyphContinue
909 *************************************************************************/
911 // Returnwerte: (BP: ich wuerde es genau umdrehen, aber die UI wuenscht es so)
912 // HYPH_CONTINUE, wenn eine Trennstelle anliegt
913 // HYPH_OK, wenn der selektierte Bereich abgearbeitet wurde.
916 uno::Reference< uno::XInterface >
917 SwEditShell::HyphContinue( sal_uInt16* pPageCnt, sal_uInt16* pPageSt )
919 if (pHyphIter->GetSh() != this)
920 return 0;
922 if( pPageCnt && !*pPageCnt && !*pPageSt )
924 sal_uInt16 nEndPage = GetLayout()->GetPageNum();
925 nEndPage += nEndPage * 10 / 100;
926 if( nEndPage > 14 )
928 *pPageCnt = nEndPage;
929 ::StartProgress( STR_STATSTR_HYPHEN, 0, nEndPage, GetDoc()->GetDocShell());
931 else // Hiermit unterdruecken wir ein fuer allemal
932 *pPageSt = 1; // das StatLineStartPercent
935 ASSERT( pHyphIter, "wo ist mein Iterator?" );
936 //JP 18.07.95: verhinder bei Fehlermeldungen die Anzeige der Selektionen
937 // KEIN StartAction, da damit auch die Paints abgeschaltet
938 // werden !!!!!
939 ++nStartAction;
940 uno::Reference< uno::XInterface > xRet;
941 pHyphIter->Continue( pPageCnt, pPageSt ) >>= xRet;
942 --nStartAction;
944 if( xRet.is() )
945 pHyphIter->ShowSelection();
947 return xRet;
951 /*************************************************************************
952 * SwEditShell::InsertSoftHyph
953 *************************************************************************/
955 // Zum Einfuegen des SoftHyphens, Position ist der Offset
956 // innerhalb des getrennten Wortes.
959 void SwEditShell::InsertSoftHyph( const xub_StrLen nHyphPos )
961 ASSERT( pHyphIter, "wo ist mein Iterator?" );
962 pHyphIter->InsertSoftHyph( nHyphPos );
966 /*************************************************************************
967 * SwEditShell::HyphIgnore
968 *************************************************************************/
970 // Beschreibung: Trennstelle ignorieren
972 void SwEditShell::HyphIgnore()
974 ASSERT( pHyphIter, "wo ist mein Iterator?" );
975 //JP 18.07.95: verhinder bei Fehlermeldungen die Anzeige der Selektionen
976 // KEIN StartAction, da damit auch die Paints abgeschaltet
977 // werden !!!!!
978 ++nStartAction;
979 pHyphIter->Ignore();
980 --nStartAction;
982 pHyphIter->ShowSelection();
985 /*************************************************************************
986 * SwEditShell::GetCorrection()
987 * liefert eine Liste von Vorschlaegen fuer falsch geschriebene Worte,
988 * ein NULL-Pointer signalisiert, dass das Wort richtig geschrieben ist,
989 * eine leere Liste, dass das Wort zwar unbekannt ist, aber keine Alternativen
990 * geliefert werden koennen.
991 *************************************************************************/
994 uno::Reference< XSpellAlternatives >
995 SwEditShell::GetCorrection( const Point* pPt, SwRect& rSelectRect )
997 uno::Reference< XSpellAlternatives > xSpellAlt;
999 if( IsTableMode() )
1000 return NULL;
1001 SwPaM* pCrsr = GetCrsr();
1002 SwPosition aPos( *pCrsr->GetPoint() );
1003 Point aPt( *pPt );
1004 SwCrsrMoveState eTmpState( MV_SETONLYTEXT );
1005 SwTxtNode *pNode;
1006 SwWrongList *pWrong;
1007 if( GetLayout()->GetCrsrOfst( &aPos, aPt, &eTmpState ) &&
1008 0 != (pNode = aPos.nNode.GetNode().GetTxtNode()) &&
1009 0 != (pWrong = pNode->GetWrong()) &&
1010 !pNode->IsInProtectSect() )
1012 xub_StrLen nBegin = aPos.nContent.GetIndex();
1013 xub_StrLen nLen = 1;
1014 if( pWrong->InWrongWord(nBegin,nLen) && !pNode->IsSymbol(nBegin) )
1016 String aText( pNode->GetTxt().Copy( nBegin, nLen ) );
1017 String aWord( aText );
1018 aWord.EraseAllChars( CH_TXTATR_BREAKWORD ).EraseAllChars( CH_TXTATR_INWORD );
1020 uno::Reference< XSpellChecker1 > xSpell( ::GetSpellChecker() );
1021 if( xSpell.is() )
1023 LanguageType eActLang = (LanguageType)pNode->GetLang( nBegin, nLen );
1024 if( xSpell->hasLanguage( eActLang ))
1026 // restrict the maximal number of suggestions displayed
1027 // in the context menu.
1028 // Note: That could of course be done by clipping the
1029 // resulting sequence but the current third party
1030 // implementations result differs greatly if the number of
1031 // suggestions to be retuned gets changed. Statistically
1032 // it gets much better if told to return e.g. only 7 strings
1033 // than returning e.g. 16 suggestions and using only the
1034 // first 7. Thus we hand down the value to use to that
1035 // implementation here by providing an additional parameter.
1036 Sequence< PropertyValue > aPropVals(1);
1037 PropertyValue &rVal = aPropVals.getArray()[0];
1038 rVal.Name = C2U( UPN_MAX_NUMBER_OF_SUGGESTIONS );
1039 rVal.Value <<= (INT16) 7;
1041 xSpellAlt = xSpell->spell( aWord, eActLang, aPropVals );
1045 if ( xSpellAlt.is() ) // error found?
1047 //save the start and end positons of the line and the starting point
1048 Push();
1049 LeftMargin();
1050 xub_StrLen nLineStart = GetCrsr()->GetPoint()->nContent.GetIndex();
1051 RightMargin();
1052 xub_StrLen nLineEnd = GetCrsr()->GetPoint()->nContent.GetIndex();
1053 Pop(FALSE);
1055 // make sure the selection build later from the
1056 // data below does not include footnotes and other
1057 // "in word" character to the left and right in order
1058 // to preserve those. Therefore count those "in words"
1059 // in order to modify the selection accordingly.
1060 const sal_Unicode* pChar = aText.GetBuffer();
1061 xub_StrLen nLeft = 0;
1062 while (pChar && *pChar++ == CH_TXTATR_INWORD)
1063 ++nLeft;
1064 pChar = aText.Len() ? aText.GetBuffer() + aText.Len() - 1 : 0;
1065 xub_StrLen nRight = 0;
1066 while (pChar && *pChar-- == CH_TXTATR_INWORD)
1067 ++nRight;
1069 aPos.nContent = nBegin + nLeft;
1070 pCrsr = GetCrsr();
1071 *pCrsr->GetPoint() = aPos;
1072 pCrsr->SetMark();
1073 ExtendSelection( sal_True, nLen - nLeft - nRight );
1074 //no determine the rectangle in the current line
1075 xub_StrLen nWordStart = (nBegin + nLeft) < nLineStart ? nLineStart : nBegin + nLeft;
1076 //take one less than the line end - otherwise the next line would be calculated
1077 xub_StrLen nWordEnd = (nBegin + nLen - nLeft - nRight) > nLineEnd ? nLineEnd - 1: (nBegin + nLen - nLeft - nRight);
1078 Push();
1079 pCrsr->DeleteMark();
1080 SwIndex& rContent = GetCrsr()->GetPoint()->nContent;
1081 rContent = nWordStart;
1082 SwRect aStartRect;
1083 SwCrsrMoveState aState;
1084 aState.bRealWidth = TRUE;
1085 SwCntntNode* pCntntNode = pCrsr->GetCntntNode();
1086 SwCntntFrm *pCntntFrame = pCntntNode->GetFrm(pPt, pCrsr->GetPoint(), FALSE);
1088 pCntntFrame->GetCharRect( aStartRect, *pCrsr->GetPoint(), &aState );
1089 rContent = nWordEnd;
1090 SwRect aEndRect;
1091 pCntntFrame->GetCharRect( aEndRect, *pCrsr->GetPoint(),&aState );
1092 rSelectRect = aStartRect.Union( aEndRect );
1093 Pop(FALSE);
1097 return xSpellAlt;
1100 /*-------------------------------------------------------------------------
1102 -----------------------------------------------------------------------*/
1104 bool SwEditShell::GetGrammarCorrection(
1105 linguistic2::ProofreadingResult /*out*/ &rResult, // the complete result
1106 sal_Int32 /*out*/ &rErrorPosInText, // offset of error position in string that was grammar checked...
1107 sal_Int32 /*out*/ &rErrorIndexInResult, // index of error in rResult.aGrammarErrors
1108 uno::Sequence< rtl::OUString > /*out*/ &rSuggestions, // suggestions to be used for the error found
1109 const Point *pPt, SwRect &rSelectRect )
1111 bool bRes = false;
1113 if( IsTableMode() )
1114 return bRes;
1116 SwPaM* pCrsr = GetCrsr();
1117 SwPosition aPos( *pCrsr->GetPoint() );
1118 Point aPt( *pPt );
1119 SwCrsrMoveState eTmpState( MV_SETONLYTEXT );
1120 SwTxtNode *pNode;
1121 SwGrammarMarkUp *pWrong;
1122 if( GetLayout()->GetCrsrOfst( &aPos, aPt, &eTmpState ) &&
1123 0 != (pNode = aPos.nNode.GetNode().GetTxtNode()) &&
1124 0 != (pWrong = pNode->GetGrammarCheck()) &&
1125 !pNode->IsInProtectSect() )
1127 xub_StrLen nBegin = aPos.nContent.GetIndex();
1128 xub_StrLen nLen = 1;
1129 if (pWrong->InWrongWord(nBegin, nLen))
1131 String aText( pNode->GetTxt().Copy( nBegin, nLen ) );
1132 String aWord( aText );
1133 aWord.EraseAllChars( CH_TXTATR_BREAKWORD ).EraseAllChars( CH_TXTATR_INWORD );
1135 uno::Reference< linguistic2::XProofreadingIterator > xGCIterator( pDoc->GetGCIterator() );
1136 if (xGCIterator.is())
1138 // LanguageType eActLang = (LanguageType)pNode->GetLang( nBegin, nLen );
1139 uno::Reference< lang::XComponent > xDoc( pDoc->GetDocShell()->GetBaseModel(), uno::UNO_QUERY );
1141 // Expand the string:
1142 rtl::OUString aExpandText;
1143 const ModelToViewHelper::ConversionMap* pConversionMap =
1144 pNode->BuildConversionMap( aExpandText );
1145 // get XFlatParagraph to use...
1146 uno::Reference< text::XFlatParagraph > xFlatPara = new SwXFlatParagraph( *pNode, aExpandText, pConversionMap );
1148 // get error position of cursor in XFlatParagraph
1149 rErrorPosInText = ModelToViewHelper::ConvertToViewPosition( pConversionMap, nBegin );
1151 sal_Int32 nStartOfSentence = ModelToViewHelper::ConvertToViewPosition( pConversionMap, pWrong->getSentenceStart( nBegin ) );
1152 sal_Int32 nEndOfSentence = ModelToViewHelper::ConvertToViewPosition( pConversionMap, pWrong->getSentenceEnd( nBegin ) );
1153 if( nEndOfSentence == STRING_LEN )
1155 /* if( nStartOfSentence == 0 )
1157 nStartOfSentence = -1;
1158 nEndOfSentence = -1;
1160 else */
1161 nEndOfSentence = aExpandText.getLength();
1164 rResult = xGCIterator->checkSentenceAtPosition(
1165 xDoc, xFlatPara, aExpandText, lang::Locale(), nStartOfSentence, nEndOfSentence, rErrorPosInText );
1166 bRes = true;
1168 // get suggestions to use for the specific error position
1169 sal_Int32 nErrors = rResult.aErrors.getLength();
1170 rSuggestions.realloc( 0 );
1171 for (sal_Int32 i = 0; i < nErrors; ++i )
1173 // return suggestions for first error that includes the given error position
1174 const linguistic2::SingleProofreadingError &rError = rResult.aErrors[i];
1175 if (rError.nErrorStart <= rErrorPosInText &&
1176 rErrorPosInText < rError.nErrorStart + rError.nErrorLength)
1178 rSuggestions = rError.aSuggestions;
1179 rErrorIndexInResult = i;
1180 break;
1185 if (rResult.aErrors.getLength() > 0) // error found?
1187 //save the start and end positons of the line and the starting point
1188 Push();
1189 LeftMargin();
1190 xub_StrLen nLineStart = GetCrsr()->GetPoint()->nContent.GetIndex();
1191 RightMargin();
1192 xub_StrLen nLineEnd = GetCrsr()->GetPoint()->nContent.GetIndex();
1193 Pop(FALSE);
1195 #if OSL_DEBUG_LEVEL > 1
1196 // pNode->GetGrammarCheck()->Invalidate( 0, STRING_LEN );
1197 // pNode->SetGrammarCheckDirty( true );
1198 #endif
1199 // make sure the selection build later from the
1200 // data below does not include footnotes and other
1201 // "in word" character to the left and right in order
1202 // to preserve those. Therefore count those "in words"
1203 // in order to modify the selection accordingly.
1204 const sal_Unicode* pChar = aText.GetBuffer();
1205 xub_StrLen nLeft = 0;
1206 while (pChar && *pChar++ == CH_TXTATR_INWORD)
1207 ++nLeft;
1208 pChar = aText.Len() ? aText.GetBuffer() + aText.Len() - 1 : 0;
1209 xub_StrLen nRight = 0;
1210 while (pChar && *pChar-- == CH_TXTATR_INWORD)
1211 ++nRight;
1213 aPos.nContent = nBegin + nLeft;
1214 pCrsr = GetCrsr();
1215 *pCrsr->GetPoint() = aPos;
1216 pCrsr->SetMark();
1217 ExtendSelection( sal_True, nLen - nLeft - nRight );
1218 //no determine the rectangle in the current line
1219 xub_StrLen nWordStart = (nBegin + nLeft) < nLineStart ? nLineStart : nBegin + nLeft;
1220 //take one less than the line end - otherwise the next line would be calculated
1221 xub_StrLen nWordEnd = (nBegin + nLen - nLeft - nRight) > nLineEnd ? nLineEnd - 1: (nBegin + nLen - nLeft - nRight);
1222 Push();
1223 pCrsr->DeleteMark();
1224 SwIndex& rContent = GetCrsr()->GetPoint()->nContent;
1225 rContent = nWordStart;
1226 SwRect aStartRect;
1227 SwCrsrMoveState aState;
1228 aState.bRealWidth = TRUE;
1229 SwCntntNode* pCntntNode = pCrsr->GetCntntNode();
1230 SwCntntFrm *pCntntFrame = pCntntNode->GetFrm(pPt, pCrsr->GetPoint(), FALSE);
1232 pCntntFrame->GetCharRect( aStartRect, *pCrsr->GetPoint(), &aState );
1233 rContent = nWordEnd;
1234 SwRect aEndRect;
1235 pCntntFrame->GetCharRect( aEndRect, *pCrsr->GetPoint(),&aState );
1236 rSelectRect = aStartRect.Union( aEndRect );
1237 Pop(FALSE);
1242 return bRes;
1245 /*-- 18.09.2003 15:08:18---------------------------------------------------
1247 -----------------------------------------------------------------------*/
1248 bool SwEditShell::SpellSentence(::svx::SpellPortions& rPortions, bool bIsGrammarCheck)
1250 ASSERT( pSpellIter, "SpellIter missing" );
1251 if(!pSpellIter)
1252 return false;
1253 bool bRet = pSpellIter->SpellSentence(rPortions, bIsGrammarCheck);
1255 // make Selection visible - this should simply move the
1256 // cursor to the end of the sentence
1257 StartAction();
1258 EndAction();
1259 return bRet;
1261 /*-- 08.09.2008 09:35:19---------------------------------------------------
1262 make SpellIter start with the current sentence when called next time
1263 -----------------------------------------------------------------------*/
1264 void SwEditShell::PutSpellingToSentenceStart()
1266 ASSERT( pSpellIter, "SpellIter missing" );
1267 if(!pSpellIter)
1268 return;
1269 pSpellIter->ToSentenceStart();
1271 /*-- 02.02.2005 14:34:41---------------------------------------------------
1273 -----------------------------------------------------------------------*/
1274 sal_uInt32 lcl_CountRedlines(
1275 const ::svx::SpellPortions& rLastPortions)
1277 sal_uInt32 nRet = 0;
1278 SpellPortions::const_iterator aIter = rLastPortions.begin();
1279 for( ; aIter != rLastPortions.end(); ++aIter)
1281 if( aIter->bIsHidden )
1282 ++nRet;
1284 return nRet;
1286 /*-- 18.09.2003 15:08:20---------------------------------------------------
1288 -----------------------------------------------------------------------*/
1289 void SwEditShell::ApplyChangedSentence(const ::svx::SpellPortions& rNewPortions, bool bIsGrammarCheck)
1291 ASSERT( pSpellIter, "SpellIter missing" );
1292 if(pSpellIter)
1294 const SpellPortions& rLastPortions = pSpellIter->GetLastPortions();
1295 const SpellContentPositions rLastPositions = pSpellIter->GetLastPositions();
1296 ASSERT(rLastPortions.size() > 0 &&
1297 rLastPortions.size() == rLastPositions.size(),
1298 "last vectors of spelling results are not set or not equal")
1300 // iterate over the new portions, beginning at the end to take advantage of the previously
1301 // saved content positions
1303 if(!rLastPortions.size())
1304 return;
1306 SwPaM *pCrsr = GetCrsr();
1307 pDoc->StartUndo( UNDO_OVERWRITE, NULL );
1308 StartAction();
1309 sal_uInt32 nRedlinePortions = lcl_CountRedlines(rLastPortions);
1310 if((rLastPortions.size() - nRedlinePortions) == rNewPortions.size())
1312 //the simple case: the same number of elements on both sides
1313 //each changed element has to be applied to the corresponding source element
1314 svx::SpellPortions::const_iterator aCurrentNewPortion = rNewPortions.end();
1315 SpellPortions::const_iterator aCurrentOldPortion = rLastPortions.end();
1316 SpellContentPositions::const_iterator aCurrentOldPosition = rLastPositions.end();
1319 --aCurrentNewPortion;
1320 --aCurrentOldPortion;
1321 --aCurrentOldPosition;
1322 //jump over redline portions
1323 while(aCurrentOldPortion->bIsHidden)
1325 --aCurrentOldPortion;
1326 --aCurrentOldPosition;
1328 if ( !pCrsr->HasMark() )
1329 pCrsr->SetMark();
1330 pCrsr->GetPoint()->nContent = aCurrentOldPosition->nLeft;
1331 pCrsr->GetMark()->nContent = aCurrentOldPosition->nRight;
1332 USHORT nScriptType = GetI18NScriptTypeOfLanguage( aCurrentNewPortion->eLanguage );
1333 USHORT nLangWhichId = RES_CHRATR_LANGUAGE;
1334 switch(nScriptType)
1336 case SCRIPTTYPE_ASIAN : nLangWhichId = RES_CHRATR_CJK_LANGUAGE; break;
1337 case SCRIPTTYPE_COMPLEX : nLangWhichId = RES_CHRATR_CTL_LANGUAGE; break;
1339 if(aCurrentNewPortion->sText != aCurrentOldPortion->sText)
1341 //change text ...
1342 pDoc->DeleteAndJoin(*pCrsr);
1343 // ... and apply language if necessary
1344 if(aCurrentNewPortion->eLanguage != aCurrentOldPortion->eLanguage)
1345 SetAttr( SvxLanguageItem(aCurrentNewPortion->eLanguage, nLangWhichId), nLangWhichId );
1346 pDoc->InsertString(*pCrsr, aCurrentNewPortion->sText);
1348 else if(aCurrentNewPortion->eLanguage != aCurrentOldPortion->eLanguage)
1350 //apply language
1351 SetAttr( SvxLanguageItem(aCurrentNewPortion->eLanguage, nLangWhichId), nLangWhichId );
1353 else if( aCurrentNewPortion->bIgnoreThisError )
1355 //add the 'ignore' markup to the TextNode's grammar ignore markup list
1356 IgnoreGrammarErrorAt( *pCrsr );
1357 DBG_ERROR("TODO: add ignore mark to text node");
1359 if(aCurrentNewPortion == rNewPortions.begin())
1360 break;
1362 while(aCurrentNewPortion != rNewPortions.begin());
1364 else
1366 //select the complete sentence
1367 SpellContentPositions::const_iterator aCurrentEndPosition = rLastPositions.end();
1368 --aCurrentEndPosition;
1369 SpellContentPositions::const_iterator aCurrentStartPosition = rLastPositions.begin();
1370 pCrsr->GetPoint()->nContent = aCurrentStartPosition->nLeft;
1371 pCrsr->GetMark()->nContent = aCurrentEndPosition->nRight;
1373 //delete the sentence completely
1374 pDoc->DeleteAndJoin(*pCrsr);
1375 svx::SpellPortions::const_iterator aCurrentNewPortion = rNewPortions.begin();
1376 while(aCurrentNewPortion != rNewPortions.end())
1378 //set the language attribute
1379 USHORT nScriptType = GetScriptType();
1380 USHORT nLangWhichId = RES_CHRATR_LANGUAGE;
1381 switch(nScriptType)
1383 case SCRIPTTYPE_ASIAN : nLangWhichId = RES_CHRATR_CJK_LANGUAGE; break;
1384 case SCRIPTTYPE_COMPLEX : nLangWhichId = RES_CHRATR_CTL_LANGUAGE; break;
1386 SfxItemSet aSet(GetAttrPool(), nLangWhichId, nLangWhichId, 0);
1387 GetCurAttr( aSet );
1388 const SvxLanguageItem& rLang = static_cast<const SvxLanguageItem& >(aSet.Get(nLangWhichId));
1389 if(rLang.GetLanguage() != aCurrentNewPortion->eLanguage)
1390 SetAttr( SvxLanguageItem(aCurrentNewPortion->eLanguage, nLangWhichId) );
1391 //insert the new string
1392 pDoc->InsertString(*pCrsr, aCurrentNewPortion->sText);
1394 //set the cursor to the end of the inserted string
1395 *pCrsr->Start() = *pCrsr->End();
1396 ++aCurrentNewPortion;
1400 //set the cursor to the end of the new sentence
1401 *pCrsr->Start() = *pCrsr->End();
1402 if( bIsGrammarCheck)
1404 //in grammar check the current sentence has to be checked again
1405 GoStartSentence();
1407 pDoc->EndUndo( UNDO_OVERWRITE, NULL );
1408 EndAction();
1411 /*-- 02.02.2005 10:46:45---------------------------------------------------
1412 collect all deleted redlines of the current text node beginning at the
1413 start of the cursor position
1414 -----------------------------------------------------------------------*/
1415 SpellContentPositions lcl_CollectDeletedRedlines(SwEditShell* pSh)
1417 SpellContentPositions aRedlines;
1418 SwDoc* pDoc = pSh->GetDoc();
1419 const bool bShowChg = IDocumentRedlineAccess::IsShowChanges( pDoc->GetRedlineMode() );
1420 if ( bShowChg )
1422 SwPaM *pCrsr = pSh->GetCrsr();
1423 const SwPosition* pStartPos = pCrsr->Start();
1424 const SwTxtNode* pTxtNode = pCrsr->GetNode()->GetTxtNode();
1426 USHORT nAct = pDoc->GetRedlinePos( *pTxtNode, USHRT_MAX );
1427 const xub_StrLen nStartIndex = pStartPos->nContent.GetIndex();
1428 for ( ; nAct < pDoc->GetRedlineTbl().Count(); nAct++ )
1430 const SwRedline* pRed = pDoc->GetRedlineTbl()[ nAct ];
1432 if ( pRed->Start()->nNode > pTxtNode->GetIndex() )
1433 break;
1435 if( nsRedlineType_t::REDLINE_DELETE == pRed->GetType() )
1437 xub_StrLen nStart, nEnd;
1438 pRed->CalcStartEnd( pTxtNode->GetIndex(), nStart, nEnd );
1439 if(nStart >= nStartIndex || nEnd >= nStartIndex)
1441 SpellContentPosition aAdd;
1442 aAdd.nLeft = nStart;
1443 aAdd.nRight = nEnd;
1444 aRedlines.push_back(aAdd);
1449 return aRedlines;
1451 /*-- 02.02.2005 11:06:12---------------------------------------------------
1452 remove the redline positions after the current selection
1453 -----------------------------------------------------------------------*/
1454 void lcl_CutRedlines( SpellContentPositions& aDeletedRedlines, SwEditShell* pSh )
1456 if(!aDeletedRedlines.empty())
1458 SwPaM *pCrsr = pSh->GetCrsr();
1459 const SwPosition* pEndPos = pCrsr->End();
1460 xub_StrLen nEnd = pEndPos->nContent.GetIndex();
1461 while(!aDeletedRedlines.empty() &&
1462 aDeletedRedlines.back().nLeft > nEnd)
1464 aDeletedRedlines.pop_back();
1468 /*-- 02.02.2005 11:43:00---------------------------------------------------
1470 -----------------------------------------------------------------------*/
1471 SpellContentPosition lcl_FindNextDeletedRedline(
1472 const SpellContentPositions& rDeletedRedlines,
1473 xub_StrLen nSearchFrom )
1475 SpellContentPosition aRet;
1476 aRet.nLeft = aRet.nRight = STRING_MAXLEN;
1477 if(!rDeletedRedlines.empty())
1479 SpellContentPositions::const_iterator aIter = rDeletedRedlines.begin();
1480 for( ; aIter != rDeletedRedlines.end(); ++aIter)
1482 if(aIter->nLeft < nSearchFrom)
1483 continue;
1484 aRet = *aIter;
1485 break;
1488 return aRet;
1490 /*-- 18.09.2003 15:08:20---------------------------------------------------
1492 -----------------------------------------------------------------------*/
1493 bool SwSpellIter::SpellSentence(::svx::SpellPortions& rPortions, bool bIsGrammarCheck)
1495 bool bRet = false;
1496 aLastPortions.clear();
1497 aLastPositions.clear();
1499 SwEditShell *pMySh = GetSh();
1500 if( !pMySh )
1501 return false;
1503 ASSERT( GetEnd(), "SwEditShell::SpellSentence() ohne Start?");
1505 uno::Reference< XSpellAlternatives > xSpellRet;
1506 linguistic2::ProofreadingResult aGrammarResult;
1507 sal_Bool bGoOn = sal_True;
1508 bool bGrammarErrorFound = false;
1509 do {
1510 SwPaM *pCrsr = pMySh->GetCrsr();
1511 if ( !pCrsr->HasMark() )
1512 pCrsr->SetMark();
1514 *pCrsr->GetPoint() = *GetCurr();
1515 *pCrsr->GetMark() = *GetEnd();
1517 if( bBackToStartOfSentence )
1519 pMySh->GoStartSentence();
1520 bBackToStartOfSentence = false;
1522 uno::Any aSpellRet =
1523 pMySh->GetDoc()->Spell(*pCrsr,
1524 xSpeller, 0, 0, bIsGrammarCheck );
1525 aSpellRet >>= xSpellRet;
1526 aSpellRet >>= aGrammarResult;
1527 bGoOn = GetCrsrCnt() > 1;
1528 bGrammarErrorFound = aGrammarResult.aErrors.getLength() > 0;
1529 if( xSpellRet.is() || bGrammarErrorFound )
1531 bGoOn = sal_False;
1532 SwPosition* pNewPoint = new SwPosition( *pCrsr->GetPoint() );
1533 SwPosition* pNewMark = new SwPosition( *pCrsr->GetMark() );
1535 SetCurr( pNewPoint );
1536 SetCurrX( pNewMark );
1538 if( bGoOn )
1540 pMySh->Pop( sal_False );
1541 pCrsr = pMySh->GetCrsr();
1542 if ( *pCrsr->GetPoint() > *pCrsr->GetMark() )
1543 pCrsr->Exchange();
1544 SwPosition* pNew = new SwPosition( *pCrsr->GetPoint() );
1545 SetStart( pNew );
1546 pNew = new SwPosition( *pCrsr->GetMark() );
1547 SetEnd( pNew );
1548 pNew = new SwPosition( *GetStart() );
1549 SetCurr( pNew );
1550 pNew = new SwPosition( *pNew );
1551 SetCurrX( pNew );
1552 pCrsr->SetMark();
1553 --GetCrsrCnt();
1556 while ( bGoOn );
1557 if(xSpellRet.is() || bGrammarErrorFound)
1559 //an error has been found
1560 //To fill the spell portions the beginning of the sentence has to be found
1561 SwPaM *pCrsr = pMySh->GetCrsr();
1562 //set the mark to the right if necessary
1563 if ( *pCrsr->GetPoint() > *pCrsr->GetMark() )
1564 pCrsr->Exchange();
1565 //the cursor has to be collapsed on the left to go to the start of the sentence - if sentence ends inside of the error
1566 pCrsr->DeleteMark();
1567 pCrsr->SetMark();
1568 BOOL bStartSent = 0 != pMySh->GoStartSentence();
1569 SpellContentPositions aDeletedRedlines = lcl_CollectDeletedRedlines(pMySh);
1570 if(bStartSent)
1572 //create a portion from the start part
1573 AddPortion(0, 0, aDeletedRedlines);
1575 //Set the cursor to the error already found
1576 *pCrsr->GetPoint() = *GetCurrX();
1577 *pCrsr->GetMark() = *GetCurr();
1578 AddPortion(xSpellRet, &aGrammarResult, aDeletedRedlines);
1581 //save the end position of the error to continue from here
1582 SwPosition aSaveStartPos = *pCrsr->End();
1583 //determine the end of the current sentence
1584 if ( *pCrsr->GetPoint() < *pCrsr->GetMark() )
1585 pCrsr->Exchange();
1586 //again collapse to start marking after the end of the error
1587 pCrsr->DeleteMark();
1588 pCrsr->SetMark();
1590 pMySh->GoEndSentence();
1591 if( bGrammarErrorFound )
1593 rtl::OUString aExpandText;
1594 const ModelToViewHelper::ConversionMap* pConversionMap = ((SwTxtNode*)pCrsr->GetNode())->BuildConversionMap( aExpandText );
1595 xub_StrLen nSentenceEnd = (xub_StrLen)ModelToViewHelper::ConvertToViewPosition( pConversionMap, aGrammarResult.nBehindEndOfSentencePosition );
1596 // remove trailing space
1597 if( aExpandText[nSentenceEnd - 1] == ' ' )
1598 --nSentenceEnd;
1599 if( pCrsr->End()->nContent.GetIndex() < nSentenceEnd )
1601 pCrsr->End()->nContent.Assign(
1602 pCrsr->End()->nNode.GetNode().GetCntntNode(), nSentenceEnd);
1606 lcl_CutRedlines( aDeletedRedlines, pMySh );
1607 //save the 'global' end of the spellchecking
1608 const SwPosition aSaveEndPos = *GetEnd();
1609 //set the sentence end as 'local' end
1610 SetEnd( new SwPosition( *pCrsr->End() ));
1612 *pCrsr->GetPoint() = aSaveStartPos;
1613 *pCrsr->GetMark() = *GetEnd();
1614 //now the rest of the sentence has to be searched for errors
1615 // for each error the non-error text between the current and the last error has
1616 // to be added to the portions - if necessary broken into same-language-portions
1617 if( !bGrammarErrorFound ) //in grammar check there's only one error returned
1621 xSpellRet = 0;
1622 // don't search for grammar errors here anymore!
1623 pMySh->GetDoc()->Spell(*pCrsr,
1624 xSpeller, 0, 0, false ) >>= xSpellRet;
1625 if ( *pCrsr->GetPoint() > *pCrsr->GetMark() )
1626 pCrsr->Exchange();
1627 SetCurr( new SwPosition( *pCrsr->GetPoint() ));
1628 SetCurrX( new SwPosition( *pCrsr->GetMark() ));
1630 //if an error has been found go back to the text
1631 //preceeding the error
1632 if(xSpellRet.is())
1634 *pCrsr->GetPoint() = aSaveStartPos;
1635 *pCrsr->GetMark() = *GetCurr();
1637 //add the portion
1638 AddPortion(0, 0, aDeletedRedlines);
1640 if(xSpellRet.is())
1642 *pCrsr->GetPoint() = *GetCurr();
1643 *pCrsr->GetMark() = *GetCurrX();
1644 AddPortion(xSpellRet, 0, aDeletedRedlines);
1645 //move the cursor to the end of the error string
1646 *pCrsr->GetPoint() = *GetCurrX();
1647 //and save the end of the error as new start position
1648 aSaveStartPos = *GetCurrX();
1649 //and the end of the sentence
1650 *pCrsr->GetMark() = *GetEnd();
1652 // if the end of the sentence has already been reached then break here
1653 if(*GetCurrX() >= *GetEnd())
1654 break;
1656 while(xSpellRet.is());
1658 else
1660 //go to the end of sentence as the grammar check returned it
1661 // at this time the Point is behind the grammar error
1662 // and the mark points to the sentence end as
1663 if ( *pCrsr->GetPoint() < *pCrsr->GetMark() )
1664 pCrsr->Exchange();
1667 // the part between the last error and the end of the sentence has to be added
1668 *pMySh->GetCrsr()->GetPoint() = *GetEnd();
1669 if(*GetCurrX() < *GetEnd())
1671 AddPortion(0, 0, aDeletedRedlines);
1673 //set the shell cursor to the end of the sentence to prevent a visible selection
1674 *pCrsr->GetMark() = *GetEnd();
1675 if( !bIsGrammarCheck )
1677 //set the current position to the end of the sentence
1678 SetCurr( new SwPosition(*GetEnd()) );
1680 //restore the 'global' end
1681 SetEnd( new SwPosition(aSaveEndPos) );
1682 rPortions = aLastPortions;
1683 bRet = true;
1685 else
1687 //if no error could be found the selection has to be corrected - at least if it's not in the body
1688 *pMySh->GetCrsr()->GetPoint() = *GetEnd();
1689 pMySh->GetCrsr()->DeleteMark();
1692 return bRet;
1695 /*-- 08.09.2008 09:37:15---------------------------------------------------
1697 -----------------------------------------------------------------------*/
1698 void SwSpellIter::ToSentenceStart()
1700 bBackToStartOfSentence = true;
1702 /*-- 08.10.2003 08:49:56---------------------------------------------------
1704 -----------------------------------------------------------------------*/
1705 LanguageType lcl_GetLanguage(SwEditShell& rSh)
1707 USHORT nScriptType = rSh.GetScriptType();
1708 USHORT nLangWhichId = RES_CHRATR_LANGUAGE;
1710 switch(nScriptType)
1712 case SCRIPTTYPE_ASIAN : nLangWhichId = RES_CHRATR_CJK_LANGUAGE; break;
1713 case SCRIPTTYPE_COMPLEX : nLangWhichId = RES_CHRATR_CTL_LANGUAGE; break;
1715 SfxItemSet aSet(rSh.GetAttrPool(), nLangWhichId, nLangWhichId, 0);
1716 rSh.GetCurAttr( aSet );
1717 const SvxLanguageItem& rLang = static_cast<const SvxLanguageItem& >(aSet.Get(nLangWhichId));
1718 return rLang.GetLanguage();
1720 /*-- 08.10.2003 08:53:27---------------------------------------------------
1721 create a text portion at the given position
1722 -----------------------------------------------------------------------*/
1723 void SwSpellIter::CreatePortion(uno::Reference< XSpellAlternatives > xAlt,
1724 linguistic2::ProofreadingResult* pGrammarResult,
1725 bool bIsField, bool bIsHidden)
1727 svx::SpellPortion aPortion;
1728 String sText;
1729 GetSh()->GetSelectedText( sText );
1730 if(sText.Len())
1732 //in case of redlined deletions the selection of an error is not
1733 //the same as the _real_ word
1734 if(xAlt.is())
1735 aPortion.sText = xAlt->getWord();
1736 else if(pGrammarResult)
1738 aPortion.bIsGrammarError = true;
1739 if(pGrammarResult->aErrors.getLength())
1741 aPortion.aGrammarError = pGrammarResult->aErrors[0];
1742 aPortion.sText = pGrammarResult->aText.copy( aPortion.aGrammarError.nErrorStart, aPortion.aGrammarError.nErrorLength );
1743 aPortion.xGrammarChecker = pGrammarResult->xProofreader;
1744 const beans::PropertyValue* pProperties = pGrammarResult->aProperties.getConstArray();
1745 for( sal_Int32 nProp = 0; nProp < pGrammarResult->aProperties.getLength(); ++nProp )
1747 if( pProperties->Name.equalsAscii("DialogTitle") )
1749 pProperties->Value >>= aPortion.sDialogTitle;
1750 break;
1755 else
1756 aPortion.sText = sText;
1757 aPortion.eLanguage = lcl_GetLanguage(*GetSh());
1758 aPortion.bIsField = bIsField;
1759 aPortion.bIsHidden = bIsHidden;
1760 aPortion.xAlternatives = xAlt;
1761 SpellContentPosition aPosition;
1762 SwPaM *pCrsr = GetSh()->GetCrsr();
1763 aPosition.nLeft = pCrsr->Start()->nContent.GetIndex();
1764 aPosition.nRight = pCrsr->End()->nContent.GetIndex();
1765 aLastPortions.push_back(aPortion);
1766 aLastPositions.push_back(aPosition);
1769 /*-- 19.09.2003 13:05:43---------------------------------------------------
1771 -----------------------------------------------------------------------*/
1772 void SwSpellIter::AddPortion(uno::Reference< XSpellAlternatives > xAlt,
1773 linguistic2::ProofreadingResult* pGrammarResult,
1774 const SpellContentPositions& rDeletedRedlines)
1776 SwEditShell *pMySh = GetSh();
1777 String sText;
1778 pMySh->GetSelectedText( sText );
1779 if(sText.Len())
1781 if(xAlt.is() || pGrammarResult != 0)
1783 CreatePortion(xAlt, pGrammarResult, false, false);
1785 else
1787 SwPaM *pCrsr = GetSh()->GetCrsr();
1788 if ( *pCrsr->GetPoint() > *pCrsr->GetMark() )
1789 pCrsr->Exchange();
1790 //save the start and end positions
1791 SwPosition aStart(*pCrsr->GetPoint());
1792 SwPosition aEnd(*pCrsr->GetMark());
1793 //iterate over the text to find changes in language
1794 //set the mark equal to the point
1795 *pCrsr->GetMark() = aStart;
1796 SwTxtNode* pTxtNode = pCrsr->GetNode()->GetTxtNode();
1797 LanguageType eStartLanguage = lcl_GetLanguage(*GetSh());
1798 SpellContentPosition aNextRedline = lcl_FindNextDeletedRedline(
1799 rDeletedRedlines, aStart.nContent.GetIndex() );
1800 if( aNextRedline.nLeft == aStart.nContent.GetIndex() )
1802 //select until the end of the current redline
1803 xub_StrLen nEnd = aEnd.nContent.GetIndex() < aNextRedline.nRight ?
1804 aEnd.nContent.GetIndex() : aNextRedline.nRight;
1805 pCrsr->GetPoint()->nContent.Assign( pTxtNode, nEnd );
1806 CreatePortion(xAlt, pGrammarResult, false, true);
1807 aStart = *pCrsr->End();
1808 //search for next redline
1809 aNextRedline = lcl_FindNextDeletedRedline(
1810 rDeletedRedlines, aStart.nContent.GetIndex() );
1812 while(*pCrsr->GetPoint() < aEnd)
1814 //#125786 in table cell with fixed row height the cursor might not move forward
1815 if(!GetSh()->Right(1, CRSR_SKIP_CELLS))
1816 break;
1818 bool bField = false;
1819 //read the character at the current position to check if it's a field
1820 xub_Unicode cChar = pTxtNode->GetTxt().GetChar( pCrsr->GetMark()->nContent.GetIndex() );
1821 if( CH_TXTATR_BREAKWORD == cChar || CH_TXTATR_INWORD == cChar)
1823 const SwTxtAttr* pTxtAttr = pTxtNode->GetTxtAttrForCharAt(
1824 pCrsr->GetMark()->nContent.GetIndex() );
1825 const USHORT nWhich = pTxtAttr
1826 ? pTxtAttr->Which()
1827 : static_cast<USHORT>(RES_TXTATR_END);
1828 switch (nWhich)
1830 case RES_TXTATR_FIELD:
1831 case RES_TXTATR_FTN:
1832 case RES_TXTATR_FLYCNT:
1833 bField = true;
1834 break;
1838 LanguageType eCurLanguage = lcl_GetLanguage(*GetSh());
1839 bool bRedline = aNextRedline.nLeft == pCrsr->GetPoint()->nContent.GetIndex();
1840 // create a portion if the next character
1841 // - is a field,
1842 // - is at the beginning of a deleted redline
1843 // - has a different language
1844 if(bField || bRedline || eCurLanguage != eStartLanguage)
1846 eStartLanguage = eCurLanguage;
1847 //go one step back - the cursor currently selects the first character
1848 //with a different language
1849 //in the case of redlining it's different
1850 if(eCurLanguage != eStartLanguage || bField)
1851 *pCrsr->GetPoint() = *pCrsr->GetMark();
1852 //set to the last start
1853 *pCrsr->GetMark() = aStart;
1854 //create portion should only be called if a selection exists
1855 //there's no selection if there's a field at the beginning
1856 if(*pCrsr->Start() != *pCrsr->End())
1857 CreatePortion(xAlt, pGrammarResult, false, false);
1858 aStart = *pCrsr->End();
1859 //now export the field - if there is any
1860 if(bField)
1862 *pCrsr->GetMark() = *pCrsr->GetPoint();
1863 GetSh()->Right(1, CRSR_SKIP_CELLS);
1864 CreatePortion(xAlt, pGrammarResult, true, false);
1865 aStart = *pCrsr->End();
1868 // if a redline start then create a portion for it
1869 if(bRedline)
1871 *pCrsr->GetMark() = *pCrsr->GetPoint();
1872 //select until the end of the current redline
1873 xub_StrLen nEnd = aEnd.nContent.GetIndex() < aNextRedline.nRight ?
1874 aEnd.nContent.GetIndex() : aNextRedline.nRight;
1875 pCrsr->GetPoint()->nContent.Assign( pTxtNode, nEnd );
1876 CreatePortion(xAlt, pGrammarResult, false, true);
1877 aStart = *pCrsr->End();
1878 //search for next redline
1879 aNextRedline = lcl_FindNextDeletedRedline(
1880 rDeletedRedlines, aStart.nContent.GetIndex() );
1882 *pCrsr->GetMark() = *pCrsr->GetPoint();
1884 pCrsr->SetMark();
1885 *pCrsr->GetMark() = aStart;
1886 CreatePortion(xAlt, pGrammarResult, false, false);
1890 /*-- 07.08.2008 15:01:25---------------------------------------------------
1892 -----------------------------------------------------------------------*/
1893 void SwEditShell::IgnoreGrammarErrorAt( SwPaM& rErrorPosition )
1895 SwTxtNode *pNode;
1896 SwWrongList *pWrong;
1897 SwNodeIndex aIdx = rErrorPosition.Start()->nNode;
1898 SwNodeIndex aEndIdx = rErrorPosition.Start()->nNode;
1899 xub_StrLen nStart = rErrorPosition.Start()->nContent.GetIndex();
1900 xub_StrLen nEnd = STRING_LEN;
1901 while( aIdx <= aEndIdx )
1903 pNode = aIdx.GetNode().GetTxtNode();
1904 if( pNode ) {
1905 if( aIdx == aEndIdx )
1906 nEnd = rErrorPosition.End()->nContent.GetIndex();
1907 pWrong = pNode->GetGrammarCheck();
1908 if( pWrong )
1909 pWrong->RemoveEntry( nStart, nEnd );
1910 pWrong = pNode->GetWrong();
1911 if( pWrong )
1912 pWrong->RemoveEntry( nStart, nEnd );
1913 ::repaintTextFrames( *pNode );
1915 ++aIdx;
1916 nStart = 0;