/**************************************************************
 * 
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 * 
 *   http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 * 
 *************************************************************/



// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_sw.hxx"


#include <hintids.hxx>
#include <tools/shl.hxx>
#include <svl/itemiter.hxx>
#include <sfx2/app.hxx>
#include <editeng/colritem.hxx>
#include <editeng/udlnitem.hxx>
#include <editeng/crsditem.hxx>
#include <swmodule.hxx>
#include <doc.hxx>
#include <IDocumentUndoRedo.hxx>
#include <docary.hxx>
#include <ndtxt.hxx>
#include <redline.hxx>
#include <swundo.hxx>
#include <UndoCore.hxx>
#include <UndoRedline.hxx>
#include <hints.hxx>
#include <pamtyp.hxx>
#include <poolfmt.hxx>
#include <viewsh.hxx>
#include <rootfrm.hxx>

#include <comcore.hrc>

using namespace com::sun::star;

TYPEINIT1(SwRedlineHint, SfxHint);

#ifndef DBG_UTIL

	#define _CHECK_REDLINE( pDoc )
    #define _DEBUG_REDLINE( pDoc )

#else

#define _ERROR_PREFIX "redline table corrupted: "

    // helper function for lcl_CheckRedline
    // 1. make sure that pPos->nContent points into pPos->nNode
    //    (or into the 'special' no-content-node-IndexReg)
    // 2. check that position is valid and doesn't point behind text
    void lcl_CheckPosition( const SwPosition* pPos )
    {
        SwPosition aComparePos( *pPos );
        aComparePos.nContent.Assign(
            aComparePos.nNode.GetNode().GetCntntNode(), 0 );
        DBG_ASSERT( pPos->nContent.GetIdxReg() ==
                    aComparePos.nContent.GetIdxReg(),
                    _ERROR_PREFIX "illegal position" );

        SwTxtNode* pTxtNode = pPos->nNode.GetNode().GetTxtNode();
        if( pTxtNode == NULL )
        {
            DBG_ASSERT( pPos->nContent == 0,
                        _ERROR_PREFIX "non-text-node with content" );
        }
        else
        {
            DBG_ASSERT( pPos->nContent >= 0  &&
                        pPos->nContent <= pTxtNode->Len(),
                        _ERROR_PREFIX "index behind text" );
        }
    }

    void lcl_CheckPam( const SwPaM* pPam )
    {
        DBG_ASSERT( pPam != NULL, _ERROR_PREFIX "illegal argument" );
        lcl_CheckPosition( pPam->GetPoint() );
        lcl_CheckPosition( pPam->GetMark() );
    }

    // check validity of the redline table. Checks redline bounds, and make
    // sure the redlines are sorted and non-overlapping.
	void lcl_CheckRedline( const SwDoc* pDoc )
	{
		const SwRedlineTbl& rTbl = pDoc->GetRedlineTbl();

        // verify valid redline positions
		for( sal_uInt16 i = 0; i < rTbl.Count(); ++i )
            lcl_CheckPam( rTbl[ i ] );

        for( sal_uInt16 j = 0; j < rTbl.Count(); ++j )
        {
            // check for empty redlines
            DBG_ASSERT( ( *(rTbl[j]->GetPoint()) != *(rTbl[j]->GetMark()) ) ||
                        ( rTbl[j]->GetContentIdx() != NULL ),
                        _ERROR_PREFIX "empty redline" );
 		}

        // verify proper redline sorting
		for( sal_uInt16 n = 1; n < rTbl.Count(); ++n )
		{
			const SwRedline* pPrev = rTbl[ n-1 ];
            const SwRedline* pCurrent = rTbl[ n ];

            // check redline sorting
            DBG_ASSERT( *pPrev->Start() <= *pCurrent->Start(),
                        _ERROR_PREFIX "not sorted correctly" );

            // check for overlapping redlines
            DBG_ASSERT( *pPrev->End() <= *pCurrent->Start(),
                        _ERROR_PREFIX "overlapping redlines" );
		}
	}

	#define _CHECK_REDLINE( pDoc ) lcl_CheckRedline( pDoc );

	void lcl_DebugRedline( const SwDoc* pDoc )
	{
        static sal_uInt16 nWatch = 0;
		const SwRedlineTbl& rTbl = pDoc->GetRedlineTbl();
		for( sal_uInt16 n = 0; n < rTbl.Count(); ++n )
		{
            sal_uInt16 nDummy = 0;
            const SwRedline* pCurrent = rTbl[ n ];
            const SwRedline* pNext = n+1 < rTbl.Count() ? rTbl[ n+1 ] : 0;
            if( pCurrent == pNext )
                ++nDummy;
            if( n == nWatch )
                ++nDummy; // Possible debugger breakpoint
		}
    }

	#define _DEBUG_REDLINE( pDoc ) lcl_DebugRedline( pDoc );

#endif

SV_IMPL_OP_PTRARR_SORT( _SwRedlineTbl, SwRedlinePtr )

RedlineMode_t SwDoc::GetRedlineMode() const
{
    return eRedlineMode;
}

void SwDoc::SetRedlineMode( RedlineMode_t eMode )
{
	if( eRedlineMode != eMode )
	{
		if( (nsRedlineMode_t::REDLINE_SHOW_MASK & eRedlineMode) != (nsRedlineMode_t::REDLINE_SHOW_MASK & eMode)
			|| 0 == (nsRedlineMode_t::REDLINE_SHOW_MASK & eMode) )
		{
			bool bSaveInXMLImportFlag = IsInXMLImport();
			SetInXMLImport( false );
			// und dann alles verstecken, anzeigen
			void (SwRedline::*pFnc)( sal_uInt16 ) = 0;

			switch( nsRedlineMode_t::REDLINE_SHOW_MASK & eMode )
			{
            case nsRedlineMode_t::REDLINE_SHOW_INSERT | nsRedlineMode_t::REDLINE_SHOW_DELETE :
				pFnc = &SwRedline::Show;
				break;
			case nsRedlineMode_t::REDLINE_SHOW_INSERT:
				pFnc = &SwRedline::Hide;
				break;
			case nsRedlineMode_t::REDLINE_SHOW_DELETE:
				pFnc = &SwRedline::ShowOriginal;
				break;

			default:
				pFnc = &SwRedline::Hide;
				eMode = (RedlineMode_t)(eMode | nsRedlineMode_t::REDLINE_SHOW_INSERT);
				break;
			}

			_CHECK_REDLINE( this )

			if( pFnc )
				for( sal_uInt16 nLoop = 1; nLoop <= 2; ++nLoop )
					for( sal_uInt16 i = 0; i < pRedlineTbl->Count(); ++i )
						((*pRedlineTbl)[ i ]->*pFnc)( nLoop );
			_CHECK_REDLINE( this )
			SetInXMLImport( bSaveInXMLImportFlag );
		}
		eRedlineMode = eMode;
        SetModified();
	}
}

bool SwDoc::IsRedlineOn() const
{
    return IDocumentRedlineAccess::IsRedlineOn(eRedlineMode);
}

bool SwDoc::IsIgnoreRedline() const
{
    return (nsRedlineMode_t::REDLINE_IGNORE & eRedlineMode);
}

void SwDoc::SetRedlineMode_intern(RedlineMode_t eMode)
{
    eRedlineMode = eMode;
}

const SwRedlineTbl& SwDoc::GetRedlineTbl() const
{
    return *pRedlineTbl;
}

bool SwDoc::IsRedlineMove() const
{
    return mbIsRedlineMove;
}

void SwDoc::SetRedlineMove(bool bFlag)
{
    mbIsRedlineMove = bFlag;
}

const uno::Sequence <sal_Int8>& SwDoc::GetRedlinePassword() const
{
    return aRedlinePasswd;
}

inline bool IsPrevPos( const SwPosition rPos1, const SwPosition rPos2 )
{
	const SwCntntNode* pCNd;
	return 0 == rPos2.nContent.GetIndex() &&
			rPos2.nNode.GetIndex() - 1 == rPos1.nNode.GetIndex() &&
			0 != ( pCNd = rPos1.nNode.GetNode().GetCntntNode() )
				? rPos1.nContent.GetIndex() == pCNd->Len()
				: false;
}

#ifdef DEBUG
bool CheckPosition( const SwPosition* pStt, const SwPosition* pEnd )
{
    int nError = 0;
    SwNode* pSttNode = &pStt->nNode.GetNode();
    SwNode* pEndNode = &pEnd->nNode.GetNode();
    SwNode* pSttTab = pSttNode->StartOfSectionNode()->FindTableNode();
    SwNode* pEndTab = pEndNode->StartOfSectionNode()->FindTableNode();
    SwNode* pSttStart = pSttNode;
    while( pSttStart && (!pSttStart->IsStartNode() || pSttStart->IsSectionNode() ||
        pSttStart->IsTableNode() ) )
        pSttStart = pSttStart->StartOfSectionNode();
    SwNode* pEndStart = pEndNode;
    while( pEndStart && (!pEndStart->IsStartNode() || pEndStart->IsSectionNode() ||
        pEndStart->IsTableNode() ) )
        pEndStart = pEndStart->StartOfSectionNode();
    if( pSttTab != pEndTab )
        nError = 1;
    if( !pSttTab && pSttStart != pEndStart )
        nError |= 2;
    if( nError )
        nError += 10;
    return nError != 0;
}
#endif

/*

Text heisst, nicht von Redline "verseuchter" Text.

Verhalten von Insert-Redline:
	- im Text							- Redline Object einfuegen
	- im InsertRedline (eigenes)		- ignorieren, bestehendes wird
										  aufgespannt
	- im InsertRedline (andere)			- Insert Redline aufsplitten
										  Redline Object einfuegen
	- in DeleteRedline					- Delete Redline aufsplitten oder
										  am Ende/Anfang verschieben

Verhalten von Delete-Redline:
	- im Text							- Redline Object einfuegen
	- im DeleteRedline (eigenes/andere)	- ignorieren
	- im InsertRedline (eigenes)		- ignorieren, Zeichen aber loeschen
	- im InsertRedline (andere)			- Insert Redline aufsplitten
										  Redline Object einfuegen
	- Ueberlappung von Text und 		- Text in eigenen Insert loeschen,
	  eigenem Insert					  im andereren Text aufspannen (bis
										  zum Insert!
	- Ueberlappung von Text und 		- Redline Object einfuegen, der
	  anderem Insert                      andere Insert wird vom Delete
										  ueberlappt
*/

