sw/inc/PostItMgr.hxx                                                    |   16 
 sw/qa/extras/uiwriter/data/tdf108791_comments_with_tracked_changes.docx |binary
 sw/qa/extras/uiwriter/data/tdf108791_comments_with_tracked_changes.fodt |   40 
+
 sw/qa/extras/uiwriter/uiwriter11.cxx                                    |  290 
++++++++++
 sw/source/uibase/docvw/AnnotationWin.cxx                                |    1 
 sw/source/uibase/docvw/PostItMgr.cxx                                    |   44 
+
 6 files changed, 390 insertions(+), 1 deletion(-)

New commits:
commit 3bf75e92e9ea089b707cb4e163def156ad28f7e0
Author:     Mike Kaganski <mike.kagan...@collabora.com>
AuthorDate: Fri Aug 29 19:11:39 2025 +0500
Commit:     Mike Kaganski <mike.kagan...@collabora.com>
CommitDate: Tue Sep 2 19:53:45 2025 +0200

    tdf#108791: Ignore deleted comments in redlines of non-native documents
    
    ODF (and its native applications) can properly handle redline data of
    deleted comments. Other formats (or rather, respective applications
    like MS Word) don't understand the "comment anchor deletion" markup,
    and show the deleted comment as normal.
    
    Commit 419b70b5d4db227509614bdea5b4b89bcf7a6032 (tdf#105485 DOCX: import
    deleted comments as deleted, 2019-08-26) had implemented correct round-
    trip of the redline through DOCX. However, since Word doesn't support
    that, it created a situation when users can't correctly collaborate on
    documents.
    
    This change introduces a special handling of all non-native file formats
    in Writer, where deletion of a comment is handled just as in Word: it is
    deleted immediately, instead of marking as deleted. This doesn't affect
    deleting ranges of text, which contain comments: they are handled by
    both Writer and Word correctly.
    
    The solution works without any compatibility flags. This allows to have
    consistent behavior (same types of files will work the same way on all
    systems), zero configuration, and maximum functionality using native
    formats, unaffected by any settings.
    
    Change-Id: I2f8d3caaecd78af38e11a1ab6900d0afd73ed614
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/190376
    Tested-by: Jenkins
    Reviewed-by: Mike Kaganski <mike.kagan...@collabora.com>

diff --git a/sw/inc/PostItMgr.hxx b/sw/inc/PostItMgr.hxx
index 02acfcdd7b99..9ea58c7fa1d5 100644
--- a/sw/inc/PostItMgr.hxx
+++ b/sw/inc/PostItMgr.hxx
@@ -206,7 +206,7 @@ class SAL_DLLPUBLIC_RTTI SwPostItMgr final : public 
SfxListener,
         tools::Long GetNextBorder();
 
         sw::annotation::SwAnnotationWin* GetActiveSidebarWin() { return 
mpActivePostIt; }
-        void SetActiveSidebarWin( sw::annotation::SwAnnotationWin* p);
+        SW_DLLPUBLIC void SetActiveSidebarWin( 
sw::annotation::SwAnnotationWin* p);
         SW_DLLPUBLIC bool HasActiveSidebarWin() const;
         bool HasActiveAnnotationWin() const;
         void GrabFocusOnActiveSidebarWin();
