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

Miklos Vajna (via logerrit) logerrit at kemper.freedesktop.org
Tue Sep 28 06:11:14 UTC 2021


 sw/inc/ndtxt.hxx                            |    6 +++++
 sw/qa/core/txtnode/data/fly-anchor-undo.odt |binary
 sw/qa/core/txtnode/txtnode.cxx              |   25 +++++++++++++++++++++
 sw/source/core/txtnode/ndtxt.cxx            |   33 +++++++++++++++++-----------
 sw/source/core/undo/undel.cxx               |    2 +
 5 files changed, 54 insertions(+), 12 deletions(-)

New commits:
commit 1734e97222324c137ecd084ad2464abdff2698d1
Author:     Miklos Vajna <vmiklos at collabora.com>
AuthorDate: Mon Sep 27 19:59:54 2021 +0200
Commit:     Miklos Vajna <vmiklos at collabora.com>
CommitDate: Tue Sep 28 08:10:40 2021 +0200

    tdf#143819 sw: fix undo not restoring adjusted anchor
    
    Regression from commit 0a4d77f35e96e4dfdf69cc5ceb788ddaa849084c
    (SwTxtNode::Update: don't move anchors at insert position, 2014-10-06),
    the problem is that in case backspace adjusts the anchor point of a fly
    and undo does an insert (which now doesn't adjust the anchor point),
    then the user action and its undo is not in sync.
    
    Fix this by informing SwTextNode::Update() if an undo is in progress and
    doing the old behavior in that case.
    
    Change-Id: I0b3f3954be11420846f84287e486b993b2dc39e8
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/122727
    Tested-by: Jenkins
    Reviewed-by: Miklos Vajna <vmiklos at collabora.com>

diff --git a/sw/inc/ndtxt.hxx b/sw/inc/ndtxt.hxx
index 6b64fdef8b19..d3320d995d06 100644
--- a/sw/inc/ndtxt.hxx
+++ b/sw/inc/ndtxt.hxx
@@ -117,6 +117,9 @@ class SW_DLLPUBLIC SwTextNode final
        Needed to avoid duplicate handling of attribute change actions. */
     bool mbInSetOrResetAttr;
 
+    /// Is an undo operation in progress?
+    bool m_bInUndo;
+
     std::optional< OUString > m_oNumStringCache;
 
     css::uno::WeakReference<css::text::XTextContent> m_wXParagraph;
@@ -790,6 +793,7 @@ public:
     /// sfx2::Metadatable
     virtual ::sfx2::IXmlIdRegistry& GetRegistry() override;
     virtual bool IsInClipboard() const override;
+    /// Is this node in the undo array?
     virtual bool IsInUndo() const override;
     virtual bool IsInContent() const override;
     virtual css::uno::Reference< css::rdf::XMetadatable > MakeUnoObject() override;
@@ -811,6 +815,8 @@ public:
     static bool IsIgnoredCharFormatForNumbering(const sal_uInt16 nWhich, bool bIsCharStyle = false);
     void FormatDropNotify(const SwFormatDrop& rDrop) override
             { TriggerNodeUpdate(sw::LegacyModifyHint(&rDrop, &rDrop)); };
+
+    void SetInSwUndo(bool bInUndo);
 };
 
 inline SwpHints & SwTextNode::GetSwpHints()
diff --git a/sw/qa/core/txtnode/data/fly-anchor-undo.odt b/sw/qa/core/txtnode/data/fly-anchor-undo.odt
new file mode 100644
index 000000000000..dd2093161fa5
Binary files /dev/null and b/sw/qa/core/txtnode/data/fly-anchor-undo.odt differ
diff --git a/sw/qa/core/txtnode/txtnode.cxx b/sw/qa/core/txtnode/txtnode.cxx
index f4bb070ac972..5b43ee8591f0 100644
--- a/sw/qa/core/txtnode/txtnode.cxx
+++ b/sw/qa/core/txtnode/txtnode.cxx
@@ -154,6 +154,31 @@ CPPUNIT_TEST_FIXTURE(SwCoreTxtnodeTest, testTitleFieldInvalidate)
     comphelper::LibreOfficeKit::setActive(false);
 }
 
