sw/source/uibase/docvw/OutlineContentVisibilityWin.cxx |    3 
 sw/source/uibase/docvw/edtwin.cxx                      |   77 +++++++++++------
 sw/source/uibase/inc/edtwin.hxx                        |    7 -
 3 files changed, 56 insertions(+), 31 deletions(-)

New commits:
commit 492a64a694679bbf0fad2b7ef2a5ca0941f7eed7
Author:     Jim Raykowski <rayk...@gmail.com>
AuthorDate: Tue Dec 28 23:03:59 2021 -0900
Commit:     Jim Raykowski <rayk...@gmail.com>
CommitDate: Tue Jan 4 08:01:31 2022 +0100

    Outline folding: Check frame area is valid before using pointer to
    
    saved outline frame
    
    It seems when a frame is removed it is not immediately destroyed, so a
    pointer to the removed frame may not be a null pointer. This patch
    checks for valid frame area definition before using the save outline
    frame pointer with intention to fix an intermittent crash occurrence
    when an outline paragraph is removed.
    
    Change-Id: I4f9b55acc6aeb83553a3f26c2701159c2ba439a2
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/127717
    Tested-by: Jenkins
    Reviewed-by: Jim Raykowski <rayk...@gmail.com>

diff --git a/sw/source/uibase/docvw/OutlineContentVisibilityWin.cxx 
b/sw/source/uibase/docvw/OutlineContentVisibilityWin.cxx
index 0253e8a93023..3e16a5e0997f 100644
--- a/sw/source/uibase/docvw/OutlineContentVisibilityWin.cxx
+++ b/sw/source/uibase/docvw/OutlineContentVisibilityWin.cxx
@@ -211,7 +211,8 @@ IMPL_LINK(SwOutlineContentVisibilityWin, MouseMoveHdl, 
const MouseEvent&, rMEvt,
                     // for saved outline frame is now disposed.
                 }
             }
-            
GetEditWin()->SetSavedOutlineFrame(const_cast<SwFrame*>(GetFrame()));
+            GetEditWin()->SetSavedOutlineFrame(
+                static_cast<SwTextFrame*>(const_cast<SwFrame*>(GetFrame())));
         }
         if (!m_bDestroyed && m_aDelayTimer.IsActive())
             m_aDelayTimer.Stop();
diff --git a/sw/source/uibase/docvw/edtwin.cxx 
b/sw/source/uibase/docvw/edtwin.cxx
index 85a47603a971..a820f4731fe1 100644
--- a/sw/source/uibase/docvw/edtwin.cxx
+++ b/sw/source/uibase/docvw/edtwin.cxx
@@ -3892,40 +3892,56 @@ void SwEditWin::MouseMove(const MouseEvent& _rMEvt)
         SwContentAtPos aSwContentAtPos(IsAttrAtPos::Outline);
         if (rSh.GetContentAtPos(PixelToLogic(rMEvt.GetPosPixel()), 
aSwContentAtPos))
         {
+            // mouse pointer is on an outline paragraph node
             if(aSwContentAtPos.aFnd.pNode && 
aSwContentAtPos.aFnd.pNode->IsTextNode())
             {
-                SwContentFrame* pContentFrame = 
aSwContentAtPos.aFnd.pNode->GetTextNode()->getLayoutFrame(nullptr);
+                // Get the outline paragraph frame and compare it to the saved 
ouline frame. If they
+                // are not the same, remove the fold button from the saved 
outline frame, if not
+                // already removed, and then add a fold button to the mouse 
over outline frame if
+                // the content is not folded.
+                SwContentFrame* pContentFrame =
+                        
aSwContentAtPos.aFnd.pNode->GetTextNode()->getLayoutFrame(rSh.GetLayout());
                 if (pContentFrame != m_pSavedOutlineFrame)
                 {
-                    if (m_pSavedOutlineFrame && 
!m_pSavedOutlineFrame->IsInDtor())
+                    if (m_pSavedOutlineFrame)
                     {
-                        SwTextNode* pTextNode =
-                                
static_cast<SwTextFrame*>(m_pSavedOutlineFrame)->GetTextNodeFirst();
-                        if (pTextNode && 
rNds.GetOutLineNds().Seek_Entry(pTextNode, &nPos) &&
-                                rSh.GetAttrOutlineContentVisible(nPos))
-                            GetFrameControlsManager().RemoveControlsByType(
-                                        FrameControlType::Outline, 
m_pSavedOutlineFrame);
+                        if (m_pSavedOutlineFrame->isFrameAreaDefinitionValid())
+                        {
+                            SwTextNode* pTextNode = 
m_pSavedOutlineFrame->GetTextNodeFirst();
+                            if (pTextNode && 
rNds.GetOutLineNds().Seek_Entry(pTextNode, &nPos) &&
+                                    rSh.GetAttrOutlineContentVisible(nPos))
+                            {
+                                GetFrameControlsManager().RemoveControlsByType(
+                                            FrameControlType::Outline, 
m_pSavedOutlineFrame);
+                            }
+                        }
                     }
-                    m_pSavedOutlineFrame = pContentFrame;
+                    m_pSavedOutlineFrame = 
static_cast<SwTextFrame*>(pContentFrame);
                 }
-                // show button
+                // show fold button if outline content is visible
                 if 
(rNds.GetOutLineNds().Seek_Entry(aSwContentAtPos.aFnd.pNode->GetTextNode(), 
&nPos) &&
                         rSh.GetAttrOutlineContentVisible(nPos))
                     
GetFrameControlsManager().SetOutlineContentVisibilityButton(pContentFrame);
             }
         }
