summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMiklos Vajna <vmiklos@collabora.com>2021-09-27 19:59:54 +0200
committerMiklos Vajna <vmiklos@collabora.com>2021-09-28 08:10:40 +0200
commit1734e97222324c137ecd084ad2464abdff2698d1 (patch)
tree34e62cc9f21a5c38c8d07060edcc122d2850f466
parente753de4630fb74ac837d0339be23a305f18d0725 (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>
-rw-r--r--sw/inc/ndtxt.hxx6
-rw-r--r--sw/qa/core/txtnode/data/fly-anchor-undo.odtbin0 -> 10299 bytes
-rw-r--r--sw/qa/core/txtnode/txtnode.cxx25
-rw-r--r--sw/source/core/txtnode/ndtxt.cxx33
-rw-r--r--sw/source/core/undo/undel.cxx2
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
new file mode 100644
index 000000000000..dd2093161fa5
--- /dev/null
+++ b/sw/qa/core/txtnode/data/fly-anchor-undo.odt
Binary files 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