Home | History | Annotate | Download | only in prefs
      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