summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMatti Tyrväinen <matty@uef.fi>2023-02-13 21:04:56 +0200
committerMiklos Vajna <vmiklos@collabora.com>2023-05-19 12:28:35 +0200
commit384a80fc56e75e3d1ee18ffc303db85490716829 (patch)
treeba0f7b3caa753cc6cbbf8970b7894ce9f136c50b
parent595b42b686b33bbba0eeba1740277b5f6e0f5433 (diff)
tdf#81720 Don't expand Reference Marks
Make Reference Marks behave like nesting attributes such as Hyperlinks. This is described as the ideal behavior in <https://bugs.documentfoundation.org/show_bug.cgi?id=81720#c24> Change-Id: I34ddfb3a6aa0147ba4bc281ebbb6342089b7bd08 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/146941 Reviewed-by: Matti <matty@uef.fi> Tested-by: Jenkins Reviewed-by: Miklos Vajna <vmiklos@collabora.com>
-rw-r--r--sw/inc/txtrfmrk.hxx3
-rw-r--r--sw/qa/core/txtnode/txtnode.cxx41
-rw-r--r--sw/source/core/txtnode/atrref.cxx52
-rw-r--r--sw/source/uibase/shells/basesh.cxx81
4 files changed, 98 insertions, 79 deletions
diff --git a/sw/inc/txtrfmrk.hxx b/sw/inc/txtrfmrk.hxx
index f73f8cf71019..c01387998392 100644
--- a/sw/inc/txtrfmrk.hxx
+++ b/sw/inc/txtrfmrk.hxx
@@ -21,6 +21,8 @@
#include "txatbase.hxx"
+class SwDoc;
+class SwWrtShell;
class SwTextNode;
// Attribute for content-/position references in text.
@@ -37,6 +39,7 @@ public:
virtual const sal_Int32* GetEnd() const override; // SwTextAttr
virtual void SetEnd(sal_Int32) override; // SwTextAttr
+ void UpdateFieldContent(SwDoc* pDoc, SwWrtShell& rWrtSh, OUString aContent);
// get and set TextNode pointer
inline const SwTextNode& GetTextNode() const;
diff --git a/sw/qa/core/txtnode/txtnode.cxx b/sw/qa/core/txtnode/txtnode.cxx
index f99cc3dd54dd..640df69ed211 100644
--- a/sw/qa/core/txtnode/txtnode.cxx
+++ b/sw/qa/core/txtnode/txtnode.cxx
@@ -11,6 +11,7 @@
#include <LibreOfficeKit/LibreOfficeKitEnums.h>
#include <comphelper/lok.hxx>
+#include <comphelper/propertyvalue.hxx>
#include <sfx2/viewsh.hxx>
#include <vcl/gdimtf.hxx>
#include <vcl/scheduler.hxx>
@@ -31,6 +32,7 @@
#include <ndtxt.hxx>
#include <textcontentcontrol.hxx>
#include <swdtflvr.hxx>
+#include <txtrfmrk.hxx>
/// Covers sw/source/core/txtnode/ fixes.
class SwCoreTxtnodeTest : public SwModelTestBase
@@ -219,6 +221,45 @@ CPPUNIT_TEST_FIXTURE(SwCoreTxtnodeTest, testSplitNodeSuperscriptCopy)
CPPUNIT_ASSERT(!aSet.HasItem(RES_CHRATR_ESCAPEMENT));
}
+CPPUNIT_TEST_FIXTURE(SwCoreTxtnodeTest, testDontExpandRefmark)
+{
+ // Given a document with a refmark:
+ createSwDoc();
+
+ uno::Sequence<css::beans::PropertyValue> aArgs = {
+ comphelper::makePropertyValue("TypeName", uno::Any(OUString("SetRef"))),
+ comphelper::makePropertyValue(
+ "Name", uno::Any(OUString("ZOTERO_ITEM CSL_CITATION {} RNDpyJknp173F"))),
+ comphelper::makePropertyValue("Content", uno::Any(OUString("foo"))),
+ };
+ dispatchCommand(mxComponent, ".uno:InsertField", aArgs);
+
+ SwDoc* pDoc = getSwDoc();
+ SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell();
+ SwPosition& rCursor = *pWrtShell->GetCursor()->GetPoint();
+ SwTextNode* pTextNode = rCursor.GetNode().GetTextNode();
+ std::vector<SwTextAttr*> aAttrs
+ = pTextNode->GetTextAttrsAt(rCursor.GetContentIndex(), RES_TXTATR_REFMARK);
+
+ auto& rRefmark = const_cast<SwFormatRefMark&>(aAttrs[0]->GetRefMark());
+ auto pTextRefMark = const_cast<SwTextRefMark*>(rRefmark.GetTextRefMark());
+
+ // When typing after the refmark...
+ pWrtShell->SttEndDoc(/*bStt=*/true);
+ pWrtShell->Right(SwCursorSkipMode::Chars, /*bSelect=*/false, 3, /*bBasicCall=*/false);
+ pWrtShell->Insert(" bar");
+
+ // and skipping back to insert a comma after the refmark
+ pWrtShell->Left(SwCursorSkipMode::Chars, /*bSelect=*/false, 4, /*bBasicCall=*/false);
+ pWrtShell->Insert(",");
+
+ // Without the accompanying fix in place, this test would have failed with:
+ // - Expected: 3
+ // - Actual : 4
+ // i.e. the reference mark expanded
+ CPPUNIT_ASSERT_EQUAL(3, static_cast<int>(*pTextRefMark->End()));
+}
+
CPPUNIT_TEST_FIXTURE(SwCoreTxtnodeTest, testInsertDropDownContentControlTwice)
{
// Given an already selected dropdown content control:
diff --git a/sw/source/core/txtnode/atrref.cxx b/sw/source/core/txtnode/atrref.cxx
index b93b62e7433a..ffb4509aee70 100644
--- a/sw/source/core/txtnode/atrref.cxx
+++ b/sw/source/core/txtnode/atrref.cxx
@@ -32,6 +32,9 @@
#include <comphelper/lok.hxx>
#include <doc.hxx>
#include <ndtxt.hxx>
+#include <pam.hxx>
+#include <translatehelper.hxx>
+#include <wrtsh.hxx>
SwFormatRefMark::~SwFormatRefMark( )
{
@@ -118,6 +121,8 @@ SwTextRefMark::SwTextRefMark( SwFormatRefMark& rAttr,
}
SetDontMoveAttr( true );
SetOverlapAllowedAttr( true );
+ SetDontExpand( true ); // like hyperlinks, reference markers shouldn't expand
+ SetLockExpandFlag( true ); // protect the flag
}
SwTextRefMark::~SwTextRefMark()
@@ -153,6 +158,53 @@ void SwTextRefMark::SetEnd(sal_Int32 n)
m_pHints->EndPosChanged();
}
+void SwTextRefMark::UpdateFieldContent(SwDoc* pDoc, SwWrtShell& rWrtSh, OUString aContent)
+{
+ if (!this->End())
+ {
+ return;
+ }
+
+ // Insert markers to remember where the paste positions are.
+ const SwTextNode& rTextNode = this->GetTextNode();
+ SwPaM aMarkers(SwPosition(rTextNode, *this->End()));
+ IDocumentContentOperations& rIDCO = pDoc->getIDocumentContentOperations();
+ this->SetLockExpandFlag(false);
+ this->SetDontExpand(false);
+ if (rIDCO.InsertString(aMarkers, "XY"))
+ {
+ SwPaM aPasteEnd(SwPosition(rTextNode, *this->End()));
+ aPasteEnd.Move(fnMoveBackward, GoInContent);
+
+ // Paste HTML content.
+ SwPaM* pCursorPos = rWrtSh.GetCursor();
+ *pCursorPos = aPasteEnd;
+ SwTranslateHelper::PasteHTMLToPaM(rWrtSh, pCursorPos, aContent.toUtf8(), true);
+
+ // Update the refmark to point to the new content.
+ sal_Int32 nOldStart = this->GetStart();
+ sal_Int32 nNewStart = *this->End();
+ // First grow it to include text till the end of the paste position.
+ this->SetEnd(aPasteEnd.GetPoint()->GetContentIndex());
+ // Then shrink it to only start at the paste start: we know that the refmark was
+ // truncated to the paste start, as the refmark has to stay inside a single text node
+ this->SetStart(nNewStart);
+ rTextNode.GetSwpHints().SortIfNeedBe();
+ SwPaM aEndMarker(*aPasteEnd.GetPoint());
+ aEndMarker.SetMark();
+ aEndMarker.GetMark()->AdjustContent(1);
+ SwPaM aStartMarker(SwPosition(rTextNode, nOldStart), SwPosition(rTextNode, nNewStart));
+
+ // Remove markers. The start marker includes the old content as well.
+ rIDCO.DeleteAndJoin(aStartMarker);
+ rIDCO.DeleteAndJoin(aEndMarker);
+ }
+ // Restore flags.
+ this->SetDontExpand(true);
+ this->SetLockExpandFlag(true);
+}
+
+
void SwTextRefMark::dumpAsXml(xmlTextWriterPtr pWriter) const
{
(void)xmlTextWriterStartElement(pWriter, BAD_CAST("SwTextRefMark"));
diff --git a/sw/source/uibase/shells/basesh.cxx b/sw/source/uibase/shells/basesh.cxx
index 4add92e90068..9b917005bfed 100644
--- a/sw/source/uibase/shells/basesh.cxx
+++ b/sw/source/uibase/shells/basesh.cxx
@@ -840,45 +840,7 @@ bool UpdateFieldContents(SfxRequest& rReq, SwWrtShell& rWrtSh)
OUString aContent = aMap["Content"].get<OUString>();
auto pTextRefMark = const_cast<SwTextRefMark*>(pRefMark->GetTextRefMark());
- if (!pTextRefMark->End())
- {
- continue;
- }
-
- // Insert markers to remember where the paste positions are.
- const SwTextNode& rTextNode = pTextRefMark->GetTextNode();
- SwPaM aMarkers(SwPosition(rTextNode, *pTextRefMark->End()));
- IDocumentContentOperations& rIDCO = pDoc->getIDocumentContentOperations();
- pTextRefMark->SetDontExpand(false);
- bool bSuccess = rIDCO.InsertString(aMarkers, "XY");
- if (bSuccess)
- {
- SwPaM aPasteEnd(SwPosition(rTextNode, *pTextRefMark->End()));
- aPasteEnd.Move(fnMoveBackward, GoInContent);
-
- // Paste HTML content.
- SwPaM* pCursorPos = rWrtSh.GetCursor();
- *pCursorPos = aPasteEnd;
- SwTranslateHelper::PasteHTMLToPaM(rWrtSh, pCursorPos, aContent.toUtf8(), true);
-
- // Update the refmark to point to the new content.
- sal_Int32 nOldStart = pTextRefMark->GetStart();
- sal_Int32 nNewStart = *pTextRefMark->End();
- // First grow it to include text till the end of the paste position.
- pTextRefMark->SetEnd(aPasteEnd.GetPoint()->GetContentIndex());
- // Then shrink it to only start at the paste start: we know that the refmark was
- // truncated to the paste start, as the refmark has to stay inside a single text node
- pTextRefMark->SetStart(nNewStart);
- rTextNode.GetSwpHints().SortIfNeedBe();
- SwPaM aEndMarker(*aPasteEnd.GetPoint());
- aEndMarker.SetMark();
- aEndMarker.GetMark()->AdjustContent(1);
- SwPaM aStartMarker(SwPosition(rTextNode, nOldStart), SwPosition(rTextNode, nNewStart));
-
- // Remove markers. The start marker includes the old content as well.
- rIDCO.DeleteAndJoin(aStartMarker);
- rIDCO.DeleteAndJoin(aEndMarker);
- }
+ pTextRefMark->UpdateFieldContent(pDoc, rWrtSh, aContent);
}
rWrtSh.EndAction();
@@ -945,46 +907,7 @@ void UpdateFieldContent(SfxRequest& rReq, SwWrtShell& rWrtSh)
OUString aContent = aMap["Content"].get<OUString>();
auto pTextRefMark = const_cast<SwTextRefMark*>(rRefmark.GetTextRefMark());
- if (!pTextRefMark->End())
- {
- return;
- }
-
- // Insert markers to remember where the paste positions are.
- const SwTextNode& rTextNode = pTextRefMark->GetTextNode();
- SwPaM aMarkers(SwPosition(rTextNode, *pTextRefMark->End()));
- IDocumentContentOperations& rIDCO = pDoc->getIDocumentContentOperations();
- pTextRefMark->SetDontExpand(false);
- if (!rIDCO.InsertString(aMarkers, "XY"))
- {
- return;
- }
-
- SwPaM aPasteEnd(SwPosition(rTextNode, *pTextRefMark->End()));
- aPasteEnd.Move(fnMoveBackward, GoInContent);
-
- // Paste HTML content.
- SwPaM* pCursorPos = rWrtSh.GetCursor();
- *pCursorPos = aPasteEnd;
- SwTranslateHelper::PasteHTMLToPaM(rWrtSh, pCursorPos, aContent.toUtf8(), true);
-
- // Update the refmark to point to the new content.
- sal_Int32 nOldStart = pTextRefMark->GetStart();
- sal_Int32 nNewStart = *pTextRefMark->End();
- // First grow it to include text till the end of the paste position.
- pTextRefMark->SetEnd(aPasteEnd.GetPoint()->GetContentIndex());
- // Then shrink it to only start at the paste start: we know that the refmark was
- // truncated to the paste start, as the refmark has to stay inside a single text node
- pTextRefMark->SetStart(nNewStart);
- rTextNode.GetSwpHints().SortIfNeedBe();
- SwPaM aEndMarker(*aPasteEnd.GetPoint());
- aEndMarker.SetMark();
- aEndMarker.GetMark()->AdjustContent(1);
- SwPaM aStartMarker(SwPosition(rTextNode, nOldStart), SwPosition(rTextNode, nNewStart));
-
- // Remove markers. The start marker includes the old content as well.
- rIDCO.DeleteAndJoin(aStartMarker);
- rIDCO.DeleteAndJoin(aEndMarker);
+ pTextRefMark->UpdateFieldContent(pDoc, rWrtSh, aContent);
}
}