/**************************************************************
 * 
 * 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"

#define _SVSTDARR_USHORTS
#define _SVSTDARR_USHORTSSORT
#include <UndoAttribute.hxx>

#include <svl/itemiter.hxx>

#include <editeng/tstpitem.hxx>

#include <svx/svdmodel.hxx>
#include <svx/svdpage.hxx>

#include <hintids.hxx>
#include <fmtflcnt.hxx>
#include <txtftn.hxx>
#include <fmtornt.hxx>
#include <fmtanchr.hxx>
#include <fmtfsize.hxx>
#include <frmfmt.hxx>
#include <fmtcntnt.hxx>
#include <ftnidx.hxx>
#include <doc.hxx>
#include <IDocumentUndoRedo.hxx>
#include <IShellCursorSupplier.hxx>
#include <docary.hxx>
#include <swundo.hxx>			// fuer die UndoIds
#include <pam.hxx>
#include <ndtxt.hxx>
#include <swtable.hxx>
#include <swtblfmt.hxx>
#include <UndoCore.hxx>
#include <hints.hxx>
#include <rolbck.hxx>
#include <ndnotxt.hxx>
#include <dcontact.hxx>
#include <ftninfo.hxx>
#include <redline.hxx>
#include <section.hxx>
#include <charfmt.hxx>
#include <switerator.hxx>


// -----------------------------------------------------

SwUndoFmtAttrHelper::SwUndoFmtAttrHelper( SwFmt& rFmt, bool bSvDrwPt )
    : SwClient( &rFmt )
    , m_pUndo( 0 )
    , m_bSaveDrawPt( bSvDrwPt )
{
}

void SwUndoFmtAttrHelper::Modify( const SfxPoolItem* pOld, const SfxPoolItem* pNew )
{
	if( pOld )
	{
        if ( pOld->Which() == RES_OBJECTDYING )
        {   
            CheckRegistration( pOld, pNew );
        }
        else if ( pNew )
        {
		    if( POOLATTR_END >= pOld->Which() )
		    {
                if ( GetUndo() )
                {
                    m_pUndo->PutAttr( *pOld );
                }
                else
                {
                    m_pUndo.reset( new SwUndoFmtAttr( *pOld,
                            *static_cast<SwFmt*>(GetRegisteredInNonConst()), m_bSaveDrawPt ) );
                }
            }
            else if ( RES_ATTRSET_CHG == pOld->Which() )
            {
                if ( GetUndo() )
                {
                    SfxItemIter aIter(
                            *(static_cast<const SwAttrSetChg*>(pOld))->GetChgSet() );
                    const SfxPoolItem* pItem = aIter.GetCurItem();
                    while ( pItem )
                    {
                        m_pUndo->PutAttr( *pItem );
					    if( aIter.IsAtEnd() )
						    break;
					    pItem = aIter.NextItem();
				    }
                }
                else
                {
                    m_pUndo.reset( new SwUndoFmtAttr(
                            *static_cast<const SwAttrSetChg*>(pOld)->GetChgSet(),
                            *static_cast<SwFmt*>(GetRegisteredInNonConst()), m_bSaveDrawPt ) );
                }
            }
        }
	}
}

// -----------------------------------------------------

SwUndoFmtAttr::SwUndoFmtAttr( const SfxItemSet& rOldSet,
                              SwFmt& rChgFmt,
                              bool bSaveDrawPt )
    : SwUndo( UNDO_INSFMTATTR )
    , m_pFmt( &rChgFmt )
      // --> OD 2007-07-11 #i56253#
    , m_pOldSet( new SfxItemSet( rOldSet ) )
      // <--
    , m_nNodeIndex( 0 )
    , m_nFmtWhich( rChgFmt.Which() )
    , m_bSaveDrawPt( bSaveDrawPt )
{
    Init();
}

SwUndoFmtAttr::SwUndoFmtAttr( const SfxPoolItem& rItem, SwFmt& rChgFmt,
                              bool bSaveDrawPt )
    : SwUndo( UNDO_INSFMTATTR )
    , m_pFmt( &rChgFmt )
    , m_pOldSet( m_pFmt->GetAttrSet().Clone( sal_False ) )
    , m_nNodeIndex( 0 )
    , m_nFmtWhich( rChgFmt.Which() )
    , m_bSaveDrawPt( bSaveDrawPt )
{
    m_pOldSet->Put( rItem );
    Init();
}

void SwUndoFmtAttr::Init()
{
    // treat change of anchor specially
    if ( SFX_ITEM_SET == m_pOldSet->GetItemState( RES_ANCHOR, sal_False ))
    {
        SaveFlyAnchor( m_bSaveDrawPt );
    }
    else if ( RES_FRMFMT == m_nFmtWhich )
    {
        SwDoc* pDoc = m_pFmt->GetDoc();
        if (USHRT_MAX != pDoc->GetTblFrmFmts()->GetPos(
                            static_cast<const SwFrmFmtPtr>(m_pFmt)))
        {
            // Table Format: save table position, table formats are volatile!
            SwTable * pTbl = SwIterator<SwTable,SwFmt>::FirstElement( *m_pFmt );
            if ( pTbl )
            {
                m_nNodeIndex = pTbl->GetTabSortBoxes()[ 0 ]->GetSttNd()
                    ->FindTableNode()->GetIndex();
            }
        }
        else if (USHRT_MAX != pDoc->GetSections().GetPos(
                                static_cast<const SwSectionFmtPtr>(m_pFmt)))
        {
            m_nNodeIndex = m_pFmt->GetCntnt().GetCntntIdx()->GetIndex();
        }
        else if ( 0 != dynamic_cast< SwTableBoxFmt* >( m_pFmt ) )
        {
            SwTableBox * pTblBox = SwIterator<SwTableBox,SwFmt>::FirstElement( *m_pFmt );
            if ( pTblBox )
            {
                m_nNodeIndex = pTblBox->GetSttIdx();
            }
        }
    }
}

SwUndoFmtAttr::~SwUndoFmtAttr()
{
}

void SwUndoFmtAttr::UndoImpl(::sw::UndoRedoContext & rContext)
{
    // OD 2004-10-26 #i35443#
    // Important note: <Undo(..)> also called by <ReDo(..)>

    if ( !m_pOldSet.get() || !m_pFmt || !IsFmtInDoc( &rContext.GetDoc() ))
        return;

    // --> OD 2004-10-26 #i35443# - If anchor attribute has been successfull
    // restored, all other attributes are also restored.
    // Thus, keep track of its restoration
    bool bAnchorAttrRestored( false );
    if ( SFX_ITEM_SET == m_pOldSet->GetItemState( RES_ANCHOR, sal_False ))
    {
        bAnchorAttrRestored = RestoreFlyAnchor(rContext);
        if ( bAnchorAttrRestored )
        {
            // Anchor attribute successfull restored.
            // Thus, keep anchor position for redo
            SaveFlyAnchor();
        }
        else
        {
            // Anchor attribute not restored due to invalid anchor position.
            // Thus, delete anchor attribute.
            m_pOldSet->ClearItem( RES_ANCHOR );
        }
    }

    if ( !bAnchorAttrRestored )
    // <--
    {
        SwUndoFmtAttrHelper aTmp( *m_pFmt, m_bSaveDrawPt );
        m_pFmt->SetFmtAttr( *m_pOldSet );
        if ( aTmp.GetUndo() )
        {
            // transfer ownership of helper object's old set
            m_pOldSet = aTmp.GetUndo()->m_pOldSet;
        }
        else
        {
            m_pOldSet->ClearItem();
        }

        if ( RES_FLYFRMFMT == m_nFmtWhich || RES_DRAWFRMFMT == m_nFmtWhich )
        {
            rContext.SetSelections(static_cast<SwFrmFmt*>(m_pFmt), 0);
        }
    }
}

bool SwUndoFmtAttr::IsFmtInDoc( SwDoc* pDoc )
{
    // search for the Format in the Document; if it does not exist any more,
    // the attribute is not restored!
    sal_uInt16 nPos = USHRT_MAX;
    switch ( m_nFmtWhich )
    {
        case RES_TXTFMTCOLL:
            nPos = pDoc->GetTxtFmtColls()->GetPos(
                    static_cast<const SwTxtFmtCollPtr>(m_pFmt) );
            break;

        case RES_GRFFMTCOLL:
            nPos = pDoc->GetGrfFmtColls()->GetPos(
                    static_cast<const SwGrfFmtCollPtr>(m_pFmt) );
            break;

        case RES_CHRFMT:
            nPos = pDoc->GetCharFmts()->GetPos(
                    static_cast<SwCharFmtPtr>(m_pFmt) );
            break;

        case RES_FRMFMT:
            if ( m_nNodeIndex && (m_nNodeIndex < pDoc->GetNodes().Count()) )
            {
                SwNode* pNd = pDoc->GetNodes()[ m_nNodeIndex ];
                if ( pNd->IsTableNode() )
                {
                    m_pFmt =
                        static_cast<SwTableNode*>(pNd)->GetTable().GetFrmFmt();
                    nPos = 0;
                    break;
                }
                else if ( pNd->IsSectionNode() )
                {
                    m_pFmt =
                        static_cast<SwSectionNode*>(pNd)->GetSection().GetFmt();
                    nPos = 0;
                    break;
                }
                else if ( pNd->IsStartNode() && (SwTableBoxStartNode ==
                    static_cast< SwStartNode* >(pNd)->GetStartNodeType()) )
                {
                    SwTableNode* pTblNode = pNd->FindTableNode();
                    if ( pTblNode )
                    {
                        SwTableBox* pBox =
                            pTblNode->GetTable().GetTblBox( m_nNodeIndex );
                        if ( pBox )
                        {
                            m_pFmt = pBox->GetFrmFmt();
                            nPos = 0;
                            break;
                        }
                    }
                }
            }
            // no break!
        case RES_DRAWFRMFMT:
        case RES_FLYFRMFMT:
            nPos = pDoc->GetSpzFrmFmts()->GetPos(
                    static_cast<const SwFrmFmtPtr>(m_pFmt) );
            if ( USHRT_MAX == nPos )
            {
                nPos = pDoc->GetFrmFmts()->GetPos(
                    static_cast<const SwFrmFmtPtr>(m_pFmt) );
            }
            break;
    }

    if ( USHRT_MAX == nPos )
    {
        // Format does not exist; reset
        m_pFmt = 0;
    }

    return 0 != m_pFmt;
}

// prueft, ob es noch im Doc ist!
SwFmt* SwUndoFmtAttr::GetFmt( SwDoc& rDoc )
{
    return m_pFmt && IsFmtInDoc( &rDoc ) ? m_pFmt : 0;
}

void SwUndoFmtAttr::RedoImpl(::sw::UndoRedoContext & rContext)
{
    // --> OD 2004-10-26 #i35443# - Because the undo stores the attributes for
    // redo, the same code as for <Undo(..)> can be applied for <Redo(..)>
    UndoImpl(rContext);
    // <--
}

void SwUndoFmtAttr::RepeatImpl(::sw::RepeatContext & rContext)
{
    if ( !m_pOldSet.get() )
        return;

    SwDoc & rDoc(rContext.GetDoc());

    switch ( m_nFmtWhich )
    {
	case RES_GRFFMTCOLL:
		{
            SwNoTxtNode *const pNd =
                rContext.GetRepeatPaM().GetNode()->GetNoTxtNode();
			if( pNd )
            {
                rDoc.SetAttr( m_pFmt->GetAttrSet(), *pNd->GetFmtColl() );
            }
        }
		break;

	case RES_TXTFMTCOLL:
		{
            SwTxtNode *const pNd =
                rContext.GetRepeatPaM().GetNode()->GetTxtNode();
			if( pNd )
            {
                rDoc.SetAttr( m_pFmt->GetAttrSet(), *pNd->GetFmtColl() );
            }
        }
		break;

//	case RES_CHRFMT:
//	case RES_FRMFMT:

	case RES_FLYFRMFMT:
		{
			// erstal pruefen, ob der Cursor ueberhaupt in einem fliegenden
			// Rahmen steht. Der Weg ist: suche in allen FlyFrmFormaten
			// nach dem FlyCntnt-Attribut und teste ob der Cursor in der
			// entsprechenden Section liegt.
            SwFrmFmt *const pFly =
                rContext.GetRepeatPaM().GetNode()->GetFlyFmt();
			if( pFly )
			{
				// Bug 43672: es duerfen nicht alle Attribute gesetzt werden!
                if (SFX_ITEM_SET ==
                        m_pFmt->GetAttrSet().GetItemState( RES_CNTNT ))
                {
                    SfxItemSet aTmpSet( m_pFmt->GetAttrSet() );
					aTmpSet.ClearItem( RES_CNTNT );
					if( aTmpSet.Count() )
                    {
						rDoc.SetAttr( aTmpSet, *pFly );
                    }
                }
                else
                {
                    rDoc.SetAttr( m_pFmt->GetAttrSet(), *pFly );
                }
            }
			break;
		}
	}
}

SwRewriter SwUndoFmtAttr::GetRewriter() const
{
    SwRewriter aRewriter;

    if (m_pFmt)
    {
        aRewriter.AddRule(UNDO_ARG1, m_pFmt->GetName());
    }

    return aRewriter;
}

void SwUndoFmtAttr::PutAttr( const SfxPoolItem& rItem )
{
    m_pOldSet->Put( rItem );
    if ( RES_ANCHOR == rItem.Which() )
    {
        SaveFlyAnchor( m_bSaveDrawPt );
    }
}

void SwUndoFmtAttr::SaveFlyAnchor( bool bSvDrwPt )
{
	// das Format ist gueltig, sonst wuerde man gar bis hier kommen
	if( bSvDrwPt )
    {
        if ( RES_DRAWFRMFMT == m_pFmt->Which() )
        {
            Point aPt( static_cast<SwFrmFmt*>(m_pFmt)->FindSdrObject()
                            ->GetRelativePos() );
            // store old value as attribute, to keep SwUndoFmtAttr small
            m_pOldSet->Put( SwFmtFrmSize( ATT_VAR_SIZE, aPt.X(), aPt.Y() ) );
        }
/*		else
		{
			pOldSet->Put( pFmt->GetVertOrient() );
			pOldSet->Put( pFmt->GetHoriOrient() );
		}
*/	}

    const SwFmtAnchor& rAnchor =
        static_cast<const SwFmtAnchor&>( m_pOldSet->Get( RES_ANCHOR, sal_False ) );
	if( !rAnchor.GetCntntAnchor() )
		return;

	xub_StrLen nCntnt = 0;
	switch( rAnchor.GetAnchorId() )
	{
    case FLY_AS_CHAR:
    case FLY_AT_CHAR:
		nCntnt = rAnchor.GetCntntAnchor()->nContent.GetIndex();
    case FLY_AT_PARA:
    case FLY_AT_FLY:
        m_nNodeIndex = rAnchor.GetCntntAnchor()->nNode.GetIndex();
		break;
	default:
		return;
	}

	SwFmtAnchor aAnchor( rAnchor.GetAnchorId(), nCntnt );
    m_pOldSet->Put( aAnchor );
}