@@ -253,6 +253,20 @@ class SAL_DLLPUBLIC_RTTI SwPostItMgr final : public 
SfxListener,
         void PaintTile(OutputDevice& rRenderContext);
 
         sw::sidebarwindows::SidebarPosition GetSidebarPos(const Point& 
rPointLogic);
+
+        // The commands that directly delete comments (as opposed to deletion 
of the text that the
+        // comments are anchored to) behave differently, depending on the 
document type, when the
+        // change tracking is on. For ODF, we allow comments to be marked as 
deleted; for external
+        // document types, we delete them immediately, as if change tracking 
os off.
+        class CommentDeleteFlagsRestore
+        {
+        public:
+            virtual ~CommentDeleteFlagsRestore() = default;
+        };
+        // Checks if the respective configuration must be changed for 'delete' 
operation, makes the
+        // change if needed, and returns a RAII object that will restore the 
original configuration
+        // in its dtor.
+        [[nodiscard]] std::unique_ptr<CommentDeleteFlagsRestore> 
ConfigureForCommentDelete();
 };
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git 
a/sw/qa/extras/uiwriter/data/tdf108791_comments_with_tracked_changes.docx 
b/sw/qa/extras/uiwriter/data/tdf108791_comments_with_tracked_changes.docx
new file mode 100644
index 000000000000..9eefbdd403b0
Binary files /dev/null and 
b/sw/qa/extras/uiwriter/data/tdf108791_comments_with_tracked_changes.docx differ
diff --git 
a/sw/qa/extras/uiwriter/data/tdf108791_comments_with_tracked_changes.fodt 
b/sw/qa/extras/uiwriter/data/tdf108791_comments_with_tracked_changes.fodt
new file mode 100644
index 000000000000..ed727ab0fd69
--- /dev/null
+++ b/sw/qa/extras/uiwriter/data/tdf108791_comments_with_tracked_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:ooo="http://openoffice.org/2004/office"; 
xmlns:fo="urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0" 
xmlns:xlink="http://www.w3.org/1999/xlink"; 
xmlns:config="urn:oasis:names:tc:opendocument:xmlns:config:1.0" 
xmlns:dc="http://purl.org/dc/elements/1.1/"; 
xmlns:meta="urn:oasis:names:tc:opendocument:xmlns:meta:1.0" 
xmlns:style="urn:oasis:names:tc:opendocument:xmlns:style:1.0" 
xmlns:text="urn:oasis:names:tc:opendocument:xmlns:text:1.0" 
xmlns:rpt="http://openoffice.org/2005/report"; 
xmlns:draw="urn:oasis:names:tc:opendocument:xmlns:drawing:1.0" 
xmlns:dr3d="urn:oasis:names:tc:opendocument:xmlns:dr3d:1.0" 
xmlns:svg="urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0" 
xmlns:chart="urn:oasis:names:tc:opendocument:xmlns:chart:1.0" 
xmlns:table="urn:oasis:names:tc:opendocument:xmlns:table:1.0" 
xmlns:number="urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0" 
xmlns:ooow="http://openoffice.org/200
 4/writer" xmlns:oooc="http://openoffice.org/2004/calc"; 
xmlns:of="urn:oasis:names:tc:opendocument:xmlns:of:1.2" 
xmlns:xforms="http://www.w3.org/2002/xforms"; 
xmlns:tableooo="http://openoffice.org/2009/table"; 
xmlns:calcext="urn:org:documentfoundation:names:experimental:calc:xmlns:calcext:1.0"
 xmlns:drawooo="http://openoffice.org/2010/draw"; 
xmlns:loext="urn:org:documentfoundation:names:experimental:office:xmlns:loext:1.0"
 xmlns:field="urn:openoffice:names:experimental:ooo-ms-interop:xmlns:field:1.0" 
xmlns:math="http://www.w3.org/1998/Math/MathML"; 
xmlns:form="urn:oasis:names:tc:opendocument:xmlns:form:1.0" 
xmlns:script="urn:oasis:names:tc:opendocument:xmlns:script:1.0" 
xmlns:formx="urn:openoffice:names:experimental:ooxml-odf-interop:xmlns:form:1.0"
 xmlns:dom="http://www.w3.org/2001/xml-events"; 
xmlns:xsd="http://www.w3.org/2001/XMLSchema"; 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"; 
xmlns:xhtml="http://www.w3.org/1999/xhtml"; 
xmlns:grddl="http://www.w3.org/2003/g/data-view#"; xmlns
 :css3t="http://www.w3.org/TR/css3-text/"; 
