desktop/qa/data/comments.odt                                |binary
 desktop/qa/desktop_lib/test_desktop_lib.cxx                 |   14 +++---
 include/xmloff/xmltoken.hxx                                 |    1 
 schema/libreoffice/OpenDocument-v1.3+libreoffice-schema.rng |    5 ++
 sw/inc/AnnotationWin.hxx                                    |    3 +
 sw/inc/docufld.hxx                                          |   10 ++++
 sw/inc/unoprnms.hxx                                         |    1 
 sw/source/core/fields/docufld.cxx                           |   23 +++++++++-
 sw/source/core/inc/bookmark.hxx                             |    2 
 sw/source/core/inc/unofldmid.h                              |    1 
 sw/source/core/unocore/unofield.cxx                         |   11 ++++
 sw/source/core/unocore/unomap.cxx                           |    1 
 sw/source/uibase/docvw/AnnotationWin.cxx                    |   14 ++++++
 sw/source/uibase/docvw/PostItMgr.cxx                        |   27 +++++++++++-
 sw/source/uibase/shells/textfld.cxx                         |    8 +++
 sw/source/uibase/uno/unotxdoc.cxx                           |    3 -
 xmloff/inc/txtfldi.hxx                                      |    1 
 xmloff/qa/unit/text.cxx                                     |    8 +++
 xmloff/source/core/xmltoken.cxx                             |    1 
 xmloff/source/text/txtflde.cxx                              |    9 ++++
 xmloff/source/text/txtfldi.cxx                              |    6 ++
 xmloff/source/token/tokens.txt                              |    1 
 22 files changed, 133 insertions(+), 17 deletions(-)

New commits:
commit 62cc2217217650d23c72e4646ccd793f76722d94
Author:     Gökay Şatır <gokaysa...@gmail.com>
AuthorDate: Fri Sep 1 09:49:53 2023 +0300
Commit:     Miklos Vajna <vmik...@collabora.com>
CommitDate: Tue Sep 12 17:09:18 2023 +0200

    Added parent / child relationship to comments.
    
    Adding parent name of a comment into odf file when there is a parent.
    
    Also includes:
    
        Added test case to comment property test.
    
        Change-Id: I033f6574b4875fcb76b16c8b5b9d9f7d55b52cbe
    
    Also includes:
    
        Add parent / child relations to replied comments.
    
        Change-Id: Ia7d95c4e6020b501798a89cbdcae64dc5691437c
    
    Change-Id: I08b5ab6eb11adcafcbf3559896d79d41b449b26a
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/156824
    Tested-by: Jenkins
    Reviewed-by: Miklos Vajna <vmik...@collabora.com>

diff --git a/desktop/qa/data/comments.odt b/desktop/qa/data/comments.odt
index ee7f15f8b755..1bcdcc0385ea 100644
Binary files a/desktop/qa/data/comments.odt and b/desktop/qa/data/comments.odt 
differ
diff --git a/desktop/qa/desktop_lib/test_desktop_lib.cxx 
b/desktop/qa/desktop_lib/test_desktop_lib.cxx
index 8a55ae18172d..8f90f3198b27 100644
--- a/desktop/qa/desktop_lib/test_desktop_lib.cxx
+++ b/desktop/qa/desktop_lib/test_desktop_lib.cxx
@@ -2452,7 +2452,7 @@ void DesktopLOKTest::testCommentsWriter()
         // This is a reply comment
         else if (rComment.second.get<std::string>("text") == "Reply to Comment 
2")
         {
-            CPPUNIT_ASSERT_EQUAL(nComment2Id, 
rComment.second.get<int>("parent"));
+            CPPUNIT_ASSERT_EQUAL(nComment2Id, 
rComment.second.get<int>("parentId"));
         }
     }
 
@@ -2594,8 +2594,8 @@ void DesktopLOKTest::testCommentsCallbacksWriter()
     // We received a LOK_CALLBACK_COMMENT callback with comment 'Add' action 
and linked to its parent comment
     CPPUNIT_ASSERT_EQUAL(std::string("Add"), 
aView1.m_aCommentCallbackResult.get<std::string>("action"));
     CPPUNIT_ASSERT_EQUAL(std::string("Add"), 
aView2.m_aCommentCallbackResult.get<std::string>("action"));
-    CPPUNIT_ASSERT_EQUAL(nCommentId1, 
aView1.m_aCommentCallbackResult.get<int>("parent"));
-    CPPUNIT_ASSERT_EQUAL(nCommentId1, 
aView2.m_aCommentCallbackResult.get<int>("parent"));
+    CPPUNIT_ASSERT_EQUAL(nCommentId1, 
aView1.m_aCommentCallbackResult.get<int>("parentId"));
+    CPPUNIT_ASSERT_EQUAL(nCommentId1, 
aView2.m_aCommentCallbackResult.get<int>("parentId"));
     CPPUNIT_ASSERT_EQUAL(std::string("Reply comment"), 
aView1.m_aCommentCallbackResult.get<std::string>("text"));
     CPPUNIT_ASSERT_EQUAL(std::string("Reply comment"), 
aView2.m_aCommentCallbackResult.get<std::string>("text"));
     int nCommentId2 = aView1.m_aCommentCallbackResult.get<int>("id");
