license.bot | bf09a50 | 2008-08-24 00:55:55 | [diff] [blame] | 1 | // 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.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 4 | |
| 5 | #include "chrome/common/pref_service.h" |
| 6 | |
[email protected] | a92b864 | 2009-05-05 23:38:56 | [diff] [blame] | 7 | #include "app/l10n_util.h" |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 8 | #include "base/logging.h" |
| 9 | #include "base/message_loop.h" |
[email protected] | 80720414 | 2009-05-05 03:31:44 | [diff] [blame] | 10 | #include "base/stl_util-inl.h" |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 11 | #include "base/string_util.h" |
[email protected] | 66de4f09 | 2009-09-04 23:59:40 | [diff] [blame^] | 12 | #include "base/sys_string_conversions.h" |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 13 | #include "base/thread.h" |
[email protected] | 66de4f09 | 2009-09-04 23:59:40 | [diff] [blame^] | 14 | #include "build/build_config.h" |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 15 | #include "chrome/common/json_value_serializer.h" |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 16 | #include "chrome/common/notification_service.h" |
[email protected] | 34ac8f3 | 2009-02-22 23:03:27 | [diff] [blame] | 17 | #include "grit/generated_resources.h" |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 18 | |
| 19 | namespace { |
| 20 | |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 21 | // 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. |
| 24 | Value* 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] | 41fb1d7 | 2009-02-28 01:01:50 | [diff] [blame] | 37 | return Value::CreateIntegerValue( |
| 38 | StringToInt(WideToUTF16Hack(resource_string))); |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 39 | break; |
| 40 | } |
| 41 | |
| 42 | case Value::TYPE_REAL: { |
[email protected] | 41fb1d7 | 2009-02-28 01:01:50 | [diff] [blame] | 43 | return Value::CreateRealValue( |
| 44 | StringToDouble(WideToUTF16Hack(resource_string))); |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 45 | break; |
| 46 | } |
| 47 | |
| 48 | case Value::TYPE_STRING: { |
| 49 | return Value::CreateStringValue(resource_string); |
| 50 | break; |
| 51 | } |
| 52 | |
| 53 | default: { |
[email protected] | b154e6f | 2009-03-06 01:52:40 | [diff] [blame] | 54 | NOTREACHED() << |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 55 | "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] | 6faa0e0d | 2009-04-28 06:50:36 | [diff] [blame] | 64 | PrefService::PrefService(const FilePath& pref_filename, |
| 65 | const base::Thread* backend_thread) |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 66 | : persistent_(new DictionaryValue), |
| 67 | transient_(new DictionaryValue), |
[email protected] | 6faa0e0d | 2009-04-28 06:50:36 | [diff] [blame] | 68 | writer_(pref_filename, backend_thread) { |
| 69 | ReloadPersistentPrefs(); |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 70 | } |
| 71 | |
| 72 | PrefService::~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] | 6c116404 | 2009-05-08 14:41:08 | [diff] [blame] | 89 | |
| 90 | if (writer_.HasPendingWrite()) |
| 91 | writer_.DoScheduledWrite(); |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 92 | } |
| 93 | |
[email protected] | 6faa0e0d | 2009-04-28 06:50:36 | [diff] [blame] | 94 | bool PrefService::ReloadPersistentPrefs() { |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 95 | DCHECK(CalledOnValidThread()); |
| 96 | |
[email protected] | 6faa0e0d | 2009-04-28 06:50:36 | [diff] [blame] | 97 | JSONFileValueSerializer serializer(writer_.path()); |
[email protected] | b4cebf8 | 2008-12-29 19:59:08 | [diff] [blame] | 98 | scoped_ptr<Value> root(serializer.Deserialize(NULL)); |
| 99 | if (!root.get()) |
| 100 | return false; |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 101 | |
[email protected] | b4cebf8 | 2008-12-29 19:59:08 | [diff] [blame] | 102 | // Preferences should always have a dictionary root. |
| 103 | if (!root->IsType(Value::TYPE_DICTIONARY)) |
| 104 | return false; |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 105 | |
[email protected] | b4cebf8 | 2008-12-29 19:59:08 | [diff] [blame] | 106 | persistent_.reset(static_cast<DictionaryValue*>(root.release())); |
[email protected] | b4cebf8 | 2008-12-29 19:59:08 | [diff] [blame] | 107 | for (PreferenceSet::iterator it = prefs_.begin(); |
| 108 | it != prefs_.end(); ++it) { |
| 109 | (*it)->root_pref_ = persistent_.get(); |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 110 | } |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 111 | |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 112 | return true; |
| 113 | } |
| 114 | |
[email protected] | 6faa0e0d | 2009-04-28 06:50:36 | [diff] [blame] | 115 | bool PrefService::SavePersistentPrefs() { |
| 116 | DCHECK(CalledOnValidThread()); |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 117 | |
[email protected] | 6faa0e0d | 2009-04-28 06:50:36 | [diff] [blame] | 118 | std::string data; |
[email protected] | 6c116404 | 2009-05-08 14:41:08 | [diff] [blame] | 119 | if (!SerializeData(&data)) |
[email protected] | 6faa0e0d | 2009-04-28 06:50:36 | [diff] [blame] | 120 | return false; |
| 121 | |
| 122 | writer_.WriteNow(data); |
| 123 | return true; |
| 124 | } |
| 125 | |
[email protected] | 6c116404 | 2009-05-08 14:41:08 | [diff] [blame] | 126 | void PrefService::ScheduleSavePersistentPrefs() { |
[email protected] | 6faa0e0d | 2009-04-28 06:50:36 | [diff] [blame] | 127 | DCHECK(CalledOnValidThread()); |
[email protected] | 6c116404 | 2009-05-08 14:41:08 | [diff] [blame] | 128 | writer_.ScheduleWrite(this); |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 129 | } |
| 130 | |
| 131 | void 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 | |
| 138 | void 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 | |
| 145 | void 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 | |
| 152 | void 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] | b963600 | 2009-03-04 00:05:25 | [diff] [blame] | 159 | void 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.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 166 | void PrefService::RegisterListPref(const wchar_t* path) { |
| 167 | Preference* pref = new Preference(persistent_.get(), path, |
| 168 | new ListValue); |
| 169 | RegisterPreference(pref); |
| 170 | } |
| 171 | |
| 172 | void PrefService::RegisterDictionaryPref(const wchar_t* path) { |
| 173 | Preference* pref = new Preference(persistent_.get(), path, |
| 174 | new DictionaryValue()); |
| 175 | RegisterPreference(pref); |
| 176 | } |
| 177 | |
| 178 | void 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 | |
| 185 | void 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 | |
| 192 | void 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 | |
| 199 | void 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 | |
| 206 | bool 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 | |
| 212 | bool PrefService::GetBoolean(const wchar_t* path) const { |
| 213 | DCHECK(CalledOnValidThread()); |
| 214 | |
| 215 | bool result = false; |
[email protected] | 8e50b60 | 2009-03-03 22:59:43 | [diff] [blame] | 216 | if (transient_->GetBoolean(path, &result)) |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 217 | return result; |
| 218 | |
| 219 | const Preference* pref = FindPreference(path); |
| 220 | if (!pref) { |
[email protected] | b154e6f | 2009-03-06 01:52:40 | [diff] [blame] | 221 | NOTREACHED() << "Trying to read an unregistered pref: " << path; |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 222 | return result; |
| 223 | } |
| 224 | bool rv = pref->GetValue()->GetAsBoolean(&result); |
| 225 | DCHECK(rv); |
| 226 | return result; |
| 227 | } |
| 228 | |
| 229 | int PrefService::GetInteger(const wchar_t* path) const { |
| 230 | DCHECK(CalledOnValidThread()); |
| 231 | |
| 232 | int result = 0; |
[email protected] | 8e50b60 | 2009-03-03 22:59:43 | [diff] [blame] | 233 | if (transient_->GetInteger(path, &result)) |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 234 | return result; |
| 235 | |
| 236 | const Preference* pref = FindPreference(path); |
| 237 | if (!pref) { |
[email protected] | b154e6f | 2009-03-06 01:52:40 | [diff] [blame] | 238 | NOTREACHED() << "Trying to read an unregistered pref: " << path; |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 239 | return result; |
| 240 | } |
| 241 | bool rv = pref->GetValue()->GetAsInteger(&result); |
| 242 | DCHECK(rv); |
| 243 | return result; |
| 244 | } |
| 245 | |
| 246 | double PrefService::GetReal(const wchar_t* path) const { |
| 247 | DCHECK(CalledOnValidThread()); |
| 248 | |
| 249 | double result = 0.0; |
[email protected] | 8e50b60 | 2009-03-03 22:59:43 | [diff] [blame] | 250 | if (transient_->GetReal(path, &result)) |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 251 | return result; |
| 252 | |
| 253 | const Preference* pref = FindPreference(path); |
| 254 | if (!pref) { |
[email protected] | b154e6f | 2009-03-06 01:52:40 | [diff] [blame] | 255 | NOTREACHED() << "Trying to read an unregistered pref: " << path; |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 256 | return result; |
| 257 | } |
| 258 | bool rv = pref->GetValue()->GetAsReal(&result); |
| 259 | DCHECK(rv); |
| 260 | return result; |
| 261 | } |
| 262 | |
| 263 | std::wstring PrefService::GetString(const wchar_t* path) const { |
| 264 | DCHECK(CalledOnValidThread()); |
| 265 | |
[email protected] | 3a79b3c | 2009-03-03 21:49:53 | [diff] [blame] | 266 | std::wstring result; |
[email protected] | 8e50b60 | 2009-03-03 22:59:43 | [diff] [blame] | 267 | if (transient_->GetString(path, &result)) |
| 268 | return result; |
| 269 | |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 270 | const Preference* pref = FindPreference(path); |
| 271 | if (!pref) { |
[email protected] | b154e6f | 2009-03-06 01:52:40 | [diff] [blame] | 272 | NOTREACHED() << "Trying to read an unregistered pref: " << path; |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 273 | return result; |
| 274 | } |
| 275 | bool rv = pref->GetValue()->GetAsString(&result); |
| 276 | DCHECK(rv); |
| 277 | return result; |
| 278 | } |
| 279 | |
[email protected] | b963600 | 2009-03-04 00:05:25 | [diff] [blame] | 280 | FilePath 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] | b154e6f | 2009-03-06 01:52:40 | [diff] [blame] | 289 | NOTREACHED() << "Trying to read an unregistered pref: " << path; |
[email protected] | b963600 | 2009-03-04 00:05:25 | [diff] [blame] | 290 | return FilePath(result); |
| 291 | } |
| 292 | bool rv = pref->GetValue()->GetAsString(&result); |
| 293 | DCHECK(rv); |
[email protected] | 66de4f09 | 2009-09-04 23:59:40 | [diff] [blame^] | 294 | #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] | b963600 | 2009-03-04 00:05:25 | [diff] [blame] | 298 | return FilePath(result); |
| 299 | } |
| 300 | |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 301 | bool PrefService::HasPrefPath(const wchar_t* path) const { |
| 302 | Value* value = NULL; |
[email protected] | 8e50b60 | 2009-03-03 22:59:43 | [diff] [blame] | 303 | return (transient_->Get(path, &value) || persistent_->Get(path, &value)); |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 304 | } |
| 305 | |
| 306 | const 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 | |
| 314 | const DictionaryValue* PrefService::GetDictionary(const wchar_t* path) const { |
| 315 | DCHECK(CalledOnValidThread()); |
| 316 | |
| 317 | DictionaryValue* result = NULL; |
[email protected] | 8e50b60 | 2009-03-03 22:59:43 | [diff] [blame] | 318 | if (transient_->GetDictionary(path, &result)) |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 319 | return result; |
| 320 | |
| 321 | const Preference* pref = FindPreference(path); |
| 322 | if (!pref) { |
[email protected] | b154e6f | 2009-03-06 01:52:40 | [diff] [blame] | 323 | NOTREACHED() << "Trying to read an unregistered pref: " << path; |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 324 | 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 | |
| 332 | const ListValue* PrefService::GetList(const wchar_t* path) const { |
| 333 | DCHECK(CalledOnValidThread()); |
| 334 | |
| 335 | ListValue* result = NULL; |
[email protected] | 8e50b60 | 2009-03-03 22:59:43 | [diff] [blame] | 336 | if (transient_->GetList(path, &result)) |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 337 | return result; |
| 338 | |
| 339 | const Preference* pref = FindPreference(path); |
| 340 | if (!pref) { |
[email protected] | b154e6f | 2009-03-06 01:52:40 | [diff] [blame] | 341 | NOTREACHED() << "Trying to read an unregistered pref: " << path; |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 342 | 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 | |
| 350 | void PrefService::AddPrefObserver(const wchar_t* path, |
| 351 | NotificationObserver* obs) { |
| 352 | DCHECK(CalledOnValidThread()); |
| 353 | |
| 354 | const Preference* pref = FindPreference(path); |
| 355 | if (!pref) { |
[email protected] | b154e6f | 2009-03-06 01:52:40 | [diff] [blame] | 356 | NOTREACHED() << "Trying to add an observer for an unregistered pref: " |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 357 | << 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] | 933cc00 | 2008-11-21 20:50:39 | [diff] [blame] | 374 | while ((existing_obs = it.GetNext()) != NULL) { |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 375 | 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 | |
| 384 | void 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 | |
| 397 | void PrefService::RegisterPreference(Preference* pref) { |
| 398 | DCHECK(CalledOnValidThread()); |
| 399 | |
| 400 | if (FindPreference(pref->name().c_str())) { |
[email protected] | b154e6f | 2009-03-06 01:52:40 | [diff] [blame] | 401 | NOTREACHED() << "Tried to register duplicate pref " << pref->name(); |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 402 | delete pref; |
| 403 | return; |
| 404 | } |
| 405 | prefs_.insert(pref); |
| 406 | } |
| 407 | |
| 408 | void PrefService::ClearPref(const wchar_t* path) { |
| 409 | DCHECK(CalledOnValidThread()); |
| 410 | |
| 411 | const Preference* pref = FindPreference(path); |
| 412 | if (!pref) { |
[email protected] | b154e6f | 2009-03-06 01:52:40 | [diff] [blame] | 413 | NOTREACHED() << "Trying to clear an unregistered pref: " << path; |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 414 | return; |
| 415 | } |
| 416 | |
[email protected] | 8e50b60 | 2009-03-03 22:59:43 | [diff] [blame] | 417 | transient_->Remove(path, NULL); |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 418 | Value* value; |
[email protected] | 8e50b60 | 2009-03-03 22:59:43 | [diff] [blame] | 419 | bool has_old_value = persistent_->Get(path, &value); |
| 420 | persistent_->Remove(path, NULL); |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 421 | |
| 422 | if (has_old_value) |
| 423 | FireObservers(path); |
| 424 | } |
| 425 | |
| 426 | void PrefService::SetBoolean(const wchar_t* path, bool value) { |
| 427 | DCHECK(CalledOnValidThread()); |
| 428 | |
| 429 | const Preference* pref = FindPreference(path); |
| 430 | if (!pref) { |
[email protected] | b154e6f | 2009-03-06 01:52:40 | [diff] [blame] | 431 | NOTREACHED() << "Trying to write an unregistered pref: " << path; |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 432 | return; |
| 433 | } |
| 434 | if (pref->type() != Value::TYPE_BOOLEAN) { |
[email protected] | b154e6f | 2009-03-06 01:52:40 | [diff] [blame] | 435 | NOTREACHED() << "Wrong type for SetBoolean: " << path; |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 436 | return; |
| 437 | } |
| 438 | |
| 439 | scoped_ptr<Value> old_value(GetPrefCopy(path)); |
[email protected] | 8e50b60 | 2009-03-03 22:59:43 | [diff] [blame] | 440 | bool rv = persistent_->SetBoolean(path, value); |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 441 | DCHECK(rv); |
| 442 | |
| 443 | FireObserversIfChanged(path, old_value.get()); |
| 444 | } |
| 445 | |
| 446 | void PrefService::SetInteger(const wchar_t* path, int value) { |
| 447 | DCHECK(CalledOnValidThread()); |
| 448 | |
| 449 | const Preference* pref = FindPreference(path); |
| 450 | if (!pref) { |
[email protected] | b154e6f | 2009-03-06 01:52:40 | [diff] [blame] | 451 | NOTREACHED() << "Trying to write an unregistered pref: " << path; |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 452 | return; |
| 453 | } |
| 454 | if (pref->type() != Value::TYPE_INTEGER) { |
[email protected] | b154e6f | 2009-03-06 01:52:40 | [diff] [blame] | 455 | NOTREACHED() << "Wrong type for SetInteger: " << path; |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 456 | return; |
| 457 | } |
| 458 | |
| 459 | scoped_ptr<Value> old_value(GetPrefCopy(path)); |
[email protected] | 8e50b60 | 2009-03-03 22:59:43 | [diff] [blame] | 460 | bool rv = persistent_->SetInteger(path, value); |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 461 | DCHECK(rv); |
| 462 | |
| 463 | FireObserversIfChanged(path, old_value.get()); |
| 464 | } |
| 465 | |
| 466 | void PrefService::SetReal(const wchar_t* path, double value) { |
| 467 | DCHECK(CalledOnValidThread()); |
| 468 | |
| 469 | const Preference* pref = FindPreference(path); |
| 470 | if (!pref) { |
[email protected] | b154e6f | 2009-03-06 01:52:40 | [diff] [blame] | 471 | NOTREACHED() << "Trying to write an unregistered pref: " << path; |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 472 | return; |
| 473 | } |
| 474 | if (pref->type() != Value::TYPE_REAL) { |
[email protected] | b154e6f | 2009-03-06 01:52:40 | [diff] [blame] | 475 | NOTREACHED() << "Wrong type for SetReal: " << path; |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 476 | return; |
| 477 | } |
| 478 | |
| 479 | scoped_ptr<Value> old_value(GetPrefCopy(path)); |
[email protected] | 8e50b60 | 2009-03-03 22:59:43 | [diff] [blame] | 480 | bool rv = persistent_->SetReal(path, value); |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 481 | DCHECK(rv); |
| 482 | |
| 483 | FireObserversIfChanged(path, old_value.get()); |
| 484 | } |
| 485 | |
| 486 | void 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] | b154e6f | 2009-03-06 01:52:40 | [diff] [blame] | 491 | NOTREACHED() << "Trying to write an unregistered pref: " << path; |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 492 | return; |
| 493 | } |
| 494 | if (pref->type() != Value::TYPE_STRING) { |
[email protected] | b154e6f | 2009-03-06 01:52:40 | [diff] [blame] | 495 | NOTREACHED() << "Wrong type for SetString: " << path; |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 496 | return; |
| 497 | } |
| 498 | |
| 499 | scoped_ptr<Value> old_value(GetPrefCopy(path)); |
[email protected] | 8e50b60 | 2009-03-03 22:59:43 | [diff] [blame] | 500 | bool rv = persistent_->SetString(path, value); |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 501 | DCHECK(rv); |
| 502 | |
| 503 | FireObserversIfChanged(path, old_value.get()); |
| 504 | } |
| 505 | |
[email protected] | b963600 | 2009-03-04 00:05:25 | [diff] [blame] | 506 | void PrefService::SetFilePath(const wchar_t* path, const FilePath& value) { |
| 507 | DCHECK(CalledOnValidThread()); |
| 508 | |
| 509 | const Preference* pref = FindPreference(path); |
| 510 | if (!pref) { |
[email protected] | b154e6f | 2009-03-06 01:52:40 | [diff] [blame] | 511 | NOTREACHED() << "Trying to write an unregistered pref: " << path; |
[email protected] | b963600 | 2009-03-04 00:05:25 | [diff] [blame] | 512 | return; |
| 513 | } |
| 514 | if (pref->type() != Value::TYPE_STRING) { |
[email protected] | b154e6f | 2009-03-06 01:52:40 | [diff] [blame] | 515 | NOTREACHED() << "Wrong type for SetFilePath: " << path; |
[email protected] | b963600 | 2009-03-04 00:05:25 | [diff] [blame] | 516 | return; |
| 517 | } |
| 518 | |
| 519 | scoped_ptr<Value> old_value(GetPrefCopy(path)); |
[email protected] | 66de4f09 | 2009-09-04 23:59:40 | [diff] [blame^] | 520 | #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] | b963600 | 2009-03-04 00:05:25 | [diff] [blame] | 526 | bool rv = persistent_->SetString(path, value.value()); |
[email protected] | 66de4f09 | 2009-09-04 23:59:40 | [diff] [blame^] | 527 | #endif |
[email protected] | b963600 | 2009-03-04 00:05:25 | [diff] [blame] | 528 | DCHECK(rv); |
| 529 | |
| 530 | FireObserversIfChanged(path, old_value.get()); |
| 531 | } |
| 532 | |
[email protected] | 0bb1a62 | 2009-03-04 03:22:32 | [diff] [blame] | 533 | void PrefService::SetInt64(const wchar_t* path, int64 value) { |
| 534 | DCHECK(CalledOnValidThread()); |
| 535 | |
| 536 | const Preference* pref = FindPreference(path); |
| 537 | if (!pref) { |
[email protected] | b154e6f | 2009-03-06 01:52:40 | [diff] [blame] | 538 | NOTREACHED() << "Trying to write an unregistered pref: " << path; |
[email protected] | 0bb1a62 | 2009-03-04 03:22:32 | [diff] [blame] | 539 | return; |
| 540 | } |
| 541 | if (pref->type() != Value::TYPE_STRING) { |
[email protected] | b154e6f | 2009-03-06 01:52:40 | [diff] [blame] | 542 | NOTREACHED() << "Wrong type for SetInt64: " << path; |
[email protected] | 0bb1a62 | 2009-03-04 03:22:32 | [diff] [blame] | 543 | 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 | |
| 553 | int64 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] | b154e6f | 2009-03-06 01:52:40 | [diff] [blame] | 562 | NOTREACHED() << "Trying to read an unregistered pref: " << path; |
[email protected] | 0bb1a62 | 2009-03-04 03:22:32 | [diff] [blame] | 563 | return StringToInt64(WideToUTF16Hack(result)); |
| 564 | } |
| 565 | bool rv = pref->GetValue()->GetAsString(&result); |
| 566 | DCHECK(rv); |
| 567 | return StringToInt64(WideToUTF16Hack(result)); |
| 568 | } |
| 569 | |
| 570 | void 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.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 576 | DictionaryValue* PrefService::GetMutableDictionary(const wchar_t* path) { |
| 577 | DCHECK(CalledOnValidThread()); |
| 578 | |
| 579 | const Preference* pref = FindPreference(path); |
| 580 | if (!pref) { |
[email protected] | b154e6f | 2009-03-06 01:52:40 | [diff] [blame] | 581 | NOTREACHED() << "Trying to get an unregistered pref: " << path; |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 582 | return NULL; |
| 583 | } |
| 584 | if (pref->type() != Value::TYPE_DICTIONARY) { |
[email protected] | b154e6f | 2009-03-06 01:52:40 | [diff] [blame] | 585 | NOTREACHED() << "Wrong type for GetMutableDictionary: " << path; |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 586 | return NULL; |
| 587 | } |
| 588 | |
| 589 | DictionaryValue* dict = NULL; |
[email protected] | 8e50b60 | 2009-03-03 22:59:43 | [diff] [blame] | 590 | bool rv = persistent_->GetDictionary(path, &dict); |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 591 | if (!rv) { |
| 592 | dict = new DictionaryValue; |
[email protected] | 8e50b60 | 2009-03-03 22:59:43 | [diff] [blame] | 593 | rv = persistent_->Set(path, dict); |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 594 | DCHECK(rv); |
| 595 | } |
| 596 | return dict; |
| 597 | } |
| 598 | |
| 599 | ListValue* PrefService::GetMutableList(const wchar_t* path) { |
| 600 | DCHECK(CalledOnValidThread()); |
| 601 | |
| 602 | const Preference* pref = FindPreference(path); |
| 603 | if (!pref) { |
[email protected] | b154e6f | 2009-03-06 01:52:40 | [diff] [blame] | 604 | NOTREACHED() << "Trying to get an unregistered pref: " << path; |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 605 | return NULL; |
| 606 | } |
| 607 | if (pref->type() != Value::TYPE_LIST) { |
[email protected] | b154e6f | 2009-03-06 01:52:40 | [diff] [blame] | 608 | NOTREACHED() << "Wrong type for GetMutableList: " << path; |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 609 | return NULL; |
| 610 | } |
| 611 | |
| 612 | ListValue* list = NULL; |
[email protected] | 8e50b60 | 2009-03-03 22:59:43 | [diff] [blame] | 613 | bool rv = persistent_->GetList(path, &list); |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 614 | if (!rv) { |
| 615 | list = new ListValue; |
[email protected] | 8e50b60 | 2009-03-03 22:59:43 | [diff] [blame] | 616 | rv = persistent_->Set(path, list); |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 617 | DCHECK(rv); |
| 618 | } |
| 619 | return list; |
| 620 | } |
| 621 | |
| 622 | Value* 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 | |
| 630 | void PrefService::FireObserversIfChanged(const wchar_t* path, |
| 631 | const Value* old_value) { |
| 632 | Value* new_value = NULL; |
[email protected] | 8e50b60 | 2009-03-03 22:59:43 | [diff] [blame] | 633 | persistent_->Get(path, &new_value); |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 634 | if (!old_value->Equals(new_value)) |
| 635 | FireObservers(path); |
| 636 | } |
| 637 | |
| 638 | void 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] | 933cc00 | 2008-11-21 20:50:39 | [diff] [blame] | 650 | while ((observer = it.GetNext()) != NULL) { |
[email protected] | bfd04a6 | 2009-02-01 18:16:56 | [diff] [blame] | 651 | observer->Observe(NotificationType::PREF_CHANGED, |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 652 | Source<PrefService>(this), |
| 653 | Details<std::wstring>(&path_str)); |
| 654 | } |
| 655 | } |
| 656 | |
[email protected] | 6c116404 | 2009-05-08 14:41:08 | [diff] [blame] | 657 | bool PrefService::SerializeData(std::string* output) { |
[email protected] | 6faa0e0d | 2009-04-28 06:50:36 | [diff] [blame] | 658 | // 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.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 665 | /////////////////////////////////////////////////////////////////////////////// |
| 666 | // PrefService::Preference |
| 667 | |
| 668 | PrefService::Preference::Preference(DictionaryValue* root_pref, |
| 669 | const wchar_t* name, |
| 670 | Value* default_value) |
[email protected] | 933cc00 | 2008-11-21 20:50:39 | [diff] [blame] | 671 | : type_(Value::TYPE_NULL), |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 672 | name_(name), |
| 673 | default_value_(default_value), |
[email protected] | 933cc00 | 2008-11-21 20:50:39 | [diff] [blame] | 674 | root_pref_(root_pref) { |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 675 | 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 | |
| 689 | const 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] | 8e50b60 | 2009-03-03 22:59:43 | [diff] [blame] | 694 | if (root_pref_->Get(name_.c_str(), &temp_value) && |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 695 | 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 | |
| 703 | bool PrefService::Preference::IsDefaultValue() const { |
| 704 | DCHECK(default_value_.get()); |
| 705 | return default_value_->Equals(GetValue()); |
| 706 | } |