[Libreoffice-commits] core.git: Branch 'distro/collabora/co-2021' - sw/qa writerfilter/CustomTarget_source.mk writerfilter/inc writerfilter/source

Mike Kaganski (via logerrit) logerrit at kemper.freedesktop.org
Fri Apr 16 21:54:12 UTC 2021


 sw/qa/extras/ooxmlexport/ooxmlexport16.cxx            |   56 ++++++++++++---
 writerfilter/CustomTarget_source.mk                   |    1 
 writerfilter/inc/dmapper/CommentProperties.hxx        |   21 +++++
 writerfilter/inc/dmapper/resourcemodel.hxx            |    4 +
 writerfilter/inc/ooxml/OOXMLDocument.hxx              |    2 
 writerfilter/source/dmapper/DomainMapper.cxx          |   12 +++
 writerfilter/source/dmapper/DomainMapper.hxx          |    2 
 writerfilter/source/dmapper/DomainMapper_Impl.cxx     |   21 +++++
 writerfilter/source/dmapper/DomainMapper_Impl.hxx     |    7 +
 writerfilter/source/dmapper/PropertyMap.hxx           |    4 +
 writerfilter/source/ooxml/OOXMLDocumentImpl.cxx       |   11 +++
 writerfilter/source/ooxml/OOXMLDocumentImpl.hxx       |    4 +
 writerfilter/source/ooxml/OOXMLFactory.hxx            |    3 
 writerfilter/source/ooxml/OOXMLFastContextHandler.cxx |   37 ++++++++++
 writerfilter/source/ooxml/OOXMLFastContextHandler.hxx |   16 ++++
 writerfilter/source/ooxml/OOXMLStreamImpl.cxx         |    5 +
 writerfilter/source/ooxml/model.xml                   |   64 ++++++++++++++++++
 17 files changed, 257 insertions(+), 13 deletions(-)

New commits:
commit 3adf3fa04e5644dcc68996caa621b07b642e9829
Author:     Mike Kaganski <mike.kaganski at collabora.com>
AuthorDate: Fri Apr 16 14:30:28 2021 +0300
Commit:     Mike Kaganski <mike.kaganski at collabora.com>
CommitDate: Fri Apr 16 23:10:34 2021 +0300

    tdf#122222: add DOCX import of resolved comments as "done"
    
    Change-Id: Id596d18965de2d8c98853c281188fe8d749055f4
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/114204
    Tested-by: Jenkins
    Reviewed-by: Mike Kaganski <mike.kaganski at collabora.com>

diff --git a/sw/qa/extras/ooxmlexport/ooxmlexport16.cxx b/sw/qa/extras/ooxmlexport/ooxmlexport16.cxx
index 3bb23d4e40aa..33d7bffa7ed6 100644
--- a/sw/qa/extras/ooxmlexport/ooxmlexport16.cxx
+++ b/sw/qa/extras/ooxmlexport/ooxmlexport16.cxx
@@ -15,6 +15,7 @@
 #include <svx/svdobj.hxx>
 
 #include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/text/XTextFieldsSupplier.hpp>
 #include <com/sun/star/text/XTextViewCursorSupplier.hpp>
 #include <com/sun/star/text/XTextTable.hpp>
 #include <com/sun/star/text/XTextTablesSupplier.hpp>
@@ -172,18 +173,8 @@ DECLARE_OOXMLEXPORT_TEST(testTdf133473_shadowSize, "tdf133473.docx")
     CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(200000), nSize1);
 }
 
-DECLARE_OOXMLEXPORT_TEST(testCommentDone, "CommentDone.docx")
+DECLARE_OOXMLEXPORT_EXPORTONLY_TEST(testCommentDone, "CommentDone.docx")
 {
-    if (!mbExported)
-    {
-        // This manually toggles (enables) the resolved state of the first comment now, while
-        // import is not yet implemented (TODO)
-        uno::Sequence<beans::PropertyValue> aPropertyValues = comphelper::InitPropertySequence(
-            { { "Id", uno::makeAny(OUString("1")) } });
-        dispatchCommand(mxComponent, ".uno:ResolveComment", aPropertyValues);
-        return;
-    }
-
     xmlDocUniquePtr pXmlComm = parseExport("word/comments.xml");
     assertXPath(pXmlComm, "/w:comments/w:comment[1]/w:p", 2);
     OUString idLastPara = getXPath(pXmlComm, "/w:comments/w:comment[1]/w:p[2]", "paraId");
@@ -195,6 +186,49 @@ DECLARE_OOXMLEXPORT_TEST(testCommentDone, "CommentDone.docx")
     assertXPath(pXmlCommExt, "/w15:commentsEx/w15:commentEx", "done", "1");
 }
 
