sw_redlinehide_3: adapt SwDoc::MoveParagraph()

Very tricky...

Change-Id: Ic4157d14c2a3ee7c90f103561a376ac6f753a694
diff --git a/sw/inc/doc.hxx b/sw/inc/doc.hxx
index 1958c34..593428d3 100644
--- a/sw/inc/doc.hxx
+++ b/sw/inc/doc.hxx
@@ -1117,7 +1117,8 @@ public:

    /** Move selected paragraphes (not only numberings)
     according to offsets. (if negative: go to doc start). */
    bool MoveParagraph( const SwPaM&, long nOffset, bool bIsOutlMv = false );
    bool MoveParagraph(SwPaM&, long nOffset, bool bIsOutlMv = false);
    bool MoveParagraphImpl(SwPaM&, long nOffset, bool bIsOutlMv, SwRootFrame const*);

    bool NumOrNoNum( const SwNodeIndex& rIdx, bool bDel = false);

diff --git a/sw/source/core/doc/docnum.cxx b/sw/source/core/doc/docnum.cxx
index c9e6066..fbcb01f 100644
--- a/sw/source/core/doc/docnum.cxx
+++ b/sw/source/core/doc/docnum.cxx
@@ -29,6 +29,7 @@
#include <IDocumentState.hxx>
#include <IDocumentStylePoolAccess.hxx>
#include <pam.hxx>
#include <unocrsr.hxx>
#include <ndtxt.hxx>
#include <doctxm.hxx>
#include <poolfmt.hxx>
@@ -1781,7 +1782,120 @@ bool SwDoc::NumUpDown(const SwPaM& rPam, bool bDown, SwRootFrame const*const pLa
    return bRet;
}

bool SwDoc::MoveParagraph( const SwPaM& rPam, long nOffset, bool bIsOutlMv )
// this function doesn't contain any numbering-related code, but it is
// primarily called to move numbering-relevant paragraphs around, hence
// it will expand its selection to include full SwTextFrames.
bool SwDoc::MoveParagraph(SwPaM& rPam, long nOffset, bool const bIsOutlMv)
{
    // sw_redlinehide: as long as a layout with Hide mode exists, only
    // move nodes that have merged frames *completely*
    SwRootFrame const* pLayout(nullptr);
    for (SwRootFrame const*const pLay : GetAllLayouts())
    {
        if (pLay->IsHideRedlines())
        {
            pLayout = pLay;
        }
    }
    if (pLayout)
    {
        std::pair<SwTextNode *, SwTextNode *> nodes(
            sw::GetFirstAndLastNode(*pLayout, rPam.Start()->nNode));
        if (nodes.first && nodes.first != &rPam.Start()->nNode.GetNode())
        {
            assert(nodes.second);
            if (nOffset < 0)
            {
                nOffset += rPam.Start()->nNode.GetIndex() - nodes.first->GetIndex();
                if (0 <= nOffset)   // hack: there are callers that know what
                {                   // node they want; those should never need
                    nOffset = -1;   // this; other callers just pass in -1
                }                   // and those should still move
            }
            if (!rPam.HasMark())
            {
                rPam.SetMark();
            }
            assert(nodes.first->GetIndex() < rPam.Start()->nNode.GetIndex());
            rPam.Start()->nNode = *nodes.first;
            rPam.Start()->nContent.Assign(nodes.first, 0);
        }
        nodes = sw::GetFirstAndLastNode(*pLayout, rPam.End()->nNode);
        if (nodes.second && nodes.second != &rPam.End()->nNode.GetNode())
        {
            assert(nodes.first);
            if (0 < nOffset)
            {
                nOffset -= nodes.second->GetIndex() - rPam.End()->nNode.GetIndex();
                if (nOffset <= 0)   // hack: there are callers that know what
                {                   // node they want; those should never need
                    nOffset = +1;   // this; other callers just pass in +1
                }                   // and those should still move
            }
            if (!rPam.HasMark())
            {
                rPam.SetMark();
            }
            assert(rPam.End()->nNode.GetIndex() < nodes.second->GetIndex());
            rPam.End()->nNode = *nodes.second;
            // until end, otherwise Impl will detect overlapping redline
            rPam.End()->nContent.Assign(nodes.second, nodes.second->GetTextNode()->Len());
        }

        if (nOffset > 0)
        {   // sw_redlinehide: avoid moving into delete redline, skip forward
            if (GetNodes().GetEndOfContent().GetIndex() <= rPam.End()->nNode.GetIndex() + nOffset)
            {
                return false; // can't move
            }
            SwNode const* pNode(GetNodes()[rPam.End()->nNode.GetIndex() + nOffset + 1]);
            if (   pNode->GetRedlineMergeFlag() != SwNode::Merge::None
                && pNode->GetRedlineMergeFlag() != SwNode::Merge::First)
            {
                for ( ; ; ++nOffset)
                {
                    pNode = GetNodes()[rPam.End()->nNode.GetIndex() + nOffset];
                    if (pNode->IsTextNode())
                    {
                        nodes = GetFirstAndLastNode(*pLayout, *pNode->GetTextNode());
                        assert(nodes.first && nodes.second);
                        nOffset += nodes.second->GetIndex() - pNode->GetIndex();
                        // on last; will be incremented below to behind-last
                        break;
                    }
                }
            }
        }
        else
        {   // sw_redlinehide: avoid moving into delete redline, skip backward
            if (rPam.Start()->nNode.GetIndex() + nOffset < 1)
            {
                return false; // can't move
            }
            SwNode const* pNode(GetNodes()[rPam.Start()->nNode.GetIndex() + nOffset]);
            if (   pNode->GetRedlineMergeFlag() != SwNode::Merge::None
                && pNode->GetRedlineMergeFlag() != SwNode::Merge::First)
            {
                for ( ; ; --nOffset)
                {
                    pNode = GetNodes()[rPam.Start()->nNode.GetIndex() + nOffset];
                    if (pNode->IsTextNode())
                    {
                        nodes = GetFirstAndLastNode(*pLayout, *pNode->GetTextNode());
                        assert(nodes.first && nodes.second);
                        nOffset -= pNode->GetIndex() - nodes.first->GetIndex();
                        // on first
                        break;
                    }
                }
            }
        }
    }
    return MoveParagraphImpl(rPam, nOffset, bIsOutlMv, pLayout);
}