// --> OD 2004-10-26 #i35443# - Add return value, type <bool>.
// Return value indicates, if anchor attribute is restored.
// Note: If anchor attribute is restored, all other existing attributes
//       are also restored.
bool SwUndoFmtAttr::RestoreFlyAnchor(::sw::UndoRedoContext & rContext)
{
    SwDoc *const pDoc = & rContext.GetDoc();
    SwFlyFrmFmt* pFrmFmt = static_cast<SwFlyFrmFmt*>(m_pFmt);
    const SwFmtAnchor& rAnchor =
        static_cast<const SwFmtAnchor&>( m_pOldSet->Get( RES_ANCHOR, sal_False ) );

	SwFmtAnchor aNewAnchor( rAnchor.GetAnchorId() );
    if (FLY_AT_PAGE != rAnchor.GetAnchorId())
    {
        SwNode* pNd = pDoc->GetNodes()[ m_nNodeIndex  ];

        if (  (FLY_AT_FLY == rAnchor.GetAnchorId())
            ? ( !pNd->IsStartNode() || (SwFlyStartNode !=
                    static_cast<SwStartNode*>(pNd)->GetStartNodeType()) )
            : !pNd->IsTxtNode() )
        {
            // --> OD 2004-10-26 #i35443# - invalid position.
            // Thus, anchor attribute not restored
            return false;
            // <--
        }

		SwPosition aPos( *pNd );
        if ((FLY_AS_CHAR == rAnchor.GetAnchorId()) ||
            (FLY_AT_CHAR == rAnchor.GetAnchorId()))
        {
			aPos.nContent.Assign( (SwTxtNode*)pNd, rAnchor.GetPageNum() );
            if ( aPos.nContent.GetIndex() >
                    static_cast<SwTxtNode*>(pNd)->GetTxt().Len() )
            {
                // --> OD 2004-10-26 #i35443# - invalid position.
                // Thus, anchor attribute not restored
                return false;
                // <--
            }
		}
		aNewAnchor.SetAnchor( &aPos );
	}
	else
		aNewAnchor.SetPageNum( rAnchor.GetPageNum() );

	Point aDrawSavePt, aDrawOldPt;
	if( pDoc->GetCurrentViewShell() )	//swmod 071108//swmod 071225
	{
		if( RES_DRAWFRMFMT == pFrmFmt->Which() )
		{
			// den alten zwischengespeicherten Wert herausholen.
            const SwFmtFrmSize& rOldSize = static_cast<const SwFmtFrmSize&>(
                    m_pOldSet->Get( RES_FRM_SIZE ) );
			aDrawSavePt.X() = rOldSize.GetWidth();
			aDrawSavePt.Y() = rOldSize.GetHeight();
            m_pOldSet->ClearItem( RES_FRM_SIZE );

			// den akt. wieder zwischenspeichern
			aDrawOldPt = pFrmFmt->FindSdrObject()->GetRelativePos();
//JP 08.10.97: ist laut AMA/MA nicht mehr noetig
//			pCont->DisconnectFromLayout();
        }
        else
        {
            pFrmFmt->DelFrms();         // delete Frms
        }
    }

	const SwFmtAnchor &rOldAnch = pFrmFmt->GetAnchor();
    // --> OD 2006-03-13 #i54336#
    // Consider case, that as-character anchored object has moved its anchor position.
    if (FLY_AS_CHAR == rOldAnch.GetAnchorId())
    // <--
	{
		//Bei InCntnt's wird es spannend: Das TxtAttribut muss vernichtet
		//werden. Leider reisst dies neben den Frms auch noch das Format mit
		//in sein Grab. Um dass zu unterbinden loesen wir vorher die
		//Verbindung zwischen Attribut und Format.
		const SwPosition *pPos = rOldAnch.GetCntntAnchor();
		SwTxtNode *pTxtNode = (SwTxtNode*)&pPos->nNode.GetNode();
		ASSERT( pTxtNode->HasHints(), "Missing FlyInCnt-Hint." );
		const xub_StrLen nIdx = pPos->nContent.GetIndex();
        SwTxtAttr * const pHnt =
            pTxtNode->GetTxtAttrForCharAt( nIdx, RES_TXTATR_FLYCNT );
		ASSERT( pHnt && pHnt->Which() == RES_TXTATR_FLYCNT,
					"Missing FlyInCnt-Hint." );
		ASSERT( pHnt && pHnt->GetFlyCnt().GetFrmFmt() == pFrmFmt,
					"Wrong TxtFlyCnt-Hint." );
        const_cast<SwFmtFlyCnt&>(pHnt->GetFlyCnt()).SetFlyFmt();

		//Die Verbindung ist geloest, jetzt muss noch das Attribut vernichtet
		//werden.
        pTxtNode->DeleteAttributes( RES_TXTATR_FLYCNT, nIdx, nIdx );
    }

    {
        m_pOldSet->Put( aNewAnchor );
        SwUndoFmtAttrHelper aTmp( *m_pFmt, m_bSaveDrawPt );
        m_pFmt->SetFmtAttr( *m_pOldSet );
        if ( aTmp.GetUndo() )
        {
            m_nNodeIndex = aTmp.GetUndo()->m_nNodeIndex;
            // transfer ownership of helper object's old set
            m_pOldSet = aTmp.GetUndo()->m_pOldSet;
        }
        else
        {
            m_pOldSet->ClearItem();
        }
    }

    if ( RES_DRAWFRMFMT == pFrmFmt->Which() )
    {
        SwDrawContact *pCont =
            static_cast<SwDrawContact*>(pFrmFmt->FindContactObj());
		// das Draw-Model hat auch noch ein Undo-Object fuer die
		// richtige Position vorbereitet; dieses ist aber relativ.
		// Darum verhinder hier, das durch setzen des Ankers das
		// Contact-Object seine Position aendert.
//JP 08.10.97: ist laut AMA/MA nicht mehr noetig
//			pCont->ConnectToLayout();
		SdrObject* pObj = pCont->GetMaster();

        if( pCont->GetAnchorFrm() && !pObj->IsInserted() )
		{
			ASSERT( pDoc->GetDrawModel(), "RestoreFlyAnchor without DrawModel" );
			pDoc->GetDrawModel()->GetPage( 0 )->InsertObject( pObj );
		}
		pObj->SetRelativePos( aDrawSavePt );

		// den alten Wert wieder zwischenspeichern.
        m_pOldSet->Put(
            SwFmtFrmSize( ATT_VAR_SIZE, aDrawOldPt.X(), aDrawOldPt.Y() ) );
    }

    if (FLY_AS_CHAR == aNewAnchor.GetAnchorId())
    {
		const SwPosition* pPos = aNewAnchor.GetCntntAnchor();
		SwTxtNode* pTxtNd = pPos->nNode.GetNode().GetTxtNode();
        ASSERT( pTxtNd, "no Text Node at position." );
        SwFmtFlyCnt aFmt( pFrmFmt );
        pTxtNd->InsertItem( aFmt, pPos->nContent.GetIndex(), 0 );
    }


	if( RES_DRAWFRMFMT != pFrmFmt->Which() )
		pFrmFmt->MakeFrms();

    rContext.SetSelections(pFrmFmt, 0);

    // --> OD 2004-10-26 #i35443# - anchor attribute restored.
    return true;
    // <--
}