+DECLARE_OOXMLEXPORT_TEST(testCommentDoneModel, "CommentDone.docx")
+{
+    css::uno::Reference<css::text::XTextFieldsSupplier> xTextFieldsSupplier(
+        mxComponent, css::uno::UNO_QUERY_THROW);
+    auto xFields(xTextFieldsSupplier->getTextFields()->createEnumeration());
+
+    // First comment: initially resolved, toggled to unresolved on import, unresolved on roundtrip
+    CPPUNIT_ASSERT(xFields->hasMoreElements());
+    css::uno::Any aComment = xFields->nextElement();
+    css::uno::Reference<css::beans::XPropertySet> xComment(aComment, css::uno::UNO_QUERY_THROW);
+
+    if (!mbExported)
+    {
+        // Check that it's resolved when initially read
+        CPPUNIT_ASSERT_EQUAL(true, xComment->getPropertyValue("Resolved").get<bool>());
+        // Set to unresolved
+        xComment->setPropertyValue("Resolved", css::uno::Any(false));
+    }
+    else
+    {
+        // After the roundtrip, it keeps the "unresolved" state set above
+        CPPUNIT_ASSERT_EQUAL(false, xComment->getPropertyValue("Resolved").get<bool>());
+    }
+
+    // Second comment: initially unresolved, toggled to resolved on import, resolved on roundtrip
+    CPPUNIT_ASSERT(xFields->hasMoreElements());
+    aComment = xFields->nextElement();
+    xComment.set(aComment, css::uno::UNO_QUERY_THROW);
+
+    if (!mbExported)
+    {
+        // Check that it's unresolved when initially read
+        CPPUNIT_ASSERT_EQUAL(false, xComment->getPropertyValue("Resolved").get<bool>());
+        // Set to resolved
+        xComment->setPropertyValue("Resolved", css::uno::Any(true));
+    }
+    else
+    {
+        // After the roundtrip, it keeps the "resolved" state set above
+        CPPUNIT_ASSERT_EQUAL(true, xComment->getPropertyValue("Resolved").get<bool>());
+    }
+}
+
 CPPUNIT_PLUGIN_IMPLEMENT();
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/writerfilter/CustomTarget_source.mk b/writerfilter/CustomTarget_source.mk
index 8d7b3d22b690..d0085654a146 100644
--- a/writerfilter/CustomTarget_source.mk
+++ b/writerfilter/CustomTarget_source.mk
@@ -41,6 +41,7 @@ writerfilter_OOXMLNAMESPACES= \
 	vml-wordprocessingDrawing \
 	wp14 \
 	w14 \
+	w15 \
 	a14 \
 	wml
 
diff --git a/writerfilter/inc/dmapper/CommentProperties.hxx b/writerfilter/inc/dmapper/CommentProperties.hxx
new file mode 100644
index 000000000000..1cba6930d4c6
--- /dev/null
+++ b/writerfilter/inc/dmapper/CommentProperties.hxx
@@ -0,0 +1,21 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#pragma once
+
+namespace writerfilter
+{
+struct CommentProperties
+{
+    bool bDone;
+    // TODO: a reference to a parent comment (paraIdParent: [MS-DOCX] sect. 2.5.3.1 CT_CommentEx)
+};
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
diff --git a/writerfilter/inc/dmapper/resourcemodel.hxx b/writerfilter/inc/dmapper/resourcemodel.hxx
index 5ea1512fb1ba..7ecb82335d23 100644
--- a/writerfilter/inc/dmapper/resourcemodel.hxx
+++ b/writerfilter/inc/dmapper/resourcemodel.hxx
@@ -55,6 +55,8 @@ typedef sal_uInt32 Id;
 
 namespace writerfilter
 {
+struct CommentProperties;
+
 /**
     Reference to a resource that generates events and sends them to a
     handler.
@@ -297,6 +299,8 @@ public:
     /// Receives end mark for glossary document entry.
     virtual void endGlossaryEntry() = 0;
 
+    virtual void commentProps(const OUString& /*sId*/, const CommentProperties& /*rProps*/) {}
+
 protected:
     ~Stream() override {}
 };
