[Libreoffice-commits] core.git: sw/source

Jim Raykowski (via logerrit) logerrit at kemper.freedesktop.org
Fri May 14 04:15:17 UTC 2021


 sw/source/core/crsr/crsrsh.cxx                         |   25 +
 sw/source/core/crsr/swcrsr.cxx                         |   14 
 sw/source/core/doc/docnum.cxx                          |    3 
 sw/source/core/edit/ednumber.cxx                       |   47 --
 sw/source/core/edit/edundo.cxx                         |    6 
 sw/source/core/inc/txtfrm.hxx                          |    4 
 sw/source/core/layout/frmtool.cxx                      |    4 
 sw/source/core/layout/paintfrm.cxx                     |    8 
 sw/source/core/text/frmpaint.cxx                       |    2 
 sw/source/core/text/txtfrm.cxx                         |   21 +
 sw/source/uibase/app/appopt.cxx                        |   59 ---
 sw/source/uibase/app/docst.cxx                         |    2 
 sw/source/uibase/docvw/FrameControlsManager.cxx        |   99 -----
 sw/source/uibase/docvw/OutlineContentVisibilityWin.cxx |   78 ----
 sw/source/uibase/docvw/edtwin.cxx                      |  143 +++-----
 sw/source/uibase/docvw/edtwin2.cxx                     |    3 
 sw/source/uibase/inc/FrameControlsManager.hxx          |    6 
 sw/source/uibase/inc/OutlineContentVisibilityWin.hxx   |    2 
 sw/source/uibase/inc/edtwin.hxx                        |    1 
 sw/source/uibase/inc/wrtsh.hxx                         |   47 ++
 sw/source/uibase/shells/basesh.cxx                     |   50 ++
 sw/source/uibase/uiview/view.cxx                       |    3 
 sw/source/uibase/uiview/view0.cxx                      |   37 --
 sw/source/uibase/uiview/view2.cxx                      |   12 
 sw/source/uibase/uiview/viewport.cxx                   |    5 
 sw/source/uibase/utlui/content.cxx                     |   77 ----
 sw/source/uibase/wrtsh/wrtsh1.cxx                      |  285 ++++++++++++-----
 27 files changed, 518 insertions(+), 525 deletions(-)

New commits:
commit 6b09276d157abada74e1a4989700139167207778
Author:     Jim Raykowski <raykowj at gmail.com>
AuthorDate: Sun Apr 18 23:00:38 2021 -0800
Commit:     Jim Raykowski <raykowj at gmail.com>
CommitDate: Fri May 14 06:14:35 2021 +0200

    Outline folding experimental feature rehack
    
    * Changes the way the outline content visibility button is shown to
    similiar how the table un-float button is shown.
    
    * Toggle function is replaced by an invalidate function that makes
    outline content visible or not visible only if needed.
    
    * Removes the left and right arrow keys restrictions of cursor movement
    in and out of an outline node paragraph having outline content
    visibility attribute set false (folded outline content). These were
    prevented due to causing an assert in txtfrm.cxx
    SwTextFrame::MapModelToView but seems to do no harm here if allowed.
    
    * Makes a selection read-only if it spans an outline node that has
    folded content and disallows actions that would cause loss of folded
    content.
    
    * Adds RestoreSavePos when Move fails in SwCursor::LeftRight to fix a
    bug that occurs in documents with outline content folded at the end of
    the document. When the cursor is at the end of the visible document and
    right arrow key is pressed Move fails after moving the cursor to the
    end of the document model, which doesn't have a node frame and causes
    wierd numbers to be displayed in the statusbar page number count. Left
    arrow, when in this state causes a crash without the added
    RestoreSavePos.
    
    * Addresses tdf#141390 concerning position of view when feature is
    turned off and on.
    
    Change-Id: I0430f73643201aa08ffc347c1597b44b1de290e8
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/114255
    Tested-by: Jenkins
    Reviewed-by: Jim Raykowski <raykowj at gmail.com>