bool SwDoc::AppendRedline( SwRedline* pNewRedl, bool bCallDelete )
{
#if 0
// #i93179# disabled: ASSERT in ~SwIndexReg     #ifdef DBG_UTIL 
    SwRedline aCopy( *pNewRedl );
#endif
    bool bError = true;
	_CHECK_REDLINE( this )

	if( IsRedlineOn() && !IsShowOriginal( eRedlineMode ) &&
		 pNewRedl->GetAuthorString().Len() )
	{
		pNewRedl->InvalidateRange();

		if( mbIsAutoFmtRedline )
		{
			pNewRedl->SetAutoFmtFlag();
			if( pAutoFmtRedlnComment && pAutoFmtRedlnComment->Len() )
			{
				pNewRedl->SetComment( *pAutoFmtRedlnComment );
				pNewRedl->SetSeqNo( nAutoFmtRedlnCommentNo );
			}
		}

		SwPosition* pStt = pNewRedl->Start(),
				  * pEnd = pStt == pNewRedl->GetPoint() ? pNewRedl->GetMark()
														: pNewRedl->GetPoint();
        {
            SwTxtNode* pTxtNode = pStt->nNode.GetNode().GetTxtNode();
            if( pTxtNode == NULL )
            {
                if( pStt->nContent > 0 )
                {
                    DBG_ASSERT( false, "Redline start: non-text-node with content" );
                    pStt->nContent = 0;
                }
            }
            else
            {
                if( pStt->nContent > pTxtNode->Len() )
                {
                    DBG_ASSERT( false, "Redline start: index behind text" );
                    pStt->nContent = pTxtNode->Len();
                }
            }
            pTxtNode = pEnd->nNode.GetNode().GetTxtNode();
            if( pTxtNode == NULL )
            {
                if( pEnd->nContent > 0 )
                {
                    DBG_ASSERT( false, "Redline end: non-text-node with content" );
                    pEnd->nContent = 0;
                }
            }
            else
            {
                if( pEnd->nContent > pTxtNode->Len() )
                {
                    DBG_ASSERT( false, "Redline end: index behind text" );
                    pEnd->nContent = pTxtNode->Len();
                }
            }
        }
        if( ( *pStt == *pEnd ) &&
            ( pNewRedl->GetContentIdx() == NULL ) )
        {   // Do not insert empty redlines
            delete pNewRedl;
            return sal_False;
        }
		sal_Bool bCompress = sal_False;
		sal_uInt16 n = 0;
			// zur StartPos das erste Redline suchen
		if( !GetRedline( *pStt, &n ) && n )
			--n;
        bool bDec = false;

		for( ; pNewRedl && n < pRedlineTbl->Count(); bDec ? n : ++n )
		{
            bDec = false;
#ifdef DVO_TEST
			_CHECK_REDLINE( this )
#endif

			SwRedline* pRedl = (*pRedlineTbl)[ n ];
			SwPosition* pRStt = pRedl->Start(),
					  * pREnd = pRStt == pRedl->GetPoint() ? pRedl->GetMark()
														   : pRedl->GetPoint();

            // #i8518# remove empty redlines while we're at it
            if( ( *pRStt == *pREnd ) &&
                ( pRedl->GetContentIdx() == NULL ) )
            {
                pRedlineTbl->DeleteAndDestroy(n);
                continue;
            }

			SwComparePosition eCmpPos = ComparePosition( *pStt, *pEnd, *pRStt, *pREnd );

			switch( pNewRedl->GetType() )
			{
            case nsRedlineType_t::REDLINE_INSERT:
				switch( pRedl->GetType() )
				{
                case nsRedlineType_t::REDLINE_INSERT:
					if( pRedl->IsOwnRedline( *pNewRedl ) )
					{
						bool bDelete = false;

						// ggfs. verschmelzen?
						if( (( POS_BEHIND == eCmpPos &&
                               IsPrevPos( *pREnd, *pStt ) ) ||
							 ( POS_COLLIDE_START == eCmpPos ) ||
                             ( POS_OVERLAP_BEHIND == eCmpPos ) ) &&
							pRedl->CanCombine( *pNewRedl ) &&
							( n+1 >= pRedlineTbl->Count() ||
                             ( *(*pRedlineTbl)[ n+1 ]->Start() >= *pEnd &&
							 *(*pRedlineTbl)[ n+1 ]->Start() != *pREnd ) ) )
						{
							pRedl->SetEnd( *pEnd, pREnd );
							if( !pRedl->HasValidRange() )
							{
								// neu einsortieren
								pRedlineTbl->Remove( n );
								pRedlineTbl->Insert( pRedl );
							}

                            bError = false;
							bDelete = true;
						}
						else if( (( POS_BEFORE == eCmpPos &&
									IsPrevPos( *pEnd, *pRStt ) ) ||
							 	  ( POS_COLLIDE_END == eCmpPos ) ||
                                  ( POS_OVERLAP_BEFORE == eCmpPos ) ) &&
							pRedl->CanCombine( *pNewRedl ) &&
							( !n ||
							 *(*pRedlineTbl)[ n-1 ]->End() != *pRStt ))
						{
							pRedl->SetStart( *pStt, pRStt );
							// neu einsortieren
							pRedlineTbl->Remove( n );
							pRedlineTbl->Insert( pRedl );

                            bError = false;
							bDelete = true;
						}
						else if ( POS_OUTSIDE == eCmpPos )
						{
							// #107164# own insert-over-insert
							// redlines: just scrap the inside ones
							pRedlineTbl->Remove( n );
							bDec = true;
						}
						// <- #107164#
						else if( POS_OVERLAP_BEHIND == eCmpPos )
						{
							*pStt = *pREnd;
                            if( ( *pStt == *pEnd ) &&
                                ( pNewRedl->GetContentIdx() == NULL ) )
                                bDelete = true;
                        }
						else if( POS_OVERLAP_BEFORE == eCmpPos )
						{
							*pEnd = *pRStt;
                            if( ( *pStt == *pEnd ) &&
                                ( pNewRedl->GetContentIdx() == NULL ) )
                                bDelete = true;
						}
						else if( POS_INSIDE == eCmpPos || POS_EQUAL == eCmpPos)
							bDelete = true;

						if( bDelete )
						{
							delete pNewRedl, pNewRedl = 0;
							bCompress = sal_True;
						}
					}
					else if( POS_INSIDE == eCmpPos )
					{
						// aufsplitten
						if( *pEnd != *pREnd )
						{
							SwRedline* pCpy = new SwRedline( *pRedl );
							pCpy->SetStart( *pEnd );
							pRedlineTbl->Insert( pCpy );
						}
						pRedl->SetEnd( *pStt, pREnd );
                        if( ( *pStt == *pRStt ) &&
                            ( pRedl->GetContentIdx() == NULL ) )
                        {
							pRedlineTbl->DeleteAndDestroy( n );
                            bDec = true;
                        }
						else if( !pRedl->HasValidRange() )
						{
							// neu einsortieren
							pRedlineTbl->Remove( n );
							pRedlineTbl->Insert( pRedl );
						}
					}
                    else if ( POS_OUTSIDE == eCmpPos )
                    {
                        // #102366# handle overlapping redlines in broken
                        // documents

                        // split up the new redline, since it covers the
                        // existing redline. Insert the first part, and
                        // progress with the remainder as usual
                        SwRedline* pSplit = new SwRedline( *pNewRedl );
                        pSplit->SetEnd( *pRStt );
                        pNewRedl->SetStart( *pREnd );
                        pRedlineTbl->Insert( pSplit );
                        if( *pStt == *pEnd && pNewRedl->GetContentIdx() == NULL )
                        {
                            delete pNewRedl;
                            pNewRedl = 0;
                            bCompress = true;
                        }
                    }
                    else if ( POS_OVERLAP_BEHIND == eCmpPos )
                    {
                        // #107164# handle overlapping redlines in broken
                        // documents
                        pNewRedl->SetStart( *pREnd );
                    }
                    else if ( POS_OVERLAP_BEFORE == eCmpPos )
                    {
                        // #107164# handle overlapping redlines in broken
                        // documents
                        *pEnd = *pRStt;
                        if( ( *pStt == *pEnd ) &&
                            ( pNewRedl->GetContentIdx() == NULL ) )
                        {
                            delete pNewRedl;
                            pNewRedl = 0;
                            bCompress = true;
                        }
                    }
					break;
                case nsRedlineType_t::REDLINE_DELETE:
					if( POS_INSIDE == eCmpPos )
					{
						// aufsplitten
						if( *pEnd != *pREnd )
						{
							SwRedline* pCpy = new SwRedline( *pRedl );
							pCpy->SetStart( *pEnd );
							pRedlineTbl->Insert( pCpy );
						}
						pRedl->SetEnd( *pStt, pREnd );
                        if( ( *pStt == *pRStt ) &&
                            ( pRedl->GetContentIdx() == NULL ) )
                        {
							pRedlineTbl->DeleteAndDestroy( n );
                            bDec = true;
                        }
						else if( !pRedl->HasValidRange() )
						{
							// neu einsortieren
							pRedlineTbl->Remove( n );
							pRedlineTbl->Insert( pRedl, n );
						}
					}
                    else if ( POS_OUTSIDE == eCmpPos )
                    {
                        // #102366# handle overlapping redlines in broken
                        // documents

                        // split up the new redline, since it covers the
                        // existing redline. Insert the first part, and
                        // progress with the remainder as usual
                        SwRedline* pSplit = new SwRedline( *pNewRedl );
                        pSplit->SetEnd( *pRStt );
                        pNewRedl->SetStart( *pREnd );
                        pRedlineTbl->Insert( pSplit );
                        if( *pStt == *pEnd && pNewRedl->GetContentIdx() == NULL )
                        {
                            delete pNewRedl;
                            pNewRedl = 0;
                            bCompress = true;
                        }
                    }
                    else if ( POS_EQUAL == eCmpPos )
                    {
                        // #112895# handle identical redlines in broken
                        // documents - delete old (delete) redline
                        pRedlineTbl->DeleteAndDestroy( n );
                        bDec = true;
                    }
                    else if ( POS_OVERLAP_BEHIND == eCmpPos )
                    {   // Another workaround for broken redlines (#107164#)
                        pNewRedl->SetStart( *pREnd );
                    }
					break;
                case nsRedlineType_t::REDLINE_FORMAT:
					switch( eCmpPos )
					{
					case POS_OVERLAP_BEFORE:
						pRedl->SetStart( *pEnd, pRStt );
						// neu einsortieren
						pRedlineTbl->Remove( n );
						pRedlineTbl->Insert( pRedl, n );
                        bDec = true;
						break;

					case POS_OVERLAP_BEHIND:
						pRedl->SetEnd( *pStt, pREnd );
                        if( *pStt == *pRStt && pRedl->GetContentIdx() == NULL )
                        {
                            pRedlineTbl->DeleteAndDestroy( n );
                            bDec = true;
                        }
						break;

					case POS_EQUAL:
					case POS_OUTSIDE:
						// ueberlappt den akt. komplett oder hat gleiche
						// Ausdehung, dann muss der alte geloescht werden
						pRedlineTbl->DeleteAndDestroy( n );
                        bDec = true;
						break;

					case POS_INSIDE:
						// ueberlappt den akt. komplett, dann muss
						// der neue gesplittet oder verkuertzt werden
						if( *pEnd != *pREnd )
						{
                            if( *pEnd != *pRStt )
                            {
                                SwRedline* pNew = new SwRedline( *pRedl );
                                pNew->SetStart( *pEnd );
                                pRedl->SetEnd( *pStt, pREnd );
                                if( *pStt == *pRStt && pRedl->GetContentIdx() == NULL )
                                    pRedlineTbl->DeleteAndDestroy( n );
                                AppendRedline( pNew, bCallDelete );
                                n = 0;		// neu Aufsetzen
                                bDec = true;
                            }
						}
						else
							pRedl->SetEnd( *pStt, pREnd );
						break;
					default:
						break;
					}
					break;
				default:
					break;
				}
				break;

            case nsRedlineType_t::REDLINE_DELETE:
				switch( pRedl->GetType() )
				{
                case nsRedlineType_t::REDLINE_DELETE:
					switch( eCmpPos )
					{
					case POS_OUTSIDE:
						{
							// ueberlappt den akt. komplett
							// dann muss der neue gesplittet werden
							if( *pEnd != *pREnd )
							{
								SwRedline* pNew = new SwRedline( *pNewRedl );
								pNew->SetStart( *pREnd );
								pNewRedl->SetEnd( *pRStt, pEnd );
								AppendRedline( pNew, bCallDelete );
								n = 0;		// neu Aufsetzen
                                bDec = true;
							}
							else
								pNewRedl->SetEnd( *pRStt, pEnd );
						}
						break;

					case POS_INSIDE:
					case POS_EQUAL:
						delete pNewRedl, pNewRedl = 0;
						bCompress = sal_True;
						break;

					case POS_OVERLAP_BEFORE:
					case POS_OVERLAP_BEHIND:
						if( pRedl->IsOwnRedline( *pNewRedl ) &&
//							1 == pRedl->GetStackCount() &&
							pRedl->CanCombine( *pNewRedl ))
						{
							// dann kann das zusammengefasst werden, sprich
							// der neue deckt das schon ab.
							if( POS_OVERLAP_BEHIND == eCmpPos )
								pNewRedl->SetStart( *pRStt, pStt );
							else
								pNewRedl->SetEnd( *pREnd, pEnd );
							pRedlineTbl->DeleteAndDestroy( n );
                            bDec = true;
						}
						else if( POS_OVERLAP_BEHIND == eCmpPos )
							pNewRedl->SetStart( *pREnd, pStt );
						else
							pNewRedl->SetEnd( *pRStt, pEnd );
						break;

					case POS_COLLIDE_START:
					case POS_COLLIDE_END:
						if( pRedl->IsOwnRedline( *pNewRedl ) &&
//							1 == pRedl->GetStackCount() &&
							pRedl->CanCombine( *pNewRedl ) )
						{
							if( IsHideChanges( eRedlineMode ))
							{
								// dann erstmal sichtbar machen, bevor
								// die zusammengefasst werden koennen!
								// Damit pNew auch beim Verschieben der
								// Indizies behandelt wird, erstmal
								// temporaer einfuegen
								pRedlineTbl->SavePtrInArr( pNewRedl );
								pRedl->Show();
								pRedlineTbl->Remove( pRedlineTbl->GetPos(pNewRedl ));
								pRStt = pRedl->Start();
								pREnd = pRedl->End();
							}

							// dann kann das zusammengefasst werden, sprich
							// der neue deckt das schon ab.
							if( POS_COLLIDE_START == eCmpPos )
								pNewRedl->SetStart( *pRStt, pStt );
							else
								pNewRedl->SetEnd( *pREnd, pEnd );

                            // delete current (below), and restart process with
                            // previous
                            sal_uInt16 nToBeDeleted = n;
                            bDec = true;

                            // #107359# Do it again, Sam!
                            // If you can do it for them, you can do it for me.
                            if( *(pNewRedl->Start()) <= *pREnd )
                            {
                                // Whoooah, we just extended the new 'redline'
                                // beyond previous redlines, so better start
                                // again. Of course this is not supposed to
                                // happen, and in an ideal world it doesn't,
                                // but unfortunately this code is buggy and
                                // totally rotten so it does happen and we
                                // better fix it.
                                n = 0;
                                bDec = true;
                            }

                            pRedlineTbl->DeleteAndDestroy( nToBeDeleted );
						}
						break;
					default:
						break;
					}
					break;

                case nsRedlineType_t::REDLINE_INSERT:
                {
                    // b62341295: Do not throw away redlines
                    // even if they are not allowed to be combined
                    RedlineMode_t eOld = eRedlineMode;
                    if( !( eOld & nsRedlineMode_t::REDLINE_DONTCOMBINE_REDLINES ) &&
                        pRedl->IsOwnRedline( *pNewRedl ) )
                    {

// auf NONE setzen, damit das Delete::Redo die RedlineDaten wieder richtig
// zusammen fasst! Der ShowMode muss erhalten bleiben!
              eRedlineMode = (RedlineMode_t)(eOld & ~(nsRedlineMode_t::REDLINE_ON | nsRedlineMode_t::REDLINE_IGNORE));
						switch( eCmpPos )
						{
						case POS_EQUAL:
							bCompress = sal_True;
							pRedlineTbl->DeleteAndDestroy( n );
                            bDec = true;
							// kein break!

						case POS_INSIDE:
							if( bCallDelete )
							{
                              eRedlineMode = (RedlineMode_t)(eRedlineMode | nsRedlineMode_t::REDLINE_IGNOREDELETE_REDLINES);

                                // #98863# DeleteAndJoin does not yield the
                                // desired result if there is no paragraph to
                                // join with, i.e. at the end of the document.
                                // For this case, we completely delete the
                                // paragraphs (if, of course, we also start on
                                // a paragraph boundary).
                                if( (pStt->nContent == 0) &&
                                    pEnd->nNode.GetNode().IsEndNode() )
                                {
                                    pEnd->nNode--;
                                    pEnd->nContent.Assign(
                                        pEnd->nNode.GetNode().GetTxtNode(), 0);
                                    DelFullPara( *pNewRedl );
                                }
                                else
                                    DeleteAndJoin( *pNewRedl );

								bCompress = sal_True;
							}
							delete pNewRedl, pNewRedl = 0;
							break;

						case POS_OUTSIDE:
							{
								pRedlineTbl->Remove( n );
                                bDec = true;
								// damit pNew auch beim Verschieben der Indizies
								// behandelt wird, erstmal temp. einfuegen
								if( bCallDelete )
								{
									pRedlineTbl->SavePtrInArr( pNewRedl );
									DeleteAndJoin( *pRedl );
									sal_uInt16 nFnd = pRedlineTbl->GetPos(pNewRedl );
									if( USHRT_MAX != nFnd )
										pRedlineTbl->Remove( nFnd );
									else
										pNewRedl = 0;
								}
								delete pRedl;
							}
							break;

						case POS_OVERLAP_BEFORE:
							{
								SwPaM aPam( *pRStt, *pEnd );

								if( *pEnd == *pREnd )
									pRedlineTbl->DeleteAndDestroy( n );
								else
								{
									pRedl->SetStart( *pEnd, pRStt );
									// neu einsortieren
									pRedlineTbl->Remove( n );
									pRedlineTbl->Insert( pRedl, n );
								}

								if( bCallDelete )
								{
									// damit pNew auch beim Verschieben der Indizies
									// behandelt wird, erstmal temp. einfuegen
									pRedlineTbl->SavePtrInArr( pNewRedl );
									DeleteAndJoin( aPam );
									sal_uInt16 nFnd = pRedlineTbl->GetPos(pNewRedl );
									if( USHRT_MAX != nFnd )
										pRedlineTbl->Remove( nFnd );
									else
										pNewRedl = 0;
									n = 0;		// neu Aufsetzen
								}
                                bDec = true;
							}
							break;

						case POS_OVERLAP_BEHIND:
							{
								SwPaM aPam( *pStt, *pREnd );

								if( *pStt == *pRStt )
                                {
									pRedlineTbl->DeleteAndDestroy( n );
                                    bDec = true;
                                }
								else
									pRedl->SetEnd( *pStt, pREnd );

								if( bCallDelete )
								{
									// damit pNew auch beim Verschieben der Indizies
									// behandelt wird, erstmal temp. einfuegen
									pRedlineTbl->SavePtrInArr( pNewRedl );
									DeleteAndJoin( aPam );
									sal_uInt16 nFnd = pRedlineTbl->GetPos(pNewRedl );
									if( USHRT_MAX != nFnd )
										pRedlineTbl->Remove( nFnd );
									else
										pNewRedl = 0;
									n = 0;		// neu Aufsetzen
                                    bDec = true;
								}
							}
							break;
						default:
							break;
						}

						eRedlineMode = eOld;
					}
					else
					{
                        // it may be necessary to split the existing redline in
                        // two. In this case, pRedl will be changed to cover
                        // only part of it's former range, and pNew will cover
                        // the remainder.
						SwRedline* pNew = 0;

						switch( eCmpPos )
						{
						case POS_EQUAL:
							{
								pRedl->PushData( *pNewRedl );
								delete pNewRedl, pNewRedl = 0;
								if( IsHideChanges( eRedlineMode ))
									pRedl->Hide();
								bCompress = sal_True;
							}
							break;

						case POS_INSIDE:
							{
								if( *pRStt == *pStt )
								{
                                    // --> mst 2010-05-17 #i97421#
                                    // redline w/out extent loops
                                    if (*pStt != *pEnd)
                                    // <--
                                    {
                                        pNewRedl->PushData( *pRedl, sal_False );
                                        pRedl->SetStart( *pEnd, pRStt );
                                        // re-insert
                                        pRedlineTbl->Remove( n );
                                        pRedlineTbl->Insert( pRedl, n );
                                        bDec = true;
                                    }
                                }
                                else
                                {
                                    pNewRedl->PushData( *pRedl, sal_False );
									if( *pREnd != *pEnd )
									{
										pNew = new SwRedline( *pRedl );
										pNew->SetStart( *pEnd );
									}
                                    pRedl->SetEnd( *pStt, pREnd );
									if( !pRedl->HasValidRange() )
									{
										// neu einsortieren
										pRedlineTbl->Remove( n );
										pRedlineTbl->Insert( pRedl, n );
									}
								}
							}
							break;

						case POS_OUTSIDE:
							{
								pRedl->PushData( *pNewRedl );
                                if( *pEnd == *pREnd )
									pNewRedl->SetEnd( *pRStt, pEnd );
                                else
                                {
                                    pNew = new SwRedline( *pNewRedl );
                                    pNew->SetEnd( *pRStt );
                                    pNewRedl->SetStart( *pREnd, pStt );
                                }
								bCompress = sal_True;
							}
							break;

						case POS_OVERLAP_BEFORE:
							{
								if( *pEnd == *pREnd )
								{
									pRedl->PushData( *pNewRedl );
									pNewRedl->SetEnd( *pRStt, pEnd );
									if( IsHideChanges( eRedlineMode ))
									{
										pRedlineTbl->SavePtrInArr( pNewRedl );
										pRedl->Hide();
										pRedlineTbl->Remove(
											pRedlineTbl->GetPos(pNewRedl ));
									}
								}
								else
								{
									pNew = new SwRedline( *pRedl );
									pNew->PushData( *pNewRedl );
									pNew->SetEnd( *pEnd );
									pNewRedl->SetEnd( *pRStt, pEnd );
									pRedl->SetStart( *pNew->End(), pRStt ) ;
									// neu einsortieren
									pRedlineTbl->Remove( n );
									pRedlineTbl->Insert( pRedl );
                                    bDec = true;
								}
							}
							break;

						case POS_OVERLAP_BEHIND:
							{
								if( *pStt == *pRStt )
								{
									pRedl->PushData( *pNewRedl );
									pNewRedl->SetStart( *pREnd, pStt );
									if( IsHideChanges( eRedlineMode ))
									{
										pRedlineTbl->SavePtrInArr( pNewRedl );
										pRedl->Hide();
										pRedlineTbl->Remove(
											pRedlineTbl->GetPos(pNewRedl ));
									}
								}
								else
								{
									pNew = new SwRedline( *pRedl );
									pNew->PushData( *pNewRedl );
									pNew->SetStart( *pStt );
									pNewRedl->SetStart( *pREnd, pStt );
									pRedl->SetEnd( *pNew->Start(), pREnd );
									if( !pRedl->HasValidRange() )
									{
										// neu einsortieren
										pRedlineTbl->Remove( n );
										pRedlineTbl->Insert( pRedl );
									}
								}
							}
							break;
						default:
							break;
						}

                        // insert the pNew part (if it exists)
						if( pNew )
						{
                            // AppendRedline( pNew, bCallDelete );
                            //sal_Bool bRet =
                            pRedlineTbl->Insert( pNew );

                            // pNew must be deleted if Insert() wasn't
                            // successful. But that can't happen, since pNew is
                            // part of the original pRedl redline.
                            // ASSERT( bRet, "Can't insert existing redline?" );

                            // restart (now with pRedl being split up)
							n = 0;
                            bDec = true;
						}
					}
                }
                break;

                case nsRedlineType_t::REDLINE_FORMAT:
					switch( eCmpPos )
					{
					case POS_OVERLAP_BEFORE:
						pRedl->SetStart( *pEnd, pRStt );
						// neu einsortieren
						pRedlineTbl->Remove( n );
						pRedlineTbl->Insert( pRedl, n );
                        bDec = true;
						break;

					case POS_OVERLAP_BEHIND:
						pRedl->SetEnd( *pStt, pREnd );
						break;

					case POS_EQUAL:
					case POS_OUTSIDE:
						// ueberlappt den akt. komplett oder hat gleiche
						// Ausdehung, dann muss der alte geloescht werden
						pRedlineTbl->DeleteAndDestroy( n );
                        bDec = true;
						break;

					case POS_INSIDE:
						// ueberlappt den akt. komplett, dann muss
						// der neue gesplittet oder verkuertzt werden
						if( *pEnd != *pREnd )
						{
                            if( *pEnd != *pRStt )
                            {
                                SwRedline* pNew = new SwRedline( *pRedl );
                                pNew->SetStart( *pEnd );
                                pRedl->SetEnd( *pStt, pREnd );
                                if( ( *pStt == *pRStt ) &&
                                    ( pRedl->GetContentIdx() == NULL ) )
                                    pRedlineTbl->DeleteAndDestroy( n );
                                AppendRedline( pNew, bCallDelete );
                                n = 0;		// neu Aufsetzen
                                bDec = true;
                            }
						}
						else
							pRedl->SetEnd( *pStt, pREnd );
						break;
					default:
						break;
					}
					break;
				default:
					break;
				}
				break;

            case nsRedlineType_t::REDLINE_FORMAT:
				switch( pRedl->GetType() )
				{
                case nsRedlineType_t::REDLINE_INSERT:
                case nsRedlineType_t::REDLINE_DELETE:
					switch( eCmpPos )
					{
					case POS_OVERLAP_BEFORE:
						pNewRedl->SetEnd( *pRStt, pEnd );
						break;

					case POS_OVERLAP_BEHIND:
						pNewRedl->SetStart( *pREnd, pStt );
						break;

					case POS_EQUAL:
					case POS_INSIDE:
                        delete pNewRedl, pNewRedl = 0;
						break;

					case POS_OUTSIDE:
						// ueberlappt den akt. komplett, dann muss
						// der neue gesplittet oder verkuerzt werden
						if( *pEnd != *pREnd )
						{
                            if( *pEnd != *pRStt )
                            {
                                SwRedline* pNew = new SwRedline( *pNewRedl );
                                pNew->SetStart( *pREnd );
                                pNewRedl->SetEnd( *pRStt, pEnd );
                                AppendRedline( pNew, bCallDelete );
                                n = 0;		// neu Aufsetzen
                                bDec = true;
                            }
						}
						else
							pNewRedl->SetEnd( *pRStt, pEnd );
						break;
					default:
						break;
					}
					break;
                case nsRedlineType_t::REDLINE_FORMAT:
					switch( eCmpPos )
					{
					case POS_OUTSIDE:
					case POS_EQUAL:
						{
							// ueberlappt den akt. komplett oder hat gleiche
							// Ausdehnung, dann muss der alte geloescht werden
							pRedlineTbl->DeleteAndDestroy( n );
                            bDec = true;
						}
						break;

					case POS_INSIDE:
						if( pRedl->IsOwnRedline( *pNewRedl ) &&
							pRedl->CanCombine( *pNewRedl ))
							// ein eigenes kann komplett ignoriert werden
							delete pNewRedl, pNewRedl = 0;

						else if( *pREnd == *pEnd )
							// ansonsten nur den akt. verkuerzen
							pRedl->SetEnd( *pStt, pREnd );
						else if( *pRStt == *pStt )
						{
							// ansonsten nur den akt. verkuerzen
							pRedl->SetStart( *pEnd, pRStt );
							// neu einsortieren
							pRedlineTbl->Remove( n );
							pRedlineTbl->Insert( pRedl, n );
                            bDec = true;
						}
						else
						{
							// liegt komplett im akt.
							// dann muss der gesplittet werden
							SwRedline* pNew = new SwRedline( *pRedl );
							pNew->SetStart( *pEnd );
							pRedl->SetEnd( *pStt, pREnd );
							AppendRedline( pNew, bCallDelete );
							n = 0;		// neu Aufsetzen
                            bDec = true;
						}
						break;

					case POS_OVERLAP_BEFORE:
					case POS_OVERLAP_BEHIND:
						if( pRedl->IsOwnRedline( *pNewRedl ) &&
							pRedl->CanCombine( *pNewRedl ))
						{
							// dann kann das zusammengefasst werden, sprich
							// der neue deckt das schon ab.
							if( POS_OVERLAP_BEHIND == eCmpPos )
								pNewRedl->SetStart( *pRStt, pStt );
							else
								pNewRedl->SetEnd( *pREnd, pEnd );
							pRedlineTbl->DeleteAndDestroy( n );
                            bDec = 0;
						}
						else if( POS_OVERLAP_BEHIND == eCmpPos )
							pNewRedl->SetStart( *pREnd, pStt );
						else
							pNewRedl->SetEnd( *pRStt, pEnd );
						break;

					case POS_COLLIDE_END:
						if( pRedl->IsOwnRedline( *pNewRedl ) &&
							pRedl->CanCombine( *pNewRedl ) && n &&
							*(*pRedlineTbl)[ n-1 ]->End() < *pStt )
						{
							// dann kann das zusammengefasst werden, sprich
							// der neue deckt das schon ab.
							pNewRedl->SetEnd( *pREnd, pEnd );
							pRedlineTbl->DeleteAndDestroy( n );
                            bDec = true;
						}
						break;
					case POS_COLLIDE_START:
						if( pRedl->IsOwnRedline( *pNewRedl ) &&
							pRedl->CanCombine( *pNewRedl ) &&
							n+1 < pRedlineTbl->Count() &&
							*(*pRedlineTbl)[ n+1 ]->Start() < *pEnd )
						{
							// dann kann das zusammengefasst werden, sprich
							// der neue deckt das schon ab.
							pNewRedl->SetStart( *pRStt, pStt );
							pRedlineTbl->DeleteAndDestroy( n );
                            bDec = true;
						}
						break;
					default:
						break;
					}
					break;
				default:
					break;
				}
				break;


            case nsRedlineType_t::REDLINE_FMTCOLL:
				// wie soll das verhalten sein????
				// erstmal so einfuegen
				break;
			default:
				break;
			}
		}

		if( pNewRedl )
        {
            if( ( *pStt == *pEnd ) &&
                ( pNewRedl->GetContentIdx() == NULL ) )
            {   // Do not insert empty redlines
                delete pNewRedl;
                pNewRedl = 0;
            }
            else
                pRedlineTbl->Insert( pNewRedl );
        }

		if( bCompress )
			CompressRedlines();
	}
	else
	{
        if( bCallDelete && nsRedlineType_t::REDLINE_DELETE == pNewRedl->GetType() )
		{
			RedlineMode_t eOld = eRedlineMode;
// auf NONE setzen, damit das Delete::Redo die RedlineDaten wieder richtig
// zusammen fasst! Der ShowMode muss erhalten bleiben!
            eRedlineMode = (RedlineMode_t)(eOld & ~(nsRedlineMode_t::REDLINE_ON | nsRedlineMode_t::REDLINE_IGNORE));
			DeleteAndJoin( *pNewRedl );
			eRedlineMode = eOld;
		}
		delete pNewRedl, pNewRedl = 0;
	}
	_CHECK_REDLINE( this )

	return ( 0 != pNewRedl ) || !bError;
}