// -----------------------------------------------------

// --> OD 2008-02-12 #newlistlevelattrs#
SwUndoFmtResetAttr::SwUndoFmtResetAttr( SwFmt& rChangedFormat,
                                        const sal_uInt16 nWhichId )
    : SwUndo( UNDO_RESETATTR )
    , m_pChangedFormat( &rChangedFormat )
    , m_nWhichId( nWhichId )
    , m_pOldItem( 0 )
{
    const SfxPoolItem* pItem = 0;
    if (rChangedFormat.GetItemState( nWhichId, sal_False, &pItem ) == SFX_ITEM_SET)
    {
        m_pOldItem.reset( pItem->Clone() );
    }
}

SwUndoFmtResetAttr::~SwUndoFmtResetAttr()
{
}

void SwUndoFmtResetAttr::UndoImpl(::sw::UndoRedoContext &)
{
    if ( m_pOldItem.get() )
    {
        m_pChangedFormat->SetFmtAttr( *m_pOldItem );
    }
}

void SwUndoFmtResetAttr::RedoImpl(::sw::UndoRedoContext &)
{
    if ( m_pOldItem.get() )
    {
        m_pChangedFormat->ResetFmtAttr( m_nWhichId );
    }
}
// <--

// -----------------------------------------------------

SwUndoResetAttr::SwUndoResetAttr( const SwPaM& rRange, sal_uInt16 nFmtId )
    : SwUndo( UNDO_RESETATTR ), SwUndRng( rRange )
    , m_pHistory( new SwHistory )
    , m_nFormatId( nFmtId )
{
}

