1 // Copyright (c) 2012 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. 4 5 #include "base/prefs/pref_member.h" 6 7 #include "base/callback.h" 8 #include "base/callback_helpers.h" 9 #include "base/location.h" 10 #include "base/prefs/pref_service.h" 11 #include "base/value_conversions.h" 12 13 using base::MessageLoopProxy; 14 15 namespace subtle { 16 17 PrefMemberBase::PrefMemberBase() 18 : prefs_(NULL), 19 setting_value_(false) { 20 } 21 22 PrefMemberBase::~PrefMemberBase() { 23 Destroy(); 24 } 25 26 void PrefMemberBase::Init(const char* pref_name, 27 PrefService* prefs, 28 const NamedChangeCallback& observer) { 29 observer_ = observer; 30 Init(pref_name, prefs); 31 } 32 33 void PrefMemberBase::Init(const char* pref_name, 34 PrefService* prefs) { 35 DCHECK(pref_name); 36 DCHECK(prefs); 37 DCHECK(pref_name_.empty()); // Check that Init is only called once. 38 prefs_ = prefs; 39 pref_name_ = pref_name; 40 // Check that the preference is registered. 41 DCHECK(prefs_->FindPreference(pref_name_.c_str())) 42 << pref_name << " not registered."; 43 44 // Add ourselves as a pref observer so we can keep our local value in sync. 45 prefs_->AddPrefObserver(pref_name, this); 46 } 47 48 void PrefMemberBase::Destroy() { 49 if (prefs_ && !pref_name_.empty()) { 50 prefs_->RemovePrefObserver(pref_name_.c_str(), this); 51 prefs_ = NULL; 52 } 53 } 54 55 void PrefMemberBase::MoveToThread( 56 const scoped_refptr<MessageLoopProxy>& message_loop) { 57 VerifyValuePrefName(); 58 // Load the value from preferences if it hasn't been loaded so far. 59 if (!internal()) 60 UpdateValueFromPref(base::Closure()); 61 internal()->MoveToThread(message_loop); 62 } 63 64 void PrefMemberBase::OnPreferenceChanged(PrefService* service, 65 const std::string& pref_name) { 66 VerifyValuePrefName(); 67 UpdateValueFromPref((!setting_value_ && !observer_.is_null()) ? 68 base::Bind(observer_, pref_name) : base::Closure()); 69 } 70 71 void PrefMemberBase::UpdateValueFromPref(const base::Closure& callback) const { 72 VerifyValuePrefName(); 73 const PrefService::Preference* pref = 74 prefs_->FindPreference(pref_name_.c_str()); 75 DCHECK(pref); 76 if (!internal()) 77 CreateInternal(); 78 internal()->UpdateValue(pref->GetValue()->DeepCopy(), 79 pref->IsManaged(), 80 pref->IsUserModifiable(), 81 callback); 82 } 83 84 void PrefMemberBase::VerifyPref() const { 85 VerifyValuePrefName(); 86 if (!internal()) 87 UpdateValueFromPref(base::Closure()); 88 } 89 90 void PrefMemberBase::InvokeUnnamedCallback(const base::Closure& callback, 91 const std::string& pref_name) { 92 callback.Run(); 93 } 94 95 PrefMemberBase::Internal::Internal() 96 : thread_loop_(MessageLoopProxy::current()), 97 is_managed_(false), 98 is_user_modifiable_(false) { 99 } 100 PrefMemberBase::Internal::~Internal() { } 101 102 bool PrefMemberBase::Internal::IsOnCorrectThread() const { 103 // In unit tests, there may not be a message loop. 104 return thread_loop_.get() == NULL || thread_loop_->BelongsToCurrentThread(); 105 } 106 107 void PrefMemberBase::Internal::UpdateValue( 108 base::Value* v, 109 bool is_managed, 110 bool is_user_modifiable, 111 const base::Closure& callback) const { 112 scoped_ptr<base::Value> value(v); 113 base::ScopedClosureRunner closure_runner(callback); 114 if (IsOnCorrectThread()) { 115 bool rv = UpdateValueInternal(*value); 116 DCHECK(rv); 117 is_managed_ = is_managed; 118 is_user_modifiable_ = is_user_modifiable; 119 } else { 120 bool may_run = thread_loop_->PostTask( 121 FROM_HERE, 122 base::Bind(&PrefMemberBase::Internal::UpdateValue, this, 123 value.release(), is_managed, is_user_modifiable, 124 closure_runner.Release())); 125 DCHECK(may_run); 126 } 127 } 128 129 void PrefMemberBase::Internal::MoveToThread( 130 const scoped_refptr<MessageLoopProxy>& message_loop) { 131 CheckOnCorrectThread(); 132 thread_loop_ = message_loop; 133 } 134 135 bool PrefMemberVectorStringUpdate(const base::Value& value, 136 std::vector<std::string>* string_vector) { 137 if (!value.IsType(base::Value::TYPE_LIST)) 138 return false; 139 const base::ListValue* list = static_cast<const base::ListValue*>(&value); 140 141 std::vector<std::string> local_vector; 142 for (base::ListValue::const_iterator it = list->begin(); 143 it != list->end(); ++it) { 144 std::string string_value; 145 if (!(*it)->GetAsString(&string_value)) 146 return false; 147 148 local_vector.push_back(string_value); 149 } 150 151 string_vector->swap(local_vector); 152 return true; 153 } 154 155 } // namespace subtle 156 157 template <> 158 void PrefMember<bool>::UpdatePref(const bool& value) { 159 prefs()->SetBoolean(pref_name().c_str(), value); 160 } 161 162 template <> 163 bool PrefMember<bool>::Internal::UpdateValueInternal( 164 const base::Value& value) const { 165 return value.GetAsBoolean(&value_); 166 } 167 168 template <> 169 void PrefMember<int>::UpdatePref(const int& value) { 170 prefs()->SetInteger(pref_name().c_str(), value); 171 } 172 173 template <> 174 bool PrefMember<int>::Internal::UpdateValueInternal( 175 const base::Value& value) const { 176 return value.GetAsInteger(&value_); 177 } 178 179 template <> 180 void PrefMember<double>::UpdatePref(const double& value) { 181 prefs()->SetDouble(pref_name().c_str(), value); 182 } 183 184 template <> 185 bool PrefMember<double>::Internal::UpdateValueInternal(const base::Value& value) 186 const { 187 return value.GetAsDouble(&value_); 188 } 189 190 template <> 191 void PrefMember<std::string>::UpdatePref(const std::string& value) { 192 prefs()->SetString(pref_name().c_str(), value); 193 } 194 195 template <> 196 bool PrefMember<std::string>::Internal::UpdateValueInternal( 197 const base::Value& value) 198 const { 199 return value.GetAsString(&value_); 200 } 201 202 template <> 203 void PrefMember<base::FilePath>::UpdatePref(const base::FilePath& value) { 204 prefs()->SetFilePath(pref_name().c_str(), value); 205 } 206 207 template <> 208 bool PrefMember<base::FilePath>::Internal::UpdateValueInternal( 209 const base::Value& value) 210 const { 211 return base::GetValueAsFilePath(value, &value_); 212 } 213 214 template <> 215 void PrefMember<std::vector<std::string> >::UpdatePref( 216 const std::vector<std::string>& value) { 217 base::ListValue list_value; 218 list_value.AppendStrings(value); 219 prefs()->Set(pref_name().c_str(), list_value); 220 } 221 222 template <> 223 bool PrefMember<std::vector<std::string> >::Internal::UpdateValueInternal( 224 const base::Value& value) const { 225 return subtle::PrefMemberVectorStringUpdate(value, &value_); 226 } 227