sw: implement proper Undo for SwDoc::UpdateRsid

This is annoying because it's not possible to use StartUndo/EndUndo
because that would break grouping via SwUndoInsert::CanGrouping();
also SwUndoAttr is somehow incapable of removing the inserted hints of a
grouped insert (it seems to leave no-length hints behind); so add an
explicit call to DeleteAttributes which should avoid the no-length
hints.

Change-Id: I1533daed9b2cf59886f380141b4eace4b22c15e0
diff --git a/sw/inc/doc.hxx b/sw/inc/doc.hxx
index ee66745..e3eeb61 100644
--- a/sw/inc/doc.hxx
+++ b/sw/inc/doc.hxx
@@ -866,7 +866,6 @@
    virtual bool Overwrite(const SwPaM &rRg, const String& rStr);
    virtual bool InsertString(const SwPaM &rRg, const String&,
              const enum InsertFlags nInsertMode = INS_EMPTYEXPAND );
    virtual bool UpdateRsid( SwTxtNode *pTxtNode, xub_StrLen nStt, xub_StrLen nEnd );
    virtual bool UpdateParRsid( SwTxtNode *pTxtNode, sal_uInt32 nVal = 0 );
    virtual bool UpdateRsid( const SwPaM &rRg, xub_StrLen nLen );
    virtual SwFlyFrmFmt* Insert(const SwPaM &rRg, const String& rGrfName, const String& rFltName, const Graphic* pGraphic,
diff --git a/sw/source/core/doc/doc.cxx b/sw/source/core/doc/doc.cxx
index 42aa6df..139735d 100644
--- a/sw/source/core/doc/doc.cxx
+++ b/sw/source/core/doc/doc.cxx
@@ -52,7 +52,6 @@
#include <editeng/forbiddencharacterstable.hxx>
#include <svx/svdmodel.hxx>
#include <editeng/pbinitem.hxx>
#include <editeng/rsiditem.hxx>
#include <unotools/charclass.hxx>
#include <unotools/localedatawrapper.hxx>
#include <vcl/timer.hxx>
@@ -1111,40 +1110,6 @@
    return 0;
}

/// Set the rsid from nStt to nEnd of pTxtNode to the current session number
bool SwDoc::UpdateRsid( SwTxtNode *pTxtNode, xub_StrLen nStt, xub_StrLen nEnd )
{
    if ( !pTxtNode )
    {
        return false;
    }

    SvxRsidItem aRsid( mnRsid, RES_CHRATR_RSID );
    SwTxtAttr* pAttr = MakeTxtAttr( *this, aRsid, nStt, nEnd );
    return pTxtNode->InsertHint( pAttr, INS_DEFAULT );
}

/// Set the rsid of the next nLen symbols of rRg to the current session number
bool SwDoc::UpdateRsid( const SwPaM &rRg, const xub_StrLen nLen )
{
    const SwPosition* pPos = rRg.GetPoint();
    SwTxtNode *pTxtNode = pPos->nNode.GetNode().GetTxtNode();
    xub_StrLen nInsPos = pPos->nContent.GetIndex();

    return UpdateRsid( pTxtNode, nInsPos - nLen, nInsPos );
}

bool SwDoc::UpdateParRsid( SwTxtNode *pTxtNode, sal_uInt32 nVal )
{
    if ( !pTxtNode )
    {
        return false;
    }

    SvxRsidItem aRsid( nVal ? nVal : mnRsid, RES_PARATR_RSID );
    return pTxtNode->SetAttr( aRsid );
}