@@ -2609,8 +2609,8 @@ void DesktopLOKTest::testCommentsCallbacksWriter()
     CPPUNIT_ASSERT_EQUAL(std::string("Modify"), 
aView1.m_aCommentCallbackResult.get<std::string>("action"));
     CPPUNIT_ASSERT_EQUAL(std::string("Modify"), 
aView2.m_aCommentCallbackResult.get<std::string>("action"));
     // parent is unchanged still
-    CPPUNIT_ASSERT_EQUAL(nCommentId1, 
aView1.m_aCommentCallbackResult.get<int>("parent"));
-    CPPUNIT_ASSERT_EQUAL(nCommentId1, 
aView2.m_aCommentCallbackResult.get<int>("parent"));
+    CPPUNIT_ASSERT_EQUAL(nCommentId1, 
aView1.m_aCommentCallbackResult.get<int>("parentId"));
+    CPPUNIT_ASSERT_EQUAL(nCommentId1, 
aView2.m_aCommentCallbackResult.get<int>("parentId"));
     CPPUNIT_ASSERT_EQUAL(std::string("Edited comment"), 
aView1.m_aCommentCallbackResult.get<std::string>("text"));
     CPPUNIT_ASSERT_EQUAL(std::string("Edited comment"), 
aView2.m_aCommentCallbackResult.get<std::string>("text"));
 
@@ -2633,8 +2633,8 @@ void DesktopLOKTest::testCommentsCallbacksWriter()
     // We received a LOK_CALLBACK_COMMENT callback with comment 'Add' action 
and linked to its parent comment
     CPPUNIT_ASSERT_EQUAL(std::string("Add"), 
aView1.m_aCommentCallbackResult.get<std::string>("action"));
     CPPUNIT_ASSERT_EQUAL(std::string("Add"), 
aView2.m_aCommentCallbackResult.get<std::string>("action"));
-    CPPUNIT_ASSERT_EQUAL(nCommentId1, 
aView1.m_aCommentCallbackResult.get<int>("parent"));
-    CPPUNIT_ASSERT_EQUAL(nCommentId1, 
aView2.m_aCommentCallbackResult.get<int>("parent"));
+    CPPUNIT_ASSERT_EQUAL(nCommentId1, 
aView1.m_aCommentCallbackResult.get<int>("parentId"));
+    CPPUNIT_ASSERT_EQUAL(nCommentId1, 
aView2.m_aCommentCallbackResult.get<int>("parentId"));
     CPPUNIT_ASSERT_EQUAL(std::string("Reply comment again"), 
aView1.m_aCommentCallbackResult.get<std::string>("text"));
     CPPUNIT_ASSERT_EQUAL(std::string("Reply comment again"), 
aView2.m_aCommentCallbackResult.get<std::string>("text"));
 
