desktop/qa/data/three-changes.fodt          |   40 ++++++
 desktop/qa/desktop_lib/test_desktop_lib.cxx |  162 +++++++++++++++++++++++++++-
 desktop/source/lib/init.cxx                 |   13 ++
 include/LibreOfficeKit/LibreOfficeKit.h     |    3 
 include/LibreOfficeKit/LibreOfficeKit.hxx   |   10 +
 include/sfx2/lokhelper.hxx                  |    2 
 include/sfx2/viewsh.hxx                     |    7 -
 sfx2/source/control/dispatch.cxx            |   16 ++
 sfx2/source/view/lokhelper.cxx              |    9 +
 sw/source/uibase/misc/redlndlg.cxx          |   16 ++
 10 files changed, 271 insertions(+), 7 deletions(-)

New commits:
commit ad4ab7241272da9aee2c8a8228f3bd2a2c64b9ae
Author:     Mike Kaganski <[email protected]>
AuthorDate: Thu Jun 19 11:40:26 2025 +0500
Commit:     Mike Kaganski <[email protected]>
CommitDate: Fri Jun 20 11:15:42 2025 +0200

    LOK: enable dialog controls in AllowManageRedlines mode
    
    The new function takes the "accept all" command state into account,
    which goes through SfxDispatcher::FindServer_, which considers the
    read-only mode for document, view, and all special cases.
    
    Change-Id: I532789dd6886589ab1b6896889fd269909d40204
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/186701
    Tested-by: Jenkins CollaboraOffice <[email protected]>
    Reviewed-by: Miklos Vajna <[email protected]>
    (cherry picked from commit d89d3e73a7a0c43ea700d6bd402081c449573a7f)
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/186736
    Tested-by: Jenkins
    Reviewed-by: Mike Kaganski <[email protected]>

diff --git a/sw/source/uibase/misc/redlndlg.cxx 
b/sw/source/uibase/misc/redlndlg.cxx
index 776b881475de..3e28f4ded579 100644
--- a/sw/source/uibase/misc/redlndlg.cxx
+++ b/sw/source/uibase/misc/redlndlg.cxx
@@ -35,6 +35,7 @@
 #include <swwait.hxx>
 #include <uitool.hxx>
 #include <o3tl/string_view.hxx>
+#include <o3tl/temporary.hxx>
 
 #include <cmdid.h>
 #include <strings.hrc>
@@ -311,6 +312,15 @@ void SwRedlineAcceptDlg::Init(SwRedlineTable::size_type 
nStart)
     lcl_reselect(rTreeView, pSelectedEntryRedlineData);
 }
 
+static bool isAcceptRejectCommandsEnabled(const SwView& rView)
+{
+    // Check the state of the command, including read-only mode and special 
cases
+    // like LOK AllowChangeComments mode
+    return 
rView.GetViewFrame().GetDispatcher()->QueryState(FN_REDLINE_ACCEPT_ALL,
+                                                            
o3tl::temporary(SfxPoolItemHolder()))
+           != SfxItemState::DISABLED;
+}
+
 void SwRedlineAcceptDlg::InitAuthors()
 {
     if (!m_xTabPagesCTRL)
@@ -358,8 +368,7 @@ void SwRedlineAcceptDlg::InitAuthors()
         pFilterPage->SelectAuthor(aStrings[0]);
 
     weld::TreeView& rTreeView = m_pTable->GetWidget();
-    SwDocShell* pShell = pSh ? pSh->GetDoc()->GetDocShell() : nullptr;
-    bool const bEnable = pShell && !pShell->IsReadOnly()
+    bool const bEnable = isAcceptRejectCommandsEnabled(*pView)
         && rTreeView.n_children() != 0
         && 
!pSh->getIDocumentRedlineAccess().GetRedlinePassword().hasElements();
     bool bSel = rTreeView.get_selected(nullptr);
@@ -1384,8 +1393,7 @@ IMPL_LINK_NOARG(SwRedlineAcceptDlg, GotoHdl, Timer *, 
void)
         }
     }
 
