oox/source/token/tokens.txt | 1 sw/inc/docufld.hxx | 10 +++ sw/inc/unoprnms.hxx | 2 sw/qa/extras/ooxmlexport/data/CommentReply.docx |binary sw/qa/extras/ooxmlexport/ooxmlexport16.cxx | 16 +++++ sw/source/core/fields/docufld.cxx | 50 ++++++++++++++++- sw/source/core/inc/unofldmid.h | 1 sw/source/core/unocore/unofield.cxx | 27 +++++++++ sw/source/core/unocore/unomap.cxx | 2 sw/source/filter/ww8/docxattributeoutput.cxx | 51 +++++++++++++++--- sw/source/filter/ww8/docxattributeoutput.hxx | 12 +++- sw/source/filter/ww8/docxexport.cxx | 4 - writerfilter/inc/dmapper/CommentProperties.hxx | 6 +- writerfilter/source/dmapper/DomainMapper_Impl.cxx | 7 ++ writerfilter/source/dmapper/DomainMapper_Impl.hxx | 2 writerfilter/source/ooxml/OOXMLFastContextHandler.cxx | 7 ++ writerfilter/source/ooxml/OOXMLFastContextHandler.hxx | 2 writerfilter/source/ooxml/model.xml | 3 - 18 files changed, 183 insertions(+), 20 deletions(-)
New commits: commit 0c2ed51a775871c91ac8f01c8982f23c34e8248d Author: Paris Oplopoios <paris.oplopo...@collabora.com> AuthorDate: Fri Jan 13 19:49:23 2023 +0200 Commit: Miklos Vajna <vmik...@collabora.com> CommitDate: Wed Jan 18 15:28:37 2023 +0000 tdf#119229 docx: Preserve w15:paraIdParent attribute in commentsExtended w15:paraIdParent attribute indicates that the comment is a reply to the value id Change-Id: I9e6eca6a656594c956629c1434b8e5c3aa573c60 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/145314 Tested-by: Jenkins Reviewed-by: Miklos Vajna <vmik...@collabora.com> diff --git a/oox/source/token/tokens.txt b/oox/source/token/tokens.txt index 25951891d2a7..dee9010df789 100644 --- a/oox/source/token/tokens.txt +++ b/oox/source/token/tokens.txt @@ -3884,6 +3884,7 @@ parTransId parTxLTRAlign parTxRTLAlign paraId +paraIdParent paragraph parallel parallelogram diff --git a/sw/inc/docufld.hxx b/sw/inc/docufld.hxx index b907763a2d8c..89a5341222db 100644 --- a/sw/inc/docufld.hxx +++ b/sw/inc/docufld.hxx @@ -456,6 +456,8 @@ class SW_DLLPUBLIC SwPostItField final : public SwField std::optional<OutlinerParaObject> mpText; rtl::Reference<SwTextAPIObject> m_xTextObject; sal_uInt32 m_nPostItId; + sal_uInt32 m_nParentId; + sal_uInt32 m_nParaId; public: static sal_uInt32 s_nLastPostItId; @@ -467,7 +469,9 @@ public: OUString aName, const DateTime& rDate, const bool bResolved = false, - const sal_uInt32 nPostItId = 0); + const sal_uInt32 nPostItId = 0, + const sal_uInt32 nParentId = 0, + const sal_uInt32 nParaId = 0); SwPostItField(const SwPostItField&) = delete; SwPostItField* operator=(const SwPostItField&) = delete; @@ -482,6 +486,10 @@ public: tools::Time GetTime() const { return tools::Time(m_aDateTime.GetTime()); } sal_uInt32 GetPostItId() const { return m_nPostItId; } void SetPostItId(const sal_uInt32 nPostItId = 0); + sal_uInt32 GetParentId() const { return m_nParentId; } + void SetParentId(const sal_uInt32 nParentId); + sal_uInt32 GetParaId() const { return m_nParaId; } + void SetParaId(const sal_uInt32 nParaId); /// Author virtual OUString GetPar1() const override; diff --git a/sw/inc/unoprnms.hxx b/sw/inc/unoprnms.hxx index 85a1938d61ce..eb70f1d79d8d 100644 --- a/sw/inc/unoprnms.hxx +++ b/sw/inc/unoprnms.hxx @@ -923,6 +923,8 @@ inline constexpr OUStringLiteral UNO_NAME_ID = u"Id"; inline constexpr OUStringLiteral UNO_NAME_TAB_INDEX = u"TabIndex"; inline constexpr OUStringLiteral UNO_NAME_LOCK = u"Lock"; inline constexpr OUStringLiteral UNO_NAME_DATE_STRING = u"DateString"; +inline constexpr OUStringLiteral UNO_NAME_PARA_ID = u"ParaId"; +inline constexpr OUStringLiteral UNO_NAME_PARA_ID_PARENT = u"ParaIdParent"; #endif /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/qa/extras/ooxmlexport/data/CommentReply.docx b/sw/qa/extras/ooxmlexport/data/CommentReply.docx new file mode 100644 index 000000000000..4a78d84d55e6 Binary files /dev/null and b/sw/qa/extras/ooxmlexport/data/CommentReply.docx differ diff --git a/sw/qa/extras/ooxmlexport/ooxmlexport16.cxx b/sw/qa/extras/ooxmlexport/ooxmlexport16.cxx index 4c27a18101fd..30ef1735c73f 100644 --- a/sw/qa/extras/ooxmlexport/ooxmlexport16.cxx +++ b/sw/qa/extras/ooxmlexport/ooxmlexport16.cxx @@ -880,6 +880,22 @@ DECLARE_OOXMLEXPORT_TEST(testTdf105688, "tdf105688.docx") CPPUNIT_ASSERT_EQUAL(2, getPages()); } +CPPUNIT_TEST_FIXTURE(Test, testCommentReply) +{ + loadAndSave("CommentReply.docx"); + xmlDocUniquePtr pXmlComm = parseExport("word/comments.xml"); + xmlDocUniquePtr pXmlCommExt = parseExport("word/commentsExtended.xml"); + OUString sParentId = getXPath(pXmlComm, "/w:comments/w:comment[1]/w:p[1]", "paraId"); + OUString sChildId = getXPath(pXmlComm, "/w:comments/w:comment[2]/w:p[1]", "paraId"); + OUString sChildIdEx = getXPath(pXmlCommExt, "/w15:commentsEx/w15:commentEx", "paraId"); + OUString sChildParentId = getXPath(pXmlCommExt, + "/w15:commentsEx/w15:commentEx", "paraIdParent"); + // Make sure exported extended paraId matches the one in comments.xml + CPPUNIT_ASSERT_EQUAL(sChildId, sChildIdEx); + // Make sure the paraIdParent matches the id of its parent + CPPUNIT_ASSERT_EQUAL(sParentId, sChildParentId); +} + CPPUNIT_TEST_FIXTURE(Test, testCommentDone) { loadAndSave("CommentDone.docx"); diff --git a/sw/source/core/fields/docufld.cxx b/sw/source/core/fields/docufld.cxx index 98010119566e..d9e998ad41f4 100644 --- a/sw/source/core/fields/docufld.cxx +++ b/sw/source/core/fields/docufld.cxx @@ -1741,7 +1741,9 @@ SwPostItField::SwPostItField( SwPostItFieldType* pT, OUString aName, const DateTime& rDateTime, const bool bResolved, - const sal_uInt32 nPostItId + const sal_uInt32 nPostItId, + const sal_uInt32 nParentId, + const sal_uInt32 nParaId ) : SwField( pT ) , m_sText( std::move(aText) ) @@ -1750,6 +1752,8 @@ SwPostItField::SwPostItField( SwPostItFieldType* pT, , m_sName( std::move(aName) ) , m_aDateTime( rDateTime ) , m_bResolved( bResolved ) + , m_nParentId( nParentId ) + , m_nParaId( nParaId ) { m_nPostItId = nPostItId == 0 ? s_nLastPostItId++ : nPostItId; } @@ -1792,7 +1796,7 @@ bool SwPostItField::GetResolved() const std::unique_ptr<SwField> SwPostItField::Copy() const { std::unique_ptr<SwPostItField> pRet(new SwPostItField( static_cast<SwPostItFieldType*>(GetTyp()), m_sAuthor, m_sText, m_sInitials, m_sName, - m_aDateTime, m_bResolved, m_nPostItId)); + m_aDateTime, m_bResolved, m_nPostItId, m_nParentId, m_nParaId)); if (mpText) pRet->SetTextObject( *mpText ); @@ -1847,6 +1851,16 @@ void SwPostItField::SetPostItId(const sal_uInt32 nPostItId) m_nPostItId = nPostItId == 0 ? s_nLastPostItId++ : nPostItId; } +void SwPostItField::SetParentId(const sal_uInt32 nParentId) +{ + m_nParentId = nParentId; +} + +void SwPostItField::SetParaId(const sal_uInt32 nParaId) +{ + m_nParaId = nParaId; +} + bool SwPostItField::QueryValue( uno::Any& rAny, sal_uInt16 nWhichId ) const { switch( nWhichId ) @@ -1897,6 +1911,24 @@ bool SwPostItField::QueryValue( uno::Any& rAny, sal_uInt16 nWhichId ) const rAny <<= m_aDateTime.GetUNODateTime(); } break; + case FIELD_PROP_PAR5: + { + OUString sTemp; + std::stringstream ss; + ss << std::uppercase << std::hex << m_nParentId; + sTemp = OUString::createFromAscii(ss.str().c_str()); + rAny <<= sTemp; + } + break; + case FIELD_PROP_PAR6: + { + OUString sTemp; + std::stringstream ss; + ss << std::uppercase << std::hex << m_nPostItId; + sTemp = OUString::createFromAscii(ss.str().c_str()); + rAny <<= sTemp; + } + break; default: assert(false); } @@ -1941,6 +1973,20 @@ bool SwPostItField::PutValue( const uno::Any& rAny, sal_uInt16 nWhichId ) m_aDateTime = DateTime(aDateTimeValue); } break; + case FIELD_PROP_PAR5: + { + OUString sTemp; + rAny >>= sTemp; + m_nParentId = sTemp.toInt32(16); + } + break; + case FIELD_PROP_PAR6: + { + OUString sTemp; + rAny >>= sTemp; + m_nPostItId = sTemp.toInt32(16); + } + break; default: assert(false); } diff --git a/sw/source/core/inc/unofldmid.h b/sw/source/core/inc/unofldmid.h index e6146fe011a5..f9b7d5bdc75e 100644 --- a/sw/source/core/inc/unofldmid.h +++ b/sw/source/core/inc/unofldmid.h @@ -48,6 +48,7 @@ #define FIELD_PROP_TEXT 34 #define FIELD_PROP_TITLE 35 +#define FIELD_PROP_PAR6 36 #endif diff --git a/sw/source/core/unocore/unofield.cxx b/sw/source/core/unocore/unofield.cxx index 84ae8fe2d8f5..d5126bfaaf81 100644 --- a/sw/source/core/unocore/unofield.cxx +++ b/sw/source/core/unocore/unofield.cxx @@ -1042,6 +1042,8 @@ struct SwFieldProperties_Impl OUString sPar2; OUString sPar3; OUString sPar4; + OUString sPar5; + OUString sPar6; Date aDate; double fDouble; uno::Sequence<beans::PropertyValue> aPropSeq; @@ -1373,6 +1375,14 @@ void SAL_CALL SwXTextField::attach( { aDateTime = *(m_pImpl->m_pProps->pDateTime); } + + sal_uInt32 nImportedId = 0; + if (!m_pImpl->m_pProps->sPar6.isEmpty()) + nImportedId = m_pImpl->m_pProps->sPar6.toInt32(16); + sal_uInt32 nParentId = 0; + if (!m_pImpl->m_pProps->sPar5.isEmpty()) + nParentId = m_pImpl->m_pProps->sPar5.toInt32(16); + SwPostItField* pPostItField = new SwPostItField( static_cast<SwPostItFieldType*>(pFieldType), m_pImpl->m_pProps->sPar1, // author @@ -1380,7 +1390,10 @@ void SAL_CALL SwXTextField::attach( m_pImpl->m_pProps->sPar3, // author's initials m_pImpl->m_pProps->sPar4, // name aDateTime, - m_pImpl->m_pProps->bBool1 // resolvedflag + m_pImpl->m_pProps->bBool1, // resolvedflag + 0, // id + nParentId, // parent id + nImportedId // imported para id ); if ( m_pImpl->m_xTextObject.is() ) { @@ -2220,6 +2233,12 @@ SwXTextField::setPropertyValue( case FIELD_PROP_PAR4: rValue >>= m_pImpl->m_pProps->sPar4; break; + case FIELD_PROP_PAR5: + rValue >>= m_pImpl->m_pProps->sPar5; + break; + case FIELD_PROP_PAR6: + rValue >>= m_pImpl->m_pProps->sPar6; + break; case FIELD_PROP_FORMAT: rValue >>= m_pImpl->m_pProps->nFormat; m_pImpl->m_pProps->bFormatIsDefault = false; @@ -2420,6 +2439,12 @@ uno::Any SAL_CALL SwXTextField::getPropertyValue(const OUString& rPropertyName) case FIELD_PROP_PAR4: aRet <<= m_pImpl->m_pProps->sPar4; break; + case FIELD_PROP_PAR5: + aRet <<= m_pImpl->m_pProps->sPar5; + break; + case FIELD_PROP_PAR6: + aRet <<= m_pImpl->m_pProps->sPar6; + break; case FIELD_PROP_FORMAT: aRet <<= m_pImpl->m_pProps->nFormat; break; diff --git a/sw/source/core/unocore/unomap.cxx b/sw/source/core/unocore/unomap.cxx index 0e036bff1884..92f0d8aea861 100644 --- a/sw/source/core/unocore/unomap.cxx +++ b/sw/source/core/unocore/unomap.cxx @@ -855,6 +855,8 @@ o3tl::span<const SfxItemPropertyMapEntry> SwUnoPropertyMapProvider::GetPropertyM {UNO_NAME_CONTENT, FIELD_PROP_PAR2, cppu::UnoType<OUString>::get(), PROPERTY_NONE, 0}, {UNO_NAME_INITIALS, FIELD_PROP_PAR3, cppu::UnoType<OUString>::get(), PROPERTY_NONE, 0}, {UNO_NAME_NAME, FIELD_PROP_PAR4, cppu::UnoType<OUString>::get(), PROPERTY_NONE, 0}, + {UNO_NAME_PARA_ID_PARENT, FIELD_PROP_PAR5, cppu::UnoType<OUString>::get(), PROPERTY_NONE, 0}, + {UNO_NAME_PARA_ID, FIELD_PROP_PAR6, cppu::UnoType<OUString>::get(), PROPERTY_NONE, 0}, {UNO_NAME_RESOLVED, FIELD_PROP_BOOL1, cppu::UnoType<bool>::get(), PROPERTY_NONE, 0}, {UNO_NAME_DATE_TIME_VALUE, FIELD_PROP_DATE_TIME, cppu::UnoType<css::util::DateTime>::get(), PROPERTY_NONE, 0}, {UNO_NAME_DATE, FIELD_PROP_DATE, cppu::UnoType<css::util::Date>::get(), PROPERTY_NONE, 0}, diff --git a/sw/source/filter/ww8/docxattributeoutput.cxx b/sw/source/filter/ww8/docxattributeoutput.cxx index fd4794593f1f..e1516042cd95 100644 --- a/sw/source/filter/ww8/docxattributeoutput.cxx +++ b/sw/source/filter/ww8/docxattributeoutput.cxx @@ -8794,12 +8794,29 @@ void DocxAttributeOutput::WritePostitFieldReference() } } -DocxAttributeOutput::hasResolved DocxAttributeOutput::WritePostitFields() +DocxAttributeOutput::hasProperties DocxAttributeOutput::WritePostitFields() { bool bRemovePersonalInfo = SvtSecurityOptions::IsOptionSet( SvtSecurityOptions::EOption::DocWarnRemovePersonalInfo ); - hasResolved eResult = hasResolved::no; + hasProperties eResult = hasProperties::no; + for (auto& [f1, data1] : m_postitFields) + { + if (f1->GetParentId() != 0) + { + for (size_t i = 0; i < m_postitFields.size(); i++) + { + auto& [f2, data2] = m_postitFields[i]; + if (f2->GetParaId() == f1->GetParentId()) + { + data2.parentStatus = ParentStatus::IsParent; + data1.parentStatus = ParentStatus::HasParent; + data1.parentIndex = i; + break; + } + } + } + } for (auto& [f, data] : m_postitFields) { OString idstr = OString::number(data.id); @@ -8821,9 +8838,10 @@ DocxAttributeOutput::hasResolved DocxAttributeOutput::WritePostitFields() : f->GetInitials().toUtf8()); m_pSerializer->startElementNS( XML_w, XML_comment, pAttributeList ); - const bool bNeedParaId = f->GetResolved(); + // Make sure to give parent/child fields a paraId + const bool bNeedParaId = f->GetResolved() || data.parentStatus != ParentStatus::None; if (bNeedParaId) - eResult = hasResolved::yes; + eResult = hasProperties::yes; if (f->GetTextObject() != nullptr) { @@ -8856,11 +8874,30 @@ void DocxAttributeOutput::WritePostItFieldsResolved() { for (auto& [f, data] : m_postitFields) { - if (!f->GetResolved()) + // Parent fields don't need to be exported here if they don't have a resolved attribute + if (!f->GetResolved() && data.parentStatus != ParentStatus::HasParent) continue; OUString idstr = NumberToHexBinary(data.lastParaId); - m_pSerializer->singleElementNS(XML_w15, XML_commentEx, FSNS(XML_w15, XML_paraId), idstr, - FSNS(XML_w15, XML_done), "1"); + std::optional<OUString> sDone, sParentId; + if (f->GetParentId() != 0) + { + if (data.parentStatus == ParentStatus::HasParent) + { + // Since parent fields have been resolved first, they should already have an id + auto& aParentFieldData = m_postitFields[data.parentIndex].second; + sParentId = NumberToHexBinary(aParentFieldData.lastParaId); + } + else + { + SAL_WARN("sw.ww8", "SwPostItField has a parent id, but a matching parent was not found"); + } + } + if (f->GetResolved()) + sDone = "1"; + m_pSerializer->singleElementNS(XML_w15, XML_commentEx, + FSNS(XML_w15, XML_paraId), idstr, + FSNS(XML_w15, XML_done), sDone, + FSNS(XML_w15, XML_paraIdParent), sParentId); } } diff --git a/sw/source/filter/ww8/docxattributeoutput.hxx b/sw/source/filter/ww8/docxattributeoutput.hxx index 989a76268e81..1f5cda25eda3 100644 --- a/sw/source/filter/ww8/docxattributeoutput.hxx +++ b/sw/source/filter/ww8/docxattributeoutput.hxx @@ -982,9 +982,17 @@ private: std::vector<PostponedDrawing> m_aPostponedActiveXControls; const SwField* m_PendingPlaceholder; + enum class ParentStatus + { + None, + IsParent, + HasParent + }; struct PostItDOCXData{ sal_Int32 id; sal_Int32 lastParaId = 0; // [MS-DOCX] 2.5.3.1 CT_CommentEx needs paraId attribute + ParentStatus parentStatus = ParentStatus::None; + size_t parentIndex = 0; }; /// Maps postit fields to ID's, used in commentRangeStart/End, commentReference and comment.xml. std::vector<std::pair<const SwPostItField*, PostItDOCXData>> m_postitFields; @@ -1061,8 +1069,8 @@ public: static void WriteFootnoteEndnotePr( ::sax_fastparser::FSHelperPtr const & fs, int tag, const SwEndNoteInfo& info, int listtag ); bool HasPostitFields() const; - enum class hasResolved { no, yes }; - hasResolved WritePostitFields(); + enum class hasProperties { no, yes }; + hasProperties WritePostitFields(); void WritePostItFieldsResolved(); /// VMLTextExport diff --git a/sw/source/filter/ww8/docxexport.cxx b/sw/source/filter/ww8/docxexport.cxx index f060773576eb..a0dced9a5559 100644 --- a/sw/source/filter/ww8/docxexport.cxx +++ b/sw/source/filter/ww8/docxexport.cxx @@ -756,12 +756,12 @@ void DocxExport::WritePostitFields() pPostitFS->startElementNS( XML_w, XML_comments, MainXmlNamespaces()); m_pAttrOutput->SetSerializer( pPostitFS ); - const auto eHasResolved = m_pAttrOutput->WritePostitFields(); + const auto eHasProperties = m_pAttrOutput->WritePostitFields(); m_pAttrOutput->SetSerializer( m_pDocumentFS ); pPostitFS->endElementNS( XML_w, XML_comments ); pPostitFS->endDocument(); - if (eHasResolved != DocxAttributeOutput::hasResolved::yes) + if (eHasProperties != DocxAttributeOutput::hasProperties::yes) return; m_rFilter.addRelation(m_pDocumentFS->getOutputStream(), diff --git a/writerfilter/inc/dmapper/CommentProperties.hxx b/writerfilter/inc/dmapper/CommentProperties.hxx index d22a2f7261d3..fe66cceed3f8 100644 --- a/writerfilter/inc/dmapper/CommentProperties.hxx +++ b/writerfilter/inc/dmapper/CommentProperties.hxx @@ -9,12 +9,14 @@ #pragma once +#include <rtl/ustring.hxx> + namespace writerfilter { /** A container for the extended comment properties linked to the last paragraph of a comment - Corresponds to the data available in w15:commentEx elements from commentsExtended stream + Corresponds to the data available in w5:commentEx elements from commentsExtended stream ([MS-DOCX]): resolved state and parent (referring to comment that this one answers to; TODO). @since 7.2 @@ -22,7 +24,7 @@ namespace writerfilter struct CommentProperties { bool bDone; - // TODO: a reference to a parent comment (paraIdParent: [MS-DOCX] sect. 2.5.3.1 CT_CommentEx) + OUString sParaIdParent; }; } diff --git a/writerfilter/source/dmapper/DomainMapper_Impl.cxx b/writerfilter/source/dmapper/DomainMapper_Impl.cxx index 600086ca6121..8358596bdf8e 100644 --- a/writerfilter/source/dmapper/DomainMapper_Impl.cxx +++ b/writerfilter/source/dmapper/DomainMapper_Impl.cxx @@ -2675,6 +2675,8 @@ void DomainMapper_Impl::finishParagraph( const PropertyMapPtr& pPropertyMap, con if (const auto& item = m_aCommentProps.find(sParaId); item != m_aCommentProps.end()) { m_bAnnotationResolved = item->second.bDone; + m_sAnnotationParent = item->second.sParaIdParent; + m_sAnnotationImportedParaId = sParaId; } } } @@ -3825,6 +3827,9 @@ void DomainMapper_Impl::PopAnnotation() if (m_bAnnotationResolved) m_xAnnotationField->setPropertyValue("Resolved", css::uno::Any(true)); + m_xAnnotationField->setPropertyValue("ParaIdParent", css::uno::Any(m_sAnnotationParent)); + m_xAnnotationField->setPropertyValue("ParaId", css::uno::Any(m_sAnnotationImportedParaId)); + // See if the annotation will be a single position or a range. if (m_nAnnotationId == -1 || !m_aAnnotationPositions[m_nAnnotationId].m_xStart.is() || !m_aAnnotationPositions[m_nAnnotationId].m_xEnd.is()) { @@ -3872,6 +3877,8 @@ void DomainMapper_Impl::PopAnnotation() } m_xAnnotationField.clear(); + m_sAnnotationParent.clear(); + m_sAnnotationImportedParaId.clear(); m_nAnnotationId = -1; m_bAnnotationResolved = false; } diff --git a/writerfilter/source/dmapper/DomainMapper_Impl.hxx b/writerfilter/source/dmapper/DomainMapper_Impl.hxx index 0c6c8cd75f31..d4d25a75b4dc 100644 --- a/writerfilter/source/dmapper/DomainMapper_Impl.hxx +++ b/writerfilter/source/dmapper/DomainMapper_Impl.hxx @@ -619,6 +619,8 @@ private: css::uno::Reference< css::beans::XPropertySet > m_xAnnotationField; sal_Int32 m_nAnnotationId; bool m_bAnnotationResolved = false; + OUString m_sAnnotationParent; + OUString m_sAnnotationImportedParaId; std::unordered_map< sal_Int32, AnnotationPosition > m_aAnnotationPositions; void SetNumberFormat(const OUString& rCommand, css::uno::Reference<css::beans::XPropertySet> const& xPropertySet, bool bDetectFormat = false); diff --git a/writerfilter/source/ooxml/OOXMLFastContextHandler.cxx b/writerfilter/source/ooxml/OOXMLFastContextHandler.cxx index 2563956bf97a..bf12a4e35dd1 100644 --- a/writerfilter/source/ooxml/OOXMLFastContextHandler.cxx +++ b/writerfilter/source/ooxml/OOXMLFastContextHandler.cxx @@ -2323,7 +2323,7 @@ OOXMLFastContextHandlerCommentEx::OOXMLFastContextHandlerCommentEx( void OOXMLFastContextHandlerCommentEx::lcl_endFastElement(Token_t /*Element*/) { - mpStream->commentProps(m_sParaId, { m_bDone }); + mpStream->commentProps(m_sParaId, { m_bDone, m_sParentId }); } void OOXMLFastContextHandlerCommentEx::att_paraId(const OOXMLValue::Pointer_t& pValue) @@ -2337,6 +2337,11 @@ void OOXMLFastContextHandlerCommentEx::att_done(const OOXMLValue::Pointer_t& pVa m_bDone = true; } +void OOXMLFastContextHandlerCommentEx::att_paraIdParent(const OOXMLValue::Pointer_t& pValue) +{ + m_sParentId = pValue->getString(); +} + } /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/writerfilter/source/ooxml/OOXMLFastContextHandler.hxx b/writerfilter/source/ooxml/OOXMLFastContextHandler.hxx index 30491f08dc43..14dd62f00d64 100644 --- a/writerfilter/source/ooxml/OOXMLFastContextHandler.hxx +++ b/writerfilter/source/ooxml/OOXMLFastContextHandler.hxx @@ -621,10 +621,12 @@ public: void att_paraId(const OOXMLValue::Pointer_t& pValue); void att_done(const OOXMLValue::Pointer_t& pValue); + void att_paraIdParent(const OOXMLValue::Pointer_t& pValue); private: OUString m_sParaId; bool m_bDone = false; + OUString m_sParentId {}; }; } diff --git a/writerfilter/source/ooxml/model.xml b/writerfilter/source/ooxml/model.xml index 6ec446d67d48..352623d3e86d 100644 --- a/writerfilter/source/ooxml/model.xml +++ b/writerfilter/source/ooxml/model.xml @@ -5404,11 +5404,9 @@ <attribute name="paraId"> <ref name="ST_LongHexNumber"/> </attribute> - <!-- Not yet used <attribute name="paraIdParent"> <ref name="ST_LongHexNumber"/> </attribute> - --> <attribute name="done"> <ref name="ST_OnOff"/> </attribute> @@ -5430,6 +5428,7 @@ </resource> <resource name="CT_CommentEx" resource="CommentEx"> <attribute name="paraId" tokenid="ooxml:CT_CommentEx_paraId" action="att_paraId"/> + <attribute name="paraIdParent" tokenid="ooxml:CT_CommentEx_paraIdParent" action="att_paraIdParent"/> <attribute name="done" tokenid="ooxml:CT_CommentEx_done" action="att_done"/> </resource> <resource name="ST_LongHexNumber" resource="String"/>