xmlns:officeooo="http://openoffice.org/2009/office"; office:version="1.4" 
office:mimetype="application/vnd.oasis.opendocument.text">
+ <office:settings>
+  <config:config-item-set config:name="ooo:view-settings">
+   <config:config-item config:name="ShowRedlineChanges" 
config:type="boolean">true</config:config-item>
+  </config:config-item-set>
+ </office:settings>
+ <office:body>
+  <office:text>
+   <text:tracked-changes text:track-changes="true"/>
+   <text:p>First paragraph <office:annotation office:name="__Annotation__1">
+      <dc:creator>Author1</dc:creator>
+      <dc:date>2025-09-01T10:00:00</dc:date>
+      <text:p>Comment thread 1 head</text:p>
+     </office:annotation><office:annotation 
loext:parent-name="__Annotation__1">
+      <dc:creator>Author2</dc:creator>
+      <dc:date>2025-09-01T10:02:00</dc:date>
+      <text:p>Comment thread 1 reply 1</text:p>
+     </office:annotation><office:annotation 
loext:parent-name="__Annotation__1">
+      <dc:creator>Author3</dc:creator>
+      <dc:date>2025-09-01T10:04:00</dc:date>
+      <text:p>Comment thread 1 reply 2</text:p>
+     </office:annotation>text.</text:p>
+   <text:p>Second paragraph <office:annotation office:name="__Annotation__2">
+      <dc:creator>Author1</dc:creator>
+      <dc:date>2025-09-01T10:01:00</dc:date>
+      <text:p>Comment thread 2 head</text:p>
+     </office:annotation><office:annotation 
loext:parent-name="__Annotation__2">
+      <dc:creator>Author2</dc:creator>
+      <dc:date>2025-09-01T10:03:00</dc:date>
+      <text:p>Comment thread 2 reply 1</text:p>
+     </office:annotation><office:annotation 
loext:parent-name="__Annotation__2">
+      <dc:creator>Author3</dc:creator>
+      <dc:date>2025-09-01T10:05:00</dc:date>
+      <text:p>Comment thread 2 reply 2</text:p>
+     </office:annotation>text.</text:p>
+  </office:text>
+ </office:body>
+</office:document>
\ No newline at end of file
diff --git a/sw/qa/extras/uiwriter/uiwriter11.cxx 
b/sw/qa/extras/uiwriter/uiwriter11.cxx
index 4fa9f14f4238..13aab01fd1c8 100644
--- a/sw/qa/extras/uiwriter/uiwriter11.cxx
+++ b/sw/qa/extras/uiwriter/uiwriter11.cxx
@@ -15,7 +15,11 @@
 #include <comphelper/scopeguard.hxx>
 #include <comphelper/configuration.hxx>
 
+#include <AnnotationWin.hxx>
+#include <cmdid.h>
+#include <docufld.hxx>
 #include <edtwin.hxx>
+#include <PostItMgr.hxx>
 #include <view.hxx>
 #include <wrtsh.hxx>
 #include <unotxdoc.hxx>
@@ -66,6 +70,292 @@ CPPUNIT_TEST_FIXTURE(SwUiWriterTest11, 
testTdf167760_numberedPara)
     CPPUNIT_ASSERT_EQUAL(OUString(), getProperty<OUString>(getParagraph(1), 
"ListLabelString"));
 }
 