diff --git a/sw/source/core/crsr/crsrsh.cxx b/sw/source/core/crsr/crsrsh.cxx
index 64a9d34906e2..a7d4d2474613 100644
--- a/sw/source/core/crsr/crsrsh.cxx
+++ b/sw/source/core/crsr/crsrsh.cxx
@@ -3344,6 +3344,31 @@ void SwCursorShell::SetReadOnlyAvailable( bool bFlag )
 
 bool SwCursorShell::HasReadonlySel() const
 {
+    if (GetViewOptions()->IsShowOutlineContentVisibilityButton())
+    {
+        // Treat selections that span over start or end of paragraph of an outline node
+        // with folded outline content as read-only.
+        SwWrtShell* pWrtSh = GetDoc()->GetDocShell()->GetWrtShell();
+        if (pWrtSh)
+        {
+            for(SwPaM& rPaM : GetCursor()->GetRingContainer())
+            {
+                rPaM.Normalize();
+                SwNodeIndex aPointIdx(rPaM.GetPoint()->nNode.GetNode());
+                SwNodeIndex aMarkIdx(rPaM.GetMark()->nNode.GetNode());
+                if (aPointIdx == aMarkIdx)
+                    continue;
+                // If any nodes in PaM are folded outline content nodes, then set read-only.
+                SwOutlineNodes::size_type nPos;
+                for (SwNodeIndex aIdx = aPointIdx; aIdx <= aMarkIdx; aIdx++)
+                {
+                    if (GetDoc()->GetNodes().GetOutLineNds().Seek_Entry(&(aIdx.GetNode()), &nPos) &&
+                            !pWrtSh->GetAttrOutlineContentVisible(nPos))
+                        return true;
+                }
+            }
+        }
+    }
     bool bRet = false;
     // If protected area is to be ignored, then selections are never read-only.
     if ((IsReadOnlyAvailable() || GetViewOptions()->IsFormView() ||
diff --git a/sw/source/core/crsr/swcrsr.cxx b/sw/source/core/crsr/swcrsr.cxx
index a2c4264f6301..69388177ab28 100644
--- a/sw/source/core/crsr/swcrsr.cxx
+++ b/sw/source/core/crsr/swcrsr.cxx
@@ -57,6 +57,8 @@
 #include <comphelper/lok.hxx>
 #include <editsh.hxx>
 
+#include <viewopt.hxx>
+
 using namespace ::com::sun::star::i18n;
 
 const sal_uInt16 coSrchRplcThreshold = 60000;
@@ -1798,7 +1800,19 @@ bool SwCursor::LeftRight( bool bLeft, sal_uInt16 nCnt, sal_uInt16 nMode,
         }
 
         if ( !Move( fnMove, fnGo ) )
+        {
+            SwEditShell* rSh = GetDoc().GetEditShell();
+            if (rSh && rSh->GetViewOptions() &&
+                    rSh->GetViewOptions()->IsShowOutlineContentVisibilityButton())
+                // Fixes crash that occurs in documents with outline content folded at the end of
+                // the document. When the cursor is at the end of the visible document and
+                // right arrow key is pressed Move fails after moving the cursor to the
+                // end of the document model, which doesn't have a node frame and causes
+                // wierd numbers to be displayed in the statusbar page number count. Left
+                // arrow, when in this state, causes a crash without RestoredSavePos() added here.
+                RestoreSavePos();
             break;
+        }
 
         if (pFrame)
         {
diff --git a/sw/source/core/doc/docnum.cxx b/sw/source/core/doc/docnum.cxx
index b0bffd31c205..5e287e84f19d 100644
--- a/sw/source/core/doc/docnum.cxx
+++ b/sw/source/core/doc/docnum.cxx
@@ -55,6 +55,7 @@
 #include <map>
 #include <stdlib.h>
 
+#include <wrtsh.hxx>
 
 namespace {
     void lcl_ResetIndentAttrs(SwDoc *pDoc, const SwPaM &rPam, sal_uInt16 marker,
@@ -1825,6 +1826,8 @@ bool SwDoc::NumUpDown(const SwPaM& rPam, bool bDown, SwRootFrame const*const pLa
 // it will expand its selection to include full SwTextFrames.
 bool SwDoc::MoveParagraph(SwPaM& rPam, tools::Long nOffset, bool const bIsOutlMv)
 {
+    MakeAllOutlineContentTemporarilyVisible a(this);
+
     // sw_redlinehide: as long as a layout with Hide mode exists, only
     // move nodes that have merged frames *completely*
     SwRootFrame const* pLayout(nullptr);
diff --git a/sw/source/core/edit/ednumber.cxx b/sw/source/core/edit/ednumber.cxx
index 38582a4143e3..af7ec8178e41 100644
--- a/sw/source/core/edit/ednumber.cxx
+++ b/sw/source/core/edit/ednumber.cxx
@@ -394,55 +394,8 @@ void SwEditShell::SetIndent(short nIndent, const SwPosition & rPos)
     EndAllAction();
 }
 
-namespace
-{
-class MakeAllOutlineContentTemporarilyVisibile
-{
-private:
-    SwWrtShell* pWrtShell;
-    std::vector<SwNode*> aOutlineNdsArray;
-public:
-    MakeAllOutlineContentTemporarilyVisibile(SwWrtShell* pShell)
-        : pWrtShell(pShell)
-    {
-        if (!(pWrtShell && pWrtShell->GetViewOptions() && pWrtShell->GetViewOptions()->IsShowOutlineContentVisibilityButton()))
-            return;
-
-        // make all outlines content visible and store outline nodes having
-        // content visible attribute value false
-        SwOutlineNodes rOutlineNds = pWrtShell->GetNodes().GetOutLineNds();
-        for (SwOutlineNodes::size_type nPos = 0; nPos < rOutlineNds.size(); ++nPos)
-        {
-            SwNode* pNd = rOutlineNds[nPos];
-            if (pNd->IsTextNode()) // should always be true
-            {
-                bool bOutlineContentVisibleAttr = true;
-                pNd->GetTextNode()->GetAttrOutlineContentVisible(bOutlineContentVisibleAttr);
-                if (!bOutlineContentVisibleAttr)
-                {
-                    aOutlineNdsArray.push_back(pNd);
-                    pWrtShell->ToggleOutlineContentVisibility(nPos);
-                }
-            }
-        }
-    }
-
-    ~MakeAllOutlineContentTemporarilyVisibile() COVERITY_NOEXCEPT_FALSE
-    {
-        if (!pWrtShell)
-            return;
-        // restore outlines content visibility
-        for (SwNode* pNd : aOutlineNdsArray)
-            pWrtShell->ToggleOutlineContentVisibility(pNd, true);
-    }
-};
-}
-
 bool SwEditShell::MoveParagraph( tools::Long nOffset )
 {
-    // make all outline nodes content temporarily visible for paragraph move
-    MakeAllOutlineContentTemporarilyVisibile a(dynamic_cast<SwWrtShell*>(this));
-
     StartAllAction();
 
     SwPaM *pCursor = GetCursor();
diff --git a/sw/source/core/edit/edundo.cxx b/sw/source/core/edit/edundo.cxx
index a55f45651fba..bfadd01aaffd 100644
--- a/sw/source/core/edit/edundo.cxx
+++ b/sw/source/core/edit/edundo.cxx
@@ -35,6 +35,8 @@
 #include <docsh.hxx>
 #include <pagefrm.hxx>
 
+#include <wrtsh.hxx>
+
 /** helper function to select all objects in an SdrMarkList;
  * implementation: see below */
 static void lcl_SelectSdrMarkList( SwEditShell* pShell,
@@ -96,6 +98,8 @@ void SwEditShell::HandleUndoRedoContext(::sw::UndoRedoContext & rContext)
 
 void SwEditShell::Undo(sal_uInt16 const nCount)
 {
+    MakeAllOutlineContentTemporarilyVisible a(GetDoc());
+
     CurrShell aCurr( this );
 
     // current undo state was not saved
@@ -152,6 +156,8 @@ void SwEditShell::Undo(sal_uInt16 const nCount)
 
 void SwEditShell::Redo(sal_uInt16 const nCount)
 {
+    MakeAllOutlineContentTemporarilyVisible a(GetDoc());
+
     CurrShell aCurr( this );
 
     bool bRet = false;
diff --git a/sw/source/core/inc/txtfrm.hxx b/sw/source/core/inc/txtfrm.hxx
index 1473697a07ad..abef52f448aa 100644
--- a/sw/source/core/inc/txtfrm.hxx
+++ b/sw/source/core/inc/txtfrm.hxx
@@ -46,6 +46,7 @@ class SwPortionHandler;
 class SwScriptInfo;
 enum class ExpandMode;
 class SwTextAttr;
+class SwWrtShell;
 
 #define NON_PRINTING_CHARACTER_COLOR Color(0x26, 0x8b, 0xd2)
 
@@ -319,6 +320,9 @@ class SW_DLLPUBLIC SwTextFrame: public SwContentFrame
     virtual void DestroyImpl() override;
     virtual ~SwTextFrame() override;
 
+    void UpdateOutlineContentVisibilityButton(SwWrtShell* pWrtSh) const;
+    void PaintOutlineContentVisibilityButton() const;
+
 protected:
     virtual void SwClientNotify(SwModify const& rModify, SfxHint const& rHint) override;
 
diff --git a/sw/source/core/layout/frmtool.cxx b/sw/source/core/layout/frmtool.cxx
index 557bc2414e63..14a73d4d5869 100644
--- a/sw/source/core/layout/frmtool.cxx
+++ b/sw/source/core/layout/frmtool.cxx
@@ -3827,7 +3827,9 @@ bool IsExtraData( const SwDoc *pDoc )
     return rInf.IsPaintLineNumbers() ||
            rInf.IsCountInFlys() ||
            (static_cast<sal_Int16>(SW_MOD()->GetRedlineMarkPos()) != text::HoriOrientation::NONE &&
-            !pDoc->getIDocumentRedlineAccess().GetRedlineTable().empty());
+            !pDoc->getIDocumentRedlineAccess().GetRedlineTable().empty()) ||
+            (pDoc->GetEditShell() && pDoc->GetEditShell()->GetViewOptions() &&
+             pDoc->GetEditShell()->GetViewOptions()->IsShowOutlineContentVisibilityButton());
 }
 
 // OD 22.09.2003 #110978#
diff --git a/sw/source/core/layout/paintfrm.cxx b/sw/source/core/layout/paintfrm.cxx
index 9e5cd3a16c05..27cbf1b4a997 100644
--- a/sw/source/core/layout/paintfrm.cxx
+++ b/sw/source/core/layout/paintfrm.cxx
@@ -4247,6 +4247,14 @@ void SwFlyFrame::PaintDecorators() const
     }
 }
 
+void SwTextFrame::PaintOutlineContentVisibilityButton() const
+{
+    SwWrtShell* pWrtSh = dynamic_cast<SwWrtShell*>(gProp.pSGlobalShell);
+    if (pWrtSh && pWrtSh->GetViewOptions()->IsShowOutlineContentVisibilityButton())
+        UpdateOutlineContentVisibilityButton(pWrtSh);
+}
+
+
 void SwTabFrame::PaintSwFrame(vcl::RenderContext& rRenderContext, SwRect const& rRect, SwPrintData const*const) const
 {
     const SwViewOption* pViewOption = gProp.pSGlobalShell->GetViewOptions();
diff --git a/sw/source/core/text/frmpaint.cxx b/sw/source/core/text/frmpaint.cxx
index 6f1d1fc12ad1..7f35ea7633b6 100644
--- a/sw/source/core/text/frmpaint.cxx
+++ b/sw/source/core/text/frmpaint.cxx
@@ -305,6 +305,8 @@ void SwTextFrame::PaintExtraData( const SwRect &rRect ) const
     if( getFrameArea().Top() > rRect.Bottom() || getFrameArea().Bottom() < rRect.Top() )
         return;
 
+    PaintOutlineContentVisibilityButton();
+
     SwDoc const& rDoc(GetDoc());
     const IDocumentRedlineAccess& rIDRA = rDoc.getIDocumentRedlineAccess();
     const SwLineNumberInfo &rLineInf = rDoc.GetLineNumberInfo();
diff --git a/sw/source/core/text/txtfrm.cxx b/sw/source/core/text/txtfrm.cxx
index acd1b1b4f5be..6a91cfd36a3d 100644
--- a/sw/source/core/text/txtfrm.cxx
+++ b/sw/source/core/text/txtfrm.cxx
@@ -71,6 +71,10 @@
 #include <ftnidx.hxx>
 #include <ftnfrm.hxx>
 
+#include <wrtsh.hxx>
+#include <view.hxx>
+#include <edtwin.hxx>
+#include <FrameControlsManager.hxx>
 
 namespace sw {
 
@@ -878,6 +882,12 @@ void SwTextFrame::DestroyImpl()
         }
     }
 
+    if (!GetDoc().IsInDtor())
+    {
+        if (SwView* pView = GetActiveView())
+            pView->GetEditWin().GetFrameControlsManager().RemoveControls(this);
+    }
+
     SwContentFrame::DestroyImpl();
 }
 
@@ -4024,4 +4034,15 @@ void SwTextFrame::repaintTextFrames( const SwTextNode& rNode )
     }
 }
 
+void SwTextFrame::UpdateOutlineContentVisibilityButton(SwWrtShell* pWrtSh) const
+{
+    if (pWrtSh && pWrtSh->GetViewOptions()->IsShowOutlineContentVisibilityButton() &&
+            GetTextNodeFirst()->IsOutline())
+    {
+        SwEditWin& rEditWin = pWrtSh->GetView().GetEditWin();
+        SwFrameControlsManager& rMngr = rEditWin.GetFrameControlsManager();
+        rMngr.SetOutlineContentVisibilityButton(this);
+    }
+}
+
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/uibase/app/appopt.cxx b/sw/source/uibase/app/appopt.cxx
index 9862da388021..1b22068ebe7f 100644
--- a/sw/source/uibase/app/appopt.cxx
+++ b/sw/source/uibase/app/appopt.cxx
@@ -261,51 +261,23 @@ void SwModule::ApplyItemSet( sal_uInt16 nId, const SfxItemSet& rSet )
     }
 
     // Elements - interpret Item
-    std::vector<SwNode*> aFoldedOutlineNdsArray;
-    bool bShow = false;
+    bool bFlag = true;
     if( SfxItemState::SET == rSet.GetItemState( FN_PARAM_ELEM, false, &pItem ) )
     {
         const SwElemItem* pElemItem = static_cast<const SwElemItem*>(pItem);
         pElemItem->FillViewOptions( aViewOpt );
 
         SwWrtShell* pWrtShell = GetActiveWrtShell();
-        bShow = pWrtShell->GetViewOptions()->IsShowOutlineContentVisibilityButton();
+        bFlag = pWrtShell->GetViewOptions()->IsShowOutlineContentVisibilityButton();
         bool bTreatSubsChanged = aViewOpt.IsTreatSubOutlineLevelsAsContent()
                 != pWrtShell->GetViewOptions()->IsTreatSubOutlineLevelsAsContent();
-
-        // move cursor to top if something with the outline mode changed
-        if ((bShow != aViewOpt.IsShowOutlineContentVisibilityButton()) ||
-                (pWrtShell->GetViewOptions()->IsTreatSubOutlineLevelsAsContent() !=
-                 aViewOpt.IsTreatSubOutlineLevelsAsContent()))
-        {
-            // move cursor to top of document
-            if (pWrtShell->IsSelFrameMode())
-            {
-                pWrtShell->UnSelectFrame();
-                pWrtShell->LeaveSelFrameMode();
-            }
-            pWrtShell->EnterStdMode();
-            pWrtShell->SttEndDoc(true);
-        }
-
-        if (bShow && (!aViewOpt.IsShowOutlineContentVisibilityButton() || bTreatSubsChanged))
+        if (bFlag && (!aViewOpt.IsShowOutlineContentVisibilityButton() || bTreatSubsChanged))
         {
             // outline mode options have change which require to show all content
-            const SwOutlineNodes& rOutlineNds = pWrtShell->GetNodes().GetOutLineNds();
-            for (SwOutlineNodes::size_type nPos = 0; nPos < rOutlineNds.size(); ++nPos)
-            {
-                SwNode* pNd = rOutlineNds[nPos];
-                if (pNd->IsTextNode()) // should always be true
-                {
-                    bool bOutlineContentVisibleAttr = true;
-                    pNd->GetTextNode()->GetAttrOutlineContentVisible(bOutlineContentVisibleAttr);
-                    if (!bOutlineContentVisibleAttr)
-                    {
-                        aFoldedOutlineNdsArray.push_back(pNd);
-                        pWrtShell->ToggleOutlineContentVisibility(nPos);
-                    }
-                }
-            }
+            pWrtShell->MakeAllFoldedOutlineContentVisible();
+
+            if (bTreatSubsChanged)
+                bFlag = false; // folding method changed, set bFlag false to refold below
         }
     }
 
@@ -429,21 +401,8 @@ void SwModule::ApplyItemSet( sal_uInt16 nId, const SfxItemSet& rSet )
     if (SfxItemState::SET != rSet.GetItemState(FN_PARAM_ELEM, false))
         return;
 
-    if (!GetActiveWrtShell()->GetViewOptions()->IsShowOutlineContentVisibilityButton())
-    {
-        // outline mode is no longer active
-        // set outline content visible attribute to false for nodes in the array
-        for (SwNode* pNd : aFoldedOutlineNdsArray)
-            pNd->GetTextNode()->SetAttrOutlineContentVisible(false);
-    }
-    else if (bShow)
-    {
-        // outline mode remained active
-        // sub level treatment might have changed
-        // ToggleOutlineContentVisibility only knows sub level treatment after ApplyUserPref
-        for (SwNode* pNd : aFoldedOutlineNdsArray)
-            GetActiveWrtShell()->ToggleOutlineContentVisibility(pNd, true);
-    }
+    if (!bFlag)
+        GetActiveWrtShell()->MakeAllFoldedOutlineContentVisible(false);
 }
 
 std::unique_ptr<SfxTabPage> SwModule::CreateTabPage( sal_uInt16 nId, weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rSet )
diff --git a/sw/source/uibase/app/docst.cxx b/sw/source/uibase/app/docst.cxx
index aceb1c548ded..654ff05a0650 100644
--- a/sw/source/uibase/app/docst.cxx
+++ b/sw/source/uibase/app/docst.cxx
@@ -1108,6 +1108,8 @@ void SwDocShell::Hide(const OUString &rName, SfxStyleFamily nFamily, bool bHidde
 SfxStyleFamily SwDocShell::ApplyStyles(const OUString &rName, SfxStyleFamily nFamily,
                                SwWrtShell* pShell, const sal_uInt16 nMode )
 {
+    MakeAllOutlineContentTemporarilyVisible a(GetDoc());
+
     SwDocStyleSheet* pStyle = static_cast<SwDocStyleSheet*>( m_xBasePool->Find( rName, nFamily ) );
 
     SAL_WARN_IF( !pStyle, "sw.ui", "Style not found" );
diff --git a/sw/source/uibase/docvw/FrameControlsManager.cxx b/sw/source/uibase/docvw/FrameControlsManager.cxx
index 622d5fced30b..9b6cbdf2a8db 100644
--- a/sw/source/uibase/docvw/FrameControlsManager.cxx
+++ b/sw/source/uibase/docvw/FrameControlsManager.cxx
@@ -40,7 +40,6 @@ SwFrameControlsManager::~SwFrameControlsManager()
 void SwFrameControlsManager::dispose()
 {
     m_aControls.clear();
-    m_aTextNodeContentFrameMap.clear();
 }
 
 SwFrameControlPtr SwFrameControlsManager::GetControl( FrameControlType eType, const SwFrame* pFrame )
@@ -188,64 +187,8 @@ SwFrameMenuButtonBase::SwFrameMenuButtonBase(SwEditWin* pEditWin, const SwFrame*
 {
 }
 
-void SwFrameControlsManager::SetOutlineContentVisibilityButtons()
+void SwFrameControlsManager::SetOutlineContentVisibilityButton(const SwContentFrame* pContentFrame)
 {
-    // remove entries with outline node keys that are not in the outline nodes list
-    IDocumentOutlineNodes::tSortedOutlineNodeList aOutlineNodes;
-    m_pEditWin->GetView().GetWrtShell().getIDocumentOutlineNodesAccess()->getOutlineNodes(aOutlineNodes);
-    std::map<const SwTextNode*, const SwContentFrame*>::iterator it = m_aTextNodeContentFrameMap.begin();
-    while(it != m_aTextNodeContentFrameMap.end())
-    {
-        const SwNode* pNd = it->first;
-        IDocumentOutlineNodes::tSortedOutlineNodeList::iterator i = std::find(aOutlineNodes.begin(), aOutlineNodes.end(), pNd);
-        if (i == aOutlineNodes.end())
-        {
-            RemoveControlsByType(FrameControlType::Outline, it->second);
-            it = m_aTextNodeContentFrameMap.erase(it);
-        }
-        else
-            ++it;
-    }
-    for (SwNode* pNd : m_pEditWin->GetView().GetWrtShell().GetNodes().GetOutLineNds())
-    {
-        bool bOutlineContentVisibleAttr = true;
-        pNd->GetTextNode()->GetAttrOutlineContentVisible(bOutlineContentVisibleAttr);
-        if (!bOutlineContentVisibleAttr)
-            SetOutlineContentVisibilityButton(pNd->GetTextNode());
-    }
-}
-
-void SwFrameControlsManager::SetOutlineContentVisibilityButton(const SwTextNode* pTextNd)
-{
-    const SwContentFrame* pContentFrame = pTextNd->getLayoutFrame(nullptr);
-
-    // has node frame changed or been deleted?
-    std::map<const SwTextNode*, const SwContentFrame*>::iterator iter = m_aTextNodeContentFrameMap.find(pTextNd);
-    if (iter != m_aTextNodeContentFrameMap.end())
-    {
-        const SwContentFrame* pFrameWas = iter->second;
-        if (pContentFrame != pFrameWas)
-        {
-            // frame does not match frame in map for node
-            RemoveControlsByType(FrameControlType::Outline, pFrameWas);
-            m_aTextNodeContentFrameMap.erase(iter);
-        }
-    }
-    if (pContentFrame && !pContentFrame->IsInDtor())
-    {
-        // frame is not being destroyed and isn't in map
-        m_aTextNodeContentFrameMap.insert(make_pair(pTextNd, pContentFrame));
-    }
-    else
-    {
-        if (pContentFrame)
-        {
-            // frame is being destroyed
-            RemoveControlsByType(FrameControlType::Outline, pContentFrame);
-        }
-        return;
-    }
-
     // Check if we already have the control
     SwFrameControlPtr pControl;
 
@@ -266,48 +209,10 @@ void SwFrameControlsManager::SetOutlineContentVisibilityButton(const SwTextNode*
     }
 
     SwOutlineContentVisibilityWin* pWin = dynamic_cast<SwOutlineContentVisibilityWin *>(pControl->GetWindow());
-    assert(pWin != nullptr) ;
     pWin->Set();
 
     if (pWin->GetSymbol() == ButtonSymbol::SHOW)
-    {
-        // show expand button immediately
-        pWin->Show();
-        /*
-           The outline content might be visible here. This happens on document load,
-           undo outline moves, and show of outline content that itself has outline nodes
-           having outline content visibility attribute false, for example tables and text
-           frames containing outline nodes.
-        */
-        SwOutlineNodes::size_type nPos;
-        SwOutlineNodes rOutlineNds = m_pEditWin->GetView().GetWrtShell().GetNodes().GetOutLineNds();
-        if (rOutlineNds.Seek_Entry(const_cast<SwTextNode*>(pTextNd), &nPos))
-        {
-            SwNodeIndex aIdx(*pTextNd, +1);
-            // there shouldn't be a layout frame
-            // if there is then force visibility false
-            if (!m_pEditWin->GetView().GetWrtShell().GetViewOptions()->IsTreatSubOutlineLevelsAsContent())
-            {
-                if (!(aIdx.GetNode().IsEndNode() ||
-                      (nPos + 1 < rOutlineNds.size() && &aIdx.GetNode() == rOutlineNds[nPos +1]))
-                        && aIdx.GetNode().IsContentNode()
-                        // this determines if the content is really visible
-                        && aIdx.GetNode().GetContentNode()->getLayoutFrame(nullptr))
-                {
-                    // force outline content visibility false
-                    m_pEditWin->GetView().GetWrtShell().ToggleOutlineContentVisibility(nPos, true);
-                }
-            }
-            else if (!aIdx.GetNode().IsEndNode()
-                     && aIdx.GetNode().IsContentNode()
-                     // this determines if the content is really visible
-                     && aIdx.GetNode().GetContentNode()->getLayoutFrame(nullptr))
-            {
-                // force outline content visibility false
-                m_pEditWin->GetView().GetWrtShell().ToggleOutlineContentVisibility(nPos, true);
-            }
-        }
-    }
+        pWin->Show(); // show the SHOW button immediately
     else if (!pWin->IsVisible() && pWin->GetSymbol() == ButtonSymbol::HIDE)
         pWin->ShowAll(true);
 }
diff --git a/sw/source/uibase/docvw/OutlineContentVisibilityWin.cxx b/sw/source/uibase/docvw/OutlineContentVisibilityWin.cxx
index a50832c3385f..d511812f4278 100644
--- a/sw/source/uibase/docvw/OutlineContentVisibilityWin.cxx
+++ b/sw/source/uibase/docvw/OutlineContentVisibilityWin.cxx
@@ -107,28 +107,17 @@ void SwOutlineContentVisibilityWin::SetSymbol(ButtonSymbol eStyle)
 void SwOutlineContentVisibilityWin::Set()
 {
     const SwTextFrame* pTextFrame = static_cast<const SwTextFrame*>(GetFrame());
-
-    // outline node frame containing folded outline node content might be folded so need to hide it
-    if (!pTextFrame || pTextFrame->IsInDtor())
-    {
-        SetSymbol(ButtonSymbol::NONE);
-        Hide();
-        return;
-    }
     const SwTextNode* pTextNode = pTextFrame->GetTextNodeFirst();
     SwWrtShell& rSh = GetEditWin()->GetView().GetWrtShell();
     const SwOutlineNodes& rOutlineNodes = rSh.GetNodes().GetOutLineNds();
-    if (!pTextNode
-        || !rOutlineNodes.Seek_Entry(static_cast<SwNode*>(const_cast<SwTextNode*>(pTextNode)),
-                                     &m_nOutlinePos)
-        || m_nOutlinePos == SwOutlineNodes::npos)
-    {
-        assert(false); // should never get here
-        return;
-    }
+
+    rOutlineNodes.Seek_Entry(static_cast<SwNode*>(const_cast<SwTextNode*>(pTextNode)),
+                             &m_nOutlinePos);
 
     // set symbol displayed on button
-    SetSymbol(rSh.IsOutlineContentVisible(m_nOutlinePos) ? ButtonSymbol::HIDE : ButtonSymbol::SHOW);
+    bool bVisible = true;
+    const_cast<SwTextNode*>(pTextNode)->GetAttrOutlineContentVisible(bVisible);
+    SetSymbol(bVisible ? ButtonSymbol::HIDE : ButtonSymbol::SHOW);
 
     // set quick help
     SwOutlineNodes::size_type nOutlineNodesCount
@@ -147,11 +136,11 @@ void SwOutlineContentVisibilityWin::Set()
     SwRect aCharRect;
     GetFrame()->GetCharRect(aCharRect, SwPosition(*pTextNode));
     Point aPxPt(GetEditWin()->GetOutDev()->LogicToPixel(
-        Point(aCharRect.Right(), aFrameAreaRect.Center().getY())));
+        Point(aCharRect.Left(), aFrameAreaRect.Center().getY())));
     if (GetFrame()->IsRightToLeft())
-        aPxPt.AdjustX(5);
+        aPxPt.AdjustX(2);
     else
-        aPxPt.AdjustX(-(GetSizePixel().getWidth() + 5));
+        aPxPt.AdjustX(-(GetSizePixel().getWidth() + 2));
     aPxPt.AdjustY(-GetSizePixel().getHeight() / 2);
     SetPosPixel(aPxPt);
 }
@@ -178,39 +167,6 @@ bool SwOutlineContentVisibilityWin::Contains(const Point& rDocPt) const
     return false;
 }
 
-void SwOutlineContentVisibilityWin::ToggleOutlineContentVisibility(const bool bSubs)
-{
-    SwWrtShell& rSh = GetEditWin()->GetView().GetWrtShell();
-    rSh.LockView(true);
-    if (GetEditWin()->GetView().GetDrawView()->IsTextEdit())
-        rSh.EndTextEdit();
-    if (GetEditWin()->GetView().IsDrawMode())
-        GetEditWin()->GetView().LeaveDrawCreate();
-    rSh.EnterStdMode();
-    if (rSh.GetViewOptions()->IsTreatSubOutlineLevelsAsContent())
-        rSh.ToggleOutlineContentVisibility(m_nOutlinePos);
-    else if (bSubs)
-    {
-        // toggle including sub levels
-        SwOutlineNodes::size_type nPos = m_nOutlinePos;
-        SwOutlineNodes::size_type nOutlineNodesCount
-            = rSh.getIDocumentOutlineNodesAccess()->getOutlineNodesCount();
-        int nLevel = rSh.getIDocumentOutlineNodesAccess()->getOutlineLevel(m_nOutlinePos);
-        bool bVisible = rSh.IsOutlineContentVisible(m_nOutlinePos);
-        do
-        {
-            if (rSh.IsOutlineContentVisible(nPos) == bVisible)
-                rSh.ToggleOutlineContentVisibility(nPos);
-        } while (++nPos < nOutlineNodesCount
-                 && rSh.getIDocumentOutlineNodesAccess()->getOutlineLevel(nPos) > nLevel);
-    }
-    else
-        rSh.ToggleOutlineContentVisibility(m_nOutlinePos);
-    // set cursor position to the toggled outline node
-    rSh.GotoOutline(m_nOutlinePos);
-    rSh.LockView(false);
-}
-
 IMPL_LINK(SwOutlineContentVisibilityWin, MouseMoveHdl, const MouseEvent&, rMEvt, bool)
 {
     if (rMEvt.IsLeaveWindow())
@@ -264,27 +220,17 @@ IMPL_LINK(SwOutlineContentVisibilityWin, MouseMoveHdl, const MouseEvent&, rMEvt,
     return false;
 }
 
+// Toggle the outline content visibility on mouse press
 IMPL_LINK(SwOutlineContentVisibilityWin, MousePressHdl, const MouseEvent&, rMEvt, bool)
 {
     Hide();
-    // Crash occurs if control does not have focus when toggling from hidden to shown.
-    // Seems to happen due to the control being disposed in the toggle process.
-    // Does NOT crash in debugger with GrabFocus and GrabFocusToDocument commented out.
-    // DOES crash in debugger on GrabFocusToDocument when GrabFocus is commented out.
-    // Until light is shed on why this happens, prevent crash by doing the following:
-    //  1) grab focus to the control
-    //  2) toggle content visibility
-    //  3) grab focus to the document
-    if (!ControlHasFocus())
-        GrabFocus();
-    ToggleOutlineContentVisibility(rMEvt.IsRight());
-    GrabFocusToDocument();
+    GetEditWin()->ToggleOutlineContentVisibility(m_nOutlinePos, rMEvt.IsRight());
     return false;
 }
 
 IMPL_LINK_NOARG(SwOutlineContentVisibilityWin, DelayAppearHandler, Timer*, void)
 {
-    const int TICKS_BEFORE_WE_APPEAR = 5;
+    const int TICKS_BEFORE_WE_APPEAR = 3;
     if (m_nDelayAppearing < TICKS_BEFORE_WE_APPEAR)
     {
         ++m_nDelayAppearing;
diff --git a/sw/source/uibase/docvw/edtwin.cxx b/sw/source/uibase/docvw/edtwin.cxx
index ea0cf5c23e0f..752de942539b 100644
--- a/sw/source/uibase/docvw/edtwin.cxx
+++ b/sw/source/uibase/docvw/edtwin.cxx
@@ -1366,32 +1366,6 @@ void SwEditWin::KeyInput(const KeyEvent &rKEvt)
         }
     }
 
-    if (rSh.GetViewOptions()->IsShowOutlineContentVisibilityButton())
-    {
-        // not allowed if outline content visibility is false
-        sal_uInt16 nKey = rKEvt.GetKeyCode().GetCode();
-        if ((rSh.IsSttPara() && (nKey == KEY_BACKSPACE || nKey == KEY_LEFT))
-                || (rSh.IsEndOfPara() && (nKey == KEY_DELETE || nKey == KEY_RETURN || nKey == KEY_RIGHT)))
-        {
-            SwContentNode* pContentNode = rSh.GetCurrentShellCursor().GetContentNode();
-            SwOutlineNodes::size_type nPos;
-            if (rSh.GetDoc()->GetNodes().GetOutLineNds().Seek_Entry(pContentNode, &nPos))
-            {
-                bool bOutlineContentVisibleAttr = true;
-                pContentNode->GetTextNode()->GetAttrOutlineContentVisible(bOutlineContentVisibleAttr);
-                if (!bOutlineContentVisibleAttr)
-                    return; // outline content visibility is false
-                if (rSh.IsSttPara() && (nKey == KEY_BACKSPACE || nKey == KEY_LEFT) && (nPos-1 != SwOutlineNodes::npos))
-                {
-                    bOutlineContentVisibleAttr = true;
-                    rSh.GetDoc()->GetNodes().GetOutLineNds()[nPos-1]->GetTextNode()->GetAttrOutlineContentVisible(bOutlineContentVisibleAttr);
-                    if (!bOutlineContentVisibleAttr)
-                        return; // previous outline node has content visibility false
-                }
-            }
-        }
-    }
-
     if( rKEvt.GetKeyCode().GetCode() == KEY_ESCAPE &&
         m_pApplyTempl && m_pApplyTempl->m_pFormatClipboard )
     {
@@ -2704,10 +2678,6 @@ KEYINPUT_CHECKTABLE_INSDEL:
         }
     }
 
-    // x11 backend doesn't like not having this
-    if (rSh.GetViewOptions()->IsShowOutlineContentVisibilityButton())
-        GetFrameControlsManager().SetOutlineContentVisibilityButtons();
-
     // update the page number in the statusbar
     sal_uInt16 nKey = rKEvt.GetKeyCode().GetCode();
     if( KEY_UP == nKey || KEY_DOWN == nKey || KEY_PAGEUP == nKey || KEY_PAGEDOWN == nKey )
@@ -3536,16 +3506,16 @@ void SwEditWin::MouseButtonDown(const MouseEvent& _rMEvt)
                     {
                         if (rSh.GetViewOptions()->IsShowOutlineContentVisibilityButton())
                         {
+                            // ctrl+left-click on outline node frame
                             SwContentAtPos aContentAtPos(IsAttrAtPos::Outline);
                             if(rSh.GetContentAtPos(aDocPos, aContentAtPos))
                             {
-                                // move cursor to outline para start and toggle outline content visibility
-                                MoveCursor(rSh, aDocPos, bOnlyText, bLockView);
-                                SwPaM aPam(*rSh.GetCurrentShellCursor().GetPoint());
                                 SwOutlineNodes::size_type nPos;
-                                if (rSh.GetNodes().GetOutLineNds().Seek_Entry(&aPam.GetPoint()->nNode.GetNode(), &nPos))
-                                    rSh.ToggleOutlineContentVisibility(nPos);
-                                return;
+                                if (rSh.GetNodes().GetOutLineNds().Seek_Entry(aContentAtPos.aFnd.pNode, &nPos))
+                                {
+                                    ToggleOutlineContentVisibility(nPos, false);
+                                    return;
+                                }
                             }
                         }
                         if ( !m_bInsDraw && IsDrawObjSelectable( rSh, aDocPos ) && !lcl_urlOverBackground( rSh, aDocPos ) )
@@ -3784,29 +3754,14 @@ void SwEditWin::MouseButtonDown(const MouseEvent& _rMEvt)
         if (rSh.GetViewOptions()->IsShowOutlineContentVisibilityButton()
             && aMEvt.GetModifier() == KEY_MOD1)
         {
+            // ctrl+right-click on outline node frame
             SwContentAtPos aContentAtPos(IsAttrAtPos::Outline);
             if(rSh.GetContentAtPos(aDocPos, aContentAtPos))
             {
-                // move cursor to para start toggle outline content visibility and set the same visibility for subs
-                MoveCursor(rSh, aDocPos, false, true);
-                SwPaM aPam(*rSh.GetCurrentShellCursor().GetPoint());
                 SwOutlineNodes::size_type nPos;
-                if (rSh.GetNodes().GetOutLineNds().Seek_Entry(&aPam.GetPoint()->nNode.GetNode(), &nPos))
+                if (rSh.GetNodes().GetOutLineNds().Seek_Entry(aContentAtPos.aFnd.pNode, &nPos))
                 {
-                    if (rSh.GetViewOptions()->IsTreatSubOutlineLevelsAsContent())
-                        rSh.ToggleOutlineContentVisibility(nPos);
-                    else
-                    {
-                        SwOutlineNodes::size_type nOutlineNodesCount = rSh.getIDocumentOutlineNodesAccess()->getOutlineNodesCount();
-                        int nLevel = rSh.getIDocumentOutlineNodesAccess()->getOutlineLevel(nPos);
-                        bool bVisible = rSh.IsOutlineContentVisible(nPos);
-                        do
-                        {
-                            if (rSh.IsOutlineContentVisible(nPos) == bVisible)
-                                rSh.ToggleOutlineContentVisibility(nPos);
-                        } while (++nPos < nOutlineNodesCount
-                                 && rSh.getIDocumentOutlineNodesAccess()->getOutlineLevel(nPos) > nLevel);
-                    }
+                    ToggleOutlineContentVisibility(nPos, !rSh.GetViewOptions()->IsTreatSubOutlineLevelsAsContent());
                     return;
                 }
             }
@@ -3940,48 +3895,37 @@ void SwEditWin::MouseMove(const MouseEvent& _rMEvt)
 
     if (rSh.GetViewOptions()->IsShowOutlineContentVisibilityButton())
     {
-        // add/remove outline collapse button
+        // add/remove outline content hide button
+        const SwNodes& rNds = rSh.GetDoc()->GetNodes();
+        SwOutlineNodes::size_type nPos;
         SwContentAtPos aSwContentAtPos(IsAttrAtPos::Outline);
         if (rSh.GetContentAtPos(PixelToLogic(rMEvt.GetPosPixel()), aSwContentAtPos))
         {
             if(aSwContentAtPos.aFnd.pNode && aSwContentAtPos.aFnd.pNode->IsTextNode())
             {
-                const SwNodes& rNds = rSh.GetDoc()->GetNodes();
-                SwOutlineNodes::size_type nPos;
                 SwContentFrame* pContentFrame = aSwContentAtPos.aFnd.pNode->GetTextNode()->getLayoutFrame(nullptr);
                 if (pContentFrame != m_pSavedOutlineFrame)
                 {
-                    // remove collapse button when saved frame is not frame at mouse position
-                    if (m_pSavedOutlineFrame && /* is it possible that m_pSavedOutlineFrame is removed? */ !m_pSavedOutlineFrame->IsInDtor() &&
+                    if (m_pSavedOutlineFrame && !m_pSavedOutlineFrame->IsInDtor() &&
                             rNds.GetOutLineNds().Seek_Entry(static_cast<SwTextFrame*>(m_pSavedOutlineFrame)->GetTextNodeFirst(), &nPos) &&
-                            rSh.IsOutlineContentVisible(nPos))
-                    {
+                            rSh.GetAttrOutlineContentVisible(nPos))
                         GetFrameControlsManager().RemoveControlsByType(FrameControlType::Outline, m_pSavedOutlineFrame);
-                    }
                     m_pSavedOutlineFrame = pContentFrame;
                 }
-                // show collapse button
-                if (rNds.GetOutLineNds().Seek_Entry(aSwContentAtPos.aFnd.pNode->GetTextNode(),
-                                                    &nPos) && rSh.IsOutlineContentVisible(nPos))
-                {
-                    GetFrameControlsManager().SetOutlineContentVisibilityButton(aSwContentAtPos.aFnd.pNode->GetTextNode());
-                }
+                // show button
+                if (rNds.GetOutLineNds().Seek_Entry(aSwContentAtPos.aFnd.pNode->GetTextNode(), &nPos) &&
+                        rSh.GetAttrOutlineContentVisible(nPos))
+                    GetFrameControlsManager().SetOutlineContentVisibilityButton(pContentFrame);
             }
         }
         else if (m_pSavedOutlineFrame && !m_pSavedOutlineFrame->IsInDtor())
         {
             // current pointer pos is not over an outline frame
             // previous frame was an outline frame
-            // remove collapse button if showing
-            const SwNodes& rNds = rSh.GetDoc()->GetNodes();
-            SwOutlineNodes::size_type nPos;
-            if (rNds.GetOutLineNds().Seek_Entry(static_cast<SwTextFrame*>(m_pSavedOutlineFrame)->
-                                                GetTextNodeFirst(), &nPos) &&
-                    rSh.IsOutlineContentVisible(nPos))
-            {
-                GetFrameControlsManager().RemoveControlsByType(FrameControlType::Outline,
-                                                               m_pSavedOutlineFrame);
-            }
+            // remove outline content visibility button if showing
+            if (rNds.GetOutLineNds().Seek_Entry(static_cast<SwTextFrame*>(m_pSavedOutlineFrame)->GetTextNodeFirst(), &nPos) &&
+                    rSh.GetAttrOutlineContentVisible(nPos))
+                GetFrameControlsManager().RemoveControlsByType(FrameControlType::Outline, m_pSavedOutlineFrame);
             m_pSavedOutlineFrame = nullptr;
         }
     }
@@ -4025,11 +3969,11 @@ void SwEditWin::MouseMove(const MouseEvent& _rMEvt)
         if (m_pSavedOutlineFrame && !bInsWin)
         {
             // the mouse pointer has left the building
-            // 86 the collapse button if showing
+            // remove the outline content visibility button if showing
             const SwNodes& rNds = rSh.GetDoc()->GetNodes();
             SwOutlineNodes::size_type nPos;
-            rNds.GetOutLineNds().Seek_Entry(static_cast<SwTextFrame*>(m_pSavedOutlineFrame)->GetTextNodeFirst(), &nPos);
-            if (rSh.IsOutlineContentVisible(nPos))
+            if (rNds.GetOutLineNds().Seek_Entry(static_cast<SwTextFrame*>(m_pSavedOutlineFrame)->GetTextNodeFirst(), &nPos) &&
+                    rSh.GetAttrOutlineContentVisible(nPos))
                 GetFrameControlsManager().RemoveControlsByType(FrameControlType::Outline, m_pSavedOutlineFrame);
             m_pSavedOutlineFrame = nullptr;
         }
@@ -6668,4 +6612,41 @@ SwFrameControlsManager& SwEditWin::GetFrameControlsManager()
     return *m_pFrameControlsManager;
 }
 
+void SwEditWin::ToggleOutlineContentVisibility(const size_t nOutlinePos, const bool bSubs)
+{
+    SwWrtShell& rSh = GetView().GetWrtShell();
+
+    if (GetView().GetDrawView()->IsTextEdit())
+        rSh.EndTextEdit();
+    if (GetView().IsDrawMode())
+        GetView().LeaveDrawCreate();
+    rSh.EnterStdMode();
+
+    if (!bSubs || rSh.GetViewOptions()->IsTreatSubOutlineLevelsAsContent())
+    {
+        SwNode* pNode = rSh.GetNodes().GetOutLineNds()[nOutlinePos];
+        bool bVisible = true;
+        pNode->GetTextNode()->GetAttrOutlineContentVisible(bVisible);
+        pNode->GetTextNode()->SetAttrOutlineContentVisible(!bVisible);
+    }
+    else if (bSubs)
+    {
+        // toggle including sub levels
+        SwOutlineNodes::size_type nPos = nOutlinePos;
+        SwOutlineNodes::size_type nOutlineNodesCount
+                = rSh.getIDocumentOutlineNodesAccess()->getOutlineNodesCount();
+        int nLevel = rSh.getIDocumentOutlineNodesAccess()->getOutlineLevel(nOutlinePos);
+        bool bVisible = rSh.IsOutlineContentVisible(nOutlinePos);
+        do
+        {
+            if (rSh.IsOutlineContentVisible(nPos) == bVisible)
+                rSh.GetNodes().GetOutLineNds()[nPos]->GetTextNode()->SetAttrOutlineContentVisible(!bVisible);
+        } while (++nPos < nOutlineNodesCount
+                 && rSh.getIDocumentOutlineNodesAccess()->getOutlineLevel(nPos) > nLevel);
+    }
+
+    rSh.InvalidateOutlineContentVisibility();
+    rSh.GotoOutline(nOutlinePos);
+}
+
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/uibase/docvw/edtwin2.cxx b/sw/source/uibase/docvw/edtwin2.cxx
index a72554202f2e..0f4a2e1250d8 100644
--- a/sw/source/uibase/docvw/edtwin2.cxx
+++ b/sw/source/uibase/docvw/edtwin2.cxx
@@ -467,9 +467,6 @@ void SwEditWin::Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle
 
     if( bPaintShadowCursor )
         m_pShadCursor->Paint();
-
-    if (pWrtShell->GetViewOptions()->IsShowOutlineContentVisibilityButton())
-        GetFrameControlsManager().SetOutlineContentVisibilityButtons();
 }
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/uibase/inc/FrameControlsManager.hxx b/sw/source/uibase/inc/FrameControlsManager.hxx
index cb51be62f860..f73f226b36d7 100644
--- a/sw/source/uibase/inc/FrameControlsManager.hxx
+++ b/sw/source/uibase/inc/FrameControlsManager.hxx
@@ -25,14 +25,13 @@ typedef std::shared_ptr< SwFrameControl > SwFrameControlPtr;
 
 typedef std::map<const SwFrame*, SwFrameControlPtr> SwFrameControlPtrMap;
 
-/** A container for the Header/Footer, or PageBreak controls.
+/** A container for the Header/Footer, PageBreak, and Outline Content Visibility controls.
 */
 class SwFrameControlsManager
 {
     private:
         VclPtr<SwEditWin> m_pEditWin;
         std::map< FrameControlType, SwFrameControlPtrMap > m_aControls;
-        std::map<const SwTextNode*, const SwContentFrame*> m_aTextNodeContentFrameMap;
 
     public:
         SwFrameControlsManager( SwEditWin* pEditWin );
@@ -49,8 +48,7 @@ class SwFrameControlsManager
         void SetHeaderFooterControl( const SwPageFrame* pPageFrame, FrameControlType eType, Point aOffset );
         void SetPageBreakControl( const SwPageFrame* pPageFrame );
         void SetUnfloatTableButton( const SwFlyFrame* pFlyFrame, bool bShow, Point aTopRightPixel = Point() );
-        void SetOutlineContentVisibilityButton(const SwTextNode* pTextNd);
-        void SetOutlineContentVisibilityButtons();
+        void SetOutlineContentVisibilityButton(const SwContentFrame* pContentFrame);
 };
 
 #endif
diff --git a/sw/source/uibase/inc/OutlineContentVisibilityWin.hxx b/sw/source/uibase/inc/OutlineContentVisibilityWin.hxx
index 96c0c0500ac4..db993021aa11 100644
--- a/sw/source/uibase/inc/OutlineContentVisibilityWin.hxx
+++ b/sw/source/uibase/inc/OutlineContentVisibilityWin.hxx
@@ -32,8 +32,6 @@ private:
     bool m_bDestroyed;
     size_t m_nOutlinePos;
 
-    void ToggleOutlineContentVisibility(const bool bSubs);
-
 public:
     SwOutlineContentVisibilityWin(SwEditWin* pEditWin, const SwFrame* pFrame);
     virtual ~SwOutlineContentVisibilityWin() override { disposeOnce(); }
diff --git a/sw/source/uibase/inc/edtwin.hxx b/sw/source/uibase/inc/edtwin.hxx
index cb736bdf562f..44985f903c86 100644
--- a/sw/source/uibase/inc/edtwin.hxx
+++ b/sw/source/uibase/inc/edtwin.hxx
@@ -293,6 +293,7 @@ public:
 
     const SwFrame* GetSavedOutlineFrame() const { return m_pSavedOutlineFrame; }
     void SetSavedOutlineFrame(SwFrame* pFrame) { m_pSavedOutlineFrame = pFrame; }
+    void ToggleOutlineContentVisibility(const size_t nOutlinePos, const bool bSubs);
 
     virtual FactoryFunction GetUITestFactory() const override;
 };
diff --git a/sw/source/uibase/inc/wrtsh.hxx b/sw/source/uibase/inc/wrtsh.hxx
index 67b626dc70bc..3e7b5d7eaf89 100644
--- a/sw/source/uibase/inc/wrtsh.hxx
+++ b/sw/source/uibase/inc/wrtsh.hxx
@@ -30,10 +30,12 @@
 #include <svx/swframetypes.hxx>
 #include <vcl/weld.hxx>
 
+#include <doc.hxx>
+#include <docsh.hxx>
+#include <viewopt.hxx>
+
 namespace vcl { class Window; }
 class SbxArray;
-class SwDoc;
-class SwViewOption;
 class SwFlyFrameAttrMgr;
 class SwField;
 class SwTOXBase;
@@ -492,8 +494,10 @@ typedef bool (SwWrtShell::*FNSimpleMove)();
     void InsertPostIt(SwFieldMgr& rFieldMgr, const SfxRequest& rReq);
 
     bool IsOutlineContentVisible(const size_t nPos);
-    void ToggleOutlineContentVisibility(SwNode* pNd, const bool bForceNotVisible = false);
-    void ToggleOutlineContentVisibility(const size_t nPos, const bool bForceNotVisible = false);
+    void MakeOutlineContentVisible(const size_t nPos, bool bMakeVisible = true);
+    void MakeAllFoldedOutlineContentVisible(bool bMakeVisible = true);
+    void InvalidateOutlineContentVisibility();
+    bool GetAttrOutlineContentVisible(const size_t nPos);
 
 private:
 
@@ -653,4 +657,39 @@ inline bool SwWrtShell::Is_FnDragEQBeginDrag() const
 #endif
 }
 
