blob: 9db99bc6cb2993674e2622dba2c68ed9e69784d8 [file] [log] [blame]
// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/pref_service.h"
#include <algorithm>
#include <string>
#include "app/l10n_util.h"
#include "base/command_line.h"
#include "base/histogram.h"
#include "base/logging.h"
#include "base/message_loop.h"
#include "base/path_service.h"
#include "base/stl_util-inl.h"
#include "base/string_util.h"
#include "base/sys_string_conversions.h"
#include "base/utf_string_conversions.h"
#include "build/build_config.h"
#include "chrome/browser/chrome_thread.h"
#if defined(OS_WIN)
#include "chrome/browser/configuration_policy_provider_win.h"
#elif defined(OS_MACOSX)
#include "chrome/browser/configuration_policy_provider_mac.h"
#elif defined(OS_POSIX)
#include "chrome/browser/config_dir_policy_provider.h"
#endif
#include "chrome/browser/dummy_configuration_policy_provider.h"
#include "chrome/browser/command_line_pref_store.h"
#include "chrome/browser/configuration_policy_pref_store.h"
#include "chrome/browser/extensions/extension_pref_store.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/common/json_pref_store.h"
#include "chrome/common/notification_service.h"
#include "grit/chromium_strings.h"
#include "grit/generated_resources.h"
namespace {
// A helper function for RegisterLocalized*Pref that creates a Value* based on
// the string value in the locale dll. Because we control the values in a
// locale dll, this should always return a Value of the appropriate type.
Value* CreateLocaleDefaultValue(Value::ValueType type, int message_id) {
std::wstring resource_string = l10n_util::GetString(message_id);
DCHECK(!resource_string.empty());
switch (type) {
case Value::TYPE_BOOLEAN: {
if (L"true" == resource_string)
return Value::CreateBooleanValue(true);
if (L"false" == resource_string)
return Value::CreateBooleanValue(false);
break;
}
case Value::TYPE_INTEGER: {
return Value::CreateIntegerValue(
StringToInt(WideToUTF16Hack(resource_string)));
break;
}
case Value::TYPE_REAL: {
return Value::CreateRealValue(
StringToDouble(WideToUTF16Hack(resource_string)));
break;
}
case Value::TYPE_STRING: {
return Value::CreateStringValue(resource_string);
break;
}
default: {
NOTREACHED() <<
"list and dictionary types can not have default locale values";
}
}
NOTREACHED();
return Value::CreateNullValue();
}
// Forwards a notification after a PostMessage so that we can wait for the
// MessageLoop to run.
void NotifyReadError(PrefService* pref, int message_id) {
Source<PrefService> source(pref);
NotificationService::current()->Notify(NotificationType::PROFILE_ERROR,
source, Details<int>(&message_id));
}
} // namespace
// static
PrefService* PrefService::CreatePrefService(const FilePath& pref_filename) {
PrefStore* managed_prefs = NULL;
// TODO(pamg): Reinstate extension pref store after Mstone6 branch, when its
// memory leaks are fixed and any extension API is using it.
// ExtensionPrefStore* extension_prefs = new ExtensionPrefStore(NULL);
ExtensionPrefStore* extension_prefs = NULL;
CommandLinePrefStore* command_line_prefs = new CommandLinePrefStore(
CommandLine::ForCurrentProcess());
PrefStore* local_prefs = new JsonPrefStore(
pref_filename,
ChromeThread::GetMessageLoopProxyForThread(ChromeThread::FILE));
PrefStore* recommended_prefs = NULL;
ConfigurationPolicyProvider* managed_prefs_provider = NULL;
ConfigurationPolicyProvider* recommended_prefs_provider = NULL;
#if defined(OS_WIN)
managed_prefs_provider = new ConfigurationPolicyProviderWin();
recommended_prefs_provider = new DummyConfigurationPolicyProvider();
#elif defined(OS_MACOSX)
managed_prefs_provider = new ConfigurationPolicyProviderMac();
recommended_prefs_provider = new DummyConfigurationPolicyProvider();
#elif defined(OS_POSIX)
FilePath config_dir_path;
if (PathService::Get(chrome::DIR_POLICY_FILES, &config_dir_path)) {
managed_prefs_provider = new ConfigDirPolicyProvider(
config_dir_path.Append(FILE_PATH_LITERAL("managed")));
recommended_prefs_provider = new ConfigDirPolicyProvider(
config_dir_path.Append(FILE_PATH_LITERAL("recommended")));
} else {
managed_prefs_provider = new DummyConfigurationPolicyProvider();
recommended_prefs_provider = new DummyConfigurationPolicyProvider();
}
#endif
// The ConfigurationPolicyPrefStore takes ownership of the passed
// |provider|.
managed_prefs = new ConfigurationPolicyPrefStore(
CommandLine::ForCurrentProcess(),
managed_prefs_provider);
recommended_prefs = new ConfigurationPolicyPrefStore(
CommandLine::ForCurrentProcess(),
recommended_prefs_provider);
// The PrefValueStore takes ownership of the PrefStores.
PrefValueStore* value_store = new PrefValueStore(
managed_prefs,
extension_prefs,
command_line_prefs,
local_prefs,
recommended_prefs);
PrefService* pref_service = new PrefService(value_store);
// TODO(pamg): Uncomment when ExtensionPrefStore is reinstated.
// extension_prefs->SetPrefService(pref_service);
return pref_service;
}
// static
PrefService* PrefService::CreateUserPrefService(
const FilePath& pref_filename) {
PrefValueStore* value_store = new PrefValueStore(
NULL, /* no enforced prefs */
NULL, /* no extension prefs */
NULL, /* no command-line prefs */
new JsonPrefStore(
pref_filename,
ChromeThread::GetMessageLoopProxyForThread(ChromeThread::FILE)),
/* user prefs */
NULL /* no advised prefs */);
return new PrefService(value_store);
}
PrefService::PrefService(PrefValueStore* pref_value_store)
: pref_value_store_(pref_value_store) {
InitFromStorage();
}
PrefService::~PrefService() {
DCHECK(CalledOnValidThread());
// Verify that there are no pref observers when we shut down.
for (PrefObserverMap::iterator it = pref_observers_.begin();
it != pref_observers_.end(); ++it) {
NotificationObserverList::Iterator obs_iterator(*(it->second));
if (obs_iterator.GetNext()) {
LOG(WARNING) << "pref observer found at shutdown " << it->first;
}
}
STLDeleteContainerPointers(prefs_.begin(), prefs_.end());
prefs_.clear();
STLDeleteContainerPairSecondPointers(pref_observers_.begin(),
pref_observers_.end());
pref_observers_.clear();
}
void PrefService::InitFromStorage() {
PrefStore::PrefReadError error = LoadPersistentPrefs();
if (error == PrefStore::PREF_READ_ERROR_NONE)
return;
// Failing to load prefs on startup is a bad thing(TM). See bug 38352 for
// an example problem that this can cause.
// Do some diagnosis and try to avoid losing data.
int message_id = 0;
if (error <= PrefStore::PREF_READ_ERROR_JSON_TYPE) {
message_id = IDS_PREFERENCES_CORRUPT_ERROR;
} else if (error != PrefStore::PREF_READ_ERROR_NO_FILE) {
message_id = IDS_PREFERENCES_UNREADABLE_ERROR;
}
if (message_id) {
ChromeThread::PostTask(ChromeThread::UI, FROM_HERE,
NewRunnableFunction(&NotifyReadError, this, message_id));
}
UMA_HISTOGRAM_ENUMERATION("PrefService.ReadError", error, 20);
}
bool PrefService::ReloadPersistentPrefs() {
return (LoadPersistentPrefs() == PrefStore::PREF_READ_ERROR_NONE);
}
PrefStore::PrefReadError PrefService::LoadPersistentPrefs() {
DCHECK(CalledOnValidThread());
PrefStore::PrefReadError pref_error = pref_value_store_->ReadPrefs();
for (PreferenceSet::iterator it = prefs_.begin();
it != prefs_.end(); ++it) {
(*it)->pref_value_store_ = pref_value_store_.get();
}
return pref_error;
}
bool PrefService::SavePersistentPrefs() {
DCHECK(CalledOnValidThread());
return pref_value_store_->WritePrefs();
}
void PrefService::ScheduleSavePersistentPrefs() {
DCHECK(CalledOnValidThread());
pref_value_store_->ScheduleWritePrefs();
}
void PrefService::RegisterBooleanPref(const wchar_t* path,
bool default_value) {
Preference* pref = new Preference(pref_value_store_.get(), path,
Value::CreateBooleanValue(default_value));
RegisterPreference(pref);
}
void PrefService::RegisterIntegerPref(const wchar_t* path,
int default_value) {
Preference* pref = new Preference(pref_value_store_.get(), path,
Value::CreateIntegerValue(default_value));
RegisterPreference(pref);
}
void PrefService::RegisterRealPref(const wchar_t* path,
double default_value) {
Preference* pref = new Preference(pref_value_store_.get(), path,
Value::CreateRealValue(default_value));
RegisterPreference(pref);
}
void PrefService::RegisterStringPref(const wchar_t* path,
const std::string& default_value) {
Preference* pref = new Preference(pref_value_store_.get(), path,
Value::CreateStringValue(default_value));
RegisterPreference(pref);
}
void PrefService::RegisterFilePathPref(const wchar_t* path,
const FilePath& default_value) {
Preference* pref = new Preference(pref_value_store_.get(), path,
Value::CreateStringValue(default_value.value()));
RegisterPreference(pref);
}
void PrefService::RegisterListPref(const wchar_t* path) {
Preference* pref = new Preference(pref_value_store_.get(), path,
new ListValue);
RegisterPreference(pref);
}
void PrefService::RegisterDictionaryPref(const wchar_t* path) {
Preference* pref = new Preference(pref_value_store_.get(), path,
new DictionaryValue());
RegisterPreference(pref);
}
void PrefService::RegisterLocalizedBooleanPref(const wchar_t* path,
int locale_default_message_id) {
Preference* pref = new Preference(pref_value_store_.get(), path,
CreateLocaleDefaultValue(Value::TYPE_BOOLEAN, locale_default_message_id));
RegisterPreference(pref);
}
void PrefService::RegisterLocalizedIntegerPref(const wchar_t* path,
int locale_default_message_id) {
Preference* pref = new Preference(pref_value_store_.get(), path,
CreateLocaleDefaultValue(Value::TYPE_INTEGER, locale_default_message_id));
RegisterPreference(pref);
}
void PrefService::RegisterLocalizedRealPref(const wchar_t* path,
int locale_default_message_id) {
Preference* pref = new Preference(pref_value_store_.get(), path,
CreateLocaleDefaultValue(Value::TYPE_REAL, locale_default_message_id));
RegisterPreference(pref);
}
void PrefService::RegisterLocalizedStringPref(const wchar_t* path,
int locale_default_message_id) {
Preference* pref = new Preference(pref_value_store_.get(), path,
CreateLocaleDefaultValue(Value::TYPE_STRING, locale_default_message_id));
RegisterPreference(pref);
}
bool PrefService::GetBoolean(const wchar_t* path) const {
DCHECK(CalledOnValidThread());
bool result = false;
const Preference* pref = FindPreference(path);
if (!pref) {
NOTREACHED() << "Trying to read an unregistered pref: " << path;
return result;
}
bool rv = pref->GetValue()->GetAsBoolean(&result);
DCHECK(rv);
return result;
}
int PrefService::GetInteger(const wchar_t* path) const {
DCHECK(CalledOnValidThread());
int result = 0;
const Preference* pref = FindPreference(path);
if (!pref) {
NOTREACHED() << "Trying to read an unregistered pref: " << path;
return result;
}
bool rv = pref->GetValue()->GetAsInteger(&result);
DCHECK(rv);
return result;
}
double PrefService::GetReal(const wchar_t* path) const {
DCHECK(CalledOnValidThread());
double result = 0.0;
const Preference* pref = FindPreference(path);
if (!pref) {
NOTREACHED() << "Trying to read an unregistered pref: " << path;
return result;
}
bool rv = pref->GetValue()->GetAsReal(&result);
DCHECK(rv);
return result;
}
std::string PrefService::GetString(const wchar_t* path) const {
DCHECK(CalledOnValidThread());
std::string result;
const Preference* pref = FindPreference(path);
if (!pref) {
NOTREACHED() << "Trying to read an unregistered pref: " << path;
return result;
}
bool rv = pref->GetValue()->GetAsString(&result);
DCHECK(rv);
return result;
}
FilePath PrefService::GetFilePath(const wchar_t* path) const {
DCHECK(CalledOnValidThread());
FilePath::StringType result;
const Preference* pref = FindPreference(path);
if (!pref) {
NOTREACHED() << "Trying to read an unregistered pref: " << path;
return FilePath(result);
}
bool rv = pref->GetValue()->GetAsString(&result);
DCHECK(rv);
#if defined(OS_POSIX)
// We store filepaths as UTF8, so convert it back to the system type.
result = base::SysWideToNativeMB(UTF8ToWide(result));
#endif
return FilePath(result);
}
bool PrefService::HasPrefPath(const wchar_t* path) const {
return pref_value_store_->HasPrefPath(path);
}
const PrefService::Preference* PrefService::FindPreference(
const wchar_t* pref_name) const {
DCHECK(CalledOnValidThread());
Preference p(NULL, pref_name, NULL);
PreferenceSet::const_iterator it = prefs_.find(&p);
return it == prefs_.end() ? NULL : *it;
}
bool PrefService::IsManagedPreference(const wchar_t* pref_name) const {
const Preference* pref = FindPreference(pref_name);
if (pref && pref->IsManaged()) {
return true;
}
return false;
}
void PrefService::FireObserversIfChanged(const wchar_t* path,
const Value* old_value) {
if (PrefIsChanged(path, old_value))
FireObservers(path);
}
bool PrefService::PrefIsChanged(const wchar_t* path,
const Value* old_value) {
Value* new_value = NULL;
pref_value_store_->GetValue(path, &new_value);
// Some unit tests have no values for certain prefs.
return (!new_value || !old_value->Equals(new_value));
}
const DictionaryValue* PrefService::GetDictionary(const wchar_t* path) const {
DCHECK(CalledOnValidThread());
const Preference* pref = FindPreference(path);
if (!pref) {
NOTREACHED() << "Trying to read an unregistered pref: " << path;
return NULL;
}
const Value* value = pref->GetValue();
if (value->GetType() == Value::TYPE_NULL)
return NULL;
return static_cast<const DictionaryValue*>(value);
}
const ListValue* PrefService::GetList(const wchar_t* path) const {
DCHECK(CalledOnValidThread());
const Preference* pref = FindPreference(path);
if (!pref) {
NOTREACHED() << "Trying to read an unregistered pref: " << path;
return NULL;
}
const Value* value = pref->GetValue();
if (value->GetType() == Value::TYPE_NULL)
return NULL;
return static_cast<const ListValue*>(value);
}
void PrefService::AddPrefObserver(const wchar_t* path,
NotificationObserver* obs) {
DCHECK(CalledOnValidThread());
const Preference* pref = FindPreference(path);
if (!pref) {
NOTREACHED() << "Trying to add an observer for an unregistered pref: "
<< path;
return;
}
// Get the pref observer list associated with the path.
NotificationObserverList* observer_list = NULL;
PrefObserverMap::iterator observer_iterator = pref_observers_.find(path);
if (observer_iterator == pref_observers_.end()) {
observer_list = new NotificationObserverList;
pref_observers_[path] = observer_list;
} else {
observer_list = observer_iterator->second;
}
// Verify that this observer doesn't already exist.
NotificationObserverList::Iterator it(*observer_list);
NotificationObserver* existing_obs;
while ((existing_obs = it.GetNext()) != NULL) {
DCHECK(existing_obs != obs) << path << " observer already registered";
if (existing_obs == obs)
return;
}
// Ok, safe to add the pref observer.
observer_list->AddObserver(obs);
}
void PrefService::RemovePrefObserver(const wchar_t* path,
NotificationObserver* obs) {
DCHECK(CalledOnValidThread());
PrefObserverMap::iterator observer_iterator = pref_observers_.find(path);
if (observer_iterator == pref_observers_.end()) {
return;
}
NotificationObserverList* observer_list = observer_iterator->second;
observer_list->RemoveObserver(obs);
}
void PrefService::RegisterPreference(Preference* pref) {
DCHECK(CalledOnValidThread());
if (FindPreference(pref->name().c_str())) {
NOTREACHED() << "Tried to register duplicate pref " << pref->name();
delete pref;
return;
}
prefs_.insert(pref);
}
void PrefService::ClearPref(const wchar_t* path) {
DCHECK(CalledOnValidThread());
const Preference* pref = FindPreference(path);
if (!pref) {
NOTREACHED() << "Trying to clear an unregistered pref: " << path;
return;
}
Value* value;
bool has_old_value = pref_value_store_->GetValue(path, &value);
pref_value_store_->RemoveUserPrefValue(path);
if (has_old_value)
FireObservers(path);
}
void PrefService::Set(const wchar_t* path, const Value& value) {
DCHECK(CalledOnValidThread());
const Preference* pref = FindPreference(path);
if (!pref) {
NOTREACHED() << "Trying to write an unregistered pref: " << path;
return;
}
// Allow dictionary and list types to be set to null.
if (value.GetType() == Value::TYPE_NULL &&
(pref->type() == Value::TYPE_DICTIONARY ||
pref->type() == Value::TYPE_LIST)) {
scoped_ptr<Value> old_value(GetPrefCopy(path));
if (!old_value->Equals(&value)) {
pref_value_store_->RemoveUserPrefValue(path);
FireObservers(path);
}
return;
}
if (pref->type() != value.GetType()) {
NOTREACHED() << "Wrong type for Set: " << path;
}
scoped_ptr<Value> old_value(GetPrefCopy(path));
pref_value_store_->SetUserPrefValue(path, value.DeepCopy());
FireObserversIfChanged(path, old_value.get());
}
void PrefService::SetBoolean(const wchar_t* path, bool value) {
DCHECK(CalledOnValidThread());
const Preference* pref = FindPreference(path);
if (!pref) {
NOTREACHED() << "Trying to write an unregistered pref: " << path;
return;
}
if (pref->IsManaged()) {
NOTREACHED() << "Preference is managed: " << path;
return;
}
if (pref->type() != Value::TYPE_BOOLEAN) {
NOTREACHED() << "Wrong type for SetBoolean: " << path;
return;
}
scoped_ptr<Value> old_value(GetPrefCopy(path));
Value* new_value = Value::CreateBooleanValue(value);
pref_value_store_->SetUserPrefValue(path, new_value);
FireObserversIfChanged(path, old_value.get());
}
void PrefService::SetInteger(const wchar_t* path, int value) {
DCHECK(CalledOnValidThread());
const Preference* pref = FindPreference(path);
if (!pref) {
NOTREACHED() << "Trying to write an unregistered pref: " << path;
return;
}
if (pref->IsManaged()) {
NOTREACHED() << "Preference is managed: " << path;
return;
}
if (pref->type() != Value::TYPE_INTEGER) {
NOTREACHED() << "Wrong type for SetInteger: " << path;
return;
}
scoped_ptr<Value> old_value(GetPrefCopy(path));
Value* new_value = Value::CreateIntegerValue(value);
pref_value_store_->SetUserPrefValue(path, new_value);
FireObserversIfChanged(path, old_value.get());
}
void PrefService::SetReal(const wchar_t* path, double value) {
DCHECK(CalledOnValidThread());
const Preference* pref = FindPreference(path);
if (!pref) {
NOTREACHED() << "Trying to write an unregistered pref: " << path;
return;
}
if (pref->IsManaged()) {
NOTREACHED() << "Preference is managed: " << path;
return;
}
if (pref->type() != Value::TYPE_REAL) {
NOTREACHED() << "Wrong type for SetReal: " << path;
return;
}
scoped_ptr<Value> old_value(GetPrefCopy(path));
Value* new_value = Value::CreateRealValue(value);
pref_value_store_->SetUserPrefValue(path, new_value);
FireObserversIfChanged(path, old_value.get());
}
void PrefService::SetString(const wchar_t* path, const std::string& value) {
DCHECK(CalledOnValidThread());
const Preference* pref = FindPreference(path);
if (!pref) {
NOTREACHED() << "Trying to write an unregistered pref: " << path;
return;
}
if (pref->IsManaged()) {
NOTREACHED() << "Preference is managed: " << path;
return;
}
if (pref->type() != Value::TYPE_STRING) {
NOTREACHED() << "Wrong type for SetString: " << path;
return;
}
scoped_ptr<Value> old_value(GetPrefCopy(path));
Value* new_value = Value::CreateStringValue(value);
pref_value_store_->SetUserPrefValue(path, new_value);
FireObserversIfChanged(path, old_value.get());
}
void PrefService::SetFilePath(const wchar_t* path, const FilePath& value) {
DCHECK(CalledOnValidThread());
const Preference* pref = FindPreference(path);
if (!pref) {
NOTREACHED() << "Trying to write an unregistered pref: " << path;
return;
}
if (pref->IsManaged()) {
NOTREACHED() << "Preference is managed: " << path;
return;
}
if (pref->type() != Value::TYPE_STRING) {
NOTREACHED() << "Wrong type for SetFilePath: " << path;
return;
}
scoped_ptr<Value> old_value(GetPrefCopy(path));
#if defined(OS_POSIX)
// Value::SetString only knows about UTF8 strings, so convert the path from
// the system native value to UTF8.
std::string path_utf8 = WideToUTF8(base::SysNativeMBToWide(value.value()));
Value* new_value = Value::CreateStringValue(path_utf8);
pref_value_store_->SetUserPrefValue(path, new_value);
#else
Value* new_value = Value::CreateStringValue(value.value());
pref_value_store_->SetUserPrefValue(path, new_value);
#endif
FireObserversIfChanged(path, old_value.get());
}
void PrefService::SetInt64(const wchar_t* path, int64 value) {
DCHECK(CalledOnValidThread());
const Preference* pref = FindPreference(path);
if (!pref) {
NOTREACHED() << "Trying to write an unregistered pref: " << path;
return;
}
if (pref->IsManaged()) {
NOTREACHED() << "Preference is managed: " << path;
return;
}
if (pref->type() != Value::TYPE_STRING) {
NOTREACHED() << "Wrong type for SetInt64: " << path;
return;
}
scoped_ptr<Value> old_value(GetPrefCopy(path));
Value* new_value = Value::CreateStringValue(Int64ToWString(value));
pref_value_store_->SetUserPrefValue(path, new_value);
FireObserversIfChanged(path, old_value.get());
}
int64 PrefService::GetInt64(const wchar_t* path) const {
DCHECK(CalledOnValidThread());
const Preference* pref = FindPreference(path);
if (!pref) {
NOTREACHED() << "Trying to read an unregistered pref: " << path;
return 0;
}
std::wstring result(L"0");
bool rv = pref->GetValue()->GetAsString(&result);
DCHECK(rv);
return StringToInt64(WideToUTF16Hack(result));
}
void PrefService::RegisterInt64Pref(const wchar_t* path, int64 default_value) {
Preference* pref = new Preference(pref_value_store_.get(), path,
Value::CreateStringValue(Int64ToWString(default_value)));
RegisterPreference(pref);
}
DictionaryValue* PrefService::GetMutableDictionary(const wchar_t* path) {
DCHECK(CalledOnValidThread());
const Preference* pref = FindPreference(path);
if (!pref) {
NOTREACHED() << "Trying to get an unregistered pref: " << path;
return NULL;
}
if (pref->type() != Value::TYPE_DICTIONARY) {
NOTREACHED() << "Wrong type for GetMutableDictionary: " << path;
return NULL;
}
DictionaryValue* dict = NULL;
Value* tmp_value = NULL;
if (!pref_value_store_->GetValue(path, &tmp_value) ||
!tmp_value->IsType(Value::TYPE_DICTIONARY)) {
dict = new DictionaryValue;
pref_value_store_->SetUserPrefValue(path, dict);
} else {
dict = static_cast<DictionaryValue*>(tmp_value);
}
return dict;
}
ListValue* PrefService::GetMutableList(const wchar_t* path) {
DCHECK(CalledOnValidThread());
const Preference* pref = FindPreference(path);
if (!pref) {
NOTREACHED() << "Trying to get an unregistered pref: " << path;
return NULL;
}
if (pref->type() != Value::TYPE_LIST) {
NOTREACHED() << "Wrong type for GetMutableList: " << path;
return NULL;
}
ListValue* list = NULL;
Value* tmp_value = NULL;
if (!pref_value_store_->GetValue(path, &tmp_value)) {
list = new ListValue;
pref_value_store_->SetUserPrefValue(path, list);
} else {
list = static_cast<ListValue*>(tmp_value);
}
return list;
}
Value* PrefService::GetPrefCopy(const wchar_t* path) {
DCHECK(CalledOnValidThread());
const Preference* pref = FindPreference(path);
DCHECK(pref);
return pref->GetValue()->DeepCopy();
}
void PrefService::FireObservers(const wchar_t* path) {
DCHECK(CalledOnValidThread());
// Convert path to a std::wstring because the Details constructor requires a
// class.
std::wstring path_str(path);
PrefObserverMap::iterator observer_iterator = pref_observers_.find(path_str);
if (observer_iterator == pref_observers_.end())
return;
NotificationObserverList::Iterator it(*(observer_iterator->second));
NotificationObserver* observer;
while ((observer = it.GetNext()) != NULL) {
observer->Observe(NotificationType::PREF_CHANGED,
Source<PrefService>(this),
Details<std::wstring>(&path_str));
}
}
///////////////////////////////////////////////////////////////////////////////
// PrefService::Preference
PrefService::Preference::Preference(PrefValueStore* pref_value_store,
const wchar_t* name,
Value* default_value)
: type_(Value::TYPE_NULL),
name_(name),
default_value_(default_value),
pref_value_store_(pref_value_store) {
DCHECK(name);
if (default_value) {
type_ = default_value->GetType();
DCHECK(type_ != Value::TYPE_NULL && type_ != Value::TYPE_BINARY) <<
"invalid preference type: " << type_;
}
// We set the default value of lists and dictionaries to be null so it's
// easier for callers to check for empty list/dict prefs.
if (Value::TYPE_LIST == type_ || Value::TYPE_DICTIONARY == type_)
default_value_.reset(Value::CreateNullValue());
}
const Value* PrefService::Preference::GetValue() const {
DCHECK(NULL != pref_value_store_) <<
"Must register pref before getting its value";
Value* temp_value = NULL;
if (pref_value_store_->GetValue(name_, &temp_value) &&
temp_value->GetType() == type_) {
return temp_value;
}
// Pref not found, just return the app default.
return default_value_.get();
}
bool PrefService::Preference::IsDefaultValue() const {
DCHECK(default_value_.get());
return default_value_->Equals(GetValue());
}
bool PrefService::Preference::IsManaged() const {
return pref_value_store_->PrefValueInManagedStore(name_.c_str());
}
bool PrefService::Preference::HasExtensionSetting() const {
return pref_value_store_->PrefValueInExtensionStore(name_.c_str());
}
bool PrefService::Preference::HasUserSetting() const {
return pref_value_store_->PrefValueInUserStore(name_.c_str());
}
bool PrefService::Preference::IsExtensionControlled() const {
return pref_value_store_->PrefValueFromExtensionStore(name_.c_str());
}
bool PrefService::Preference::IsUserControlled() const {
return pref_value_store_->PrefValueFromUserStore(name_.c_str());
}