+CPPUNIT_TEST_FIXTURE(SwUiWriterTest11, testTdf108791)
+{
+    auto getPostItMgr = [](SwDocShell* pDocShell) {
+        CPPUNIT_ASSERT(pDocShell);
+        SwView* pView = pDocShell->GetView();
+        CPPUNIT_ASSERT(pView);
+        SwPostItMgr* pPostItMgr = pView->GetPostItMgr();
+        CPPUNIT_ASSERT(pPostItMgr);
+        return pPostItMgr;
+    };
+
+    // Given a document with tracked changes enabled, having some threads of 
comments:
+
+    createSwDoc("tdf108791_comments_with_tracked_changes.fodt");
+
+    {
+        // Test "Delete Comment": the selected comment must be marked as 
deleted
+
+        SwPostItMgr* pPostItMgr = getPostItMgr(getSwDocShell());
+        auto& aPostItFields = pPostItMgr->GetPostItFields();
+
+        CPPUNIT_ASSERT_EQUAL(size_t(6), aPostItFields.size());
+        for (size_t i = 0; i < aPostItFields.size(); ++i)
+        {
+            CPPUNIT_ASSERT(aPostItFields[i]);
+            CPPUNIT_ASSERT_EQUAL(SwPostItHelper::SwLayoutStatus::VISIBLE,
+                                 aPostItFields[i]->mLayoutStatus);
+        }
+
+        // Select "Comment thread 1 reply 2"
+        CPPUNIT_ASSERT(aPostItFields[2]->mpPostIt);
+        const SwPostItField* pPostItField = 
aPostItFields[2]->mpPostIt->GetPostItField();
+        CPPUNIT_ASSERT(pPostItField);
+        CPPUNIT_ASSERT_EQUAL(u"Comment thread 1 reply 2"_ustr, 
pPostItField->GetText());
+
+        pPostItMgr->SetActiveSidebarWin(aPostItFields[2]->mpPostIt);
+        dispatchCommand(mxComponent, u".uno:DeleteComment"_ustr, {});
+
+        CPPUNIT_ASSERT_EQUAL(size_t(6), aPostItFields.size());
+        for (size_t i = 0; i < aPostItFields.size(); ++i)
+        {
+            CPPUNIT_ASSERT(aPostItFields[i]);
+            CPPUNIT_ASSERT_EQUAL(i == 2 ? 
SwPostItHelper::SwLayoutStatus::DELETED
+                                        : 
SwPostItHelper::SwLayoutStatus::VISIBLE,
+                                 aPostItFields[i]->mLayoutStatus);
+        }
+    }
+
+    // load it anew
+    createSwDoc("tdf108791_comments_with_tracked_changes.fodt");
+
+    {
+        // Test "Delete Comment Tread": the comment, and all its thread, must 
be marked as deleted
+
+        SwPostItMgr* pPostItMgr = getPostItMgr(getSwDocShell());
+        auto& aPostItFields = pPostItMgr->GetPostItFields();
+
+        CPPUNIT_ASSERT_EQUAL(size_t(6), aPostItFields.size());
+        for (size_t i = 0; i < aPostItFields.size(); ++i)
+        {
+            CPPUNIT_ASSERT(aPostItFields[i]);
+            CPPUNIT_ASSERT_EQUAL(SwPostItHelper::SwLayoutStatus::VISIBLE,
+                                 aPostItFields[i]->mLayoutStatus);
+        }
+
+        // Select "Comment thread 1 reply 2"
+        CPPUNIT_ASSERT(aPostItFields[2]->mpPostIt);
+        const SwPostItField* pPostItField = 
aPostItFields[2]->mpPostIt->GetPostItField();
+        CPPUNIT_ASSERT(pPostItField);
+        CPPUNIT_ASSERT_EQUAL(u"Comment thread 1 reply 2"_ustr, 
pPostItField->GetText());
+
+        pPostItMgr->SetActiveSidebarWin(aPostItFields[2]->mpPostIt);
+        dispatchCommand(mxComponent, u".uno:DeleteCommentThread"_ustr, {});
+
+        CPPUNIT_ASSERT_EQUAL(size_t(6), aPostItFields.size());
+        for (size_t i = 0; i < aPostItFields.size(); ++i)
+        {
+            CPPUNIT_ASSERT(aPostItFields[i]);
+            CPPUNIT_ASSERT_EQUAL(i <= 2 ? 
SwPostItHelper::SwLayoutStatus::DELETED
+                                        : 
SwPostItHelper::SwLayoutStatus::VISIBLE,
+                                 aPostItFields[i]->mLayoutStatus);
+        }
+    }
+
+    // load it anew
+    createSwDoc("tdf108791_comments_with_tracked_changes.fodt");
+
+    {
+        // Test "Delete Comments by Author3": the author's comments must be 
marked as deleted
+
+        SwPostItMgr* pPostItMgr = getPostItMgr(getSwDocShell());
+        auto& aPostItFields = pPostItMgr->GetPostItFields();
+
+        CPPUNIT_ASSERT_EQUAL(size_t(6), aPostItFields.size());
+        for (size_t i = 0; i < aPostItFields.size(); ++i)
+        {
+            CPPUNIT_ASSERT(aPostItFields[i]);
+            CPPUNIT_ASSERT_EQUAL(SwPostItHelper::SwLayoutStatus::VISIBLE,
+                                 aPostItFields[i]->mLayoutStatus);
+        }
+
+        // Select "Comment thread 1 reply 2"
+        CPPUNIT_ASSERT(aPostItFields[2]->mpPostIt);
+        const SwPostItField* pPostItField = 
aPostItFields[2]->mpPostIt->GetPostItField();
+        CPPUNIT_ASSERT(pPostItField);
+        CPPUNIT_ASSERT_EQUAL(u"Author3"_ustr, pPostItField->GetPar1());
+
+        pPostItMgr->SetActiveSidebarWin(aPostItFields[2]->mpPostIt);
+        dispatchCommand(mxComponent, u".uno:DeleteAuthor"_ustr, {});
+
+        CPPUNIT_ASSERT_EQUAL(size_t(6), aPostItFields.size());
+        for (size_t i = 0; i < aPostItFields.size(); ++i)
+        {
+            CPPUNIT_ASSERT(aPostItFields[i]);
+            CPPUNIT_ASSERT(aPostItFields[i]->mpPostIt);
+            pPostItField = aPostItFields[i]->mpPostIt->GetPostItField();
+            CPPUNIT_ASSERT(pPostItField);
+            CPPUNIT_ASSERT_EQUAL(pPostItField->GetPar1() == "Author3"
+                                     ? SwPostItHelper::SwLayoutStatus::DELETED
+                                     : SwPostItHelper::SwLayoutStatus::VISIBLE,
+                                 aPostItFields[i]->mLayoutStatus);
+        }
+    }
+
+    // load it anew
+    createSwDoc("tdf108791_comments_with_tracked_changes.fodt");
+
+    {
+        // Test "Delete All Comments": all comments must be marked as deleted
+
+        SwPostItMgr* pPostItMgr = getPostItMgr(getSwDocShell());
+        auto& aPostItFields = pPostItMgr->GetPostItFields();
+
+        CPPUNIT_ASSERT_EQUAL(size_t(6), aPostItFields.size());
+        for (size_t i = 0; i < aPostItFields.size(); ++i)
+        {
+            CPPUNIT_ASSERT(aPostItFields[i]);
+            CPPUNIT_ASSERT_EQUAL(SwPostItHelper::SwLayoutStatus::VISIBLE,
+                                 aPostItFields[i]->mLayoutStatus);
+        }
+
+        // Select any comment
+        CPPUNIT_ASSERT(aPostItFields[2]->mpPostIt);
+
+        pPostItMgr->SetActiveSidebarWin(aPostItFields[2]->mpPostIt);
+        dispatchCommand(mxComponent, u".uno:DeleteAllNotes"_ustr, {});
+
+        CPPUNIT_ASSERT_EQUAL(size_t(6), aPostItFields.size());
+        for (size_t i = 0; i < aPostItFields.size(); ++i)
+        {
+            CPPUNIT_ASSERT(aPostItFields[i]);
+            CPPUNIT_ASSERT_EQUAL(SwPostItHelper::SwLayoutStatus::DELETED,
+                                 aPostItFields[i]->mLayoutStatus);
+        }
+    }
+
+    // Now test the same with an equivalent DOCX: comment deletion must delete 
immediately
+
+    createSwDoc("tdf108791_comments_with_tracked_changes.docx");
+
+    {
+        // Test "Delete Comment": the selected comment must be deleted
+
+        SwPostItMgr* pPostItMgr = getPostItMgr(getSwDocShell());
+        auto& aPostItFields = pPostItMgr->GetPostItFields();
+
+        CPPUNIT_ASSERT_EQUAL(size_t(6), aPostItFields.size());
+        for (size_t i = 0; i < aPostItFields.size(); ++i)
+        {
+            CPPUNIT_ASSERT(aPostItFields[i]);
+            CPPUNIT_ASSERT_EQUAL(SwPostItHelper::SwLayoutStatus::VISIBLE,
+                                 aPostItFields[i]->mLayoutStatus);
+        }
+
+        // Select "Comment thread 1 reply 2"
+        CPPUNIT_ASSERT(aPostItFields[2]->mpPostIt);
+        const SwPostItField* pPostItField = 
aPostItFields[2]->mpPostIt->GetPostItField();
+        CPPUNIT_ASSERT(pPostItField);
+        CPPUNIT_ASSERT_EQUAL(u"Comment thread 1 reply 2"_ustr, 
pPostItField->GetText());
+
+        pPostItMgr->SetActiveSidebarWin(aPostItFields[2]->mpPostIt);
+        dispatchCommand(mxComponent, u".uno:DeleteComment"_ustr, {});
+
+        CPPUNIT_ASSERT_EQUAL(size_t(5), aPostItFields.size());
+        for (size_t i = 0; i < aPostItFields.size(); ++i)
+        {
+            CPPUNIT_ASSERT(aPostItFields[i]);
+            CPPUNIT_ASSERT(aPostItFields[i]->mpPostIt);
+            CPPUNIT_ASSERT(aPostItFields[i]->mpPostIt->GetPostItField());
+            
CPPUNIT_ASSERT(aPostItFields[i]->mpPostIt->GetPostItField()->GetText()
+                           != "Comment thread 1 reply 2");
+        }
+    }
+
+    // load it anew
+    createSwDoc("tdf108791_comments_with_tracked_changes.docx");
+
+    {
+        // Test "Delete Comment Tread": the comment, and all its thread, must 
be deleted
+
+        SwPostItMgr* pPostItMgr = getPostItMgr(getSwDocShell());
+        auto& aPostItFields = pPostItMgr->GetPostItFields();
+
+        CPPUNIT_ASSERT_EQUAL(size_t(6), aPostItFields.size());
+        for (size_t i = 0; i < aPostItFields.size(); ++i)
+        {
+            CPPUNIT_ASSERT(aPostItFields[i]);
+            CPPUNIT_ASSERT_EQUAL(SwPostItHelper::SwLayoutStatus::VISIBLE,
+                                 aPostItFields[i]->mLayoutStatus);
+        }
+
+        // Select "Comment thread 1 reply 2"
+        CPPUNIT_ASSERT(aPostItFields[2]->mpPostIt);
+        const SwPostItField* pPostItField = 
aPostItFields[2]->mpPostIt->GetPostItField();
+        CPPUNIT_ASSERT(pPostItField);
+        CPPUNIT_ASSERT_EQUAL(u"Comment thread 1 reply 2"_ustr, 
pPostItField->GetText());
+
+        pPostItMgr->SetActiveSidebarWin(aPostItFields[2]->mpPostIt);
+        dispatchCommand(mxComponent, u".uno:DeleteCommentThread"_ustr, {});
+
+        CPPUNIT_ASSERT_EQUAL(size_t(3), aPostItFields.size());
+    }
+
+    // load it anew
+    createSwDoc("tdf108791_comments_with_tracked_changes.docx");
+
+    {
+        // Test "Delete Comments by Author3": the author's comments must be 
deleted
+
+        SwPostItMgr* pPostItMgr = getPostItMgr(getSwDocShell());
+        auto& aPostItFields = pPostItMgr->GetPostItFields();
+
+        CPPUNIT_ASSERT_EQUAL(size_t(6), aPostItFields.size());
+        for (size_t i = 0; i < aPostItFields.size(); ++i)
+        {
+            CPPUNIT_ASSERT(aPostItFields[i]);
+            CPPUNIT_ASSERT_EQUAL(SwPostItHelper::SwLayoutStatus::VISIBLE,
+                                 aPostItFields[i]->mLayoutStatus);
+        }
+
+        // Select "Comment thread 1 reply 2"
+        CPPUNIT_ASSERT(aPostItFields[2]->mpPostIt);
+        const SwPostItField* pPostItField = 
aPostItFields[2]->mpPostIt->GetPostItField();
+        CPPUNIT_ASSERT(pPostItField);
+        CPPUNIT_ASSERT_EQUAL(u"Author3"_ustr, pPostItField->GetPar1());
+
+        pPostItMgr->SetActiveSidebarWin(aPostItFields[2]->mpPostIt);
+        dispatchCommand(mxComponent, u".uno:DeleteAuthor"_ustr, {});
+
+        CPPUNIT_ASSERT_EQUAL(size_t(4), aPostItFields.size());
+        for (size_t i = 0; i < aPostItFields.size(); ++i)
+        {
+            CPPUNIT_ASSERT(aPostItFields[i]);
+            CPPUNIT_ASSERT(aPostItFields[i]->mpPostIt);
+            CPPUNIT_ASSERT(aPostItFields[i]->mpPostIt->GetPostItField());
+            
CPPUNIT_ASSERT(aPostItFields[i]->mpPostIt->GetPostItField()->GetPar1() != 
"Author3");
+        }
+    }
+
+    // load it anew
+    createSwDoc("tdf108791_comments_with_tracked_changes.docx");
+
+    {
+        // Test "Delete All Comments": all comments must be deleted
+
+        SwPostItMgr* pPostItMgr = getPostItMgr(getSwDocShell());
+        auto& aPostItFields = pPostItMgr->GetPostItFields();
+
+        CPPUNIT_ASSERT_EQUAL(size_t(6), aPostItFields.size());
+        for (size_t i = 0; i < aPostItFields.size(); ++i)
+        {
+            CPPUNIT_ASSERT(aPostItFields[i]);
+            CPPUNIT_ASSERT_EQUAL(SwPostItHelper::SwLayoutStatus::VISIBLE,
+                                 aPostItFields[i]->mLayoutStatus);
+        }
+
+        // Select any comment
+        CPPUNIT_ASSERT(aPostItFields[2]->mpPostIt);
+
+        pPostItMgr->SetActiveSidebarWin(aPostItFields[2]->mpPostIt);
+        dispatchCommand(mxComponent, u".uno:DeleteAllNotes"_ustr, {});
+
+        CPPUNIT_ASSERT(aPostItFields.empty());
+    }
+}
+
 } // end of anonymous namespace
 CPPUNIT_PLUGIN_IMPLEMENT();
 
