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