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