sw/qa/extras/globalfilter/data/date_form_field.odt |binary sw/qa/extras/globalfilter/globalfilter.cxx | 97 +++++++++++++++++++++ sw/source/core/doc/docbm.cxx | 6 - sw/source/filter/ww8/docxattributeoutput.cxx | 93 ++++++++++++++++++++ sw/source/filter/ww8/docxattributeoutput.hxx | 2 sw/source/filter/ww8/fields.hxx | 3 sw/source/filter/ww8/wrtw8nds.cxx | 40 +++++--- xmloff/source/text/XMLTextMarkImportContext.cxx | 5 - 8 files changed, 228 insertions(+), 18 deletions(-)
New commits: commit 865bfe5cc95c11ab7273bd3ac74cd4f4bd9e097e Author: Tamás Zolnai <[email protected]> AuthorDate: Fri Jun 21 20:40:27 2019 +0200 Commit: Tamás Zolnai <[email protected]> CommitDate: Fri Jul 12 03:17:36 2019 +0200 MSForms: DOCX export of date content control Change-Id: I546af6d552e5e3801925285d0095fc8502896a15 Reviewed-on: https://gerrit.libreoffice.org/75446 Tested-by: Jenkins Reviewed-by: Tamás Zolnai <[email protected]> diff --git a/sw/source/filter/ww8/docxattributeoutput.cxx b/sw/source/filter/ww8/docxattributeoutput.cxx index e5167a264f41..0ccf7001c0e1 100644 --- a/sw/source/filter/ww8/docxattributeoutput.cxx +++ b/sw/source/filter/ww8/docxattributeoutput.cxx @@ -239,6 +239,7 @@ public: m_pSerializer->endElementNS( XML_w, XML_checkBox ); writeFinish(); } + void WriteFormText( const OUString& rName, const OUString& rEntryMacro, const OUString& rExitMacro, @@ -1877,6 +1878,84 @@ void DocxAttributeOutput::WriteFFData( const FieldInfos& rInfos ) } } +void DocxAttributeOutput::WriteFormDate(const OUString& sCurrentDate, const OUString& sDateFormat, const OUString& sLang) +{ + m_pSerializer->startElementNS(XML_w, XML_sdt); + m_pSerializer->startElementNS(XML_w, XML_sdtPr); + + if (!sCurrentDate.isEmpty()) + { + OString sDate = sCurrentDate.toUtf8() + "T00:00:00Z"; + m_pSerializer->startElementNS(XML_w, XML_date, FSNS(XML_w, XML_fullDate), sDate); + } + else + m_pSerializer->startElementNS(XML_w, XML_date); + + m_pSerializer->singleElementNS(XML_w, XML_dateFormat, + FSNS(XML_w, XML_val), sDateFormat.toUtf8()); + m_pSerializer->singleElementNS(XML_w, XML_lid, + FSNS(XML_w, XML_val), sLang.toUtf8()); + m_pSerializer->singleElementNS(XML_w, XML_storeMappedDataAs, + FSNS(XML_w, XML_val), "dateTime"); + m_pSerializer->singleElementNS(XML_w, XML_calendar, + FSNS(XML_w, XML_val), "gregorian"); + + m_pSerializer->endElementNS(XML_w, XML_date); + m_pSerializer->endElementNS(XML_w, XML_sdtPr); + + m_pSerializer->startElementNS(XML_w, XML_sdtContent); + m_pSerializer->startElementNS(XML_w, XML_r); + + if (!sCurrentDate.isEmpty()) + { + // Convert the current date to the right format + if (!sCurrentDate.isEmpty()) + { + SvNumberFormatter* pFormatter = m_rExport.m_pDoc->GetNumberFormatter(); + + double dCurrentDate = 0.0; + // First get the date internal double representation + sal_uInt32 nFormat = pFormatter->GetEntryKey(ODF_FORMDATE_CURRENTDATE_FORMAT, ODF_FORMDATE_CURRENTDATE_LANGUAGE); if (nFormat == NUMBERFORMAT_ENTRY_NOT_FOUND) + if (nFormat == NUMBERFORMAT_ENTRY_NOT_FOUND) + { + sal_Int32 nCheckPos = 0; + SvNumFormatType nType; + OUString sFormat = ODF_FORMDATE_CURRENTDATE_FORMAT; + pFormatter->PutEntry(sFormat, + nCheckPos, + nType, + nFormat, + ODF_FORMDATE_CURRENTDATE_LANGUAGE); + } + pFormatter->IsNumberFormat(sCurrentDate, nFormat, dCurrentDate); + + // Then convert the date to a fromatter string + OUString sOutput; + Color* pCol = nullptr; + nFormat = pFormatter->GetEntryKey(sDateFormat, LanguageTag(sLang).getLanguageType()); + if (nFormat == NUMBERFORMAT_ENTRY_NOT_FOUND) + { + sal_Int32 nCheckPos = 0; + SvNumFormatType nType; + OUString sNonConstDateFormat = sDateFormat; + pFormatter->PutEntry(sNonConstDateFormat, + nCheckPos, + nType, + nFormat, + LanguageTag(sLang).getLanguageType()); + } + pFormatter->GetOutputString(dCurrentDate, nFormat, sOutput, &pCol, false); + + RunText(sOutput); + } + } + + m_pSerializer->endElementNS(XML_w, XML_r); + m_pSerializer->endElementNS(XML_w, XML_sdtContent); + + m_pSerializer->endElementNS(XML_w, XML_sdt); +} + void DocxAttributeOutput::StartField_Impl( const SwTextNode* pNode, sal_Int32 nPos, FieldInfos const & rInfos, bool bWriteRun ) { if ( rInfos.pField && rInfos.eType == ww::eUNKNOWN ) @@ -1884,6 +1963,20 @@ void DocxAttributeOutput::StartField_Impl( const SwTextNode* pNode, sal_Int32 nP // Expand unsupported fields RunText( rInfos.pField->GetFieldName() ); } + else if ( rInfos.eType == ww::eFORMDATE ) + { + const ::sw::mark::IFieldmark& rFieldmark = *rInfos.pFieldmark; + FieldMarkParamsHelper params( rFieldmark ); + + OUString sCurrentDate; + params.extractParam( ODF_FORMDATE_CURRENTDATE, sCurrentDate ); + OUString sDateFormat; + params.extractParam( ODF_FORMDATE_DATEFORMAT, sDateFormat ); + OUString sLang; + params.extractParam( ODF_FORMDATE_DATEFORMAT_LANGUAGE, sLang ); + + WriteFormDate( sCurrentDate, sDateFormat, sLang ); + } else if ( rInfos.eType != ww::eNONE ) // HYPERLINK fields are just commands { if ( bWriteRun ) diff --git a/sw/source/filter/ww8/docxattributeoutput.hxx b/sw/source/filter/ww8/docxattributeoutput.hxx index 2d4726bbebdb..b4c8204052af 100644 --- a/sw/source/filter/ww8/docxattributeoutput.hxx +++ b/sw/source/filter/ww8/docxattributeoutput.hxx @@ -707,6 +707,8 @@ private: /// Closes a currently open SDT block. void EndSdtBlock(); + void WriteFormDate(const OUString& sCurrentDate, const OUString& sDateFormat, const OUString& sLang); + void StartField_Impl( const SwTextNode* pNode, sal_Int32 nPos, FieldInfos const & rInfos, bool bWriteRun = false ); void DoWriteCmd( const OUString& rCmd ); void CmdField_Impl( const SwTextNode* pNode, sal_Int32 nPos, FieldInfos const & rInfos, bool bWriteRun ); diff --git a/sw/source/filter/ww8/fields.hxx b/sw/source/filter/ww8/fields.hxx index 4bdd5641d8c4..8e24ca11d37b 100644 --- a/sw/source/filter/ww8/fields.hxx +++ b/sw/source/filter/ww8/fields.hxx @@ -124,7 +124,8 @@ namespace ww // NOTE: values > 95 / 0x5F do not correspond to documented WW8 fields // and thus need special handling in WW8Export::OutputField()! eBIBLIOGRPAHY=96, - eCITATION = 97 + eCITATION = 97, + eFORMDATE = 98, }; /** Find the English Field Name from a winword index diff --git a/sw/source/filter/ww8/wrtw8nds.cxx b/sw/source/filter/ww8/wrtw8nds.cxx index 19b901fe0e31..a322da5f9ed3 100644 --- a/sw/source/filter/ww8/wrtw8nds.cxx +++ b/sw/source/filter/ww8/wrtw8nds.cxx @@ -128,6 +128,8 @@ static OUString lcl_getFieldCode( const IFieldmark* pFieldmark ) return OUString(" FORMDROPDOWN "); if ( pFieldmark->GetFieldname( ) == ODF_FORMCHECKBOX ) return OUString(" FORMCHECKBOX "); + if ( pFieldmark->GetFieldname( ) == ODF_FORMDATE ) + return OUString(" ODFFORMDATE "); if ( pFieldmark->GetFieldname( ) == ODF_TOC ) return OUString(" TOC "); if ( pFieldmark->GetFieldname( ) == ODF_HYPERLINK ) @@ -147,6 +149,8 @@ static ww::eField lcl_getFieldId( const IFieldmark* pFieldmark ) { return ww::eFORMDROPDOWN; if ( pFieldmark->GetFieldname( ) == ODF_FORMCHECKBOX ) return ww::eFORMCHECKBOX; + if ( pFieldmark->GetFieldname( ) == ODF_FORMDATE ) + return ww::eFORMDATE; if ( pFieldmark->GetFieldname( ) == ODF_TOC ) return ww::eTOC; if ( pFieldmark->GetFieldname( ) == ODF_HYPERLINK ) @@ -2406,21 +2410,31 @@ void MSWordExportBase::OutputTextNode( SwTextNode& rNode ) { SwPosition aPosition( rNode, SwIndex( &rNode, nCurrentPos ) ); ::sw::mark::IFieldmark const * const pFieldmark = pMarkAccess->getFieldmarkFor( aPosition ); - OSL_ENSURE( pFieldmark, "Looks like this doc is broken...; where is the Fieldmark for the FIELDSTART??" ); - - bool isDropdownOrCheckbox = pFieldmark && (pFieldmark->GetFieldname( ) == ODF_FORMDROPDOWN || - pFieldmark->GetFieldname( ) == ODF_FORMCHECKBOX ); - if ( isDropdownOrCheckbox ) - AppendBookmark( pFieldmark->GetName() ); - OutputField( nullptr, lcl_getFieldId( pFieldmark ), - lcl_getFieldCode( pFieldmark ), - FieldFlags::Start | FieldFlags::CmdStart ); - if ( isDropdownOrCheckbox ) + // Date field is exported as content control, not as a simple field + if(pFieldmark && pFieldmark->GetFieldname( ) == ODF_FORMDATE && + GetExportFormat() == MSWordExportBase::ExportFormat::DOCX) // supported by DOCX only + { + OutputField( nullptr, lcl_getFieldId( pFieldmark ), + lcl_getFieldCode( pFieldmark ), + FieldFlags::Start | FieldFlags::CmdStart ); WriteFormData( *pFieldmark ); - OutputField( nullptr, lcl_getFieldId( pFieldmark ), OUString(), FieldFlags::Close ); - if ( isDropdownOrCheckbox ) - AppendBookmark( pFieldmark->GetName() ); + } + else + { + bool isDropdownOrCheckbox = pFieldmark && (pFieldmark->GetFieldname( ) == ODF_FORMDROPDOWN || + pFieldmark->GetFieldname( ) == ODF_FORMCHECKBOX ); + if ( isDropdownOrCheckbox ) + AppendBookmark( pFieldmark->GetName() ); + OutputField( nullptr, lcl_getFieldId( pFieldmark ), + lcl_getFieldCode( pFieldmark ), + FieldFlags::Start | FieldFlags::CmdStart ); + if ( isDropdownOrCheckbox ) + WriteFormData( *pFieldmark ); + OutputField( nullptr, lcl_getFieldId( pFieldmark ), OUString(), FieldFlags::Close ); + if ( isDropdownOrCheckbox ) + AppendBookmark( pFieldmark->GetName() ); + } } nLen -= ofs; commit 46a59d10dbbe3cb9bb9962df93e5a79a5318dcfd Author: Tamás Zolnai <[email protected]> AuthorDate: Fri Jun 21 17:56:30 2019 +0200 Commit: Tamás Zolnai <[email protected]> CommitDate: Fri Jul 12 03:17:16 2019 +0200 MSForms: ODF import / export of text-based date field Change-Id: Ib535f1ce065a7f298fcccf95e82d1ffab4d1e1e2 Reviewed-on: https://gerrit.libreoffice.org/75445 Tested-by: Jenkins Reviewed-by: Tamás Zolnai <[email protected]> diff --git a/sw/qa/extras/globalfilter/data/date_form_field.odt b/sw/qa/extras/globalfilter/data/date_form_field.odt new file mode 100644 index 000000000000..8e15793c2d59 Binary files /dev/null and b/sw/qa/extras/globalfilter/data/date_form_field.odt differ diff --git a/sw/qa/extras/globalfilter/globalfilter.cxx b/sw/qa/extras/globalfilter/globalfilter.cxx index 337d182b4809..87a28cd3676b 100644 --- a/sw/qa/extras/globalfilter/globalfilter.cxx +++ b/sw/qa/extras/globalfilter/globalfilter.cxx @@ -50,6 +50,7 @@ public: void testTextFormField(); void testCheckBoxFormField(); void testDropDownFormField(); + void testDateFormField(); CPPUNIT_TEST_SUITE(Test); CPPUNIT_TEST(testEmbeddedGraphicRoundtrip); @@ -68,6 +69,7 @@ public: CPPUNIT_TEST(testTextFormField); CPPUNIT_TEST(testCheckBoxFormField); CPPUNIT_TEST(testDropDownFormField); + CPPUNIT_TEST(testDateFormField); CPPUNIT_TEST_SUITE_END(); }; @@ -1237,6 +1239,101 @@ void Test::testDropDownFormField() } } +void Test::testDateFormField() +{ + const OUString aFilterNames[] = { + "writer8", + //"MS Word 97", + //"Office Open XML Text", + }; + + for (const OUString& rFilterName : aFilterNames) + { + if (mxComponent.is()) + mxComponent->dispose(); + mxComponent = loadFromDesktop(m_directories.getURLFromSrc("/sw/qa/extras/globalfilter/data/date_form_field.odt"), "com.sun.star.text.TextDocument"); + + const OString sFailedMessage = OString("Failed on filter: ") + rFilterName.toUtf8(); + + // Export the document and import again for a check + uno::Reference<frame::XStorable> xStorable(mxComponent, uno::UNO_QUERY); + utl::MediaDescriptor aMediaDescriptor; + aMediaDescriptor["FilterName"] <<= rFilterName; + utl::TempFile aTempFile; + aTempFile.EnableKillingFile(); + xStorable->storeToURL(aTempFile.GetURL(), aMediaDescriptor.getAsConstPropertyValueList()); + uno::Reference< lang::XComponent > xComponent(xStorable, uno::UNO_QUERY); + xComponent->dispose(); + mxComponent = loadFromDesktop(aTempFile.GetURL(), "com.sun.star.text.TextDocument"); + + // Check the document after round trip + SwXTextDocument* pTextDoc = dynamic_cast<SwXTextDocument *>(mxComponent.get()); + CPPUNIT_ASSERT_MESSAGE(sFailedMessage.getStr(), pTextDoc); + SwDoc* pDoc = pTextDoc->GetDocShell()->GetDoc(); + IDocumentMarkAccess* pMarkAccess = pDoc->getIDocumentMarkAccess(); + + CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage.getStr(), sal_Int32(3), pMarkAccess->getAllMarksCount()); + + int nIndex = 0; + for(auto aIter = pMarkAccess->getAllMarksBegin(); aIter != pMarkAccess->getAllMarksEnd(); ++aIter) + { + ::sw::mark::IFieldmark* pFieldmark = dynamic_cast<::sw::mark::IFieldmark*>(*aIter); + + if(!pFieldmark) + continue; + + CPPUNIT_ASSERT_MESSAGE(sFailedMessage.getStr(), pFieldmark); + CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage.getStr(), OUString(ODF_FORMDATE), pFieldmark->GetFieldname()); + + // Check date form field's parameters. + const sw::mark::IFieldmark::parameter_map_t* const pParameters = pFieldmark->GetParameters(); + OUString sDateFormat; + auto pResult = pParameters->find(ODF_FORMDATE_DATEFORMAT); + if (pResult != pParameters->end()) + { + pResult->second >>= sDateFormat; + } + + OUString sLang; + pResult = pParameters->find(ODF_FORMDATE_DATEFORMAT_LANGUAGE); + if (pResult != pParameters->end()) + { + pResult->second >>= sLang; + } + + OUString sCurrentDate; + pResult = pParameters->find(ODF_FORMDATE_CURRENTDATE); + if (pResult != pParameters->end()) + { + pResult->second >>= sCurrentDate; + } + + // The first one is empty + if(nIndex == 0) + { + + CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage.getStr(), OUString("MM/DD/YY"), sDateFormat); + CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage.getStr(), OUString("en-US"), sLang); + CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage.getStr(), OUString(""), sCurrentDate); + } + else if (nIndex == 1) // The second has the default format + { + CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage.getStr(), OUString("MM/DD/YY"), sDateFormat); + CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage.getStr(), OUString("en-US"), sLang); + CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage.getStr(), OUString("2019-06-12"), sCurrentDate); + } + else // The third one has special format + { + CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage.getStr(), OUString("[NatNum12 MMMM=abbreviation]YYYY\". \"MMMM D."), sDateFormat); + CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage.getStr(), OUString("hu-HU"), sLang); + CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage.getStr(), OUString("2019-06-11"), sCurrentDate); + } + ++nIndex; + } + CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage.getStr(), int(3), nIndex); + } +} + CPPUNIT_TEST_SUITE_REGISTRATION(Test); CPPUNIT_PLUGIN_IMPLEMENT(); diff --git a/sw/source/core/doc/docbm.cxx b/sw/source/core/doc/docbm.cxx index b02d8a68730f..012914060003 100644 --- a/sw/source/core/doc/docbm.cxx +++ b/sw/source/core/doc/docbm.cxx @@ -1279,17 +1279,17 @@ namespace sw { namespace mark bool bActualChange = false; if(rNewType == ODF_FORMDROPDOWN) { - if (dynamic_cast<::sw::mark::CheckboxFieldmark*>(pFieldmark)) + if (!dynamic_cast<::sw::mark::DropDownFieldmark*>(pFieldmark)) bActualChange = true; } else if(rNewType == ODF_FORMCHECKBOX) { - if (dynamic_cast<::sw::mark::DropDownFieldmark*>(pFieldmark)) + if (!dynamic_cast<::sw::mark::CheckboxFieldmark*>(pFieldmark)) bActualChange = true; } else if(rNewType == ODF_FORMDATE) { - if (dynamic_cast<::sw::mark::DateFieldmark*>(pFieldmark)) + if (!dynamic_cast<::sw::mark::DateFieldmark*>(pFieldmark)) bActualChange = true; } diff --git a/xmloff/source/text/XMLTextMarkImportContext.cxx b/xmloff/source/text/XMLTextMarkImportContext.cxx index 62e58c8a84c1..aff9a18c38d1 100644 --- a/xmloff/source/text/XMLTextMarkImportContext.cxx +++ b/xmloff/source/text/XMLTextMarkImportContext.cxx @@ -137,6 +137,8 @@ static const char *lcl_getFormFieldmarkName(OUString const &name) else if (name == ODF_FORMDROPDOWN || name == "ecma.office-open-xml.field.FORMDROPDOWN") return ODF_FORMDROPDOWN; + else if (name == ODF_FORMDATE) + return ODF_FORMDATE; else return nullptr; } @@ -330,7 +332,8 @@ void XMLTextMarkImportContext::EndElement() OUString const type(m_rHelper.getCurrentFieldType()); fieldmarkTypeName = lcl_getFieldmarkName(type); if (fieldmarkTypeName == ODF_FORMCHECKBOX || - fieldmarkTypeName == ODF_FORMDROPDOWN) + fieldmarkTypeName == ODF_FORMDROPDOWN || + fieldmarkTypeName == ODF_FORMDATE) { // sw can't handle checkbox with start+end SAL_INFO("xmloff.text", "invalid fieldmark-start/fieldmark-end ignored"); isInvalid = true; _______________________________________________ Libreoffice-commits mailing list [email protected] https://lists.freedesktop.org/mailman/listinfo/libreoffice-commits