+CPPUNIT_TEST_FIXTURE(SwCoreTxtnodeTest, testFlyAnchorUndo)
+{
+    // Given a document with a fly frame, anchored after the last char of the document:
+    load(DATA_DIRECTORY, "fly-anchor-undo.odt");
+    SwXTextDocument* pTextDoc = dynamic_cast<SwXTextDocument*>(mxComponent.get());
+    SwDocShell* pShell = pTextDoc->GetDocShell();
+    SwDoc* pDoc = pShell->GetDoc();
+    const SwFrameFormats& rSpz = *pDoc->GetSpzFrameFormats();
+    sal_Int32 nExpected = rSpz[0]->GetAnchor().GetContentAnchor()->nContent.GetIndex();
+
+    // When deleting that last character and undoing it:
+    SwWrtShell* pWrtShell = pShell->GetWrtShell();
+    pWrtShell->SttEndDoc(/*bStt=*/false);
+    pWrtShell->DelLeft();
+    pWrtShell->Undo();
+
+    // Then make sure the anchor position after the undo is the same as the original:
+    sal_Int32 nActual = rSpz[0]->GetAnchor().GetContentAnchor()->nContent.GetIndex();
+    // Without the accompanying fix in place, this test would have failed with:
+    // - Expected: 3
+    // - Actual  : 2
+    // i.e. the anchor position was left unchanged by the undo.
+    CPPUNIT_ASSERT_EQUAL(nExpected, nActual);
+}
+
 CPPUNIT_PLUGIN_IMPLEMENT();
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/core/txtnode/ndtxt.cxx b/sw/source/core/txtnode/ndtxt.cxx
index 05548bb3e69b..8d5a58eccb25 100644
--- a/sw/source/core/txtnode/ndtxt.cxx
+++ b/sw/source/core/txtnode/ndtxt.cxx
@@ -194,7 +194,8 @@ SwTextNode::SwTextNode( const SwNodeIndex &rWhere, SwTextFormatColl *pTextColl,
     m_bLastOutlineState( false ),
     m_bNotifiable( false ),
     mbEmptyListStyleSetDueToSetOutlineLevelAttr( false ),
-    mbInSetOrResetAttr( false )
+    mbInSetOrResetAttr( false ),
+    m_bInUndo(false)
 {
     InitSwParaStatistics( true );
 
@@ -1426,20 +1427,23 @@ void SwTextNode::Update(
         }
 
         // at-char anchored flys shouldn't be moved, either.
-        std::vector<SwFrameFormat*> const& rFlys(GetAnchoredFlys());
-        for (size_t i = 0; i != rFlys.size(); ++i)
+        if (!m_bInUndo)
         {
-            SwFrameFormat const*const pFormat = rFlys[i];
-            const SwFormatAnchor& rAnchor = pFormat->GetAnchor();
-            const SwPosition* pContentAnchor = rAnchor.GetContentAnchor();
-            if (rAnchor.GetAnchorId() == RndStdIds::FLY_AT_CHAR && pContentAnchor)
+            std::vector<SwFrameFormat*> const& rFlys(GetAnchoredFlys());
+            for (size_t i = 0; i != rFlys.size(); ++i)
             {
-                // The fly is at-char anchored and has an anchor position.
-                SwIndex& rEndIdx = const_cast<SwIndex&>(pContentAnchor->nContent);
-                if (&pContentAnchor->nNode.GetNode() == this && rEndIdx.GetIndex() == rPos.GetIndex())
+                SwFrameFormat const*const pFormat = rFlys[i];
+                const SwFormatAnchor& rAnchor = pFormat->GetAnchor();
+                const SwPosition* pContentAnchor = rAnchor.GetContentAnchor();
+                if (rAnchor.GetAnchorId() == RndStdIds::FLY_AT_CHAR && pContentAnchor)
                 {
-                    // The anchor position is exactly our insert position.
-                    rEndIdx.Assign(&aTmpIdxReg, rEndIdx.GetIndex());
+                    // The fly is at-char anchored and has an anchor position.
+                    SwIndex& rEndIdx = const_cast<SwIndex&>(pContentAnchor->nContent);
+                    if (&pContentAnchor->nNode.GetNode() == this && rEndIdx.GetIndex() == rPos.GetIndex())
+                    {
+                        // The anchor position is exactly our insert position.
+                        rEndIdx.Assign(&aTmpIdxReg, rEndIdx.GetIndex());
+                    }
                 }
             }
         }
@@ -4859,6 +4863,11 @@ bool SwTextNode::SetAttr( const SfxItemSet& rSet )
     return bRet;
 }
 
+void SwTextNode::SetInSwUndo(bool bInUndo)
+{
+    m_bInUndo = bInUndo;
+}
+
 namespace {
     // Helper class for special handling of resetting attributes at text node:
     // In constructor an instance of the helper class recognize whose attributes
diff --git a/sw/source/core/undo/undel.cxx b/sw/source/core/undo/undel.cxx
index f3fbf5eac553..790dd2e3ea67 100644
--- a/sw/source/core/undo/undel.cxx
+++ b/sw/source/core/undo/undel.cxx
@@ -1015,8 +1015,10 @@ void SwUndoDelete::UndoImpl(::sw::UndoRedoContext & rContext)
                 // SectionNode mode and selection from top to bottom:
                 //  -> in StartNode is still the rest of the Join => delete
                 aPos.nContent.Assign( pTextNd, m_nSttContent );
+                pTextNd->SetInSwUndo(true);
                 OUString const ins( pTextNd->InsertText(*m_aSttStr, aPos.nContent,
                         SwInsertFlags::NOHINTEXPAND) );
+                pTextNd->SetInSwUndo(false);
                 assert(ins.getLength() == m_aSttStr->getLength()); // must succeed
                 (void) ins;
                 // METADATA: restore


More information about the Libreoffice-commits mailing list