sw_redlinehide_4a: SwAutoCorrDoc iterates frames, not nodes

Adapt this in a similar way, with a DeleteSel() that skips over
delete redlines.

The Replace functions fortunately only have callers that replace 1
character currently, but there is another ReplaceRange() call that
needs a litte more complicated handling.

Change-Id: Idd5c80e96c0f355d3dc965b2f70376258d23e1a3
(cherry picked from commit 9926ea7dd07f1f3d012ddf97941a42bb7fa5717d)
diff --git a/sw/source/core/edit/acorrect.cxx b/sw/source/core/edit/acorrect.cxx
index a78c949..e5ca4d6 100644
--- a/sw/source/core/edit/acorrect.cxx
+++ b/sw/source/core/edit/acorrect.cxx
@@ -27,6 +27,8 @@
#include <editsh.hxx>
#include <doc.hxx>
#include <pam.hxx>
#include <unocrsr.hxx>
#include <txtfrm.hxx>
#include <ndtxt.hxx>
#include <acorrect.hxx>
#include <shellio.hxx>
@@ -100,12 +102,32 @@ SwAutoCorrDoc::~SwAutoCorrDoc()

void SwAutoCorrDoc::DeleteSel( SwPaM& rDelPam )
{
    // this should work with plain SwPaM as well because start and end
    // are always in same node, but since there is GetRanges already...
    std::vector<std::shared_ptr<SwUnoCursor>> ranges;
    if (sw::GetRanges(ranges, *rEditSh.GetDoc(), rDelPam))
    {
        DeleteSelImpl(rDelPam);
    }
    else
    {
        for (auto const& pCursor : ranges)
        {
            DeleteSelImpl(*pCursor);
        }
    }
}

