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