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

Reply via email to