void SwDoc::CompressRedlines()
{
	_CHECK_REDLINE( this )

	void (SwRedline::*pFnc)(sal_uInt16) = 0;
    switch( nsRedlineMode_t::REDLINE_SHOW_MASK & eRedlineMode )
	{
    case nsRedlineMode_t::REDLINE_SHOW_INSERT | nsRedlineMode_t::REDLINE_SHOW_DELETE:
		pFnc = &SwRedline::Show;
		break;
    case nsRedlineMode_t::REDLINE_SHOW_INSERT:
		pFnc = &SwRedline::Hide;
		break;
	}

	// versuche gleiche zusammenzufassen
	for( sal_uInt16 n = 1; n < pRedlineTbl->Count(); ++n )
	{
		SwRedline* pPrev = (*pRedlineTbl)[ n-1 ],
					* pCur = (*pRedlineTbl)[ n ];
		const SwPosition* pPrevStt = pPrev->Start(),
						* pPrevEnd = pPrevStt == pPrev->GetPoint()
							? pPrev->GetMark() : pPrev->GetPoint();
		const SwPosition* pCurStt = pCur->Start(),
						* pCurEnd = pCurStt == pCur->GetPoint()
							? pCur->GetMark() : pCur->GetPoint();
		if( *pPrevEnd == *pCurStt && pPrev->CanCombine( *pCur ) &&
            pPrevStt->nNode.GetNode().StartOfSectionNode() ==
            pCurEnd->nNode.GetNode().StartOfSectionNode() &&
            !pCurEnd->nNode.GetNode().StartOfSectionNode()->IsTableNode() )
		{
			// dann koennen die zusammen gefasst werden
			pPrev->Show();
			pCur->Show();

			pPrev->SetEnd( *pCur->End() );
			pRedlineTbl->DeleteAndDestroy( n );
			--n;
			if( pFnc )
				(pPrev->*pFnc)(0);
		}
	}
	_CHECK_REDLINE( this )
}

bool SwDoc::SplitRedline( const SwPaM& rRange )
{
	sal_Bool bChg = sal_False;
	sal_uInt16 n = 0;
	const SwPosition* pStt = rRange.Start(),
				  * pEnd = pStt == rRange.GetPoint() ? rRange.GetMark()
													 : rRange.GetPoint();
	GetRedline( *pStt, &n );
	for( ; n < pRedlineTbl->Count() ; ++n )
	{
		SwRedline* pTmp = (*pRedlineTbl)[ n ];
		SwPosition* pTStt = pTmp->Start(),
				  * pTEnd = pTStt == pTmp->GetPoint() ? pTmp->GetMark()
													  : pTmp->GetPoint();
		if( *pTStt <= *pStt && *pStt <= *pTEnd &&
			*pTStt <= *pEnd && *pEnd <= *pTEnd )
		{
			bChg = sal_True;
			int nn = 0;
			if( *pStt == *pTStt )
				nn += 1;
			if( *pEnd == *pTEnd )
				nn += 2;

			SwRedline* pNew = 0;
			switch( nn )
			{
			case 0:
				pNew = new SwRedline( *pTmp );
				pTmp->SetEnd( *pStt, pTEnd );
				pNew->SetStart( *pEnd );
				break;

			case 1:
				*pTStt = *pEnd;
				break;

			case 2:
				*pTEnd = *pStt;
				break;

			case 3:
				pTmp->InvalidateRange();
				pRedlineTbl->DeleteAndDestroy( n-- );
				pTmp = 0;
				break;
			}
			if( pTmp && !pTmp->HasValidRange() )
			{
				// neu einsortieren
				pRedlineTbl->Remove( n );
				pRedlineTbl->Insert( pTmp, n );
			}
			if( pNew )
				pRedlineTbl->Insert( pNew, n );
		}
		else if( *pEnd < *pTStt )
			break;
	}
	return bChg;
}

bool SwDoc::DeleteRedline( const SwPaM& rRange, bool bSaveInUndo,
							sal_uInt16 nDelType )
{
    if( nsRedlineMode_t::REDLINE_IGNOREDELETE_REDLINES & eRedlineMode ||
		!rRange.HasMark() || *rRange.GetMark() == *rRange.GetPoint() )
		return sal_False;

	sal_Bool bChg = sal_False;

    if (bSaveInUndo && GetIDocumentUndoRedo().DoesUndo())
    {
		SwUndoRedline* pUndo = new SwUndoRedline( UNDO_REDLINE, rRange );
		if( pUndo->GetRedlSaveCount() )
        {
            GetIDocumentUndoRedo().AppendUndo(pUndo);
        }
        else
			delete pUndo;
	}

	const SwPosition* pStt = rRange.Start(),
					* pEnd = pStt == rRange.GetPoint() ? rRange.GetMark()
													   : rRange.GetPoint();
	sal_uInt16 n = 0;
	GetRedline( *pStt, &n );
	for( ; n < pRedlineTbl->Count() ; ++n )
	{
		SwRedline* pRedl = (*pRedlineTbl)[ n ];
		if( USHRT_MAX != nDelType && nDelType != pRedl->GetType() )
			continue;

		SwPosition* pRStt = pRedl->Start(),
				  * pREnd = pRStt == pRedl->GetPoint() ? pRedl->GetMark()
													   : pRedl->GetPoint();
		sal_Bool bDel = sal_False;
		switch( ComparePosition( *pStt, *pEnd, *pRStt, *pREnd ) )
		{
		case POS_EQUAL:
		case POS_OUTSIDE:
			bDel = sal_True;
			break;

		case POS_OVERLAP_BEFORE:
			if( *pEnd == *pREnd )
				bDel = sal_True;
			else
			{
				pRedl->InvalidateRange();
				pRedl->SetStart( *pEnd, pRStt );
				// neu einsortieren
				pRedlineTbl->Remove( n );
				pRedlineTbl->Insert( pRedl );
				--n;
			}
			break;

		case POS_OVERLAP_BEHIND:
			if( *pStt == *pRStt )
				bDel = sal_True;
			else
			{
				pRedl->InvalidateRange();
				pRedl->SetEnd( *pStt, pREnd );
				if( !pRedl->HasValidRange() )
				{
					// neu einsortieren
					pRedlineTbl->Remove( n );
					pRedlineTbl->Insert( pRedl );
					--n;
				}
			}
			break;

		case POS_INSIDE:
			{
				// der muss gesplittet werden
				pRedl->InvalidateRange();
				if( *pRStt == *pStt )
				{
					pRedl->SetStart( *pEnd, pRStt );
					// neu einsortieren
					pRedlineTbl->Remove( n );
					pRedlineTbl->Insert( pRedl );
					--n;
				}
				else
				{
					SwRedline* pCpy;
					if( *pREnd != *pEnd )
					{
						pCpy = new SwRedline( *pRedl );
						pCpy->SetStart( *pEnd );
					}
					else
						pCpy = 0;
					pRedl->SetEnd( *pStt, pREnd );
					if( !pRedl->HasValidRange() )
					{
						// neu einsortieren
						pRedlineTbl->Remove( pRedlineTbl->GetPos( pRedl ));
						pRedlineTbl->Insert( pRedl );
						--n;
					}
					if( pCpy )
						pRedlineTbl->Insert( pCpy );
				}
			}
			break;

		case POS_COLLIDE_END:
		case POS_BEFORE:
			n = pRedlineTbl->Count();
			break;
		default:
			break;
		}

		if( bDel )
		{
			pRedl->InvalidateRange();
			pRedlineTbl->DeleteAndDestroy( n-- );
			bChg = sal_True;
		}
	}

	if( bChg )
		SetModified();

	return bChg;
}