-    SwDocShell* pShell = pSh->GetDoc()->GetDocShell();
-    bool const bEnable = pShell && !pShell->IsReadOnly()
+    bool const bEnable = isAcceptRejectCommandsEnabled(*pView)
         && 
!pSh->getIDocumentRedlineAccess().GetRedlinePassword().hasElements();
     m_pTPView->EnableAccept( bEnable && bSel /*&& !bReadonlySel*/ );
     m_pTPView->EnableReject( bEnable && bSel /*&& !bReadonlySel*/ );
commit 84f96525bddff8406e52f05c681e263755056c6b
Author:     Mike Kaganski <[email protected]>
AuthorDate: Wed Jun 18 14:22:17 2025 +0500
Commit:     Mike Kaganski <[email protected]>
CommitDate: Fri Jun 20 11:15:35 2025 +0200

    LOK: Introduce "read-only mode with tracked changes management"
    
    When it is enabled, most of the editing commands in a read-only view
    are disabled, as usual; but the commands to manage tracked changes
    are enabled, and allow user to accept / reject / comment on changes.
    Saving is enabled, too.
    
    Change-Id: Ic8bafc335c47ecd1b897c428a804cea2bc677cb3
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/186686
    Tested-by: Jenkins CollaboraOffice <[email protected]>
    Reviewed-by: Miklos Vajna <[email protected]>
    (cherry picked from commit c4f3d75567d5664259e01ff14a75e6f3e952ac9a)
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/186733
    Tested-by: Jenkins
    Reviewed-by: Mike Kaganski <[email protected]>

diff --git a/desktop/qa/data/three-changes.fodt 
b/desktop/qa/data/three-changes.fodt
new file mode 100644
index 000000000000..0c7072b244a0
--- /dev/null
+++ b/desktop/qa/data/three-changes.fodt
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<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="T1" style:family="text">
+   <style:text-properties fo:font-weight="bold"/>
+  </style:style>
+ </office:automatic-styles>
+ <office:body>
+  <office:text>
+   <text:tracked-changes text:track-changes="false">
+    <text:changed-region xml:id="ct2412392131792" text:id="ct2412392131792">
+     <text:deletion>
+      <office:change-info>
+       <dc:creator>Mike</dc:creator>
+       <dc:date>2025-06-16T14:08:27</dc:date>
+      </office:change-info>
+     </text:deletion>
+    </text:changed-region>
+    <text:changed-region xml:id="ct2412428113776" text:id="ct2412428113776">
+     <text:format-change>
+      <office:change-info>
+       <dc:creator>Mike</dc:creator>
+       <dc:date>2025-06-17T12:41:00</dc:date>
+      </office:change-info>
+     </text:format-change>
+    </text:changed-region>
+    <text:changed-region xml:id="ct2412428117232" text:id="ct2412428117232">
+     <text:insertion>
+      <office:change-info>
+       <dc:creator>Mike</dc:creator>
+       <dc:date>2025-06-17T12:41:19</dc:date>
+      </office:change-info>
+     </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>
+  </office:text>
+ </office:body>
+</office:document>
\ No newline at end of file
diff --git a/desktop/qa/desktop_lib/test_desktop_lib.cxx 
b/desktop/qa/desktop_lib/test_desktop_lib.cxx
index 7a29bcbc818f..231aea8d0f3c 100644
--- a/desktop/qa/desktop_lib/test_desktop_lib.cxx
+++ b/desktop/qa/desktop_lib/test_desktop_lib.cxx
@@ -190,6 +190,7 @@ public:
     void testCommentsCallbacksWriter();
     void testCommentsAddEditDeleteDraw();
     void testCommentsInReadOnlyMode();
+    void testRedlinesInReadOnlyMode();
     void testCalcValidityDropdown();
     void testCalcValidityDropdownInReadonlyMode();
     void testRunMacro();
@@ -266,6 +267,7 @@ public:
     CPPUNIT_TEST(testCommentsCallbacksWriter);
     CPPUNIT_TEST(testCommentsAddEditDeleteDraw);
     CPPUNIT_TEST(testCommentsInReadOnlyMode);
+    CPPUNIT_TEST(testRedlinesInReadOnlyMode);
     CPPUNIT_TEST(testCalcValidityDropdown);
     CPPUNIT_TEST(testCalcValidityDropdownInReadonlyMode);
     CPPUNIT_TEST(testRunMacro);
