blob: fcc8af3500cee419c52715dcb60cac1264038164 [file] [log] [blame]
[email protected]c0858b02010-05-12 15:03:321// Copyright (c) 2010 The Chromium Authors. All rights reserved.
license.botbf09a502008-08-24 00:55:552// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
initial.commit09911bf2008-07-26 23:55:294
[email protected]052313b2010-02-19 09:43:085#include "chrome/browser/pref_service.h"
initial.commit09911bf2008-07-26 23:55:296
[email protected]1cb92b82010-03-08 23:12:157#include <algorithm>
8#include <string>
9
[email protected]a92b8642009-05-05 23:38:5610#include "app/l10n_util.h"
[email protected]aa4dc5e22010-06-16 11:32:5411#include "base/command_line.h"
[email protected]ba399672010-04-06 15:42:3912#include "base/histogram.h"
initial.commit09911bf2008-07-26 23:55:2913#include "base/logging.h"
14#include "base/message_loop.h"
[email protected]02e2a3d2010-06-23 13:26:1115#include "base/path_service.h"
[email protected]807204142009-05-05 03:31:4416#include "base/stl_util-inl.h"
initial.commit09911bf2008-07-26 23:55:2917#include "base/string_util.h"
[email protected]66de4f092009-09-04 23:59:4018#include "base/sys_string_conversions.h"
[email protected]1cb92b82010-03-08 23:12:1519#include "base/utf_string_conversions.h"
[email protected]66de4f092009-09-04 23:59:4020#include "build/build_config.h"
[email protected]ba399672010-04-06 15:42:3921#include "chrome/browser/chrome_thread.h"
[email protected]b0069e72010-06-14 13:58:4722
23#if defined(OS_WIN)
24#include "chrome/browser/configuration_policy_provider_win.h"
25#elif defined(OS_MACOSX)
[email protected]031857d2010-06-15 16:01:2426#include "chrome/browser/configuration_policy_provider_mac.h"
[email protected]b0069e72010-06-14 13:58:4727#elif defined(OS_POSIX)
[email protected]02e2a3d2010-06-23 13:26:1128#include "chrome/browser/config_dir_policy_provider.h"
[email protected]b0069e72010-06-14 13:58:4729#endif
[email protected]02e2a3d2010-06-23 13:26:1130#include "chrome/browser/dummy_configuration_policy_provider.h"
[email protected]b0069e72010-06-14 13:58:4731
32#include "chrome/browser/configuration_policy_pref_store.h"
[email protected]db198b22010-07-12 16:48:4933#include "chrome/browser/extensions/extension_pref_store.h"
[email protected]02e2a3d2010-06-23 13:26:1134#include "chrome/common/chrome_paths.h"
[email protected]d8b08c92010-06-07 13:13:2835#include "chrome/common/json_pref_store.h"
initial.commit09911bf2008-07-26 23:55:2936#include "chrome/common/notification_service.h"
[email protected]ba399672010-04-06 15:42:3937#include "grit/chromium_strings.h"
[email protected]34ac8f32009-02-22 23:03:2738#include "grit/generated_resources.h"
initial.commit09911bf2008-07-26 23:55:2939
40namespace {
41
initial.commit09911bf2008-07-26 23:55:2942// A helper function for RegisterLocalized*Pref that creates a Value* based on
43// the string value in the locale dll. Because we control the values in a
44// locale dll, this should always return a Value of the appropriate type.
45Value* CreateLocaleDefaultValue(Value::ValueType type, int message_id) {
46 std::wstring resource_string = l10n_util::GetString(message_id);
47 DCHECK(!resource_string.empty());
48 switch (type) {
49 case Value::TYPE_BOOLEAN: {
50 if (L"true" == resource_string)
51 return Value::CreateBooleanValue(true);
52 if (L"false" == resource_string)
53 return Value::CreateBooleanValue(false);
54 break;
55 }
56
57 case Value::TYPE_INTEGER: {
[email protected]41fb1d72009-02-28 01:01:5058 return Value::CreateIntegerValue(
59 StringToInt(WideToUTF16Hack(resource_string)));
initial.commit09911bf2008-07-26 23:55:2960 break;
61 }
62
63 case Value::TYPE_REAL: {
[email protected]41fb1d72009-02-28 01:01:5064 return Value::CreateRealValue(
65 StringToDouble(WideToUTF16Hack(resource_string)));
initial.commit09911bf2008-07-26 23:55:2966 break;
67 }
68
69 case Value::TYPE_STRING: {
70 return Value::CreateStringValue(resource_string);
71 break;
72 }
73
74 default: {
[email protected]b154e6f2009-03-06 01:52:4075 NOTREACHED() <<
initial.commit09911bf2008-07-26 23:55:2976 "list and dictionary types can not have default locale values";
77 }
78 }
79 NOTREACHED();
80 return Value::CreateNullValue();
81}
82
[email protected]ba399672010-04-06 15:42:3983// Forwards a notification after a PostMessage so that we can wait for the
84// MessageLoop to run.
85void NotifyReadError(PrefService* pref, int message_id) {
86 Source<PrefService> source(pref);
87 NotificationService::current()->Notify(NotificationType::PROFILE_ERROR,
88 source, Details<int>(&message_id));
89}
90
initial.commit09911bf2008-07-26 23:55:2991} // namespace
92
[email protected]db198b22010-07-12 16:48:4993// static
[email protected]d8b08c92010-06-07 13:13:2894PrefService* PrefService::CreatePrefService(const FilePath& pref_filename) {
[email protected]b0069e72010-06-14 13:58:4795 PrefStore* managed_prefs = NULL;
[email protected]db198b22010-07-12 16:48:4996 ExtensionPrefStore* extension_prefs = new ExtensionPrefStore(NULL);
[email protected]b0069e72010-06-14 13:58:4797 PrefStore* local_prefs = new JsonPrefStore(
98 pref_filename,
99 ChromeThread::GetMessageLoopProxyForThread(ChromeThread::FILE));
100 PrefStore* recommended_prefs = NULL;
101
102 ConfigurationPolicyProvider* managed_prefs_provider = NULL;
[email protected]02e2a3d2010-06-23 13:26:11103 ConfigurationPolicyProvider* recommended_prefs_provider = NULL;
104
[email protected]b0069e72010-06-14 13:58:47105#if defined(OS_WIN)
106 managed_prefs_provider = new ConfigurationPolicyProviderWin();
[email protected]02e2a3d2010-06-23 13:26:11107 recommended_prefs_provider = new DummyConfigurationPolicyProvider();
[email protected]b0069e72010-06-14 13:58:47108#elif defined(OS_MACOSX)
[email protected]031857d2010-06-15 16:01:24109 managed_prefs_provider = new ConfigurationPolicyProviderMac();
[email protected]02e2a3d2010-06-23 13:26:11110 recommended_prefs_provider = new DummyConfigurationPolicyProvider();
[email protected]b0069e72010-06-14 13:58:47111#elif defined(OS_POSIX)
[email protected]02e2a3d2010-06-23 13:26:11112 FilePath config_dir_path;
113 if (PathService::Get(chrome::DIR_POLICY_FILES, &config_dir_path)) {
114 managed_prefs_provider = new ConfigDirPolicyProvider(
115 config_dir_path.Append(FILE_PATH_LITERAL("managed")));
116 recommended_prefs_provider = new ConfigDirPolicyProvider(
117 config_dir_path.Append(FILE_PATH_LITERAL("recommended")));
118 } else {
119 managed_prefs_provider = new DummyConfigurationPolicyProvider();
120 recommended_prefs_provider = new DummyConfigurationPolicyProvider();
121 }
[email protected]b0069e72010-06-14 13:58:47122#endif
123
[email protected]02e2a3d2010-06-23 13:26:11124 // The ConfigurationPolicyPrefStore takes ownership of the passed
[email protected]b0069e72010-06-14 13:58:47125 // |provider|.
[email protected]aa4dc5e22010-06-16 11:32:54126 managed_prefs = new ConfigurationPolicyPrefStore(
127 CommandLine::ForCurrentProcess(),
128 managed_prefs_provider);
[email protected]02e2a3d2010-06-23 13:26:11129 recommended_prefs = new ConfigurationPolicyPrefStore(
130 CommandLine::ForCurrentProcess(),
131 recommended_prefs_provider);
[email protected]b0069e72010-06-14 13:58:47132
[email protected]db198b22010-07-12 16:48:49133 // The PrefValueStore takes ownership of the PrefStores.
[email protected]d8b08c92010-06-07 13:13:28134 PrefValueStore* value_store = new PrefValueStore(
[email protected]b0069e72010-06-14 13:58:47135 managed_prefs,
[email protected]db198b22010-07-12 16:48:49136 extension_prefs,
[email protected]b0069e72010-06-14 13:58:47137 local_prefs,
138 recommended_prefs);
[email protected]db198b22010-07-12 16:48:49139
140 PrefService* pref_service = new PrefService(value_store);
141 extension_prefs->SetPrefService(pref_service);
142
143 return pref_service;
144}
145
146// static
147PrefService* PrefService::CreateUserPrefService(
148 const FilePath& pref_filename) {
149 PrefValueStore* value_store = new PrefValueStore(
150 NULL, /* no enforced prefs */
151 NULL, /* no extension prefs */
152 new JsonPrefStore(
153 pref_filename,
154 ChromeThread::GetMessageLoopProxyForThread(ChromeThread::FILE)),
155 /* user prefs */
156 NULL /* no advised prefs */);
[email protected]d8b08c92010-06-07 13:13:28157 return new PrefService(value_store);
158}
159
160PrefService::PrefService(PrefValueStore* pref_value_store)
161 : pref_value_store_(pref_value_store) {
[email protected]277404c22010-04-22 13:09:45162 InitFromStorage();
initial.commit09911bf2008-07-26 23:55:29163}
164
165PrefService::~PrefService() {
166 DCHECK(CalledOnValidThread());
167
168 // Verify that there are no pref observers when we shut down.
169 for (PrefObserverMap::iterator it = pref_observers_.begin();
170 it != pref_observers_.end(); ++it) {
171 NotificationObserverList::Iterator obs_iterator(*(it->second));
172 if (obs_iterator.GetNext()) {
173 LOG(WARNING) << "pref observer found at shutdown " << it->first;
174 }
175 }
176
177 STLDeleteContainerPointers(prefs_.begin(), prefs_.end());
178 prefs_.clear();
179 STLDeleteContainerPairSecondPointers(pref_observers_.begin(),
180 pref_observers_.end());
181 pref_observers_.clear();
182}
183
[email protected]277404c22010-04-22 13:09:45184void PrefService::InitFromStorage() {
185 PrefStore::PrefReadError error = LoadPersistentPrefs();
186 if (error == PrefStore::PREF_READ_ERROR_NONE)
[email protected]ba399672010-04-06 15:42:39187 return;
initial.commit09911bf2008-07-26 23:55:29188
[email protected]ba399672010-04-06 15:42:39189 // Failing to load prefs on startup is a bad thing(TM). See bug 38352 for
190 // an example problem that this can cause.
191 // Do some diagnosis and try to avoid losing data.
192 int message_id = 0;
[email protected]277404c22010-04-22 13:09:45193 if (error <= PrefStore::PREF_READ_ERROR_JSON_TYPE) {
[email protected]ba399672010-04-06 15:42:39194 message_id = IDS_PREFERENCES_CORRUPT_ERROR;
[email protected]277404c22010-04-22 13:09:45195 } else if (error != PrefStore::PREF_READ_ERROR_NO_FILE) {
[email protected]ba399672010-04-06 15:42:39196 message_id = IDS_PREFERENCES_UNREADABLE_ERROR;
197 }
198
199 if (message_id) {
200 ChromeThread::PostTask(ChromeThread::UI, FROM_HERE,
201 NewRunnableFunction(&NotifyReadError, this, message_id));
202 }
203 UMA_HISTOGRAM_ENUMERATION("PrefService.ReadError", error, 20);
204}
205
206bool PrefService::ReloadPersistentPrefs() {
[email protected]277404c22010-04-22 13:09:45207 return (LoadPersistentPrefs() == PrefStore::PREF_READ_ERROR_NONE);
[email protected]ba399672010-04-06 15:42:39208}
209
[email protected]277404c22010-04-22 13:09:45210PrefStore::PrefReadError PrefService::LoadPersistentPrefs() {
[email protected]ba399672010-04-06 15:42:39211 DCHECK(CalledOnValidThread());
[email protected]ba399672010-04-06 15:42:39212
[email protected]d8b08c92010-06-07 13:13:28213 PrefStore::PrefReadError pref_error = pref_value_store_->ReadPrefs();
[email protected]7aa0a962010-04-21 17:24:42214
[email protected]7aa0a962010-04-21 17:24:42215 for (PreferenceSet::iterator it = prefs_.begin();
216 it != prefs_.end(); ++it) {
[email protected]d8b08c92010-06-07 13:13:28217 (*it)->pref_value_store_ = pref_value_store_.get();
[email protected]7aa0a962010-04-21 17:24:42218 }
219
[email protected]277404c22010-04-22 13:09:45220 return pref_error;
initial.commit09911bf2008-07-26 23:55:29221}
222
[email protected]6faa0e0d2009-04-28 06:50:36223bool PrefService::SavePersistentPrefs() {
224 DCHECK(CalledOnValidThread());
initial.commit09911bf2008-07-26 23:55:29225
[email protected]d8b08c92010-06-07 13:13:28226 return pref_value_store_->WritePrefs();
[email protected]6faa0e0d2009-04-28 06:50:36227}
228
[email protected]6c1164042009-05-08 14:41:08229void PrefService::ScheduleSavePersistentPrefs() {
[email protected]6faa0e0d2009-04-28 06:50:36230 DCHECK(CalledOnValidThread());
[email protected]ba399672010-04-06 15:42:39231
[email protected]d8b08c92010-06-07 13:13:28232 pref_value_store_->ScheduleWritePrefs();
initial.commit09911bf2008-07-26 23:55:29233}
234
235void PrefService::RegisterBooleanPref(const wchar_t* path,
236 bool default_value) {
[email protected]d8b08c92010-06-07 13:13:28237 Preference* pref = new Preference(pref_value_store_.get(), path,
initial.commit09911bf2008-07-26 23:55:29238 Value::CreateBooleanValue(default_value));
239 RegisterPreference(pref);
240}
241
242void PrefService::RegisterIntegerPref(const wchar_t* path,
243 int default_value) {
[email protected]d8b08c92010-06-07 13:13:28244 Preference* pref = new Preference(pref_value_store_.get(), path,
initial.commit09911bf2008-07-26 23:55:29245 Value::CreateIntegerValue(default_value));
246 RegisterPreference(pref);
247}
248
249void PrefService::RegisterRealPref(const wchar_t* path,
250 double default_value) {
[email protected]d8b08c92010-06-07 13:13:28251 Preference* pref = new Preference(pref_value_store_.get(), path,
initial.commit09911bf2008-07-26 23:55:29252 Value::CreateRealValue(default_value));
253 RegisterPreference(pref);
254}
255
256void PrefService::RegisterStringPref(const wchar_t* path,
[email protected]20ce516d2010-06-18 02:20:04257 const std::string& default_value) {
[email protected]d8b08c92010-06-07 13:13:28258 Preference* pref = new Preference(pref_value_store_.get(), path,
initial.commit09911bf2008-07-26 23:55:29259 Value::CreateStringValue(default_value));
260 RegisterPreference(pref);
261}
262
[email protected]b9636002009-03-04 00:05:25263void PrefService::RegisterFilePathPref(const wchar_t* path,
264 const FilePath& default_value) {
[email protected]d8b08c92010-06-07 13:13:28265 Preference* pref = new Preference(pref_value_store_.get(), path,
[email protected]b9636002009-03-04 00:05:25266 Value::CreateStringValue(default_value.value()));
267 RegisterPreference(pref);
268}
269
initial.commit09911bf2008-07-26 23:55:29270void PrefService::RegisterListPref(const wchar_t* path) {
[email protected]d8b08c92010-06-07 13:13:28271 Preference* pref = new Preference(pref_value_store_.get(), path,
initial.commit09911bf2008-07-26 23:55:29272 new ListValue);
273 RegisterPreference(pref);
274}
275
276void PrefService::RegisterDictionaryPref(const wchar_t* path) {
[email protected]d8b08c92010-06-07 13:13:28277 Preference* pref = new Preference(pref_value_store_.get(), path,
initial.commit09911bf2008-07-26 23:55:29278 new DictionaryValue());
279 RegisterPreference(pref);
280}
281
282void PrefService::RegisterLocalizedBooleanPref(const wchar_t* path,
283 int locale_default_message_id) {
[email protected]d8b08c92010-06-07 13:13:28284 Preference* pref = new Preference(pref_value_store_.get(), path,
initial.commit09911bf2008-07-26 23:55:29285 CreateLocaleDefaultValue(Value::TYPE_BOOLEAN, locale_default_message_id));
286 RegisterPreference(pref);
287}
288
289void PrefService::RegisterLocalizedIntegerPref(const wchar_t* path,
290 int locale_default_message_id) {
[email protected]d8b08c92010-06-07 13:13:28291 Preference* pref = new Preference(pref_value_store_.get(), path,
initial.commit09911bf2008-07-26 23:55:29292 CreateLocaleDefaultValue(Value::TYPE_INTEGER, locale_default_message_id));
293 RegisterPreference(pref);
294}
295
296void PrefService::RegisterLocalizedRealPref(const wchar_t* path,
297 int locale_default_message_id) {
[email protected]d8b08c92010-06-07 13:13:28298 Preference* pref = new Preference(pref_value_store_.get(), path,
initial.commit09911bf2008-07-26 23:55:29299 CreateLocaleDefaultValue(Value::TYPE_REAL, locale_default_message_id));
300 RegisterPreference(pref);
301}
302
303void PrefService::RegisterLocalizedStringPref(const wchar_t* path,
304 int locale_default_message_id) {
[email protected]d8b08c92010-06-07 13:13:28305 Preference* pref = new Preference(pref_value_store_.get(), path,
initial.commit09911bf2008-07-26 23:55:29306 CreateLocaleDefaultValue(Value::TYPE_STRING, locale_default_message_id));
307 RegisterPreference(pref);
308}
309
initial.commit09911bf2008-07-26 23:55:29310bool PrefService::GetBoolean(const wchar_t* path) const {
311 DCHECK(CalledOnValidThread());
312
313 bool result = false;
initial.commit09911bf2008-07-26 23:55:29314
315 const Preference* pref = FindPreference(path);
316 if (!pref) {
[email protected]b154e6f2009-03-06 01:52:40317 NOTREACHED() << "Trying to read an unregistered pref: " << path;
initial.commit09911bf2008-07-26 23:55:29318 return result;
319 }
320 bool rv = pref->GetValue()->GetAsBoolean(&result);
321 DCHECK(rv);
322 return result;
323}
324
325int PrefService::GetInteger(const wchar_t* path) const {
326 DCHECK(CalledOnValidThread());
327
328 int result = 0;
initial.commit09911bf2008-07-26 23:55:29329
330 const Preference* pref = FindPreference(path);
331 if (!pref) {
[email protected]b154e6f2009-03-06 01:52:40332 NOTREACHED() << "Trying to read an unregistered pref: " << path;
initial.commit09911bf2008-07-26 23:55:29333 return result;
334 }
335 bool rv = pref->GetValue()->GetAsInteger(&result);
336 DCHECK(rv);
337 return result;
338}
339
340double PrefService::GetReal(const wchar_t* path) const {
341 DCHECK(CalledOnValidThread());
342
343 double result = 0.0;
initial.commit09911bf2008-07-26 23:55:29344
345 const Preference* pref = FindPreference(path);
346 if (!pref) {
[email protected]b154e6f2009-03-06 01:52:40347 NOTREACHED() << "Trying to read an unregistered pref: " << path;
initial.commit09911bf2008-07-26 23:55:29348 return result;
349 }
350 bool rv = pref->GetValue()->GetAsReal(&result);
351 DCHECK(rv);
352 return result;
353}
354
[email protected]ddd231e2010-06-29 20:35:19355std::string PrefService::GetString(const wchar_t* path) const {
initial.commit09911bf2008-07-26 23:55:29356 DCHECK(CalledOnValidThread());
357
[email protected]ddd231e2010-06-29 20:35:19358 std::string result;
[email protected]8e50b602009-03-03 22:59:43359
initial.commit09911bf2008-07-26 23:55:29360 const Preference* pref = FindPreference(path);
361 if (!pref) {
[email protected]b154e6f2009-03-06 01:52:40362 NOTREACHED() << "Trying to read an unregistered pref: " << path;
initial.commit09911bf2008-07-26 23:55:29363 return result;
364 }
365 bool rv = pref->GetValue()->GetAsString(&result);
366 DCHECK(rv);
367 return result;
368}
369
[email protected]b9636002009-03-04 00:05:25370FilePath PrefService::GetFilePath(const wchar_t* path) const {
371 DCHECK(CalledOnValidThread());
372
373 FilePath::StringType result;
[email protected]b9636002009-03-04 00:05:25374
375 const Preference* pref = FindPreference(path);
376 if (!pref) {
[email protected]b154e6f2009-03-06 01:52:40377 NOTREACHED() << "Trying to read an unregistered pref: " << path;
[email protected]b9636002009-03-04 00:05:25378 return FilePath(result);
379 }
380 bool rv = pref->GetValue()->GetAsString(&result);
381 DCHECK(rv);
[email protected]66de4f092009-09-04 23:59:40382#if defined(OS_POSIX)
383 // We store filepaths as UTF8, so convert it back to the system type.
384 result = base::SysWideToNativeMB(UTF8ToWide(result));
385#endif
[email protected]b9636002009-03-04 00:05:25386 return FilePath(result);
387}
388
initial.commit09911bf2008-07-26 23:55:29389bool PrefService::HasPrefPath(const wchar_t* path) const {
[email protected]d8b08c92010-06-07 13:13:28390 return pref_value_store_->HasPrefPath(path);
initial.commit09911bf2008-07-26 23:55:29391}
392
393const PrefService::Preference* PrefService::FindPreference(
394 const wchar_t* pref_name) const {
395 DCHECK(CalledOnValidThread());
396 Preference p(NULL, pref_name, NULL);
397 PreferenceSet::const_iterator it = prefs_.find(&p);
398 return it == prefs_.end() ? NULL : *it;
399}
400
[email protected]db198b22010-07-12 16:48:49401void PrefService::FireObserversIfChanged(const wchar_t* path,
402 const Value* old_value) {
403 if (PrefIsChanged(path, old_value))
404 FireObservers(path);
405}
406
407bool PrefService::PrefIsChanged(const wchar_t* path,
408 const Value* old_value) {
409 Value* new_value = NULL;
410 pref_value_store_->GetValue(path, &new_value);
411 // Some unit tests have no values for certain prefs.
412 return (!new_value || !old_value->Equals(new_value));
413}
414
initial.commit09911bf2008-07-26 23:55:29415const DictionaryValue* PrefService::GetDictionary(const wchar_t* path) const {
416 DCHECK(CalledOnValidThread());
417
initial.commit09911bf2008-07-26 23:55:29418 const Preference* pref = FindPreference(path);
419 if (!pref) {
[email protected]b154e6f2009-03-06 01:52:40420 NOTREACHED() << "Trying to read an unregistered pref: " << path;
initial.commit09911bf2008-07-26 23:55:29421 return NULL;
422 }
423 const Value* value = pref->GetValue();
424 if (value->GetType() == Value::TYPE_NULL)
425 return NULL;
426 return static_cast<const DictionaryValue*>(value);
427}
428
429const ListValue* PrefService::GetList(const wchar_t* path) const {
430 DCHECK(CalledOnValidThread());
431
initial.commit09911bf2008-07-26 23:55:29432 const Preference* pref = FindPreference(path);
433 if (!pref) {
[email protected]b154e6f2009-03-06 01:52:40434 NOTREACHED() << "Trying to read an unregistered pref: " << path;
initial.commit09911bf2008-07-26 23:55:29435 return NULL;
436 }
437 const Value* value = pref->GetValue();
438 if (value->GetType() == Value::TYPE_NULL)
439 return NULL;
440 return static_cast<const ListValue*>(value);
441}
442
443void PrefService::AddPrefObserver(const wchar_t* path,
444 NotificationObserver* obs) {
445 DCHECK(CalledOnValidThread());
446
447 const Preference* pref = FindPreference(path);
448 if (!pref) {
[email protected]b154e6f2009-03-06 01:52:40449 NOTREACHED() << "Trying to add an observer for an unregistered pref: "
initial.commit09911bf2008-07-26 23:55:29450 << path;
451 return;
452 }
453
454 // Get the pref observer list associated with the path.
455 NotificationObserverList* observer_list = NULL;
456 PrefObserverMap::iterator observer_iterator = pref_observers_.find(path);
457 if (observer_iterator == pref_observers_.end()) {
458 observer_list = new NotificationObserverList;
459 pref_observers_[path] = observer_list;
460 } else {
461 observer_list = observer_iterator->second;
462 }
463
464 // Verify that this observer doesn't already exist.
465 NotificationObserverList::Iterator it(*observer_list);
466 NotificationObserver* existing_obs;
[email protected]933cc002008-11-21 20:50:39467 while ((existing_obs = it.GetNext()) != NULL) {
initial.commit09911bf2008-07-26 23:55:29468 DCHECK(existing_obs != obs) << path << " observer already registered";
469 if (existing_obs == obs)
470 return;
471 }
472
473 // Ok, safe to add the pref observer.
474 observer_list->AddObserver(obs);
475}
476
477void PrefService::RemovePrefObserver(const wchar_t* path,
478 NotificationObserver* obs) {
479 DCHECK(CalledOnValidThread());
480
481 PrefObserverMap::iterator observer_iterator = pref_observers_.find(path);
482 if (observer_iterator == pref_observers_.end()) {
483 return;
484 }
485
486 NotificationObserverList* observer_list = observer_iterator->second;
487 observer_list->RemoveObserver(obs);
488}
489
490void PrefService::RegisterPreference(Preference* pref) {
491 DCHECK(CalledOnValidThread());
492
493 if (FindPreference(pref->name().c_str())) {
[email protected]b154e6f2009-03-06 01:52:40494 NOTREACHED() << "Tried to register duplicate pref " << pref->name();
initial.commit09911bf2008-07-26 23:55:29495 delete pref;
496 return;
497 }
498 prefs_.insert(pref);
499}
500
501void PrefService::ClearPref(const wchar_t* path) {
502 DCHECK(CalledOnValidThread());
503
504 const Preference* pref = FindPreference(path);
505 if (!pref) {
[email protected]b154e6f2009-03-06 01:52:40506 NOTREACHED() << "Trying to clear an unregistered pref: " << path;
initial.commit09911bf2008-07-26 23:55:29507 return;
508 }
initial.commit09911bf2008-07-26 23:55:29509 Value* value;
[email protected]d8b08c92010-06-07 13:13:28510 bool has_old_value = pref_value_store_->GetValue(path, &value);
511 pref_value_store_->RemoveUserPrefValue(path);
initial.commit09911bf2008-07-26 23:55:29512
513 if (has_old_value)
514 FireObservers(path);
515}
516
[email protected]a048d7e42009-12-01 01:02:39517void PrefService::Set(const wchar_t* path, const Value& value) {
518 DCHECK(CalledOnValidThread());
519
520 const Preference* pref = FindPreference(path);
521 if (!pref) {
522 NOTREACHED() << "Trying to write an unregistered pref: " << path;
523 return;
524 }
[email protected]ecde2742010-04-02 17:36:18525
526 // Allow dictionary and list types to be set to null.
527 if (value.GetType() == Value::TYPE_NULL &&
528 (pref->type() == Value::TYPE_DICTIONARY ||
529 pref->type() == Value::TYPE_LIST)) {
530 scoped_ptr<Value> old_value(GetPrefCopy(path));
531 if (!old_value->Equals(&value)) {
[email protected]d8b08c92010-06-07 13:13:28532 pref_value_store_->RemoveUserPrefValue(path);
[email protected]ecde2742010-04-02 17:36:18533 FireObservers(path);
534 }
535 return;
536 }
537
[email protected]a048d7e42009-12-01 01:02:39538 if (pref->type() != value.GetType()) {
539 NOTREACHED() << "Wrong type for Set: " << path;
540 }
541
542 scoped_ptr<Value> old_value(GetPrefCopy(path));
[email protected]d8b08c92010-06-07 13:13:28543 pref_value_store_->SetUserPrefValue(path, value.DeepCopy());
[email protected]a048d7e42009-12-01 01:02:39544
545 FireObserversIfChanged(path, old_value.get());
546}
547
initial.commit09911bf2008-07-26 23:55:29548void PrefService::SetBoolean(const wchar_t* path, bool value) {
549 DCHECK(CalledOnValidThread());
550
551 const Preference* pref = FindPreference(path);
552 if (!pref) {
[email protected]b154e6f2009-03-06 01:52:40553 NOTREACHED() << "Trying to write an unregistered pref: " << path;
initial.commit09911bf2008-07-26 23:55:29554 return;
555 }
[email protected]91ae7e32010-04-23 12:58:50556 if (pref->IsManaged()) {
557 NOTREACHED() << "Preference is managed: " << path;
558 return;
559 }
initial.commit09911bf2008-07-26 23:55:29560 if (pref->type() != Value::TYPE_BOOLEAN) {
[email protected]b154e6f2009-03-06 01:52:40561 NOTREACHED() << "Wrong type for SetBoolean: " << path;
initial.commit09911bf2008-07-26 23:55:29562 return;
563 }
564
565 scoped_ptr<Value> old_value(GetPrefCopy(path));
[email protected]d8b08c92010-06-07 13:13:28566 Value* new_value = Value::CreateBooleanValue(value);
567 pref_value_store_->SetUserPrefValue(path, new_value);
initial.commit09911bf2008-07-26 23:55:29568
569 FireObserversIfChanged(path, old_value.get());
570}
571
572void PrefService::SetInteger(const wchar_t* path, int value) {
573 DCHECK(CalledOnValidThread());
574
575 const Preference* pref = FindPreference(path);
576 if (!pref) {
[email protected]b154e6f2009-03-06 01:52:40577 NOTREACHED() << "Trying to write an unregistered pref: " << path;
initial.commit09911bf2008-07-26 23:55:29578 return;
579 }
[email protected]91ae7e32010-04-23 12:58:50580 if (pref->IsManaged()) {
581 NOTREACHED() << "Preference is managed: " << path;
582 return;
583 }
initial.commit09911bf2008-07-26 23:55:29584 if (pref->type() != Value::TYPE_INTEGER) {
[email protected]b154e6f2009-03-06 01:52:40585 NOTREACHED() << "Wrong type for SetInteger: " << path;
initial.commit09911bf2008-07-26 23:55:29586 return;
587 }
588
589 scoped_ptr<Value> old_value(GetPrefCopy(path));
[email protected]d8b08c92010-06-07 13:13:28590 Value* new_value = Value::CreateIntegerValue(value);
591 pref_value_store_->SetUserPrefValue(path, new_value);
initial.commit09911bf2008-07-26 23:55:29592
593 FireObserversIfChanged(path, old_value.get());
594}
595
596void PrefService::SetReal(const wchar_t* path, double value) {
597 DCHECK(CalledOnValidThread());
598
599 const Preference* pref = FindPreference(path);
600 if (!pref) {
[email protected]b154e6f2009-03-06 01:52:40601 NOTREACHED() << "Trying to write an unregistered pref: " << path;
initial.commit09911bf2008-07-26 23:55:29602 return;
603 }
[email protected]91ae7e32010-04-23 12:58:50604 if (pref->IsManaged()) {
605 NOTREACHED() << "Preference is managed: " << path;
606 return;
607 }
initial.commit09911bf2008-07-26 23:55:29608 if (pref->type() != Value::TYPE_REAL) {
[email protected]b154e6f2009-03-06 01:52:40609 NOTREACHED() << "Wrong type for SetReal: " << path;
initial.commit09911bf2008-07-26 23:55:29610 return;
611 }
612
613 scoped_ptr<Value> old_value(GetPrefCopy(path));
[email protected]d8b08c92010-06-07 13:13:28614 Value* new_value = Value::CreateRealValue(value);
615 pref_value_store_->SetUserPrefValue(path, new_value);
initial.commit09911bf2008-07-26 23:55:29616
617 FireObserversIfChanged(path, old_value.get());
618}
619
[email protected]ddd231e2010-06-29 20:35:19620void PrefService::SetString(const wchar_t* path, const std::string& value) {
initial.commit09911bf2008-07-26 23:55:29621 DCHECK(CalledOnValidThread());
622
623 const Preference* pref = FindPreference(path);
624 if (!pref) {
[email protected]b154e6f2009-03-06 01:52:40625 NOTREACHED() << "Trying to write an unregistered pref: " << path;
initial.commit09911bf2008-07-26 23:55:29626 return;
627 }
[email protected]91ae7e32010-04-23 12:58:50628 if (pref->IsManaged()) {
629 NOTREACHED() << "Preference is managed: " << path;
630 return;
631 }
initial.commit09911bf2008-07-26 23:55:29632 if (pref->type() != Value::TYPE_STRING) {
[email protected]b154e6f2009-03-06 01:52:40633 NOTREACHED() << "Wrong type for SetString: " << path;
initial.commit09911bf2008-07-26 23:55:29634 return;
635 }
636
637 scoped_ptr<Value> old_value(GetPrefCopy(path));
[email protected]d8b08c92010-06-07 13:13:28638 Value* new_value = Value::CreateStringValue(value);
639 pref_value_store_->SetUserPrefValue(path, new_value);
initial.commit09911bf2008-07-26 23:55:29640
641 FireObserversIfChanged(path, old_value.get());
642}
643
[email protected]b9636002009-03-04 00:05:25644void PrefService::SetFilePath(const wchar_t* path, const FilePath& value) {
645 DCHECK(CalledOnValidThread());
646
647 const Preference* pref = FindPreference(path);
648 if (!pref) {
[email protected]b154e6f2009-03-06 01:52:40649 NOTREACHED() << "Trying to write an unregistered pref: " << path;
[email protected]b9636002009-03-04 00:05:25650 return;
651 }
[email protected]91ae7e32010-04-23 12:58:50652 if (pref->IsManaged()) {
653 NOTREACHED() << "Preference is managed: " << path;
654 return;
655 }
[email protected]b9636002009-03-04 00:05:25656 if (pref->type() != Value::TYPE_STRING) {
[email protected]b154e6f2009-03-06 01:52:40657 NOTREACHED() << "Wrong type for SetFilePath: " << path;
[email protected]b9636002009-03-04 00:05:25658 return;
659 }
660
661 scoped_ptr<Value> old_value(GetPrefCopy(path));
[email protected]66de4f092009-09-04 23:59:40662#if defined(OS_POSIX)
663 // Value::SetString only knows about UTF8 strings, so convert the path from
664 // the system native value to UTF8.
665 std::string path_utf8 = WideToUTF8(base::SysNativeMBToWide(value.value()));
[email protected]d8b08c92010-06-07 13:13:28666 Value* new_value = Value::CreateStringValue(path_utf8);
667 pref_value_store_->SetUserPrefValue(path, new_value);
[email protected]66de4f092009-09-04 23:59:40668#else
[email protected]d8b08c92010-06-07 13:13:28669 Value* new_value = Value::CreateStringValue(value.value());
670 pref_value_store_->SetUserPrefValue(path, new_value);
[email protected]66de4f092009-09-04 23:59:40671#endif
[email protected]b9636002009-03-04 00:05:25672
673 FireObserversIfChanged(path, old_value.get());
674}
675
[email protected]0bb1a622009-03-04 03:22:32676void PrefService::SetInt64(const wchar_t* path, int64 value) {
677 DCHECK(CalledOnValidThread());
678
679 const Preference* pref = FindPreference(path);
680 if (!pref) {
[email protected]b154e6f2009-03-06 01:52:40681 NOTREACHED() << "Trying to write an unregistered pref: " << path;
[email protected]0bb1a622009-03-04 03:22:32682 return;
683 }
[email protected]91ae7e32010-04-23 12:58:50684 if (pref->IsManaged()) {
685 NOTREACHED() << "Preference is managed: " << path;
686 return;
687 }
[email protected]0bb1a622009-03-04 03:22:32688 if (pref->type() != Value::TYPE_STRING) {
[email protected]b154e6f2009-03-06 01:52:40689 NOTREACHED() << "Wrong type for SetInt64: " << path;
[email protected]0bb1a622009-03-04 03:22:32690 return;
691 }
692
693 scoped_ptr<Value> old_value(GetPrefCopy(path));
[email protected]d8b08c92010-06-07 13:13:28694 Value* new_value = Value::CreateStringValue(Int64ToWString(value));
695 pref_value_store_->SetUserPrefValue(path, new_value);
[email protected]0bb1a622009-03-04 03:22:32696
697 FireObserversIfChanged(path, old_value.get());
698}
699
700int64 PrefService::GetInt64(const wchar_t* path) const {
701 DCHECK(CalledOnValidThread());
702
[email protected]0bb1a622009-03-04 03:22:32703 const Preference* pref = FindPreference(path);
704 if (!pref) {
[email protected]b154e6f2009-03-06 01:52:40705 NOTREACHED() << "Trying to read an unregistered pref: " << path;
[email protected]c3453302009-12-01 01:33:08706 return 0;
[email protected]0bb1a622009-03-04 03:22:32707 }
[email protected]c3453302009-12-01 01:33:08708 std::wstring result(L"0");
[email protected]0bb1a622009-03-04 03:22:32709 bool rv = pref->GetValue()->GetAsString(&result);
710 DCHECK(rv);
711 return StringToInt64(WideToUTF16Hack(result));
712}
713
714void PrefService::RegisterInt64Pref(const wchar_t* path, int64 default_value) {
[email protected]d8b08c92010-06-07 13:13:28715 Preference* pref = new Preference(pref_value_store_.get(), path,
[email protected]0bb1a622009-03-04 03:22:32716 Value::CreateStringValue(Int64ToWString(default_value)));
717 RegisterPreference(pref);
718}
719
initial.commit09911bf2008-07-26 23:55:29720DictionaryValue* PrefService::GetMutableDictionary(const wchar_t* path) {
721 DCHECK(CalledOnValidThread());
722
723 const Preference* pref = FindPreference(path);
724 if (!pref) {
[email protected]b154e6f2009-03-06 01:52:40725 NOTREACHED() << "Trying to get an unregistered pref: " << path;
initial.commit09911bf2008-07-26 23:55:29726 return NULL;
727 }
728 if (pref->type() != Value::TYPE_DICTIONARY) {
[email protected]b154e6f2009-03-06 01:52:40729 NOTREACHED() << "Wrong type for GetMutableDictionary: " << path;
initial.commit09911bf2008-07-26 23:55:29730 return NULL;
731 }
732
733 DictionaryValue* dict = NULL;
[email protected]d8b08c92010-06-07 13:13:28734 Value* tmp_value = NULL;
[email protected]91761242010-06-10 15:35:37735 if (!pref_value_store_->GetValue(path, &tmp_value) ||
736 !tmp_value->IsType(Value::TYPE_DICTIONARY)) {
initial.commit09911bf2008-07-26 23:55:29737 dict = new DictionaryValue;
[email protected]d8b08c92010-06-07 13:13:28738 pref_value_store_->SetUserPrefValue(path, dict);
739 } else {
740 dict = static_cast<DictionaryValue*>(tmp_value);
initial.commit09911bf2008-07-26 23:55:29741 }
742 return dict;
743}
744
745ListValue* PrefService::GetMutableList(const wchar_t* path) {
746 DCHECK(CalledOnValidThread());
747
748 const Preference* pref = FindPreference(path);
749 if (!pref) {
[email protected]b154e6f2009-03-06 01:52:40750 NOTREACHED() << "Trying to get an unregistered pref: " << path;
initial.commit09911bf2008-07-26 23:55:29751 return NULL;
752 }
753 if (pref->type() != Value::TYPE_LIST) {
[email protected]b154e6f2009-03-06 01:52:40754 NOTREACHED() << "Wrong type for GetMutableList: " << path;
initial.commit09911bf2008-07-26 23:55:29755 return NULL;
756 }
757
758 ListValue* list = NULL;
[email protected]d8b08c92010-06-07 13:13:28759 Value* tmp_value = NULL;
760 if (!pref_value_store_->GetValue(path, &tmp_value)) {
initial.commit09911bf2008-07-26 23:55:29761 list = new ListValue;
[email protected]d8b08c92010-06-07 13:13:28762 pref_value_store_->SetUserPrefValue(path, list);
763 } else {
764 list = static_cast<ListValue*>(tmp_value);
initial.commit09911bf2008-07-26 23:55:29765 }
766 return list;
767}
768
769Value* PrefService::GetPrefCopy(const wchar_t* path) {
770 DCHECK(CalledOnValidThread());
771
772 const Preference* pref = FindPreference(path);
773 DCHECK(pref);
774 return pref->GetValue()->DeepCopy();
775}
776
initial.commit09911bf2008-07-26 23:55:29777void PrefService::FireObservers(const wchar_t* path) {
778 DCHECK(CalledOnValidThread());
779
780 // Convert path to a std::wstring because the Details constructor requires a
781 // class.
782 std::wstring path_str(path);
783 PrefObserverMap::iterator observer_iterator = pref_observers_.find(path_str);
784 if (observer_iterator == pref_observers_.end())
785 return;
786
787 NotificationObserverList::Iterator it(*(observer_iterator->second));
788 NotificationObserver* observer;
[email protected]933cc002008-11-21 20:50:39789 while ((observer = it.GetNext()) != NULL) {
[email protected]bfd04a62009-02-01 18:16:56790 observer->Observe(NotificationType::PREF_CHANGED,
initial.commit09911bf2008-07-26 23:55:29791 Source<PrefService>(this),
792 Details<std::wstring>(&path_str));
793 }
794}
795
796///////////////////////////////////////////////////////////////////////////////
797// PrefService::Preference
798
[email protected]d8b08c92010-06-07 13:13:28799PrefService::Preference::Preference(PrefValueStore* pref_value_store,
initial.commit09911bf2008-07-26 23:55:29800 const wchar_t* name,
801 Value* default_value)
[email protected]933cc002008-11-21 20:50:39802 : type_(Value::TYPE_NULL),
initial.commit09911bf2008-07-26 23:55:29803 name_(name),
804 default_value_(default_value),
[email protected]d8b08c92010-06-07 13:13:28805 pref_value_store_(pref_value_store) {
initial.commit09911bf2008-07-26 23:55:29806 DCHECK(name);
807
808 if (default_value) {
809 type_ = default_value->GetType();
810 DCHECK(type_ != Value::TYPE_NULL && type_ != Value::TYPE_BINARY) <<
811 "invalid preference type: " << type_;
812 }
813
814 // We set the default value of lists and dictionaries to be null so it's
815 // easier for callers to check for empty list/dict prefs.
816 if (Value::TYPE_LIST == type_ || Value::TYPE_DICTIONARY == type_)
817 default_value_.reset(Value::CreateNullValue());
818}
819
820const Value* PrefService::Preference::GetValue() const {
[email protected]d8b08c92010-06-07 13:13:28821 DCHECK(NULL != pref_value_store_) <<
initial.commit09911bf2008-07-26 23:55:29822 "Must register pref before getting its value";
823
824 Value* temp_value = NULL;
[email protected]d8b08c92010-06-07 13:13:28825 if (pref_value_store_->GetValue(name_, &temp_value) &&
initial.commit09911bf2008-07-26 23:55:29826 temp_value->GetType() == type_) {
827 return temp_value;
828 }
829
830 // Pref not found, just return the app default.
831 return default_value_.get();
832}
833
834bool PrefService::Preference::IsDefaultValue() const {
835 DCHECK(default_value_.get());
836 return default_value_->Equals(GetValue());
837}
[email protected]d8b08c92010-06-07 13:13:28838
839bool PrefService::Preference::IsManaged() const {
[email protected]d7449e82010-07-14 11:42:35840 return pref_value_store_->PrefValueInManagedStore(name_.c_str());
[email protected]d8b08c92010-06-07 13:13:28841}
842
[email protected]d7449e82010-07-14 11:42:35843bool PrefService::Preference::HasExtensionSetting() const {
844 return pref_value_store_->PrefValueInExtensionStore(name_.c_str());
845}
846
847bool PrefService::Preference::HasUserSetting() const {
848 return pref_value_store_->PrefValueInUserStore(name_.c_str());
849}
850
851bool PrefService::Preference::IsExtensionControlled() const {
852 return pref_value_store_->PrefValueFromExtensionStore(name_.c_str());
853}
854
855bool PrefService::Preference::IsUserControlled() const {
856 return pref_value_store_->PrefValueFromUserStore(name_.c_str());
857}