include/vcl/toolkit/field.hxx | 2 vcl/source/control/field2.cxx | 147 ++++++++++++++++++++++++++++++++---------- 2 files changed, 115 insertions(+), 34 deletions(-)
New commits: commit ccc48da9f9de2c93c01b9571f98221ff2eb07275 Author: Eike Rathke <er...@redhat.com> AuthorDate: Mon Jul 5 18:37:37 2021 +0200 Commit: Eike Rathke <er...@redhat.com> CommitDate: Mon Jul 5 23:40:53 2021 +0200 DateFormatter: make TextToDate() long date calendar aware, tdf#125035 Using number formatter to display long date now can generate any arbitrary date string in any calendar known to the locale. Cope with non-default non-Gregorian calendars when parsing such string back to a date and convert to Gregorian for the calendar widget. This currently relies on month names being different between calendars, which isn't fail-proof but at least works for the ar_DZ Hijri->Gregorian case. A better approach would be to remember the calendar used in the number formatter output, but that's not available (yet?). Change-Id: I829655275de4d1983b7e453624efca967b16a3bd Reviewed-on: https://gerrit.libreoffice.org/c/core/+/118449 Reviewed-by: Eike Rathke <er...@redhat.com> Tested-by: Jenkins (cherry picked from commit 28859cd06cc699708bb43cb5e4ac7077d3a10f5b) Reviewed-on: https://gerrit.libreoffice.org/c/core/+/118428 diff --git a/vcl/source/control/field2.cxx b/vcl/source/control/field2.cxx index 6ed04e3a16ee..033905250b12 100644 --- a/vcl/source/control/field2.cxx +++ b/vcl/source/control/field2.cxx @@ -36,6 +36,7 @@ #include <svdata.hxx> #include <com/sun/star/i18n/XCharacterClassification.hpp> +#include <com/sun/star/i18n/CalendarFieldIndex.hdl> #include <unotools/localedatawrapper.hxx> #include <unotools/calendarwrapper.hxx> @@ -1201,20 +1202,83 @@ static bool ImplCutMonthName( OUString& rStr, std::u16string_view _rLookupMonthN return index >= 0; } -static sal_uInt16 ImplCutMonthFromString( OUString& rStr, const CalendarWrapper& rCalendarWrapper ) +static sal_uInt16 ImplGetMonthFromCalendarItem( OUString& rStr, const uno::Sequence< i18n::CalendarItem2 >& rMonths ) { - // search for a month' name - for ( sal_uInt16 i=1; i <= 12; i++ ) + const sal_uInt16 nMonths = rMonths.getLength(); + for (sal_uInt16 i=0; i < nMonths; ++i) { - OUString aMonthName = rCalendarWrapper.getMonths()[i-1].FullName; // long month name? - if ( ImplCutMonthName( rStr, aMonthName ) ) - return i; + if ( ImplCutMonthName( rStr, rMonths[i].FullName ) ) + return i+1; // short month name? - OUString aAbbrevMonthName = rCalendarWrapper.getMonths()[i-1].AbbrevName; - if ( ImplCutMonthName( rStr, aAbbrevMonthName ) ) - return i; + if ( ImplCutMonthName( rStr, rMonths[i].AbbrevName ) ) + return i+1; + } + return 0; +} + +static sal_uInt16 ImplCutMonthFromString( OUString& rStr, OUString& rCalendarName, + const LocaleDataWrapper& rLocaleData, const CalendarWrapper& rCalendarWrapper ) +{ + const OUString aDefaultCalendarName( rCalendarWrapper.getUniqueID()); + rCalendarName = aDefaultCalendarName; + + // Search for a month name of the loaded default calendar. + const uno::Sequence< i18n::CalendarItem2 > aMonths = rCalendarWrapper.getMonths(); + sal_uInt16 nMonth = ImplGetMonthFromCalendarItem( rStr, aMonths); + if (nMonth > 0) + return nMonth; + + // And also possessive genitive and partitive month names. + const uno::Sequence< i18n::CalendarItem2 > aGenitiveMonths = rCalendarWrapper.getGenitiveMonths(); + if (aGenitiveMonths != aMonths) + { + nMonth = ImplGetMonthFromCalendarItem( rStr, aGenitiveMonths); + if (nMonth > 0) + return nMonth; + } + const uno::Sequence< i18n::CalendarItem2 > aPartitiveMonths = rCalendarWrapper.getPartitiveMonths(); + if (aPartitiveMonths != aMonths) + { + nMonth = ImplGetMonthFromCalendarItem( rStr, aPartitiveMonths); + if (nMonth > 0) + return nMonth; + } + + // Check if there are more calendars and try them if so, as the long date + // format is obtained from the number formatter this is possible (e.g. + // ar_DZ "[~hijri] ...") + const uno::Sequence< i18n::Calendar2 > aCalendars = rLocaleData.getAllCalendars(); + if (aCalendars.getLength() > 1) + { + for (const auto& rCalendar : aCalendars) + { + if (rCalendar.Name != aDefaultCalendarName) + { + rCalendarName = rCalendar.Name; + + nMonth = ImplGetMonthFromCalendarItem( rStr, rCalendar.Months); + if (nMonth > 0) + return nMonth; + + if (rCalendar.Months != rCalendar.GenitiveMonths) + { + nMonth = ImplGetMonthFromCalendarItem( rStr, rCalendar.GenitiveMonths); + if (nMonth > 0) + return nMonth; + } + + if (rCalendar.Months != rCalendar.PartitiveMonths) + { + nMonth = ImplGetMonthFromCalendarItem( rStr, rCalendar.PartitiveMonths); + if (nMonth > 0) + return nMonth; + } + + rCalendarName = aDefaultCalendarName; + } + } } return ImplCutNumberFromString( rStr ); @@ -1251,26 +1315,50 @@ bool DateFormatter::TextToDate(const OUString& rStr, Date& rDate, ExtDateFieldFo if ( eDateOrder == ExtDateFieldFormat::SystemLong ) { + OUString aCalendarName; DateOrder eFormat = rLocaleDataWrapper.getLongDateOrder(); switch( eFormat ) { case DateOrder::MDY: - nMonth = ImplCutMonthFromString( aStr, rCalendarWrapper ); + nMonth = ImplCutMonthFromString( aStr, aCalendarName, rLocaleDataWrapper, rCalendarWrapper ); nDay = ImplCutNumberFromString( aStr ); nYear = ImplCutNumberFromString( aStr ); break; case DateOrder::DMY: nDay = ImplCutNumberFromString( aStr ); - nMonth = ImplCutMonthFromString( aStr, rCalendarWrapper ); + nMonth = ImplCutMonthFromString( aStr, aCalendarName, rLocaleDataWrapper, rCalendarWrapper ); nYear = ImplCutNumberFromString( aStr ); break; case DateOrder::YMD: default: nYear = ImplCutNumberFromString( aStr ); - nMonth = ImplCutMonthFromString( aStr, rCalendarWrapper ); + nMonth = ImplCutMonthFromString( aStr, aCalendarName, rLocaleDataWrapper, rCalendarWrapper ); nDay = ImplCutNumberFromString( aStr ); break; } + if (aCalendarName != "gregorian") + { + // Calendar widget is Gregorian, convert date. + // Need full date. + bError = !nDay || !nMonth || !nYear; + if (!bError) + { + CalendarWrapper aCW( rLocaleDataWrapper.getComponentContext()); + aCW.loadCalendar( aCalendarName, rLocaleDataWrapper.getLoadedLanguageTag().getLocale()); + aCW.setDateTime(0.5); // get rid of current time, set some day noon + aCW.setValue( i18n::CalendarFieldIndex::DAY_OF_MONTH, nDay); + aCW.setValue( i18n::CalendarFieldIndex::MONTH, nMonth - 1); + aCW.setValue( i18n::CalendarFieldIndex::YEAR, nYear); + bError = !aCW.isValid(); + if (!bError) + { + Date aDate = aCW.getEpochStart() + aCW.getDateTime(); + nYear = aDate.GetYear(); + nMonth = aDate.GetMonth(); + nDay = aDate.GetDay(); + } + } + } } else { commit e8b1f2197776a08ac0b3d7e9a754c3e92327345a Author: Eike Rathke <er...@redhat.com> AuthorDate: Mon Jul 5 14:24:27 2021 +0200 Commit: Eike Rathke <er...@redhat.com> CommitDate: Mon Jul 5 23:40:33 2021 +0200 Pass Formatter::StaticFormatter also from weld:DateFormatter, tdf#125035 Change-Id: I8e6b0e581b9522fb04225fc945e579406a4be208 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/118438 Reviewed-by: Eike Rathke <er...@redhat.com> Tested-by: Jenkins (cherry picked from commit 0335a319c5662f0b849a2231e48338dfeb6aa845) Reviewed-on: https://gerrit.libreoffice.org/c/core/+/118427 diff --git a/include/vcl/toolkit/field.hxx b/include/vcl/toolkit/field.hxx index d6ae05f51fc5..1eb55fabfd29 100644 --- a/include/vcl/toolkit/field.hxx +++ b/include/vcl/toolkit/field.hxx @@ -417,7 +417,7 @@ protected: SAL_DLLPRIVATE bool ImplAllowMalformedInput() const; public: - static OUString FormatDate(const Date& rNewDate, ExtDateFieldFormat eFormat, const LocaleDataWrapper& rLocaleData, CalendarWrapper& rCalendarWrapper, const Formatter::StaticFormatter* pStaticFormatter = nullptr); + static OUString FormatDate(const Date& rNewDate, ExtDateFieldFormat eFormat, const LocaleDataWrapper& rLocaleData, const Formatter::StaticFormatter& rStaticFormatter); static bool TextToDate(const OUString& rStr, Date& rTime, ExtDateFieldFormat eFormat, const LocaleDataWrapper& rLocaleDataWrapper, const CalendarWrapper& rCalendarWrapper); static int GetDateArea(ExtDateFieldFormat eFormat, const OUString& rText, int nCursor, const LocaleDataWrapper& rLocaleDataWrapper); diff --git a/vcl/source/control/field2.cxx b/vcl/source/control/field2.cxx index 603415672f38..6ed04e3a16ee 100644 --- a/vcl/source/control/field2.cxx +++ b/vcl/source/control/field2.cxx @@ -1388,8 +1388,8 @@ namespace } OUString DateFormatter::FormatDate(const Date& rDate, ExtDateFieldFormat eExtFormat, - const LocaleDataWrapper& rLocaleData, CalendarWrapper& rCalendarWrapper, - const Formatter::StaticFormatter* pStaticFormatter) + const LocaleDataWrapper& rLocaleData, + const Formatter::StaticFormatter& rStaticFormatter) { bool bShowCentury = false; switch (eExtFormat) @@ -1439,22 +1439,16 @@ OUString DateFormatter::FormatDate(const Date& rDate, ExtDateFieldFormat eExtFor { case ExtDateFieldFormat::SystemLong: { - /* TODO: adapt all callers to pass a StaticFormatter. */ - if (!pStaticFormatter) - return rLocaleData.getLongDate( rDate, rCalendarWrapper, !bShowCentury ); - else - { - SvNumberFormatter* pFormatter = *pStaticFormatter; - const LanguageTag aFormatterLang( pFormatter->GetLanguageTag()); - const sal_uInt32 nIndex = pFormatter->GetFormatIndex( NF_DATE_SYSTEM_LONG, - rLocaleData.getLanguageTag().getLanguageType(false)); - OUString aStr; - const Color* pCol; - pFormatter->GetOutputString( rDate - pFormatter->GetNullDate(), nIndex, aStr, &pCol); - // Reset to what other uses may expect. - pFormatter->ChangeIntl( aFormatterLang.getLanguageType(false)); - return aStr; - } + SvNumberFormatter* pFormatter = rStaticFormatter; + const LanguageTag aFormatterLang( pFormatter->GetLanguageTag()); + const sal_uInt32 nIndex = pFormatter->GetFormatIndex( NF_DATE_SYSTEM_LONG, + rLocaleData.getLanguageTag().getLanguageType(false)); + OUString aStr; + const Color* pCol; + pFormatter->GetOutputString( rDate - pFormatter->GetNullDate(), nIndex, aStr, &pCol); + // Reset to what other uses may expect. + pFormatter->ChangeIntl( aFormatterLang.getLanguageType(false)); + return aStr; } case ExtDateFieldFormat::ShortDDMMYY: case ExtDateFieldFormat::ShortDDMMYYYY: @@ -1499,8 +1493,7 @@ OUString DateFormatter::FormatDate(const Date& rDate, ExtDateFieldFormat eExtFor OUString DateFormatter::ImplGetDateAsText( const Date& rDate ) const { - return DateFormatter::FormatDate(rDate, GetExtDateFormat(), ImplGetLocaleDataWrapper(), - GetCalendarWrapper(), &maStaticFormatter); + return DateFormatter::FormatDate(rDate, GetExtDateFormat(), ImplGetLocaleDataWrapper(), maStaticFormatter); } static void ImplDateIncrementDay( Date& rDate, bool bUp ) @@ -2219,7 +2212,7 @@ namespace weld OUString DateFormatter::FormatNumber(int nValue) const { const LocaleDataWrapper& rLocaleData = Application::GetSettings().GetLocaleDataWrapper(); - return ::DateFormatter::FormatDate(Date(nValue), m_eFormat, rLocaleData, GetCalendarWrapper()); + return ::DateFormatter::FormatDate(Date(nValue), m_eFormat, rLocaleData, m_aStaticFormatter); } IMPL_LINK_NOARG(DateFormatter, FormatOutputHdl, LinkParamNone*, bool) _______________________________________________ Libreoffice-commits mailing list libreoffice-comm...@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/libreoffice-commits