forms/source/component/DatabaseForm.cxx | 114 +++++++++++++++++++++++++------- forms/source/component/DatabaseForm.hxx | 4 + 2 files changed, 96 insertions(+), 22 deletions(-)
New commits: commit e6f843c1c5c2cb075ff0ae358735c5801e56f51f Author: Mike Kaganski <mike.kagan...@collabora.com> AuthorDate: Sun Jul 20 23:34:03 2025 +0500 Commit: Xisco Fauli <xiscofa...@libreoffice.org> CommitDate: Sun Aug 10 11:16:45 2025 +0200 tdf#167591: Convert date string to date early To insert a default value, ODatabaseForm gets its value from column properties, and passes to XColumnUpdate. The problem appeared when the default was a localized date string, like "20/07/25". The string was set as the value of a ORowSetValue; then, when its value was requested, its getDate() called DBTypeConversion::toDate, which only handles ISO date strings. But for correct conversion, not only the string is needed, but also its format key. This information is already lost at that point. The conversion failed, and the result date was invalid, somewhere in the beginning of CE. Try to overcome this problem by converting the default value from date string to date(time) where all the information is available. Change-Id: I73e96e433895da18cbf6145ffc26b16fa4844452 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/188093 Reviewed-by: Mike Kaganski <mike.kagan...@collabora.com> Tested-by: Jenkins Signed-off-by: Xisco Fauli <xiscofa...@libreoffice.org> Reviewed-on: https://gerrit.libreoffice.org/c/core/+/188682 diff --git a/forms/source/component/DatabaseForm.cxx b/forms/source/component/DatabaseForm.cxx index e45842e02764..bb5cf9200284 100644 --- a/forms/source/component/DatabaseForm.cxx +++ b/forms/source/component/DatabaseForm.cxx @@ -53,11 +53,13 @@ #include <com/sun/star/sdbc/XRowSet.hpp> #include <com/sun/star/sdbcx/Privilege.hpp> #include <com/sun/star/sdbcx/XColumnsSupplier.hpp> +#include <com/sun/star/util/NumberFormatter.hpp> #include <com/sun/star/util/URLTransformer.hpp> #include <com/sun/star/util/XURLTransformer.hpp> #include <com/sun/star/util/XModifiable2.hpp> #include <comphelper/basicio.hxx> +#include <comphelper/numbers.hxx> #include <comphelper/property.hxx> #include <comphelper/seqstream.hxx> #include <comphelper/sequence.hxx> @@ -68,6 +70,7 @@ #include <rtl/math.hxx> #include <rtl/tencinfo.h> #include <svl/inettype.hxx> +#include <svl/numformat.hxx> #include <tools/datetime.hxx> #include <tools/debug.hxx> #include <comphelper/diagnose_ex.hxx> @@ -1923,6 +1926,70 @@ void SAL_CALL ODatabaseForm::reset() } } +Reference<XNumberFormatter> ODatabaseForm::getFormatter() +{ + if (auto xSupplier = dbtools::getNumberFormats(getConnection(), true, m_xContext)) + { + auto result = NumberFormatter::create(m_xContext); + result->attachNumberFormatsSupplier(xSupplier); + return result; + } + return {}; +} + +static void maybeConvertDefaultStringToDate(Any& def, const auto& getFieldPropOrDefault, + const auto& getFormatter) +{ + OUString sDefault; + if (!(def >>= sDefault)) + return; + + sal_Int32 dataType = getFieldPropOrDefault(PROPERTY_FIELDTYPE, sal_Int32()); + if (dataType != css::sdbc::DataType::DATE && dataType != css::sdbc::DataType::TIMESTAMP) + return; + + Reference<XNumberFormatter> xFormatter = getFormatter(); + if (!xFormatter) + return; + + // Convert to a date + sal_uInt32 nFormatKey = xFormatter->detectNumberFormat( + getFieldPropOrDefault(PROPERTY_FORMATKEY, sal_uInt32()), sDefault); + sal_Int16 nType = comphelper::getNumberFormatType(xFormatter, nFormatKey); + if ((nType & css::util::NumberFormat::DATE) == 0) + return; + + Reference<XNumberFormatsSupplier> xSupplier = xFormatter->getNumberFormatsSupplier(); + css::util::Date aNull; + try + { + if (!(xSupplier->getNumberFormatSettings()->getPropertyValue(u"NullDate"_ustr) >>= aNull)) + return; + } + catch (const Exception&) + { + return; + } + ::Date d(aNull); + + double value = xFormatter->convertStringToNumber(nFormatKey, sDefault); + switch (dataType) + { + case css::sdbc::DataType::DATE: + { + d.AddDays(value); + def <<= d.GetUNODate(); + break; + } + case css::sdbc::DataType::TIMESTAMP: + { + ::DateTime dt(d); + dt.AddTime(value); + def <<= dt.GetUNODateTime(); + break; + } + } +} void ODatabaseForm::reset_impl(bool _bApproveByListeners) { @@ -1956,24 +2023,27 @@ void ODatabaseForm::reset_impl(bool _bApproveByListeners) if ( !xColUpdate.is() ) continue; - Reference< XPropertySetInfo > xPSI; - if ( xColProps.is() ) - xPSI = xColProps->getPropertySetInfo( ); - - static constexpr OUString PROPERTY_CONTROLDEFAULT = u"ControlDefault"_ustr; - if (!xPSI || !xPSI->hasPropertyByName(PROPERTY_CONTROLDEFAULT)) - continue; + auto getPropValOrDefault = [&xColProps, xPSI = xColProps->getPropertySetInfo()]( + const OUString& propname, auto default_value) + { + if (xPSI && xPSI->hasPropertyByName(propname)) + fromAny(xColProps->getPropertyValue(propname), &default_value); + return default_value; + }; - Any aDefault = xColProps->getPropertyValue( PROPERTY_CONTROLDEFAULT ); + Any aDefault = getPropValOrDefault(u"ControlDefault"_ustr, Any()); if (!aDefault.hasValue()) continue; - bool bReadOnly = false; - if ( xPSI->hasPropertyByName( PROPERTY_ISREADONLY ) ) - xColProps->getPropertyValue( PROPERTY_ISREADONLY ) >>= bReadOnly; - if (bReadOnly) + if (getPropValOrDefault(PROPERTY_ISREADONLY, false)) continue; + // If the column is a date, and the default is a string, it may be + // impossible to convert the string to date at a later stage (namely, in + // DBTypeConversion::getValue, where the column formatting is unknown). + maybeConvertDefaultStringToDate(aDefault, getPropValOrDefault, + [this]() { return getFormatter(); }); + try { xColUpdate->updateObject( aDefault ); diff --git a/forms/source/component/DatabaseForm.hxx b/forms/source/component/DatabaseForm.hxx index 73831a9c67ba..a9c4badb6545 100644 --- a/forms/source/component/DatabaseForm.hxx +++ b/forms/source/component/DatabaseForm.hxx @@ -54,6 +54,7 @@ #include <com/sun/star/beans/XPropertyContainer.hpp> #include <com/sun/star/beans/XPropertyAccess.hpp> #include <com/sun/star/sdbc/XWarningsSupplier.hpp> +#include <com/sun/star/util/XNumberFormatter.hpp> #include <tools/link.hxx> @@ -518,6 +519,9 @@ private: void impl_construct(); DECL_LINK( OnTimeout, Timer*, void ); + + css::uno::Reference<css::util::XNumberFormatter> getFormatter(); + protected: using OPropertySetHelper::getPropertyValues; }; commit 5633027b0d1af9c627d250b32284901d9bae20c7 Author: Mike Kaganski <mike.kagan...@collabora.com> AuthorDate: Sun Jul 20 20:02:35 2025 +0500 Commit: Xisco Fauli <xiscofa...@libreoffice.org> CommitDate: Sun Aug 10 11:16:36 2025 +0200 Flatten ODatabaseForm::reset_impl a bit Change-Id: I47ad680ef80ed5ed40b329ff83d2c38506a64d54 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/188085 Tested-by: Jenkins Reviewed-by: Mike Kaganski <mike.kagan...@collabora.com> Signed-off-by: Xisco Fauli <xiscofa...@libreoffice.org> Reviewed-on: https://gerrit.libreoffice.org/c/core/+/188681 diff --git a/forms/source/component/DatabaseForm.cxx b/forms/source/component/DatabaseForm.cxx index 999bc986bf07..e45842e02764 100644 --- a/forms/source/component/DatabaseForm.cxx +++ b/forms/source/component/DatabaseForm.cxx @@ -1961,26 +1961,26 @@ void ODatabaseForm::reset_impl(bool _bApproveByListeners) xPSI = xColProps->getPropertySetInfo( ); static constexpr OUString PROPERTY_CONTROLDEFAULT = u"ControlDefault"_ustr; - if ( xPSI.is() && xPSI->hasPropertyByName( PROPERTY_CONTROLDEFAULT ) ) - { - Any aDefault = xColProps->getPropertyValue( PROPERTY_CONTROLDEFAULT ); + if (!xPSI || !xPSI->hasPropertyByName(PROPERTY_CONTROLDEFAULT)) + continue; - bool bReadOnly = false; - if ( xPSI->hasPropertyByName( PROPERTY_ISREADONLY ) ) - xColProps->getPropertyValue( PROPERTY_ISREADONLY ) >>= bReadOnly; + Any aDefault = xColProps->getPropertyValue( PROPERTY_CONTROLDEFAULT ); + if (!aDefault.hasValue()) + continue; - if ( !bReadOnly ) - { - try - { - if ( aDefault.hasValue() ) - xColUpdate->updateObject( aDefault ); - } - catch(const Exception&) - { - DBG_UNHANDLED_EXCEPTION("forms.component"); - } - } + bool bReadOnly = false; + if ( xPSI->hasPropertyByName( PROPERTY_ISREADONLY ) ) + xColProps->getPropertyValue( PROPERTY_ISREADONLY ) >>= bReadOnly; + if (bReadOnly) + continue; + + try + { + xColUpdate->updateObject( aDefault ); + } + catch(const Exception&) + { + DBG_UNHANDLED_EXCEPTION("forms.component"); } } }