diff --git a/sw/source/uibase/docvw/AnnotationWin.cxx 
b/sw/source/uibase/docvw/AnnotationWin.cxx
index 21a79b078755..63c80ddcc3fc 100644
--- a/sw/source/uibase/docvw/AnnotationWin.cxx
+++ b/sw/source/uibase/docvw/AnnotationWin.cxx
@@ -417,6 +417,7 @@ void SwAnnotationWin::Delete()
     // we delete the field directly, the Mgr cleans up the PostIt by listening
     GrabFocusToDocument();
     pWrtShell->ClearMark();
+    auto restoreGuard = mrMgr.ConfigureForCommentDelete();
     pWrtShell->DelRight();
 }
 
diff --git a/sw/source/uibase/docvw/PostItMgr.cxx 
b/sw/source/uibase/docvw/PostItMgr.cxx
index 237c6bc0fb46..4fb7a9f33406 100644
--- a/sw/source/uibase/docvw/PostItMgr.cxx
+++ b/sw/source/uibase/docvw/PostItMgr.cxx
@@ -45,6 +45,7 @@
 #include <doc.hxx>
 #include <IDocumentSettingAccess.hxx>
 #include <IDocumentFieldsAccess.hxx>
+#include <IDocumentRedlineAccess.hxx>
 #if ENABLE_YRS
 #include <IDocumentState.hxx>
 #endif