diff --git a/include/xmloff/xmltoken.hxx b/include/xmloff/xmltoken.hxx
index ee0c6ec57d89..773d54f79318 100644
--- a/include/xmloff/xmltoken.hxx
+++ b/include/xmloff/xmltoken.hxx
@@ -1506,6 +1506,7 @@ namespace xmloff::token {
         XML_PARAGRAPH_START_MARGIN,
         XML_PARALLEL,
         XML_PARAM,
+        XML_PARENT_NAME,
         XML_PARENT_STYLE_NAME,
         XML_PARSE_SQL_STATEMENT,
         XML_PARSED,
diff --git a/schema/libreoffice/OpenDocument-v1.3+libreoffice-schema.rng 
b/schema/libreoffice/OpenDocument-v1.3+libreoffice-schema.rng
index b7ad4b8a1a7c..0f71070ea983 100644
--- a/schema/libreoffice/OpenDocument-v1.3+libreoffice-schema.rng
+++ b/schema/libreoffice/OpenDocument-v1.3+libreoffice-schema.rng
@@ -977,6 +977,11 @@ 
xmlns:loext="urn:org:documentfoundation:names:experimental:office:xmlns:loext:1.
             <rng:ref name="boolean"/>
           </rng:attribute>
         </rng:optional>
+        <rng:optional>
+          <rng:attribute name="loext:parent-name">
+            <rng:ref name="string"/>
+          </rng:attribute>
+        </rng:optional>
       </rng:interleave>
     </rng:define>
 
diff --git a/sw/inc/AnnotationWin.hxx b/sw/inc/AnnotationWin.hxx
index 2a3bf339f581..2aad107fe04e 100644
--- a/sw/inc/AnnotationWin.hxx
+++ b/sw/inc/AnnotationWin.hxx
@@ -30,6 +30,7 @@
 #include "swrect.hxx"
 #include "SidebarWindowsTypes.hxx"
 #include <optional>
+#include <annotationmark.hxx>
 
 class EditView;
 class PopupMenu;
@@ -76,6 +77,7 @@ class SAL_DLLPUBLIC_RTTI SwAnnotationWin final : public 
InterimItemWindow
         OUString GetAuthor() const;
         Date     GetDate() const;
         tools::Time GetTime() const;
+        void GeneratePostItName();
 
         sal_uInt32 MoveCaret();
 
@@ -192,6 +194,7 @@ class SAL_DLLPUBLIC_RTTI SwAnnotationWin final : public 
InterimItemWindow
 
         // Get annotation paraId or generate one if it doesn't exist
         sal_uInt32 GetParaId();
+        sal_uInt32 GetPostItId();
         // Used to generate a unique paraId
         static sal_uInt32 CreateUniqueParaId();
 
diff --git a/sw/inc/docufld.hxx b/sw/inc/docufld.hxx
index 17e99a94225e..71096d5758b0 100644
--- a/sw/inc/docufld.hxx
+++ b/sw/inc/docufld.hxx
@@ -458,6 +458,8 @@ class SW_DLLPUBLIC SwPostItField final : public SwField
     sal_uInt32 m_nPostItId;
     sal_uInt32 m_nParentId;
     sal_uInt32 m_nParaId;
+    sal_uInt32 m_nParentPostItId;
+    OUString m_sParentName; /// Parent comment's name.
 
 public:
     static sal_uInt32 s_nLastPostItId;
@@ -471,7 +473,9 @@ public:
                    const bool bResolved = false,
                    const sal_uInt32 nPostItId = 0,
                    const sal_uInt32 nParentId = 0,
-                   const sal_uInt32 nParaId = 0);
+                   const sal_uInt32 nParaId = 0,
+                   const sal_uInt32 nParentPostItId = 0,
+                   const OUString aParentName = OUString());
 
     SwPostItField(const SwPostItField&) = delete;
     SwPostItField* operator=(const SwPostItField&) = delete;
@@ -486,7 +490,9 @@ public:
     tools::Time GetTime() const                 { return 
tools::Time(m_aDateTime.GetTime()); }
     sal_uInt32 GetPostItId() const             { return m_nPostItId; }
     void SetPostItId(const sal_uInt32 nPostItId = 0);
+    void SetParentPostItId(const sal_uInt32 nParentPostItId = 0);
     sal_uInt32 GetParentId() const             { return m_nParentId; }
+    sal_uInt32 GetParentPostItId() const       { return m_nParentPostItId; }
     void SetParentId(const sal_uInt32 nParentId);
     sal_uInt32 GetParaId() const               { return m_nParaId; }
     void SetParaId(const sal_uInt32 nParaId);
@@ -502,6 +508,8 @@ public:
     const OUString&         GetInitials() const { return m_sInitials;}
     void                    SetName(const OUString& rStr);
     const OUString&         GetName() const { return m_sName;}
+    const OUString&         GetParentName() const { return m_sParentName; }
+    void                    SetParentName(const OUString& rStr);
 
     const OutlinerParaObject* GetTextObject() const { return mpText ? &*mpText 
: nullptr;}
     void SetTextObject( std::optional<OutlinerParaObject> pText );
diff --git a/sw/inc/unoprnms.hxx b/sw/inc/unoprnms.hxx
index 599286022f9a..6553153b459d 100644
--- a/sw/inc/unoprnms.hxx
+++ b/sw/inc/unoprnms.hxx
@@ -88,6 +88,7 @@ inline constexpr OUStringLiteral UNO_NAME_TEXT_RANGE = 
u"TextRange";
 inline constexpr OUStringLiteral UNO_NAME_TEXT_BOX = u"TextBox";
 inline constexpr OUStringLiteral UNO_NAME_TEXT_BOX_CONTENT = u"TextBoxContent";
 inline constexpr OUStringLiteral UNO_NAME_NAME = u"Name";
+inline constexpr OUStringLiteral UNO_NAME_PARENT_NAME = u"ParentName";
 inline constexpr OUStringLiteral UNO_NAME_CHAR_STYLE_NAME = u"CharStyleName";
 inline constexpr OUStringLiteral UNO_NAME_ANCHOR_CHAR_STYLE_NAME = 
