diff options
author | Miklos Vajna <vmiklos@collabora.com> | 2021-09-27 19:59:54 +0200 |
---|---|---|
committer | Miklos Vajna <vmiklos@collabora.com> | 2021-09-28 08:10:40 +0200 |
commit | 1734e97222324c137ecd084ad2464abdff2698d1 (patch) | |
tree | 34e62cc9f21a5c38c8d07060edcc122d2850f466 /sw | |
parent | e753de4630fb74ac837d0339be23a305f18d0725 (diff) |
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@collabora.com>
Diffstat (limited to 'sw')
-rw-r--r-- | sw/inc/ndtxt.hxx | 6 | ||||
-rw-r--r-- | sw/qa/core/txtnode/data/fly-anchor-undo.odt | bin | 0 -> 10299 bytes | |||
-rw-r--r-- | sw/qa/core/txtnode/txtnode.cxx | 25 | ||||
-rw-r--r-- | sw/source/core/txtnode/ndtxt.cxx | 33 | ||||
-rw-r--r-- | sw/source/core/undo/undel.cxx | 2 |
5 files changed, 54 insertions, 12 deletions
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 Binary files differnew file mode 100644 index 000000000000..dd2093161fa5 --- /dev/null +++ b/sw/qa/core/txtnode/data/fly-anchor-undo.odt 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 |