bool SwDoc::MoveParagraphImpl(SwPaM& rPam, long const nOffset,
        bool const bIsOutlMv, SwRootFrame const*const pLayout)
{
    const SwPosition *pStt = rPam.Start(), *pEnd = rPam.End();

@@ -1983,7 +2097,7 @@ bool SwDoc::MoveParagraph( const SwPaM& rPam, long nOffset, bool bIsOutlMv )

            SwPaM aPam( pStt->nNode, 0, aMvRg.aEnd, 0 );

            SwPaM& rOrigPam = const_cast<SwPaM&>(rPam);
            SwPaM& rOrigPam(rPam);
            rOrigPam.DeleteMark();
            rOrigPam.GetPoint()->nNode = aIdx.GetIndex() - 1;
            rOrigPam.GetPoint()->nContent.Assign( rOrigPam.GetContentNode(), 0 );
@@ -2112,6 +2226,10 @@ bool SwDoc::MoveParagraph( const SwPaM& rPam, long nOffset, bool bIsOutlMv )
        nMoved = rPam.End()->nNode.GetIndex() - rPam.Start()->nNode.GetIndex() + 1;
    }

    (void) pLayout; // note: move will insert between aIdx-1 and aIdx
    assert(!pLayout // check not moving *into* delete redline (caller's fault)
        || aIdx.GetNode().GetRedlineMergeFlag() == SwNode::Merge::None
        || aIdx.GetNode().GetRedlineMergeFlag() == SwNode::Merge::First);
    getIDocumentContentOperations().MoveNodeRange( aMvRg, aIdx, SwMoveFlags::REDLINES );

    if( pUndo )
