sw/qa/uibase/shells/shells.cxx    |   67 ++++++++++++++++++++++++++++++++++----
 sw/source/uibase/uno/loktxdoc.cxx |   31 ++++++++++++++---
 2 files changed, 86 insertions(+), 12 deletions(-)

New commits:
commit 55a132e59ac1b4fa2e7fc6776928ba12eec13442
Author:     Mike Kaganski <mike.kagan...@collabora.com>
AuthorDate: Mon Jun 30 13:38:51 2025 +0500
Commit:     Mike Kaganski <mike.kagan...@collabora.com>
CommitDate: Mon Jun 30 17:54:48 2025 +0200

    LOK Extract API: add contextLen filter argument to redline data extraction
    
    Allows to specify the length of returned textBefore / textAfter fields.
    
    Change-Id: I17abd72fa063d8033e552e55844bf6b7fc1780d0
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/187189
    Tested-by: Jenkins
    Reviewed-by: Mike Kaganski <mike.kagan...@collabora.com>

diff --git a/sw/qa/uibase/shells/shells.cxx b/sw/qa/uibase/shells/shells.cxx
index 9a467cd89ab0..22da30260421 100644
--- a/sw/qa/uibase/shells/shells.cxx
+++ b/sw/qa/uibase/shells/shells.cxx
@@ -892,14 +892,18 @@ CPPUNIT_TEST_FIXTURE(SwUibaseShellsTest, 
testDocumentStructureExtractRedlines)
 {
     createSwDoc("three-changes.fodt");
 
-    // extract
-    tools::JsonWriter aJsonWriter;
-    std::string_view 
aCommand(".uno:ExtractDocumentStructure?filter=trackchanges");
-    getSwTextDoc()->getCommandValues(aJsonWriter, aCommand);
-
     boost::property_tree::ptree tree;
-    std::stringstream 
aStream(std::string(aJsonWriter.finishAndGetAsOString()));
-    boost::property_tree::read_json(aStream, tree);
+
+    // 1. No filter arguments
+    {
+        // extract
+        tools::JsonWriter aJsonWriter;
+        std::string_view 
aCommand(".uno:ExtractDocumentStructure?filter=trackchanges");
+        getSwTextDoc()->getCommandValues(aJsonWriter, aCommand);
+
+        std::stringstream 
aStream(std::string(aJsonWriter.finishAndGetAsOString()));
+        boost::property_tree::read_json(aStream, tree);
+    }
 
     CPPUNIT_ASSERT_EQUAL(size_t(1), tree.size());
     boost::property_tree::ptree docStructure = tree.get_child("DocStructure");
@@ -969,6 +973,55 @@ CPPUNIT_TEST_FIXTURE(SwUibaseShellsTest, 
testDocumentStructureExtractRedlines)
     }
 
     CPPUNIT_ASSERT(bool(it == docStructure.end()));
+
+    // 2. Test contextLen filter argument
+    {
+        // extract
+        tools::JsonWriter aJsonWriter;
+        std::string_view aCommand(
+            ".uno:ExtractDocumentStructure?filter=trackchanges,foo:bar, 
contextLen: 15,,");
+        getSwTextDoc()->getCommandValues(aJsonWriter, aCommand);
+
+        std::stringstream 
aStream(std::string(aJsonWriter.finishAndGetAsOString()));
+        boost::property_tree::read_json(aStream, tree);
+    }
+
+    CPPUNIT_ASSERT_EQUAL(size_t(1), tree.size());
+    docStructure = tree.get_child("DocStructure");
+    CPPUNIT_ASSERT_EQUAL(size_t(3), docStructure.size());
+    it = docStructure.begin();
+
+    {
+        // First change
+        CPPUNIT_ASSERT(it != docStructure.end());
+        const auto & [ name, change ] = *it;
+        CPPUNIT_ASSERT_EQUAL("TrackChanges.ByIndex.0"s, name);
+        CPPUNIT_ASSERT_EQUAL("ursus egestas. "s, 
change.get<std::string>("textBefore"));
+        CPPUNIT_ASSERT_EQUAL(" blandit auctor"s, 
change.get<std::string>("textAfter"));
+        ++it;
+    }
+
+    {
+        // Second change
+        CPPUNIT_ASSERT(it != docStructure.end());
+        const auto & [ name, change ] = *it;
+        CPPUNIT_ASSERT_EQUAL("TrackChanges.ByIndex.1"s, name);
+        CPPUNIT_ASSERT_EQUAL("ctor arcu, nec "s, 
change.get<std::string>("textBefore"));
+        CPPUNIT_ASSERT_EQUAL(" eros molestie "s, 
change.get<std::string>("textAfter"));
+        ++it;
+    }
+
+    {
+        // Third change
+        CPPUNIT_ASSERT(it != docStructure.end());
+        const auto & [ name, change ] = *it;
+        CPPUNIT_ASSERT_EQUAL("TrackChanges.ByIndex.2"s, name);
+        CPPUNIT_ASSERT_EQUAL("esque est orci."s, 
change.get<std::string>("textBefore"));
+        CPPUNIT_ASSERT_EQUAL(""s, change.get<std::string>("textAfter"));
+        ++it;
+    }
+
+    CPPUNIT_ASSERT(bool(it == docStructure.end()));
 }
 
 CPPUNIT_TEST_FIXTURE(SwUibaseShellsTest, testUpdateRefmarks)
