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