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 // A helper class that stays in sync with a preference (bool, int, real, 6 // string or filepath). For example: 7 // 8 // class MyClass { 9 // public: 10 // MyClass(PrefService* prefs) { 11 // my_string_.Init(prefs::kHomePage, prefs); 12 // } 13 // private: 14 // StringPrefMember my_string_; 15 // }; 16 // 17 // my_string_ should stay in sync with the prefs::kHomePage pref and will 18 // update if either the pref changes or if my_string_.SetValue is called. 19 // 20 // An optional observer can be passed into the Init method which can be used to 21 // notify MyClass of changes. Note that if you use SetValue(), the observer 22 // will not be notified. 23 24 #ifndef BASE_PREFS_PREF_MEMBER_H_ 25 #define BASE_PREFS_PREF_MEMBER_H_ 26 27 #include <string> 28 #include <vector> 29 30 #include "base/basictypes.h" 31 #include "base/bind.h" 32 #include "base/callback_forward.h" 33 #include "base/files/file_path.h" 34 #include "base/logging.h" 35 #include "base/memory/ref_counted.h" 36 #include "base/message_loop/message_loop_proxy.h" 37 #include "base/prefs/base_prefs_export.h" 38 #include "base/prefs/pref_observer.h" 39 #include "base/values.h" 40 41 class PrefService; 42 43 namespace subtle { 44 45 class BASE_PREFS_EXPORT PrefMemberBase : public PrefObserver { 46 public: 47 // Type of callback you can register if you need to know the name of 48 // the pref that is changing. 49 typedef base::Callback<void(const std::string&)> NamedChangeCallback; 50 prefs()51 PrefService* prefs() { return prefs_; } prefs()52 const PrefService* prefs() const { return prefs_; } 53 54 protected: 55 class BASE_PREFS_EXPORT Internal 56 : public base::RefCountedThreadSafe<Internal> { 57 public: 58 Internal(); 59 60 // Update the value, either by calling |UpdateValueInternal| directly 61 // or by dispatching to the right thread. 62 // Takes ownership of |value|. 63 void UpdateValue(base::Value* value, 64 bool is_managed, 65 bool is_user_modifiable, 66 const base::Closure& callback) const; 67 68 void MoveToThread( 69 const scoped_refptr<base::MessageLoopProxy>& message_loop); 70 71 // See PrefMember<> for description. IsManaged()72 bool IsManaged() const { 73 return is_managed_; 74 } 75 IsUserModifiable()76 bool IsUserModifiable() const { 77 return is_user_modifiable_; 78 } 79 80 protected: 81 friend class base::RefCountedThreadSafe<Internal>; 82 virtual ~Internal(); 83 CheckOnCorrectThread()84 void CheckOnCorrectThread() const { 85 DCHECK(IsOnCorrectThread()); 86 } 87 88 private: 89 // This method actually updates the value. It should only be called from 90 // the thread the PrefMember is on. 91 virtual bool UpdateValueInternal(const base::Value& value) const = 0; 92 93 bool IsOnCorrectThread() const; 94 95 scoped_refptr<base::MessageLoopProxy> thread_loop_; 96 mutable bool is_managed_; 97 mutable bool is_user_modifiable_; 98 99 DISALLOW_COPY_AND_ASSIGN(Internal); 100 }; 101 102 PrefMemberBase(); 103 virtual ~PrefMemberBase(); 104 105 // See PrefMember<> for description. 106 void Init(const char* pref_name, PrefService* prefs, 107 const NamedChangeCallback& observer); 108 void Init(const char* pref_name, PrefService* prefs); 109 110 virtual void CreateInternal() const = 0; 111 112 // See PrefMember<> for description. 113 void Destroy(); 114 115 void MoveToThread(const scoped_refptr<base::MessageLoopProxy>& message_loop); 116 117 // PrefObserver 118 virtual void OnPreferenceChanged(PrefService* service, 119 const std::string& pref_name) OVERRIDE; 120 VerifyValuePrefName()121 void VerifyValuePrefName() const { 122 DCHECK(!pref_name_.empty()); 123 } 124 125 // This method is used to do the actual sync with the preference. 126 // Note: it is logically const, because it doesn't modify the state 127 // seen by the outside world. It is just doing a lazy load behind the scenes. 128 void UpdateValueFromPref(const base::Closure& callback) const; 129 130 // Verifies the preference name, and lazily loads the preference value if 131 // it hasn't been loaded yet. 132 void VerifyPref() const; 133 pref_name()134 const std::string& pref_name() const { return pref_name_; } 135 136 virtual Internal* internal() const = 0; 137 138 // Used to allow registering plain base::Closure callbacks. 139 static void InvokeUnnamedCallback(const base::Closure& callback, 140 const std::string& pref_name); 141 142 private: 143 // Ordered the members to compact the class instance. 144 std::string pref_name_; 145 NamedChangeCallback observer_; 146 PrefService* prefs_; 147 148 protected: 149 bool setting_value_; 150 }; 151 152 // This function implements StringListPrefMember::UpdateValue(). 153 // It is exposed here for testing purposes. 154 bool BASE_PREFS_EXPORT PrefMemberVectorStringUpdate( 155 const base::Value& value, 156 std::vector<std::string>* string_vector); 157 158 } // namespace subtle 159 160 template <typename ValueType> 161 class PrefMember : public subtle::PrefMemberBase { 162 public: 163 // Defer initialization to an Init method so it's easy to make this class be 164 // a member variable. PrefMember()165 PrefMember() {} ~PrefMember()166 virtual ~PrefMember() {} 167 168 // Do the actual initialization of the class. Use the two-parameter 169 // version if you don't want any notifications of changes. This 170 // method should only be called on the UI thread. Init(const char * pref_name,PrefService * prefs,const NamedChangeCallback & observer)171 void Init(const char* pref_name, PrefService* prefs, 172 const NamedChangeCallback& observer) { 173 subtle::PrefMemberBase::Init(pref_name, prefs, observer); 174 } Init(const char * pref_name,PrefService * prefs,const base::Closure & observer)175 void Init(const char* pref_name, PrefService* prefs, 176 const base::Closure& observer) { 177 subtle::PrefMemberBase::Init( 178 pref_name, prefs, 179 base::Bind(&PrefMemberBase::InvokeUnnamedCallback, observer)); 180 } Init(const char * pref_name,PrefService * prefs)181 void Init(const char* pref_name, PrefService* prefs) { 182 subtle::PrefMemberBase::Init(pref_name, prefs); 183 } 184 185 // Unsubscribes the PrefMember from the PrefService. After calling this 186 // function, the PrefMember may not be used any more on the UI thread. 187 // Assuming |MoveToThread| was previously called, |GetValue|, |IsManaged|, 188 // and |IsUserModifiable| can still be called from the other thread but 189 // the results will no longer update from the PrefService. 190 // This method should only be called on the UI thread. Destroy()191 void Destroy() { 192 subtle::PrefMemberBase::Destroy(); 193 } 194 195 // Moves the PrefMember to another thread, allowing read accesses from there. 196 // Changes from the PrefService will be propagated asynchronously 197 // via PostTask. 198 // This method should only be used from the thread the PrefMember is currently 199 // on, which is the UI thread by default. MoveToThread(const scoped_refptr<base::MessageLoopProxy> & message_loop)200 void MoveToThread(const scoped_refptr<base::MessageLoopProxy>& message_loop) { 201 subtle::PrefMemberBase::MoveToThread(message_loop); 202 } 203 204 // Check whether the pref is managed, i.e. controlled externally through 205 // enterprise configuration management (e.g. windows group policy). Returns 206 // false for unknown prefs. 207 // This method should only be used from the thread the PrefMember is currently 208 // on, which is the UI thread unless changed by |MoveToThread|. IsManaged()209 bool IsManaged() const { 210 VerifyPref(); 211 return internal_->IsManaged(); 212 } 213 214 // Checks whether the pref can be modified by the user. This returns false 215 // when the pref is managed by a policy or an extension, and when a command 216 // line flag overrides the pref. 217 // This method should only be used from the thread the PrefMember is currently 218 // on, which is the UI thread unless changed by |MoveToThread|. IsUserModifiable()219 bool IsUserModifiable() const { 220 VerifyPref(); 221 return internal_->IsUserModifiable(); 222 } 223 224 // Retrieve the value of the member variable. 225 // This method should only be used from the thread the PrefMember is currently 226 // on, which is the UI thread unless changed by |MoveToThread|. GetValue()227 ValueType GetValue() const { 228 VerifyPref(); 229 return internal_->value(); 230 } 231 232 // Provided as a convenience. 233 ValueType operator*() const { 234 return GetValue(); 235 } 236 237 // Set the value of the member variable. 238 // This method should only be called on the UI thread. SetValue(const ValueType & value)239 void SetValue(const ValueType& value) { 240 VerifyValuePrefName(); 241 setting_value_ = true; 242 UpdatePref(value); 243 setting_value_ = false; 244 } 245 246 // Returns the pref name. GetPrefName()247 const std::string& GetPrefName() const { 248 return pref_name(); 249 } 250 251 private: 252 class Internal : public subtle::PrefMemberBase::Internal { 253 public: Internal()254 Internal() : value_(ValueType()) {} 255 value()256 ValueType value() { 257 CheckOnCorrectThread(); 258 return value_; 259 } 260 261 protected: ~Internal()262 virtual ~Internal() {} 263 264 virtual BASE_PREFS_EXPORT bool UpdateValueInternal( 265 const base::Value& value) const OVERRIDE; 266 267 // We cache the value of the pref so we don't have to keep walking the pref 268 // tree. 269 mutable ValueType value_; 270 271 DISALLOW_COPY_AND_ASSIGN(Internal); 272 }; 273 internal()274 virtual Internal* internal() const OVERRIDE { return internal_.get(); } CreateInternal()275 virtual void CreateInternal() const OVERRIDE { internal_ = new Internal(); } 276 277 // This method is used to do the actual sync with pref of the specified type. 278 void BASE_PREFS_EXPORT UpdatePref(const ValueType& value); 279 280 mutable scoped_refptr<Internal> internal_; 281 282 DISALLOW_COPY_AND_ASSIGN(PrefMember); 283 }; 284 285 // Declaration of template specialization need to be repeated here 286 // specifically for each specialization (rather than just once above) 287 // or at least one of our compilers won't be happy in all cases. 288 // Specifically, it was failing on ChromeOS with a complaint about 289 // PrefMember<FilePath>::UpdateValueInternal not being defined when 290 // built in a chroot with the following parameters: 291 // 292 // FEATURES="noclean nostrip" USE="-chrome_debug -chrome_remoting 293 // -chrome_internal -chrome_pdf component_build" 294 // ~/trunk/goma/goma-wrapper cros_chrome_make --board=${BOARD} 295 // --install --runhooks 296 297 template <> 298 BASE_PREFS_EXPORT void PrefMember<bool>::UpdatePref(const bool& value); 299 300 template <> 301 BASE_PREFS_EXPORT bool PrefMember<bool>::Internal::UpdateValueInternal( 302 const base::Value& value) const; 303 304 template <> 305 BASE_PREFS_EXPORT void PrefMember<int>::UpdatePref(const int& value); 306 307 template <> 308 BASE_PREFS_EXPORT bool PrefMember<int>::Internal::UpdateValueInternal( 309 const base::Value& value) const; 310 311 template <> 312 BASE_PREFS_EXPORT void PrefMember<double>::UpdatePref(const double& value); 313 314 template <> 315 BASE_PREFS_EXPORT bool PrefMember<double>::Internal::UpdateValueInternal( 316 const base::Value& value) const; 317 318 template <> 319 BASE_PREFS_EXPORT void PrefMember<std::string>::UpdatePref( 320 const std::string& value); 321 322 template <> 323 BASE_PREFS_EXPORT bool PrefMember<std::string>::Internal::UpdateValueInternal( 324 const base::Value& value) const; 325 326 template <> 327 BASE_PREFS_EXPORT void PrefMember<base::FilePath>::UpdatePref( 328 const base::FilePath& value); 329 330 template <> 331 BASE_PREFS_EXPORT bool 332 PrefMember<base::FilePath>::Internal::UpdateValueInternal( 333 const base::Value& value) const; 334 335 template <> 336 BASE_PREFS_EXPORT void PrefMember<std::vector<std::string> >::UpdatePref( 337 const std::vector<std::string>& value); 338 339 template <> 340 BASE_PREFS_EXPORT bool 341 PrefMember<std::vector<std::string> >::Internal::UpdateValueInternal( 342 const base::Value& value) const; 343 344 typedef PrefMember<bool> BooleanPrefMember; 345 typedef PrefMember<int> IntegerPrefMember; 346 typedef PrefMember<double> DoublePrefMember; 347 typedef PrefMember<std::string> StringPrefMember; 348 typedef PrefMember<base::FilePath> FilePathPrefMember; 349 // This preference member is expensive for large string arrays. 350 typedef PrefMember<std::vector<std::string> > StringListPrefMember; 351 352 #endif // BASE_PREFS_PREF_MEMBER_H_ 353