desktop/source/lib/init.cxx         |    2 
 include/vcl/ITiledRenderable.hxx    |    2 
 sw/inc/cmdid.h                      |    1 
 sw/inc/unotxdoc.hxx                 |    4 -
 sw/qa/uibase/shells/shells.cxx      |   51 +++++++++++++++++++++++++
 sw/qa/uibase/uno/uno.cxx            |   28 +++++++++++++
 sw/sdi/_textsh.sdi                  |    6 ++
 sw/sdi/swriter.sdi                  |   14 ++++++
 sw/source/uibase/shells/textsh1.cxx |   73 ++++++++++++++++++++++++++++++++++++
 sw/source/uibase/uno/loktxdoc.cxx   |   42 +++++++++++++++++++-
 10 files changed, 216 insertions(+), 7 deletions(-)

New commits:
commit 9f5bf1d44460fbff958c15bbe86d791050dcf1f1
Author:     Pranam Lashkari <lpra...@collabora.com>
AuthorDate: Wed Jan 11 08:14:55 2023 +0530
Commit:     Miklos Vajna <vmik...@collabora.com>
CommitDate: Wed Feb 1 08:39:49 2023 +0100

    sw: rename .uno:UpdateSections command fields
    
    renamed fields name in JSON to be consistent with section insertion and 
getter
    
    (cherry picked from commit 92deea6301a02f5530f17263f58402344f82013c)
    
    Change-Id: Icca0be155542b7dc6df1b29e6c7d4191db8659ac

diff --git a/sw/qa/uibase/shells/shells.cxx b/sw/qa/uibase/shells/shells.cxx
index 261a363f12f9..93f9351313af 100644
--- a/sw/qa/uibase/shells/shells.cxx
+++ b/sw/qa/uibase/shells/shells.cxx
@@ -675,11 +675,11 @@ CPPUNIT_TEST_FIXTURE(SwUibaseShellsTest, 
testUpdateSections)
         "type": "[][]com.sun.star.beans.PropertyValue",
         "value": [
             {
-                "Section": {
+                "RegionName": {
                     "type": "string",
                     "value": "ZOTERO_BIBL {} CSL_BIBLIOGRAPHY RNDnew"
                 },
-                "SectionText": {
+                "Content": {
                     "type": "string",
                     "value": "new content"
                 }
diff --git a/sw/source/uibase/shells/textsh1.cxx 
b/sw/source/uibase/shells/textsh1.cxx
index 62ec341bdce7..8faa175ce88a 100644
--- a/sw/source/uibase/shells/textsh1.cxx
+++ b/sw/source/uibase/shells/textsh1.cxx
@@ -419,7 +419,7 @@ void UpdateSections(SfxRequest& rReq, SwWrtShell& rWrtSh)
         }
 
         comphelper::SequenceAsHashMap aMap(aSections[nSectionIndex++]);
-        OUString aSectionName = aMap["Section"].get<OUString>();
+        OUString aSectionName = aMap["RegionName"].get<OUString>();
         if (aSectionName != pFormat->GetName())
         {
             const_cast<SwSectionFormat*>(pFormat)->SetFormatName(aSectionName, 
/*bBroadcast=*/true);
@@ -440,7 +440,7 @@ void UpdateSections(SfxRequest& rReq, SwWrtShell& rWrtSh)
             rIDCO.DeleteAndJoin(*pCursorPos);
             rWrtSh.EndSelect();
 
-            OUString aSectionText = aMap["SectionText"].get<OUString>();
+            OUString aSectionText = aMap["Content"].get<OUString>();
             SwTranslateHelper::PasteHTMLToPaM(rWrtSh, pCursorPos, 
aSectionText.toUtf8(), true);
         }
     }
commit 1602275e7717db9c5a49425c6113c0ae45b6765c
Author:     Miklos Vajna <vmik...@collabora.com>
AuthorDate: Tue Jan 10 08:16:47 2023 +0100
Commit:     Miklos Vajna <vmik...@collabora.com>
CommitDate: Wed Feb 1 08:34:53 2023 +0100

    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.
    
    (cherry picked from commit 71a479afb7e9762de930361e6089e23ab8d4af74)
    
    Change-Id: Idde6d5ed1b0f25f40df502bb6b7e7ca590ef9151

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 7457c62806c1..261a363f12f9 100644
--- a/sw/qa/uibase/shells/shells.cxx
+++ b/sw/qa/uibase/shells/shells.cxx
@@ -653,6 +653,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 ca01f0afe7d1..90f60c6f756e 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 d4521ac148b1..e9699450ce80 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 a33f23ed9d2f..62ec341bdce7 100644
--- a/sw/source/uibase/shells/textsh1.cxx
+++ b/sw/source/uibase/shells/textsh1.cxx
@@ -114,6 +114,7 @@
 #include <translatehelper.hxx>
 #include <IDocumentContentOperations.hxx>
 #include <IDocumentUndoRedo.hxx>
+#include <fmtcntnt.hxx>
 
 using namespace ::com::sun::star;
 using namespace com::sun::star::beans;
@@ -381,6 +382,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))
@@ -860,6 +928,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
commit dc89de8c548c4341318d3f2093b569acbb15c5f4
Author:     Miklos Vajna <vmik...@collabora.com>
AuthorDate: Mon Jan 9 15:30:26 2023 +0100
Commit:     Miklos Vajna <vmik...@collabora.com>
CommitDate: Wed Feb 1 08:27:26 2023 +0100

    vcl ITiledRenderable: rename supportsCommandValues() to supportsCommand()
    
    It gets a single command (to determine if using it with
    getCommandValues() is OK or not), so the plural was confusing, as
    mentioned at
    
