sw/inc/cmdid.h | 1 sw/qa/uibase/shells/shells.cxx | 51 +++++++++++++++++++++++++ sw/sdi/_textsh.sdi | 6 ++ sw/sdi/swriter.sdi | 14 ++++++ sw/source/uibase/shells/textsh1.cxx | 73 ++++++++++++++++++++++++++++++++++++ 5 files changed, 145 insertions(+)
New commits: commit 71a479afb7e9762de930361e6089e23ab8d4af74 Author: Miklos Vajna <vmik...@collabora.com> AuthorDate: Tue Jan 10 08:16:47 2023 +0100 Commit: Miklos Vajna <vmik...@collabora.com> CommitDate: Tue Jan 10 08:11:17 2023 +0000 sw: add a new .uno:UpdateSections command There was LOK API to insert a new section with provided HTML content and to query it, but there was no LOK API to update such created section with new names/contents. This is needed in case Zotero wants to store citations with refmarks, in which case it wants to store the bibliography with sections. Introduce a .uno:UpdateSections UNO command that can do this: the sections will be renamed if necessary & the content will be updated. The content update is reasonably straightforward, because the section always contains at least one empty paragraph, so there is no danger in simply deleting the old content before inserting the new one. This is similar to babba472391d26aed68d7ac31c7a918c08e65256 (sw, UpdateFields: add new TypeName, NamePrefix and Fields parameters, 2023-01-04), but that was for refmarks / citations, this is for sections / bibliography. Change-Id: Idde6d5ed1b0f25f40df502bb6b7e7ca590ef9151 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/145249 Reviewed-by: Miklos Vajna <vmik...@collabora.com> Tested-by: Jenkins diff --git a/sw/inc/cmdid.h b/sw/inc/cmdid.h index 6f51a0e5e855..bec1acbe5446 100644 --- a/sw/inc/cmdid.h +++ b/sw/inc/cmdid.h @@ -323,6 +323,7 @@ class SwUINumRuleItem; #define FN_EDIT_BOOKMARK (FN_INSERT2 + 33 ) /* Bookmark */ #define FN_UPDATE_BOOKMARKS (FN_INSERT2 + 34) +#define FN_UPDATE_SECTIONS (FN_INSERT2 + 35) // 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 841a07993c98..8dbdee89267c 100644 --- a/sw/qa/uibase/shells/shells.cxx +++ b/sw/qa/uibase/shells/shells.cxx @@ -662,6 +662,57 @@ CPPUNIT_TEST_FIXTURE(SwUibaseShellsTest, testUpdateFieldmark) CPPUNIT_ASSERT_EQUAL(OUString("new result 1"), aActual); } +CPPUNIT_TEST_FIXTURE(SwUibaseShellsTest, testUpdateSections) +{ + // Given a document with a section: + createSwDoc(); + uno::Sequence<css::beans::PropertyValue> aArgs = { + comphelper::makePropertyValue("RegionName", + uno::Any(OUString("ZOTERO_BIBL {} CSL_BIBLIOGRAPHY RNDold"))), + comphelper::makePropertyValue("Content", uno::Any(OUString("old content"))), + }; + dispatchCommand(mxComponent, ".uno:InsertSection", aArgs); + + // When updating that section: + std::vector<beans::PropertyValue> aArgsVec = comphelper::JsonToPropertyValues(R"json( +{ + "SectionNamePrefix": { + "type": "string", + "value": "ZOTERO_BIBL" + }, + "Sections": { + "type": "[][]com.sun.star.beans.PropertyValue", + "value": [ + { + "Section": { + "type": "string", + "value": "ZOTERO_BIBL {} CSL_BIBLIOGRAPHY RNDnew" + }, + "SectionText": { + "type": "string", + "value": "new content" + } + } + ] + } +} +)json"); + aArgs = comphelper::containerToSequence(aArgsVec); + dispatchCommand(mxComponent, ".uno:UpdateSections", aArgs); + + // Then make sure that the section is updated: + SwWrtShell* pWrtShell = getSwDocShell()->GetWrtShell(); + pWrtShell->SttEndDoc(/*bStt=*/true); + pWrtShell->EndOfSection(/*bSelect=*/true); + SwCursor* pCursor = pWrtShell->GetCursor(); + OUString aActualResult = pCursor->GetText(); + // Without the accompanying fix in place, this test would have failed with: + // - Expected: new content + // - Actual : old content + // i.e. the content wasn't updated. + CPPUNIT_ASSERT_EQUAL(OUString("new content"), aActualResult); +} + CPPUNIT_PLUGIN_IMPLEMENT(); /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/sdi/_textsh.sdi b/sw/sdi/_textsh.sdi index 6e77c6d15c21..f712ea376776 100644 --- a/sw/sdi/_textsh.sdi +++ b/sw/sdi/_textsh.sdi @@ -152,6 +152,12 @@ interface BaseText StateMethod = GetState ; DisableFlags="SfxDisableFlags::SwOnProtectedCursor"; ] + FN_UPDATE_SECTIONS + [ + ExecMethod = Execute ; + StateMethod = GetState ; + DisableFlags="SfxDisableFlags::SwOnProtectedCursor"; + ] FN_SET_REMINDER [ ExecMethod = Execute ; diff --git a/sw/sdi/swriter.sdi b/sw/sdi/swriter.sdi index 48131d6126f1..bc0c5456aef8 100644 --- a/sw/sdi/swriter.sdi +++ b/sw/sdi/swriter.sdi @@ -2600,6 +2600,20 @@ SfxVoidItem UpdateBookmarks FN_UPDATE_BOOKMARKS GroupId = SfxGroupId::Insert; ] +SfxVoidItem UpdateSections FN_UPDATE_SECTIONS +(SfxStringItem SectionNamePrefix FN_PARAM_1, SfxUnoAnyItem Sections FN_PARAM_2) +[ + AutoUpdate = FALSE, + FastCall = FALSE, + ReadOnlyDoc = FALSE, + Toggle = FALSE, + Container = FALSE, + RecordAbsolute = FALSE, + RecordPerSet; + + GroupId = SfxGroupId::Insert; +] + SfxVoidItem SetReminder FN_SET_REMINDER [ diff --git a/sw/source/uibase/shells/textsh1.cxx b/sw/source/uibase/shells/textsh1.cxx index 400a9d39bce0..df519ed9782b 100644 --- a/sw/source/uibase/shells/textsh1.cxx +++ b/sw/source/uibase/shells/textsh1.cxx @@ -112,6 +112,7 @@ #include <translatehelper.hxx> #include <IDocumentContentOperations.hxx> #include <IDocumentUndoRedo.hxx> +#include <fmtcntnt.hxx> using namespace ::com::sun::star; using namespace com::sun::star::beans; @@ -379,6 +380,73 @@ OUString GetLocalURL(const SwWrtShell& rSh) return rLocalURL; } +void UpdateSections(SfxRequest& rReq, SwWrtShell& rWrtSh) +{ + OUString aSectionNamePrefix; + const SfxStringItem* pSectionNamePrefix = rReq.GetArg<SfxStringItem>(FN_PARAM_1); + if (pSectionNamePrefix) + { + aSectionNamePrefix = pSectionNamePrefix->GetValue(); + } + + uno::Sequence<beans::PropertyValues> aSections; + const SfxUnoAnyItem* pSections = rReq.GetArg<SfxUnoAnyItem>(FN_PARAM_2); + if (pSections) + { + pSections->GetValue() >>= aSections; + } + + rWrtSh.GetDoc()->GetIDocumentUndoRedo().StartUndo(SwUndoId::INSSECTION, nullptr); + rWrtSh.StartAction(); + + SwDoc* pDoc = rWrtSh.GetDoc(); + sal_Int32 nSectionIndex = 0; + const SwSectionFormats& rFormats = pDoc->GetSections(); + IDocumentContentOperations& rIDCO = pDoc->getIDocumentContentOperations(); + for (size_t i = 0; i < rFormats.size(); ++i) + { + const SwSectionFormat* pFormat = rFormats[i]; + if (!pFormat->GetName().startsWith(aSectionNamePrefix)) + { + continue; + } + + if (nSectionIndex >= aSections.getLength()) + { + break; + } + + comphelper::SequenceAsHashMap aMap(aSections[nSectionIndex++]); + OUString aSectionName = aMap["Section"].get<OUString>(); + if (aSectionName != pFormat->GetName()) + { + const_cast<SwSectionFormat*>(pFormat)->SetFormatName(aSectionName, /*bBroadcast=*/true); + SwSectionData aSectionData(*pFormat->GetSection()); + aSectionData.SetSectionName(aSectionName); + pDoc->UpdateSection(i, aSectionData); + } + + const SwFormatContent& rContent = pFormat->GetContent(); + const SwNodeIndex* pContentNodeIndex = rContent.GetContentIdx(); + if (pContentNodeIndex) + { + SwPaM aSectionStart(SwPosition{*pContentNodeIndex}); + aSectionStart.Move(fnMoveForward, GoInContent); + SwPaM* pCursorPos = rWrtSh.GetCursor(); + *pCursorPos = aSectionStart; + rWrtSh.EndOfSection(/*bSelect=*/true); + rIDCO.DeleteAndJoin(*pCursorPos); + rWrtSh.EndSelect(); + + OUString aSectionText = aMap["SectionText"].get<OUString>(); + SwTranslateHelper::PasteHTMLToPaM(rWrtSh, pCursorPos, aSectionText.toUtf8(), true); + } + } + + rWrtSh.EndAction(); + rWrtSh.GetDoc()->GetIDocumentUndoRedo().EndUndo(SwUndoId::INSSECTION, nullptr); +} + void UpdateBookmarks(SfxRequest& rReq, SwWrtShell& rWrtSh) { if (rWrtSh.getIDocumentSettingAccess().get(DocumentSettingId::PROTECT_BOOKMARKS)) @@ -858,6 +926,11 @@ void SwTextShell::Execute(SfxRequest &rReq) } break; } + case FN_UPDATE_SECTIONS: + { + UpdateSections(rReq, rWrtSh); + break; + } case FN_SET_REMINDER: { // collect and sort navigator reminder names