SwUndoResetAttr::SwUndoResetAttr( const SwPosition& rPos, sal_uInt16 nFmtId )
    : SwUndo( UNDO_RESETATTR )
    , m_pHistory( new SwHistory )
    , m_nFormatId( nFmtId )
{
    nSttNode = nEndNode = rPos.nNode.GetIndex();
    nSttCntnt = nEndCntnt = rPos.nContent.GetIndex();
}

SwUndoResetAttr::~SwUndoResetAttr()
{
}

void SwUndoResetAttr::UndoImpl(::sw::UndoRedoContext & rContext)
{
    // reset old values
    SwDoc & rDoc = rContext.GetDoc();
    m_pHistory->TmpRollback( &rDoc, 0 );
    m_pHistory->SetTmpEnd( m_pHistory->Count() );

    if ((RES_CONDTXTFMTCOLL == m_nFormatId) &&
        (nSttNode == nEndNode) && (nSttCntnt == nEndCntnt))
    {
		SwTxtNode* pTNd = rDoc.GetNodes()[ nSttNode ]->GetTxtNode();
		if( pTNd )
		{
			SwIndex aIdx( pTNd, nSttCntnt );
			pTNd->DontExpandFmt( aIdx, sal_False );
		}
	}

    AddUndoRedoPaM(rContext);
}

