sw/qa/uitest/writer_tests7/tdf46561.py |   13 +++++
 sw/source/core/doc/docdesc.cxx         |   84 +++++++++++++++++++++++++++++++++
 2 files changed, 97 insertions(+)

New commits:
commit a456306df9d66e109a807a4245256b341e81040b
Author:     Daniel Arato (NISZ) <arato.dan...@nisz.hu>
AuthorDate: Mon Apr 26 15:04:17 2021 +0200
Commit:     Tünde Tóth <toth.tu...@nisz.hu>
CommitDate: Thu Oct 21 13:06:43 2021 +0200

    tdf#141613 sw: fix crash at header/footer undo
    
    Undoing the creation of a header/footer used to leave their
    corresponding document nodes intact, causing the node index
    of a previous undo entry to point to the wrong node.
    
    We now force the destruction of the header/footer nodes manually.
    We also cut the redo chain which loses the redo history, but solves
    another crash for now (when redoing the creation of the header).
    
    The proper solution would be to create a new SwUndo* derived class
    from scratch to represent the creation of a new header/footer section
    in the document.
    
    Regression from commit 8d8486f43c1a8a51157bfc3e0b87090b05a9229e
    (tdf#46561 sw: fix lost undo stack setting header/footer)
    
    Change-Id: I97188aa8ded802bc6b6fa88ddd83a95c40de8bc3
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/114667
    Tested-by: László Németh <nem...@numbertext.org>
    Reviewed-by: László Németh <nem...@numbertext.org>
    (cherry picked from commit 65e52cb61d74b0c71b45b63b2da131bc6b621104)
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/123976
    Tested-by: Tünde Tóth <toth.tu...@nisz.hu>
    Reviewed-by: Tünde Tóth <toth.tu...@nisz.hu>

diff --git a/sw/qa/uitest/writer_tests7/tdf46561.py 
b/sw/qa/uitest/writer_tests7/tdf46561.py
index 235136524903..02760cf76d96 100644
--- a/sw/qa/uitest/writer_tests7/tdf46561.py
+++ b/sw/qa/uitest/writer_tests7/tdf46561.py
@@ -102,4 +102,17 @@ class tdf46561(UITestCase):
 
         self.ui_test.close_doc()
 
+    # Check that former crash has been fixed
+    def test_tdf141613(self):
+        self.ui_test.create_doc_in_start_center("writer")
+
+        xWriterDoc = self.xUITest.getTopFocusWindow()
+        xWriterEdit = xWriterDoc.getChild("writer_edit")
+
+        xArgs = mkPropertyValues({"Text": "something"})
+        self.xUITest.executeCommandWithParameters(".uno:InsertText", xArgs)
+        self.xUITest.executeCommand(".uno:InsertPageHeader")
+        self.xUITest.executeCommand(".uno:Undo")
+        self.xUITest.executeCommand(".uno:Undo")
+
 # vim: set shiftwidth=4 softtabstop=4 expandtab:
diff --git a/sw/source/core/doc/docdesc.cxx b/sw/source/core/doc/docdesc.cxx
index a85975eac359..164404ce3016 100644
--- a/sw/source/core/doc/docdesc.cxx
+++ b/sw/source/core/doc/docdesc.cxx
@@ -419,6 +419,90 @@ void SwDoc::ChgPageDesc( size_t i, const SwPageDesc 
&rChged )
 
         
GetIDocumentUndoRedo().AppendUndo(std::make_unique<SwUndoPageDesc>(rDesc, 
rChged, this));
     }