<https://gerrit.libreoffice.org/c/core/+/145082/5#message-802b1be9194440a3dcee0cad5e54795cbbdea584>.
    
    (cherry picked from commit 913b399a73c4d6dfd2c9f5983f56f612f3262fa7)
    
    Change-Id: Idf3c81aadeaeb3d42a50aba2ac58d5ed4278651f

diff --git a/desktop/source/lib/init.cxx b/desktop/source/lib/init.cxx
index 5d67ac352926..ea5f556d7f65 100644
--- a/desktop/source/lib/init.cxx
+++ b/desktop/source/lib/init.cxx
@@ -5915,7 +5915,7 @@ static char* doc_getCommandValues(LibreOfficeKitDocument* 
pThis, const char* pCo
     {
         return getFontSubset(aCommand.substr(aFontSubset.getLength()));
     }
-    else if 
(pDoc->supportsCommandValues(INetURLObject(OUString::fromUtf8(aCommand)).GetURLPath()))
+    else if 
(pDoc->supportsCommand(INetURLObject(OUString::fromUtf8(aCommand)).GetURLPath()))
     {
         tools::JsonWriter aJsonWriter;
         pDoc->getCommandValues(aJsonWriter, aCommand);
diff --git a/include/vcl/ITiledRenderable.hxx b/include/vcl/ITiledRenderable.hxx
index 7d3f4b7aaf33..d110e33f7e19 100644
--- a/include/vcl/ITiledRenderable.hxx
+++ b/include/vcl/ITiledRenderable.hxx
@@ -370,7 +370,7 @@ public:
     virtual void setPaintTextEdit(bool) {}
 
     /// Decides if it's OK to call getCommandValues(rCommand).
-    virtual bool supportsCommandValues(std::u16string_view /*rCommand*/) { 
return false; }
+    virtual bool supportsCommand(std::u16string_view /*rCommand*/) { return 
false; }
 
     /// Returns a json mapping of the possible values for the given command.
     virtual void getCommandValues(tools::JsonWriter& /*rJsonWriter*/, 
std::string_view /*rCommand*/)
diff --git a/sw/inc/unotxdoc.hxx b/sw/inc/unotxdoc.hxx
index a7bbcb776f44..57cb3ccca589 100644
--- a/sw/inc/unotxdoc.hxx
+++ b/sw/inc/unotxdoc.hxx
@@ -462,8 +462,8 @@ public:
     /// @see vcl::ITiledRenderable::getCommandValues().
     void getCommandValues(tools::JsonWriter& rJsonWriter, std::string_view 
rCommand) override;
 
-    /// @see vcl::ITiledRenderable::supportsCommandValues().
-    bool supportsCommandValues(std::u16string_view rCommand) override;
+    /// @see vcl::ITiledRenderable::supportsCommand().
+    bool supportsCommand(std::u16string_view rCommand) override;
 
     void                        Invalidate();
     void                        Reactivate(SwDocShell* pNewDocShell);
diff --git a/sw/source/uibase/uno/loktxdoc.cxx 
b/sw/source/uibase/uno/loktxdoc.cxx
index 4598daa3031f..b4350bb430de 100644
--- a/sw/source/uibase/uno/loktxdoc.cxx
+++ b/sw/source/uibase/uno/loktxdoc.cxx
@@ -323,7 +323,7 @@ void GetSections(tools::JsonWriter& rJsonWriter, 
SwDocShell* pDocShell,
 }
 }
 
-bool SwXTextDocument::supportsCommandValues(std::u16string_view rCommand)
+bool SwXTextDocument::supportsCommand(std::u16string_view rCommand)
 {
     static const std::initializer_list<std::u16string_view> vForward
         = { u"TextFormFields", u"TextFormField", u"SetDocumentProperties",
commit 83c0b0a77250aaac278cbfe9132c9d4ac8a81d2f
Author:     Miklos Vajna <vmik...@collabora.com>
AuthorDate: Mon Jan 9 13:53:35 2023 +0100
Commit:     Miklos Vajna <vmik...@collabora.com>
CommitDate: Wed Feb 1 08:26:22 2023 +0100

    sw, lok: implement a getCommandValues(Sections)
    
    There was no LOK API to get a list of all sections where the name
    matches a certain prefix.
    
    This is useful in case the API client wants to know what previously
    inserted sections were deleted by the user as part of deleting text
    content.
    
    Add a new getCommandValues(".uno:Sections") that returns the names of
    matching sections. Do not return the section text, assuming that would
    be updated by the API client anyway.
    
    In practice this is needed by Zotero in case it wants to model its
    bibliography items with sections.
    
    (cherry picked from commit 2ddd41b420cea7f1b988f0b8acbca564b2811382)
    
    Change-Id: If4f02d2a27f2328020934b319d30561aeaaf6612

diff --git a/sw/qa/uibase/uno/uno.cxx b/sw/qa/uibase/uno/uno.cxx
index b89b129100cd..0a398aa87555 100644
--- a/sw/qa/uibase/uno/uno.cxx
+++ b/sw/qa/uibase/uno/uno.cxx
@@ -414,6 +414,34 @@ CPPUNIT_TEST_FIXTURE(SwUibaseUnoTest, testGetTextFormField)
                          field.get<std::string>("command"));
 }
 
+CPPUNIT_TEST_FIXTURE(SwUibaseUnoTest, testGetSections)
+{
+    // Given a document with a section:
+    createSwDoc();
+    uno::Sequence<css::beans::PropertyValue> aArgs = {
+        comphelper::makePropertyValue(
+            "RegionName", uno::Any(OUString("ZOTERO_BIBL {} CSL_BIBLIOGRAPHY 
RNDRfiit6mXBc"))),
+        comphelper::makePropertyValue("Content", 
uno::Any(OUString("<p>aaa</p><p>bbb</p>"))),
+    };
+    dispatchCommand(mxComponent, ".uno:InsertSection", aArgs);
+
+    // When asking for a list of section names:
+    tools::JsonWriter aJsonWriter;
+    std::string_view aCommand(".uno:Sections?namePrefix=ZOTERO_BIBL");
+    auto pXTextDocument = dynamic_cast<SwXTextDocument*>(mxComponent.get());
+    pXTextDocument->getCommandValues(aJsonWriter, aCommand);
+
+    // Make sure we find our just inserted section:
+    std::unique_ptr<char[], o3tl::free_delete> 
pJSON(aJsonWriter.extractData());
+    std::stringstream aStream(pJSON.get());
+    boost::property_tree::ptree aTree;
+    boost::property_tree::read_json(aStream, aTree);
+    // Without the accompanying fix in place, this test would have failed with:
+    // - No such node (sections)
+    // i.e. the returned JSON was an empty object.
+    CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), 
aTree.get_child("sections").count(""));
+}
+
 CPPUNIT_PLUGIN_IMPLEMENT();
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/uibase/uno/loktxdoc.cxx 
b/sw/source/uibase/uno/loktxdoc.cxx
index 623da5f049e8..4598daa3031f 100644
--- a/sw/source/uibase/uno/loktxdoc.cxx
+++ b/sw/source/uibase/uno/loktxdoc.cxx
@@ -290,13 +290,44 @@ void GetFields(tools::JsonWriter& rJsonWriter, 
SwDocShell* pDocShell,
         rJsonWriter.put("name", pRefMark->GetRefName());
     }
 }
+
+/// Implements getCommandValues(".uno:Sections").
+///
+/// Parameters:
+///
+/// - namePrefix: field name prefix to not return all sections
+void GetSections(tools::JsonWriter& rJsonWriter, SwDocShell* pDocShell,
+                 const std::map<OUString, OUString>& rArguments)
+{
+    OUString aNamePrefix;
+    {
+        auto it = rArguments.find("namePrefix");
+        if (it != rArguments.end())
+        {
+            aNamePrefix = it->second;
+        }
+    }
+
+    SwDoc* pDoc = pDocShell->GetDoc();
+    tools::ScopedJsonWriterArray aBookmarks = 
rJsonWriter.startArray("sections");
+    for (const auto& pSection : pDoc->GetSections())
+    {
+        if (!pSection->GetName().startsWith(aNamePrefix))
+        {
+            continue;
+        }
+
+        tools::ScopedJsonWriterStruct aProperty = rJsonWriter.startStruct();
+        rJsonWriter.put("name", pSection->GetName());
+    }
+}
 }
 
 bool SwXTextDocument::supportsCommandValues(std::u16string_view rCommand)
 {
     static const std::initializer_list<std::u16string_view> vForward
-        = { u"TextFormFields", u"TextFormField", u"SetDocumentProperties", 
u"Bookmarks",
-            u"Fields" };
+        = { u"TextFormFields", u"TextFormField", u"SetDocumentProperties",
+            u"Bookmarks",      u"Fields",        u"Sections" };
 
     return std::find(vForward.begin(), vForward.end(), rCommand) != 
vForward.end();
 }
@@ -310,6 +341,7 @@ void SwXTextDocument::getCommandValues(tools::JsonWriter& 
rJsonWriter, std::stri
     static constexpr OStringLiteral 
aSetDocumentProperties(".uno:SetDocumentProperties");
     static constexpr OStringLiteral aBookmarks(".uno:Bookmarks");
     static constexpr OStringLiteral aFields(".uno:Fields");
+    static constexpr OStringLiteral aSections(".uno:Sections");
 
     INetURLObject aParser(OUString::fromUtf8(rCommand));
     OUString aArguments = aParser.GetParam();
@@ -353,6 +385,10 @@ void SwXTextDocument::getCommandValues(tools::JsonWriter& 
rJsonWriter, std::stri
     {
         GetFields(rJsonWriter, m_pDocShell, aMap);
     }
+    else if (o3tl::starts_with(rCommand, aSections))
+    {
+        GetSections(rJsonWriter, m_pDocShell, aMap);
+    }
 }
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Reply via email to