void SwUndoResetAttr::RedoImpl(::sw::UndoRedoContext & rContext)
{
    SwDoc & rDoc = rContext.GetDoc();
    SwPaM & rPam = AddUndoRedoPaM(rContext);
    SvUShortsSort* pIdArr = m_Ids.Count() ? &m_Ids : 0;

    switch ( m_nFormatId )
    {
	case RES_CHRFMT:
        rDoc.RstTxtAttrs(rPam);
		break;
	case RES_TXTFMTCOLL:
        rDoc.ResetAttrs(rPam, sal_False, pIdArr );
		break;
	case RES_CONDTXTFMTCOLL:
        rDoc.ResetAttrs(rPam, sal_True, pIdArr );

		break;
	case RES_TXTATR_TOXMARK:
        // special treatment for TOXMarks
        {
			SwTOXMarks aArr;
			SwNodeIndex aIdx( rDoc.GetNodes(), nSttNode );
			SwPosition aPos( aIdx, SwIndex( aIdx.GetNode().GetCntntNode(),
																nSttCntnt ));

			sal_uInt16 nCnt = rDoc.GetCurTOXMark( aPos, aArr );
			if( nCnt )
			{
				if( 1 < nCnt )
				{
                    // search for the right one
                    SwHistoryHint* pHHint = (GetHistory())[ 0 ];
					if( pHHint && HSTRY_SETTOXMARKHNT == pHHint->Which() )
					{
						while( nCnt )
                        {
                            if ( static_cast<SwHistorySetTOXMark*>(pHHint)
                                    ->IsEqual( *aArr[ --nCnt ] ) )
                            {
								++nCnt;
								break;
                            }
                        }
					}
					else
						nCnt = 0;
				}
				// gefunden, also loeschen
				if( nCnt-- )
                {
                    rDoc.DeleteTOXMark( aArr[ nCnt ] );
                }
			}
		}
		break;
	}
}

void SwUndoResetAttr::RepeatImpl(::sw::RepeatContext & rContext)
{
    if (m_nFormatId < RES_FMT_BEGIN)
    {
        return;
    }

    SvUShortsSort* pIdArr = m_Ids.Count() ? &m_Ids : 0;
    switch ( m_nFormatId )
    {
	case RES_CHRFMT:
        rContext.GetDoc().RstTxtAttrs(rContext.GetRepeatPaM());
		break;
	case RES_TXTFMTCOLL:
        rContext.GetDoc().ResetAttrs(rContext.GetRepeatPaM(), false, pIdArr);
		break;
	case RES_CONDTXTFMTCOLL:
        rContext.GetDoc().ResetAttrs(rContext.GetRepeatPaM(), true, pIdArr);
		break;
	}
}


void SwUndoResetAttr::SetAttrs( const SvUShortsSort& rArr )
{
    if ( m_Ids.Count() )
    {
        m_Ids.Remove( 0, m_Ids.Count() );
    }
    m_Ids.Insert( &rArr );
}

// -----------------------------------------------------