@@ -2201,6 +2203,49 @@ void DesktopLOKTest::testRedlineCalc()
 
 namespace {
 
+struct RedlineInfo
+{
+    std::string action;
+    std::string index;
+    std::string author;
+    std::string type;
+    std::string comment;
+    std::string description;
+    std::string dateTime;
+};
+
+std::vector<RedlineInfo> getRedlineInfo(const boost::property_tree::ptree& 
redlineNode)
+{
+    std::vector<RedlineInfo> result;
+    result.reserve(redlineNode.size());
+    for (const auto& redline : redlineNode)
+    {
+        result.emplace_back();
+        result.back().index = redline.second.get<std::string>("index");
+        result.back().author = redline.second.get<std::string>("author");
+        result.back().type = redline.second.get<std::string>("type");
+        result.back().comment = redline.second.get<std::string>("comment");
+        result.back().description = 
redline.second.get<std::string>("description");
+        result.back().dateTime = redline.second.get<std::string>("dateTime");
+        if (auto oAction = redline.second.get_optional<std::string>("action"))
+            result.back().action = *oAction;
+    }
+
+    return result;
+}
+
+std::vector<RedlineInfo> getRedlineInfo(LibLODocument_Impl* pDocument)
+{
+    char* json
+        = pDocument->m_pDocumentClass->getCommandValues(pDocument, 
".uno:AcceptTrackedChanges");
+    std::stringstream stream(json);
+    free(json);
+    CPPUNIT_ASSERT(!stream.str().empty());
+    boost::property_tree::ptree tree;
+    boost::property_tree::read_json(stream, tree);
+    return getRedlineInfo(tree.get_child("redlines"));
+}
+
 class ViewCallback
 {
     LibLODocument_Impl* mpDocument;
@@ -2216,6 +2261,7 @@ public:
     tools::Rectangle m_aOwnCursor;
     boost::property_tree::ptree m_aCommentCallbackResult;
     boost::property_tree::ptree m_aColorPaletteCallbackResult;
+    RedlineInfo m_aLastRedlineInfo;
 
     ViewCallback(LibLODocument_Impl* pDocument)
         : mpDocument(pDocument),
@@ -2299,6 +2345,17 @@ public:
             boost::property_tree::read_json(aStream, m_JSONDialog);
         }
         break;
+        case LOK_CALLBACK_REDLINE_TABLE_SIZE_CHANGED:
+        case LOK_CALLBACK_REDLINE_TABLE_ENTRY_MODIFIED:
+        {
+            std::stringstream aStream(pPayload);
+            boost::property_tree::ptree tree;
+            boost::property_tree::read_json(aStream, tree);
+            auto redlines = getRedlineInfo(tree);
+            CPPUNIT_ASSERT_EQUAL(size_t(1), redlines.size());
+            m_aLastRedlineInfo = redlines[0];
+        }
+        break;
         }
     }
 };
@@ -2893,6 +2950,108 @@ void DesktopLOKTest::testCommentsInReadOnlyMode()
     //CPPUNIT_ASSERT_EQUAL(nCommentId, 
aView.m_aCommentCallbackResult.get<int>("id"));
 }
 
