зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1426907
- Add OSPreferences::OverrideDateTimePattern method; r=zbraniecki
This new method allows for the user to override the long and short date and time patterns by prefs. If no overrides are set or it fails while processing the prefs, it will fallback to the existing methods for determining the patterns. Since the user may have only overriden one of date or time, it is necessary to be able to look up the other separately and combine the results. This adds a prefix callback that watches the new prefs and flushes the cache if they change. Otherwise, the user would have to restart the browser to see the results of changing a pref, and would make testing more difficult. Unregistering this callback required changes to the destructor, which was previously defined separately on each operating system. A new RemoveObservers method has been added to handle OS specific cleanup. Differential Revision: https://phabricator.services.mozilla.com/D94433
This commit is contained in:
Родитель
686b723d0d
Коммит
429ae74074
|
@ -26,6 +26,11 @@ mozilla::StaticRefPtr<OSPreferences> OSPreferences::sInstance;
|
|||
OSPreferences* OSPreferences::GetInstance() {
|
||||
if (!sInstance) {
|
||||
sInstance = new OSPreferences();
|
||||
|
||||
DebugOnly<nsresult> rv = Preferences::RegisterPrefixCallback(
|
||||
PreferenceChanged, "intl.date_time.pattern_override");
|
||||
MOZ_ASSERT(NS_SUCCEEDED(rv), "Adding observers failed.");
|
||||
|
||||
ClearOnShutdown(&sInstance);
|
||||
}
|
||||
return sInstance;
|
||||
|
@ -44,6 +49,20 @@ void OSPreferences::Refresh() {
|
|||
}
|
||||
}
|
||||
|
||||
OSPreferences::~OSPreferences() {
|
||||
Preferences::UnregisterPrefixCallback(PreferenceChanged,
|
||||
"intl.date_time.pattern_override");
|
||||
RemoveObservers();
|
||||
}
|
||||
|
||||
/*static*/
|
||||
void OSPreferences::PreferenceChanged(const char* aPrefName,
|
||||
void* /* aClosure */) {
|
||||
if (sInstance) {
|
||||
sInstance->mPatternCache.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This method should be called by every method of OSPreferences that
|
||||
* retrieves a locale id from external source.
|
||||
|
@ -171,6 +190,126 @@ bool OSPreferences::GetDateTimeSkeletonForStyle(DateTimeFormatStyle aDateStyle,
|
|||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method checks for preferences that override the defaults
|
||||
*/
|
||||
bool OSPreferences::OverrideDateTimePattern(DateTimeFormatStyle aDateStyle,
|
||||
DateTimeFormatStyle aTimeStyle,
|
||||
const nsACString& aLocale,
|
||||
nsACString& aRetVal) {
|
||||
const auto PrefToMaybeString = [](const char* pref) -> Maybe<nsAutoCString> {
|
||||
nsAutoCString value;
|
||||
nsresult nr = Preferences::GetCString(pref, value);
|
||||
if (NS_FAILED(nr) || value.IsEmpty()) {
|
||||
return Nothing();
|
||||
}
|
||||
return Some(std::move(value));
|
||||
};
|
||||
|
||||
Maybe<nsAutoCString> timeSkeleton;
|
||||
switch (aTimeStyle) {
|
||||
case DateTimeFormatStyle::Short:
|
||||
timeSkeleton =
|
||||
PrefToMaybeString("intl.date_time.pattern_override.time_short");
|
||||
break;
|
||||
case DateTimeFormatStyle::Medium:
|
||||
timeSkeleton =
|
||||
PrefToMaybeString("intl.date_time.pattern_override.time_medium");
|
||||
break;
|
||||
case DateTimeFormatStyle::Long:
|
||||
timeSkeleton =
|
||||
PrefToMaybeString("intl.date_time.pattern_override.time_long");
|
||||
break;
|
||||
case DateTimeFormatStyle::Full:
|
||||
timeSkeleton =
|
||||
PrefToMaybeString("intl.date_time.pattern_override.time_full");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
Maybe<nsAutoCString> dateSkeleton;
|
||||
switch (aDateStyle) {
|
||||
case DateTimeFormatStyle::Short:
|
||||
dateSkeleton =
|
||||
PrefToMaybeString("intl.date_time.pattern_override.date_short");
|
||||
break;
|
||||
case DateTimeFormatStyle::Medium:
|
||||
dateSkeleton =
|
||||
PrefToMaybeString("intl.date_time.pattern_override.date_medium");
|
||||
break;
|
||||
case DateTimeFormatStyle::Long:
|
||||
dateSkeleton =
|
||||
PrefToMaybeString("intl.date_time.pattern_override.date_long");
|
||||
break;
|
||||
case DateTimeFormatStyle::Full:
|
||||
dateSkeleton =
|
||||
PrefToMaybeString("intl.date_time.pattern_override.date_full");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
nsAutoCString locale;
|
||||
if (aLocale.IsEmpty()) {
|
||||
AutoTArray<nsCString, 10> regionalPrefsLocales;
|
||||
LocaleService::GetInstance()->GetRegionalPrefsLocales(regionalPrefsLocales);
|
||||
locale.Assign(regionalPrefsLocales[0]);
|
||||
} else {
|
||||
locale.Assign(aLocale);
|
||||
}
|
||||
|
||||
const auto FillConnectorPattern = [&locale](
|
||||
const nsAutoCString& datePattern,
|
||||
const nsAutoCString& timePattern) {
|
||||
nsAutoCString pattern;
|
||||
GetDateTimeConnectorPattern(nsDependentCString(locale.get()), pattern);
|
||||
int32_t index = pattern.Find("{1}");
|
||||
if (index != kNotFound) {
|
||||
pattern.Replace(index, 3, datePattern);
|
||||
}
|
||||
index = pattern.Find("{0}");
|
||||
if (index != kNotFound) {
|
||||
pattern.Replace(index, 3, timePattern);
|
||||
}
|
||||
return pattern;
|
||||
};
|
||||
|
||||
if (timeSkeleton && dateSkeleton) {
|
||||
aRetVal.Assign(FillConnectorPattern(*dateSkeleton, *timeSkeleton));
|
||||
} else if (timeSkeleton) {
|
||||
if (aDateStyle != DateTimeFormatStyle::None) {
|
||||
nsAutoCString pattern;
|
||||
if (!ReadDateTimePattern(aDateStyle, DateTimeFormatStyle::None, aLocale,
|
||||
pattern) &&
|
||||
!GetDateTimePatternForStyle(aDateStyle, DateTimeFormatStyle::None,
|
||||
aLocale, pattern)) {
|
||||
return false;
|
||||
}
|
||||
aRetVal.Assign(FillConnectorPattern(pattern, *timeSkeleton));
|
||||
} else {
|
||||
aRetVal.Assign(*timeSkeleton);
|
||||
}
|
||||
} else if (dateSkeleton) {
|
||||
if (aTimeStyle != DateTimeFormatStyle::None) {
|
||||
nsAutoCString pattern;
|
||||
if (!ReadDateTimePattern(DateTimeFormatStyle::None, aTimeStyle, aLocale,
|
||||
pattern) &&
|
||||
!GetDateTimePatternForStyle(DateTimeFormatStyle::None, aTimeStyle,
|
||||
aLocale, pattern)) {
|
||||
return false;
|
||||
}
|
||||
aRetVal.Assign(FillConnectorPattern(*dateSkeleton, pattern));
|
||||
} else {
|
||||
aRetVal.Assign(*dateSkeleton);
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function is a counterpart to GetDateTimeSkeletonForStyle.
|
||||
*
|
||||
|
@ -347,11 +486,13 @@ OSPreferences::GetDateTimePattern(int32_t aDateFormatStyle,
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
if (!OverrideDateTimePattern(dateStyle, timeStyle, aLocale, pattern)) {
|
||||
if (!ReadDateTimePattern(dateStyle, timeStyle, aLocale, pattern)) {
|
||||
if (!GetDateTimePatternForStyle(dateStyle, timeStyle, aLocale, pattern)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (mPatternCache.Count() == kMaxCachedPatterns) {
|
||||
// Don't allow unlimited cache growth; just throw it away in the case of
|
||||
|
|
|
@ -125,6 +125,10 @@ class OSPreferences : public mozIOSPreferences {
|
|||
const nsACString& aLocale,
|
||||
nsACString& aRetVal);
|
||||
|
||||
bool OverrideDateTimePattern(DateTimeFormatStyle aDateStyle,
|
||||
DateTimeFormatStyle aTimeStyle,
|
||||
const nsACString& aLocale, nsACString& aRetVal);
|
||||
|
||||
/**
|
||||
* This is a host environment specific method that will be implemented
|
||||
* separately for each platform.
|
||||
|
@ -154,6 +158,18 @@ class OSPreferences : public mozIOSPreferences {
|
|||
bool ReadDateTimePattern(DateTimeFormatStyle aDateFormatStyle,
|
||||
DateTimeFormatStyle aTimeFormatStyle,
|
||||
const nsACString& aLocale, nsACString& aRetVal);
|
||||
|
||||
/**
|
||||
* This is called by the destructor to clean up any OS specific observers
|
||||
* that are registered.
|
||||
*/
|
||||
void RemoveObservers();
|
||||
|
||||
/**
|
||||
* This is called by the destructor to clean up any OS specific observers
|
||||
* that are registered.
|
||||
*/
|
||||
static void PreferenceChanged(const char* aPrefName, void* /* aClosure */);
|
||||
};
|
||||
|
||||
} // namespace intl
|
||||
|
|
|
@ -13,8 +13,6 @@ using namespace mozilla::intl;
|
|||
|
||||
OSPreferences::OSPreferences() {}
|
||||
|
||||
OSPreferences::~OSPreferences() {}
|
||||
|
||||
bool OSPreferences::ReadSystemLocales(nsTArray<nsCString>& aLocaleList) {
|
||||
if (!mozilla::jni::IsAvailable()) {
|
||||
return false;
|
||||
|
@ -46,3 +44,5 @@ bool OSPreferences::ReadDateTimePattern(DateTimeFormatStyle aDateStyle,
|
|||
nsACString& aRetVal) {
|
||||
return false;
|
||||
}
|
||||
|
||||
void OSPreferences::RemoveObservers() {}
|
||||
|
|
|
@ -16,8 +16,6 @@ using namespace mozilla::intl;
|
|||
|
||||
OSPreferences::OSPreferences() = default;
|
||||
|
||||
OSPreferences::~OSPreferences() = default;
|
||||
|
||||
bool OSPreferences::ReadSystemLocales(nsTArray<nsCString>& aLocaleList) {
|
||||
MOZ_ASSERT(aLocaleList.IsEmpty());
|
||||
|
||||
|
@ -198,3 +196,5 @@ bool OSPreferences::ReadDateTimePattern(DateTimeFormatStyle aDateStyle,
|
|||
|
||||
return true;
|
||||
}
|
||||
|
||||
void OSPreferences::RemoveObservers() {}
|
||||
|
|
|
@ -28,12 +28,6 @@ OSPreferences::OSPreferences() {
|
|||
CFNotificationSuspensionBehaviorDeliverImmediately);
|
||||
}
|
||||
|
||||
OSPreferences::~OSPreferences() {
|
||||
::CFNotificationCenterRemoveObserver(
|
||||
::CFNotificationCenterGetLocalCenter(), this,
|
||||
kCTFontManagerRegisteredFontsChangedNotification, 0);
|
||||
}
|
||||
|
||||
bool OSPreferences::ReadSystemLocales(nsTArray<nsCString>& aLocaleList) {
|
||||
MOZ_ASSERT(aLocaleList.IsEmpty());
|
||||
|
||||
|
@ -156,3 +150,9 @@ bool OSPreferences::ReadDateTimePattern(DateTimeFormatStyle aDateStyle,
|
|||
aRetVal = NS_ConvertUTF16toUTF8(str);
|
||||
return true;
|
||||
}
|
||||
|
||||
void OSPreferences::RemoveObservers() {
|
||||
::CFNotificationCenterRemoveObserver(
|
||||
::CFNotificationCenterGetLocalCenter(), this,
|
||||
kCTFontManagerRegisteredFontsChangedNotification, 0);
|
||||
}
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
|
||||
#include "gtest/gtest.h"
|
||||
#include "mozilla/ArrayUtils.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
#include "mozilla/intl/OSPreferences.h"
|
||||
|
||||
using namespace mozilla::intl;
|
||||
|
@ -78,3 +79,70 @@ TEST(Intl_Locale_OSPreferences, GetDateTimePattern)
|
|||
|
||||
ASSERT_TRUE(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that is possible to override the OS defaults through a pref.
|
||||
*/
|
||||
TEST(Intl_Locale_OSPreferences, GetDateTimePatternPrefOverrides)
|
||||
{
|
||||
nsresult nr;
|
||||
nsAutoCString default_pattern, pattern;
|
||||
OSPreferences* osprefs = OSPreferences::GetInstance();
|
||||
|
||||
struct {
|
||||
const char* DatePref;
|
||||
const char* TimePref;
|
||||
int32_t DateTimeFormatStyle;
|
||||
} configs[] = {{"intl.date_time.pattern_override.date_short",
|
||||
"intl.date_time.pattern_override.time_short",
|
||||
mozIOSPreferences::dateTimeFormatStyleShort},
|
||||
{"intl.date_time.pattern_override.date_medium",
|
||||
"intl.date_time.pattern_override.time_medium",
|
||||
mozIOSPreferences::dateTimeFormatStyleMedium},
|
||||
{"intl.date_time.pattern_override.date_long",
|
||||
"intl.date_time.pattern_override.time_long",
|
||||
mozIOSPreferences::dateTimeFormatStyleLong},
|
||||
{"intl.date_time.pattern_override.date_full",
|
||||
"intl.date_time.pattern_override.time_full",
|
||||
mozIOSPreferences::dateTimeFormatStyleFull}};
|
||||
|
||||
for (const auto& config : configs) {
|
||||
// Get default value for the OS
|
||||
nr = osprefs->GetDateTimePattern(config.DateTimeFormatStyle,
|
||||
mozIOSPreferences::dateTimeFormatStyleNone,
|
||||
nsDependentCString(""), default_pattern);
|
||||
ASSERT_TRUE(NS_SUCCEEDED(nr));
|
||||
|
||||
// Override date format
|
||||
mozilla::Preferences::SetCString(config.DatePref, "yy-MM");
|
||||
nr = osprefs->GetDateTimePattern(config.DateTimeFormatStyle,
|
||||
mozIOSPreferences::dateTimeFormatStyleNone,
|
||||
nsDependentCString(""), pattern);
|
||||
ASSERT_TRUE(NS_SUCCEEDED(nr));
|
||||
ASSERT_TRUE(pattern.EqualsASCII("yy-MM"));
|
||||
|
||||
// Override time format
|
||||
mozilla::Preferences::SetCString(config.TimePref, "HH:mm");
|
||||
nr = osprefs->GetDateTimePattern(mozIOSPreferences::dateTimeFormatStyleNone,
|
||||
config.DateTimeFormatStyle,
|
||||
nsDependentCString(""), pattern);
|
||||
ASSERT_TRUE(NS_SUCCEEDED(nr));
|
||||
ASSERT_TRUE(pattern.EqualsASCII("HH:mm"));
|
||||
|
||||
// Override both
|
||||
nr = osprefs->GetDateTimePattern(config.DateTimeFormatStyle,
|
||||
config.DateTimeFormatStyle,
|
||||
nsDependentCString(""), pattern);
|
||||
ASSERT_TRUE(NS_SUCCEEDED(nr));
|
||||
ASSERT_TRUE(pattern.EqualsASCII("yy-MM, HH:mm"));
|
||||
|
||||
// Clear overrides, we should get the default value back.
|
||||
mozilla::Preferences::SetCString(config.DatePref, "");
|
||||
mozilla::Preferences::SetCString(config.TimePref, "");
|
||||
nr = osprefs->GetDateTimePattern(config.DateTimeFormatStyle,
|
||||
mozIOSPreferences::dateTimeFormatStyleNone,
|
||||
nsDependentCString(""), pattern);
|
||||
ASSERT_TRUE(NS_SUCCEEDED(nr));
|
||||
ASSERT_EQ(default_pattern, pattern);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -27,8 +27,6 @@ using namespace mozilla::intl;
|
|||
|
||||
OSPreferences::OSPreferences() {}
|
||||
|
||||
OSPreferences::~OSPreferences() {}
|
||||
|
||||
bool OSPreferences::ReadSystemLocales(nsTArray<nsCString>& aLocaleList) {
|
||||
MOZ_ASSERT(aLocaleList.IsEmpty());
|
||||
|
||||
|
@ -330,3 +328,5 @@ bool OSPreferences::ReadDateTimePattern(DateTimeFormatStyle aDateStyle,
|
|||
|
||||
return true;
|
||||
}
|
||||
|
||||
void OSPreferences::RemoveObservers() {}
|
||||
|
|
Загрузка…
Ссылка в новой задаче