SwUndoAttr::SwUndoAttr( const SwPaM& rRange, const SfxPoolItem& rAttr,
                        const SetAttrMode nFlags )
    : SwUndo( UNDO_INSATTR ), SwUndRng( rRange )
    , m_AttrSet( rRange.GetDoc()->GetAttrPool(), rAttr.Which(), rAttr.Which() )
    , m_pHistory( new SwHistory )
    , m_pRedlineData( 0 )
    , m_pRedlineSaveData( 0 )
    , m_nNodeIndex( ULONG_MAX )
    , m_nInsertFlags( nFlags )
{
    m_AttrSet.Put( rAttr );
}

SwUndoAttr::SwUndoAttr( const SwPaM& rRange, const SfxItemSet& rSet,
                        const SetAttrMode nFlags )
    : SwUndo( UNDO_INSATTR ), SwUndRng( rRange )
    , m_AttrSet( rSet )
    , m_pHistory( new SwHistory )
    , m_pRedlineData( 0 )
    , m_pRedlineSaveData( 0 )
    , m_nNodeIndex( ULONG_MAX )
    , m_nInsertFlags( nFlags )
{
}

SwUndoAttr::~SwUndoAttr()
{
}

void SwUndoAttr::SaveRedlineData( const SwPaM& rPam, sal_Bool bIsCntnt )
{
    SwDoc* pDoc = rPam.GetDoc();
    if ( pDoc->IsRedlineOn() )
    {
        m_pRedlineData.reset( new SwRedlineData( bIsCntnt
                                    ? nsRedlineType_t::REDLINE_INSERT
                                    : nsRedlineType_t::REDLINE_FORMAT,
                                pDoc->GetRedlineAuthor() ) );
    }

    m_pRedlineSaveData.reset( new SwRedlineSaveDatas );
    if ( !FillSaveDataForFmt( rPam, *m_pRedlineSaveData ))
    {
        m_pRedlineSaveData.reset(0);
    }

    SetRedlineMode( pDoc->GetRedlineMode() );
    if ( bIsCntnt )
    {
        m_nNodeIndex = rPam.GetPoint()->nNode.GetIndex();
    }
}

void SwUndoAttr::UndoImpl(::sw::UndoRedoContext & rContext)
{
    SwDoc *const pDoc = & rContext.GetDoc();

	RemoveIdx( *pDoc );

	if( IDocumentRedlineAccess::IsRedlineOn( GetRedlineMode() ) )
	{
        SwPaM aPam(pDoc->GetNodes().GetEndOfContent());
        if ( ULONG_MAX != m_nNodeIndex )
        {
            aPam.DeleteMark();
            aPam.GetPoint()->nNode = m_nNodeIndex;
            aPam.GetPoint()->nContent.Assign( aPam.GetCntntNode(), nSttCntnt );
            aPam.SetMark();
            aPam.GetPoint()->nContent++;
            pDoc->DeleteRedline(aPam, false, USHRT_MAX);
		}
		else
		{
			// alle Format-Redlines entfernen, werden ggfs. neu gesetzt
            SetPaM(aPam);
            pDoc->DeleteRedline(aPam, false, nsRedlineType_t::REDLINE_FORMAT);
            if ( m_pRedlineSaveData.get() )
            {
                SetSaveData( *pDoc, *m_pRedlineSaveData );
            }
        }
    }

    const bool bToLast =  (1 == m_AttrSet.Count())
                       && (RES_TXTATR_FIELD <= *m_AttrSet.GetRanges())
                       && (*m_AttrSet.GetRanges() <= RES_TXTATR_ANNOTATION);

    // restore old values
    m_pHistory->TmpRollback( pDoc, 0, !bToLast );
    m_pHistory->SetTmpEnd( m_pHistory->Count() );

    // set cursor onto Undo area
    AddUndoRedoPaM(rContext);
}

void SwUndoAttr::RepeatImpl(::sw::RepeatContext & rContext)
{
    // RefMarks are not repeat capable
    if ( SFX_ITEM_SET != m_AttrSet.GetItemState( RES_TXTATR_REFMARK, sal_False ) )
    {
        rContext.GetDoc().InsertItemSet( rContext.GetRepeatPaM(),
                                           m_AttrSet, m_nInsertFlags );
    }
    else if ( 1 < m_AttrSet.Count() )
    {
        SfxItemSet aTmpSet( m_AttrSet );
        aTmpSet.ClearItem( RES_TXTATR_REFMARK );
        rContext.GetDoc().InsertItemSet( rContext.GetRepeatPaM(),
                                           aTmpSet, m_nInsertFlags );
    }
}

void SwUndoAttr::RedoImpl(::sw::UndoRedoContext & rContext)
{
    SwDoc & rDoc = rContext.GetDoc();
    SwPaM & rPam = AddUndoRedoPaM(rContext);

    if ( m_pRedlineData.get() &&
         IDocumentRedlineAccess::IsRedlineOn( GetRedlineMode() ) )
    {
        RedlineMode_t eOld = rDoc.GetRedlineMode();
        rDoc.SetRedlineMode_intern(static_cast<RedlineMode_t>(
                    eOld & ~nsRedlineMode_t::REDLINE_IGNORE));
        rDoc.InsertItemSet( rPam, m_AttrSet, m_nInsertFlags );

        if ( ULONG_MAX != m_nNodeIndex )
        {
            rPam.SetMark();
            if ( rPam.Move( fnMoveBackward ) )
            {
                rDoc.AppendRedline( new SwRedline( *m_pRedlineData, rPam ),
                        true);
            }
            rPam.DeleteMark();
        }
        else
        {
            rDoc.AppendRedline( new SwRedline( *m_pRedlineData, rPam ), true);
        }

        rDoc.SetRedlineMode_intern( eOld );
    }
    else
    {
        rDoc.InsertItemSet( rPam, m_AttrSet, m_nInsertFlags );
    }
}


