sw/qa/extras/ooxmlexport/data/comment-annotationref.docx |binary sw/qa/extras/ooxmlexport/ooxmlexport22.cxx | 13 +++++++++++++ sw/source/filter/ww8/docxattributeoutput.cxx | 6 +++++- sw/source/filter/ww8/docxexport.cxx | 9 ++++++++- sw/source/filter/ww8/docxexport.hxx | 3 ++- 5 files changed, 28 insertions(+), 3 deletions(-)
New commits: commit 1dacb5512b23bd804bbbfc184755512c80a8c4fa Author: Jaume Pujantell <jaume.pujant...@collabora.com> AuthorDate: Tue Apr 8 17:56:13 2025 +0200 Commit: Miklos Vajna <vmik...@collabora.com> CommitDate: Fri Apr 11 08:19:15 2025 +0200 tdf#166126 sw: docx: add annotationRef on comments Right now we never add <w:annotationRef/> to any comment when saving to docx. According to the standard, not having it is the same as having it in the beginning. But when round-tripping a document with multiple comments without text from MS Word, the comments get mangled if the annotationRef tags aren't kept. So it's better to always write the implicit annotationRef at the beginning of comments. Change-Id: I6c395bbc691a29533e2be9a93663993e083db65b Reviewed-on: https://gerrit.libreoffice.org/c/core/+/183856 Tested-by: Jenkins CollaboraOffice <jenkinscollaboraoff...@gmail.com> Reviewed-by: Miklos Vajna <vmik...@collabora.com> Reviewed-on: https://gerrit.libreoffice.org/c/core/+/183975 Tested-by: Jenkins diff --git a/sw/qa/extras/ooxmlexport/data/comment-annotationref.docx b/sw/qa/extras/ooxmlexport/data/comment-annotationref.docx new file mode 100644 index 000000000000..2350a8c6bb1d Binary files /dev/null and b/sw/qa/extras/ooxmlexport/data/comment-annotationref.docx differ diff --git a/sw/qa/extras/ooxmlexport/ooxmlexport22.cxx b/sw/qa/extras/ooxmlexport/ooxmlexport22.cxx index 8bcf3ca68762..25559988a6b5 100644 --- a/sw/qa/extras/ooxmlexport/ooxmlexport22.cxx +++ b/sw/qa/extras/ooxmlexport/ooxmlexport22.cxx @@ -234,6 +234,19 @@ DECLARE_OOXMLEXPORT_TEST(testTdf139418, "tdf139418.docx") CPPUNIT_ASSERT_EQUAL(sal_Int32(0), nPorLen3); } +CPPUNIT_TEST_FIXTURE(Test, testAnnotationRef) +{ + loadAndSave("comment-annotationref.docx"); + + // Check that the exported comment also has annotationRef + xmlDocUniquePtr pXmlComments = parseExport(u"word/comments.xml"_ustr); + CPPUNIT_ASSERT(pXmlComments); + // Wihtout the fix it fails with + // - Expected: 1 + // - Actual : 0 + assertXPath(pXmlComments, "//w:comments/w:comment[1]/w:p[1]/w:r[1]/w:annotationRef"); +} + } // end of anonymous namespace CPPUNIT_PLUGIN_IMPLEMENT(); diff --git a/sw/source/filter/ww8/docxattributeoutput.cxx b/sw/source/filter/ww8/docxattributeoutput.cxx index f9e66565ac4c..9e47caf07b18 100644 --- a/sw/source/filter/ww8/docxattributeoutput.cxx +++ b/sw/source/filter/ww8/docxattributeoutput.cxx @@ -8561,7 +8561,8 @@ DocxAttributeOutput::hasProperties DocxAttributeOutput::WritePostitFields() if (f->GetTextObject() != nullptr) { // richtext - data.lastParaId = GetExport().WriteOutliner(*f->GetTextObject(), TXT_ATN, bNeedParaId); + data.lastParaId + = GetExport().WriteOutliner(*f->GetTextObject(), TXT_ATN, bNeedParaId, true); } else { @@ -8575,6 +8576,9 @@ DocxAttributeOutput::hasProperties DocxAttributeOutput::WritePostitFields() } m_pSerializer->startElementNS(XML_w, XML_p, FSNS(XML_w14, XML_paraId), aParaId); m_pSerializer->startElementNS(XML_w, XML_r); + m_pSerializer->singleElementNS(XML_w, XML_annotationRef); + m_pSerializer->endElementNS(XML_w, XML_r); + m_pSerializer->startElementNS(XML_w, XML_r); RunText(f->GetText()); m_pSerializer->endElementNS(XML_w, XML_r); m_pSerializer->endElementNS(XML_w, XML_p); diff --git a/sw/source/filter/ww8/docxexport.cxx b/sw/source/filter/ww8/docxexport.cxx index ebbeaf257f83..c8700e1f7898 100644 --- a/sw/source/filter/ww8/docxexport.cxx +++ b/sw/source/filter/ww8/docxexport.cxx @@ -2024,7 +2024,7 @@ bool DocxExport::ignoreAttributeForStyleDefaults( sal_uInt16 nWhich ) const } sal_Int32 DocxExport::WriteOutliner(const OutlinerParaObject& rParaObj, sal_uInt8 nTyp, - bool bNeedsLastParaId) + bool bNeedsLastParaId, bool bWriteAnnotRef) { const EditTextObject& rEditObj = rParaObj.GetTextObject(); MSWord_SdrAttrIter aAttrIter( *this, rEditObj, nTyp ); @@ -2049,6 +2049,13 @@ sal_Int32 DocxExport::WriteOutliner(const OutlinerParaObject& rParaObj, sal_uInt SfxItemSet aParagraphMarkerProperties(m_rDoc.GetAttrPool()); AttrOutput().EndParagraphProperties(aParagraphMarkerProperties, nullptr, nullptr, nullptr); + if (bWriteAnnotRef && n == 0) + { + m_pAttrOutput->GetSerializer()->startElementNS(XML_w, XML_r); + m_pAttrOutput->GetSerializer()->singleElementNS(XML_w, XML_annotationRef); + m_pAttrOutput->GetSerializer()->endElementNS(XML_w, XML_r); + } + do { AttrOutput().StartRun( nullptr, 0 ); const sal_Int32 nNextAttr = std::min(aAttrIter.WhereNext(), nEnd); diff --git a/sw/source/filter/ww8/docxexport.hxx b/sw/source/filter/ww8/docxexport.hxx index 7588586579d9..8343417f1b19 100644 --- a/sw/source/filter/ww8/docxexport.hxx +++ b/sw/source/filter/ww8/docxexport.hxx @@ -206,7 +206,8 @@ public: /// Writes the shape using drawingML syntax. void OutputDML( css::uno::Reference< css::drawing::XShape > const & xShape ); - sal_Int32 WriteOutliner(const OutlinerParaObject& rOutliner, sal_uInt8 nTyp, bool bNeedsLastParaId); + sal_Int32 WriteOutliner(const OutlinerParaObject& rOutliner, sal_uInt8 nTyp, + bool bNeedsLastParaId, bool bWriteAnnotRef = false); virtual ExportFormat GetExportFormat() const override { return ExportFormat::DOCX; }