sw/inc/ndtxt.hxx                       |   11 +++++++
 sw/source/core/crsr/annotationmark.cxx |   12 +++++---
 sw/source/core/txtnode/ndtxt.cxx       |   49 +++++++++++++++++++++++++++++++++
 sw/source/core/txtnode/thints.cxx      |    5 ++-
 4 files changed, 72 insertions(+), 5 deletions(-)

New commits:
commit d3716d69b298bd817cc8a06b4b7cfbe7191d00dc
Author:     Gökay Şatır <gokaysa...@collabora.com>
AuthorDate: Wed Nov 27 12:10:19 2024 +0300
Commit:     Miklos Vajna <vmik...@collabora.com>
CommitDate: Fri Nov 29 11:58:59 2024 +0100

    cool#10610 Ensure the parent-child relations of comments.
    
    Previously, parent-child (comment-reply) relations were established using 
the position of comments.
    For some time now, users can add comments to the same position and they 
still won't be replies to first comment.
    This is provided with parent-name, parentPostItId etc variables.
    When copying a portion of text, comments are also copied.
    While copying the comments, we need to re-establish their parent-child 
relations.
    This code uses a temp map for the purpose and re-connects replies to their 
new parent comments.
    
    Signed-off-by: Gökay Şatır <gokaysa...@collabora.com>
    Change-Id: Id0fe7f419228b115a6e3d1e10ccb2fc70db57cea
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/177396
    Reviewed-by: Miklos Vajna <vmik...@collabora.com>
    Tested-by: Jenkins CollaboraOffice <jenkinscollaboraoff...@gmail.com>

diff --git a/sw/inc/ndtxt.hxx b/sw/inc/ndtxt.hxx
index 352dad71c247..1024974c60b6 100644
--- a/sw/inc/ndtxt.hxx
+++ b/sw/inc/ndtxt.hxx
@@ -37,6 +37,7 @@
 #include <memory>
 #include <vector>
 #include <functional>
+#include <map>
 
 class SfxHint;
 class SwNumRule;
@@ -375,6 +376,16 @@ public:
                const SwPosition &rStart,
                sal_Int32 nLen,
                const bool bForceCopyOfAllAttrs = false );
+    /*
+        After copying a text portion with its comments, the replies will still 
reference to their original parent.
+        We need to set their reference to their copied-parent.
+        idMapForComments and nameMapForComments variables hold the original 
ids of comments as keys.
+        And they hold the new ids and names of comments as values.
+        So we can find a reply's (child comment) new parent (value) by looking 
up its original parent (key).
+    */
+    static void EstablishParentChildRelationsOfComments(const SwTextNode* 
pDest,
+                std::map<sal_Int32, sal_Int32>& idMapForComments,
+                std::map<sal_Int32, OUString>& nameMapForComments);
 
     void        CutText(SwTextNode * const pDest,
                     const SwContentIndex & rStart, const sal_Int32 nLen);
diff --git a/sw/source/core/crsr/annotationmark.cxx 
b/sw/source/core/crsr/annotationmark.cxx
index 28e0bcf85b24..af3f7c656b64 100644
--- a/sw/source/core/crsr/annotationmark.cxx
+++ b/sw/source/core/crsr/annotationmark.cxx
@@ -59,14 +59,18 @@ namespace sw::mark
         auto pPostItField
             = dynamic_cast<const 
SwPostItField*>(pTextField->GetFormatField().GetField());
         assert(pPostItField);
+
         // use the annotation mark's name as the annotation name, if
         // - the annotation field has an empty annotation name or
         // - the annotation mark's name differs (on mark creation a name clash 