bool SwDoc::DeleteRedline( const SwStartNode& rNode, bool bSaveInUndo,
							sal_uInt16 nDelType )
{
	SwPaM aTemp(*rNode.EndOfSectionNode(), rNode);
	return DeleteRedline(aTemp, bSaveInUndo, nDelType);
}

sal_uInt16 SwDoc::GetRedlinePos( const SwNode& rNd, sal_uInt16 nType ) const
{
	const sal_uLong nNdIdx = rNd.GetIndex();
	for( sal_uInt16 n = 0; n < pRedlineTbl->Count() ; ++n )
	{
		const SwRedline* pTmp = (*pRedlineTbl)[ n ];
		sal_uLong nPt = pTmp->GetPoint()->nNode.GetIndex(),
			  nMk = pTmp->GetMark()->nNode.GetIndex();
		if( nPt < nMk ) { long nTmp = nMk; nMk = nPt; nPt = nTmp; }

		if( ( USHRT_MAX == nType || nType == pTmp->GetType()) &&
			nMk <= nNdIdx && nNdIdx <= nPt )
			return n;

		if( nMk > nNdIdx )
			break;
	}
	return USHRT_MAX;
}

const SwRedline* SwDoc::GetRedline( const SwPosition& rPos,
									sal_uInt16* pFndPos ) const
{
	sal_uInt16 nO = pRedlineTbl->Count(), nM, nU = 0;
	if( nO > 0 )
	{
		nO--;
		while( nU <= nO )
		{
			nM = nU + ( nO - nU ) / 2;
			const SwRedline* pRedl = (*pRedlineTbl)[ nM ];
			const SwPosition* pStt = pRedl->Start();
			const SwPosition* pEnd = pStt == pRedl->GetPoint()
										? pRedl->GetMark()
										: pRedl->GetPoint();
			if( pEnd == pStt
					? *pStt == rPos
					: ( *pStt <= rPos && rPos < *pEnd ) )
			{
                /* #107318# returned wrong redline ???*/
				while( nM && rPos == *(*pRedlineTbl)[ nM - 1 ]->End() &&
                    rPos == *(*pRedlineTbl)[ nM - 1 ]->Start() )
				{
					--nM;
					pRedl = (*pRedlineTbl)[ nM ];
				}

				if( pFndPos )
					*pFndPos = nM;
				return pRedl;
			}
			else if( *pEnd <= rPos )
				nU = nM + 1;
			else if( nM == 0 )
			{
				if( pFndPos )
					*pFndPos = nU;
				return 0;
			}
			else
				nO = nM - 1;
		}
	}
	if( pFndPos )
		*pFndPos = nU;
	return 0;
}

typedef sal_Bool (*Fn_AcceptReject)( SwRedlineTbl& rArr, sal_uInt16& rPos,
						sal_Bool bCallDelete,
						const SwPosition* pSttRng,
						const SwPosition* pEndRng);

sal_Bool lcl_AcceptRedline( SwRedlineTbl& rArr, sal_uInt16& rPos,
						sal_Bool bCallDelete,
						const SwPosition* pSttRng = 0,
						const SwPosition* pEndRng = 0 )
{
	sal_Bool bRet = sal_True;
	SwRedline* pRedl = rArr[ rPos ];
	SwPosition *pRStt = 0, *pREnd = 0;
	SwComparePosition eCmp = POS_OUTSIDE;
	if( pSttRng && pEndRng )
	{
		pRStt = pRedl->Start();
		pREnd = pRedl->End();
		eCmp = ComparePosition( *pSttRng, *pEndRng, *pRStt, *pREnd );
	}

	pRedl->InvalidateRange();

	switch( pRedl->GetType() )
	{
	case nsRedlineType_t::REDLINE_INSERT:
	case nsRedlineType_t::REDLINE_FORMAT:
		{
			sal_Bool bCheck = sal_False, bReplace = sal_False;
			switch( eCmp )
			{
			case POS_INSIDE:
				if( *pSttRng == *pRStt )
					pRedl->SetStart( *pEndRng, pRStt );
				else
				{
					if( *pEndRng != *pREnd )
					{
						// aufsplitten
						SwRedline* pNew = new SwRedline( *pRedl );
						pNew->SetStart( *pEndRng );
						rArr.Insert( pNew ); ++rPos;
					}
					pRedl->SetEnd( *pSttRng, pREnd );
					bCheck = sal_True;
				}
				break;

			case POS_OVERLAP_BEFORE:
				pRedl->SetStart( *pEndRng, pRStt );
				bReplace = sal_True;
				break;

			case POS_OVERLAP_BEHIND:
				pRedl->SetEnd( *pSttRng, pREnd );
				bCheck = sal_True;
				break;

			case POS_OUTSIDE:
			case POS_EQUAL:
				rArr.DeleteAndDestroy( rPos-- );
				break;

			default:
				bRet = sal_False;
			}

			if( bReplace || ( bCheck && !pRedl->HasValidRange() ))
			{
				// neu einsortieren
				rArr.Remove( rArr.GetPos( pRedl ));
				rArr.Insert( pRedl );
			}
		}
		break;
	case nsRedlineType_t::REDLINE_DELETE:
		{
			SwDoc& rDoc = *pRedl->GetDoc();
			const SwPosition *pDelStt = 0, *pDelEnd = 0;
			sal_Bool bDelRedl = sal_False;
			switch( eCmp )
			{
			case POS_INSIDE:
				if( bCallDelete )
				{
					pDelStt = pSttRng;
					pDelEnd = pEndRng;
				}
				break;

			case POS_OVERLAP_BEFORE:
				if( bCallDelete )
				{
					pDelStt = pRStt;
					pDelEnd = pEndRng;
				}
				break;
			case POS_OVERLAP_BEHIND:
				if( bCallDelete )
				{
					pDelStt = pREnd;
					pDelEnd = pSttRng;
				}
				break;

			case POS_OUTSIDE:
			case POS_EQUAL:
				{
					rArr.Remove( rPos-- );
					bDelRedl = sal_True;
					if( bCallDelete )
					{
						pDelStt = pRedl->Start();
						pDelEnd = pRedl->End();
					}
				}
				break;
			default:
				bRet = sal_False;
			}

			if( pDelStt && pDelEnd )
			{
				SwPaM aPam( *pDelStt, *pDelEnd );
				SwCntntNode* pCSttNd = pDelStt->nNode.GetNode().GetCntntNode();
				SwCntntNode* pCEndNd = pDelEnd->nNode.GetNode().GetCntntNode();

				if( bDelRedl )
					delete pRedl;

				RedlineMode_t eOld = rDoc.GetRedlineMode();
				rDoc.SetRedlineMode_intern( (RedlineMode_t)(eOld & ~(nsRedlineMode_t::REDLINE_ON | nsRedlineMode_t::REDLINE_IGNORE)));

				if( pCSttNd && pCEndNd )
					rDoc.DeleteAndJoin( aPam );
				else
				{
                    rDoc.DeleteRange( aPam );

					if( pCSttNd && !pCEndNd )
					{
						aPam.GetBound( sal_True ).nContent.Assign( 0, 0 );
						aPam.GetBound( sal_False ).nContent.Assign( 0, 0 );
						aPam.DeleteMark();
						rDoc.DelFullPara( aPam );
					}
				}
				rDoc.SetRedlineMode_intern( eOld );
			}
			else if( bDelRedl )
				delete pRedl;
		}
		break;

	case nsRedlineType_t::REDLINE_FMTCOLL:
		rArr.DeleteAndDestroy( rPos-- );
		break;

	default:
		bRet = sal_False;
	}
	return bRet;
}

sal_Bool lcl_RejectRedline( SwRedlineTbl& rArr, sal_uInt16& rPos,
						sal_Bool bCallDelete,
						const SwPosition* pSttRng = 0,
						const SwPosition* pEndRng = 0 )
{
	sal_Bool bRet = sal_True;
	SwRedline* pRedl = rArr[ rPos ];
	SwPosition *pRStt = 0, *pREnd = 0;
	SwComparePosition eCmp = POS_OUTSIDE;
	if( pSttRng && pEndRng )
	{
		pRStt = pRedl->Start();
		pREnd = pRedl->End();
		eCmp = ComparePosition( *pSttRng, *pEndRng, *pRStt, *pREnd );
	}

	pRedl->InvalidateRange();

	switch( pRedl->GetType() )
	{
	case nsRedlineType_t::REDLINE_INSERT:
		{
			SwDoc& rDoc = *pRedl->GetDoc();
			const SwPosition *pDelStt = 0, *pDelEnd = 0;
			sal_Bool bDelRedl = sal_False;
			switch( eCmp )
			{
			case POS_INSIDE:
				if( bCallDelete )
				{
					pDelStt = pSttRng;
					pDelEnd = pEndRng;
				}
				break;

			case POS_OVERLAP_BEFORE:
				if( bCallDelete )
				{
					pDelStt = pRStt;
					pDelEnd = pEndRng;
				}
				break;
			case POS_OVERLAP_BEHIND:
				if( bCallDelete )
				{
					pDelStt = pREnd;
					pDelEnd = pSttRng;
				}
				break;
			case POS_OUTSIDE:
			case POS_EQUAL:
				{
					// dann den Bereich wieder loeschen
					rArr.Remove( rPos-- );
					bDelRedl = sal_True;
					if( bCallDelete )
					{
						pDelStt = pRedl->Start();
						pDelEnd = pRedl->End();
					}
				}
				break;

			default:
				bRet = sal_False;
			}
			if( pDelStt && pDelEnd )
			{
				SwPaM aPam( *pDelStt, *pDelEnd );

				SwCntntNode* pCSttNd = pDelStt->nNode.GetNode().GetCntntNode();
				SwCntntNode* pCEndNd = pDelEnd->nNode.GetNode().GetCntntNode();

				if( bDelRedl )
					delete pRedl;

				RedlineMode_t eOld = rDoc.GetRedlineMode();
				rDoc.SetRedlineMode_intern( (RedlineMode_t)(eOld & ~(nsRedlineMode_t::REDLINE_ON | nsRedlineMode_t::REDLINE_IGNORE)));

				if( pCSttNd && pCEndNd )
					rDoc.DeleteAndJoin( aPam );
				else
				{
                    rDoc.DeleteRange( aPam );

					if( pCSttNd && !pCEndNd )
					{
						aPam.GetBound( sal_True ).nContent.Assign( 0, 0 );
						aPam.GetBound( sal_False ).nContent.Assign( 0, 0 );
						aPam.DeleteMark();
						rDoc.DelFullPara( aPam );
					}
				}
				rDoc.SetRedlineMode_intern( eOld );
			}
			else if( bDelRedl )
				delete pRedl;
		}
		break;
	case nsRedlineType_t::REDLINE_DELETE:
		{
			SwRedline* pNew = 0;
			sal_Bool bCheck = sal_False, bReplace = sal_False;

			switch( eCmp )
			{
			case POS_INSIDE:
				{
					if( 1 < pRedl->GetStackCount() )
					{
						pNew = new SwRedline( *pRedl );
						pNew->PopData();
					}
					if( *pSttRng == *pRStt )
					{
						pRedl->SetStart( *pEndRng, pRStt );
						bReplace = sal_True;
						if( pNew )
							pNew->SetEnd( *pEndRng );
					}
					else
					{
						if( *pEndRng != *pREnd )
						{
							// aufsplitten
							SwRedline* pCpy = new SwRedline( *pRedl );
							pCpy->SetStart( *pEndRng );
							rArr.Insert( pCpy ); ++rPos;
							if( pNew )
								pNew->SetEnd( *pEndRng );
						}

						pRedl->SetEnd( *pSttRng, pREnd );
						bCheck = sal_True;
						if( pNew )
							pNew->SetStart( *pSttRng );
					}
				}
				break;

			case POS_OVERLAP_BEFORE:
				if( 1 < pRedl->GetStackCount() )
				{
					pNew = new SwRedline( *pRedl );
					pNew->PopData();
				}
				pRedl->SetStart( *pEndRng, pRStt );
				bReplace = sal_True;
				if( pNew )
					pNew->SetEnd( *pEndRng );
				break;

			case POS_OVERLAP_BEHIND:
				if( 1 < pRedl->GetStackCount() )
				{
					pNew = new SwRedline( *pRedl );
					pNew->PopData();
				}
				pRedl->SetEnd( *pSttRng, pREnd );
				bCheck = sal_True;
				if( pNew )
					pNew->SetStart( *pSttRng );
				break;

			case POS_OUTSIDE:
			case POS_EQUAL:
				if( !pRedl->PopData() )
					// das RedlineObject loeschen reicht
					rArr.DeleteAndDestroy( rPos-- );
				break;

			default:
				bRet = sal_False;
			}

			if( pNew )
			{
				rArr.Insert( pNew ); ++rPos;
			}

			if( bReplace || ( bCheck && !pRedl->HasValidRange() ))
			{
				// neu einsortieren
				rArr.Remove( rArr.GetPos( pRedl ));
				rArr.Insert( pRedl );
			}
		}
		break;

	case nsRedlineType_t::REDLINE_FORMAT:
	case nsRedlineType_t::REDLINE_FMTCOLL:
		{
			if( pRedl->GetExtraData() )
				pRedl->GetExtraData()->Reject( *pRedl );
			rArr.DeleteAndDestroy( rPos-- );
		}
		break;

	default:
		bRet = sal_False;
	}
	return bRet;
}


const SwRedline* lcl_FindCurrRedline( const SwPosition& rSttPos,
										sal_uInt16& rPos,
										sal_Bool bNext = sal_True )
{
	const SwRedline* pFnd = 0;
	const SwRedlineTbl& rArr = rSttPos.nNode.GetNode().GetDoc()->GetRedlineTbl();
	for( ; rPos < rArr.Count() ; ++rPos )
	{
		const SwRedline* pTmp = rArr[ rPos ];
		if( pTmp->HasMark() && pTmp->IsVisible() )
		{
			const SwPosition* pRStt = pTmp->Start(),
					  * pREnd = pRStt == pTmp->GetPoint() ? pTmp->GetMark()
														  : pTmp->GetPoint();
			if( bNext ? *pRStt <= rSttPos : *pRStt < rSttPos )
			{
				if( bNext ? *pREnd > rSttPos : *pREnd >= rSttPos )
				{
					pFnd = pTmp;
					break;
				}
			}
			else
				break;
		}
	}
	return pFnd;
}

// #111827#
int lcl_AcceptRejectRedl( Fn_AcceptReject fn_AcceptReject,
							SwRedlineTbl& rArr, sal_Bool bCallDelete,
							const SwPaM& rPam)
{
	sal_uInt16 n = 0;
    int nCount = 0; // #111827#

	const SwPosition* pStt = rPam.Start(),
					* pEnd = pStt == rPam.GetPoint() ? rPam.GetMark()
													 : rPam.GetPoint();
	const SwRedline* pFnd = lcl_FindCurrRedline( *pStt, n, sal_True );
	if( pFnd &&		// neu ein Teil davon?
		( *pFnd->Start() != *pStt || *pFnd->End() > *pEnd ))
	{
		// dann nur die TeilSelektion aufheben
		if( (*fn_AcceptReject)( rArr, n, bCallDelete, pStt, pEnd ))
            nCount++; // #111827#
		++n;
	}

	for( ; n < rArr.Count(); ++n )
	{
		SwRedline* pTmp = rArr[ n ];
		if( pTmp->HasMark() && pTmp->IsVisible() )
		{
			if( *pTmp->End() <= *pEnd )
			{
				if( (*fn_AcceptReject)( rArr, n, bCallDelete, 0, 0 ))
					nCount++; // #111827#
			}
			else
			{
				if( *pTmp->Start() < *pEnd )
				{
					// dann nur in der TeilSelektion aufheben
					if( (*fn_AcceptReject)( rArr, n, bCallDelete, pStt, pEnd ))
						nCount++; // #111827#
				}
				break;
			}
		}
	}
	return nCount; // #111827#
}

