summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMiklos Vajna <vmiklos@collabora.com>2022-04-12 08:25:16 +0200
committerMiklos Vajna <vmiklos@collabora.com>2022-04-12 09:06:47 +0200
commitb40f9c536c1cefae8404a3f1c0080473151913d2 (patch)
tree59da9bd4be86d2e3b8d5415c4158bede7b5c66ba
parent618d40799d25474c48d984ce1d52b0f08f220958 (diff)
sw content controls: add initial DOCX export
Wrap the text portions inside the content control inside <w:sdtContent> and <w:sdt>. Also map the (so far) single property of it to <w:showingPlcHdr>. This is just initial export for inline text content controls, more properties are to be added in follow-up commits. Change-Id: I21e085496b4c79114b158656c5611aff8ffdd08a Reviewed-on: https://gerrit.libreoffice.org/c/core/+/132875 Reviewed-by: Miklos Vajna <vmiklos@collabora.com> Tested-by: Jenkins
-rw-r--r--sw/qa/extras/ooxmlexport/ooxmlexport17.cxx34
-rw-r--r--sw/source/filter/ww8/attributeoutputbase.hxx6
-rw-r--r--sw/source/filter/ww8/docxattributeoutput.cxx26
-rw-r--r--sw/source/filter/ww8/docxattributeoutput.hxx10
-rw-r--r--sw/source/filter/ww8/wrtw8nds.cxx19
5 files changed, 95 insertions, 0 deletions
diff --git a/sw/qa/extras/ooxmlexport/ooxmlexport17.cxx b/sw/qa/extras/ooxmlexport/ooxmlexport17.cxx
index e592e376336e..0c357607be22 100644
--- a/sw/qa/extras/ooxmlexport/ooxmlexport17.cxx
+++ b/sw/qa/extras/ooxmlexport/ooxmlexport17.cxx
@@ -13,6 +13,8 @@
#include <com/sun/star/text/XTextField.hpp>
#include <com/sun/star/drawing/XShapes.hpp>
#include <com/sun/star/util/XRefreshable.hpp>
+#include <com/sun/star/text/XTextDocument.hpp>
+#include <com/sun/star/frame/XStorable.hpp>
#include <comphelper/scopeguard.hxx>
#include <officecfg/Office/Common.hxx>
@@ -125,6 +127,38 @@ CPPUNIT_TEST_FIXTURE(Test, testClearingBreak)
assertXPath(pXmlDoc, "/w:document/w:body/w:p/w:r/w:br", "clear", "all");
}
+CPPUNIT_TEST_FIXTURE(Test, testContentControlExport)
+{
+ // Given a document with a content control around one or more text portions:
+ mxComponent = loadFromDesktop("private:factory/swriter");
+ uno::Reference<lang::XMultiServiceFactory> xMSF(mxComponent, uno::UNO_QUERY);
+ uno::Reference<text::XTextDocument> xTextDocument(mxComponent, uno::UNO_QUERY);
+ uno::Reference<text::XText> xText = xTextDocument->getText();
+ uno::Reference<text::XTextCursor> xCursor = xText->createTextCursor();
+ xText->insertString(xCursor, "test", /*bAbsorb=*/false);
+ xCursor->gotoStart(/*bExpand=*/false);
+ xCursor->gotoEnd(/*bExpand=*/true);
+ uno::Reference<text::XTextContent> xContentControl(
+ xMSF->createInstance("com.sun.star.text.ContentControl"), uno::UNO_QUERY);
+ uno::Reference<beans::XPropertySet> xContentControlProps(xContentControl, uno::UNO_QUERY);
+ xContentControlProps->setPropertyValue("ShowingPlaceHolder", uno::makeAny(true));
+ xText->insertTextContent(xCursor, xContentControl, /*bAbsorb=*/true);
+
+ // When exporting to DOCX:
+ save("Office Open XML Text", maTempFile);
+ mbExported = true;
+
+ // Then make sure the expected markup is used:
+ xmlDocUniquePtr pXmlDoc = parseExport("word/document.xml");
+ // Without the accompanying fix in place, this test would have failed with:
+ // - Expected: 1
+ // - Actual : 0
+ // XPath '//w:sdt/w:sdtPr/w:showingPlcHdr' number of nodes is incorrect
+ // i.e. the SDT elements were missing on export.
+ assertXPath(pXmlDoc, "//w:sdt/w:sdtPr/w:showingPlcHdr", 1);
+ assertXPath(pXmlDoc, "//w:sdt/w:sdtContent", 1);
+}
+
DECLARE_OOXMLEXPORT_TEST(testTdf137466, "tdf137466.docx")
{
xmlDocUniquePtr pXmlDoc = parseExport("word/document.xml");
diff --git a/sw/source/filter/ww8/attributeoutputbase.hxx b/sw/source/filter/ww8/attributeoutputbase.hxx
index 8461f2e1510c..a9331c9b628b 100644
--- a/sw/source/filter/ww8/attributeoutputbase.hxx
+++ b/sw/source/filter/ww8/attributeoutputbase.hxx
@@ -369,6 +369,12 @@ public:
const OUString &rNumberingString,
const SvxBrushItem* pBrush) = 0; // #i120928 export graphic of bullet
+ /// Output content control start.
+ virtual void StartContentControl(const SwFormatContentControl& /*rFormatContentControl*/) {}
+
+ /// Output content control end.
+ virtual void EndContentControl() {}
+
protected:
static void GetNumberPara( OUString& rStr, const SwField& rField );
diff --git a/sw/source/filter/ww8/docxattributeoutput.cxx b/sw/source/filter/ww8/docxattributeoutput.cxx
index 1e2d490e653c..47d4117ae052 100644
--- a/sw/source/filter/ww8/docxattributeoutput.cxx
+++ b/sw/source/filter/ww8/docxattributeoutput.cxx
@@ -362,6 +362,13 @@ void DocxAttributeOutput::WriteFloatingTable(ww8::Frame const* pParentFrame)
m_rExport.SetFloatingTableFrame(nullptr);
}
+void DocxAttributeOutput::StartContentControl(const SwFormatContentControl& rFormatContentControl)
+{
+ m_pContentControl = rFormatContentControl.GetContentControl();
+}
+
+void DocxAttributeOutput::EndContentControl() { ++m_nCloseContentControl; }
+
static void checkAndWriteFloatingTables(DocxAttributeOutput& rDocxAttributeOutput)
{
const auto& rExport = rDocxAttributeOutput.GetExport();
@@ -1621,6 +1628,12 @@ void DocxAttributeOutput::EndRun(const SwTextNode* pNode, sal_Int32 nPos, bool /
m_bEndCharSdt = false;
}
+ for (; m_nCloseContentControl > 0; --m_nCloseContentControl)
+ {
+ m_pSerializer->endElementNS(XML_w, XML_sdtContent);
+ m_pSerializer->endElementNS(XML_w, XML_sdt);
+ }
+
if ( m_closeHyperlinkInPreviousRun )
{
if ( m_startedHyperlink )
@@ -1718,6 +1731,19 @@ void DocxAttributeOutput::EndRun(const SwTextNode* pNode, sal_Int32 nPos, bool /
m_nHyperLinkCount++;
}
+ if (m_pContentControl)
+ {
+ m_pSerializer->startElementNS(XML_w, XML_sdt);
+ m_pSerializer->startElementNS(XML_w, XML_sdtPr);
+ if (m_pContentControl->GetShowingPlaceHolder())
+ {
+ m_pSerializer->singleElementNS(XML_w, XML_showingPlcHdr);
+ }
+ m_pSerializer->endElementNS(XML_w, XML_sdtPr);
+ m_pSerializer->startElementNS(XML_w, XML_sdtContent);
+ m_pContentControl = nullptr;
+ }
+
// if there is some redlining in the document, output it
StartRedline( m_pRedlineData );
diff --git a/sw/source/filter/ww8/docxattributeoutput.hxx b/sw/source/filter/ww8/docxattributeoutput.hxx
index 843fc0450bfb..4b4be1ca6160 100644
--- a/sw/source/filter/ww8/docxattributeoutput.hxx
+++ b/sw/source/filter/ww8/docxattributeoutput.hxx
@@ -52,6 +52,7 @@ class SwGrfNode;
class SdrObject;
enum class SvxBoxItemLine;
enum class SwLineBreakClear;
+class SwContentControl;
namespace docx { class FootnotesList; }
namespace oox::drawingml { class DrawingML; }
@@ -404,6 +405,12 @@ public:
void WriteFloatingTable(ww8::Frame const* pParentFrame);
+ /// See AttributeOutputBase::StartContentControl().
+ void StartContentControl(const SwFormatContentControl& rFormatContentControl) override;
+
+ /// See AttributeOutputBase::EndContentControl().
+ void EndContentControl() override;
+
private:
/// Initialize the structures where we are going to collect some of the paragraph properties.
///
@@ -780,6 +787,7 @@ private:
rtl::Reference<sax_fastparser::FastAttributeList> m_pSectionSpacingAttrList;
rtl::Reference<sax_fastparser::FastAttributeList> m_pParagraphSpacingAttrList;
rtl::Reference<sax_fastparser::FastAttributeList> m_pHyperlinkAttrList;
+ const SwContentControl* m_pContentControl = nullptr;
/// If the current SDT around runs should be ended before the current run.
bool m_bEndCharSdt;
/// Attributes of the run color
@@ -903,6 +911,8 @@ private:
o3tl::sorted_vector<const SwFrameFormat*> m_aFloatingTablesOfParagraph;
sal_Int32 m_nTextFrameLevel;
+ sal_Int32 m_nCloseContentControl = 0;
+
// close of hyperlink needed
bool m_closeHyperlinkInThisRun;
bool m_closeHyperlinkInPreviousRun;
diff --git a/sw/source/filter/ww8/wrtw8nds.cxx b/sw/source/filter/ww8/wrtw8nds.cxx
index 5fd077a634e6..36750bf6005a 100644
--- a/sw/source/filter/ww8/wrtw8nds.cxx
+++ b/sw/source/filter/ww8/wrtw8nds.cxx
@@ -1399,6 +1399,14 @@ int SwWW8AttrIter::OutAttrWithRange(const SwTextNode& rNode, sal_Int32 nPos)
--nRet;
}
break;
+ case RES_TXTATR_CONTENTCONTROL:
+ pEnd = pHt->End();
+ if (nPos == *pEnd && nPos != pHt->GetStart())
+ {
+ m_rExport.AttrOutput().EndContentControl();
+ --nRet;
+ }
+ break;
}
if (nPos < pHt->GetAnyEnd())
break; // sorted by end
@@ -1453,6 +1461,17 @@ int SwWW8AttrIter::OutAttrWithRange(const SwTextNode& rNode, sal_Int32 nPos)
--nRet;
}
break;
+ case RES_TXTATR_CONTENTCONTROL:
+ if (nPos == pHt->GetStart())
+ {
+ auto pFormatContentControl
+ = static_cast<const SwFormatContentControl*>(pItem);
+ m_rExport.AttrOutput().StartContentControl(*pFormatContentControl);
+ ++nRet;
+ }
+ // We know that the content control is never empty as it has a dummy character
+ // at least.
+ break;
}
if (nPos < pHt->GetStart())
break; // sorted by start