xref: /trunk/main/sw/source/core/doc/docredln.cxx (revision cdf0e10c4e3984b49a9502b011690b615761d4a3)
1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_sw.hxx"
30 
31 
32 #include <hintids.hxx>
33 #include <tools/shl.hxx>
34 #include <svl/itemiter.hxx>
35 #include <sfx2/app.hxx>
36 #include <editeng/colritem.hxx>
37 #include <editeng/udlnitem.hxx>
38 #include <editeng/crsditem.hxx>
39 #include <swmodule.hxx>
40 #include <doc.hxx>
41 #include <IDocumentUndoRedo.hxx>
42 #include <docary.hxx>
43 #include <ndtxt.hxx>
44 #include <redline.hxx>
45 #include <swundo.hxx>
46 #include <UndoCore.hxx>
47 #include <UndoRedline.hxx>
48 #include <hints.hxx>
49 #include <pamtyp.hxx>
50 #include <poolfmt.hxx>
51 #include <viewsh.hxx>
52 #include <rootfrm.hxx>
53 
54 #include <comcore.hrc>
55 
56 using namespace com::sun::star;
57 
58 TYPEINIT1(SwRedlineHint, SfxHint);
59 
60 #ifndef DBG_UTIL
61 
62     #define _CHECK_REDLINE( pDoc )
63     #define _DEBUG_REDLINE( pDoc )
64 
65 #else
66 
67 #define _ERROR_PREFIX "redline table corrupted: "
68 
69     // helper function for lcl_CheckRedline
70     // 1. make sure that pPos->nContent points into pPos->nNode
71     //    (or into the 'special' no-content-node-IndexReg)
72     // 2. check that position is valid and doesn't point behind text
73     void lcl_CheckPosition( const SwPosition* pPos )
74     {
75         SwPosition aComparePos( *pPos );
76         aComparePos.nContent.Assign(
77             aComparePos.nNode.GetNode().GetCntntNode(), 0 );
78         DBG_ASSERT( pPos->nContent.GetIdxReg() ==
79                     aComparePos.nContent.GetIdxReg(),
80                     _ERROR_PREFIX "illegal position" );
81 
82         SwTxtNode* pTxtNode = pPos->nNode.GetNode().GetTxtNode();
83         if( pTxtNode == NULL )
84         {
85             DBG_ASSERT( pPos->nContent == 0,
86                         _ERROR_PREFIX "non-text-node with content" );
87         }
88         else
89         {
90             DBG_ASSERT( pPos->nContent >= 0  &&
91                         pPos->nContent <= pTxtNode->Len(),
92                         _ERROR_PREFIX "index behind text" );
93         }
94     }
95 
96     void lcl_CheckPam( const SwPaM* pPam )
97     {
98         DBG_ASSERT( pPam != NULL, _ERROR_PREFIX "illegal argument" );
99         lcl_CheckPosition( pPam->GetPoint() );
100         lcl_CheckPosition( pPam->GetMark() );
101     }
102 
103     // check validity of the redline table. Checks redline bounds, and make
104     // sure the redlines are sorted and non-overlapping.
105     void lcl_CheckRedline( const SwDoc* pDoc )
106     {
107         const SwRedlineTbl& rTbl = pDoc->GetRedlineTbl();
108 
109         // verify valid redline positions
110         for( sal_uInt16 i = 0; i < rTbl.Count(); ++i )
111             lcl_CheckPam( rTbl[ i ] );
112 
113         for( sal_uInt16 j = 0; j < rTbl.Count(); ++j )
114         {
115             // check for empty redlines
116             DBG_ASSERT( ( *(rTbl[j]->GetPoint()) != *(rTbl[j]->GetMark()) ) ||
117                         ( rTbl[j]->GetContentIdx() != NULL ),
118                         _ERROR_PREFIX "empty redline" );
119         }
120 
121         // verify proper redline sorting
122         for( sal_uInt16 n = 1; n < rTbl.Count(); ++n )
123         {
124             const SwRedline* pPrev = rTbl[ n-1 ];
125             const SwRedline* pCurrent = rTbl[ n ];
126 
127             // check redline sorting
128             DBG_ASSERT( *pPrev->Start() <= *pCurrent->Start(),
129                         _ERROR_PREFIX "not sorted correctly" );
130 
131             // check for overlapping redlines
132             DBG_ASSERT( *pPrev->End() <= *pCurrent->Start(),
133                         _ERROR_PREFIX "overlapping redlines" );
134         }
135     }
136 
137     #define _CHECK_REDLINE( pDoc ) lcl_CheckRedline( pDoc );
138 
139     void lcl_DebugRedline( const SwDoc* pDoc )
140     {
141         static sal_uInt16 nWatch = 0;
142         const SwRedlineTbl& rTbl = pDoc->GetRedlineTbl();
143         for( sal_uInt16 n = 0; n < rTbl.Count(); ++n )
144         {
145             sal_uInt16 nDummy = 0;
146             const SwRedline* pCurrent = rTbl[ n ];
147             const SwRedline* pNext = n+1 < rTbl.Count() ? rTbl[ n+1 ] : 0;
148             if( pCurrent == pNext )
149                 ++nDummy;
150             if( n == nWatch )
151                 ++nDummy; // Possible debugger breakpoint
152         }
153     }
154 
155     #define _DEBUG_REDLINE( pDoc ) lcl_DebugRedline( pDoc );
156 
157 #endif
158 
159 SV_IMPL_OP_PTRARR_SORT( _SwRedlineTbl, SwRedlinePtr )
160 
161 RedlineMode_t SwDoc::GetRedlineMode() const
162 {
163     return eRedlineMode;
164 }
165 
166 void SwDoc::SetRedlineMode( RedlineMode_t eMode )
167 {
168     if( eRedlineMode != eMode )
169     {
170         if( (nsRedlineMode_t::REDLINE_SHOW_MASK & eRedlineMode) != (nsRedlineMode_t::REDLINE_SHOW_MASK & eMode)
171             || 0 == (nsRedlineMode_t::REDLINE_SHOW_MASK & eMode) )
172         {
173             bool bSaveInXMLImportFlag = IsInXMLImport();
174             SetInXMLImport( false );
175             // und dann alles verstecken, anzeigen
176             void (SwRedline::*pFnc)( sal_uInt16 ) = 0;
177 
178             switch( nsRedlineMode_t::REDLINE_SHOW_MASK & eMode )
179             {
180             case nsRedlineMode_t::REDLINE_SHOW_INSERT | nsRedlineMode_t::REDLINE_SHOW_DELETE :
181                 pFnc = &SwRedline::Show;
182                 break;
183             case nsRedlineMode_t::REDLINE_SHOW_INSERT:
184                 pFnc = &SwRedline::Hide;
185                 break;
186             case nsRedlineMode_t::REDLINE_SHOW_DELETE:
187                 pFnc = &SwRedline::ShowOriginal;
188                 break;
189 
190             default:
191                 pFnc = &SwRedline::Hide;
192                 eMode = (RedlineMode_t)(eMode | nsRedlineMode_t::REDLINE_SHOW_INSERT);
193                 break;
194             }
195 
196             _CHECK_REDLINE( this )
197 
198             if( pFnc )
199                 for( sal_uInt16 nLoop = 1; nLoop <= 2; ++nLoop )
200                     for( sal_uInt16 i = 0; i < pRedlineTbl->Count(); ++i )
201                         ((*pRedlineTbl)[ i ]->*pFnc)( nLoop );
202             _CHECK_REDLINE( this )
203             SetInXMLImport( bSaveInXMLImportFlag );
204         }
205         eRedlineMode = eMode;
206         SetModified();
207     }
208 }
209 
210 bool SwDoc::IsRedlineOn() const
211 {
212     return IDocumentRedlineAccess::IsRedlineOn(eRedlineMode);
213 }
214 
215 bool SwDoc::IsIgnoreRedline() const
216 {
217     return (nsRedlineMode_t::REDLINE_IGNORE & eRedlineMode);
218 }
219 
220 void SwDoc::SetRedlineMode_intern(RedlineMode_t eMode)
221 {
222     eRedlineMode = eMode;
223 }
224 
225 const SwRedlineTbl& SwDoc::GetRedlineTbl() const
226 {
227     return *pRedlineTbl;
228 }
229 
230 bool SwDoc::IsRedlineMove() const
231 {
232     return mbIsRedlineMove;
233 }
234 
235 void SwDoc::SetRedlineMove(bool bFlag)
236 {
237     mbIsRedlineMove = bFlag;
238 }
239 
240 const uno::Sequence <sal_Int8>& SwDoc::GetRedlinePassword() const
241 {
242     return aRedlinePasswd;
243 }
244 
245 inline bool IsPrevPos( const SwPosition rPos1, const SwPosition rPos2 )
246 {
247     const SwCntntNode* pCNd;
248     return 0 == rPos2.nContent.GetIndex() &&
249             rPos2.nNode.GetIndex() - 1 == rPos1.nNode.GetIndex() &&
250             0 != ( pCNd = rPos1.nNode.GetNode().GetCntntNode() )
251                 ? rPos1.nContent.GetIndex() == pCNd->Len()
252                 : false;
253 }
254 
255 #ifdef DEBUG
256 bool CheckPosition( const SwPosition* pStt, const SwPosition* pEnd )
257 {
258     int nError = 0;
259     SwNode* pSttNode = &pStt->nNode.GetNode();
260     SwNode* pEndNode = &pEnd->nNode.GetNode();
261     SwNode* pSttTab = pSttNode->StartOfSectionNode()->FindTableNode();
262     SwNode* pEndTab = pEndNode->StartOfSectionNode()->FindTableNode();
263     SwNode* pSttStart = pSttNode;
264     while( pSttStart && (!pSttStart->IsStartNode() || pSttStart->IsSectionNode() ||
265         pSttStart->IsTableNode() ) )
266         pSttStart = pSttStart->StartOfSectionNode();
267     SwNode* pEndStart = pEndNode;
268     while( pEndStart && (!pEndStart->IsStartNode() || pEndStart->IsSectionNode() ||
269         pEndStart->IsTableNode() ) )
270         pEndStart = pEndStart->StartOfSectionNode();
271     if( pSttTab != pEndTab )
272         nError = 1;
273     if( !pSttTab && pSttStart != pEndStart )
274         nError |= 2;
275     if( nError )
276         nError += 10;
277     return nError != 0;
278 }
279 #endif
280 
281 /*
282 
283 Text heisst, nicht von Redline "verseuchter" Text.
284 
285 Verhalten von Insert-Redline:
286     - im Text                           - Redline Object einfuegen
287     - im InsertRedline (eigenes)        - ignorieren, bestehendes wird
288                                           aufgespannt
289     - im InsertRedline (andere)         - Insert Redline aufsplitten
290                                           Redline Object einfuegen
291     - in DeleteRedline                  - Delete Redline aufsplitten oder
292                                           am Ende/Anfang verschieben
293 
294 Verhalten von Delete-Redline:
295     - im Text                           - Redline Object einfuegen
296     - im DeleteRedline (eigenes/andere) - ignorieren
297     - im InsertRedline (eigenes)        - ignorieren, Zeichen aber loeschen
298     - im InsertRedline (andere)         - Insert Redline aufsplitten
299                                           Redline Object einfuegen
300     - Ueberlappung von Text und         - Text in eigenen Insert loeschen,
301       eigenem Insert                      im andereren Text aufspannen (bis
302                                           zum Insert!
303     - Ueberlappung von Text und         - Redline Object einfuegen, der
304       anderem Insert                      andere Insert wird vom Delete
305                                           ueberlappt
306 */
307 
308 bool SwDoc::AppendRedline( SwRedline* pNewRedl, bool bCallDelete )
309 {
310 #if 0
311 // #i93179# disabled: ASSERT in ~SwIndexReg     #ifdef DBG_UTIL
312     SwRedline aCopy( *pNewRedl );
313 #endif
314     bool bError = true;
315     _CHECK_REDLINE( this )
316 
317     if( IsRedlineOn() && !IsShowOriginal( eRedlineMode ) &&
318          pNewRedl->GetAuthorString().Len() )
319     {
320         pNewRedl->InvalidateRange();
321 
322         if( mbIsAutoFmtRedline )
323         {
324             pNewRedl->SetAutoFmtFlag();
325             if( pAutoFmtRedlnComment && pAutoFmtRedlnComment->Len() )
326             {
327                 pNewRedl->SetComment( *pAutoFmtRedlnComment );
328                 pNewRedl->SetSeqNo( nAutoFmtRedlnCommentNo );
329             }
330         }
331 
332         SwPosition* pStt = pNewRedl->Start(),
333                   * pEnd = pStt == pNewRedl->GetPoint() ? pNewRedl->GetMark()
334                                                         : pNewRedl->GetPoint();
335         {
336             SwTxtNode* pTxtNode = pStt->nNode.GetNode().GetTxtNode();
337             if( pTxtNode == NULL )
338             {
339                 if( pStt->nContent > 0 )
340                 {
341                     DBG_ASSERT( false, "Redline start: non-text-node with content" );
342                     pStt->nContent = 0;
343                 }
344             }
345             else
346             {
347                 if( pStt->nContent > pTxtNode->Len() )
348                 {
349                     DBG_ASSERT( false, "Redline start: index behind text" );
350                     pStt->nContent = pTxtNode->Len();
351                 }
352             }
353             pTxtNode = pEnd->nNode.GetNode().GetTxtNode();
354             if( pTxtNode == NULL )
355             {
356                 if( pEnd->nContent > 0 )
357                 {
358                     DBG_ASSERT( false, "Redline end: non-text-node with content" );
359                     pEnd->nContent = 0;
360                 }
361             }
362             else
363             {
364                 if( pEnd->nContent > pTxtNode->Len() )
365                 {
366                     DBG_ASSERT( false, "Redline end: index behind text" );
367                     pEnd->nContent = pTxtNode->Len();
368                 }
369             }
370         }
371         if( ( *pStt == *pEnd ) &&
372             ( pNewRedl->GetContentIdx() == NULL ) )
373         {   // Do not insert empty redlines
374             delete pNewRedl;
375             return sal_False;
376         }
377         sal_Bool bCompress = sal_False;
378         sal_uInt16 n = 0;
379             // zur StartPos das erste Redline suchen
380         if( !GetRedline( *pStt, &n ) && n )
381             --n;
382         bool bDec = false;
383 
384         for( ; pNewRedl && n < pRedlineTbl->Count(); bDec ? n : ++n )
385         {
386             bDec = false;
387 #ifdef DVO_TEST
388             _CHECK_REDLINE( this )
389 #endif
390 
391             SwRedline* pRedl = (*pRedlineTbl)[ n ];
392             SwPosition* pRStt = pRedl->Start(),
393                       * pREnd = pRStt == pRedl->GetPoint() ? pRedl->GetMark()
394                                                            : pRedl->GetPoint();
395 
396             // #i8518# remove empty redlines while we're at it
397             if( ( *pRStt == *pREnd ) &&
398                 ( pRedl->GetContentIdx() == NULL ) )
399             {
400                 pRedlineTbl->DeleteAndDestroy(n);
401                 continue;
402             }
403 
404             SwComparePosition eCmpPos = ComparePosition( *pStt, *pEnd, *pRStt, *pREnd );
405 
406             switch( pNewRedl->GetType() )
407             {
408             case nsRedlineType_t::REDLINE_INSERT:
409                 switch( pRedl->GetType() )
410                 {
411                 case nsRedlineType_t::REDLINE_INSERT:
412                     if( pRedl->IsOwnRedline( *pNewRedl ) )
413                     {
414                         bool bDelete = false;
415 
416                         // ggfs. verschmelzen?
417                         if( (( POS_BEHIND == eCmpPos &&
418                                IsPrevPos( *pREnd, *pStt ) ) ||
419                              ( POS_COLLIDE_START == eCmpPos ) ||
420                              ( POS_OVERLAP_BEHIND == eCmpPos ) ) &&
421                             pRedl->CanCombine( *pNewRedl ) &&
422                             ( n+1 >= pRedlineTbl->Count() ||
423                              ( *(*pRedlineTbl)[ n+1 ]->Start() >= *pEnd &&
424                              *(*pRedlineTbl)[ n+1 ]->Start() != *pREnd ) ) )
425                         {
426                             pRedl->SetEnd( *pEnd, pREnd );
427                             if( !pRedl->HasValidRange() )
428                             {
429                                 // neu einsortieren
430                                 pRedlineTbl->Remove( n );
431                                 pRedlineTbl->Insert( pRedl );
432                             }
433 
434                             bError = false;
435                             bDelete = true;
436                         }
437                         else if( (( POS_BEFORE == eCmpPos &&
438                                     IsPrevPos( *pEnd, *pRStt ) ) ||
439                                   ( POS_COLLIDE_END == eCmpPos ) ||
440                                   ( POS_OVERLAP_BEFORE == eCmpPos ) ) &&
441                             pRedl->CanCombine( *pNewRedl ) &&
442                             ( !n ||
443                              *(*pRedlineTbl)[ n-1 ]->End() != *pRStt ))
444                         {
445                             pRedl->SetStart( *pStt, pRStt );
446                             // neu einsortieren
447                             pRedlineTbl->Remove( n );
448                             pRedlineTbl->Insert( pRedl );
449 
450                             bError = false;
451                             bDelete = true;
452                         }
453                         else if ( POS_OUTSIDE == eCmpPos )
454                         {
455                             // #107164# own insert-over-insert
456                             // redlines: just scrap the inside ones
457                             pRedlineTbl->Remove( n );
458                             bDec = true;
459                         }
460                         // <- #107164#
461                         else if( POS_OVERLAP_BEHIND == eCmpPos )
462                         {
463                             *pStt = *pREnd;
464                             if( ( *pStt == *pEnd ) &&
465                                 ( pNewRedl->GetContentIdx() == NULL ) )
466                                 bDelete = true;
467                         }
468                         else if( POS_OVERLAP_BEFORE == eCmpPos )
469                         {
470                             *pEnd = *pRStt;
471                             if( ( *pStt == *pEnd ) &&
472                                 ( pNewRedl->GetContentIdx() == NULL ) )
473                                 bDelete = true;
474                         }
475                         else if( POS_INSIDE == eCmpPos || POS_EQUAL == eCmpPos)
476                             bDelete = true;
477 
478                         if( bDelete )
479                         {
480                             delete pNewRedl, pNewRedl = 0;
481                             bCompress = sal_True;
482                         }
483                     }
484                     else if( POS_INSIDE == eCmpPos )
485                     {
486                         // aufsplitten
487                         if( *pEnd != *pREnd )
488                         {
489                             SwRedline* pCpy = new SwRedline( *pRedl );
490                             pCpy->SetStart( *pEnd );
491                             pRedlineTbl->Insert( pCpy );
492                         }
493                         pRedl->SetEnd( *pStt, pREnd );
494                         if( ( *pStt == *pRStt ) &&
495                             ( pRedl->GetContentIdx() == NULL ) )
496                         {
497                             pRedlineTbl->DeleteAndDestroy( n );
498                             bDec = true;
499                         }
500                         else if( !pRedl->HasValidRange() )
501                         {
502                             // neu einsortieren
503                             pRedlineTbl->Remove( n );
504                             pRedlineTbl->Insert( pRedl );
505                         }
506                     }
507                     else if ( POS_OUTSIDE == eCmpPos )
508                     {
509                         // #102366# handle overlapping redlines in broken
510                         // documents
511 
512                         // split up the new redline, since it covers the
513                         // existing redline. Insert the first part, and
514                         // progress with the remainder as usual
515                         SwRedline* pSplit = new SwRedline( *pNewRedl );
516                         pSplit->SetEnd( *pRStt );
517                         pNewRedl->SetStart( *pREnd );
518                         pRedlineTbl->Insert( pSplit );
519                         if( *pStt == *pEnd && pNewRedl->GetContentIdx() == NULL )
520                         {
521                             delete pNewRedl;
522                             pNewRedl = 0;
523                             bCompress = true;
524                         }
525                     }
526                     else if ( POS_OVERLAP_BEHIND == eCmpPos )
527                     {
528                         // #107164# handle overlapping redlines in broken
529                         // documents
530                         pNewRedl->SetStart( *pREnd );
531                     }
532                     else if ( POS_OVERLAP_BEFORE == eCmpPos )
533                     {
534                         // #107164# handle overlapping redlines in broken
535                         // documents
536                         *pEnd = *pRStt;
537                         if( ( *pStt == *pEnd ) &&
538                             ( pNewRedl->GetContentIdx() == NULL ) )
539                         {
540                             delete pNewRedl;
541                             pNewRedl = 0;
542                             bCompress = true;
543                         }
544                     }
545                     break;
546                 case nsRedlineType_t::REDLINE_DELETE:
547                     if( POS_INSIDE == eCmpPos )
548                     {
549                         // aufsplitten
550                         if( *pEnd != *pREnd )
551                         {
552                             SwRedline* pCpy = new SwRedline( *pRedl );
553                             pCpy->SetStart( *pEnd );
554                             pRedlineTbl->Insert( pCpy );
555                         }
556                         pRedl->SetEnd( *pStt, pREnd );
557                         if( ( *pStt == *pRStt ) &&
558                             ( pRedl->GetContentIdx() == NULL ) )
559                         {
560                             pRedlineTbl->DeleteAndDestroy( n );
561                             bDec = true;
562                         }
563                         else if( !pRedl->HasValidRange() )
564                         {
565                             // neu einsortieren
566                             pRedlineTbl->Remove( n );
567                             pRedlineTbl->Insert( pRedl, n );
568                         }
569                     }
570                     else if ( POS_OUTSIDE == eCmpPos )
571                     {
572                         // #102366# handle overlapping redlines in broken
573                         // documents
574 
575                         // split up the new redline, since it covers the
576                         // existing redline. Insert the first part, and
577                         // progress with the remainder as usual
578                         SwRedline* pSplit = new SwRedline( *pNewRedl );
579                         pSplit->SetEnd( *pRStt );
580                         pNewRedl->SetStart( *pREnd );
581                         pRedlineTbl->Insert( pSplit );
582                         if( *pStt == *pEnd && pNewRedl->GetContentIdx() == NULL )
583                         {
584                             delete pNewRedl;
585                             pNewRedl = 0;
586                             bCompress = true;
587                         }
588                     }
589                     else if ( POS_EQUAL == eCmpPos )
590                     {
591                         // #112895# handle identical redlines in broken
592                         // documents - delete old (delete) redline
593                         pRedlineTbl->DeleteAndDestroy( n );
594                         bDec = true;
595                     }
596                     else if ( POS_OVERLAP_BEHIND == eCmpPos )
597                     {   // Another workaround for broken redlines (#107164#)
598                         pNewRedl->SetStart( *pREnd );
599                     }
600                     break;
601                 case nsRedlineType_t::REDLINE_FORMAT:
602                     switch( eCmpPos )
603                     {
604                     case POS_OVERLAP_BEFORE:
605                         pRedl->SetStart( *pEnd, pRStt );
606                         // neu einsortieren
607                         pRedlineTbl->Remove( n );
608                         pRedlineTbl->Insert( pRedl, n );
609                         bDec = true;
610                         break;
611 
612                     case POS_OVERLAP_BEHIND:
613                         pRedl->SetEnd( *pStt, pREnd );
614                         if( *pStt == *pRStt && pRedl->GetContentIdx() == NULL )
615                         {
616                             pRedlineTbl->DeleteAndDestroy( n );
617                             bDec = true;
618                         }
619                         break;
620 
621                     case POS_EQUAL:
622                     case POS_OUTSIDE:
623                         // ueberlappt den akt. komplett oder hat gleiche
624                         // Ausdehung, dann muss der alte geloescht werden
625                         pRedlineTbl->DeleteAndDestroy( n );
626                         bDec = true;
627                         break;
628 
629                     case POS_INSIDE:
630                         // ueberlappt den akt. komplett, dann muss
631                         // der neue gesplittet oder verkuertzt werden
632                         if( *pEnd != *pREnd )
633                         {
634                             if( *pEnd != *pRStt )
635                             {
636                                 SwRedline* pNew = new SwRedline( *pRedl );
637                                 pNew->SetStart( *pEnd );
638                                 pRedl->SetEnd( *pStt, pREnd );
639                                 if( *pStt == *pRStt && pRedl->GetContentIdx() == NULL )
640                                     pRedlineTbl->DeleteAndDestroy( n );
641                                 AppendRedline( pNew, bCallDelete );
642                                 n = 0;      // neu Aufsetzen
643                                 bDec = true;
644                             }
645                         }
646                         else
647                             pRedl->SetEnd( *pStt, pREnd );
648                         break;
649                     default:
650                         break;
651                     }
652                     break;
653                 default:
654                     break;
655                 }
656                 break;
657 
658             case nsRedlineType_t::REDLINE_DELETE:
659                 switch( pRedl->GetType() )
660                 {
661                 case nsRedlineType_t::REDLINE_DELETE:
662                     switch( eCmpPos )
663                     {
664                     case POS_OUTSIDE:
665                         {
666                             // ueberlappt den akt. komplett
667                             // dann muss der neue gesplittet werden
668                             if( *pEnd != *pREnd )
669                             {
670                                 SwRedline* pNew = new SwRedline( *pNewRedl );
671                                 pNew->SetStart( *pREnd );
672                                 pNewRedl->SetEnd( *pRStt, pEnd );
673                                 AppendRedline( pNew, bCallDelete );
674                                 n = 0;      // neu Aufsetzen
675                                 bDec = true;
676                             }
677                             else
678                                 pNewRedl->SetEnd( *pRStt, pEnd );
679                         }
680                         break;
681 
682                     case POS_INSIDE:
683                     case POS_EQUAL:
684                         delete pNewRedl, pNewRedl = 0;
685                         bCompress = sal_True;
686                         break;
687 
688                     case POS_OVERLAP_BEFORE:
689                     case POS_OVERLAP_BEHIND:
690                         if( pRedl->IsOwnRedline( *pNewRedl ) &&
691 //                          1 == pRedl->GetStackCount() &&
692                             pRedl->CanCombine( *pNewRedl ))
693                         {
694                             // dann kann das zusammengefasst werden, sprich
695                             // der neue deckt das schon ab.
696                             if( POS_OVERLAP_BEHIND == eCmpPos )
697                                 pNewRedl->SetStart( *pRStt, pStt );
698                             else
699                                 pNewRedl->SetEnd( *pREnd, pEnd );
700                             pRedlineTbl->DeleteAndDestroy( n );
701                             bDec = true;
702                         }
703                         else if( POS_OVERLAP_BEHIND == eCmpPos )
704                             pNewRedl->SetStart( *pREnd, pStt );
705                         else
706                             pNewRedl->SetEnd( *pRStt, pEnd );
707                         break;
708 
709                     case POS_COLLIDE_START:
710                     case POS_COLLIDE_END:
711                         if( pRedl->IsOwnRedline( *pNewRedl ) &&
712 //                          1 == pRedl->GetStackCount() &&
713                             pRedl->CanCombine( *pNewRedl ) )
714                         {
715                             if( IsHideChanges( eRedlineMode ))
716                             {
717                                 // dann erstmal sichtbar machen, bevor
718                                 // die zusammengefasst werden koennen!
719                                 // Damit pNew auch beim Verschieben der
720                                 // Indizies behandelt wird, erstmal
721                                 // temporaer einfuegen
722                                 pRedlineTbl->SavePtrInArr( pNewRedl );
723                                 pRedl->Show();
724                                 pRedlineTbl->Remove( pRedlineTbl->GetPos(pNewRedl ));
725                                 pRStt = pRedl->Start();
726                                 pREnd = pRedl->End();
727                             }
728 
729                             // dann kann das zusammengefasst werden, sprich
730                             // der neue deckt das schon ab.
731                             if( POS_COLLIDE_START == eCmpPos )
732                                 pNewRedl->SetStart( *pRStt, pStt );
733                             else
734                                 pNewRedl->SetEnd( *pREnd, pEnd );
735 
736                             // delete current (below), and restart process with
737                             // previous
738                             sal_uInt16 nToBeDeleted = n;
739                             bDec = true;
740 
741                             // #107359# Do it again, Sam!
742                             // If you can do it for them, you can do it for me.
743                             if( *(pNewRedl->Start()) <= *pREnd )
744                             {
745                                 // Whoooah, we just extended the new 'redline'
746                                 // beyond previous redlines, so better start
747                                 // again. Of course this is not supposed to
748                                 // happen, and in an ideal world it doesn't,
749                                 // but unfortunately this code is buggy and
750                                 // totally rotten so it does happen and we
751                                 // better fix it.
752                                 n = 0;
753                                 bDec = true;
754                             }
755 
756                             pRedlineTbl->DeleteAndDestroy( nToBeDeleted );
757                         }
758                         break;
759                     default:
760                         break;
761                     }
762                     break;
763 
764                 case nsRedlineType_t::REDLINE_INSERT:
765                 {
766                     // b62341295: Do not throw away redlines
767                     // even if they are not allowed to be combined
768                     RedlineMode_t eOld = eRedlineMode;
769                     if( !( eOld & nsRedlineMode_t::REDLINE_DONTCOMBINE_REDLINES ) &&
770                         pRedl->IsOwnRedline( *pNewRedl ) )
771                     {
772 
773 // auf NONE setzen, damit das Delete::Redo die RedlineDaten wieder richtig
774 // zusammen fasst! Der ShowMode muss erhalten bleiben!
775               eRedlineMode = (RedlineMode_t)(eOld & ~(nsRedlineMode_t::REDLINE_ON | nsRedlineMode_t::REDLINE_IGNORE));
776                         switch( eCmpPos )
777                         {
778                         case POS_EQUAL:
779                             bCompress = sal_True;
780                             pRedlineTbl->DeleteAndDestroy( n );
781                             bDec = true;
782                             // kein break!
783 
784                         case POS_INSIDE:
785                             if( bCallDelete )
786                             {
787                               eRedlineMode = (RedlineMode_t)(eRedlineMode | nsRedlineMode_t::REDLINE_IGNOREDELETE_REDLINES);
788 
789                                 // #98863# DeleteAndJoin does not yield the
790                                 // desired result if there is no paragraph to
791                                 // join with, i.e. at the end of the document.
792                                 // For this case, we completely delete the
793                                 // paragraphs (if, of course, we also start on
794                                 // a paragraph boundary).
795                                 if( (pStt->nContent == 0) &&
796                                     pEnd->nNode.GetNode().IsEndNode() )
797                                 {
798                                     pEnd->nNode--;
799                                     pEnd->nContent.Assign(
800                                         pEnd->nNode.GetNode().GetTxtNode(), 0);
801                                     DelFullPara( *pNewRedl );
802                                 }
803                                 else
804                                     DeleteAndJoin( *pNewRedl );
805 
806                                 bCompress = sal_True;
807                             }
808                             delete pNewRedl, pNewRedl = 0;
809                             break;
810 
811                         case POS_OUTSIDE:
812                             {
813                                 pRedlineTbl->Remove( n );
814                                 bDec = true;
815                                 // damit pNew auch beim Verschieben der Indizies
816                                 // behandelt wird, erstmal temp. einfuegen
817                                 if( bCallDelete )
818                                 {
819                                     pRedlineTbl->SavePtrInArr( pNewRedl );
820                                     DeleteAndJoin( *pRedl );
821                                     sal_uInt16 nFnd = pRedlineTbl->GetPos(pNewRedl );
822                                     if( USHRT_MAX != nFnd )
823                                         pRedlineTbl->Remove( nFnd );
824                                     else
825                                         pNewRedl = 0;
826                                 }
827                                 delete pRedl;
828                             }
829                             break;
830 
831                         case POS_OVERLAP_BEFORE:
832                             {
833                                 SwPaM aPam( *pRStt, *pEnd );
834 
835                                 if( *pEnd == *pREnd )
836                                     pRedlineTbl->DeleteAndDestroy( n );
837                                 else
838                                 {
839                                     pRedl->SetStart( *pEnd, pRStt );
840                                     // neu einsortieren
841                                     pRedlineTbl->Remove( n );
842                                     pRedlineTbl->Insert( pRedl, n );
843                                 }
844 
845                                 if( bCallDelete )
846                                 {
847                                     // damit pNew auch beim Verschieben der Indizies
848                                     // behandelt wird, erstmal temp. einfuegen
849                                     pRedlineTbl->SavePtrInArr( pNewRedl );
850                                     DeleteAndJoin( aPam );
851                                     sal_uInt16 nFnd = pRedlineTbl->GetPos(pNewRedl );
852                                     if( USHRT_MAX != nFnd )
853                                         pRedlineTbl->Remove( nFnd );
854                                     else
855                                         pNewRedl = 0;
856                                     n = 0;      // neu Aufsetzen
857                                 }
858                                 bDec = true;
859                             }
860                             break;
861 
862                         case POS_OVERLAP_BEHIND:
863                             {
864                                 SwPaM aPam( *pStt, *pREnd );
865 
866                                 if( *pStt == *pRStt )
867                                 {
868                                     pRedlineTbl->DeleteAndDestroy( n );
869                                     bDec = true;
870                                 }
871                                 else
872                                     pRedl->SetEnd( *pStt, pREnd );
873 
874                                 if( bCallDelete )
875                                 {
876                                     // damit pNew auch beim Verschieben der Indizies
877                                     // behandelt wird, erstmal temp. einfuegen
878                                     pRedlineTbl->SavePtrInArr( pNewRedl );
879                                     DeleteAndJoin( aPam );
880                                     sal_uInt16 nFnd = pRedlineTbl->GetPos(pNewRedl );
881                                     if( USHRT_MAX != nFnd )
882                                         pRedlineTbl->Remove( nFnd );
883                                     else
884                                         pNewRedl = 0;
885                                     n = 0;      // neu Aufsetzen
886                                     bDec = true;
887                                 }
888                             }
889                             break;
890                         default:
891                             break;
892                         }
893 
894                         eRedlineMode = eOld;
895                     }
896                     else
897                     {
898                         // it may be necessary to split the existing redline in
899                         // two. In this case, pRedl will be changed to cover
900                         // only part of it's former range, and pNew will cover
901                         // the remainder.
902                         SwRedline* pNew = 0;
903 
904                         switch( eCmpPos )
905                         {
906                         case POS_EQUAL:
907                             {
908                                 pRedl->PushData( *pNewRedl );
909                                 delete pNewRedl, pNewRedl = 0;
910                                 if( IsHideChanges( eRedlineMode ))
911                                     pRedl->Hide();
912                                 bCompress = sal_True;
913                             }
914                             break;
915 
916                         case POS_INSIDE:
917                             {
918                                 if( *pRStt == *pStt )
919                                 {
920                                     // --> mst 2010-05-17 #i97421#
921                                     // redline w/out extent loops
922                                     if (*pStt != *pEnd)
923                                     // <--
924                                     {
925                                         pNewRedl->PushData( *pRedl, sal_False );
926                                         pRedl->SetStart( *pEnd, pRStt );
927                                         // re-insert
928                                         pRedlineTbl->Remove( n );
929                                         pRedlineTbl->Insert( pRedl, n );
930                                         bDec = true;
931                                     }
932                                 }
933                                 else
934                                 {
935                                     pNewRedl->PushData( *pRedl, sal_False );
936                                     if( *pREnd != *pEnd )
937                                     {
938                                         pNew = new SwRedline( *pRedl );
939                                         pNew->SetStart( *pEnd );
940                                     }
941                                     pRedl->SetEnd( *pStt, pREnd );
942                                     if( !pRedl->HasValidRange() )
943                                     {
944                                         // neu einsortieren
945                                         pRedlineTbl->Remove( n );
946                                         pRedlineTbl->Insert( pRedl, n );
947                                     }
948                                 }
949                             }
950                             break;
951 
952                         case POS_OUTSIDE:
953                             {
954                                 pRedl->PushData( *pNewRedl );
955                                 if( *pEnd == *pREnd )
956                                     pNewRedl->SetEnd( *pRStt, pEnd );
957                                 else
958                                 {
959                                     pNew = new SwRedline( *pNewRedl );
960                                     pNew->SetEnd( *pRStt );
961                                     pNewRedl->SetStart( *pREnd, pStt );
962                                 }
963                                 bCompress = sal_True;
964                             }
965                             break;
966 
967                         case POS_OVERLAP_BEFORE:
968                             {
969                                 if( *pEnd == *pREnd )
970                                 {
971                                     pRedl->PushData( *pNewRedl );
972                                     pNewRedl->SetEnd( *pRStt, pEnd );
973                                     if( IsHideChanges( eRedlineMode ))
974                                     {
975                                         pRedlineTbl->SavePtrInArr( pNewRedl );
976                                         pRedl->Hide();
977                                         pRedlineTbl->Remove(
978                                             pRedlineTbl->GetPos(pNewRedl ));
979                                     }
980                                 }
981                                 else
982                                 {
983                                     pNew = new SwRedline( *pRedl );
984                                     pNew->PushData( *pNewRedl );
985                                     pNew->SetEnd( *pEnd );
986                                     pNewRedl->SetEnd( *pRStt, pEnd );
987                                     pRedl->SetStart( *pNew->End(), pRStt ) ;
988                                     // neu einsortieren
989                                     pRedlineTbl->Remove( n );
990                                     pRedlineTbl->Insert( pRedl );
991                                     bDec = true;
992                                 }
993                             }
994                             break;
995 
996                         case POS_OVERLAP_BEHIND:
997                             {
998                                 if( *pStt == *pRStt )
999                                 {
1000                                     pRedl->PushData( *pNewRedl );
1001                                     pNewRedl->SetStart( *pREnd, pStt );
1002                                     if( IsHideChanges( eRedlineMode ))
1003                                     {
1004                                         pRedlineTbl->SavePtrInArr( pNewRedl );
1005                                         pRedl->Hide();
1006                                         pRedlineTbl->Remove(
1007                                             pRedlineTbl->GetPos(pNewRedl ));
1008                                     }
1009                                 }
1010                                 else
1011                                 {
1012                                     pNew = new SwRedline( *pRedl );
1013                                     pNew->PushData( *pNewRedl );
1014                                     pNew->SetStart( *pStt );
1015                                     pNewRedl->SetStart( *pREnd, pStt );
1016                                     pRedl->SetEnd( *pNew->Start(), pREnd );
1017                                     if( !pRedl->HasValidRange() )
1018                                     {
1019                                         // neu einsortieren
1020                                         pRedlineTbl->Remove( n );
1021                                         pRedlineTbl->Insert( pRedl );
1022                                     }
1023                                 }
1024                             }
1025                             break;
1026                         default:
1027                             break;
1028                         }
1029 
1030                         // insert the pNew part (if it exists)
1031                         if( pNew )
1032                         {
1033                             // AppendRedline( pNew, bCallDelete );
1034                             //sal_Bool bRet =
1035                             pRedlineTbl->Insert( pNew );
1036 
1037                             // pNew must be deleted if Insert() wasn't
1038                             // successful. But that can't happen, since pNew is
1039                             // part of the original pRedl redline.
1040                             // ASSERT( bRet, "Can't insert existing redline?" );
1041 
1042                             // restart (now with pRedl being split up)
1043                             n = 0;
1044                             bDec = true;
1045                         }
1046                     }
1047                 }
1048                 break;
1049 
1050                 case nsRedlineType_t::REDLINE_FORMAT:
1051                     switch( eCmpPos )
1052                     {
1053                     case POS_OVERLAP_BEFORE:
1054                         pRedl->SetStart( *pEnd, pRStt );
1055                         // neu einsortieren
1056                         pRedlineTbl->Remove( n );
1057                         pRedlineTbl->Insert( pRedl, n );
1058                         bDec = true;
1059                         break;
1060 
1061                     case POS_OVERLAP_BEHIND:
1062                         pRedl->SetEnd( *pStt, pREnd );
1063                         break;
1064 
1065                     case POS_EQUAL:
1066                     case POS_OUTSIDE:
1067                         // ueberlappt den akt. komplett oder hat gleiche
1068                         // Ausdehung, dann muss der alte geloescht werden
1069                         pRedlineTbl->DeleteAndDestroy( n );
1070                         bDec = true;
1071                         break;
1072 
1073                     case POS_INSIDE:
1074                         // ueberlappt den akt. komplett, dann muss
1075                         // der neue gesplittet oder verkuertzt werden
1076                         if( *pEnd != *pREnd )
1077                         {
1078                             if( *pEnd != *pRStt )
1079                             {
1080                                 SwRedline* pNew = new SwRedline( *pRedl );
1081                                 pNew->SetStart( *pEnd );
1082                                 pRedl->SetEnd( *pStt, pREnd );
1083                                 if( ( *pStt == *pRStt ) &&
1084                                     ( pRedl->GetContentIdx() == NULL ) )
1085                                     pRedlineTbl->DeleteAndDestroy( n );
1086                                 AppendRedline( pNew, bCallDelete );
1087                                 n = 0;      // neu Aufsetzen
1088                                 bDec = true;
1089                             }
1090                         }
1091                         else
1092                             pRedl->SetEnd( *pStt, pREnd );
1093                         break;
1094                     default:
1095                         break;
1096                     }
1097                     break;
1098                 default:
1099                     break;
1100                 }
1101                 break;
1102 
1103             case nsRedlineType_t::REDLINE_FORMAT:
1104                 switch( pRedl->GetType() )
1105                 {
1106                 case nsRedlineType_t::REDLINE_INSERT:
1107                 case nsRedlineType_t::REDLINE_DELETE:
1108                     switch( eCmpPos )
1109                     {
1110                     case POS_OVERLAP_BEFORE:
1111                         pNewRedl->SetEnd( *pRStt, pEnd );
1112                         break;
1113 
1114                     case POS_OVERLAP_BEHIND:
1115                         pNewRedl->SetStart( *pREnd, pStt );
1116                         break;
1117 
1118                     case POS_EQUAL:
1119                     case POS_INSIDE:
1120                         delete pNewRedl, pNewRedl = 0;
1121                         break;
1122 
1123                     case POS_OUTSIDE:
1124                         // ueberlappt den akt. komplett, dann muss
1125                         // der neue gesplittet oder verkuerzt werden
1126                         if( *pEnd != *pREnd )
1127                         {
1128                             if( *pEnd != *pRStt )
1129                             {
1130                                 SwRedline* pNew = new SwRedline( *pNewRedl );
1131                                 pNew->SetStart( *pREnd );
1132                                 pNewRedl->SetEnd( *pRStt, pEnd );
1133                                 AppendRedline( pNew, bCallDelete );
1134                                 n = 0;      // neu Aufsetzen
1135                                 bDec = true;
1136                             }
1137                         }
1138                         else
1139                             pNewRedl->SetEnd( *pRStt, pEnd );
1140                         break;
1141                     default:
1142                         break;
1143                     }
1144                     break;
1145                 case nsRedlineType_t::REDLINE_FORMAT:
1146                     switch( eCmpPos )
1147                     {
1148                     case POS_OUTSIDE:
1149                     case POS_EQUAL:
1150                         {
1151                             // ueberlappt den akt. komplett oder hat gleiche
1152                             // Ausdehnung, dann muss der alte geloescht werden
1153                             pRedlineTbl->DeleteAndDestroy( n );
1154                             bDec = true;
1155                         }
1156                         break;
1157 
1158                     case POS_INSIDE:
1159                         if( pRedl->IsOwnRedline( *pNewRedl ) &&
1160                             pRedl->CanCombine( *pNewRedl ))
1161                             // ein eigenes kann komplett ignoriert werden
1162                             delete pNewRedl, pNewRedl = 0;
1163 
1164                         else if( *pREnd == *pEnd )
1165                             // ansonsten nur den akt. verkuerzen
1166                             pRedl->SetEnd( *pStt, pREnd );
1167                         else if( *pRStt == *pStt )
1168                         {
1169                             // ansonsten nur den akt. verkuerzen
1170                             pRedl->SetStart( *pEnd, pRStt );
1171                             // neu einsortieren
1172                             pRedlineTbl->Remove( n );
1173                             pRedlineTbl->Insert( pRedl, n );
1174                             bDec = true;
1175                         }
1176                         else
1177                         {
1178                             // liegt komplett im akt.
1179                             // dann muss der gesplittet werden
1180                             SwRedline* pNew = new SwRedline( *pRedl );
1181                             pNew->SetStart( *pEnd );
1182                             pRedl->SetEnd( *pStt, pREnd );
1183                             AppendRedline( pNew, bCallDelete );
1184                             n = 0;      // neu Aufsetzen
1185                             bDec = true;
1186                         }
1187                         break;
1188 
1189                     case POS_OVERLAP_BEFORE:
1190                     case POS_OVERLAP_BEHIND:
1191                         if( pRedl->IsOwnRedline( *pNewRedl ) &&
1192                             pRedl->CanCombine( *pNewRedl ))
1193                         {
1194                             // dann kann das zusammengefasst werden, sprich
1195                             // der neue deckt das schon ab.
1196                             if( POS_OVERLAP_BEHIND == eCmpPos )
1197                                 pNewRedl->SetStart( *pRStt, pStt );
1198                             else
1199                                 pNewRedl->SetEnd( *pREnd, pEnd );
1200                             pRedlineTbl->DeleteAndDestroy( n );
1201                             bDec = 0;
1202                         }
1203                         else if( POS_OVERLAP_BEHIND == eCmpPos )
1204                             pNewRedl->SetStart( *pREnd, pStt );
1205                         else
1206                             pNewRedl->SetEnd( *pRStt, pEnd );
1207                         break;
1208 
1209                     case POS_COLLIDE_END:
1210                         if( pRedl->IsOwnRedline( *pNewRedl ) &&
1211                             pRedl->CanCombine( *pNewRedl ) && n &&
1212                             *(*pRedlineTbl)[ n-1 ]->End() < *pStt )
1213                         {
1214                             // dann kann das zusammengefasst werden, sprich
1215                             // der neue deckt das schon ab.
1216                             pNewRedl->SetEnd( *pREnd, pEnd );
1217                             pRedlineTbl->DeleteAndDestroy( n );
1218                             bDec = true;
1219                         }
1220                         break;
1221                     case POS_COLLIDE_START:
1222                         if( pRedl->IsOwnRedline( *pNewRedl ) &&
1223                             pRedl->CanCombine( *pNewRedl ) &&
1224                             n+1 < pRedlineTbl->Count() &&
1225                             *(*pRedlineTbl)[ n+1 ]->Start() < *pEnd )
1226                         {
1227                             // dann kann das zusammengefasst werden, sprich
1228                             // der neue deckt das schon ab.
1229                             pNewRedl->SetStart( *pRStt, pStt );
1230                             pRedlineTbl->DeleteAndDestroy( n );
1231                             bDec = true;
1232                         }
1233                         break;
1234                     default:
1235                         break;
1236                     }
1237                     break;
1238                 default:
1239                     break;
1240                 }
1241                 break;
1242 
1243 
1244             case nsRedlineType_t::REDLINE_FMTCOLL:
1245                 // wie soll das verhalten sein????
1246                 // erstmal so einfuegen
1247                 break;
1248             default:
1249                 break;
1250             }
1251         }
1252 
1253         if( pNewRedl )
1254         {
1255             if( ( *pStt == *pEnd ) &&
1256                 ( pNewRedl->GetContentIdx() == NULL ) )
1257             {   // Do not insert empty redlines
1258                 delete pNewRedl;
1259                 pNewRedl = 0;
1260             }
1261             else
1262                 pRedlineTbl->Insert( pNewRedl );
1263         }
1264 
1265         if( bCompress )
1266             CompressRedlines();
1267     }
1268     else
1269     {
1270         if( bCallDelete && nsRedlineType_t::REDLINE_DELETE == pNewRedl->GetType() )
1271         {
1272             RedlineMode_t eOld = eRedlineMode;
1273 // auf NONE setzen, damit das Delete::Redo die RedlineDaten wieder richtig
1274 // zusammen fasst! Der ShowMode muss erhalten bleiben!
1275             eRedlineMode = (RedlineMode_t)(eOld & ~(nsRedlineMode_t::REDLINE_ON | nsRedlineMode_t::REDLINE_IGNORE));
1276             DeleteAndJoin( *pNewRedl );
1277             eRedlineMode = eOld;
1278         }
1279         delete pNewRedl, pNewRedl = 0;
1280     }
1281     _CHECK_REDLINE( this )
1282 
1283     return ( 0 != pNewRedl ) || !bError;
1284 }
1285 
1286 void SwDoc::CompressRedlines()
1287 {
1288     _CHECK_REDLINE( this )
1289 
1290     void (SwRedline::*pFnc)(sal_uInt16) = 0;
1291     switch( nsRedlineMode_t::REDLINE_SHOW_MASK & eRedlineMode )
1292     {
1293     case nsRedlineMode_t::REDLINE_SHOW_INSERT | nsRedlineMode_t::REDLINE_SHOW_DELETE:
1294         pFnc = &SwRedline::Show;
1295         break;
1296     case nsRedlineMode_t::REDLINE_SHOW_INSERT:
1297         pFnc = &SwRedline::Hide;
1298         break;
1299     }
1300 
1301     // versuche gleiche zusammenzufassen
1302     for( sal_uInt16 n = 1; n < pRedlineTbl->Count(); ++n )
1303     {
1304         SwRedline* pPrev = (*pRedlineTbl)[ n-1 ],
1305                     * pCur = (*pRedlineTbl)[ n ];
1306         const SwPosition* pPrevStt = pPrev->Start(),
1307                         * pPrevEnd = pPrevStt == pPrev->GetPoint()
1308                             ? pPrev->GetMark() : pPrev->GetPoint();
1309         const SwPosition* pCurStt = pCur->Start(),
1310                         * pCurEnd = pCurStt == pCur->GetPoint()
1311                             ? pCur->GetMark() : pCur->GetPoint();
1312         if( *pPrevEnd == *pCurStt && pPrev->CanCombine( *pCur ) &&
1313             pPrevStt->nNode.GetNode().StartOfSectionNode() ==
1314             pCurEnd->nNode.GetNode().StartOfSectionNode() &&
1315             !pCurEnd->nNode.GetNode().StartOfSectionNode()->IsTableNode() )
1316         {
1317             // dann koennen die zusammen gefasst werden
1318             pPrev->Show();
1319             pCur->Show();
1320 
1321             pPrev->SetEnd( *pCur->End() );
1322             pRedlineTbl->DeleteAndDestroy( n );
1323             --n;
1324             if( pFnc )
1325                 (pPrev->*pFnc)(0);
1326         }
1327     }
1328     _CHECK_REDLINE( this )
1329 }
1330 
1331 bool SwDoc::SplitRedline( const SwPaM& rRange )
1332 {
1333     sal_Bool bChg = sal_False;
1334     sal_uInt16 n = 0;
1335     const SwPosition* pStt = rRange.Start(),
1336                   * pEnd = pStt == rRange.GetPoint() ? rRange.GetMark()
1337                                                      : rRange.GetPoint();
1338     GetRedline( *pStt, &n );
1339     for( ; n < pRedlineTbl->Count() ; ++n )
1340     {
1341         SwRedline* pTmp = (*pRedlineTbl)[ n ];
1342         SwPosition* pTStt = pTmp->Start(),
1343                   * pTEnd = pTStt == pTmp->GetPoint() ? pTmp->GetMark()
1344                                                       : pTmp->GetPoint();
1345         if( *pTStt <= *pStt && *pStt <= *pTEnd &&
1346             *pTStt <= *pEnd && *pEnd <= *pTEnd )
1347         {
1348             bChg = sal_True;
1349             int nn = 0;
1350             if( *pStt == *pTStt )
1351                 nn += 1;
1352             if( *pEnd == *pTEnd )
1353                 nn += 2;
1354 
1355             SwRedline* pNew = 0;
1356             switch( nn )
1357             {
1358             case 0:
1359                 pNew = new SwRedline( *pTmp );
1360                 pTmp->SetEnd( *pStt, pTEnd );
1361                 pNew->SetStart( *pEnd );
1362                 break;
1363 
1364             case 1:
1365                 *pTStt = *pEnd;
1366                 break;
1367 
1368             case 2:
1369                 *pTEnd = *pStt;
1370                 break;
1371 
1372             case 3:
1373                 pTmp->InvalidateRange();
1374                 pRedlineTbl->DeleteAndDestroy( n-- );
1375                 pTmp = 0;
1376                 break;
1377             }
1378             if( pTmp && !pTmp->HasValidRange() )
1379             {
1380                 // neu einsortieren
1381                 pRedlineTbl->Remove( n );
1382                 pRedlineTbl->Insert( pTmp, n );
1383             }
1384             if( pNew )
1385                 pRedlineTbl->Insert( pNew, n );
1386         }
1387         else if( *pEnd < *pTStt )
1388             break;
1389     }
1390     return bChg;
1391 }
1392 
1393 bool SwDoc::DeleteRedline( const SwPaM& rRange, bool bSaveInUndo,
1394                             sal_uInt16 nDelType )
1395 {
1396     if( nsRedlineMode_t::REDLINE_IGNOREDELETE_REDLINES & eRedlineMode ||
1397         !rRange.HasMark() || *rRange.GetMark() == *rRange.GetPoint() )
1398         return sal_False;
1399 
1400     sal_Bool bChg = sal_False;
1401 
1402     if (bSaveInUndo && GetIDocumentUndoRedo().DoesUndo())
1403     {
1404         SwUndoRedline* pUndo = new SwUndoRedline( UNDO_REDLINE, rRange );
1405         if( pUndo->GetRedlSaveCount() )
1406         {
1407             GetIDocumentUndoRedo().AppendUndo(pUndo);
1408         }
1409         else
1410             delete pUndo;
1411     }
1412 
1413     const SwPosition* pStt = rRange.Start(),
1414                     * pEnd = pStt == rRange.GetPoint() ? rRange.GetMark()
1415                                                        : rRange.GetPoint();
1416     sal_uInt16 n = 0;
1417     GetRedline( *pStt, &n );
1418     for( ; n < pRedlineTbl->Count() ; ++n )
1419     {
1420         SwRedline* pRedl = (*pRedlineTbl)[ n ];
1421         if( USHRT_MAX != nDelType && nDelType != pRedl->GetType() )
1422             continue;
1423 
1424         SwPosition* pRStt = pRedl->Start(),
1425                   * pREnd = pRStt == pRedl->GetPoint() ? pRedl->GetMark()
1426                                                        : pRedl->GetPoint();
1427         sal_Bool bDel = sal_False;
1428         switch( ComparePosition( *pStt, *pEnd, *pRStt, *pREnd ) )
1429         {
1430         case POS_EQUAL:
1431         case POS_OUTSIDE:
1432             bDel = sal_True;
1433             break;
1434 
1435         case POS_OVERLAP_BEFORE:
1436             if( *pEnd == *pREnd )
1437                 bDel = sal_True;
1438             else
1439             {
1440                 pRedl->InvalidateRange();
1441                 pRedl->SetStart( *pEnd, pRStt );
1442                 // neu einsortieren
1443                 pRedlineTbl->Remove( n );
1444                 pRedlineTbl->Insert( pRedl );
1445                 --n;
1446             }
1447             break;
1448 
1449         case POS_OVERLAP_BEHIND:
1450             if( *pStt == *pRStt )
1451                 bDel = sal_True;
1452             else
1453             {
1454                 pRedl->InvalidateRange();
1455                 pRedl->SetEnd( *pStt, pREnd );
1456                 if( !pRedl->HasValidRange() )
1457                 {
1458                     // neu einsortieren
1459                     pRedlineTbl->Remove( n );
1460                     pRedlineTbl->Insert( pRedl );
1461                     --n;
1462                 }
1463             }
1464             break;
1465 
1466         case POS_INSIDE:
1467             {
1468                 // der muss gesplittet werden
1469                 pRedl->InvalidateRange();
1470                 if( *pRStt == *pStt )
1471                 {
1472                     pRedl->SetStart( *pEnd, pRStt );
1473                     // neu einsortieren
1474                     pRedlineTbl->Remove( n );
1475                     pRedlineTbl->Insert( pRedl );
1476                     --n;
1477                 }
1478                 else
1479                 {
1480                     SwRedline* pCpy;
1481                     if( *pREnd != *pEnd )
1482                     {
1483                         pCpy = new SwRedline( *pRedl );
1484                         pCpy->SetStart( *pEnd );
1485                     }
1486                     else
1487                         pCpy = 0;
1488                     pRedl->SetEnd( *pStt, pREnd );
1489                     if( !pRedl->HasValidRange() )
1490                     {
1491                         // neu einsortieren
1492                         pRedlineTbl->Remove( pRedlineTbl->GetPos( pRedl ));
1493                         pRedlineTbl->Insert( pRedl );
1494                         --n;
1495                     }
1496                     if( pCpy )
1497                         pRedlineTbl->Insert( pCpy );
1498                 }
1499             }
1500             break;
1501 
1502         case POS_COLLIDE_END:
1503         case POS_BEFORE:
1504             n = pRedlineTbl->Count();
1505             break;
1506         default:
1507             break;
1508         }
1509 
1510         if( bDel )
1511         {
1512             pRedl->InvalidateRange();
1513             pRedlineTbl->DeleteAndDestroy( n-- );
1514             bChg = sal_True;
1515         }
1516     }
1517 
1518     if( bChg )
1519         SetModified();
1520 
1521     return bChg;
1522 }
1523 
1524 bool SwDoc::DeleteRedline( const SwStartNode& rNode, bool bSaveInUndo,
1525                             sal_uInt16 nDelType )
1526 {
1527     SwPaM aTemp(*rNode.EndOfSectionNode(), rNode);
1528     return DeleteRedline(aTemp, bSaveInUndo, nDelType);
1529 }
1530 
1531 sal_uInt16 SwDoc::GetRedlinePos( const SwNode& rNd, sal_uInt16 nType ) const
1532 {
1533     const sal_uLong nNdIdx = rNd.GetIndex();
1534     for( sal_uInt16 n = 0; n < pRedlineTbl->Count() ; ++n )
1535     {
1536         const SwRedline* pTmp = (*pRedlineTbl)[ n ];
1537         sal_uLong nPt = pTmp->GetPoint()->nNode.GetIndex(),
1538               nMk = pTmp->GetMark()->nNode.GetIndex();
1539         if( nPt < nMk ) { long nTmp = nMk; nMk = nPt; nPt = nTmp; }
1540 
1541         if( ( USHRT_MAX == nType || nType == pTmp->GetType()) &&
1542             nMk <= nNdIdx && nNdIdx <= nPt )
1543             return n;
1544 
1545         if( nMk > nNdIdx )
1546             break;
1547     }
1548     return USHRT_MAX;
1549 }
1550 
1551 const SwRedline* SwDoc::GetRedline( const SwPosition& rPos,
1552                                     sal_uInt16* pFndPos ) const
1553 {
1554     sal_uInt16 nO = pRedlineTbl->Count(), nM, nU = 0;
1555     if( nO > 0 )
1556     {
1557         nO--;
1558         while( nU <= nO )
1559         {
1560             nM = nU + ( nO - nU ) / 2;
1561             const SwRedline* pRedl = (*pRedlineTbl)[ nM ];
1562             const SwPosition* pStt = pRedl->Start();
1563             const SwPosition* pEnd = pStt == pRedl->GetPoint()
1564                                         ? pRedl->GetMark()
1565                                         : pRedl->GetPoint();
1566             if( pEnd == pStt
1567                     ? *pStt == rPos
1568                     : ( *pStt <= rPos && rPos < *pEnd ) )
1569             {
1570                 /* #107318# returned wrong redline ???*/
1571                 while( nM && rPos == *(*pRedlineTbl)[ nM - 1 ]->End() &&
1572                     rPos == *(*pRedlineTbl)[ nM - 1 ]->Start() )
1573                 {
1574                     --nM;
1575                     pRedl = (*pRedlineTbl)[ nM ];
1576                 }
1577 
1578                 if( pFndPos )
1579                     *pFndPos = nM;
1580                 return pRedl;
1581             }
1582             else if( *pEnd <= rPos )
1583                 nU = nM + 1;
1584             else if( nM == 0 )
1585             {
1586                 if( pFndPos )
1587                     *pFndPos = nU;
1588                 return 0;
1589             }
1590             else
1591                 nO = nM - 1;
1592         }
1593     }
1594     if( pFndPos )
1595         *pFndPos = nU;
1596     return 0;
1597 }
1598 
1599 typedef sal_Bool (*Fn_AcceptReject)( SwRedlineTbl& rArr, sal_uInt16& rPos,
1600                         sal_Bool bCallDelete,
1601                         const SwPosition* pSttRng,
1602                         const SwPosition* pEndRng);
1603 
1604 sal_Bool lcl_AcceptRedline( SwRedlineTbl& rArr, sal_uInt16& rPos,
1605                         sal_Bool bCallDelete,
1606                         const SwPosition* pSttRng = 0,
1607                         const SwPosition* pEndRng = 0 )
1608 {
1609     sal_Bool bRet = sal_True;
1610     SwRedline* pRedl = rArr[ rPos ];
1611     SwPosition *pRStt = 0, *pREnd = 0;
1612     SwComparePosition eCmp = POS_OUTSIDE;
1613     if( pSttRng && pEndRng )
1614     {
1615         pRStt = pRedl->Start();
1616         pREnd = pRedl->End();
1617         eCmp = ComparePosition( *pSttRng, *pEndRng, *pRStt, *pREnd );
1618     }
1619 
1620     pRedl->InvalidateRange();
1621 
1622     switch( pRedl->GetType() )
1623     {
1624     case nsRedlineType_t::REDLINE_INSERT:
1625     case nsRedlineType_t::REDLINE_FORMAT:
1626         {
1627             sal_Bool bCheck = sal_False, bReplace = sal_False;
1628             switch( eCmp )
1629             {
1630             case POS_INSIDE:
1631                 if( *pSttRng == *pRStt )
1632                     pRedl->SetStart( *pEndRng, pRStt );
1633                 else
1634                 {
1635                     if( *pEndRng != *pREnd )
1636                     {
1637                         // aufsplitten
1638                         SwRedline* pNew = new SwRedline( *pRedl );
1639                         pNew->SetStart( *pEndRng );
1640                         rArr.Insert( pNew ); ++rPos;
1641                     }
1642                     pRedl->SetEnd( *pSttRng, pREnd );
1643                     bCheck = sal_True;
1644                 }
1645                 break;
1646 
1647             case POS_OVERLAP_BEFORE:
1648                 pRedl->SetStart( *pEndRng, pRStt );
1649                 bReplace = sal_True;
1650                 break;
1651 
1652             case POS_OVERLAP_BEHIND:
1653                 pRedl->SetEnd( *pSttRng, pREnd );
1654                 bCheck = sal_True;
1655                 break;
1656 
1657             case POS_OUTSIDE:
1658             case POS_EQUAL:
1659                 rArr.DeleteAndDestroy( rPos-- );
1660                 break;
1661 
1662             default:
1663                 bRet = sal_False;
1664             }
1665 
1666             if( bReplace || ( bCheck && !pRedl->HasValidRange() ))
1667             {
1668                 // neu einsortieren
1669                 rArr.Remove( rArr.GetPos( pRedl ));
1670                 rArr.Insert( pRedl );
1671             }
1672         }
1673         break;
1674     case nsRedlineType_t::REDLINE_DELETE:
1675         {
1676             SwDoc& rDoc = *pRedl->GetDoc();
1677             const SwPosition *pDelStt = 0, *pDelEnd = 0;
1678             sal_Bool bDelRedl = sal_False;
1679             switch( eCmp )
1680             {
1681             case POS_INSIDE:
1682                 if( bCallDelete )
1683                 {
1684                     pDelStt = pSttRng;
1685                     pDelEnd = pEndRng;
1686                 }
1687                 break;
1688 
1689             case POS_OVERLAP_BEFORE:
1690                 if( bCallDelete )
1691                 {
1692                     pDelStt = pRStt;
1693                     pDelEnd = pEndRng;
1694                 }
1695                 break;
1696             case POS_OVERLAP_BEHIND:
1697                 if( bCallDelete )
1698                 {
1699                     pDelStt = pREnd;
1700                     pDelEnd = pSttRng;
1701                 }
1702                 break;
1703 
1704             case POS_OUTSIDE:
1705             case POS_EQUAL:
1706                 {
1707                     rArr.Remove( rPos-- );
1708                     bDelRedl = sal_True;
1709                     if( bCallDelete )
1710                     {
1711                         pDelStt = pRedl->Start();
1712                         pDelEnd = pRedl->End();
1713                     }
1714                 }
1715                 break;
1716             default:
1717                 bRet = sal_False;
1718             }
1719 
1720             if( pDelStt && pDelEnd )
1721             {
1722                 SwPaM aPam( *pDelStt, *pDelEnd );
1723                 SwCntntNode* pCSttNd = pDelStt->nNode.GetNode().GetCntntNode();
1724                 SwCntntNode* pCEndNd = pDelEnd->nNode.GetNode().GetCntntNode();
1725 
1726                 if( bDelRedl )
1727                     delete pRedl;
1728 
1729                 RedlineMode_t eOld = rDoc.GetRedlineMode();
1730                 rDoc.SetRedlineMode_intern( (RedlineMode_t)(eOld & ~(nsRedlineMode_t::REDLINE_ON | nsRedlineMode_t::REDLINE_IGNORE)));
1731 
1732                 if( pCSttNd && pCEndNd )
1733                     rDoc.DeleteAndJoin( aPam );
1734                 else
1735                 {
1736                     rDoc.DeleteRange( aPam );
1737 
1738                     if( pCSttNd && !pCEndNd )
1739                     {
1740                         aPam.GetBound( sal_True ).nContent.Assign( 0, 0 );
1741                         aPam.GetBound( sal_False ).nContent.Assign( 0, 0 );
1742                         aPam.DeleteMark();
1743                         rDoc.DelFullPara( aPam );
1744                     }
1745                 }
1746                 rDoc.SetRedlineMode_intern( eOld );
1747             }
1748             else if( bDelRedl )
1749                 delete pRedl;
1750         }
1751         break;
1752 
1753     case nsRedlineType_t::REDLINE_FMTCOLL:
1754         rArr.DeleteAndDestroy( rPos-- );
1755         break;
1756 
1757     default:
1758         bRet = sal_False;
1759     }
1760     return bRet;
1761 }
1762 
1763 sal_Bool lcl_RejectRedline( SwRedlineTbl& rArr, sal_uInt16& rPos,
1764                         sal_Bool bCallDelete,
1765                         const SwPosition* pSttRng = 0,
1766                         const SwPosition* pEndRng = 0 )
1767 {
1768     sal_Bool bRet = sal_True;
1769     SwRedline* pRedl = rArr[ rPos ];
1770     SwPosition *pRStt = 0, *pREnd = 0;
1771     SwComparePosition eCmp = POS_OUTSIDE;
1772     if( pSttRng && pEndRng )
1773     {
1774         pRStt = pRedl->Start();
1775         pREnd = pRedl->End();
1776         eCmp = ComparePosition( *pSttRng, *pEndRng, *pRStt, *pREnd );
1777     }
1778 
1779     pRedl->InvalidateRange();
1780 
1781     switch( pRedl->GetType() )
1782     {
1783     case nsRedlineType_t::REDLINE_INSERT:
1784         {
1785             SwDoc& rDoc = *pRedl->GetDoc();
1786             const SwPosition *pDelStt = 0, *pDelEnd = 0;
1787             sal_Bool bDelRedl = sal_False;
1788             switch( eCmp )
1789             {
1790             case POS_INSIDE:
1791                 if( bCallDelete )
1792                 {
1793                     pDelStt = pSttRng;
1794                     pDelEnd = pEndRng;
1795                 }
1796                 break;
1797 
1798             case POS_OVERLAP_BEFORE:
1799                 if( bCallDelete )
1800                 {
1801                     pDelStt = pRStt;
1802                     pDelEnd = pEndRng;
1803                 }
1804                 break;
1805             case POS_OVERLAP_BEHIND:
1806                 if( bCallDelete )
1807                 {
1808                     pDelStt = pREnd;
1809                     pDelEnd = pSttRng;
1810                 }
1811                 break;
1812             case POS_OUTSIDE:
1813             case POS_EQUAL:
1814                 {
1815                     // dann den Bereich wieder loeschen
1816                     rArr.Remove( rPos-- );
1817                     bDelRedl = sal_True;
1818                     if( bCallDelete )
1819                     {
1820                         pDelStt = pRedl->Start();
1821                         pDelEnd = pRedl->End();
1822                     }
1823                 }
1824                 break;
1825 
1826             default:
1827                 bRet = sal_False;
1828             }
1829             if( pDelStt && pDelEnd )
1830             {
1831                 SwPaM aPam( *pDelStt, *pDelEnd );
1832 
1833                 SwCntntNode* pCSttNd = pDelStt->nNode.GetNode().GetCntntNode();
1834                 SwCntntNode* pCEndNd = pDelEnd->nNode.GetNode().GetCntntNode();
1835 
1836                 if( bDelRedl )
1837                     delete pRedl;
1838 
1839                 RedlineMode_t eOld = rDoc.GetRedlineMode();
1840                 rDoc.SetRedlineMode_intern( (RedlineMode_t)(eOld & ~(nsRedlineMode_t::REDLINE_ON | nsRedlineMode_t::REDLINE_IGNORE)));
1841 
1842                 if( pCSttNd && pCEndNd )
1843                     rDoc.DeleteAndJoin( aPam );
1844                 else
1845                 {
1846                     rDoc.DeleteRange( aPam );
1847 
1848                     if( pCSttNd && !pCEndNd )
1849                     {
1850                         aPam.GetBound( sal_True ).nContent.Assign( 0, 0 );
1851                         aPam.GetBound( sal_False ).nContent.Assign( 0, 0 );
1852                         aPam.DeleteMark();
1853                         rDoc.DelFullPara( aPam );
1854                     }
1855                 }
1856                 rDoc.SetRedlineMode_intern( eOld );
1857             }
1858             else if( bDelRedl )
1859                 delete pRedl;
1860         }
1861         break;
1862     case nsRedlineType_t::REDLINE_DELETE:
1863         {
1864             SwRedline* pNew = 0;
1865             sal_Bool bCheck = sal_False, bReplace = sal_False;
1866 
1867             switch( eCmp )
1868             {
1869             case POS_INSIDE:
1870                 {
1871                     if( 1 < pRedl->GetStackCount() )
1872                     {
1873                         pNew = new SwRedline( *pRedl );
1874                         pNew->PopData();
1875                     }
1876                     if( *pSttRng == *pRStt )
1877                     {
1878                         pRedl->SetStart( *pEndRng, pRStt );
1879                         bReplace = sal_True;
1880                         if( pNew )
1881                             pNew->SetEnd( *pEndRng );
1882                     }
1883                     else
1884                     {
1885                         if( *pEndRng != *pREnd )
1886                         {
1887                             // aufsplitten
1888                             SwRedline* pCpy = new SwRedline( *pRedl );
1889                             pCpy->SetStart( *pEndRng );
1890                             rArr.Insert( pCpy ); ++rPos;
1891                             if( pNew )
1892                                 pNew->SetEnd( *pEndRng );
1893                         }
1894 
1895                         pRedl->SetEnd( *pSttRng, pREnd );
1896                         bCheck = sal_True;
1897                         if( pNew )
1898                             pNew->SetStart( *pSttRng );
1899                     }
1900                 }
1901                 break;
1902 
1903             case POS_OVERLAP_BEFORE:
1904                 if( 1 < pRedl->GetStackCount() )
1905                 {
1906                     pNew = new SwRedline( *pRedl );
1907                     pNew->PopData();
1908                 }
1909                 pRedl->SetStart( *pEndRng, pRStt );
1910                 bReplace = sal_True;
1911                 if( pNew )
1912                     pNew->SetEnd( *pEndRng );
1913                 break;
1914 
1915             case POS_OVERLAP_BEHIND:
1916                 if( 1 < pRedl->GetStackCount() )
1917                 {
1918                     pNew = new SwRedline( *pRedl );
1919                     pNew->PopData();
1920                 }
1921                 pRedl->SetEnd( *pSttRng, pREnd );
1922                 bCheck = sal_True;
1923                 if( pNew )
1924                     pNew->SetStart( *pSttRng );
1925                 break;
1926 
1927             case POS_OUTSIDE:
1928             case POS_EQUAL:
1929                 if( !pRedl->PopData() )
1930                     // das RedlineObject loeschen reicht
1931                     rArr.DeleteAndDestroy( rPos-- );
1932                 break;
1933 
1934             default:
1935                 bRet = sal_False;
1936             }
1937 
1938             if( pNew )
1939             {
1940                 rArr.Insert( pNew ); ++rPos;
1941             }
1942 
1943             if( bReplace || ( bCheck && !pRedl->HasValidRange() ))
1944             {
1945                 // neu einsortieren
1946                 rArr.Remove( rArr.GetPos( pRedl ));
1947                 rArr.Insert( pRedl );
1948             }
1949         }
1950         break;
1951 
1952     case nsRedlineType_t::REDLINE_FORMAT:
1953     case nsRedlineType_t::REDLINE_FMTCOLL:
1954         {
1955             if( pRedl->GetExtraData() )
1956                 pRedl->GetExtraData()->Reject( *pRedl );
1957             rArr.DeleteAndDestroy( rPos-- );
1958         }
1959         break;
1960 
1961     default:
1962         bRet = sal_False;
1963     }
1964     return bRet;
1965 }
1966 
1967 
1968 const SwRedline* lcl_FindCurrRedline( const SwPosition& rSttPos,
1969                                         sal_uInt16& rPos,
1970                                         sal_Bool bNext = sal_True )
1971 {
1972     const SwRedline* pFnd = 0;
1973     const SwRedlineTbl& rArr = rSttPos.nNode.GetNode().GetDoc()->GetRedlineTbl();
1974     for( ; rPos < rArr.Count() ; ++rPos )
1975     {
1976         const SwRedline* pTmp = rArr[ rPos ];
1977         if( pTmp->HasMark() && pTmp->IsVisible() )
1978         {
1979             const SwPosition* pRStt = pTmp->Start(),
1980                       * pREnd = pRStt == pTmp->GetPoint() ? pTmp->GetMark()
1981                                                           : pTmp->GetPoint();
1982             if( bNext ? *pRStt <= rSttPos : *pRStt < rSttPos )
1983             {
1984                 if( bNext ? *pREnd > rSttPos : *pREnd >= rSttPos )
1985                 {
1986                     pFnd = pTmp;
1987                     break;
1988                 }
1989             }
1990             else
1991                 break;
1992         }
1993     }
1994     return pFnd;
1995 }
1996 
1997 // #111827#
1998 int lcl_AcceptRejectRedl( Fn_AcceptReject fn_AcceptReject,
1999                             SwRedlineTbl& rArr, sal_Bool bCallDelete,
2000                             const SwPaM& rPam)
2001 {
2002     sal_uInt16 n = 0;
2003     int nCount = 0; // #111827#
2004 
2005     const SwPosition* pStt = rPam.Start(),
2006                     * pEnd = pStt == rPam.GetPoint() ? rPam.GetMark()
2007                                                      : rPam.GetPoint();
2008     const SwRedline* pFnd = lcl_FindCurrRedline( *pStt, n, sal_True );
2009     if( pFnd &&     // neu ein Teil davon?
2010         ( *pFnd->Start() != *pStt || *pFnd->End() > *pEnd ))
2011     {
2012         // dann nur die TeilSelektion aufheben
2013         if( (*fn_AcceptReject)( rArr, n, bCallDelete, pStt, pEnd ))
2014             nCount++; // #111827#
2015         ++n;
2016     }
2017 
2018     for( ; n < rArr.Count(); ++n )
2019     {
2020         SwRedline* pTmp = rArr[ n ];
2021         if( pTmp->HasMark() && pTmp->IsVisible() )
2022         {
2023             if( *pTmp->End() <= *pEnd )
2024             {
2025                 if( (*fn_AcceptReject)( rArr, n, bCallDelete, 0, 0 ))
2026                     nCount++; // #111827#
2027             }
2028             else
2029             {
2030                 if( *pTmp->Start() < *pEnd )
2031                 {
2032                     // dann nur in der TeilSelektion aufheben
2033                     if( (*fn_AcceptReject)( rArr, n, bCallDelete, pStt, pEnd ))
2034                         nCount++; // #111827#
2035                 }
2036                 break;
2037             }
2038         }
2039     }
2040     return nCount; // #111827#
2041 }
2042 
2043 void lcl_AdjustRedlineRange( SwPaM& rPam )
2044 {
2045     // die Selektion steht nur im ContentBereich. Wenn es aber Redlines
2046     // davor oder dahinter auf nicht ContentNodes stehen, dann erweiter die
2047     // die Selection auf diese
2048     SwPosition* pStt = rPam.Start(),
2049               * pEnd = pStt == rPam.GetPoint() ? rPam.GetMark()
2050                                                : rPam.GetPoint();
2051     SwDoc* pDoc = rPam.GetDoc();
2052     if( !pStt->nContent.GetIndex() &&
2053         !pDoc->GetNodes()[ pStt->nNode.GetIndex() - 1 ]->IsCntntNode() )
2054     {
2055         const SwRedline* pRedl = pDoc->GetRedline( *pStt, 0 );
2056         if( pRedl )
2057         {
2058             const SwPosition* pRStt = pRedl->Start();
2059             if( !pRStt->nContent.GetIndex() && pRStt->nNode.GetIndex() ==
2060                 pStt->nNode.GetIndex() - 1 )
2061                 *pStt = *pRStt;
2062         }
2063     }
2064     if( pEnd->nNode.GetNode().IsCntntNode() &&
2065         !pDoc->GetNodes()[ pEnd->nNode.GetIndex() + 1 ]->IsCntntNode() &&
2066         pEnd->nContent.GetIndex() == pEnd->nNode.GetNode().GetCntntNode()->Len()    )
2067     {
2068         const SwRedline* pRedl = pDoc->GetRedline( *pEnd, 0 );
2069         if( pRedl )
2070         {
2071             const SwPosition* pREnd = pRedl->End();
2072             if( !pREnd->nContent.GetIndex() && pREnd->nNode.GetIndex() ==
2073                 pEnd->nNode.GetIndex() + 1 )
2074                 *pEnd = *pREnd;
2075         }
2076     }
2077 }
2078 
2079 
2080 bool SwDoc::AcceptRedline( sal_uInt16 nPos, bool bCallDelete )
2081 {
2082     sal_Bool bRet = sal_False;
2083 
2084     // aufjedenfall auf sichtbar umschalten
2085     if( (nsRedlineMode_t::REDLINE_SHOW_INSERT | nsRedlineMode_t::REDLINE_SHOW_DELETE) !=
2086         (nsRedlineMode_t::REDLINE_SHOW_MASK & eRedlineMode) )
2087       SetRedlineMode( (RedlineMode_t)(nsRedlineMode_t::REDLINE_SHOW_INSERT | nsRedlineMode_t::REDLINE_SHOW_DELETE | eRedlineMode));
2088 
2089     SwRedline* pTmp = (*pRedlineTbl)[ nPos ];
2090     if( pTmp->HasMark() && pTmp->IsVisible() )
2091     {
2092         if (GetIDocumentUndoRedo().DoesUndo())
2093         {
2094             // #111827#
2095             SwRewriter aRewriter;
2096 
2097             aRewriter.AddRule(UNDO_ARG1, pTmp->GetDescr());
2098             GetIDocumentUndoRedo().StartUndo(UNDO_ACCEPT_REDLINE, &aRewriter);
2099         }
2100 
2101         int nLoopCnt = 2;
2102         sal_uInt16 nSeqNo = pTmp->GetSeqNo();
2103 
2104         do {
2105 
2106             if (GetIDocumentUndoRedo().DoesUndo())
2107             {
2108                 SwUndo *const pUndo( new SwUndoAcceptRedline(*pTmp) );
2109                 GetIDocumentUndoRedo().AppendUndo(pUndo);
2110             }
2111 
2112             bRet |= lcl_AcceptRedline( *pRedlineTbl, nPos, bCallDelete );
2113 
2114             if( nSeqNo )
2115             {
2116                 if( USHRT_MAX == nPos )
2117                     nPos = 0;
2118                 sal_uInt16 nFndPos = 2 == nLoopCnt
2119                                     ? pRedlineTbl->FindNextSeqNo( nSeqNo, nPos )
2120                                     : pRedlineTbl->FindPrevSeqNo( nSeqNo, nPos );
2121                 if( USHRT_MAX != nFndPos || ( 0 != ( --nLoopCnt ) &&
2122                     USHRT_MAX != ( nFndPos =
2123                         pRedlineTbl->FindPrevSeqNo( nSeqNo, nPos ))) )
2124                     pTmp = (*pRedlineTbl)[ nPos = nFndPos ];
2125                 else
2126                     nLoopCnt = 0;
2127             }
2128             else
2129                 nLoopCnt = 0;
2130 
2131         } while( nLoopCnt );
2132 
2133         if( bRet )
2134         {
2135             CompressRedlines();
2136             SetModified();
2137         }
2138 
2139         if (GetIDocumentUndoRedo().DoesUndo())
2140         {
2141             GetIDocumentUndoRedo().EndUndo(UNDO_END, 0);
2142         }
2143     }
2144     return bRet;
2145 }
2146 
2147 bool SwDoc::AcceptRedline( const SwPaM& rPam, bool bCallDelete )
2148 {
2149     // aufjedenfall auf sichtbar umschalten
2150     if( (nsRedlineMode_t::REDLINE_SHOW_INSERT | nsRedlineMode_t::REDLINE_SHOW_DELETE) !=
2151         (nsRedlineMode_t::REDLINE_SHOW_MASK & eRedlineMode) )
2152       SetRedlineMode( (RedlineMode_t)(nsRedlineMode_t::REDLINE_SHOW_INSERT | nsRedlineMode_t::REDLINE_SHOW_DELETE | eRedlineMode));
2153 
2154     // die Selektion steht nur im ContentBereich. Wenn es aber Redlines
2155     // davor oder dahinter auf nicht ContentNodes stehen, dann erweiter die
2156     // die Selection auf diese
2157     SwPaM aPam( *rPam.GetMark(), *rPam.GetPoint() );
2158     lcl_AdjustRedlineRange( aPam );
2159 
2160     if (GetIDocumentUndoRedo().DoesUndo())
2161     {
2162         GetIDocumentUndoRedo().StartUndo( UNDO_ACCEPT_REDLINE, NULL );
2163         GetIDocumentUndoRedo().AppendUndo( new SwUndoAcceptRedline( aPam ));
2164     }
2165 
2166     // #111827#
2167     int nRet = lcl_AcceptRejectRedl( lcl_AcceptRedline, *pRedlineTbl,
2168                                      bCallDelete, aPam );
2169     if( nRet > 0 )
2170     {
2171         CompressRedlines();
2172         SetModified();
2173     }
2174     if (GetIDocumentUndoRedo().DoesUndo())
2175     {
2176         // #111827#
2177         String aTmpStr;
2178 
2179         {
2180             SwRewriter aRewriter;
2181             aRewriter.AddRule(UNDO_ARG1, String::CreateFromInt32(nRet));
2182             aTmpStr = aRewriter.Apply(String(SW_RES(STR_N_REDLINES)));
2183         }
2184 
2185         SwRewriter aRewriter;
2186         aRewriter.AddRule(UNDO_ARG1, aTmpStr);
2187 
2188         GetIDocumentUndoRedo().EndUndo( UNDO_ACCEPT_REDLINE, &aRewriter );
2189     }
2190     return nRet != 0;
2191 }
2192 
2193 bool SwDoc::RejectRedline( sal_uInt16 nPos, bool bCallDelete )
2194 {
2195     sal_Bool bRet = sal_False;
2196 
2197     // aufjedenfall auf sichtbar umschalten
2198     if( (nsRedlineMode_t::REDLINE_SHOW_INSERT | nsRedlineMode_t::REDLINE_SHOW_DELETE) !=
2199         (nsRedlineMode_t::REDLINE_SHOW_MASK & eRedlineMode) )
2200       SetRedlineMode( (RedlineMode_t)(nsRedlineMode_t::REDLINE_SHOW_INSERT | nsRedlineMode_t::REDLINE_SHOW_DELETE | eRedlineMode));
2201 
2202     SwRedline* pTmp = (*pRedlineTbl)[ nPos ];
2203     if( pTmp->HasMark() && pTmp->IsVisible() )
2204     {
2205         if (GetIDocumentUndoRedo().DoesUndo())
2206         {
2207             // #111827#
2208             SwRewriter aRewriter;
2209 
2210             aRewriter.AddRule(UNDO_ARG1, pTmp->GetDescr());
2211             GetIDocumentUndoRedo().StartUndo(UNDO_REJECT_REDLINE, &aRewriter);
2212         }
2213 
2214         int nLoopCnt = 2;
2215         sal_uInt16 nSeqNo = pTmp->GetSeqNo();
2216 
2217         do {
2218 
2219             if (GetIDocumentUndoRedo().DoesUndo())
2220             {
2221                 SwUndo *const pUndo( new SwUndoRejectRedline( *pTmp ) );
2222                 GetIDocumentUndoRedo().AppendUndo(pUndo);
2223             }
2224 
2225             bRet |= lcl_RejectRedline( *pRedlineTbl, nPos, bCallDelete );
2226 
2227             if( nSeqNo )
2228             {
2229                 if( USHRT_MAX == nPos )
2230                     nPos = 0;
2231                 sal_uInt16 nFndPos = 2 == nLoopCnt
2232                                     ? pRedlineTbl->FindNextSeqNo( nSeqNo, nPos )
2233                                     : pRedlineTbl->FindPrevSeqNo( nSeqNo, nPos );
2234                 if( USHRT_MAX != nFndPos || ( 0 != ( --nLoopCnt ) &&
2235                     USHRT_MAX != ( nFndPos =
2236                             pRedlineTbl->FindPrevSeqNo( nSeqNo, nPos ))) )
2237                     pTmp = (*pRedlineTbl)[ nPos = nFndPos ];
2238                 else
2239                     nLoopCnt = 0;
2240             }
2241             else
2242                 nLoopCnt = 0;
2243 
2244         } while( nLoopCnt );
2245 
2246         if( bRet )
2247         {
2248             CompressRedlines();
2249             SetModified();
2250         }
2251 
2252         if (GetIDocumentUndoRedo().DoesUndo())
2253         {
2254             GetIDocumentUndoRedo().EndUndo(UNDO_END, 0);
2255         }
2256     }
2257     return bRet;
2258 }
2259 
2260 bool SwDoc::RejectRedline( const SwPaM& rPam, bool bCallDelete )
2261 {
2262     // aufjedenfall auf sichtbar umschalten
2263     if( (nsRedlineMode_t::REDLINE_SHOW_INSERT | nsRedlineMode_t::REDLINE_SHOW_DELETE) !=
2264         (nsRedlineMode_t::REDLINE_SHOW_MASK & eRedlineMode) )
2265       SetRedlineMode((RedlineMode_t)(nsRedlineMode_t::REDLINE_SHOW_INSERT | nsRedlineMode_t::REDLINE_SHOW_DELETE | eRedlineMode));
2266 
2267     // die Selektion steht nur im ContentBereich. Wenn es aber Redlines
2268     // davor oder dahinter auf nicht ContentNodes stehen, dann erweiter die
2269     // die Selection auf diese
2270     SwPaM aPam( *rPam.GetMark(), *rPam.GetPoint() );
2271     lcl_AdjustRedlineRange( aPam );
2272 
2273     if (GetIDocumentUndoRedo().DoesUndo())
2274     {
2275         GetIDocumentUndoRedo().StartUndo( UNDO_REJECT_REDLINE, NULL );
2276         GetIDocumentUndoRedo().AppendUndo( new SwUndoRejectRedline(aPam) );
2277     }
2278 
2279     // #111827#
2280     int nRet = lcl_AcceptRejectRedl( lcl_RejectRedline, *pRedlineTbl,
2281                                         bCallDelete, aPam );
2282     if( nRet > 0 )
2283     {
2284         CompressRedlines();
2285         SetModified();
2286     }
2287     if (GetIDocumentUndoRedo().DoesUndo())
2288     {
2289         // #111827#
2290         String aTmpStr;
2291 
2292         {
2293             SwRewriter aRewriter;
2294             aRewriter.AddRule(UNDO_ARG1, String::CreateFromInt32(nRet));
2295             aTmpStr = aRewriter.Apply(String(SW_RES(STR_N_REDLINES)));
2296         }
2297 
2298         SwRewriter aRewriter;
2299         aRewriter.AddRule(UNDO_ARG1, aTmpStr);
2300 
2301         GetIDocumentUndoRedo().EndUndo( UNDO_REJECT_REDLINE, &aRewriter );
2302     }
2303 
2304     return nRet != 0;
2305 }
2306 
2307 const SwRedline* SwDoc::SelNextRedline( SwPaM& rPam ) const
2308 {
2309     rPam.DeleteMark();
2310     rPam.SetMark();
2311 
2312     SwPosition& rSttPos = *rPam.GetPoint();
2313     SwPosition aSavePos( rSttPos );
2314     sal_Bool bRestart;
2315 
2316     // sollte die StartPos auf dem letzen gueligen ContentNode stehen,
2317     // dann aufjedenfall das naechste Redline nehmen
2318     sal_uInt16 n = 0;
2319     const SwRedline* pFnd = lcl_FindCurrRedline( rSttPos, n, sal_True );
2320     if( pFnd )
2321     {
2322         const SwPosition* pEnd = pFnd->End();
2323         if( !pEnd->nNode.GetNode().IsCntntNode() )
2324         {
2325             SwNodeIndex aTmp( pEnd->nNode );
2326             SwCntntNode* pCNd = GetNodes().GoPrevSection( &aTmp );
2327             if( !pCNd || ( aTmp == rSttPos.nNode &&
2328                 pCNd->Len() == rSttPos.nContent.GetIndex() ))
2329                 pFnd = 0;
2330         }
2331         if( pFnd )
2332             rSttPos = *pFnd->End();
2333     }
2334 
2335     do {
2336         bRestart = sal_False;
2337 
2338         for( ; !pFnd && n < pRedlineTbl->Count(); ++n )
2339         {
2340             pFnd = (*pRedlineTbl)[ n ];
2341             if( pFnd->HasMark() && pFnd->IsVisible() )
2342             {
2343                 *rPam.GetMark() = *pFnd->Start();
2344                 rSttPos = *pFnd->End();
2345                 break;
2346             }
2347             else
2348                 pFnd = 0;
2349         }
2350 
2351         if( pFnd )
2352         {
2353             // alle vom gleichen Typ und Author, die hinter einander liegen
2354             // zu einer Selektion zusammenfassen.
2355             const SwPosition* pPrevEnd = pFnd->End();
2356             while( ++n < pRedlineTbl->Count() )
2357             {
2358                 const SwRedline* pTmp = (*pRedlineTbl)[ n ];
2359                 if( pTmp->HasMark() && pTmp->IsVisible() )
2360                 {
2361                     const SwPosition *pRStt;
2362                     if( pFnd->GetType() == pTmp->GetType() &&
2363                         pFnd->GetAuthor() == pTmp->GetAuthor() &&
2364                         ( *pPrevEnd == *( pRStt = pTmp->Start() ) ||
2365                           IsPrevPos( *pPrevEnd, *pRStt )) )
2366                     {
2367                         pPrevEnd = pTmp->End();
2368                         rSttPos = *pPrevEnd;
2369                     }
2370                     else
2371                         break;
2372                 }
2373             }
2374         }
2375 
2376         if( pFnd )
2377         {
2378             const SwRedline* pSaveFnd = pFnd;
2379 
2380             SwCntntNode* pCNd;
2381             SwNodeIndex* pIdx = &rPam.GetMark()->nNode;
2382             if( !pIdx->GetNode().IsCntntNode() &&
2383                 0 != ( pCNd = GetNodes().GoNextSection( pIdx )) )
2384             {
2385                 if( *pIdx <= rPam.GetPoint()->nNode )
2386                     rPam.GetMark()->nContent.Assign( pCNd, 0 );
2387                 else
2388                     pFnd = 0;
2389             }
2390 
2391             if( pFnd )
2392             {
2393                 pIdx = &rPam.GetPoint()->nNode;
2394                 if( !pIdx->GetNode().IsCntntNode() &&
2395                     0 != ( pCNd = GetNodes().GoPrevSection( pIdx )) )
2396                 {
2397                     if( *pIdx >= rPam.GetMark()->nNode )
2398                         rPam.GetPoint()->nContent.Assign( pCNd, pCNd->Len() );
2399                     else
2400                         pFnd = 0;
2401                 }
2402             }
2403 
2404             if( !pFnd || *rPam.GetMark() == *rPam.GetPoint() )
2405             {
2406                 if( n < pRedlineTbl->Count() )
2407                 {
2408                     bRestart = sal_True;
2409                     *rPam.GetPoint() = *pSaveFnd->End();
2410                 }
2411                 else
2412                 {
2413                     rPam.DeleteMark();
2414                     *rPam.GetPoint() = aSavePos;
2415                 }
2416                 pFnd = 0;
2417             }
2418         }
2419     } while( bRestart );
2420 
2421     return pFnd;
2422 }
2423 
2424 const SwRedline* SwDoc::SelPrevRedline( SwPaM& rPam ) const
2425 {
2426     rPam.DeleteMark();
2427     rPam.SetMark();
2428 
2429     SwPosition& rSttPos = *rPam.GetPoint();
2430     SwPosition aSavePos( rSttPos );
2431     sal_Bool bRestart;
2432 
2433     // sollte die StartPos auf dem ersten gueligen ContentNode stehen,
2434     // dann aufjedenfall das vorherige Redline nehmen
2435     sal_uInt16 n = 0;
2436     const SwRedline* pFnd = lcl_FindCurrRedline( rSttPos, n, sal_False );
2437     if( pFnd )
2438     {
2439         const SwPosition* pStt = pFnd->Start();
2440         if( !pStt->nNode.GetNode().IsCntntNode() )
2441         {
2442             SwNodeIndex aTmp( pStt->nNode );
2443             SwCntntNode* pCNd = GetNodes().GoNextSection( &aTmp );
2444             if( !pCNd || ( aTmp == rSttPos.nNode &&
2445                 !rSttPos.nContent.GetIndex() ))
2446                 pFnd = 0;
2447         }
2448         if( pFnd )
2449             rSttPos = *pFnd->Start();
2450     }
2451 
2452     do {
2453         bRestart = sal_False;
2454 
2455         while( !pFnd && 0 < n )
2456         {
2457             pFnd = (*pRedlineTbl)[ --n ];
2458             if( pFnd->HasMark() && pFnd->IsVisible() )
2459             {
2460                 *rPam.GetMark() = *pFnd->End();
2461                 rSttPos = *pFnd->Start();
2462             }
2463             else
2464                 pFnd = 0;
2465         }
2466 
2467         if( pFnd )
2468         {
2469             // alle vom gleichen Typ und Author, die hinter einander liegen
2470             // zu einer Selektion zusammenfassen.
2471             const SwPosition* pNextStt = pFnd->Start();
2472             while( 0 < n )
2473             {
2474                 const SwRedline* pTmp = (*pRedlineTbl)[ --n ];
2475                 if( pTmp->HasMark() && pTmp->IsVisible() )
2476                 {
2477                     const SwPosition *pREnd;
2478                     if( pFnd->GetType() == pTmp->GetType() &&
2479                         pFnd->GetAuthor() == pTmp->GetAuthor() &&
2480                         ( *pNextStt == *( pREnd = pTmp->End() ) ||
2481                           IsPrevPos( *pREnd, *pNextStt )) )
2482                     {
2483                         pNextStt = pTmp->Start();
2484                         rSttPos = *pNextStt;
2485                     }
2486                     else
2487                     {
2488                         ++n;
2489                         break;
2490                     }
2491                 }
2492             }
2493         }
2494 
2495         if( pFnd )
2496         {
2497             const SwRedline* pSaveFnd = pFnd;
2498 
2499             SwCntntNode* pCNd;
2500             SwNodeIndex* pIdx = &rPam.GetMark()->nNode;
2501             if( !pIdx->GetNode().IsCntntNode() &&
2502                 0 != ( pCNd = GetNodes().GoPrevSection( pIdx )) )
2503             {
2504                 if( *pIdx >= rPam.GetPoint()->nNode )
2505                     rPam.GetMark()->nContent.Assign( pCNd, pCNd->Len() );
2506                 else
2507                     pFnd = 0;
2508             }
2509 
2510             if( pFnd )
2511             {
2512                 pIdx = &rPam.GetPoint()->nNode;
2513                 if( !pIdx->GetNode().IsCntntNode() &&
2514                     0 != ( pCNd = GetNodes().GoNextSection( pIdx )) )
2515                 {
2516                     if( *pIdx <= rPam.GetMark()->nNode )
2517                         rPam.GetPoint()->nContent.Assign( pCNd, 0 );
2518                     else
2519                         pFnd = 0;
2520                 }
2521             }
2522 
2523             if( !pFnd || *rPam.GetMark() == *rPam.GetPoint() )
2524             {
2525                 if( n )
2526                 {
2527                     bRestart = sal_True;
2528                     *rPam.GetPoint() = *pSaveFnd->Start();
2529                 }
2530                 else
2531                 {
2532                     rPam.DeleteMark();
2533                     *rPam.GetPoint() = aSavePos;
2534                 }
2535                 pFnd = 0;
2536             }
2537         }
2538     } while( bRestart );
2539 
2540     return pFnd;
2541 }
2542 
2543 // Kommentar am Redline setzen
2544 bool SwDoc::SetRedlineComment( const SwPaM& rPaM, const String& rS )
2545 {
2546     sal_Bool bRet = sal_False;
2547     const SwPosition* pStt = rPaM.Start(),
2548                     * pEnd = pStt == rPaM.GetPoint() ? rPaM.GetMark()
2549                                                      : rPaM.GetPoint();
2550     sal_uInt16 n = 0;
2551     if( lcl_FindCurrRedline( *pStt, n, sal_True ) )
2552     {
2553         for( ; n < pRedlineTbl->Count(); ++n )
2554         {
2555             bRet = sal_True;
2556             SwRedline* pTmp = (*pRedlineTbl)[ n ];
2557             if( pStt != pEnd && *pTmp->Start() > *pEnd )
2558                 break;
2559 
2560             pTmp->SetComment( rS );
2561             if( *pTmp->End() >= *pEnd )
2562                 break;
2563         }
2564     }
2565     if( bRet )
2566         SetModified();
2567 
2568     return bRet;
2569 }
2570 
2571 // legt gebenenfalls einen neuen Author an
2572 sal_uInt16 SwDoc::GetRedlineAuthor()
2573 {
2574     return SW_MOD()->GetRedlineAuthor();
2575 }
2576 
2577     // fuer die Reader usw. - neuen Author in die Tabelle eintragen
2578 sal_uInt16 SwDoc::InsertRedlineAuthor( const String& rNew )
2579 {
2580     return SW_MOD()->InsertRedlineAuthor(rNew);
2581 }
2582 
2583 void SwDoc::UpdateRedlineAttr()
2584 {
2585     const SwRedlineTbl& rTbl = GetRedlineTbl();
2586     for( sal_uInt16 n = 0; n < rTbl.Count(); ++n )
2587     {
2588         SwRedline* pRedl = rTbl[ n ];
2589         if( pRedl->IsVisible() )
2590             pRedl->InvalidateRange();
2591     }
2592 }
2593 
2594     // setze Kommentar-Text fuers Redline, das dann per AppendRedline
2595     // hereinkommt. Wird vom Autoformat benutzt. 0-Pointer setzt den Modus
2596     // wieder zurueck. Pointer wird nicht kopiert, muss also gueltig bleiben!
2597 void SwDoc::SetAutoFmtRedlineComment( const String* pTxt, sal_uInt16 nSeqNo )
2598 {
2599     mbIsAutoFmtRedline = 0 != pTxt;
2600     if( pTxt )
2601     {
2602         if( !pAutoFmtRedlnComment )
2603             pAutoFmtRedlnComment = new String( *pTxt );
2604         else
2605             *pAutoFmtRedlnComment = *pTxt;
2606     }
2607     else if( pAutoFmtRedlnComment )
2608         delete pAutoFmtRedlnComment, pAutoFmtRedlnComment = 0;
2609 
2610     nAutoFmtRedlnCommentNo = nSeqNo;
2611 }
2612 
2613 void SwDoc::SetRedlinePassword(
2614             /*[in]*/const uno::Sequence <sal_Int8>& rNewPassword)
2615 {
2616     aRedlinePasswd = rNewPassword;
2617     SetModified();
2618 }
2619 
2620 /*  */
2621 
2622 sal_Bool SwRedlineTbl::Insert( SwRedlinePtr& p, sal_Bool bIns )
2623 {
2624     sal_Bool bRet = sal_False;
2625     if( p->HasValidRange() )
2626     {
2627         bRet = _SwRedlineTbl::Insert( p );
2628         p->CallDisplayFunc();
2629     }
2630     else if( bIns )
2631         bRet = InsertWithValidRanges( p );
2632     else
2633     {
2634         ASSERT( !this, "Redline: falscher Bereich" );
2635     }
2636     return bRet;
2637 }
2638 
2639 sal_Bool SwRedlineTbl::Insert( SwRedlinePtr& p, sal_uInt16& rP, sal_Bool bIns )
2640 {
2641     sal_Bool bRet = sal_False;
2642     if( p->HasValidRange() )
2643     {
2644         bRet = _SwRedlineTbl::Insert( p, rP );
2645         p->CallDisplayFunc();
2646     }
2647     else if( bIns )
2648         bRet = InsertWithValidRanges( p, &rP );
2649     else
2650     {
2651         ASSERT( !this, "Redline: falscher Bereich" );
2652     }
2653     return bRet;
2654 }
2655 
2656 sal_Bool SwRedlineTbl::InsertWithValidRanges( SwRedlinePtr& p, sal_uInt16* pInsPos )
2657 {
2658     // erzeuge aus den Selektion gueltige "Teilbereiche".
2659     sal_Bool bAnyIns = sal_False;
2660     SwPosition* pStt = p->Start(),
2661               * pEnd = pStt == p->GetPoint() ? p->GetMark() : p->GetPoint();
2662     SwPosition aNewStt( *pStt );
2663     SwNodes& rNds = aNewStt.nNode.GetNodes();
2664     SwCntntNode* pC;
2665 
2666     if( !aNewStt.nNode.GetNode().IsCntntNode() )
2667     {
2668         pC = rNds.GoNext( &aNewStt.nNode );
2669         if( pC )
2670             aNewStt.nContent.Assign( pC, 0 );
2671         else
2672             aNewStt.nNode = rNds.GetEndOfContent();
2673     }
2674 
2675     SwRedline* pNew = 0;
2676     sal_uInt16 nInsPos;
2677 
2678     if( aNewStt < *pEnd )
2679         do {
2680             if( !pNew )
2681                 pNew = new SwRedline( p->GetRedlineData(), aNewStt );
2682             else
2683             {
2684                 pNew->DeleteMark();
2685                 *pNew->GetPoint() = aNewStt;
2686             }
2687 
2688             pNew->SetMark();
2689             GoEndSection( pNew->GetPoint() );
2690             // i60396: If the redlines starts before a table but the table is the last member
2691             // of the section, the GoEndSection will end inside the table.
2692             // This will result in an incorrect redline, so we've to go back
2693             SwNode* pTab = pNew->GetPoint()->nNode.GetNode().StartOfSectionNode()->FindTableNode();
2694             // We end in a table when pTab != 0
2695             if( pTab && !pNew->GetMark()->nNode.GetNode().StartOfSectionNode()->FindTableNode() )
2696             { // but our Mark was outside the table => Correction
2697                 do
2698                 {
2699                     // We want to be before the table
2700                     *pNew->GetPoint() = SwPosition(*pTab);
2701                     pC = GoPreviousNds( &pNew->GetPoint()->nNode, sal_False ); // here we are.
2702                     if( pC )
2703                         pNew->GetPoint()->nContent.Assign( pC, 0 );
2704                     pTab = pNew->GetPoint()->nNode.GetNode().StartOfSectionNode()->FindTableNode();
2705                 }while( pTab ); // If there is another table we have to repeat our step backwards
2706             }
2707 
2708             if( *pNew->GetPoint() > *pEnd )
2709             {
2710                 pC = 0;
2711                 if( aNewStt.nNode != pEnd->nNode )
2712                     do {
2713                         SwNode& rCurNd = aNewStt.nNode.GetNode();
2714                         if( rCurNd.IsStartNode() )
2715                         {
2716                             if( rCurNd.EndOfSectionIndex() < pEnd->nNode.GetIndex() )
2717                                 aNewStt.nNode = *rCurNd.EndOfSectionNode();
2718                             else
2719                                 break;
2720                         }
2721                         else if( rCurNd.IsCntntNode() )
2722                             pC = rCurNd.GetCntntNode();
2723                         aNewStt.nNode++;
2724                     } while( aNewStt.nNode.GetIndex() < pEnd->nNode.GetIndex() );
2725 
2726                 if( aNewStt.nNode == pEnd->nNode )
2727                     aNewStt.nContent = pEnd->nContent;
2728                 else if( pC )
2729                 {
2730                     aNewStt.nNode = *pC;
2731                     aNewStt.nContent.Assign( pC, pC->Len() );
2732                 }
2733 
2734                 if( aNewStt <= *pEnd )
2735                     *pNew->GetPoint() = aNewStt;
2736             }
2737             else
2738                 aNewStt = *pNew->GetPoint();
2739 #ifdef DEBUG
2740             CheckPosition( pNew->GetPoint(), pNew->GetMark() );
2741 #endif
2742             if( *pNew->GetPoint() != *pNew->GetMark() &&
2743                 _SwRedlineTbl::Insert( pNew, nInsPos ) )
2744             {
2745                 pNew->CallDisplayFunc();
2746                 bAnyIns = sal_True;
2747                 pNew = 0;
2748                 if( pInsPos && *pInsPos < nInsPos )
2749                     *pInsPos = nInsPos;
2750             }
2751 
2752             if( aNewStt >= *pEnd ||
2753                 0 == (pC = rNds.GoNext( &aNewStt.nNode )) )
2754                 break;
2755 
2756             aNewStt.nContent.Assign( pC, 0 );
2757 
2758         } while( aNewStt < *pEnd );
2759 
2760     delete pNew;
2761     delete p, p = 0;
2762     return bAnyIns;
2763 }
2764 
2765 void SwRedlineTbl::Remove( sal_uInt16 nP, sal_uInt16 nL )
2766 {
2767     SwDoc* pDoc = 0;
2768     if( !nP && nL && nL == _SwRedlineTbl::Count() )
2769         pDoc = _SwRedlineTbl::GetObject( 0 )->GetDoc();
2770 
2771     _SwRedlineTbl::Remove( nP, nL );
2772 
2773     ViewShell* pSh;
2774     if( pDoc && !pDoc->IsInDtor() &&
2775         0 != ( pSh = pDoc->GetCurrentViewShell()) ) //swmod 071108//swmod 071225
2776         pSh->InvalidateWindows( SwRect( 0, 0, LONG_MAX, LONG_MAX ) );
2777 }
2778 
2779 void SwRedlineTbl::DeleteAndDestroy( sal_uInt16 nP, sal_uInt16 nL )
2780 {
2781     SwDoc* pDoc = 0;
2782     if( !nP && nL && nL == _SwRedlineTbl::Count() )
2783         pDoc = _SwRedlineTbl::GetObject( 0 )->GetDoc();
2784 
2785     _SwRedlineTbl::DeleteAndDestroy( nP, nL );
2786 
2787     ViewShell* pSh;
2788     if( pDoc && !pDoc->IsInDtor() &&
2789         0 != ( pSh = pDoc->GetCurrentViewShell() ) )    //swmod 071108//swmod 071225
2790         pSh->InvalidateWindows( SwRect( 0, 0, LONG_MAX, LONG_MAX ) );
2791 }
2792 
2793 // suche den naechsten oder vorherigen Redline mit dergleichen Seq.No
2794 // Mit dem Lookahead kann die Suche eingeschraenkt werden. 0 oder
2795 // USHRT_MAX suchen im gesamten Array.
2796 sal_uInt16 SwRedlineTbl::FindNextOfSeqNo( sal_uInt16 nSttPos, sal_uInt16 nLookahead ) const
2797 {
2798     return nSttPos + 1 < _SwRedlineTbl::Count()
2799                 ? FindNextSeqNo( _SwRedlineTbl::GetObject( nSttPos )
2800                                     ->GetSeqNo(), nSttPos+1, nLookahead )
2801                 : USHRT_MAX;
2802 }
2803 
2804 sal_uInt16 SwRedlineTbl::FindPrevOfSeqNo( sal_uInt16 nSttPos, sal_uInt16 nLookahead ) const
2805 {
2806     return nSttPos ? FindPrevSeqNo( _SwRedlineTbl::GetObject(
2807                                         nSttPos )->GetSeqNo(),
2808                                     nSttPos-1, nLookahead )
2809                    : USHRT_MAX;
2810 }
2811 
2812 sal_uInt16 SwRedlineTbl::FindNextSeqNo( sal_uInt16 nSeqNo, sal_uInt16 nSttPos,
2813                                     sal_uInt16 nLookahead ) const
2814 {
2815     sal_uInt16 nRet = USHRT_MAX, nEnd;
2816     if( nSeqNo && nSttPos < _SwRedlineTbl::Count() )
2817     {
2818         nEnd = _SwRedlineTbl::Count();
2819         if( nLookahead && USHRT_MAX != nLookahead &&
2820             nSttPos + nLookahead < _SwRedlineTbl::Count() )
2821             nEnd = nSttPos + nLookahead;
2822 
2823         for( ; nSttPos < nEnd; ++nSttPos )
2824             if( nSeqNo == _SwRedlineTbl::GetObject( nSttPos )->GetSeqNo() )
2825             {
2826                 nRet = nSttPos;
2827                 break;
2828             }
2829     }
2830     return nRet;
2831 }
2832 
2833 sal_uInt16 SwRedlineTbl::FindPrevSeqNo( sal_uInt16 nSeqNo, sal_uInt16 nSttPos,
2834                                     sal_uInt16 nLookahead ) const
2835 {
2836     sal_uInt16 nRet = USHRT_MAX, nEnd;
2837     if( nSeqNo && nSttPos < _SwRedlineTbl::Count() )
2838     {
2839         nEnd = 0;
2840         if( nLookahead && USHRT_MAX != nLookahead && nSttPos > nLookahead )
2841             nEnd = nSttPos - nLookahead;
2842 
2843         ++nSttPos;
2844         while( nSttPos > nEnd )
2845             if( nSeqNo == _SwRedlineTbl::GetObject( --nSttPos )->GetSeqNo() )
2846             {
2847                 nRet = nSttPos;
2848                 break;
2849             }
2850     }
2851     return nRet;
2852 }
2853 
2854 /*  */
2855 
2856 SwRedlineExtraData::~SwRedlineExtraData()
2857 {
2858 }
2859 
2860 void SwRedlineExtraData::Accept( SwPaM& ) const
2861 {
2862 }
2863 
2864 void SwRedlineExtraData::Reject( SwPaM& ) const
2865 {
2866 }
2867 
2868 int SwRedlineExtraData::operator == ( const SwRedlineExtraData& ) const
2869 {
2870     return sal_False;
2871 }
2872 
2873 
2874 SwRedlineExtraData_FmtColl::SwRedlineExtraData_FmtColl( const String& rColl,
2875                                                 sal_uInt16 nPoolFmtId,
2876                                                 const SfxItemSet* pItemSet )
2877     : sFmtNm(rColl), pSet(0), nPoolId(nPoolFmtId)
2878 {
2879     if( pItemSet && pItemSet->Count() )
2880         pSet = new SfxItemSet( *pItemSet );
2881 }
2882 
2883 SwRedlineExtraData_FmtColl::~SwRedlineExtraData_FmtColl()
2884 {
2885     delete pSet;
2886 }
2887 
2888 SwRedlineExtraData* SwRedlineExtraData_FmtColl::CreateNew() const
2889 {
2890     return new SwRedlineExtraData_FmtColl( sFmtNm, nPoolId, pSet );
2891 }
2892 
2893 void SwRedlineExtraData_FmtColl::Reject( SwPaM& rPam ) const
2894 {
2895     SwDoc* pDoc = rPam.GetDoc();
2896 
2897 // was ist mit Undo ? ist das abgeschaltet ??
2898     SwTxtFmtColl* pColl = USHRT_MAX == nPoolId
2899                             ? pDoc->FindTxtFmtCollByName( sFmtNm )
2900                             : pDoc->GetTxtCollFromPool( nPoolId );
2901     if( pColl )
2902         pDoc->SetTxtFmtColl( rPam, pColl, false );
2903 
2904     if( pSet )
2905     {
2906         rPam.SetMark();
2907         SwPosition& rMark = *rPam.GetMark();
2908         SwTxtNode* pTNd = rMark.nNode.GetNode().GetTxtNode();
2909         if( pTNd )
2910         {
2911             rMark.nContent.Assign( pTNd, pTNd->GetTxt().Len() );
2912 
2913             if( pTNd->HasSwAttrSet() )
2914             {
2915                 // nur die setzen, die nicht mehr vorhanden sind. Andere
2916                 // koennen jetzt veraendert drin stehen, aber die werden
2917                 // nicht angefasst.
2918                 SfxItemSet aTmp( *pSet );
2919                 aTmp.Differentiate( *pTNd->GetpSwAttrSet() );
2920                 pDoc->InsertItemSet( rPam, aTmp, 0 );
2921             }
2922             else
2923             {
2924                 pDoc->InsertItemSet( rPam, *pSet, 0 );
2925             }
2926         }
2927         rPam.DeleteMark();
2928     }
2929 }
2930 
2931 int SwRedlineExtraData_FmtColl::operator == ( const SwRedlineExtraData& r) const
2932 {
2933     const SwRedlineExtraData_FmtColl& rCmp = (SwRedlineExtraData_FmtColl&)r;
2934     return sFmtNm == rCmp.sFmtNm && nPoolId == rCmp.nPoolId &&
2935             ( ( !pSet && !rCmp.pSet ) ||
2936                ( pSet && rCmp.pSet && *pSet == *rCmp.pSet ) );
2937 }
2938 
2939 void SwRedlineExtraData_FmtColl::SetItemSet( const SfxItemSet& rSet )
2940 {
2941     delete pSet;
2942     if( rSet.Count() )
2943         pSet = new SfxItemSet( rSet );
2944     else
2945         pSet = 0;
2946 }
2947 
2948 
2949 SwRedlineExtraData_Format::SwRedlineExtraData_Format( const SfxItemSet& rSet )
2950 {
2951     SfxItemIter aIter( rSet );
2952     const SfxPoolItem* pItem = aIter.FirstItem();
2953     while( sal_True )
2954     {
2955         aWhichIds.Insert( pItem->Which(), aWhichIds.Count() );
2956         if( aIter.IsAtEnd() )
2957             break;
2958         pItem = aIter.NextItem();
2959     }
2960 }
2961 
2962 SwRedlineExtraData_Format::SwRedlineExtraData_Format(
2963         const SwRedlineExtraData_Format& rCpy )
2964     : SwRedlineExtraData(), aWhichIds( (sal_uInt8)rCpy.aWhichIds.Count() )
2965 {
2966     aWhichIds.Insert( &rCpy.aWhichIds, 0 );
2967 }
2968 
2969 SwRedlineExtraData_Format::~SwRedlineExtraData_Format()
2970 {
2971 }
2972 
2973 SwRedlineExtraData* SwRedlineExtraData_Format::CreateNew() const
2974 {
2975     return new SwRedlineExtraData_Format( *this );
2976 }
2977 
2978 void SwRedlineExtraData_Format::Reject( SwPaM& rPam ) const
2979 {
2980     SwDoc* pDoc = rPam.GetDoc();
2981 
2982     RedlineMode_t eOld = pDoc->GetRedlineMode();
2983     pDoc->SetRedlineMode_intern((RedlineMode_t)(eOld & ~(nsRedlineMode_t::REDLINE_ON | nsRedlineMode_t::REDLINE_IGNORE)));
2984 
2985     // eigentlich muesste hier das Attribut zurueck gesetzt werden!!!
2986     for( sal_uInt16 n = 0, nEnd = aWhichIds.Count(); n < nEnd; ++n )
2987     {
2988         pDoc->InsertPoolItem( rPam, *GetDfltAttr( aWhichIds[ n ] ),
2989                 nsSetAttrMode::SETATTR_DONTEXPAND );
2990     }
2991 
2992     pDoc->SetRedlineMode_intern( eOld );
2993 }
2994 
2995 int SwRedlineExtraData_Format::operator == ( const SwRedlineExtraData& rCmp ) const
2996 {
2997     int nRet = 1;
2998     sal_uInt16 n = 0, nEnd = aWhichIds.Count();
2999     if( nEnd != ((SwRedlineExtraData_Format&)rCmp).aWhichIds.Count() )
3000         nRet = 0;
3001     else
3002         for( ; n < nEnd; ++n )
3003             if( ((SwRedlineExtraData_Format&)rCmp).aWhichIds[n] != aWhichIds[n])
3004             {
3005                 nRet = 0;
3006                 break;
3007             }
3008     return nRet;
3009 }
3010 
3011 /*  */
3012 
3013 SwRedlineData::SwRedlineData( RedlineType_t eT, sal_uInt16 nAut )
3014     : pNext( 0 ), pExtraData( 0 ), eType( eT ), nAuthor( nAut ), nSeqNo( 0 )
3015 {
3016     aStamp.SetSec( 0 );
3017     aStamp.Set100Sec( 0 );
3018 }
3019 
3020 SwRedlineData::SwRedlineData( const SwRedlineData& rCpy, sal_Bool bCpyNext )
3021     :
3022     pNext( (bCpyNext && rCpy.pNext) ? new SwRedlineData( *rCpy.pNext ) : 0 ),
3023     pExtraData( rCpy.pExtraData ? rCpy.pExtraData->CreateNew() : 0 ),
3024     sComment( rCpy.sComment ), aStamp( rCpy.aStamp ), eType( rCpy.eType ),
3025     nAuthor( rCpy.nAuthor ), nSeqNo( rCpy.nSeqNo )
3026 {
3027 }
3028 
3029     // fuer sw3io: pNext geht in eigenen Besitz ueber!
3030 SwRedlineData::SwRedlineData(RedlineType_t eT, sal_uInt16 nAut, const DateTime& rDT,
3031     const String& rCmnt, SwRedlineData *pNxt, SwRedlineExtraData* pData)
3032     : pNext(pNxt), pExtraData(pData), sComment(rCmnt), aStamp(rDT),
3033     eType(eT), nAuthor(nAut), nSeqNo(0)
3034 {
3035 }
3036 
3037 SwRedlineData::~SwRedlineData()
3038 {
3039     delete pExtraData;
3040     delete pNext;
3041 }
3042 
3043     // ExtraData wird kopiert, der Pointer geht also NICHT in den Besitz
3044     // des RedlineObjectes!
3045 void SwRedlineData::SetExtraData( const SwRedlineExtraData* pData )
3046 {
3047     delete pExtraData;
3048 
3049     if( pData )
3050         pExtraData = pData->CreateNew();
3051     else
3052         pExtraData = 0;
3053 }
3054 
3055 // #111827#
3056 String SwRedlineData::GetDescr() const
3057 {
3058     String aResult;
3059 
3060     aResult += String(SW_RES(STR_REDLINE_INSERT + GetType()));
3061 
3062     return aResult;
3063 }
3064 
3065 /*  */
3066 
3067 SwRedline::SwRedline(RedlineType_t eTyp, const SwPaM& rPam )
3068     : SwPaM( *rPam.GetMark(), *rPam.GetPoint() ),
3069     pRedlineData( new SwRedlineData( eTyp, GetDoc()->GetRedlineAuthor() ) ),
3070     pCntntSect( 0 )
3071 {
3072     bDelLastPara = bIsLastParaDelete = sal_False;
3073     bIsVisible = sal_True;
3074     if( !rPam.HasMark() )
3075         DeleteMark();
3076 }
3077 
3078 SwRedline::SwRedline( const SwRedlineData& rData, const SwPaM& rPam )
3079     : SwPaM( *rPam.GetMark(), *rPam.GetPoint() ),
3080     pRedlineData( new SwRedlineData( rData )),
3081     pCntntSect( 0 )
3082 {
3083     bDelLastPara = bIsLastParaDelete = sal_False;
3084     bIsVisible = sal_True;
3085     if( !rPam.HasMark() )
3086         DeleteMark();
3087 }
3088 
3089 SwRedline::SwRedline( const SwRedlineData& rData, const SwPosition& rPos )
3090     : SwPaM( rPos ),
3091     pRedlineData( new SwRedlineData( rData )),
3092     pCntntSect( 0 )
3093 {
3094     bDelLastPara = bIsLastParaDelete = sal_False;
3095     bIsVisible = sal_True;
3096 }
3097 
3098 SwRedline::SwRedline( const SwRedline& rCpy )
3099     : SwPaM( *rCpy.GetMark(), *rCpy.GetPoint() ),
3100     pRedlineData( new SwRedlineData( *rCpy.pRedlineData )),
3101     pCntntSect( 0 )
3102 {
3103     bDelLastPara = bIsLastParaDelete = sal_False;
3104     bIsVisible = sal_True;
3105     if( !rCpy.HasMark() )
3106         DeleteMark();
3107 }
3108 
3109 SwRedline::~SwRedline()
3110 {
3111     if( pCntntSect )
3112     {
3113         // dann den Content Bereich loeschen
3114         if( !GetDoc()->IsInDtor() )
3115             GetDoc()->DeleteSection( &pCntntSect->GetNode() );
3116         delete pCntntSect;
3117     }
3118     delete pRedlineData;
3119 }
3120 
3121 // liegt eine gueltige Selektion vor?
3122 sal_Bool SwRedline::HasValidRange() const
3123 {
3124     const SwNode* pPtNd = &GetPoint()->nNode.GetNode(),
3125                 * pMkNd = &GetMark()->nNode.GetNode();
3126     if( pPtNd->StartOfSectionNode() == pMkNd->StartOfSectionNode() &&
3127         !pPtNd->StartOfSectionNode()->IsTableNode() &&
3128         // JP 18.5.2001: Bug 87222 - invalid if points on the end of content
3129         // DVO 25.03.2002: #96530# end-of-content only invalid if no content
3130         //                 index exists
3131         ( pPtNd != pMkNd || GetContentIdx() != NULL ||
3132           pPtNd != &pPtNd->GetNodes().GetEndOfContent() )
3133         )
3134         return sal_True;
3135     return sal_False;
3136 }
3137 
3138 void SwRedline::CallDisplayFunc( sal_uInt16 nLoop )
3139 {
3140     switch( nsRedlineMode_t::REDLINE_SHOW_MASK & GetDoc()->GetRedlineMode() )
3141     {
3142     case nsRedlineMode_t::REDLINE_SHOW_INSERT | nsRedlineMode_t::REDLINE_SHOW_DELETE:
3143         Show( nLoop );
3144         break;
3145     case nsRedlineMode_t::REDLINE_SHOW_INSERT:
3146         Hide( nLoop );
3147         break;
3148     case nsRedlineMode_t::REDLINE_SHOW_DELETE:
3149         ShowOriginal( nLoop );
3150         break;
3151     }
3152 }
3153 
3154 void SwRedline::Show( sal_uInt16 nLoop )
3155 {
3156     if( 1 <= nLoop )
3157     {
3158         SwDoc* pDoc = GetDoc();
3159         RedlineMode_t eOld = pDoc->GetRedlineMode();
3160         pDoc->SetRedlineMode_intern((RedlineMode_t)(eOld | nsRedlineMode_t::REDLINE_IGNORE));
3161         ::sw::UndoGuard const undoGuard(pDoc->GetIDocumentUndoRedo());
3162 
3163         switch( GetType() )
3164         {
3165         case nsRedlineType_t::REDLINE_INSERT:           // Inhalt wurde eingefuegt
3166             bIsVisible = sal_True;
3167             MoveFromSection();
3168             break;
3169 
3170         case nsRedlineType_t::REDLINE_DELETE:           // Inhalt wurde geloescht
3171             bIsVisible = sal_True;
3172             MoveFromSection();
3173             break;
3174 
3175         case nsRedlineType_t::REDLINE_FORMAT:           // Attributierung wurde angewendet
3176         case nsRedlineType_t::REDLINE_TABLE:                // TabellenStruktur wurde veraendert
3177             InvalidateRange();
3178             break;
3179         default:
3180             break;
3181         }
3182         pDoc->SetRedlineMode_intern( eOld );
3183     }
3184 }
3185 
3186 void SwRedline::Hide( sal_uInt16 nLoop )
3187 {
3188     SwDoc* pDoc = GetDoc();
3189     RedlineMode_t eOld = pDoc->GetRedlineMode();
3190     pDoc->SetRedlineMode_intern((RedlineMode_t)(eOld | nsRedlineMode_t::REDLINE_IGNORE));
3191     ::sw::UndoGuard const undoGuard(pDoc->GetIDocumentUndoRedo());
3192 
3193     switch( GetType() )
3194     {
3195     case nsRedlineType_t::REDLINE_INSERT:           // Inhalt wurde eingefuegt
3196         bIsVisible = sal_True;
3197         if( 1 <= nLoop )
3198             MoveFromSection();
3199         break;
3200 
3201     case nsRedlineType_t::REDLINE_DELETE:           // Inhalt wurde geloescht
3202         bIsVisible = sal_False;
3203         switch( nLoop )
3204         {
3205         case 0: MoveToSection();    break;
3206         case 1: CopyToSection();    break;
3207         case 2: DelCopyOfSection(); break;
3208         }
3209         break;
3210 
3211     case nsRedlineType_t::REDLINE_FORMAT:           // Attributierung wurde angewendet
3212     case nsRedlineType_t::REDLINE_TABLE:                // TabellenStruktur wurde veraendert
3213         if( 1 <= nLoop )
3214             InvalidateRange();
3215         break;
3216     default:
3217         break;
3218     }
3219     pDoc->SetRedlineMode_intern( eOld );
3220 }
3221 
3222 void SwRedline::ShowOriginal( sal_uInt16 nLoop )
3223 {
3224     SwDoc* pDoc = GetDoc();
3225     RedlineMode_t eOld = pDoc->GetRedlineMode();
3226     SwRedlineData* pCur;
3227 
3228     pDoc->SetRedlineMode_intern((RedlineMode_t)(eOld | nsRedlineMode_t::REDLINE_IGNORE));
3229     ::sw::UndoGuard const undoGuard(pDoc->GetIDocumentUndoRedo());
3230 
3231     // bestimme den Type, ist der erste auf Stack
3232     for( pCur = pRedlineData; pCur->pNext; )
3233         pCur = pCur->pNext;
3234 
3235     switch( pCur->eType )
3236     {
3237     case nsRedlineType_t::REDLINE_INSERT:           // Inhalt wurde eingefuegt
3238         bIsVisible = sal_False;
3239         switch( nLoop )
3240         {
3241         case 0: MoveToSection();    break;
3242         case 1: CopyToSection();    break;
3243         case 2: DelCopyOfSection(); break;
3244         }
3245         break;
3246 
3247     case nsRedlineType_t::REDLINE_DELETE:           // Inhalt wurde geloescht
3248         bIsVisible = sal_True;
3249         if( 1 <= nLoop )
3250             MoveFromSection();
3251         break;
3252 
3253     case nsRedlineType_t::REDLINE_FORMAT:           // Attributierung wurde angewendet
3254     case nsRedlineType_t::REDLINE_TABLE:                // TabellenStruktur wurde veraendert
3255         if( 1 <= nLoop )
3256             InvalidateRange();
3257         break;
3258     default:
3259         break;
3260     }
3261     pDoc->SetRedlineMode_intern( eOld );
3262 }
3263 
3264 
3265 void SwRedline::InvalidateRange()       // das Layout anstossen
3266 {
3267     sal_uLong nSttNd = GetMark()->nNode.GetIndex(),
3268             nEndNd = GetPoint()->nNode.GetIndex();
3269     sal_uInt16 nSttCnt = GetMark()->nContent.GetIndex(),
3270             nEndCnt = GetPoint()->nContent.GetIndex();
3271 
3272     if( nSttNd > nEndNd || ( nSttNd == nEndNd && nSttCnt > nEndCnt ))
3273     {
3274         sal_uLong nTmp = nSttNd; nSttNd = nEndNd; nEndNd = nTmp;
3275         nTmp = nSttCnt; nSttCnt = nEndCnt; nEndCnt = (sal_uInt16)nTmp;
3276     }
3277 
3278     SwUpdateAttr aHt( 0, 0, RES_FMT_CHG );
3279     SwNodes& rNds = GetDoc()->GetNodes();
3280     SwNode* pNd;
3281     for( sal_uLong n = nSttNd; n <= nEndNd; ++n )
3282         if( ND_TEXTNODE == ( pNd = rNds[ n ] )->GetNodeType() )
3283         {
3284             aHt.nStart = n == nSttNd ? nSttCnt : 0;
3285             aHt.nEnd = n == nEndNd ? nEndCnt : ((SwTxtNode*)pNd)->GetTxt().Len();
3286             ((SwTxtNode*)pNd)->ModifyNotification( &aHt, &aHt );
3287         }
3288 }
3289 
3290 /*************************************************************************
3291  *                      SwRedline::CalcStartEnd()
3292  * Calculates the start and end position of the intersection rTmp and
3293  * text node nNdIdx
3294  *************************************************************************/
3295 
3296 void SwRedline::CalcStartEnd( sal_uLong nNdIdx, sal_uInt16& nStart, sal_uInt16& nEnd ) const
3297 {
3298     const SwPosition *pRStt = Start(), *pREnd = End();
3299     if( pRStt->nNode < nNdIdx )
3300     {
3301         if( pREnd->nNode > nNdIdx )
3302         {
3303             nStart = 0;             // Absatz ist komplett enthalten
3304             nEnd = STRING_LEN;
3305         }
3306         else
3307         {
3308             ASSERT( pREnd->nNode == nNdIdx,
3309                 "SwRedlineItr::Seek: GetRedlinePos Error" );
3310             nStart = 0;             // Absatz wird vorne ueberlappt
3311             nEnd = pREnd->nContent.GetIndex();
3312         }
3313     }
3314     else if( pRStt->nNode == nNdIdx )
3315     {
3316         nStart = pRStt->nContent.GetIndex();
3317         if( pREnd->nNode == nNdIdx )
3318             nEnd = pREnd->nContent.GetIndex(); // Innerhalb des Absatzes
3319         else
3320             nEnd = STRING_LEN;      // Absatz wird hinten ueberlappt
3321     }
3322     else
3323     {
3324         nStart = STRING_LEN;
3325         nEnd = STRING_LEN;
3326     }
3327 }
3328 
3329 void SwRedline::MoveToSection()
3330 {
3331     if( !pCntntSect )
3332     {
3333         const SwPosition* pStt = Start(),
3334                         * pEnd = pStt == GetPoint() ? GetMark() : GetPoint();
3335 
3336         SwDoc* pDoc = GetDoc();
3337         SwPaM aPam( *pStt, *pEnd );
3338         SwCntntNode* pCSttNd = pStt->nNode.GetNode().GetCntntNode();
3339         SwCntntNode* pCEndNd = pEnd->nNode.GetNode().GetCntntNode();
3340 
3341         if( !pCSttNd )
3342         {
3343             // damit die Indizies der anderen Redlines nicht mitverschoben
3344             // werden, diese aufs Ende setzen (ist exclusive).
3345             const SwRedlineTbl& rTbl = pDoc->GetRedlineTbl();
3346             for( sal_uInt16 n = 0; n < rTbl.Count(); ++n )
3347             {
3348                 SwRedline* pRedl = rTbl[ n ];
3349                 if( pRedl->GetBound(sal_True) == *pStt )
3350                     pRedl->GetBound(sal_True) = *pEnd;
3351                 if( pRedl->GetBound(sal_False) == *pStt )
3352                     pRedl->GetBound(sal_False) = *pEnd;
3353             }
3354         }
3355 
3356         SwStartNode* pSttNd;
3357         SwNodes& rNds = pDoc->GetNodes();
3358         if( pCSttNd || pCEndNd )
3359         {
3360             SwTxtFmtColl* pColl = (pCSttNd && pCSttNd->IsTxtNode() )
3361                                     ? ((SwTxtNode*)pCSttNd)->GetTxtColl()
3362                                     : (pCEndNd && pCEndNd->IsTxtNode() )
3363                                         ? ((SwTxtNode*)pCEndNd)->GetTxtColl()
3364                                         : pDoc->GetTxtCollFromPool(
3365                                                 RES_POOLCOLL_STANDARD );
3366 
3367             pSttNd = rNds.MakeTextSection( SwNodeIndex( rNds.GetEndOfRedlines() ),
3368                                             SwNormalStartNode, pColl );
3369             SwTxtNode* pTxtNd = rNds[ pSttNd->GetIndex() + 1 ]->GetTxtNode();
3370 
3371             SwNodeIndex aNdIdx( *pTxtNd );
3372             SwPosition aPos( aNdIdx, SwIndex( pTxtNd ));
3373             if( pCSttNd && pCEndNd )
3374                 pDoc->MoveAndJoin( aPam, aPos, IDocumentContentOperations::DOC_MOVEDEFAULT );
3375             else
3376             {
3377                 if( pCSttNd && !pCEndNd )
3378                     bDelLastPara = sal_True;
3379                 pDoc->MoveRange( aPam, aPos,
3380                     IDocumentContentOperations::DOC_MOVEDEFAULT );
3381             }
3382         }
3383         else
3384         {
3385             pSttNd = rNds.MakeEmptySection( SwNodeIndex( rNds.GetEndOfRedlines() ),
3386                                             SwNormalStartNode );
3387 
3388             SwPosition aPos( *pSttNd->EndOfSectionNode() );
3389             pDoc->MoveRange( aPam, aPos,
3390                 IDocumentContentOperations::DOC_MOVEDEFAULT );
3391         }
3392         pCntntSect = new SwNodeIndex( *pSttNd );
3393 
3394         if( pStt == GetPoint() )
3395             Exchange();
3396 
3397         DeleteMark();
3398     }
3399     else
3400         InvalidateRange();
3401 }
3402 
3403 void SwRedline::CopyToSection()
3404 {
3405     if( !pCntntSect )
3406     {
3407         const SwPosition* pStt = Start(),
3408                         * pEnd = pStt == GetPoint() ? GetMark() : GetPoint();
3409 
3410         SwCntntNode* pCSttNd = pStt->nNode.GetNode().GetCntntNode();
3411         SwCntntNode* pCEndNd = pEnd->nNode.GetNode().GetCntntNode();
3412 
3413         SwStartNode* pSttNd;
3414         SwDoc* pDoc = GetDoc();
3415         SwNodes& rNds = pDoc->GetNodes();
3416 
3417         sal_Bool bSaveCopyFlag = pDoc->IsCopyIsMove(),
3418              bSaveRdlMoveFlg = pDoc->IsRedlineMove();
3419         pDoc->SetCopyIsMove( sal_True );
3420 
3421         // #100619# The IsRedlineMove() flag causes the behaviour of the
3422         // SwDoc::_CopyFlyInFly method to change, which will eventually be
3423         // called by the pDoc->Copy line below (through SwDoc::_Copy,
3424         // SwDoc::CopyWithFlyInFly). This rather obscure bugfix was introduced
3425         // for #63198# and #64896#, and apparently never really worked.
3426         pDoc->SetRedlineMove( pStt->nContent == 0 );
3427 
3428         if( pCSttNd )
3429         {
3430             SwTxtFmtColl* pColl = (pCSttNd && pCSttNd->IsTxtNode() )
3431                                     ? ((SwTxtNode*)pCSttNd)->GetTxtColl()
3432                                     : pDoc->GetTxtCollFromPool(
3433                                                 RES_POOLCOLL_STANDARD );
3434 
3435             pSttNd = rNds.MakeTextSection( SwNodeIndex( rNds.GetEndOfRedlines() ),
3436                                             SwNormalStartNode, pColl );
3437 
3438             SwNodeIndex aNdIdx( *pSttNd, 1 );
3439             SwTxtNode* pTxtNd = aNdIdx.GetNode().GetTxtNode();
3440             SwPosition aPos( aNdIdx, SwIndex( pTxtNd ));
3441             pDoc->CopyRange( *this, aPos, false );
3442 
3443             // JP 08.10.98: die Vorlage vom EndNode ggfs. mit uebernehmen
3444             //              - ist im Doc::Copy nicht erwuenscht
3445             if( pCEndNd && pCEndNd != pCSttNd )
3446             {
3447                 SwCntntNode* pDestNd = aPos.nNode.GetNode().GetCntntNode();
3448                 if( pDestNd )
3449                 {
3450                     if( pDestNd->IsTxtNode() && pCEndNd->IsTxtNode() )
3451                         ((SwTxtNode*)pCEndNd)->CopyCollFmt(
3452                                             *(SwTxtNode*)pDestNd );
3453                     else
3454                         pDestNd->ChgFmtColl( pCEndNd->GetFmtColl() );
3455                 }
3456             }
3457         }
3458         else
3459         {
3460             pSttNd = rNds.MakeEmptySection( SwNodeIndex( rNds.GetEndOfRedlines() ),
3461                                             SwNormalStartNode );
3462 
3463             if( pCEndNd )
3464             {
3465                 SwPosition aPos( *pSttNd->EndOfSectionNode() );
3466                 pDoc->CopyRange( *this, aPos, false );
3467             }
3468             else
3469             {
3470                 SwNodeIndex aInsPos( *pSttNd->EndOfSectionNode() );
3471                 SwNodeRange aRg( pStt->nNode, 0, pEnd->nNode, 1 );
3472                 pDoc->CopyWithFlyInFly( aRg, 0, aInsPos );
3473             }
3474         }
3475         pCntntSect = new SwNodeIndex( *pSttNd );
3476 
3477         pDoc->SetCopyIsMove( bSaveCopyFlag );
3478         pDoc->SetRedlineMove( bSaveRdlMoveFlg );
3479     }
3480 }
3481 
3482 void SwRedline::DelCopyOfSection()
3483 {
3484     if( pCntntSect )
3485     {
3486         const SwPosition* pStt = Start(),
3487                         * pEnd = pStt == GetPoint() ? GetMark() : GetPoint();
3488 
3489         SwDoc* pDoc = GetDoc();
3490         SwPaM aPam( *pStt, *pEnd );
3491         SwCntntNode* pCSttNd = pStt->nNode.GetNode().GetCntntNode();
3492         SwCntntNode* pCEndNd = pEnd->nNode.GetNode().GetCntntNode();
3493 
3494         if( !pCSttNd )
3495         {
3496             // damit die Indizies der anderen Redlines nicht mitverschoben
3497             // werden, diese aufs Ende setzen (ist exclusive).
3498             const SwRedlineTbl& rTbl = pDoc->GetRedlineTbl();
3499             for( sal_uInt16 n = 0; n < rTbl.Count(); ++n )
3500             {
3501                 SwRedline* pRedl = rTbl[ n ];
3502                 if( pRedl->GetBound(sal_True) == *pStt )
3503                     pRedl->GetBound(sal_True) = *pEnd;
3504                 if( pRedl->GetBound(sal_False) == *pStt )
3505                     pRedl->GetBound(sal_False) = *pEnd;
3506             }
3507         }
3508 
3509         if( pCSttNd && pCEndNd )
3510         {
3511             // --> OD 2009-08-20 #i100466#
3512             // force a <join next> on <delete and join> operation
3513             pDoc->DeleteAndJoin( aPam, true );
3514             // <--
3515         }
3516         else if( pCSttNd || pCEndNd )
3517         {
3518             if( pCSttNd && !pCEndNd )
3519                 bDelLastPara = sal_True;
3520             pDoc->DeleteRange( aPam );
3521 
3522             if( bDelLastPara )
3523             {
3524                 // #100611# To prevent dangling references to the paragraph to
3525                 // be deleted, redline that point into this paragraph should be
3526                 // moved to the new end position. Since redlines in the redline
3527                 // table are sorted and the pEnd position is an endnode (see
3528                 // bDelLastPara condition above), only redlines before the
3529                 // current ones can be affected.
3530                 const SwRedlineTbl& rTbl = pDoc->GetRedlineTbl();
3531                 sal_uInt16 n = rTbl.GetPos( this );
3532                 ASSERT( n != USHRT_MAX, "How strange. We don't exist!" );
3533                 for( sal_Bool bBreak = sal_False; !bBreak && n > 0; )
3534                 {
3535                     --n;
3536                     bBreak = sal_True;
3537                     if( rTbl[ n ]->GetBound(sal_True) == *aPam.GetPoint() )
3538                     {
3539                         rTbl[ n ]->GetBound(sal_True) = *pEnd;
3540                         bBreak = sal_False;
3541                     }
3542                     if( rTbl[ n ]->GetBound(sal_False) == *aPam.GetPoint() )
3543                     {
3544                         rTbl[ n ]->GetBound(sal_False) = *pEnd;
3545                         bBreak = sal_False;
3546                     }
3547                 }
3548 
3549                 SwPosition aEnd( *pEnd );
3550                 *GetPoint() = *pEnd;
3551                 *GetMark() = *pEnd;
3552                 DeleteMark();
3553 
3554                 aPam.GetBound( sal_True ).nContent.Assign( 0, 0 );
3555                 aPam.GetBound( sal_False ).nContent.Assign( 0, 0 );
3556                 aPam.DeleteMark();
3557                 pDoc->DelFullPara( aPam );
3558             }
3559         }
3560         else
3561         {
3562             pDoc->DeleteRange( aPam );
3563         }
3564 
3565         if( pStt == GetPoint() )
3566             Exchange();
3567 
3568         DeleteMark();
3569     }
3570 }
3571 
3572 void SwRedline::MoveFromSection()
3573 {
3574     if( pCntntSect )
3575     {
3576         SwDoc* pDoc = GetDoc();
3577         const SwRedlineTbl& rTbl = pDoc->GetRedlineTbl();
3578         SvPtrarr aBeforeArr( 16, 16 ), aBehindArr( 16, 16 );
3579         sal_uInt16 nMyPos = rTbl.GetPos( this );
3580         ASSERT( this, "this nicht im Array?" );
3581         sal_Bool bBreak = sal_False;
3582         sal_uInt16 n;
3583 
3584         for( n = nMyPos+1; !bBreak && n < rTbl.Count(); ++n )
3585         {
3586             bBreak = sal_True;
3587             if( rTbl[ n ]->GetBound(sal_True) == *GetPoint() )
3588             {
3589                 void* pTmp = &rTbl[ n ]->GetBound(sal_True);
3590                 aBehindArr.Insert( pTmp, aBehindArr.Count());
3591                 bBreak = sal_False;
3592             }
3593             if( rTbl[ n ]->GetBound(sal_False) == *GetPoint() )
3594             {
3595                 void* pTmp = &rTbl[ n ]->GetBound(sal_False);
3596                 aBehindArr.Insert( pTmp, aBehindArr.Count() );
3597                 bBreak = sal_False;
3598             }
3599         }
3600         for( bBreak = sal_False, n = nMyPos; !bBreak && n ; )
3601         {
3602             --n;
3603             bBreak = sal_True;
3604             if( rTbl[ n ]->GetBound(sal_True) == *GetPoint() )
3605             {
3606                 void* pTmp = &rTbl[ n ]->GetBound(sal_True);
3607                 aBeforeArr.Insert( pTmp, aBeforeArr.Count() );
3608                 bBreak = sal_False;
3609             }
3610             if( rTbl[ n ]->GetBound(sal_False) == *GetPoint() )
3611             {
3612                 void* pTmp = &rTbl[ n ]->GetBound(sal_False);
3613                 aBeforeArr.Insert( pTmp, aBeforeArr.Count() );
3614                 bBreak = sal_False;
3615             }
3616         }
3617 
3618         // --> OD 2009-03-17 #i95711#
3619         const SwNode* pKeptCntntSectNode( &pCntntSect->GetNode() );
3620         // <--
3621         {
3622             SwPaM aPam( pCntntSect->GetNode(),
3623                         *pCntntSect->GetNode().EndOfSectionNode(), 1,
3624                         ( bDelLastPara ? -2 : -1 ) );
3625             SwCntntNode* pCNd = aPam.GetCntntNode();
3626             if( pCNd )
3627                 aPam.GetPoint()->nContent.Assign( pCNd, pCNd->Len() );
3628             else
3629                 aPam.GetPoint()->nNode++;
3630 
3631             SwFmtColl* pColl = pCNd && pCNd->Len() && aPam.GetPoint()->nNode !=
3632                                         aPam.GetMark()->nNode
3633                                 ? pCNd->GetFmtColl() : 0;
3634 
3635             SwNodeIndex aNdIdx( GetPoint()->nNode, -1 );
3636             sal_uInt16 nPos = GetPoint()->nContent.GetIndex();
3637 
3638             SwPosition aPos( *GetPoint() );
3639             if( bDelLastPara && *aPam.GetPoint() == *aPam.GetMark() )
3640             {
3641                 aPos.nNode--;
3642 
3643                 pDoc->AppendTxtNode( aPos );
3644             }
3645             else
3646             {
3647                 pDoc->MoveRange( aPam, aPos,
3648                     IDocumentContentOperations::DOC_MOVEALLFLYS );
3649             }
3650 
3651             SetMark();
3652             *GetPoint() = aPos;
3653             GetMark()->nNode = aNdIdx.GetIndex() + 1;
3654             pCNd = GetMark()->nNode.GetNode().GetCntntNode();
3655             GetMark()->nContent.Assign( pCNd, nPos );
3656 
3657             if( bDelLastPara )
3658             {
3659                 GetPoint()->nNode++;
3660                 GetPoint()->nContent.Assign( pCNd = GetCntntNode(), 0 );
3661                 bDelLastPara = sal_False;
3662             }
3663             else if( pColl )
3664                 pCNd = GetCntntNode();
3665 
3666             if( pColl && pCNd )
3667                 pCNd->ChgFmtColl( pColl );
3668         }
3669         // --> OD 2009-03-17 #i95771#
3670         // Under certain conditions the previous <SwDoc::Move(..)> has already
3671         // remove the change tracking section of this <SwRedline> instance from
3672         // the change tracking nodes area.
3673         // Thus, check, if <pCntntSect> still points to the change tracking section
3674         // by comparing it with the "indexed" <SwNode> instance copied before
3675         // perform the intrinsic move.
3676         // Note: Such condition is e.g. a "delete" change tracking only containing a table.
3677         if ( &pCntntSect->GetNode() == pKeptCntntSectNode )
3678         {
3679             pDoc->DeleteSection( &pCntntSect->GetNode() );
3680         }
3681         // <--
3682         delete pCntntSect, pCntntSect = 0;
3683 
3684         // #100611# adjustment of redline table positions must take start and
3685         // end into account, not point and mark.
3686         for( n = 0; n < aBeforeArr.Count(); ++n )
3687             *(SwPosition*)aBeforeArr[ n ] = *Start();
3688         for( n = 0; n < aBehindArr.Count(); ++n )
3689             *(SwPosition*)aBehindArr[ n ] = *End();
3690     }
3691     else
3692         InvalidateRange();
3693 }
3694 
3695 // fuers Undo
3696 void SwRedline::SetContentIdx( const SwNodeIndex* pIdx )
3697 {
3698     if( pIdx && !pCntntSect )
3699     {
3700         pCntntSect = new SwNodeIndex( *pIdx );
3701         bIsVisible = sal_False;
3702     }
3703     else if( !pIdx && pCntntSect )
3704     {
3705         delete pCntntSect, pCntntSect = 0;
3706         bIsVisible = sal_False;
3707     }
3708 #ifdef DBG_UTIL
3709     else
3710         ASSERT( !this, "das ist keine gueltige Operation" );
3711 #endif
3712 }
3713 
3714 sal_Bool SwRedline::CanCombine( const SwRedline& rRedl ) const
3715 {
3716     return  IsVisible() && rRedl.IsVisible() &&
3717             pRedlineData->CanCombine( *rRedl.pRedlineData );
3718 }
3719 
3720 void SwRedline::PushData( const SwRedline& rRedl, sal_Bool bOwnAsNext )
3721 {
3722 //  SwRedlineData* pNew = new SwRedlineData( rRedl.GetType(),
3723 //                                           rRedl.GetAuthor() );
3724     SwRedlineData* pNew = new SwRedlineData( *rRedl.pRedlineData, sal_False );
3725     if( bOwnAsNext )
3726     {
3727         pNew->pNext = pRedlineData;
3728         pRedlineData = pNew;
3729     }
3730     else
3731     {
3732         pNew->pNext = pRedlineData->pNext;
3733         pRedlineData->pNext = pNew;
3734     }
3735 }
3736 
3737 sal_Bool SwRedline::PopData()
3738 {
3739     if( !pRedlineData->pNext )
3740         return sal_False;
3741     SwRedlineData* pCur = pRedlineData;
3742     pRedlineData = pCur->pNext;
3743     pCur->pNext = 0;
3744     delete pCur;
3745     return sal_True;
3746 }
3747 
3748 sal_uInt16 SwRedline::GetStackCount() const
3749 {
3750     sal_uInt16 nRet = 1;
3751     for( SwRedlineData* pCur = pRedlineData; pCur->pNext; ++nRet )
3752         pCur = pCur->pNext;
3753     return nRet;
3754 }
3755 
3756 // -> #111827#
3757 sal_uInt16 SwRedline::GetAuthor( sal_uInt16 nPos ) const
3758 {
3759     return GetRedlineData(nPos).nAuthor;
3760 }
3761 
3762 const String& SwRedline::GetAuthorString( sal_uInt16 nPos ) const
3763 {
3764     return SW_MOD()->GetRedlineAuthor(GetRedlineData(nPos).nAuthor);
3765 }
3766 
3767 const DateTime& SwRedline::GetTimeStamp( sal_uInt16 nPos ) const
3768 {
3769     return GetRedlineData(nPos).aStamp;
3770 }
3771 
3772 RedlineType_t SwRedline::GetRealType( sal_uInt16 nPos ) const
3773 {
3774     return GetRedlineData(nPos).eType;
3775 }
3776 
3777 const String& SwRedline::GetComment( sal_uInt16 nPos ) const
3778 {
3779     return GetRedlineData(nPos).sComment;
3780 }
3781 // <- #111827#
3782 
3783 int SwRedline::operator==( const SwRedline& rCmp ) const
3784 {
3785     return this == &rCmp;
3786 }
3787 
3788 int SwRedline::operator<( const SwRedline& rCmp ) const
3789 {
3790     sal_Bool nResult = sal_False;
3791 
3792     if (*Start() < *rCmp.Start())
3793         nResult = sal_True;
3794     else if (*Start() == *rCmp.Start())
3795         if (*End() < *rCmp.End())
3796             nResult = sal_True;
3797 
3798     return nResult;
3799 }
3800 
3801 // -> #111827#
3802 const SwRedlineData & SwRedline::GetRedlineData(sal_uInt16 nPos) const
3803 {
3804     SwRedlineData * pCur = pRedlineData;
3805 
3806     while (nPos > 0 && NULL != pCur->pNext)
3807     {
3808         pCur = pCur->pNext;
3809 
3810         nPos--;
3811     }
3812 
3813     ASSERT( 0 == nPos, "Pos angabe ist zu gross" );
3814 
3815     return *pCur;
3816 }
3817 
3818 String SwRedline::GetDescr(sal_uInt16 nPos)
3819 {
3820     String aResult;
3821 
3822     // get description of redline data (e.g.: "insert $1")
3823     aResult = GetRedlineData(nPos).GetDescr();
3824 
3825     SwPaM * pPaM = NULL;
3826     bool bDeletePaM = false;
3827 
3828     // if this redline is visible the content is in this PaM
3829     if (NULL == pCntntSect)
3830     {
3831         pPaM = this;
3832     }
3833     else // otherwise it is saved in pCntntSect
3834     {
3835         SwNodeIndex aTmpIdx( *pCntntSect->GetNode().EndOfSectionNode() );
3836         pPaM = new SwPaM(*pCntntSect, aTmpIdx );
3837         bDeletePaM = true;
3838     }
3839 
3840     // replace $1 in description by description of the redlines text
3841     String aTmpStr;
3842     aTmpStr += String(SW_RES(STR_START_QUOTE));
3843     aTmpStr += ShortenString(pPaM->GetTxt(), nUndoStringLength,
3844                              String(SW_RES(STR_LDOTS)));
3845     aTmpStr += String(SW_RES(STR_END_QUOTE));
3846 
3847     SwRewriter aRewriter;
3848     aRewriter.AddRule(UNDO_ARG1, aTmpStr);
3849 
3850     aResult = aRewriter.Apply(aResult);
3851 
3852     if (bDeletePaM)
3853         delete pPaM;
3854 
3855     return aResult;
3856 }
3857 // <- #111827#
3858 
3859 
3860 bool SwDoc::IsInRedlines(const SwNode & rNode) const
3861 {
3862     SwPosition aPos(rNode);
3863     SwNode & rEndOfRedlines = GetNodes().GetEndOfRedlines();
3864     SwPaM aPam(SwPosition(*rEndOfRedlines.StartOfSectionNode()),
3865                SwPosition(rEndOfRedlines));
3866 
3867     return aPam.ContainsPosition(aPos) ? true : false;
3868 }
3869