u"AnchorCharStyleName";
 inline constexpr OUStringLiteral UNO_NAME_SUFFIX = u"Suffix";
diff --git a/sw/source/core/fields/docufld.cxx 
b/sw/source/core/fields/docufld.cxx
index 6ff655cfa4b6..f52650925ace 100644
--- a/sw/source/core/fields/docufld.cxx
+++ b/sw/source/core/fields/docufld.cxx
@@ -1747,7 +1747,9 @@ SwPostItField::SwPostItField( SwPostItFieldType* pT,
         const bool bResolved,
         const sal_uInt32 nPostItId,
         const sal_uInt32 nParentId,
-        const sal_uInt32 nParaId
+        const sal_uInt32 nParaId,
+        const sal_uInt32 nParentPostItId,
+        const OUString aParentName
 )
     : SwField( pT )
     , m_sText( std::move(aText) )
@@ -1758,6 +1760,8 @@ SwPostItField::SwPostItField( SwPostItFieldType* pT,
     , m_bResolved( bResolved )
     , m_nParentId( nParentId )
     , m_nParaId( nParaId )
+    , m_nParentPostItId ( nParentPostItId )
+    , m_sParentName( aParentName )
 {
     m_nPostItId = nPostItId == 0 ? s_nLastPostItId++ : nPostItId;
 }
@@ -1800,7 +1804,7 @@ bool SwPostItField::GetResolved() const
 std::unique_ptr<SwField> SwPostItField::Copy() const
 {
     std::unique_ptr<SwPostItField> pRet(new SwPostItField( 
static_cast<SwPostItFieldType*>(GetTyp()), m_sAuthor, m_sText, m_sInitials, 
m_sName,
-                                                           m_aDateTime, 
m_bResolved, m_nPostItId, m_nParentId, m_nParaId));
+                                                           m_aDateTime, 
m_bResolved, m_nPostItId, m_nParentId, m_nParaId, m_nParentPostItId, 
m_sParentName));
     if (mpText)
         pRet->SetTextObject( *mpText );
 
@@ -1839,6 +1843,10 @@ void SwPostItField::SetName(const OUString& rName)
     m_sName = rName;
 }
 
+void SwPostItField::SetParentName(const OUString& rName)
+{
+    m_sParentName = rName;
+}
 
 void SwPostItField::SetTextObject( std::optional<OutlinerParaObject> pText )
 {
@@ -1861,6 +1869,11 @@ void SwPostItField::SetPostItId(const sal_uInt32 
nPostItId)
     m_nPostItId = nPostItId == 0 ? s_nLastPostItId++ : nPostItId;
 }
 
