• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
PrefMemberBase()14 PrefMemberBase::PrefMemberBase()
15     : observer_(NULL),
16       prefs_(NULL),
17       setting_value_(false) {
18 }
19 
~PrefMemberBase()20 PrefMemberBase::~PrefMemberBase() {
21   Destroy();
22 }
23 
24 
Init(const char * pref_name,PrefService * prefs,NotificationObserver * observer)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 
Destroy()39 void PrefMemberBase::Destroy() {
40   if (prefs_ && !pref_name_.empty()) {
41     prefs_->RemovePrefObserver(pref_name_.c_str(), this);
42     prefs_ = NULL;
43   }
44 }
45 
MoveToThread(BrowserThread::ID thread_id)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 
Observe(NotificationType type,const NotificationSource & source,const NotificationDetails & details)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 
UpdateValueFromPref() const64 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 
VerifyPref() const74 void PrefMemberBase::VerifyPref() const {
75   VerifyValuePrefName();
76   if (!internal())
77     UpdateValueFromPref();
78 }
79 
Internal()80 PrefMemberBase::Internal::Internal() : thread_id_(BrowserThread::UI) { }
~Internal()81 PrefMemberBase::Internal::~Internal() { }
82 
IsOnCorrectThread() const83 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 
UpdateValue(Value * v,bool is_managed) const90 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 
MoveToThread(BrowserThread::ID thread_id)106 void PrefMemberBase::Internal::MoveToThread(BrowserThread::ID thread_id) {
107   CheckOnCorrectThread();
108   thread_id_ = thread_id;
109 }
110 
111 }  // namespace subtle
112 
113 template <>
UpdatePref(const bool & value)114 void PrefMember<bool>::UpdatePref(const bool& value) {
115   prefs()->SetBoolean(pref_name().c_str(), value);
116 }
117 
118 template <>
UpdateValueInternal(const Value & value) const119 bool PrefMember<bool>::Internal::UpdateValueInternal(const Value& value) const {
120   return value.GetAsBoolean(&value_);
121 }
122 
123 template <>
UpdatePref(const int & value)124 void PrefMember<int>::UpdatePref(const int& value) {
125   prefs()->SetInteger(pref_name().c_str(), value);
126 }
127 
128 template <>
UpdateValueInternal(const Value & value) const129 bool PrefMember<int>::Internal::UpdateValueInternal(const Value& value) const {
130   return value.GetAsInteger(&value_);
131 }
132 
133 template <>
UpdatePref(const double & value)134 void PrefMember<double>::UpdatePref(const double& value) {
135   prefs()->SetDouble(pref_name().c_str(), value);
136 }
137 
138 template <>
UpdateValueInternal(const Value & value) const139 bool PrefMember<double>::Internal::UpdateValueInternal(const Value& value)
140     const {
141   return value.GetAsDouble(&value_);
142 }
143 
144 template <>
UpdatePref(const std::string & value)145 void PrefMember<std::string>::UpdatePref(const std::string& value) {
146   prefs()->SetString(pref_name().c_str(), value);
147 }
148 
149 template <>
UpdateValueInternal(const Value & value) const150 bool PrefMember<std::string>::Internal::UpdateValueInternal(const Value& value)
151     const {
152   return value.GetAsString(&value_);
153 }
154 
155 template <>
UpdatePref(const FilePath & value)156 void PrefMember<FilePath>::UpdatePref(const FilePath& value) {
157   prefs()->SetFilePath(pref_name().c_str(), value);
158 }
159 
160 template <>
UpdateValueInternal(const Value & value) const161 bool PrefMember<FilePath>::Internal::UpdateValueInternal(const Value& value)
162     const {
163   return base::GetValueAsFilePath(value, &value_);
164 }
165 
166 template <>
UpdatePref(ListValue * const & value)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 <>
UpdateValueInternal(const Value & value) const173 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 <>
~Internal()186 PrefMember<ListValue*>::Internal::~Internal() {
187   delete value_;
188 }
189 
190