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(); } }