1 // Copyright 2012 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 // A helper class that stays in sync with a preference (bool, int, real,
6 // string or filepath). For example:
10 // MyClass(PrefService* prefs) {
11 // my_string_.Init(prefs::kHomePage, prefs);
14 // StringPrefMember my_string_;
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.
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.
24 #ifndef COMPONENTS_PREFS_PREF_MEMBER_H_
25 #define COMPONENTS_PREFS_PREF_MEMBER_H_
30 #include "base/check.h"
31 #include "base/files/file_path.h"
32 #include "base/functional/bind.h"
33 #include "base/functional/callback_forward.h"
34 #include "base/memory/raw_ptr.h"
35 #include "base/memory/ref_counted.h"
36 #include "base/task/sequenced_task_runner.h"
37 #include "base/values.h"
38 #include "components/prefs/pref_observer.h"
39 #include "components/prefs/prefs_export.h"
45 class COMPONENTS_PREFS_EXPORT PrefMemberBase : public PrefObserver {
47 // Type of callback you can register if you need to know the name of
48 // the pref that is changing.
49 using NamedChangeCallback = base::RepeatingCallback<void(const std::string&)>;
51 PrefService* prefs() { return prefs_; }
52 const PrefService* prefs() const { return prefs_; }
55 class COMPONENTS_PREFS_EXPORT Internal
56 : public base::RefCountedThreadSafe<Internal> {
60 Internal(const Internal&) = delete;
61 Internal& operator=(const Internal&) = delete;
63 // Update the value, either by calling |UpdateValueInternal| directly
64 // or by dispatching to the right sequence.
65 // Takes ownership of |value|.
66 void UpdateValue(base::Value* value,
68 bool is_user_modifiable,
69 bool is_default_value,
70 base::OnceClosure callback) const;
72 void MoveToSequence(scoped_refptr<base::SequencedTaskRunner> task_runner);
74 // See PrefMember<> for description.
75 bool IsManaged() const { return is_managed_; }
76 bool IsUserModifiable() const { return is_user_modifiable_; }
77 bool IsDefaultValue() const { return is_default_value_; }
80 friend class base::RefCountedThreadSafe<Internal>;
83 void CheckOnCorrectSequence() const { DCHECK(IsOnCorrectSequence()); }
86 // This method actually updates the value. It should only be called from
87 // the sequence the PrefMember is on.
88 virtual bool UpdateValueInternal(const base::Value& value) const = 0;
90 bool IsOnCorrectSequence() const;
92 scoped_refptr<base::SequencedTaskRunner> owning_task_runner_;
93 mutable bool is_managed_ = false;
94 mutable bool is_user_modifiable_ = false;
95 mutable bool is_default_value_ = false;
99 virtual ~PrefMemberBase();
101 // See PrefMember<> for description.
102 void Init(const std::string& pref_name,
104 const NamedChangeCallback& observer);
105 void Init(const std::string& pref_name, PrefService* prefs);
107 virtual void CreateInternal() const = 0;
109 // See PrefMember<> for description.
112 void MoveToSequence(scoped_refptr<base::SequencedTaskRunner> task_runner);
115 void OnPreferenceChanged(PrefService* service,
116 const std::string& pref_name) override;
118 void VerifyValuePrefName() const {
119 DCHECK(!pref_name_.empty());
122 // This method is used to do the actual sync with the preference.
123 // Note: it is logically const, because it doesn't modify the state
124 // seen by the outside world. It is just doing a lazy load behind the scenes.
125 void UpdateValueFromPref(base::OnceClosure callback) const;
127 // Verifies the preference name, and lazily loads the preference value if
128 // it hasn't been loaded yet.
129 void VerifyPref() const;
131 const std::string& pref_name() const { return pref_name_; }
133 virtual Internal* internal() const = 0;
135 // Used to allow registering plain base::RepeatingClosure callbacks.
136 static void InvokeUnnamedCallback(const base::RepeatingClosure& callback,
137 const std::string& pref_name);
140 // Ordered the members to compact the class instance.
141 std::string pref_name_;
142 NamedChangeCallback observer_;
143 raw_ptr<PrefService> prefs_;
149 // This function implements StringListPrefMember::UpdateValue().
150 // It is exposed here for testing purposes.
151 bool COMPONENTS_PREFS_EXPORT PrefMemberVectorStringUpdate(
152 const base::Value& value,
153 std::vector<std::string>* string_vector);
155 } // namespace subtle
157 template <typename ValueType>
158 class PrefMember : public subtle::PrefMemberBase {
160 // Defer initialization to an Init method so it's easy to make this class be
161 // a member variable.
164 PrefMember(const PrefMember&) = delete;
165 PrefMember& operator=(const PrefMember&) = delete;
167 virtual ~PrefMember() {}
169 // Do the actual initialization of the class. Use the two-parameter
170 // version if you don't want any notifications of changes. This
171 // method should only be called on the UI thread.
172 void Init(const std::string& pref_name,
174 const NamedChangeCallback& observer) {
175 subtle::PrefMemberBase::Init(pref_name, prefs, observer);
177 void Init(const std::string& pref_name,
179 const base::RepeatingClosure& observer) {
180 subtle::PrefMemberBase::Init(
182 base::BindRepeating(&PrefMemberBase::InvokeUnnamedCallback, observer));
184 void Init(const std::string& pref_name, PrefService* prefs) {
185 subtle::PrefMemberBase::Init(pref_name, prefs);
188 // Unsubscribes the PrefMember from the PrefService. After calling this
189 // function, the PrefMember may not be used any more on the UI thread.
190 // Assuming |MoveToSequence| was previously called, |GetValue|, |IsManaged|,
191 // and |IsUserModifiable| can still be called from the other sequence but
192 // the results will no longer update from the PrefService.
193 // This method should only be called on the UI thread.
195 subtle::PrefMemberBase::Destroy();
198 // Moves the PrefMember to another sequence, allowing read accesses from
199 // there. Changes from the PrefService will be propagated asynchronously
201 // This method should only be used from the sequence the PrefMember is
202 // currently on, which is the UI thread by default.
203 void MoveToSequence(scoped_refptr<base::SequencedTaskRunner> task_runner) {
204 subtle::PrefMemberBase::MoveToSequence(task_runner);
207 // Check whether the pref is managed, i.e. controlled externally through
208 // enterprise configuration management (e.g. windows group policy). Returns
209 // false for unknown prefs.
210 // This method should only be used from the sequence the PrefMember is
211 // currently on, which is the UI thread unless changed by |MoveToSequence|.
212 bool IsManaged() const {
214 return internal_->IsManaged();
217 // Checks whether the pref can be modified by the user. This returns false
218 // when the pref is managed by a policy or an extension, and when a command
219 // line flag overrides the pref.
220 // This method should only be used from the sequence the PrefMember is
221 // currently on, which is the UI thread unless changed by |MoveToSequence|.
222 bool IsUserModifiable() const {
224 return internal_->IsUserModifiable();
227 // Checks whether the pref is currently using its default value, and has not
228 // been set by any higher-priority source (even with the same value). This
229 // method should only be used from the sequence the PrefMember is currently
230 // on, which is the UI thread unless changed by |MoveToSequence|.
231 bool IsDefaultValue() const {
233 return internal_->IsDefaultValue();
236 // Retrieve the value of the member variable.
237 // This method should only be used from the sequence the PrefMember is
238 // currently on, which is the UI thread unless changed by |MoveToSequence|.
239 ValueType GetValue() const {
241 return internal_->value();
244 // Provided as a convenience.
245 ValueType operator*() const {
249 // Set the value of the member variable.
250 // This method should only be called on the UI thread.
251 void SetValue(const ValueType& value) {
252 VerifyValuePrefName();
253 setting_value_ = true;
255 setting_value_ = false;
258 // Returns the pref name.
259 const std::string& GetPrefName() const {
264 class Internal : public subtle::PrefMemberBase::Internal {
266 Internal() : value_(ValueType()) {}
268 Internal(const Internal&) = delete;
269 Internal& operator=(const Internal&) = delete;
272 CheckOnCorrectSequence();
277 ~Internal() override {}
279 COMPONENTS_PREFS_EXPORT bool UpdateValueInternal(
280 const base::Value& value) const override;
282 // We cache the value of the pref so we don't have to keep walking the pref
284 mutable ValueType value_;
287 Internal* internal() const override { return internal_.get(); }
288 void CreateInternal() const override { internal_ = new Internal(); }
290 // This method is used to do the actual sync with pref of the specified type.
291 void COMPONENTS_PREFS_EXPORT UpdatePref(const ValueType& value);
293 mutable scoped_refptr<Internal> internal_;
296 // Declaration of template specialization need to be repeated here
297 // specifically for each specialization (rather than just once above)
298 // or at least one of our compilers won't be happy in all cases.
299 // Specifically, it was failing on ChromeOS with a complaint about
300 // PrefMember<FilePath>::UpdateValueInternal not being defined when
301 // built in a chroot with the following parameters:
303 // FEATURES="noclean nostrip" USE="-chrome_debug -chrome_remoting
304 // -chrome_internal -chrome_pdf component_build"
305 // ~/trunk/goma/goma-wrapper cros_chrome_make --board=${BOARD}
306 // --install --runhooks
309 COMPONENTS_PREFS_EXPORT void PrefMember<bool>::UpdatePref(const bool& value);
312 COMPONENTS_PREFS_EXPORT bool PrefMember<bool>::Internal::UpdateValueInternal(
313 const base::Value& value) const;
316 COMPONENTS_PREFS_EXPORT void PrefMember<int>::UpdatePref(const int& value);
319 COMPONENTS_PREFS_EXPORT bool PrefMember<int>::Internal::UpdateValueInternal(
320 const base::Value& value) const;
323 COMPONENTS_PREFS_EXPORT void
324 PrefMember<double>::UpdatePref(const double& value);
327 COMPONENTS_PREFS_EXPORT bool PrefMember<double>::Internal::UpdateValueInternal(
328 const base::Value& value) const;
331 COMPONENTS_PREFS_EXPORT void PrefMember<std::string>::UpdatePref(
332 const std::string& value);
335 COMPONENTS_PREFS_EXPORT bool
336 PrefMember<std::string>::Internal::UpdateValueInternal(
337 const base::Value& value) const;
340 COMPONENTS_PREFS_EXPORT void PrefMember<base::FilePath>::UpdatePref(
341 const base::FilePath& value);
344 COMPONENTS_PREFS_EXPORT bool
345 PrefMember<base::FilePath>::Internal::UpdateValueInternal(
346 const base::Value& value) const;
349 COMPONENTS_PREFS_EXPORT void PrefMember<std::vector<std::string>>::UpdatePref(
350 const std::vector<std::string>& value);
353 COMPONENTS_PREFS_EXPORT bool
354 PrefMember<std::vector<std::string>>::Internal::UpdateValueInternal(
355 const base::Value& value) const;
357 typedef PrefMember<bool> BooleanPrefMember;
358 typedef PrefMember<int> IntegerPrefMember;
359 typedef PrefMember<double> DoublePrefMember;
360 typedef PrefMember<std::string> StringPrefMember;
361 typedef PrefMember<base::FilePath> FilePathPrefMember;
362 // This preference member is expensive for large string arrays.
363 typedef PrefMember<std::vector<std::string>> StringListPrefMember;
365 #endif // COMPONENTS_PREFS_PREF_MEMBER_H_