+    else
+    {
+        SwUndoId nBeingUndone;
+        GetIDocumentUndoRedo().GetFirstRedoInfo(nullptr, &nBeingUndone);
+        if (SwUndoId::HEADER_FOOTER == nBeingUndone)
+        {
+            // The last format change is currently being undone. Remove 
header/footer and corresponding nodes.
+            auto rDescMasterHeaderFormat = 
rDesc.GetMaster().GetFormatAttr(RES_HEADER);
+            auto rDescLeftHeaderFormat = 
rDesc.GetLeft().GetFormatAttr(RES_HEADER);
+            auto rDescFirstLeftHeaderFormat = 
rDesc.GetFirstLeft().GetFormatAttr(RES_HEADER);
+            auto rDescMasterFooterFormat = 
rDesc.GetMaster().GetFormatAttr(RES_FOOTER);
+            auto rDescLeftFooterFormat = 
rDesc.GetLeft().GetFormatAttr(RES_FOOTER);
+            auto rDescFirstLeftFooterFormat = 
rDesc.GetFirstLeft().GetFormatAttr(RES_FOOTER);
+
+            auto rChgedMasterHeaderFormat = 
rChged.GetMaster().GetFormatAttr(RES_HEADER);
+            auto rChgedLeftHeaderFormat = 
rChged.GetLeft().GetFormatAttr(RES_HEADER);
+            auto rChgedFirstLeftHeaderFormat = 
rChged.GetFirstLeft().GetFormatAttr(RES_HEADER);
+            auto rChgedMasterFooterFormat = 
rChged.GetMaster().GetFormatAttr(RES_FOOTER);
+            auto rChgedLeftFooterFormat = 
rChged.GetLeft().GetFormatAttr(RES_FOOTER);
+            auto rChgedFirstLeftFooterFormat = 
rChged.GetFirstLeft().GetFormatAttr(RES_FOOTER);
+
+            rDesc.GetMaster().ResetFormatAttr(RES_HEADER);
+            rDesc.GetLeft().ResetFormatAttr(RES_HEADER);
+            rDesc.GetFirstLeft().ResetFormatAttr(RES_HEADER);
+            rDesc.GetMaster().ResetFormatAttr(RES_FOOTER);
+            rDesc.GetLeft().ResetFormatAttr(RES_FOOTER);
+            rDesc.GetFirstLeft().ResetFormatAttr(RES_FOOTER);
+
+            auto lDelHFFormat = [this](SwClient* pToRemove, SwFrameFormat* 
pFormat)
+            {
+                // Code taken from lcl_DelHFFormat
+                pFormat->Remove(pToRemove);
+                SwFormatContent& rCnt = 
const_cast<SwFormatContent&>(pFormat->GetContent());
+                if (rCnt.GetContentIdx())
+                {
+                    SwNode* pNode = nullptr;
+                    {
+                        SwNodeIndex aIdx(*rCnt.GetContentIdx(), 0);
+                        pNode = &aIdx.GetNode();
+                        sal_uInt32 nEnd = pNode->EndOfSectionIndex();
+                        while (aIdx < nEnd)
+                        {
+                            if (pNode->IsContentNode() &&
+                                
static_cast<SwContentNode*>(pNode)->HasWriterListeners())
+                            {
+                                SwCursorShell* pShell = 
SwIterator<SwCursorShell, 
SwContentNode>(*static_cast<SwContentNode*>(pNode)).First();
+                                if (pShell)
+                                {
+                                    pShell->ParkCursor(aIdx);
+                                    aIdx = nEnd - 1;
+                                }
+                            }
+                            ++aIdx;
+                            pNode = &aIdx.GetNode();
+                        }
+                    }
+                    rCnt.SetNewContentIdx(nullptr);
+
+                    ::sw::UndoGuard const undoGuard(GetIDocumentUndoRedo());
+
+                    assert(pNode);
+                    getIDocumentContentOperations().DeleteSection(pNode);
+                }
+                delete pFormat;
+            };
+
+            if (rDescMasterHeaderFormat.GetHeaderFormat() && 
rDescMasterHeaderFormat != rChgedMasterHeaderFormat)
+                lDelHFFormat(&rDescMasterHeaderFormat, 
rDescMasterHeaderFormat.GetHeaderFormat());
+            else if (rDescLeftHeaderFormat.GetHeaderFormat() && 
rDescLeftHeaderFormat != rChgedLeftHeaderFormat)
+                lDelHFFormat(&rDescLeftHeaderFormat, 
rDescLeftHeaderFormat.GetHeaderFormat());
+            else if (rDescFirstLeftHeaderFormat.GetHeaderFormat() && 
rDescFirstLeftHeaderFormat != rChgedFirstLeftHeaderFormat)
+                lDelHFFormat(&rDescFirstLeftHeaderFormat, 
rDescFirstLeftHeaderFormat.GetHeaderFormat());
+
+            else if (rDescMasterFooterFormat.GetFooterFormat() && 
rDescMasterFooterFormat != rChgedMasterFooterFormat)
+                lDelHFFormat(&rDescMasterFooterFormat, 
rDescMasterFooterFormat.GetFooterFormat());
+            else if (rDescLeftFooterFormat.GetFooterFormat() && 
rDescLeftFooterFormat != rChgedLeftFooterFormat)
+                lDelHFFormat(&rDescLeftFooterFormat, 
rDescLeftFooterFormat.GetFooterFormat());
+            else if (rDescFirstLeftFooterFormat.GetFooterFormat() && 
rDescFirstLeftFooterFormat != rChgedFirstLeftFooterFormat)
+                lDelHFFormat(&rDescFirstLeftFooterFormat, 
rDescFirstLeftFooterFormat.GetFooterFormat());
+
+            // FIXME: Disable redoing this change until we figure out how
+            GetIDocumentUndoRedo().ClearRedo();
+        }
+    }
     ::sw::UndoGuard const undoGuard(GetIDocumentUndoRedo());
 
     // Mirror at first if needed.

Reply via email to