void SwDoc::SetDocStat( const SwDocStat& rStat )
{
    *mpDocStat = rStat;
diff --git a/sw/source/core/doc/docfmt.cxx b/sw/source/core/doc/docfmt.cxx
index 49a36da..748b5b2 100644
--- a/sw/source/core/doc/docfmt.cxx
+++ b/sw/source/core/doc/docfmt.cxx
@@ -26,6 +26,7 @@
#include <editeng/langitem.hxx>
#include <editeng/lrspitem.hxx>
#include <editeng/formatbreakitem.hxx>
#include <editeng/rsiditem.hxx>
#include <svl/whiter.hxx>
#include <svl/zforlist.hxx>
#include <comphelper/processfactory.hxx>
@@ -44,6 +45,7 @@
#include <pam.hxx>
#include <UndoCore.hxx>
#include <UndoAttribute.hxx>
#include <UndoInsert.hxx>
#include <ndgrf.hxx>
#include <pagedesc.hxx>         // For special treatment in InsFrmFmt
#include <rolbck.hxx>           // Undo-Attr
@@ -63,6 +65,7 @@
#include <fmtautofmt.hxx>
#include <istyleaccess.hxx>
#include <SwUndoFmt.hxx>
#include <UndoManager.hxx>
#include <docsh.hxx>

using namespace ::com::sun::star::i18n;
@@ -1098,6 +1101,47 @@
    return bRet;
}

/// Set the rsid of the next nLen symbols of rRg to the current session number
bool SwDoc::UpdateRsid( const SwPaM &rRg, const xub_StrLen nLen )
{
    SwTxtNode *pTxtNode = rRg.GetPoint()->nNode.GetNode().GetTxtNode();
    if (!pTxtNode)
    {
        return false;
    }
    xub_StrLen const nStart(rRg.GetPoint()->nContent.GetIndex() - nLen);
    SvxRsidItem aRsid( mnRsid, RES_CHRATR_RSID );

    SfxItemSet aSet(GetAttrPool(), RES_CHRATR_RSID, RES_CHRATR_RSID);
    aSet.Put(aRsid);
    bool const bRet(pTxtNode->SetAttr(aSet, nStart,
        rRg.GetPoint()->nContent.GetIndex(), nsSetAttrMode::SETATTR_DEFAULT));

    if (bRet && GetIDocumentUndoRedo().DoesUndo())
    {
        SwUndo *const pLastUndo = GetUndoManager().GetLastUndo();
        SwUndoInsert *const pUndoInsert(dynamic_cast<SwUndoInsert*>(pLastUndo));
        // this function is called after Insert so expects to find SwUndoInsert
        assert(pUndoInsert);
        if (pUndoInsert)
        {
            pUndoInsert->SetWithRsid();
        }
    }
    return bRet;
}

bool SwDoc::UpdateParRsid( SwTxtNode *pTxtNode, sal_uInt32 nVal )
{
    if (!pTxtNode)
    {
        return false;
    }

    SvxRsidItem aRsid( nVal ? nVal : mnRsid, RES_PARATR_RSID );
    return pTxtNode->SetAttr( aRsid );
}

/// Set the attribute according to the stated format.
/// If Undo is enabled, the old values is added to the Undo history.
void SwDoc::SetAttr( const SfxPoolItem& rAttr, SwFmt& rFmt )
diff --git a/sw/source/core/edit/editsh.cxx b/sw/source/core/edit/editsh.cxx
index a13598a..c49cb15 100644
--- a/sw/source/core/edit/editsh.cxx
+++ b/sw/source/core/edit/editsh.cxx
@@ -95,14 +95,17 @@
            const bool bSuccess =
                GetDoc()->InsertString(*_pStartCrsr, rStr, nInsertFlags);
            OSL_ENSURE( bSuccess, "Doc->Insert() failed." );
            (void) bSuccess;

            GetDoc()->UpdateRsid( *_pStartCrsr, rStr.Len() );
            if (bSuccess)
            {
                GetDoc()->UpdateRsid( *_pStartCrsr, rStr.Len() );

            // Set paragraph rsid if beginning of paragraph
            SwTxtNode *pTxtNode = _pStartCrsr->GetPoint()->nNode.GetNode().GetTxtNode();
            if( pTxtNode && pTxtNode->Len() == 1)
                GetDoc()->UpdateParRsid( pTxtNode );
                // Set paragraph rsid if beginning of paragraph
                SwTxtNode *const pTxtNode =
                    _pStartCrsr->GetPoint()->nNode.GetNode().GetTxtNode();
                if( pTxtNode && pTxtNode->Len() == 1)
                    GetDoc()->UpdateParRsid( pTxtNode );
            }

            SaveTblBoxCntnt( _pStartCrsr->GetPoint() );