+void DesktopLOKTest::testRedlinesInReadOnlyMode()
+{
+    // In AllowManageRedlines mode, it must be possible to perform redline 
editing commands,
+    // even in read-only mode.
+
+    using namespace std::string_literals;
+
+    LibLODocument_Impl* pDocument = loadDoc("three-changes.fodt");
+
+    int viewId = pDocument->m_pDocumentClass->createView(pDocument);
+    pDocument->m_pDocumentClass->setView(pDocument, viewId);
+    pDocument->m_pDocumentClass->initializeForRendering(pDocument, "{}");
+    ViewCallback aCallback(pDocument);
+    Scheduler::ProcessEventsToIdle();
+
+    CPPUNIT_ASSERT_EQUAL(size_t(3), getRedlineInfo(pDocument).size());
+
+    // Activate read-only mode
+    SfxLokHelper::setViewReadOnly(viewId, true);
+
+    // Go to the 1st tracked change: "Delete “Donec”"
+    pDocument->pClass->postUnoCommand(pDocument, ".uno:NextTrackedChange", {}, 
false);
+    Scheduler::ProcessEventsToIdle();
+
+    // Check that redline management commands don't work in pure read-only
+    // Try to reject current redline
+    pDocument->pClass->postUnoCommand(pDocument, ".uno:RejectTrackedChange", 
{}, false);
+    Scheduler::ProcessEventsToIdle();
+    // Nothing happened
+    CPPUNIT_ASSERT_EQUAL(size_t(3), getRedlineInfo(pDocument).size());
+    CPPUNIT_ASSERT_EQUAL(""s, aCallback.m_aLastRedlineInfo.action);
+    CPPUNIT_ASSERT_EQUAL(""s, aCallback.m_aLastRedlineInfo.author);
+    CPPUNIT_ASSERT_EQUAL(""s, aCallback.m_aLastRedlineInfo.type);
+    CPPUNIT_ASSERT_EQUAL(""s, aCallback.m_aLastRedlineInfo.comment);
+    CPPUNIT_ASSERT_EQUAL(""s, aCallback.m_aLastRedlineInfo.description);
+    CPPUNIT_ASSERT_EQUAL(""s, aCallback.m_aLastRedlineInfo.dateTime);
+
+    // Activate the AllowManageRedlines mode
+    SfxLokHelper::setAllowManageRedlines(viewId, true);
+
+    // Try to reject current redline
+    pDocument->pClass->postUnoCommand(pDocument, ".uno:RejectTrackedChange", 
{}, false);
+    Scheduler::ProcessEventsToIdle();
+    // One change gone; it is recorded "Remove"d in 
aCallback.m_aLastRedlineInfo
+    CPPUNIT_ASSERT_EQUAL(size_t(2), getRedlineInfo(pDocument).size());
+    CPPUNIT_ASSERT_EQUAL("Remove"s, aCallback.m_aLastRedlineInfo.action);
+    CPPUNIT_ASSERT_EQUAL("Mike"s, aCallback.m_aLastRedlineInfo.author);
+    CPPUNIT_ASSERT_EQUAL("Delete"s, aCallback.m_aLastRedlineInfo.type);
+    CPPUNIT_ASSERT_EQUAL(""s, aCallback.m_aLastRedlineInfo.comment);
+    CPPUNIT_ASSERT_EQUAL("Delete “Donec”"s, 
aCallback.m_aLastRedlineInfo.description);
+    CPPUNIT_ASSERT_EQUAL("2025-06-16T14:08:27"s, 
aCallback.m_aLastRedlineInfo.dateTime);
+
+    // Go to the 2nd tracked change: "Attributes changed"
+    pDocument->pClass->postUnoCommand(pDocument, ".uno:NextTrackedChange", {}, 
false);
+    Scheduler::ProcessEventsToIdle();
+
+    // Comment on it
+    pDocument->pClass->postUnoCommand(pDocument, ".uno:CommentChangeTracking",
+                                      
R"({"Text":{"type":"string","value":"Some comment"}})",
+                                      false);
+    Scheduler::ProcessEventsToIdle();
+    // One change got a comment; it is recorded "Modify"ed in 
aCallback.m_aLastRedlineInfo
+    CPPUNIT_ASSERT_EQUAL(size_t(2), getRedlineInfo(pDocument).size());
+    CPPUNIT_ASSERT_EQUAL("Modify"s, aCallback.m_aLastRedlineInfo.action);
+    CPPUNIT_ASSERT_EQUAL("Mike"s, aCallback.m_aLastRedlineInfo.author);
+    CPPUNIT_ASSERT_EQUAL("Format"s, aCallback.m_aLastRedlineInfo.type);
+    CPPUNIT_ASSERT_EQUAL("Some comment"s, 
aCallback.m_aLastRedlineInfo.comment);
+    CPPUNIT_ASSERT_EQUAL("Attributes changed"s, 
aCallback.m_aLastRedlineInfo.description);
+    CPPUNIT_ASSERT_EQUAL("2025-06-17T12:41:00"s, 
aCallback.m_aLastRedlineInfo.dateTime);
+
+    // Go to the 3rd tracked change: "Insert “ Sapienti sat.”"
+    pDocument->pClass->postUnoCommand(pDocument, ".uno:NextTrackedChange", {}, 
false);
+    Scheduler::ProcessEventsToIdle();
+
+    // Accept it
+    pDocument->pClass->postUnoCommand(pDocument, ".uno:AcceptTrackedChange", 
{}, false);
+    Scheduler::ProcessEventsToIdle();
+    // One change gone; it is recorded "Remove"d in 
aCallback.m_aLastRedlineInfo
+    CPPUNIT_ASSERT_EQUAL(size_t(1), getRedlineInfo(pDocument).size());
+    CPPUNIT_ASSERT_EQUAL("Remove"s, aCallback.m_aLastRedlineInfo.action);
+    CPPUNIT_ASSERT_EQUAL("Mike"s, aCallback.m_aLastRedlineInfo.author);
+    CPPUNIT_ASSERT_EQUAL("Insert"s, aCallback.m_aLastRedlineInfo.type);
+    CPPUNIT_ASSERT_EQUAL(""s, aCallback.m_aLastRedlineInfo.comment);
+    CPPUNIT_ASSERT_EQUAL("Insert “ Sapienti sat.”"s, 
aCallback.m_aLastRedlineInfo.description);
+    CPPUNIT_ASSERT_EQUAL("2025-06-17T12:41:19"s, 
aCallback.m_aLastRedlineInfo.dateTime);
+
+    // Make sure that another (unrelated to redline management) editing 
command is not working
+    pDocument->pClass->postUnoCommand(pDocument, ".uno:InsertAnnotation",
+                                      
R"({"Text":{"type":"string","value":"Comment"}})",
+                                      false);
+    Scheduler::ProcessEventsToIdle();
+    CPPUNIT_ASSERT(aCallback.m_aCommentCallbackResult.empty());
+
+    // Check that the same command would succeed in AllowChangeComments mode
+    SfxLokHelper::setAllowChangeComments(viewId, true);
+    pDocument->pClass->postUnoCommand(pDocument, ".uno:InsertAnnotation",
+                                      
R"({"Text":{"type":"string","value":"Comment"}})",
+                                      false);
+    Scheduler::ProcessEventsToIdle();
+    CPPUNIT_ASSERT(!aCallback.m_aCommentCallbackResult.empty());
+}
+
 void DesktopLOKTest::testCalcValidityDropdown()
 {
     LibLODocument_Impl* pDocument = loadDoc("validity.ods");
@@ -3972,9 +4131,10 @@ void DesktopLOKTest::testABI()
     CPPUNIT_ASSERT_EQUAL(documentClassOffset(76), offsetof(struct 
_LibreOfficeKitDocumentClass, postSlideshowCleanup));
     CPPUNIT_ASSERT_EQUAL(documentClassOffset(77), offsetof(struct 
_LibreOfficeKitDocumentClass, renderNextSlideLayer));
     CPPUNIT_ASSERT_EQUAL(documentClassOffset(78), offsetof(struct 
_LibreOfficeKitDocumentClass, setViewOption));
+    CPPUNIT_ASSERT_EQUAL(documentClassOffset(79), offsetof(struct 
_LibreOfficeKitDocumentClass, setAllowManageRedlines));
 
     // As above
-    CPPUNIT_ASSERT_EQUAL(documentClassOffset(79), sizeof(struct 
_LibreOfficeKitDocumentClass));
+    CPPUNIT_ASSERT_EQUAL(documentClassOffset(80), sizeof(struct 
_LibreOfficeKitDocumentClass));
 }
 
 CPPUNIT_TEST_SUITE_REGISTRATION(DesktopLOKTest);