@@ -64,6 +65,8 @@
 #include <strings.hrc>
 #include <cmdid.h>
 
+#include <sfx2/docfile.hxx>
+#include <sfx2/docfilt.hxx>
 #include <sfx2/request.hxx>
 #include <sfx2/event.hxx>
 #include <svl/srchitem.hxx>
@@ -372,6 +375,29 @@ namespace {
         }
     };
 
+// a RAII object that sets Ignore redline flag, and restores previous redline 
flags in dtor
+class CommentDeleteFlagsRestoreImpl : public 
SwPostItMgr::CommentDeleteFlagsRestore
+{
+public:
+    CommentDeleteFlagsRestoreImpl(SwWrtShell* shell)
+        : m_pWrtShell(shell)
+        , m_eRestreFlags(m_pWrtShell->GetRedlineFlags())
+    {
+        m_pWrtShell->SetRedlineFlags(m_eRestreFlags | RedlineFlags::Ignore);
+    }
+    ~CommentDeleteFlagsRestoreImpl() { 
m_pWrtShell->SetRedlineFlags(m_eRestreFlags); }
+
+private:
+    SwWrtShell* m_pWrtShell;
+    RedlineFlags m_eRestreFlags;
+};
+
+bool isOwnFileFormat(SfxMedium* pMedium)
+{
+    // Assume that unsaved documents are own format
+    return !pMedium || !pMedium->GetFilter() || 
pMedium->GetFilter()->IsOwnFormat();
+}
+
 } // anonymous namespace
 
 SwPostItMgr::SwPostItMgr(SwView* pView)