+void SwPostItField::SetParentPostItId(const sal_uInt32 nParentPostItId)
+{
+    m_nParentPostItId = nParentPostItId;
+}
+
 void SwPostItField::SetParentId(const sal_uInt32 nParentId)
 {
     m_nParentId = nParentId;
@@ -1889,6 +1902,9 @@ bool SwPostItField::QueryValue( uno::Any& rAny, 
sal_uInt16 nWhichId ) const
     case FIELD_PROP_PAR4:
         rAny <<= m_sName;
         break;
+    case FIELD_PROP_PAR7: // PAR5 (Parent Para Id) and PAR6 (Para Id) are 
skipped - they are not written into xml. Used for file convertion.
+        rAny <<= m_sParentName;
+        break;
     case FIELD_PROP_BOOL1:
         rAny <<= m_bResolved;
         break;
@@ -1955,6 +1971,9 @@ bool SwPostItField::PutValue( const uno::Any& rAny, 
sal_uInt16 nWhichId )
     case FIELD_PROP_PAR4:
         rAny >>= m_sName;
         break;
+    case FIELD_PROP_PAR7: // PAR5 (Parent Para Id) and PAR6 (Para Id) are 
skipped - they are not written into xml. Used for file convertion.
+        rAny >>= m_sParentName;
+        break;
     case FIELD_PROP_BOOL1:
         rAny >>= m_bResolved;
         break;
diff --git a/sw/source/core/inc/bookmark.hxx b/sw/source/core/inc/bookmark.hxx
index 6ba9484b3bd8..8a3fc98f260c 100644
--- a/sw/source/core/inc/bookmark.hxx
+++ b/sw/source/core/inc/bookmark.hxx
@@ -106,6 +106,7 @@ namespace sw::mark {
                     { return m_wXBookmark; }
             void SetXBookmark(rtl::Reference<SwXBookmark> const& xBkmk);
 
+            static OUString GenerateNewName(std::u16string_view rPrefix);
         protected:
             // SwClient
             void SwClientNotify(const SwModify&, const SfxHint&) override;
@@ -114,7 +115,6 @@ namespace sw::mark {
             std::optional<SwPosition> m_oPos1;
             std::optional<SwPosition> m_oPos2;
             OUString m_aName;
-            static OUString GenerateNewName(std::u16string_view rPrefix);
 
             unotools::WeakReference<SwXBookmark> m_wXBookmark;
         };
diff --git a/sw/source/core/inc/unofldmid.h b/sw/source/core/inc/unofldmid.h
index f9b7d5bdc75e..59f4583f3d6f 100644
--- a/sw/source/core/inc/unofldmid.h
+++ b/sw/source/core/inc/unofldmid.h
@@ -49,6 +49,7 @@
 #define FIELD_PROP_TEXT             34
 #define FIELD_PROP_TITLE 35
 #define FIELD_PROP_PAR6             36
+#define FIELD_PROP_PAR7             37
 
 #endif
 
diff --git a/sw/source/core/unocore/unofield.cxx 
b/sw/source/core/unocore/unofield.cxx
index d9924bcd834a..3d0296c964e5 100644
--- a/sw/source/core/unocore/unofield.cxx
+++ b/sw/source/core/unocore/unofield.cxx
@@ -1032,6 +1032,7 @@ struct SwFieldProperties_Impl
     OUString    sPar4;
     OUString    sPar5;
     OUString    sPar6;
+    OUString    sPar7;
     Date            aDate;
     double          fDouble;
     uno::Sequence<beans::PropertyValue> aPropSeq;
@@ -1364,7 +1365,9 @@ void SAL_CALL SwXTextField::attach(
                         m_pImpl->m_pProps->bBool1, // resolvedflag
                         0, // id
                         nParentId, // parent id
-                        nImportedId // imported para id
+                        nImportedId, // imported para id
+                        0, // PostIt Parent ID.
+                        m_pImpl->m_pProps->sPar7
                     );
                     if ( m_pImpl->m_xTextObject.is() )
                     {
@@ -2204,6 +2207,9 @@ SwXTextField::setPropertyValue(
         case FIELD_PROP_PAR4:
             rValue >>= m_pImpl->m_pProps->sPar4;
             break;
+        case FIELD_PROP_PAR7:
+            rValue >>= m_pImpl->m_pProps->sPar7;
+            break;
         case FIELD_PROP_PAR5:
             rValue >>= m_pImpl->m_pProps->sPar5;
             break;
@@ -2410,6 +2416,9 @@ uno::Any SAL_CALL SwXTextField::getPropertyValue(const 
OUString& rPropertyName)
             case FIELD_PROP_PAR4:
                 aRet <<= m_pImpl->m_pProps->sPar4;
                 break;
+            case FIELD_PROP_PAR7:
+                aRet <<= m_pImpl->m_pProps->sPar7;
+                break;
             case FIELD_PROP_PAR5:
                 aRet <<= m_pImpl->m_pProps->sPar5;
                 break;
diff --git a/sw/source/core/unocore/unomap.cxx 
b/sw/source/core/unocore/unomap.cxx
index ea8bb59f5cdd..63db34aa3fbc 100644
--- a/sw/source/core/unocore/unomap.cxx
+++ b/sw/source/core/unocore/unomap.cxx
@@ -898,6 +898,7 @@ o3tl::span<const SfxItemPropertyMapEntry> 
SwUnoPropertyMapProvider::GetPropertyM
                     {UNO_NAME_NAME,       FIELD_PROP_PAR4,    
cppu::UnoType<OUString>::get(),   PROPERTY_NONE, 0},
                     {UNO_NAME_PARA_ID_PARENT,       FIELD_PROP_PAR5,    
cppu::UnoType<OUString>::get(),   PROPERTY_NONE, 0},
                     {UNO_NAME_PARA_ID,       FIELD_PROP_PAR6,    
cppu::UnoType<OUString>::get(),   PROPERTY_NONE, 0},
+                    {UNO_NAME_PARENT_NAME,   FIELD_PROP_PAR7,   
cppu::UnoType<OUString>::get(),   PROPERTY_NONE, 0},
                     {UNO_NAME_RESOLVED,       FIELD_PROP_BOOL1,    
cppu::UnoType<bool>::get(),   PROPERTY_NONE, 0},
                     {UNO_NAME_DATE_TIME_VALUE,    FIELD_PROP_DATE_TIME,   
cppu::UnoType<css::util::DateTime>::get(),    PROPERTY_NONE, 0},
                     {UNO_NAME_DATE,    FIELD_PROP_DATE,   
cppu::UnoType<css::util::Date>::get(),    PROPERTY_NONE, 0},
diff --git a/sw/source/uibase/docvw/AnnotationWin.cxx 
b/sw/source/uibase/docvw/AnnotationWin.cxx
index c8f442dafc26..57c8616f997b 100644
--- a/sw/source/uibase/docvw/AnnotationWin.cxx
+++ b/sw/source/uibase/docvw/AnnotationWin.cxx
@@ -204,6 +204,14 @@ void SwAnnotationWin::SetPostItText()
     Invalidate();
 }
 
+void SwAnnotationWin::GeneratePostItName()
+{
+    if (mpField && mpField->GetName().isEmpty())
+    {
+        
mpField->SetName(sw::mark::MarkBase::GenerateNewName(u"__Annotation__"));
+    }
+}
+
 void SwAnnotationWin::SetResolved(bool resolved)
 {
     bool oldState = IsResolved();
@@ -256,6 +264,12 @@ sal_uInt32 SwAnnotationWin::GetParaId()
     return nParaId;
 }
 
+sal_uInt32 SwAnnotationWin::GetPostItId()
+{
+    auto pField = static_cast<SwPostItField*>(mpFormatField->GetField());
+    return pField->GetPostItId();
+}
+
 sal_uInt32 SwAnnotationWin::CreateUniqueParaId()
 {
     return comphelper::rng::uniform_uint_distribution(0, 
std::numeric_limits<sal_uInt32>::max());
diff --git a/sw/source/uibase/docvw/PostItMgr.cxx 
b/sw/source/uibase/docvw/PostItMgr.cxx
index e85b191a60fb..64579d75124b 100644
--- a/sw/source/uibase/docvw/PostItMgr.cxx
+++ b/sw/source/uibase/docvw/PostItMgr.cxx
@@ -169,8 +169,7 @@ namespace {
             const OString sRects = comphelper::string::join("; ", aRects);
 
             aAnnotation.put("id", pField->GetPostItId());
-            aAnnotation.put("parent", pWin->CalcParent());
-            aAnnotation.put("paraIdParent", pField->GetParentId());
+            aAnnotation.put("parentId", pField->GetParentPostItId());
             aAnnotation.put("author", pField->GetPar1().toUtf8().getStr());
             aAnnotation.put("text", pField->GetPar2().toUtf8().getStr());
             aAnnotation.put("resolved", pField->GetResolved() ? "true" : 
"false");
@@ -1324,6 +1323,30 @@ void SwPostItMgr::AddPostIts(const bool bCheckExistence, 
const bool bFocus)
     SwFieldType* pType = 
mpView->GetDocShell()->GetDoc()->getIDocumentFieldsAccess().GetFieldType(SwFieldIds::Postit,
 OUString(),false);
     std::vector<SwFormatField*> vFormatFields;
     pType->CollectPostIts(vFormatFields, rIDRA, 
mpWrtShell->GetLayout()->IsHideRedlines());
+
+    for (std::vector<SwFormatField*>::iterator i = vFormatFields.begin(); i != 
vFormatFields.end(); i++)
+    {
+        SwPostItField *pChildPostIt = 
static_cast<SwPostItField*>((*i)->GetField());
+
+        if (pChildPostIt->GetParentId() != 0 || 
!pChildPostIt->GetParentName().isEmpty())
+        {
+            for (std::vector<SwFormatField*>::iterator j = 
vFormatFields.begin(); j != vFormatFields.end(); j++)
+            {
+                SwPostItField *pParentPostIt = 
static_cast<SwPostItField*>((*j)->GetField());
+                if (pChildPostIt->GetParentId() != 0 && 
pParentPostIt->GetParaId() == pChildPostIt->GetParentId())
+                {
+                    
pChildPostIt->SetParentPostItId(pParentPostIt->GetPostItId());
+                    pChildPostIt->SetParentName(pParentPostIt->GetName());
+                }
+                else if (!pParentPostIt->GetName().isEmpty() && 
pParentPostIt->GetName() == pChildPostIt->GetParentName())
+                {
+                    
pChildPostIt->SetParentPostItId(pParentPostIt->GetPostItId());
+                    pChildPostIt->SetParentName(pParentPostIt->GetName());
+                }
+            }
+        }
+    }
+
     for(auto pFormatField : vFormatFields)
         InsertItem(pFormatField, bCheckExistence, bFocus);
     // if we just added the first one we have to update the view for centering
diff --git a/sw/source/uibase/shells/textfld.cxx 
b/sw/source/uibase/shells/textfld.cxx
index 70c8ee1c73d9..53fd4471ce37 100644
--- a/sw/source/uibase/shells/textfld.cxx
+++ b/sw/source/uibase/shells/textfld.cxx
@@ -461,6 +461,14 @@ void SwTextShell::ExecField(SfxRequest &rReq)
                             sText = pTextItem->GetValue();
                         pMgr->RegisterAnswerText(sText);
                         pWin->ExecuteCommand(nSlot);
+
+                        // Set the parent postit id of the reply.
+                        
GetView().GetPostItMgr()->GetLatestPostItField()->SetParentPostItId(pIdItem->GetValue().toUInt32());
+
+                        // If name of the replied comment is empty, we need to 
set a name in order to connect them in the xml file.
+                        pWin->GeneratePostItName(); // Generates a name if the 
current name is empty.
+
+                        
GetView().GetPostItMgr()->GetLatestPostItField()->SetParentName(pWin->GetPostItField()->GetName());
                     }
                 }
             }
diff --git a/sw/source/uibase/uno/unotxdoc.cxx 
b/sw/source/uibase/uno/unotxdoc.cxx
index 0bdfdd41f42e..18a4d1b20ce8 100644
--- a/sw/source/uibase/uno/unotxdoc.cxx
+++ b/sw/source/uibase/uno/unotxdoc.cxx
@@ -3370,8 +3370,7 @@ void SwXTextDocument::getPostIts(tools::JsonWriter& 
rJsonWriter)
 
         auto commentNode = rJsonWriter.startStruct();
         rJsonWriter.put("id", pField->GetPostItId());
-        rJsonWriter.put("parent", pWin->CalcParent());
-        rJsonWriter.put("paraIdParent", pField->GetParentId());
+        rJsonWriter.put("parentId", pField->GetParentPostItId());
         rJsonWriter.put("author", pField->GetPar1());
         rJsonWriter.put("text", pField->GetPar2());
         rJsonWriter.put("resolved", pField->GetResolved() ? "true" : "false");
diff --git a/xmloff/inc/txtfldi.hxx b/xmloff/inc/txtfldi.hxx
index 243feb630fc8..0a15329c31ec 100644
--- a/xmloff/inc/txtfldi.hxx
+++ b/xmloff/inc/txtfldi.hxx
@@ -961,6 +961,7 @@ class XMLAnnotationImportContext final : public 
XMLTextFieldImportContext
     OUStringBuffer aAuthorBuffer;
     OUStringBuffer aInitialsBuffer;
     OUString aName;
+    OUString aParentName;
     OUStringBuffer aTextBuffer;
     OUStringBuffer aDateBuffer;
     OUString aResolved;
diff --git a/xmloff/qa/unit/text.cxx b/xmloff/qa/unit/text.cxx
index 8c500dccce24..47bd6d969fb5 100644
--- a/xmloff/qa/unit/text.cxx
+++ b/xmloff/qa/unit/text.cxx
@@ -50,7 +50,7 @@ CPPUNIT_TEST_FIXTURE(XmloffStyleTest, testMailMergeInEditeng)
     loadFromURL(u"mail-merge-editeng.odt");
 }
 
-CPPUNIT_TEST_FIXTURE(XmloffStyleTest, testCommentResolved)
+CPPUNIT_TEST_FIXTURE(XmloffStyleTest, testCommentProperty)
 {
     mxComponent = loadFromDesktop("private:factory/swriter");
     uno::Sequence<beans::PropertyValue> aCommentProps = 
comphelper::InitPropertySequence({
@@ -67,6 +67,7 @@ CPPUNIT_TEST_FIXTURE(XmloffStyleTest, testCommentResolved)
     uno::Reference<beans::XPropertySet> 
xField(xPortion->getPropertyValue("TextField"),
                                                uno::UNO_QUERY);
     xField->setPropertyValue("Resolved", uno::Any(true));
+    xField->setPropertyValue("ParentName", 
uno::Any(OUString("parent_comment_name")));
 
     saveAndReload("writer8");
     xTextDocument.set(mxComponent, uno::UNO_QUERY);
@@ -78,6 +79,11 @@ CPPUNIT_TEST_FIXTURE(XmloffStyleTest, testCommentResolved)
     xField.set(xPortion->getPropertyValue("TextField"), uno::UNO_QUERY);
     bool bResolved = false;
     xField->getPropertyValue("Resolved") >>= bResolved;
+    OUString parentName;
+    xField->getPropertyValue("ParentName") >>= parentName;
+    CPPUNIT_ASSERT_EQUAL(
+        OUString("parent_comment_name"),
+        parentName); // Check if the parent comment name is written and read 
correctly.
     // Without the accompanying fix in place, this test would have failed, as 
the resolved state was
     // not saved for non-range comments.
     CPPUNIT_ASSERT(bResolved);
diff --git a/xmloff/source/core/xmltoken.cxx b/xmloff/source/core/xmltoken.cxx
index eac87c5e2c63..38ee9bb853c3 100644
--- a/xmloff/source/core/xmltoken.cxx
+++ b/xmloff/source/core/xmltoken.cxx
@@ -1519,6 +1519,7 @@ namespace xmloff::token {
         TOKEN( "paragraph-start-margin",          XML_PARAGRAPH_START_MARGIN ),
         TOKEN( "parallel",                        XML_PARALLEL ),
         TOKEN( "param",                           XML_PARAM ),
+        TOKEN( "parent-name",                     XML_PARENT_NAME ),
         TOKEN( "parent-style-name",               XML_PARENT_STYLE_NAME ),
         TOKEN( "parse-sql-statement",             XML_PARSE_SQL_STATEMENT ),
         TOKEN( "parsed",                          XML_PARSED ),
diff --git a/xmloff/source/text/txtflde.cxx b/xmloff/source/text/txtflde.cxx
index a6a0936423d8..271a7d41285d 100644
--- a/xmloff/source/text/txtflde.cxx
+++ b/xmloff/source/text/txtflde.cxx
@@ -342,6 +342,7 @@ constexpr OUStringLiteral gsPropertyItems(u"Items");
 constexpr OUStringLiteral gsPropertyLevel(u"Level");
 constexpr OUStringLiteral gsPropertyMeasureKind(u"Kind");
 constexpr OUStringLiteral gsPropertyName(u"Name");
+constexpr OUStringLiteral gsPropertyParentName(u"ParentName");
 constexpr OUStringLiteral gsPropertyNumberFormat(u"NumberFormat");
 constexpr OUStringLiteral gsPropertyNumberingSeparator(u"NumberingSeparator");
 constexpr OUStringLiteral gsPropertyNumberingType(u"NumberingType");
@@ -1728,6 +1729,14 @@ void XMLTextFieldExport::ExportFieldHelper(
         {
             GetExport().AddAttribute(XML_NAMESPACE_OFFICE, XML_NAME, aName);
         }
+
+        OUString aParentName;
+        rPropSet->getPropertyValue(gsPropertyParentName) >>= aParentName;
+        if (!aParentName.isEmpty())
+        {
+            GetExport().AddAttribute(XML_NAMESPACE_LO_EXT, XML_PARENT_NAME, 
aParentName);
+        }
+
         SvtSaveOptions::ODFSaneDefaultVersion eVersion = 
rExport.getSaneDefaultVersion();
         if (eVersion & SvtSaveOptions::ODFSVER_EXTENDED)
         {
diff --git a/xmloff/source/text/txtfldi.cxx b/xmloff/source/text/txtfldi.cxx
index af89551343c8..dc6fb6646857 100644
--- a/xmloff/source/text/txtfldi.cxx
+++ b/xmloff/source/text/txtfldi.cxx
@@ -106,6 +106,7 @@ constexpr OUStringLiteral sAPI_content  = u"Content";
 constexpr OUStringLiteral sAPI_author   = u"Author";
 constexpr OUStringLiteral sAPI_hint     = u"Hint";
 constexpr OUStringLiteral sAPI_name     = u"Name";
+constexpr OUStringLiteral sAPI_parent_name = u"ParentName";
 constexpr OUStringLiteral sAPI_sub_type = u"SubType";
 constexpr OUStringLiteral sAPI_date_time_value = u"DateTimeValue";
 constexpr OUStringLiteral sAPI_number_format = u"NumberFormat";
@@ -3152,6 +3153,8 @@ void XMLAnnotationImportContext::ProcessAttribute(
         aName = OUString::fromUtf8(sAttrValue);
     else if (nAttrToken == XML_ELEMENT(LO_EXT, XML_RESOLVED))
         aResolved = OUString::fromUtf8(sAttrValue);
+    else if (nAttrToken == XML_ELEMENT(LO_EXT, XML_PARENT_NAME))
+        aParentName = OUString::fromUtf8(sAttrValue);
     else
         XMLOFF_WARN_UNKNOWN_ATTR("xmloff", nAttrToken, sAttrValue);
 }
@@ -3340,6 +3343,9 @@ void XMLAnnotationImportContext::PrepareField(
 
     if (!aName.isEmpty())
         xPropertySet->setPropertyValue(sAPI_name, Any(aName));
+
+    if (!aParentName.isEmpty())
+        xPropertySet->setPropertyValue(sAPI_parent_name, Any(aParentName));
 }
 
 
diff --git a/xmloff/source/token/tokens.txt b/xmloff/source/token/tokens.txt
index 8bc75993eadf..58f8ff8e8c4e 100644
--- a/xmloff/source/token/tokens.txt
+++ b/xmloff/source/token/tokens.txt
@@ -1419,6 +1419,7 @@ paragraph-end-margin
 paragraph-start-margin
 parallel
 param
+parent-name
 parent-style-name
 parse-sql-statement
 parsed

Reply via email to