sw/qa/uibase/shells/data/three-changes.fodt | 6 ++++- sw/qa/uibase/shells/shells.cxx | 12 ++++++++--- sw/source/uibase/uno/loktxdoc.cxx | 30 ++++++++++++++++++++++++++++ 3 files changed, 44 insertions(+), 4 deletions(-)
New commits: commit d6e4ffb0cc06e54b1d04441c8ca8f51161c873cf Author: Mike Kaganski <[email protected]> AuthorDate: Fri Sep 19 12:18:39 2025 +0500 Commit: Miklos Vajna <[email protected]> CommitDate: Mon Sep 22 08:54:38 2025 +0200 LOK Extract API: add startPageNumber argument to redline data extraction Allows to obtain page number of starting points of redlines, returned in new startPageNumber field. Since this information requires manipulations with XTextViewCursor, which is expensive, this is made optional, and is off by default. The argument must get "true" value to enable the functionality. Change-Id: I6180eb8789f44cd20d8da277452987df6ebce055 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/191177 Tested-by: Jenkins CollaboraOffice <[email protected]> Reviewed-by: Miklos Vajna <[email protected]> diff --git a/sw/qa/uibase/shells/data/three-changes.fodt b/sw/qa/uibase/shells/data/three-changes.fodt index 0c7072b244a0..ba13bcb58f41 100644 --- a/sw/qa/uibase/shells/data/three-changes.fodt +++ b/sw/qa/uibase/shells/data/three-changes.fodt @@ -2,6 +2,9 @@ <office:document xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" xmlns:fo="urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:style="urn:oasis:names:tc:opendocument:xmlns:style:1.0" xmlns:text="urn:oasis:names:tc:opendocument:xmlns:text:1.0" office:version="1.4" office:mimetype="application/vnd.oasis.opendocument.text"> <office:automatic-styles> + <style:style style:name="P1" style:family="paragraph"> + <style:paragraph-properties fo:break-before="page"/> + </style:style> <style:style style:name="T1" style:family="text"> <style:text-properties fo:font-weight="bold"/> </style:style> @@ -34,7 +37,8 @@ </text:insertion> </text:changed-region> </text:tracked-changes> - <text:p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vestibulum consequat mi quis pretium semper. Proin luctus orci ac neque venenatis, quis commodo dolor posuere. Curabitur dignissim sapien quis cursus egestas. <text:change-start text:change-id="ct2412392131792"/>Donec<text:change-end text:change-id="ct2412392131792"/> blandit auctor arcu, nec <text:change-start text:change-id="ct2412428113776"/><text:span text:style-name="T1">pellentesque</text:span><text:change-end text:change-id="ct2412428113776"/> eros molestie eget. In consectetur aliquam hendrerit. Sed cursus mauris vitae ligula pellentesque, non pellentesque urna aliquet. Fusce placerat mauris enim, nec rutrum purus semper vel. Praesent tincidunt neque eu pellentesque pharetra. Fusce pellentesque est orci.<text:change-start text:change-id="ct2412428117232"/> Sapienti sat.<text:change-end text:change-id="ct2412428117232"/></text:p> + <text:p/> + <text:p text:style-name="P1">Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vestibulum consequat mi quis pretium semper. Proin luctus orci ac neque venenatis, quis commodo dolor posuere. Curabitur dignissim sapien quis cursus egestas. <text:change-start text:change-id="ct2412392131792"/>Donec<text:change-end text:change-id="ct2412392131792"/> blandit auctor arcu, nec <text:change-start text:change-id="ct2412428113776"/><text:span text:style-name="T1">pellentesque</text:span><text:change-end text:change-id="ct2412428113776"/> eros molestie eget. In consectetur aliquam hendrerit. Sed cursus mauris vitae ligula pellentesque, non pellentesque urna aliquet. Fusce placerat mauris enim, nec rutrum purus semper vel. Praesent tincidunt neque eu pellentesque pharetra. Fusce pellentesque est orci.<text:change-start text:change-id="ct2412428117232"/> Sapienti sat.<text:change-end text:change-id="ct2412428117232"/></text:p> </office:text> </office:body> </office:document> \ No newline at end of file diff --git a/sw/qa/uibase/shells/shells.cxx b/sw/qa/uibase/shells/shells.cxx index 2780cce809ff..165eb7589379 100644 --- a/sw/qa/uibase/shells/shells.cxx +++ b/sw/qa/uibase/shells/shells.cxx @@ -921,6 +921,7 @@ CPPUNIT_TEST_FIXTURE(SwUibaseShellsTest, testDocumentStructureExtractRedlines) CPPUNIT_ASSERT_EQUAL("Mike"s, change.get<std::string>("author")); CPPUNIT_ASSERT_EQUAL("Delete “Donec”"s, change.get<std::string>("description")); CPPUNIT_ASSERT_EQUAL(""s, change.get<std::string>("comment")); + CPPUNIT_ASSERT(bool(change.find("startPageNumber") == change.not_found())); auto text_before = change.get<std::string>("textBefore"); CPPUNIT_ASSERT_EQUAL(size_t(200), text_before.size()); CPPUNIT_ASSERT(text_before.ends_with(" egestas. ")); @@ -942,6 +943,7 @@ CPPUNIT_TEST_FIXTURE(SwUibaseShellsTest, testDocumentStructureExtractRedlines) CPPUNIT_ASSERT_EQUAL("Mike"s, change.get<std::string>("author")); CPPUNIT_ASSERT_EQUAL("Attributes changed"s, change.get<std::string>("description")); CPPUNIT_ASSERT_EQUAL(""s, change.get<std::string>("comment")); + CPPUNIT_ASSERT(bool(change.find("startPageNumber") == change.not_found())); auto text_before = change.get<std::string>("textBefore"); CPPUNIT_ASSERT_EQUAL(size_t(200), text_before.size()); CPPUNIT_ASSERT(text_before.ends_with(" arcu, nec ")); @@ -963,6 +965,7 @@ CPPUNIT_TEST_FIXTURE(SwUibaseShellsTest, testDocumentStructureExtractRedlines) CPPUNIT_ASSERT_EQUAL("Mike"s, change.get<std::string>("author")); CPPUNIT_ASSERT_EQUAL("Insert “ Sapienti sat.”"s, change.get<std::string>("description")); CPPUNIT_ASSERT_EQUAL(""s, change.get<std::string>("comment")); + CPPUNIT_ASSERT(bool(change.find("startPageNumber") == change.not_found())); auto text_before = change.get<std::string>("textBefore"); CPPUNIT_ASSERT_EQUAL(size_t(200), text_before.size()); CPPUNIT_ASSERT(text_before.ends_with(" est orci.")); @@ -974,12 +977,12 @@ CPPUNIT_TEST_FIXTURE(SwUibaseShellsTest, testDocumentStructureExtractRedlines) CPPUNIT_ASSERT(bool(it == docStructure.end())); - // 2. Test contextLen filter argument + // 2. Test contextLen and startPageNumber filter arguments { // extract tools::JsonWriter aJsonWriter; - std::string_view aCommand( - ".uno:ExtractDocumentStructure?filter=trackchanges,foo:bar, contextLen: 15,,"); + std::string_view aCommand(".uno:ExtractDocumentStructure?filter=trackchanges,foo:bar, " + "contextLen: 15, startPageNumber :true ,,"); getSwTextDoc()->getCommandValues(aJsonWriter, aCommand); std::stringstream aStream(std::string(aJsonWriter.finishAndGetAsOString())); @@ -996,6 +999,7 @@ CPPUNIT_TEST_FIXTURE(SwUibaseShellsTest, testDocumentStructureExtractRedlines) CPPUNIT_ASSERT(it != docStructure.end()); const auto & [ name, change ] = *it; CPPUNIT_ASSERT_EQUAL("TrackChanges.ByIndex.0"s, name); + CPPUNIT_ASSERT_EQUAL("2"s, change.get<std::string>("startPageNumber")); CPPUNIT_ASSERT_EQUAL("ursus egestas. "s, change.get<std::string>("textBefore")); CPPUNIT_ASSERT_EQUAL(" blandit auctor"s, change.get<std::string>("textAfter")); ++it; @@ -1006,6 +1010,7 @@ CPPUNIT_TEST_FIXTURE(SwUibaseShellsTest, testDocumentStructureExtractRedlines) CPPUNIT_ASSERT(it != docStructure.end()); const auto & [ name, change ] = *it; CPPUNIT_ASSERT_EQUAL("TrackChanges.ByIndex.1"s, name); + CPPUNIT_ASSERT_EQUAL("2"s, change.get<std::string>("startPageNumber")); CPPUNIT_ASSERT_EQUAL("ctor arcu, nec "s, change.get<std::string>("textBefore")); CPPUNIT_ASSERT_EQUAL(" eros molestie "s, change.get<std::string>("textAfter")); ++it; @@ -1016,6 +1021,7 @@ CPPUNIT_TEST_FIXTURE(SwUibaseShellsTest, testDocumentStructureExtractRedlines) CPPUNIT_ASSERT(it != docStructure.end()); const auto & [ name, change ] = *it; CPPUNIT_ASSERT_EQUAL("TrackChanges.ByIndex.2"s, name); + CPPUNIT_ASSERT_EQUAL("2"s, change.get<std::string>("startPageNumber")); CPPUNIT_ASSERT_EQUAL("esque est orci."s, change.get<std::string>("textBefore")); CPPUNIT_ASSERT_EQUAL(""s, change.get<std::string>("textAfter")); ++it; diff --git a/sw/source/uibase/uno/loktxdoc.cxx b/sw/source/uibase/uno/loktxdoc.cxx index 4b6e2216bf07..f5539e48b39b 100644 --- a/sw/source/uibase/uno/loktxdoc.cxx +++ b/sw/source/uibase/uno/loktxdoc.cxx @@ -25,6 +25,7 @@ #include <com/sun/star/beans/XPropertyAccess.hpp> +#include <comphelper/diagnose_ex.hxx> #include <comphelper/sequence.hxx> #include <o3tl/string_view.hxx> #include <tools/json_writer.hxx> @@ -51,7 +52,9 @@ #include <pagefrm.hxx> #include <com/sun/star/text/XTextContent.hpp> +#include <com/sun/star/text/XPageCursor.hpp> #include <com/sun/star/text/XTextEmbeddedObjectsSupplier.hpp> +#include <com/sun/star/text/XTextViewCursorSupplier.hpp> #include <com/sun/star/chart2/XInternalDataProvider.hpp> #include <com/sun/star/chart2/XChartDocument.hpp> #include <com/sun/star/chart/XChartDocument.hpp> @@ -956,6 +959,7 @@ void GetDocStructureTrackChanges(tools::JsonWriter& rJsonWriter, SwDocShell* pDo if (!filterArguments.empty() && !filterArguments.starts_with(u",")) return; // not a correct filter sal_Int16 nContextLen = 200; + bool bPageNumbers = false; for (size_t paramPos = 1; paramPos < filterArguments.size();) { std::u16string_view param = o3tl::getToken(filterArguments, u',', paramPos); @@ -968,11 +972,25 @@ void GetDocStructureTrackChanges(tools::JsonWriter& rJsonWriter, SwDocShell* pDo if (!value.empty()) nContextLen = o3tl::toInt32(value); } + else if (token == u"startPageNumber") + { + bPageNumbers = value == u"true"; + } // else unknown filter argument (maybe from a newer API?) - ignore } SwDoc& rDoc = *pDocShell->GetDoc(); const SwRedlineTable& rTable = rDoc.getIDocumentRedlineAccess().GetRedlineTable(); + uno::Reference<text::XTextCursor> xTextViewCursor; + uno::Reference<text::XPageCursor> xTextPageCursor; + if (bPageNumbers) + { + if (auto xSupplier = pDocShell->GetController().query<text::XTextViewCursorSupplier>()) + { + xTextViewCursor.set(xSupplier->getViewCursor()); + xTextPageCursor.set(xTextViewCursor, uno::UNO_QUERY); + } + } for (size_t i = 0; i < rTable.size(); ++i) { @@ -1001,6 +1019,18 @@ void GetDocStructureTrackChanges(tools::JsonWriter& rJsonWriter, SwDocShell* pDo { auto xCursor = xStart->getText()->createTextCursorByRange(xStart); xCursor->goLeft(nContextLen, /*bExpand*/ true); + if (xTextPageCursor) + { + try + { + xTextViewCursor->gotoRange(xStart, false); + rJsonWriter.put("startPageNumber", xTextPageCursor->getPage()); + } + catch (const uno::Exception&) + { + DBG_UNHANDLED_EXCEPTION("sw.ui"); + } + } rJsonWriter.put("textBefore", xCursor->getString()); } if (xEnd)