+class MakeAllOutlineContentTemporarilyVisible
+{
+private:
+    SwWrtShell* m_pWrtSh;
+    bool m_bDone = false;
+public:
+    static sal_uInt32 nLock;
+    MakeAllOutlineContentTemporarilyVisible(SwDoc* pDoc)
+    {
+        ++nLock;
+        if (nLock > 1)
+            return;
+        if (SwDocShell* pDocSh = pDoc->GetDocShell())
+            if ((m_pWrtSh = pDocSh->GetWrtShell()) && m_pWrtSh->GetViewOptions() &&
+                    m_pWrtSh->GetViewOptions()->IsShowOutlineContentVisibilityButton())
+            {
+                m_pWrtSh->StartAllAction();
+                m_pWrtSh->MakeAllFoldedOutlineContentVisible();
+                m_bDone = true;
+            }
+    }
+
+    ~MakeAllOutlineContentTemporarilyVisible() COVERITY_NOEXCEPT_FALSE
+    {
+        --nLock;
+        if (nLock > 0)
+            return;
+        if (m_bDone && m_pWrtSh)
+        {
+            m_pWrtSh->MakeAllFoldedOutlineContentVisible(false);
+            m_pWrtSh->EndAllAction();
+        }
+    }
+};
+
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/uibase/shells/basesh.cxx b/sw/source/uibase/shells/basesh.cxx
index d8b4c3210547..5942e7cc7340 100644
--- a/sw/source/uibase/shells/basesh.cxx
+++ b/sw/source/uibase/shells/basesh.cxx
@@ -99,6 +99,8 @@
 #include <shellres.hxx>
 #include <UndoTable.hxx>
 