void lcl_AdjustRedlineRange( SwPaM& rPam )
{
	// die Selektion steht nur im ContentBereich. Wenn es aber Redlines
	// davor oder dahinter auf nicht ContentNodes stehen, dann erweiter die
	// die Selection auf diese
	SwPosition* pStt = rPam.Start(),
			  * pEnd = pStt == rPam.GetPoint() ? rPam.GetMark()
											   : rPam.GetPoint();
	SwDoc* pDoc = rPam.GetDoc();
	if( !pStt->nContent.GetIndex() &&
		!pDoc->GetNodes()[ pStt->nNode.GetIndex() - 1 ]->IsCntntNode() )
	{
		const SwRedline* pRedl = pDoc->GetRedline( *pStt, 0 );
		if( pRedl )
		{
			const SwPosition* pRStt = pRedl->Start();
			if( !pRStt->nContent.GetIndex() && pRStt->nNode.GetIndex() ==
				pStt->nNode.GetIndex() - 1 )
				*pStt = *pRStt;
		}
	}
	if( pEnd->nNode.GetNode().IsCntntNode() &&
		!pDoc->GetNodes()[ pEnd->nNode.GetIndex() + 1 ]->IsCntntNode() &&
		pEnd->nContent.GetIndex() == pEnd->nNode.GetNode().GetCntntNode()->Len()	)
	{
		const SwRedline* pRedl = pDoc->GetRedline( *pEnd, 0 );
		if( pRedl )
		{
			const SwPosition* pREnd = pRedl->End();
			if( !pREnd->nContent.GetIndex() && pREnd->nNode.GetIndex() ==
				pEnd->nNode.GetIndex() + 1 )
				*pEnd = *pREnd;
		}
	}
}


bool SwDoc::AcceptRedline( sal_uInt16 nPos, bool bCallDelete )
{
	sal_Bool bRet = sal_False;

	// aufjedenfall auf sichtbar umschalten
    if( (nsRedlineMode_t::REDLINE_SHOW_INSERT | nsRedlineMode_t::REDLINE_SHOW_DELETE) !=
        (nsRedlineMode_t::REDLINE_SHOW_MASK & eRedlineMode) )
      SetRedlineMode( (RedlineMode_t)(nsRedlineMode_t::REDLINE_SHOW_INSERT | nsRedlineMode_t::REDLINE_SHOW_DELETE | eRedlineMode));

	SwRedline* pTmp = (*pRedlineTbl)[ nPos ];
	if( pTmp->HasMark() && pTmp->IsVisible() )
	{
        if (GetIDocumentUndoRedo().DoesUndo())
        {
            // #111827#
            SwRewriter aRewriter;

            aRewriter.AddRule(UNDO_ARG1, pTmp->GetDescr());
            GetIDocumentUndoRedo().StartUndo(UNDO_ACCEPT_REDLINE, &aRewriter);
        }

		int nLoopCnt = 2;
		sal_uInt16 nSeqNo = pTmp->GetSeqNo();

		do {

            if (GetIDocumentUndoRedo().DoesUndo())
            {
                SwUndo *const pUndo( new SwUndoAcceptRedline(*pTmp) );
                GetIDocumentUndoRedo().AppendUndo(pUndo);
            }

			bRet |= lcl_AcceptRedline( *pRedlineTbl, nPos, bCallDelete );

			if( nSeqNo )
			{
				if( USHRT_MAX == nPos )
					nPos = 0;
				sal_uInt16 nFndPos = 2 == nLoopCnt
									? pRedlineTbl->FindNextSeqNo( nSeqNo, nPos )
									: pRedlineTbl->FindPrevSeqNo( nSeqNo, nPos );
				if( USHRT_MAX != nFndPos || ( 0 != ( --nLoopCnt ) &&
					USHRT_MAX != ( nFndPos =
						pRedlineTbl->FindPrevSeqNo( nSeqNo, nPos ))) )
					pTmp = (*pRedlineTbl)[ nPos = nFndPos ];
				else
					nLoopCnt = 0;
			}
			else
				nLoopCnt = 0;

		} while( nLoopCnt );

		if( bRet )
		{
			CompressRedlines();
			SetModified();
		}

        if (GetIDocumentUndoRedo().DoesUndo())
        {
            GetIDocumentUndoRedo().EndUndo(UNDO_END, 0);
        }
	}
	return bRet;
}

bool SwDoc::AcceptRedline( const SwPaM& rPam, bool bCallDelete )
{
	// aufjedenfall auf sichtbar umschalten
    if( (nsRedlineMode_t::REDLINE_SHOW_INSERT | nsRedlineMode_t::REDLINE_SHOW_DELETE) !=
        (nsRedlineMode_t::REDLINE_SHOW_MASK & eRedlineMode) )
      SetRedlineMode( (RedlineMode_t)(nsRedlineMode_t::REDLINE_SHOW_INSERT | nsRedlineMode_t::REDLINE_SHOW_DELETE | eRedlineMode));

	// die Selektion steht nur im ContentBereich. Wenn es aber Redlines
	// davor oder dahinter auf nicht ContentNodes stehen, dann erweiter die
	// die Selection auf diese
	SwPaM aPam( *rPam.GetMark(), *rPam.GetPoint() );
	lcl_AdjustRedlineRange( aPam );

    if (GetIDocumentUndoRedo().DoesUndo())
    {
        GetIDocumentUndoRedo().StartUndo( UNDO_ACCEPT_REDLINE, NULL );
        GetIDocumentUndoRedo().AppendUndo( new SwUndoAcceptRedline( aPam ));
    }

    // #111827#
	int nRet = lcl_AcceptRejectRedl( lcl_AcceptRedline, *pRedlineTbl,
                                     bCallDelete, aPam );
	if( nRet > 0 )
	{
		CompressRedlines();
		SetModified();
	}
    if (GetIDocumentUndoRedo().DoesUndo())
    {
        // #111827#
        String aTmpStr;

        {
            SwRewriter aRewriter;
            aRewriter.AddRule(UNDO_ARG1, String::CreateFromInt32(nRet));
            aTmpStr = aRewriter.Apply(String(SW_RES(STR_N_REDLINES)));
        }

        SwRewriter aRewriter;
        aRewriter.AddRule(UNDO_ARG1, aTmpStr);

        GetIDocumentUndoRedo().EndUndo( UNDO_ACCEPT_REDLINE, &aRewriter );
    }
	return nRet != 0;
}

bool SwDoc::RejectRedline( sal_uInt16 nPos, bool bCallDelete )
{
	sal_Bool bRet = sal_False;

	// aufjedenfall auf sichtbar umschalten
    if( (nsRedlineMode_t::REDLINE_SHOW_INSERT | nsRedlineMode_t::REDLINE_SHOW_DELETE) !=
        (nsRedlineMode_t::REDLINE_SHOW_MASK & eRedlineMode) )
      SetRedlineMode( (RedlineMode_t)(nsRedlineMode_t::REDLINE_SHOW_INSERT | nsRedlineMode_t::REDLINE_SHOW_DELETE | eRedlineMode));

	SwRedline* pTmp = (*pRedlineTbl)[ nPos ];
	if( pTmp->HasMark() && pTmp->IsVisible() )
	{
        if (GetIDocumentUndoRedo().DoesUndo())
        {
            // #111827#
            SwRewriter aRewriter;

            aRewriter.AddRule(UNDO_ARG1, pTmp->GetDescr());
            GetIDocumentUndoRedo().StartUndo(UNDO_REJECT_REDLINE, &aRewriter);
        }

		int nLoopCnt = 2;
		sal_uInt16 nSeqNo = pTmp->GetSeqNo();

		do {

            if (GetIDocumentUndoRedo().DoesUndo())
            {
                SwUndo *const pUndo( new SwUndoRejectRedline( *pTmp ) );
                GetIDocumentUndoRedo().AppendUndo(pUndo);
            }

			bRet |= lcl_RejectRedline( *pRedlineTbl, nPos, bCallDelete );

			if( nSeqNo )
			{
				if( USHRT_MAX == nPos )
					nPos = 0;
				sal_uInt16 nFndPos = 2 == nLoopCnt
									? pRedlineTbl->FindNextSeqNo( nSeqNo, nPos )
									: pRedlineTbl->FindPrevSeqNo( nSeqNo, nPos );
				if( USHRT_MAX != nFndPos || ( 0 != ( --nLoopCnt ) &&
					USHRT_MAX != ( nFndPos =
							pRedlineTbl->FindPrevSeqNo( nSeqNo, nPos ))) )
					pTmp = (*pRedlineTbl)[ nPos = nFndPos ];
				else
					nLoopCnt = 0;
			}
			else
				nLoopCnt = 0;

		} while( nLoopCnt );

		if( bRet )
		{
			CompressRedlines();
			SetModified();
		}

        if (GetIDocumentUndoRedo().DoesUndo())
        {
            GetIDocumentUndoRedo().EndUndo(UNDO_END, 0);
        }
	}
	return bRet;
}

bool SwDoc::RejectRedline( const SwPaM& rPam, bool bCallDelete )
{
	// aufjedenfall auf sichtbar umschalten
    if( (nsRedlineMode_t::REDLINE_SHOW_INSERT | nsRedlineMode_t::REDLINE_SHOW_DELETE) !=
        (nsRedlineMode_t::REDLINE_SHOW_MASK & eRedlineMode) )
      SetRedlineMode((RedlineMode_t)(nsRedlineMode_t::REDLINE_SHOW_INSERT | nsRedlineMode_t::REDLINE_SHOW_DELETE | eRedlineMode));

	// die Selektion steht nur im ContentBereich. Wenn es aber Redlines
	// davor oder dahinter auf nicht ContentNodes stehen, dann erweiter die
	// die Selection auf diese
	SwPaM aPam( *rPam.GetMark(), *rPam.GetPoint() );
	lcl_AdjustRedlineRange( aPam );

    if (GetIDocumentUndoRedo().DoesUndo())
    {
        GetIDocumentUndoRedo().StartUndo( UNDO_REJECT_REDLINE, NULL );
        GetIDocumentUndoRedo().AppendUndo( new SwUndoRejectRedline(aPam) );
    }

    // #111827#
	int nRet = lcl_AcceptRejectRedl( lcl_RejectRedline, *pRedlineTbl,
										bCallDelete, aPam );
	if( nRet > 0 )
	{
		CompressRedlines();
		SetModified();
	}
    if (GetIDocumentUndoRedo().DoesUndo())
    {
        // #111827#
        String aTmpStr;

        {
            SwRewriter aRewriter;
            aRewriter.AddRule(UNDO_ARG1, String::CreateFromInt32(nRet));
            aTmpStr = aRewriter.Apply(String(SW_RES(STR_N_REDLINES)));
        }

        SwRewriter aRewriter;
        aRewriter.AddRule(UNDO_ARG1, aTmpStr);

        GetIDocumentUndoRedo().EndUndo( UNDO_REJECT_REDLINE, &aRewriter );
    }

	return nRet != 0;
}

const SwRedline* SwDoc::SelNextRedline( SwPaM& rPam ) const
{
	rPam.DeleteMark();
	rPam.SetMark();

	SwPosition& rSttPos = *rPam.GetPoint();
	SwPosition aSavePos( rSttPos );
	sal_Bool bRestart;

	// sollte die StartPos auf dem letzen gueligen ContentNode stehen,
	// dann aufjedenfall das naechste Redline nehmen
	sal_uInt16 n = 0;
	const SwRedline* pFnd = lcl_FindCurrRedline( rSttPos, n, sal_True );
	if( pFnd )
	{
		const SwPosition* pEnd = pFnd->End();
		if( !pEnd->nNode.GetNode().IsCntntNode() )
		{
			SwNodeIndex aTmp( pEnd->nNode );
			SwCntntNode* pCNd = GetNodes().GoPrevSection( &aTmp );
			if( !pCNd || ( aTmp == rSttPos.nNode &&
				pCNd->Len() == rSttPos.nContent.GetIndex() ))
				pFnd = 0;
		}
		if( pFnd )
			rSttPos = *pFnd->End();
	}

	do {
		bRestart = sal_False;

		for( ; !pFnd && n < pRedlineTbl->Count(); ++n )
		{
			pFnd = (*pRedlineTbl)[ n ];
			if( pFnd->HasMark() && pFnd->IsVisible() )
			{
				*rPam.GetMark() = *pFnd->Start();
				rSttPos = *pFnd->End();
				break;
			}
			else
				pFnd = 0;
		}

		if( pFnd )
		{
			// alle vom gleichen Typ und Author, die hinter einander liegen
			// zu einer Selektion zusammenfassen.
			const SwPosition* pPrevEnd = pFnd->End();
			while( ++n < pRedlineTbl->Count() )
			{
				const SwRedline* pTmp = (*pRedlineTbl)[ n ];
				if( pTmp->HasMark() && pTmp->IsVisible() )
				{
					const SwPosition *pRStt;
					if( pFnd->GetType() == pTmp->GetType() &&
						pFnd->GetAuthor() == pTmp->GetAuthor() &&
						( *pPrevEnd == *( pRStt = pTmp->Start() ) ||
						  IsPrevPos( *pPrevEnd, *pRStt )) )
					{
						pPrevEnd = pTmp->End();
						rSttPos = *pPrevEnd;
					}
					else
						break;
				}
			}
		}

		if( pFnd )
		{
			const SwRedline* pSaveFnd = pFnd;

			SwCntntNode* pCNd;
			SwNodeIndex* pIdx = &rPam.GetMark()->nNode;
			if( !pIdx->GetNode().IsCntntNode() &&
				0 != ( pCNd = GetNodes().GoNextSection( pIdx )) )
			{
				if( *pIdx <= rPam.GetPoint()->nNode )
					rPam.GetMark()->nContent.Assign( pCNd, 0 );
				else
					pFnd = 0;
			}

			if( pFnd )
			{
				pIdx = &rPam.GetPoint()->nNode;
				if( !pIdx->GetNode().IsCntntNode() &&
					0 != ( pCNd = GetNodes().GoPrevSection( pIdx )) )
				{
					if( *pIdx >= rPam.GetMark()->nNode )
						rPam.GetPoint()->nContent.Assign( pCNd, pCNd->Len() );
					else
						pFnd = 0;
				}
			}

			if( !pFnd || *rPam.GetMark() == *rPam.GetPoint() )
			{
				if( n < pRedlineTbl->Count() )
				{
					bRestart = sal_True;
					*rPam.GetPoint() = *pSaveFnd->End();
				}
				else
				{
					rPam.DeleteMark();
					*rPam.GetPoint() = aSavePos;
				}
				pFnd = 0;
			}
		}
	} while( bRestart );

	return pFnd;
}

const SwRedline* SwDoc::SelPrevRedline( SwPaM& rPam ) const
{
	rPam.DeleteMark();
	rPam.SetMark();

	SwPosition& rSttPos = *rPam.GetPoint();
	SwPosition aSavePos( rSttPos );
	sal_Bool bRestart;

	// sollte die StartPos auf dem ersten gueligen ContentNode stehen,
	// dann aufjedenfall das vorherige Redline nehmen
	sal_uInt16 n = 0;
	const SwRedline* pFnd = lcl_FindCurrRedline( rSttPos, n, sal_False );
	if( pFnd )
	{
		const SwPosition* pStt = pFnd->Start();
		if( !pStt->nNode.GetNode().IsCntntNode() )
		{
			SwNodeIndex aTmp( pStt->nNode );
			SwCntntNode* pCNd = GetNodes().GoNextSection( &aTmp );
			if( !pCNd || ( aTmp == rSttPos.nNode &&
				!rSttPos.nContent.GetIndex() ))
				pFnd = 0;
		}
		if( pFnd )
			rSttPos = *pFnd->Start();
	}

	do {
		bRestart = sal_False;

		while( !pFnd && 0 < n )
		{
			pFnd = (*pRedlineTbl)[ --n ];
			if( pFnd->HasMark() && pFnd->IsVisible() )
			{
				*rPam.GetMark() = *pFnd->End();
				rSttPos = *pFnd->Start();
			}
			else
				pFnd = 0;
		}

		if( pFnd )
		{
			// alle vom gleichen Typ und Author, die hinter einander liegen
			// zu einer Selektion zusammenfassen.
			const SwPosition* pNextStt = pFnd->Start();
			while( 0 < n )
			{
				const SwRedline* pTmp = (*pRedlineTbl)[ --n ];
				if( pTmp->HasMark() && pTmp->IsVisible() )
				{
					const SwPosition *pREnd;
					if( pFnd->GetType() == pTmp->GetType() &&
						pFnd->GetAuthor() == pTmp->GetAuthor() &&
						( *pNextStt == *( pREnd = pTmp->End() ) ||
						  IsPrevPos( *pREnd, *pNextStt )) )
					{
						pNextStt = pTmp->Start();
						rSttPos = *pNextStt;
					}
					else
					{
						++n;
						break;
					}
				}
			}
		}

		if( pFnd )
		{
			const SwRedline* pSaveFnd = pFnd;

			SwCntntNode* pCNd;
			SwNodeIndex* pIdx = &rPam.GetMark()->nNode;
			if( !pIdx->GetNode().IsCntntNode() &&
				0 != ( pCNd = GetNodes().GoPrevSection( pIdx )) )
			{
				if( *pIdx >= rPam.GetPoint()->nNode )
					rPam.GetMark()->nContent.Assign( pCNd, pCNd->Len() );
				else
					pFnd = 0;
			}

			if( pFnd )
			{
				pIdx = &rPam.GetPoint()->nNode;
				if( !pIdx->GetNode().IsCntntNode() &&
					0 != ( pCNd = GetNodes().GoNextSection( pIdx )) )
				{
					if( *pIdx <= rPam.GetMark()->nNode )
						rPam.GetPoint()->nContent.Assign( pCNd, 0 );
					else
						pFnd = 0;
				}
			}

			if( !pFnd || *rPam.GetMark() == *rPam.GetPoint() )
			{
				if( n )
				{
					bRestart = sal_True;
					*rPam.GetPoint() = *pSaveFnd->Start();
				}
				else
				{
					rPam.DeleteMark();
					*rPam.GetPoint() = aSavePos;
				}
				pFnd = 0;
			}
		}
	} while( bRestart );

	return pFnd;
}

