From 5c078787a324b19ae68da9a60d52c02117515e57 Mon Sep 17 00:00:00 2001 From: nkottary Date: Sun, 5 Apr 2020 14:02:55 +0530 Subject: [PATCH 01/20] WIP: Thousands separators with locale grouping --- include/wx/intl.h | 4 ++++ interface/wx/intl.h | 10 ++++++++++ src/common/intl.cpp | 21 ++++++++++++++++++++- src/common/numformatter.cpp | 2 ++ 4 files changed, 36 insertions(+), 1 deletion(-) diff --git a/include/wx/intl.h b/include/wx/intl.h index d66e3043d87a..39296b090cec 100644 --- a/include/wx/intl.h +++ b/include/wx/intl.h @@ -118,6 +118,10 @@ enum wxLocaleInfo // the character used as decimal point (for wxLOCALE_CAT_NUMBER or MONEY) wxLOCALE_DECIMAL_POINT, + // Specifies the amount of digits that form each of the groups to be + // separated by thousands separator (for wxLOCALE_CAT_NUMBER or MONEY) + wxLOCALE_GROUPING, + // the stftime()-formats used for short/long date and time representations // (under some platforms short and long date formats are the same) // diff --git a/interface/wx/intl.h b/interface/wx/intl.h index 8fbe58fbd4e7..3924f553bc30 100644 --- a/interface/wx/intl.h +++ b/interface/wx/intl.h @@ -127,6 +127,16 @@ enum wxLocaleInfo */ wxLOCALE_DECIMAL_POINT, + /** + Specifies the amount of digits that form each of the groups + to be separated by thousands_sep separator for non-monetary + quantities. + + This value can be used with either wxLOCALE_CAT_NUMBER or + wxLOCALE_CAT_MONEY categories. + */ + wxLOCALE_GROUPING, + /** Short date format. diff --git a/src/common/intl.cpp b/src/common/intl.cpp index 0ba14ae52475..24f110fd1940 100644 --- a/src/common/intl.cpp +++ b/src/common/intl.cpp @@ -1639,6 +1639,10 @@ GetInfoFromLCID(LCID lcid, } break; + case wxLOCALE_GROUPING: + if ( ::GetLocaleInfo(lcid, LOCALE_SGROUPING, buf, WXSIZEOF(buf)) ) + str = buf; + break; case wxLOCALE_SHORT_DATE_FMT: case wxLOCALE_LONG_DATE_FMT: case wxLOCALE_TIME_FMT: @@ -1712,6 +1716,9 @@ wxString wxLocale::GetInfo(wxLocaleInfo index, wxLocaleCategory cat) case wxLOCALE_DECIMAL_POINT: return "."; + case wxLOCALE_GROUPING: + return "3;0"; + case wxLOCALE_SHORT_DATE_FMT: return "%m/%d/%y"; @@ -1770,6 +1777,10 @@ wxString wxLocale::GetInfo(wxLocaleInfo index, wxLocaleCategory WXUNUSED(cat)) cfstr = (CFStringRef) CFLocaleGetValue(userLocaleRef, kCFLocaleDecimalSeparator); break; + case wxLOCALE_GROUPING: + cfstr = (CFStringRef) "3;0"; + break; + case wxLOCALE_SHORT_DATE_FMT: case wxLOCALE_LONG_DATE_FMT: case wxLOCALE_DATE_TIME_FMT: @@ -1920,7 +1931,6 @@ wxString wxLocale::GetInfo(wxLocaleInfo index, wxLocaleCategory cat) wxFAIL_MSG( "invalid wxLocaleCategory" ); break; - case wxLOCALE_DECIMAL_POINT: if ( cat == wxLOCALE_CAT_NUMBER ) return lc->decimal_point; @@ -1930,6 +1940,15 @@ wxString wxLocale::GetInfo(wxLocaleInfo index, wxLocaleCategory cat) wxFAIL_MSG( "invalid wxLocaleCategory" ); break; + case wxLOCALE_GROUPING: + if ( cat == wxLOCALE_CAT_NUMBER ) + return lc->grouping; + else if ( cat == wxLOCALE_CAT_MONEY ) + return lc->mon_grouping; + + wxFAIL_MSG( "invalid wxLocaleCategory" ); + break; + case wxLOCALE_SHORT_DATE_FMT: case wxLOCALE_LONG_DATE_FMT: case wxLOCALE_DATE_TIME_FMT: diff --git a/src/common/numformatter.cpp b/src/common/numformatter.cpp index 369ec15b5c3b..b2ffe16e17fe 100644 --- a/src/common/numformatter.cpp +++ b/src/common/numformatter.cpp @@ -240,6 +240,8 @@ void wxNumberFormatter::AddThousandsSeparators(wxString& s) // and GetLocaleInfo(LOCALE_SGROUPING) (under MSW) to get information about // the correct grouping to use. This is something that needs to be done at // wxLocale level first and then used here in the future (TODO). + + wxString g = wxLocale::GetInfo(wxLOCALE_GROUPING, wxLOCALE_CAT_NUMBER); const size_t GROUP_LEN = 3; while ( pos > start + GROUP_LEN ) From 12569586a86439425d3bff6668907f60a5a111ce Mon Sep 17 00:00:00 2001 From: nkottary Date: Mon, 6 Apr 2020 11:09:39 +0530 Subject: [PATCH 02/20] Fixes --- include/wx/language.h | 1 + include/wx/numformatter.h | 2 +- interface/wx/language.h | 1 + interface/wx/numformatter.h | 2 +- misc/languages/langtabl.txt | 1 + src/common/intl.cpp | 2 +- src/common/languageinfo.cpp | 4 ++++ src/common/numformatter.cpp | 47 +++++++++++++++++++++++++++---------- 8 files changed, 44 insertions(+), 16 deletions(-) diff --git a/include/wx/language.h b/include/wx/language.h index 5d788abcc247..6a04d8f66934 100644 --- a/include/wx/language.h +++ b/include/wx/language.h @@ -108,6 +108,7 @@ enum wxLanguage wxLANGUAGE_ENGLISH_SOUTH_AFRICA, wxLANGUAGE_ENGLISH_TRINIDAD, wxLANGUAGE_ENGLISH_ZIMBABWE, + wxLANGUAGE_ENGLISH_INDIA, wxLANGUAGE_ESPERANTO, wxLANGUAGE_ESTONIAN, wxLANGUAGE_FAEROESE, diff --git a/include/wx/numformatter.h b/include/wx/numformatter.h index 13b47b210b1f..6cfd9cf0c264 100644 --- a/include/wx/numformatter.h +++ b/include/wx/numformatter.h @@ -56,7 +56,7 @@ class WXDLLIMPEXP_BASE wxNumberFormatter // Get the thousands separator if grouping of the digits is used by the // current locale. The value returned in sep should be only used if the // function returns true. - static bool GetThousandsSeparatorIfUsed(wxChar *sep); + static bool GetThousandsSeparatorAndGroupingIfUsed(wxChar *sep, wxString *gr); private: // Post-process the string representing an integer. diff --git a/interface/wx/language.h b/interface/wx/language.h index 7ad4df159a05..f0a08c4e9cb0 100644 --- a/interface/wx/language.h +++ b/interface/wx/language.h @@ -93,6 +93,7 @@ enum wxLanguage wxLANGUAGE_ENGLISH_SOUTH_AFRICA, wxLANGUAGE_ENGLISH_TRINIDAD, wxLANGUAGE_ENGLISH_ZIMBABWE, + wxLANGUAGE_ENGLISH_INDIA, wxLANGUAGE_ESPERANTO, wxLANGUAGE_ESTONIAN, wxLANGUAGE_FAEROESE, diff --git a/interface/wx/numformatter.h b/interface/wx/numformatter.h index db678d08f5e3..2052322fdf86 100644 --- a/interface/wx/numformatter.h +++ b/interface/wx/numformatter.h @@ -121,6 +121,6 @@ class wxNumberFormatter if it is used by the current locale. May be @NULL if only the function return value is needed. */ - static bool GetThousandsSeparatorIfUsed(wxChar *sep); + static bool GetThousandsSeparatorAndGroupingIfUsed(wxChar *sep, wxString *gr); }; diff --git a/misc/languages/langtabl.txt b/misc/languages/langtabl.txt index 5264da8ceb2d..b256d86e5136 100644 --- a/misc/languages/langtabl.txt +++ b/misc/languages/langtabl.txt @@ -69,6 +69,7 @@ wxLANGUAGE_ENGLISH_PHILIPPINES en_PH LANG_ENGLISH SUBLANG_ENGLISH_P wxLANGUAGE_ENGLISH_SOUTH_AFRICA en_ZA LANG_ENGLISH SUBLANG_ENGLISH_SOUTH_AFRICA LTR "English (South Africa)" wxLANGUAGE_ENGLISH_TRINIDAD en_TT LANG_ENGLISH SUBLANG_ENGLISH_TRINIDAD LTR "English (Trinidad)" wxLANGUAGE_ENGLISH_ZIMBABWE en_ZW LANG_ENGLISH SUBLANG_ENGLISH_ZIMBABWE LTR "English (Zimbabwe)" +wxLANGUAGE_ENGLISH_INDIA en_IN LANG_ENGLISH SUBLANG_ENGLISH_INDIA LTR "English (India)" wxLANGUAGE_ESPERANTO eo - - LTR "Esperanto" wxLANGUAGE_ESTONIAN et_EE LANG_ESTONIAN SUBLANG_DEFAULT LTR "Estonian" wxLANGUAGE_FAEROESE fo_FO LANG_FAEROESE SUBLANG_DEFAULT LTR "Faeroese" diff --git a/src/common/intl.cpp b/src/common/intl.cpp index 24f110fd1940..f7c2871527e1 100644 --- a/src/common/intl.cpp +++ b/src/common/intl.cpp @@ -1717,7 +1717,7 @@ wxString wxLocale::GetInfo(wxLocaleInfo index, wxLocaleCategory cat) return "."; case wxLOCALE_GROUPING: - return "3;0"; + return "\3\0"; case wxLOCALE_SHORT_DATE_FMT: return "%m/%d/%y"; diff --git a/src/common/languageinfo.cpp b/src/common/languageinfo.cpp index 9929b0f656c3..d514055f4064 100644 --- a/src/common/languageinfo.cpp +++ b/src/common/languageinfo.cpp @@ -388,6 +388,9 @@ #ifndef SUBLANG_ENGLISH_ZIMBABWE #define SUBLANG_ENGLISH_ZIMBABWE SUBLANG_DEFAULT #endif +#ifndef SUBLANG_ENGLISH_INDIA +#define SUBLANG_ENGLISH_INDIA SUBLANG_DEFAULT +#endif #ifndef SUBLANG_FRENCH #define SUBLANG_FRENCH SUBLANG_DEFAULT #endif @@ -628,6 +631,7 @@ void wxLocale::InitLanguagesDB() LNG(wxLANGUAGE_ENGLISH_SOUTH_AFRICA, "en_ZA", LANG_ENGLISH , SUBLANG_ENGLISH_SOUTH_AFRICA , wxLayout_LeftToRight, "English (South Africa)") LNG(wxLANGUAGE_ENGLISH_TRINIDAD, "en_TT", LANG_ENGLISH , SUBLANG_ENGLISH_TRINIDAD , wxLayout_LeftToRight, "English (Trinidad)") LNG(wxLANGUAGE_ENGLISH_ZIMBABWE, "en_ZW", LANG_ENGLISH , SUBLANG_ENGLISH_ZIMBABWE , wxLayout_LeftToRight, "English (Zimbabwe)") + LNG(wxLANGUAGE_ENGLISH_INDIA, "en_IN", LANG_ENGLISH , SUBLANG_ENGLISH_INDIA , wxLayout_LeftToRight, "English (India)") LNG(wxLANGUAGE_ESPERANTO, "eo" , 0 , 0 , wxLayout_LeftToRight, "Esperanto") LNG(wxLANGUAGE_ESTONIAN, "et_EE", LANG_ESTONIAN , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Estonian") LNG(wxLANGUAGE_FAEROESE, "fo_FO", LANG_FAEROESE , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Faeroese") diff --git a/src/common/numformatter.cpp b/src/common/numformatter.cpp index b2ffe16e17fe..d26389aa13bc 100644 --- a/src/common/numformatter.cpp +++ b/src/common/numformatter.cpp @@ -22,6 +22,7 @@ #include "wx/intl.h" #include // for setlocale and LC_ALL +#include // for CHAR_MAX // ---------------------------------------------------------------------------- // local helpers @@ -140,10 +141,11 @@ wxChar wxNumberFormatter::GetDecimalSeparator() #endif // wxUSE_INTL/!wxUSE_INTL } -bool wxNumberFormatter::GetThousandsSeparatorIfUsed(wxChar *sep) +bool wxNumberFormatter::GetThousandsSeparatorAndGroupingIfUsed(wxChar *sep, wxString *gr) { #if wxUSE_INTL static wxChar s_thousandsSeparator = 0; + static wxString s_grouping; static LocaleId s_localeUsedForInit; if ( s_localeUsedForInit.NotInitializedOrHasChanged() ) @@ -153,6 +155,10 @@ bool wxNumberFormatter::GetThousandsSeparatorIfUsed(wxChar *sep) if ( s.length() == 1 ) { s_thousandsSeparator = s[0]; + const wxString + g = wxLocale::GetInfo(wxLOCALE_GROUPING, wxLOCALE_CAT_NUMBER); + if ( g[0] != '\0' || g[0] != CHAR_MAX ) + s_grouping = g; } //else: Unlike above it's perfectly fine for the thousands separator to // be empty if grouping is not used, so just leave it as 0. @@ -162,11 +168,16 @@ bool wxNumberFormatter::GetThousandsSeparatorIfUsed(wxChar *sep) return false; if ( sep ) + { *sep = s_thousandsSeparator; + if ( gr ) + *gr = s_grouping; + } return true; #else // !wxUSE_INTL wxUnusedVar(sep); + wxUnusedVar(gr); return false; #endif // wxUSE_INTL/!wxUSE_INTL } @@ -221,7 +232,8 @@ void wxNumberFormatter::AddThousandsSeparators(wxString& s) return; wxChar thousandsSep; - if ( !GetThousandsSeparatorIfUsed(&thousandsSep) ) + wxString grouping; + if ( !GetThousandsSeparatorAndGroupingIfUsed(&thousandsSep, &grouping) ) return; size_t pos = s.find(GetDecimalSeparator()); @@ -235,19 +247,27 @@ void wxNumberFormatter::AddThousandsSeparators(wxString& s) // before their start. const size_t start = s.find_first_of("0123456789"); - // We currently group digits by 3 independently of the locale. This is not - // the right thing to do and we should use lconv::grouping (under POSIX) - // and GetLocaleInfo(LOCALE_SGROUPING) (under MSW) to get information about - // the correct grouping to use. This is something that needs to be done at - // wxLocale level first and then used here in the future (TODO). + // We get the grouping style from locale. This is represented by a character + // array where each element is the number of digits in a group starting + // from the right of the number. If the last element in the grouping is a 0 + // then the last but one element is the number used for grouping the + // remaining digits. If the last element is CHAR_MAX then no grouping is + // done for the remaining digits. - wxString g = wxLocale::GetInfo(wxLOCALE_GROUPING, wxLOCALE_CAT_NUMBER); - const size_t GROUP_LEN = 3; - - while ( pos > start + GROUP_LEN ) + size_t i = 0; + while((grouping[i] != '\0') && (grouping[i] != CHAR_MAX) && (pos > start + (size_t)grouping[i])) { - pos -= GROUP_LEN; + pos -= (size_t)grouping[i]; s.insert(pos, thousandsSep); + i++; + } + if ( grouping[i] == '\0' && i > 0 ) + { + while ( pos > start + (size_t)grouping[i - 1] ) + { + pos -= (size_t)grouping[i - 1]; + s.insert(pos, thousandsSep); + } } } @@ -283,7 +303,8 @@ void wxNumberFormatter::RemoveTrailingZeroes(wxString& s) void wxNumberFormatter::RemoveThousandsSeparators(wxString& s) { wxChar thousandsSep; - if ( !GetThousandsSeparatorIfUsed(&thousandsSep) ) + wxString grouping; + if ( !GetThousandsSeparatorAndGroupingIfUsed(&thousandsSep, &grouping) ) return; s.Replace(wxString(thousandsSep), wxString()); From 1c574cd60b61a4d1c325278bb757bf41b2a8e981 Mon Sep 17 00:00:00 2001 From: nkottary Date: Mon, 6 Apr 2020 12:21:19 +0530 Subject: [PATCH 03/20] Fix default grouping for mac --- src/common/intl.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/common/intl.cpp b/src/common/intl.cpp index f7c2871527e1..0a880a752b44 100644 --- a/src/common/intl.cpp +++ b/src/common/intl.cpp @@ -1778,7 +1778,7 @@ wxString wxLocale::GetInfo(wxLocaleInfo index, wxLocaleCategory WXUNUSED(cat)) break; case wxLOCALE_GROUPING: - cfstr = (CFStringRef) "3;0"; + cfstr = (CFStringRef) "\3\0"; break; case wxLOCALE_SHORT_DATE_FMT: From a95ac3b29c2168e9750273114936cfd79ba8f7a5 Mon Sep 17 00:00:00 2001 From: nkottary Date: Tue, 7 Apr 2020 16:46:51 +0530 Subject: [PATCH 04/20] restore GetThousandsSeparatorIfUsed method --- include/wx/numformatter.h | 3 +++ interface/wx/numformatter.h | 20 ++++++++++++++++++++ src/common/numformatter.cpp | 34 ++++++++++++++++++++++++++++++++-- 3 files changed, 55 insertions(+), 2 deletions(-) diff --git a/include/wx/numformatter.h b/include/wx/numformatter.h index 6cfd9cf0c264..6c30e77d7174 100644 --- a/include/wx/numformatter.h +++ b/include/wx/numformatter.h @@ -56,6 +56,9 @@ class WXDLLIMPEXP_BASE wxNumberFormatter // Get the thousands separator if grouping of the digits is used by the // current locale. The value returned in sep should be only used if the // function returns true. + static bool GetThousandsSeparatorIfUsed(wxChar *sep); + + // Same as the above method but provides the grouping format as well static bool GetThousandsSeparatorAndGroupingIfUsed(wxChar *sep, wxString *gr); private: diff --git a/interface/wx/numformatter.h b/interface/wx/numformatter.h index 2052322fdf86..23aa6a193219 100644 --- a/interface/wx/numformatter.h +++ b/interface/wx/numformatter.h @@ -121,6 +121,26 @@ class wxNumberFormatter if it is used by the current locale. May be @NULL if only the function return value is needed. */ + static bool GetThousandsSeparatorIfUsed(wxChar *sep); + + /** + Get the thousands separator and grouping format if grouping of the + digits is used by the current locale. + + The value returned in @a sep and @a gr should be only used if the + function returns @true, otherwise no thousands separator should be + used at all. + + @param sep + Points to the variable receiving the thousands separator character + if it is used by the current locale. May be @NULL if only the + function return value is needed. + + @param gr + Points to the variable receiving the grouping format string + if it is used by the current locale. May be @NULL if only the + function return value is needed. + */ static bool GetThousandsSeparatorAndGroupingIfUsed(wxChar *sep, wxString *gr); }; diff --git a/src/common/numformatter.cpp b/src/common/numformatter.cpp index d26389aa13bc..426268676110 100644 --- a/src/common/numformatter.cpp +++ b/src/common/numformatter.cpp @@ -141,6 +141,37 @@ wxChar wxNumberFormatter::GetDecimalSeparator() #endif // wxUSE_INTL/!wxUSE_INTL } +bool wxNumberFormatter::GetThousandsSeparatorIfUsed(wxChar *sep) +{ +#if wxUSE_INTL + static wxChar s_thousandsSeparator = 0; + static LocaleId s_localeUsedForInit; + + if ( s_localeUsedForInit.NotInitializedOrHasChanged() ) + { + const wxString + s = wxLocale::GetInfo(wxLOCALE_THOUSANDS_SEP, wxLOCALE_CAT_NUMBER); + if ( s.length() == 1 ) + { + s_thousandsSeparator = s[0]; + } + //else: Unlike above it's perfectly fine for the thousands separator to + // be empty if grouping is not used, so just leave it as 0. + } + + if ( !s_thousandsSeparator ) + return false; + + if ( sep ) + *sep = s_thousandsSeparator; + + return true; +#else // !wxUSE_INTL + wxUnusedVar(sep); + return false; +#endif // wxUSE_INTL/!wxUSE_INTL +} + bool wxNumberFormatter::GetThousandsSeparatorAndGroupingIfUsed(wxChar *sep, wxString *gr) { #if wxUSE_INTL @@ -303,8 +334,7 @@ void wxNumberFormatter::RemoveTrailingZeroes(wxString& s) void wxNumberFormatter::RemoveThousandsSeparators(wxString& s) { wxChar thousandsSep; - wxString grouping; - if ( !GetThousandsSeparatorAndGroupingIfUsed(&thousandsSep, &grouping) ) + if ( !GetThousandsSeparatorIfUsed(&thousandsSep) ) return; s.Replace(wxString(thousandsSep), wxString()); From c38d186f55aabeea2fb61c536d7cdc021f0707ca Mon Sep 17 00:00:00 2001 From: "Nishanth H. Kottary" Date: Tue, 7 Apr 2020 16:48:11 +0530 Subject: [PATCH 05/20] Update interface/wx/intl.h Co-Authored-By: VZ --- interface/wx/intl.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/interface/wx/intl.h b/interface/wx/intl.h index 3924f553bc30..345be697defc 100644 --- a/interface/wx/intl.h +++ b/interface/wx/intl.h @@ -134,6 +134,8 @@ enum wxLocaleInfo This value can be used with either wxLOCALE_CAT_NUMBER or wxLOCALE_CAT_MONEY categories. + + @since 3.1.4 */ wxLOCALE_GROUPING, @@ -536,4 +538,3 @@ class wxLocale Get the current locale object (note that it may be NULL!) */ wxLocale* wxGetLocale(); - From 15a5d98f1f1cc3ca2950ae735ab09e25ba0def11 Mon Sep 17 00:00:00 2001 From: nkottary Date: Tue, 7 Apr 2020 16:52:28 +0530 Subject: [PATCH 06/20] Restore blank line --- src/common/intl.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/common/intl.cpp b/src/common/intl.cpp index 0a880a752b44..1f9b1f725a69 100644 --- a/src/common/intl.cpp +++ b/src/common/intl.cpp @@ -1920,6 +1920,7 @@ wxString wxLocale::GetInfo(wxLocaleInfo index, wxLocaleCategory cat) if ( !lc ) return wxString(); + switch ( index ) { case wxLOCALE_THOUSANDS_SEP: From 7c910a58681f6d6e97d0737cb7a33457dd7b60e7 Mon Sep 17 00:00:00 2001 From: nkottary Date: Tue, 7 Apr 2020 19:18:41 +0530 Subject: [PATCH 07/20] Fix mac string --- src/common/intl.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/common/intl.cpp b/src/common/intl.cpp index 1f9b1f725a69..2d8b4d0f6f3e 100644 --- a/src/common/intl.cpp +++ b/src/common/intl.cpp @@ -1778,7 +1778,7 @@ wxString wxLocale::GetInfo(wxLocaleInfo index, wxLocaleCategory WXUNUSED(cat)) break; case wxLOCALE_GROUPING: - cfstr = (CFStringRef) "\3\0"; + cfstr = CFStringCreateWithCString(NULL, "\3\0", kCFStringEncodingASCII); break; case wxLOCALE_SHORT_DATE_FMT: From 62d3ef3699e6a06ff3715d582a88c4b310e72fcc Mon Sep 17 00:00:00 2001 From: nkottary Date: Tue, 7 Apr 2020 19:27:03 +0530 Subject: [PATCH 08/20] Blank line fix --- src/common/intl.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/common/intl.cpp b/src/common/intl.cpp index 2d8b4d0f6f3e..a86405bb2f52 100644 --- a/src/common/intl.cpp +++ b/src/common/intl.cpp @@ -1920,7 +1920,6 @@ wxString wxLocale::GetInfo(wxLocaleInfo index, wxLocaleCategory cat) if ( !lc ) return wxString(); - switch ( index ) { case wxLOCALE_THOUSANDS_SEP: @@ -1932,6 +1931,7 @@ wxString wxLocale::GetInfo(wxLocaleInfo index, wxLocaleCategory cat) wxFAIL_MSG( "invalid wxLocaleCategory" ); break; + case wxLOCALE_DECIMAL_POINT: if ( cat == wxLOCALE_CAT_NUMBER ) return lc->decimal_point; From cf4d61228a70bd680008e6f2976a98c883d428f8 Mon Sep 17 00:00:00 2001 From: nkottary Date: Sat, 11 Apr 2020 17:14:23 +0530 Subject: [PATCH 09/20] Add version in doc, format grouping string to windows format --- include/wx/intl.h | 4 ++++ interface/wx/numformatter.h | 2 ++ src/common/intl.cpp | 34 ++++++++++++++++++++++++++++++---- src/common/numformatter.cpp | 28 ++++++++++++++++------------ 4 files changed, 52 insertions(+), 16 deletions(-) diff --git a/include/wx/intl.h b/include/wx/intl.h index 39296b090cec..47b699397055 100644 --- a/include/wx/intl.h +++ b/include/wx/intl.h @@ -360,6 +360,10 @@ class WXDLLIMPEXP_BASE wxLocale const wxString& shortName, bool bLoadDefault); + // Converts a grouping format string returned by localeconv() + // to the kind used on Windows platform + static wxString StandardizeGroupingString(wxString g); + wxString m_strLocale, // this locale name m_strShort; // short name for the locale diff --git a/interface/wx/numformatter.h b/interface/wx/numformatter.h index 23aa6a193219..eed96cf7b463 100644 --- a/interface/wx/numformatter.h +++ b/interface/wx/numformatter.h @@ -140,6 +140,8 @@ class wxNumberFormatter Points to the variable receiving the grouping format string if it is used by the current locale. May be @NULL if only the function return value is needed. + + @since 3.1.4 */ static bool GetThousandsSeparatorAndGroupingIfUsed(wxChar *sep, wxString *gr); diff --git a/src/common/intl.cpp b/src/common/intl.cpp index a86405bb2f52..7b88280c274b 100644 --- a/src/common/intl.cpp +++ b/src/common/intl.cpp @@ -1717,7 +1717,7 @@ wxString wxLocale::GetInfo(wxLocaleInfo index, wxLocaleCategory cat) return "."; case wxLOCALE_GROUPING: - return "\3\0"; + return "3;0"; case wxLOCALE_SHORT_DATE_FMT: return "%m/%d/%y"; @@ -1778,7 +1778,7 @@ wxString wxLocale::GetInfo(wxLocaleInfo index, wxLocaleCategory WXUNUSED(cat)) break; case wxLOCALE_GROUPING: - cfstr = CFStringCreateWithCString(NULL, "\3\0", kCFStringEncodingASCII); + cfstr = CFStringCreateWithCString(NULL, "3;0", kCFStringEncodingASCII); break; case wxLOCALE_SHORT_DATE_FMT: @@ -1911,6 +1911,32 @@ wxString GetDateFormatFromLangInfo(wxLocaleInfo index) } // anonymous namespace +// Convert a grouping format string returned by localeconv() to +// a standardized format. Our standard format is the one used on +// Windows SGROUPING. Here we convert char sized integers to ASCII +// characters. That is, for example '\3' becomes '3'. We also add +// the a ';' delimiter between each number. A '\0' or a CHAR_MAX +// signifies the end of the argument string. If the argument string +// ends with a '\0' then we insert a '0' to the return string. +// The return string will be NULL terminated. + +/* static */ +wxString wxLocale::StandardizeGroupingString(wxString g) +{ + wxString s = ""; + int i; + for (i = 0; g[i] != '\0' && g[i] != CHAR_MAX; i++) + { + s.Append((char)((int)g[i] + (int)'0')); + s.Append(';'); + } + if (g[i] == '\0') + s.Append('0'); + else + s.RemoveLast(); // Remove extra ; + return s; +} + /* static */ wxString wxLocale::GetInfo(wxLocaleInfo index, wxLocaleCategory cat) { @@ -1943,9 +1969,9 @@ wxString wxLocale::GetInfo(wxLocaleInfo index, wxLocaleCategory cat) case wxLOCALE_GROUPING: if ( cat == wxLOCALE_CAT_NUMBER ) - return lc->grouping; + return StandardizeGroupingString(lc->grouping); else if ( cat == wxLOCALE_CAT_MONEY ) - return lc->mon_grouping; + return StandardizeGroupingString(lc->mon_grouping); wxFAIL_MSG( "invalid wxLocaleCategory" ); break; diff --git a/src/common/numformatter.cpp b/src/common/numformatter.cpp index 426268676110..175d36d7d539 100644 --- a/src/common/numformatter.cpp +++ b/src/common/numformatter.cpp @@ -278,25 +278,29 @@ void wxNumberFormatter::AddThousandsSeparators(wxString& s) // before their start. const size_t start = s.find_first_of("0123456789"); - // We get the grouping style from locale. This is represented by a character - // array where each element is the number of digits in a group starting - // from the right of the number. If the last element in the grouping is a 0 - // then the last but one element is the number used for grouping the - // remaining digits. If the last element is CHAR_MAX then no grouping is - // done for the remaining digits. + // We get the grouping style from locale. This is represented by a ';' + // delimited character array where each element is the number of digits + // in a group starting from the right of the number. If the last element + // in the grouping is a 0 then the last but one element is the number + // used for grouping the remaining digits. size_t i = 0; - while((grouping[i] != '\0') && (grouping[i] != CHAR_MAX) && (pos > start + (size_t)grouping[i])) + while((grouping[i] != '\0') && (grouping[i] != '0')) { - pos -= (size_t)grouping[i]; - s.insert(pos, thousandsSep); + if (grouping[i] != ';') + { + if (pos <= start + (size_t)(grouping[i] - '0')) + break; + pos -= (size_t)(grouping[i] - '0'); + s.insert(pos, thousandsSep); + } i++; } - if ( grouping[i] == '\0' && i > 0 ) + if ( grouping[i] == '0' && i > 0 ) { - while ( pos > start + (size_t)grouping[i - 1] ) + while ( pos > start + (size_t)(grouping[i - 2] - '0')) { - pos -= (size_t)grouping[i - 1]; + pos -= (size_t)(grouping[i - 2] - '0'); s.insert(pos, thousandsSep); } } From 5b46fd3b7cd39f676c7214310627fbe493c27886 Mon Sep 17 00:00:00 2001 From: nkottary Date: Sat, 11 Apr 2020 20:05:21 +0530 Subject: [PATCH 10/20] Attempt grouping on Mac OS --- src/common/intl.cpp | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/src/common/intl.cpp b/src/common/intl.cpp index 7b88280c274b..15dfeedce512 100644 --- a/src/common/intl.cpp +++ b/src/common/intl.cpp @@ -1778,7 +1778,31 @@ wxString wxLocale::GetInfo(wxLocaleInfo index, wxLocaleCategory WXUNUSED(cat)) break; case wxLOCALE_GROUPING: - cfstr = CFStringCreateWithCString(NULL, "3;0", kCFStringEncodingASCII); + wxCFRef numFormatterRef( + CFNumberFormatterCreate(NULL, userLocalRef, kCFNumberFormatterDecimalStyle)); + CFNumberRef size = (CFNumberRef) CFNumberFormatterCopyProperty( + numFormatterRef, kCFNumberFormatterGroupingSize); + CFNumberRef secSize = (CFNumberRef) CFNumberFormatterCopyProperty( + numFormatterRef, kCFNumberFormatterSecondaryGroupingSize); + // Convert the size and secondary size to char and create the grouping string + char s, ss; + if (CFNumberGetValue(size, kCFNumberCharType, &s)) + { + if (CFNumberGetValue(secSize, kCFNumberCharType, &ss) && ss != s) + { + s += '0'; + ss += '0'; + cfstr = CFStringCreateWithCString( + NULL, {s, ';', ss, ';', '0', '\0'}, kCFStringEncodingASCII); + } else { + s += '0'; + cfstr = CFStringCreateWithCString( + NULL, {s, ';', '0', '\0'}, kCFStringEncodingASCII); + } + } else { + // No grouping + cfstr = CFStringCreateWithCString(NULL, "", kCFStringEncodingASCII); + } break; case wxLOCALE_SHORT_DATE_FMT: From d83f3cad3be9b6a9ecef43ef155d352dc34c1945 Mon Sep 17 00:00:00 2001 From: nkottary Date: Sun, 12 Apr 2020 09:30:04 +0530 Subject: [PATCH 11/20] Fix build issues --- src/common/intl.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/common/intl.cpp b/src/common/intl.cpp index 15dfeedce512..4e60056a80ec 100644 --- a/src/common/intl.cpp +++ b/src/common/intl.cpp @@ -69,6 +69,7 @@ #include "wx/osx/core/cfstring.h" #include #include + #include #include #endif @@ -1779,7 +1780,7 @@ wxString wxLocale::GetInfo(wxLocaleInfo index, wxLocaleCategory WXUNUSED(cat)) case wxLOCALE_GROUPING: wxCFRef numFormatterRef( - CFNumberFormatterCreate(NULL, userLocalRef, kCFNumberFormatterDecimalStyle)); + CFNumberFormatterCreate(NULL, userLocaleRef, kCFNumberFormatterDecimalStyle)); CFNumberRef size = (CFNumberRef) CFNumberFormatterCopyProperty( numFormatterRef, kCFNumberFormatterGroupingSize); CFNumberRef secSize = (CFNumberRef) CFNumberFormatterCopyProperty( @@ -1792,12 +1793,14 @@ wxString wxLocale::GetInfo(wxLocaleInfo index, wxLocaleCategory WXUNUSED(cat)) { s += '0'; ss += '0'; + char gstr[] = {s, ';', ss, ';', '0', '\0'}; cfstr = CFStringCreateWithCString( - NULL, {s, ';', ss, ';', '0', '\0'}, kCFStringEncodingASCII); + NULL, &gstr[0], kCFStringEncodingASCII); } else { s += '0'; + char gstr[] = {s, ';', '0', '\0'}; cfstr = CFStringCreateWithCString( - NULL, {s, ';', '0', '\0'}, kCFStringEncodingASCII); + NULL, &gstr[0], kCFStringEncodingASCII); } } else { // No grouping From 90744e33a2733d9d892a0e13c514b7a8063f8879 Mon Sep 17 00:00:00 2001 From: nkottary Date: Sun, 12 Apr 2020 12:08:42 +0530 Subject: [PATCH 12/20] Bracket around case --- src/common/intl.cpp | 46 +++++++++++++++++++++++---------------------- 1 file changed, 24 insertions(+), 22 deletions(-) diff --git a/src/common/intl.cpp b/src/common/intl.cpp index 4e60056a80ec..9be53b22c239 100644 --- a/src/common/intl.cpp +++ b/src/common/intl.cpp @@ -1779,32 +1779,34 @@ wxString wxLocale::GetInfo(wxLocaleInfo index, wxLocaleCategory WXUNUSED(cat)) break; case wxLOCALE_GROUPING: - wxCFRef numFormatterRef( - CFNumberFormatterCreate(NULL, userLocaleRef, kCFNumberFormatterDecimalStyle)); - CFNumberRef size = (CFNumberRef) CFNumberFormatterCopyProperty( - numFormatterRef, kCFNumberFormatterGroupingSize); - CFNumberRef secSize = (CFNumberRef) CFNumberFormatterCopyProperty( - numFormatterRef, kCFNumberFormatterSecondaryGroupingSize); - // Convert the size and secondary size to char and create the grouping string - char s, ss; - if (CFNumberGetValue(size, kCFNumberCharType, &s)) { - if (CFNumberGetValue(secSize, kCFNumberCharType, &ss) && ss != s) + wxCFRef numFormatterRef( + CFNumberFormatterCreate(NULL, userLocaleRef, kCFNumberFormatterDecimalStyle)); + CFNumberRef size = (CFNumberRef) CFNumberFormatterCopyProperty( + numFormatterRef, kCFNumberFormatterGroupingSize); + CFNumberRef secSize = (CFNumberRef) CFNumberFormatterCopyProperty( + numFormatterRef, kCFNumberFormatterSecondaryGroupingSize); + // Convert the size and secondary size to char and create the grouping string + char s, ss; + if (CFNumberGetValue(size, kCFNumberCharType, &s)) { - s += '0'; - ss += '0'; - char gstr[] = {s, ';', ss, ';', '0', '\0'}; - cfstr = CFStringCreateWithCString( - NULL, &gstr[0], kCFStringEncodingASCII); + if (CFNumberGetValue(secSize, kCFNumberCharType, &ss) && ss != s) + { + s += '0'; + ss += '0'; + char gstr[] = {s, ';', ss, ';', '0', '\0'}; + cfstr = CFStringCreateWithCString( + NULL, &gstr[0], kCFStringEncodingASCII); + } else { + s += '0'; + char gstr[] = {s, ';', '0', '\0'}; + cfstr = CFStringCreateWithCString( + NULL, &gstr[0], kCFStringEncodingASCII); + } } else { - s += '0'; - char gstr[] = {s, ';', '0', '\0'}; - cfstr = CFStringCreateWithCString( - NULL, &gstr[0], kCFStringEncodingASCII); + // No grouping + cfstr = CFStringCreateWithCString(NULL, "", kCFStringEncodingASCII); } - } else { - // No grouping - cfstr = CFStringCreateWithCString(NULL, "", kCFStringEncodingASCII); } break; From 8414b63068a6f78cab0339fddb0e7d99d975432d Mon Sep 17 00:00:00 2001 From: nkottary Date: Sun, 19 Apr 2020 12:50:21 +0530 Subject: [PATCH 13/20] Refactor, add test for Indian locale --- include/wx/numformatter.h | 5 + interface/wx/numformatter.h | 27 +++ src/common/numformatter.cpp | 14 +- tests/strings/numformatter.cpp | 330 ++++++++++++++++++++++++++++++++- 4 files changed, 372 insertions(+), 4 deletions(-) diff --git a/include/wx/numformatter.h b/include/wx/numformatter.h index 6c30e77d7174..14dd24dcfd32 100644 --- a/include/wx/numformatter.h +++ b/include/wx/numformatter.h @@ -61,6 +61,11 @@ class WXDLLIMPEXP_BASE wxNumberFormatter // Same as the above method but provides the grouping format as well static bool GetThousandsSeparatorAndGroupingIfUsed(wxChar *sep, wxString *gr); + // Format a number s with the specified thousands separator, decimal separator + // and grouping format for the thousands separator + static void FormatNumber(wxString &s, wxChar thousandsSep, + wxChar decSep, wxString grouping); + private: // Post-process the string representing an integer. static wxString PostProcessIntString(wxString s, int style); diff --git a/interface/wx/numformatter.h b/interface/wx/numformatter.h index eed96cf7b463..92146812224f 100644 --- a/interface/wx/numformatter.h +++ b/interface/wx/numformatter.h @@ -145,4 +145,31 @@ class wxNumberFormatter */ static bool GetThousandsSeparatorAndGroupingIfUsed(wxChar *sep, wxString *gr); + /** + Format a number with the thousands separator based on grouping format. + The grouping format is a string of digits separated by ';'. Each digit + indicates the number of digits of the string s to be grouped starting + from the right. If the last digit is '0' then the last but one digit + is used for grouping the remaining digits. + + Examples: + Number: "123456789", Grouping format: "3;0", result: "123,456,789" + Number: "123456789", Grouping format: "3;2;0", result: "12,34,56,789" + + @param s + The number to be formatted as a string + + @param thousandsSep + The thousands separator + + @param decSep + The decimal separator + + @param grouping + The string representing the thousands separator grouping format. + + @since 3.1.4 + */ + static void FormatNumber(wxString &s, wxChar thousandsSep, wxChar decSep, + wxString grouping); }; diff --git a/src/common/numformatter.cpp b/src/common/numformatter.cpp index 175d36d7d539..e4d8f0647afe 100644 --- a/src/common/numformatter.cpp +++ b/src/common/numformatter.cpp @@ -22,7 +22,6 @@ #include "wx/intl.h" #include // for setlocale and LC_ALL -#include // for CHAR_MAX // ---------------------------------------------------------------------------- // local helpers @@ -188,7 +187,7 @@ bool wxNumberFormatter::GetThousandsSeparatorAndGroupingIfUsed(wxChar *sep, wxSt s_thousandsSeparator = s[0]; const wxString g = wxLocale::GetInfo(wxLOCALE_GROUPING, wxLOCALE_CAT_NUMBER); - if ( g[0] != '\0' || g[0] != CHAR_MAX ) + if ( g[0] != '\0') s_grouping = g; } //else: Unlike above it's perfectly fine for the thousands separator to @@ -263,11 +262,20 @@ void wxNumberFormatter::AddThousandsSeparators(wxString& s) return; wxChar thousandsSep; + wxChar decSep; wxString grouping; if ( !GetThousandsSeparatorAndGroupingIfUsed(&thousandsSep, &grouping) ) return; - size_t pos = s.find(GetDecimalSeparator()); + decSep = GetDecimalSeparator(); + wxNumberFormatter::FormatNumber( + s, thousandsSep, decSep, grouping); +} + +void wxNumberFormatter::FormatNumber( + wxString& s, wxChar thousandsSep, wxChar decSep, wxString grouping) +{ + size_t pos = s.find(decSep); if ( pos == wxString::npos ) { // Start grouping at the end of an integer number. diff --git a/tests/strings/numformatter.cpp b/tests/strings/numformatter.cpp index 9a583f8a7c51..88d690251ce7 100644 --- a/tests/strings/numformatter.cpp +++ b/tests/strings/numformatter.cpp @@ -20,7 +20,7 @@ #include "wx/intl.h" // ---------------------------------------------------------------------------- -// test class +// test class (UK locale) // ---------------------------------------------------------------------------- class NumFormatterTestCase : public CppUnit::TestCase @@ -347,3 +347,331 @@ void NumFormatterTestCase::DoubleFromString() CPPUNIT_ASSERT( wxNumberFormatter::FromString("123456789.012", &d) ); CPPUNIT_ASSERT_EQUAL( 123456789.012, d ); } + +// ---------------------------------------------------------------------------- +// test class (India locale) +// ---------------------------------------------------------------------------- +class NumFormatterAlternateTestCase : public CppUnit::TestCase +{ +public: + NumFormatterAlternateTestCase() { m_locale = NULL; } + + virtual void setUp() wxOVERRIDE + { + // We need to use a locale with known decimal point and which uses the + // thousands separator for the tests to make sense. + m_locale = new wxLocale(wxLANGUAGE_ENGLISH_INDIA, + wxLOCALE_DONT_LOAD_DEFAULT); + if ( !m_locale->IsOk() ) + tearDown(); + } + + virtual void tearDown() wxOVERRIDE + { + delete m_locale; + m_locale = NULL; + } + +private: + CPPUNIT_TEST_SUITE( NumFormatterAlternateTestCase ); + CPPUNIT_TEST( LongToString ); +#ifdef wxHAS_LONG_LONG_T_DIFFERENT_FROM_LONG + CPPUNIT_TEST( LongLongToString ); +#endif // wxHAS_LONG_LONG_T_DIFFERENT_FROM_LONG + CPPUNIT_TEST( DoubleToString ); + CPPUNIT_TEST( NoTrailingZeroes ); + CPPUNIT_TEST( LongFromString ); +#ifdef wxHAS_LONG_LONG_T_DIFFERENT_FROM_LONG + CPPUNIT_TEST( LongLongFromString ); +#endif // wxHAS_LONG_LONG_T_DIFFERENT_FROM_LONG + CPPUNIT_TEST( DoubleFromString ); + CPPUNIT_TEST_SUITE_END(); + + void LongToString(); +#ifdef wxHAS_LONG_LONG_T_DIFFERENT_FROM_LONG + void LongLongToString(); +#endif // wxHAS_LONG_LONG_T_DIFFERENT_FROM_LONG + void DoubleToString(); + void NoTrailingZeroes(); + void LongFromString(); +#ifdef wxHAS_LONG_LONG_T_DIFFERENT_FROM_LONG + void LongLongFromString(); +#endif // wxHAS_LONG_LONG_T_DIFFERENT_FROM_LONG + void DoubleFromString(); + + wxLocale *m_locale; + + wxDECLARE_NO_COPY_CLASS(NumFormatterAlternateTestCase); +}; + +// register in the unnamed registry so that these tests are run by default +CPPUNIT_TEST_SUITE_REGISTRATION( NumFormatterAlternateTestCase ); + +// also include in its own registry so that these tests can be run alone +CPPUNIT_TEST_SUITE_NAMED_REGISTRATION( NumFormatterAlternateTestCase, "NumFormatterAlternateTestCase" ); + +// ---------------------------------------------------------------------------- +// tests themselves +// ---------------------------------------------------------------------------- + +void NumFormatterAlternateTestCase::LongToString() +{ + if ( !m_locale ) + return; + + CPPUNIT_ASSERT_EQUAL( "1", wxNumberFormatter::ToString( 1L)); + CPPUNIT_ASSERT_EQUAL( "-1", wxNumberFormatter::ToString( -1L)); + CPPUNIT_ASSERT_EQUAL( "12", wxNumberFormatter::ToString( 12L)); + CPPUNIT_ASSERT_EQUAL( "-12", wxNumberFormatter::ToString( -12L)); + CPPUNIT_ASSERT_EQUAL( "123", wxNumberFormatter::ToString( 123L)); + CPPUNIT_ASSERT_EQUAL( "-123", wxNumberFormatter::ToString( -123L)); + CPPUNIT_ASSERT_EQUAL( "1,234", wxNumberFormatter::ToString( 1234L)); + CPPUNIT_ASSERT_EQUAL( "-1,234", wxNumberFormatter::ToString( -1234L)); + CPPUNIT_ASSERT_EQUAL( "12,345", wxNumberFormatter::ToString( 12345L)); + CPPUNIT_ASSERT_EQUAL( "-12,345", wxNumberFormatter::ToString( -12345L)); + CPPUNIT_ASSERT_EQUAL( "1,23,456", wxNumberFormatter::ToString( 123456L)); + CPPUNIT_ASSERT_EQUAL( "-1,23,456", wxNumberFormatter::ToString( -123456L)); + CPPUNIT_ASSERT_EQUAL( "12,34,567", wxNumberFormatter::ToString( 1234567L)); + CPPUNIT_ASSERT_EQUAL( "-12,34,567", wxNumberFormatter::ToString( -1234567L)); + CPPUNIT_ASSERT_EQUAL( "1,23,45,678", wxNumberFormatter::ToString( 12345678L)); + CPPUNIT_ASSERT_EQUAL("-1,23,45,678", wxNumberFormatter::ToString( -12345678L)); + CPPUNIT_ASSERT_EQUAL("12,34,56,789", wxNumberFormatter::ToString( 123456789L)); +} + +#ifdef wxHAS_LONG_LONG_T_DIFFERENT_FROM_LONG + +void NumFormatterAlternateTestCase::LongLongToString() +{ + if ( !m_locale ) + return; + + CPPUNIT_ASSERT_EQUAL( "1", wxNumberFormatter::ToString(wxLL( 1))); + CPPUNIT_ASSERT_EQUAL( "12", wxNumberFormatter::ToString(wxLL( 12))); + CPPUNIT_ASSERT_EQUAL( "123", wxNumberFormatter::ToString(wxLL( 123))); + CPPUNIT_ASSERT_EQUAL( "1,234", wxNumberFormatter::ToString(wxLL( 1234))); + CPPUNIT_ASSERT_EQUAL( "12,345", wxNumberFormatter::ToString(wxLL( 12345))); + CPPUNIT_ASSERT_EQUAL( "1,23,456", wxNumberFormatter::ToString(wxLL( 123456))); + CPPUNIT_ASSERT_EQUAL( "12,34,567", wxNumberFormatter::ToString(wxLL( 1234567))); + CPPUNIT_ASSERT_EQUAL( "1,23,45,678", wxNumberFormatter::ToString(wxLL( 12345678))); + CPPUNIT_ASSERT_EQUAL("12,34,56,789", wxNumberFormatter::ToString(wxLL( 123456789))); +} + +#endif // wxHAS_LONG_LONG_T_DIFFERENT_FROM_LONG + +void NumFormatterAlternateTestCase::DoubleToString() +{ + if ( !m_locale ) + return; + + CPPUNIT_ASSERT_EQUAL("1.0", wxNumberFormatter::ToString(1., 1)); + CPPUNIT_ASSERT_EQUAL("0.123456", wxNumberFormatter::ToString(0.123456, 6)); + CPPUNIT_ASSERT_EQUAL("1.234567", wxNumberFormatter::ToString(1.234567, 6)); + CPPUNIT_ASSERT_EQUAL("12.34567", wxNumberFormatter::ToString(12.34567, 5)); + CPPUNIT_ASSERT_EQUAL("123.4567", wxNumberFormatter::ToString(123.4567, 4)); + CPPUNIT_ASSERT_EQUAL("1,234.56", wxNumberFormatter::ToString(1234.56, 2)); + CPPUNIT_ASSERT_EQUAL("12,345.6", wxNumberFormatter::ToString(12345.6, 1)); + CPPUNIT_ASSERT_EQUAL("12,345.6", wxNumberFormatter::ToString(12345.6, 1)); + CPPUNIT_ASSERT_EQUAL("12,34,56,789.0", + wxNumberFormatter::ToString(123456789., 1)); + CPPUNIT_ASSERT_EQUAL("12,34,56,789.012", + wxNumberFormatter::ToString(123456789.012, 3)); + CPPUNIT_ASSERT_EQUAL("12,345", + wxNumberFormatter::ToString(12345.012, -1)); + CPPUNIT_ASSERT_EQUAL("-123.1230", + wxNumberFormatter::ToString(-123.123, 4, wxNumberFormatter::Style_None)); + CPPUNIT_ASSERT_EQUAL("0.0", + wxNumberFormatter::ToString(0.02, 1, wxNumberFormatter::Style_None)); + CPPUNIT_ASSERT_EQUAL("-0.0", + wxNumberFormatter::ToString(-0.02, 1, wxNumberFormatter::Style_None)); +} + +void NumFormatterAlternateTestCase::NoTrailingZeroes() +{ + WX_ASSERT_FAILS_WITH_ASSERT + ( + wxNumberFormatter::ToString(123L, wxNumberFormatter::Style_NoTrailingZeroes) + ); + + if ( !m_locale ) + return; + + CPPUNIT_ASSERT_EQUAL + ( + "123.000", + wxNumberFormatter::ToString(123., 3) + ); + + CPPUNIT_ASSERT_EQUAL + ( + "123", + wxNumberFormatter::ToString(123., 3, wxNumberFormatter::Style_NoTrailingZeroes) + ); + + CPPUNIT_ASSERT_EQUAL + ( + "123", + wxNumberFormatter::ToString(123., 9, wxNumberFormatter::Style_NoTrailingZeroes) + ); + + CPPUNIT_ASSERT_EQUAL + ( + "123.456", + wxNumberFormatter::ToString(123.456, 3, wxNumberFormatter::Style_NoTrailingZeroes) + ); + + CPPUNIT_ASSERT_EQUAL + ( + "123.456000000", + wxNumberFormatter::ToString(123.456, 9) + ); + + CPPUNIT_ASSERT_EQUAL + ( + "123.456", + wxNumberFormatter::ToString(123.456, 9, wxNumberFormatter::Style_NoTrailingZeroes) + ); + + CPPUNIT_ASSERT_EQUAL + ( + "123.12", + wxNumberFormatter::ToString(123.123, 2, wxNumberFormatter::Style_NoTrailingZeroes) + ); + + CPPUNIT_ASSERT_EQUAL + ( + "123", + wxNumberFormatter::ToString(123.123, 0, wxNumberFormatter::Style_NoTrailingZeroes) + ); + + CPPUNIT_ASSERT_EQUAL + ( + "0", + wxNumberFormatter::ToString(-0.000123, 3, wxNumberFormatter::Style_NoTrailingZeroes) + ); + + CPPUNIT_ASSERT_EQUAL + ( + "123", + wxNumberFormatter::ToString(123., -1, wxNumberFormatter::Style_NoTrailingZeroes) + ); + + CPPUNIT_ASSERT_EQUAL + ( + "1e-120", + wxNumberFormatter::ToString(1e-120, -1, wxNumberFormatter::Style_NoTrailingZeroes) + ); +} + +void NumFormatterAlternateTestCase::LongFromString() +{ + if ( !m_locale ) + return; + + WX_ASSERT_FAILS_WITH_ASSERT + ( + wxNumberFormatter::FromString("123", static_cast(0)) + ); + + long l; + CPPUNIT_ASSERT( !wxNumberFormatter::FromString("", &l) ); + CPPUNIT_ASSERT( !wxNumberFormatter::FromString("foo", &l) ); + CPPUNIT_ASSERT( !wxNumberFormatter::FromString("1.234", &l) ); + + CPPUNIT_ASSERT( wxNumberFormatter::FromString("123", &l) ); + CPPUNIT_ASSERT_EQUAL( 123, l ); + + CPPUNIT_ASSERT( wxNumberFormatter::FromString("1234", &l) ); + CPPUNIT_ASSERT_EQUAL( 1234, l ); + + CPPUNIT_ASSERT( wxNumberFormatter::FromString("1,234", &l) ); + CPPUNIT_ASSERT_EQUAL( 1234, l ); + + CPPUNIT_ASSERT( wxNumberFormatter::FromString("12,345", &l) ); + CPPUNIT_ASSERT_EQUAL( 12345, l ); + + CPPUNIT_ASSERT( wxNumberFormatter::FromString("1,23,456", &l) ); + CPPUNIT_ASSERT_EQUAL( 123456, l ); + + CPPUNIT_ASSERT( wxNumberFormatter::FromString("1,234,567", &l) ); + CPPUNIT_ASSERT_EQUAL( 1234567, l ); +} + +#ifdef wxHAS_LONG_LONG_T_DIFFERENT_FROM_LONG + +void NumFormatterAlternateTestCase::LongLongFromString() +{ + if ( !m_locale ) + return; + + WX_ASSERT_FAILS_WITH_ASSERT + ( + wxNumberFormatter::FromString("123", static_cast(0)) + ); + + wxLongLong_t l; + CPPUNIT_ASSERT( !wxNumberFormatter::FromString("", &l) ); + CPPUNIT_ASSERT( !wxNumberFormatter::FromString("foo", &l) ); + CPPUNIT_ASSERT( !wxNumberFormatter::FromString("1.234", &l) ); + + CPPUNIT_ASSERT( wxNumberFormatter::FromString("123", &l) ); + CPPUNIT_ASSERT_EQUAL( 123, l ); + + CPPUNIT_ASSERT( wxNumberFormatter::FromString("1234", &l) ); + CPPUNIT_ASSERT_EQUAL( 1234, l ); + + CPPUNIT_ASSERT( wxNumberFormatter::FromString("1,234", &l) ); + CPPUNIT_ASSERT_EQUAL( 1234, l ); + + CPPUNIT_ASSERT( wxNumberFormatter::FromString("12,345", &l) ); + CPPUNIT_ASSERT_EQUAL( 12345, l ); + + CPPUNIT_ASSERT( wxNumberFormatter::FromString("1,23,456", &l) ); + CPPUNIT_ASSERT_EQUAL( 123456, l ); + + CPPUNIT_ASSERT( wxNumberFormatter::FromString("12,34,567", &l) ); + CPPUNIT_ASSERT_EQUAL( 1234567, l ); +} + +#endif // wxHAS_LONG_LONG_T_DIFFERENT_FROM_LONG + +void NumFormatterAlternateTestCase::DoubleFromString() +{ + if ( !m_locale ) + return; + + WX_ASSERT_FAILS_WITH_ASSERT + ( + wxNumberFormatter::FromString("123", static_cast(0)) + ); + + double d; + CPPUNIT_ASSERT( !wxNumberFormatter::FromString("", &d) ); + CPPUNIT_ASSERT( !wxNumberFormatter::FromString("bar", &d) ); + + CPPUNIT_ASSERT( wxNumberFormatter::FromString("123", &d) ); + CPPUNIT_ASSERT_EQUAL( 123., d ); + + CPPUNIT_ASSERT( wxNumberFormatter::FromString("123.456789012", &d) ); + CPPUNIT_ASSERT_EQUAL( 123.456789012, d ); + + CPPUNIT_ASSERT( wxNumberFormatter::FromString("1,234.56789012", &d) ); + CPPUNIT_ASSERT_EQUAL( 1234.56789012, d ); + + CPPUNIT_ASSERT( wxNumberFormatter::FromString("12,345.6789012", &d) ); + CPPUNIT_ASSERT_EQUAL( 12345.6789012, d ); + + CPPUNIT_ASSERT( wxNumberFormatter::FromString("1,23,456.789012", &d) ); + CPPUNIT_ASSERT_EQUAL( 123456.789012, d ); + + CPPUNIT_ASSERT( wxNumberFormatter::FromString("1,234,567.89012", &d) ); + CPPUNIT_ASSERT_EQUAL( 1234567.89012, d ); + + CPPUNIT_ASSERT( wxNumberFormatter::FromString("1,23,45,678.9012", &d) ); + CPPUNIT_ASSERT_EQUAL( 12345678.9012, d ); + + CPPUNIT_ASSERT( wxNumberFormatter::FromString("12,34,56,789.012", &d) ); + CPPUNIT_ASSERT_EQUAL( 123456789.012, d ); + + CPPUNIT_ASSERT( wxNumberFormatter::FromString("123456789.012", &d) ); + CPPUNIT_ASSERT_EQUAL( 123456789.012, d ); +} From 61fcec2538c4807e11b59c7264c7b4760648c0ae Mon Sep 17 00:00:00 2001 From: nkottary Date: Sun, 26 Apr 2020 13:26:14 +0530 Subject: [PATCH 14/20] Add debug printing of grouping and locale --- tests/strings/numformatter.cpp | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/tests/strings/numformatter.cpp b/tests/strings/numformatter.cpp index 88d690251ce7..bf831b497b09 100644 --- a/tests/strings/numformatter.cpp +++ b/tests/strings/numformatter.cpp @@ -19,6 +19,9 @@ #include "wx/numformatter.h" #include "wx/intl.h" +// ===== Temporary: For debug info +#include + // ---------------------------------------------------------------------------- // test class (UK locale) // ---------------------------------------------------------------------------- @@ -364,6 +367,16 @@ class NumFormatterAlternateTestCase : public CppUnit::TestCase wxLOCALE_DONT_LOAD_DEFAULT); if ( !m_locale->IsOk() ) tearDown(); + // ===== Debugging info + else { + wxChar thousandsSep; + wxString grouping; + if ( wxNumberFormatter::GetThousandsSeparatorAndGroupingIfUsed(&thousandsSep, &grouping) ) { + std::cout << "*** Grouping : " << grouping << " Locale C Name: " << m_locale->GetCanonicalName() << std::endl; + } else + std::cout << "*** Unable to get grouping" << std::endl; + } + // ===== } virtual void tearDown() wxOVERRIDE From 1f6b5b8bd9e4510ead6b344c5f680eac204aca55 Mon Sep 17 00:00:00 2001 From: nkottary Date: Sun, 26 Apr 2020 15:28:28 +0530 Subject: [PATCH 15/20] More debug info --- tests/strings/numformatter.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/strings/numformatter.cpp b/tests/strings/numformatter.cpp index bf831b497b09..55c243ca8d80 100644 --- a/tests/strings/numformatter.cpp +++ b/tests/strings/numformatter.cpp @@ -372,7 +372,7 @@ class NumFormatterAlternateTestCase : public CppUnit::TestCase wxChar thousandsSep; wxString grouping; if ( wxNumberFormatter::GetThousandsSeparatorAndGroupingIfUsed(&thousandsSep, &grouping) ) { - std::cout << "*** Grouping : " << grouping << " Locale C Name: " << m_locale->GetCanonicalName() << std::endl; + std::cout << "*** Grouping: " << grouping << " Locale: " << m_locale->GetLocale() << " Name: " << m_locale->GetName() << " SysName: " << m_locale->GetSysName() << std::endl; } else std::cout << "*** Unable to get grouping" << std::endl; } From 9bb252000c86a4bd2fff754a7565d1a32b7f00e2 Mon Sep 17 00:00:00 2001 From: nkottary Date: Mon, 27 Apr 2020 10:16:03 +0530 Subject: [PATCH 16/20] Remove debug prints, dont test indian locale if grouping is incorrect --- tests/strings/numformatter.cpp | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/tests/strings/numformatter.cpp b/tests/strings/numformatter.cpp index 55c243ca8d80..56d304e6889f 100644 --- a/tests/strings/numformatter.cpp +++ b/tests/strings/numformatter.cpp @@ -19,9 +19,6 @@ #include "wx/numformatter.h" #include "wx/intl.h" -// ===== Temporary: For debug info -#include - // ---------------------------------------------------------------------------- // test class (UK locale) // ---------------------------------------------------------------------------- @@ -367,16 +364,20 @@ class NumFormatterAlternateTestCase : public CppUnit::TestCase wxLOCALE_DONT_LOAD_DEFAULT); if ( !m_locale->IsOk() ) tearDown(); - // ===== Debugging info - else { + else + { wxChar thousandsSep; wxString grouping; - if ( wxNumberFormatter::GetThousandsSeparatorAndGroupingIfUsed(&thousandsSep, &grouping) ) { - std::cout << "*** Grouping: " << grouping << " Locale: " << m_locale->GetLocale() << " Name: " << m_locale->GetName() << " SysName: " << m_locale->GetSysName() << std::endl; - } else - std::cout << "*** Unable to get grouping" << std::endl; + if ( wxNumberFormatter::GetThousandsSeparatorAndGroupingIfUsed(&thousandsSep, &grouping) ) + { + // On some Windows systems the grouping is "3;2" which is incorrect + // Skip this test in that case + if ( !grouping.IsSameAs(wxString("3;2;0")) ) + tearDown(); + } + else + tearDown(); } - // ===== } virtual void tearDown() wxOVERRIDE From 67b945e509a7e7ecd2790a1aa9c6065be38bca2d Mon Sep 17 00:00:00 2001 From: nkottary Date: Mon, 27 Apr 2020 12:19:52 +0530 Subject: [PATCH 17/20] Add tests for FormatNumber --- tests/strings/numformatter.cpp | 199 +++++++++++++++++++++++++++++++++ 1 file changed, 199 insertions(+) diff --git a/tests/strings/numformatter.cpp b/tests/strings/numformatter.cpp index 56d304e6889f..42a59b916067 100644 --- a/tests/strings/numformatter.cpp +++ b/tests/strings/numformatter.cpp @@ -689,3 +689,202 @@ void NumFormatterAlternateTestCase::DoubleFromString() CPPUNIT_ASSERT( wxNumberFormatter::FromString("123456789.012", &d) ); CPPUNIT_ASSERT_EQUAL( 123456789.012, d ); } + +//-------------------------------------------------------------------------- +// Test case for wxNumberFormatter::FormatNumber +//-------------------------------------------------------------------------- + +class FormatNumberTestCase : public CppUnit::TestCase +{ +public: + FormatNumberTestCase() {} +private: + static const wxChar thousandsSep = ',', decSep = '.'; + static const wxString grouping_UK; + + static wxString FormatNumberAndReturn(wxString s); + + CPPUNIT_TEST_SUITE( FormatNumberTestCase ); + CPPUNIT_TEST( PositiveIntegers ); + CPPUNIT_TEST( NegativeIntegers ); + CPPUNIT_TEST( PositiveReals ); + CPPUNIT_TEST( NegativeReals ); + CPPUNIT_TEST_SUITE_END(); + + void PositiveIntegers(); + void NegativeIntegers(); + void PositiveReals(); + void NegativeReals(); +}; + +const wxString FormatNumberTestCase::grouping_UK = "3;0"; +wxString FormatNumberTestCase::FormatNumberAndReturn(wxString s) +{ + wxString ret = s.Clone(); + wxNumberFormatter::FormatNumber(ret, thousandsSep, decSep, grouping_UK); + return ret; +} + +// register in the unnamed registry so that these tests are run by default +CPPUNIT_TEST_SUITE_REGISTRATION( FormatNumberTestCase ); + +// also include in its own registry so that these tests can be run alone +CPPUNIT_TEST_SUITE_NAMED_REGISTRATION( FormatNumberTestCase, "FormatNumberTestCase" ); + +void FormatNumberTestCase::PositiveIntegers() +{ + CPPUNIT_ASSERT(FormatNumberAndReturn( "0").IsSameAs( "0")); + CPPUNIT_ASSERT(FormatNumberAndReturn( "1").IsSameAs( "1")); + CPPUNIT_ASSERT(FormatNumberAndReturn( "12").IsSameAs( "12")); + CPPUNIT_ASSERT(FormatNumberAndReturn( "123").IsSameAs( "123")); + CPPUNIT_ASSERT(FormatNumberAndReturn( "1234").IsSameAs( "1,234")); + CPPUNIT_ASSERT(FormatNumberAndReturn( "12345").IsSameAs( "12,345")); + CPPUNIT_ASSERT(FormatNumberAndReturn( "123456").IsSameAs( "123,456")); + CPPUNIT_ASSERT(FormatNumberAndReturn( "1234567").IsSameAs( "1,234,567")); + CPPUNIT_ASSERT(FormatNumberAndReturn( "12345678").IsSameAs( "12,345,678")); + CPPUNIT_ASSERT(FormatNumberAndReturn( "123456789").IsSameAs( "123,456,789")); + CPPUNIT_ASSERT(FormatNumberAndReturn("1234567890").IsSameAs("1,234,567,890")); +} + +void FormatNumberTestCase::NegativeIntegers() +{ + CPPUNIT_ASSERT(FormatNumberAndReturn( "-1").IsSameAs( "-1")); + CPPUNIT_ASSERT(FormatNumberAndReturn( "-12").IsSameAs( "-12")); + CPPUNIT_ASSERT(FormatNumberAndReturn( "-123").IsSameAs( "-123")); + CPPUNIT_ASSERT(FormatNumberAndReturn( "-1234").IsSameAs( "-1,234")); + CPPUNIT_ASSERT(FormatNumberAndReturn( "-12345").IsSameAs( "-12,345")); + CPPUNIT_ASSERT(FormatNumberAndReturn( "-123456").IsSameAs( "-123,456")); + CPPUNIT_ASSERT(FormatNumberAndReturn( "-1234567").IsSameAs( "-1,234,567")); + CPPUNIT_ASSERT(FormatNumberAndReturn( "-12345678").IsSameAs( "-12,345,678")); + CPPUNIT_ASSERT(FormatNumberAndReturn( "-123456789").IsSameAs( "-123,456,789")); + CPPUNIT_ASSERT(FormatNumberAndReturn("-1234567890").IsSameAs("-1,234,567,890")); +} + +void FormatNumberTestCase::PositiveReals() +{ + CPPUNIT_ASSERT(FormatNumberAndReturn( "0.1234").IsSameAs( "0.1234")); + CPPUNIT_ASSERT(FormatNumberAndReturn( "1.1234").IsSameAs( "1.1234")); + CPPUNIT_ASSERT(FormatNumberAndReturn( "12.1234").IsSameAs( "12.1234")); + CPPUNIT_ASSERT(FormatNumberAndReturn( "123.1234").IsSameAs( "123.1234")); + CPPUNIT_ASSERT(FormatNumberAndReturn( "1234.1234").IsSameAs( "1,234.1234")); + CPPUNIT_ASSERT(FormatNumberAndReturn( "12345.1234").IsSameAs( "12,345.1234")); + CPPUNIT_ASSERT(FormatNumberAndReturn( "123456.1234").IsSameAs( "123,456.1234")); + CPPUNIT_ASSERT(FormatNumberAndReturn( "1234567.1234").IsSameAs( "1,234,567.1234")); + CPPUNIT_ASSERT(FormatNumberAndReturn( "12345678.1234").IsSameAs( "12,345,678.1234")); + CPPUNIT_ASSERT(FormatNumberAndReturn( "123456789.1234").IsSameAs( "123,456,789.1234")); + CPPUNIT_ASSERT(FormatNumberAndReturn("1234567890.1234").IsSameAs("1,234,567,890.1234")); +} + +void FormatNumberTestCase::NegativeReals() +{ + CPPUNIT_ASSERT(FormatNumberAndReturn( "-1.1234").IsSameAs( "-1.1234")); + CPPUNIT_ASSERT(FormatNumberAndReturn( "-12.1234").IsSameAs( "-12.1234")); + CPPUNIT_ASSERT(FormatNumberAndReturn( "-123.1234").IsSameAs( "-123.1234")); + CPPUNIT_ASSERT(FormatNumberAndReturn( "-1234.1234").IsSameAs( "-1,234.1234")); + CPPUNIT_ASSERT(FormatNumberAndReturn( "-12345.1234").IsSameAs( "-12,345.1234")); + CPPUNIT_ASSERT(FormatNumberAndReturn( "-123456.1234").IsSameAs( "-123,456.1234")); + CPPUNIT_ASSERT(FormatNumberAndReturn( "-1234567.1234").IsSameAs( "-1,234,567.1234")); + CPPUNIT_ASSERT(FormatNumberAndReturn( "-12345678.1234").IsSameAs( "-12,345,678.1234")); + CPPUNIT_ASSERT(FormatNumberAndReturn( "-123456789.1234").IsSameAs( "-123,456,789.1234")); + CPPUNIT_ASSERT(FormatNumberAndReturn("-1234567890.1234").IsSameAs("-1,234,567,890.1234")); +} + +//-------------------------------------------------------------------------- +// Alternate test case for wxNumberFormatter::FormatNumber with grouping in +// Indian format i.e, "3;2;0" +//-------------------------------------------------------------------------- + +class FormatNumberAlternateTestCase : public CppUnit::TestCase +{ +public: + FormatNumberAlternateTestCase() {} +private: + static const wxChar thousandsSep = ',', decSep = '.'; + static const wxString grouping_India; + + static wxString FormatNumberAndReturn(wxString s); + + CPPUNIT_TEST_SUITE( FormatNumberAlternateTestCase ); + CPPUNIT_TEST( PositiveIntegers ); + CPPUNIT_TEST( NegativeIntegers ); + CPPUNIT_TEST( PositiveReals ); + CPPUNIT_TEST( NegativeReals ); + CPPUNIT_TEST_SUITE_END(); + + void PositiveIntegers(); + void NegativeIntegers(); + void PositiveReals(); + void NegativeReals(); +}; + +const wxString FormatNumberAlternateTestCase::grouping_India = "3;2;0"; +wxString FormatNumberAlternateTestCase::FormatNumberAndReturn(wxString s) +{ + wxString ret = s.Clone(); + wxNumberFormatter::FormatNumber(ret, thousandsSep, decSep, grouping_India); + return ret; +} + +// register in the unnamed registry so that these tests are run by default +CPPUNIT_TEST_SUITE_REGISTRATION( FormatNumberAlternateTestCase ); + +// also include in its own registry so that these tests can be run alone +CPPUNIT_TEST_SUITE_NAMED_REGISTRATION( FormatNumberAlternateTestCase, "FormatNumberAlternateTestCase" ); + +void FormatNumberAlternateTestCase::PositiveIntegers() +{ + CPPUNIT_ASSERT(FormatNumberAndReturn( "0").IsSameAs( "0")); + CPPUNIT_ASSERT(FormatNumberAndReturn( "1").IsSameAs( "1")); + CPPUNIT_ASSERT(FormatNumberAndReturn( "12").IsSameAs( "12")); + CPPUNIT_ASSERT(FormatNumberAndReturn( "123").IsSameAs( "123")); + CPPUNIT_ASSERT(FormatNumberAndReturn( "1234").IsSameAs( "1,234")); + CPPUNIT_ASSERT(FormatNumberAndReturn( "12345").IsSameAs( "12,345")); + CPPUNIT_ASSERT(FormatNumberAndReturn( "123456").IsSameAs( "1,23,456")); + CPPUNIT_ASSERT(FormatNumberAndReturn( "1234567").IsSameAs( "12,34,567")); + CPPUNIT_ASSERT(FormatNumberAndReturn( "12345678").IsSameAs( "1,23,45,678")); + CPPUNIT_ASSERT(FormatNumberAndReturn( "123456789").IsSameAs( "12,34,56,789")); + CPPUNIT_ASSERT(FormatNumberAndReturn("1234567890").IsSameAs("1,23,45,67,890")); +} + +void FormatNumberAlternateTestCase::NegativeIntegers() +{ + CPPUNIT_ASSERT(FormatNumberAndReturn( "-1").IsSameAs( "-1")); + CPPUNIT_ASSERT(FormatNumberAndReturn( "-12").IsSameAs( "-12")); + CPPUNIT_ASSERT(FormatNumberAndReturn( "-123").IsSameAs( "-123")); + CPPUNIT_ASSERT(FormatNumberAndReturn( "-1234").IsSameAs( "-1,234")); + CPPUNIT_ASSERT(FormatNumberAndReturn( "-12345").IsSameAs( "-12,345")); + CPPUNIT_ASSERT(FormatNumberAndReturn( "-123456").IsSameAs( "-1,23,456")); + CPPUNIT_ASSERT(FormatNumberAndReturn( "-1234567").IsSameAs( "-12,34,567")); + CPPUNIT_ASSERT(FormatNumberAndReturn( "-12345678").IsSameAs( "-1,23,45,678")); + CPPUNIT_ASSERT(FormatNumberAndReturn( "-123456789").IsSameAs( "-12,34,56,789")); + CPPUNIT_ASSERT(FormatNumberAndReturn("-1234567890").IsSameAs("-1,23,45,67,890")); +} + +void FormatNumberAlternateTestCase::PositiveReals() +{ + CPPUNIT_ASSERT(FormatNumberAndReturn( "0.1234").IsSameAs( "0.1234")); + CPPUNIT_ASSERT(FormatNumberAndReturn( "1.1234").IsSameAs( "1.1234")); + CPPUNIT_ASSERT(FormatNumberAndReturn( "12.1234").IsSameAs( "12.1234")); + CPPUNIT_ASSERT(FormatNumberAndReturn( "123.1234").IsSameAs( "123.1234")); + CPPUNIT_ASSERT(FormatNumberAndReturn( "1234.1234").IsSameAs( "1,234.1234")); + CPPUNIT_ASSERT(FormatNumberAndReturn( "12345.1234").IsSameAs( "12,345.1234")); + CPPUNIT_ASSERT(FormatNumberAndReturn( "123456.1234").IsSameAs( "1,23,456.1234")); + CPPUNIT_ASSERT(FormatNumberAndReturn( "1234567.1234").IsSameAs( "12,34,567.1234")); + CPPUNIT_ASSERT(FormatNumberAndReturn( "12345678.1234").IsSameAs( "1,23,45,678.1234")); + CPPUNIT_ASSERT(FormatNumberAndReturn( "123456789.1234").IsSameAs( "12,34,56,789.1234")); + CPPUNIT_ASSERT(FormatNumberAndReturn("1234567890.1234").IsSameAs("1,23,45,67,890.1234")); +} + +void FormatNumberAlternateTestCase::NegativeReals() +{ + CPPUNIT_ASSERT(FormatNumberAndReturn( "-1.1234").IsSameAs( "-1.1234")); + CPPUNIT_ASSERT(FormatNumberAndReturn( "-12.1234").IsSameAs( "-12.1234")); + CPPUNIT_ASSERT(FormatNumberAndReturn( "-123.1234").IsSameAs( "-123.1234")); + CPPUNIT_ASSERT(FormatNumberAndReturn( "-1234.1234").IsSameAs( "-1,234.1234")); + CPPUNIT_ASSERT(FormatNumberAndReturn( "-12345.1234").IsSameAs( "-12,345.1234")); + CPPUNIT_ASSERT(FormatNumberAndReturn( "-123456.1234").IsSameAs( "-1,23,456.1234")); + CPPUNIT_ASSERT(FormatNumberAndReturn( "-1234567.1234").IsSameAs( "-12,34,567.1234")); + CPPUNIT_ASSERT(FormatNumberAndReturn( "-12345678.1234").IsSameAs( "-1,23,45,678.1234")); + CPPUNIT_ASSERT(FormatNumberAndReturn( "-123456789.1234").IsSameAs( "-12,34,56,789.1234")); + CPPUNIT_ASSERT(FormatNumberAndReturn("-1234567890.1234").IsSameAs("-1,23,45,67,890.1234")); +} From 99549bcb899d8be74f7f69c588cfe6e57ea1081b Mon Sep 17 00:00:00 2001 From: VZ Date: Fri, 6 Nov 2020 00:31:58 +0100 Subject: [PATCH 18/20] Apply suggestions from code review --- include/wx/intl.h | 2 +- interface/wx/intl.h | 2 +- interface/wx/numformatter.h | 4 ++-- src/common/intl.cpp | 22 +++++++++++++--------- 4 files changed, 17 insertions(+), 13 deletions(-) diff --git a/include/wx/intl.h b/include/wx/intl.h index 47b699397055..799fe194e338 100644 --- a/include/wx/intl.h +++ b/include/wx/intl.h @@ -362,7 +362,7 @@ class WXDLLIMPEXP_BASE wxLocale // Converts a grouping format string returned by localeconv() // to the kind used on Windows platform - static wxString StandardizeGroupingString(wxString g); + static wxString StandardizeGroupingString(const wxString& g); wxString m_strLocale, // this locale name diff --git a/interface/wx/intl.h b/interface/wx/intl.h index 345be697defc..36c0deb20f7a 100644 --- a/interface/wx/intl.h +++ b/interface/wx/intl.h @@ -135,7 +135,7 @@ enum wxLocaleInfo This value can be used with either wxLOCALE_CAT_NUMBER or wxLOCALE_CAT_MONEY categories. - @since 3.1.4 + @since 3.1.5 */ wxLOCALE_GROUPING, diff --git a/interface/wx/numformatter.h b/interface/wx/numformatter.h index 92146812224f..6fa8c165f032 100644 --- a/interface/wx/numformatter.h +++ b/interface/wx/numformatter.h @@ -141,7 +141,7 @@ class wxNumberFormatter if it is used by the current locale. May be @NULL if only the function return value is needed. - @since 3.1.4 + @since 3.1.5 */ static bool GetThousandsSeparatorAndGroupingIfUsed(wxChar *sep, wxString *gr); @@ -168,7 +168,7 @@ class wxNumberFormatter @param grouping The string representing the thousands separator grouping format. - @since 3.1.4 + @since 3.1.5 */ static void FormatNumber(wxString &s, wxChar thousandsSep, wxChar decSep, wxString grouping); diff --git a/src/common/intl.cpp b/src/common/intl.cpp index 9be53b22c239..5b7d4886b5d2 100644 --- a/src/common/intl.cpp +++ b/src/common/intl.cpp @@ -1794,16 +1794,20 @@ wxString wxLocale::GetInfo(wxLocaleInfo index, wxLocaleCategory WXUNUSED(cat)) { s += '0'; ss += '0'; - char gstr[] = {s, ';', ss, ';', '0', '\0'}; + const char gstr[] = {s, ';', ss, ';', '0', '\0'}; cfstr = CFStringCreateWithCString( NULL, &gstr[0], kCFStringEncodingASCII); - } else { + } + else + { s += '0'; - char gstr[] = {s, ';', '0', '\0'}; + const char gstr[] = {s, ';', '0', '\0'}; cfstr = CFStringCreateWithCString( NULL, &gstr[0], kCFStringEncodingASCII); } - } else { + } + else + { // No grouping cfstr = CFStringCreateWithCString(NULL, "", kCFStringEncodingASCII); } @@ -1941,18 +1945,18 @@ wxString GetDateFormatFromLangInfo(wxLocaleInfo index) } // anonymous namespace // Convert a grouping format string returned by localeconv() to -// a standardized format. Our standard format is the one used on +// a standardized format. Our standard format is the one used for // Windows SGROUPING. Here we convert char sized integers to ASCII // characters. That is, for example '\3' becomes '3'. We also add -// the a ';' delimiter between each number. A '\0' or a CHAR_MAX +// a ';' delimiter between each number. A '\0' or a CHAR_MAX // signifies the end of the argument string. If the argument string -// ends with a '\0' then we insert a '0' to the return string. +// ends with a '\0' then we insert a '0' into the return string. // The return string will be NULL terminated. /* static */ -wxString wxLocale::StandardizeGroupingString(wxString g) +wxString wxLocale::StandardizeGroupingString(const wxString& g) { - wxString s = ""; + wxString s; int i; for (i = 0; g[i] != '\0' && g[i] != CHAR_MAX; i++) { From a2ef888b561a32a71bab941a4a1ca7edb7e3d8b2 Mon Sep 17 00:00:00 2001 From: nkottary Date: Fri, 6 Nov 2020 13:02:24 +0530 Subject: [PATCH 19/20] Maintain alphabetical order in langtbl.txt --- misc/languages/langtabl.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/misc/languages/langtabl.txt b/misc/languages/langtabl.txt index b256d86e5136..932bfafb2491 100644 --- a/misc/languages/langtabl.txt +++ b/misc/languages/langtabl.txt @@ -63,13 +63,13 @@ wxLANGUAGE_ENGLISH_CANADA en_CA LANG_ENGLISH SUBLANG_ENGLISH_C wxLANGUAGE_ENGLISH_CARIBBEAN en_CB LANG_ENGLISH SUBLANG_ENGLISH_CARIBBEAN LTR "English (Caribbean)" wxLANGUAGE_ENGLISH_DENMARK en_DK - - LTR "English (Denmark)" wxLANGUAGE_ENGLISH_EIRE en_IE LANG_ENGLISH SUBLANG_ENGLISH_EIRE LTR "English (Eire)" +wxLANGUAGE_ENGLISH_INDIA en_IN LANG_ENGLISH SUBLANG_ENGLISH_INDIA LTR "English (India)" wxLANGUAGE_ENGLISH_JAMAICA en_JM LANG_ENGLISH SUBLANG_ENGLISH_JAMAICA LTR "English (Jamaica)" wxLANGUAGE_ENGLISH_NEW_ZEALAND en_NZ LANG_ENGLISH SUBLANG_ENGLISH_NZ LTR "English (New Zealand)" wxLANGUAGE_ENGLISH_PHILIPPINES en_PH LANG_ENGLISH SUBLANG_ENGLISH_PHILIPPINES LTR "English (Philippines)" wxLANGUAGE_ENGLISH_SOUTH_AFRICA en_ZA LANG_ENGLISH SUBLANG_ENGLISH_SOUTH_AFRICA LTR "English (South Africa)" wxLANGUAGE_ENGLISH_TRINIDAD en_TT LANG_ENGLISH SUBLANG_ENGLISH_TRINIDAD LTR "English (Trinidad)" wxLANGUAGE_ENGLISH_ZIMBABWE en_ZW LANG_ENGLISH SUBLANG_ENGLISH_ZIMBABWE LTR "English (Zimbabwe)" -wxLANGUAGE_ENGLISH_INDIA en_IN LANG_ENGLISH SUBLANG_ENGLISH_INDIA LTR "English (India)" wxLANGUAGE_ESPERANTO eo - - LTR "Esperanto" wxLANGUAGE_ESTONIAN et_EE LANG_ESTONIAN SUBLANG_DEFAULT LTR "Estonian" wxLANGUAGE_FAEROESE fo_FO LANG_FAEROESE SUBLANG_DEFAULT LTR "Faeroese" From 9ed8ad9a908830e59f889297abd500f79112c06a Mon Sep 17 00:00:00 2001 From: nkottary Date: Fri, 6 Nov 2020 13:15:04 +0530 Subject: [PATCH 20/20] Remove null check --- src/common/numformatter.cpp | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/common/numformatter.cpp b/src/common/numformatter.cpp index e4d8f0647afe..b56b7836504c 100644 --- a/src/common/numformatter.cpp +++ b/src/common/numformatter.cpp @@ -185,10 +185,7 @@ bool wxNumberFormatter::GetThousandsSeparatorAndGroupingIfUsed(wxChar *sep, wxSt if ( s.length() == 1 ) { s_thousandsSeparator = s[0]; - const wxString - g = wxLocale::GetInfo(wxLOCALE_GROUPING, wxLOCALE_CAT_NUMBER); - if ( g[0] != '\0') - s_grouping = g; + s_grouping = wxLocale::GetInfo(wxLOCALE_GROUPING, wxLOCALE_CAT_NUMBER); } //else: Unlike above it's perfectly fine for the thousands separator to // be empty if grouping is not used, so just leave it as 0.