void SwUndoAttr::RemoveIdx( SwDoc& rDoc )
{
    if ( SFX_ITEM_SET != m_AttrSet.GetItemState( RES_TXTATR_FTN, sal_False ))
		return ;

    SwHistoryHint* pHstHnt;
	SwNodes& rNds = rDoc.GetNodes();
    for ( sal_uInt16 n = 0; n < m_pHistory->Count(); ++n )
    {
		xub_StrLen nCntnt = 0;
		sal_uLong nNode = 0;
        pHstHnt = (*m_pHistory)[ n ];
        switch ( pHstHnt->Which() )
        {
            case HSTRY_RESETTXTHNT:
                {
                    SwHistoryResetTxt * pHistoryHint
                        = static_cast<SwHistoryResetTxt*>(pHstHnt);
                    if ( RES_TXTATR_FTN == pHistoryHint->GetWhich() )
                    {
                        nNode = pHistoryHint->GetNode();
                        nCntnt = pHistoryHint->GetCntnt();
                    }
                }
                break;

            case HSTRY_RESETATTRSET:
                {
                    SwHistoryResetAttrSet * pHistoryHint
                        = static_cast<SwHistoryResetAttrSet*>(pHstHnt);
                    nCntnt = pHistoryHint->GetCntnt();
                    if ( STRING_MAXLEN != nCntnt )
                    {
                        const SvUShorts& rArr = pHistoryHint->GetArr();
                        for ( sal_uInt16 i = rArr.Count(); i; )
                        {
                            if ( RES_TXTATR_FTN == rArr[ --i ] )
                            {
                                nNode = pHistoryHint->GetNode();
                                break;
                            }
                        }
                    }
                }
                break;

            default:
                break;
        }

		if( nNode )
		{
			SwTxtNode* pTxtNd = rNds[ nNode ]->GetTxtNode();
			if( pTxtNd )
			{
                SwTxtAttr *const pTxtHt =
                    pTxtNd->GetTxtAttrForCharAt(nCntnt, RES_TXTATR_FTN);
				if( pTxtHt )
				{
					// ok, dann hole mal die Werte
                    SwTxtFtn* pFtn = static_cast<SwTxtFtn*>(pTxtHt);
					RemoveIdxFromSection( rDoc, pFtn->GetStartNode()->GetIndex() );
					return ;
				}
			}
		}
	}
}

// -----------------------------------------------------

SwUndoDefaultAttr::SwUndoDefaultAttr( const SfxItemSet& rSet )
    : SwUndo( UNDO_SETDEFTATTR )
    , m_pOldSet( 0 )
    , m_pTabStop( 0 )
{
	const SfxPoolItem* pItem;
	if( SFX_ITEM_SET == rSet.GetItemState( RES_PARATR_TABSTOP, sal_False, &pItem ) )
    {
        // store separately, because it may change!
        m_pTabStop.reset( static_cast<SvxTabStopItem*>(pItem->Clone()) );
        if ( 1 != rSet.Count() ) // are there more attributes?
        {
            m_pOldSet.reset( new SfxItemSet( rSet ) );
        }
    }
    else
    {
        m_pOldSet.reset( new SfxItemSet( rSet ) );
    }
}

SwUndoDefaultAttr::~SwUndoDefaultAttr()
{
}

void SwUndoDefaultAttr::UndoImpl(::sw::UndoRedoContext & rContext)
{
    SwDoc & rDoc = rContext.GetDoc();
    if ( m_pOldSet.get() )
    {
        SwUndoFmtAttrHelper aTmp(
                *const_cast<SwTxtFmtColl*>(rDoc.GetDfltTxtFmtColl()) );
        rDoc.SetDefault( *m_pOldSet );
        m_pOldSet.reset( 0 );
        if ( aTmp.GetUndo() )
        {
            // transfer ownership of helper object's old set
            m_pOldSet = aTmp.GetUndo()->m_pOldSet;
        }
    }
    if ( m_pTabStop.get() )
    {
        SvxTabStopItem* pOld = static_cast<SvxTabStopItem*>(
                rDoc.GetDefault( RES_PARATR_TABSTOP ).Clone() );
        rDoc.SetDefault( *m_pTabStop );
        m_pTabStop.reset( pOld );
    }
}

void SwUndoDefaultAttr::RedoImpl(::sw::UndoRedoContext & rContext)
{
    UndoImpl(rContext);
}

// -----------------------------------------------------

SwUndoMoveLeftMargin::SwUndoMoveLeftMargin(
            const SwPaM& rPam, sal_Bool bFlag, sal_Bool bMod )
    : SwUndo( bFlag ? UNDO_INC_LEFTMARGIN : UNDO_DEC_LEFTMARGIN )
    , SwUndRng( rPam )
    , m_pHistory( new SwHistory )
    , m_bModulus( bMod )
{
}

SwUndoMoveLeftMargin::~SwUndoMoveLeftMargin()
{
}

void SwUndoMoveLeftMargin::UndoImpl(::sw::UndoRedoContext & rContext)
{
    SwDoc & rDoc = rContext.GetDoc();

    // restore old values
    m_pHistory->TmpRollback( & rDoc, 0 );
    m_pHistory->SetTmpEnd( m_pHistory->Count() );

    AddUndoRedoPaM(rContext);
}

void SwUndoMoveLeftMargin::RedoImpl(::sw::UndoRedoContext & rContext)
{
    SwDoc & rDoc = rContext.GetDoc();
    SwPaM & rPam = AddUndoRedoPaM(rContext);

    rDoc.MoveLeftMargin( rPam,
            GetId() == UNDO_INC_LEFTMARGIN, m_bModulus );
}

void SwUndoMoveLeftMargin::RepeatImpl(::sw::RepeatContext & rContext)
{
    SwDoc & rDoc = rContext.GetDoc();
    rDoc.MoveLeftMargin(rContext.GetRepeatPaM(), GetId() == UNDO_INC_LEFTMARGIN,
            m_bModulus );
}