// Kommentar am Redline setzen
bool SwDoc::SetRedlineComment( const SwPaM& rPaM, const String& rS )
{
	sal_Bool bRet = sal_False;
	const SwPosition* pStt = rPaM.Start(),
					* pEnd = pStt == rPaM.GetPoint() ? rPaM.GetMark()
													 : rPaM.GetPoint();
	sal_uInt16 n = 0;
	if( lcl_FindCurrRedline( *pStt, n, sal_True ) )
	{
		for( ; n < pRedlineTbl->Count(); ++n )
		{
			bRet = sal_True;
			SwRedline* pTmp = (*pRedlineTbl)[ n ];
			if( pStt != pEnd && *pTmp->Start() > *pEnd )
				break;

			pTmp->SetComment( rS );
			if( *pTmp->End() >= *pEnd )
				break;
		}
	}
	if( bRet )
		SetModified();

	return bRet;
}

// legt gebenenfalls einen neuen Author an
sal_uInt16 SwDoc::GetRedlineAuthor()
{
	return SW_MOD()->GetRedlineAuthor();
}

	// fuer die Reader usw. - neuen Author in die Tabelle eintragen
sal_uInt16 SwDoc::InsertRedlineAuthor( const String& rNew )
{
	return SW_MOD()->InsertRedlineAuthor(rNew);
}

void SwDoc::UpdateRedlineAttr()
{
	const SwRedlineTbl& rTbl = GetRedlineTbl();
	for( sal_uInt16 n = 0; n < rTbl.Count(); ++n )
	{
		SwRedline* pRedl = rTbl[ n ];
		if( pRedl->IsVisible() )
			pRedl->InvalidateRange();
	}
}

	// setze Kommentar-Text fuers Redline, das dann per AppendRedline
	// hereinkommt. Wird vom Autoformat benutzt. 0-Pointer setzt den Modus
	// wieder zurueck. Pointer wird nicht kopiert, muss also gueltig bleiben!
void SwDoc::SetAutoFmtRedlineComment( const String* pTxt, sal_uInt16 nSeqNo )
{
	mbIsAutoFmtRedline = 0 != pTxt;
	if( pTxt )
	{
		if( !pAutoFmtRedlnComment )
			pAutoFmtRedlnComment = new String( *pTxt );
		else
			*pAutoFmtRedlnComment = *pTxt;
	}
	else if( pAutoFmtRedlnComment )
		delete pAutoFmtRedlnComment, pAutoFmtRedlnComment = 0;

	nAutoFmtRedlnCommentNo = nSeqNo;
}

void SwDoc::SetRedlinePassword(
            /*[in]*/const uno::Sequence <sal_Int8>& rNewPassword)
{
	aRedlinePasswd = rNewPassword;
	SetModified();
}

/*  */

sal_Bool SwRedlineTbl::Insert( SwRedlinePtr& p, sal_Bool bIns )
{
	sal_Bool bRet = sal_False;
	if( p->HasValidRange() )
	{
		bRet = _SwRedlineTbl::Insert( p );
		p->CallDisplayFunc();
	}
	else if( bIns )
		bRet = InsertWithValidRanges( p );
	else
	{
		ASSERT( !this, "Redline: falscher Bereich" );
	}
	return bRet;
}

sal_Bool SwRedlineTbl::Insert( SwRedlinePtr& p, sal_uInt16& rP, sal_Bool bIns )
{
	sal_Bool bRet = sal_False;
	if( p->HasValidRange() )
	{
		bRet = _SwRedlineTbl::Insert( p, rP );
		p->CallDisplayFunc();
	}
	else if( bIns )
		bRet = InsertWithValidRanges( p, &rP );
	else
	{
		ASSERT( !this, "Redline: falscher Bereich" );
	}
	return bRet;
}

sal_Bool SwRedlineTbl::InsertWithValidRanges( SwRedlinePtr& p, sal_uInt16* pInsPos )
{
	// erzeuge aus den Selektion gueltige "Teilbereiche".
	sal_Bool bAnyIns = sal_False;
	SwPosition* pStt = p->Start(),
			  * pEnd = pStt == p->GetPoint() ? p->GetMark() : p->GetPoint();
	SwPosition aNewStt( *pStt );
	SwNodes& rNds = aNewStt.nNode.GetNodes();
	SwCntntNode* pC;

	if( !aNewStt.nNode.GetNode().IsCntntNode() )
	{
		pC = rNds.GoNext( &aNewStt.nNode );
		if( pC )
			aNewStt.nContent.Assign( pC, 0 );
		else
			aNewStt.nNode = rNds.GetEndOfContent();
	}

	SwRedline* pNew = 0;
	sal_uInt16 nInsPos;

	if( aNewStt < *pEnd )
		do {
			if( !pNew )
				pNew = new SwRedline( p->GetRedlineData(), aNewStt );
			else
			{
				pNew->DeleteMark();
				*pNew->GetPoint() = aNewStt;
			}

			pNew->SetMark();
			GoEndSection( pNew->GetPoint() );
            // i60396: If the redlines starts before a table but the table is the last member
            // of the section, the GoEndSection will end inside the table.
            // This will result in an incorrect redline, so we've to go back
            SwNode* pTab = pNew->GetPoint()->nNode.GetNode().StartOfSectionNode()->FindTableNode();
            // We end in a table when pTab != 0
            if( pTab && !pNew->GetMark()->nNode.GetNode().StartOfSectionNode()->FindTableNode() )
            { // but our Mark was outside the table => Correction
                do
                {
                    // We want to be before the table
                    *pNew->GetPoint() = SwPosition(*pTab);
                    pC = GoPreviousNds( &pNew->GetPoint()->nNode, sal_False ); // here we are.
                    if( pC )
                        pNew->GetPoint()->nContent.Assign( pC, 0 );
                    pTab = pNew->GetPoint()->nNode.GetNode().StartOfSectionNode()->FindTableNode();
                }while( pTab ); // If there is another table we have to repeat our step backwards
            }

			if( *pNew->GetPoint() > *pEnd )
			{
				pC = 0;
				if( aNewStt.nNode != pEnd->nNode )
					do {
						SwNode& rCurNd = aNewStt.nNode.GetNode();
						if( rCurNd.IsStartNode() )
						{
							if( rCurNd.EndOfSectionIndex() < pEnd->nNode.GetIndex() )
								aNewStt.nNode = *rCurNd.EndOfSectionNode();
							else
								break;
						}
						else if( rCurNd.IsCntntNode() )
							pC = rCurNd.GetCntntNode();
						aNewStt.nNode++;
					} while( aNewStt.nNode.GetIndex() < pEnd->nNode.GetIndex() );

				if( aNewStt.nNode == pEnd->nNode )
					aNewStt.nContent = pEnd->nContent;
				else if( pC )
				{
					aNewStt.nNode = *pC;
					aNewStt.nContent.Assign( pC, pC->Len() );
				}

				if( aNewStt <= *pEnd )
					*pNew->GetPoint() = aNewStt;
			}
			else
				aNewStt = *pNew->GetPoint();
#ifdef DEBUG
            CheckPosition( pNew->GetPoint(), pNew->GetMark() );
#endif
			if( *pNew->GetPoint() != *pNew->GetMark() &&
				_SwRedlineTbl::Insert( pNew, nInsPos ) )
			{
				pNew->CallDisplayFunc();
				bAnyIns = sal_True;
				pNew = 0;
				if( pInsPos && *pInsPos < nInsPos )
					*pInsPos = nInsPos;
			}

			if( aNewStt >= *pEnd ||
				0 == (pC = rNds.GoNext( &aNewStt.nNode )) )
				break;

			aNewStt.nContent.Assign( pC, 0 );

		} while( aNewStt < *pEnd );

	delete pNew;
	delete p, p = 0;
	return bAnyIns;
}

void SwRedlineTbl::Remove( sal_uInt16 nP, sal_uInt16 nL )
{
	SwDoc* pDoc = 0;
	if( !nP && nL && nL == _SwRedlineTbl::Count() )
		pDoc = _SwRedlineTbl::GetObject( 0 )->GetDoc();

	_SwRedlineTbl::Remove( nP, nL );

	ViewShell* pSh;
	if( pDoc && !pDoc->IsInDtor() &&
		0 != ( pSh = pDoc->GetCurrentViewShell()) )	//swmod 071108//swmod 071225
		pSh->InvalidateWindows( SwRect( 0, 0, LONG_MAX, LONG_MAX ) );
}

void SwRedlineTbl::DeleteAndDestroy( sal_uInt16 nP, sal_uInt16 nL )
{
	SwDoc* pDoc = 0;
	if( !nP && nL && nL == _SwRedlineTbl::Count() )
		pDoc = _SwRedlineTbl::GetObject( 0 )->GetDoc();

	_SwRedlineTbl::DeleteAndDestroy( nP, nL );

	ViewShell* pSh;
	if( pDoc && !pDoc->IsInDtor() &&
		0 != ( pSh = pDoc->GetCurrentViewShell() ) )	//swmod 071108//swmod 071225
		pSh->InvalidateWindows( SwRect( 0, 0, LONG_MAX, LONG_MAX ) );
}

// suche den naechsten oder vorherigen Redline mit dergleichen Seq.No
// Mit dem Lookahead kann die Suche eingeschraenkt werden. 0 oder
// USHRT_MAX suchen im gesamten Array.
sal_uInt16 SwRedlineTbl::FindNextOfSeqNo( sal_uInt16 nSttPos, sal_uInt16 nLookahead ) const
{
	return nSttPos + 1 < _SwRedlineTbl::Count()
				? FindNextSeqNo( _SwRedlineTbl::GetObject( nSttPos )
									->GetSeqNo(), nSttPos+1, nLookahead )
				: USHRT_MAX;
}

sal_uInt16 SwRedlineTbl::FindPrevOfSeqNo( sal_uInt16 nSttPos, sal_uInt16 nLookahead ) const
{
	return nSttPos ? FindPrevSeqNo( _SwRedlineTbl::GetObject(
										nSttPos )->GetSeqNo(),
									nSttPos-1, nLookahead )
				   : USHRT_MAX;
}

sal_uInt16 SwRedlineTbl::FindNextSeqNo( sal_uInt16 nSeqNo, sal_uInt16 nSttPos,
									sal_uInt16 nLookahead ) const
{
	sal_uInt16 nRet = USHRT_MAX, nEnd;
	if( nSeqNo && nSttPos < _SwRedlineTbl::Count() )
	{
		nEnd = _SwRedlineTbl::Count();
		if( nLookahead && USHRT_MAX != nLookahead &&
			nSttPos + nLookahead < _SwRedlineTbl::Count() )
			nEnd = nSttPos + nLookahead;

		for( ; nSttPos < nEnd; ++nSttPos )
			if( nSeqNo == _SwRedlineTbl::GetObject( nSttPos )->GetSeqNo() )
			{
				nRet = nSttPos;
				break;
			}
	}
	return nRet;
}

sal_uInt16 SwRedlineTbl::FindPrevSeqNo( sal_uInt16 nSeqNo, sal_uInt16 nSttPos,
									sal_uInt16 nLookahead ) const
{
	sal_uInt16 nRet = USHRT_MAX, nEnd;
	if( nSeqNo && nSttPos < _SwRedlineTbl::Count() )
	{
		nEnd = 0;
		if( nLookahead && USHRT_MAX != nLookahead && nSttPos > nLookahead )
			nEnd = nSttPos - nLookahead;

		++nSttPos;
		while( nSttPos > nEnd )
			if( nSeqNo == _SwRedlineTbl::GetObject( --nSttPos )->GetSeqNo() )
			{
				nRet = nSttPos;
				break;
			}
	}
	return nRet;
}

/*  */

SwRedlineExtraData::~SwRedlineExtraData()
{
}

void SwRedlineExtraData::Accept( SwPaM& ) const
{
}

void SwRedlineExtraData::Reject( SwPaM& ) const
{
}

int SwRedlineExtraData::operator == ( const SwRedlineExtraData& ) const
{
	return sal_False;
}


SwRedlineExtraData_FmtColl::SwRedlineExtraData_FmtColl( const String& rColl,
												sal_uInt16 nPoolFmtId,
												const SfxItemSet* pItemSet )
	: sFmtNm(rColl), pSet(0), nPoolId(nPoolFmtId)
{
	if( pItemSet && pItemSet->Count() )
		pSet = new SfxItemSet( *pItemSet );
}

SwRedlineExtraData_FmtColl::~SwRedlineExtraData_FmtColl()
{
	delete pSet;
}

SwRedlineExtraData* SwRedlineExtraData_FmtColl::CreateNew() const
{
	return new SwRedlineExtraData_FmtColl( sFmtNm, nPoolId, pSet );
}

void SwRedlineExtraData_FmtColl::Reject( SwPaM& rPam ) const
{
	SwDoc* pDoc = rPam.GetDoc();

// was ist mit Undo ? ist das abgeschaltet ??
	SwTxtFmtColl* pColl = USHRT_MAX == nPoolId
							? pDoc->FindTxtFmtCollByName( sFmtNm )
							: pDoc->GetTxtCollFromPool( nPoolId );
	if( pColl )
        pDoc->SetTxtFmtColl( rPam, pColl, false );

	if( pSet )
	{
		rPam.SetMark();
		SwPosition& rMark = *rPam.GetMark();
		SwTxtNode* pTNd = rMark.nNode.GetNode().GetTxtNode();
		if( pTNd )
		{
			rMark.nContent.Assign( pTNd, pTNd->GetTxt().Len() );

            if( pTNd->HasSwAttrSet() )
			{
				// nur die setzen, die nicht mehr vorhanden sind. Andere
				// koennen jetzt veraendert drin stehen, aber die werden
				// nicht angefasst.
				SfxItemSet aTmp( *pSet );
				aTmp.Differentiate( *pTNd->GetpSwAttrSet() );
                pDoc->InsertItemSet( rPam, aTmp, 0 );
            }
            else
            {
                pDoc->InsertItemSet( rPam, *pSet, 0 );
            }
        }
		rPam.DeleteMark();
	}
}

int SwRedlineExtraData_FmtColl::operator == ( const SwRedlineExtraData& r) const
{
	const SwRedlineExtraData_FmtColl& rCmp = (SwRedlineExtraData_FmtColl&)r;
	return sFmtNm == rCmp.sFmtNm && nPoolId == rCmp.nPoolId &&
			( ( !pSet && !rCmp.pSet ) ||
			   ( pSet && rCmp.pSet && *pSet == *rCmp.pSet ) );
}

void SwRedlineExtraData_FmtColl::SetItemSet( const SfxItemSet& rSet )
{
	delete pSet;
	if( rSet.Count() )
		pSet = new SfxItemSet( rSet );
	else
		pSet = 0;
}


SwRedlineExtraData_Format::SwRedlineExtraData_Format( const SfxItemSet& rSet )
{
	SfxItemIter aIter( rSet );
	const SfxPoolItem* pItem = aIter.FirstItem();
	while( sal_True )
	{
		aWhichIds.Insert( pItem->Which(), aWhichIds.Count() );
		if( aIter.IsAtEnd() )
			break;
		pItem = aIter.NextItem();
	}
}

SwRedlineExtraData_Format::SwRedlineExtraData_Format(
		const SwRedlineExtraData_Format& rCpy )
	: SwRedlineExtraData(), aWhichIds( (sal_uInt8)rCpy.aWhichIds.Count() )
{
	aWhichIds.Insert( &rCpy.aWhichIds, 0 );
}

