sw/qa/extras/ooxmlexport/data/tdf148380_printField.docx |binary sw/qa/extras/ooxmlexport/ooxmlexport17.cxx | 17 ++++ writerfilter/source/dmapper/DomainMapper_Impl.cxx | 64 +++++++++++----- writerfilter/source/dmapper/DomainMapper_Impl.hxx | 1 4 files changed, 61 insertions(+), 21 deletions(-)
New commits: commit 115599cc3478e37879cd2fa0b6c6c9dabde7dfd1 Author: Justin Luth <justin_l...@sil.org> AuthorDate: Sat Apr 9 18:06:24 2022 +0200 Commit: Justin Luth <jl...@mail.com> CommitDate: Mon Apr 25 18:57:45 2022 +0200 tdf#132475 writerfilter: use proper date-field defaults When a field doesn't specify the format for a date, the system is free to implement it as it chooses. However, the user tends to disagree with that, so lets try to create a MS-similar default for these dates - since LO defaults to only displaying a date without any time component. For example: PRINTDATE \* MERGEFORMAT doesn't tell us how to display the date. MS Word uses different defaults depending on the language of the document. And that only make sense. For example, I noticed that of course en-GB's format is dd/MM/yyyy instead of en-US's M/d/yyyy. As a documentation example: 17.16.5.47 PRINTDATE Syntax: PRINTDATE [ switches ] Description: Retrieves the date and time on which the document was last printed, as recorded in the LastPrinted element of the Core File Properties part. Switches: Zero or one date-and-time-formatting-switch and zero or one of the following field-specific-switches. PRINTDATE (without any formatting switches) the results are: 1/6/2006 2:58:00 PM Change-Id: I41f3bdc155bd8cdc74177e4626b31ece9b47e16b Reviewed-on: https://gerrit.libreoffice.org/c/core/+/133208 Tested-by: Justin Luth <jl...@mail.com> Tested-by: Jenkins Reviewed-by: Justin Luth <jl...@mail.com> diff --git a/sw/qa/extras/ooxmlexport/data/tdf148380_printField.docx b/sw/qa/extras/ooxmlexport/data/tdf148380_printField.docx new file mode 100644 index 000000000000..44145748c6ed Binary files /dev/null and b/sw/qa/extras/ooxmlexport/data/tdf148380_printField.docx differ diff --git a/sw/qa/extras/ooxmlexport/ooxmlexport17.cxx b/sw/qa/extras/ooxmlexport/ooxmlexport17.cxx index 9347a8abfb54..464c0b22d6c4 100644 --- a/sw/qa/extras/ooxmlexport/ooxmlexport17.cxx +++ b/sw/qa/extras/ooxmlexport/ooxmlexport17.cxx @@ -100,6 +100,23 @@ DECLARE_OOXMLEXPORT_TEST(testTdf148380_modifiedField, "tdf148380_modifiedField.d OUString("Charles Brown"), xField->getPresentation(false)); } +DECLARE_OOXMLEXPORT_TEST(testTdf148380_printField, "tdf148380_printField.docx") +{ + // Verify that these are fields, and not just plain text + uno::Reference<text::XTextFieldsSupplier> xTextFieldsSupplier(mxComponent, uno::UNO_QUERY); + auto xFieldsAccess(xTextFieldsSupplier->getTextFields()); + uno::Reference<container::XEnumeration> xFields(xFieldsAccess->createEnumeration()); + uno::Reference<text::XTextField> xField(xFields->nextElement(), uno::UNO_QUERY); + // unspecified SAVEDATE gets default GB formatting because stylele.xml has w:lang w:val="en-GB" + //CPPUNIT_ASSERT_EQUAL(OUString("08/04/2022 07:10:00 AM"), xField->getPresentation(false)); + //CPPUNIT_ASSERT_EQUAL(OUString("DocInformation:Modified"), xField->getPresentation(true)); + //xField.set(xFields->nextElement(), uno::UNO_QUERY); + // MS Word actually shows "8 o'clock-ish" until the document is reprinted, + // but it seems best to actually show the real last-printed date since it can't be FIXEDFLD + CPPUNIT_ASSERT_EQUAL(OUString("08/04/2022 06:47:00 AM"), xField->getPresentation(false)); + CPPUNIT_ASSERT_EQUAL(OUString("DocInformation:Last printed"), xField->getPresentation(true)); +} + DECLARE_OOXMLEXPORT_TEST(testTdf132475_printField, "tdf132475_printField.docx") { // The last printed date field: formatted two different ways diff --git a/writerfilter/source/dmapper/DomainMapper_Impl.cxx b/writerfilter/source/dmapper/DomainMapper_Impl.cxx index 6206a9386edb..d8327fa8d248 100644 --- a/writerfilter/source/dmapper/DomainMapper_Impl.cxx +++ b/writerfilter/source/dmapper/DomainMapper_Impl.cxx @@ -35,6 +35,8 @@ #include <com/sun/star/document/IndexedPropertyValues.hpp> #include <com/sun/star/drawing/XDrawPageSupplier.hpp> #include <com/sun/star/embed/XEmbeddedObject.hpp> +#include <com/sun/star/i18n/NumberFormatMapper.hpp> +#include <com/sun/star/i18n/NumberFormatIndex.hpp> #include <com/sun/star/lang/XServiceInfo.hpp> #include <com/sun/star/style/XStyleFamiliesSupplier.hpp> #include <com/sun/star/style/LineNumberPosition.hpp> @@ -1187,6 +1189,15 @@ uno::Any DomainMapper_Impl::GetAnyProperty(PropertyIds eId, const PropertyMapPtr return aProperty->second; } + // then look whether it was directly applied as a paragraph property + PropertyMapPtr pParaContext = GetTopContextOfType(CONTEXT_PARAGRAPH); + if (pParaContext && rContext != pParaContext) + { + std::optional<PropertyMap::Property> aProperty = pParaContext->getProperty(eId); + if (aProperty) + return aProperty->second; + } + // then look whether it was inherited from a directly applied character style if ( eId != PROP_CHAR_STYLE_NAME && isCharacterProperty(eId) ) { @@ -4429,23 +4440,6 @@ static OUString lcl_trim(std::u16string_view sValue) return OUString(o3tl::trim(sValue)).replaceAll("\"","").replaceAll(u"“", "").replaceAll(u"”", ""); } -void DomainMapper_Impl::GetCurrentLocale(lang::Locale& rLocale) -{ - PropertyMapPtr pTopContext = GetTopContext(); - std::optional<PropertyMap::Property> pLocale = pTopContext->getProperty(PROP_CHAR_LOCALE); - if( pLocale ) - pLocale->second >>= rLocale; - else - { - PropertyMapPtr pParaContext = GetTopContextOfType(CONTEXT_PARAGRAPH); - pLocale = pParaContext->getProperty(PROP_CHAR_LOCALE); - if( pLocale ) - { - pLocale->second >>= rLocale; - } - } -} - /*------------------------------------------------------------------------- extract the number format from the command and apply the resulting number format to the XPropertySet @@ -4461,9 +4455,39 @@ void DomainMapper_Impl::SetNumberFormat( const OUString& rCommand, aUSLocale.Language = "en"; aUSLocale.Country = "US"; - //determine current locale - todo: is it necessary to initialize this locale? - lang::Locale aCurrentLocale = aUSLocale; - GetCurrentLocale( aCurrentLocale ); + lang::Locale aCurrentLocale; + GetAnyProperty(PROP_CHAR_LOCALE, GetTopContext()) >>= aCurrentLocale; + + if (sFormatString.isEmpty()) + { + // No format specified. MS Word uses different formats depending on w:lang, + // "M/d/yyyy h:mm:ss AM/PM" for en-US, and "dd/MM/yyyy hh:mm:ss AM/PM" for en-GB. + // ALSO SEE: ww8par5's GetWordDefaultDateStringAsUS. + sal_Int32 nPos = rCommand.indexOf(" \\"); + OUString sCommand = nPos == -1 ? rCommand.trim() + : OUString(o3tl::trim(rCommand.subView(0, nPos))); + if (sCommand == "CREATEDATE" || sCommand == "PRINTDATE" || sCommand == "SAVEDATE") + { + try + { + css::uno::Reference<css::i18n::XNumberFormatCode> const& xNumberFormatCode = + i18n::NumberFormatMapper::create(m_xComponentContext); + sFormatString = xNumberFormatCode->getFormatCode( + css::i18n::NumberFormatIndex::DATE_SYSTEM_SHORT, aCurrentLocale).Code; + nPos = sFormatString.indexOf("YYYY"); + if (nPos == -1) + sFormatString = sFormatString.replaceFirst("YY", "YYYY"); + if (aCurrentLocale == aUSLocale) + sFormatString += " h:mm:ss AM/PM"; + else + sFormatString += " hh:mm:ss AM/PM"; + } + catch(const uno::Exception&) + { + DBG_UNHANDLED_EXCEPTION("writerfilter.dmapper"); + } + } + } OUString sFormat = ConversionHelper::ConvertMSFormatStringToSO( sFormatString, aCurrentLocale, bHijri); //get the number formatter and convert the string to a format value try diff --git a/writerfilter/source/dmapper/DomainMapper_Impl.hxx b/writerfilter/source/dmapper/DomainMapper_Impl.hxx index a8355e17a4c9..32721e170c38 100644 --- a/writerfilter/source/dmapper/DomainMapper_Impl.hxx +++ b/writerfilter/source/dmapper/DomainMapper_Impl.hxx @@ -614,7 +614,6 @@ private: bool m_bAnnotationResolved = false; std::unordered_map< sal_Int32, AnnotationPosition > m_aAnnotationPositions; - void GetCurrentLocale(css::lang::Locale& rLocale); void SetNumberFormat(const OUString& rCommand, css::uno::Reference<css::beans::XPropertySet> const& xPropertySet, bool bDetectFormat = false); /// @throws css::uno::Exception css::uno::Reference<css::beans::XPropertySet> FindOrCreateFieldMaster(const char* pFieldMasterService, const OUString& rFieldMasterName);