diff options
author | Michael Stahl <Michael.Stahl@cib.de> | 2020-02-26 13:00:23 +0100 |
---|---|---|
committer | Caolán McNamara <caolanm@redhat.com> | 2020-02-28 18:28:48 +0100 |
commit | 2a04b3d676a1db76cc8fb19a1126648e7548dc47 (patch) | |
tree | ec6ef8674bb771a01916e8de7412b4e97d8d3390 /sw | |
parent | 02ef89cf647065ae39fb4845259f084c9b7ac008 (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>
Diffstat (limited to 'sw')
-rw-r--r-- | sw/qa/extras/ooxmlexport/ooxmlexport13.cxx | 29 | ||||
-rw-r--r-- | sw/source/filter/ww8/docxattributeoutput.cxx | 91 | ||||
-rw-r--r-- | sw/source/filter/ww8/docxattributeoutput.hxx | 3 |
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 ); |