SwRedlineExtraData_Format::~SwRedlineExtraData_Format()
{
}

SwRedlineExtraData* SwRedlineExtraData_Format::CreateNew() const
{
	return new SwRedlineExtraData_Format( *this );
}

void SwRedlineExtraData_Format::Reject( SwPaM& rPam ) const
{
	SwDoc* pDoc = rPam.GetDoc();

	RedlineMode_t eOld = pDoc->GetRedlineMode();
	pDoc->SetRedlineMode_intern((RedlineMode_t)(eOld & ~(nsRedlineMode_t::REDLINE_ON | nsRedlineMode_t::REDLINE_IGNORE)));

	// eigentlich muesste hier das Attribut zurueck gesetzt werden!!!
	for( sal_uInt16 n = 0, nEnd = aWhichIds.Count(); n < nEnd; ++n )
    {
        pDoc->InsertPoolItem( rPam, *GetDfltAttr( aWhichIds[ n ] ),
                nsSetAttrMode::SETATTR_DONTEXPAND );
    }

	pDoc->SetRedlineMode_intern( eOld );
}

int SwRedlineExtraData_Format::operator == ( const SwRedlineExtraData& rCmp ) const
{
	int nRet = 1;
	sal_uInt16 n = 0, nEnd = aWhichIds.Count();
	if( nEnd != ((SwRedlineExtraData_Format&)rCmp).aWhichIds.Count() )
		nRet = 0;
	else
		for( ; n < nEnd; ++n )
			if( ((SwRedlineExtraData_Format&)rCmp).aWhichIds[n] != aWhichIds[n])
			{
				nRet = 0;
				break;
			}
	return nRet;
}

/*  */

SwRedlineData::SwRedlineData( RedlineType_t eT, sal_uInt16 nAut )
	: pNext( 0 ), pExtraData( 0 ), eType( eT ), nAuthor( nAut ), nSeqNo( 0 )
{
	aStamp.SetSec( 0 );
	aStamp.Set100Sec( 0 );
}

SwRedlineData::SwRedlineData( const SwRedlineData& rCpy, sal_Bool bCpyNext )
	:
	pNext( (bCpyNext && rCpy.pNext) ? new SwRedlineData( *rCpy.pNext ) : 0 ),
	pExtraData( rCpy.pExtraData ? rCpy.pExtraData->CreateNew() : 0 ),
	sComment( rCpy.sComment ), aStamp( rCpy.aStamp ), eType( rCpy.eType ),
	nAuthor( rCpy.nAuthor ), nSeqNo( rCpy.nSeqNo )
{
}

	// fuer sw3io: pNext geht in eigenen Besitz ueber!
SwRedlineData::SwRedlineData(RedlineType_t eT, sal_uInt16 nAut, const DateTime& rDT,
	const String& rCmnt, SwRedlineData *pNxt, SwRedlineExtraData* pData)
	: pNext(pNxt), pExtraData(pData), sComment(rCmnt), aStamp(rDT),
	eType(eT), nAuthor(nAut), nSeqNo(0)
{
}

SwRedlineData::~SwRedlineData()
{
	delete pExtraData;
	delete pNext;
}

	// ExtraData wird kopiert, der Pointer geht also NICHT in den Besitz
	// des RedlineObjectes!
void SwRedlineData::SetExtraData( const SwRedlineExtraData* pData )
{
	delete pExtraData;

	if( pData )
		pExtraData = pData->CreateNew();
	else
		pExtraData = 0;
}

// #111827#
String SwRedlineData::GetDescr() const
{
    String aResult;

    aResult += String(SW_RES(STR_REDLINE_INSERT + GetType()));

    return aResult;
}

/*  */

SwRedline::SwRedline(RedlineType_t eTyp, const SwPaM& rPam )
	: SwPaM( *rPam.GetMark(), *rPam.GetPoint() ),
	pRedlineData( new SwRedlineData( eTyp, GetDoc()->GetRedlineAuthor() ) ),
	pCntntSect( 0 )
{
	bDelLastPara = bIsLastParaDelete = sal_False;
	bIsVisible = sal_True;
	if( !rPam.HasMark() )
		DeleteMark();
}

SwRedline::SwRedline( const SwRedlineData& rData, const SwPaM& rPam )
	: SwPaM( *rPam.GetMark(), *rPam.GetPoint() ),
	pRedlineData( new SwRedlineData( rData )),
	pCntntSect( 0 )
{
	bDelLastPara = bIsLastParaDelete = sal_False;
	bIsVisible = sal_True;
	if( !rPam.HasMark() )
		DeleteMark();
}

SwRedline::SwRedline( const SwRedlineData& rData, const SwPosition& rPos )
	: SwPaM( rPos ),
	pRedlineData( new SwRedlineData( rData )),
	pCntntSect( 0 )
{
	bDelLastPara = bIsLastParaDelete = sal_False;
	bIsVisible = sal_True;
}

SwRedline::SwRedline( const SwRedline& rCpy )
	: SwPaM( *rCpy.GetMark(), *rCpy.GetPoint() ),
	pRedlineData( new SwRedlineData( *rCpy.pRedlineData )),
	pCntntSect( 0 )
{
	bDelLastPara = bIsLastParaDelete = sal_False;
	bIsVisible = sal_True;
	if( !rCpy.HasMark() )
		DeleteMark();
}

SwRedline::~SwRedline()
{
	if( pCntntSect )
	{
		// dann den Content Bereich loeschen
		if( !GetDoc()->IsInDtor() )
			GetDoc()->DeleteSection( &pCntntSect->GetNode() );
		delete pCntntSect;
	}
	delete pRedlineData;
}

// liegt eine gueltige Selektion vor?
sal_Bool SwRedline::HasValidRange() const
{
	const SwNode* pPtNd = &GetPoint()->nNode.GetNode(),
				* pMkNd = &GetMark()->nNode.GetNode();
    if( pPtNd->StartOfSectionNode() == pMkNd->StartOfSectionNode() &&
        !pPtNd->StartOfSectionNode()->IsTableNode() &&
		// JP 18.5.2001: Bug 87222 - invalid if points on the end of content
        // DVO 25.03.2002: #96530# end-of-content only invalid if no content
        //                 index exists
		( pPtNd != pMkNd || GetContentIdx() != NULL ||
          pPtNd != &pPtNd->GetNodes().GetEndOfContent() )
		)
		return sal_True;
	return sal_False;
}

void SwRedline::CallDisplayFunc( sal_uInt16 nLoop )
{
	switch( nsRedlineMode_t::REDLINE_SHOW_MASK & GetDoc()->GetRedlineMode() )
	{
	case nsRedlineMode_t::REDLINE_SHOW_INSERT | nsRedlineMode_t::REDLINE_SHOW_DELETE:
		Show( nLoop );
		break;
	case nsRedlineMode_t::REDLINE_SHOW_INSERT:
		Hide( nLoop );
		break;
	case nsRedlineMode_t::REDLINE_SHOW_DELETE:
		ShowOriginal( nLoop );
		break;
	}
}

void SwRedline::Show( sal_uInt16 nLoop )
{
	if( 1 <= nLoop )
	{
		SwDoc* pDoc = GetDoc();
		RedlineMode_t eOld = pDoc->GetRedlineMode();
		pDoc->SetRedlineMode_intern((RedlineMode_t)(eOld | nsRedlineMode_t::REDLINE_IGNORE));
        ::sw::UndoGuard const undoGuard(pDoc->GetIDocumentUndoRedo());

		switch( GetType() )
		{
		case nsRedlineType_t::REDLINE_INSERT: 			// Inhalt wurde eingefuegt
			bIsVisible = sal_True;
			MoveFromSection();
			break;

		case nsRedlineType_t::REDLINE_DELETE: 			// Inhalt wurde geloescht
			bIsVisible = sal_True;
			MoveFromSection();
			break;

		case nsRedlineType_t::REDLINE_FORMAT:			// Attributierung wurde angewendet
		case nsRedlineType_t::REDLINE_TABLE:				// TabellenStruktur wurde veraendert
			InvalidateRange();
			break;
		default:
			break;
		}
		pDoc->SetRedlineMode_intern( eOld );
    }
}

void SwRedline::Hide( sal_uInt16 nLoop )
{
	SwDoc* pDoc = GetDoc();
	RedlineMode_t eOld = pDoc->GetRedlineMode();
	pDoc->SetRedlineMode_intern((RedlineMode_t)(eOld | nsRedlineMode_t::REDLINE_IGNORE));
    ::sw::UndoGuard const undoGuard(pDoc->GetIDocumentUndoRedo());

	switch( GetType() )
	{
	case nsRedlineType_t::REDLINE_INSERT: 			// Inhalt wurde eingefuegt
		bIsVisible = sal_True;
		if( 1 <= nLoop )
			MoveFromSection();
		break;

	case nsRedlineType_t::REDLINE_DELETE: 			// Inhalt wurde geloescht
		bIsVisible = sal_False;
		switch( nLoop )
		{
		case 0:	MoveToSection();	break;
		case 1:	CopyToSection();	break;
		case 2:	DelCopyOfSection();	break;
		}
		break;

	case nsRedlineType_t::REDLINE_FORMAT:			// Attributierung wurde angewendet
	case nsRedlineType_t::REDLINE_TABLE:				// TabellenStruktur wurde veraendert
		if( 1 <= nLoop )
			InvalidateRange();
		break;
	default:
		break;
	}
	pDoc->SetRedlineMode_intern( eOld );
}

void SwRedline::ShowOriginal( sal_uInt16 nLoop )
{
	SwDoc* pDoc = GetDoc();
	RedlineMode_t eOld = pDoc->GetRedlineMode();
	SwRedlineData* pCur;

	pDoc->SetRedlineMode_intern((RedlineMode_t)(eOld | nsRedlineMode_t::REDLINE_IGNORE));
    ::sw::UndoGuard const undoGuard(pDoc->GetIDocumentUndoRedo());

	// bestimme den Type, ist der erste auf Stack
	for( pCur = pRedlineData; pCur->pNext; )
		pCur = pCur->pNext;

	switch( pCur->eType )
	{
	case nsRedlineType_t::REDLINE_INSERT: 			// Inhalt wurde eingefuegt
		bIsVisible = sal_False;
		switch( nLoop )
		{
		case 0:	MoveToSection();	break;
		case 1:	CopyToSection();	break;
		case 2:	DelCopyOfSection();	break;
		}
		break;

	case nsRedlineType_t::REDLINE_DELETE: 			// Inhalt wurde geloescht
		bIsVisible = sal_True;
		if( 1 <= nLoop )
			MoveFromSection();
		break;

	case nsRedlineType_t::REDLINE_FORMAT:			// Attributierung wurde angewendet
	case nsRedlineType_t::REDLINE_TABLE:				// TabellenStruktur wurde veraendert
		if( 1 <= nLoop )
			InvalidateRange();
		break;
	default:
		break;
	}
	pDoc->SetRedlineMode_intern( eOld );
}


void SwRedline::InvalidateRange()		// das Layout anstossen
{
	sal_uLong nSttNd = GetMark()->nNode.GetIndex(),
			nEndNd = GetPoint()->nNode.GetIndex();
	sal_uInt16 nSttCnt = GetMark()->nContent.GetIndex(),
			nEndCnt = GetPoint()->nContent.GetIndex();

	if( nSttNd > nEndNd || ( nSttNd == nEndNd && nSttCnt > nEndCnt ))
	{
		sal_uLong nTmp = nSttNd; nSttNd = nEndNd; nEndNd = nTmp;
		nTmp = nSttCnt; nSttCnt = nEndCnt; nEndCnt = (sal_uInt16)nTmp;
	}

	SwUpdateAttr aHt( 0, 0, RES_FMT_CHG );
	SwNodes& rNds = GetDoc()->GetNodes();
	SwNode* pNd;
	for( sal_uLong n = nSttNd; n <= nEndNd; ++n )
		if( ND_TEXTNODE == ( pNd = rNds[ n ] )->GetNodeType() )
		{
			aHt.nStart = n == nSttNd ? nSttCnt : 0;
			aHt.nEnd = n == nEndNd ? nEndCnt : ((SwTxtNode*)pNd)->GetTxt().Len();
			((SwTxtNode*)pNd)->ModifyNotification( &aHt, &aHt );
		}
}

/*************************************************************************
 *                      SwRedline::CalcStartEnd()
 * Calculates the start and end position of the intersection rTmp and
 * text node nNdIdx
 *************************************************************************/

void SwRedline::CalcStartEnd( sal_uLong nNdIdx, sal_uInt16& nStart, sal_uInt16& nEnd ) const
{
    const SwPosition *pRStt = Start(), *pREnd = End();
	if( pRStt->nNode < nNdIdx )
	{
		if( pREnd->nNode > nNdIdx )
		{
			nStart = 0;				// Absatz ist komplett enthalten
			nEnd = STRING_LEN;
		}
		else
		{
			ASSERT( pREnd->nNode == nNdIdx,
				"SwRedlineItr::Seek: GetRedlinePos Error" );
			nStart = 0;				// Absatz wird vorne ueberlappt
			nEnd = pREnd->nContent.GetIndex();
		}
	}
	else if( pRStt->nNode == nNdIdx )
	{
		nStart = pRStt->nContent.GetIndex();
		if( pREnd->nNode == nNdIdx )
			nEnd = pREnd->nContent.GetIndex(); // Innerhalb des Absatzes
		else
			nEnd = STRING_LEN;		// Absatz wird hinten ueberlappt
	}
	else
	{
		nStart = STRING_LEN;
		nEnd = STRING_LEN;
	}
}

void SwRedline::MoveToSection()
{
	if( !pCntntSect )
	{
		const SwPosition* pStt = Start(),
						* pEnd = pStt == GetPoint() ? GetMark() : GetPoint();

		SwDoc* pDoc = GetDoc();
		SwPaM aPam( *pStt, *pEnd );
		SwCntntNode* pCSttNd = pStt->nNode.GetNode().GetCntntNode();
		SwCntntNode* pCEndNd = pEnd->nNode.GetNode().GetCntntNode();

		if( !pCSttNd )
		{
			// damit die Indizies der anderen Redlines nicht mitverschoben
			// werden, diese aufs Ende setzen (ist exclusive).
			const SwRedlineTbl& rTbl = pDoc->GetRedlineTbl();
			for( sal_uInt16 n = 0; n < rTbl.Count(); ++n )
			{
				SwRedline* pRedl = rTbl[ n ];
				if( pRedl->GetBound(sal_True) == *pStt )
					pRedl->GetBound(sal_True) = *pEnd;
				if( pRedl->GetBound(sal_False) == *pStt )
					pRedl->GetBound(sal_False) = *pEnd;
			}
		}

		SwStartNode* pSttNd;
		SwNodes& rNds = pDoc->GetNodes();
		if( pCSttNd || pCEndNd )
		{
			SwTxtFmtColl* pColl = (pCSttNd && pCSttNd->IsTxtNode() )
									? ((SwTxtNode*)pCSttNd)->GetTxtColl()
									: (pCEndNd && pCEndNd->IsTxtNode() )
										? ((SwTxtNode*)pCEndNd)->GetTxtColl()
										: pDoc->GetTxtCollFromPool(
												RES_POOLCOLL_STANDARD );

			pSttNd = rNds.MakeTextSection( SwNodeIndex( rNds.GetEndOfRedlines() ),
											SwNormalStartNode, pColl );
			SwTxtNode* pTxtNd = rNds[ pSttNd->GetIndex() + 1 ]->GetTxtNode();

			SwNodeIndex aNdIdx( *pTxtNd );
			SwPosition aPos( aNdIdx, SwIndex( pTxtNd ));
			if( pCSttNd && pCEndNd )
				pDoc->MoveAndJoin( aPam, aPos, IDocumentContentOperations::DOC_MOVEDEFAULT );
			else
			{
				if( pCSttNd && !pCEndNd )
					bDelLastPara = sal_True;
                pDoc->MoveRange( aPam, aPos,
                    IDocumentContentOperations::DOC_MOVEDEFAULT );
			}
		}
		else
		{
			pSttNd = rNds.MakeEmptySection( SwNodeIndex( rNds.GetEndOfRedlines() ),
											SwNormalStartNode );

			SwPosition aPos( *pSttNd->EndOfSectionNode() );
            pDoc->MoveRange( aPam, aPos,
                IDocumentContentOperations::DOC_MOVEDEFAULT );
		}
		pCntntSect = new SwNodeIndex( *pSttNd );

		if( pStt == GetPoint() )
			Exchange();

		DeleteMark();
	}
	else
		InvalidateRange();
}