diff --git a/desktop/source/lib/init.cxx b/desktop/source/lib/init.cxx
index b4fd24cfbcd8..022ed601813b 100644
--- a/desktop/source/lib/init.cxx
+++ b/desktop/source/lib/init.cxx
@@ -1327,6 +1327,8 @@ static void doc_setViewReadOnly(LibreOfficeKitDocument* 
pThis, int nId, const bo
 
 static void doc_setAllowChangeComments(LibreOfficeKitDocument* pThis, int nId, 
const bool allow);
 
+static void doc_setAllowManageRedlines(LibreOfficeKitDocument* pThis, int nId, 
bool allow);
+
 static void doc_setAccessibilityState(LibreOfficeKitDocument* pThis, int nId, 
bool bEnabled);
 
 static char* doc_getA11yFocusedParagraph(LibreOfficeKitDocument* pThis);
@@ -1544,6 +1546,7 @@ LibLODocument_Impl::LibLODocument_Impl(uno::Reference 
<css::lang::XComponent> xC
         m_pDocumentClass->setViewReadOnly = doc_setViewReadOnly;
 
         m_pDocumentClass->setAllowChangeComments = doc_setAllowChangeComments;
+        m_pDocumentClass->setAllowManageRedlines = doc_setAllowManageRedlines;
 
         m_pDocumentClass->getPresentationInfo = doc_getPresentationInfo;
         m_pDocumentClass->createSlideRenderer = doc_createSlideRenderer;
@@ -7596,6 +7599,16 @@ static void 
doc_setAllowChangeComments(SAL_UNUSED_PARAMETER LibreOfficeKitDocume
     SfxLokHelper::setAllowChangeComments(nId, allow);
 }
 
+static void doc_setAllowManageRedlines(SAL_UNUSED_PARAMETER 
LibreOfficeKitDocument* /*pThis*/, int nId, bool allow)
+{
+    comphelper::ProfileZone aZone("doc_setAllowManageRedlines");
+
+    SolarMutexGuard aGuard;
+    SetLastExceptionMsg();
+
+    SfxLokHelper::setAllowManageRedlines(nId, allow);
+}
+
 static void doc_setAccessibilityState(SAL_UNUSED_PARAMETER 
LibreOfficeKitDocument* pThis, int nId, bool nEnabled)
 {
     SolarMutexGuard aGuard;
diff --git a/include/LibreOfficeKit/LibreOfficeKit.h 
b/include/LibreOfficeKit/LibreOfficeKit.h
index 66ff0418e326..af08534cdc0c 100644
--- a/include/LibreOfficeKit/LibreOfficeKit.h
+++ b/include/LibreOfficeKit/LibreOfficeKit.h
@@ -559,6 +559,9 @@ struct _LibreOfficeKitDocumentClass
     /// @see lok::Document::setViewOption
     void (*setViewOption)(LibreOfficeKitDocument* pThis, const char* pOption, 
const char* pValue);
 
+    /// @see lok::Document::setAllowManageRedlines().
+    void (*setAllowManageRedlines)(LibreOfficeKitDocument* pThis, int nId, 
bool allow);
+
 #endif // defined LOK_USE_UNSTABLE_API || defined LIBO_INTERNAL_ONLY
 };
 
diff --git a/include/LibreOfficeKit/LibreOfficeKit.hxx 
b/include/LibreOfficeKit/LibreOfficeKit.hxx
index f6f581c1ca43..51e521680ad4 100644
--- a/include/LibreOfficeKit/LibreOfficeKit.hxx
+++ b/include/LibreOfficeKit/LibreOfficeKit.hxx
@@ -879,6 +879,16 @@ public:
         mpDoc->pClass->setAllowChangeComments(mpDoc, nId, allow);
     }
 
+    /** Set if the view can manage redlines in readonly mode or not.
+     *
+     * @param nId view ID
+     * @param allow
+    */
+    void setAllowManageRedlines(int nId, bool allow)
+    {
+        mpDoc->pClass->setAllowManageRedlines(mpDoc, nId, allow);
+    }
+
     /**
      * Enable/Disable accessibility support for the window with the specified 
nId.
      *
diff --git a/include/sfx2/lokhelper.hxx b/include/sfx2/lokhelper.hxx
index c0d8efb6eb0d..feb8048331fb 100644
--- a/include/sfx2/lokhelper.hxx
+++ b/include/sfx2/lokhelper.hxx
@@ -125,6 +125,8 @@ public:
     static void setViewReadOnly(int nId, bool readOnly);
     // In readonly view, can user add / modify comments or not.
     static void setAllowChangeComments(int nId, bool allow);
+    // In readonly view, can user accept / reject tracked changes or not.
+    static void setAllowManageRedlines(int nId, bool allow);
     /// Get the language used by the loading view (used for all save 
operations).
     static const LanguageTag & getLoadLanguage();
     /// Set the language used by the loading view (used for all save 
operations).
diff --git a/include/sfx2/viewsh.hxx b/include/sfx2/viewsh.hxx
index 5f1349fa1b29..81430800350a 100644
--- a/include/sfx2/viewsh.hxx
+++ b/include/sfx2/viewsh.hxx
@@ -220,8 +220,9 @@ private:
 
     LOKDocumentFocusListener& GetLOKDocumentFocusListener();
     const LOKDocumentFocusListener& GetLOKDocumentFocusListener() const;
-    bool                        lokReadOnlyView = false; // When true, this is 
a LOK readonly view.
-    bool                        allowChangeComments = false; // When true, 
user can edit comments in readonly view mode.
+    bool lokReadOnlyView : 1 = false; // When true, this is a LOK readonly view
+    bool allowChangeComments : 1 = false; // Allow editing comments in 
readonly view mode
+    bool allowManageRedlines : 1 = false; // Allow accepting/rejecting changes 
in readonly view mode
 
 public:
 
@@ -249,6 +250,8 @@ public:
     bool                        IsLokReadOnlyView() const { return 
lokReadOnlyView; };
     void                        SetAllowChangeComments(bool allow) { 
allowChangeComments = allow; }
     bool                        IsAllowChangeComments() const { return 
allowChangeComments; }
+    void                        SetAllowManageRedlines(bool allow) { 
allowManageRedlines = allow; }
+    bool                        IsAllowManageRedlines() const { return 
allowManageRedlines; }
 
     // Misc
 
diff --git a/sfx2/source/control/dispatch.cxx b/sfx2/source/control/dispatch.cxx
index f427dee9d209..4dba2cd3b4fd 100644
--- a/sfx2/source/control/dispatch.cxx
+++ b/sfx2/source/control/dispatch.cxx
@@ -1555,6 +1555,22 @@ static bool 
IsCommandAllowedInLokReadOnlyViewMode(std::u16string_view commandNam
         if (std::find(std::begin(allowed), std::end(allowed), commandName) != 
std::end(allowed))
             return true;
     }
+    if (viewShell.IsAllowManageRedlines())
+    {
+        static constexpr std::u16string_view allowed[] = {
+            u".uno:AcceptTrackedChange",
+            u".uno:RejectTrackedChange",
+            u".uno:AcceptAllTrackedChanges",
+            u".uno:RejectAllTrackedChanges",
+            u".uno:AcceptTrackedChangeToNext",
+            u".uno:RejectTrackedChangeToNext",
+            u".uno:CommentChangeTracking",
+            u".uno:Save",
+        };
+
+        if (std::find(std::begin(allowed), std::end(allowed), commandName) != 
std::end(allowed))
+            return true;
+    }
     return false;
 }
 
diff --git a/sfx2/source/view/lokhelper.cxx b/sfx2/source/view/lokhelper.cxx
index 580df4546bdb..cc09eda66683 100644
--- a/sfx2/source/view/lokhelper.cxx
+++ b/sfx2/source/view/lokhelper.cxx
@@ -344,6 +344,15 @@ void SfxLokHelper::setAllowChangeComments(int nId, bool 
allow)
     }
 }
 
+void SfxLokHelper::setAllowManageRedlines(int nId, bool allow)
+{
+    if (SfxViewShell* pViewShell = getViewOfId(nId))
+    {
+        LOK_INFO("lok.readonlyview", "SfxLokHelper::setAllowManageRedlines: 
view id: " << nId << ", allow: " << allow);
+        pViewShell->SetAllowManageRedlines(allow);
+    }
+}
+
 void SfxLokHelper::setAccessibilityState(int nId, bool nEnabled)
 {
     if (SfxViewShell* pViewShell = getViewOfId(nId))

Reply via email to