[Libreoffice-commits] core.git: Branch 'private/mst/sw_fieldmarkhide' - 14 commits - connectivity/Library_mysqlc.mk external/mariadb-connector-c sw/inc sw/source writerfilter/source

Michael Stahl (via logerrit) logerrit at kemper.freedesktop.org
Fri Nov 6 21:00:18 UTC 2020


Rebased ref, commits from common ancestor:
commit baa84a3f29dc7b36ea4898c5c63eab4f28c46566
Author:     Michael Stahl <Michael.Stahl at cib.de>
AuthorDate: Fri Nov 6 21:47:21 2020 +0100
Commit:     Michael Stahl <Michael.Stahl at cib.de>
CommitDate: Fri Nov 6 21:56:41 2020 +0100

    init fieldmark mode from options, TODO fails sw_layoutwriter
    
    Change-Id: Ied4302a60c0d7e0937b647e4e3a6a5f78ee31dc2

diff --git a/sw/source/core/layout/newfrm.cxx b/sw/source/core/layout/newfrm.cxx
index cd527d13903c..0431299cdd72 100644
--- a/sw/source/core/layout/newfrm.cxx
+++ b/sw/source/core/layout/newfrm.cxx
@@ -414,7 +414,9 @@ SwRootFrame::SwRootFrame( SwFrameFormat *pFormat, SwViewShell * pSh ) :
     mbCallbackActionEnabled ( false ),
     mbLayoutFreezed ( false ),
     mbHideRedlines(pFormat->GetDoc()->GetDocumentRedlineManager().IsHideRedlines()),
-    m_FieldmarkMode(sw::FieldmarkMode::ShowBoth),
+    m_FieldmarkMode(pSh->GetViewOptions()->IsFieldName()
+            ? sw::FieldmarkMode::ShowCommand
+            : sw::FieldmarkMode::ShowResult),
     mnBrowseWidth(MIN_BROWSE_WIDTH),
     mpTurbo( nullptr ),
     mpLastPage( nullptr ),
commit 0914e7410b65eb93fed4115bacef91996153ccf9
Author:     Michael Stahl <Michael.Stahl at cib.de>
AuthorDate: Tue Nov 3 22:07:24 2020 +0100
Commit:     Michael Stahl <Michael.Stahl at cib.de>
CommitDate: Fri Nov 6 21:56:41 2020 +0100

    WIP draft
    
    Change-Id: I1e059c41ad0c82fa3d7c17ab324b87fc3b840861

