summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Stahl <Michael.Stahl@cib.de>2020-02-26 13:00:23 +0100
committerCaolán McNamara <caolanm@redhat.com>2020-02-28 18:28:48 +0100
commit2a04b3d676a1db76cc8fb19a1126648e7548dc47 (patch)
treeec6ef8674bb771a01916e8de7412b4e97d8d3390
parent02ef89cf647065ae39fb4845259f084c9b7ac008 (diff)
sw: DOCX export: for SwDropDownField, don't write FORMDROPDOWN
... because Word's funny limitation to 25 listEntry children causes data loss, as seen in commit d9634e3c9bfaf826b3d4d39e9a57d6c2d8d9a3dc "sw: DOCX export: limit FORMDROPDOWN listEntry to Word's abilities". Instead write SDT dropDownList, which appears to be able to store at least 26 listItem children without complaint from Word, so it's an improvement. Funnily domainmapper converts it to a form control on DOCX import. Change-Id: Ic0f24144cb2b5233f82c7b3bc67946a6e56448a8 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/89541 Tested-by: Jenkins Reviewed-by: Michael Stahl <michael.stahl@cib.de> (cherry picked from commit d55b26a093bdbced08985dbc7113190b52a8bc66) Reviewed-on: https://gerrit.libreoffice.org/c/core/+/89622 Reviewed-by: Caolán McNamara <caolanm@redhat.com>
-rw-r--r--sw/qa/extras/ooxmlexport/ooxmlexport13.cxx29
-rw-r--r--sw/source/filter/ww8/docxattributeoutput.cxx91
-rw-r--r--sw/source/filter/ww8/docxattributeoutput.hxx3
3 files changed, 92 insertions, 31 deletions
diff --git a/sw/qa/extras/ooxmlexport/ooxmlexport13.cxx b/sw/qa/extras/ooxmlexport/ooxmlexport13.cxx
index 6696bae7e527..d0edf4d5fcd4 100644
--- a/sw/qa/extras/ooxmlexport/ooxmlexport13.cxx
+++ b/sw/qa/extras/ooxmlexport/ooxmlexport13.cxx
@@ -428,12 +428,29 @@ DECLARE_OOXMLEXPORT_TEST(testParaAdjustDistribute, "para-adjust-distribute.docx"
DECLARE_OOXMLEXPORT_TEST(testInputListExport, "tdf122186_input_list.odt")
{
- // We need to make sure we don't export the text itself next to the input list field
- xmlDocPtr pXmlDoc = parseExport("word/document.xml");
- if (!pXmlDoc)
- return;
- assertXPath(pXmlDoc, "/w:document/w:body/w:p/w:r", 5);
- assertXPath(pXmlDoc, "/w:document/w:body/w:p/w:r[4]/w:t", 0);
+ if (!mbExported) // importing the ODT, an input field
+ {
+ uno::Reference<text::XTextFieldsSupplier> xTextFieldsSupplier(mxComponent, uno::UNO_QUERY);
+ uno::Reference<container::XEnumerationAccess> xFieldsAccess(xTextFieldsSupplier->getTextFields());
+ uno::Reference<container::XEnumeration> xFields(xFieldsAccess->createEnumeration());
+ CPPUNIT_ASSERT(xFields->hasMoreElements());
+ uno::Any aField = xFields->nextElement();
+ uno::Reference<lang::XServiceInfo> xServiceInfo(aField, uno::UNO_QUERY);
+ CPPUNIT_ASSERT(xServiceInfo->supportsService("com.sun.star.text.textfield.DropDown"));
+ }
+ else // importing the DOCX, a form control
+ {
+ uno::Reference<drawing::XControlShape> xControlShape(getShape(1), uno::UNO_QUERY);
+ uno::Reference<beans::XPropertySet> xPropertySet(xControlShape->getControl(), uno::UNO_QUERY);
+ uno::Reference<lang::XServiceInfo> xServiceInfo(xPropertySet, uno::UNO_QUERY);
+ CPPUNIT_ASSERT(xServiceInfo->supportsService("com.sun.star.form.component.ComboBox"));
+ CPPUNIT_ASSERT(getProperty<bool>(xPropertySet, "Dropdown"));
+ auto const items(getProperty<uno::Sequence<OUString>>(xPropertySet, "StringItemList"));
+ CPPUNIT_ASSERT_EQUAL(sal_Int32(3), items.getLength());
+ CPPUNIT_ASSERT_EQUAL(OUString("1"), items[0]);
+ CPPUNIT_ASSERT_EQUAL(OUString("2"), items[1]);
+ CPPUNIT_ASSERT_EQUAL(OUString("3"), items[2]);
+ }
}
DECLARE_OOXMLEXPORT_TEST(testTdf116371, "tdf116371.odt")
diff --git a/sw/source/filter/ww8/docxattributeoutput.cxx b/sw/source/filter/ww8/docxattributeoutput.cxx
index d41691d39d59..6885e002bf29 100644
--- a/sw/source/filter/ww8/docxattributeoutput.cxx
+++ b/sw/source/filter/ww8/docxattributeoutput.cxx
@@ -1326,7 +1326,7 @@ void DocxAttributeOutput::EndRun(const SwTextNode* pNode, sal_Int32 nPos, bool /
for ( std::vector<FieldInfos>::iterator pIt = m_Fields.begin() + nFieldsInPrevHyperlink; pIt != m_Fields.end(); )
{
// Add the fields starts for all but hyperlinks and TOCs
- if ( pIt->bOpen && pIt->pField )
+ if (pIt->bOpen && pIt->pField && pIt->eType != ww::eFORMDROPDOWN)
{
StartField_Impl( pNode, nPos, *pIt );
@@ -1391,7 +1391,7 @@ void DocxAttributeOutput::EndRun(const SwTextNode* pNode, sal_Int32 nPos, bool /
for ( std::vector<FieldInfos>::iterator pIt = m_Fields.begin(); pIt != m_Fields.end(); )
{
// Add the fields starts for hyperlinks, TOCs and index marks
- if ( pIt->bOpen && !pIt->pField )
+ if (pIt->bOpen && (!pIt->pField || pIt->eType == ww::eFORMDROPDOWN))
{
StartRedline( m_pRedlineData );
StartField_Impl( pNode, nPos, *pIt, true );
@@ -1926,12 +1926,57 @@ void DocxAttributeOutput::WriteFormDateStart(const OUString& sFullDate, const OU
m_pSerializer->startElementNS(XML_w, XML_sdtContent);
}
-void DocxAttributeOutput::WriteFormDateEnd()
+void DocxAttributeOutput::WriteSdtEnd()
{
m_pSerializer->endElementNS(XML_w, XML_sdtContent);
m_pSerializer->endElementNS(XML_w, XML_sdt);
}
+void DocxAttributeOutput::WriteSdtDropDownStart(
+ OUString const& rName,
+ OUString const& rSelected,
+ uno::Sequence<OUString> const& rListItems)
+{
+ m_pSerializer->startElementNS(XML_w, XML_sdt);
+ m_pSerializer->startElementNS(XML_w, XML_sdtPr);
+
+ m_pSerializer->singleElementNS(XML_w, XML_alias,
+ FSNS(XML_w, XML_val), OUStringToOString(rName, RTL_TEXTENCODING_UTF8));
+
+ sal_Int32 nId = comphelper::findValue(rListItems, rSelected);
+ if (nId == -1)
+ {
+ nId = 0;
+ }
+
+ m_pSerializer->startElementNS(XML_w, XML_dropDownList,
+ FSNS(XML_w, XML_lastValue), OString::number(nId));
+
+ for (auto const& rItem : rListItems)
+ {
+ auto const item(OUStringToOString(rItem, RTL_TEXTENCODING_UTF8));
+ m_pSerializer->singleElementNS(XML_w, XML_listItem,
+ FSNS(XML_w, XML_value), item,
+ FSNS(XML_w, XML_displayText), item);
+ }
+
+ m_pSerializer->endElementNS(XML_w, XML_dropDownList);
+ m_pSerializer->endElementNS(XML_w, XML_sdtPr);
+
+ m_pSerializer->startElementNS(XML_w, XML_sdtContent);
+
+ // the lastValue only identifies the entry in the list, also export
+ // currently selected item's displayText as run content (if one exists)
+ if (rListItems.size())
+ {
+ m_pSerializer->startElementNS(XML_w, XML_r);
+ m_pSerializer->startElementNS(XML_w, XML_t);
+ m_pSerializer->writeEscaped(rListItems[nId]);
+ m_pSerializer->endElementNS(XML_w, XML_t);
+ m_pSerializer->endElementNS(XML_w, XML_r);
+ }
+}
+
void DocxAttributeOutput::StartField_Impl( const SwTextNode* pNode, sal_Int32 nPos, FieldInfos const & rInfos, bool bWriteRun )
{
if ( rInfos.pField && rInfos.eType == ww::eUNKNOWN )
@@ -1967,6 +2012,14 @@ void DocxAttributeOutput::StartField_Impl( const SwTextNode* pNode, sal_Int32 nP
WriteFormDateStart( sFullDate, sDateFormat, sLang );
}
+ else if (rInfos.eType == ww::eFORMDROPDOWN && rInfos.pField)
+ {
+ assert(!rInfos.pFieldmark);
+ SwDropDownField const& rField2(*static_cast<SwDropDownField const*>(rInfos.pField.get()));
+ WriteSdtDropDownStart(rField2.GetName(),
+ rField2.GetSelectedItem(),
+ rField2.GetItemSequence());
+ }
else if ( rInfos.eType != ww::eNONE ) // HYPERLINK fields are just commands
{
if ( bWriteRun )
@@ -1974,27 +2027,16 @@ void DocxAttributeOutput::StartField_Impl( const SwTextNode* pNode, sal_Int32 nP
if ( rInfos.eType == ww::eFORMDROPDOWN )
{
- m_pSerializer->startElementNS( XML_w, XML_fldChar,
- FSNS( XML_w, XML_fldCharType ), "begin" );
- if ( rInfos.pFieldmark && !rInfos.pField )
- WriteFFData( rInfos );
- if ( rInfos.pField )
- {
- const SwDropDownField& rField2 = *static_cast<const SwDropDownField*>(rInfos.pField.get());
- uno::Sequence<OUString> aItems =
- rField2.GetItemSequence();
- GetExport().DoComboBox(rField2.GetName(),
- rField2.GetHelp(),
- rField2.GetToolTip(),
- rField2.GetSelectedItem(), aItems);
- }
- m_pSerializer->endElementNS( XML_w, XML_fldChar );
+ m_pSerializer->startElementNS( XML_w, XML_fldChar,
+ FSNS( XML_w, XML_fldCharType ), "begin" );
+ assert( rInfos.pFieldmark && !rInfos.pField );
+ WriteFFData(rInfos);
+ m_pSerializer->endElementNS( XML_w, XML_fldChar );
- if ( bWriteRun )
- m_pSerializer->endElementNS( XML_w, XML_r );
+ if ( bWriteRun )
+ m_pSerializer->endElementNS( XML_w, XML_r );
- if ( !rInfos.pField )
- CmdField_Impl( pNode, nPos, rInfos, bWriteRun );
+ CmdField_Impl( pNode, nPos, rInfos, bWriteRun );
}
else
{
@@ -2179,9 +2221,10 @@ void DocxAttributeOutput::DoWriteFieldRunProperties( const SwTextNode * pNode, s
void DocxAttributeOutput::EndField_Impl( const SwTextNode* pNode, sal_Int32 nPos, FieldInfos& rInfos )
{
- if ( rInfos.eType == ww::eFORMDATE )
+ if (rInfos.eType == ww::eFORMDATE
+ || (rInfos.eType == ww::eFORMDROPDOWN && rInfos.pField))
{
- WriteFormDateEnd();
+ WriteSdtEnd();
return;
}
diff --git a/sw/source/filter/ww8/docxattributeoutput.hxx b/sw/source/filter/ww8/docxattributeoutput.hxx
index 67561087ceb3..ef95f70fb881 100644
--- a/sw/source/filter/ww8/docxattributeoutput.hxx
+++ b/sw/source/filter/ww8/docxattributeoutput.hxx
@@ -717,7 +717,8 @@ private:
void EndSdtBlock();
void WriteFormDateStart(const OUString& sFullDate, const OUString& sDateFormat, const OUString& sLang);
- void WriteFormDateEnd();
+ void WriteSdtDropDownStart(OUString const& rName, OUString const& rSelected, uno::Sequence<OUString> const& rListItems);
+ void WriteSdtEnd();
void StartField_Impl( const SwTextNode* pNode, sal_Int32 nPos, FieldInfos const & rInfos, bool bWriteRun = false );
void DoWriteCmd( const OUString& rCmd );