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 b0a4afc58e1c9434e56ddb96c41f4ebe5985ed0a Author: Gökay Şatır <[email protected]> AuthorDate: Wed Nov 27 12:10:19 2024 +0300 Commit: Miklos Vajna <[email protected]> CommitDate: Fri Jan 31 18:41:43 2025 +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. Change-Id: Id0fe7f419228b115a6e3d1e10ccb2fc70db57cea Reviewed-on: https://gerrit.libreoffice.org/c/core/+/180991 Tested-by: Jenkins Reviewed-by: Miklos Vajna <[email protected]> diff --git a/sw/inc/ndtxt.hxx b/sw/inc/ndtxt.hxx index 0678c4086cd6..db42d937ef18 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; @@ -383,6 +384,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 033e65bf5de7..686a5ff15849 100644 --- a/sw/source/core/txtnode/ndtxt.cxx +++ b/sw/source/core/txtnode/ndtxt.cxx @@ -53,6 +53,7 @@ #include <IDocumentRedlineAccess.hxx> #include <IDocumentLayoutAccess.hxx> #include <docary.hxx> +#include <docufld.hxx> #include <pam.hxx> #include <fldbas.hxx> #include <paratr.hxx> @@ -2097,6 +2098,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, @@ -2212,6 +2242,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) { @@ -2320,6 +2360,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()) { @@ -2349,6 +2396,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 9330d2e037bd..f0da91513913 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> @@ -1092,7 +1093,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(); } }