diff --git a/sw/source/core/edit/ednumber.cxx b/sw/source/core/edit/ednumber.cxx
index 3e417e7..ee35d6e 100644
--- a/sw/source/core/edit/ednumber.cxx
+++ b/sw/source/core/edit/ednumber.cxx
@@ -460,6 +460,13 @@ bool SwEditShell::MoveNumParas( bool bUpperLower, bool bUpperLeft )
                else
                {
                    sal_uLong nStt = aPos.nNode.GetIndex(), nIdx = nStt - 1;

                    if (SwTextNode const*const pStt = aPos.nNode.GetNode().GetTextNode())
                    {
                        std::pair<SwTextNode *, SwTextNode *> nodes(
                            sw::GetFirstAndLastNode(*GetLayout(), *pStt));
                        nIdx = nodes.first->GetIndex() - 1;
                    }
                    while( nIdx && (
                        ( pNd = GetDoc()->GetNodes()[ nIdx ])->IsSectionNode() ||
                        ( pNd->IsEndNode() && pNd->StartOfSectionNode()->IsSectionNode())))
@@ -477,18 +484,38 @@ bool SwEditShell::MoveNumParas( bool bUpperLower, bool bUpperLeft )
                    pOrig == aCursor.GetNode().GetTextNode()->GetNumRule() )
                {
                    sal_uLong nStt = aCursor.GetPoint()->nNode.GetIndex(), nIdx = nStt+1;
                    if (SwTextNode const*const pStt = aCursor.GetPoint()->nNode.GetNode().GetTextNode())
                    {
                        std::pair<SwTextNode *, SwTextNode *> nodes(
                            sw::GetFirstAndLastNode(*GetLayout(), *pStt));
                        nIdx = nodes.second->GetIndex() + 1;
                    }

                    while (nIdx < GetDoc()->GetNodes().Count()-1)
                    {
                        pNd = GetDoc()->GetNodes()[ nIdx ];

                        if (pNd->IsSectionNode() ||
                            ( pNd->IsEndNode() && pNd->StartOfSectionNode()->IsSectionNode()) ||
                            ( pNd->IsTextNode() && pOrig == static_cast<const SwTextNode*>(pNd)->GetNumRule() &&
                              static_cast<const SwTextNode*>(pNd)->GetActualListLevel() > nUpperLevel ))
                            (pNd->IsEndNode() && pNd->StartOfSectionNode()->IsSectionNode()))
                        {
                            ++nIdx;
                        }
                        else if (pNd->IsTextNode())
                        {
                            SwTextNode const*const pTextNode =
                                sw::GetParaPropsNode(*GetLayout(), SwNodeIndex(*pNd));
                            if (pOrig == pTextNode->GetNumRule()
                                && pTextNode->GetActualListLevel() > nUpperLevel)
                            {
                                std::pair<SwTextNode *, SwTextNode *> nodes(
                                    sw::GetFirstAndLastNode(*GetLayout(), *pTextNode));
                                nIdx = nodes.second->GetIndex() + 1;
                            }
                            else
                            {
                                break;
                            }
                        }
                        // #i57856#
                        else
                        {
diff --git a/sw/source/core/inc/txtfrm.hxx b/sw/source/core/inc/txtfrm.hxx
index dfea9d4..5cb4c55 100644
--- a/sw/source/core/inc/txtfrm.hxx
+++ b/sw/source/core/inc/txtfrm.hxx
@@ -103,6 +103,8 @@ bool FrameContainsNode(SwContentFrame const& rFrame, sal_uLong nNodeIndex);
bool IsParaPropsNode(SwRootFrame const& rLayout, SwTextNode const& rNode);
SwTextNode * GetParaPropsNode(SwRootFrame const& rLayout, SwNodeIndex const& rNode);
SwPosition GetParaPropsPos(SwRootFrame const& rLayout, SwPosition const& rPos);
std::pair<SwTextNode *, SwTextNode *>
GetFirstAndLastNode(SwRootFrame const& rLayout, SwNodeIndex const& rPos);

TextFrameIndex UpdateMergedParaForDelete(MergedPara & rMerged,
        bool isRealDelete,
diff --git a/sw/source/core/text/txtfrm.cxx b/sw/source/core/text/txtfrm.cxx
index 8e5d64c..bc5f6e9 100644
--- a/sw/source/core/text/txtfrm.cxx
+++ b/sw/source/core/text/txtfrm.cxx
@@ -351,6 +351,23 @@ namespace sw {
        return pos;
    }

    std::pair<SwTextNode *, SwTextNode *>
    GetFirstAndLastNode(SwRootFrame const& rLayout, SwNodeIndex const& rPos)
    {
        SwTextNode *const pTextNode(rPos.GetNode().GetTextNode());
        if (pTextNode && rLayout.IsHideRedlines())
        {
            if (SwTextFrame const*const pFrame = static_cast<SwTextFrame*>(pTextNode->getLayoutFrame(&rLayout)))
            {
                if (sw::MergedPara const*const pMerged = pFrame->GetMergedPara())
                {
                    return std::make_pair(pMerged->pFirstNode, const_cast<SwTextNode*>(pMerged->pLastNode));
                }
            }
        }
        return std::make_pair(pTextNode, pTextNode);
    }

} // namespace sw

/// Switches width and height of the text frame