1 // Copyright (c) 2011 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, NULL /* no observer */); 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 CHROME_BROWSER_PREFS_PREF_MEMBER_H_ 25 #define CHROME_BROWSER_PREFS_PREF_MEMBER_H_ 26 #pragma once 27 28 #include <string> 29 30 #include "base/basictypes.h" 31 #include "base/file_path.h" 32 #include "base/memory/ref_counted.h" 33 #include "base/values.h" 34 #include "content/browser/browser_thread.h" 35 #include "content/common/notification_observer.h" 36 37 class PrefService; 38 39 namespace subtle { 40 41 class PrefMemberBase : public NotificationObserver { 42 protected: 43 class Internal : public base::RefCountedThreadSafe<Internal> { 44 public: 45 Internal(); 46 47 // Update the value, either by calling |UpdateValueInternal| directly 48 // or by dispatching to the right thread. 49 // Takes ownership of |value|. 50 virtual void UpdateValue(Value* value, bool is_managed) const; 51 52 void MoveToThread(BrowserThread::ID thread_id); 53 54 // See PrefMember<> for description. IsManaged()55 bool IsManaged() const { 56 return is_managed_; 57 } 58 59 protected: 60 friend class base::RefCountedThreadSafe<Internal>; 61 virtual ~Internal(); 62 CheckOnCorrectThread()63 void CheckOnCorrectThread() const { 64 DCHECK(IsOnCorrectThread()); 65 } 66 67 private: 68 // This method actually updates the value. It should only be called from 69 // the thread the PrefMember is on. 70 virtual bool UpdateValueInternal(const Value& value) const = 0; 71 72 bool IsOnCorrectThread() const; 73 74 BrowserThread::ID thread_id_; 75 mutable bool is_managed_; 76 77 DISALLOW_COPY_AND_ASSIGN(Internal); 78 }; 79 80 PrefMemberBase(); 81 virtual ~PrefMemberBase(); 82 83 // See PrefMember<> for description. 84 void Init(const char* pref_name, PrefService* prefs, 85 NotificationObserver* observer); 86 87 virtual void CreateInternal() const = 0; 88 89 // See PrefMember<> for description. 90 void Destroy(); 91 92 void MoveToThread(BrowserThread::ID thread_id); 93 94 // NotificationObserver 95 virtual void Observe(NotificationType type, 96 const NotificationSource& source, 97 const NotificationDetails& details); 98 VerifyValuePrefName()99 void VerifyValuePrefName() const { 100 DCHECK(!pref_name_.empty()); 101 } 102 103 // This method is used to do the actual sync with the preference. 104 // Note: it is logically const, because it doesn't modify the state 105 // seen by the outside world. It is just doing a lazy load behind the scenes. 106 virtual void UpdateValueFromPref() const; 107 108 // Verifies the preference name, and lazily loads the preference value if 109 // it hasn't been loaded yet. 110 void VerifyPref() const; 111 pref_name()112 const std::string& pref_name() const { return pref_name_; } prefs()113 PrefService* prefs() { return prefs_; } prefs()114 const PrefService* prefs() const { return prefs_; } 115 116 virtual Internal* internal() const = 0; 117 118 // Ordered the members to compact the class instance. 119 private: 120 std::string pref_name_; 121 NotificationObserver* observer_; 122 PrefService* prefs_; 123 124 protected: 125 bool setting_value_; 126 }; 127 128 } // namespace subtle 129 130 template <typename ValueType> 131 class PrefMember : public subtle::PrefMemberBase { 132 public: 133 // Defer initialization to an Init method so it's easy to make this class be 134 // a member variable. PrefMember()135 PrefMember() {} ~PrefMember()136 virtual ~PrefMember() {} 137 138 // Do the actual initialization of the class. |observer| may be null if you 139 // don't want any notifications of changes. 140 // This method should only be called on the UI thread. Init(const char * pref_name,PrefService * prefs,NotificationObserver * observer)141 void Init(const char* pref_name, PrefService* prefs, 142 NotificationObserver* observer) { 143 subtle::PrefMemberBase::Init(pref_name, prefs, observer); 144 } 145 146 // Unsubscribes the PrefMember from the PrefService. After calling this 147 // function, the PrefMember may not be used any more. 148 // This method should only be called on the UI thread. Destroy()149 void Destroy() { 150 subtle::PrefMemberBase::Destroy(); 151 } 152 153 // Moves the PrefMember to another thread, allowing read accesses from there. 154 // Changes from the PrefService will be propagated asynchronously 155 // via PostTask. 156 // This method should only be used from the thread the PrefMember is currently 157 // on, which is the UI thread by default. MoveToThread(BrowserThread::ID thread_id)158 void MoveToThread(BrowserThread::ID thread_id) { 159 subtle::PrefMemberBase::MoveToThread(thread_id); 160 } 161 162 // Check whether the pref is managed, i.e. controlled externally through 163 // enterprise configuration management (e.g. windows group policy). Returns 164 // false for unknown prefs. 165 // This method should only be used from the thread the PrefMember is currently 166 // on, which is the UI thread unless changed by |MoveToThread|. IsManaged()167 bool IsManaged() const { 168 VerifyPref(); 169 return internal_->IsManaged(); 170 } 171 172 // Retrieve the value of the member variable. 173 // This method should only be used from the thread the PrefMember is currently 174 // on, which is the UI thread unless changed by |MoveToThread|. GetValue()175 ValueType GetValue() const { 176 VerifyPref(); 177 return internal_->value(); 178 } 179 180 // Provided as a convenience. 181 ValueType operator*() const { 182 return GetValue(); 183 } 184 185 // Set the value of the member variable. 186 // This method should only be called on the UI thread. SetValue(const ValueType & value)187 void SetValue(const ValueType& value) { 188 VerifyValuePrefName(); 189 setting_value_ = true; 190 UpdatePref(value); 191 setting_value_ = false; 192 } 193 194 // Set the value of the member variable if it is not managed. 195 // This method should only be called on the UI thread. SetValueIfNotManaged(const ValueType & value)196 void SetValueIfNotManaged(const ValueType& value) { 197 if (!IsManaged()) { 198 SetValue(value); 199 } 200 } 201 202 // Returns the pref name. GetPrefName()203 const std::string& GetPrefName() const { 204 return pref_name(); 205 } 206 207 private: 208 class Internal : public subtle::PrefMemberBase::Internal { 209 public: Internal()210 Internal() : value_(ValueType()) {} 211 value()212 ValueType value() { 213 CheckOnCorrectThread(); 214 return value_; 215 } 216 217 protected: ~Internal()218 virtual ~Internal() {} 219 220 virtual bool UpdateValueInternal(const Value& value) const; 221 222 // We cache the value of the pref so we don't have to keep walking the pref 223 // tree. 224 mutable ValueType value_; 225 226 DISALLOW_COPY_AND_ASSIGN(Internal); 227 }; 228 internal()229 virtual Internal* internal() const { return internal_; } CreateInternal()230 virtual void CreateInternal() const { 231 internal_ = new Internal(); 232 } 233 234 // This method is used to do the actual sync with pref of the specified type. 235 virtual void UpdatePref(const ValueType& value); 236 237 mutable scoped_refptr<Internal> internal_; 238 239 DISALLOW_COPY_AND_ASSIGN(PrefMember); 240 }; 241 242 typedef PrefMember<bool> BooleanPrefMember; 243 typedef PrefMember<int> IntegerPrefMember; 244 typedef PrefMember<double> DoublePrefMember; 245 typedef PrefMember<std::string> StringPrefMember; 246 typedef PrefMember<FilePath> FilePathPrefMember; 247 typedef PrefMember<ListValue*> ListPrefMember; 248 249 #endif // CHROME_BROWSER_PREFS_PREF_MEMBER_H_ 250