void SwRedline::CopyToSection()
{
	if( !pCntntSect )
	{
		const SwPosition* pStt = Start(),
						* pEnd = pStt == GetPoint() ? GetMark() : GetPoint();

		SwCntntNode* pCSttNd = pStt->nNode.GetNode().GetCntntNode();
		SwCntntNode* pCEndNd = pEnd->nNode.GetNode().GetCntntNode();

		SwStartNode* pSttNd;
		SwDoc* pDoc = GetDoc();
		SwNodes& rNds = pDoc->GetNodes();

		sal_Bool bSaveCopyFlag = pDoc->IsCopyIsMove(),
			 bSaveRdlMoveFlg = pDoc->IsRedlineMove();
		pDoc->SetCopyIsMove( sal_True );

        // #100619# The IsRedlineMove() flag causes the behaviour of the
        // SwDoc::_CopyFlyInFly method to change, which will eventually be
        // called by the pDoc->Copy line below (through SwDoc::_Copy,
        // SwDoc::CopyWithFlyInFly). This rather obscure bugfix was introduced
        // for #63198# and #64896#, and apparently never really worked.
		pDoc->SetRedlineMove( pStt->nContent == 0 );

		if( pCSttNd )
		{
			SwTxtFmtColl* pColl = (pCSttNd && pCSttNd->IsTxtNode() )
									? ((SwTxtNode*)pCSttNd)->GetTxtColl()
									: pDoc->GetTxtCollFromPool(
												RES_POOLCOLL_STANDARD );

			pSttNd = rNds.MakeTextSection( SwNodeIndex( rNds.GetEndOfRedlines() ),
											SwNormalStartNode, pColl );

			SwNodeIndex aNdIdx( *pSttNd, 1 );
			SwTxtNode* pTxtNd = aNdIdx.GetNode().GetTxtNode();
			SwPosition aPos( aNdIdx, SwIndex( pTxtNd ));
            pDoc->CopyRange( *this, aPos, false );

			// JP 08.10.98: die Vorlage vom EndNode ggfs. mit uebernehmen
			//				- ist im Doc::Copy nicht erwuenscht
			if( pCEndNd && pCEndNd != pCSttNd )
			{
				SwCntntNode* pDestNd = aPos.nNode.GetNode().GetCntntNode();
				if( pDestNd )
				{
					if( pDestNd->IsTxtNode() && pCEndNd->IsTxtNode() )
						((SwTxtNode*)pCEndNd)->CopyCollFmt(
											*(SwTxtNode*)pDestNd );
					else
						pDestNd->ChgFmtColl( pCEndNd->GetFmtColl() );
				}
			}
		}
		else
		{
			pSttNd = rNds.MakeEmptySection( SwNodeIndex( rNds.GetEndOfRedlines() ),
											SwNormalStartNode );

			if( pCEndNd )
			{
				SwPosition aPos( *pSttNd->EndOfSectionNode() );
                pDoc->CopyRange( *this, aPos, false );
			}
			else
			{
				SwNodeIndex aInsPos( *pSttNd->EndOfSectionNode() );
				SwNodeRange aRg( pStt->nNode, 0, pEnd->nNode, 1 );
                pDoc->CopyWithFlyInFly( aRg, 0, aInsPos );
			}
		}
		pCntntSect = new SwNodeIndex( *pSttNd );

		pDoc->SetCopyIsMove( bSaveCopyFlag );
		pDoc->SetRedlineMove( bSaveRdlMoveFlg );
	}
}

void SwRedline::DelCopyOfSection()
{
	if( pCntntSect )
	{
		const SwPosition* pStt = Start(),
						* pEnd = pStt == GetPoint() ? GetMark() : GetPoint();

		SwDoc* pDoc = GetDoc();
		SwPaM aPam( *pStt, *pEnd );
		SwCntntNode* pCSttNd = pStt->nNode.GetNode().GetCntntNode();
		SwCntntNode* pCEndNd = pEnd->nNode.GetNode().GetCntntNode();

		if( !pCSttNd )
		{
			// damit die Indizies der anderen Redlines nicht mitverschoben
			// werden, diese aufs Ende setzen (ist exclusive).
			const SwRedlineTbl& rTbl = pDoc->GetRedlineTbl();
			for( sal_uInt16 n = 0; n < rTbl.Count(); ++n )
			{
				SwRedline* pRedl = rTbl[ n ];
				if( pRedl->GetBound(sal_True) == *pStt )
					pRedl->GetBound(sal_True) = *pEnd;
				if( pRedl->GetBound(sal_False) == *pStt )
					pRedl->GetBound(sal_False) = *pEnd;
			}
		}

		if( pCSttNd && pCEndNd )
        {
            // --> OD 2009-08-20 #i100466#
            // force a <join next> on <delete and join> operation
            pDoc->DeleteAndJoin( aPam, true );
            // <--
        }
		else if( pCSttNd || pCEndNd )
		{
			if( pCSttNd && !pCEndNd )
				bDelLastPara = sal_True;
            pDoc->DeleteRange( aPam );

			if( bDelLastPara )
			{
                // #100611# To prevent dangling references to the paragraph to
                // be deleted, redline that point into this paragraph should be
                // moved to the new end position. Since redlines in the redline
                // table are sorted and the pEnd position is an endnode (see
                // bDelLastPara condition above), only redlines before the
                // current ones can be affected.
				const SwRedlineTbl& rTbl = pDoc->GetRedlineTbl();
				sal_uInt16 n = rTbl.GetPos( this );
                ASSERT( n != USHRT_MAX, "How strange. We don't exist!" );
				for( sal_Bool bBreak = sal_False; !bBreak && n > 0; )
				{
                    --n;
					bBreak = sal_True;
					if( rTbl[ n ]->GetBound(sal_True) == *aPam.GetPoint() )
					{
						rTbl[ n ]->GetBound(sal_True) = *pEnd;
						bBreak = sal_False;
					}
					if( rTbl[ n ]->GetBound(sal_False) == *aPam.GetPoint() )
					{
						rTbl[ n ]->GetBound(sal_False) = *pEnd;
						bBreak = sal_False;
					}
				}

				SwPosition aEnd( *pEnd );
				*GetPoint() = *pEnd;
				*GetMark() = *pEnd;
				DeleteMark();

				aPam.GetBound( sal_True ).nContent.Assign( 0, 0 );
				aPam.GetBound( sal_False ).nContent.Assign( 0, 0 );
				aPam.DeleteMark();
				pDoc->DelFullPara( aPam );
			}
		}
		else
        {
            pDoc->DeleteRange( aPam );
        }

		if( pStt == GetPoint() )
			Exchange();

		DeleteMark();
	}
}

void SwRedline::MoveFromSection()
{
	if( pCntntSect )
	{
		SwDoc* pDoc = GetDoc();
		const SwRedlineTbl& rTbl = pDoc->GetRedlineTbl();
		SvPtrarr aBeforeArr( 16, 16 ), aBehindArr( 16, 16 );
		sal_uInt16 nMyPos = rTbl.GetPos( this );
		ASSERT( this, "this nicht im Array?" );
		sal_Bool bBreak = sal_False;
		sal_uInt16 n;

		for( n = nMyPos+1; !bBreak && n < rTbl.Count(); ++n )
		{
			bBreak = sal_True;
			if( rTbl[ n ]->GetBound(sal_True) == *GetPoint() )
			{
				void* pTmp = &rTbl[ n ]->GetBound(sal_True);
				aBehindArr.Insert( pTmp, aBehindArr.Count());
				bBreak = sal_False;
			}
			if( rTbl[ n ]->GetBound(sal_False) == *GetPoint() )
			{
				void* pTmp = &rTbl[ n ]->GetBound(sal_False);
				aBehindArr.Insert( pTmp, aBehindArr.Count() );
				bBreak = sal_False;
			}
		}
		for( bBreak = sal_False, n = nMyPos; !bBreak && n ; )
		{
			--n;
			bBreak = sal_True;
			if( rTbl[ n ]->GetBound(sal_True) == *GetPoint() )
			{
				void* pTmp = &rTbl[ n ]->GetBound(sal_True);
				aBeforeArr.Insert( pTmp, aBeforeArr.Count() );
				bBreak = sal_False;
			}
			if( rTbl[ n ]->GetBound(sal_False) == *GetPoint() )
			{
				void* pTmp = &rTbl[ n ]->GetBound(sal_False);
				aBeforeArr.Insert( pTmp, aBeforeArr.Count() );
				bBreak = sal_False;
			}
		}

        // --> OD 2009-03-17 #i95711#
        const SwNode* pKeptCntntSectNode( &pCntntSect->GetNode() );
        // <--
		{
			SwPaM aPam( pCntntSect->GetNode(),
						*pCntntSect->GetNode().EndOfSectionNode(), 1,
						( bDelLastPara ? -2 : -1 ) );
			SwCntntNode* pCNd = aPam.GetCntntNode();
			if( pCNd )
				aPam.GetPoint()->nContent.Assign( pCNd, pCNd->Len() );
			else
				aPam.GetPoint()->nNode++;

			SwFmtColl* pColl = pCNd && pCNd->Len() && aPam.GetPoint()->nNode !=
										aPam.GetMark()->nNode
								? pCNd->GetFmtColl() : 0;

			SwNodeIndex aNdIdx( GetPoint()->nNode, -1 );
			sal_uInt16 nPos = GetPoint()->nContent.GetIndex();

			SwPosition aPos( *GetPoint() );
			if( bDelLastPara && *aPam.GetPoint() == *aPam.GetMark() )
			{
				aPos.nNode--;

				pDoc->AppendTxtNode( aPos );
            }
            else
            {
                pDoc->MoveRange( aPam, aPos,
                    IDocumentContentOperations::DOC_MOVEALLFLYS );
            }

			SetMark();
			*GetPoint() = aPos;
			GetMark()->nNode = aNdIdx.GetIndex() + 1;
			pCNd = GetMark()->nNode.GetNode().GetCntntNode();
			GetMark()->nContent.Assign( pCNd, nPos );

			if( bDelLastPara )
			{
				GetPoint()->nNode++;
				GetPoint()->nContent.Assign( pCNd = GetCntntNode(), 0 );
				bDelLastPara = sal_False;
			}
			else if( pColl )
				pCNd = GetCntntNode();

			if( pColl && pCNd )
				pCNd->ChgFmtColl( pColl );
		}
        // --> OD 2009-03-17 #i95771#
        // Under certain conditions the previous <SwDoc::Move(..)> has already
        // remove the change tracking section of this <SwRedline> instance from
        // the change tracking nodes area.
        // Thus, check, if <pCntntSect> still points to the change tracking section
        // by comparing it with the "indexed" <SwNode> instance copied before
        // perform the intrinsic move.
        // Note: Such condition is e.g. a "delete" change tracking only containing a table.
        if ( &pCntntSect->GetNode() == pKeptCntntSectNode )
        {
            pDoc->DeleteSection( &pCntntSect->GetNode() );
        }
        // <--
		delete pCntntSect, pCntntSect = 0;

        // #100611# adjustment of redline table positions must take start and
        // end into account, not point and mark.
		for( n = 0; n < aBeforeArr.Count(); ++n )
			*(SwPosition*)aBeforeArr[ n ] = *Start();
		for( n = 0; n < aBehindArr.Count(); ++n )
			*(SwPosition*)aBehindArr[ n ] = *End();
	}
	else
		InvalidateRange();
}

// fuers Undo
void SwRedline::SetContentIdx( const SwNodeIndex* pIdx )
{
	if( pIdx && !pCntntSect )
	{
		pCntntSect = new SwNodeIndex( *pIdx );
		bIsVisible = sal_False;
	}
	else if( !pIdx && pCntntSect )
	{
		delete pCntntSect, pCntntSect = 0;
		bIsVisible = sal_False;
	}
#ifdef DBG_UTIL
	else
		ASSERT( !this, "das ist keine gueltige Operation" );
#endif
}

sal_Bool SwRedline::CanCombine( const SwRedline& rRedl ) const
{
	return	IsVisible() && rRedl.IsVisible() &&
			pRedlineData->CanCombine( *rRedl.pRedlineData );
}

void SwRedline::PushData( const SwRedline& rRedl, sal_Bool bOwnAsNext )
{
//	SwRedlineData* pNew = new SwRedlineData( rRedl.GetType(),
//											 rRedl.GetAuthor() );
	SwRedlineData* pNew = new SwRedlineData( *rRedl.pRedlineData, sal_False );
	if( bOwnAsNext )
	{
		pNew->pNext = pRedlineData;
		pRedlineData = pNew;
	}
	else
	{
		pNew->pNext = pRedlineData->pNext;
		pRedlineData->pNext = pNew;
	}
}

sal_Bool SwRedline::PopData()
{
	if( !pRedlineData->pNext )
		return sal_False;
	SwRedlineData* pCur = pRedlineData;
	pRedlineData = pCur->pNext;
	pCur->pNext = 0;
	delete pCur;
	return sal_True;
}

sal_uInt16 SwRedline::GetStackCount() const
{
	sal_uInt16 nRet = 1;
	for( SwRedlineData* pCur = pRedlineData; pCur->pNext; ++nRet )
		pCur = pCur->pNext;
	return nRet;
}

// -> #111827#
sal_uInt16 SwRedline::GetAuthor( sal_uInt16 nPos ) const
{
    return GetRedlineData(nPos).nAuthor;
}

const String& SwRedline::GetAuthorString( sal_uInt16 nPos ) const
{
    return SW_MOD()->GetRedlineAuthor(GetRedlineData(nPos).nAuthor);
}

const DateTime& SwRedline::GetTimeStamp( sal_uInt16 nPos ) const
{
    return GetRedlineData(nPos).aStamp;
}

RedlineType_t SwRedline::GetRealType( sal_uInt16 nPos ) const
{
    return GetRedlineData(nPos).eType;
}

const String& SwRedline::GetComment( sal_uInt16 nPos ) const
{
    return GetRedlineData(nPos).sComment;
}
// <- #111827#

int SwRedline::operator==( const SwRedline& rCmp ) const
{
	return this == &rCmp;
}

int SwRedline::operator<( const SwRedline& rCmp ) const
{
    sal_Bool nResult = sal_False;

    if (*Start() < *rCmp.Start())
        nResult = sal_True;
    else if (*Start() == *rCmp.Start())
        if (*End() < *rCmp.End())
            nResult = sal_True;

    return nResult;
}

// -> #111827#
const SwRedlineData & SwRedline::GetRedlineData(sal_uInt16 nPos) const
{
    SwRedlineData * pCur = pRedlineData;

    while (nPos > 0 && NULL != pCur->pNext)
    {
        pCur = pCur->pNext;

        nPos--;
    }

	ASSERT( 0 == nPos, "Pos angabe ist zu gross" );

    return *pCur;
}

String SwRedline::GetDescr(sal_uInt16 nPos)
{
    String aResult;

    // get description of redline data (e.g.: "insert $1")
    aResult = GetRedlineData(nPos).GetDescr();

    SwPaM * pPaM = NULL;
    bool bDeletePaM = false;

    // if this redline is visible the content is in this PaM
    if (NULL == pCntntSect)
    {
        pPaM = this;
    }
    else // otherwise it is saved in pCntntSect
    {
        SwNodeIndex aTmpIdx( *pCntntSect->GetNode().EndOfSectionNode() );
        pPaM = new SwPaM(*pCntntSect, aTmpIdx );
        bDeletePaM = true;
    }

    // replace $1 in description by description of the redlines text
    String aTmpStr;
    aTmpStr += String(SW_RES(STR_START_QUOTE));
    aTmpStr += ShortenString(pPaM->GetTxt(), nUndoStringLength,
                             String(SW_RES(STR_LDOTS)));
    aTmpStr += String(SW_RES(STR_END_QUOTE));

    SwRewriter aRewriter;
    aRewriter.AddRule(UNDO_ARG1, aTmpStr);

    aResult = aRewriter.Apply(aResult);

    if (bDeletePaM)
        delete pPaM;

    return aResult;
}
// <- #111827#


bool SwDoc::IsInRedlines(const SwNode & rNode) const
{
    SwPosition aPos(rNode);
    SwNode & rEndOfRedlines = GetNodes().GetEndOfRedlines();
    SwPaM aPam(SwPosition(*rEndOfRedlines.StartOfSectionNode()),
               SwPosition(rEndOfRedlines));

    return aPam.ContainsPosition(aPos) ? true : false;
}