@@ -1640,6 +1666,17 @@ static bool ConfirmDeleteAll(const SwView& pView, const 
OUString& sText)
     return bConfirm;
 }
 
+std::unique_ptr<SwPostItMgr::CommentDeleteFlagsRestore> 
SwPostItMgr::ConfigureForCommentDelete()
+{
+    if (!mpWrtShell->IsRedlineOn())
+        return {}; // No track changes - no need to disable it
+    if (isOwnFileFormat(mpView->GetDocShell()->GetMedium()))
+        return {}; // Format is smart enough to handle deleted comments in 
redlines
+
+    return std::unique_ptr<CommentDeleteFlagsRestore>(
+        new CommentDeleteFlagsRestoreImpl(mpWrtShell));
+}
+
 // copy to new vector, otherwise RemoveItem would operate and delete stuff on 
mvPostItFields as well
 // RemoveItem will clean up the core field and visible postit if necessary
 // we cannot just delete everything as before, as postits could move into 
change tracking
@@ -1667,11 +1704,13 @@ void SwPostItMgr::Delete(const OUString& rAuthor)
     IDocumentRedlineAccess const& 
rIDRA(mpWrtShell->getIDocumentRedlineAccess());
     IsFieldNotDeleted aFilter2(rIDRA, aFilter);
     FieldDocWatchingStack aStack(mvPostItFields, *mpView->GetDocShell(), 
aFilter2);
+    auto restoreGuard = ConfigureForCommentDelete();
     while (const SwFormatField* pField = aStack.pop())
     {
         if (mpWrtShell->GotoField(*pField))
             mpWrtShell->DelRight();
     }