// -----------------------------------------------------

SwUndoChangeFootNote::SwUndoChangeFootNote(
            const SwPaM& rRange, const String& rTxt,
            sal_uInt16 nNum, bool bIsEndNote )
    : SwUndo( UNDO_CHGFTN ), SwUndRng( rRange )
    , m_pHistory( new SwHistory() )
    , m_Text( rTxt )
    , m_nNumber( nNum )
    , m_bEndNote( bIsEndNote )
{
}

SwUndoChangeFootNote::~SwUndoChangeFootNote()
{
}

void SwUndoChangeFootNote::UndoImpl(::sw::UndoRedoContext & rContext)
{
    SwDoc & rDoc = rContext.GetDoc();

    m_pHistory->TmpRollback( &rDoc, 0 );
    m_pHistory->SetTmpEnd( m_pHistory->Count() );

	rDoc.GetFtnIdxs().UpdateAllFtn();

    AddUndoRedoPaM(rContext);
}

void SwUndoChangeFootNote::RedoImpl(::sw::UndoRedoContext & rContext)
{
    SwDoc & rDoc( rContext.GetDoc() );
    SwPaM & rPaM = AddUndoRedoPaM(rContext);
    rDoc.SetCurFtn(rPaM, m_Text, m_nNumber, m_bEndNote);
    SetPaM(rPaM);
}

void SwUndoChangeFootNote::RepeatImpl(::sw::RepeatContext & rContext)
{
    SwDoc & rDoc = rContext.GetDoc();
    rDoc.SetCurFtn( rContext.GetRepeatPaM(), m_Text, m_nNumber, m_bEndNote );
}


// -----------------------------------------------------


SwUndoFootNoteInfo::SwUndoFootNoteInfo( const SwFtnInfo &rInfo )
    : SwUndo( UNDO_FTNINFO )
    , m_pFootNoteInfo( new SwFtnInfo( rInfo ) )
{
}

SwUndoFootNoteInfo::~SwUndoFootNoteInfo()
{
}

void SwUndoFootNoteInfo::UndoImpl(::sw::UndoRedoContext & rContext)
{
    SwDoc & rDoc = rContext.GetDoc();
	SwFtnInfo *pInf = new SwFtnInfo( rDoc.GetFtnInfo() );
    rDoc.SetFtnInfo( *m_pFootNoteInfo );
    m_pFootNoteInfo.reset( pInf );
}

void SwUndoFootNoteInfo::RedoImpl(::sw::UndoRedoContext & rContext)
{
    SwDoc & rDoc = rContext.GetDoc();
	SwFtnInfo *pInf = new SwFtnInfo( rDoc.GetFtnInfo() );
    rDoc.SetFtnInfo( *m_pFootNoteInfo );
    m_pFootNoteInfo.reset( pInf );
}


// -----------------------------------------------------

SwUndoEndNoteInfo::SwUndoEndNoteInfo( const SwEndNoteInfo &rInfo )
    : SwUndo( UNDO_FTNINFO )
    , m_pEndNoteInfo( new SwEndNoteInfo( rInfo ) )
{
}

SwUndoEndNoteInfo::~SwUndoEndNoteInfo()
{
}

void SwUndoEndNoteInfo::UndoImpl(::sw::UndoRedoContext & rContext)
{
    SwDoc & rDoc = rContext.GetDoc();
	SwEndNoteInfo *pInf = new SwEndNoteInfo( rDoc.GetEndNoteInfo() );
    rDoc.SetEndNoteInfo( *m_pEndNoteInfo );
    m_pEndNoteInfo.reset( pInf );
}

void SwUndoEndNoteInfo::RedoImpl(::sw::UndoRedoContext & rContext)
{
    SwDoc & rDoc = rContext.GetDoc();
	SwEndNoteInfo *pInf = new SwEndNoteInfo( rDoc.GetEndNoteInfo() );
    rDoc.SetEndNoteInfo( *m_pEndNoteInfo );
    m_pEndNoteInfo.reset( pInf );
}

// -----------------------------------------------------

SwUndoDontExpandFmt::SwUndoDontExpandFmt( const SwPosition& rPos )
    : SwUndo( UNDO_DONTEXPAND )
    , m_nNodeIndex( rPos.nNode.GetIndex() )
    , m_nContentIndex( rPos.nContent.GetIndex() )
{
}

void SwUndoDontExpandFmt::UndoImpl(::sw::UndoRedoContext & rContext)
{
    SwPaM *const pPam(& rContext.GetCursorSupplier().CreateNewShellCursor());
    SwDoc *const pDoc = & rContext.GetDoc();

	SwPosition& rPos = *pPam->GetPoint();
    rPos.nNode = m_nNodeIndex;
    rPos.nContent.Assign( rPos.nNode.GetNode().GetCntntNode(), m_nContentIndex);
	pDoc->DontExpandFmt( rPos, sal_False );
}


void SwUndoDontExpandFmt::RedoImpl(::sw::UndoRedoContext & rContext)
{
    SwPaM *const pPam(& rContext.GetCursorSupplier().CreateNewShellCursor());
    SwDoc *const pDoc = & rContext.GetDoc();

	SwPosition& rPos = *pPam->GetPoint();
    rPos.nNode = m_nNodeIndex;
    rPos.nContent.Assign( rPos.nNode.GetNode().GetCntntNode(), m_nContentIndex);
	pDoc->DontExpandFmt( rPos );
}

void SwUndoDontExpandFmt::RepeatImpl(::sw::RepeatContext & rContext)
{
    SwPaM & rPam = rContext.GetRepeatPaM();
    SwDoc & rDoc = rContext.GetDoc();
    rDoc.DontExpandFmt( *rPam.GetPoint() );
}