diff options
Diffstat (limited to 'base/prefs/pref_member.h')
-rw-r--r-- | base/prefs/pref_member.h | 354 |
1 files changed, 354 insertions, 0 deletions
diff --git a/base/prefs/pref_member.h b/base/prefs/pref_member.h new file mode 100644 index 0000000..e0e88f5 --- /dev/null +++ b/base/prefs/pref_member.h @@ -0,0 +1,354 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// +// A helper class that stays in sync with a preference (bool, int, real, +// string or filepath). For example: +// +// class MyClass { +// public: +// MyClass(PrefService* prefs) { +// my_string_.Init(prefs::kHomePage, prefs); +// } +// private: +// StringPrefMember my_string_; +// }; +// +// my_string_ should stay in sync with the prefs::kHomePage pref and will +// update if either the pref changes or if my_string_.SetValue is called. +// +// An optional observer can be passed into the Init method which can be used to +// notify MyClass of changes. Note that if you use SetValue(), the observer +// will not be notified. + +#ifndef BASE_PREFS_PREF_MEMBER_H_ +#define BASE_PREFS_PREF_MEMBER_H_ + +#include <string> +#include <vector> + +#include "base/basictypes.h" +#include "base/bind.h" +#include "base/callback_forward.h" +#include "base/files/file_path.h" +#include "base/logging.h" +#include "base/memory/ref_counted.h" +#include "base/message_loop_proxy.h" +#include "base/prefs/base_prefs_export.h" +#include "base/prefs/pref_observer.h" +#include "base/values.h" + +class PrefService; + +namespace subtle { + +class BASE_PREFS_EXPORT PrefMemberBase : public PrefObserver { + public: + // Type of callback you can register if you need to know the name of + // the pref that is changing. + typedef base::Callback<void(const std::string&)> NamedChangeCallback; + + PrefService* prefs() { return prefs_; } + const PrefService* prefs() const { return prefs_; } + + protected: + class BASE_PREFS_EXPORT Internal + : public base::RefCountedThreadSafe<Internal> { + public: + Internal(); + + // Update the value, either by calling |UpdateValueInternal| directly + // or by dispatching to the right thread. + // Takes ownership of |value|. + void UpdateValue(base::Value* value, + bool is_managed, + bool is_user_modifiable, + const base::Closure& callback) const; + + void MoveToThread( + const scoped_refptr<base::MessageLoopProxy>& message_loop); + + // See PrefMember<> for description. + bool IsManaged() const { + return is_managed_; + } + + bool IsUserModifiable() const { + return is_user_modifiable_; + } + + protected: + friend class base::RefCountedThreadSafe<Internal>; + virtual ~Internal(); + + void CheckOnCorrectThread() const { + DCHECK(IsOnCorrectThread()); + } + + private: + // This method actually updates the value. It should only be called from + // the thread the PrefMember is on. + virtual bool UpdateValueInternal(const base::Value& value) const = 0; + + bool IsOnCorrectThread() const; + + scoped_refptr<base::MessageLoopProxy> thread_loop_; + mutable bool is_managed_; + mutable bool is_user_modifiable_; + + DISALLOW_COPY_AND_ASSIGN(Internal); + }; + + PrefMemberBase(); + virtual ~PrefMemberBase(); + + // See PrefMember<> for description. + void Init(const char* pref_name, PrefService* prefs, + const NamedChangeCallback& observer); + void Init(const char* pref_name, PrefService* prefs); + + virtual void CreateInternal() const = 0; + + // See PrefMember<> for description. + void Destroy(); + + void MoveToThread(const scoped_refptr<base::MessageLoopProxy>& message_loop); + + // PrefObserver + virtual void OnPreferenceChanged(PrefService* service, + const std::string& pref_name) OVERRIDE; + + void VerifyValuePrefName() const { + DCHECK(!pref_name_.empty()); + } + + // This method is used to do the actual sync with the preference. + // Note: it is logically const, because it doesn't modify the state + // seen by the outside world. It is just doing a lazy load behind the scenes. + void UpdateValueFromPref(const base::Closure& callback) const; + + // Verifies the preference name, and lazily loads the preference value if + // it hasn't been loaded yet. + void VerifyPref() const; + + const std::string& pref_name() const { return pref_name_; } + + virtual Internal* internal() const = 0; + + // Used to allow registering plain base::Closure callbacks. + static void InvokeUnnamedCallback(const base::Closure& callback, + const std::string& pref_name); + + private: + // Ordered the members to compact the class instance. + std::string pref_name_; + NamedChangeCallback observer_; + PrefService* prefs_; + + protected: + bool setting_value_; +}; + +// This function implements StringListPrefMember::UpdateValue(). +// It is exposed here for testing purposes. +bool BASE_PREFS_EXPORT PrefMemberVectorStringUpdate( + const base::Value& value, + std::vector<std::string>* string_vector); + +} // namespace subtle + +template <typename ValueType> +class PrefMember : public subtle::PrefMemberBase { + public: + // Defer initialization to an Init method so it's easy to make this class be + // a member variable. + PrefMember() {} + virtual ~PrefMember() {} + + // Do the actual initialization of the class. Use the two-parameter + // version if you don't want any notifications of changes. This + // method should only be called on the UI thread. + void Init(const char* pref_name, PrefService* prefs, + const NamedChangeCallback& observer) { + subtle::PrefMemberBase::Init(pref_name, prefs, observer); + } + void Init(const char* pref_name, PrefService* prefs, + const base::Closure& observer) { + subtle::PrefMemberBase::Init( + pref_name, prefs, + base::Bind(&PrefMemberBase::InvokeUnnamedCallback, observer)); + } + void Init(const char* pref_name, PrefService* prefs) { + subtle::PrefMemberBase::Init(pref_name, prefs); + } + + // Unsubscribes the PrefMember from the PrefService. After calling this + // function, the PrefMember may not be used any more on the UI thread. + // Assuming |MoveToThread| was previously called, |GetValue|, |IsManaged|, + // and |IsUserModifiable| can still be called from the other thread but + // the results will no longer update from the PrefService. + // This method should only be called on the UI thread. + void Destroy() { + subtle::PrefMemberBase::Destroy(); + } + + // Moves the PrefMember to another thread, allowing read accesses from there. + // Changes from the PrefService will be propagated asynchronously + // via PostTask. + // This method should only be used from the thread the PrefMember is currently + // on, which is the UI thread by default. + void MoveToThread(const scoped_refptr<base::MessageLoopProxy>& message_loop) { + subtle::PrefMemberBase::MoveToThread(message_loop); + } + + // Check whether the pref is managed, i.e. controlled externally through + // enterprise configuration management (e.g. windows group policy). Returns + // false for unknown prefs. + // This method should only be used from the thread the PrefMember is currently + // on, which is the UI thread unless changed by |MoveToThread|. + bool IsManaged() const { + VerifyPref(); + return internal_->IsManaged(); + } + + // Checks whether the pref can be modified by the user. This returns false + // when the pref is managed by a policy or an extension, and when a command + // line flag overrides the pref. + // This method should only be used from the thread the PrefMember is currently + // on, which is the UI thread unless changed by |MoveToThread|. + bool IsUserModifiable() const { + VerifyPref(); + return internal_->IsUserModifiable(); + } + + // Retrieve the value of the member variable. + // This method should only be used from the thread the PrefMember is currently + // on, which is the UI thread unless changed by |MoveToThread|. + ValueType GetValue() const { + VerifyPref(); + return internal_->value(); + } + + // Provided as a convenience. + ValueType operator*() const { + return GetValue(); + } + + // Set the value of the member variable. + // This method should only be called on the UI thread. + void SetValue(const ValueType& value) { + VerifyValuePrefName(); + setting_value_ = true; + UpdatePref(value); + setting_value_ = false; + } + + // Returns the pref name. + const std::string& GetPrefName() const { + return pref_name(); + } + + private: + class Internal : public subtle::PrefMemberBase::Internal { + public: + Internal() : value_(ValueType()) {} + + ValueType value() { + CheckOnCorrectThread(); + return value_; + } + + protected: + virtual ~Internal() {} + + virtual BASE_PREFS_EXPORT bool UpdateValueInternal( + const base::Value& value) const OVERRIDE; + + // We cache the value of the pref so we don't have to keep walking the pref + // tree. + mutable ValueType value_; + + DISALLOW_COPY_AND_ASSIGN(Internal); + }; + + virtual Internal* internal() const OVERRIDE { return internal_; } + virtual void CreateInternal() const OVERRIDE { + internal_ = new Internal(); + } + + // This method is used to do the actual sync with pref of the specified type. + void BASE_PREFS_EXPORT UpdatePref(const ValueType& value); + + mutable scoped_refptr<Internal> internal_; + + DISALLOW_COPY_AND_ASSIGN(PrefMember); +}; + +// Declaration of template specialization need to be repeated here +// specifically for each specialization (rather than just once above) +// or at least one of our compilers won't be happy in all cases. +// Specifically, it was failing on ChromeOS with a complaint about +// PrefMember<FilePath>::UpdateValueInternal not being defined when +// built in a chroot with the following parameters: +// +// FEATURES="noclean nostrip" USE="-chrome_debug -chrome_remoting +// -chrome_internal -chrome_pdf component_build" +// ~/trunk/goma/goma-wrapper cros_chrome_make --board=${BOARD} +// --install --runhooks + +template <> +BASE_PREFS_EXPORT void PrefMember<bool>::UpdatePref(const bool& value); + +template <> +BASE_PREFS_EXPORT bool PrefMember<bool>::Internal::UpdateValueInternal( + const Value& value) const; + +template <> +BASE_PREFS_EXPORT void PrefMember<int>::UpdatePref(const int& value); + +template <> +BASE_PREFS_EXPORT bool PrefMember<int>::Internal::UpdateValueInternal( + const Value& value) const; + +template <> +BASE_PREFS_EXPORT void PrefMember<double>::UpdatePref(const double& value); + +template <> +BASE_PREFS_EXPORT bool PrefMember<double>::Internal::UpdateValueInternal( + const Value& value) const; + +template <> +BASE_PREFS_EXPORT void PrefMember<std::string>::UpdatePref( + const std::string& value); + +template <> +BASE_PREFS_EXPORT bool PrefMember<std::string>::Internal::UpdateValueInternal( + const base::Value& value) const; + +template <> +BASE_PREFS_EXPORT void PrefMember<base::FilePath>::UpdatePref( + const base::FilePath& value); + +template <> +BASE_PREFS_EXPORT bool +PrefMember<base::FilePath>::Internal::UpdateValueInternal( + const base::Value& value) const; + +template <> +BASE_PREFS_EXPORT void PrefMember<std::vector<std::string> >::UpdatePref( + const std::vector<std::string>& value); + +template <> +BASE_PREFS_EXPORT bool +PrefMember<std::vector<std::string> >::Internal::UpdateValueInternal( + const base::Value& value) const; + +typedef PrefMember<bool> BooleanPrefMember; +typedef PrefMember<int> IntegerPrefMember; +typedef PrefMember<double> DoublePrefMember; +typedef PrefMember<std::string> StringPrefMember; +typedef PrefMember<base::FilePath> FilePathPrefMember; +// This preference member is expensive for large string arrays. +typedef PrefMember<std::vector<std::string> > StringListPrefMember; + +#endif // BASE_PREFS_PREF_MEMBER_H_ |