Home | History | Annotate | Download | only in prefs
      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 #include "chrome/browser/prefs/pref_member.h"
      6 
      7 #include "base/logging.h"
      8 #include "base/value_conversions.h"
      9 #include "chrome/browser/prefs/pref_service.h"
     10 #include "content/common/notification_type.h"
     11 
     12 namespace subtle {
     13 
     14 PrefMemberBase::PrefMemberBase()
     15     : observer_(NULL),
     16       prefs_(NULL),
     17       setting_value_(false) {
     18 }
     19 
     20 PrefMemberBase::~PrefMemberBase() {
     21   Destroy();
     22 }
     23 
     24 
     25 void PrefMemberBase::Init(const char* pref_name, PrefService* prefs,
     26                           NotificationObserver* observer) {
     27   DCHECK(pref_name);
     28   DCHECK(prefs);
     29   DCHECK(pref_name_.empty());  // Check that Init is only called once.
     30   observer_ = observer;
     31   prefs_ = prefs;
     32   pref_name_ = pref_name;
     33   DCHECK(!pref_name_.empty());
     34 
     35   // Add ourselves as a pref observer so we can keep our local value in sync.
     36   prefs_->AddPrefObserver(pref_name, this);
     37 }
     38 
     39 void PrefMemberBase::Destroy() {
     40   if (prefs_ && !pref_name_.empty()) {
     41     prefs_->RemovePrefObserver(pref_name_.c_str(), this);
     42     prefs_ = NULL;
     43   }
     44 }
     45 
     46 void PrefMemberBase::MoveToThread(BrowserThread::ID thread_id) {
     47   VerifyValuePrefName();
     48   // Load the value from preferences if it hasn't been loaded so far.
     49   if (!internal())
     50     UpdateValueFromPref();
     51   internal()->MoveToThread(thread_id);
     52 }
     53 
     54 void PrefMemberBase::Observe(NotificationType type,
     55                              const NotificationSource& source,
     56                              const NotificationDetails& details) {
     57   VerifyValuePrefName();
     58   DCHECK(NotificationType::PREF_CHANGED == type);
     59   UpdateValueFromPref();
     60   if (!setting_value_ && observer_)
     61     observer_->Observe(type, source, details);
     62 }
     63 
     64 void PrefMemberBase::UpdateValueFromPref() const {
     65   VerifyValuePrefName();
     66   const PrefService::Preference* pref =
     67       prefs_->FindPreference(pref_name_.c_str());
     68   DCHECK(pref);
     69   if (!internal())
     70     CreateInternal();
     71   internal()->UpdateValue(pref->GetValue()->DeepCopy(), pref->IsManaged());
     72 }
     73 
     74 void PrefMemberBase::VerifyPref() const {
     75   VerifyValuePrefName();
     76   if (!internal())
     77     UpdateValueFromPref();
     78 }
     79 
     80 PrefMemberBase::Internal::Internal() : thread_id_(BrowserThread::UI) { }
     81 PrefMemberBase::Internal::~Internal() { }
     82 
     83 bool PrefMemberBase::Internal::IsOnCorrectThread() const {
     84   // In unit tests, there may not be a UI thread.
     85   return (BrowserThread::CurrentlyOn(thread_id_) ||
     86           (thread_id_ == BrowserThread::UI &&
     87            !BrowserThread::IsMessageLoopValid(BrowserThread::UI)));
     88 }
     89 
     90 void PrefMemberBase::Internal::UpdateValue(Value* v, bool is_managed) const {
     91   scoped_ptr<Value> value(v);
     92   if (IsOnCorrectThread()) {
     93     bool rv = UpdateValueInternal(*value);
     94     DCHECK(rv);
     95     is_managed_ = is_managed;
     96   } else {
     97     bool rv = BrowserThread::PostTask(
     98         thread_id_, FROM_HERE,
     99         NewRunnableMethod(this,
    100                           &PrefMemberBase::Internal::UpdateValue,
    101                           value.release(), is_managed));
    102     DCHECK(rv);
    103   }
    104 }
    105 
    106 void PrefMemberBase::Internal::MoveToThread(BrowserThread::ID thread_id) {
    107   CheckOnCorrectThread();
    108   thread_id_ = thread_id;
    109 }
    110 
    111 }  // namespace subtle
    112 
    113 template <>
    114 void PrefMember<bool>::UpdatePref(const bool& value) {
    115   prefs()->SetBoolean(pref_name().c_str(), value);
    116 }
    117 
    118 template <>
    119 bool PrefMember<bool>::Internal::UpdateValueInternal(const Value& value) const {
    120   return value.GetAsBoolean(&value_);
    121 }
    122 
    123 template <>
    124 void PrefMember<int>::UpdatePref(const int& value) {
    125   prefs()->SetInteger(pref_name().c_str(), value);
    126 }
    127 
    128 template <>
    129 bool PrefMember<int>::Internal::UpdateValueInternal(const Value& value) const {
    130   return value.GetAsInteger(&value_);
    131 }
    132 
    133 template <>
    134 void PrefMember<double>::UpdatePref(const double& value) {
    135   prefs()->SetDouble(pref_name().c_str(), value);
    136 }
    137 
    138 template <>
    139 bool PrefMember<double>::Internal::UpdateValueInternal(const Value& value)
    140     const {
    141   return value.GetAsDouble(&value_);
    142 }
    143 
    144 template <>
    145 void PrefMember<std::string>::UpdatePref(const std::string& value) {
    146   prefs()->SetString(pref_name().c_str(), value);
    147 }
    148 
    149 template <>
    150 bool PrefMember<std::string>::Internal::UpdateValueInternal(const Value& value)
    151     const {
    152   return value.GetAsString(&value_);
    153 }
    154 
    155 template <>
    156 void PrefMember<FilePath>::UpdatePref(const FilePath& value) {
    157   prefs()->SetFilePath(pref_name().c_str(), value);
    158 }
    159 
    160 template <>
    161 bool PrefMember<FilePath>::Internal::UpdateValueInternal(const Value& value)
    162     const {
    163   return base::GetValueAsFilePath(value, &value_);
    164 }
    165 
    166 template <>
    167 void PrefMember<ListValue*>::UpdatePref(ListValue*const& value) {
    168   // prefs takes ownership of the value passed, so make a copy.
    169   prefs()->SetList(pref_name().c_str(), value->DeepCopy());
    170 }
    171 
    172 template <>
    173 bool PrefMember<ListValue*>::Internal::UpdateValueInternal(const Value& value)
    174     const {
    175   // Verify the type before doing the DeepCopy to avoid leaking the copy.
    176   if (value.GetType() != Value::TYPE_LIST)
    177     return false;
    178 
    179   // ListPrefMember keeps a copy of the ListValue and of its contents.
    180   // GetAsList() assigns its |this| (the DeepCopy) to |value_|.
    181   delete value_;
    182   return value.DeepCopy()->GetAsList(&value_);
    183 }
    184 
    185 template <>
    186 PrefMember<ListValue*>::Internal::~Internal() {
    187   delete value_;
    188 }
    189 
    190