1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
|
// Copyright (c) 2011 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, NULL /* no observer */);
// }
// 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 CHROME_BROWSER_PREFS_PREF_MEMBER_H_
#define CHROME_BROWSER_PREFS_PREF_MEMBER_H_
#pragma once
#include <string>
#include "base/basictypes.h"
#include "base/file_path.h"
#include "base/ref_counted.h"
#include "base/values.h"
#include "chrome/common/notification_observer.h"
#include "content/browser/browser_thread.h"
class PrefService;
namespace subtle {
class PrefMemberBase : public NotificationObserver {
protected:
class 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|.
virtual void UpdateValue(Value* value) const;
void MoveToThread(BrowserThread::ID thread_id);
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 Value& value) const = 0;
bool IsOnCorrectThread() const;
BrowserThread::ID thread_id_;
DISALLOW_COPY_AND_ASSIGN(Internal);
};
PrefMemberBase();
virtual ~PrefMemberBase();
// See PrefMember<> for description.
void Init(const char* pref_name, PrefService* prefs,
NotificationObserver* observer);
virtual void CreateInternal() const = 0;
// See PrefMember<> for description.
void Destroy();
// See PrefMember<> for description.
bool IsManaged() const;
void MoveToThread(BrowserThread::ID thread_id);
// NotificationObserver
virtual void Observe(NotificationType type,
const NotificationSource& source,
const NotificationDetails& details);
void VerifyValuePrefName() const;
// 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.
virtual void UpdateValueFromPref() const;
const std::string& pref_name() const { return pref_name_; }
PrefService* prefs() { return prefs_; }
const PrefService* prefs() const { return prefs_; }
virtual Internal* internal() const = 0;
// Ordered the members to compact the class instance.
private:
std::string pref_name_;
NotificationObserver* observer_;
PrefService* prefs_;
protected:
bool setting_value_;
};
} // 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. |observer| may be null 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,
NotificationObserver* observer) {
subtle::PrefMemberBase::Init(pref_name, prefs, observer);
}
// Unsubscribes the PrefMember from the PrefService. After calling this
// function, the PrefMember may not be used any more.
// 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(BrowserThread::ID thread_id) {
subtle::PrefMemberBase::MoveToThread(thread_id);
}
// 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 called on the UI thread.
bool IsManaged() const {
return subtle::PrefMemberBase::IsManaged();
}
// 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 {
VerifyValuePrefName();
// We lazily fetch the value from the pref service the first time GetValue
// is called.
if (!internal_.get())
UpdateValueFromPref();
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;
}
// Set the value of the member variable if it is not managed.
// This method should only be called on the UI thread.
void SetValueIfNotManaged(const ValueType& value) {
if (!IsManaged()) {
SetValue(value);
}
}
// 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 bool UpdateValueInternal(const Value& value) const;
// 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 { return internal_; }
virtual void CreateInternal() const {
internal_ = new Internal();
}
// This method is used to do the actual sync with pref of the specified type.
virtual void UpdatePref(const ValueType& value);
mutable scoped_refptr<Internal> internal_;
DISALLOW_COPY_AND_ASSIGN(PrefMember);
};
typedef PrefMember<bool> BooleanPrefMember;
typedef PrefMember<int> IntegerPrefMember;
typedef PrefMember<double> DoublePrefMember;
typedef PrefMember<std::string> StringPrefMember;
typedef PrefMember<FilePath> FilePathPrefMember;
#endif // CHROME_BROWSER_PREFS_PREF_MEMBER_H_
|