diff --git a/sw/source/core/inc/UndoInsert.hxx b/sw/source/core/inc/UndoInsert.hxx
index e16644c..b4689d3 100644
--- a/sw/source/core/inc/UndoInsert.hxx
+++ b/sw/source/core/inc/UndoInsert.hxx
@@ -40,6 +40,7 @@
    xub_StrLen nCntnt, nLen;
    sal_Bool bIsWordDelim : 1;
    sal_Bool bIsAppend : 1;
    sal_Bool m_bWithRsid : 1;

    const IDocumentContentOperations::InsertFlags m_nInsertFlags;

@@ -76,6 +77,8 @@
     */
    virtual SwRewriter GetRewriter() const;

    void SetWithRsid() { m_bWithRsid = true; }

    DECL_FIXEDMEMPOOL_NEWDEL(SwUndoInsert)
};

diff --git a/sw/source/core/undo/unins.cxx b/sw/source/core/undo/unins.cxx
index eafb7f4..cbacd83 100644
--- a/sw/source/core/undo/unins.cxx
+++ b/sw/source/core/undo/unins.cxx
@@ -115,6 +115,7 @@
    : SwUndo(UNDO_TYPING), pTxt( 0 ), pRedlData( 0 ),
        nNode( rNd.GetIndex() ), nCntnt(nCnt), nLen(nL),
        bIsWordDelim( bWDelim ), bIsAppend( sal_False )
    , m_bWithRsid(false)
    , m_nInsertFlags(nInsertFlags)
{
    Init(rNd);
@@ -125,6 +126,7 @@
    : SwUndo(UNDO_SPLITNODE), pTxt( 0 ),
        pRedlData( 0 ), nNode( rNd.GetIndex() ), nCntnt(0), nLen(1),
        bIsWordDelim( sal_False ), bIsAppend( sal_True )
    , m_bWithRsid(false)
    , m_nInsertFlags(IDocumentContentOperations::INS_EMPTYEXPAND)
{
    Init(rNd);
@@ -208,8 +210,6 @@
    delete pUndoTxt;
}



void SwUndoInsert::UndoImpl(::sw::UndoRedoContext & rContext)
{
    SwDoc *const pTmpDoc = & rContext.GetDoc();
@@ -249,6 +249,18 @@
                aPaM.GetPoint()->nContent -= nLen;
                if( IDocumentRedlineAccess::IsRedlineOn( GetRedlineMode() ))
                    pTmpDoc->DeleteRedline( aPaM, true, USHRT_MAX );
                if (m_bWithRsid)
                {
                    // RSID was added: remove any CHARFMT/AUTOFMT that may be
                    // set on the deleted text; EraseText will leave empty
                    // ones behind otherwise
                    pTxtNode->DeleteAttributes(RES_TXTATR_AUTOFMT,
                        aPaM.GetPoint()->nContent.GetIndex(),
                        aPaM.GetMark()->nContent.GetIndex());
                    pTxtNode->DeleteAttributes(RES_TXTATR_CHARFMT,
                        aPaM.GetPoint()->nContent.GetIndex(),
                        aPaM.GetMark()->nContent.GetIndex());
                }
                RemoveIdxFromRange( aPaM, sal_False );
                pTxt = new String( pTxtNode->GetTxt().copy(nCntnt-nLen, nLen) );
                pTxtNode->EraseText( aPaM.GetPoint()->nContent, nLen );
@@ -354,6 +366,11 @@
                    m_nInsertFlags) );
                assert(ins.getLength() == pTxt->Len()); // must succeed
                DELETEZ( pTxt );
                if (m_bWithRsid) // re-insert RSID
                {
                    SwPaM pam(*pPam->GetMark(), 0); // mark -> point
                    pTmpDoc->UpdateRsid(pam, ins.getLength());
                }
            }
            else
            {
@@ -384,7 +401,6 @@
    pUndoTxt = GetTxtFromDoc();
}


void SwUndoInsert::RepeatImpl(::sw::RepeatContext & rContext)
{
    if( !nLen )