summaryrefslogtreecommitdiff
path: root/sw/source
diff options
context:
space:
mode:
authorJustin Luth <justin.luth@collabora.com>2024-04-26 14:23:34 -0400
committerMiklos Vajna <vmiklos@collabora.com>2024-05-06 09:09:53 +0200
commit7ae84ed99b133cdb4c197ecb43e2454f90b0439a (patch)
treebdc177146456286c1e0ebc0acf87e369806d2a4c /sw/source
parent8fe2ab985d974440265f48c6f70dbf813a760c40 (diff)
tdf#160814 writerfilter: insert comment after other comments
If multiple comments all have on the same range (comment replies typically, but not necessarily) then make sure that later replies are not inserted in front of the earlier replies. MSO can anchor their comments anywhere in the document, so this is not a perfect, fool-proof solution. However, it should handle the typical cases. make CppunitTest_sw_ooxmlexport21 / CPPUNIT_TEST_NAME=testTdf160814_commentOrder Change-Id: I8ebdae83e4dec25ee34dffc3e84bbd3068a15f57 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/166765 Reviewed-by: Justin Luth <jluth@mail.com> Reviewed-by: Miklos Vajna <vmiklos@collabora.com> Tested-by: Jenkins
Diffstat (limited to 'sw/source')
-rw-r--r--sw/source/writerfilter/dmapper/DomainMapper_Impl.cxx70
1 files changed, 70 insertions, 0 deletions
diff --git a/sw/source/writerfilter/dmapper/DomainMapper_Impl.cxx b/sw/source/writerfilter/dmapper/DomainMapper_Impl.cxx
index a0f0af0831f5..a26c517064ec 100644
--- a/sw/source/writerfilter/dmapper/DomainMapper_Impl.cxx
+++ b/sw/source/writerfilter/dmapper/DomainMapper_Impl.cxx
@@ -4545,6 +4545,76 @@ void DomainMapper_Impl::PopAnnotation()
}
xCursor->gotoRange(aAnnotationPosition.m_xEnd, true);
+
+ // MS Word can anchor a comment anywhere in the document, but LO always anchors it
+ // immediately at the end of the range it spans.
+ // If multiple comments have the same end-point, we need to expand the range so that
+ // this later comment doesn't insert itself before any earlier ones.
+ const uno::Reference<frame::XModel> xModel(static_cast<SfxBaseModel*>(m_xTextDocument.get()));
+ const uno::Reference<text::XTextFieldsSupplier> xTFS(xModel, uno::UNO_QUERY);
+ if (xTFS.is())
+ {
+ // sadly, the enumeration is not correctly sorted, which really complicates things.
+ const uno::Reference<container::XEnumerationAccess> xFieldEA(xTFS->getTextFields());
+ bool bRetry(false);
+ // keep track of the relevant (unsorted) fields that might have the same end point
+ std::vector<uno::Reference<text::XTextRange>> xRetryFields;
+
+ uno::Reference<container::XEnumeration> xEnum = xFieldEA->createEnumeration();
+ // Although the primary interest is other comments, the same principle
+ // probably applies to any kind of field.
+ while (xEnum->hasMoreElements())
+ {
+ try
+ {
+ // IMPORTANT: nextElement() MUST run before any possible exception...
+ const uno::Reference<text::XTextField> xField(xEnum->nextElement(),
+ uno::UNO_QUERY_THROW);
+ if (xTextRangeCompare->compareRegionStarts(xCursor->getEnd(),
+ xField->getAnchor()) == 1)
+ {
+ // Not interesting: our comment-to-insert ends before this field begins
+ continue;
+ }
+
+ const sal_Int32 nCompare = xTextRangeCompare->compareRegionEnds(
+ xCursor->getEnd(), xField->getAnchor());
+ if (nCompare == 0) // both end at the same spot
+ {
+ bRetry = xCursor->goRight(1, true);
+ }
+ else if (nCompare == 1) // this field ends later than our comment-to-insert
+ {
+ // current implementation of SwModify::Add is basically in reverse order
+ // so placing at the front of the list should effectively sort them.
+ xRetryFields.emplace(xRetryFields.begin(), xField->getAnchor());
+ }
+ }
+ catch (uno::Exception&)
+ {
+ }
+ }
+ // if the comment range expanded, retry with cached relevant fields
+ while (bRetry && xRetryFields.size())
+ {
+ bRetry = false;
+ auto iter = xRetryFields.cbegin();
+ while (iter != xRetryFields.cend())
+ {
+ const sal_Int32 nCompare
+ = xTextRangeCompare->compareRegionEnds(xCursor->getEnd(), *iter);
+ if (nCompare == 1) // this field still ends later than our comment
+ ++iter;
+ else
+ {
+ iter = xRetryFields.erase(iter);
+ if (nCompare == 0) // both end at the same spot
+ bRetry = xCursor->goRight(1, true);
+ }
+ }
+ }
+ }
+
uno::Reference<text::XTextRange> const xTextRange(xCursor, uno::UNO_QUERY_THROW);
// Attach the annotation to the range.