update dev300-m58
[ooovba.git] / sw / source / core / edit / edlingu.cxx
blob052937fb5efd3921ee38fcb42dde842ec6320f82
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 <fmthbsh.hxx>
53 #include <charatr.hxx>
54 #include <editsh.hxx>
55 #include <doc.hxx>
56 #include <rootfrm.hxx> // SwRootFrm
57 #include <pam.hxx>
58 #include <swundo.hxx> // fuer die UndoIds
59 #include <ndtxt.hxx> // AdjHyphPos
60 #include <viewopt.hxx> // HyphStart/End
61 #include <viscrs.hxx> // SwShellCrsr
62 #include <SwGrammarMarkUp.hxx> // SwWrongList
63 #include <mdiexp.hxx> // Statusanzeige
64 #ifndef _STATSTR_HRC
65 #include <statstr.hrc> // StatLine-String
66 #endif
67 #include <cntfrm.hxx>
68 #include <crsskip.hxx>
69 #include <splargs.hxx>
70 #include <redline.hxx> // SwRedline
71 #include <docary.hxx> // SwRedlineTbl
72 #include <docsh.hxx>
74 using namespace ::svx;
75 using namespace ::com::sun::star;
76 using namespace ::com::sun::star::uno;
77 using namespace ::com::sun::star::beans;
78 using namespace ::com::sun::star::linguistic2;
80 #define C2U(cChar) rtl::OUString::createFromAscii(cChar)
82 extern void repaintTextFrames( SwModify& rModify );
84 /*************************************************************************
85 * class SwLinguIter
86 *************************************************************************/
88 class SwLinguIter
90 SwEditShell *pSh;
91 SwPosition *pStart;
92 SwPosition *pEnd;
93 SwPosition *pCurr;
94 SwPosition *pCurrX;
95 sal_uInt16 nCrsrCnt;
96 public:
97 SwLinguIter();
99 inline SwEditShell *GetSh() { return pSh; }
100 inline const SwEditShell *GetSh() const { return pSh; }
102 inline const SwPosition *GetEnd() const { return pEnd; }
103 inline void SetEnd( SwPosition* pNew ){ delete pEnd; pEnd = pNew; }
105 inline const SwPosition *GetStart() const { return pStart; }
106 inline void SetStart( SwPosition* pNew ){ delete pStart; pStart = pNew; }
108 inline const SwPosition *GetCurr() const { return pCurr; }
109 inline void SetCurr( SwPosition* pNew ){ delete pCurr; pCurr = pNew; }
111 inline const SwPosition *GetCurrX() const { return pCurrX; }
112 inline void SetCurrX( SwPosition* pNew ){ delete pCurrX; pCurrX = pNew; }
114 inline sal_uInt16& GetCrsrCnt(){ return nCrsrCnt; }
116 // Der UI-Bauchladen:
117 void _Start( SwEditShell *pSh, SwDocPositions eStart,
118 SwDocPositions eEnd );
119 void _End(bool bRestoreSelection = true);
122 /*************************************************************************
123 * class SwSpellIter
124 *************************************************************************/
126 // #i18881# to be able to identify the postions of the changed words
127 // the content positions of each portion need to be saved
128 struct SpellContentPosition
130 USHORT nLeft;
131 USHORT nRight;
133 typedef std::vector<SpellContentPosition> SpellContentPositions;
134 class SwSpellIter : public SwLinguIter
136 uno::Reference< XSpellChecker1 > xSpeller;
137 ::svx::SpellPortions aLastPortions;
139 SpellContentPositions aLastPositions;
140 bool bBackToStartOfSentence;
143 void CreatePortion(uno::Reference< XSpellAlternatives > xAlt,
144 linguistic2::ProofreadingResult* pGrammarResult,
145 bool bIsField, bool bIsHidden);
147 void AddPortion(uno::Reference< XSpellAlternatives > xAlt,
148 linguistic2::ProofreadingResult* pGrammarResult,
149 const SpellContentPositions& rDeletedRedlines);
150 public:
151 SwSpellIter() :
152 bBackToStartOfSentence(false) {}
154 void Start( SwEditShell *pSh, SwDocPositions eStart, SwDocPositions eEnd );
156 uno::Any Continue( sal_uInt16* pPageCnt, sal_uInt16* pPageSt );
158 bool SpellSentence(::svx::SpellPortions& rPortions, bool bIsGrammarCheck);
159 void ToSentenceStart();
160 const ::svx::SpellPortions GetLastPortions(){ return aLastPortions;}
161 SpellContentPositions GetLastPositions() {return aLastPositions;}
164 /*************************************************************************
165 * class SwConvIter
166 * used for text conversion
167 *************************************************************************/
169 class SwConvIter : public SwLinguIter
171 SwConversionArgs &rArgs;
172 public:
173 SwConvIter( SwConversionArgs &rConvArgs ) :
174 rArgs( rConvArgs )
177 void Start( SwEditShell *pSh, SwDocPositions eStart, SwDocPositions eEnd );
179 uno::Any Continue( sal_uInt16* pPageCnt, sal_uInt16* pPageSt );
182 /*************************************************************************
183 * class SwHyphIter
184 *************************************************************************/
186 class SwHyphIter : public SwLinguIter
188 sal_Bool bOldIdle;
189 void DelSoftHyph( SwPaM &rPam );
191 public:
192 SwHyphIter() : bOldIdle(sal_False) {}
194 void Start( SwEditShell *pSh, SwDocPositions eStart, SwDocPositions eEnd );
195 void End();
197 void Ignore();
199 uno::Any Continue( sal_uInt16* pPageCnt, sal_uInt16* pPageSt );
201 sal_Bool IsAuto();
202 void InsertSoftHyph( const xub_StrLen nHyphPos );
203 void ShowSelection();
206 static SwSpellIter* pSpellIter = 0;
207 static SwConvIter* pConvIter = 0;
208 static SwHyphIter* pHyphIter = 0;
210 // Wir ersparen uns in Hyphenate ein GetFrm()
211 // Achtung: in txtedt.cxx stehen extern-Deklarationen auf diese Pointer!
212 const SwTxtNode *pLinguNode;
213 SwTxtFrm *pLinguFrm;
215 /*************************************************************************
216 * SwLinguIter::SwLinguIter
217 *************************************************************************/
219 SwLinguIter::SwLinguIter()
220 : pSh( 0 ), pStart( 0 ), pEnd( 0 ), pCurr( 0 ), pCurrX( 0 )
222 // @@@ es fehlt: Sicherstellen der Reentrance, ASSERTs etc.
225 /*************************************************************************
226 * SwLinguIter::Start
227 *************************************************************************/
231 void SwLinguIter::_Start( SwEditShell *pShell, SwDocPositions eStart,
232 SwDocPositions eEnd )
234 // es fehlt: Sicherstellen der Reentrance, Locking
235 if( pSh )
236 return;
238 sal_Bool bSetCurr;
240 pSh = pShell;
242 SET_CURR_SHELL( pSh );
244 ASSERT( !pEnd, "LinguStart ohne End?");
246 SwPaM *pCrsr = pSh->GetCrsr();
248 // pStk->SetCurCrsr();
249 // if( pCrsr->HasMark() || pCrsr != pCrsr->GetNext() )
250 if( pShell->HasSelection() || pCrsr != pCrsr->GetNext() )
252 bSetCurr = 0 != GetCurr();
253 nCrsrCnt = pSh->GetCrsrCnt();
254 if( pSh->IsTableMode() )
255 pSh->TblCrsrToCursor();
257 pSh->Push();
258 sal_uInt16 n;
259 for( n = 0; n < nCrsrCnt; ++n )
261 pSh->Push();
262 pSh->DestroyCrsr();
264 pSh->Pop( sal_False );
266 else
268 bSetCurr = sal_False;
269 nCrsrCnt = 1;
270 pSh->Push();
271 pSh->SetLinguRange( eStart, eEnd );
274 pCrsr = pSh->GetCrsr();
275 if ( *pCrsr->GetPoint() > *pCrsr->GetMark() )
276 pCrsr->Exchange();
278 pStart = new SwPosition( *pCrsr->GetPoint() );
279 pEnd = new SwPosition( *pCrsr->GetMark() );
280 if( bSetCurr )
282 SwPosition* pNew = new SwPosition( *GetStart() );
283 SetCurr( pNew );
284 pNew = new SwPosition( *pNew );
285 SetCurrX( pNew );
288 pCrsr->SetMark();
290 pLinguFrm = 0;
291 pLinguNode = 0;
294 /*************************************************************************
295 * SwLinguIter::End
296 *************************************************************************/
300 void SwLinguIter::_End(bool bRestoreSelection)
302 if( !pSh )
303 return;
305 ASSERT( pEnd, "SwEditShell::SpellEnd() ohne Start?");
306 if(bRestoreSelection)
308 while( nCrsrCnt-- )
309 pSh->Pop( sal_False );
311 pSh->KillPams();
312 pSh->ClearMark();
314 DELETEZ(pStart);
315 DELETEZ(pEnd);
316 DELETEZ(pCurr);
317 DELETEZ(pCurrX);
319 pSh = 0;
321 #ifdef LINGU_STATISTIK
322 aSwLinguStat.Flush();
323 #endif
326 /*************************************************************************
327 * virtual SwSpellIter::Start()
328 *************************************************************************/
332 void SwSpellIter::Start( SwEditShell *pShell, SwDocPositions eStart,
333 SwDocPositions eEnd )
335 if( GetSh() )
336 return;
338 uno::Reference< beans::XPropertySet > xProp( ::GetLinguPropertySet() );
339 xSpeller = ::GetSpellChecker();
340 if ( xSpeller.is() )
341 _Start( pShell, eStart, eEnd );
342 aLastPortions.clear();
343 aLastPositions.clear();
346 /*************************************************************************
347 * SwSpellIter::Continue
348 *************************************************************************/
350 // SwSpellIter::Continue ist das alte Original von
351 // SwEditShell::SpellContinue()
353 uno::Any SwSpellIter::Continue( sal_uInt16* pPageCnt, sal_uInt16* pPageSt )
355 //!!
356 //!! Please check SwConvIter also when modifying this
357 //!!
359 uno::Any aSpellRet;
360 SwEditShell *pMySh = GetSh();
361 if( !pMySh )
362 return aSpellRet;
364 // const SwPosition *pEnd = GetEnd();
366 ASSERT( GetEnd(), "SwEditShell::SpellContinue() ohne Start?");
368 uno::Reference< uno::XInterface > xSpellRet;
369 sal_Bool bGoOn = sal_True;
370 do {
371 SwPaM *pCrsr = pMySh->GetCrsr();
372 if ( !pCrsr->HasMark() )
373 pCrsr->SetMark();
375 uno::Reference< beans::XPropertySet > xProp( GetLinguPropertySet() );
376 *pMySh->GetCrsr()->GetPoint() = *GetCurr();
377 *pMySh->GetCrsr()->GetMark() = *GetEnd();
378 pMySh->GetDoc()->Spell(*pMySh->GetCrsr(),
379 xSpeller, pPageCnt, pPageSt, false ) >>= xSpellRet;
380 bGoOn = GetCrsrCnt() > 1;
381 if( xSpellRet.is() )
383 bGoOn = sal_False;
384 SwPosition* pNewPoint = new SwPosition( *pCrsr->GetPoint() );
385 SwPosition* pNewMark = new SwPosition( *pCrsr->GetMark() );
386 SetCurr( pNewPoint );
387 SetCurrX( pNewMark );
389 if( bGoOn )
391 pMySh->Pop( sal_False );
392 pCrsr = pMySh->GetCrsr();
393 if ( *pCrsr->GetPoint() > *pCrsr->GetMark() )
394 pCrsr->Exchange();
395 SwPosition* pNew = new SwPosition( *pCrsr->GetPoint() );
396 SetStart( pNew );
397 pNew = new SwPosition( *pCrsr->GetMark() );
398 SetEnd( pNew );
399 pNew = new SwPosition( *GetStart() );
400 SetCurr( pNew );
401 pNew = new SwPosition( *pNew );
402 SetCurrX( pNew );
403 pCrsr->SetMark();
404 --GetCrsrCnt();
406 }while ( bGoOn );
407 aSpellRet <<= xSpellRet;
408 return aSpellRet;
411 /*************************************************************************
412 * virtual SwConvIter::Start()
413 *************************************************************************/
417 void SwConvIter::Start( SwEditShell *pShell, SwDocPositions eStart,
418 SwDocPositions eEnd )
420 if( GetSh() )
421 return;
422 _Start( pShell, eStart, eEnd );
425 /*************************************************************************
426 * SwConvIter::Continue
427 *************************************************************************/
429 uno::Any SwConvIter::Continue( sal_uInt16* pPageCnt, sal_uInt16* pPageSt )
431 //!!
432 //!! Please check SwSpellIter also when modifying this
433 //!!
435 uno::Any aConvRet( makeAny( rtl::OUString() ) );
436 SwEditShell *pMySh = GetSh();
437 if( !pMySh )
438 return aConvRet;
440 // const SwPosition *pEnd = GetEnd();
442 ASSERT( GetEnd(), "SwConvIter::Continue() ohne Start?");
444 rtl::OUString aConvText;
445 sal_Bool bGoOn = sal_True;
446 do {
447 SwPaM *pCrsr = pMySh->GetCrsr();
448 if ( !pCrsr->HasMark() )
449 pCrsr->SetMark();
451 *pMySh->GetCrsr()->GetPoint() = *GetCurr();
452 *pMySh->GetCrsr()->GetMark() = *GetEnd();
454 // call function to find next text portion to be converted
455 uno::Reference< linguistic2::XSpellChecker1 > xEmpty;
456 pMySh->GetDoc()->Spell( *pMySh->GetCrsr(),
457 xEmpty, pPageCnt, pPageSt, false, &rArgs ) >>= aConvText;
459 bGoOn = GetCrsrCnt() > 1;
460 if( aConvText.getLength() )
462 bGoOn = sal_False;
463 SwPosition* pNewPoint = new SwPosition( *pCrsr->GetPoint() );
464 SwPosition* pNewMark = new SwPosition( *pCrsr->GetMark() );
466 SetCurr( pNewPoint );
467 SetCurrX( pNewMark );
469 if( bGoOn )
471 pMySh->Pop( sal_False );
472 pCrsr = pMySh->GetCrsr();
473 if ( *pCrsr->GetPoint() > *pCrsr->GetMark() )
474 pCrsr->Exchange();
475 SwPosition* pNew = new SwPosition( *pCrsr->GetPoint() );
476 SetStart( pNew );
477 pNew = new SwPosition( *pCrsr->GetMark() );
478 SetEnd( pNew );
479 pNew = new SwPosition( *GetStart() );
480 SetCurr( pNew );
481 pNew = new SwPosition( *pNew );
482 SetCurrX( pNew );
483 pCrsr->SetMark();
484 --GetCrsrCnt();
486 }while ( bGoOn );
487 return makeAny( aConvText );
491 /*************************************************************************
492 * SwHyphIter
493 *************************************************************************/
496 sal_Bool SwHyphIter::IsAuto()
498 uno::Reference< beans::XPropertySet > xProp( ::GetLinguPropertySet() );
499 return xProp.is() ? *(sal_Bool*)xProp->getPropertyValue(
500 C2U(UPN_IS_HYPH_AUTO) ).getValue()
501 : sal_False;
505 void SwHyphIter::ShowSelection()
507 SwEditShell *pMySh = GetSh();
508 if( pMySh )
510 pMySh->StartAction();
511 // Ganz fatal: durch das EndAction() werden Formatierungen
512 // angeregt, die dazu fuehren koennen, dass im Hyphenator
513 // neue Worte eingestellt werden. Deswegen sichern!
514 pMySh->EndAction();
518 /*************************************************************************
519 * virtual SwHyphIter::Start()
520 *************************************************************************/
524 void SwHyphIter::Start( SwEditShell *pShell, SwDocPositions eStart, SwDocPositions eEnd )
526 // robust
527 if( GetSh() || GetEnd() )
529 ASSERT( !GetSh(), "+SwEditShell::HyphStart: missing HyphEnd()" );
530 return;
533 // nothing to be done (at least not in the way as in the "else" part)
534 bOldIdle = pShell->GetViewOptions()->IsIdle();
535 ((SwViewOption*)pShell->GetViewOptions())->SetIdle( sal_False );
536 _Start( pShell, eStart, eEnd );
539 /*************************************************************************
540 * virtual SwHyphIter::End
541 *************************************************************************/
543 // Selektionen wiederherstellen
547 void SwHyphIter::End()
549 if( !GetSh() )
550 return;
551 ((SwViewOption*)GetSh()->GetViewOptions())->SetIdle( bOldIdle );
552 _End();
555 /*************************************************************************
556 * SwHyphIter::Continue
557 *************************************************************************/
559 uno::Any SwHyphIter::Continue( sal_uInt16* pPageCnt, sal_uInt16* pPageSt )
561 uno::Any aHyphRet;
562 SwEditShell *pMySh = GetSh();
563 if( !pMySh )
564 return aHyphRet;
566 const sal_Bool bAuto = IsAuto();
567 uno::Reference< XHyphenatedWord > xHyphWord;
568 sal_uInt16 nRet;
569 sal_Bool bGoOn = sal_False;
570 do {
571 SwPaM *pCrsr;
572 do {
573 ASSERT( GetEnd(), "SwEditShell::SpellContinue() ohne Start?" );
574 pCrsr = pMySh->GetCrsr();
575 if ( !pCrsr->HasMark() )
576 pCrsr->SetMark();
577 if ( *pCrsr->GetPoint() < *pCrsr->GetMark() )
579 pCrsr->Exchange();
580 pCrsr->SetMark();
583 // geraten BUG:
584 if ( *pCrsr->End() > *GetEnd() )
585 nRet = 0;
586 else
588 *pCrsr->GetMark() = *GetEnd();
590 // Muss an der aktuellen Cursorpos das Wort getrennt werden ?
591 const Point aCrsrPos( pMySh->GetCharRect().Pos() );
592 xHyphWord = pMySh->GetDoc()->Hyphenate( pCrsr, aCrsrPos,
593 pPageCnt, pPageSt );
596 if( bAuto && xHyphWord.is() )
598 pMySh->InsertSoftHyph( xHyphWord->getHyphenationPos() + 1);
600 } while( bAuto && xHyphWord.is() ); //end of do-while
601 bGoOn = !xHyphWord.is() && GetCrsrCnt() > 1;
603 if( bGoOn )
605 pMySh->Pop( sal_False );
606 pCrsr = pMySh->GetCrsr();
607 if ( *pCrsr->GetPoint() > *pCrsr->GetMark() )
608 pCrsr->Exchange();
609 SwPosition* pNew = new SwPosition(*pCrsr->End());
610 SetEnd( pNew );
611 pCrsr->SetMark();
612 --GetCrsrCnt();
614 } while ( bGoOn );
615 aHyphRet <<= xHyphWord;
616 return aHyphRet;
619 /*************************************************************************
620 * SwHyphIter::HyphIgnore
621 *************************************************************************/
623 // Beschreibung: Trennstelle ignorieren
625 void SwHyphIter::Ignore()
627 SwEditShell *pMySh = GetSh();
628 SwPaM *pCrsr = pMySh->GetCrsr();
630 // Alten SoftHyphen loeschen
631 DelSoftHyph( *pCrsr );
633 // und weiter
634 pCrsr->Start()->nContent = pCrsr->End()->nContent;
635 pCrsr->SetMark();
638 /*************************************************************************
639 * SwHyphIter::DelSoftHyph
640 *************************************************************************/
642 void SwHyphIter::DelSoftHyph( SwPaM &rPam )
644 const SwPosition* pStt = rPam.Start();
645 const xub_StrLen nStart = pStt->nContent.GetIndex();
646 const xub_StrLen nEnd = rPam.End()->nContent.GetIndex();
647 SwTxtNode *pNode = pStt->nNode.GetNode().GetTxtNode();
648 pNode->DelSoftHyph( nStart, nEnd );
651 /*************************************************************************
652 * SwHyphIter::InsertSoftHyph
653 *************************************************************************/
656 void SwHyphIter::InsertSoftHyph( const xub_StrLen nHyphPos )
658 SwEditShell *pMySh = GetSh();
659 ASSERT( pMySh, "+SwEditShell::InsertSoftHyph: missing HyphStart()");
660 if( !pMySh )
661 return;
663 SwPaM *pCrsr = pMySh->GetCrsr();
664 SwPosition* pSttPos = pCrsr->Start();
665 SwPosition* pEndPos = pCrsr->End();
667 xub_StrLen nLastHyphLen = GetEnd()->nContent.GetIndex() -
668 pSttPos->nContent.GetIndex();
670 if( pSttPos->nNode != pEndPos->nNode || !nLastHyphLen )
672 ASSERT( pSttPos->nNode == pEndPos->nNode,
673 "+SwEditShell::InsertSoftHyph: node warp during hyphenation" );
674 ASSERT(nLastHyphLen, "+SwEditShell::InsertSoftHyph: missing HyphContinue()");
675 *pSttPos = *pEndPos;
676 return;
679 pMySh->StartAction();
681 SwDoc *pDoc = pMySh->GetDoc();
682 DelSoftHyph( *pCrsr );
683 pSttPos->nContent += nHyphPos;
684 SwPaM aRg( *pSttPos );
685 pDoc->Insert( aRg, CHAR_SOFTHYPHEN );
686 // Durch das Einfuegen des SoftHyphs ist ein Zeichen hinzugekommen
687 //JP 18.07.95: warum, ist doch ein SwIndex, dieser wird doch mitverschoben !!
688 // pSttPos->nContent++;
690 // Die Selektion wird wieder aufgehoben
691 pCrsr->DeleteMark();
692 pMySh->EndAction();
693 pCrsr->SetMark();
696 // --------------------- Methoden der SwEditShell ------------------------
698 /*************************************************************************
699 * SwEditShell::HasConvIter
700 *************************************************************************/
702 BOOL SwEditShell::HasConvIter() const
704 return 0 != pConvIter;
707 /*************************************************************************
708 * SwEditShell::HasHyphIter
709 *************************************************************************/
711 BOOL SwEditShell::HasHyphIter() const
713 return 0 != pHyphIter;
716 /*************************************************************************
717 * SwEditShell::SetFindRange
718 *************************************************************************/
720 void SwEditShell::SetLinguRange( SwDocPositions eStart, SwDocPositions eEnd )
722 SwPaM *pCrsr = GetCrsr();
723 MakeFindRange( static_cast<USHORT>(eStart), static_cast<USHORT>(eEnd), pCrsr );
724 if( *pCrsr->GetPoint() > *pCrsr->GetMark() )
725 pCrsr->Exchange();
728 /*************************************************************************
729 * SwEditShell::SpellStart
730 *************************************************************************/
732 void SwEditShell::SpellStart(
733 SwDocPositions eStart, SwDocPositions eEnd, SwDocPositions eCurr,
734 SwConversionArgs *pConvArgs )
736 SwLinguIter *pLinguIter = 0;
738 // do not spell if interactive spelling is active elsewhere
739 if (!pConvArgs && !pSpellIter)
741 ASSERT( !pSpellIter, "wer ist da schon am spellen?" );
742 pSpellIter = new SwSpellIter;
743 pLinguIter = pSpellIter;
745 // do not do text conversion if it is active elsewhere
746 if (pConvArgs && !pConvIter)
748 ASSERT( !pConvIter, "text conversion already active!" );
749 pConvIter = new SwConvIter( *pConvArgs );
750 pLinguIter = pConvIter;
753 if (pLinguIter)
755 SwCursor* pSwCrsr = GetSwCrsr();
757 SwPosition *pTmp = new SwPosition( *pSwCrsr->GetPoint() );
758 pSwCrsr->FillFindPos( eCurr, *pTmp );
759 pLinguIter->SetCurr( pTmp );
761 pTmp = new SwPosition( *pTmp );
762 pLinguIter->SetCurrX( pTmp );
765 if (!pConvArgs && pSpellIter)
766 pSpellIter->Start( this, eStart, eEnd );
767 if (pConvArgs && pConvIter)
768 pConvIter->Start( this, eStart, eEnd );
771 /*************************************************************************
772 * SwEditShell::SpellEnd
773 *************************************************************************/
775 void SwEditShell::SpellEnd( SwConversionArgs *pConvArgs, bool bRestoreSelection )
777 if (!pConvArgs && pSpellIter && pSpellIter->GetSh() == this)
779 ASSERT( pSpellIter, "wo ist mein Iterator?" );
780 pSpellIter->_End(bRestoreSelection);
781 delete pSpellIter, pSpellIter = 0;
783 if (pConvArgs && pConvIter && pConvIter->GetSh() == this)
785 ASSERT( pConvIter, "wo ist mein Iterator?" );
786 pConvIter->_End();
787 delete pConvIter, pConvIter = 0;
791 /*************************************************************************
792 * SwEditShell::SpellContinue
793 *************************************************************************/
795 // liefert Rueckgabewerte entsprechend SPL_ in splchk.hxx
797 uno::Any SwEditShell::SpellContinue(
798 sal_uInt16* pPageCnt, sal_uInt16* pPageSt,
799 SwConversionArgs *pConvArgs )
801 uno::Any aRes;
803 if ((!pConvArgs && pSpellIter->GetSh() != this) ||
804 ( pConvArgs && pConvIter->GetSh() != this))
805 return aRes;
807 if( pPageCnt && !*pPageCnt )
809 sal_uInt16 nEndPage = GetLayout()->GetPageNum();
810 nEndPage += nEndPage * 10 / 100;
811 *pPageCnt = nEndPage;
812 if( nEndPage )
813 ::StartProgress( STR_STATSTR_SPELL, 0, nEndPage, GetDoc()->GetDocShell() );
816 ASSERT( pConvArgs || pSpellIter, "SpellIter missing" );
817 ASSERT( !pConvArgs || pConvIter, "ConvIter missing" );
818 //JP 18.07.95: verhinder bei Fehlermeldungen die Anzeige der Selektionen
819 // KEIN StartAction, da damit auch die Paints abgeschaltet
820 // werden !!!!!
821 ++nStartAction;
822 rtl::OUString aRet;
823 uno::Reference< uno::XInterface > xRet;
824 if (pConvArgs)
826 pConvIter->Continue( pPageCnt, pPageSt ) >>= aRet;
827 aRes <<= aRet;
829 else
831 pSpellIter->Continue( pPageCnt, pPageSt ) >>= xRet;
832 aRes <<= xRet;
834 --nStartAction;
836 if( aRet.getLength() || xRet.is() )
838 // dann die awt::Selection sichtbar machen
839 StartAction();
840 EndAction();
842 return aRes;
844 /*************************************************************************
845 * SwEditShell::HyphStart
846 *************************************************************************/
848 /* Interaktive Trennung, BP 10.03.93
850 * 1) HyphStart
851 * - Aufheben aller Selektionen
852 * - Sichern des aktuellen Cursors
853 * - falls keine Selektion vorhanden:
854 * - neue Selektion bis zum Dokumentende
855 * 2) HyphContinue
856 * - nLastHyphLen wird auf den Selektionsstart addiert
857 * - iteriert ueber alle selektierten Bereiche
858 * - pDoc->Hyphenate() iteriert ueber alle Nodes der Selektion
859 * - pTxtNode->Hyphenate() ruft das SwTxtFrm::Hyphenate zur EditShell
860 * - SwTxtFrm:Hyphenate() iteriert ueber die Zeilen des Pams
861 * - LineIter::Hyphenate() stellt den Hyphenator
862 * und den Pam auf das zu trennende Wort ein.
863 * - Es gibt nur zwei Returnwerte sal_True, wenn eine Trennstelle anliegt
864 * und sal_False, wenn der Pam abgearbeitet wurde.
865 * - Bei sal_True wird das selektierte Wort zur Anzeige gebracht und
866 * nLastHyphLen gesetzt.
867 * - Bei sal_False wird die aktuelle Selektion geloescht und die naechste
868 * zur aktuellen gewaehlt. Return HYPH_OK, wenn keine mehr vorhanden.
869 * 3) InsertSoftHyph (wird ggf. von der UI gerufen)
870 * - Der aktuelle Cursor wird plaziert und das Attribut eingefuegt.
871 * 4) HyphEnd
872 * - Wiederherstellen des alten Cursors, EndAction
877 void SwEditShell::HyphStart( SwDocPositions eStart, SwDocPositions eEnd )
879 // do not hyphenate if interactive hyphenationg is active elsewhere
880 if (!pHyphIter)
882 ASSERT( !pHyphIter, "wer ist da schon am hyphinieren?" );
883 pHyphIter = new SwHyphIter;
884 pHyphIter->Start( this, eStart, eEnd );
888 /*************************************************************************
889 * SwEditShell::HyphEnd
890 *************************************************************************/
892 // Selektionen wiederherstellen
896 void SwEditShell::HyphEnd()
898 if (pHyphIter->GetSh() == this)
900 ASSERT( pHyphIter, "wo ist mein Iterator?" );
901 pHyphIter->End();
902 delete pHyphIter, pHyphIter = 0;
906 /*************************************************************************
907 * SwEditShell::HyphContinue
908 *************************************************************************/
910 // Returnwerte: (BP: ich wuerde es genau umdrehen, aber die UI wuenscht es so)
911 // HYPH_CONTINUE, wenn eine Trennstelle anliegt
912 // HYPH_OK, wenn der selektierte Bereich abgearbeitet wurde.
915 uno::Reference< uno::XInterface >
916 SwEditShell::HyphContinue( sal_uInt16* pPageCnt, sal_uInt16* pPageSt )
918 if (pHyphIter->GetSh() != this)
919 return 0;
921 if( pPageCnt && !*pPageCnt && !*pPageSt )
923 sal_uInt16 nEndPage = GetLayout()->GetPageNum();
924 nEndPage += nEndPage * 10 / 100;
925 if( nEndPage > 14 )
927 *pPageCnt = nEndPage;
928 ::StartProgress( STR_STATSTR_HYPHEN, 0, nEndPage, GetDoc()->GetDocShell());
930 else // Hiermit unterdruecken wir ein fuer allemal
931 *pPageSt = 1; // das StatLineStartPercent
934 ASSERT( pHyphIter, "wo ist mein Iterator?" );
935 //JP 18.07.95: verhinder bei Fehlermeldungen die Anzeige der Selektionen
936 // KEIN StartAction, da damit auch die Paints abgeschaltet
937 // werden !!!!!
938 ++nStartAction;
939 uno::Reference< uno::XInterface > xRet;
940 pHyphIter->Continue( pPageCnt, pPageSt ) >>= xRet;
941 --nStartAction;
943 if( xRet.is() )
944 pHyphIter->ShowSelection();
946 return xRet;
950 /*************************************************************************
951 * SwEditShell::InsertSoftHyph
952 *************************************************************************/
954 // Zum Einfuegen des SoftHyphens, Position ist der Offset
955 // innerhalb des getrennten Wortes.
958 void SwEditShell::InsertSoftHyph( const xub_StrLen nHyphPos )
960 ASSERT( pHyphIter, "wo ist mein Iterator?" );
961 pHyphIter->InsertSoftHyph( nHyphPos );
965 /*************************************************************************
966 * SwEditShell::HyphIgnore
967 *************************************************************************/
969 // Beschreibung: Trennstelle ignorieren
971 void SwEditShell::HyphIgnore()
973 ASSERT( pHyphIter, "wo ist mein Iterator?" );
974 //JP 18.07.95: verhinder bei Fehlermeldungen die Anzeige der Selektionen
975 // KEIN StartAction, da damit auch die Paints abgeschaltet
976 // werden !!!!!
977 ++nStartAction;
978 pHyphIter->Ignore();
979 --nStartAction;
981 pHyphIter->ShowSelection();
984 /*************************************************************************
985 * SwEditShell::GetCorrection()
986 * liefert eine Liste von Vorschlaegen fuer falsch geschriebene Worte,
987 * ein NULL-Pointer signalisiert, dass das Wort richtig geschrieben ist,
988 * eine leere Liste, dass das Wort zwar unbekannt ist, aber keine Alternativen
989 * geliefert werden koennen.
990 *************************************************************************/
993 uno::Reference< XSpellAlternatives >
994 SwEditShell::GetCorrection( const Point* pPt, SwRect& rSelectRect )
996 uno::Reference< XSpellAlternatives > xSpellAlt;
998 if( IsTableMode() )
999 return NULL;
1000 SwPaM* pCrsr = GetCrsr();
1001 SwPosition aPos( *pCrsr->GetPoint() );
1002 Point aPt( *pPt );
1003 SwCrsrMoveState eTmpState( MV_SETONLYTEXT );
1004 SwTxtNode *pNode;
1005 SwWrongList *pWrong;
1006 if( GetLayout()->GetCrsrOfst( &aPos, aPt, &eTmpState ) &&
1007 0 != (pNode = aPos.nNode.GetNode().GetTxtNode()) &&
1008 0 != (pWrong = pNode->GetWrong()) &&
1009 !pNode->IsInProtectSect() )
1011 xub_StrLen nBegin = aPos.nContent.GetIndex();
1012 xub_StrLen nLen = 1;
1013 if( pWrong->InWrongWord(nBegin,nLen) && !pNode->IsSymbol(nBegin) )
1015 String aText( pNode->GetTxt().Copy( nBegin, nLen ) );
1016 String aWord( aText );
1017 aWord.EraseAllChars( CH_TXTATR_BREAKWORD ).EraseAllChars( CH_TXTATR_INWORD );
1019 uno::Reference< XSpellChecker1 > xSpell( ::GetSpellChecker() );
1020 if( xSpell.is() )
1022 LanguageType eActLang = (LanguageType)pNode->GetLang( nBegin, nLen );
1023 if( xSpell->hasLanguage( eActLang ))
1025 // restrict the maximal number of suggestions displayed
1026 // in the context menu.
1027 // Note: That could of course be done by clipping the
1028 // resulting sequence but the current third party
1029 // implementations result differs greatly if the number of
1030 // suggestions to be retuned gets changed. Statistically
1031 // it gets much better if told to return e.g. only 7 strings
1032 // than returning e.g. 16 suggestions and using only the
1033 // first 7. Thus we hand down the value to use to that
1034 // implementation here by providing an additional parameter.
1035 Sequence< PropertyValue > aPropVals(1);
1036 PropertyValue &rVal = aPropVals.getArray()[0];
1037 rVal.Name = C2U( UPN_MAX_NUMBER_OF_SUGGESTIONS );
1038 rVal.Value <<= (INT16) 7;
1040 xSpellAlt = xSpell->spell( aWord, eActLang, aPropVals );
1044 if ( xSpellAlt.is() ) // error found?
1046 //save the start and end positons of the line and the starting point
1047 Push();
1048 LeftMargin();
1049 xub_StrLen nLineStart = GetCrsr()->GetPoint()->nContent.GetIndex();
1050 RightMargin();
1051 xub_StrLen nLineEnd = GetCrsr()->GetPoint()->nContent.GetIndex();
1052 Pop(FALSE);
1054 // make sure the selection build later from the
1055 // data below does not include footnotes and other
1056 // "in word" character to the left and right in order
1057 // to preserve those. Therefore count those "in words"
1058 // in order to modify the selection accordingly.
1059 const sal_Unicode* pChar = aText.GetBuffer();
1060 xub_StrLen nLeft = 0;
1061 while (pChar && *pChar++ == CH_TXTATR_INWORD)
1062 ++nLeft;
1063 pChar = aText.Len() ? aText.GetBuffer() + aText.Len() - 1 : 0;
1064 xub_StrLen nRight = 0;
1065 while (pChar && *pChar-- == CH_TXTATR_INWORD)
1066 ++nRight;
1068 aPos.nContent = nBegin + nLeft;
1069 pCrsr = GetCrsr();
1070 *pCrsr->GetPoint() = aPos;
1071 pCrsr->SetMark();
1072 ExtendSelection( sal_True, nLen - nLeft - nRight );
1073 //no determine the rectangle in the current line
1074 xub_StrLen nWordStart = (nBegin + nLeft) < nLineStart ? nLineStart : nBegin + nLeft;
1075 //take one less than the line end - otherwise the next line would be calculated
1076 xub_StrLen nWordEnd = (nBegin + nLen - nLeft - nRight) > nLineEnd ? nLineEnd - 1: (nBegin + nLen - nLeft - nRight);
1077 Push();
1078 pCrsr->DeleteMark();
1079 SwIndex& rContent = GetCrsr()->GetPoint()->nContent;
1080 rContent = nWordStart;
1081 SwRect aStartRect;
1082 SwCrsrMoveState aState;
1083 aState.bRealWidth = TRUE;
1084 SwCntntNode* pCntntNode = pCrsr->GetCntntNode();
1085 SwCntntFrm *pCntntFrame = pCntntNode->GetFrm(pPt, pCrsr->GetPoint(), FALSE);
1087 pCntntFrame->GetCharRect( aStartRect, *pCrsr->GetPoint(), &aState );
1088 rContent = nWordEnd;
1089 SwRect aEndRect;
1090 pCntntFrame->GetCharRect( aEndRect, *pCrsr->GetPoint(),&aState );
1091 rSelectRect = aStartRect.Union( aEndRect );
1092 Pop(FALSE);
1096 return xSpellAlt;
1099 /*-------------------------------------------------------------------------
1101 -----------------------------------------------------------------------*/
1103 bool SwEditShell::GetGrammarCorrection(
1104 linguistic2::ProofreadingResult /*out*/ &rResult, // the complete result
1105 sal_Int32 /*out*/ &rErrorPosInText, // offset of error position in string that was grammar checked...
1106 sal_Int32 /*out*/ &rErrorIndexInResult, // index of error in rResult.aGrammarErrors
1107 uno::Sequence< rtl::OUString > /*out*/ &rSuggestions, // suggestions to be used for the error found
1108 const Point *pPt, SwRect &rSelectRect )
1110 bool bRes = false;
1112 if( IsTableMode() )
1113 return bRes;
1115 SwPaM* pCrsr = GetCrsr();
1116 SwPosition aPos( *pCrsr->GetPoint() );
1117 Point aPt( *pPt );
1118 SwCrsrMoveState eTmpState( MV_SETONLYTEXT );
1119 SwTxtNode *pNode;
1120 SwGrammarMarkUp *pWrong;
1121 if( GetLayout()->GetCrsrOfst( &aPos, aPt, &eTmpState ) &&
1122 0 != (pNode = aPos.nNode.GetNode().GetTxtNode()) &&
1123 0 != (pWrong = pNode->GetGrammarCheck()) &&
1124 !pNode->IsInProtectSect() )
1126 xub_StrLen nBegin = aPos.nContent.GetIndex();
1127 xub_StrLen nLen = 1;
1128 if (pWrong->InWrongWord(nBegin, nLen))
1130 String aText( pNode->GetTxt().Copy( nBegin, nLen ) );
1131 String aWord( aText );
1132 aWord.EraseAllChars( CH_TXTATR_BREAKWORD ).EraseAllChars( CH_TXTATR_INWORD );
1134 uno::Reference< linguistic2::XProofreadingIterator > xGCIterator( pDoc->GetGCIterator() );
1135 if (xGCIterator.is())
1137 // LanguageType eActLang = (LanguageType)pNode->GetLang( nBegin, nLen );
1138 uno::Reference< lang::XComponent > xDoc( pDoc->GetDocShell()->GetBaseModel(), uno::UNO_QUERY );
1140 // Expand the string:
1141 rtl::OUString aExpandText;
1142 const ModelToViewHelper::ConversionMap* pConversionMap =
1143 pNode->BuildConversionMap( aExpandText );
1144 // get XFlatParagraph to use...
1145 uno::Reference< text::XFlatParagraph > xFlatPara = new SwXFlatParagraph( *pNode, aExpandText, pConversionMap );
1147 // get error position of cursor in XFlatParagraph
1148 rErrorPosInText = ModelToViewHelper::ConvertToViewPosition( pConversionMap, nBegin );
1150 sal_Int32 nStartOfSentence = ModelToViewHelper::ConvertToViewPosition( pConversionMap, pWrong->getSentenceStart( nBegin ) );
1151 sal_Int32 nEndOfSentence = ModelToViewHelper::ConvertToViewPosition( pConversionMap, pWrong->getSentenceEnd( nBegin ) );
1152 if( nEndOfSentence == STRING_LEN )
1154 /* if( nStartOfSentence == 0 )
1156 nStartOfSentence = -1;
1157 nEndOfSentence = -1;
1159 else */
1160 nEndOfSentence = aExpandText.getLength();
1163 rResult = xGCIterator->checkSentenceAtPosition(
1164 xDoc, xFlatPara, aExpandText, lang::Locale(), nStartOfSentence, nEndOfSentence, rErrorPosInText );
1165 bRes = true;
1167 // get suggestions to use for the specific error position
1168 sal_Int32 nErrors = rResult.aErrors.getLength();
1169 rSuggestions.realloc( 0 );
1170 for (sal_Int32 i = 0; i < nErrors; ++i )
1172 // return suggestions for first error that includes the given error position
1173 const linguistic2::SingleProofreadingError &rError = rResult.aErrors[i];
1174 if (rError.nErrorStart <= rErrorPosInText &&
1175 rErrorPosInText < rError.nErrorStart + rError.nErrorLength)
1177 rSuggestions = rError.aSuggestions;
1178 rErrorIndexInResult = i;
1179 break;
1184 if (rResult.aErrors.getLength() > 0) // error found?
1186 //save the start and end positons of the line and the starting point
1187 Push();
1188 LeftMargin();
1189 xub_StrLen nLineStart = GetCrsr()->GetPoint()->nContent.GetIndex();
1190 RightMargin();
1191 xub_StrLen nLineEnd = GetCrsr()->GetPoint()->nContent.GetIndex();
1192 Pop(FALSE);
1194 #if OSL_DEBUG_LEVEL > 1
1195 // pNode->GetGrammarCheck()->Invalidate( 0, STRING_LEN );
1196 // pNode->SetGrammarCheckDirty( true );
1197 #endif
1198 // make sure the selection build later from the
1199 // data below does not include footnotes and other
1200 // "in word" character to the left and right in order
1201 // to preserve those. Therefore count those "in words"
1202 // in order to modify the selection accordingly.
1203 const sal_Unicode* pChar = aText.GetBuffer();
1204 xub_StrLen nLeft = 0;
1205 while (pChar && *pChar++ == CH_TXTATR_INWORD)
1206 ++nLeft;
1207 pChar = aText.Len() ? aText.GetBuffer() + aText.Len() - 1 : 0;
1208 xub_StrLen nRight = 0;
1209 while (pChar && *pChar-- == CH_TXTATR_INWORD)
1210 ++nRight;
1212 aPos.nContent = nBegin + nLeft;
1213 pCrsr = GetCrsr();
1214 *pCrsr->GetPoint() = aPos;
1215 pCrsr->SetMark();
1216 ExtendSelection( sal_True, nLen - nLeft - nRight );
1217 //no determine the rectangle in the current line
1218 xub_StrLen nWordStart = (nBegin + nLeft) < nLineStart ? nLineStart : nBegin + nLeft;
1219 //take one less than the line end - otherwise the next line would be calculated
1220 xub_StrLen nWordEnd = (nBegin + nLen - nLeft - nRight) > nLineEnd ? nLineEnd - 1: (nBegin + nLen - nLeft - nRight);
1221 Push();
1222 pCrsr->DeleteMark();
1223 SwIndex& rContent = GetCrsr()->GetPoint()->nContent;
1224 rContent = nWordStart;
1225 SwRect aStartRect;
1226 SwCrsrMoveState aState;
1227 aState.bRealWidth = TRUE;
1228 SwCntntNode* pCntntNode = pCrsr->GetCntntNode();
1229 SwCntntFrm *pCntntFrame = pCntntNode->GetFrm(pPt, pCrsr->GetPoint(), FALSE);
1231 pCntntFrame->GetCharRect( aStartRect, *pCrsr->GetPoint(), &aState );
1232 rContent = nWordEnd;
1233 SwRect aEndRect;
1234 pCntntFrame->GetCharRect( aEndRect, *pCrsr->GetPoint(),&aState );
1235 rSelectRect = aStartRect.Union( aEndRect );
1236 Pop(FALSE);
1241 return bRes;
1244 /*-- 18.09.2003 15:08:18---------------------------------------------------
1246 -----------------------------------------------------------------------*/
1247 bool SwEditShell::SpellSentence(::svx::SpellPortions& rPortions, bool bIsGrammarCheck)
1249 ASSERT( pSpellIter, "SpellIter missing" );
1250 if(!pSpellIter)
1251 return false;
1252 bool bRet = pSpellIter->SpellSentence(rPortions, bIsGrammarCheck);
1254 // make Selection visible - this should simply move the
1255 // cursor to the end of the sentence
1256 StartAction();
1257 EndAction();
1258 return bRet;
1260 /*-- 08.09.2008 09:35:19---------------------------------------------------
1261 make SpellIter start with the current sentence when called next time
1262 -----------------------------------------------------------------------*/
1263 void SwEditShell::PutSpellingToSentenceStart()
1265 ASSERT( pSpellIter, "SpellIter missing" );
1266 if(!pSpellIter)
1267 return;
1268 pSpellIter->ToSentenceStart();
1270 /*-- 02.02.2005 14:34:41---------------------------------------------------
1272 -----------------------------------------------------------------------*/
1273 sal_uInt32 lcl_CountRedlines(
1274 const ::svx::SpellPortions& rLastPortions)
1276 sal_uInt32 nRet = 0;
1277 SpellPortions::const_iterator aIter = rLastPortions.begin();
1278 for( ; aIter != rLastPortions.end(); ++aIter)
1280 if( aIter->bIsHidden )
1281 ++nRet;
1283 return nRet;
1285 /*-- 18.09.2003 15:08:20---------------------------------------------------
1287 -----------------------------------------------------------------------*/
1288 void SwEditShell::ApplyChangedSentence(const ::svx::SpellPortions& rNewPortions, bool bIsGrammarCheck)
1290 ASSERT( pSpellIter, "SpellIter missing" );
1291 if(pSpellIter)
1293 const SpellPortions& rLastPortions = pSpellIter->GetLastPortions();
1294 const SpellContentPositions rLastPositions = pSpellIter->GetLastPositions();
1295 ASSERT(rLastPortions.size() > 0 &&
1296 rLastPortions.size() == rLastPositions.size(),
1297 "last vectors of spelling results are not set or not equal")
1299 // iterate over the new portions, beginning at the end to take advantage of the previously
1300 // saved content positions
1302 if(!rLastPortions.size())
1303 return;
1305 SwPaM *pCrsr = GetCrsr();
1306 pDoc->StartUndo( UNDO_OVERWRITE, NULL );
1307 StartAction();
1308 sal_uInt32 nRedlinePortions = lcl_CountRedlines(rLastPortions);
1309 if((rLastPortions.size() - nRedlinePortions) == rNewPortions.size())
1311 //the simple case: the same number of elements on both sides
1312 //each changed element has to be applied to the corresponding source element
1313 svx::SpellPortions::const_iterator aCurrentNewPortion = rNewPortions.end();
1314 SpellPortions::const_iterator aCurrentOldPortion = rLastPortions.end();
1315 SpellContentPositions::const_iterator aCurrentOldPosition = rLastPositions.end();
1318 --aCurrentNewPortion;
1319 --aCurrentOldPortion;
1320 --aCurrentOldPosition;
1321 //jump over redline portions
1322 while(aCurrentOldPortion->bIsHidden)
1324 --aCurrentOldPortion;
1325 --aCurrentOldPosition;
1327 if ( !pCrsr->HasMark() )
1328 pCrsr->SetMark();
1329 pCrsr->GetPoint()->nContent = aCurrentOldPosition->nLeft;
1330 pCrsr->GetMark()->nContent = aCurrentOldPosition->nRight;
1331 USHORT nScriptType = GetI18NScriptTypeOfLanguage( aCurrentNewPortion->eLanguage );
1332 USHORT nLangWhichId = RES_CHRATR_LANGUAGE;
1333 switch(nScriptType)
1335 case SCRIPTTYPE_ASIAN : nLangWhichId = RES_CHRATR_CJK_LANGUAGE; break;
1336 case SCRIPTTYPE_COMPLEX : nLangWhichId = RES_CHRATR_CTL_LANGUAGE; break;
1338 if(aCurrentNewPortion->sText != aCurrentOldPortion->sText)
1340 //change text ...
1341 pDoc->DeleteAndJoin(*pCrsr);
1342 // ... and apply language if necessary
1343 if(aCurrentNewPortion->eLanguage != aCurrentOldPortion->eLanguage)
1344 SetAttr( SvxLanguageItem(aCurrentNewPortion->eLanguage, nLangWhichId), nLangWhichId );
1345 pDoc->Insert(*pCrsr, aCurrentNewPortion->sText, true);
1347 else if(aCurrentNewPortion->eLanguage != aCurrentOldPortion->eLanguage)
1349 //apply language
1350 SetAttr( SvxLanguageItem(aCurrentNewPortion->eLanguage, nLangWhichId), nLangWhichId );
1352 else if( aCurrentNewPortion->bIgnoreThisError )
1354 //add the 'ignore' markup to the TextNode's grammar ignore markup list
1355 IgnoreGrammarErrorAt( *pCrsr );
1356 DBG_ERROR("TODO: add ignore mark to text node");
1358 if(aCurrentNewPortion == rNewPortions.begin())
1359 break;
1361 while(aCurrentNewPortion != rNewPortions.begin());
1363 else
1365 //select the complete sentence
1366 SpellContentPositions::const_iterator aCurrentEndPosition = rLastPositions.end();
1367 --aCurrentEndPosition;
1368 SpellContentPositions::const_iterator aCurrentStartPosition = rLastPositions.begin();
1369 pCrsr->GetPoint()->nContent = aCurrentStartPosition->nLeft;
1370 pCrsr->GetMark()->nContent = aCurrentEndPosition->nRight;
1372 //delete the sentence completely
1373 pDoc->DeleteAndJoin(*pCrsr);
1374 svx::SpellPortions::const_iterator aCurrentNewPortion = rNewPortions.begin();
1375 while(aCurrentNewPortion != rNewPortions.end())
1377 //set the language attribute
1378 USHORT nScriptType = GetScriptType();
1379 USHORT nLangWhichId = RES_CHRATR_LANGUAGE;
1380 switch(nScriptType)
1382 case SCRIPTTYPE_ASIAN : nLangWhichId = RES_CHRATR_CJK_LANGUAGE; break;
1383 case SCRIPTTYPE_COMPLEX : nLangWhichId = RES_CHRATR_CTL_LANGUAGE; break;
1385 SfxItemSet aSet(GetAttrPool(), nLangWhichId, nLangWhichId, 0);
1386 GetCurAttr( aSet );
1387 const SvxLanguageItem& rLang = static_cast<const SvxLanguageItem& >(aSet.Get(nLangWhichId));
1388 if(rLang.GetLanguage() != aCurrentNewPortion->eLanguage)
1389 SetAttr( SvxLanguageItem(aCurrentNewPortion->eLanguage, nLangWhichId) );
1390 //insert the new string
1391 pDoc->Insert(*pCrsr, aCurrentNewPortion->sText, true);
1393 //set the cursor to the end of the inserted string
1394 *pCrsr->Start() = *pCrsr->End();
1395 ++aCurrentNewPortion;
1399 //set the cursor to the end of the new sentence
1400 *pCrsr->Start() = *pCrsr->End();
1401 if( bIsGrammarCheck)
1403 //in grammar check the current sentence has to be checked again
1404 GoStartSentence();
1406 pDoc->EndUndo( UNDO_OVERWRITE, NULL );
1407 EndAction();
1410 /*-- 02.02.2005 10:46:45---------------------------------------------------
1411 collect all deleted redlines of the current text node beginning at the
1412 start of the cursor position
1413 -----------------------------------------------------------------------*/
1414 SpellContentPositions lcl_CollectDeletedRedlines(SwEditShell* pSh)
1416 SpellContentPositions aRedlines;
1417 SwDoc* pDoc = pSh->GetDoc();
1418 const bool bShowChg = IDocumentRedlineAccess::IsShowChanges( pDoc->GetRedlineMode() );
1419 if ( bShowChg )
1421 SwPaM *pCrsr = pSh->GetCrsr();
1422 const SwPosition* pStartPos = pCrsr->Start();
1423 const SwTxtNode* pTxtNode = pCrsr->GetNode()->GetTxtNode();
1425 USHORT nAct = pDoc->GetRedlinePos( *pTxtNode, USHRT_MAX );
1426 const xub_StrLen nStartIndex = pStartPos->nContent.GetIndex();
1427 for ( ; nAct < pDoc->GetRedlineTbl().Count(); nAct++ )
1429 const SwRedline* pRed = pDoc->GetRedlineTbl()[ nAct ];
1431 if ( pRed->Start()->nNode > pTxtNode->GetIndex() )
1432 break;
1434 if( nsRedlineType_t::REDLINE_DELETE == pRed->GetType() )
1436 xub_StrLen nStart, nEnd;
1437 pRed->CalcStartEnd( pTxtNode->GetIndex(), nStart, nEnd );
1438 if(nStart >= nStartIndex || nEnd >= nStartIndex)
1440 SpellContentPosition aAdd;
1441 aAdd.nLeft = nStart;
1442 aAdd.nRight = nEnd;
1443 aRedlines.push_back(aAdd);
1448 return aRedlines;
1450 /*-- 02.02.2005 11:06:12---------------------------------------------------
1451 remove the redline positions after the current selection
1452 -----------------------------------------------------------------------*/
1453 void lcl_CutRedlines( SpellContentPositions& aDeletedRedlines, SwEditShell* pSh )
1455 if(!aDeletedRedlines.empty())
1457 SwPaM *pCrsr = pSh->GetCrsr();
1458 const SwPosition* pEndPos = pCrsr->End();
1459 xub_StrLen nEnd = pEndPos->nContent.GetIndex();
1460 while(!aDeletedRedlines.empty() &&
1461 aDeletedRedlines.back().nLeft > nEnd)
1463 aDeletedRedlines.pop_back();
1467 /*-- 02.02.2005 11:43:00---------------------------------------------------
1469 -----------------------------------------------------------------------*/
1470 SpellContentPosition lcl_FindNextDeletedRedline(
1471 const SpellContentPositions& rDeletedRedlines,
1472 xub_StrLen nSearchFrom )
1474 SpellContentPosition aRet;
1475 aRet.nLeft = aRet.nRight = STRING_MAXLEN;
1476 if(!rDeletedRedlines.empty())
1478 SpellContentPositions::const_iterator aIter = rDeletedRedlines.begin();
1479 for( ; aIter != rDeletedRedlines.end(); ++aIter)
1481 if(aIter->nLeft < nSearchFrom)
1482 continue;
1483 aRet = *aIter;
1484 break;
1487 return aRet;
1489 /*-- 18.09.2003 15:08:20---------------------------------------------------
1491 -----------------------------------------------------------------------*/
1492 bool SwSpellIter::SpellSentence(::svx::SpellPortions& rPortions, bool bIsGrammarCheck)
1494 bool bRet = false;
1495 aLastPortions.clear();
1496 aLastPositions.clear();
1498 SwEditShell *pMySh = GetSh();
1499 if( !pMySh )
1500 return false;
1502 ASSERT( GetEnd(), "SwEditShell::SpellSentence() ohne Start?");
1504 uno::Reference< XSpellAlternatives > xSpellRet;
1505 linguistic2::ProofreadingResult aGrammarResult;
1506 sal_Bool bGoOn = sal_True;
1507 bool bGrammarErrorFound = false;
1508 do {
1509 SwPaM *pCrsr = pMySh->GetCrsr();
1510 if ( !pCrsr->HasMark() )
1511 pCrsr->SetMark();
1513 *pCrsr->GetPoint() = *GetCurr();
1514 *pCrsr->GetMark() = *GetEnd();
1516 if( bBackToStartOfSentence )
1518 pMySh->GoStartSentence();
1519 bBackToStartOfSentence = false;
1521 uno::Any aSpellRet =
1522 pMySh->GetDoc()->Spell(*pCrsr,
1523 xSpeller, 0, 0, bIsGrammarCheck );
1524 aSpellRet >>= xSpellRet;
1525 aSpellRet >>= aGrammarResult;
1526 bGoOn = GetCrsrCnt() > 1;
1527 bGrammarErrorFound = aGrammarResult.aErrors.getLength() > 0;
1528 if( xSpellRet.is() || bGrammarErrorFound )
1530 bGoOn = sal_False;
1531 SwPosition* pNewPoint = new SwPosition( *pCrsr->GetPoint() );
1532 SwPosition* pNewMark = new SwPosition( *pCrsr->GetMark() );
1534 SetCurr( pNewPoint );
1535 SetCurrX( pNewMark );
1537 if( bGoOn )
1539 pMySh->Pop( sal_False );
1540 pCrsr = pMySh->GetCrsr();
1541 if ( *pCrsr->GetPoint() > *pCrsr->GetMark() )
1542 pCrsr->Exchange();
1543 SwPosition* pNew = new SwPosition( *pCrsr->GetPoint() );
1544 SetStart( pNew );
1545 pNew = new SwPosition( *pCrsr->GetMark() );
1546 SetEnd( pNew );
1547 pNew = new SwPosition( *GetStart() );
1548 SetCurr( pNew );
1549 pNew = new SwPosition( *pNew );
1550 SetCurrX( pNew );
1551 pCrsr->SetMark();
1552 --GetCrsrCnt();
1555 while ( bGoOn );
1556 if(xSpellRet.is() || bGrammarErrorFound)
1558 //an error has been found
1559 //To fill the spell portions the beginning of the sentence has to be found
1560 SwPaM *pCrsr = pMySh->GetCrsr();
1561 //set the mark to the right if necessary
1562 if ( *pCrsr->GetPoint() > *pCrsr->GetMark() )
1563 pCrsr->Exchange();
1564 //the cursor has to be collapsed on the left to go to the start of the sentence - if sentence ends inside of the error
1565 pCrsr->DeleteMark();
1566 pCrsr->SetMark();
1567 BOOL bStartSent = 0 != pMySh->GoStartSentence();
1568 SpellContentPositions aDeletedRedlines = lcl_CollectDeletedRedlines(pMySh);
1569 if(bStartSent)
1571 //create a portion from the start part
1572 AddPortion(0, 0, aDeletedRedlines);
1574 //Set the cursor to the error already found
1575 *pCrsr->GetPoint() = *GetCurrX();
1576 *pCrsr->GetMark() = *GetCurr();
1577 AddPortion(xSpellRet, &aGrammarResult, aDeletedRedlines);
1580 //save the end position of the error to continue from here
1581 SwPosition aSaveStartPos = *pCrsr->End();
1582 //determine the end of the current sentence
1583 if ( *pCrsr->GetPoint() < *pCrsr->GetMark() )
1584 pCrsr->Exchange();
1585 //again collapse to start marking after the end of the error
1586 pCrsr->DeleteMark();
1587 pCrsr->SetMark();
1589 pMySh->GoEndSentence();
1590 if( bGrammarErrorFound )
1592 rtl::OUString aExpandText;
1593 const ModelToViewHelper::ConversionMap* pConversionMap = ((SwTxtNode*)pCrsr->GetNode())->BuildConversionMap( aExpandText );
1594 xub_StrLen nSentenceEnd = (xub_StrLen)ModelToViewHelper::ConvertToViewPosition( pConversionMap, aGrammarResult.nBehindEndOfSentencePosition );
1595 // remove trailing space
1596 if( aExpandText[nSentenceEnd - 1] == ' ' )
1597 --nSentenceEnd;
1598 if( pCrsr->End()->nContent.GetIndex() < nSentenceEnd )
1600 pCrsr->End()->nContent.Assign(
1601 pCrsr->End()->nNode.GetNode().GetCntntNode(), nSentenceEnd);
1605 lcl_CutRedlines( aDeletedRedlines, pMySh );
1606 //save the 'global' end of the spellchecking
1607 const SwPosition aSaveEndPos = *GetEnd();
1608 //set the sentence end as 'local' end
1609 SetEnd( new SwPosition( *pCrsr->End() ));
1611 *pCrsr->GetPoint() = aSaveStartPos;
1612 *pCrsr->GetMark() = *GetEnd();
1613 //now the rest of the sentence has to be searched for errors
1614 // for each error the non-error text between the current and the last error has
1615 // to be added to the portions - if necessary broken into same-language-portions
1616 if( !bGrammarErrorFound ) //in grammar check there's only one error returned
1620 xSpellRet = 0;
1621 // don't search for grammar errors here anymore!
1622 pMySh->GetDoc()->Spell(*pCrsr,
1623 xSpeller, 0, 0, false ) >>= xSpellRet;
1624 if ( *pCrsr->GetPoint() > *pCrsr->GetMark() )
1625 pCrsr->Exchange();
1626 SetCurr( new SwPosition( *pCrsr->GetPoint() ));
1627 SetCurrX( new SwPosition( *pCrsr->GetMark() ));
1629 //if an error has been found go back to the text
1630 //preceeding the error
1631 if(xSpellRet.is())
1633 *pCrsr->GetPoint() = aSaveStartPos;
1634 *pCrsr->GetMark() = *GetCurr();
1636 //add the portion
1637 AddPortion(0, 0, aDeletedRedlines);
1639 if(xSpellRet.is())
1641 *pCrsr->GetPoint() = *GetCurr();
1642 *pCrsr->GetMark() = *GetCurrX();
1643 AddPortion(xSpellRet, 0, aDeletedRedlines);
1644 //move the cursor to the end of the error string
1645 *pCrsr->GetPoint() = *GetCurrX();
1646 //and save the end of the error as new start position
1647 aSaveStartPos = *GetCurrX();
1648 //and the end of the sentence
1649 *pCrsr->GetMark() = *GetEnd();
1651 // if the end of the sentence has already been reached then break here
1652 if(*GetCurrX() >= *GetEnd())
1653 break;
1655 while(xSpellRet.is());
1657 else
1659 //go to the end of sentence as the grammar check returned it
1660 // at this time the Point is behind the grammar error
1661 // and the mark points to the sentence end as
1662 if ( *pCrsr->GetPoint() < *pCrsr->GetMark() )
1663 pCrsr->Exchange();
1666 // the part between the last error and the end of the sentence has to be added
1667 *pMySh->GetCrsr()->GetPoint() = *GetEnd();
1668 if(*GetCurrX() < *GetEnd())
1670 AddPortion(0, 0, aDeletedRedlines);
1672 //set the shell cursor to the end of the sentence to prevent a visible selection
1673 *pCrsr->GetMark() = *GetEnd();
1674 if( !bIsGrammarCheck )
1676 //set the current position to the end of the sentence
1677 SetCurr( new SwPosition(*GetEnd()) );
1679 //restore the 'global' end
1680 SetEnd( new SwPosition(aSaveEndPos) );
1681 rPortions = aLastPortions;
1682 bRet = true;
1684 else
1686 //if no error could be found the selection has to be corrected - at least if it's not in the body
1687 *pMySh->GetCrsr()->GetPoint() = *GetEnd();
1688 pMySh->GetCrsr()->DeleteMark();
1691 return bRet;
1694 /*-- 08.09.2008 09:37:15---------------------------------------------------
1696 -----------------------------------------------------------------------*/
1697 void SwSpellIter::ToSentenceStart()
1699 bBackToStartOfSentence = true;
1701 /*-- 08.10.2003 08:49:56---------------------------------------------------
1703 -----------------------------------------------------------------------*/
1704 LanguageType lcl_GetLanguage(SwEditShell& rSh)
1706 USHORT nScriptType = rSh.GetScriptType();
1707 USHORT nLangWhichId = RES_CHRATR_LANGUAGE;
1709 switch(nScriptType)
1711 case SCRIPTTYPE_ASIAN : nLangWhichId = RES_CHRATR_CJK_LANGUAGE; break;
1712 case SCRIPTTYPE_COMPLEX : nLangWhichId = RES_CHRATR_CTL_LANGUAGE; break;
1714 SfxItemSet aSet(rSh.GetAttrPool(), nLangWhichId, nLangWhichId, 0);
1715 rSh.GetCurAttr( aSet );
1716 const SvxLanguageItem& rLang = static_cast<const SvxLanguageItem& >(aSet.Get(nLangWhichId));
1717 return rLang.GetLanguage();
1719 /*-- 08.10.2003 08:53:27---------------------------------------------------
1720 create a text portion at the given position
1721 -----------------------------------------------------------------------*/
1722 void SwSpellIter::CreatePortion(uno::Reference< XSpellAlternatives > xAlt,
1723 linguistic2::ProofreadingResult* pGrammarResult,
1724 bool bIsField, bool bIsHidden)
1726 svx::SpellPortion aPortion;
1727 String sText;
1728 GetSh()->GetSelectedText( sText );
1729 if(sText.Len())
1731 //in case of redlined deletions the selection of an error is not
1732 //the same as the _real_ word
1733 if(xAlt.is())
1734 aPortion.sText = xAlt->getWord();
1735 else if(pGrammarResult)
1737 aPortion.bIsGrammarError = true;
1738 if(pGrammarResult->aErrors.getLength())
1740 aPortion.aGrammarError = pGrammarResult->aErrors[0];
1741 aPortion.sText = pGrammarResult->aText.copy( aPortion.aGrammarError.nErrorStart, aPortion.aGrammarError.nErrorLength );
1742 aPortion.xGrammarChecker = pGrammarResult->xProofreader;
1743 const beans::PropertyValue* pProperties = pGrammarResult->aProperties.getConstArray();
1744 for( sal_Int32 nProp = 0; nProp < pGrammarResult->aProperties.getLength(); ++nProp )
1746 if( pProperties->Name.equalsAscii("DialogTitle") )
1748 pProperties->Value >>= aPortion.sDialogTitle;
1749 break;
1754 else
1755 aPortion.sText = sText;
1756 aPortion.eLanguage = lcl_GetLanguage(*GetSh());
1757 aPortion.bIsField = bIsField;
1758 aPortion.bIsHidden = bIsHidden;
1759 aPortion.xAlternatives = xAlt;
1760 SpellContentPosition aPosition;
1761 SwPaM *pCrsr = GetSh()->GetCrsr();
1762 aPosition.nLeft = pCrsr->Start()->nContent.GetIndex();
1763 aPosition.nRight = pCrsr->End()->nContent.GetIndex();
1764 aLastPortions.push_back(aPortion);
1765 aLastPositions.push_back(aPosition);
1768 /*-- 19.09.2003 13:05:43---------------------------------------------------
1770 -----------------------------------------------------------------------*/
1771 void SwSpellIter::AddPortion(uno::Reference< XSpellAlternatives > xAlt,
1772 linguistic2::ProofreadingResult* pGrammarResult,
1773 const SpellContentPositions& rDeletedRedlines)
1775 SwEditShell *pMySh = GetSh();
1776 String sText;
1777 pMySh->GetSelectedText( sText );
1778 if(sText.Len())
1780 if(xAlt.is() || pGrammarResult != 0)
1782 CreatePortion(xAlt, pGrammarResult, false, false);
1784 else
1786 SwPaM *pCrsr = GetSh()->GetCrsr();
1787 if ( *pCrsr->GetPoint() > *pCrsr->GetMark() )
1788 pCrsr->Exchange();
1789 //save the start and end positions
1790 SwPosition aStart(*pCrsr->GetPoint());
1791 SwPosition aEnd(*pCrsr->GetMark());
1792 //iterate over the text to find changes in language
1793 //set the mark equal to the point
1794 *pCrsr->GetMark() = aStart;
1795 SwTxtNode* pTxtNode = pCrsr->GetNode()->GetTxtNode();
1796 LanguageType eStartLanguage = lcl_GetLanguage(*GetSh());
1797 SpellContentPosition aNextRedline = lcl_FindNextDeletedRedline(
1798 rDeletedRedlines, aStart.nContent.GetIndex() );
1799 if( aNextRedline.nLeft == aStart.nContent.GetIndex() )
1801 //select until the end of the current redline
1802 xub_StrLen nEnd = aEnd.nContent.GetIndex() < aNextRedline.nRight ?
1803 aEnd.nContent.GetIndex() : aNextRedline.nRight;
1804 pCrsr->GetPoint()->nContent.Assign( pTxtNode, nEnd );
1805 CreatePortion(xAlt, pGrammarResult, false, true);
1806 aStart = *pCrsr->End();
1807 //search for next redline
1808 aNextRedline = lcl_FindNextDeletedRedline(
1809 rDeletedRedlines, aStart.nContent.GetIndex() );
1811 while(*pCrsr->GetPoint() < aEnd)
1813 //#125786 in table cell with fixed row height the cursor might not move forward
1814 if(!GetSh()->Right(1, CRSR_SKIP_CELLS))
1815 break;
1817 bool bField = false;
1818 //read the character at the current position to check if it's a field
1819 xub_Unicode cChar = pTxtNode->GetTxt().GetChar( pCrsr->GetMark()->nContent.GetIndex() );
1820 if( CH_TXTATR_BREAKWORD == cChar || CH_TXTATR_INWORD == cChar)
1822 const SwTxtAttr* pTxtAttr = pTxtNode->GetTxtAttr(
1823 pCrsr->GetMark()->nContent.GetIndex(), RES_TXTATR_FIELD );
1824 bField = 0 != pTxtAttr;
1825 if(!bField)
1827 const SwTxtAttr* pTmpTxtAttr = pTxtNode->GetTxtAttr(
1828 pCrsr->GetMark()->nContent.GetIndex(), RES_TXTATR_FTN );
1829 bField = 0 != pTmpTxtAttr;
1831 if(!bField)
1833 const SwTxtAttr* pTmpTxtAttr = pTxtNode->GetTxtAttr(
1834 pCrsr->GetMark()->nContent.GetIndex(), RES_TXTATR_FLYCNT );
1835 bField = 0 != pTmpTxtAttr;
1839 LanguageType eCurLanguage = lcl_GetLanguage(*GetSh());
1840 bool bRedline = aNextRedline.nLeft == pCrsr->GetPoint()->nContent.GetIndex();
1841 // create a portion if the next character
1842 // - is a field,
1843 // - is at the beginning of a deleted redline
1844 // - has a different language
1845 if(bField || bRedline || eCurLanguage != eStartLanguage)
1847 eStartLanguage = eCurLanguage;
1848 //go one step back - the cursor currently selects the first character
1849 //with a different language
1850 //in the case of redlining it's different
1851 if(eCurLanguage != eStartLanguage || bField)
1852 *pCrsr->GetPoint() = *pCrsr->GetMark();
1853 //set to the last start
1854 *pCrsr->GetMark() = aStart;
1855 //create portion should only be called if a selection exists
1856 //there's no selection if there's a field at the beginning
1857 if(*pCrsr->Start() != *pCrsr->End())
1858 CreatePortion(xAlt, pGrammarResult, false, false);
1859 aStart = *pCrsr->End();
1860 //now export the field - if there is any
1861 if(bField)
1863 *pCrsr->GetMark() = *pCrsr->GetPoint();
1864 GetSh()->Right(1, CRSR_SKIP_CELLS);
1865 CreatePortion(xAlt, pGrammarResult, true, false);
1866 aStart = *pCrsr->End();
1869 // if a redline start then create a portion for it
1870 if(bRedline)
1872 *pCrsr->GetMark() = *pCrsr->GetPoint();
1873 //select until the end of the current redline
1874 xub_StrLen nEnd = aEnd.nContent.GetIndex() < aNextRedline.nRight ?
1875 aEnd.nContent.GetIndex() : aNextRedline.nRight;
1876 pCrsr->GetPoint()->nContent.Assign( pTxtNode, nEnd );
1877 CreatePortion(xAlt, pGrammarResult, false, true);
1878 aStart = *pCrsr->End();
1879 //search for next redline
1880 aNextRedline = lcl_FindNextDeletedRedline(
1881 rDeletedRedlines, aStart.nContent.GetIndex() );
1883 *pCrsr->GetMark() = *pCrsr->GetPoint();
1885 pCrsr->SetMark();
1886 *pCrsr->GetMark() = aStart;
1887 CreatePortion(xAlt, pGrammarResult, false, false);
1891 /*-- 07.08.2008 15:01:25---------------------------------------------------
1893 -----------------------------------------------------------------------*/
1894 void SwEditShell::IgnoreGrammarErrorAt( SwPaM& rErrorPosition )
1896 SwTxtNode *pNode;
1897 SwWrongList *pWrong;
1898 SwNodeIndex aIdx = rErrorPosition.Start()->nNode;
1899 SwNodeIndex aEndIdx = rErrorPosition.Start()->nNode;
1900 xub_StrLen nStart = rErrorPosition.Start()->nContent.GetIndex();
1901 xub_StrLen nEnd = STRING_LEN;
1902 while( aIdx <= aEndIdx )
1904 pNode = aIdx.GetNode().GetTxtNode();
1905 if( pNode ) {
1906 if( aIdx == aEndIdx )
1907 nEnd = rErrorPosition.End()->nContent.GetIndex();
1908 pWrong = pNode->GetGrammarCheck();
1909 if( pWrong )
1910 pWrong->RemoveEntry( nStart, nEnd );
1911 pWrong = pNode->GetWrong();
1912 if( pWrong )
1913 pWrong->RemoveEntry( nStart, nEnd );
1914 ::repaintTextFrames( *pNode );
1916 ++aIdx;
1917 nStart = 0;