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