diff --git a/sw/source/core/layout/wsfrm.cxx b/sw/source/core/layout/wsfrm.cxx
index fd3cb4a30677..5ab411897ffd 100644
--- a/sw/source/core/layout/wsfrm.cxx
+++ b/sw/source/core/layout/wsfrm.cxx
@@ -4306,10 +4306,11 @@ static void UnHideRedlines(SwRootFrame & rLayout,
             auto eMode(sw::FrameMode::Existing);
             for (SwTextFrame * pFrame : frames)
             {
-                if (rLayout.IsHideRedlines())
+                if (rLayout.HasMergedParas())
                 {
-                    assert(!pFrame->GetMergedPara() ||
-                        !rNode.IsCreateFrameWhenHidingRedlines());
+// nope: now switching from one mergedpara to different one
+//                    assert(!pFrame->GetMergedPara() ||
+//                        !rNode.IsCreateFrameWhenHidingRedlines());
                     if (rNode.IsCreateFrameWhenHidingRedlines())
                     {
                         {
@@ -4417,9 +4418,12 @@ static void UnHideRedlines(SwRootFrame & rLayout,
                 rNode.GetTableNode()->DelFrames(&rLayout);
             }
         }
+#if 1
+        // at this point it's false but it has no frames...
         if (!rNode.IsCreateFrameWhenHidingRedlines())
+#endif
         {
-            if (rLayout.IsHideRedlines())
+            if (rLayout.HasMergedParas())
             {
                 if (rNode.IsContentNode())
                 {
commit 40094a7d272b0c9f718f16582c6111aec9899c93
Author:     Michael Stahl <Michael.Stahl at cib.de>
AuthorDate: Fri Nov 6 14:11:05 2020 +0100
Commit:     Michael Stahl <Michael.Stahl at cib.de>
CommitDate: Fri Nov 6 21:56:41 2020 +0100

    move cursor outside of hidden fieldmark when toggling
    
    Change-Id: If76331fa5a65376fd210171b967736f4d356462e

diff --git a/sw/source/core/view/viewsh.cxx b/sw/source/core/view/viewsh.cxx
index c7cebf5658ac..97481efab60a 100644
--- a/sw/source/core/view/viewsh.cxx
+++ b/sw/source/core/view/viewsh.cxx
@@ -51,6 +51,7 @@
 #include <ptqueue.hxx>
 #include <docsh.hxx>
 #include <pagedesc.hxx>
+#include <bookmrk.hxx>
 #include <ndole.hxx>
 #include <ndindex.hxx>
 #include <accmap.hxx>
@@ -2145,6 +2146,45 @@ void SwViewShell::ApplyViewOptions( const SwViewOption &rOpt )
         rSh.EndAction();
 }
 
+static bool
+IsCursorInFieldmarkHidden(SwPaM const& rCursor, sw::FieldmarkMode const eMode)
+{
+    if (eMode == sw::FieldmarkMode::ShowBoth)
+    {
+        return false;
+    }
+    IDocumentMarkAccess const& rIDMA(*rCursor.GetDoc().getIDocumentMarkAccess());
+    // iterate, for nested fieldmarks
+    for (auto iter = rIDMA.getFieldmarksBegin(); iter != rIDMA.getFieldmarksEnd(); ++iter)
+    {
+        if (*rCursor.GetPoint() <= (**iter).GetMarkStart())
+        {
+            return false;
+        }
+        if (*rCursor.GetPoint() < (**iter).GetMarkEnd())
+        {
+            SwPosition const sepPos(sw::mark::FindFieldSep(
+                        *dynamic_cast<sw::mark::IFieldmark*>(*iter)));
+            if (eMode == sw::FieldmarkMode::ShowResult)
+            {
+                if (*rCursor.GetPoint() <= sepPos
+                    && *rCursor.GetPoint() != (**iter).GetMarkStart())
+                {
+                    return true;
+                }
+            }
+            else
+            {
+                if (sepPos < *rCursor.GetPoint())
+                {
+                    return true;
+                }
+            }
+        }
+    }
+    return false;
+}
+
 void SwViewShell::ImplApplyViewOptions( const SwViewOption &rOpt )
 {
     if (*mpOpt == rOpt)
@@ -2187,7 +2227,7 @@ void SwViewShell::ImplApplyViewOptions( const SwViewOption &rOpt )
     // - fieldnames apply or not ...
     // ( - SwEndPortion must _no_ longer be generated. )
     // - Of course, the screen is something completely different than the printer ...
-    bool const isEnableFieldNames(mpOpt->IsFieldName() != rOpt.IsFieldName() && rOpt.IsFieldName());
+    bool const isToggleFieldNames(mpOpt->IsFieldName() != rOpt.IsFieldName());
 
     if (mpOpt->IsFieldName() != rOpt.IsFieldName())
     {
@@ -2283,14 +2323,16 @@ void SwViewShell::ImplApplyViewOptions( const SwViewOption &rOpt )
         EndAction();
     }
 
-    if (isEnableFieldNames)
+    if (isToggleFieldNames)
     {
         for(SwViewShell& rSh : GetRingContainer())
         {
             if (SwCursorShell *const pSh = dynamic_cast<SwCursorShell *>(&rSh))
             {
-                if (pSh->CursorInsideInputField())
-                {   // move cursor out of input field
+                if ((mpOpt->IsFieldName() && pSh->CursorInsideInputField())
+                    || IsCursorInFieldmarkHidden(*pSh->GetCursor(),
+                            pSh->GetLayout()->GetFieldmarkMode()))
+                {   // move cursor out of field
                     pSh->Left(1, CRSR_SKIP_CHARS);
                 }
             }
commit 3131ab862f46bb421e46ce08c07bd9898bb19fd6
Author:     Michael Stahl <Michael.Stahl at cib.de>
AuthorDate: Tue Nov 3 22:06:52 2020 +0100
Commit:     Michael Stahl <Michael.Stahl at cib.de>
CommitDate: Fri Nov 6 21:56:41 2020 +0100

    SwViewShell::ImplApplyViewOptions()
    
    Change-Id: Ie7b41048fe6c222272b345995fcdca4129be8ef0

diff --git a/sw/source/core/view/viewsh.cxx b/sw/source/core/view/viewsh.cxx
index cac98fffaace..c7cebf5658ac 100644
--- a/sw/source/core/view/viewsh.cxx
+++ b/sw/source/core/view/viewsh.cxx
@@ -2187,9 +2187,16 @@ void SwViewShell::ImplApplyViewOptions( const SwViewOption &rOpt )
     // - fieldnames apply or not ...
     // ( - SwEndPortion must _no_ longer be generated. )
     // - Of course, the screen is something completely different than the printer ...
-    bReformat = bReformat || mpOpt->IsFieldName() != rOpt.IsFieldName();
     bool const isEnableFieldNames(mpOpt->IsFieldName() != rOpt.IsFieldName() && rOpt.IsFieldName());
 
+    if (mpOpt->IsFieldName() != rOpt.IsFieldName())
+    {
+        GetLayout()->SetFieldmarkMode( rOpt.IsFieldName()
+                    ? sw::FieldmarkMode::ShowCommand
+                    : sw::FieldmarkMode::ShowResult );
+        bReformat = true;
+    }
+
     // The map mode is changed, minima/maxima will be attended by UI
     if( mpOpt->GetZoom() != rOpt.GetZoom() && !IsPreview() )
     {
commit 7a6a50b33cf34f792264b8a829437ae7731b74f3
Author:     Michael Stahl <Michael.Stahl at cib.de>
AuthorDate: Fri Nov 6 21:16:20 2020 +0100
Commit:     Michael Stahl <Michael.Stahl at cib.de>
CommitDate: Fri Nov 6 21:56:41 2020 +0100

    sw_fieldmarkhide: Copy: bookmarks before MakeFrames
    
    DocumentContentOperationsManager::CopyWithFlyInFly() needs to copy
    bookmarks before creating new layout frames.
    
    Change-Id: Ib085cd230008149a55f1527b0bbd7bb7323340a0

diff --git a/sw/source/core/doc/DocumentContentOperationsManager.cxx b/sw/source/core/doc/DocumentContentOperationsManager.cxx
index d156d14aa182..4b7e3e62df22 100644
--- a/sw/source/core/doc/DocumentContentOperationsManager.cxx
+++ b/sw/source/core/doc/DocumentContentOperationsManager.cxx
@@ -3468,13 +3468,45 @@ void DocumentContentOperationsManager::CopyWithFlyInFly(
     if (rRg.aStart != rRg.aEnd)
     {
         bool bEndIsEqualEndPos = rInsPos == rRg.aEnd;
-        bool isRecreateEndNode(false);
         --aSavePos;
         SaveRedlEndPosForRestore aRedlRest( rInsPos, 0 );
 
         // insert behind the already copied start node
         m_rDoc.GetNodes().CopyNodes( rRg, rInsPos, false, true );
         aRedlRest.Restore();
+
+        if (bEndIsEqualEndPos)
+        {
+            const_cast<SwNodeIndex&>(rRg.aEnd) = SwNodeIndex(aSavePos, +1);
+        }
+    }
+
+    // Also copy all bookmarks
+    // guess this must be done before the DelDummyNodes below as that
+    // deletes nodes so would mess up the index arithmetic
+    // sw_fieldmarkhide: also needs to be done before making frames
+    if (m_rDoc.getIDocumentMarkAccess()->getAllMarksCount())
+    {
+        SwPaM aRgTmp( rRg.aStart, rRg.aEnd );
+        SwPosition targetPos(SwNodeIndex(aSavePos,
+                                         rRg.aStart != rRg.aEnd ? +1 : 0));
+        if (pCopiedPaM && rRg.aStart != pCopiedPaM->first.Start()->nNode)
+        {
+            // there is 1 (partially selected, maybe) paragraph before
+            assert(SwNodeIndex(rRg.aStart, -1) == pCopiedPaM->first.Start()->nNode);
+            // only use the passed in target SwPosition if the source PaM point
+            // is on a different node; if it was the same node then the target
+            // position was likely moved along by the copy operation and now
+            // points to the end of the range!
+            targetPos = pCopiedPaM->second;
+        }
+
+        sw::CopyBookmarks(pCopiedPaM ? pCopiedPaM->first : aRgTmp, targetPos);
+    }
+
+    if (rRg.aStart != rRg.aEnd)
+    {
+        bool isRecreateEndNode(false);
         if (bMakeNewFrames) // tdf#130685 only after aRedlRest
         {   // recreate from previous node (could be merged now)
             if (SwTextNode *const pNode = aSavePos.GetNode().GetTextNode())
@@ -3528,10 +3560,6 @@ void DocumentContentOperationsManager::CopyWithFlyInFly(
                     ? 0 : +1);
             ::MakeFrames(&rDest, aSavePos, end);
         }
-        if (bEndIsEqualEndPos)
-        {
-            const_cast<SwNodeIndex&>(rRg.aEnd) = aSavePos;
-        }
     }
 
 #if OSL_DEBUG_LEVEL > 0
@@ -3568,27 +3596,6 @@ void DocumentContentOperationsManager::CopyWithFlyInFly(
 
     SwNodeRange aCpyRange( aSavePos, rInsPos );
 
-    // Also copy all bookmarks
-    // guess this must be done before the DelDummyNodes below as that
-    // deletes nodes so would mess up the index arithmetic
-    if( m_rDoc.getIDocumentMarkAccess()->getAllMarksCount() )
-    {
-        SwPaM aRgTmp( rRg.aStart, rRg.aEnd );
-        SwPaM aCpyPaM(aCpyRange.aStart, aCpyRange.aEnd);
-        if (pCopiedPaM && rRg.aStart != pCopiedPaM->first.Start()->nNode)
-        {
-            // there is 1 (partially selected, maybe) paragraph before
-            assert(SwNodeIndex(rRg.aStart, -1) == pCopiedPaM->first.Start()->nNode);
-            // only use the passed in target SwPosition if the source PaM point
-            // is on a different node; if it was the same node then the target
-            // position was likely moved along by the copy operation and now
-            // points to the end of the range!
-            *aCpyPaM.GetPoint() = pCopiedPaM->second;
-        }
-
-        sw::CopyBookmarks(pCopiedPaM ? pCopiedPaM->first : aRgTmp, *aCpyPaM.Start());
-    }
-
     if( bDelRedlines && ( RedlineFlags::DeleteRedlines & rDest.getIDocumentRedlineAccess().GetRedlineFlags() ))
         lcl_DeleteRedlines( rRg, aCpyRange );
 
commit fa4fba9855c8789cfd9717d37cb846186ee65ac0
Author:     Michael Stahl <Michael.Stahl at cib.de>
AuthorDate: Thu Nov 5 20:28:06 2020 +0100
Commit:     Michael Stahl <Michael.Stahl at cib.de>
CommitDate: Fri Nov 6 21:56:40 2020 +0100

    SwCursor::LeftRight()
    
    Change-Id: Iff6680249dfe66d6d5b1a39c4543b51a5238b075

diff --git a/sw/source/core/crsr/swcrsr.cxx b/sw/source/core/crsr/swcrsr.cxx
index 78b85050a9e0..4d95fb1b5394 100644
--- a/sw/source/core/crsr/swcrsr.cxx
+++ b/sw/source/core/crsr/swcrsr.cxx
@@ -1783,6 +1783,20 @@ bool SwCursor::LeftRight( bool bLeft, sal_uInt16 nCnt, sal_uInt16 nMode,
             beforeIndex = pFrame->MapModelToViewPos(*GetPoint());
         }
 
+        if (!bLeft && pLayout && pLayout->GetFieldmarkMode() == sw::FieldmarkMode::ShowResult)
+        {
+            SwTextNode const*const pNode(GetPoint()->nNode.GetNode().GetTextNode());
+            assert(pNode);
+            if (pNode->Len() != GetPoint()->nContent.GetIndex()
+                && pNode->GetText()[GetPoint()->nContent.GetIndex()] == CH_TXT_ATR_FIELDSTART)
+            {
+                IDocumentMarkAccess const& rIDMA(*GetDoc().getIDocumentMarkAccess());
+                sw::mark::IFieldmark const*const pMark(rIDMA.getFieldmarkAt(*GetPoint()));
+                assert(pMark);
+                *GetPoint() = sw::mark::FindFieldSep(*pMark);
+            }
+        }
+
         if ( !Move( fnMove, fnGo ) )
             break;
 
@@ -1813,6 +1827,20 @@ bool SwCursor::LeftRight( bool bLeft, sal_uInt16 nCnt, sal_uInt16 nMode,
             }
         }
 
+        if (bLeft && pLayout && pLayout->GetFieldmarkMode() == sw::FieldmarkMode::ShowCommand)
+        {
+            SwTextNode const*const pNode(GetPoint()->nNode.GetNode().GetTextNode());
+            assert(pNode);
+            if (pNode->Len() != GetPoint()->nContent.GetIndex()
+                && pNode->GetText()[GetPoint()->nContent.GetIndex()] == CH_TXT_ATR_FIELDEND)
+            {
+                IDocumentMarkAccess const& rIDMA(*GetDoc().getIDocumentMarkAccess());
+                sw::mark::IFieldmark const*const pMark(rIDMA.getFieldmarkAt(*GetPoint()));
+                assert(pMark);
+                *GetPoint() = sw::mark::FindFieldSep(*pMark);
+            }
+        }
+
         if (isFieldNames)
         {
             SwTextNode const*const pNode(GetPoint()->nNode.GetNode().GetTextNode());
commit 9939712074e62feeb46291817ac189a42ddcefef
Author:     Michael Stahl <Michael.Stahl at cib.de>
AuthorDate: Fri Nov 6 16:01:16 2020 +0100
Commit:     Michael Stahl <Michael.Stahl at cib.de>
CommitDate: Fri Nov 6 21:56:40 2020 +0100

    clean up CheckParaRedlineMerge
    
    Change-Id: I1d557a6bd72df576038c178ac470995ad702b6f1

diff --git a/sw/source/core/text/redlnitr.cxx b/sw/source/core/text/redlnitr.cxx
index 33b55600e30a..8892ed7f0966 100644
--- a/sw/source/core/text/redlnitr.cxx
+++ b/sw/source/core/text/redlnitr.cxx
@@ -73,7 +73,8 @@ public:
     SwPosition const* GetStartPos() const { return m_pStartPos; }
     SwPosition const* GetEndPos() const { return m_pEndPos; }
 
-    HideIterator(SwTextNode & rTextNode, bool const isHideRedlines, sw::FieldmarkMode const eMode)
+    HideIterator(SwTextNode & rTextNode,
+            bool const isHideRedlines, sw::FieldmarkMode const eMode)
         : m_rIDRA(rTextNode.getIDocumentRedlineAccess())
         , m_rIDMA(*rTextNode.getIDocumentMarkAccess())
         , m_isHideRedlines(isHideRedlines)
@@ -81,7 +82,6 @@ public:
         , m_Start(rTextNode, 0)
         , m_RedlineIndex(m_rIDRA.GetRedlinePos(rTextNode, RedlineType::Any))
         , m_pStartPos(nullptr)
-        //, m_pEndPos(nullptr)
         , m_pEndPos(&m_Start)
     {
     }
@@ -89,18 +89,18 @@ public:
     // delete redlines and fieldmarks can't overlap, due to sw::CalcBreaks()
     // and no combining of adjacent redlines
     // -> dummy chars are delete-redlined *iff* entire fieldmark is
-    bool Next(/*SwTextNode const* pNode, sal_Int32 */)
+    // Note: caller is responsible for checking for immediately adjacent hides
+    bool Next()
     {
         SwPosition const* pNextRedlineHide(nullptr);
         assert(m_pEndPos);
         if (m_isHideRedlines)
         {
-        // position on current or next redline
+            // position on current or next redline
             for (; m_RedlineIndex < m_rIDRA.GetRedlineTable().size(); ++m_RedlineIndex)
             {
                 SwRangeRedline const*const pRed = m_rIDRA.GetRedlineTable()[m_RedlineIndex];
 
-                //if (pNode->GetIndex() < pRed->Start()->nNode.GetIndex())
                 if (m_pEndPos->nNode.GetIndex() < pRed->Start()->nNode.GetIndex())
                     break;
 
@@ -111,7 +111,7 @@ public:
                 SwPosition const*const pEnd(pRed->End());
                 if (*pStart == *pEnd)
                 {   // only allowed while moving (either way?)
-        //            assert(IDocumentRedlineAccess::IsHideChanges(rIDRA.GetRedlineFlags()));
+//                  assert(IDocumentRedlineAccess::IsHideChanges(rIDRA.GetRedlineFlags()));
                     continue;
                 }
                 if (pStart->nNode.GetNode().IsTableNode())
@@ -119,37 +119,23 @@ public:
                     assert(pEnd->nNode == m_Start.nNode && pEnd->nContent.GetIndex() == 0);
                     continue; // known pathology, ignore it
                 }
-                // TODO?
                 if (*m_pEndPos <= *pStart)
                 {
                     pNextRedlineHide = pStart;
                     break; // the next one
                 }
-                //m_pStartPos = pStart;
-                //m_pEndPos = pEnd;
             }
         }
 
-        // how to iterate ... m_pSepPos + pFM for the start / end ?
         // position on current or next fieldmark
-        //SwPosition const* pNextFieldmarkHide(nullptr);
-        std::optional<SwPosition> oNextFieldmarkHide;
         m_oNextFieldmarkHide.reset();
         if (m_eFieldmarkMode != sw::FieldmarkMode::ShowBoth)
         {
-            sal_Unicode const magic = m_eFieldmarkMode == sw::FieldmarkMode::ShowResult
-                ? CH_TXT_ATR_FIELDSTART
-                : CH_TXT_ATR_FIELDSEP;
-            sal_Int32 const nPos = m_pEndPos->nNode.GetNode().GetTextNode()->GetText().indexOf(magic,
-                    m_pEndPos->nContent.GetIndex());
-#if 0
-            sal_Int32 nPos = pNode->GetText().indexOf(magic,
-                    m_Fieldmark.first
-                        ? HideCommand
-                            ? m_Fieldmark.first->GetEndPos()
-                            : *m_Fieldmark.second
-                        : 0);
-#endif
+            sal_Unicode const magic(m_eFieldmarkMode == sw::FieldmarkMode::ShowResult
+                    ? CH_TXT_ATR_FIELDSTART
+                    : CH_TXT_ATR_FIELDSEP);
+            sal_Int32 const nPos(m_pEndPos->nNode.GetNode().GetTextNode()->GetText().indexOf(
+                    magic, m_pEndPos->nContent.GetIndex()));
             if (nPos != -1)
             {
                 m_oNextFieldmarkHide.emplace(*m_pEndPos->nNode.GetNode().GetTextNode(), nPos);
@@ -159,7 +145,10 @@ public:
                             : m_rIDMA.getFieldmarkFor(*m_oNextFieldmarkHide));
                 assert(pFieldmark);
                 m_Fieldmark.first = pFieldmark;
-#if 1
+                // for cursor travelling, there should be 2 visible chars;
+                // whichever char is hidden, the cursor travelling needs to
+                // be adapted in any case to skip in some situation or other;
+                // always hide the CH_TXT_ATR_FIELDSEP for now
                 if (m_eFieldmarkMode == sw::FieldmarkMode::ShowResult)
                 {
                     m_Fieldmark.second.reset(
@@ -173,43 +162,16 @@ public:
                         new SwPosition(pFieldmark->GetMarkEnd()));
                     --m_Fieldmark.second->nContent;
                 }
-#endif
-#if 0
-                ++m_oNextFieldmarkHide->nContent; // skip
-                if (m_eFieldmarkMode == sw::FieldmarkMode::ShowCommand)
-                {
-                    m_Fieldmark.second.reset(
-                        new SwPosition(pFieldmark->GetMarkEnd()));
-                }
-                else
-                {
-                    m_Fieldmark.second.reset(
-                        new SwPosition(sw::mark::FindFieldSep(*m_Fieldmark.first)));
-                    ++m_Fieldmark.second->nContent;
-                }
-                m_Fieldmark.second.reset(new SwPosition(
-                    m_eFieldmarkMode == sw::FieldmarkMode::ShowCommand
-                        ? pFieldmark->GetMarkEnd() - 1
-                        : sw::mark::FindFieldSep(*m_Fieldmark.first)));
-#endif
-    //WRONG NODe            assert(m_pEndPos->nNode.GetNode().GetTextNode()->GetNext()[m_Fieldmark.second] == CH_TXTATR_BREAKWORD);
-                //pNextFieldmarkHide = &tmp; /// FIXME UAF
-                // FIXME2: hide the sep? or the start? or none?
-                // ... how does cursor travel work? there should be just 2 visible fieldchar...
-                // ... MapViewToModel end-biased -> hide char at end?
-                // ... actually it doesn't matter: hide at the end and cursor moves in at the start; hide at the start and cursor moves in at the end
-                // ... BUT what about start at start of para / end at end of para ...
-                //     want to have pos. outside + pos. inside => always hide SEP?
-                // FIXME3: in case the start char is hidden -> must merge with prev redline?
-                //                     end                  ->                 next
-                //         NO - CheckParaRedlineMerge already merges
             }
         }
 
-            // the = case may depend on which CH is hidden ?
+        // == can happen only if redline starts inside field command, and in
+        // that case redline will end before field separator
+        assert(!pNextRedlineHide || !m_oNextFieldmarkHide
+            || *pNextRedlineHide != *m_oNextFieldmarkHide
+            || *m_rIDRA.GetRedlineTable()[m_RedlineIndex]->End() < *m_Fieldmark.second);
         if (pNextRedlineHide
-            //&& (!pNextFieldmarkHide || *pNextRedlineHide <= *pNextFieldmarkHide))
-            && (!m_oNextFieldmarkHide || *pNextRedlineHide <= *m_oNextFieldmarkHide))
+            && (!m_oNextFieldmarkHide || *pNextRedlineHide < *m_oNextFieldmarkHide))
         {
             SwRangeRedline const*const pRed(m_rIDRA.GetRedlineTable()[m_RedlineIndex]);
             m_pStartPos = pRed->Start();
@@ -217,26 +179,15 @@ public:
             ++m_RedlineIndex;
             return true;
         }
-        //else if (pNextFieldmarkHide)
         else if (m_oNextFieldmarkHide)
         {
-            //assert(!pNextRedlineHide || *pNextFieldmarkHide < *pNextRedlineHide);
             assert(!pNextRedlineHide || *m_oNextFieldmarkHide < *pNextRedlineHide);
-            // ??? how to iterate vs not
-            //m_pStartPos = pNextFieldmarkHide; // FIXME UAF
             m_pStartPos = &*m_oNextFieldmarkHide;
-#if 0
-            m_pEndPos = m_eFieldmarkMode == sw::FieldmarkMode::ShowResult
-                ? m_Fieldmark.second.get()
-                : &m_Fieldmark.first->GetMarkEnd();
-#else
             m_pEndPos = m_Fieldmark.second.get();
-#endif
             return true;
         }
         else // nothing
         {
-            //assert(!pNextRedlineHide && !pNextFieldmarkHide);
             assert(!pNextRedlineHide && !m_oNextFieldmarkHide);
             m_pStartPos = nullptr;
             m_pEndPos = nullptr;
@@ -253,7 +204,6 @@ std::unique_ptr<sw::MergedPara>
 CheckParaRedlineMerge(SwTextFrame & rFrame, SwTextNode & rTextNode,
        FrameMode const eMode)
 {
-//    IDocumentRedlineAccess const& rIDRA = rTextNode.getIDocumentRedlineAccess();
     if (!rFrame.getRootFrame()->HasMergedParas())
     {
         return nullptr;
@@ -271,31 +221,6 @@ CheckParaRedlineMerge(SwTextFrame & rFrame, SwTextNode & rTextNode,
                 rFrame.getRootFrame()->IsHideRedlines(),
                 rFrame.getRootFrame()->GetFieldmarkMode()); iter.Next(); )
     {
-#if 0
-    for (auto i = rIDRA.GetRedlinePos(rTextNode, RedlineType::Any);
-         i < rIDRA.GetRedlineTable().size(); ++i)
-    {
-        SwRangeRedline const*const pRed = rIDRA.GetRedlineTable()[i];
-
-        if (pNode->GetIndex() < pRed->Start()->nNode.GetIndex())
-            break;
-
-        if (pRed->GetType() != RedlineType::Delete)
-            continue;
-
-        SwPosition const*const pStart(pRed->Start());
-        SwPosition const*const pEnd(pRed->End());
-        if (*pStart == *pEnd)
-        {   // only allowed while moving (either way?)
-//            assert(IDocumentRedlineAccess::IsHideChanges(rIDRA.GetRedlineFlags()));
-            continue;
-        }
-        if (pStart->nNode.GetNode().IsTableNode())
-        {
-            assert(&pEnd->nNode.GetNode() == &rTextNode && pEnd->nContent.GetIndex() == 0);
-            continue; // known pathology, ignore it
-        }
-#endif
         SwPosition const*const pStart(iter.GetStartPos());
         SwPosition const*const pEnd(iter.GetEndPos());
         bHaveRedlines = true;
commit 8548f71c5b471819194299a21128ac96cdf297b0
Author:     Michael Stahl <Michael.Stahl at cib.de>
AuthorDate: Tue Nov 3 22:11:59 2020 +0100
Commit:     Michael Stahl <Michael.Stahl at cib.de>
CommitDate: Fri Nov 6 21:56:40 2020 +0100

    CheckParaRedlineMerge
    
    Change-Id: I4c6eac864da4b4bf531437e555a3994fd2670367

diff --git a/sw/source/core/text/redlnitr.cxx b/sw/source/core/text/redlnitr.cxx
index b878f26e27f5..33b55600e30a 100644
--- a/sw/source/core/text/redlnitr.cxx
+++ b/sw/source/core/text/redlnitr.cxx
@@ -35,6 +35,9 @@
 #include <doc.hxx>
 #include <IDocumentRedlineAccess.hxx>
 #include <IDocumentLayoutAccess.hxx>
+#include <IDocumentMarkAccess.hxx>
+#include <IMark.hxx>
+#include <bookmrk.hxx>
 #include <rootfrm.hxx>
 #include <breakit.hxx>
 #include <vcl/commandevent.hxx>
@@ -47,14 +50,211 @@
 
 using namespace ::com::sun::star;
 
+namespace {
+
+class HideIterator
+{
+private:
+    IDocumentRedlineAccess const& m_rIDRA;
+    IDocumentMarkAccess const& m_rIDMA;
+    bool const m_isHideRedlines;
+    sw::FieldmarkMode const m_eFieldmarkMode;
+    SwPosition const m_Start;
+    /// next redline
+    SwRedlineTable::size_type m_RedlineIndex;
+    /// next fieldmark
+    std::pair<sw::mark::IFieldmark const*, std::unique_ptr<SwPosition>> m_Fieldmark;
+    std::optional<SwPosition> m_oNextFieldmarkHide;
+    /// current start/end pair
+    SwPosition const* m_pStartPos;
+    SwPosition const* m_pEndPos;
+
+public:
+    SwPosition const* GetStartPos() const { return m_pStartPos; }
+    SwPosition const* GetEndPos() const { return m_pEndPos; }
+
+    HideIterator(SwTextNode & rTextNode, bool const isHideRedlines, sw::FieldmarkMode const eMode)
+        : m_rIDRA(rTextNode.getIDocumentRedlineAccess())
+        , m_rIDMA(*rTextNode.getIDocumentMarkAccess())
+        , m_isHideRedlines(isHideRedlines)
+        , m_eFieldmarkMode(eMode)
+        , m_Start(rTextNode, 0)
+        , m_RedlineIndex(m_rIDRA.GetRedlinePos(rTextNode, RedlineType::Any))
+        , m_pStartPos(nullptr)
+        //, m_pEndPos(nullptr)
+        , m_pEndPos(&m_Start)
+    {
+    }
+
+    // delete redlines and fieldmarks can't overlap, due to sw::CalcBreaks()
+    // and no combining of adjacent redlines
+    // -> dummy chars are delete-redlined *iff* entire fieldmark is
+    bool Next(/*SwTextNode const* pNode, sal_Int32 */)
+    {
+        SwPosition const* pNextRedlineHide(nullptr);
+        assert(m_pEndPos);
+        if (m_isHideRedlines)
+        {
+        // position on current or next redline
+            for (; m_RedlineIndex < m_rIDRA.GetRedlineTable().size(); ++m_RedlineIndex)
+            {
+                SwRangeRedline const*const pRed = m_rIDRA.GetRedlineTable()[m_RedlineIndex];
+
+                //if (pNode->GetIndex() < pRed->Start()->nNode.GetIndex())
+                if (m_pEndPos->nNode.GetIndex() < pRed->Start()->nNode.GetIndex())
+                    break;
+
+                if (pRed->GetType() != RedlineType::Delete)
+                    continue;
+
+                SwPosition const*const pStart(pRed->Start());
+                SwPosition const*const pEnd(pRed->End());
+                if (*pStart == *pEnd)
+                {   // only allowed while moving (either way?)
+        //            assert(IDocumentRedlineAccess::IsHideChanges(rIDRA.GetRedlineFlags()));
+                    continue;
+                }
+                if (pStart->nNode.GetNode().IsTableNode())
+                {
+                    assert(pEnd->nNode == m_Start.nNode && pEnd->nContent.GetIndex() == 0);
+                    continue; // known pathology, ignore it
+                }
+                // TODO?
+                if (*m_pEndPos <= *pStart)
+                {
+                    pNextRedlineHide = pStart;
+                    break; // the next one
+                }
+                //m_pStartPos = pStart;
+                //m_pEndPos = pEnd;
+            }
+        }
+
+        // how to iterate ... m_pSepPos + pFM for the start / end ?
+        // position on current or next fieldmark
+        //SwPosition const* pNextFieldmarkHide(nullptr);
+        std::optional<SwPosition> oNextFieldmarkHide;
+        m_oNextFieldmarkHide.reset();
+        if (m_eFieldmarkMode != sw::FieldmarkMode::ShowBoth)
+        {
+            sal_Unicode const magic = m_eFieldmarkMode == sw::FieldmarkMode::ShowResult
+                ? CH_TXT_ATR_FIELDSTART
+                : CH_TXT_ATR_FIELDSEP;
+            sal_Int32 const nPos = m_pEndPos->nNode.GetNode().GetTextNode()->GetText().indexOf(magic,
+                    m_pEndPos->nContent.GetIndex());
+#if 0
+            sal_Int32 nPos = pNode->GetText().indexOf(magic,
+                    m_Fieldmark.first
+                        ? HideCommand
+                            ? m_Fieldmark.first->GetEndPos()
+                            : *m_Fieldmark.second
+                        : 0);
+#endif
+            if (nPos != -1)
+            {
+                m_oNextFieldmarkHide.emplace(*m_pEndPos->nNode.GetNode().GetTextNode(), nPos);
+                sw::mark::IFieldmark const*const pFieldmark(
+                        m_eFieldmarkMode == sw::FieldmarkMode::ShowResult
+                            ? m_rIDMA.getFieldmarkAt(*m_oNextFieldmarkHide)
+                            : m_rIDMA.getFieldmarkFor(*m_oNextFieldmarkHide));
+                assert(pFieldmark);
+                m_Fieldmark.first = pFieldmark;
+#if 1
+                if (m_eFieldmarkMode == sw::FieldmarkMode::ShowResult)
+                {
+                    m_Fieldmark.second.reset(
+                        new SwPosition(sw::mark::FindFieldSep(*m_Fieldmark.first)));
+                    ++m_Fieldmark.second->nContent;
+                    ++m_oNextFieldmarkHide->nContent; // skip start
+                }
+                else
+                {
+                    m_Fieldmark.second.reset(
+                        new SwPosition(pFieldmark->GetMarkEnd()));
+                    --m_Fieldmark.second->nContent;
+                }
+#endif
+#if 0
+                ++m_oNextFieldmarkHide->nContent; // skip
+                if (m_eFieldmarkMode == sw::FieldmarkMode::ShowCommand)
+                {
+                    m_Fieldmark.second.reset(
+                        new SwPosition(pFieldmark->GetMarkEnd()));
+                }
+                else
+                {
+                    m_Fieldmark.second.reset(
+                        new SwPosition(sw::mark::FindFieldSep(*m_Fieldmark.first)));
+                    ++m_Fieldmark.second->nContent;
+                }
+                m_Fieldmark.second.reset(new SwPosition(
+                    m_eFieldmarkMode == sw::FieldmarkMode::ShowCommand
+                        ? pFieldmark->GetMarkEnd() - 1
+                        : sw::mark::FindFieldSep(*m_Fieldmark.first)));
+#endif
+    //WRONG NODe            assert(m_pEndPos->nNode.GetNode().GetTextNode()->GetNext()[m_Fieldmark.second] == CH_TXTATR_BREAKWORD);
+                //pNextFieldmarkHide = &tmp; /// FIXME UAF
+                // FIXME2: hide the sep? or the start? or none?
+                // ... how does cursor travel work? there should be just 2 visible fieldchar...
+                // ... MapViewToModel end-biased -> hide char at end?
+                // ... actually it doesn't matter: hide at the end and cursor moves in at the start; hide at the start and cursor moves in at the end
+                // ... BUT what about start at start of para / end at end of para ...
+                //     want to have pos. outside + pos. inside => always hide SEP?
+                // FIXME3: in case the start char is hidden -> must merge with prev redline?
+                //                     end                  ->                 next
+                //         NO - CheckParaRedlineMerge already merges
+            }
+        }
+
+            // the = case may depend on which CH is hidden ?
+        if (pNextRedlineHide
+            //&& (!pNextFieldmarkHide || *pNextRedlineHide <= *pNextFieldmarkHide))
+            && (!m_oNextFieldmarkHide || *pNextRedlineHide <= *m_oNextFieldmarkHide))
+        {
+            SwRangeRedline const*const pRed(m_rIDRA.GetRedlineTable()[m_RedlineIndex]);
+            m_pStartPos = pRed->Start();
+            m_pEndPos = pRed->End();
+            ++m_RedlineIndex;
+            return true;
+        }
+        //else if (pNextFieldmarkHide)
+        else if (m_oNextFieldmarkHide)
+        {
+            //assert(!pNextRedlineHide || *pNextFieldmarkHide < *pNextRedlineHide);
+            assert(!pNextRedlineHide || *m_oNextFieldmarkHide < *pNextRedlineHide);
+            // ??? how to iterate vs not
+            //m_pStartPos = pNextFieldmarkHide; // FIXME UAF
+            m_pStartPos = &*m_oNextFieldmarkHide;
+#if 0
+            m_pEndPos = m_eFieldmarkMode == sw::FieldmarkMode::ShowResult
+                ? m_Fieldmark.second.get()
+                : &m_Fieldmark.first->GetMarkEnd();
+#else
+            m_pEndPos = m_Fieldmark.second.get();
+#endif
+            return true;
+        }
+        else // nothing
+        {
+            //assert(!pNextRedlineHide && !pNextFieldmarkHide);
+            assert(!pNextRedlineHide && !m_oNextFieldmarkHide);
+            m_pStartPos = nullptr;
+            m_pEndPos = nullptr;
+            return false;
+        }
+    }
+};
+
+}
+
 namespace sw {
 
 std::unique_ptr<sw::MergedPara>
 CheckParaRedlineMerge(SwTextFrame & rFrame, SwTextNode & rTextNode,
        FrameMode const eMode)
 {
-    IDocumentRedlineAccess const& rIDRA = rTextNode.getIDocumentRedlineAccess();
-    if (!rFrame.getRootFrame()->IsHideRedlines())
+//    IDocumentRedlineAccess const& rIDRA = rTextNode.getIDocumentRedlineAccess();
+    if (!rFrame.getRootFrame()->HasMergedParas())
     {
         return nullptr;
     }
@@ -67,6 +267,11 @@ CheckParaRedlineMerge(SwTextFrame & rFrame, SwTextNode & rTextNode,
     SwTextNode * pParaPropsNode(nullptr);
     SwTextNode * pNode(&rTextNode);
     sal_Int32 nLastEnd(0);
+    for (auto iter = HideIterator(rTextNode,
+                rFrame.getRootFrame()->IsHideRedlines(),
+                rFrame.getRootFrame()->GetFieldmarkMode()); iter.Next(); )
+    {
+#if 0
     for (auto i = rIDRA.GetRedlinePos(rTextNode, RedlineType::Any);
          i < rIDRA.GetRedlineTable().size(); ++i)
     {
@@ -90,6 +295,9 @@ CheckParaRedlineMerge(SwTextFrame & rFrame, SwTextNode & rTextNode,
             assert(&pEnd->nNode.GetNode() == &rTextNode && pEnd->nContent.GetIndex() == 0);
             continue; // known pathology, ignore it
         }
+#endif
+        SwPosition const*const pStart(iter.GetStartPos());
+        SwPosition const*const pEnd(iter.GetEndPos());
         bHaveRedlines = true;
         assert(pNode != &rTextNode || &pStart->nNode.GetNode() == &rTextNode); // detect calls with wrong start node
         if (pStart->nContent != nLastEnd) // not 0 so we eliminate adjacent deletes
commit c0bc67de53e70e87dcc7c072e34e147852088cc2
Author:     Michael Stahl <Michael.Stahl at cib.de>
AuthorDate: Tue Nov 3 21:32:39 2020 +0100
Commit:     Michael Stahl <Michael.Stahl at cib.de>
CommitDate: Fri Nov 6 21:56:40 2020 +0100

    sw_fieldmarkhide: replace IsHideRedlines() with HasMergedParas()
    
    ... where obvious.
    
    Change-Id: Id941d59feea5a3539da9006725ef376b14bc7d1c

diff --git a/sw/source/core/crsr/crbm.cxx b/sw/source/core/crsr/crbm.cxx
index 2311cf8d93f6..1b60a3f7e290 100644
--- a/sw/source/core/crsr/crbm.cxx
+++ b/sw/source/core/crsr/crbm.cxx
@@ -126,7 +126,7 @@ namespace sw {
 
 bool IsMarkHidden(SwRootFrame const& rLayout, ::sw::mark::IMark const& rMark)
 {
-    if (!rLayout.IsHideRedlines())
+    if (!rLayout.HasMergedParas())
     {
         return false;
     }
diff --git a/sw/source/core/crsr/crsrsh.cxx b/sw/source/core/crsr/crsrsh.cxx
index 80cc4f69da90..5a07b8aa677b 100644
--- a/sw/source/core/crsr/crsrsh.cxx
+++ b/sw/source/core/crsr/crsrsh.cxx
@@ -1081,7 +1081,7 @@ bool SwCursorShell::IsSelOnePara() const
     {
         return true;
     }
-    if (GetLayout()->IsHideRedlines())
+    if (GetLayout()->HasMergedParas())
     {
         SwContentFrame const*const pFrame(GetCurrFrame(false));
         auto const n(m_pCurrentCursor->GetMark()->nNode.GetIndex());
@@ -1092,7 +1092,7 @@ bool SwCursorShell::IsSelOnePara() const
 
 bool SwCursorShell::IsSttPara() const
 {
-    if (GetLayout()->IsHideRedlines())
+    if (GetLayout()->HasMergedParas())
     {
         SwTextNode const*const pNode(m_pCurrentCursor->GetPoint()->nNode.GetNode().GetTextNode());
         if (pNode)
@@ -1111,7 +1111,7 @@ bool SwCursorShell::IsSttPara() const
 
 bool SwCursorShell::IsEndPara() const
 {
-    if (GetLayout()->IsHideRedlines())
+    if (GetLayout()->HasMergedParas())
     {
         SwTextNode const*const pNode(m_pCurrentCursor->GetPoint()->nNode.GetNode().GetTextNode());
         if (pNode)
@@ -2525,7 +2525,7 @@ void SwCursorShell::CallChgLnk()
 OUString SwCursorShell::GetSelText() const
 {
     OUString aText;
-    if (GetLayout()->IsHideRedlines())
+    if (GetLayout()->HasMergedParas())
     {
         SwContentFrame const*const pFrame(GetCurrFrame(false));
         if (FrameContainsNode(*pFrame, m_pCurrentCursor->GetMark()->nNode.GetIndex()))
diff --git a/sw/source/core/crsr/swcrsr.cxx b/sw/source/core/crsr/swcrsr.cxx
index 4086ae11e899..78b85050a9e0 100644
--- a/sw/source/core/crsr/swcrsr.cxx
+++ b/sw/source/core/crsr/swcrsr.cxx
@@ -1165,7 +1165,7 @@ struct HideWrapper
         , m_rpTextNode(rpTextNode)
         , m_rPtPos(rPtPos)
     {
-        if (pLayout && pLayout->IsHideRedlines())
+        if (pLayout && pLayout->HasMergedParas())
         {
             m_pFrame = static_cast<SwTextFrame*>(rpTextNode->getLayoutFrame(pLayout));
             m_pText = &m_pFrame->GetText();
@@ -1281,7 +1281,7 @@ bool SwCursor::IsStartEndSentence(bool bEnd, SwRootFrame const*const pLayout) co
                     GetContentNode() && GetPoint()->nContent == GetContentNode()->Len() :
                     GetPoint()->nContent.GetIndex() == 0;
 
-    if ((pLayout != nullptr && pLayout->IsHideRedlines()) || !bRet)
+    if ((pLayout != nullptr && pLayout->HasMergedParas()) || !bRet)
     {
         SwCursor aCursor(*GetPoint(), nullptr);
         SwPosition aOrigPos = *aCursor.GetPoint();
diff --git a/sw/source/core/doc/DocumentContentOperationsManager.cxx b/sw/source/core/doc/DocumentContentOperationsManager.cxx
index 2e018b7a0567..d156d14aa182 100644
--- a/sw/source/core/doc/DocumentContentOperationsManager.cxx
+++ b/sw/source/core/doc/DocumentContentOperationsManager.cxx
@@ -1149,7 +1149,7 @@ namespace //local functions originally from docfmt.cxx
         bool ret(false);
         SwTextNode *const pTNd = rNode.GetTextNode();
         sw::MergedPara const* pMerged(nullptr);
-        if (pLayout && pLayout->IsHideRedlines() && pTNd)
+        if (pLayout && pLayout->HasMergedParas() && pTNd)
         {
             SwTextFrame const*const pTextFrame(static_cast<SwTextFrame const*>(
                 pTNd->getLayoutFrame(pLayout)));
@@ -1191,7 +1191,7 @@ namespace //local functions originally from docfmt.cxx
         }
 
         // input cursor can't be on hidden node, and iteration skips them
-        assert(!pLayout || !pLayout->IsHideRedlines()
+        assert(!pLayout || !pLayout->HasMergedParas()
             || rNode.GetRedlineMergeFlag() != SwNode::Merge::Hidden);
 
         if (!pMerged)
@@ -1473,7 +1473,7 @@ namespace //local functions originally from docfmt.cxx
                     else
                     {
                         SwContentNode * pFirstNode(pNode);
-                        if (pLayout && pLayout->IsHideRedlines())
+                        if (pLayout && pLayout->HasMergedParas())
                         {
                             pFirstNode = sw::GetFirstAndLastNode(*pLayout, pStt->nNode).first;
                         }
@@ -1774,7 +1774,7 @@ namespace //local functions originally from docfmt.cxx
             if (!pTNd)
                 continue;
 
-            if (pLayout && pLayout->IsHideRedlines()
+            if (pLayout && pLayout->HasMergedParas()
                 && pTNd->GetRedlineMergeFlag() == SwNode::Merge::Hidden)
             {   // not really sure what to do here, but applying to hidden
                 continue; // nodes doesn't make sense...
@@ -3486,7 +3486,7 @@ void DocumentContentOperationsManager::CopyWithFlyInFly(
                     SwIterator<SwTextFrame, SwTextNode, sw::IteratorMode::UnwrapMulti> aIter(*pEndNode);
                     for (SwTextFrame* pFrame = aIter.First(); pFrame; pFrame = aIter.Next())
                     {
-                        if (pFrame->getRootFrame()->IsHideRedlines())
+                        if (pFrame->getRootFrame()->HasMergedParas())
                         {
                             frames.insert(pFrame);
                         }
@@ -3498,7 +3498,7 @@ void DocumentContentOperationsManager::CopyWithFlyInFly(
                     SwIterator<SwTextFrame, SwTextNode, sw::IteratorMode::UnwrapMulti> aIter(*pEndNode);
                     for (SwTextFrame* pFrame = aIter.First(); pFrame; pFrame = aIter.Next())
                     {
-                        if (pFrame->getRootFrame()->IsHideRedlines())
+                        if (pFrame->getRootFrame()->HasMergedParas())
                         {
                             auto const it = frames.find(pFrame);
                             if (it != frames.end())
@@ -3863,7 +3863,7 @@ void DocumentContentOperationsManager::CopyFlyInFlyImpl(
 bool DocumentContentOperationsManager::lcl_RstTextAttr( const SwNodePtr& rpNd, void* pArgs )
 {
     ParaRstFormat* pPara = static_cast<ParaRstFormat*>(pArgs);
-    if (pPara->pLayout && pPara->pLayout->IsHideRedlines()
+    if (pPara->pLayout && pPara->pLayout->HasMergedParas()
         && rpNd->GetRedlineMergeFlag() == SwNode::Merge::Hidden)
     {
         return true; // skip hidden, since new items aren't applied
diff --git a/sw/source/core/doc/DocumentOutlineNodesManager.cxx b/sw/source/core/doc/DocumentOutlineNodesManager.cxx
index 25f3814767bb..cd9729fa2d8b 100644
--- a/sw/source/core/doc/DocumentOutlineNodesManager.cxx
+++ b/sw/source/core/doc/DocumentOutlineNodesManager.cxx
@@ -46,7 +46,7 @@ OUString GetExpandTextMerged(SwRootFrame const*const pLayout,
         SwTextNode const& rNode, bool const bWithNumber,
         bool const bWithSpacesForLevel, ExpandMode const i_mode)
 {
-    if (pLayout && pLayout->IsHideRedlines())
+    if (pLayout && pLayout->HasMergedParas())
     {
         SwTextFrame const*const pFrame(static_cast<SwTextFrame*>(rNode.getLayoutFrame(pLayout)));
         if (pFrame)
diff --git a/sw/source/core/doc/docfmt.cxx b/sw/source/core/doc/docfmt.cxx
index 3e1817d632fc..a6dceae3d9d4 100644
--- a/sw/source/core/doc/docfmt.cxx
+++ b/sw/source/core/doc/docfmt.cxx
@@ -95,7 +95,7 @@ static bool lcl_RstAttr( const SwNodePtr& rpNd, void* pArgs )
 {
     const sw::DocumentContentOperationsManager::ParaRstFormat* pPara = static_cast<sw::DocumentContentOperationsManager::ParaRstFormat*>(pArgs);
     SwContentNode* pNode = rpNd->GetContentNode();
-    if (pPara && pPara->pLayout && pPara->pLayout->IsHideRedlines()
+    if (pPara && pPara->pLayout && pPara->pLayout->HasMergedParas()
         && pNode && pNode->GetRedlineMergeFlag() == SwNode::Merge::Hidden)
     {
         return true;
@@ -998,7 +998,7 @@ static bool lcl_SetTextFormatColl( const SwNodePtr& rpNode, void* pArgs )
 
     sw::DocumentContentOperationsManager::ParaRstFormat* pPara = static_cast<sw::DocumentContentOperationsManager::ParaRstFormat*>(pArgs);
 
-    if (pPara->pLayout && pPara->pLayout->IsHideRedlines())
+    if (pPara->pLayout && pPara->pLayout->HasMergedParas())
     {
         if (pCNd->GetRedlineMergeFlag() == SwNode::Merge::Hidden)
         {
diff --git a/sw/source/core/doc/docnum.cxx b/sw/source/core/doc/docnum.cxx
index 35740d0127a6..d84574375112 100644
--- a/sw/source/core/doc/docnum.cxx
+++ b/sw/source/core/doc/docnum.cxx
@@ -1445,7 +1445,7 @@ namespace sw {
 void
 GotoPrevLayoutTextFrame(SwNodeIndex & rIndex, SwRootFrame const*const pLayout)
 {
-    if (pLayout && pLayout->IsHideRedlines())
+    if (pLayout && pLayout->HasMergedParas())
     {
         if (rIndex.GetNode().IsTextNode())
         {
@@ -1473,7 +1473,7 @@ GotoPrevLayoutTextFrame(SwNodeIndex & rIndex, SwRootFrame const*const pLayout)
 void
 GotoNextLayoutTextFrame(SwNodeIndex & rIndex, SwRootFrame const*const pLayout)
 {
-    if (pLayout && pLayout->IsHideRedlines())
+    if (pLayout && pLayout->HasMergedParas())
     {
         if (rIndex.GetNode().IsTextNode())
         {
@@ -1830,7 +1830,7 @@ bool SwDoc::MoveParagraph(SwPaM& rPam, tools::Long nOffset, bool const bIsOutlMv
     SwRootFrame const* pLayout(nullptr);
     for (SwRootFrame const*const pLay : GetAllLayouts())
     {
-        if (pLay->IsHideRedlines())
+        if (pLay->HasMergedParas())
         {
             pLayout = pLay;
         }
diff --git a/sw/source/core/doc/doctxm.cxx b/sw/source/core/doc/doctxm.cxx
index 5642224b083f..5eb27137c14d 100644
--- a/sw/source/core/doc/doctxm.cxx
+++ b/sw/source/core/doc/doctxm.cxx
@@ -777,7 +777,7 @@ void SwTOXBaseSection::Update(const SfxItemSet* pAttr,
     if (nullptr == pSectNd ||
         !pSectNd->GetNodes().IsDocNodes() ||
         IsHiddenFlag() ||
-        (pLayout->IsHideRedlines() && pSectNd->GetRedlineMergeFlag() == SwNode::Merge::Hidden))
+        (pLayout->HasMergedParas() && pSectNd->GetRedlineMergeFlag() == SwNode::Merge::Hidden))
     {
         return;
     }
@@ -1248,7 +1248,7 @@ void SwTOXBaseSection::UpdateOutline( const SwTextNode* pOwnChapterNode,
             pTextNd->getLayoutFrame(pLayout) &&
            !pTextNd->IsHiddenByParaField() &&
            !pTextNd->HasHiddenCharAttribute( true ) &&
-           (!pLayout || !pLayout->IsHideRedlines()
+           (!pLayout || !pLayout->HasMergedParas()
                 || static_cast<SwTextFrame*>(pTextNd->getLayoutFrame(pLayout))->GetTextNodeForParaProps() == pTextNd) &&
             ( !IsFromChapter() ||
                ::lcl_FindChapterNode(*pTextNd, pLayout) == pOwnChapterNode ))
@@ -1289,7 +1289,7 @@ void SwTOXBaseSection::UpdateTemplate(const SwTextNode* pOwnChapterNode,
                 if (pTextNd->GetText().getLength() &&
                     pTextNd->getLayoutFrame(pLayout) &&
                     pTextNd->GetNodes().IsDocNodes() &&
-                    (!pLayout || !pLayout->IsHideRedlines()
+                    (!pLayout || !pLayout->HasMergedParas()
                         || static_cast<SwTextFrame*>(pTextNd->getLayoutFrame(pLayout))->GetTextNodeForParaProps() == pTextNd) &&
                     (!IsFromChapter() || pOwnChapterNode ==
                         ::lcl_FindChapterNode(*pTextNd, pLayout)))
@@ -1512,7 +1512,7 @@ void SwTOXBaseSection::UpdateContent( SwTOXElement eMyType,
             }
 
             if (pCNd->getLayoutFrame(pLayout)
-                && (!pLayout || !pLayout->IsHideRedlines()
+                && (!pLayout || !pLayout->HasMergedParas()
                     || pCNd->GetRedlineMergeFlag() != SwNode::Merge::Hidden)
                 && ( !IsFromChapter() ||
                     ::lcl_FindChapterNode(*pCNd, pLayout) == pOwnChapterNode ))
@@ -1555,7 +1555,7 @@ void SwTOXBaseSection::UpdateTable(const SwTextNode* pOwnChapterNode,
                 aContentIdx.GetIndex() < pTableNd->EndOfSectionIndex() )
             {
                 if (pCNd->getLayoutFrame(pLayout)
-                    && (!pLayout || !pLayout->IsHideRedlines()
+                    && (!pLayout || !pLayout->HasMergedParas()
                         || pCNd->GetRedlineMergeFlag() != SwNode::Merge::Hidden)
                     && (!IsFromChapter()
                         || ::lcl_FindChapterNode(*pCNd, pLayout) == pOwnChapterNode))
diff --git a/sw/source/core/docnode/ndsect.cxx b/sw/source/core/docnode/ndsect.cxx
index 415334221392..c452a4ba3b61 100644
--- a/sw/source/core/docnode/ndsect.cxx
+++ b/sw/source/core/docnode/ndsect.cxx
@@ -1052,7 +1052,7 @@ void SwSectionNode::MakeFramesForAdjacentContentNode(const SwNodeIndex & rIdx)
         while( nullptr != (pFrame = aNode2Layout.NextFrame()) )
         {
             OSL_ENSURE( pFrame->IsSctFrame(), "Depend of Section not a Section." );
-            if (pFrame->getRootFrame()->IsHideRedlines()
+            if (pFrame->getRootFrame()->HasMergedParas()
                 && !rIdx.GetNode().IsCreateFrameWhenHidingRedlines())
             {
                 continue;
diff --git a/sw/source/core/docnode/ndtbl.cxx b/sw/source/core/docnode/ndtbl.cxx
index d1c07d36246b..392823880d21 100644
--- a/sw/source/core/docnode/ndtbl.cxx
+++ b/sw/source/core/docnode/ndtbl.cxx
@@ -2375,7 +2375,7 @@ void SwTableNode::MakeFramesForAdjacentContentNode(const SwNodeIndex & rIdx)
 
     while( nullptr != (pFrame = aNode2Layout.NextFrame()) )
     {
-        if (pFrame->getRootFrame()->IsHideRedlines()
+        if (pFrame->getRootFrame()->HasMergedParas()
             && !pNode->IsCreateFrameWhenHidingRedlines())
         {
             continue;
@@ -2407,7 +2407,7 @@ void SwTableNode::MakeOwnFrames(SwNodeIndex* pIdxBehind)
     SwNode2Layout aNode2Layout( *pNd, GetIndex() );
     while( nullptr != (pUpper = aNode2Layout.UpperFrame( pFrame, *this )) )
     {
-        if (pUpper->getRootFrame()->IsHideRedlines()
+        if (pUpper->getRootFrame()->HasMergedParas()
             && !IsCreateFrameWhenHidingRedlines())
         {
             continue;
diff --git a/sw/source/core/docnode/node.cxx b/sw/source/core/docnode/node.cxx
index c13ffe5620ed..1eed7c4c10db 100644
--- a/sw/source/core/docnode/node.cxx
+++ b/sw/source/core/docnode/node.cxx
@@ -1380,7 +1380,7 @@ void SwContentNode::MakeFramesForAdjacentContentNode(SwContentNode& rNode)
 
     while( nullptr != (pUpper = aNode2Layout.UpperFrame( pFrame, rNode )) )
     {
-        if (pUpper->getRootFrame()->IsHideRedlines()
+        if (pUpper->getRootFrame()->HasMergedParas()
             && !rNode.IsCreateFrameWhenHidingRedlines())
         {
             continue;
diff --git a/sw/source/core/edit/edattr.cxx b/sw/source/core/edit/edattr.cxx
index d0a3730e000b..58bb555c2e08 100644
--- a/sw/source/core/edit/edattr.cxx
+++ b/sw/source/core/edit/edattr.cxx
@@ -155,7 +155,7 @@ bool SwEditShell::GetPaMAttr( SwPaM* pPaM, SfxItemSet& rSet,
             {
                 if( pSet != &rSet )
                 {
-                    if (!GetLayout()->IsHideRedlines()
+                    if (!GetLayout()->HasMergedParas()
                         || pNd->GetRedlineMergeFlag() != SwNode::Merge::Hidden)
                     {
                         rSet.MergeValues( aSet );
@@ -211,7 +211,7 @@ bool SwEditShell::GetPaMParAttr( SwPaM* pPaM, SfxItemSet& rSet ) const
             // get the node
             SwNode* pNd = GetDoc()->GetNodes()[ n ];
 
-            if (GetLayout()->IsHideRedlines()
+            if (GetLayout()->HasMergedParas()
                 && pNd->GetRedlineMergeFlag() == SwNode::Merge::Hidden)
             {
                 continue;
diff --git a/sw/source/core/edit/editsh.cxx b/sw/source/core/edit/editsh.cxx
index cacb319b15da..85c065d60fed 100644
--- a/sw/source/core/edit/editsh.cxx
+++ b/sw/source/core/edit/editsh.cxx
@@ -859,7 +859,7 @@ sal_uInt16 SwEditShell::GetLineCount()
         {
             SwTextFrame *const pFrame(static_cast<SwTextFrame*>(pContentFrame));
             nRet = nRet + pFrame->GetLineCount(TextFrameIndex(COMPLETE_STRING));
-            if (GetLayout()->IsHideRedlines())
+            if (GetLayout()->HasMergedParas())
             {
                 if (auto const*const pMerged = pFrame->GetMergedPara())
                 {
diff --git a/sw/source/core/fields/reffld.cxx b/sw/source/core/fields/reffld.cxx
index 7d9e73feb7de..5d9c348e53dd 100644
--- a/sw/source/core/fields/reffld.cxx
+++ b/sw/source/core/fields/reffld.cxx
@@ -1104,7 +1104,7 @@ namespace sw {
 bool IsMarkHintHidden(SwRootFrame const& rLayout,
         SwTextNode const& rNode, SwTextAttrEnd const& rHint)
 {
-    if (!rLayout.IsHideRedlines())
+    if (!rLayout.HasMergedParas())
     {
         return false;
     }
diff --git a/sw/source/core/layout/frmtool.cxx b/sw/source/core/layout/frmtool.cxx
index baba2d3fe7f4..8ec418efd90a 100644
--- a/sw/source/core/layout/frmtool.cxx
+++ b/sw/source/core/layout/frmtool.cxx
@@ -1382,7 +1382,7 @@ void RecreateStartTextFrames(SwTextNode & rNode)
     SwIterator<SwTextFrame, SwTextNode, sw::IteratorMode::UnwrapMulti> aIter(rNode);
     for (SwTextFrame* pFrame = aIter.First(); pFrame; pFrame = aIter.Next())
     {
-        if (pFrame->getRootFrame()->IsHideRedlines())
+        if (pFrame->getRootFrame()->HasMergedParas())
         {
             frames.push_back(pFrame);
         }
@@ -1534,7 +1534,7 @@ void InsertCnt_( SwLayoutFrame *pLay, SwDoc *pDoc,
         if ( pNd->IsContentNode() )
         {
             SwContentNode* pNode = static_cast<SwContentNode*>(pNd);
-            if (pLayout->IsHideRedlines() && !pNd->IsCreateFrameWhenHidingRedlines())
+            if (pLayout->HasMergedParas() && !pNd->IsCreateFrameWhenHidingRedlines())
             {
                 if (pNd->IsTextNode()
                     && pNd->GetRedlineMergeFlag() == SwNode::Merge::NonFirst)
@@ -1612,7 +1612,7 @@ void InsertCnt_( SwLayoutFrame *pLay, SwDoc *pDoc,
                     continue;
                 }
             }
-            if (pLayout->IsHideRedlines() && !pNd->IsCreateFrameWhenHidingRedlines())
+            if (pLayout->HasMergedParas() && !pNd->IsCreateFrameWhenHidingRedlines())
             {
                 assert(pNd->GetRedlineMergeFlag() == SwNode::Merge::Hidden);
                 nIndex = pTableNode->EndOfSectionIndex();
@@ -1675,7 +1675,7 @@ void InsertCnt_( SwLayoutFrame *pLay, SwDoc *pDoc,
         }
         else if ( pNd->IsSectionNode() )
         {
-            if (pLayout->IsHideRedlines() && !pNd->IsCreateFrameWhenHidingRedlines())
+            if (pLayout->HasMergedParas() && !pNd->IsCreateFrameWhenHidingRedlines())
             {
                 assert(pNd->GetRedlineMergeFlag() == SwNode::Merge::Hidden);
                 continue; // skip it
@@ -1799,7 +1799,7 @@ void InsertCnt_( SwLayoutFrame *pLay, SwDoc *pDoc,
         }
         else if ( pNd->IsEndNode() && pNd->StartOfSectionNode()->IsSectionNode() )
         {
-            if (pLayout->IsHideRedlines() && !pNd->IsCreateFrameWhenHidingRedlines())
+            if (pLayout->HasMergedParas() && !pNd->IsCreateFrameWhenHidingRedlines())
             {
                 assert(pNd->GetRedlineMergeFlag() == SwNode::Merge::Hidden);
                 continue; // skip it
@@ -1875,7 +1875,7 @@ void InsertCnt_( SwLayoutFrame *pLay, SwDoc *pDoc,
         else if( pNd->IsStartNode() &&
                  SwFlyStartNode == static_cast<SwStartNode*>(pNd)->GetStartNodeType() )
         {
-            if (pLayout->IsHideRedlines() && !pNd->IsCreateFrameWhenHidingRedlines())
+            if (pLayout->HasMergedParas() && !pNd->IsCreateFrameWhenHidingRedlines())
             {
                 assert(pNd->GetRedlineMergeFlag() == SwNode::Merge::Hidden);
                 assert(false); // actually a fly-section can't be deleted?
@@ -1890,7 +1890,7 @@ void InsertCnt_( SwLayoutFrame *pLay, SwDoc *pDoc,
         }
         else
         {
-            assert(!pLayout->IsHideRedlines()
+            assert(!pLayout->HasMergedParas()
                 || pNd->GetRedlineMergeFlag() != SwNode::Merge::Hidden);
             // Neither Content nor table nor section, so we are done.
             break;
diff --git a/sw/source/core/layout/ssfrm.cxx b/sw/source/core/layout/ssfrm.cxx
index 9f0da8f708b6..0eeaba0de1bc 100644
--- a/sw/source/core/layout/ssfrm.cxx
+++ b/sw/source/core/layout/ssfrm.cxx
@@ -415,7 +415,7 @@ SwContentFrame::SwContentFrame( SwContentNode * const pContent, SwFrame* pSib )
     SwFrame( pContent, pSib ),
     SwFlowFrame( static_cast<SwFrame&>(*this) )
 {
-    assert(!getRootFrame()->IsHideRedlines() || pContent->IsCreateFrameWhenHidingRedlines());
+    assert(!getRootFrame()->HasMergedParas() || pContent->IsCreateFrameWhenHidingRedlines());
 }
 
 void SwContentFrame::DestroyImpl()
diff --git a/sw/source/core/text/txtfrm.cxx b/sw/source/core/text/txtfrm.cxx
index b9dfd52fa9cb..ae81e324ec16 100644
--- a/sw/source/core/text/txtfrm.cxx
+++ b/sw/source/core/text/txtfrm.cxx
@@ -306,7 +306,7 @@ namespace sw {
 
     bool IsParaPropsNode(SwRootFrame const& rLayout, SwTextNode const& rNode)
     {
-        if (rLayout.IsHideRedlines())
+        if (rLayout.HasMergedParas())
         {
             if (SwTextFrame const*const pFrame = static_cast<SwTextFrame*>(rNode.getLayoutFrame(&rLayout)))
             {
@@ -351,7 +351,7 @@ namespace sw {
     GetFirstAndLastNode(SwRootFrame const& rLayout, SwNodeIndex const& rPos)
     {
         SwTextNode *const pTextNode(rPos.GetNode().GetTextNode());
-        if (pTextNode && rLayout.IsHideRedlines())
+        if (pTextNode && rLayout.HasMergedParas())
         {
             if (SwTextFrame const*const pFrame = static_cast<SwTextFrame*>(pTextNode->getLayoutFrame(&rLayout)))
             {
@@ -368,7 +368,7 @@ namespace sw {
             SwTextNode const& rNode, SwRootFrame const*const pLayout)
     {
         rNode.SwContentNode::GetAttr(rFormatSet);
-        if (pLayout && pLayout->IsHideRedlines())
+        if (pLayout && pLayout->HasMergedParas())
         {
             auto pFrame = static_cast<SwTextFrame*>(rNode.getLayoutFrame(pLayout));
             if (sw::MergedPara const*const pMerged = pFrame ? pFrame->GetMergedPara() : nullptr)
diff --git a/sw/source/core/tox/ToxTextGenerator.cxx b/sw/source/core/tox/ToxTextGenerator.cxx
index 11ced0144d8f..0cd6babd20b1 100644
--- a/sw/source/core/tox/ToxTextGenerator.cxx
+++ b/sw/source/core/tox/ToxTextGenerator.cxx
@@ -80,7 +80,7 @@ ToxTextGenerator::GetNumStringOfFirstNode(const SwTOXSortTabBase& rBase,
     if (!pNd) {
         return sRet;
     }
-    if (pLayout && pLayout->IsHideRedlines())
+    if (pLayout && pLayout->HasMergedParas())
     {   // note: pNd could be any node, since it could be Sequence etc.
         pNd = sw::GetParaPropsNode(*pLayout, SwNodeIndex(*pNd));
     }
@@ -366,7 +366,7 @@ ToxTextGenerator::HandleTextToken(const SwTOXSortTabBase& source,
 
     sal_Int32 nOffset(0);
     GetAttributesForNode(result, nOffset, *pSrc, stripper, pool, pLayout);
-    if (pLayout && pLayout->IsHideRedlines())
+    if (pLayout && pLayout->HasMergedParas())
     {
         if (SwTextFrame const*const pFrame = static_cast<SwTextFrame*>(pSrc->getLayoutFrame(pLayout)))
         {
diff --git a/sw/source/core/tox/tox.cxx b/sw/source/core/tox/tox.cxx
index 0f9526488cb8..16a86201bce1 100644
--- a/sw/source/core/tox/tox.cxx
+++ b/sw/source/core/tox/tox.cxx
@@ -176,8 +176,8 @@ void SwTOXMark::Notify(const SfxHint& rHint)
         // Check for being hidden
         if(rNode.IsHiddenByParaField() || SwScriptInfo::IsInHiddenRange(rNode, rTextMark.GetStart()))
             return;
-        // Xhwxk for being hidden by hidden redlines
-        if(pLayout && pLayout->IsHideRedlines() && sw::IsMarkHintHidden(*pLayout, rNode, rTextMark))
+        // Check for being hidden by hidden redlines
+        if (pLayout && pLayout->HasMergedParas() && sw::IsMarkHintHidden(*pLayout, rNode, rTextMark))
             return;
         pCollectLayoutHint->m_rMarks.push_back(rTextMark);
     }
diff --git a/sw/source/core/tox/txmsrt.cxx b/sw/source/core/tox/txmsrt.cxx
index 7afb7fcd08c9..08f4087a7bb0 100644
--- a/sw/source/core/tox/txmsrt.cxx
+++ b/sw/source/core/tox/txmsrt.cxx
@@ -599,7 +599,7 @@ void SwTOXPara::FillText( SwTextNode& rNd, const SwIndex& rInsPos, sal_uInt16,
             // sw_redlinehide: this probably won't HideDeletions
             pSrc->CopyExpandText( rNd, &rInsPos, 0, -1,
                     pLayout, false, false, true );
-            if (pLayout && pLayout->IsHideRedlines())
+            if (pLayout && pLayout->HasMergedParas())
             {
                 if (SwTextFrame const*const pFrame = static_cast<SwTextFrame*>(pSrc->getLayoutFrame(pLayout)))
                 {
diff --git a/sw/source/core/txtnode/ndtxt.cxx b/sw/source/core/txtnode/ndtxt.cxx
index 62cf217563a1..d1933b790a4a 100644
--- a/sw/source/core/txtnode/ndtxt.cxx
+++ b/sw/source/core/txtnode/ndtxt.cxx
@@ -534,7 +534,7 @@ SwTextNode *SwTextNode::SplitContentNode(const SwPosition & rPos,
         SwIterator<SwTextFrame, SwTextNode, sw::IteratorMode::UnwrapMulti> aIter(*this);
         for (SwTextFrame* pFrame = aIter.First(); pFrame; pFrame = aIter.Next())
         {
-            if (pFrame->getRootFrame()->IsHideRedlines())
+            if (pFrame->getRootFrame()->HasMergedParas())
             {
                 isHide = true;
             }
@@ -635,7 +635,7 @@ SwTextNode *SwTextNode::SplitContentNode(const SwPosition & rPos,
         for (SwTextFrame * pFrame = aIter.First(); pFrame; pFrame = aIter.Next())
         {
             frames.push_back(pFrame);
-            if (pFrame->getRootFrame()->IsHideRedlines())
+            if (pFrame->getRootFrame()->HasMergedParas())
             {
                 isHide = true;
             }
@@ -805,7 +805,7 @@ void MoveDeletedPrevFrames(const SwTextNode & rDeletedPrev, SwTextNode & rNode)
     SwIterator<SwTextFrame, SwTextNode, sw::IteratorMode::UnwrapMulti> aIter(rDeletedPrev);
     for (SwTextFrame* pFrame = aIter.First(); pFrame; pFrame = aIter.Next())
     {
-        if (pFrame->getRootFrame()->IsHideRedlines())
+        if (pFrame->getRootFrame()->HasMergedParas())
         {
             frames.push_back(pFrame);
         }
@@ -815,7 +815,7 @@ void MoveDeletedPrevFrames(const SwTextNode & rDeletedPrev, SwTextNode & rNode)
         SwIterator<SwTextFrame, SwTextNode, sw::IteratorMode::UnwrapMulti> aIt(rNode);
         for (SwTextFrame* pFrame = aIt.First(); pFrame; pFrame = aIt.Next())
         {
-            if (pFrame->getRootFrame()->IsHideRedlines())
+            if (pFrame->getRootFrame()->HasMergedParas())
             {
                 auto const it(std::find(frames2.begin(), frames2.end(), pFrame));
                 assert(it != frames2.end());
@@ -868,7 +868,7 @@ void CheckResetRedlineMergeFlag(SwTextNode & rNode, Recreate const eRecreateMerg
         SwIterator<SwTextFrame, SwTextNode, sw::IteratorMode::UnwrapMulti> aIter(*pMergeNode);
         for (SwTextFrame* pFrame = aIter.First(); pFrame; pFrame = aIter.Next())
         {
-            if (pFrame->getRootFrame()->IsHideRedlines())
+            if (pFrame->getRootFrame()->HasMergedParas())
             {
                 frames.push_back(pFrame);
             }
@@ -902,7 +902,7 @@ void CheckResetRedlineMergeFlag(SwTextNode & rNode, Recreate const eRecreateMerg
                 }
                 break; // checking once is enough
             }
-            else if (pFrame->getRootFrame()->IsHideRedlines())
+            else if (pFrame->getRootFrame()->HasMergedParas())
             {
                 rNode.SetRedlineMergeFlag(SwNode::Merge::None);
                 break; // checking once is enough
diff --git a/sw/source/core/txtnode/thints.cxx b/sw/source/core/txtnode/thints.cxx
index 297e847e05d9..af1f220fa448 100644
--- a/sw/source/core/txtnode/thints.cxx
+++ b/sw/source/core/txtnode/thints.cxx
@@ -2114,7 +2114,7 @@ bool SwTextNode::GetParaAttr(SfxItemSet& rSet, sal_Int32 nStt, sal_Int32 nEnd,
 {
     assert(!rSet.Count()); // handled inconsistently, typically an error?
 
-    if (pLayout && pLayout->IsHideRedlines())
+    if (pLayout && pLayout->HasMergedParas())
     {
         if (GetRedlineMergeFlag() == SwNode::Merge::Hidden)
         {
diff --git a/sw/source/core/undo/undel.cxx b/sw/source/core/undo/undel.cxx
index 245dfd3d3921..745914096add 100644
--- a/sw/source/core/undo/undel.cxx
+++ b/sw/source/core/undo/undel.cxx
@@ -127,7 +127,7 @@ static void DelFullParaMoveFrames(SwDoc & rDoc, SwUndRng const& rRange,
     SwIterator<SwTextFrame, SwTextNode, sw::IteratorMode::UnwrapMulti> aIter(*pFirstMergedDeletedTextNode);
     for (SwTextFrame* pFrame = aIter.First(); pFrame; pFrame = aIter.Next())
     {
-        if (pFrame->getRootFrame()->IsHideRedlines())
+        if (pFrame->getRootFrame()->HasMergedParas())
         {
             assert(pFrame->GetMergedPara());
             assert(pFrame->GetMergedPara()->pFirstNode == pFirstMergedDeletedTextNode);
@@ -1079,7 +1079,7 @@ void SwUndoDelete::UndoImpl(::sw::UndoRedoContext & rContext)
             SwIterator<SwTextFrame, SwTextNode, sw::IteratorMode::UnwrapMulti> aIter(*pNextNode);
             for (SwTextFrame* pFrame = aIter.First(); pFrame; pFrame = aIter.Next())
             {
-                if (pFrame->getRootFrame()->IsHideRedlines())
+                if (pFrame->getRootFrame()->HasMergedParas())
                 {
                     frames.push_back(pFrame);
                 }
diff --git a/sw/source/filter/xml/wrtxml.cxx b/sw/source/filter/xml/wrtxml.cxx
index 3c1a468474ff..af7cd294e336 100644
--- a/sw/source/filter/xml/wrtxml.cxx
+++ b/sw/source/filter/xml/wrtxml.cxx
@@ -372,7 +372,7 @@ ErrCode SwXMLWriter::Write_( const uno::Reference < task::XStatusIndicator >& xS
     if( m_pDoc->getIDocumentLayoutAccess().GetCurrentViewShell() && m_pDoc->getIDocumentStatistics().GetDocStat().nPage > 1 &&
         !(m_bOrganizerMode || m_bBlock || bErr ||
             // sw_redlinehide: disable layout cache for now
-            m_pDoc->getIDocumentLayoutAccess().GetCurrentLayout()->IsHideRedlines()))
+            m_pDoc->getIDocumentLayoutAccess().GetCurrentLayout()->HasMergedParas()))
     {
         try
         {
commit a0d0a75995aee91eb34b622af13710bf251eca16
Author:     Michael Stahl <Michael.Stahl at cib.de>
AuthorDate: Tue Nov 3 21:48:02 2020 +0100
Commit:     Michael Stahl <Michael.Stahl at cib.de>
CommitDate: Fri Nov 6 21:56:40 2020 +0100

    sw_fieldmarkhide: add FieldmarkMode to SwRootFrame
    
    Change-Id: I366fe171fbcadad7643c54d76c3e28cc4b6b5dfa

diff --git a/sw/source/core/inc/rootfrm.hxx b/sw/source/core/inc/rootfrm.hxx
index 74a015c90d53..fbc95b8a8691 100644
--- a/sw/source/core/inc/rootfrm.hxx
+++ b/sw/source/core/inc/rootfrm.hxx
@@ -46,6 +46,8 @@ namespace sw {
     {
         Shown, Hidden
     };
+
+    enum class FieldmarkMode { ShowCommand = 1, ShowResult = 2, ShowBoth = 3 };
 };
 
 enum class SwInvalidateFlags
@@ -118,6 +120,7 @@ class SAL_DLLPUBLIC_RTTI SwRootFrame: public SwLayoutFrame
                                       // @see dcontact.cxx, ::Changed()
     bool    mbLayoutFreezed;
     bool    mbHideRedlines;
+    sw::FieldmarkMode m_FieldmarkMode;
 
     /**
      * For BrowseMode
@@ -416,6 +419,11 @@ public:
      */
     bool IsHideRedlines() const { return mbHideRedlines; }
     void SetHideRedlines(bool);
+    sw::FieldmarkMode GetFieldmarkMode() const { return m_FieldmarkMode; }
+    void SetFieldmarkMode(sw::FieldmarkMode);
+    bool HasMergedParas() const {
+        return IsHideRedlines() || GetFieldmarkMode() != sw::FieldmarkMode::ShowBoth;
+    }
 };
 
 inline tools::Long SwRootFrame::GetBrowseWidth() const
diff --git a/sw/source/core/layout/newfrm.cxx b/sw/source/core/layout/newfrm.cxx
index 8a62abd8aa54..cd527d13903c 100644
--- a/sw/source/core/layout/newfrm.cxx
+++ b/sw/source/core/layout/newfrm.cxx
@@ -414,6 +414,7 @@ SwRootFrame::SwRootFrame( SwFrameFormat *pFormat, SwViewShell * pSh ) :
     mbCallbackActionEnabled ( false ),
     mbLayoutFreezed ( false ),
     mbHideRedlines(pFormat->GetDoc()->GetDocumentRedlineManager().IsHideRedlines()),
+    m_FieldmarkMode(sw::FieldmarkMode::ShowBoth),
     mnBrowseWidth(MIN_BROWSE_WIDTH),
     mpTurbo( nullptr ),
     mpLastPage( nullptr ),
diff --git a/sw/source/core/layout/wsfrm.cxx b/sw/source/core/layout/wsfrm.cxx
index ae422dc2ea46..fd3cb4a30677 100644
--- a/sw/source/core/layout/wsfrm.cxx
+++ b/sw/source/core/layout/wsfrm.cxx
@@ -4497,15 +4497,10 @@ static void UnHideRedlinesExtras(SwRootFrame & rLayout,
     }
 }
 
-void SwRootFrame::SetHideRedlines(bool const bHideRedlines)
+static void DoHide(SwRootFrame & rLayout)
 {
-    if (bHideRedlines == mbHideRedlines)
-    {
-        return;
-    }
-    mbHideRedlines = bHideRedlines;
-    assert(GetCurrShell()->ActionPend()); // tdf#125754 avoid recursive layout
-    SwDoc & rDoc(*GetFormat()->GetDoc());
+    assert(rLayout.GetCurrShell()->ActionPend()); // tdf#125754 avoid recursive layout
+    SwDoc & rDoc(*rLayout.GetFormat()->GetDoc());
     // don't do early return if there are no redlines:
     // Show->Hide must init hidden number trees
     // Hide->Show may be called after all redlines have been deleted but there
@@ -4535,26 +4530,26 @@ void SwRootFrame::SetHideRedlines(bool const bHideRedlines)
     // vice-versa; alas flys may contain flys, so we skip some of them
     // if they have already been created from scratch via their anchor flys.
     std::set<sal_uLong> skippedFlys;
-    UnHideRedlinesExtras(*this, rNodes, rNodes.GetEndOfAutotext(),
+    UnHideRedlinesExtras(rLayout, rNodes, rNodes.GetEndOfAutotext(),
         // when un-hiding, delay all fly frame creation to AppendAllObjs below
-                         IsHideRedlines() ? &skippedFlys : nullptr);
+                         rLayout.IsHideRedlines() ? &skippedFlys : nullptr);
     // Footnotes are created automatically (after invalidation etc.) by
     // ConnectFootnote(), but need to be deleted manually. Footnotes do not
     // occur in flys or headers/footers.
-    UnHideRedlinesExtras(*this, rNodes, rNodes.GetEndOfInserts(), nullptr);
-    UnHideRedlines(*this, rNodes, rNodes.GetEndOfContent(), nullptr);
+    UnHideRedlinesExtras(rLayout, rNodes, rNodes.GetEndOfInserts(), nullptr);
+    UnHideRedlines(rLayout, rNodes, rNodes.GetEndOfContent(), nullptr);
 
-    if (!IsHideRedlines())
+    if (!rLayout.IsHideRedlines())
     {   // create all previously hidden flys at once:
         // * Flys on first node of pre-existing merged frames that are hidden
         //   (in delete redline), to be added to the existing frame
         // * Flys on non-first (hidden/merged) nodes of pre-existing merged
         //   frames, to be added to the new frame of their node
         // * Flys anchored in other flys that are hidden
-        AppendAllObjs(rDoc.GetSpzFrameFormats(), this);
+        AppendAllObjs(rDoc.GetSpzFrameFormats(), &rLayout);
     }
 
-    const bool bIsShowChangesInMargin = GetCurrShell()->GetViewOptions()->IsShowChangesInMargin();
+    const bool bIsShowChangesInMargin = rLayout.GetCurrShell()->GetViewOptions()->IsShowChangesInMargin();
     for (auto const pRedline : rDoc.getIDocumentRedlineAccess().GetRedlineTable())
     {   // DELETE are handled by the code above; for other types, need to
         // trigger repaint of text frames to add/remove the redline color font
@@ -4597,7 +4592,7 @@ void SwRootFrame::SetHideRedlines(bool const bHideRedlines)
 
     // update SwPostItMgr / notes in the margin
     // note: as long as all shells share layout, broadcast to all shells!
-    rDoc.GetDocShell()->Broadcast( SwFormatFieldHint(nullptr, bHideRedlines
+    rDoc.GetDocShell()->Broadcast( SwFormatFieldHint(nullptr, rLayout.IsHideRedlines()
             ? SwFormatFieldHintWhich::REMOVED
             : SwFormatFieldHintWhich::INSERTED) );
 
@@ -4605,4 +4600,27 @@ void SwRootFrame::SetHideRedlines(bool const bHideRedlines)
 //    InvalidateAllContent(SwInvalidateFlags::Size); // ??? TODO what to invalidate?  this is the big hammer
 }
 
+void SwRootFrame::SetHideRedlines(bool const bHideRedlines)
+{
+    if (bHideRedlines == mbHideRedlines)
+    {
+        return;
+    }
+    mbHideRedlines = bHideRedlines;
+    DoHide(*this);
+}
+
+void SwRootFrame::SetFieldmarkMode(sw::FieldmarkMode const eMode)
+{
+    if (eMode == m_FieldmarkMode)
+    {
+        return;
+    }
+    // TODO: remove temporary ShowBoth
+    m_FieldmarkMode = sw::FieldmarkMode::ShowBoth;
+    DoHide(*this);
+    m_FieldmarkMode = eMode;
+    DoHide(*this);
+}
+
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
commit 453a566d082e5a91541baa6c2e80e21907d13283
Author:     Michael Stahl <Michael.Stahl at cib.de>
AuthorDate: Tue Nov 3 16:40:45 2020 +0100
Commit:     Michael Stahl <Michael.Stahl at cib.de>
CommitDate: Fri Nov 6 21:56:02 2020 +0100

    sw_fieldmarkhide: SwRedlineItr assumption that Show means no MergedPara
    
    ... in SwRedlineItr::CheckLine() and also SwRedlineItr::Seek()
    
    Change-Id: I711ec37bd345cbf5f5f5339b8d792bcb56c425c7

diff --git a/sw/source/core/text/redlnitr.cxx b/sw/source/core/text/redlnitr.cxx
index 9dafe23aff05..b878f26e27f5 100644
--- a/sw/source/core/text/redlnitr.cxx
+++ b/sw/source/core/text/redlnitr.cxx
@@ -463,7 +463,8 @@ void SwAttrIter::CtorInitAttrIter(SwTextNode & rTextNode,
         }
         // TODO this is true initially but after delete ops it may be false... need to delete m_pMerged somewhere?
         // assert(SwRedlineTable::npos != nRedlPos);
-        assert(SwRedlineTable::npos != nRedlPos || m_pMergedPara->extents.size() <= 1);
+        // false now with fieldmarks
+        // assert(SwRedlineTable::npos != nRedlPos || m_pMergedPara->extents.size() <= 1);
     }
     if (!(pExtInp || m_pMergedPara || SwRedlineTable::npos != nRedlPos))
         return;
@@ -476,7 +477,7 @@ void SwAttrIter::CtorInitAttrIter(SwTextNode & rTextNode,
     }
 
     m_pRedline.reset(new SwRedlineItr( rTextNode, *m_pFont, m_aAttrHandler, nRedlPos,
-                    m_pMergedPara
+                    (pRootFrame && pRootFrame->IsHideRedlines())
                         ? SwRedlineItr::Mode::Hide
                         : bShow
                             ? SwRedlineItr::Mode::Show
@@ -539,7 +540,6 @@ short SwRedlineItr::Seek(SwFont& rFnt,
     if( ExtOn() )
         return 0; // Abbreviation: if we're within an ExtendTextInputs
                   // there can't be other changes of attributes (not even by redlining)
-    assert(m_eMode == Mode::Hide || m_nNdIdx == nNode);
     if (m_eMode == Mode::Show)
     {
         if (m_bOn)
@@ -570,7 +570,7 @@ short SwRedlineItr::Seek(SwFont& rFnt,
 
         for ( ; m_nAct < m_rDoc.getIDocumentRedlineAccess().GetRedlineTable().size() ; ++m_nAct)
         {
-            m_rDoc.getIDocumentRedlineAccess().GetRedlineTable()[ m_nAct ]->CalcStartEnd(m_nNdIdx, m_nStart, m_nEnd);
+            m_rDoc.getIDocumentRedlineAccess().GetRedlineTable()[ m_nAct ]->CalcStartEnd(nNode, m_nStart, m_nEnd);
 
             if (nNew < m_nEnd)
             {
@@ -811,7 +811,6 @@ bool SwRedlineItr::CheckLine(
     // case, but surely that was a bug?
     if (m_nFirst == SwRedlineTable::npos || m_eMode != Mode::Show)
         return false;
-    assert(nStartNode == nEndNode); (void) nStartNode; (void) nEndNode;
     if( nChkEnd == nChkStart ) // empty lines look one char further
         ++nChkEnd;
     sal_Int32 nOldStart = m_nStart;
@@ -819,23 +818,42 @@ bool SwRedlineItr::CheckLine(
     SwRedlineTable::size_type const nOldAct = m_nAct;
     bool bRet = bRedlineEnd = false;
 
+    SwPosition const start(*m_rDoc.GetNodes()[nStartNode]->GetContentNode(), nChkStart);
+    SwPosition const end(*m_rDoc.GetNodes()[nEndNode]->GetContentNode(), nChkEnd);
     for (m_nAct = m_nFirst; m_nAct < m_rDoc.getIDocumentRedlineAccess().GetRedlineTable().size(); ++m_nAct)
     {
         SwRangeRedline const*const pRedline(
             m_rDoc.getIDocumentRedlineAccess().GetRedlineTable()[ m_nAct ] );
-        pRedline->CalcStartEnd( m_nNdIdx, m_nStart, m_nEnd );
-        if (nChkEnd < m_nStart)
-            break;
-        if (nChkStart <= m_nEnd && (nChkEnd > m_nStart || COMPLETE_STRING == m_nEnd))
+        bool isBreak(false);
+        switch (ComparePosition(*pRedline->Start(), *pRedline->End(), start, end))
         {
-            bRet = true;
-            if ( rRedlineText.isEmpty() && pRedline->GetType() == RedlineType::Delete )
-                rRedlineText = const_cast<SwRangeRedline*>(pRedline)->GetDescr(/*bSimplified=*/true);
-            if ( COMPLETE_STRING == m_nEnd )
-            {
+            case SwComparePosition::Behind:
+                isBreak = true;
+                break;
+            case SwComparePosition::OverlapBehind:
+            case SwComparePosition::Outside:
+            case SwComparePosition::Equal:
                 bRedlineEnd = true;
+                isBreak = true;
+                [[fallthrough]];
+            case SwComparePosition::Inside:
+            case SwComparePosition::OverlapBefore:
+            {
+                bRet = true;
+                if (rRedlineText.isEmpty() && pRedline->GetType() == RedlineType::Delete)
+                {
+                    rRedlineText = const_cast<SwRangeRedline*>(pRedline)->GetDescr(/*bSimplified=*/true);
+                }
                 break;
             }
+            case SwComparePosition::Before:
+            case SwComparePosition::CollideStart:
+            case SwComparePosition::CollideEnd:
+                break; // -Werror=switch
+        }
+        if (isBreak)
+        {
+            break;
         }
     }
 
commit 5bf37b020c26c4cc0362e4fef46b8e263af1f3ff
Author:     Michael Stahl <Michael.Stahl at cib.de>
AuthorDate: Mon Nov 2 15:58:57 2020 +0100
Commit:     Michael Stahl <Michael.Stahl at cib.de>
CommitDate: Fri Nov 6 18:16:38 2020 +0100

    writerfilter: remove leftover comment
    
    Change-Id: Idb6dbb7ccb9a254def6029bb9ba84a3b02015d70

diff --git a/writerfilter/source/dmapper/DomainMapper_Impl.cxx b/writerfilter/source/dmapper/DomainMapper_Impl.cxx
index 7eb07f3043ac..08fe93e46a42 100644
--- a/writerfilter/source/dmapper/DomainMapper_Impl.cxx
+++ b/writerfilter/source/dmapper/DomainMapper_Impl.cxx
@@ -6001,7 +6001,6 @@ void DomainMapper_Impl::CloseFieldCommand()
             else
                 m_bParaHadField = false;
         }
-        //set the text field if there is any
     }
     catch( const uno::Exception& )
     {
commit f4f46960527dc7a317232336528f1ab32da785a3
Author:     Michael Stahl <Michael.Stahl at cib.de>
AuthorDate: Fri Oct 30 20:30:40 2020 +0100
Commit:     Michael Stahl <Michael.Stahl at cib.de>
CommitDate: Fri Nov 6 18:16:38 2020 +0100

    sw: return SwXFieldmark in SwXFieldEnumeration
    
    * Implement text::XTextField in SwXFieldmark
    * That requires overriding XTextContent, just forward to SwXBookmark
    * Also override XServiceInfo implementation in SwXFieldmark
    * Add a PropertySetInfo for SwXFieldmark, which doesn't support "Hidden"
      or "Condition" properties of SwXBookmark
    * in SwXFieldmark::setFieldType(), only allow sensible new types
    * fix DomainMapper_Impl assumptions that if it implements XTextField
      it can't be a fieldmark, which caused CppunitTest_sw_ooxmlexport10
      testTdf92157 to fail with a SAXException caused by some disposed
      SwXTextCursor
    
    Change-Id: I1ae2e9cb99ea784040874517e4d1af7e59d24405

diff --git a/sw/inc/IDocumentMarkAccess.hxx b/sw/inc/IDocumentMarkAccess.hxx
index 13bd7fdc0d7c..1ad39701d02b 100644
--- a/sw/inc/IDocumentMarkAccess.hxx
+++ b/sw/inc/IDocumentMarkAccess.hxx
@@ -312,6 +312,14 @@ class IDocumentMarkAccess
 
 
         // Fieldmarks
+        /** returns a STL-like random access iterator to the begin of the sequence of fieldmarks.
+        */
+        virtual const_iterator_t getFieldmarksBegin() const =0;
+
+        /** returns a STL-like random access iterator to the end of the sequence of fieldmarks.
+        */
+        virtual const_iterator_t getFieldmarksEnd() const =0;
+
         /// get Fieldmark for CH_TXT_ATR_FIELDSTART/CH_TXT_ATR_FIELDEND at rPos
         virtual ::sw::mark::IFieldmark* getFieldmarkAt(const SwPosition& rPos) const =0;
         virtual ::sw::mark::IFieldmark* getFieldmarkFor(const SwPosition& pos) const =0;
diff --git a/sw/inc/unomap.hxx b/sw/inc/unomap.hxx
index caee6bc5c209..1cd22609f02e 100644
--- a/sw/inc/unomap.hxx
+++ b/sw/inc/unomap.hxx
@@ -125,7 +125,8 @@ struct SfxItemPropertyMapEntry;
 #define PROPERTY_MAP_ACCESSIBILITY_TEXT_ATTRIBUTE       99
 #define PROPERTY_MAP_TABLE_STYLE                        100
 #define PROPERTY_MAP_CELL_STYLE                         101
-#define PROPERTY_MAP_END                                102
+#define PROPERTY_MAP_FIELDMARK                          102
+#define PROPERTY_MAP_END                                103
 
 //S&E
 #define WID_WORDS                0
diff --git a/sw/source/core/doc/docbm.cxx b/sw/source/core/doc/docbm.cxx
index b7076c9e82e1..c2af85f1cd0a 100644
--- a/sw/source/core/doc/docbm.cxx
+++ b/sw/source/core/doc/docbm.cxx
@@ -1347,6 +1347,13 @@ namespace sw::mark
     sal_Int32 MarkManager::getBookmarksCount() const
         { return m_vBookmarks.size(); }
 
+    IDocumentMarkAccess::const_iterator_t MarkManager::getFieldmarksBegin() const
+        { return m_vFieldmarks.begin(); }
+
+    IDocumentMarkAccess::const_iterator_t MarkManager::getFieldmarksEnd() const
+        { return m_vFieldmarks.end(); }
+
+
     // finds the first that is starting after
     IDocumentMarkAccess::const_iterator_t MarkManager::findFirstBookmarkStartsAfter(const SwPosition& rPos) const
     {
diff --git a/sw/source/core/inc/MarkManager.hxx b/sw/source/core/inc/MarkManager.hxx
index 8266198a521d..a25e414f8aa2 100644
--- a/sw/source/core/inc/MarkManager.hxx
+++ b/sw/source/core/inc/MarkManager.hxx
@@ -85,6 +85,8 @@ namespace sw::mark {
             virtual const_iterator_t findFirstBookmarkStartsAfter(const SwPosition& rPos) const override;
 
             // Fieldmarks
+            virtual const_iterator_t getFieldmarksBegin() const override;
+            virtual const_iterator_t getFieldmarksEnd() const override;
             virtual ::sw::mark::IFieldmark* getFieldmarkAt(const SwPosition& rPos) const override;
             virtual ::sw::mark::IFieldmark* getFieldmarkFor(const SwPosition& rPos) const override;
             virtual ::sw::mark::IFieldmark* getFieldmarkBefore(const SwPosition& rPos) const override;
diff --git a/sw/source/core/inc/unobookmark.hxx b/sw/source/core/inc/unobookmark.hxx
index f277748b5d7e..8ebbc373008f 100644
--- a/sw/source/core/inc/unobookmark.hxx
+++ b/sw/source/core/inc/unobookmark.hxx
@@ -25,6 +25,7 @@
 #include <com/sun/star/beans/XPropertySet.hpp>
 #include <com/sun/star/container/XNamed.hpp>
 #include <com/sun/star/text/XTextContent.hpp>
+#include <com/sun/star/text/XTextField.hpp>
 #include <com/sun/star/text/XFormField.hpp>
 
 #include <cppuhelper/implbase.hxx>
@@ -70,6 +71,8 @@ protected:
 
     IDocumentMarkAccess* GetIDocumentMarkAccess();
 
+    SwDoc * GetDoc();
+
     void registerInMark( SwXBookmark& rXMark, ::sw::mark::IMark* const pMarkBase );
 
     virtual ~SwXBookmark() override;
@@ -177,13 +180,20 @@ class SwXFieldmarkParameters
 };
 
 typedef cppu::ImplInheritanceHelper< SwXBookmark,
-    css::text::XFormField > SwXFieldmark_Base;
+        css::text::XFormField,
+        css::text::XTextField
+    > SwXFieldmark_Base;
 
 class SwXFieldmark final
     : public SwXFieldmark_Base
 {
     ::sw::mark::ICheckboxFieldmark* getCheckboxFieldmark();
-    bool m_bReplacementObject;
+    bool const m_bReplacementObject;
+
+    css::uno::Reference<css::text::XTextRange>
+        GetCommand(::sw::mark::IFieldmark const& rMark);
+    css::uno::Reference<css::text::XTextRange>
+        GetResult(::sw::mark::IFieldmark const& rMark);
 
     SwXFieldmark(bool isReplacementObject, SwDoc* pDoc);
 
@@ -194,15 +204,41 @@ public:
 
     virtual void attachToRange(
             const css::uno::Reference<css::text::XTextRange > & xTextRange) override;
-    virtual OUString SAL_CALL getFieldType() override;
-    virtual void SAL_CALL setFieldType(const OUString& description ) override;
-    virtual css::uno::Reference< css::container::XNameContainer > SAL_CALL getParameters(  ) override;
+
+    // XServiceInfo
+    virtual OUString SAL_CALL getImplementationName() override;
+    virtual css::uno::Sequence<OUString> SAL_CALL
+        getSupportedServiceNames() override;
+
+    // XPropertySet
+    virtual css::uno::Reference<css::beans::XPropertySetInfo> SAL_CALL
+        getPropertySetInfo() override;
     virtual void SAL_CALL setPropertyValue(
             const OUString& rPropertyName,
             const css::uno::Any& rValue) override;
-
     virtual css::uno::Any SAL_CALL getPropertyValue(
             const OUString& rPropertyName) override;
+
+    // XComponent
+    virtual void SAL_CALL dispose() override;
+    virtual void SAL_CALL addEventListener(
+            const css::uno::Reference<css::lang::XEventListener> & xListener) override;
+    virtual void SAL_CALL removeEventListener(
+            const css::uno::Reference<css::lang::XEventListener> & xListener) override;
+
+    // XTextContent
+    virtual void SAL_CALL attach(
+            const css::uno::Reference<css::text::XTextRange> & xTextRange) override;
+    virtual css::uno::Reference<css::text::XTextRange> SAL_CALL getAnchor() override;
+
+    // XTextField
+    virtual OUString SAL_CALL getPresentation(sal_Bool bShowCommand) override;
+
+    // XFormField
+    virtual OUString SAL_CALL getFieldType() override;
+    virtual void SAL_CALL setFieldType(const OUString& description) override;
+    virtual css::uno::Reference<css::container::XNameContainer> SAL_CALL getParameters() override;
+
 };
 
 #endif // INCLUDED_SW_SOURCE_CORE_INC_UNOBOOKMARK_HXX
diff --git a/sw/source/core/unocore/unobkm.cxx b/sw/source/core/unocore/unobkm.cxx
index 233d14b23421..853418742a72 100644
--- a/sw/source/core/unocore/unobkm.cxx
+++ b/sw/source/core/unocore/unobkm.cxx
@@ -138,6 +138,11 @@ IDocumentMarkAccess* SwXBookmark::GetIDocumentMarkAccess()
     return m_pImpl->m_pDoc->getIDocumentMarkAccess();
 }
 
+SwDoc * SwXBookmark::GetDoc()
+{
+    return m_pImpl->m_pDoc;
+}
+
 SwXBookmark::SwXBookmark(SwDoc *const pDoc)
     : m_pImpl( new SwXBookmark::Impl(pDoc) )
 {
@@ -518,10 +523,6 @@ SwXBookmark::removeVetoableChangeListener(
     OSL_FAIL("SwXBookmark::removeVetoableChangeListener(): not implemented");
 }
 
-SwXFieldmark::SwXFieldmark(bool _isReplacementObject, SwDoc* pDc)
-    : SwXFieldmark_Base(pDc)
-    , m_bReplacementObject(_isReplacementObject)
-{ }
 
 void SwXFieldmarkParameters::insertByName(const OUString& aName, const uno::Any& aElement)
 {
@@ -597,6 +598,36 @@ IFieldmark::parameter_map_t* SwXFieldmarkParameters::getCoreParameters()
     return m_pFieldmark->GetParameters();
 }
 
+SwXFieldmark::SwXFieldmark(bool const isReplacementObject, SwDoc *const pDoc)
+    : SwXFieldmark_Base(pDoc)
+    , m_bReplacementObject(isReplacementObject)
+{
+}
+
+OUString SAL_CALL
+SwXFieldmark::getImplementationName()
+{
+    return "SwXFieldmark";
+}
+
+uno::Sequence<OUString> SAL_CALL
+SwXFieldmark::getSupportedServiceNames()
+{
+    // is const, no lock needed
+    if (m_bReplacementObject)
+    {
+        return {"com.sun.star.text.TextContent",
+                "com.sun.star.text.Bookmark",
+                "com.sun.star.text.FormFieldmark"};
+    }
+    else
+    {
+        return {"com.sun.star.text.TextContent",
+                "com.sun.star.text.Bookmark",
+                "com.sun.star.text.Fieldmark"};
+    }
+}
+
 void SwXFieldmark::attachToRange( const uno::Reference < text::XTextRange >& xTextRange )
 {
 
@@ -619,9 +650,12 @@ void SwXFieldmark::setFieldType(const OUString & fieldType)
     IFieldmark *pBkm = dynamic_cast<IFieldmark*>(GetBookmark());
     if(!pBkm)
         throw uno::RuntimeException();
-    if(fieldType == getFieldType())
+
+    OUString const oldFieldType(getFieldType());
+    if (fieldType == oldFieldType)
         return;
 
+    // note: this must not change between point-fieldmarks and range-fieldmarks
     if(fieldType == ODF_FORMDROPDOWN || fieldType == ODF_FORMCHECKBOX || fieldType == ODF_FORMDATE)
     {
         ::sw::mark::IFieldmark* pNewFieldmark = GetIDocumentMarkAccess()->changeFormFieldmarkType(pBkm, fieldType);
@@ -632,8 +666,17 @@ void SwXFieldmark::setFieldType(const OUString & fieldType)
         }
     }
 
-    // We did not generate a new fieldmark, so set the type ID
-    pBkm->SetFieldname(fieldType);
+    if ((!m_bReplacementObject && (fieldType == ODF_UNHANDLED
+                                    || fieldType == ODF_FORMDATE
+                                    || fieldType == ODF_FORMTEXT))
+        || (m_bReplacementObject && (fieldType == ODF_FORMCHECKBOX
+                                    || fieldType == ODF_FORMDROPDOWN)))
+    {
+         pBkm->SetFieldname(fieldType);
+         return;
+    }
+
+    throw uno::RuntimeException("changing to that type isn't implemented");
 }
 
 uno::Reference<container::XNameContainer> SwXFieldmark::getParameters()
@@ -673,7 +716,7 @@ SwXFieldmark::CreateXFieldmark(SwDoc & rDoc, ::sw::mark::IMark *const pMark,
         else
             pXBkmk = new SwXFieldmark(isReplacementObject, &rDoc);
 
-        xMark.set(pXBkmk);
+        xMark.set(static_cast<::cppu::OWeakObject*>(pXBkmk), uno::UNO_QUERY); // work around ambiguous base
         pXBkmk->registerInMark(*pXBkmk, pMarkBase);
     }
     return xMark;
@@ -710,8 +753,7 @@ SwXFieldmark::setPropertyValue(const OUString& PropertyName,
 
         pCheckboxFm->SetChecked( bChecked );
     }
-    else
-        SwXFieldmark_Base::setPropertyValue( PropertyName, rValue );
+    // this doesn't support any SwXBookmark property
 }
 
 // support 'hidden' "Checked" property ( note: this property is just for convenience to support
@@ -728,7 +770,113 @@ uno::Any SAL_CALL SwXFieldmark::getPropertyValue(const OUString& rPropertyName)
 
         return uno::makeAny( pCheckboxFm->IsChecked() );
     }
-    return SwXFieldmark_Base::getPropertyValue( rPropertyName );
+    return uno::Any(); // this doesn't support any SwXBookmark property
+}
+
+uno::Reference<beans::XPropertySetInfo> SAL_CALL
+SwXFieldmark::getPropertySetInfo()
+{
+    SolarMutexGuard g;
+
+    static uno::Reference<beans::XPropertySetInfo> const xRef(
+        aSwMapProvider.GetPropertySet(PROPERTY_MAP_FIELDMARK)
+            ->getPropertySetInfo() );
+    return xRef;
+}
+
+// XComponent
+void SAL_CALL SwXFieldmark::dispose()
+{
+    return SwXBookmark::dispose();
+}
+void SAL_CALL SwXFieldmark::addEventListener(
+        uno::Reference<lang::XEventListener> const& xListener)
+{
+    return SwXBookmark::addEventListener(xListener);
+}
+void SAL_CALL SwXFieldmark::removeEventListener(
+        uno::Reference<lang::XEventListener> const& xListener)
+{
+    return SwXBookmark::removeEventListener(xListener);
+}
+
+// XTextContent
+void SAL_CALL SwXFieldmark::attach(
+            uno::Reference<text::XTextRange> const& xTextRange)
+{
+    return SwXBookmark::attach(xTextRange);
+}
+
+uno::Reference<text::XTextRange> SAL_CALL SwXFieldmark::getAnchor()
+{
+    return SwXBookmark::getAnchor();
+}
+
+uno::Reference<text::XTextRange>
+SwXFieldmark::GetCommand(IFieldmark const& rMark)
+{
+    SwPosition const sepPos(sw::mark::FindFieldSep(rMark));
+    SwPosition start(rMark.GetMarkStart());
+    ++start.nContent;
+    return SwXTextRange::CreateXTextRange(*GetDoc(), start, &sepPos);
+}
+
+uno::Reference<text::XTextRange>
+SwXFieldmark::GetResult(IFieldmark const& rMark)
+{
+    SwPosition sepPos(sw::mark::FindFieldSep(rMark));
+    ++sepPos.nContent;
+    SwPosition const& rEnd(rMark.GetMarkEnd());
+    return SwXTextRange::CreateXTextRange(*GetDoc(), sepPos, &rEnd);
+}
+
+// XTextField
+OUString SAL_CALL
+SwXFieldmark::getPresentation(sal_Bool const bShowCommand)
+{
+    SolarMutexGuard g;
+
+    IFieldmark const*const pMark(dynamic_cast<IFieldmark*>(GetBookmark()));
+    if (!pMark)
+    {
+        throw lang::DisposedException();
+    }
+
+    if (bShowCommand)
+    {
+        if (m_bReplacementObject)
+        {
+            return OUString();
+        }
+        else
+        {   // also for ODF_FORMDATE, which shouldn't be a fieldmark...
+            uno::Reference<text::XTextRange> const xCommand(GetCommand(*pMark));
+            return xCommand->getString();
+        }
+    }
+    else
+    {
+        OUString const type(getFieldType());
+        if (type == ODF_FORMCHECKBOX)
+        {
+            ::sw::mark::ICheckboxFieldmark const*const pCheckboxFm(
+                    dynamic_cast<ICheckboxFieldmark const*>(pMark));
+            assert(pCheckboxFm);
+            return pCheckboxFm->IsChecked()
+                    ? OUString(u"\u2612")
+                    : OUString(u"\u2610");
+        }
+        else if (type == ODF_FORMDROPDOWN)
+        {
+            return sw::mark::ExpandFieldmark(const_cast<IFieldmark *>(pMark));
+        }
+        else
+        {
+            assert(!m_bReplacementObject);
+            uno::Reference<text::XTextRange> const xResult(GetResult(*pMark));
+            return xResult->getString();
+        }
+    }
 }
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/core/unocore/unofield.cxx b/sw/source/core/unocore/unofield.cxx
index 0fd3f9535bd4..f8785897a91a 100644
--- a/sw/source/core/unocore/unofield.cxx
+++ b/sw/source/core/unocore/unofield.cxx
@@ -23,6 +23,7 @@
 
 #include <unofield.hxx>
 #include <unofieldcoll.hxx>
+#include <unobookmark.hxx>
 #include <swtypes.hxx>
 #include <cmdid.h>
 #include <doc.hxx>
@@ -3001,6 +3002,12 @@ SwXFieldEnumeration::SwXFieldEnumeration(SwDoc & rDoc)
     {
         m_pImpl->m_Items.push_back( rMetaField );
     }
+    // also add fieldmarks
+    IDocumentMarkAccess& rMarksAccess(*rDoc.getIDocumentMarkAccess());
+    for (auto iter = rMarksAccess.getFieldmarksBegin(); iter != rMarksAccess.getFieldmarksEnd(); ++iter)
+    {
+        m_pImpl->m_Items.emplace_back(SwXFieldmark::CreateXFieldmark(rDoc, *iter), uno::UNO_QUERY);
+    }
 }
 
 SwXFieldEnumeration::~SwXFieldEnumeration()
diff --git a/sw/source/core/unocore/unomap.cxx b/sw/source/core/unocore/unomap.cxx
index a609da4d53d9..0ae02dedefed 100644
--- a/sw/source/core/unocore/unomap.cxx
+++ b/sw/source/core/unocore/unomap.cxx
@@ -560,6 +560,17 @@ const SfxItemPropertyMapEntry* SwUnoPropertyMapProvider::GetPropertyMapEntries(s
                 m_aMapEntriesArr[nPropertyId] = GetBookmarkPropertyMap();
             }
             break;
+            case PROPERTY_MAP_FIELDMARK:
+            {
+                static SfxItemPropertyMapEntry const aFieldmarkMap_Impl[] =
+                {
+                    // FIXME: is this supposed to actually exist as UNO property, or is it supposed to be in the "parameters" of the field?
+                    { u"Checked", 0, cppu::UnoType<bool>::get(), PROPERTY_NONE,     0},
+                    { u"", 0, css::uno::Type(), 0, 0 }
+                };
+                m_aMapEntriesArr[nPropertyId] = aFieldmarkMap_Impl;
+            }
+            break;
             case PROPERTY_MAP_PARAGRAPH_EXTENSIONS:
             {
                 m_aMapEntriesArr[nPropertyId] = GetParagraphExtensionsPropertyMap();
diff --git a/sw/source/core/unocore/unomap1.cxx b/sw/source/core/unocore/unomap1.cxx
index 762aa4208ac7..11508d462912 100644
--- a/sw/source/core/unocore/unomap1.cxx
+++ b/sw/source/core/unocore/unomap1.cxx
@@ -1208,6 +1208,12 @@ const SfxItemPropertySet*  SwUnoPropertyMapProvider::GetPropertySet( sal_uInt16
                 m_aPropertySetArr[nPropertyId] = &aPROPERTY_MAP_BOOKMARK;
             }
             break;
+            case PROPERTY_MAP_FIELDMARK:
+            {
+                static SfxItemPropertySet aPROPERTY_MAP_FIELDMARK(pEntries);
+                m_aPropertySetArr[nPropertyId] = &aPROPERTY_MAP_FIELDMARK;
+            }
+            break;
             case PROPERTY_MAP_PARAGRAPH_EXTENSIONS:
             {
                 static SfxItemPropertySet aPROPERTY_MAP_PARAGRAPH_EXTENSIONS(pEntries);
diff --git a/writerfilter/source/dmapper/DomainMapper_Impl.cxx b/writerfilter/source/dmapper/DomainMapper_Impl.cxx
index a43e396ba461..7eb07f3043ac 100644
--- a/writerfilter/source/dmapper/DomainMapper_Impl.cxx
+++ b/writerfilter/source/dmapper/DomainMapper_Impl.cxx
@@ -3963,6 +3963,20 @@ FieldContext::~FieldContext()
 {
 }
 
+void FieldContext::SetTextField(uno::Reference<text::XTextField> const& xTextField)
+{
+#ifndef NDEBUG
+    if (xTextField.is())
+    {
+        uno::Reference<lang::XServiceInfo> const xServiceInfo(xTextField, uno::UNO_QUERY);
+        assert(xServiceInfo.is());
+        // those must be set by SetFormField()
+        assert(!xServiceInfo->supportsService("com.sun.star.text.Fieldmark")
+            && !xServiceInfo->supportsService("com.sun.star.text.FormFieldmark"));
+    }
+#endif
+    m_xTextField = xTextField;
+}
 
 void FieldContext::AppendCommand(const OUString& rPart)
 {
@@ -5472,8 +5486,7 @@ void DomainMapper_Impl::CloseFieldCommand()
                 case FIELD_FORMDROPDOWN :
                 case FIELD_FORMTEXT :
                     {
-                        uno::Reference< text::XTextField > xTextField( xFieldInterface, uno::UNO_QUERY );
-                        if ( !xTextField.is() )
+                        if (bCreateEnhancedField)
                         {
                             FFDataHandler::Pointer_t
                             pFFDataHandler(pContext->getFFDataHandler());
@@ -5950,6 +5963,11 @@ void DomainMapper_Impl::CloseFieldCommand()
                         uno::makeAny( lcl_ParseNumberingType(pContext->GetCommand()) ));
                 break;
             }
+
+            if (!bCreateEnhancedField)
+            {
+                pContext->SetTextField( uno::Reference<text::XTextField>(xFieldInterface, uno::UNO_QUERY) );
+            }
         }
         else
         {
@@ -5984,7 +6002,6 @@ void DomainMapper_Impl::CloseFieldCommand()
                 m_bParaHadField = false;
         }
         //set the text field if there is any
-        pContext->SetTextField( uno::Reference< text::XTextField >( xFieldInterface, uno::UNO_QUERY ) );
     }
     catch( const uno::Exception& )
     {
diff --git a/writerfilter/source/dmapper/DomainMapper_Impl.hxx b/writerfilter/source/dmapper/DomainMapper_Impl.hxx
index f547360df842..575f6fd1876f 100644
--- a/writerfilter/source/dmapper/DomainMapper_Impl.hxx
+++ b/writerfilter/source/dmapper/DomainMapper_Impl.hxx
@@ -200,7 +200,7 @@ public:
     const css::uno::Reference<css::beans::XPropertySet>& GetCustomField() const { return m_xCustomField; }
     void SetCustomField(css::uno::Reference<css::beans::XPropertySet> const& xCustomField) { m_xCustomField = xCustomField; }
     const css::uno::Reference<css::text::XTextField>& GetTextField() const { return m_xTextField;}
-    void SetTextField(css::uno::Reference<css::text::XTextField> const& xTextField) { m_xTextField = xTextField;}

... etc. - the rest is truncated


More information about the Libreoffice-commits mailing list