had been detected)
-        if ( pPostItField->GetName().isEmpty()
-            || pPostItField->GetName() != GetName() )
-        {
+
+        // For parent-child relation of comments, we rely on the name of 
parent comments.
+        // Changing the name here breaks the relation which established while 
copying them.
+        // Instead of changing the name of the field, now we change the name 
of the annotation mark - hoping to prevent name clashes still (see above 
comment).
+        if (!pPostItField->GetName().isEmpty())
+            SetName( pPostItField->GetName() );
+        else if (pPostItField->GetName() != GetName() || 
pPostItField->GetName().isEmpty())
             const_cast<SwPostItField*>(pPostItField)->SetName( GetName() );
-        }
 
         if (io_rDoc.GetIDocumentUndoRedo().DoesUndo())
         {
diff --git a/sw/source/core/txtnode/ndtxt.cxx b/sw/source/core/txtnode/ndtxt.cxx
index c679afc618a6..458d1e99f637 100644
--- a/sw/source/core/txtnode/ndtxt.cxx
+++ b/sw/source/core/txtnode/ndtxt.cxx
@@ -52,6 +52,7 @@
 #include <IDocumentRedlineAccess.hxx>
 #include <IDocumentLayoutAccess.hxx>
 #include <docary.hxx>
+#include <docufld.hxx>
 #include <pam.hxx>
 #include <fldbas.hxx>
 #include <paratr.hxx>
@@ -2104,6 +2105,35 @@ void SwTextNode::CopyText( SwTextNode *const pDest,
     CopyText( pDest, rDestStart, rStart.nContent, nLen, bForceCopyOfAllAttrs );
 }
 
+void SwTextNode::EstablishParentChildRelationsOfComments(
+    const SwTextNode* pDest,
+    std::map<sal_Int32, sal_Int32>& idMapForComments,
+    std::map<sal_Int32, OUString>& nameMapForComments
+)
+{
+    if (idMapForComments.size() > 0)
+    {
+        const SwpHints &rDestHints = pDest->GetSwpHints();
+        size_t hintCount = rDestHints.Count();
+        for (size_t inDest = 0; inDest < hintCount; inDest++)
+        {
+            if (rDestHints.Get(inDest)->Which() == RES_TXTATR_ANNOTATION)
+            {
+                SwPostItField* copiedField = 
const_cast<SwPostItField*>(static_cast<const 
SwPostItField*>(rDestHints.Get(inDest)->GetFormatField().GetField()));
+                if (copiedField && copiedField->GetParentPostItId() != 0)
+                {
+                    const auto correspondingParentItem = 
idMapForComments.find(copiedField->GetParentPostItId());
+                    if (correspondingParentItem != idMapForComments.end())
+                    {
+                        
copiedField->SetParentName(nameMapForComments[copiedField->GetParentPostItId()]);
 // Set name first, parent id will change.
+                        
copiedField->SetParentPostItId(correspondingParentItem->second);
+                    }
+                }
+            }
+        }
+    }
+}
+
 void SwTextNode::CopyText( SwTextNode *const pDest,
                       const SwContentIndex &rDestStart,
                       const SwContentIndex &rStart,
@@ -2219,6 +2249,16 @@ void SwTextNode::CopyText( SwTextNode *const pDest,
     SwpHts aRefMrkArr;
 
     std::vector<std::pair<sal_Int32, sal_Int32>> metaFieldRanges;
+
+    /*
+        Annotations are also copied along with other fields.
+        Annotations have parentPostItId field, used for parent-child relation.
+        So we also need to set parent ids of comments when applicable.
+        Below map variable is for memorizing the new ids and names of parent 
postits in the source node, then we will use them in target node.
+    */
+    std::map<sal_Int32, sal_Int32> idMapForComments;
+    std::map<sal_Int32, OUString> nameMapForComments;
+
     sal_Int32 nDeletedDummyChars(0);
     for (size_t n = 0; n < nSize; ++n)
     {
@@ -2327,6 +2367,13 @@ void SwTextNode::CopyText( SwTextNode *const pDest,
             if (pNewHt)
             {
                 lcl_CopyHint( nWhich, pHt, pNewHt, pOtherDoc, pDest );
+                if (nWhich == RES_TXTATR_ANNOTATION)
+                {
+                    const SwPostItField* annotationField = static_cast<const 
SwPostItField*>(pHt->GetFormatField().GetField());
+                    // Preparation for EstablishParentChildRelationsOfComments.
+                    idMapForComments[annotationField->GetPostItId()] = 
static_cast<const 
SwPostItField*>(pNewHt->GetFormatField().GetField())->GetPostItId();
+                    nameMapForComments[annotationField->GetPostItId()] = 
static_cast<const 
SwPostItField*>(pNewHt->GetFormatField().GetField())->GetName();
+                }
             }
             else if (pHt->HasDummyChar())
             {
@@ -2356,6 +2403,8 @@ void SwTextNode::CopyText( SwTextNode *const pDest,
         }
     }
 
+    EstablishParentChildRelationsOfComments(pDest, idMapForComments, 
nameMapForComments);
+
     // this can only happen when copying into self
     for (SwTextAttr* i : aArr)
     {
diff --git a/sw/source/core/txtnode/thints.cxx 
b/sw/source/core/txtnode/thints.cxx
index c499294f4f26..942cb0080abd 100644
--- a/sw/source/core/txtnode/thints.cxx
+++ b/sw/source/core/txtnode/thints.cxx
@@ -20,6 +20,7 @@
 #include <sal/config.h>
 #include <sal/log.hxx>
 
+#include <bookmark.hxx>
 #include <DocumentContentOperationsManager.hxx>
 #include <hintids.hxx>
 #include <editeng/rsiditem.hxx>
@@ -1098,7 +1099,9 @@ SwTextAttr* MakeTextAttr(
                 // If the annotation mark is also copied, the relation and 
thus the annotated text range will be reestablished,
                 // when the annotation mark is created and inserted into the 
document.
                 auto& pField = const_cast<SwPostItField&>(dynamic_cast<const 
SwPostItField&>(*(pNew->GetFormatField().GetField())));
-                pField.SetName(OUString());
+
+                // We set the name here to make the object referencable.
+                
pField.SetName(sw::mark::MarkBase::GenerateNewName(u"__Annotation__"));
                 pField.SetPostItId();
             }
         }

Reply via email to