diff --git a/sw/source/uibase/uno/loktxdoc.cxx 
b/sw/source/uibase/uno/loktxdoc.cxx
index c1a905368e34..e638a8142c60 100644
--- a/sw/source/uibase/uno/loktxdoc.cxx
+++ b/sw/source/uibase/uno/loktxdoc.cxx
@@ -855,8 +855,29 @@ void GetDocStructureDocProps(tools::JsonWriter& 
rJsonWriter, const SwDocShell* p
 }
 
 /// Implements getCommandValues(".uno:ExtractDocumentStructures") for redlines
-void GetDocStructureTrackChanges(tools::JsonWriter& rJsonWriter, const 
SwDocShell* pDocShell)
+void GetDocStructureTrackChanges(tools::JsonWriter& rJsonWriter, const 
SwDocShell* pDocShell,
+                                 std::u16string_view filterArguments)
 {
+    // filter arguments are separated from the filter name by comma, and are 
name:value pairs
+    // separated by commas
+    if (!filterArguments.empty() && !filterArguments.starts_with(u","))
+        return; // not a correct filter
+    sal_Int16 nContextLen = 200;
+    for (size_t paramPos = 1; paramPos < filterArguments.size();)
+    {
+        std::u16string_view param = o3tl::getToken(filterArguments, u',', 
paramPos);
+        sal_Int32 nIndex = 0;
+        std::u16string_view token = o3tl::trim(o3tl::getToken(param, 0, u':', 
nIndex));
+        std::u16string_view value
+            = nIndex > 0 ? o3tl::trim(param.substr(nIndex)) : 
std::u16string_view{};
+        if (token == u"contextLen")
+        {
+            if (!value.empty())
+                nContextLen = o3tl::toInt32(value);
+        }
+        // else unknown filter argument (maybe from a newer API?) - ignore
+    }
+
     auto xRedlinesEnum = 
pDocShell->GetBaseModel()->getRedlines()->createEnumeration();
     for (sal_Int32 i = 0; xRedlinesEnum->hasMoreElements(); ++i)
     {
@@ -881,13 +902,13 @@ void GetDocStructureTrackChanges(tools::JsonWriter& 
rJsonWriter, const SwDocShel
         if (xStart)
         {
             auto xCursor = xStart->getText()->createTextCursorByRange(xStart);
-            xCursor->goLeft(200, /*bExpand*/ true);
+            xCursor->goLeft(nContextLen, /*bExpand*/ true);
             rJsonWriter.put("textBefore", xCursor->getString());
         }
         if (xEnd)
         {
             auto xCursor = xEnd->getText()->createTextCursorByRange(xEnd);
-            xCursor->goRight(200, /*bExpand*/ true);
+            xCursor->goRight(nContextLen, /*bExpand*/ true);
             rJsonWriter.put("textAfter", xCursor->getString());
         }
         OUString changeText;
@@ -938,8 +959,8 @@ void GetDocStructure(tools::JsonWriter& rJsonWriter, const 
SwDocShell* pDocShell
     if (filter.isEmpty() || filter == "docprops")
         GetDocStructureDocProps(rJsonWriter, pDocShell);
 
-    if (filter.isEmpty() || filter == "trackchanges")
-        GetDocStructureTrackChanges(rJsonWriter, pDocShell);
+    if (std::u16string_view rest; filter.isEmpty() || 
filter.startsWith("trackchanges", &rest))
+        GetDocStructureTrackChanges(rJsonWriter, pDocShell, o3tl::trim(rest));
 }
 
 /// Implements getCommandValues(".uno:Sections").

Reply via email to