-        else if (m_pSavedOutlineFrame && !m_pSavedOutlineFrame->IsInDtor())
+        else if (m_pSavedOutlineFrame)
         {
-            // current pointer pos is not over an outline frame
-            // previous pointer pos was over an outline frame
-            // remove outline content visibility button if showing
-            if (m_pSavedOutlineFrame->isFrameAreaDefinitionValid() &&
-                    m_pSavedOutlineFrame->IsTextFrame() &&
-                    rNds.GetOutLineNds().Seek_Entry(
-                        
static_cast<SwTextFrame*>(m_pSavedOutlineFrame)->GetTextNodeFirst(), &nPos)
-                    && rSh.GetAttrOutlineContentVisible(nPos))
-                
GetFrameControlsManager().RemoveControlsByType(FrameControlType::Outline,
-                                                               
m_pSavedOutlineFrame);
+            // The saved frame may not still be in the document, e.g., when an 
outline paragraph
+            // is deleted. This causes the call to GetTextNodeFirst to behave 
badly. Use
+            // isFrameAreaDefinitionValid to check if the frame is still in 
the document.
+            if (m_pSavedOutlineFrame->isFrameAreaDefinitionValid())
+            {
+                // current pointer pos is not over an outline frame
+                // previous pointer pos was over an outline frame
+                // remove outline content visibility button if showing
+                SwTextNode* pTextNode = 
m_pSavedOutlineFrame->GetTextNodeFirst();
+                if (pTextNode && rNds.GetOutLineNds().Seek_Entry(pTextNode, 
&nPos) &&
+                        rSh.GetAttrOutlineContentVisible(nPos))
+                {
+                    GetFrameControlsManager().RemoveControlsByType(
+                                FrameControlType::Outline, 
m_pSavedOutlineFrame);
+                }
+            }
             m_pSavedOutlineFrame = nullptr;
         }
     }
@@ -3968,13 +3984,20 @@ void SwEditWin::MouseMove(const MouseEvent& _rMEvt)
     {
         if (m_pSavedOutlineFrame && !bInsWin)
         {
-            // the mouse pointer has left the building
+            // the mouse pointer has left the building (edit window)
             // remove the outline content visibility 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.GetAttrOutlineContentVisible(nPos))
-                
GetFrameControlsManager().RemoveControlsByType(FrameControlType::Outline, 
m_pSavedOutlineFrame);
+            if (m_pSavedOutlineFrame->isFrameAreaDefinitionValid())
+            {
+                const SwNodes& rNds = rSh.GetDoc()->GetNodes();
+                SwOutlineNodes::size_type nPos;
+                SwTextNode* pTextNode = 
m_pSavedOutlineFrame->GetTextNodeFirst();
+                if (pTextNode && rNds.GetOutLineNds().Seek_Entry(pTextNode, 
&nPos) &&
+                        rSh.GetAttrOutlineContentVisible(nPos))
+                {
+                    
GetFrameControlsManager().RemoveControlsByType(FrameControlType::Outline,
+                                                                   
m_pSavedOutlineFrame);
+                }
+            }
             m_pSavedOutlineFrame = nullptr;
         }
     }
diff --git a/sw/source/uibase/inc/edtwin.hxx b/sw/source/uibase/inc/edtwin.hxx
index 0db0e6d2b35a..108dbfb05307 100644
--- a/sw/source/uibase/inc/edtwin.hxx
+++ b/sw/source/uibase/inc/edtwin.hxx
@@ -45,6 +45,7 @@ struct  QuickHelpData;
 class   SdrDropMarkerOverlay;
 class   SwFrameControlsManager;
 enum class SdrHitKind;
+class SwTextFrame;
 
 // input window
 
@@ -127,7 +128,7 @@ class SW_DLLPUBLIC SwEditWin final : public vcl::Window,
 
     std::unique_ptr<SwFrameControlsManager> m_pFrameControlsManager;
 
-     SwFrame* m_pSavedOutlineFrame = nullptr;
+     SwTextFrame* m_pSavedOutlineFrame = nullptr;
 
     void            LeaveArea(const Point &);
     void            JustifyAreaTimer();
@@ -291,8 +292,8 @@ public:
     /// Allows starting or ending a graphic move or resize action.
     void SetGraphicTwipPosition(bool bStart, const Point& rPosition);
 
-    const SwFrame* GetSavedOutlineFrame() const { return m_pSavedOutlineFrame; 
}
-    void SetSavedOutlineFrame(SwFrame* pFrame) { m_pSavedOutlineFrame = 
pFrame; }
+    const SwTextFrame* GetSavedOutlineFrame() const { return 
m_pSavedOutlineFrame; }
+    void SetSavedOutlineFrame(SwTextFrame* pFrame) { m_pSavedOutlineFrame = 
pFrame; }
     void ToggleOutlineContentVisibility(const size_t nOutlinePos, const bool 
bSubs);
 
     virtual FactoryFunction GetUITestFactory() const override;

Reply via email to