void SwAutoCorrDoc::DeleteSelImpl(SwPaM & rDelPam)
{
    SwDoc* pDoc = rEditSh.GetDoc();
    if( pDoc->IsAutoFormatRedline() )
    {
        // so that also the DelPam be moved,  include it in the
        // Shell-Cursr-Ring !!
        PaMIntoCursorShellRing aTmp( rEditSh, rCursor, rDelPam );
        // ??? is that really necessary - this should never join nodes, so Update should be enough?
//        PaMIntoCursorShellRing aTmp( rEditSh, rCursor, rDelPam );
        assert(rDelPam.GetPoint()->nNode == rDelPam.GetMark()->nNode);
        pDoc->getIDocumentContentOperations().DeleteAndJoin( rDelPam );
    }
    else
@@ -116,8 +138,12 @@ void SwAutoCorrDoc::DeleteSel( SwPaM& rDelPam )

bool SwAutoCorrDoc::Delete( sal_Int32 nStt, sal_Int32 nEnd )
{
    const SwNodeIndex& rNd = rCursor.GetPoint()->nNode;
    SwPaM aSel( rNd, nStt, rNd, nEnd );
    SwTextNode const*const pTextNd = rCursor.GetNode().GetTextNode();
    SwTextFrame const*const pFrame(static_cast<SwTextFrame const*>(
                pTextNd->getLayoutFrame(rEditSh.GetLayout())));
    assert(pFrame);
    SwPaM aSel(pFrame->MapViewToModelPos(TextFrameIndex(nStt)),
               pFrame->MapViewToModelPos(TextFrameIndex(nEnd)));
    DeleteSel( aSel );

    if( bUndoIdInitialized )
@@ -127,7 +153,11 @@ bool SwAutoCorrDoc::Delete( sal_Int32 nStt, sal_Int32 nEnd )

bool SwAutoCorrDoc::Insert( sal_Int32 nPos, const OUString& rText )
{
    SwPaM aPam( rCursor.GetPoint()->nNode.GetNode(), nPos );
    SwTextNode const*const pTextNd = rCursor.GetNode().GetTextNode();
    SwTextFrame const*const pFrame(static_cast<SwTextFrame const*>(
                pTextNd->getLayoutFrame(rEditSh.GetLayout())));
    assert(pFrame);
    SwPaM aPam(pFrame->MapViewToModelPos(TextFrameIndex(nPos)));
    rEditSh.GetDoc()->getIDocumentContentOperations().InsertString( aPam, rText );
    if( !bUndoIdInitialized )
    {
@@ -148,28 +178,43 @@ bool SwAutoCorrDoc::Replace( sal_Int32 nPos, const OUString& rText )

bool SwAutoCorrDoc::ReplaceRange( sal_Int32 nPos, sal_Int32 nSourceLength, const OUString& rText )
{
    SwPaM* pPam = &rCursor;
    if( pPam->GetPoint()->nContent.GetIndex() != nPos )
    {
        pPam = new SwPaM( *rCursor.GetPoint() );
        pPam->GetPoint()->nContent = nPos;
    }
    assert(nSourceLength == 1); // sw_redlinehide: this is currently the case,
    // and ensures that the replace range cannot *contain* delete redlines,
    // so we don't need something along the lines of:
    //    if (sw::GetRanges(ranges, *rEditSh.GetDoc(), aPam))
    //        ReplaceImpl(...)
    //    else
    //        ReplaceImpl(ranges.begin())
    //        for (ranges.begin() + 1; ranges.end(); )
    //            DeleteImpl(*it)

    SwTextNode * const pNd = pPam->GetNode().GetTextNode();
    SwTextNode * const pNd = rCursor.GetNode().GetTextNode();
    if ( !pNd )
    {
        return false;
    }

    SwTextFrame const*const pFrame(static_cast<SwTextFrame const*>(
                pNd->getLayoutFrame(rEditSh.GetLayout())));
    assert(pFrame);
    std::pair<SwTextNode *, sal_Int32> const pos(pFrame->MapViewToModel(TextFrameIndex(nPos)));

    SwPaM* pPam = &rCursor;
    if (pPam->GetPoint()->nNode != *pos.first
        || pPam->GetPoint()->nContent != pos.second)
    {
        pPam = new SwPaM(*pos.first, pos.second);
    }

    // text attributes with dummy characters must not be replaced!
    bool bDoReplace = true;
    sal_Int32 const nLen = rText.getLength();
    for ( sal_Int32 n = 0; n < nLen && n + nPos < pNd->GetText().getLength(); ++n )
    for (sal_Int32 n = 0; n < nLen && n + nPos < pFrame->GetText().getLength(); ++n)
    {
        sal_Unicode const Char = pNd->GetText()[n + nPos];
        if ( ( CH_TXTATR_BREAKWORD == Char || CH_TXTATR_INWORD == Char )
             && pNd->GetTextAttrForCharAt( n + nPos ) )
        sal_Unicode const Char = pFrame->GetText()[n + nPos];
        if (CH_TXTATR_BREAKWORD == Char || CH_TXTATR_INWORD == Char)
        {
            assert(pFrame->MapViewToModel(TextFrameIndex(n+nPos)).first->GetTextAttrForCharAt(pFrame->MapViewToModel(TextFrameIndex(n+nPos)).second));
            bDoReplace = false;
            break;
        }
@@ -181,17 +226,18 @@ bool SwAutoCorrDoc::ReplaceRange( sal_Int32 nPos, sal_Int32 nSourceLength, const

        if( pDoc->IsAutoFormatRedline() )
        {
            if (nPos == pNd->GetText().getLength()) // at the End do an Insert
            if (nPos == pFrame->GetText().getLength()) // at the End do an Insert
            {
                pDoc->getIDocumentContentOperations().InsertString( *pPam, rText );
            }
            else
            {
                assert(pos.second != pos.first->Len()); // must be _before_ char
                PaMIntoCursorShellRing aTmp( rEditSh, rCursor, *pPam );

                pPam->SetMark();
                pPam->GetPoint()->nContent = std::min<sal_Int32>(
                        pNd->GetText().getLength(), nPos + nSourceLength);
                    pos.first->GetText().getLength(), pos.second + nSourceLength);
                pDoc->getIDocumentContentOperations().ReplaceRange( *pPam, rText, false );
                pPam->Exchange();
                pPam->DeleteMark();
@@ -203,7 +249,7 @@ bool SwAutoCorrDoc::ReplaceRange( sal_Int32 nPos, sal_Int32 nSourceLength, const
            {
                pPam->SetMark();
                pPam->GetPoint()->nContent = std::min<sal_Int32>(
                        pNd->GetText().getLength(), nPos + nSourceLength);
                    pos.first->GetText().getLength(), pos.second + nSourceLength);
                pDoc->getIDocumentContentOperations().ReplaceRange( *pPam, rText, false );
                pPam->Exchange();
                pPam->DeleteMark();
@@ -232,8 +278,12 @@ bool SwAutoCorrDoc::ReplaceRange( sal_Int32 nPos, sal_Int32 nSourceLength, const
void SwAutoCorrDoc::SetAttr( sal_Int32 nStt, sal_Int32 nEnd, sal_uInt16 nSlotId,
                                        SfxPoolItem& rItem )
{
    const SwNodeIndex& rNd = rCursor.GetPoint()->nNode;
    SwPaM aPam( rNd, nStt, rNd, nEnd );
    SwTextNode const*const pTextNd = rCursor.GetNode().GetTextNode();
    SwTextFrame const*const pFrame(static_cast<SwTextFrame const*>(
                pTextNd->getLayoutFrame(rEditSh.GetLayout())));
    assert(pFrame);
    SwPaM aPam(pFrame->MapViewToModelPos(TextFrameIndex(nStt)),
               pFrame->MapViewToModelPos(TextFrameIndex(nEnd)));

    SfxItemPool& rPool = rEditSh.GetDoc()->GetAttrPool();
    sal_uInt16 nWhich = rPool.GetWhich( nSlotId, false );
@@ -253,8 +303,12 @@ void SwAutoCorrDoc::SetAttr( sal_Int32 nStt, sal_Int32 nEnd, sal_uInt16 nSlotId,

bool SwAutoCorrDoc::SetINetAttr( sal_Int32 nStt, sal_Int32 nEnd, const OUString& rURL )
{
    const SwNodeIndex& rNd = rCursor.GetPoint()->nNode;
    SwPaM aPam( rNd, nStt, rNd, nEnd );
    SwTextNode const*const pTextNd = rCursor.GetNode().GetTextNode();
    SwTextFrame const*const pFrame(static_cast<SwTextFrame const*>(
                pTextNd->getLayoutFrame(rEditSh.GetLayout())));
    assert(pFrame);
    SwPaM aPam(pFrame->MapViewToModelPos(TextFrameIndex(nStt)),
               pFrame->MapViewToModelPos(TextFrameIndex(nEnd)));

    SfxItemSet aSet( rEditSh.GetDoc()->GetAttrPool(),
                        svl::Items<RES_TXTATR_INETFMT, RES_TXTATR_INETFMT>{} );
@@ -276,18 +330,25 @@ OUString const* SwAutoCorrDoc::GetPrevPara(bool const bAtNormalPos)
    OUString const* pStr(nullptr);

    if( bAtNormalPos || !pIdx )
        pIdx.reset(new SwNodeIndex( rCursor.GetPoint()->nNode, -1 ));
    else
        --(*pIdx);

    SwTextNode* pTNd = pIdx->GetNode().GetTextNode();
    while (pTNd && !pTNd->GetText().getLength())
    {
        --(*pIdx);
        pTNd = pIdx->GetNode().GetTextNode();
        pIdx.reset(new SwNodeIndex(rCursor.GetPoint()->nNode));
    }
    if( pTNd && 0 == pTNd->GetAttrOutlineLevel() )
        pStr = & pTNd->GetText();
    sw::GotoPrevLayoutTextFrame(*pIdx, rEditSh.GetLayout());

    SwTextFrame const* pFrame(nullptr);
    for (SwTextNode * pTextNd = pIdx->GetNode().GetTextNode();
             pTextNd; pTextNd = pIdx->GetNode().GetTextNode())
    {
        pFrame = static_cast<SwTextFrame const*>(
                pTextNd->getLayoutFrame(rEditSh.GetLayout()));
        if (pFrame && !pFrame->GetText().isEmpty())
        {
            break;
        }
        sw::GotoPrevLayoutTextFrame(*pIdx, rEditSh.GetLayout());
    }
    if (pFrame && 0 == pFrame->GetTextNodeForParaProps()->GetAttrOutlineLevel())
        pStr = & pFrame->GetText();

    if( bUndoIdInitialized )
        bUndoIdInitialized = true;
@@ -316,20 +377,24 @@ bool SwAutoCorrDoc::ChgAutoCorrWord( sal_Int32& rSttPos, sal_Int32 nEndPos,
        eLang = GetAppLanguage();
    LanguageTag aLanguageTag( eLang);

    SwTextFrame const*const pFrame(static_cast<SwTextFrame const*>(
                pTextNd->getLayoutFrame(rEditSh.GetLayout())));
    assert(pFrame);

    //JP 22.04.99: Bug 63883 - Special treatment for dots.
    bool bLastCharIsPoint = nEndPos < pTextNd->GetText().getLength() &&
                            ('.' == pTextNd->GetText()[nEndPos]);
    bool bLastCharIsPoint = nEndPos < pFrame->GetText().getLength() &&
                            ('.' == pFrame->GetText()[nEndPos]);

    const SvxAutocorrWord* pFnd = rACorrect.SearchWordsInList(
                                pTextNd->GetText(), rSttPos, nEndPos, *this, aLanguageTag );
                pFrame->GetText(), rSttPos, nEndPos, *this, aLanguageTag);
    SwDoc* pDoc = rEditSh.GetDoc();
    if( pFnd )
    {
        // replace also last colon of keywords surrounded by colons (for example, ":name:")
        bool replaceLastChar = pFnd->GetShort()[0] == ':' && pFnd->GetShort().endsWith(":");

        const SwNodeIndex& rNd = rCursor.GetPoint()->nNode;
        SwPaM aPam( rNd, rSttPos, rNd, nEndPos + (replaceLastChar ? 1 : 0) );
        SwPaM aPam(pFrame->MapViewToModelPos(TextFrameIndex(rSttPos)),
                   pFrame->MapViewToModelPos(TextFrameIndex(nEndPos + (replaceLastChar ? 1 : 0))));

        if( pFnd->IsTextOnly() )
        {
@@ -338,7 +403,23 @@ bool SwAutoCorrDoc::ChgAutoCorrWord( sal_Int32& rSttPos, sal_Int32 nEndPos,
                '.' != pFnd->GetLong()[ pFnd->GetLong().getLength() - 1 ] )
            {
                // replace the selection
                pDoc->getIDocumentContentOperations().ReplaceRange( aPam, pFnd->GetLong(), false);
                std::vector<std::shared_ptr<SwUnoCursor>> ranges;
                if (sw::GetRanges(ranges, *rEditSh.GetDoc(), aPam))
                {
                    pDoc->getIDocumentContentOperations().ReplaceRange(aPam, pFnd->GetLong(), false);
                }
                else
                {
                    assert(!ranges.empty());
                    assert(ranges.front()->GetPoint()->nNode == ranges.front()->GetMark()->nNode);
                    pDoc->getIDocumentContentOperations().ReplaceRange(
                            *ranges.front(), pFnd->GetLong(), false);
                    for (auto it = ranges.begin() + 1; it != ranges.end(); ++it)
                    {
                        DeleteSel(**it);
                    }
                }

                // tdf#83260 After calling sw::DocumentContentOperationsManager::ReplaceRange
                // pTextNd may become invalid when change tracking is on and Edit -> Track Changes -> Show == OFF.
                // ReplaceRange shows changes, this moves deleted nodes from special section to document.
@@ -360,7 +441,8 @@ bool SwAutoCorrDoc::ChgAutoCorrWord( sal_Int32& rSttPos, sal_Int32 nEndPos,
                if( pPara )
                {
                    OSL_ENSURE( !pIdx, "who has not deleted his Index?" );
                    pIdx.reset(new SwNodeIndex( rCursor.GetPoint()->nNode, -1 ));
                    pIdx.reset(new SwNodeIndex( rCursor.GetPoint()->nNode ));
                    sw::GotoPrevLayoutTextFrame(*pIdx, rEditSh.GetLayout());
                }

                SwDoc* pAutoDoc = aTBlks.GetDoc();
@@ -391,7 +473,7 @@ bool SwAutoCorrDoc::ChgAutoCorrWord( sal_Int32& rSttPos, sal_Int32 nEndPos,

                if( pPara )
                {
                    ++(*pIdx);
                    sw::GotoNextLayoutTextFrame(*pIdx, rEditSh.GetLayout());
                    pTextNd = pIdx->GetNode().GetTextNode();
                }
                bRet = true;
@@ -401,7 +483,11 @@ bool SwAutoCorrDoc::ChgAutoCorrWord( sal_Int32& rSttPos, sal_Int32 nEndPos,
    }

    if( bRet && pPara && pTextNd )
        *pPara = pTextNd->GetText();
    {
        SwTextFrame const*const pNewFrame(static_cast<SwTextFrame const*>(
                    pTextNd->getLayoutFrame(rEditSh.GetLayout())));
        *pPara = pNewFrame->GetText();
    }

    return bRet;
}
@@ -428,7 +514,12 @@ LanguageType SwAutoCorrDoc::GetLanguage( sal_Int32 nPos ) const
    SwTextNode* pNd = rCursor.GetPoint()->nNode.GetNode().GetTextNode();

    if( pNd )
        eRet = pNd->GetLang( nPos );
    {
        SwTextFrame const*const pFrame(static_cast<SwTextFrame const*>(
                    pNd->getLayoutFrame(rEditSh.GetLayout())));
        assert(pFrame);
        eRet = pFrame->GetLangOfChar(TextFrameIndex(nPos), 0, true);
    }
    if(LANGUAGE_SYSTEM == eRet)
        eRet = GetAppLanguage();
    return eRet;
diff --git a/sw/source/core/edit/autofmt.cxx b/sw/source/core/edit/autofmt.cxx
index fdc27c9..9769080 100644
--- a/sw/source/core/edit/autofmt.cxx
+++ b/sw/source/core/edit/autofmt.cxx
@@ -1119,6 +1119,8 @@ void SwAutoFormat::DeleteLeadingTrailingBlanks(bool bStart, bool bEnd)
    }
}

namespace sw {

bool GetRanges(std::vector<std::shared_ptr<SwUnoCursor>> & rRanges,
        SwDoc & rDoc, SwPaM const& rDelPam)
{
@@ -1164,6 +1166,8 @@ bool GetRanges(std::vector<std::shared_ptr<SwUnoCursor>> & rRanges,
    return isNoRedline;
}

} // namespace sw

void SwAutoFormat::DeleteSel(SwPaM & rDelPam)
{
    std::vector<std::shared_ptr<SwUnoCursor>> ranges; // need correcting cursor
diff --git a/sw/source/core/inc/acorrect.hxx b/sw/source/core/inc/acorrect.hxx
index f14edf7..73f63c1 100644
--- a/sw/source/core/inc/acorrect.hxx
+++ b/sw/source/core/inc/acorrect.hxx
@@ -21,10 +21,14 @@
#define INCLUDED_SW_SOURCE_CORE_INC_ACORRECT_HXX

#include <memory>
#include <vector>

#include <tools/solar.h>
#include <editeng/svxacorr.hxx>
#include <swundo.hxx>

class SwDoc;
class SwUnoCursor;
class SwEditShell;
class SwPaM;
class SwNodeIndex;
@@ -53,6 +57,7 @@ class SwAutoCorrDoc : public SvxAutoCorrDoc
    bool    bUndoIdInitialized;

    void DeleteSel( SwPaM& rDelPam );
    void DeleteSelImpl(SwPaM & rDelPam);

public:
    SwAutoCorrDoc( SwEditShell& rEditShell, SwPaM& rPam, sal_Unicode cIns = 0 );
@@ -111,6 +116,13 @@ public:
    bool CheckDelChar(const SwPosition& rPos);
};

namespace sw {

bool GetRanges(std::vector<std::shared_ptr<SwUnoCursor>> & rRanges,
        SwDoc & rDoc, SwPaM const& rDelPam);

} // namespace sw

#endif

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */