xref: /aoo42x/main/sw/source/core/doc/docedt.cxx (revision cdf0e10c)
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 <string.h>			// fuer strchr()
32 #include <hintids.hxx>
33 
34 #include <vcl/sound.hxx>
35 #include <editeng/cscoitem.hxx>
36 #include <editeng/brkitem.hxx>
37 #include <linguistic/lngprops.hxx>
38 #include <com/sun/star/beans/XPropertySet.hpp>
39 #include <com/sun/star/i18n/WordType.hdl>
40 #include <unotools/charclass.hxx>
41 #include <unotools/transliterationwrapper.hxx>
42 #include <fmtanchr.hxx>
43 #include <fmtcntnt.hxx>
44 #include <fmtpdsc.hxx>
45 #include <txtftn.hxx>
46 #include <acorrect.hxx>		// Autokorrektur
47 #include <IMark.hxx>		// fuer SwBookmark
48 #include <cntfrm.hxx>			// fuers Spell
49 #include <crsrsh.hxx>
50 #include <doc.hxx>
51 #include <UndoManager.hxx>
52 #include <docsh.hxx>
53 #include <docary.hxx>
54 #include <doctxm.hxx>		// beim Move: Verzeichnisse korrigieren
55 #include <ftnidx.hxx>
56 #include <ftninfo.hxx>
57 #include <mdiexp.hxx>		// Statusanzeige
58 #include <mvsave.hxx>		// Strukturen zum Sichern beim Move/Delete
59 #include <ndtxt.hxx>
60 #include <pam.hxx>
61 #include <redline.hxx>
62 #include <rootfrm.hxx>			// fuers UpdateFtn
63 #include <splargs.hxx>		// fuer Spell
64 #include <swtable.hxx>
65 #include <swundo.hxx>		// fuer die UndoIds
66 #include <txtfrm.hxx>
67 #include <hints.hxx>
68 #include <UndoSplitMove.hxx>
69 #include <UndoRedline.hxx>
70 #include <UndoOverwrite.hxx>
71 #include <UndoInsert.hxx>
72 #include <UndoDelete.hxx>
73 #include <breakit.hxx>
74 #include <hhcwrp.hxx>
75 #include <breakit.hxx>
76 #include <vcl/msgbox.hxx>
77 #include "comcore.hrc"
78 #include "editsh.hxx"
79 #include <unoflatpara.hxx>
80 #include <SwGrammarMarkUp.hxx>
81 
82 #include <vector>
83 
84 using ::rtl::OUString;
85 using namespace ::com::sun::star;
86 using namespace ::com::sun::star::linguistic2;
87 using namespace ::com::sun::star::i18n;
88 
89 //using namespace ::utl;
90 #ifndef S2U
91 #define S2U(rString) OUString::createFromAscii(rString)
92 #endif
93 
94 struct _SaveRedline
95 {
96 	SwRedline* pRedl;
97 	sal_uInt32 nStt, nEnd;
98 	xub_StrLen nSttCnt, nEndCnt;
99 
100 	_SaveRedline( SwRedline* pR, const SwNodeIndex& rSttIdx )
101 		: pRedl( pR )
102 	{
103 		const SwPosition* pStt = pR->Start(),
104 			* pEnd = pR->GetMark() == pStt ? pR->GetPoint() : pR->GetMark();
105 		sal_uInt32 nSttIdx = rSttIdx.GetIndex();
106 		nStt = pStt->nNode.GetIndex() - nSttIdx;
107 		nSttCnt = pStt->nContent.GetIndex();
108 		if( pR->HasMark() )
109 		{
110 			nEnd = pEnd->nNode.GetIndex() - nSttIdx;
111 			nEndCnt = pEnd->nContent.GetIndex();
112 		}
113 
114 		pRedl->GetPoint()->nNode = 0;
115 		pRedl->GetPoint()->nContent.Assign( 0, 0 );
116 		pRedl->GetMark()->nNode = 0;
117 		pRedl->GetMark()->nContent.Assign( 0, 0 );
118 	}
119 
120 	_SaveRedline( SwRedline* pR, const SwPosition& rPos )
121 		: pRedl( pR )
122 	{
123 		const SwPosition* pStt = pR->Start(),
124 			* pEnd = pR->GetMark() == pStt ? pR->GetPoint() : pR->GetMark();
125 		sal_uInt32 nSttIdx = rPos.nNode.GetIndex();
126 		nStt = pStt->nNode.GetIndex() - nSttIdx;
127 		nSttCnt = pStt->nContent.GetIndex();
128         if( nStt == 0 )
129             nSttCnt = nSttCnt - rPos.nContent.GetIndex();
130 		if( pR->HasMark() )
131 		{
132 			nEnd = pEnd->nNode.GetIndex() - nSttIdx;
133 			nEndCnt = pEnd->nContent.GetIndex();
134             if( nEnd == 0 )
135                 nEndCnt = nEndCnt - rPos.nContent.GetIndex();
136 		}
137 
138 		pRedl->GetPoint()->nNode = 0;
139 		pRedl->GetPoint()->nContent.Assign( 0, 0 );
140 		pRedl->GetMark()->nNode = 0;
141 		pRedl->GetMark()->nContent.Assign( 0, 0 );
142 	}
143 
144 	void SetPos( sal_uInt32 nInsPos )
145 	{
146 		pRedl->GetPoint()->nNode = nInsPos + nStt;
147 		pRedl->GetPoint()->nContent.Assign( pRedl->GetCntntNode(), nSttCnt );
148 		if( pRedl->HasMark() )
149 		{
150 			pRedl->GetMark()->nNode = nInsPos + nEnd;
151 			pRedl->GetMark()->nContent.Assign( pRedl->GetCntntNode(sal_False), nEndCnt );
152 		}
153 	}
154 
155 	void SetPos( const SwPosition& aPos )
156 	{
157 		pRedl->GetPoint()->nNode = aPos.nNode.GetIndex() + nStt;
158         pRedl->GetPoint()->nContent.Assign( pRedl->GetCntntNode(), nSttCnt + ( nStt == 0 ? aPos.nContent.GetIndex() : 0 ) );
159 		if( pRedl->HasMark() )
160 		{
161 			pRedl->GetMark()->nNode = aPos.nNode.GetIndex() + nEnd;
162 			pRedl->GetMark()->nContent.Assign( pRedl->GetCntntNode(sal_False), nEndCnt  + ( nEnd == 0 ? aPos.nContent.GetIndex() : 0 ) );
163 		}
164 	}
165 };
166 
167 SV_DECL_PTRARR_DEL( _SaveRedlines, _SaveRedline*, 0, 4 )
168 
169 SV_IMPL_VARARR( _SaveFlyArr, _SaveFly )
170 SV_IMPL_PTRARR( _SaveRedlines, _SaveRedline* )
171 
172 bool lcl_MayOverwrite( const SwTxtNode *pNode, const xub_StrLen nPos )
173 {
174     sal_Unicode cChr = pNode->GetTxt().GetChar( nPos );
175     return !( ( CH_TXTATR_BREAKWORD == cChr || CH_TXTATR_INWORD == cChr ) &&
176               (0 != pNode->GetTxtAttrForCharAt( nPos ) ) );
177 }
178 
179 void lcl_SkipAttr( const SwTxtNode *pNode, SwIndex &rIdx, xub_StrLen &rStart )
180 {
181 	if( !lcl_MayOverwrite( pNode, rStart ) )
182 	{
183 		// ueberspringe alle SonderAttribute
184 		do {
185 			// "Beep" bei jedem ausgelassenen
186 			Sound::Beep(SOUND_ERROR);
187 			rIdx++;
188 		} while( (rStart = rIdx.GetIndex()) < pNode->GetTxt().Len()
189 			   && !lcl_MayOverwrite(pNode, rStart) );
190 	}
191 }
192 
193 // -----------------------------------------------------------------
194 
195 void _RestFlyInRange( _SaveFlyArr & rArr, const SwNodeIndex& rSttIdx,
196                       const SwNodeIndex* pInsertPos )
197 {
198 	SwPosition aPos( rSttIdx );
199 	for( sal_uInt16 n = 0; n < rArr.Count(); ++n )
200 	{
201 		// neuen Anker anlegen
202 		_SaveFly& rSave = rArr[n];
203 		SwFrmFmt* pFmt = rSave.pFrmFmt;
204 
205         if( rSave.bInsertPosition )
206         {
207             if( pInsertPos != NULL )
208                 aPos.nNode = *pInsertPos;
209             else
210                 aPos.nNode = rSttIdx.GetIndex();
211         }
212         else
213             aPos.nNode = rSttIdx.GetIndex() + rSave.nNdDiff;
214 
215 		aPos.nContent.Assign( 0, 0 );
216 		SwFmtAnchor aAnchor( pFmt->GetAnchor() );
217 		aAnchor.SetAnchor( &aPos );
218 		pFmt->GetDoc()->GetSpzFrmFmts()->Insert(
219 				pFmt, pFmt->GetDoc()->GetSpzFrmFmts()->Count() );
220         pFmt->SetFmtAttr( aAnchor );
221 		SwCntntNode* pCNd = aPos.nNode.GetNode().GetCntntNode();
222 		if( pCNd && pCNd->getLayoutFrm( pFmt->GetDoc()->GetCurrentLayout(), 0, 0, sal_False ) )
223 			pFmt->MakeFrms();
224 	}
225 }
226 
227 void _SaveFlyInRange( const SwNodeRange& rRg, _SaveFlyArr& rArr )
228 {
229 	SwSpzFrmFmts& rFmts = *rRg.aStart.GetNode().GetDoc()->GetSpzFrmFmts();
230 	for( sal_uInt16 n = 0; n < rFmts.Count(); ++n )
231 	{
232         SwFrmFmt *const pFmt = static_cast<SwFrmFmt*>(rFmts[n]);
233         SwFmtAnchor const*const pAnchor = &pFmt->GetAnchor();
234         SwPosition const*const pAPos = pAnchor->GetCntntAnchor();
235         if (pAPos &&
236             ((FLY_AT_PARA == pAnchor->GetAnchorId()) ||
237              (FLY_AT_CHAR == pAnchor->GetAnchorId())) &&
238 			rRg.aStart <= pAPos->nNode && pAPos->nNode < rRg.aEnd )
239 		{
240 			_SaveFly aSave( pAPos->nNode.GetIndex() - rRg.aStart.GetIndex(),
241                             pFmt, sal_False );
242 			rArr.Insert( aSave, rArr.Count());
243 			pFmt->DelFrms();
244 			rFmts.Remove( n--, 1 );
245 		}
246 	}
247 }
248 
249 void _SaveFlyInRange( const SwPaM& rPam, const SwNodeIndex& rInsPos,
250 					   _SaveFlyArr& rArr, bool bMoveAllFlys )
251 {
252 	SwSpzFrmFmts& rFmts = *rPam.GetPoint()->nNode.GetNode().GetDoc()->GetSpzFrmFmts();
253 	SwFrmFmt* pFmt;
254 	const SwFmtAnchor* pAnchor;
255 
256 	const SwPosition* pPos = rPam.Start();
257 	const SwNodeIndex& rSttNdIdx = pPos->nNode;
258 	short nSttOff = (!bMoveAllFlys && rSttNdIdx.GetNode().IsCntntNode() &&
259 					pPos->nContent.GetIndex()) ? 1 : 0;
260 
261 	pPos = rPam.GetPoint() == pPos ? rPam.GetMark() : rPam.GetPoint();
262 	const SwNodeIndex& rEndNdIdx = pPos->nNode;
263 	short nOff = ( bMoveAllFlys || ( rEndNdIdx.GetNode().IsCntntNode() &&
264 				pPos->nContent == rEndNdIdx.GetNode().GetCntntNode()->Len() ))
265 					? 0 : 1;
266 
267 	const SwNodeIndex* pCntntIdx;
268 
269 	for( sal_uInt16 n = 0; n < rFmts.Count(); ++n )
270 	{
271 		sal_Bool bInsPos = sal_False;
272 		pFmt = (SwFrmFmt*)rFmts[n];
273 		pAnchor = &pFmt->GetAnchor();
274         const SwPosition* pAPos = pAnchor->GetCntntAnchor();
275         if (pAPos &&
276             ((FLY_AT_PARA == pAnchor->GetAnchorId()) ||
277              (FLY_AT_CHAR == pAnchor->GetAnchorId())) &&
278 			// nicht verschieben, wenn die InsPos im CntntBereich vom Fly ist
279 			( 0 == ( pCntntIdx = pFmt->GetCntnt().GetCntntIdx() ) ||
280 			  !( *pCntntIdx < rInsPos &&
281 				rInsPos < pCntntIdx->GetNode().EndOfSectionIndex() )) )
282 		{
283 			if( !bMoveAllFlys && rEndNdIdx == pAPos->nNode )
284 			{
285 				// wenn nur teil vom EndNode oder der EndNode und SttNode
286 				// identisch sind, chaos::Anchor nicht anfassen
287 				if( rSttNdIdx != pAPos->nNode )
288 				{
289 					// Anker nur an Anfang/Ende haengen
290 					SwPosition aPos( rSttNdIdx );
291 					SwFmtAnchor aAnchor( *pAnchor );
292 					aAnchor.SetAnchor( &aPos );
293                     pFmt->SetFmtAttr( aAnchor );
294 //        	        ((SwFmtAnchor*)pAnchor)->SetAnchor( &aPos );
295 				}
296 			}
297 			else if( ( rSttNdIdx.GetIndex() + nSttOff <= pAPos->nNode.GetIndex()
298 					&& pAPos->nNode.GetIndex() <= rEndNdIdx.GetIndex() - nOff ) ||
299 						0 != ( bInsPos = rInsPos == pAPos->nNode ))
300 
301 			{
302 				_SaveFly aSave( pAPos->nNode.GetIndex() - rSttNdIdx.GetIndex(),
303                                 pFmt, bInsPos );
304 				rArr.Insert( aSave, rArr.Count());
305 				pFmt->DelFrms();
306 				rFmts.Remove( n--, 1 );
307 			}
308 		}
309 	}
310 }
311 
312 // -----------------------------------------------------------------
313 
314 // loesche und verschiebe alle "Fly's am Absatz", die in der SSelection
315 // liegen. Steht am SPoint ein Fly, wird dieser auf den Mark verschoben.
316 
317 void DelFlyInRange( const SwNodeIndex& rMkNdIdx,
318 					const SwNodeIndex& rPtNdIdx )
319 {
320 	const sal_Bool bDelFwrd = rMkNdIdx.GetIndex() <= rPtNdIdx.GetIndex();
321 
322 	SwDoc* pDoc = rMkNdIdx.GetNode().GetDoc();
323 	SwSpzFrmFmts& rTbl = *pDoc->GetSpzFrmFmts();
324 	for ( sal_uInt16 i = rTbl.Count(); i; )
325 	{
326 		SwFrmFmt *pFmt = rTbl[--i];
327 		const SwFmtAnchor &rAnch = pFmt->GetAnchor();
328         SwPosition const*const pAPos = rAnch.GetCntntAnchor();
329         if (pAPos &&
330             ((rAnch.GetAnchorId() == FLY_AT_PARA) ||
331              (rAnch.GetAnchorId() == FLY_AT_CHAR)) &&
332 			( bDelFwrd
333 				? rMkNdIdx < pAPos->nNode && pAPos->nNode <= rPtNdIdx
334 				: rPtNdIdx <= pAPos->nNode && pAPos->nNode < rMkNdIdx ))
335 		{
336 			// nur den Anker verschieben ??
337 			if( rPtNdIdx == pAPos->nNode )
338 			{
339 				SwFmtAnchor aAnch( pFmt->GetAnchor() );
340 				SwPosition aPos( rMkNdIdx );
341 				aAnch.SetAnchor( &aPos );
342                 pFmt->SetFmtAttr( aAnch );
343 			}
344 			else
345 			{
346 				// wird der Fly geloescht muss auch im seinem Inhalt alle
347 				// Flys geloescht werden !!
348 				const SwFmtCntnt &rCntnt = pFmt->GetCntnt();
349 				if( rCntnt.GetCntntIdx() )
350 				{
351 					DelFlyInRange( *rCntnt.GetCntntIdx(),
352 									SwNodeIndex( *rCntnt.GetCntntIdx()->
353 											GetNode().EndOfSectionNode() ));
354 					// Position kann sich verschoben haben !
355 					if( i > rTbl.Count() )
356 						i = rTbl.Count();
357 					else if( pFmt != rTbl[i] )
358 						i = rTbl.GetPos( pFmt );
359 				}
360 
361 				pDoc->DelLayoutFmt( pFmt );
362 
363                 // --> FME 2004-10-06 #117913# DelLayoutFmt can also
364                 // trigger the deletion of objects.
365     			if( i > rTbl.Count() )
366 					i = rTbl.Count();
367                 // <--
368             }
369 		}
370 	}
371 }
372 
373 
374 bool lcl_SaveFtn( const SwNodeIndex& rSttNd, const SwNodeIndex& rEndNd,
375 				 const SwNodeIndex& rInsPos,
376 				 SwFtnIdxs& rFtnArr, SwFtnIdxs& rSaveArr,
377 				 const SwIndex* pSttCnt = 0, const SwIndex* pEndCnt = 0 )
378 {
379 	bool bUpdateFtn = sal_False;
380     const SwNodes& rNds = rInsPos.GetNodes();
381     const bool bDelFtn = rInsPos.GetIndex() < rNds.GetEndOfAutotext().GetIndex() &&
382                 rSttNd.GetIndex() >= rNds.GetEndOfAutotext().GetIndex();
383     const bool bSaveFtn = !bDelFtn &&
384                     rInsPos.GetIndex() >= rNds.GetEndOfExtras().GetIndex();
385 	if( rFtnArr.Count() )
386 	{
387 
388 		sal_uInt16 nPos;
389 		rFtnArr.SeekEntry( rSttNd, &nPos );
390 		SwTxtFtn* pSrch;
391 		const SwNode* pFtnNd;
392 
393 		// loesche/sicher erstmal alle, die dahinter stehen
394 		while( nPos < rFtnArr.Count() && ( pFtnNd =
395 			&( pSrch = rFtnArr[ nPos ] )->GetTxtNode())->GetIndex()
396 					<= rEndNd.GetIndex() )
397 		{
398 			xub_StrLen nFtnSttIdx = *pSrch->GetStart();
399 			if( ( pEndCnt && pSttCnt )
400 				? (( &rSttNd.GetNode() == pFtnNd &&
401 					 pSttCnt->GetIndex() > nFtnSttIdx) ||
402 				   ( &rEndNd.GetNode() == pFtnNd &&
403 					nFtnSttIdx >= pEndCnt->GetIndex() ))
404 				: ( &rEndNd.GetNode() == pFtnNd ))
405 			{
406 				++nPos;		// weiter suchen
407 			}
408 			else
409 			{
410 				// dann weg damit
411 				if( bDelFtn )
412 				{
413 					SwTxtNode& rTxtNd = (SwTxtNode&)pSrch->GetTxtNode();
414 					SwIndex aIdx( &rTxtNd, nFtnSttIdx );
415                     rTxtNd.EraseText( aIdx, 1 );
416                 }
417 				else
418 				{
419 					pSrch->DelFrms(0);
420 					rFtnArr.Remove( nPos );
421 					if( bSaveFtn )
422 						rSaveArr.Insert( pSrch );
423 				}
424 				bUpdateFtn = sal_True;
425 			}
426 		}
427 
428 		while( nPos-- && ( pFtnNd = &( pSrch = rFtnArr[ nPos ] )->
429 				GetTxtNode())->GetIndex() >= rSttNd.GetIndex() )
430 		{
431 			xub_StrLen nFtnSttIdx = *pSrch->GetStart();
432 			if( !pEndCnt || !pSttCnt ||
433 				!( (( &rSttNd.GetNode() == pFtnNd &&
434 					pSttCnt->GetIndex() > nFtnSttIdx ) ||
435 				   ( &rEndNd.GetNode() == pFtnNd &&
436 					nFtnSttIdx >= pEndCnt->GetIndex() )) ))
437 			{
438 				if( bDelFtn )
439 				{
440 					// dann weg damit
441 					SwTxtNode& rTxtNd = (SwTxtNode&)pSrch->GetTxtNode();
442 					SwIndex aIdx( &rTxtNd, nFtnSttIdx );
443                     rTxtNd.EraseText( aIdx, 1 );
444                 }
445 				else
446 				{
447 					pSrch->DelFrms(0);
448 					rFtnArr.Remove( nPos );
449 					if( bSaveFtn )
450 						rSaveArr.Insert( pSrch );
451 				}
452 				bUpdateFtn = sal_True;
453 			}
454 		}
455 	}
456     // When moving from redline section into document content section, e.g.
457     // after loading a document with (delete-)redlines, the footnote array
458     // has to be adjusted... (#i70572)
459     if( bSaveFtn )
460     {
461         SwNodeIndex aIdx( rSttNd );
462         while( aIdx < rEndNd ) // Check the moved section
463         {
464             SwNode* pNode = &aIdx.GetNode();
465             if( pNode->IsTxtNode() ) // Looking for text nodes...
466             {
467                 SwpHints *pHints =
468                     static_cast<SwTxtNode*>(pNode)->GetpSwpHints();
469                 if( pHints && pHints->HasFtn() ) //...with footnotes
470                 {
471                     bUpdateFtn = sal_True; // Heureka
472                     sal_uInt16 nCount = pHints->Count();
473                     for( sal_uInt16 i = 0; i < nCount; ++i )
474                     {
475                         SwTxtAttr *pAttr = pHints->GetTextHint( i );
476                         if ( pAttr->Which() == RES_TXTATR_FTN )
477                         {
478                             rSaveArr.Insert( static_cast<SwTxtFtn*>(pAttr) );
479                         }
480                     }
481                 }
482             }
483             ++aIdx;
484         }
485     }
486 	return bUpdateFtn;
487 }
488 
489 void lcl_SaveRedlines( const SwPaM& aPam, _SaveRedlines& rArr )
490 {
491 	SwDoc* pDoc = aPam.GetNode()->GetDoc();
492 
493     const SwPosition* pStart = aPam.Start();
494     const SwPosition* pEnd = aPam.End();
495 
496     // get first relevant redline
497 	sal_uInt16 nCurrentRedline;
498     pDoc->GetRedline( *pStart, &nCurrentRedline );
499     if( nCurrentRedline > 0)
500         nCurrentRedline--;
501 
502     // redline mode REDLINE_IGNORE|REDLINE_ON; save old mode
503 	RedlineMode_t eOld = pDoc->GetRedlineMode();
504 	pDoc->SetRedlineMode_intern( (RedlineMode_t)(( eOld & ~nsRedlineMode_t::REDLINE_IGNORE) | nsRedlineMode_t::REDLINE_ON ));
505 
506     // iterate over relevant redlines and decide for each whether it should
507     // be saved, or split + saved
508 	SwRedlineTbl& rRedlineTable = const_cast<SwRedlineTbl&>( pDoc->GetRedlineTbl() );
509     for( ; nCurrentRedline < rRedlineTable.Count(); nCurrentRedline++ )
510     {
511         SwRedline* pCurrent = rRedlineTable[ nCurrentRedline ];
512         SwComparePosition eCompare =
513             ComparePosition( *pCurrent->Start(), *pCurrent->End(),
514                              *pStart, *pEnd);
515 
516         // we must save this redline if it overlaps aPam
517         // (we may have to split it, too)
518         if( eCompare == POS_OVERLAP_BEHIND  ||
519             eCompare == POS_OVERLAP_BEFORE  ||
520             eCompare == POS_OUTSIDE ||
521             eCompare == POS_INSIDE ||
522             eCompare == POS_EQUAL )
523         {
524 			rRedlineTable.Remove( nCurrentRedline-- );
525 
526             // split beginning, if necessary
527             if( eCompare == POS_OVERLAP_BEFORE  ||
528                 eCompare == POS_OUTSIDE )
529             {
530 
531                 SwRedline* pNewRedline = new SwRedline( *pCurrent );
532 			    *pNewRedline->End() = *pStart;
533 			    *pCurrent->Start() = *pStart;
534                 pDoc->AppendRedline( pNewRedline, true );
535             }
536 
537             // split end, if necessary
538             if( eCompare == POS_OVERLAP_BEHIND  ||
539                 eCompare == POS_OUTSIDE )
540             {
541                 SwRedline* pNewRedline = new SwRedline( *pCurrent );
542 	    		*pNewRedline->Start() = *pEnd;
543 		    	*pCurrent->End() = *pEnd;
544                 pDoc->AppendRedline( pNewRedline, true );
545             }
546 
547             // save the current redline
548             _SaveRedline* pSave = new _SaveRedline( pCurrent, *pStart );
549             rArr.C40_INSERT( _SaveRedline, pSave, rArr.Count() );
550         }
551     }
552 
553     // restore old redline mode
554     pDoc->SetRedlineMode_intern( eOld );
555 }
556 
557 void lcl_RestoreRedlines( SwDoc* pDoc, const SwPosition& rPos, _SaveRedlines& rArr )
558 {
559 	RedlineMode_t eOld = pDoc->GetRedlineMode();
560 	pDoc->SetRedlineMode_intern( (RedlineMode_t)(( eOld & ~nsRedlineMode_t::REDLINE_IGNORE) | nsRedlineMode_t::REDLINE_ON ));
561 
562 	for( sal_uInt16 n = 0; n < rArr.Count(); ++n )
563 	{
564 		_SaveRedline* pSave = rArr[ n ];
565 		pSave->SetPos( rPos );
566 		pDoc->AppendRedline( pSave->pRedl, true );
567 	}
568 
569 	pDoc->SetRedlineMode_intern( eOld );
570 }
571 
572 
573 void lcl_SaveRedlines( const SwNodeRange& rRg, _SaveRedlines& rArr )
574 {
575 	SwDoc* pDoc = rRg.aStart.GetNode().GetDoc();
576 	sal_uInt16 nRedlPos;
577 	SwPosition aSrchPos( rRg.aStart ); aSrchPos.nNode--;
578 	aSrchPos.nContent.Assign( aSrchPos.nNode.GetNode().GetCntntNode(), 0 );
579 	if( pDoc->GetRedline( aSrchPos, &nRedlPos ) && nRedlPos )
580 		--nRedlPos;
581 	else if( nRedlPos >= pDoc->GetRedlineTbl().Count() )
582 		return ;
583 
584 	RedlineMode_t eOld = pDoc->GetRedlineMode();
585 	pDoc->SetRedlineMode_intern( (RedlineMode_t)(( eOld & ~nsRedlineMode_t::REDLINE_IGNORE) | nsRedlineMode_t::REDLINE_ON ));
586 	SwRedlineTbl& rRedlTbl = (SwRedlineTbl&)pDoc->GetRedlineTbl();
587 
588 	do {
589 		SwRedline* pTmp = rRedlTbl[ nRedlPos ];
590 
591 		const SwPosition* pRStt = pTmp->Start(),
592 						* pREnd = pTmp->GetMark() == pRStt
593 							? pTmp->GetPoint() : pTmp->GetMark();
594 
595 		if( pRStt->nNode < rRg.aStart )
596 		{
597 			if( pREnd->nNode > rRg.aStart && pREnd->nNode < rRg.aEnd )
598 			{
599 				// Kopie erzeugen und Ende vom Original ans Ende des
600 				// MoveBereiches setzen. Die Kopie wird mit verschoben
601 				SwRedline* pNewRedl = new SwRedline( *pTmp );
602 				SwPosition* pTmpPos = pNewRedl->Start();
603 				pTmpPos->nNode = rRg.aStart;
604 				pTmpPos->nContent.Assign(
605 							pTmpPos->nNode.GetNode().GetCntntNode(), 0 );
606 
607 				_SaveRedline* pSave = new _SaveRedline( pNewRedl, rRg.aStart );
608 //				rArr.Insert( pSave, rArr.Count() );
609 				rArr.C40_INSERT( _SaveRedline, pSave, rArr.Count() );
610 
611 				pTmpPos = pTmp->End();
612 				pTmpPos->nNode = rRg.aEnd;
613 				pTmpPos->nContent.Assign(
614 							pTmpPos->nNode.GetNode().GetCntntNode(), 0 );
615 			}
616 			else if( pREnd->nNode == rRg.aStart )
617 			{
618 				SwPosition* pTmpPos = pTmp->End();
619 				pTmpPos->nNode = rRg.aEnd;
620 				pTmpPos->nContent.Assign(
621 							pTmpPos->nNode.GetNode().GetCntntNode(), 0 );
622 			}
623 		}
624 		else if( pRStt->nNode < rRg.aEnd )
625 		{
626 			rRedlTbl.Remove( nRedlPos-- );
627 			if( pREnd->nNode < rRg.aEnd ||
628 				( pREnd->nNode == rRg.aEnd && !pREnd->nContent.GetIndex()) )
629 			{
630 				// gesamt verschieben
631 				_SaveRedline* pSave = new _SaveRedline( pTmp, rRg.aStart );
632 //				rArr.Insert( pSave, rArr.Count() );
633 				rArr.C40_INSERT( _SaveRedline, pSave, rArr.Count() );
634 			}
635 			else
636 			{
637 				// aufsplitten
638 				SwRedline* pNewRedl = new SwRedline( *pTmp );
639 				SwPosition* pTmpPos = pNewRedl->End();
640 				pTmpPos->nNode = rRg.aEnd;
641 				pTmpPos->nContent.Assign(
642 							pTmpPos->nNode.GetNode().GetCntntNode(), 0 );
643 
644 				_SaveRedline* pSave = new _SaveRedline( pNewRedl, rRg.aStart );
645 //				rArr.Insert( pSave, rArr.Count() );
646 				rArr.C40_INSERT( _SaveRedline, pSave, rArr.Count() );
647 
648 				pTmpPos = pTmp->Start();
649 				pTmpPos->nNode = rRg.aEnd;
650 				pTmpPos->nContent.Assign(
651 							pTmpPos->nNode.GetNode().GetCntntNode(), 0 );
652 				pDoc->AppendRedline( pTmp, true );
653 			}
654 		}
655 		else
656 			break;
657 
658 	} while( ++nRedlPos < pDoc->GetRedlineTbl().Count() );
659 	pDoc->SetRedlineMode_intern( eOld );
660 }
661 
662 void lcl_RestoreRedlines( SwDoc* pDoc, sal_uInt32 nInsPos, _SaveRedlines& rArr )
663 {
664 	RedlineMode_t eOld = pDoc->GetRedlineMode();
665 	pDoc->SetRedlineMode_intern( (RedlineMode_t)(( eOld & ~nsRedlineMode_t::REDLINE_IGNORE) | nsRedlineMode_t::REDLINE_ON ));
666 
667 	for( sal_uInt16 n = 0; n < rArr.Count(); ++n )
668 	{
669 		_SaveRedline* pSave = rArr[ n ];
670 		pSave->SetPos( nInsPos );
671 		pDoc->AppendRedline( pSave->pRedl, true );
672 	}
673 
674 	pDoc->SetRedlineMode_intern( eOld );
675 }
676 
677 // ------------------------------------------------------------------------
678 // #i59534: Redo of insertion of multiple text nodes runs into trouble
679 // because of unnecessary expanded redlines
680 // From now on this class saves the redline positions of all redlines which ends exact at the
681 // insert position (node _and_ content index)
682 
683 _SaveRedlEndPosForRestore::_SaveRedlEndPosForRestore( const SwNodeIndex& rInsIdx, xub_StrLen nCnt )
684 	: pSavArr( 0 ), pSavIdx( 0 ), nSavCntnt( nCnt )
685 {
686 	SwNode& rNd = rInsIdx.GetNode();
687 	SwDoc* pDest = rNd.GetDoc();
688 	if( pDest->GetRedlineTbl().Count() )
689 	{
690 		sal_uInt16 nFndPos;
691 		const SwPosition* pEnd;
692 		SwPosition aSrcPos( rInsIdx, SwIndex( rNd.GetCntntNode(), nCnt ));
693 		const SwRedline* pRedl = pDest->GetRedline( aSrcPos, &nFndPos );
694 		while( nFndPos-- && *( pEnd = ( pRedl =
695 			pDest->GetRedlineTbl()[ nFndPos ] )->End() ) == aSrcPos && *pRedl->Start() < aSrcPos )
696 		{
697 			if( !pSavArr )
698 			{
699 				pSavArr = new SvPtrarr( 2, 2 );
700 				pSavIdx = new SwNodeIndex( rInsIdx, -1 );
701 			}
702 			void* p = (void*)pEnd;
703 			pSavArr->Insert( p, pSavArr->Count() );
704 		}
705 	}
706 }
707 
708 _SaveRedlEndPosForRestore::~_SaveRedlEndPosForRestore()
709 {
710 	if( pSavArr )
711 	{
712 		delete pSavArr;
713 		delete pSavIdx;
714 	}
715 }
716 
717 void _SaveRedlEndPosForRestore::_Restore()
718 {
719 	(*pSavIdx)++;
720     SwCntntNode* pNode = pSavIdx->GetNode().GetCntntNode();
721     // If there's no content node at the remembered position, we will not restore the old position
722     // This may happen if a table (or section?) will be inserted.
723     if( pNode )
724     {
725         SwPosition aPos( *pSavIdx, SwIndex( pNode, nSavCntnt ));
726         for( sal_uInt16 n = pSavArr->Count(); n; )
727             *((SwPosition*)pSavArr->GetObject( --n )) = aPos;
728     }
729 }
730 
731 
732 // ------------------------------------------------------------------------
733 
734 // Loeschen einer vollstaendigen Section des NodesArray.
735 // Der uebergebene Node steht irgendwo in der gewuenschten Section
736 void SwDoc::DeleteSection( SwNode *pNode )
737 {
738 	ASSERT( pNode, "Kein Node uebergeben." );
739 	SwStartNode* pSttNd = pNode->IsStartNode() ? (SwStartNode*)pNode
740 											   : pNode->StartOfSectionNode();
741 	SwNodeIndex aSttIdx( *pSttNd ), aEndIdx( *pNode->EndOfSectionNode() );
742 
743 	// dann loesche mal alle Fly's, text::Bookmarks, ...
744 	DelFlyInRange( aSttIdx, aEndIdx );
745 	DeleteRedline( *pSttNd, true, USHRT_MAX );
746 	_DelBookmarks(aSttIdx, aEndIdx);
747 
748 	{
749 		// alle Crsr/StkCrsr/UnoCrsr aus dem Loeschbereich verschieben
750 		SwNodeIndex aMvStt( aSttIdx, 1 );
751 		CorrAbs( aMvStt, aEndIdx, SwPosition( aSttIdx ), sal_True );
752 	}
753 
754 	GetNodes().DelNodes( aSttIdx, aEndIdx.GetIndex() - aSttIdx.GetIndex() + 1 );
755 }
756 
757 
758 void SwDoc::SetModified(SwPaM &rPaM)
759 {
760     SwDataChanged aTmp( rPaM, 0 );
761     SetModified();
762 }
763 
764 /*************************************************************************
765  *				  SwDoc::Overwrite()
766  ************************************************************************/
767 
768 bool SwDoc::Overwrite( const SwPaM &rRg, const String &rStr )
769 {
770 	SwPosition& rPt = *(SwPosition*)rRg.GetPoint();
771 	if( pACEWord )					// Aufnahme in die Autokorrektur
772 	{
773 		if( 1 == rStr.Len() )
774 			pACEWord->CheckChar( rPt, rStr.GetChar( 0 ) );
775 		delete pACEWord, pACEWord = 0;
776 	}
777 
778 	SwTxtNode *pNode = rPt.nNode.GetNode().GetTxtNode();
779 	if(!pNode)
780 		return sal_False;
781 
782     if (GetIDocumentUndoRedo().DoesUndo())
783     {
784         GetIDocumentUndoRedo().ClearRedo(); // AppendUndo not always called
785     }
786 
787 	sal_uInt16 nOldAttrCnt = pNode->GetpSwpHints()
788 								? pNode->GetpSwpHints()->Count() : 0;
789 	SwDataChanged aTmp( rRg, 0 );
790 	SwIndex& rIdx = rPt.nContent;
791 	xub_StrLen nStart = 0;
792 
793 	sal_Unicode c;
794 	String aStr;
795 
796 	sal_Bool bOldExpFlg = pNode->IsIgnoreDontExpand();
797 	pNode->SetIgnoreDontExpand( sal_True );
798 
799 	for( xub_StrLen nCnt = 0; nCnt < rStr.Len(); ++nCnt )
800 	{
801 		// hinter das Zeichen (zum aufspannen der Attribute !!)
802         nStart = rIdx.GetIndex();
803         if ( nStart < pNode->GetTxt().Len() )
804         {
805             lcl_SkipAttr( pNode, rIdx, nStart );
806         }
807 		c = rStr.GetChar( nCnt );
808         if (GetIDocumentUndoRedo().DoesUndo())
809         {
810             bool bMerged(false);
811             if (GetIDocumentUndoRedo().DoesGroupUndo())
812             {
813                 SwUndo *const pUndo = GetUndoManager().GetLastUndo();
814                 SwUndoOverwrite *const pUndoOW(
815                     dynamic_cast<SwUndoOverwrite *>(pUndo) );
816                 if (pUndoOW)
817                 {
818                     // if CanGrouping() returns true it's already merged
819                     bMerged = pUndoOW->CanGrouping( this, rPt, c );
820                 }
821             }
822             if (!bMerged)
823             {
824                 SwUndo *const pUndoOW( new SwUndoOverwrite(this, rPt, c) );
825                 GetIDocumentUndoRedo().AppendUndo(pUndoOW);
826             }
827         }
828         else
829         {
830 			// hinter das Zeichen (zum Aufspannen der Attribute !!)
831 			if( nStart < pNode->GetTxt().Len() )
832 				rIdx++;
833             pNode->InsertText( c, rIdx, INS_EMPTYEXPAND );
834 			if( nStart+1 < rIdx.GetIndex() )
835 			{
836 				rIdx = nStart;
837                 pNode->EraseText( rIdx, 1 );
838 				rIdx++;
839 			}
840 		}
841 	}
842 	pNode->SetIgnoreDontExpand( bOldExpFlg );
843 
844 	sal_uInt16 nNewAttrCnt = pNode->GetpSwpHints()
845 								? pNode->GetpSwpHints()->Count() : 0;
846 	if( nOldAttrCnt != nNewAttrCnt )
847 	{
848 		SwUpdateAttr aHint( 0, 0, 0 );
849         pNode->ModifyBroadcast( 0, &aHint, TYPE( SwCrsrShell ) );
850 	}
851 
852     if (!GetIDocumentUndoRedo().DoesUndo() &&
853         !IsIgnoreRedline() && GetRedlineTbl().Count())
854     {
855 		SwPaM aPam( rPt.nNode, nStart, rPt.nNode, rPt.nContent.GetIndex() );
856 		DeleteRedline( aPam, true, USHRT_MAX );
857 	}
858 	else if( IsRedlineOn() )
859 	{
860         // FIXME: this redline is WRONG: there is no DELETE, and the skipped
861         // characters are also included in aPam
862 		SwPaM aPam( rPt.nNode, nStart, rPt.nNode, rPt.nContent.GetIndex() );
863 		AppendRedline( new SwRedline( nsRedlineType_t::REDLINE_INSERT, aPam ), true);
864 	}
865 
866 	SetModified();
867 	return sal_True;
868 }
869 
870 
871 bool SwDoc::MoveAndJoin( SwPaM& rPaM, SwPosition& rPos, SwMoveFlags eMvFlags )
872 {
873 	SwNodeIndex aIdx( rPaM.Start()->nNode );
874 	sal_Bool bJoinTxt = aIdx.GetNode().IsTxtNode();
875 	sal_Bool bOneNode = rPaM.GetPoint()->nNode == rPaM.GetMark()->nNode;
876 	aIdx--;				// vor den Move Bereich !!
877 
878     bool bRet = MoveRange( rPaM, rPos, eMvFlags );
879 	if( bRet && !bOneNode )
880 	{
881 		if( bJoinTxt )
882 			aIdx++;
883 		SwTxtNode * pTxtNd = aIdx.GetNode().GetTxtNode();
884 		SwNodeIndex aNxtIdx( aIdx );
885 		if( pTxtNd && pTxtNd->CanJoinNext( &aNxtIdx ) )
886 		{
887 			{   // Block wegen SwIndex in den Node !!
888 				CorrRel( aNxtIdx, SwPosition( aIdx, SwIndex( pTxtNd,
889 							pTxtNd->GetTxt().Len() ) ), 0, sal_True );
890 			}
891 			pTxtNd->JoinNext();
892 		}
893 	}
894 	return bRet;
895 }
896 
897 // mst: it seems that this is mostly used by SwDoc internals; the only
898 // way to call this from the outside seems to be the special case in
899 // SwDoc::CopyRange (but i have not managed to actually hit that case)
900 bool SwDoc::MoveRange( SwPaM& rPaM, SwPosition& rPos, SwMoveFlags eMvFlags )
901 {
902 	// keine Moves-Abfangen
903 	const SwPosition *pStt = rPaM.Start(), *pEnd = rPaM.End();
904 	if( !rPaM.HasMark() || *pStt >= *pEnd || (*pStt <= rPos && rPos < *pEnd))
905         return false;
906 
907 	// sicher die absatzgebundenen Flys, damit sie verschoben werden koennen.
908 	_SaveFlyArr aSaveFlyArr;
909 	_SaveFlyInRange( rPaM, rPos.nNode, aSaveFlyArr, 0 != ( DOC_MOVEALLFLYS & eMvFlags ) );
910 
911     // save redlines (if DOC_MOVEREDLINES is used)
912     _SaveRedlines aSaveRedl( 0, 4 );
913 	if( DOC_MOVEREDLINES & eMvFlags && GetRedlineTbl().Count() )
914 	{
915 		lcl_SaveRedlines( rPaM, aSaveRedl );
916 
917         // #i17764# unfortunately, code below relies on undos being
918         //          in a particular order, and presence of bookmarks
919         //          will change this order. Hence, we delete bookmarks
920         //          here without undo.
921         ::sw::UndoGuard const undoGuard(GetIDocumentUndoRedo());
922         _DelBookmarks(
923             pStt->nNode,
924             pEnd->nNode,
925             NULL,
926             &pStt->nContent,
927             &pEnd->nContent);
928     }
929 
930 
931 	int bUpdateFtn = sal_False;
932 	SwFtnIdxs aTmpFntIdx;
933 
934 	// falls Undo eingeschaltet, erzeuge das UndoMove-Objekt
935 	SwUndoMove * pUndoMove = 0;
936     if (GetIDocumentUndoRedo().DoesUndo())
937     {
938         GetIDocumentUndoRedo().ClearRedo();
939 		pUndoMove = new SwUndoMove( rPaM, rPos );
940         pUndoMove->SetMoveRedlines( eMvFlags == DOC_MOVEREDLINES );
941 	}
942 	else
943 	{
944 		bUpdateFtn = lcl_SaveFtn( pStt->nNode, pEnd->nNode, rPos.nNode,
945 									GetFtnIdxs(), aTmpFntIdx,
946 									&pStt->nContent, &pEnd->nContent );
947 	}
948 
949 	sal_Bool bSplit = sal_False;
950     SwPaM aSavePam( rPos, rPos );
951 
952 	// stelle den SPoint an den Anfang vom Bereich (Definition)
953 	if( rPaM.GetPoint() == pEnd )
954 		rPaM.Exchange();
955 
956 	// in der EditShell wird nach dem Move ein JoinNext erzeugt, wenn
957 	// vor und nach dem Move ein Text-Node steht.
958 	SwTxtNode* pSrcNd = rPaM.GetPoint()->nNode.GetNode().GetTxtNode();
959 	sal_Bool bCorrSavePam = pSrcNd && pStt->nNode != pEnd->nNode;
960 
961 	// werden ein oder mehr TextNodes bewegt, so wird
962 	// im SwNodes::Move ein SplitNode erzeugt. Dieser Updated aber nicht
963 	// den Cursor. Um das zu verhindern, wird hier ein TextNode angelegt,
964 	// um die Updaterei der Indizies zu erhalten. Nach dem Move wird
965 	// evt. der Node geloescht.
966 
967 	SwTxtNode * pTNd = rPos.nNode.GetNode().GetTxtNode();
968 	if( pTNd && rPaM.GetPoint()->nNode != rPaM.GetMark()->nNode &&
969 		( rPos.nContent.GetIndex() || ( pTNd->Len() && bCorrSavePam  )) )
970 	{
971 		bSplit = sal_True;
972 		xub_StrLen nMkCntnt = rPaM.GetMark()->nContent.GetIndex();
973 
974 		SvULongs aBkmkArr( 15, 15 );
975 		_SaveCntntIdx( this, rPos.nNode.GetIndex(), rPos.nContent.GetIndex(),
976 						aBkmkArr, SAVEFLY_SPLIT );
977 
978         pTNd = static_cast<SwTxtNode*>(pTNd->SplitCntntNode( rPos ));
979 
980 		if( aBkmkArr.Count() )
981 			_RestoreCntntIdx( this, aBkmkArr, rPos.nNode.GetIndex()-1, 0, sal_True );
982 
983 		// jetzt noch den Pam berichtigen !!
984 		if( rPos.nNode == rPaM.GetMark()->nNode )
985 		{
986 			rPaM.GetMark()->nNode = rPos.nNode.GetIndex()-1;
987 			rPaM.GetMark()->nContent.Assign( pTNd, nMkCntnt );
988 		}
989 	}
990 
991 	// setze den Pam um einen "Inhalt" zurueck; dadurch steht er immer
992 	// ausserhalb des manipulierten Bereiches. Falls kein Inhalt mehr vor-
993 	// handen, dann auf den StartNode (es ist immer einer vorhanden !!!)
994     sal_Bool bNullCntnt = !aSavePam.Move( fnMoveBackward, fnGoCntnt );
995 	if( bNullCntnt )
996     {
997         aSavePam.GetPoint()->nNode--;
998     }
999 
1000     // kopiere alle Bookmarks, die im Move Bereich stehen in ein
1001     // Array, das alle Angaben auf die Position als Offset speichert.
1002     // Die neue Zuordung erfolgt nach dem Moven.
1003     ::std::vector< ::sw::mark::SaveBookmark> aSaveBkmks;
1004     _DelBookmarks(
1005         pStt->nNode,
1006         pEnd->nNode,
1007         &aSaveBkmks,
1008         &pStt->nContent,
1009         &pEnd->nContent);
1010 
1011 	// falls durch die vorherigen Loeschungen (z.B. der Fussnoten) kein
1012 	// Bereich mehr existiert, ist das immernoch ein gueltiger Move!
1013 	if( *rPaM.GetPoint() != *rPaM.GetMark() )
1014 	{
1015         // now do the actual move
1016         GetNodes().MoveRange( rPaM, rPos, GetNodes() );
1017 
1018         // after a MoveRange() the Mark is deleted
1019         if ( rPaM.HasMark() ) // => no Move occurred!
1020         {
1021 			delete pUndoMove;
1022             return false;
1023         }
1024     }
1025 	else
1026 		rPaM.DeleteMark();
1027 
1028     ASSERT( *aSavePam.GetMark() == rPos ||
1029             ( aSavePam.GetMark()->nNode.GetNode().GetCntntNode() == NULL ),
1030 			"PaM wurde nicht verschoben, am Anfang/Ende keine ContentNodes?" );
1031     *aSavePam.GetMark() = rPos;
1032 
1033 	rPaM.SetMark();			// um den neuen Bereich eine Sel. aufspannen
1034     pTNd = aSavePam.GetNode()->GetTxtNode();
1035     if (GetIDocumentUndoRedo().DoesUndo())
1036     {
1037 		// korrigiere erstmal den Content vom SavePam
1038 		if( bNullCntnt )
1039         {
1040             aSavePam.GetPoint()->nContent = 0;
1041         }
1042 
1043 		// die Methode SwEditShell::Move() fuegt nach dem Move den Text-Node
1044 		// zusammen, in dem der rPaM steht. Wurde der Inhalt nach hinten
1045 		// geschoben und liegt der SPoint vom SavePam im naechsten Node, so
1046 		// muss beim Speichern vom Undo-Object das beachtet werden !!
1047         SwTxtNode * pPamTxtNd = 0;
1048 
1049 		// wird ans SwUndoMove weitergegeben, das dann beim Undo JoinNext
1050 		// aufruft. (falls es hier nicht moeglich ist).
1051 		sal_Bool bJoin = bSplit && pTNd;
1052 		bCorrSavePam = bCorrSavePam &&
1053 						0 != ( pPamTxtNd = rPaM.GetNode()->GetTxtNode() )
1054 						&& pPamTxtNd->CanJoinNext()
1055                         && (*rPaM.GetPoint() <= *aSavePam.GetPoint());
1056 
1057 		// muessen am SavePam 2 Nodes zusammengefasst werden ??
1058 		if( bJoin && pTNd->CanJoinNext() )
1059 		{
1060 			pTNd->JoinNext();
1061 			// kein temp. sdbcx::Index bei &&
1062 			// es sollten wohl nur die Indexwerte verglichen werden.
1063 			if( bCorrSavePam && rPaM.GetPoint()->nNode.GetIndex()+1 ==
1064                                 aSavePam.GetPoint()->nNode.GetIndex() )
1065             {
1066                 aSavePam.GetPoint()->nContent += pPamTxtNd->Len();
1067             }
1068 			bJoin = sal_False;
1069 		}
1070 //		else if( !bCorrSavePam && !pSavePam->Move( fnMoveForward, fnGoCntnt ))
1071         else if ( !aSavePam.Move( fnMoveForward, fnGoCntnt ) )
1072         {
1073             aSavePam.GetPoint()->nNode++;
1074         }
1075 
1076 		// zwischen SPoint und GetMark steht jetzt der neu eingefuegte Bereich
1077         pUndoMove->SetDestRange( aSavePam, *rPaM.GetPoint(),
1078 									bJoin, bCorrSavePam );
1079         GetIDocumentUndoRedo().AppendUndo( pUndoMove );
1080     }
1081     else
1082     {
1083         bool bRemove = true;
1084 		// muessen am SavePam 2 Nodes zusammengefasst werden ??
1085 		if( bSplit && pTNd )
1086 		{
1087 			if( pTNd->CanJoinNext())
1088             {
1089                 // --> OD 2009-08-20 #i100466#
1090                 // Always join next, because <pTNd> has to stay as it is.
1091                 // A join previous from its next would more or less delete <pTNd>
1092                 pTNd->JoinNext();
1093                 // <--
1094                 bRemove = false;
1095             }
1096 		}
1097 		if( bNullCntnt )
1098         {
1099             aSavePam.GetPoint()->nNode++;
1100             aSavePam.GetPoint()->nContent.Assign( aSavePam.GetCntntNode(), 0 );
1101         }
1102 		else if( bRemove ) // No move forward after joining with next paragraph
1103         {
1104             aSavePam.Move( fnMoveForward, fnGoCntnt );
1105         }
1106 	}
1107 
1108     // setze jetzt wieder die text::Bookmarks in das Dokument
1109     *rPaM.GetMark() = *aSavePam.Start();
1110     for(
1111         ::std::vector< ::sw::mark::SaveBookmark>::iterator pBkmk = aSaveBkmks.begin();
1112         pBkmk != aSaveBkmks.end();
1113         ++pBkmk)
1114         pBkmk->SetInDoc(
1115             this,
1116             rPaM.GetMark()->nNode,
1117             &rPaM.GetMark()->nContent);
1118     *rPaM.GetPoint() = *aSavePam.End();
1119 
1120 	// verschiebe die Flys an die neue Position
1121 	_RestFlyInRange( aSaveFlyArr, rPaM.Start()->nNode, &(rPos.nNode) );
1122 
1123     // restore redlines (if DOC_MOVEREDLINES is used)
1124 	if( aSaveRedl.Count() )
1125     {
1126         lcl_RestoreRedlines( this, *aSavePam.Start(), aSaveRedl );
1127     }
1128 
1129     if( bUpdateFtn )
1130 	{
1131 		if( aTmpFntIdx.Count() )
1132 		{
1133 			GetFtnIdxs().Insert( &aTmpFntIdx );
1134 			aTmpFntIdx.Remove( sal_uInt16( 0 ), aTmpFntIdx.Count() );
1135 		}
1136 
1137 		GetFtnIdxs().UpdateAllFtn();
1138 	}
1139 
1140 	SetModified();
1141     return true;
1142 }
1143 
1144 bool SwDoc::MoveNodeRange( SwNodeRange& rRange, SwNodeIndex& rPos,
1145         SwMoveFlags eMvFlags )
1146 {
1147 	// bewegt alle Nodes an die neue Position. Dabei werden die
1148 	// text::Bookmarks mit verschoben !! (zur Zeit ohne Undo)
1149 
1150 	// falls durchs Move Fussnoten in den Sonderbereich kommen sollten,
1151 	// dann entferne sie jetzt.
1152 	//JP 13.07.95:
1153 	// ansonsten bei allen Fussnoten, die verschoben werden, die Frames
1154 	// loeschen und nach dem Move wieder aufbauen lassen (Fussnoten koennen
1155 	// die Seite wechseln). Zusaetzlich muss natuerlich die Sortierung
1156 	// der FtnIdx-Array wieder korrigiert werden.
1157 
1158 	int bUpdateFtn = sal_False;
1159 	SwFtnIdxs aTmpFntIdx;
1160 
1161 	SwUndoMove* pUndo = 0;
1162     if ((DOC_CREATEUNDOOBJ & eMvFlags ) && GetIDocumentUndoRedo().DoesUndo())
1163     {
1164 		pUndo = new SwUndoMove( this, rRange, rPos );
1165     }
1166     else
1167     {
1168 		bUpdateFtn = lcl_SaveFtn( rRange.aStart, rRange.aEnd, rPos,
1169 									GetFtnIdxs(), aTmpFntIdx );
1170     }
1171 
1172 	_SaveRedlines aSaveRedl( 0, 4 );
1173 	SvPtrarr aSavRedlInsPosArr( 0, 4 );
1174 	if( DOC_MOVEREDLINES & eMvFlags && GetRedlineTbl().Count() )
1175 	{
1176 		lcl_SaveRedlines( rRange, aSaveRedl );
1177 
1178 		// suche alle Redlines, die an der InsPos aufhoeren. Diese muessen
1179 		// nach dem Move wieder an die "alte" Position verschoben werden
1180 		sal_uInt16 nRedlPos = GetRedlinePos( rPos.GetNode(), USHRT_MAX );
1181 		if( USHRT_MAX != nRedlPos )
1182 		{
1183 			const SwPosition *pRStt, *pREnd;
1184 			do {
1185 				SwRedline* pTmp = GetRedlineTbl()[ nRedlPos ];
1186 				pRStt = pTmp->Start();
1187 				pREnd = pTmp->End();
1188 				if( pREnd->nNode == rPos && pRStt->nNode < rPos )
1189 				{
1190 					void* p = pTmp;
1191 					aSavRedlInsPosArr.Insert( p, aSavRedlInsPosArr.Count() );
1192 				}
1193 			} while( pRStt->nNode < rPos && ++nRedlPos < GetRedlineTbl().Count());
1194 		}
1195 	}
1196 
1197     // kopiere alle Bookmarks, die im Move Bereich stehen in ein
1198     // Array, das alle Angaben auf die Position als Offset speichert.
1199     // Die neue Zuordung erfolgt nach dem Moven.
1200     ::std::vector< ::sw::mark::SaveBookmark> aSaveBkmks;
1201     _DelBookmarks(rRange.aStart, rRange.aEnd, &aSaveBkmks);
1202 
1203 	// sicher die absatzgebundenen Flys, damit verschoben werden koennen.
1204 	_SaveFlyArr aSaveFlyArr;
1205 	if( GetSpzFrmFmts()->Count() )
1206 		_SaveFlyInRange( rRange, aSaveFlyArr );
1207 
1208 	// vor die Position setzen, damit er nicht weitergeschoben wird
1209 	SwNodeIndex aIdx( rPos, -1 );
1210 
1211 	SwNodeIndex* pSaveInsPos = 0;
1212 	if( pUndo )
1213 		pSaveInsPos = new SwNodeIndex( rRange.aStart, -1 );
1214 
1215 	// verschiebe die Nodes
1216     sal_Bool bNoDelFrms = 0 != (DOC_NO_DELFRMS & eMvFlags);
1217 	if( GetNodes()._MoveNodes( rRange, GetNodes(), rPos, !bNoDelFrms ) )
1218 	{
1219 		aIdx++;		// wieder auf alte Position
1220 		if( pSaveInsPos )
1221 			(*pSaveInsPos)++;
1222 	}
1223 	else
1224 	{
1225 		aIdx = rRange.aStart;
1226 		delete pUndo, pUndo = 0;
1227 	}
1228 
1229 	// verschiebe die Flys an die neue Position
1230 	if( aSaveFlyArr.Count() )
1231 		_RestFlyInRange( aSaveFlyArr, aIdx, NULL );
1232 
1233 	// setze jetzt wieder die text::Bookmarks in das Dokument
1234     for(
1235         ::std::vector< ::sw::mark::SaveBookmark>::iterator pBkmk = aSaveBkmks.begin();
1236         pBkmk != aSaveBkmks.end();
1237         ++pBkmk)
1238 		pBkmk->SetInDoc(this, aIdx);
1239 
1240 	if( aSavRedlInsPosArr.Count() )
1241 	{
1242 		SwNode* pNewNd = &aIdx.GetNode();
1243 		for( sal_uInt16 n = 0; n < aSavRedlInsPosArr.Count(); ++n )
1244 		{
1245 			SwRedline* pTmp = (SwRedline*)aSavRedlInsPosArr[ n ];
1246 			if( USHRT_MAX != GetRedlineTbl().GetPos( pTmp ) )
1247 			{
1248 				SwPosition* pEnd = pTmp->End();
1249 				pEnd->nNode = aIdx;
1250 				pEnd->nContent.Assign( pNewNd->GetCntntNode(), 0 );
1251 			}
1252 		}
1253 	}
1254 
1255 	if( aSaveRedl.Count() )
1256 		lcl_RestoreRedlines( this, aIdx.GetIndex(), aSaveRedl );
1257 
1258 	if( pUndo )
1259     {
1260 		pUndo->SetDestRange( aIdx, rPos, *pSaveInsPos );
1261         GetIDocumentUndoRedo().AppendUndo(pUndo);
1262     }
1263 
1264 	if( pSaveInsPos )
1265 		delete pSaveInsPos;
1266 
1267 	if( bUpdateFtn )
1268 	{
1269 		if( aTmpFntIdx.Count() )
1270 		{
1271 			GetFtnIdxs().Insert( &aTmpFntIdx );
1272 			aTmpFntIdx.Remove( sal_uInt16( 0 ), aTmpFntIdx.Count() );
1273 		}
1274 
1275 		GetFtnIdxs().UpdateAllFtn();
1276 	}
1277 
1278 	SetModified();
1279 	return sal_True;
1280 }
1281 
1282 /* #107318# Convert list of ranges of whichIds to a corresponding list
1283     of whichIds*/
1284 SvUShorts * lcl_RangesToUShorts(sal_uInt16 * pRanges)
1285 {
1286     SvUShorts * pResult = new SvUShorts();
1287 
1288     int i = 0;
1289     while (pRanges[i] != 0)
1290     {
1291         ASSERT(pRanges[i+1] != 0, "malformed ranges");
1292 
1293         for (sal_uInt16 j = pRanges[i]; j < pRanges[i+1]; j++)
1294             pResult->Insert(j, pResult->Count());
1295 
1296         i += 2;
1297     }
1298 
1299     return pResult;
1300 }
1301 
1302 bool lcl_StrLenOverFlow( const SwPaM& rPam )
1303 {
1304     // If we try to merge two paragraph we have to test if afterwards
1305     // the string doesn't exceed the allowed string length
1306     bool bRet = false;
1307 	if( rPam.GetPoint()->nNode != rPam.GetMark()->nNode )
1308 	{
1309 		const SwPosition* pStt = rPam.Start(), *pEnd = rPam.End();
1310 		const SwTxtNode* pEndNd = pEnd->nNode.GetNode().GetTxtNode();
1311 		if( (0 != pEndNd) && pStt->nNode.GetNode().IsTxtNode() )
1312         {
1313             sal_uInt64 nSum = pStt->nContent.GetIndex() +
1314                 pEndNd->GetTxt().Len() - pEnd->nContent.GetIndex();
1315             if( nSum > STRING_LEN )
1316                 bRet = true;
1317         }
1318 	}
1319     return bRet;
1320 }
1321 
1322 void lcl_GetJoinFlags( SwPaM& rPam, sal_Bool& rJoinTxt, sal_Bool& rJoinPrev )
1323 {
1324     rJoinTxt = sal_False;
1325     rJoinPrev = sal_False;
1326 	if( rPam.GetPoint()->nNode != rPam.GetMark()->nNode )
1327 	{
1328 		const SwPosition* pStt = rPam.Start(), *pEnd = rPam.End();
1329 		SwTxtNode *pSttNd = pStt->nNode.GetNode().GetTxtNode();
1330         if( pSttNd )
1331         {
1332             SwTxtNode *pEndNd = pEnd->nNode.GetNode().GetTxtNode();
1333             rJoinTxt = 0 != pEndNd;
1334             if( rJoinTxt )
1335             {
1336                 bool bExchange = pStt == rPam.GetPoint();
1337                 if( !pStt->nContent.GetIndex() &&
1338                     pEndNd->GetTxt().Len() != pEnd->nContent.GetIndex() )
1339                     bExchange = !bExchange;
1340                 if( bExchange )
1341                     rPam.Exchange();
1342                 rJoinPrev = rPam.GetPoint() == pStt;
1343                 ASSERT( !pStt->nContent.GetIndex() &&
1344                     pEndNd->GetTxt().Len() != pEnd->nContent.GetIndex()
1345                     ? rPam.GetPoint()->nNode < rPam.GetMark()->nNode
1346                     : rPam.GetPoint()->nNode > rPam.GetMark()->nNode,
1347                     "lcl_GetJoinFlags");
1348             }
1349         }
1350 	}
1351 }
1352 
1353 void lcl_JoinText( SwPaM& rPam, sal_Bool bJoinPrev )
1354 {
1355 	SwNodeIndex aIdx( rPam.GetPoint()->nNode );
1356 	SwTxtNode *pTxtNd = aIdx.GetNode().GetTxtNode();
1357 	SwNodeIndex aOldIdx( aIdx );
1358 	SwTxtNode *pOldTxtNd = pTxtNd;
1359 
1360 	if( pTxtNd && pTxtNd->CanJoinNext( &aIdx ) )
1361 	{
1362 		SwDoc* pDoc = rPam.GetDoc();
1363 		if( bJoinPrev )
1364 		{
1365             // N.B.: we do not need to handle xmlids in this case, because
1366             // it is only invoked if one paragraph is completely empty
1367             // (see lcl_GetJoinFlags)
1368 			{
1369 				// falls PageBreaks geloescht / gesetzt werden, darf das
1370 				// nicht in die Undo-History aufgenommen werden !!
1371 				// (das loeschen vom Node geht auch am Undo vorbei !!!)
1372                 ::sw::UndoGuard const undoGuard(pDoc->GetIDocumentUndoRedo());
1373 
1374 				/* PageBreaks, PageDesc, ColumnBreaks */
1375 				// Sollte an der Logik zum Kopieren der PageBreak's ...
1376 				// etwas geaendert werden, muss es auch im SwUndoDelete
1377 				// geandert werden. Dort wird sich das AUTO-PageBreak
1378 				// aus dem GetMarkNode kopiert.!!!
1379 
1380 				/* Der GetMarkNode */
1381                 if( ( pTxtNd = aIdx.GetNode().GetTxtNode())->HasSwAttrSet() )
1382 				{
1383 					const SfxPoolItem* pItem;
1384 					if( SFX_ITEM_SET == pTxtNd->GetpSwAttrSet()->GetItemState(
1385 						RES_BREAK, sal_False, &pItem ) )
1386 						pTxtNd->ResetAttr( RES_BREAK );
1387                     if( pTxtNd->HasSwAttrSet() &&
1388 						SFX_ITEM_SET == pTxtNd->GetpSwAttrSet()->GetItemState(
1389 						RES_PAGEDESC, sal_False, &pItem ) )
1390 						pTxtNd->ResetAttr( RES_PAGEDESC );
1391 				}
1392 
1393 				/* Der PointNode */
1394                 if( pOldTxtNd->HasSwAttrSet() )
1395 				{
1396 					const SfxPoolItem* pItem;
1397 					SfxItemSet aSet( pDoc->GetAttrPool(), aBreakSetRange );
1398                     const SfxItemSet* pSet = pOldTxtNd->GetpSwAttrSet();
1399 					if( SFX_ITEM_SET == pSet->GetItemState( RES_BREAK,
1400 						sal_False, &pItem ) )
1401 						aSet.Put( *pItem );
1402 					if( SFX_ITEM_SET == pSet->GetItemState( RES_PAGEDESC,
1403 						sal_False, &pItem ) )
1404 						aSet.Put( *pItem );
1405 					if( aSet.Count() )
1406                         pTxtNd->SetAttr( aSet );
1407 				}
1408 				pOldTxtNd->FmtToTxtAttr( pTxtNd );
1409 
1410 				SvULongs aBkmkArr( 15, 15 );
1411 				::_SaveCntntIdx( pDoc, aOldIdx.GetIndex(),
1412 									pOldTxtNd->Len(), aBkmkArr );
1413 
1414 				SwIndex aAlphaIdx(pTxtNd);
1415                 pOldTxtNd->CutText( pTxtNd, aAlphaIdx, SwIndex(pOldTxtNd),
1416 									pOldTxtNd->Len() );
1417 				SwPosition aAlphaPos( aIdx, aAlphaIdx );
1418 				pDoc->CorrRel( rPam.GetPoint()->nNode, aAlphaPos, 0, sal_True );
1419 
1420 				// verschiebe noch alle Bookmarks/TOXMarks
1421 				if( aBkmkArr.Count() )
1422 					::_RestoreCntntIdx( pDoc, aBkmkArr, aIdx.GetIndex() );
1423 
1424 				// falls der uebergebene PaM nicht im Crsr-Ring steht,
1425 				// gesondert behandeln (z.B. Aufruf aus dem Auto-Format)
1426 				if( pOldTxtNd == rPam.GetBound( sal_True ).nContent.GetIdxReg() )
1427 					rPam.GetBound( sal_True ) = aAlphaPos;
1428 				if( pOldTxtNd == rPam.GetBound( sal_False ).nContent.GetIdxReg() )
1429 					rPam.GetBound( sal_False ) = aAlphaPos;
1430 			}
1431 			// jetzt nur noch den Node loeschen
1432 			pDoc->GetNodes().Delete( aOldIdx, 1 );
1433 		}
1434 		else
1435 		{
1436 			SwTxtNode* pDelNd = aIdx.GetNode().GetTxtNode();
1437 			if( pTxtNd->Len() )
1438 				pDelNd->FmtToTxtAttr( pTxtNd );
1439 			else
1440             {
1441                 /* #107318# This case was missed:
1442 
1443                    <something></something>   <-- pTxtNd
1444                    <other>ccc</other>        <-- pDelNd
1445 
1446                    <something> and <other> are paragraph
1447                    attributes. The attribute <something> stayed if not
1448                    overwritten by an attribute in "ccc". Fixed by
1449                    first resetting all character attributes in first
1450                    paragraph (pTxtNd).
1451                 */
1452                 SvUShorts * pShorts =
1453                     lcl_RangesToUShorts(aCharFmtSetRange);
1454                 pTxtNd->ResetAttr(*pShorts);
1455                 delete pShorts;
1456 
1457                 if( pDelNd->HasSwAttrSet() )
1458                 {
1459                     // nur die Zeichenattribute kopieren
1460                     SfxItemSet aTmpSet( pDoc->GetAttrPool(), aCharFmtSetRange );
1461                     aTmpSet.Put( *pDelNd->GetpSwAttrSet() );
1462                     pTxtNd->SetAttr( aTmpSet );
1463                 }
1464             }
1465 
1466 			pDoc->CorrRel( aIdx, *rPam.GetPoint(), 0, sal_True );
1467             // --> OD 2009-08-20 #i100466#
1468             // adjust given <rPam>, if it does not belong to the cursors
1469             if ( pDelNd == rPam.GetBound( sal_True ).nContent.GetIdxReg() )
1470             {
1471                 rPam.GetBound( sal_True ) = SwPosition( SwNodeIndex( *pTxtNd ), SwIndex( pTxtNd ) );
1472             }
1473             if( pDelNd == rPam.GetBound( sal_False ).nContent.GetIdxReg() )
1474             {
1475                 rPam.GetBound( sal_False ) = SwPosition( SwNodeIndex( *pTxtNd ), SwIndex( pTxtNd ) );
1476             }
1477             // <--
1478 			pTxtNd->JoinNext();
1479 		}
1480 	}
1481 }
1482 
1483 static void
1484 lcl_CalcBreaks( ::std::vector<xub_StrLen> & rBreaks, SwPaM const & rPam )
1485 {
1486     SwTxtNode const * const pTxtNode(
1487             rPam.End()->nNode.GetNode().GetTxtNode() );
1488     if (!pTxtNode)
1489         return; // left-overlap only possible at end of selection...
1490 
1491     const xub_StrLen nStart(rPam.Start()->nContent.GetIndex());
1492     const xub_StrLen nEnd  (rPam.End  ()->nContent.GetIndex());
1493     if (nEnd == pTxtNode->Len())
1494         return; // paragraph selected until the end
1495 
1496     for (xub_StrLen i = nStart; i < nEnd; ++i)
1497     {
1498         const sal_Unicode c(pTxtNode->GetTxt().GetChar(i));
1499         if ((CH_TXTATR_INWORD == c) || (CH_TXTATR_BREAKWORD == c))
1500         {
1501             SwTxtAttr const * const pAttr( pTxtNode->GetTxtAttrForCharAt(i) );
1502             if (pAttr && pAttr->GetEnd() && (*pAttr->GetEnd() > nEnd))
1503             {
1504                 ASSERT(pAttr->HasDummyChar(), "GetTxtAttrForCharAt broken?");
1505                 rBreaks.push_back(i);
1506             }
1507         }
1508     }
1509 }
1510 
1511 bool lcl_DoWithBreaks(SwDoc & rDoc, SwPaM & rPam,
1512         bool (SwDoc::*pFunc)(SwPaM&, bool), const bool bForceJoinNext = false)
1513 {
1514     ::std::vector<xub_StrLen> Breaks;
1515 
1516     lcl_CalcBreaks(Breaks, rPam);
1517 
1518     if (!Breaks.size())
1519     {
1520         return (rDoc.*pFunc)(rPam, bForceJoinNext);
1521     }
1522 
1523     // N.B.: deletion must be split into several parts if the text node
1524     // contains a text attribute with end and with dummy character
1525     // and the selection does not contain the text attribute completely,
1526     // but overlaps its start (left), where the dummy character is.
1527 
1528     SwPosition const & rSelectionEnd( *rPam.End() );
1529 
1530     bool bRet( true );
1531     // iterate from end to start, to avoid invalidating the offsets!
1532     ::std::vector<xub_StrLen>::reverse_iterator iter( Breaks.rbegin() );
1533     SwPaM aPam( rSelectionEnd, rSelectionEnd ); // end node!
1534     SwPosition & rEnd( *aPam.End() );
1535     SwPosition & rStart( *aPam.Start() );
1536 
1537     while (iter != Breaks.rend())
1538     {
1539         rStart.nContent = *iter + 1;
1540         if (rEnd.nContent > rStart.nContent) // check if part is empty
1541         {
1542             bRet &= (rDoc.*pFunc)(aPam, bForceJoinNext);
1543         }
1544         rEnd.nContent = *iter;
1545         ++iter;
1546     }
1547 
1548     rStart = *rPam.Start(); // set to original start
1549     if (rEnd.nContent > rStart.nContent) // check if part is empty
1550     {
1551         bRet &= (rDoc.*pFunc)(aPam, bForceJoinNext);
1552     }
1553 
1554     return bRet;
1555 }
1556 
1557 
1558 bool SwDoc::DeleteAndJoinWithRedlineImpl( SwPaM & rPam, const bool )
1559 {
1560     ASSERT( IsRedlineOn(), "DeleteAndJoinWithRedline: redline off" );
1561 
1562     {
1563 		SwUndoRedlineDelete* pUndo = 0;
1564 		RedlineMode_t eOld = GetRedlineMode();
1565 		checkRedlining(eOld);
1566         if (GetIDocumentUndoRedo().DoesUndo())
1567         {
1568 
1569     //JP 06.01.98: MUSS noch optimiert werden!!!
1570     SetRedlineMode(
1571 		   (RedlineMode_t)(nsRedlineMode_t::REDLINE_ON | nsRedlineMode_t::REDLINE_SHOW_INSERT | nsRedlineMode_t::REDLINE_SHOW_DELETE ));
1572 
1573             GetIDocumentUndoRedo().StartUndo(UNDO_EMPTY, NULL);
1574             pUndo = new SwUndoRedlineDelete( rPam, UNDO_DELETE );
1575             GetIDocumentUndoRedo().AppendUndo(pUndo);
1576         }
1577         if( *rPam.GetPoint() != *rPam.GetMark() )
1578             AppendRedline( new SwRedline( nsRedlineType_t::REDLINE_DELETE, rPam ), true);
1579         SetModified();
1580 
1581 		if( pUndo )
1582 		{
1583             GetIDocumentUndoRedo().EndUndo(UNDO_EMPTY, NULL);
1584             // ??? why the hell is the AppendUndo not below the
1585             // CanGrouping, so this hideous cleanup wouldn't be necessary?
1586             // bah, this is redlining, probably changing this would break it...
1587             if (GetIDocumentUndoRedo().DoesGroupUndo())
1588             {
1589                 SwUndo *const pLastUndo( GetUndoManager().GetLastUndo() );
1590                 SwUndoRedlineDelete *const pUndoRedlineDel(
1591                         dynamic_cast<SwUndoRedlineDelete*>(pLastUndo) );
1592                 if (pUndoRedlineDel)
1593                 {
1594                     bool const bMerged = pUndoRedlineDel->CanGrouping(*pUndo);
1595                     if (bMerged)
1596                     {
1597                         ::sw::UndoGuard const undoGuard(GetIDocumentUndoRedo());
1598                         SwUndo const*const pDeleted =
1599                             GetUndoManager().RemoveLastUndo();
1600                         OSL_ENSURE(pDeleted == pUndo,
1601                             "DeleteAndJoinWithRedlineImpl: "
1602                             "undo removed is not undo inserted?");
1603                         delete pDeleted;
1604                     }
1605                 }
1606             }
1607 //JP 06.01.98: MUSS noch optimiert werden!!!
1608 SetRedlineMode( eOld );
1609         }
1610         return true;
1611     }
1612 }
1613 
1614 bool SwDoc::DeleteAndJoinImpl( SwPaM & rPam,
1615                                const bool bForceJoinNext )
1616 {
1617 	sal_Bool bJoinTxt, bJoinPrev;
1618 	lcl_GetJoinFlags( rPam, bJoinTxt, bJoinPrev );
1619     // --> OD 2009-08-20 #i100466#
1620     if ( bForceJoinNext )
1621     {
1622         bJoinPrev = sal_False;
1623     }
1624     // <--
1625 	{
1626         bool const bSuccess( DeleteRangeImpl( rPam ) );
1627         if (!bSuccess)
1628             return false;
1629 	}
1630 
1631 	if( bJoinTxt )
1632     {
1633 		lcl_JoinText( rPam, bJoinPrev );
1634     }
1635 
1636     return true;
1637 }
1638 
1639 bool SwDoc::DeleteRangeImpl(SwPaM & rPam, const bool)
1640 {
1641     // move all cursors out of the deleted range.
1642     // but first copy the given PaM, because it could be a cursor that
1643     // would be moved!
1644     SwPaM aDelPam( *rPam.GetMark(), *rPam.GetPoint() );
1645     ::PaMCorrAbs( aDelPam, *aDelPam.GetPoint() );
1646 
1647     bool const bSuccess( DeleteRangeImplImpl( aDelPam ) );
1648     if (bSuccess)
1649     {   // now copy position from temp copy to given PaM
1650         *rPam.GetPoint() = *aDelPam.GetPoint();
1651     }
1652 
1653     return bSuccess;
1654 }
1655 
1656 bool SwDoc::DeleteRangeImplImpl(SwPaM & rPam)
1657 {
1658 	SwPosition *pStt = (SwPosition*)rPam.Start(), *pEnd = (SwPosition*)rPam.End();
1659 
1660 	if( !rPam.HasMark() || *pStt >= *pEnd )
1661         return false;
1662 
1663 	if( pACEWord )
1664 	{
1665 		// ggfs. das gesicherte Word fuer die Ausnahme
1666 		if( pACEWord->IsDeleted() ||  pStt->nNode != pEnd->nNode ||
1667 			pStt->nContent.GetIndex() + 1 != pEnd->nContent.GetIndex() ||
1668 			!pACEWord->CheckDelChar( *pStt ))
1669 			delete pACEWord, pACEWord = 0;
1670 	}
1671 
1672 	{
1673 		// loesche alle leeren TextHints an der Mark-Position
1674 		SwTxtNode* pTxtNd = rPam.GetMark()->nNode.GetNode().GetTxtNode();
1675 		SwpHints* pHts;
1676 		if( pTxtNd &&  0 != ( pHts = pTxtNd->GetpSwpHints()) && pHts->Count() )
1677 		{
1678 			const xub_StrLen *pEndIdx;
1679 			xub_StrLen nMkCntPos = rPam.GetMark()->nContent.GetIndex();
1680 			for( sal_uInt16 n = pHts->Count(); n; )
1681 			{
1682 				const SwTxtAttr* pAttr = (*pHts)[ --n ];
1683 				if( nMkCntPos > *pAttr->GetStart() )
1684 					break;
1685 
1686 				if( nMkCntPos == *pAttr->GetStart() &&
1687 					0 != (pEndIdx = pAttr->GetEnd()) &&
1688 					*pEndIdx == *pAttr->GetStart() )
1689 					pTxtNd->DestroyAttr( pHts->Cut( n ) );
1690 			}
1691 		}
1692 	}
1693 
1694 	{
1695 		// Bug 26675:	DataChanged vorm loeschen verschicken, dann bekommt
1696 		//			man noch mit, welche Objecte sich im Bereich befinden.
1697 		//			Danach koennen sie vor/hinter der Position befinden.
1698 		SwDataChanged aTmp( rPam, 0 );
1699 	}
1700 
1701 
1702     if (GetIDocumentUndoRedo().DoesUndo())
1703     {
1704         GetIDocumentUndoRedo().ClearRedo();
1705         bool bMerged(false);
1706         if (GetIDocumentUndoRedo().DoesGroupUndo())
1707         {
1708             SwUndo *const pLastUndo( GetUndoManager().GetLastUndo() );
1709             SwUndoDelete *const pUndoDelete(
1710                     dynamic_cast<SwUndoDelete *>(pLastUndo) );
1711             if (pUndoDelete)
1712             {
1713                 bMerged = pUndoDelete->CanGrouping( this, rPam );
1714                 // if CanGrouping() returns true it's already merged
1715             }
1716         }
1717         if (!bMerged)
1718         {
1719             GetIDocumentUndoRedo().AppendUndo( new SwUndoDelete( rPam ) );
1720         }
1721 
1722 		SetModified();
1723 
1724         return true;
1725     }
1726 
1727 	if( !IsIgnoreRedline() && GetRedlineTbl().Count() )
1728 		DeleteRedline( rPam, true, USHRT_MAX );
1729 
1730     // loesche und verschiebe erstmal alle "Fly's am Absatz", die in der
1731     // Selection liegen
1732     DelFlyInRange(rPam.GetMark()->nNode, rPam.GetPoint()->nNode);
1733     _DelBookmarks(
1734         pStt->nNode,
1735         pEnd->nNode,
1736         NULL,
1737         &pStt->nContent,
1738         &pEnd->nContent);
1739 
1740 	SwNodeIndex aSttIdx( pStt->nNode );
1741 	SwCntntNode * pCNd = aSttIdx.GetNode().GetCntntNode();
1742 
1743 	do {		// middle checked loop!
1744 		if( pCNd )
1745 		{
1746             SwTxtNode * pStartTxtNode( pCNd->GetTxtNode() );
1747             if ( pStartTxtNode )
1748 			{
1749 				// verschiebe jetzt noch den Inhalt in den neuen Node
1750 				sal_Bool bOneNd = pStt->nNode == pEnd->nNode;
1751 				xub_StrLen nLen = ( bOneNd ? pEnd->nContent.GetIndex()
1752 										   : pCNd->Len() )
1753 										- pStt->nContent.GetIndex();
1754 
1755 				// falls schon leer, dann nicht noch aufrufen
1756 				if( nLen )
1757                 {
1758                     pStartTxtNode->EraseText( pStt->nContent, nLen );
1759 
1760                     if( !pStartTxtNode->Len() )
1761                     {
1762                 // METADATA: remove reference if empty (consider node deleted)
1763                         pStartTxtNode->RemoveMetadataReference();
1764                     }
1765                 }
1766 
1767 				if( bOneNd )		// das wars schon
1768 					break;
1769 
1770 				aSttIdx++;
1771 			}
1772 			else
1773 			{
1774 				// damit beim loeschen keine Indizies mehr angemeldet sind,
1775 				// wird hier der SwPaM aus dem Content entfernt !!
1776 				pStt->nContent.Assign( 0, 0 );
1777 			}
1778 		}
1779 
1780 		pCNd = pEnd->nNode.GetNode().GetCntntNode();
1781 		if( pCNd )
1782 		{
1783             SwTxtNode * pEndTxtNode( pCNd->GetTxtNode() );
1784             if( pEndTxtNode )
1785 			{
1786 				// falls schon leer, dann nicht noch aufrufen
1787 				if( pEnd->nContent.GetIndex() )
1788 				{
1789 					SwIndex aIdx( pCNd, 0 );
1790                     pEndTxtNode->EraseText( aIdx, pEnd->nContent.GetIndex() );
1791 
1792                     if( !pEndTxtNode->Len() )
1793                     {
1794                 // METADATA: remove reference if empty (consider node deleted)
1795                         pEndTxtNode->RemoveMetadataReference();
1796                     }
1797 				}
1798 			}
1799 			else
1800 			{
1801 				// damit beim Loeschen keine Indizies mehr angemeldet sind,
1802 				// wird hier der SwPaM aus dem Content entfernt !!
1803 				pEnd->nContent.Assign( 0, 0 );
1804 			}
1805 		}
1806 
1807         // if the end is not a content node, delete it as well
1808         sal_uInt32 nEnde = pEnd->nNode.GetIndex();
1809         if( pCNd == NULL )
1810             nEnde++;
1811 
1812 		if( aSttIdx != nEnde )
1813 		{
1814 			// loesche jetzt die Nodes in das NodesArary
1815 			GetNodes().Delete( aSttIdx, nEnde - aSttIdx.GetIndex() );
1816 		}
1817 
1818 		// falls der Node geloescht wurde, in dem der Cursor stand, so
1819 		// muss der Content im akt. Content angemeldet werden !!!
1820 		pStt->nContent.Assign( pStt->nNode.GetNode().GetCntntNode(),
1821 								pStt->nContent.GetIndex() );
1822 
1823 		// der PaM wird korrigiert, denn falls ueber Nodegrenzen geloescht
1824 		// wurde, so stehen sie in unterschieden Nodes. Auch die Selektion
1825 		// wird aufgehoben !
1826 		*pEnd = *pStt;
1827 		rPam.DeleteMark();
1828 
1829 	} while( sal_False );
1830 
1831 	if( !IsIgnoreRedline() && GetRedlineTbl().Count() )
1832 		CompressRedlines();
1833 	SetModified();
1834 
1835     return true;
1836 }
1837 
1838 // OD 2009-08-20 #i100466#
1839 // Add handling of new optional parameter <bForceJoinNext>
1840 bool SwDoc::DeleteAndJoin( SwPaM & rPam,
1841                            const bool bForceJoinNext )
1842 {
1843     if ( lcl_StrLenOverFlow( rPam ) )
1844         return false;
1845 
1846     return lcl_DoWithBreaks( *this, rPam, (IsRedlineOn())
1847                 ? &SwDoc::DeleteAndJoinWithRedlineImpl
1848                 : &SwDoc::DeleteAndJoinImpl,
1849                 bForceJoinNext );
1850 }
1851 
1852 bool SwDoc::DeleteRange( SwPaM & rPam )
1853 {
1854     return lcl_DoWithBreaks( *this, rPam, &SwDoc::DeleteRangeImpl );
1855 }
1856 
1857 
1858 void lcl_syncGrammarError( SwTxtNode &rTxtNode, linguistic2::ProofreadingResult& rResult,
1859     xub_StrLen /*nBeginGrammarCheck*/, const ModelToViewHelper::ConversionMap* pConversionMap )
1860 {
1861     if( rTxtNode.IsGrammarCheckDirty() )
1862         return;
1863     SwGrammarMarkUp* pWrong = rTxtNode.GetGrammarCheck();
1864 	linguistic2::SingleProofreadingError* pArray = rResult.aErrors.getArray();
1865     sal_uInt16 i, j = 0;
1866 	if( pWrong )
1867 	{
1868 		for( i = 0; i < rResult.aErrors.getLength(); ++i )
1869 		{
1870 			const linguistic2::SingleProofreadingError &rError = rResult.aErrors[i];
1871 			xub_StrLen nStart = (xub_StrLen)ModelToViewHelper::ConvertToModelPosition( pConversionMap, rError.nErrorStart ).mnPos;
1872 			xub_StrLen nEnd = (xub_StrLen)ModelToViewHelper::ConvertToModelPosition( pConversionMap, rError.nErrorStart + rError.nErrorLength ).mnPos;
1873 			if( i != j )
1874 				pArray[j] = pArray[i];
1875 			if( pWrong->LookForEntry( nStart, nEnd ) )
1876 				++j;
1877 		}
1878 	}
1879     if( rResult.aErrors.getLength() > j )
1880         rResult.aErrors.realloc( j );
1881 }
1882 
1883 
1884 uno::Any SwDoc::Spell( SwPaM& rPaM,
1885 					uno::Reference< XSpellChecker1 >  &xSpeller,
1886                     sal_uInt16* pPageCnt, sal_uInt16* pPageSt,
1887                     bool bGrammarCheck,
1888                     SwConversionArgs *pConvArgs  ) const
1889 {
1890 	SwPosition* pSttPos = rPaM.Start(), *pEndPos = rPaM.End();
1891 	uno::Reference< beans::XPropertySet >  xProp( ::GetLinguPropertySet() );
1892 
1893     SwSpellArgs      *pSpellArgs = 0;
1894     //SwConversionArgs *pConvArgs  = 0;
1895     if (pConvArgs)
1896 	{
1897         pConvArgs->SetStart(pSttPos->nNode.GetNode().GetTxtNode(), pSttPos->nContent);
1898 		pConvArgs->SetEnd(  pEndPos->nNode.GetNode().GetTxtNode(), pEndPos->nContent );
1899 	}
1900     else
1901         pSpellArgs = new SwSpellArgs( xSpeller,
1902                             pSttPos->nNode.GetNode().GetTxtNode(), pSttPos->nContent,
1903                             pEndPos->nNode.GetNode().GetTxtNode(), pEndPos->nContent,
1904                             bGrammarCheck );
1905 
1906 	sal_uLong nCurrNd = pSttPos->nNode.GetIndex();
1907 	sal_uLong nEndNd = pEndPos->nNode.GetIndex();
1908 
1909     uno::Any aRet;
1910 	if( nCurrNd <= nEndNd )
1911 	{
1912 		SwCntntFrm* pCntFrm;
1913 		sal_Bool bGoOn = sal_True;
1914 		while( bGoOn )
1915 		{
1916 			SwNode* pNd = GetNodes()[ nCurrNd ];
1917 			switch( pNd->GetNodeType() )
1918 			{
1919 			case ND_TEXTNODE:
1920 				if( 0 != ( pCntFrm = ((SwTxtNode*)pNd)->getLayoutFrm( GetCurrentLayout() )) )
1921 				{
1922 					// geschutze Cellen/Flys ueberspringen, ausgeblendete
1923 					//ebenfalls
1924 					if( pCntFrm->IsProtected() )
1925 					{
1926                         nCurrNd = pNd->EndOfSectionIndex();
1927 					}
1928 					else if( !((SwTxtFrm*)pCntFrm)->IsHiddenNow() )
1929 					{
1930 						if( pPageCnt && *pPageCnt && pPageSt )
1931 						{
1932 							sal_uInt16 nPageNr = pCntFrm->GetPhyPageNum();
1933 							if( !*pPageSt )
1934 							{
1935 								*pPageSt = nPageNr;
1936 								if( *pPageCnt < *pPageSt )
1937 									*pPageCnt = *pPageSt;
1938 							}
1939 							long nStat;
1940 							if( nPageNr >= *pPageSt )
1941                                 nStat = nPageNr - *pPageSt + 1;
1942 							else
1943                                 nStat = nPageNr + *pPageCnt - *pPageSt + 1;
1944 							::SetProgressState( nStat, (SwDocShell*)GetDocShell() );
1945 						}
1946                         //Spell() changes the pSpellArgs in case an error is found
1947                         xub_StrLen nBeginGrammarCheck = 0;
1948                         xub_StrLen nEndGrammarCheck = 0;
1949                         if( pSpellArgs && pSpellArgs->bIsGrammarCheck)
1950                         {
1951                             nBeginGrammarCheck = pSpellArgs->pStartNode == pNd ?  pSpellArgs->pStartIdx->GetIndex() : 0;
1952                             // if grammar checking starts inside of a sentence the start position has to be adjusted
1953                             if( nBeginGrammarCheck )
1954                             {
1955                                 SwIndex aStartIndex( dynamic_cast< SwTxtNode* >( pNd ), nBeginGrammarCheck );
1956                                 SwPosition aStart( *pNd, aStartIndex );
1957                                 SwCursor aCrsr(aStart, 0, false);
1958                                 SwPosition aOrigPos = *aCrsr.GetPoint();
1959                                 aCrsr.GoSentence( SwCursor::START_SENT );
1960                                 if( aOrigPos != *aCrsr.GetPoint() )
1961                                 {
1962                                     nBeginGrammarCheck = aCrsr.GetPoint()->nContent.GetIndex();
1963                                 }
1964                             }
1965                             nEndGrammarCheck = pSpellArgs->pEndNode == pNd ? pSpellArgs->pEndIdx->GetIndex() : ((SwTxtNode*)pNd)->GetTxt().Len();
1966                         }
1967 
1968                         xub_StrLen nSpellErrorPosition = ((SwTxtNode*)pNd)->GetTxt().Len();
1969                         if( (!pConvArgs &&
1970                                 ((SwTxtNode*)pNd)->Spell( pSpellArgs )) ||
1971                             ( pConvArgs &&
1972                                 ((SwTxtNode*)pNd)->Convert( *pConvArgs )))
1973 						{
1974 							// Abbrechen und Position merken
1975 							pSttPos->nNode = nCurrNd;
1976 							pEndPos->nNode = nCurrNd;
1977 							nCurrNd = nEndNd;
1978                             if( pSpellArgs )
1979                                 nSpellErrorPosition = pSpellArgs->pStartIdx->GetIndex() > pSpellArgs->pEndIdx->GetIndex() ?
1980                                             pSpellArgs->pEndIdx->GetIndex() :
1981                                             pSpellArgs->pStartIdx->GetIndex();
1982 						}
1983 
1984 
1985                         if( pSpellArgs && pSpellArgs->bIsGrammarCheck )
1986                         {
1987                             uno::Reference< linguistic2::XProofreadingIterator >  xGCIterator( GetGCIterator() );
1988                             if (xGCIterator.is())
1989                             {
1990                                 String aText( ((SwTxtNode*)pNd)->GetTxt().Copy( nBeginGrammarCheck, nEndGrammarCheck - nBeginGrammarCheck ) );
1991                                 uno::Reference< lang::XComponent > xDoc( ((SwDocShell*)GetDocShell())->GetBaseModel(), uno::UNO_QUERY );
1992                                 // Expand the string:
1993                                 rtl::OUString aExpandText;
1994                                 const ModelToViewHelper::ConversionMap* pConversionMap =
1995                                         ((SwTxtNode*)pNd)->BuildConversionMap( aExpandText );
1996                                 // get XFlatParagraph to use...
1997                                 uno::Reference< text::XFlatParagraph > xFlatPara = new SwXFlatParagraph( *((SwTxtNode*)pNd), aExpandText, pConversionMap );
1998 
1999                                 // get error position of cursor in XFlatParagraph
2000                                 sal_Int32 nGrammarErrorPosInText;
2001                                 linguistic2::ProofreadingResult aResult;
2002                                 sal_Int32 nGrammarErrors;
2003                                 do
2004                                 {
2005                                     nGrammarErrorPosInText = ModelToViewHelper::ConvertToViewPosition( pConversionMap, nBeginGrammarCheck );
2006                                     aResult = xGCIterator->checkSentenceAtPosition(
2007                                             xDoc, xFlatPara, aExpandText, lang::Locale(), nBeginGrammarCheck, -1, -1 );
2008 
2009                                     lcl_syncGrammarError( *((SwTxtNode*)pNd), aResult, nBeginGrammarCheck, pConversionMap );
2010 
2011                                     // get suggestions to use for the specific error position
2012                                     nGrammarErrors = aResult.aErrors.getLength();
2013                                     // if grammar checking doesn't have any progress then quit
2014                                     if( aResult.nStartOfNextSentencePosition <= nBeginGrammarCheck )
2015                                         break;
2016                                     // prepare next iteration
2017                                     nBeginGrammarCheck = (xub_StrLen)aResult.nStartOfNextSentencePosition;
2018                                 }
2019                                 while( nSpellErrorPosition > aResult.nBehindEndOfSentencePosition && !nGrammarErrors && aResult.nBehindEndOfSentencePosition < nEndGrammarCheck );
2020 
2021                                 if( nGrammarErrors > 0 && nSpellErrorPosition >= aResult.nBehindEndOfSentencePosition )
2022                                 {
2023                                     aRet <<= aResult;
2024                                     //put the cursor to the current error
2025                                     const linguistic2::SingleProofreadingError &rError = aResult.aErrors[0];
2026 						            nCurrNd = pNd->GetIndex();
2027                                     pSttPos->nNode = nCurrNd;
2028 							        pEndPos->nNode = nCurrNd;
2029                                     pSpellArgs->pStartNode = ((SwTxtNode*)pNd);
2030 						            pSpellArgs->pEndNode = ((SwTxtNode*)pNd);
2031                                     pSpellArgs->pStartIdx->Assign(((SwTxtNode*)pNd), (xub_StrLen)ModelToViewHelper::ConvertToModelPosition( pConversionMap, rError.nErrorStart ).mnPos );
2032                                     pSpellArgs->pEndIdx->Assign(((SwTxtNode*)pNd), (xub_StrLen)ModelToViewHelper::ConvertToModelPosition( pConversionMap, rError.nErrorStart + rError.nErrorLength ).mnPos );
2033                                     nCurrNd = nEndNd;
2034                                 }
2035                             }
2036                         }
2037                     }
2038                 }
2039 				break;
2040 			case ND_SECTIONNODE:
2041                 if( ( ((SwSectionNode*)pNd)->GetSection().IsProtect() ||
2042                     ((SwSectionNode*)pNd)->GetSection().IsHidden() ) )
2043 					nCurrNd = pNd->EndOfSectionIndex();
2044 				break;
2045 			case ND_ENDNODE:
2046 				{
2047 					break;
2048 				}
2049 			}
2050 
2051             bGoOn = nCurrNd < nEndNd;
2052             ++nCurrNd;
2053 		}
2054 	}
2055 
2056     if( !aRet.hasValue() )
2057     {
2058         if (pConvArgs)
2059             aRet <<= pConvArgs->aConvText;
2060         else
2061             aRet <<= pSpellArgs->xSpellAlt;
2062     }
2063     delete pSpellArgs;
2064 
2065     return aRet;
2066 }
2067 
2068 class SwHyphArgs : public SwInterHyphInfo
2069 {
2070 	const SwNode *pStart;
2071 	const SwNode *pEnd;
2072 		  SwNode *pNode;
2073 	sal_uInt16 *pPageCnt;
2074 	sal_uInt16 *pPageSt;
2075 
2076 	sal_uInt32 nNode;
2077 	xub_StrLen nPamStart;
2078 	xub_StrLen nPamLen;
2079 
2080 public:
2081 		 SwHyphArgs( const SwPaM *pPam, const Point &rPoint,
2082 						 sal_uInt16* pPageCount, sal_uInt16* pPageStart );
2083 	void SetPam( SwPaM *pPam ) const;
2084 	inline void SetNode( SwNode *pNew ) { pNode = pNew; }
2085 	inline const SwNode *GetNode() const { return pNode; }
2086 	inline void SetRange( const SwNode *pNew );
2087 	inline void NextNode() { ++nNode; }
2088 	inline sal_uInt16 *GetPageCnt() { return pPageCnt; }
2089 	inline sal_uInt16 *GetPageSt() { return pPageSt; }
2090 };
2091 
2092 SwHyphArgs::SwHyphArgs( const SwPaM *pPam, const Point &rCrsrPos,
2093 						 sal_uInt16* pPageCount, sal_uInt16* pPageStart )
2094 	 : SwInterHyphInfo( rCrsrPos ), pNode(0),
2095 	 pPageCnt( pPageCount ), pPageSt( pPageStart )
2096 {
2097 	// Folgende Bedingungen muessen eingehalten werden:
2098 	// 1) es gibt mindestens eine Selektion
2099 	// 2) SPoint() == Start()
2100 	ASSERT( pPam->HasMark(), "SwDoc::Hyphenate: blowing in the wind");
2101 	ASSERT( *pPam->GetPoint() <= *pPam->GetMark(),
2102 			"SwDoc::Hyphenate: New York, New York");
2103 
2104 	const SwPosition *pPoint = pPam->GetPoint();
2105 	nNode = pPoint->nNode.GetIndex();
2106 
2107 	// Start einstellen
2108 	pStart = pPoint->nNode.GetNode().GetTxtNode();
2109 	nPamStart = pPoint->nContent.GetIndex();
2110 
2111 	// Ende und Laenge einstellen.
2112 	const SwPosition *pMark = pPam->GetMark();
2113 	pEnd = pMark->nNode.GetNode().GetTxtNode();
2114 	nPamLen = pMark->nContent.GetIndex();
2115 	if( pPoint->nNode == pMark->nNode )
2116 		nPamLen = nPamLen - pPoint->nContent.GetIndex();
2117 }
2118 
2119 inline void SwHyphArgs::SetRange( const SwNode *pNew )
2120 {
2121 	nStart = pStart == pNew ? nPamStart : 0;
2122 	nLen   = pEnd	== pNew ? nPamLen : STRING_NOTFOUND;
2123 }
2124 
2125 void SwHyphArgs::SetPam( SwPaM *pPam ) const
2126 {
2127 	if( !pNode )
2128 		*pPam->GetPoint() = *pPam->GetMark();
2129 	else
2130 	{
2131 		pPam->GetPoint()->nNode = nNode;
2132 		pPam->GetPoint()->nContent.Assign( pNode->GetCntntNode(), nWordStart );
2133 		pPam->GetMark()->nNode = nNode;
2134 		pPam->GetMark()->nContent.Assign( pNode->GetCntntNode(),
2135 										  nWordStart + nWordLen );
2136 		ASSERT( nNode == pNode->GetIndex(),
2137 				"SwHyphArgs::SetPam: Pam desaster" );
2138 	}
2139 }
2140 
2141 // liefert sal_True zurueck, wenn es weitergehen soll.
2142 sal_Bool lcl_HyphenateNode( const SwNodePtr& rpNd, void* pArgs )
2143 {
2144 	// Hyphenate liefert sal_True zurueck, wenn eine Trennstelle anliegt
2145 	// und stellt pPam ein.
2146 	SwTxtNode *pNode = rpNd->GetTxtNode();
2147 	SwHyphArgs *pHyphArgs = (SwHyphArgs*)pArgs;
2148 	if( pNode )
2149 	{
2150 		SwCntntFrm* pCntFrm = pNode->getLayoutFrm( pNode->GetDoc()->GetCurrentLayout() );
2151 		if( pCntFrm && !((SwTxtFrm*)pCntFrm)->IsHiddenNow() )
2152 		{
2153 			sal_uInt16 *pPageSt = pHyphArgs->GetPageSt();
2154 			sal_uInt16 *pPageCnt = pHyphArgs->GetPageCnt();
2155 			if( pPageCnt && *pPageCnt && pPageSt )
2156 			{
2157 				sal_uInt16 nPageNr = pCntFrm->GetPhyPageNum();
2158 				if( !*pPageSt )
2159 				{
2160 					*pPageSt = nPageNr;
2161 					if( *pPageCnt < *pPageSt )
2162 						*pPageCnt = *pPageSt;
2163 				}
2164 				long nStat = nPageNr >= *pPageSt ? nPageNr - *pPageSt + 1
2165 										 : nPageNr + *pPageCnt - *pPageSt + 1;
2166 				::SetProgressState( nStat, (SwDocShell*)pNode->GetDoc()->GetDocShell() );
2167 			}
2168 			pHyphArgs->SetRange( rpNd );
2169 			if( pNode->Hyphenate( *pHyphArgs ) )
2170 			{
2171 				pHyphArgs->SetNode( rpNd );
2172 				return sal_False;
2173 			}
2174 		}
2175 	}
2176 	pHyphArgs->NextNode();
2177 	return sal_True;
2178 }
2179 
2180 uno::Reference< XHyphenatedWord >  SwDoc::Hyphenate(
2181 							SwPaM *pPam, const Point &rCrsrPos,
2182 						 	sal_uInt16* pPageCnt, sal_uInt16* pPageSt )
2183 {
2184 	ASSERT(this == pPam->GetDoc(), "SwDoc::Hyphenate: strangers in the night");
2185 
2186 	if( *pPam->GetPoint() > *pPam->GetMark() )
2187 		pPam->Exchange();
2188 
2189 	SwHyphArgs aHyphArg( pPam, rCrsrPos, pPageCnt, pPageSt );
2190 	SwNodeIndex aTmpIdx( pPam->GetMark()->nNode, 1 );
2191 	GetNodes().ForEach( pPam->GetPoint()->nNode, aTmpIdx,
2192 					lcl_HyphenateNode, &aHyphArg );
2193 	aHyphArg.SetPam( pPam );
2194 	return aHyphArg.GetHyphWord();	// will be set by lcl_HyphenateNode
2195 }
2196 
2197 
2198 sal_Bool lcl_GetTokenToParaBreak( String& rStr, String& rRet, sal_Bool bRegExpRplc )
2199 {
2200 	sal_Bool bRet = sal_False;
2201 	if( bRegExpRplc )
2202 	{
2203 		xub_StrLen nPos = 0;
2204 		String sPara( String::CreateFromAscii(
2205 									RTL_CONSTASCII_STRINGPARAM( "\\n" )));
2206 		while( STRING_NOTFOUND != ( nPos = rStr.Search( sPara, nPos )) )
2207 		{
2208 			// wurde das escaped?
2209 			if( nPos && '\\' == rStr.GetChar( nPos-1 ))
2210 			{
2211 				if( ++nPos >= rStr.Len() )
2212 					break;
2213 			}
2214 			else
2215 			{
2216 				rRet = rStr.Copy( 0, nPos );
2217 				rStr.Erase( 0, nPos + sPara.Len() );
2218 				bRet = sal_True;
2219 				break;
2220 			}
2221 		}
2222 	}
2223 	if( !bRet )
2224 	{
2225 		rRet = rStr;
2226 		rStr.Erase();
2227 	}
2228 	return bRet;
2229 }
2230 
2231 bool SwDoc::ReplaceRange( SwPaM& rPam, const String& rStr,
2232         const bool bRegExReplace )
2233 {
2234     // unfortunately replace works slightly differently from delete,
2235     // so we cannot use lcl_DoWithBreaks here...
2236 
2237     ::std::vector<xub_StrLen> Breaks;
2238 
2239     SwPaM aPam( *rPam.GetMark(), *rPam.GetPoint() );
2240     aPam.Normalize(sal_False);
2241     if (aPam.GetPoint()->nNode != aPam.GetMark()->nNode)
2242     {
2243         aPam.Move(fnMoveBackward);
2244     }
2245     ASSERT((aPam.GetPoint()->nNode == aPam.GetMark()->nNode), "invalid pam?");
2246 
2247     lcl_CalcBreaks(Breaks, aPam);
2248 
2249     while (!Breaks.empty() // skip over prefix of dummy chars
2250             && (aPam.GetMark()->nContent.GetIndex() == *Breaks.begin()) )
2251     {
2252         // skip!
2253         ++aPam.GetMark()->nContent; // always in bounds if Breaks valid
2254         Breaks.erase(Breaks.begin());
2255     }
2256     *rPam.Start() = *aPam.GetMark(); // update start of original pam w/ prefix
2257 
2258     if (!Breaks.size())
2259     {
2260         return ReplaceRangeImpl(rPam, rStr, bRegExReplace); // original pam!
2261     }
2262 
2263     // N.B.: deletion must be split into several parts if the text node
2264     // contains a text attribute with end and with dummy character
2265     // and the selection does not contain the text attribute completely,
2266     // but overlaps its start (left), where the dummy character is.
2267 
2268     bool bRet( true );
2269     // iterate from end to start, to avoid invalidating the offsets!
2270     ::std::vector<xub_StrLen>::reverse_iterator iter( Breaks.rbegin() );
2271     ASSERT(aPam.GetPoint() == aPam.End(), "wrong!");
2272     SwPosition & rEnd( *aPam.End() );
2273     SwPosition & rStart( *aPam.Start() );
2274 
2275     // set end of temp pam to original end (undo Move backward above)
2276     rEnd = *rPam.End();
2277     // after first deletion, rEnd will point into the original text node again!
2278 
2279     while (iter != Breaks.rend())
2280     {
2281         rStart.nContent = *iter + 1;
2282         if (rEnd.nContent != rStart.nContent) // check if part is empty
2283         {
2284             bRet &= (IsRedlineOn())
2285                 ? DeleteAndJoinWithRedlineImpl(aPam)
2286                 : DeleteAndJoinImpl(aPam, false);
2287         }
2288         rEnd.nContent = *iter;
2289         ++iter;
2290     }
2291 
2292     rStart = *rPam.Start(); // set to original start
2293     ASSERT(rEnd.nContent > rStart.nContent, "replace part empty!");
2294     if (rEnd.nContent > rStart.nContent) // check if part is empty
2295     {
2296         bRet &= ReplaceRangeImpl(aPam, rStr, bRegExReplace);
2297     }
2298 
2299     rPam = aPam; // update original pam (is this required?)
2300 
2301     return bRet;
2302 }
2303 
2304 // N.B.: it is possible to call Replace with a PaM that spans 2 paragraphs:
2305 // search with regex for "$", then replace _all_
2306 bool SwDoc::ReplaceRangeImpl( SwPaM& rPam, const String& rStr,
2307         const bool bRegExReplace )
2308 {
2309 	if( !rPam.HasMark() || *rPam.GetPoint() == *rPam.GetMark() )
2310         return false;
2311 
2312 	sal_Bool bJoinTxt, bJoinPrev;
2313 	lcl_GetJoinFlags( rPam, bJoinTxt, bJoinPrev );
2314 
2315 	{
2316 		// dann eine Kopie vom Cursor erzeugen um alle Pams aus den
2317 		// anderen Sichten aus dem Loeschbereich zu verschieben
2318 		// ABER NICHT SICH SELBST !!
2319 		SwPaM aDelPam( *rPam.GetMark(), *rPam.GetPoint() );
2320 		::PaMCorrAbs( aDelPam, *aDelPam.GetPoint() );
2321 
2322 		SwPosition *pStt = (SwPosition*)aDelPam.Start(),
2323 				   *pEnd = (SwPosition*)aDelPam.End();
2324 		ASSERT( pStt->nNode == pEnd->nNode ||
2325 				( pStt->nNode.GetIndex() + 1 == pEnd->nNode.GetIndex() &&
2326 					!pEnd->nContent.GetIndex() ),
2327                 "invalid range: Point and Mark on different nodes" );
2328 		sal_Bool bOneNode = pStt->nNode == pEnd->nNode;
2329 
2330 		// eigenes Undo ????
2331 		String sRepl( rStr );
2332 		SwTxtNode* pTxtNd = pStt->nNode.GetNode().GetTxtNode();
2333 		xub_StrLen nStt = pStt->nContent.GetIndex(),
2334 				nEnd = bOneNode ? pEnd->nContent.GetIndex()
2335 								: pTxtNd->GetTxt().Len();
2336 
2337 		SwDataChanged aTmp( aDelPam, 0 );
2338 
2339 		if( IsRedlineOn() )
2340         {
2341 			RedlineMode_t eOld = GetRedlineMode();
2342 			checkRedlining(eOld);
2343             if (GetIDocumentUndoRedo().DoesUndo())
2344             {
2345                 GetIDocumentUndoRedo().StartUndo(UNDO_EMPTY, NULL);
2346 
2347                 // Bug 68584 - if any Redline will change (split!) the node
2348                 const ::sw::mark::IMark* pBkmk = getIDocumentMarkAccess()->makeMark( aDelPam, ::rtl::OUString(), IDocumentMarkAccess::UNO_BOOKMARK );
2349 
2350                 //JP 06.01.98: MUSS noch optimiert werden!!!
2351                 SetRedlineMode(
2352                     (RedlineMode_t)(nsRedlineMode_t::REDLINE_ON | nsRedlineMode_t::REDLINE_SHOW_INSERT | nsRedlineMode_t::REDLINE_SHOW_DELETE ));
2353 
2354                 *aDelPam.GetPoint() = pBkmk->GetMarkPos();
2355                 if(pBkmk->IsExpanded())
2356                     *aDelPam.GetMark() = pBkmk->GetOtherMarkPos();
2357                 getIDocumentMarkAccess()->deleteMark(pBkmk);
2358                 pStt = aDelPam.Start();
2359                 pTxtNd = pStt->nNode.GetNode().GetTxtNode();
2360                 nStt = pStt->nContent.GetIndex();
2361 			}
2362 
2363 			if( sRepl.Len() )
2364 			{
2365 				// Attribute des 1. Zeichens ueber den ReplaceText setzen
2366 				SfxItemSet aSet( GetAttrPool(),
2367 							RES_CHRATR_BEGIN,	  RES_TXTATR_WITHEND_END - 1,
2368 							RES_UNKNOWNATR_BEGIN, RES_UNKNOWNATR_END-1,
2369 							0 );
2370 				pTxtNd->GetAttr( aSet, nStt+1, nStt+1 );
2371 
2372 				aSet.ClearItem( RES_TXTATR_REFMARK );
2373 				aSet.ClearItem( RES_TXTATR_TOXMARK );
2374                 aSet.ClearItem( RES_TXTATR_CJK_RUBY );
2375                 aSet.ClearItem( RES_TXTATR_INETFMT );
2376                 aSet.ClearItem( RES_TXTATR_META );
2377                 aSet.ClearItem( RES_TXTATR_METAFIELD );
2378 
2379 				if( aDelPam.GetPoint() != aDelPam.End() )
2380 					aDelPam.Exchange();
2381 
2382 				// das Ende merken
2383 				SwNodeIndex aPtNd( aDelPam.GetPoint()->nNode, -1 );
2384 				xub_StrLen nPtCnt = aDelPam.GetPoint()->nContent.GetIndex();
2385 
2386 				sal_Bool bFirst = sal_True;
2387 				String sIns;
2388                 while ( lcl_GetTokenToParaBreak( sRepl, sIns, bRegExReplace ) )
2389 				{
2390                     InsertString( aDelPam, sIns );
2391 					if( bFirst )
2392 					{
2393 						SwNodeIndex aMkNd( aDelPam.GetMark()->nNode, -1 );
2394 						xub_StrLen nMkCnt = aDelPam.GetMark()->nContent.GetIndex();
2395 
2396 						SplitNode( *aDelPam.GetPoint(), false );
2397 
2398 						aMkNd++;
2399 						aDelPam.GetMark()->nNode = aMkNd;
2400 						aDelPam.GetMark()->nContent.Assign(
2401 									aMkNd.GetNode().GetCntntNode(), nMkCnt );
2402 						bFirst = sal_False;
2403 					}
2404 					else
2405 						SplitNode( *aDelPam.GetPoint(), false );
2406 				}
2407 				if( sIns.Len() )
2408                 {
2409                     InsertString( aDelPam, sIns );
2410                 }
2411 
2412 				SwPaM aTmpRange( *aDelPam.GetPoint() );
2413 				aTmpRange.SetMark();
2414 
2415 				aPtNd++;
2416 				aDelPam.GetPoint()->nNode = aPtNd;
2417 				aDelPam.GetPoint()->nContent.Assign( aPtNd.GetNode().GetCntntNode(),
2418 													nPtCnt);
2419 				*aTmpRange.GetMark() = *aDelPam.GetPoint();
2420 
2421                 RstTxtAttrs( aTmpRange );
2422                 InsertItemSet( aTmpRange, aSet, 0 );
2423             }
2424 
2425             if (GetIDocumentUndoRedo().DoesUndo())
2426             {
2427                 SwUndo *const pUndoRD =
2428                     new SwUndoRedlineDelete( aDelPam, UNDO_REPLACE );
2429                 GetIDocumentUndoRedo().AppendUndo(pUndoRD);
2430             }
2431 			AppendRedline( new SwRedline( nsRedlineType_t::REDLINE_DELETE, aDelPam ), true);
2432 
2433 			*rPam.GetMark() = *aDelPam.GetMark();
2434             if (GetIDocumentUndoRedo().DoesUndo())
2435             {
2436 				*aDelPam.GetPoint() = *rPam.GetPoint();
2437                 GetIDocumentUndoRedo().EndUndo(UNDO_EMPTY, NULL);
2438 
2439 				// Bug 68584 - if any Redline will change (split!) the node
2440                 const ::sw::mark::IMark* pBkmk = getIDocumentMarkAccess()->makeMark( aDelPam, ::rtl::OUString(), IDocumentMarkAccess::UNO_BOOKMARK );
2441 
2442 				SwIndex& rIdx = aDelPam.GetPoint()->nContent;
2443 				rIdx.Assign( 0, 0 );
2444 				aDelPam.GetMark()->nContent = rIdx;
2445 				rPam.GetPoint()->nNode = 0;
2446 				rPam.GetPoint()->nContent = rIdx;
2447 				*rPam.GetMark() = *rPam.GetPoint();
2448 //JP 06.01.98: MUSS noch optimiert werden!!!
2449 SetRedlineMode( eOld );
2450 
2451                 *rPam.GetPoint() = pBkmk->GetMarkPos();
2452                 if(pBkmk->IsExpanded())
2453                     *rPam.GetMark() = pBkmk->GetOtherMarkPos();
2454                 getIDocumentMarkAccess()->deleteMark(pBkmk);
2455 			}
2456 			bJoinTxt = sal_False;
2457 		}
2458 		else
2459 		{
2460 			if( !IsIgnoreRedline() && GetRedlineTbl().Count() )
2461 				DeleteRedline( aDelPam, true, USHRT_MAX );
2462 
2463 			SwUndoReplace* pUndoRpl = 0;
2464             bool const bDoesUndo = GetIDocumentUndoRedo().DoesUndo();
2465             if (bDoesUndo)
2466             {
2467                 pUndoRpl = new SwUndoReplace(aDelPam, sRepl, bRegExReplace);
2468                 GetIDocumentUndoRedo().AppendUndo(pUndoRpl);
2469             }
2470             ::sw::UndoGuard const undoGuard(GetIDocumentUndoRedo());
2471 
2472 			if( aDelPam.GetPoint() != pStt )
2473 				aDelPam.Exchange();
2474 
2475 			SwNodeIndex aPtNd( pStt->nNode, -1 );
2476 			xub_StrLen nPtCnt = pStt->nContent.GetIndex();
2477 
2478 			// die Werte nochmal setzen, falls schohn Rahmen oder Fussnoten
2479 			// auf dem Text entfernt wurden!
2480 			nStt = nPtCnt;
2481 			nEnd = bOneNode ? pEnd->nContent.GetIndex()
2482 							: pTxtNd->GetTxt().Len();
2483 
2484 			sal_Bool bFirst = sal_True;
2485 			String sIns;
2486             while ( lcl_GetTokenToParaBreak( sRepl, sIns, bRegExReplace ) )
2487 			{
2488 				if( !bFirst || nStt == pTxtNd->GetTxt().Len() )
2489                 {
2490                     InsertString( aDelPam, sIns );
2491                 }
2492 				else if( nStt < nEnd || sIns.Len() )
2493                 {
2494                     pTxtNd->ReplaceText( pStt->nContent, nEnd - nStt, sIns );
2495                 }
2496 				SplitNode( *pStt, false);
2497 				bFirst = sal_False;
2498 			}
2499 
2500 			if( bFirst || sIns.Len() )
2501 			{
2502 				if( !bFirst || nStt == pTxtNd->GetTxt().Len() )
2503                 {
2504                     InsertString( aDelPam, sIns );
2505                 }
2506 				else if( nStt < nEnd || sIns.Len() )
2507                 {
2508                     pTxtNd->ReplaceText( pStt->nContent, nEnd - nStt, sIns );
2509                 }
2510             }
2511 
2512 			*rPam.GetMark() = *aDelPam.GetMark();
2513 
2514 			aPtNd++;
2515 			rPam.GetMark()->nNode = aPtNd;
2516 			rPam.GetMark()->nContent.Assign( aPtNd.GetNode().GetCntntNode(),
2517 												nPtCnt );
2518 
2519 			if( pUndoRpl )
2520             {
2521                 pUndoRpl->SetEnd(rPam);
2522             }
2523         }
2524     }
2525 
2526 	if( bJoinTxt )
2527 		lcl_JoinText( rPam, bJoinPrev );
2528 
2529 	SetModified();
2530     return true;
2531 }
2532 
2533 	// speicher die akt. Werte fuer die automatische Aufnahme von Ausnahmen
2534 	// in die Autokorrektur
2535 void SwDoc::SetAutoCorrExceptWord( SwAutoCorrExceptWord* pNew )
2536 {
2537 	if( pACEWord && pNew != pACEWord )
2538 		delete pACEWord;
2539 	pACEWord = pNew;
2540 }
2541 
2542 bool SwDoc::DelFullPara( SwPaM& rPam )
2543 {
2544 	const SwPosition &rStt = *rPam.Start(), &rEnd = *rPam.End();
2545 	const SwNode* pNd = &rStt.nNode.GetNode();
2546     sal_uInt32 nSectDiff = pNd->StartOfSectionNode()->EndOfSectionIndex() -
2547 						pNd->StartOfSectionIndex();
2548 	sal_uInt32 nNodeDiff = rEnd.nNode.GetIndex() - rStt.nNode.GetIndex();
2549 
2550 	if ( nSectDiff-2 <= nNodeDiff || IsRedlineOn() ||
2551 		 /* #i9185# Prevent getting the node after the end node (see below) */
2552         rEnd.nNode.GetIndex() + 1 == GetNodes().Count() )
2553     {
2554 		return sal_False;
2555     }
2556 
2557 	// harte SeitenUmbrueche am nachfolgenden Node verschieben
2558 	sal_Bool bSavePageBreak = sal_False, bSavePageDesc = sal_False;
2559 
2560 	/* #i9185# This whould lead to a segmentation fault if not catched
2561        above. */
2562 	sal_uLong nNextNd = rEnd.nNode.GetIndex() + 1;
2563     SwTableNode *const pTblNd = GetNodes()[ nNextNd ]->GetTableNode();
2564 
2565 	if( pTblNd && pNd->IsCntntNode() )
2566 	{
2567 		SwFrmFmt* pTableFmt = pTblNd->GetTable().GetFrmFmt();
2568 //JP 24.08.98: will man wirklich den PageDesc/Break vom
2569 //				nachfolgen Absatz ueberbuegeln?
2570 //		const SwAttrSet& rAttrSet = pTableFmt->GetAttrSet();
2571 //		if( SFX_ITEM_SET != rAttrSet.GetItemState( RES_PAGEDESC ) &&
2572 //			SFX_ITEM_SET != rAttrSet.GetItemState( RES_BREAK ))
2573 		{
2574 			const SfxPoolItem *pItem;
2575 			const SfxItemSet* pSet = ((SwCntntNode*)pNd)->GetpSwAttrSet();
2576 			if( pSet && SFX_ITEM_SET == pSet->GetItemState( RES_PAGEDESC,
2577 				sal_False, &pItem ) )
2578 			{
2579                 pTableFmt->SetFmtAttr( *pItem );
2580 				bSavePageDesc = sal_True;
2581 			}
2582 
2583 			if( pSet && SFX_ITEM_SET == pSet->GetItemState( RES_BREAK,
2584 				sal_False, &pItem ) )
2585 			{
2586                 pTableFmt->SetFmtAttr( *pItem );
2587 				bSavePageBreak = sal_True;
2588 			}
2589 		}
2590 	}
2591 
2592     bool const bDoesUndo = GetIDocumentUndoRedo().DoesUndo();
2593 	if( bDoesUndo )
2594 	{
2595 		if( !rPam.HasMark() )
2596 			rPam.SetMark();
2597 		else if( rPam.GetPoint() == &rStt )
2598 			rPam.Exchange();
2599 		rPam.GetPoint()->nNode++;
2600 
2601         SwCntntNode *pTmpNode = rPam.GetPoint()->nNode.GetNode().GetCntntNode();
2602         rPam.GetPoint()->nContent.Assign( pTmpNode, 0 );
2603         bool bGoNext = (0 == pTmpNode);
2604         pTmpNode = rPam.GetMark()->nNode.GetNode().GetCntntNode();
2605 		rPam.GetMark()->nContent.Assign( pTmpNode, 0 );
2606 
2607         GetIDocumentUndoRedo().ClearRedo();
2608 
2609 		SwPaM aDelPam( *rPam.GetMark(), *rPam.GetPoint() );
2610         {
2611             SwPosition aTmpPos( *aDelPam.GetPoint() );
2612             if( bGoNext )
2613             {
2614                 pTmpNode = GetNodes().GoNext( &aTmpPos.nNode );
2615                 aTmpPos.nContent.Assign( pTmpNode, 0 );
2616             }
2617             ::PaMCorrAbs( aDelPam, aTmpPos );
2618         }
2619 
2620 		SwUndoDelete* pUndo = new SwUndoDelete( aDelPam, sal_True );
2621 
2622 		*rPam.GetPoint() = *aDelPam.GetPoint();
2623 		pUndo->SetPgBrkFlags( bSavePageBreak, bSavePageDesc );
2624         GetIDocumentUndoRedo().AppendUndo(pUndo);
2625     }
2626     else
2627     {
2628 		SwNodeRange aRg( rStt.nNode, rEnd.nNode );
2629 		if( rPam.GetPoint() != &rEnd )
2630 			rPam.Exchange();
2631 
2632 		// versuche hinters Ende zu verschieben
2633 		if( !rPam.Move( fnMoveForward, fnGoNode ) )
2634 		{
2635 			// na gut, dann an den Anfang
2636 			rPam.Exchange();
2637 			if( !rPam.Move( fnMoveBackward, fnGoNode ))
2638 			{
2639 				ASSERT( sal_False, "kein Node mehr vorhanden" );
2640 				return sal_False;
2641 			}
2642 		}
2643         // move bookmarks, redlines etc.
2644         if (aRg.aStart == aRg.aEnd) // only first CorrAbs variant handles this
2645         {
2646             CorrAbs( aRg.aStart, *rPam.GetPoint(), 0, sal_True );
2647         }
2648         else
2649         {
2650             CorrAbs( aRg.aStart, aRg.aEnd, *rPam.GetPoint(), sal_True );
2651         }
2652 
2653 			// was ist mit Fly's ??
2654 		{
2655 			// stehen noch FlyFrames rum, loesche auch diese
2656 			for( sal_uInt16 n = 0; n < GetSpzFrmFmts()->Count(); ++n )
2657 			{
2658 				SwFrmFmt* pFly = (*GetSpzFrmFmts())[n];
2659 				const SwFmtAnchor* pAnchor = &pFly->GetAnchor();
2660                 SwPosition const*const pAPos = pAnchor->GetCntntAnchor();
2661                 if (pAPos &&
2662                     ((FLY_AT_PARA == pAnchor->GetAnchorId()) ||
2663                      (FLY_AT_CHAR == pAnchor->GetAnchorId())) &&
2664 					aRg.aStart <= pAPos->nNode && pAPos->nNode <= aRg.aEnd )
2665 				{
2666 					DelLayoutFmt( pFly );
2667 					--n;
2668 				}
2669 			}
2670 		}
2671 
2672         SwCntntNode *pTmpNode = rPam.GetBound( sal_True ).nNode.GetNode().GetCntntNode();
2673 		rPam.GetBound( sal_True ).nContent.Assign( pTmpNode, 0 );
2674         pTmpNode = rPam.GetBound( sal_False ).nNode.GetNode().GetCntntNode();
2675 		rPam.GetBound( sal_False ).nContent.Assign( pTmpNode, 0 );
2676 		GetNodes().Delete( aRg.aStart, nNodeDiff+1 );
2677 	}
2678 	rPam.DeleteMark();
2679 	SetModified();
2680 
2681 	return sal_True;
2682 }
2683 
2684 
2685 void SwDoc::TransliterateText(
2686     const SwPaM& rPaM,
2687     utl::TransliterationWrapper& rTrans )
2688 {
2689     SwUndoTransliterate *const pUndo = (GetIDocumentUndoRedo().DoesUndo())
2690         ?   new SwUndoTransliterate( rPaM, rTrans )
2691         :   0;
2692 
2693     const SwPosition* pStt = rPaM.Start(),
2694        			    * pEnd = rPaM.End();
2695     sal_uLong nSttNd = pStt->nNode.GetIndex(),
2696           nEndNd = pEnd->nNode.GetIndex();
2697 	xub_StrLen nSttCnt = pStt->nContent.GetIndex(),
2698 			   nEndCnt = pEnd->nContent.GetIndex();
2699 
2700 	SwTxtNode* pTNd = pStt->nNode.GetNode().GetTxtNode();
2701 	if( pStt == pEnd && pTNd )  // no selection?
2702 	{
2703         // set current word as 'area of effect'
2704 
2705 		Boundary aBndry;
2706 		if( pBreakIt->GetBreakIter().is() )
2707 			aBndry = pBreakIt->GetBreakIter()->getWordBoundary(
2708 						pTNd->GetTxt(), nSttCnt,
2709 						pBreakIt->GetLocale( pTNd->GetLang( nSttCnt ) ),
2710 						WordType::ANY_WORD /*ANYWORD_IGNOREWHITESPACES*/,
2711 						sal_True );
2712 
2713 		if( aBndry.startPos < nSttCnt && nSttCnt < aBndry.endPos )
2714 		{
2715 			nSttCnt = (xub_StrLen)aBndry.startPos;
2716 			nEndCnt = (xub_StrLen)aBndry.endPos;
2717 		}
2718 	}
2719 
2720 	if( nSttNd != nEndNd )  // is more than one text node involved?
2721 	{
2722         // iterate over all effected text nodes, the first and the last one
2723         // may be incomplete because the selection starts and/or ends there
2724 
2725 		SwNodeIndex aIdx( pStt->nNode );
2726 		if( nSttCnt )
2727 		{
2728 			aIdx++;
2729 			if( pTNd )
2730 				pTNd->TransliterateText( rTrans, nSttCnt, pTNd->GetTxt().Len(), pUndo );
2731 		}
2732 
2733 		for( ; aIdx.GetIndex() < nEndNd; aIdx++ )
2734         {
2735 			if( 0 != ( pTNd = aIdx.GetNode().GetTxtNode() ))
2736 				pTNd->TransliterateText( rTrans, 0, pTNd->GetTxt().Len(), pUndo );
2737         }
2738 
2739 		if( nEndCnt && 0 != ( pTNd = pEnd->nNode.GetNode().GetTxtNode() ))
2740 			pTNd->TransliterateText( rTrans, 0, nEndCnt, pUndo );
2741 	}
2742 	else if( pTNd && nSttCnt < nEndCnt )
2743 		pTNd->TransliterateText( rTrans, nSttCnt, nEndCnt, pUndo );
2744 
2745 	if( pUndo )
2746 	{
2747 		if( pUndo->HasData() )
2748         {
2749             GetIDocumentUndoRedo().AppendUndo(pUndo);
2750         }
2751         else
2752 			delete pUndo;
2753 	}
2754     SetModified();
2755 }
2756 
2757 
2758 #define MAX_REDLINE_COUNT	250
2759 // -----------------------------------------------------------------------------
2760 void SwDoc::checkRedlining(RedlineMode_t& _rReadlineMode)
2761 {
2762 	const SwRedlineTbl& rRedlineTbl = GetRedlineTbl();
2763 	SwEditShell* pEditShell = GetEditShell();
2764 	Window* pParent = pEditShell ? pEditShell->GetWin() : NULL;
2765 	if ( pParent && !mbReadlineChecked && rRedlineTbl.Count() > MAX_REDLINE_COUNT
2766 		&& !((_rReadlineMode & nsRedlineMode_t::REDLINE_SHOW_DELETE) == nsRedlineMode_t::REDLINE_SHOW_DELETE) )
2767 	{
2768 		WarningBox aWarning( pParent,SW_RES(MSG_DISABLE_READLINE_QUESTION));
2769 		sal_uInt16 nResult = aWarning.Execute();
2770 		mbReadlineChecked = sal_True;
2771 		if ( nResult == RET_YES )
2772 		{
2773 			sal_Int32 nMode = (sal_Int32)_rReadlineMode;
2774 			nMode |= nsRedlineMode_t::REDLINE_SHOW_INSERT | nsRedlineMode_t::REDLINE_SHOW_DELETE;
2775 			_rReadlineMode = (RedlineMode_t)nMode;
2776 		}
2777 	}
2778 }
2779 // -----------------------------------------------------------------------------
2780 
2781 void SwDoc::CountWords( const SwPaM& rPaM, SwDocStat& rStat ) const
2782 {
2783     // This is a modified version of SwDoc::TransliterateText
2784     const SwPosition* pStt = rPaM.Start();
2785     const SwPosition* pEnd = pStt == rPaM.GetPoint() ? rPaM.GetMark()
2786                                                      : rPaM.GetPoint();
2787 
2788     const sal_uLong nSttNd = pStt->nNode.GetIndex();
2789     const sal_uLong nEndNd = pEnd->nNode.GetIndex();
2790 
2791     const xub_StrLen nSttCnt = pStt->nContent.GetIndex();
2792     const xub_StrLen nEndCnt = pEnd->nContent.GetIndex();
2793 
2794     const SwTxtNode* pTNd = pStt->nNode.GetNode().GetTxtNode();
2795     if( pStt == pEnd && pTNd )                  // no region ?
2796     {
2797         // do nothing
2798         return;
2799     }
2800 
2801     if( nSttNd != nEndNd )
2802     {
2803         SwNodeIndex aIdx( pStt->nNode );
2804         if( nSttCnt )
2805         {
2806             aIdx++;
2807             if( pTNd )
2808                 pTNd->CountWords( rStat, nSttCnt, pTNd->GetTxt().Len() );
2809         }
2810 
2811         for( ; aIdx.GetIndex() < nEndNd; aIdx++ )
2812             if( 0 != ( pTNd = aIdx.GetNode().GetTxtNode() ))
2813                 pTNd->CountWords( rStat, 0, pTNd->GetTxt().Len() );
2814 
2815         if( nEndCnt && 0 != ( pTNd = pEnd->nNode.GetNode().GetTxtNode() ))
2816             pTNd->CountWords( rStat, 0, nEndCnt );
2817     }
2818     else if( pTNd && nSttCnt < nEndCnt )
2819         pTNd->CountWords( rStat, nSttCnt, nEndCnt );
2820 }
2821 
2822 void SwDoc::RemoveLeadingWhiteSpace(const SwPosition & rPos )
2823 {
2824     const SwTxtNode* pTNd = rPos.nNode.GetNode().GetTxtNode();
2825     if ( pTNd )
2826     {
2827         const String& rTxt = pTNd->GetTxt();
2828         xub_StrLen nIdx = 0;
2829         sal_Unicode cCh;
2830         while( nIdx < rTxt.Len() &&
2831                 ( '\t' == ( cCh = rTxt.GetChar( nIdx ) ) ||
2832                 (  ' ' == cCh ) ) )
2833             ++nIdx;
2834 
2835         if ( nIdx > 0 )
2836         {
2837             SwPaM aPam(rPos);
2838             aPam.GetPoint()->nContent = 0;
2839             aPam.SetMark();
2840             aPam.GetMark()->nContent = nIdx;
2841             DeleteRange( aPam );
2842         }
2843     }
2844 }
2845