summaryrefslogtreecommitdiff
path: root/sw
diff options
context:
space:
mode:
Diffstat (limited to 'sw')
-rw-r--r--sw/qa/uibase/shells/shells.cxx55
-rw-r--r--sw/sdi/swriter.sdi2
-rw-r--r--sw/source/uibase/shells/basesh.cxx108
3 files changed, 164 insertions, 1 deletions
diff --git a/sw/qa/uibase/shells/shells.cxx b/sw/qa/uibase/shells/shells.cxx
index 2f89720cf570..0348965b234c 100644
--- a/sw/qa/uibase/shells/shells.cxx
+++ b/sw/qa/uibase/shells/shells.cxx
@@ -532,6 +532,61 @@ CPPUNIT_TEST_FIXTURE(SwUibaseShellsTest, testInsertFieldmarkReadonly)
CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), nActual);
}
+CPPUNIT_TEST_FIXTURE(SwUibaseShellsTest, testUpdateRefmarks)
+{
+ // 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:
+ SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell();
+ pWrtShell->SttEndDoc(/*bStt=*/true);
+ std::vector<beans::PropertyValue> aArgsVec = comphelper::JsonToPropertyValues(R"json(
+{
+ "TypeName": {
+ "type": "string",
+ "value": "SetRef"
+ },
+ "NamePrefix": {
+ "type": "string",
+ "value": "ZOTERO_ITEM CSL_CITATION"
+ },
+ "Fields": {
+ "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:UpdateFields", aArgs);
+
+ // Then make sure that the document text features the new content:
+ 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 doc 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/swriter.sdi b/sw/sdi/swriter.sdi
index e14b52cba879..ebd54c064402 100644
--- a/sw/sdi/swriter.sdi
+++ b/sw/sdi/swriter.sdi
@@ -6514,7 +6514,7 @@ SfxVoidItem UpdateCurIndex FN_UPDATE_CUR_TOX
]
SfxVoidItem UpdateFields FN_UPDATE_FIELDS
-()
+(SfxStringItem TypeName FN_PARAM_1, SfxStringItem NamePrefix FN_PARAM_2, SfxUnoAnyItem Fields FN_PARAM_3)
[
AutoUpdate = FALSE,
FastCall = TRUE,
diff --git a/sw/source/uibase/shells/basesh.cxx b/sw/source/uibase/shells/basesh.cxx
index 5e13fece9132..81eaec0f7c41 100644
--- a/sw/source/uibase/shells/basesh.cxx
+++ b/sw/source/uibase/shells/basesh.cxx
@@ -90,6 +90,7 @@
#include <svx/galleryitem.hxx>
#include <sfx2/devtools/DevelopmentToolChildWindow.hxx>
#include <com/sun/star/gallery/GalleryItemType.hpp>
+#include <com/sun/star/beans/PropertyValues.hpp>
#include <memory>
#include <svx/unobrushitemhelper.hxx>
@@ -98,12 +99,16 @@
#include <osl/diagnose.h>
#include <svx/svxdlg.hxx>
+#include <comphelper/sequenceashashmap.hxx>
#include <shellres.hxx>
#include <UndoTable.hxx>
#include <ndtxt.hxx>
#include <UndoManager.hxx>
+#include <fmtrfmrk.hxx>
+#include <txtrfmrk.hxx>
+#include <translatehelper.hxx>
FlyMode SwBaseShell::s_eFrameMode = FLY_DRAG_END;
@@ -765,6 +770,102 @@ void SwBaseShell::StateUndo(SfxItemSet &rSet)
}
}
+namespace
+{
+/// Searches for the specified field type and field name prefix and update the matching fields to
+/// have the provided new name and content.
+bool UpdateFieldConents(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 false;
+ }
+
+ const SfxStringItem* pNamePrefix = rReq.GetArg<SfxStringItem>(FN_PARAM_2);
+ if (!pNamePrefix)
+ {
+ return false;
+ }
+ const OUString& rNamePrefix = pNamePrefix->GetValue();
+
+ const SfxUnoAnyItem* pFields = rReq.GetArg<SfxUnoAnyItem>(FN_PARAM_3);
+ if (!pFields)
+ {
+ return false;
+ }
+ uno::Sequence<beans::PropertyValues> aFields;
+ pFields->GetValue() >>= aFields;
+
+ SwDoc* pDoc = rWrtSh.GetDoc();
+ pDoc->GetIDocumentUndoRedo().StartUndo(SwUndoId::INSBOOKMARK, nullptr);
+ rWrtSh.StartAction();
+ for (sal_uInt16 nRefMark = 0; nRefMark < pDoc->GetRefMarks(); ++nRefMark)
+ {
+ auto pRefMark = const_cast<SwFormatRefMark*>(pDoc->GetRefMark(nRefMark));
+ if (!pRefMark->GetRefName().startsWith(rNamePrefix))
+ {
+ continue;
+ }
+
+ if (aFields.getLength() <= nRefMark)
+ {
+ continue;
+ }
+ comphelper::SequenceAsHashMap aMap(aFields[nRefMark]);
+ auto aName = aMap["Name"].get<OUString>();
+ pRefMark->GetRefName() = aName;
+
+ 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);
+ }
+ }
+
+ rWrtSh.EndAction();
+ pDoc->GetIDocumentUndoRedo().EndUndo(SwUndoId::INSBOOKMARK, nullptr);
+ return true;
+}
+}
+
// Evaluate respectively dispatching the slot Id
void SwBaseShell::Execute(SfxRequest &rReq)
@@ -787,6 +888,13 @@ void SwBaseShell::Execute(SfxRequest &rReq)
break;
case FN_UPDATE_FIELDS:
{
+ if (UpdateFieldConents(rReq, rSh))
+ {
+ // Parameters indicated that the name / content of fields has to be updated to
+ // the provided values, don't do an actual fields update.
+ break;
+ }
+
rSh.UpdateDocStat();
rSh.EndAllTableBoxEdit();
rSh.SwViewShell::UpdateFields(true);