+#include <ndtxt.hxx>
+
 FlyMode SwBaseShell::eFrameMode = FLY_DRAG_END;
 
 // These variables keep the state of Gallery (slot SID_GALLERY_BG_BRUSH)
@@ -195,11 +197,53 @@ void SwBaseShell::ExecDelete(SfxRequest &rReq)
     switch(rReq.GetSlot())
     {
         case SID_DELETE:
+            if (rSh.GetViewOptions()->IsShowOutlineContentVisibilityButton())
+            {
+                if (rSh.IsEndPara())
+                {
+                    SwNodeIndex aIdx(rSh.GetCursor()->GetNode());
+                    // disallow if this is am outline node having folded content
+                    bool bVisible = true;
+                    aIdx.GetNode().GetTextNode()->GetAttrOutlineContentVisible(bVisible);
+                    if (!bVisible)
+                        return;
+                    // disallow if the next text node is an outline node having folded content
+                    ++aIdx;
+                    SwNodeType aNodeType;
+                    while ((aNodeType = aIdx.GetNode().GetNodeType()) != SwNodeType::Text)
+                        ++aIdx;
+                    if (aIdx.GetNode().IsTextNode())
+                    {
+                        bVisible = true;
+                        aIdx.GetNode().GetTextNode()->GetAttrOutlineContentVisible(bVisible);
+                        if (!bVisible)
+                            return;
+                    }
+                }
+            }
             rSh.DelRight();
             break;
 
         case FN_BACKSPACE:
-
+            if (rSh.GetViewOptions()->IsShowOutlineContentVisibilityButton())
+            {
+                if (rSh.IsSttPara())
+                {
+                    SwNodeIndex aIdx(rSh.GetCursor()->GetNode());
+                    // disallow if this is a folded outline node
+                    bool bVisible = true;
+                    aIdx.GetNode().GetTextNode()->GetAttrOutlineContentVisible(bVisible);
+                    if (!bVisible)
+                        return;
+                    // disallow if previous text node does not have a layout frame
+                    --aIdx;
+                    SwNodeType aNodeType;
+                    while ((aNodeType = aIdx.GetNode().GetNodeType()) != SwNodeType::Text)
+                        --aIdx;
+                    if (aIdx.GetNode().IsContentNode() && !aIdx.GetNode().GetContentNode()->getLayoutFrame(nullptr))
+                        return;
+                }
+            }
             if( rSh.IsNoNum() )
             {
                 rSh.SttCursorMove();
@@ -234,6 +278,8 @@ void SwBaseShell::ExecDelete(SfxRequest &rReq)
 
 void SwBaseShell::ExecClpbrd(SfxRequest &rReq)
 {
+    MakeAllOutlineContentTemporarilyVisible a(GetShell().GetDoc());
+
     // Attention: At risk of suicide!
     // After paste, paste special the shell can be destroy.
 
@@ -523,6 +569,8 @@ void SwBaseShell::StateClpbrd(SfxItemSet &rSet)
 
 void SwBaseShell::ExecUndo(SfxRequest &rReq)
 {
+    MakeAllOutlineContentTemporarilyVisible a(GetShell().GetDoc());
+
     SwWrtShell &rWrtShell = GetShell();
 
     SwUndoId nUndoId(SwUndoId::EMPTY);
diff --git a/sw/source/uibase/uiview/view.cxx b/sw/source/uibase/uiview/view.cxx
index 58012edabf60..3091e5af3bc6 100644
--- a/sw/source/uibase/uiview/view.cxx
+++ b/sw/source/uibase/uiview/view.cxx
@@ -1051,6 +1051,9 @@ SwView::SwView( SfxViewFrame *_pFrame, SfxViewShell* pOldSh )
     if( !m_pVScrollbar->IsVisible( true ) )
         ShowVScrollbar( false );
 
+    if (m_pWrtShell && m_pWrtShell->GetViewOptions()->IsShowOutlineContentVisibilityButton())
+        m_pWrtShell->InvalidateOutlineContentVisibility();
+
     GetViewFrame()->GetWindow().AddChildEventListener( LINK( this, SwView, WindowChildEventListener ) );
 }
 
diff --git a/sw/source/uibase/uiview/view0.cxx b/sw/source/uibase/uiview/view0.cxx
index 8d7e8521664e..01bed0a3f35b 100644
--- a/sw/source/uibase/uiview/view0.cxx
+++ b/sw/source/uibase/uiview/view0.cxx
@@ -603,33 +603,20 @@ void SwView::ExecViewOptions(SfxRequest &rReq)
 
         SwWrtShell &rSh = GetWrtShell();
 
-        // move cursor to top of document
-        if (rSh.IsSelFrameMode())
-        {
-            rSh.UnSelectFrame();
-            rSh.LeaveSelFrameMode();
-        }
-        rSh.EnterStdMode();
-        rSh.SttEndDoc(true);
-
-        if (!bFlag)
-        {
-            // make all content visible
-            const SwOutlineNodes& rOutlineNds = rSh.GetNodes().GetOutLineNds();
-            for (SwOutlineNodes::size_type nPos = 0; nPos < rOutlineNds.size(); ++nPos)
-            {
-                SwNode* pNd = rOutlineNds[nPos];
-                bool bOutlineContentVisibleAttr = true;
-                pNd->GetTextNode()->GetAttrOutlineContentVisible(bOutlineContentVisibleAttr);
-                if (!bOutlineContentVisibleAttr)
-                {
-                    rSh.ToggleOutlineContentVisibility(nPos);
-                    pNd->GetTextNode()->SetAttrOutlineContentVisible(false);
-                }
-            }
-        }
+        if (!bFlag) // Outline folding is being turned ON!
+            rSh.MakeAllFoldedOutlineContentVisible();
 
         pOpt->SetShowOutlineContentVisibilityButton(bFlag);
+
+        // Apply option change here so if toggling the outline folding feature ON
+        // the invalidate function will see this.
+        rSh.StartAction();
+        rSh.ApplyViewOptions(*pOpt);
+        rSh.EndAction();
+
+        if (bFlag) // Outline folding is being turned OFF!
+            rSh.MakeAllFoldedOutlineContentVisible(false);
+
         break;
     }
 
diff --git a/sw/source/uibase/uiview/view2.cxx b/sw/source/uibase/uiview/view2.cxx
index 49d04147f063..7a30c9e8db0c 100644
--- a/sw/source/uibase/uiview/view2.cxx
+++ b/sw/source/uibase/uiview/view2.cxx
@@ -146,6 +146,8 @@
 
 #include <basegfx/utils/zoomtools.hxx>
 
+#include <ndtxt.hxx>
+
 const char sStatusDelim[] = " : ";
 
 using namespace sfx2;
@@ -1185,8 +1187,14 @@ void SwView::Execute(SfxRequest &rReq)
         {
             m_pWrtShell->EnterStdMode();
             size_t nPos(m_pWrtShell->GetOutlinePos());
-            m_pWrtShell->ToggleOutlineContentVisibility(nPos);
-            m_pWrtShell->GotoOutline(nPos);
+            if (nPos != SwOutlineNodes::npos)
+            {
+                SwNode* pNode = m_pWrtShell->GetNodes().GetOutLineNds()[nPos];
+                pNode->GetTextNode()->SetAttrOutlineContentVisible(
+                            !m_pWrtShell->GetAttrOutlineContentVisible(nPos));
+                m_pWrtShell->InvalidateOutlineContentVisibility();
+                m_pWrtShell->GotoOutline(nPos);
+            }
         }
         break;
         case FN_NAV_ELEMENT:
diff --git a/sw/source/uibase/uiview/viewport.cxx b/sw/source/uibase/uiview/viewport.cxx
index b5ebbb258187..6e20aaedf7f6 100644
--- a/sw/source/uibase/uiview/viewport.cxx
+++ b/sw/source/uibase/uiview/viewport.cxx
@@ -43,6 +43,8 @@
 
 #include "viewfunc.hxx"
 
+#include <FrameControlsManager.hxx>
+
 // The SetVisArea of the DocShell must not be called from InnerResizePixel.
 // But our adjustments must take place.
 static bool bProtectDocShellVisArea = false;
@@ -301,6 +303,9 @@ void SwView::SetVisArea( const Point &rPt, bool bUpdateScrollbar )
     if ( aPt == m_aVisArea.TopLeft() )
         return;
 
+    if (m_pWrtShell && m_pWrtShell->GetViewOptions()->IsShowOutlineContentVisibilityButton())
+        GetEditWin().GetFrameControlsManager().HideControls(FrameControlType::Outline);
+
     const tools::Long lXDiff = m_aVisArea.Left() - aPt.X();
     const tools::Long lYDiff = m_aVisArea.Top()  - aPt.Y();
     SetVisArea( tools::Rectangle( aPt,
diff --git a/sw/source/uibase/utlui/content.cxx b/sw/source/uibase/utlui/content.cxx
index f1264d026f9a..bfdf00e7aff9 100644
--- a/sw/source/uibase/utlui/content.cxx
+++ b/sw/source/uibase/utlui/content.cxx
@@ -2923,6 +2923,8 @@ void SwContentTree::Notify(SfxBroadcaster & rBC, SfxHint const& rHint)
 
 void SwContentTree::ExecCommand(std::string_view rCmd, bool bOutlineWithChildren)
 {
+    MakeAllOutlineContentTemporarilyVisible a(GetWrtShell()->GetDoc());
+
     const bool bUp = rCmd == "chapterup";
     const bool bUpDown = bUp || rCmd == "chapterdown";
     const bool bLeft = rCmd == "promote";
@@ -2987,7 +2989,6 @@ void SwContentTree::ExecCommand(std::string_view rCmd, bool bOutlineWithChildren
 
     SwOutlineNodes::difference_type nDirLast = bUp ? -1 : 1;
     bool bStartedAction = false;
-    std::vector<SwNode*> aOutlineNdsArray;
     for (auto const& pCurrentEntry : selected)
     {
         assert(pCurrentEntry && lcl_IsContent(*pCurrentEntry, *m_xTreeView));
@@ -3009,29 +3010,6 @@ void SwContentTree::ExecCommand(std::string_view rCmd, bool bOutlineWithChildren
         if (!bStartedAction)
         {
             pShell->StartAllAction();
-            if (bUpDown)
-            {
-                if (pShell->GetViewOptions()->IsShowOutlineContentVisibilityButton())
-                {
-                    // make all outline nodes content visible before move
-                    // restore outline nodes content visible state after move
-                    SwOutlineNodes rOutlineNds = pShell->GetDoc()->GetNodes().GetOutLineNds();
-                    for (SwOutlineNodes::size_type nPos = 0; nPos < rOutlineNds.size(); ++nPos)
-                    {
-                        SwNode* pNd = rOutlineNds[nPos];
-                        if (pNd->IsTextNode()) // should always be true
-                        {
-                            bool bOutlineContentVisibleAttr = true;
-                            pNd->GetTextNode()->GetAttrOutlineContentVisible(bOutlineContentVisibleAttr);
-                            if (!bOutlineContentVisibleAttr)
-                            {
-                                aOutlineNdsArray.push_back(pNd);
-                                pShell->ToggleOutlineContentVisibility(nPos);
-                            }
-                        }
-                    }
-                }
-            }
             pShell->StartUndo(bLeftRight ? SwUndoId::OUTLINE_LR : SwUndoId::OUTLINE_UD);
             bStartedAction = true;
         }
@@ -3203,15 +3181,6 @@ void SwContentTree::ExecCommand(std::string_view rCmd, bool bOutlineWithChildren
     if (bStartedAction)
     {
         pShell->EndUndo();
-        if (bUpDown)
-        {
-            if (pShell->GetViewOptions()->IsShowOutlineContentVisibilityButton())
-            {
-                // restore state of outline content visibility to before move
-                for (SwNode* pNd : aOutlineNdsArray)
-                    pShell->ToggleOutlineContentVisibility(pNd, true);
-            }
-        }
         pShell->EndAllAction();
         if (m_aActiveContentArr[ContentTypeId::OUTLINE])
             m_aActiveContentArr[ContentTypeId::OUTLINE]->Invalidate();
@@ -3637,30 +3606,10 @@ void SwContentTree::SelectOutlinesWithSelection()
 
 void SwContentTree::MoveOutline(SwOutlineNodes::size_type nTargetPos)
 {
+    MakeAllOutlineContentTemporarilyVisible a(GetWrtShell()->GetDoc());
+
     SwWrtShell *const pShell = GetWrtShell();
     pShell->StartAllAction();
-    std::vector<SwNode*> aOutlineNdsArray;
-
-    if (pShell->GetViewOptions()->IsShowOutlineContentVisibilityButton())
-    {
-        // make all outline nodes content visible before move
-        // restore outline nodes content visible state after move
-        SwOutlineNodes rOutlineNds = pShell->GetDoc()->GetNodes().GetOutLineNds();
-        for (SwOutlineNodes::size_type nPos = 0; nPos < rOutlineNds.size(); ++nPos)
-        {
-            SwNode* pNd = rOutlineNds[nPos];
-            if (pNd->IsTextNode()) // should always be true
-            {
-                bool bOutlineContentVisibleAttr = true;
-                pNd->GetTextNode()->GetAttrOutlineContentVisible(bOutlineContentVisibleAttr);
-                if (!bOutlineContentVisibleAttr)
-                {
-                    aOutlineNdsArray.push_back(pNd);
-                    pShell->ToggleOutlineContentVisibility(nPos);
-                }
-            }
-        }
-    }
     pShell->StartUndo(SwUndoId::OUTLINE_UD);
 
     SwOutlineNodes::size_type nPrevSourcePos = SwOutlineNodes::npos;
@@ -3711,12 +3660,6 @@ void SwContentTree::MoveOutline(SwOutlineNodes::size_type nTargetPos)
     }
 
     pShell->EndUndo();
-    if (pShell->GetViewOptions()->IsShowOutlineContentVisibilityButton())
-    {
-        // restore state of outline content visibility to before move
-        for (SwNode* pNd : aOutlineNdsArray)
-            pShell->ToggleOutlineContentVisibility(pNd, true);
-    }
     pShell->EndAllAction();
     m_aActiveContentArr[ContentTypeId::OUTLINE]->Invalidate();
     Display(true);
@@ -4028,9 +3971,13 @@ void SwContentTree::ExecuteContextMenuAction(const OString& rSelectedPopupEntry)
             m_pActiveShell->EnterStdMode();
             m_bIgnoreViewChange = true;
             SwOutlineContent* pCntFirst = reinterpret_cast<SwOutlineContent*>(m_xTreeView->get_id(*xFirst).toInt64());
+
+            // toggle the outline node outline content visible attribute
             if (nSelectedPopupEntry == TOGGLE_OUTLINE_CONTENT_VISIBILITY)
             {
-                m_pActiveShell->ToggleOutlineContentVisibility(pCntFirst->GetOutlinePos());
+                SwNode* pNode = m_pActiveShell->GetDoc()->GetNodes().GetOutLineNds()[pCntFirst->GetOutlinePos()];
+                pNode->GetTextNode()->SetAttrOutlineContentVisible(
+                            !m_pActiveShell->GetAttrOutlineContentVisible(pCntFirst->GetOutlinePos()));
             }
             else
             {
@@ -4048,15 +3995,16 @@ void SwContentTree::ExecuteContextMenuAction(const OString& rSelectedPopupEntry)
                 do
                 {
                     if (m_pActiveShell->IsOutlineContentVisible(nPos) != bShow)
-                        m_pActiveShell->ToggleOutlineContentVisibility(nPos);
+                        m_pActiveShell->GetDoc()->GetNodes().GetOutLineNds()[nPos]->GetTextNode()->SetAttrOutlineContentVisible(bShow);
                 } while (++nPos < nOutlineNodesCount
                          && (nLevel == -1 || m_pActiveShell->getIDocumentOutlineNodesAccess()->getOutlineLevel(nPos) > nLevel));
             }
+            m_pActiveShell->InvalidateOutlineContentVisibility();
             // show in the document what was toggled
             if (lcl_IsContentType(*xFirst, *m_xTreeView)) // Headings root entry
                 m_pActiveShell->GotoPage(1, true);
             else
-                GotoContent(pCntFirst);
+                m_pActiveShell->GotoOutline(pCntFirst->GetOutlinePos());
             grab_focus();
             m_bIgnoreViewChange = false;
         }
@@ -4314,6 +4262,7 @@ void SwContentTree::Select()
             }
         }
     }
+
     SwNavigationPI* pNavi = GetParentWindow();
     pNavi->m_xContent6ToolBox->set_item_sensitive("chapterup",  bEnable);
     pNavi->m_xContent6ToolBox->set_item_sensitive("chapterdown", bEnable);
diff --git a/sw/source/uibase/wrtsh/wrtsh1.cxx b/sw/source/uibase/wrtsh/wrtsh1.cxx
index b8c36c76eda4..98e41e16299e 100644
--- a/sw/source/uibase/wrtsh/wrtsh1.cxx
+++ b/sw/source/uibase/wrtsh/wrtsh1.cxx
@@ -121,6 +121,25 @@ void collectUIInformation(const OUString& rAction, const OUString& aParameters)
 
 }
 
+sal_uInt32 MakeAllOutlineContentTemporarilyVisible::nLock = 0;
+
+static bool lcl_IsAllowed(const SwWrtShell* rSh)
+{
+    if (rSh->GetViewOptions()->IsShowOutlineContentVisibilityButton() && rSh->IsEndPara())
+    {
+        SwTextNode* pTextNode = rSh->GetCursor()->GetNode().GetTextNode();
+        if (pTextNode && pTextNode->IsOutline())
+        {
+            // disallow if this is am outline node having folded content
+            bool bVisible = true;
+            pTextNode->GetAttrOutlineContentVisible(bVisible);
+            if (!bVisible)
+                return false;
+        }
+    }
+    return true;
+}
+
 #define BITFLD_INI_LIST \
         m_bClearMark = \
         m_bIns = true;\
@@ -876,6 +895,9 @@ void SwWrtShell::ConnectObj( svt::EmbeddedObjectRef& xObj, const SwRect &rPrt,
 // Selections will be overwritten
 void SwWrtShell::InsertPageBreak(const OUString *pPageDesc, const ::std::optional<sal_uInt16>& oPgNum )
 {
+    if (!lcl_IsAllowed(this))
+        return;
+
     ResetCursorStack();
     if( CanInsert() )
     {
@@ -911,6 +933,9 @@ void SwWrtShell::InsertPageBreak(const OUString *pPageDesc, const ::std::optiona
 
 void SwWrtShell::InsertLineBreak()
 {
+    if (!lcl_IsAllowed(this))
+        return;
+
     ResetCursorStack();
     if( CanInsert() )
     {
@@ -931,6 +956,9 @@ void SwWrtShell::InsertLineBreak()
 
 void SwWrtShell::InsertColumnBreak()
 {
+    if (!lcl_IsAllowed(this))
+        return;
+
     SwActContext aActContext(this);
     ResetCursorStack();
     if( !CanInsert() )
@@ -987,6 +1015,9 @@ void SwWrtShell::InsertFootnote(const OUString &rStr, bool bEndNote, bool bEdit
 
 void SwWrtShell::SplitNode( bool bAutoFormat )
 {
+    if (!lcl_IsAllowed(this))
+        return;
+
     ResetCursorStack();
     if( !CanInsert() )
         return;
@@ -1994,64 +2025,53 @@ void SwWrtShell::InsertPostIt(SwFieldMgr& rFieldMgr, const SfxRequest& rReq)
 }
 bool SwWrtShell::IsOutlineContentVisible(const size_t nPos)
 {
-    const SwNodes& rNodes = GetDoc()->GetNodes();
-    const SwOutlineNodes& rOutlineNodes = rNodes.GetOutLineNds();
+    const SwOutlineNodes& rOutlineNodes = GetDoc()->GetNodes().GetOutLineNds();
+    const SwNode* pOutlineNode = rOutlineNodes[nPos];
 
-    SwNode* pOutlineNode = rOutlineNodes[nPos];
-    if (pOutlineNode->IsEndNode())
-        return true;
+    // no layout frame means outline folding is set to include sub levels and the outline node has
+    // a parent outline node with outline content visible attribute false (folded outline content)
+    if (!pOutlineNode->GetTextNode()->getLayoutFrame(nullptr))
+        return false;
+
+    // try the next node to determine if this outline node has visible content
+    SwNodeIndex aIdx(*pOutlineNode, +1);
+    if (&aIdx.GetNode() == &aIdx.GetNodes().GetEndOfContent()) // end of regular content
+        return false;
 
-    bool bOutlineContentVisibleAttr = false;
-    if (pOutlineNode->GetTextNode()->GetAttrOutlineContentVisible(bOutlineContentVisibleAttr))
-        return bOutlineContentVisibleAttr;
+    if (aIdx.GetNode().IsTextNode())
+    {
+        // sublevels treated as outline content
+        //   If next node (aIdx) doesn't have a layout frame
+        //  then this outline node does not have visible outline content.
+        // sublevels NOT treated as outline content
+        //   If the next node (aIdx) is the next outline node
+        //   then return the outline content visible attribute value.
+        if (!GetViewOptions()->IsTreatSubOutlineLevelsAsContent() &&
+                nPos + 1 < rOutlineNodes.size() &&
+                rOutlineNodes[nPos + 1] == &aIdx.GetNode())
+            return GetAttrOutlineContentVisible(nPos);
 
-    return true;
-}
+        return aIdx.GetNode().GetTextNode()->getLayoutFrame(nullptr);
+    }
 
-void SwWrtShell::ToggleOutlineContentVisibility(SwNode* pNd, const bool bForceNotVisible)
-{
-    SwOutlineNodes::size_type nPos;
-    if (GetNodes().GetOutLineNds().Seek_Entry(pNd, &nPos))
-        ToggleOutlineContentVisibility(nPos, bForceNotVisible);
+    return true;
 }
 
-void SwWrtShell::ToggleOutlineContentVisibility(const size_t nPos, const bool bForceNotVisible)
+void SwWrtShell::MakeOutlineContentVisible(const size_t nPos, bool bMakeVisible)
 {
     const SwNodes& rNodes = GetNodes();
     const SwOutlineNodes& rOutlineNodes = rNodes.GetOutLineNds();
 
-    assert(nPos < rOutlineNodes.size());
-
     SwNode* pSttNd = rOutlineNodes[nPos];
-    if (pSttNd->IsEndNode())
-        return;
 
+    // determine end node
     SwNode* pEndNd = &rNodes.GetEndOfContent();
     if (rOutlineNodes.size() > nPos + 1)
         pEndNd = rOutlineNodes[nPos + 1];
 
-    if (pSttNd->GetTableBox() || pSttNd->GetIndex() < rNodes.GetEndOfExtras().GetIndex())
-    {
-        // limit toggle to within table box
-        if (pSttNd->EndOfSectionIndex() < pEndNd->GetIndex() )
-            pEndNd = pSttNd->EndOfSectionNode();
-    }
-    // if pSttNd isn't in table but pEndNd is, skip over all outline nodes in table
-    else if (pEndNd->GetTableBox())
-    {
-        pEndNd = &rNodes.GetEndOfContent();
-        for (size_t nOutlinePos = nPos + 2; nOutlinePos < rOutlineNodes.size(); nOutlinePos++)
-        {
-            if (!(rOutlineNodes[nOutlinePos]->GetTableBox()))
-            {
-                pEndNd = rOutlineNodes[nOutlinePos];
-                break;
-            }
-        }
-    }
-
     if (GetViewOptions()->IsTreatSubOutlineLevelsAsContent())
     {
+        // get the last outline node to include (iPos)
         int nLevel = pSttNd->GetTextNode()->GetAttrOutlineLevel();
         SwOutlineNodes::size_type iPos = nPos;
         while (++iPos < rOutlineNodes.size() &&
@@ -2080,64 +2100,173 @@ void SwWrtShell::ToggleOutlineContentVisibility(const size_t nPos, const bool bF
         }
     }
 
-    SwNodeIndex aIdx(*pSttNd, +1); // the next node after pSttdNd in the doc model SwNodes
-    if (!IsOutlineContentVisible(nPos) && !bForceNotVisible)
+    // table, text box, header, footer
+    if (pSttNd->GetTableBox() || pSttNd->GetIndex() < rNodes.GetEndOfExtras().GetIndex())
     {
-        // make visible
+        // limit to within section
+        if (pSttNd->EndOfSectionIndex() < pEndNd->GetIndex())
+            pEndNd = pSttNd->EndOfSectionNode();
+    }
+    // if pSttNd isn't in table but pEndNd is, skip over all outline nodes in table
+    else if (pEndNd->GetTableBox())
+    {
+        pEndNd = &rNodes.GetEndOfContent();
+        for (size_t nOutlinePos = nPos + 2; nOutlinePos < rOutlineNodes.size(); nOutlinePos++)
+        {
+            if (!(rOutlineNodes[nOutlinePos]->GetTableBox()))
+            {
+                pEndNd = rOutlineNodes[nOutlinePos];
+                break;
+            }
+        }
+    }
+    // end node determined
+
+    // Remove content frames from the next node after the starting outline node to
+    // the determined ending node. Always do this to prevent the chance of duplicate
+    // frames being made. They will be remade below if needed.
+    SwNodeIndex aIdx(*pSttNd, +1);
+    while (aIdx != *pEndNd)
+    {
+        SwNode* pNd = &aIdx.GetNode();
+        if (pNd->IsContentNode())
+            pNd->GetContentNode()->DelFrames(nullptr);
+        else if (pNd->IsTableNode())
+            pNd->GetTableNode()->DelFrames(nullptr);
+        aIdx++;
+    }
+
+    if (bMakeVisible) // make outline nodes outline content visible
+    {
+        // reset the index marker and make frames
+        aIdx.Assign(*pSttNd, +1);
         MakeFrames(GetDoc(), aIdx, *pEndNd);
 
         pSttNd->GetTextNode()->SetAttrOutlineContentVisible(true);
 
-        if (GetViewOptions()->IsShowOutlineContentVisibilityButton())
+        // make outline content made visible that have outline visible attribute false not visible
+        while (aIdx != *pEndNd)
         {
-            // remove button if focus is not on outline frame control window
-            SwContentFrame* pFrame = pSttNd->GetTextNode()->getLayoutFrame(nullptr);
-            if (pFrame && !pFrame->IsInDtor())
-            {
-                SwFrameControlPtr pOutlineFrameControl = GetView().GetEditWin().GetFrameControlsManager().GetControl(FrameControlType::Outline, pFrame);
-                if (pOutlineFrameControl && pOutlineFrameControl->GetWindow() && !pOutlineFrameControl->HasFocus())
-                    GetView().GetEditWin().GetFrameControlsManager().RemoveControlsByType(FrameControlType::Outline, pFrame);
-            }
-
-            // toggle outline content made visible that have outline visible attribute false
-            while (aIdx != *pEndNd)
+            SwNode* pNd = &aIdx.GetNode();
+            if (pNd->IsTextNode() && pNd->GetTextNode()->IsOutline())
             {
-                SwNode* pTmpNd = &aIdx.GetNode();
-                if (pTmpNd->IsTextNode() && pTmpNd->GetTextNode()->IsOutline())
+                SwTextNode* pTextNd = pNd->GetTextNode();
+                bool bOutlineContentVisibleAttr = true;
+                pTextNd->GetAttrOutlineContentVisible(bOutlineContentVisibleAttr);
+                if (!bOutlineContentVisibleAttr)
                 {
-                    SwTextNode* pTmpTextNd = pTmpNd->GetTextNode();
-                    bool bOutlineContentVisibleAttr = true;
-                    if (pTmpTextNd->GetAttrOutlineContentVisible(bOutlineContentVisibleAttr) &&
-                            !bOutlineContentVisibleAttr)
+                    SwOutlineNodes::size_type iPos;
+                    if (rOutlineNodes.Seek_Entry(pTextNd, &iPos))
                     {
-                        SwOutlineNodes::size_type iPos;
-                        if (rOutlineNodes.Seek_Entry(pTmpTextNd, &iPos))
-                        {
-                            if (pTmpTextNd->getLayoutFrame(nullptr))
-                                ToggleOutlineContentVisibility(iPos, true); // force not visible
-                        }
+                        if (pTextNd->getLayoutFrame(nullptr))
+                            MakeOutlineContentVisible(iPos, false);
                     }
                 }
-                aIdx++;
             }
+            aIdx++;
         }
     }
     else
+        pSttNd->GetTextNode()->SetAttrOutlineContentVisible(false);
+}
+
+// make content visible or not visible only if needed
+void SwWrtShell::InvalidateOutlineContentVisibility()
+{
+    GetView().GetEditWin().GetFrameControlsManager().HideControls(FrameControlType::Outline);
+
+    const SwOutlineNodes& rOutlineNds = GetNodes().GetOutLineNds();
+    for (SwOutlineNodes::size_type nPos = 0; nPos < rOutlineNds.size(); ++nPos)
     {
-        // remove content frames
-        while (aIdx != *pEndNd)
+        bool bIsOutlineContentVisible = IsOutlineContentVisible(nPos);
+        bool bOutlineContentVisibleAttr = true;
+        rOutlineNds[nPos]->GetTextNode()->GetAttrOutlineContentVisible(bOutlineContentVisibleAttr);
+        if (!bIsOutlineContentVisible && bOutlineContentVisibleAttr)
+            MakeOutlineContentVisible(nPos);
+        else if (bIsOutlineContentVisible && !bOutlineContentVisibleAttr)
+            MakeOutlineContentVisible(nPos, false);
+    }
+}
+
+void SwWrtShell::MakeAllFoldedOutlineContentVisible(bool bMakeVisible)
+{
+    // deselect any drawing or frame and leave editing mode
+    SdrView* pSdrView = GetDrawView();
+    if (pSdrView && pSdrView->IsTextEdit() )
+    {
+        bool bLockView = IsViewLocked();
+        LockView(true);
+        EndTextEdit();
+        LockView(bLockView);
+    }
+
+    if (IsSelFrameMode() || IsObjSelected())
+    {
+        UnSelectFrame();
+        LeaveSelFrameMode();
+        GetView().LeaveDrawCreate();
+        EnterStdMode();
+        DrawSelChanged();
+        GetView().StopShellTimer();
+    }
+    else
+        EnterStdMode();
+
+    SwOutlineNodes::size_type nPos = GetOutlinePos();
+
+    if (bMakeVisible)
+    {
+        // make all content visible
+
+        // When shortcut is assigned to the show outline content visibility button and used to
+        // toggle the feature and the mouse pointer is on an outline frame the button will not
+        // be removed. An easy way to make sure the button does not remain shown is to use the
+        // HideControls function.
+        GetView().GetEditWin().GetFrameControlsManager().HideControls(FrameControlType::Outline);
+
+        // temporarily set outline content visibile attribute true for folded outline nodes
+        std::vector<SwNode*> aFoldedOutlineNodeArray;
+        for (SwNode* pNd: GetNodes().GetOutLineNds())
         {
-            SwNode* pNd = &aIdx.GetNode();
-            if (pNd->IsContentNode())
-                pNd->GetContentNode()->DelFrames(nullptr);
-            else if (pNd->IsTableNode())
-                pNd->GetTableNode()->DelFrames(nullptr);
-            aIdx++;
+            bool bOutlineContentVisibleAttr = true;
+            pNd->GetTextNode()->GetAttrOutlineContentVisible(bOutlineContentVisibleAttr);
+            if (!bOutlineContentVisibleAttr)
+            {
+                aFoldedOutlineNodeArray.push_back(pNd);
+                pNd->GetTextNode()->SetAttrOutlineContentVisible(true);
+            }
         }
-        pSttNd->GetTextNode()->SetAttrOutlineContentVisible(false);
+
+        StartAction();
+        InvalidateOutlineContentVisibility();
+        EndAction();
+
+        // restore outline content visible attribute for folded outline nodes
+        for (SwNode* pNd: aFoldedOutlineNodeArray)
+            pNd->GetTextNode()->SetAttrOutlineContentVisible(false);
     }
+    else
+    {
+        StartAction();
+        InvalidateOutlineContentVisibility();
+        EndAction();
 
-    GetDoc()->GetDocShell()->Broadcast(SfxHint(SfxHintId::DocChanged));
+        // If needed, find visible outline node to place cursor.
+        if (nPos != SwOutlineNodes::npos && !IsOutlineContentVisible(nPos))
+        {
+            while (nPos != SwOutlineNodes::npos && !GetNodes().GetOutLineNds()[nPos]->GetTextNode()->getLayoutFrame(nullptr))
+                --nPos;
+            if (nPos != SwOutlineNodes::npos)
+                GotoOutline(nPos);
+        }
+    }
+}
+
+bool SwWrtShell::GetAttrOutlineContentVisible(const size_t nPos)
+{
+    bool bVisibleAttr = true;
+    GetNodes().GetOutLineNds()[nPos]->GetTextNode()->GetAttrOutlineContentVisible(bVisibleAttr);
+    return bVisibleAttr;
 }
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */


More information about the Libreoffice-commits mailing list