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 <jluth@mail.com>
Tested-by: Jenkins
Reviewed-by: Justin Luth <jluth@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 0000000..4414574
--- /dev/null
+++ b/sw/qa/extras/ooxmlexport/data/tdf148380_printField.docx
Binary files differ
diff --git a/sw/qa/extras/ooxmlexport/ooxmlexport17.cxx b/sw/qa/extras/ooxmlexport/ooxmlexport17.cxx
index 9347a8a..464c0b2 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 6206a93..d8327fa 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 a8355e1..32721e1 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);