diff --git a/writerfilter/inc/ooxml/OOXMLDocument.hxx b/writerfilter/inc/ooxml/OOXMLDocument.hxx
index 72aa04493d1b..f85507bb53aa 100644
--- a/writerfilter/inc/ooxml/OOXMLDocument.hxx
+++ b/writerfilter/inc/ooxml/OOXMLDocument.hxx
@@ -73,7 +73,7 @@ class OOXMLStream : public virtual SvRefBase
 {
 public:
     enum StreamType_t { UNKNOWN, DOCUMENT, STYLES, WEBSETTINGS, FONTTABLE, NUMBERING,
-        FOOTNOTES, ENDNOTES, COMMENTS, THEME, CUSTOMXML, CUSTOMXMLPROPS, GLOSSARY, CHARTS, EMBEDDINGS, SETTINGS, VBAPROJECT, FOOTER, HEADER, VBADATA };
+        FOOTNOTES, ENDNOTES, COMMENTS, COMMENTS_EXTENDED, THEME, CUSTOMXML, CUSTOMXMLPROPS, GLOSSARY, CHARTS, EMBEDDINGS, SETTINGS, VBAPROJECT, FOOTER, HEADER, VBADATA };
     typedef tools::SvRef<OOXMLStream> Pointer_t;
 
     /**
diff --git a/writerfilter/source/dmapper/DomainMapper.cxx b/writerfilter/source/dmapper/DomainMapper.cxx
index fd9fd7f4bce7..ea3657d94dc2 100644
--- a/writerfilter/source/dmapper/DomainMapper.cxx
+++ b/writerfilter/source/dmapper/DomainMapper.cxx
@@ -1239,6 +1239,13 @@ void DomainMapper::lcl_attribute(Id nName, Value & val)
             m_pImpl->HandleAltChunk(sStringValue);
         }
         break;
+        case NS_ooxml::LN_AG_Parids_paraId:
+            if (ParagraphPropertyMap* pParaContext
+                = dynamic_cast<ParagraphPropertyMap*>(m_pImpl->GetTopContext().get()))
+            {
+                pParaContext->SetParaId(sStringValue);
+            }
+            break;
         default:
             SAL_WARN("writerfilter", "DomainMapper::lcl_attribute: unhandled token: " << nName);
     }
@@ -4080,6 +4087,11 @@ void DomainMapper::finishParagraph(const bool bRemove, const bool bNoNumbering)
     m_pImpl->finishParagraph(m_pImpl->GetTopContextOfType(CONTEXT_PARAGRAPH), bRemove, bNoNumbering);
 }
 
+void DomainMapper::commentProps(const OUString& sId, const CommentProperties& rProps)
+{
+    m_pImpl->commentProps(sId, rProps);
+}
+
 } //namespace writerfilter
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/writerfilter/source/dmapper/DomainMapper.hxx b/writerfilter/source/dmapper/DomainMapper.hxx
index 4e47dd70a441..94b91460a6f9 100644
--- a/writerfilter/source/dmapper/DomainMapper.hxx
+++ b/writerfilter/source/dmapper/DomainMapper.hxx
@@ -131,6 +131,8 @@ public:
 
     void HandleRedline( Sprm& rSprm );
 
+    virtual void commentProps(const OUString& sId, const CommentProperties& rProps) override;
+
 private:
     // Stream
     virtual void lcl_startSectionGroup() override;
diff --git a/writerfilter/source/dmapper/DomainMapper_Impl.cxx b/writerfilter/source/dmapper/DomainMapper_Impl.cxx
index 4d405c764f7f..d3c779a10b6c 100644
--- a/writerfilter/source/dmapper/DomainMapper_Impl.cxx
+++ b/writerfilter/source/dmapper/DomainMapper_Impl.cxx
@@ -2093,6 +2093,17 @@ void DomainMapper_Impl::finishParagraph( const PropertyMapPtr& pPropertyMap, con
     m_previousRedline.clear();
     m_bParaChanged = false;
 
+    if (m_bIsInComments && pParaContext)
+    {
+        if (const OUString sParaId = pParaContext->GetParaId(); !sParaId.isEmpty())
+        {
+            if (const auto& item = m_aCommentProps.find(sParaId); item != m_aCommentProps.end())
+            {
+                m_bAnnotationResolved = item->second.bDone;
+            }
+        }
+    }
+
     if (m_bIsFirstParaInShape)
         m_bIsFirstParaInShape = false;
 
@@ -2853,6 +2864,9 @@ void DomainMapper_Impl::PopAnnotation()
 
     try
     {
+        if (m_bAnnotationResolved)
+            m_xAnnotationField->setPropertyValue("Resolved", css::uno::Any(true));
+
         // 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())
         {
@@ -2901,6 +2915,7 @@ void DomainMapper_Impl::PopAnnotation()
 
     m_xAnnotationField.clear();
     m_nAnnotationId = -1;
+    m_bAnnotationResolved = false;
 }
 
 void DomainMapper_Impl::PushPendingShape( const uno::Reference< drawing::XShape > & xShape )
@@ -7538,6 +7553,12 @@ void DomainMapper_Impl::substream(Id rName,
         assert(m_aPropertyStacks[i].size() == propSize[i]);
     }
 }
+
+void DomainMapper_Impl::commentProps(const OUString& sId, const CommentProperties& rProps)
+{
+    m_aCommentProps[sId] = rProps;
+}
+
 }
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/writerfilter/source/dmapper/DomainMapper_Impl.hxx b/writerfilter/source/dmapper/DomainMapper_Impl.hxx
index 2fb996ccd9ff..8da791182f6e 100644
--- a/writerfilter/source/dmapper/DomainMapper_Impl.hxx
+++ b/writerfilter/source/dmapper/DomainMapper_Impl.hxx
@@ -32,6 +32,8 @@
 #include <vector>
 #include <optional>
 
+#include <dmapper/CommentProperties.hxx>
+
 #include "DomainMapper.hxx"
 #include "DomainMapperTableManager.hxx"
 #include "DomainMapperTableHandler.hxx"
@@ -572,6 +574,7 @@ private:
     //annotation import
     css::uno::Reference< css::beans::XPropertySet > m_xAnnotationField;
     sal_Int32 m_nAnnotationId;
+    bool m_bAnnotationResolved = false;
     std::unordered_map< sal_Int32, AnnotationPosition > m_aAnnotationPositions;
 
     void GetCurrentLocale(css::lang::Locale& rLocale);
@@ -1103,6 +1106,8 @@ public:
     /// Handles <w:altChunk>.
     void HandleAltChunk(const OUString& rStreamName);
 
+    void commentProps(const OUString& sId, const CommentProperties& rProps);
+
 private:
     void PushPageHeaderFooter(bool bHeader, SectionPropertyMap::PageType eType);
     // Start a new index section; if needed, finish current paragraph
@@ -1119,6 +1124,8 @@ private:
     bool m_bSaveFirstParagraphInCell;
     /// Current paragraph had at least one inline object in it.
     bool m_bParaWithInlineObject;
+
+    std::unordered_map<OUString, CommentProperties> m_aCommentProps;
 };
 
 } //namespace writerfilter::dmapper
diff --git a/writerfilter/source/dmapper/PropertyMap.hxx b/writerfilter/source/dmapper/PropertyMap.hxx
index f8c976abd388..d25e87671efb 100644
--- a/writerfilter/source/dmapper/PropertyMap.hxx
+++ b/writerfilter/source/dmapper/PropertyMap.hxx
@@ -429,6 +429,7 @@ private:
     sal_Int32                                    m_yAlign;         // from ST_YAlign bottom, center, inline, inside, outside, top
     sal_Int8                                     m_nDropCapLength; // number of characters
     OUString                                     m_sParaStyleName;
+    OUString                                     m_sParaId;        // [MS-DOCX] sect. 2.2.4 "p and tr Extensions"
 
     css::uno::Reference< css::text::XTextRange > m_xStartingRange; // start of a frame
     css::uno::Reference< css::text::XTextRange > m_xEndingRange;   // end of the frame
@@ -507,6 +508,9 @@ public:
     const OUString& GetParaStyleName() const      { return m_sParaStyleName; }
     void SetParaStyleName( const OUString& rSet ) { m_sParaStyleName = rSet; }
 
+    const OUString& GetParaId() const { return m_sParaId; }
+    void SetParaId(const OUString& rSet) { m_sParaId = rSet; }
+
     void ResetFrameProperties();
 };
 
diff --git a/writerfilter/source/ooxml/OOXMLDocumentImpl.cxx b/writerfilter/source/ooxml/OOXMLDocumentImpl.cxx
index fba694b5b77b..72671cb93c1e 100644
--- a/writerfilter/source/ooxml/OOXMLDocumentImpl.cxx
+++ b/writerfilter/source/ooxml/OOXMLDocumentImpl.cxx
@@ -310,9 +310,20 @@ void OOXMLDocumentImpl::resolveEndnote(Stream & rStream,
     resolveFastSubStreamWithId(rStream, pStream, nId);
 }
 
+void OOXMLDocumentImpl::resolveCommentsExtendedStream(Stream& rStream)
+{
+    resolveFastSubStream(rStream, OOXMLStream::COMMENTS_EXTENDED);
+}
+
 void OOXMLDocumentImpl::resolveComment(Stream & rStream,
                                        const sal_Int32 nId)
 {
+    if (!mbCommentsExtendedResolved)
+    {
+        resolveCommentsExtendedStream(rStream);
+        mbCommentsExtendedResolved = true;
+    }
+
     writerfilter::Reference<Stream>::Pointer_t pStream =
         getXNoteStream(OOXMLStream::COMMENTS, nId);
 
diff --git a/writerfilter/source/ooxml/OOXMLDocumentImpl.hxx b/writerfilter/source/ooxml/OOXMLDocumentImpl.hxx
index 1848f8971766..657f3317c1d9 100644
--- a/writerfilter/source/ooxml/OOXMLDocumentImpl.hxx
+++ b/writerfilter/source/ooxml/OOXMLDocumentImpl.hxx
@@ -67,6 +67,8 @@ class OOXMLDocumentImpl : public OOXMLDocument
     /// Graphic mapper
     css::uno::Reference<css::graphic::XGraphicMapper> mxGraphicMapper;
 
+    bool mbCommentsExtendedResolved = false;
+
 private:
     void resolveFastSubStream(Stream & rStream,
                                       OOXMLStream::StreamType_t nType);
@@ -88,6 +90,8 @@ private:
     void resolveCustomXmlStream(Stream & rStream);
     void resolveGlossaryStream(Stream & rStream);
     void resolveEmbeddingsStream(const OOXMLStream::Pointer_t& pStream);
+    void resolveCommentsExtendedStream(Stream & rStream);
+
 public:
     OOXMLDocumentImpl(OOXMLStream::Pointer_t const & pStream, const css::uno::Reference<css::task::XStatusIndicator>& xStatusIndicator, bool bSkipImages, const css::uno::Sequence<css::beans::PropertyValue>& rDescriptor);
     virtual ~OOXMLDocumentImpl() override;
diff --git a/writerfilter/source/ooxml/OOXMLFactory.hxx b/writerfilter/source/ooxml/OOXMLFactory.hxx
index bf92bd6e2a51..5446e1907b64 100644
--- a/writerfilter/source/ooxml/OOXMLFactory.hxx
+++ b/writerfilter/source/ooxml/OOXMLFactory.hxx
@@ -49,7 +49,8 @@ enum class ResourceType {
     TwipsMeasure_asSigned,
     TwipsMeasure_asZero,
     HpsMeasure,
-    MeasurementOrPercent
+    MeasurementOrPercent,
+    CommentEx,
 };
 
 struct AttributeInfo
diff --git a/writerfilter/source/ooxml/OOXMLFastContextHandler.cxx b/writerfilter/source/ooxml/OOXMLFastContextHandler.cxx
index 3b62c912967e..7c01b7f2f29e 100644
--- a/writerfilter/source/ooxml/OOXMLFastContextHandler.cxx
+++ b/writerfilter/source/ooxml/OOXMLFastContextHandler.cxx
@@ -34,6 +34,7 @@
 #include "OOXMLFastContextHandler.hxx"
 #include "OOXMLFactory.hxx"
 #include "Handler.hxx"
+#include <dmapper/CommentProperties.hxx>
 #include <dmapper/PropertyIds.hxx>
 #include <comphelper/propertysequence.hxx>
 #include <comphelper/sequenceashashmap.hxx>
@@ -406,6 +407,20 @@ void OOXMLFastContextHandler::startParagraphGroup()
     {
         mpStream->startParagraphGroup();
         mpParserState->setInParagraphGroup(true);
+
+        if (const auto& pPropSet = getPropertySet())
+        {
+            OOXMLPropertySetEntryToString aHandler(NS_ooxml::LN_AG_Parids_paraId);
+            pPropSet->resolve(aHandler);
+            if (const OUString& sText = aHandler.getString(); !sText.isEmpty())
+            {
+                OOXMLStringValue::Pointer_t pVal = new OOXMLStringValue(sText);
+                OOXMLPropertySet::Pointer_t pPropertySet(new OOXMLPropertySet);
+                pPropertySet->add(NS_ooxml::LN_AG_Parids_paraId, pVal, OOXMLProperty::ATTRIBUTE);
+                mpStream->props(pPropertySet.get());
+            }
+        }
+
     }
 }
 
@@ -2198,6 +2213,28 @@ void OOXMLFastContextHandlerMath::process()
     mpStream->props( pProps.get() );
 }
 
+OOXMLFastContextHandlerCommentEx::OOXMLFastContextHandlerCommentEx(
+    OOXMLFastContextHandler* pContext)
+    : OOXMLFastContextHandler(pContext)
+{
+}
+
+void OOXMLFastContextHandlerCommentEx::lcl_endFastElement(Token_t /*Element*/)
+{
+    mpStream->commentProps(m_sParaId, { m_bDone });
+}
+
+void OOXMLFastContextHandlerCommentEx::att_paraId(const OOXMLValue::Pointer_t& pValue)
+{
+    m_sParaId = pValue->getString();
+}
+
+void OOXMLFastContextHandlerCommentEx::att_done(const OOXMLValue::Pointer_t& pValue)
+{
+    if (pValue->getInt())
+        m_bDone = true;
+}
+
 }
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/writerfilter/source/ooxml/OOXMLFastContextHandler.hxx b/writerfilter/source/ooxml/OOXMLFastContextHandler.hxx
index ac8346d3dad2..8074b5ccf5bd 100644
--- a/writerfilter/source/ooxml/OOXMLFastContextHandler.hxx
+++ b/writerfilter/source/ooxml/OOXMLFastContextHandler.hxx
@@ -600,6 +600,22 @@ protected:
     virtual void process() override;
 };
 
