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 ab866086efa7c4184e57123486c82ccedb4e98b5 Author: Jaume Pujantell <jaume.pujant...@collabora.com> AuthorDate: Tue Apr 8 17:56:13 2025 +0200 Commit: Jaume Pujantell <jaume.pujant...@collabora.com> CommitDate: Fri Apr 11 09:02:50 2025 +0200 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/+/183976 Reviewed-by: Jaume Pujantell <jaume.pujant...@collabora.com> Tested-by: Jenkins CollaboraOffice <jenkinscollaboraoff...@gmail.com> 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 46991f634f85..463f7f7db7c5 100644 --- a/sw/qa/extras/ooxmlexport/ooxmlexport22.cxx +++ b/sw/qa/extras/ooxmlexport/ooxmlexport22.cxx @@ -55,6 +55,19 @@ CPPUNIT_TEST_FIXTURE(Test, testTdf165933_noDelTextOnMove) assertXPath(pXmlDoc, "//w:moveFrom/w:r/w:delText"_ostr, 0); } +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"_ostr); +} + } // end of anonymous namespace CPPUNIT_PLUGIN_IMPLEMENT(); diff --git a/sw/source/filter/ww8/docxattributeoutput.cxx b/sw/source/filter/ww8/docxattributeoutput.cxx index 18162ccf88e6..0f88ea5a6235 100644 --- a/sw/source/filter/ww8/docxattributeoutput.cxx +++ b/sw/source/filter/ww8/docxattributeoutput.cxx @@ -8488,7 +8488,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 { @@ -8502,6 +8503,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 7abd0d5ebd7c..104f0c92ac89 100644 --- a/sw/source/filter/ww8/docxexport.cxx +++ b/sw/source/filter/ww8/docxexport.cxx @@ -2000,7 +2000,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 ); @@ -2025,6 +2025,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 7f4ab826c40d..b285e998af4d 100644 --- a/sw/source/filter/ww8/docxexport.hxx +++ b/sw/source/filter/ww8/docxexport.hxx @@ -205,7 +205,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; }