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