+    restoreGuard.reset();
     mpWrtShell->EndUndo();
     PrepareView();
     mpWrtShell->EndAllAction();
@@ -1702,7 +1741,10 @@ void SwPostItMgr::Delete(sal_uInt32 nPostItId)
     FieldDocWatchingStack aStack(mvPostItFields, *mpView->GetDocShell(), 
aFilter2);
     const SwFormatField* pField = aStack.pop();
     if (pField && mpWrtShell->GotoField(*pField))
+    {
+        auto restoreGuard = ConfigureForCommentDelete();
         mpWrtShell->DelRight();
+    }
     mpWrtShell->EndUndo();
     PrepareView();
     mpWrtShell->EndAllAction();
@@ -1802,11 +1844,13 @@ void SwPostItMgr::Delete()
     IsFieldNotDeleted aFilter2(rIDRA, aFilter);
     FieldDocWatchingStack aStack(mvPostItFields, *mpView->GetDocShell(),
         aFilter2);
+    auto restoreGuard = ConfigureForCommentDelete();
     while (const SwFormatField* pField = aStack.pop())
     {
         if (mpWrtShell->GotoField(*pField))
             mpWrtShell->DelRight();
     }
+    restoreGuard.reset();
 
     mpWrtShell->EndUndo();
     PrepareView();

Reply via email to