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))