+class OOXMLFastContextHandlerCommentEx : public OOXMLFastContextHandler
+{
+public:
+    explicit OOXMLFastContextHandlerCommentEx(OOXMLFastContextHandler* pContext);
+
+    virtual std::string getType() const override { return "CommentEx"; }
+    virtual void lcl_endFastElement(Token_t Element) override;
+
+    void att_paraId(const OOXMLValue::Pointer_t& pValue);
+    void att_done(const OOXMLValue::Pointer_t& pValue);
+
+private:
+    OUString m_sParaId;
+    bool m_bDone = false;
+};
+
 }
 #endif // INCLUDED_WRITERFILTER_SOURCE_OOXML_OOXMLFASTCONTEXTHANDLER_HXX
 
diff --git a/writerfilter/source/ooxml/OOXMLStreamImpl.cxx b/writerfilter/source/ooxml/OOXMLStreamImpl.cxx
index 7d48f1c08fce..9c7baecc6bfc 100644
--- a/writerfilter/source/ooxml/OOXMLStreamImpl.cxx
+++ b/writerfilter/source/ooxml/OOXMLStreamImpl.cxx
@@ -145,6 +145,7 @@ bool OOXMLStreamImpl::lcl_getTarget(const uno::Reference<embed::XRelationshipAcc
     static const char sFooterType[] = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/footer";
     static const char sHeaderType[] = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/header";
     static const char sOleObjectType[] = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/oleObject";
+    static const char sCommentsExtendedType[] = "http://schemas.microsoft.com/office/2011/relationships/commentsExtended";
     // OOXML strict
     static const char sDocumentTypeStrict[] = "http://purl.oclc.org/ooxml/officeDocument/relationships/officeDocument";
     static const char sStylesTypeStrict[] = "http://purl.oclc.org/ooxml/officeDocument/relationships/styles";
@@ -248,6 +249,10 @@ bool OOXMLStreamImpl::lcl_getTarget(const uno::Reference<embed::XRelationshipAcc
             sStreamType = sHeaderType;
             sStreamTypeStrict = sHeaderTypeStrict;
           break;
+        case COMMENTS_EXTENDED:
+            sStreamType = sCommentsExtendedType;
+            sStreamTypeStrict = sCommentsExtendedType;
+            break;
         default:
             break;
     }
diff --git a/writerfilter/source/ooxml/model.xml b/writerfilter/source/ooxml/model.xml
index 3f45394d5d88..77dce046fb3d 100644
--- a/writerfilter/source/ooxml/model.xml
+++ b/writerfilter/source/ooxml/model.xml
@@ -26,6 +26,7 @@
   xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships"
   xmlns:v="urn:schemas-microsoft-com:vml"
   xmlns:w14="http://schemas.microsoft.com/office/word/2010/wordml"
+  xmlns:w15="http://schemas.microsoft.com/office/word/2012/wordml"
   xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main"
   xmlns:wp14="http://schemas.microsoft.com/office/word/2010/wordprocessingDrawing"
   xmlns:wpg="http://schemas.microsoft.com/office/word/2010/wordprocessingGroup"
@@ -5359,6 +5360,54 @@
       <element name="cntxtAlts" tokenid="ooxml:cntxtAlts_cntxtAlts"/>
     </resource>
   </namespace>
+  <namespace name="w15">
+    <start name="commentsEx"/>
+    <grammar xmlns="http://relaxng.org/ns/structure/1.0" ns="http://schemas.microsoft.com/office/word/2012/wordml" attributeFormDefault="qualified">
+      <define name="commentsEx">
+        <element name="commentsEx">
+          <ref name="CT_CommentsEx"/>
+        </element>
+      </define>
+      <define name="CT_CommentsEx">
+        <element name="commentEx">
+          <ref name="CT_CommentEx"/>
+        </element>
+      </define>
+      <define name="CT_CommentEx">
+        <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>
+      </define>
+      <define name="ST_LongHexNumber">
+        <data type="hexBinary"/>
+      </define>
+      <define name="ST_OnOff">
+        <choice>
+          <value>true</value>
+          <value>false</value>
+          <value>0</value>
+          <value>1</value>
+        </choice>
+      </define>
+    </grammar>
+    <resource name="CT_CommentsEx" resource="Stream">
+      <element name="commentEx" tokenid="ooxml:CT_CommentsEx_commentEx"/>
+    </resource>
+    <resource name="CT_CommentEx" resource="CommentEx">
+      <attribute name="paraId" tokenid="ooxml:CT_CommentEx_paraId" action="att_paraId"/>
+      <attribute name="done" tokenid="ooxml:CT_CommentEx_done" action="att_done"/>
+    </resource>
+    <resource name="ST_LongHexNumber" resource="String"/>
+    <resource name="ST_OnOff" resource="Boolean"/>
+  </namespace>
   <namespace name="a14">
     <grammar xmlns="http://relaxng.org/ns/structure/1.0" ns="http://schemas.microsoft.com/office/drawing/2010/main">
       <!-- Simple types -->
@@ -14197,6 +14246,18 @@
           </element>
         </choice>
       </define>
+      <!-- [MS-DOCX] sect. 2.2.4 "p and tr Extensions" -->
+      <!-- Should rather be in w14 namespace, but I don't see how to reference things from there -->
+      <define name="AG_Parids">
+        <attribute name="w14:paraId">
+          <data type="string"/>
+        </attribute>
+        <!-- Not yet used
+        <attribute name="textId">
+          <ref name="ST_LongHexNumber"/>
+        </attribute>
+        -->
+      </define>
       <define name="CT_P">
         <element name="pPr">
           <ref name="CT_PPr"/>
@@ -14217,6 +14278,7 @@
         <attribute name="rsidRDefault">
           <data type="string"/>
         </attribute>
+        <ref name="AG_Parids"/>
         <!-- tdf#108714 : allow <w:br> at paragraph level (despite this is illegal according to ECMA-376-1:2016) - bug-to-bug compatibility with Word -->
         <element name="br">
           <ref name="CT_Br_OutOfOrder"/>
@@ -14522,6 +14584,7 @@
         <attribute name="rsidTr">
           <data type="string"/>
         </attribute>
+        <ref name="AG_Parids"/>
       </define>
       <define name="ST_TblLayout">
         <choice>
@@ -18296,6 +18359,7 @@
       <element name="subDoc" tokenid="ooxml:EG_PContent_subDoc"/>
     </resource>
     <resource name="CT_P" resource="Stream">
+      <attribute name="w14:paraId" tokenid="ooxml:AG_Parids_paraId"/>
       <action name="start" action="handleLastParagraphInSection"/>
       <action name="start" action="startParagraphGroup"/>
       <action name="start" action="setHandle"/>


More information about the Libreoffice-commits mailing list