summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMiklos Vajna <vmiklos@collabora.com>2023-01-13 08:20:48 +0100
committerMiklos Vajna <vmiklos@collabora.com>2023-01-13 09:55:20 +0000
commit402ab3d145a1e8e123caabf4567aef7b6631fc3c (patch)
tree6ac57bdfb9293c64b9a3b91d4d4a99cc9c24e706
parent55b534660e3fc99a4e4e07cf05df7798e9ba0726 (diff)
sw: add a new .uno:UpdateField UNO command
This is similar to commit ea208f6004770eb4b81d28e6930cd0c7bd5d8f12 (sw: add a new .uno:UpdateBookmark UNO command, 2023-01-11, but that was for the bookmark under cursor, and this is for fields (refmarks as a start). Change-Id: I3e547b668361898b7ed734ea325fdf1d74e5dbb2 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/145427 Reviewed-by: Miklos Vajna <vmiklos@collabora.com> Tested-by: Jenkins
-rw-r--r--sw/inc/cmdid.h1
-rw-r--r--sw/qa/uibase/shells/shells.cxx52
-rw-r--r--sw/sdi/_basesh.sdi5
-rw-r--r--sw/sdi/swriter.sdi14
-rw-r--r--sw/source/uibase/shells/basesh.cxx104
5 files changed, 176 insertions, 0 deletions
diff --git a/sw/inc/cmdid.h b/sw/inc/cmdid.h
index 3baa2f050ecc..96d935a3bd2e 100644
--- a/sw/inc/cmdid.h
+++ b/sw/inc/cmdid.h
@@ -326,6 +326,7 @@ class SwUINumRuleItem;
#define FN_UPDATE_SECTIONS (FN_INSERT2 + 35)
#define FN_DELETE_TEXT_FORMFIELDS (FN_INSERT2 + 36)
#define FN_UPDATE_BOOKMARK (FN_INSERT2 + 37)
+#define FN_UPDATE_FIELD (FN_INSERT2 + 38)
// Region: Format
#define FN_AUTOFORMAT_APPLY (FN_FORMAT + 1 ) /* apply autoformat options */
diff --git a/sw/qa/uibase/shells/shells.cxx b/sw/qa/uibase/shells/shells.cxx
index 8a7d7fce4f87..22cd709378cb 100644
--- a/sw/qa/uibase/shells/shells.cxx
+++ b/sw/qa/uibase/shells/shells.cxx
@@ -809,6 +809,58 @@ CPPUNIT_TEST_FIXTURE(SwUibaseShellsTest, testUpdateBookmark)
CPPUNIT_ASSERT(it != pDoc->getIDocumentMarkAccess()->getAllMarksEnd());
}
+CPPUNIT_TEST_FIXTURE(SwUibaseShellsTest, testUpdateRefmark)
+{
+ // Given a document with a refmark:
+ createSwDoc();
+ SwDoc* pDoc = getSwDoc();
+ uno::Sequence<css::beans::PropertyValue> aArgs = {
+ comphelper::makePropertyValue("TypeName", uno::Any(OUString("SetRef"))),
+ comphelper::makePropertyValue(
+ "Name", uno::Any(OUString("ZOTERO_ITEM CSL_CITATION {} old refmark"))),
+ comphelper::makePropertyValue("Content", uno::Any(OUString("old content"))),
+ };
+ dispatchCommand(mxComponent, ".uno:InsertField", aArgs);
+
+ // When updating that refmark:
+ std::vector<beans::PropertyValue> aArgsVec = comphelper::JsonToPropertyValues(R"json(
+{
+ "TypeName": {
+ "type": "string",
+ "value": "SetRef"
+ },
+ "NamePrefix": {
+ "type": "string",
+ "value": "ZOTERO_ITEM CSL_CITATION"
+ },
+ "Field": {
+ "type": "[]com.sun.star.beans.PropertyValue",
+ "value": {
+ "Name": {
+ "type": "string",
+ "value": "ZOTERO_ITEM CSL_CITATION {} new refmark"
+ },
+ "Content": {
+ "type": "string",
+ "value": "new content"
+ }
+ }
+ }
+}
+)json");
+ aArgs = comphelper::containerToSequence(aArgsVec);
+ dispatchCommand(mxComponent, ".uno:UpdateField", aArgs);
+
+ // Then make sure that the document text features the new content:
+ SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell();
+ SwTextNode* pTextNode = pWrtShell->GetCursor()->GetPointNode().GetTextNode();
+ // Without the accompanying fix in place, this test would have failed with:
+ // - Expected: new content
+ // - Actual : old content
+ // i.e. the content was not updated.
+ CPPUNIT_ASSERT_EQUAL(OUString("new content"), pTextNode->GetText());
+}
+
CPPUNIT_PLUGIN_IMPLEMENT();
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/sdi/_basesh.sdi b/sw/sdi/_basesh.sdi
index dd195496d1a8..5ac4cb001eb3 100644
--- a/sw/sdi/_basesh.sdi
+++ b/sw/sdi/_basesh.sdi
@@ -154,6 +154,11 @@ interface BaseTextSelection
StateMethod = NoState ;
]
+ FN_UPDATE_FIELD // status(final|play)
+ [
+ ExecMethod = Execute ;
+ ]
+
FN_UPDATE_CHARTS // status(final|play)
[
ExecMethod = Execute ;
diff --git a/sw/sdi/swriter.sdi b/sw/sdi/swriter.sdi
index ebded3b24b72..0a0073ea5020 100644
--- a/sw/sdi/swriter.sdi
+++ b/sw/sdi/swriter.sdi
@@ -6576,6 +6576,20 @@ SfxVoidItem UpdateFields FN_UPDATE_FIELDS
GroupId = SfxGroupId::Edit;
]
+SfxVoidItem UpdateField FN_UPDATE_FIELD
+(SfxStringItem TypeName FN_PARAM_1, SfxStringItem NamePrefix FN_PARAM_2, SfxUnoAnyItem Field FN_PARAM_3)
+[
+ AutoUpdate = FALSE,
+ FastCall = TRUE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ GroupId = SfxGroupId::Edit;
+]
+
SfxVoidItem UpdateInputFields FN_UPDATE_INPUTFIELDS
()
[
diff --git a/sw/source/uibase/shells/basesh.cxx b/sw/source/uibase/shells/basesh.cxx
index d6d4ac2ff8bb..2e7489fda6de 100644
--- a/sw/source/uibase/shells/basesh.cxx
+++ b/sw/source/uibase/shells/basesh.cxx
@@ -882,6 +882,105 @@ bool UpdateFieldContents(SfxRequest& rReq, SwWrtShell& rWrtSh)
pDoc->GetIDocumentUndoRedo().EndUndo(SwUndoId::INSBOOKMARK, nullptr);
return true;
}
+
+/// Searches for the specified field type and field name prefix under cursor and update the matching
+/// field to have the provided new name and content.
+void UpdateFieldContent(SfxRequest& rReq, SwWrtShell& rWrtSh)
+{
+ const SfxStringItem* pTypeName = rReq.GetArg<SfxStringItem>(FN_PARAM_1);
+ if (!pTypeName || pTypeName->GetValue() != "SetRef")
+ {
+ // This is implemented so far only for reference marks.
+ return;
+ }
+
+ const SfxStringItem* pNamePrefix = rReq.GetArg<SfxStringItem>(FN_PARAM_2);
+ if (!pNamePrefix)
+ {
+ return;
+ }
+ const OUString& rNamePrefix = pNamePrefix->GetValue();
+
+ const SfxUnoAnyItem* pField = rReq.GetArg<SfxUnoAnyItem>(FN_PARAM_3);
+ if (!pField)
+ {
+ return;
+ }
+ uno::Sequence<beans::PropertyValue> aField;
+ pField->GetValue() >>= aField;
+
+ SwDoc* pDoc = rWrtSh.GetDoc();
+ pDoc->GetIDocumentUndoRedo().StartUndo(SwUndoId::INSBOOKMARK, nullptr);
+ rWrtSh.StartAction();
+ comphelper::ScopeGuard g(
+ [&rWrtSh]
+ {
+ rWrtSh.EndAction();
+ rWrtSh.GetDoc()->GetIDocumentUndoRedo().EndUndo(SwUndoId::INSBOOKMARK, nullptr);
+ });
+
+ SwPosition& rCursor = *rWrtSh.GetCursor()->GetPoint();
+ SwTextNode* pTextNode = rCursor.GetNode().GetTextNode();
+ std::vector<SwTextAttr*> aAttrs
+ = pTextNode->GetTextAttrsAt(rCursor.GetContentIndex(), RES_TXTATR_REFMARK);
+ if (aAttrs.empty())
+ {
+ return;
+ }
+
+ auto& rRefmark = const_cast<SwFormatRefMark&>(aAttrs[0]->GetRefMark());
+ if (!rRefmark.GetRefName().startsWith(rNamePrefix))
+ {
+ return;
+ }
+
+ comphelper::SequenceAsHashMap aMap(aField);
+ auto aName = aMap["Name"].get<OUString>();
+ rRefmark.GetRefName() = aName;
+
+ 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);
+}
}
// Evaluate respectively dispatching the slot Id
@@ -926,6 +1025,11 @@ void SwBaseShell::Execute(SfxRequest &rReq)
}
}
break;
+ case FN_UPDATE_FIELD:
+ {
+ UpdateFieldContent(rReq, rSh);
+ }
+ break;
case FN_UPDATE_CHARTS:
{
SwWait aWait( *m_rView.GetDocShell(), true );