OLD | NEW |
---|---|
1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "chrome/browser/extensions/extension_pref_store.h" | 5 #include "chrome/browser/extensions/extension_pref_store.h" |
6 | 6 |
7 #include "base/logging.h" | |
8 #include "base/values.h" | |
9 #include "chrome/browser/browser_process.h" | |
10 #include "chrome/browser/prefs/pref_service.h" | |
11 #include "chrome/browser/profile.h" | 7 #include "chrome/browser/profile.h" |
12 #include "chrome/common/extensions/extension.h" | |
13 #include "chrome/common/notification_service.h" | |
14 | 8 |
15 ExtensionPrefStore::ExtensionPrefStore(Profile* profile, | 9 ExtensionPrefStore::ExtensionPrefStore(Profile* profile) : profile_(profile) { |
16 PrefNotifier::PrefStoreType type) | 10 // |profile| may be NULL in case of LocalState. |
17 : prefs_(new DictionaryValue()), | 11 if (profile_) |
Aaron Boodman
2010/12/03 09:02:11
In Profile, I commented that I didn't understand w
battre (please use the other)
2010/12/03 19:32:58
Removed pointer from profile as discussed. Done.
| |
18 profile_(profile), | 12 profile_->SetExtensionPrefStore(this); |
19 type_(type) { | |
20 RegisterObservers(); | |
21 } | 13 } |
22 | 14 |
23 ExtensionPrefStore::~ExtensionPrefStore() { | 15 ExtensionPrefStore::~ExtensionPrefStore() { |
24 STLDeleteElements(&extension_stack_); | 16 if (profile_) |
25 notification_registrar_.RemoveAll(); | 17 profile_->SetExtensionPrefStore(NULL); |
26 } | 18 } |
27 | |
28 void ExtensionPrefStore::InstallExtensionPref(const Extension* extension, | |
29 const char* new_pref_path, | |
30 Value* new_pref_value) { | |
31 ExtensionStack::iterator i; | |
32 for (i = extension_stack_.begin(); i != extension_stack_.end(); ++i) { | |
33 if ((*i)->extension == extension) | |
34 break; | |
35 } | |
36 | |
37 // If this extension is not already in the stack, add it. Otherwise, update | |
38 // or add the value of this preference, but don't change the extension's | |
39 // position in the stack. We store the extension even if this preference | |
40 // isn't registered with our PrefService, so that the ordering of extensions | |
41 // is consistent among all local-state and user ExtensionPrefStores. | |
42 PrefService* pref_service = GetPrefService(); | |
43 // The pref_service may be NULL in unit testing. | |
44 bool is_registered_pref = (pref_service == NULL || | |
45 pref_service->FindPreference(new_pref_path) != NULL); | |
46 PrefValueMap* pref_values; | |
47 if (i == extension_stack_.end()) { | |
48 pref_values = new PrefValueMap(); | |
49 if (is_registered_pref) | |
50 (*pref_values)[new_pref_path] = new_pref_value; | |
51 | |
52 ExtensionPrefs* extension_prefs = new ExtensionPrefs(extension, | |
53 pref_values); | |
54 extension_stack_.push_front(extension_prefs); | |
55 } else if (is_registered_pref) { | |
56 pref_values = (*i)->pref_values; | |
57 delete (*pref_values)[new_pref_path]; | |
58 (*pref_values)[new_pref_path] = new_pref_value; | |
59 } | |
60 | |
61 // Apply the preference to our local |prefs_| store. | |
62 UpdateOnePref(new_pref_path); | |
63 } | |
64 | |
65 void ExtensionPrefStore::UninstallExtension(const Extension* extension) { | |
66 // Remove this extension from the stack. | |
67 for (ExtensionStack::iterator i = extension_stack_.begin(); | |
68 i != extension_stack_.end(); ++i) { | |
69 if ((*i)->extension == extension) { | |
70 scoped_ptr<ExtensionPrefs> to_be_deleted(*i); | |
71 extension_stack_.erase(i); | |
72 UpdatePrefs(to_be_deleted->pref_values); | |
73 return; | |
74 } | |
75 } | |
76 } | |
77 | |
78 void ExtensionPrefStore::GetExtensionIDs(std::vector<std::string>* result) { | |
79 for (ExtensionStack::iterator i = extension_stack_.begin(); | |
80 i != extension_stack_.end(); ++i) { | |
81 (*result).push_back((*i)->extension->id()); | |
82 } | |
83 } | |
84 | |
85 // This could be sped up by keeping track of which extension currently controls | |
86 // a given preference, among other optimizations. But probably fewer than 10 | |
87 // installed extensions will be trying to control any preferences, so stick | |
88 // with this simpler algorithm until it causes a problem. | |
89 void ExtensionPrefStore::UpdateOnePref(const char* path) { | |
90 PrefService* pref_service = GetPrefService(); | |
91 | |
92 // There are at least two PrefServices, one for local state and one for | |
93 // user prefs. (See browser_main.cc.) Different preferences are registered | |
94 // in each; if this one doesn't have the desired pref registered, we ignore | |
95 // it and let the other one handle it. | |
96 // The pref_service may be NULL in unit testing. | |
97 if (pref_service && !pref_service->FindPreference(path)) | |
98 return; | |
99 | |
100 // Save the old value before removing it from the local cache. | |
101 Value* my_old_value_ptr = NULL; | |
102 prefs_->Get(path, &my_old_value_ptr); | |
103 scoped_ptr<Value> my_old_value; | |
104 if (my_old_value_ptr) | |
105 my_old_value.reset(my_old_value_ptr->DeepCopy()); | |
106 | |
107 // DictionaryValue::Set complains if a key is overwritten with the same | |
108 // value, so remove it first. | |
109 prefs_->Remove(path, NULL); | |
110 | |
111 // Find the first extension that wants to set this pref and use its value. | |
112 Value* my_new_value = NULL; | |
113 for (ExtensionStack::iterator ext_iter = extension_stack_.begin(); | |
114 ext_iter != extension_stack_.end(); ++ext_iter) { | |
115 PrefValueMap::iterator value_iter = (*ext_iter)->pref_values->find(path); | |
116 if (value_iter != (*ext_iter)->pref_values->end()) { | |
117 prefs_->Set(path, (*value_iter).second->DeepCopy()); | |
118 my_new_value = (*value_iter).second; | |
119 break; | |
120 } | |
121 } | |
122 | |
123 if (pref_service) { | |
124 bool value_changed = true; | |
125 if (!my_old_value.get() && !my_new_value) { | |
126 value_changed = false; | |
127 } else if (my_old_value.get() && | |
128 my_new_value && | |
129 my_old_value->Equals(my_new_value)) { | |
130 value_changed = false; | |
131 } | |
132 | |
133 if (value_changed) | |
134 pref_service->pref_notifier()->OnPreferenceSet(path, type_); | |
135 } | |
136 } | |
137 | |
138 void ExtensionPrefStore::UpdatePrefs(const PrefValueMap* pref_values) { | |
139 if (!pref_values) | |
140 return; | |
141 | |
142 for (PrefValueMap::const_iterator i = pref_values->begin(); | |
143 i != pref_values->end(); ++i) { | |
144 UpdateOnePref(i->first); | |
145 } | |
146 } | |
147 | |
148 PrefService* ExtensionPrefStore::GetPrefService() { | |
149 if (profile_) | |
150 return profile_->GetPrefs(); | |
151 return g_browser_process->local_state(); | |
152 } | |
153 | |
154 void ExtensionPrefStore::RegisterObservers() { | |
155 notification_registrar_.Add(this, | |
156 NotificationType::EXTENSION_PREF_CHANGED, | |
157 NotificationService::AllSources()); | |
158 | |
159 notification_registrar_.Add(this, | |
160 NotificationType::EXTENSION_UNLOADED, | |
161 NotificationService::AllSources()); | |
162 } | |
163 | |
164 void ExtensionPrefStore::Observe(NotificationType type, | |
165 const NotificationSource& source, | |
166 const NotificationDetails& details) { | |
167 switch (type.value) { | |
168 case NotificationType::EXTENSION_PREF_CHANGED: { | |
169 Profile* extension_profile = Source<Profile>(source).ptr(); | |
170 // The ExtensionPrefStore for the local state watches all profiles. | |
171 if (!profile_ || profile_ == extension_profile) { | |
172 ExtensionPrefStore::ExtensionPrefDetails* data = | |
173 Details<ExtensionPrefStore::ExtensionPrefDetails>(details).ptr(); | |
174 InstallExtensionPref(data->first, data->second.first, | |
175 data->second.second); | |
176 } | |
177 break; | |
178 } | |
179 case NotificationType::EXTENSION_UNLOADED: { | |
180 Profile* extension_profile = Source<Profile>(source).ptr(); | |
181 const Extension* extension = Details<const Extension>(details).ptr(); | |
182 // The ExtensionPrefStore for the local state watches all profiles. | |
183 if (profile_ == NULL || profile_ == extension_profile) | |
184 UninstallExtension(extension); | |
185 break; | |
186 } | |
187 default: { | |
188 NOTREACHED(); | |
189 } | |
190 } | |
191 } | |
192 | |
193 ExtensionPrefStore::ExtensionPrefs::ExtensionPrefs(const Extension* extension, | |
194 PrefValueMap* values) : extension(extension), pref_values(values) {} | |
195 | |
196 ExtensionPrefStore::ExtensionPrefs::~ExtensionPrefs() { | |
197 STLDeleteValues(pref_values); | |
198 delete pref_values; | |
199 } | |
OLD | NEW |