blob: 989d43885e41cd2b6763e94f6b30de6f0f72890e [file] [log] [blame]
license.botbf09a502008-08-24 00:55:551// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
2// 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
5#include "chrome/common/pref_service.h"
6
[email protected]a92b8642009-05-05 23:38:567#include "app/l10n_util.h"
initial.commit09911bf2008-07-26 23:55:298#include "base/logging.h"
9#include "base/message_loop.h"
[email protected]807204142009-05-05 03:31:4410#include "base/stl_util-inl.h"
initial.commit09911bf2008-07-26 23:55:2911#include "base/string_util.h"
[email protected]66de4f092009-09-04 23:59:4012#include "base/sys_string_conversions.h"
initial.commit09911bf2008-07-26 23:55:2913#include "base/thread.h"
[email protected]66de4f092009-09-04 23:59:4014#include "build/build_config.h"
initial.commit09911bf2008-07-26 23:55:2915#include "chrome/common/json_value_serializer.h"
initial.commit09911bf2008-07-26 23:55:2916#include "chrome/common/notification_service.h"
[email protected]34ac8f32009-02-22 23:03:2717#include "grit/generated_resources.h"
initial.commit09911bf2008-07-26 23:55:2918
19namespace {
20
initial.commit09911bf2008-07-26 23:55:2921// A helper function for RegisterLocalized*Pref that creates a Value* based on
22// the string value in the locale dll. Because we control the values in a
23// locale dll, this should always return a Value of the appropriate type.
24Value* CreateLocaleDefaultValue(Value::ValueType type, int message_id) {
25 std::wstring resource_string = l10n_util::GetString(message_id);
26 DCHECK(!resource_string.empty());
27 switch (type) {
28 case Value::TYPE_BOOLEAN: {
29 if (L"true" == resource_string)
30 return Value::CreateBooleanValue(true);
31 if (L"false" == resource_string)
32 return Value::CreateBooleanValue(false);
33 break;
34 }
35
36 case Value::TYPE_INTEGER: {
[email protected]41fb1d72009-02-28 01:01:5037 return Value::CreateIntegerValue(
38 StringToInt(WideToUTF16Hack(resource_string)));
initial.commit09911bf2008-07-26 23:55:2939 break;
40 }
41
42 case Value::TYPE_REAL: {
[email protected]41fb1d72009-02-28 01:01:5043 return Value::CreateRealValue(
44 StringToDouble(WideToUTF16Hack(resource_string)));
initial.commit09911bf2008-07-26 23:55:2945 break;
46 }
47
48 case Value::TYPE_STRING: {
49 return Value::CreateStringValue(resource_string);
50 break;
51 }
52
53 default: {
[email protected]b154e6f2009-03-06 01:52:4054 NOTREACHED() <<
initial.commit09911bf2008-07-26 23:55:2955 "list and dictionary types can not have default locale values";
56 }
57 }
58 NOTREACHED();
59 return Value::CreateNullValue();
60}
61
62} // namespace
63
[email protected]6faa0e0d2009-04-28 06:50:3664PrefService::PrefService(const FilePath& pref_filename,
65 const base::Thread* backend_thread)
initial.commit09911bf2008-07-26 23:55:2966 : persistent_(new DictionaryValue),
67 transient_(new DictionaryValue),
[email protected]6faa0e0d2009-04-28 06:50:3668 writer_(pref_filename, backend_thread) {
69 ReloadPersistentPrefs();
initial.commit09911bf2008-07-26 23:55:2970}
71
72PrefService::~PrefService() {
73 DCHECK(CalledOnValidThread());
74
75 // Verify that there are no pref observers when we shut down.
76 for (PrefObserverMap::iterator it = pref_observers_.begin();
77 it != pref_observers_.end(); ++it) {
78 NotificationObserverList::Iterator obs_iterator(*(it->second));
79 if (obs_iterator.GetNext()) {
80 LOG(WARNING) << "pref observer found at shutdown " << it->first;
81 }
82 }
83
84 STLDeleteContainerPointers(prefs_.begin(), prefs_.end());
85 prefs_.clear();
86 STLDeleteContainerPairSecondPointers(pref_observers_.begin(),
87 pref_observers_.end());
88 pref_observers_.clear();
[email protected]6c1164042009-05-08 14:41:0889
90 if (writer_.HasPendingWrite())
91 writer_.DoScheduledWrite();
initial.commit09911bf2008-07-26 23:55:2992}
93
[email protected]6faa0e0d2009-04-28 06:50:3694bool PrefService::ReloadPersistentPrefs() {
initial.commit09911bf2008-07-26 23:55:2995 DCHECK(CalledOnValidThread());
96
[email protected]6faa0e0d2009-04-28 06:50:3697 JSONFileValueSerializer serializer(writer_.path());
[email protected]b4cebf82008-12-29 19:59:0898 scoped_ptr<Value> root(serializer.Deserialize(NULL));
99 if (!root.get())
100 return false;
initial.commit09911bf2008-07-26 23:55:29101
[email protected]b4cebf82008-12-29 19:59:08102 // Preferences should always have a dictionary root.
103 if (!root->IsType(Value::TYPE_DICTIONARY))
104 return false;
initial.commit09911bf2008-07-26 23:55:29105
[email protected]b4cebf82008-12-29 19:59:08106 persistent_.reset(static_cast<DictionaryValue*>(root.release()));
[email protected]b4cebf82008-12-29 19:59:08107 for (PreferenceSet::iterator it = prefs_.begin();
108 it != prefs_.end(); ++it) {
109 (*it)->root_pref_ = persistent_.get();
initial.commit09911bf2008-07-26 23:55:29110 }
initial.commit09911bf2008-07-26 23:55:29111
initial.commit09911bf2008-07-26 23:55:29112 return true;
113}
114
[email protected]6faa0e0d2009-04-28 06:50:36115bool PrefService::SavePersistentPrefs() {
116 DCHECK(CalledOnValidThread());
initial.commit09911bf2008-07-26 23:55:29117
[email protected]6faa0e0d2009-04-28 06:50:36118 std::string data;
[email protected]6c1164042009-05-08 14:41:08119 if (!SerializeData(&data))
[email protected]6faa0e0d2009-04-28 06:50:36120 return false;
121
122 writer_.WriteNow(data);
123 return true;
124}
125
[email protected]6c1164042009-05-08 14:41:08126void PrefService::ScheduleSavePersistentPrefs() {
[email protected]6faa0e0d2009-04-28 06:50:36127 DCHECK(CalledOnValidThread());
[email protected]6c1164042009-05-08 14:41:08128 writer_.ScheduleWrite(this);
initial.commit09911bf2008-07-26 23:55:29129}
130
131void PrefService::RegisterBooleanPref(const wchar_t* path,
132 bool default_value) {
133 Preference* pref = new Preference(persistent_.get(), path,
134 Value::CreateBooleanValue(default_value));
135 RegisterPreference(pref);
136}
137
138void PrefService::RegisterIntegerPref(const wchar_t* path,
139 int default_value) {
140 Preference* pref = new Preference(persistent_.get(), path,
141 Value::CreateIntegerValue(default_value));
142 RegisterPreference(pref);
143}
144
145void PrefService::RegisterRealPref(const wchar_t* path,
146 double default_value) {
147 Preference* pref = new Preference(persistent_.get(), path,
148 Value::CreateRealValue(default_value));
149 RegisterPreference(pref);
150}
151
152void PrefService::RegisterStringPref(const wchar_t* path,
153 const std::wstring& default_value) {
154 Preference* pref = new Preference(persistent_.get(), path,
155 Value::CreateStringValue(default_value));
156 RegisterPreference(pref);
157}
158
[email protected]b9636002009-03-04 00:05:25159void PrefService::RegisterFilePathPref(const wchar_t* path,
160 const FilePath& default_value) {
161 Preference* pref = new Preference(persistent_.get(), path,
162 Value::CreateStringValue(default_value.value()));
163 RegisterPreference(pref);
164}
165
initial.commit09911bf2008-07-26 23:55:29166void PrefService::RegisterListPref(const wchar_t* path) {
167 Preference* pref = new Preference(persistent_.get(), path,
168 new ListValue);
169 RegisterPreference(pref);
170}
171
172void PrefService::RegisterDictionaryPref(const wchar_t* path) {
173 Preference* pref = new Preference(persistent_.get(), path,
174 new DictionaryValue());
175 RegisterPreference(pref);
176}
177
178void PrefService::RegisterLocalizedBooleanPref(const wchar_t* path,
179 int locale_default_message_id) {
180 Preference* pref = new Preference(persistent_.get(), path,
181 CreateLocaleDefaultValue(Value::TYPE_BOOLEAN, locale_default_message_id));
182 RegisterPreference(pref);
183}
184
185void PrefService::RegisterLocalizedIntegerPref(const wchar_t* path,
186 int locale_default_message_id) {
187 Preference* pref = new Preference(persistent_.get(), path,
188 CreateLocaleDefaultValue(Value::TYPE_INTEGER, locale_default_message_id));
189 RegisterPreference(pref);
190}
191
192void PrefService::RegisterLocalizedRealPref(const wchar_t* path,
193 int locale_default_message_id) {
194 Preference* pref = new Preference(persistent_.get(), path,
195 CreateLocaleDefaultValue(Value::TYPE_REAL, locale_default_message_id));
196 RegisterPreference(pref);
197}
198
199void PrefService::RegisterLocalizedStringPref(const wchar_t* path,
200 int locale_default_message_id) {
201 Preference* pref = new Preference(persistent_.get(), path,
202 CreateLocaleDefaultValue(Value::TYPE_STRING, locale_default_message_id));
203 RegisterPreference(pref);
204}
205
206bool PrefService::IsPrefRegistered(const wchar_t* path) {
207 DCHECK(CalledOnValidThread());
208 // TODO(tc): We can remove this method and just use FindPreference.
209 return FindPreference(path) ? true : false;
210}
211
212bool PrefService::GetBoolean(const wchar_t* path) const {
213 DCHECK(CalledOnValidThread());
214
215 bool result = false;
[email protected]8e50b602009-03-03 22:59:43216 if (transient_->GetBoolean(path, &result))
initial.commit09911bf2008-07-26 23:55:29217 return result;
218
219 const Preference* pref = FindPreference(path);
220 if (!pref) {
[email protected]b154e6f2009-03-06 01:52:40221 NOTREACHED() << "Trying to read an unregistered pref: " << path;
initial.commit09911bf2008-07-26 23:55:29222 return result;
223 }
224 bool rv = pref->GetValue()->GetAsBoolean(&result);
225 DCHECK(rv);
226 return result;
227}
228
229int PrefService::GetInteger(const wchar_t* path) const {
230 DCHECK(CalledOnValidThread());
231
232 int result = 0;
[email protected]8e50b602009-03-03 22:59:43233 if (transient_->GetInteger(path, &result))
initial.commit09911bf2008-07-26 23:55:29234 return result;
235
236 const Preference* pref = FindPreference(path);
237 if (!pref) {
[email protected]b154e6f2009-03-06 01:52:40238 NOTREACHED() << "Trying to read an unregistered pref: " << path;
initial.commit09911bf2008-07-26 23:55:29239 return result;
240 }
241 bool rv = pref->GetValue()->GetAsInteger(&result);
242 DCHECK(rv);
243 return result;
244}
245
246double PrefService::GetReal(const wchar_t* path) const {
247 DCHECK(CalledOnValidThread());
248
249 double result = 0.0;
[email protected]8e50b602009-03-03 22:59:43250 if (transient_->GetReal(path, &result))
initial.commit09911bf2008-07-26 23:55:29251 return result;
252
253 const Preference* pref = FindPreference(path);
254 if (!pref) {
[email protected]b154e6f2009-03-06 01:52:40255 NOTREACHED() << "Trying to read an unregistered pref: " << path;
initial.commit09911bf2008-07-26 23:55:29256 return result;
257 }
258 bool rv = pref->GetValue()->GetAsReal(&result);
259 DCHECK(rv);
260 return result;
261}
262
263std::wstring PrefService::GetString(const wchar_t* path) const {
264 DCHECK(CalledOnValidThread());
265
[email protected]3a79b3c2009-03-03 21:49:53266 std::wstring result;
[email protected]8e50b602009-03-03 22:59:43267 if (transient_->GetString(path, &result))
268 return result;
269
initial.commit09911bf2008-07-26 23:55:29270 const Preference* pref = FindPreference(path);
271 if (!pref) {
[email protected]b154e6f2009-03-06 01:52:40272 NOTREACHED() << "Trying to read an unregistered pref: " << path;
initial.commit09911bf2008-07-26 23:55:29273 return result;
274 }
275 bool rv = pref->GetValue()->GetAsString(&result);
276 DCHECK(rv);
277 return result;
278}
279
[email protected]b9636002009-03-04 00:05:25280FilePath PrefService::GetFilePath(const wchar_t* path) const {
281 DCHECK(CalledOnValidThread());
282
283 FilePath::StringType result;
284 if (transient_->GetString(path, &result))
285 return FilePath(result);
286
287 const Preference* pref = FindPreference(path);
288 if (!pref) {
[email protected]b154e6f2009-03-06 01:52:40289 NOTREACHED() << "Trying to read an unregistered pref: " << path;
[email protected]b9636002009-03-04 00:05:25290 return FilePath(result);
291 }
292 bool rv = pref->GetValue()->GetAsString(&result);
293 DCHECK(rv);
[email protected]66de4f092009-09-04 23:59:40294#if defined(OS_POSIX)
295 // We store filepaths as UTF8, so convert it back to the system type.
296 result = base::SysWideToNativeMB(UTF8ToWide(result));
297#endif
[email protected]b9636002009-03-04 00:05:25298 return FilePath(result);
299}
300
initial.commit09911bf2008-07-26 23:55:29301bool PrefService::HasPrefPath(const wchar_t* path) const {
302 Value* value = NULL;
[email protected]8e50b602009-03-03 22:59:43303 return (transient_->Get(path, &value) || persistent_->Get(path, &value));
initial.commit09911bf2008-07-26 23:55:29304}
305
306const PrefService::Preference* PrefService::FindPreference(
307 const wchar_t* pref_name) const {
308 DCHECK(CalledOnValidThread());
309 Preference p(NULL, pref_name, NULL);
310 PreferenceSet::const_iterator it = prefs_.find(&p);
311 return it == prefs_.end() ? NULL : *it;
312}
313
314const DictionaryValue* PrefService::GetDictionary(const wchar_t* path) const {
315 DCHECK(CalledOnValidThread());
316
317 DictionaryValue* result = NULL;
[email protected]8e50b602009-03-03 22:59:43318 if (transient_->GetDictionary(path, &result))
initial.commit09911bf2008-07-26 23:55:29319 return result;
320
321 const Preference* pref = FindPreference(path);
322 if (!pref) {
[email protected]b154e6f2009-03-06 01:52:40323 NOTREACHED() << "Trying to read an unregistered pref: " << path;
initial.commit09911bf2008-07-26 23:55:29324 return NULL;
325 }
326 const Value* value = pref->GetValue();
327 if (value->GetType() == Value::TYPE_NULL)
328 return NULL;
329 return static_cast<const DictionaryValue*>(value);
330}
331
332const ListValue* PrefService::GetList(const wchar_t* path) const {
333 DCHECK(CalledOnValidThread());
334
335 ListValue* result = NULL;
[email protected]8e50b602009-03-03 22:59:43336 if (transient_->GetList(path, &result))
initial.commit09911bf2008-07-26 23:55:29337 return result;
338
339 const Preference* pref = FindPreference(path);
340 if (!pref) {
[email protected]b154e6f2009-03-06 01:52:40341 NOTREACHED() << "Trying to read an unregistered pref: " << path;
initial.commit09911bf2008-07-26 23:55:29342 return NULL;
343 }
344 const Value* value = pref->GetValue();
345 if (value->GetType() == Value::TYPE_NULL)
346 return NULL;
347 return static_cast<const ListValue*>(value);
348}
349
350void PrefService::AddPrefObserver(const wchar_t* path,
351 NotificationObserver* obs) {
352 DCHECK(CalledOnValidThread());
353
354 const Preference* pref = FindPreference(path);
355 if (!pref) {
[email protected]b154e6f2009-03-06 01:52:40356 NOTREACHED() << "Trying to add an observer for an unregistered pref: "
initial.commit09911bf2008-07-26 23:55:29357 << path;
358 return;
359 }
360
361 // Get the pref observer list associated with the path.
362 NotificationObserverList* observer_list = NULL;
363 PrefObserverMap::iterator observer_iterator = pref_observers_.find(path);
364 if (observer_iterator == pref_observers_.end()) {
365 observer_list = new NotificationObserverList;
366 pref_observers_[path] = observer_list;
367 } else {
368 observer_list = observer_iterator->second;
369 }
370
371 // Verify that this observer doesn't already exist.
372 NotificationObserverList::Iterator it(*observer_list);
373 NotificationObserver* existing_obs;
[email protected]933cc002008-11-21 20:50:39374 while ((existing_obs = it.GetNext()) != NULL) {
initial.commit09911bf2008-07-26 23:55:29375 DCHECK(existing_obs != obs) << path << " observer already registered";
376 if (existing_obs == obs)
377 return;
378 }
379
380 // Ok, safe to add the pref observer.
381 observer_list->AddObserver(obs);
382}
383
384void PrefService::RemovePrefObserver(const wchar_t* path,
385 NotificationObserver* obs) {
386 DCHECK(CalledOnValidThread());
387
388 PrefObserverMap::iterator observer_iterator = pref_observers_.find(path);
389 if (observer_iterator == pref_observers_.end()) {
390 return;
391 }
392
393 NotificationObserverList* observer_list = observer_iterator->second;
394 observer_list->RemoveObserver(obs);
395}
396
397void PrefService::RegisterPreference(Preference* pref) {
398 DCHECK(CalledOnValidThread());
399
400 if (FindPreference(pref->name().c_str())) {
[email protected]b154e6f2009-03-06 01:52:40401 NOTREACHED() << "Tried to register duplicate pref " << pref->name();
initial.commit09911bf2008-07-26 23:55:29402 delete pref;
403 return;
404 }
405 prefs_.insert(pref);
406}
407
408void PrefService::ClearPref(const wchar_t* path) {
409 DCHECK(CalledOnValidThread());
410
411 const Preference* pref = FindPreference(path);
412 if (!pref) {
[email protected]b154e6f2009-03-06 01:52:40413 NOTREACHED() << "Trying to clear an unregistered pref: " << path;
initial.commit09911bf2008-07-26 23:55:29414 return;
415 }
416
[email protected]8e50b602009-03-03 22:59:43417 transient_->Remove(path, NULL);
initial.commit09911bf2008-07-26 23:55:29418 Value* value;
[email protected]8e50b602009-03-03 22:59:43419 bool has_old_value = persistent_->Get(path, &value);
420 persistent_->Remove(path, NULL);
initial.commit09911bf2008-07-26 23:55:29421
422 if (has_old_value)
423 FireObservers(path);
424}
425
426void PrefService::SetBoolean(const wchar_t* path, bool value) {
427 DCHECK(CalledOnValidThread());
428
429 const Preference* pref = FindPreference(path);
430 if (!pref) {
[email protected]b154e6f2009-03-06 01:52:40431 NOTREACHED() << "Trying to write an unregistered pref: " << path;
initial.commit09911bf2008-07-26 23:55:29432 return;
433 }
434 if (pref->type() != Value::TYPE_BOOLEAN) {
[email protected]b154e6f2009-03-06 01:52:40435 NOTREACHED() << "Wrong type for SetBoolean: " << path;
initial.commit09911bf2008-07-26 23:55:29436 return;
437 }
438
439 scoped_ptr<Value> old_value(GetPrefCopy(path));
[email protected]8e50b602009-03-03 22:59:43440 bool rv = persistent_->SetBoolean(path, value);
initial.commit09911bf2008-07-26 23:55:29441 DCHECK(rv);
442
443 FireObserversIfChanged(path, old_value.get());
444}
445
446void PrefService::SetInteger(const wchar_t* path, int value) {
447 DCHECK(CalledOnValidThread());
448
449 const Preference* pref = FindPreference(path);
450 if (!pref) {
[email protected]b154e6f2009-03-06 01:52:40451 NOTREACHED() << "Trying to write an unregistered pref: " << path;
initial.commit09911bf2008-07-26 23:55:29452 return;
453 }
454 if (pref->type() != Value::TYPE_INTEGER) {
[email protected]b154e6f2009-03-06 01:52:40455 NOTREACHED() << "Wrong type for SetInteger: " << path;
initial.commit09911bf2008-07-26 23:55:29456 return;
457 }
458
459 scoped_ptr<Value> old_value(GetPrefCopy(path));
[email protected]8e50b602009-03-03 22:59:43460 bool rv = persistent_->SetInteger(path, value);
initial.commit09911bf2008-07-26 23:55:29461 DCHECK(rv);
462
463 FireObserversIfChanged(path, old_value.get());
464}
465
466void PrefService::SetReal(const wchar_t* path, double value) {
467 DCHECK(CalledOnValidThread());
468
469 const Preference* pref = FindPreference(path);
470 if (!pref) {
[email protected]b154e6f2009-03-06 01:52:40471 NOTREACHED() << "Trying to write an unregistered pref: " << path;
initial.commit09911bf2008-07-26 23:55:29472 return;
473 }
474 if (pref->type() != Value::TYPE_REAL) {
[email protected]b154e6f2009-03-06 01:52:40475 NOTREACHED() << "Wrong type for SetReal: " << path;
initial.commit09911bf2008-07-26 23:55:29476 return;
477 }
478
479 scoped_ptr<Value> old_value(GetPrefCopy(path));
[email protected]8e50b602009-03-03 22:59:43480 bool rv = persistent_->SetReal(path, value);
initial.commit09911bf2008-07-26 23:55:29481 DCHECK(rv);
482
483 FireObserversIfChanged(path, old_value.get());
484}
485
486void PrefService::SetString(const wchar_t* path, const std::wstring& value) {
487 DCHECK(CalledOnValidThread());
488
489 const Preference* pref = FindPreference(path);
490 if (!pref) {
[email protected]b154e6f2009-03-06 01:52:40491 NOTREACHED() << "Trying to write an unregistered pref: " << path;
initial.commit09911bf2008-07-26 23:55:29492 return;
493 }
494 if (pref->type() != Value::TYPE_STRING) {
[email protected]b154e6f2009-03-06 01:52:40495 NOTREACHED() << "Wrong type for SetString: " << path;
initial.commit09911bf2008-07-26 23:55:29496 return;
497 }
498
499 scoped_ptr<Value> old_value(GetPrefCopy(path));
[email protected]8e50b602009-03-03 22:59:43500 bool rv = persistent_->SetString(path, value);
initial.commit09911bf2008-07-26 23:55:29501 DCHECK(rv);
502
503 FireObserversIfChanged(path, old_value.get());
504}
505
[email protected]b9636002009-03-04 00:05:25506void PrefService::SetFilePath(const wchar_t* path, const FilePath& value) {
507 DCHECK(CalledOnValidThread());
508
509 const Preference* pref = FindPreference(path);
510 if (!pref) {
[email protected]b154e6f2009-03-06 01:52:40511 NOTREACHED() << "Trying to write an unregistered pref: " << path;
[email protected]b9636002009-03-04 00:05:25512 return;
513 }
514 if (pref->type() != Value::TYPE_STRING) {
[email protected]b154e6f2009-03-06 01:52:40515 NOTREACHED() << "Wrong type for SetFilePath: " << path;
[email protected]b9636002009-03-04 00:05:25516 return;
517 }
518
519 scoped_ptr<Value> old_value(GetPrefCopy(path));
[email protected]66de4f092009-09-04 23:59:40520#if defined(OS_POSIX)
521 // Value::SetString only knows about UTF8 strings, so convert the path from
522 // the system native value to UTF8.
523 std::string path_utf8 = WideToUTF8(base::SysNativeMBToWide(value.value()));
524 bool rv = persistent_->SetString(path, path_utf8);
525#else
[email protected]b9636002009-03-04 00:05:25526 bool rv = persistent_->SetString(path, value.value());
[email protected]66de4f092009-09-04 23:59:40527#endif
[email protected]b9636002009-03-04 00:05:25528 DCHECK(rv);
529
530 FireObserversIfChanged(path, old_value.get());
531}
532
[email protected]0bb1a622009-03-04 03:22:32533void PrefService::SetInt64(const wchar_t* path, int64 value) {
534 DCHECK(CalledOnValidThread());
535
536 const Preference* pref = FindPreference(path);
537 if (!pref) {
[email protected]b154e6f2009-03-06 01:52:40538 NOTREACHED() << "Trying to write an unregistered pref: " << path;
[email protected]0bb1a622009-03-04 03:22:32539 return;
540 }
541 if (pref->type() != Value::TYPE_STRING) {
[email protected]b154e6f2009-03-06 01:52:40542 NOTREACHED() << "Wrong type for SetInt64: " << path;
[email protected]0bb1a622009-03-04 03:22:32543 return;
544 }
545
546 scoped_ptr<Value> old_value(GetPrefCopy(path));
547 bool rv = persistent_->SetString(path, Int64ToWString(value));
548 DCHECK(rv);
549
550 FireObserversIfChanged(path, old_value.get());
551}
552
553int64 PrefService::GetInt64(const wchar_t* path) const {
554 DCHECK(CalledOnValidThread());
555
556 std::wstring result;
557 if (transient_->GetString(path, &result))
558 return StringToInt64(WideToUTF16Hack(result));
559
560 const Preference* pref = FindPreference(path);
561 if (!pref) {
[email protected]b154e6f2009-03-06 01:52:40562 NOTREACHED() << "Trying to read an unregistered pref: " << path;
[email protected]0bb1a622009-03-04 03:22:32563 return StringToInt64(WideToUTF16Hack(result));
564 }
565 bool rv = pref->GetValue()->GetAsString(&result);
566 DCHECK(rv);
567 return StringToInt64(WideToUTF16Hack(result));
568}
569
570void PrefService::RegisterInt64Pref(const wchar_t* path, int64 default_value) {
571 Preference* pref = new Preference(persistent_.get(), path,
572 Value::CreateStringValue(Int64ToWString(default_value)));
573 RegisterPreference(pref);
574}
575
initial.commit09911bf2008-07-26 23:55:29576DictionaryValue* PrefService::GetMutableDictionary(const wchar_t* path) {
577 DCHECK(CalledOnValidThread());
578
579 const Preference* pref = FindPreference(path);
580 if (!pref) {
[email protected]b154e6f2009-03-06 01:52:40581 NOTREACHED() << "Trying to get an unregistered pref: " << path;
initial.commit09911bf2008-07-26 23:55:29582 return NULL;
583 }
584 if (pref->type() != Value::TYPE_DICTIONARY) {
[email protected]b154e6f2009-03-06 01:52:40585 NOTREACHED() << "Wrong type for GetMutableDictionary: " << path;
initial.commit09911bf2008-07-26 23:55:29586 return NULL;
587 }
588
589 DictionaryValue* dict = NULL;
[email protected]8e50b602009-03-03 22:59:43590 bool rv = persistent_->GetDictionary(path, &dict);
initial.commit09911bf2008-07-26 23:55:29591 if (!rv) {
592 dict = new DictionaryValue;
[email protected]8e50b602009-03-03 22:59:43593 rv = persistent_->Set(path, dict);
initial.commit09911bf2008-07-26 23:55:29594 DCHECK(rv);
595 }
596 return dict;
597}
598
599ListValue* PrefService::GetMutableList(const wchar_t* path) {
600 DCHECK(CalledOnValidThread());
601
602 const Preference* pref = FindPreference(path);
603 if (!pref) {
[email protected]b154e6f2009-03-06 01:52:40604 NOTREACHED() << "Trying to get an unregistered pref: " << path;
initial.commit09911bf2008-07-26 23:55:29605 return NULL;
606 }
607 if (pref->type() != Value::TYPE_LIST) {
[email protected]b154e6f2009-03-06 01:52:40608 NOTREACHED() << "Wrong type for GetMutableList: " << path;
initial.commit09911bf2008-07-26 23:55:29609 return NULL;
610 }
611
612 ListValue* list = NULL;
[email protected]8e50b602009-03-03 22:59:43613 bool rv = persistent_->GetList(path, &list);
initial.commit09911bf2008-07-26 23:55:29614 if (!rv) {
615 list = new ListValue;
[email protected]8e50b602009-03-03 22:59:43616 rv = persistent_->Set(path, list);
initial.commit09911bf2008-07-26 23:55:29617 DCHECK(rv);
618 }
619 return list;
620}
621
622Value* PrefService::GetPrefCopy(const wchar_t* path) {
623 DCHECK(CalledOnValidThread());
624
625 const Preference* pref = FindPreference(path);
626 DCHECK(pref);
627 return pref->GetValue()->DeepCopy();
628}
629
630void PrefService::FireObserversIfChanged(const wchar_t* path,
631 const Value* old_value) {
632 Value* new_value = NULL;
[email protected]8e50b602009-03-03 22:59:43633 persistent_->Get(path, &new_value);
initial.commit09911bf2008-07-26 23:55:29634 if (!old_value->Equals(new_value))
635 FireObservers(path);
636}
637
638void PrefService::FireObservers(const wchar_t* path) {
639 DCHECK(CalledOnValidThread());
640
641 // Convert path to a std::wstring because the Details constructor requires a
642 // class.
643 std::wstring path_str(path);
644 PrefObserverMap::iterator observer_iterator = pref_observers_.find(path_str);
645 if (observer_iterator == pref_observers_.end())
646 return;
647
648 NotificationObserverList::Iterator it(*(observer_iterator->second));
649 NotificationObserver* observer;
[email protected]933cc002008-11-21 20:50:39650 while ((observer = it.GetNext()) != NULL) {
[email protected]bfd04a62009-02-01 18:16:56651 observer->Observe(NotificationType::PREF_CHANGED,
initial.commit09911bf2008-07-26 23:55:29652 Source<PrefService>(this),
653 Details<std::wstring>(&path_str));
654 }
655}
656
[email protected]6c1164042009-05-08 14:41:08657bool PrefService::SerializeData(std::string* output) {
[email protected]6faa0e0d2009-04-28 06:50:36658 // TODO(tc): Do we want to prune webkit preferences that match the default
659 // value?
660 JSONStringValueSerializer serializer(output);
661 serializer.set_pretty_print(true);
662 return serializer.Serialize(*(persistent_.get()));
663}
664
initial.commit09911bf2008-07-26 23:55:29665///////////////////////////////////////////////////////////////////////////////
666// PrefService::Preference
667
668PrefService::Preference::Preference(DictionaryValue* root_pref,
669 const wchar_t* name,
670 Value* default_value)
[email protected]933cc002008-11-21 20:50:39671 : type_(Value::TYPE_NULL),
initial.commit09911bf2008-07-26 23:55:29672 name_(name),
673 default_value_(default_value),
[email protected]933cc002008-11-21 20:50:39674 root_pref_(root_pref) {
initial.commit09911bf2008-07-26 23:55:29675 DCHECK(name);
676
677 if (default_value) {
678 type_ = default_value->GetType();
679 DCHECK(type_ != Value::TYPE_NULL && type_ != Value::TYPE_BINARY) <<
680 "invalid preference type: " << type_;
681 }
682
683 // We set the default value of lists and dictionaries to be null so it's
684 // easier for callers to check for empty list/dict prefs.
685 if (Value::TYPE_LIST == type_ || Value::TYPE_DICTIONARY == type_)
686 default_value_.reset(Value::CreateNullValue());
687}
688
689const Value* PrefService::Preference::GetValue() const {
690 DCHECK(NULL != root_pref_) <<
691 "Must register pref before getting its value";
692
693 Value* temp_value = NULL;
[email protected]8e50b602009-03-03 22:59:43694 if (root_pref_->Get(name_.c_str(), &temp_value) &&
initial.commit09911bf2008-07-26 23:55:29695 temp_value->GetType() == type_) {
696 return temp_value;
697 }
698
699 // Pref not found, just return the app default.
700 return default_value_.get();
701}
702
703bool PrefService::Preference::IsDefaultValue() const {
704 DCHECK(default_value_.get());
705 return default_value_->Equals(GetValue());
706}