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/ui/webui/options/core_options_handler.h"
6
7 #include "base/json/json_reader.h"
8 #include "base/memory/scoped_ptr.h"
9 #include "base/string16.h"
10 #include "base/string_number_conversions.h"
11 #include "base/utf_string_conversions.h"
12 #include "base/values.h"
13 #include "chrome/browser/browser_process.h"
14 #include "chrome/browser/google/google_util.h"
15 #include "chrome/browser/metrics/user_metrics.h"
16 #include "chrome/browser/prefs/pref_service.h"
17 #include "chrome/browser/profiles/profile.h"
18 #include "chrome/common/pref_names.h"
19 #include "chrome/common/url_constants.h"
20 #include "content/common/notification_details.h"
21 #include "content/common/notification_type.h"
22 #include "googleurl/src/gurl.h"
23 #include "grit/chromium_strings.h"
24 #include "grit/generated_resources.h"
25 #include "grit/locale_settings.h"
26 #include "grit/theme_resources.h"
27 #include "ui/base/l10n/l10n_util.h"
28
CoreOptionsHandler()29 CoreOptionsHandler::CoreOptionsHandler()
30 : handlers_host_(NULL) {
31 }
32
~CoreOptionsHandler()33 CoreOptionsHandler::~CoreOptionsHandler() {}
34
Initialize()35 void CoreOptionsHandler::Initialize() {
36 clear_plugin_lso_data_enabled_.Init(prefs::kClearPluginLSODataEnabled,
37 g_browser_process->local_state(),
38 this);
39 UpdateClearPluginLSOData();
40 }
41
GetLocalizedValues(DictionaryValue * localized_strings)42 void CoreOptionsHandler::GetLocalizedValues(
43 DictionaryValue* localized_strings) {
44 DCHECK(localized_strings);
45 // Main
46 localized_strings->SetString("title",
47 l10n_util::GetStringUTF16(IDS_SETTINGS_TITLE));
48
49 // Managed prefs
50 localized_strings->SetString("managedPrefsBannerText",
51 l10n_util::GetStringUTF16(IDS_OPTIONS_MANAGED_PREFS));
52
53 // Search
54 RegisterTitle(localized_strings, "searchPage", IDS_OPTIONS_SEARCH_PAGE_TITLE);
55 localized_strings->SetString("searchPlaceholder",
56 l10n_util::GetStringUTF16(IDS_OPTIONS_SEARCH_PLACEHOLDER));
57 localized_strings->SetString("searchPageNoMatches",
58 l10n_util::GetStringUTF16(IDS_OPTIONS_SEARCH_PAGE_NO_MATCHES));
59 localized_strings->SetString("searchPageHelpLabel",
60 l10n_util::GetStringUTF16(IDS_OPTIONS_SEARCH_PAGE_HELP_LABEL));
61 localized_strings->SetString("searchPageHelpTitle",
62 l10n_util::GetStringFUTF16(IDS_OPTIONS_SEARCH_PAGE_HELP_TITLE,
63 l10n_util::GetStringUTF16(IDS_PRODUCT_NAME)));
64 localized_strings->SetString("searchPageHelpURL",
65 google_util::AppendGoogleLocaleParam(
66 GURL(chrome::kChromeHelpURL)).spec());
67
68 // Common
69 localized_strings->SetString("ok",
70 l10n_util::GetStringUTF16(IDS_OK));
71 localized_strings->SetString("cancel",
72 l10n_util::GetStringUTF16(IDS_CANCEL));
73 localized_strings->SetString("learnMore",
74 l10n_util::GetStringUTF16(IDS_LEARN_MORE));
75 localized_strings->SetString("close",
76 l10n_util::GetStringUTF16(IDS_CLOSE));
77 }
78
Uninitialize()79 void CoreOptionsHandler::Uninitialize() {
80 std::string last_pref;
81 for (PreferenceCallbackMap::const_iterator iter = pref_callback_map_.begin();
82 iter != pref_callback_map_.end();
83 ++iter) {
84 if (last_pref != iter->first) {
85 StopObservingPref(iter->first);
86 last_pref = iter->first;
87 }
88 }
89 }
90
Attach(WebUI * web_ui)91 WebUIMessageHandler* CoreOptionsHandler::Attach(WebUI* web_ui) {
92 WebUIMessageHandler* result = WebUIMessageHandler::Attach(web_ui);
93 DCHECK(web_ui_);
94 registrar_.Init(web_ui_->GetProfile()->GetPrefs());
95 return result;
96 }
97
Observe(NotificationType type,const NotificationSource & source,const NotificationDetails & details)98 void CoreOptionsHandler::Observe(NotificationType type,
99 const NotificationSource& source,
100 const NotificationDetails& details) {
101 if (type == NotificationType::PREF_CHANGED)
102 NotifyPrefChanged(Details<std::string>(details).ptr());
103 }
104
RegisterMessages()105 void CoreOptionsHandler::RegisterMessages() {
106 web_ui_->RegisterMessageCallback("coreOptionsInitialize",
107 NewCallback(this, &CoreOptionsHandler::HandleInitialize));
108 web_ui_->RegisterMessageCallback("fetchPrefs",
109 NewCallback(this, &CoreOptionsHandler::HandleFetchPrefs));
110 web_ui_->RegisterMessageCallback("observePrefs",
111 NewCallback(this, &CoreOptionsHandler::HandleObservePrefs));
112 web_ui_->RegisterMessageCallback("setBooleanPref",
113 NewCallback(this, &CoreOptionsHandler::HandleSetBooleanPref));
114 web_ui_->RegisterMessageCallback("setIntegerPref",
115 NewCallback(this, &CoreOptionsHandler::HandleSetIntegerPref));
116 web_ui_->RegisterMessageCallback("setDoublePref",
117 NewCallback(this, &CoreOptionsHandler::HandleSetDoublePref));
118 web_ui_->RegisterMessageCallback("setStringPref",
119 NewCallback(this, &CoreOptionsHandler::HandleSetStringPref));
120 web_ui_->RegisterMessageCallback("setListPref",
121 NewCallback(this, &CoreOptionsHandler::HandleSetListPref));
122 web_ui_->RegisterMessageCallback("clearPref",
123 NewCallback(this, &CoreOptionsHandler::HandleClearPref));
124 web_ui_->RegisterMessageCallback("coreOptionsUserMetricsAction",
125 NewCallback(this, &CoreOptionsHandler::HandleUserMetricsAction));
126 }
127
HandleInitialize(const ListValue * args)128 void CoreOptionsHandler::HandleInitialize(const ListValue* args) {
129 DCHECK(handlers_host_);
130 handlers_host_->InitializeHandlers();
131 }
132
FetchPref(const std::string & pref_name)133 Value* CoreOptionsHandler::FetchPref(const std::string& pref_name) {
134 PrefService* pref_service = web_ui_->GetProfile()->GetPrefs();
135
136 const PrefService::Preference* pref =
137 pref_service->FindPreference(pref_name.c_str());
138
139 Value* return_value;
140 if (pref) {
141 DictionaryValue* dict = new DictionaryValue;
142 dict->Set("value", pref->GetValue()->DeepCopy());
143 dict->SetBoolean("managed", pref->IsManaged());
144 return_value = dict;
145 } else {
146 return_value = Value::CreateNullValue();
147 }
148 return return_value;
149 }
150
ObservePref(const std::string & pref_name)151 void CoreOptionsHandler::ObservePref(const std::string& pref_name) {
152 registrar_.Add(pref_name.c_str(), this);
153 }
154
SetPref(const std::string & pref_name,const Value * value,const std::string & metric)155 void CoreOptionsHandler::SetPref(const std::string& pref_name,
156 const Value* value,
157 const std::string& metric) {
158 PrefService* pref_service = web_ui_->GetProfile()->GetPrefs();
159
160 switch (value->GetType()) {
161 case Value::TYPE_BOOLEAN:
162 case Value::TYPE_INTEGER:
163 case Value::TYPE_DOUBLE:
164 case Value::TYPE_STRING:
165 pref_service->Set(pref_name.c_str(), *value);
166 break;
167
168 default:
169 NOTREACHED();
170 return;
171 }
172
173 pref_service->ScheduleSavePersistentPrefs();
174 ProcessUserMetric(value, metric);
175 }
176
ClearPref(const std::string & pref_name,const std::string & metric)177 void CoreOptionsHandler::ClearPref(const std::string& pref_name,
178 const std::string& metric) {
179 PrefService* pref_service = web_ui_->GetProfile()->GetPrefs();
180 pref_service->ClearPref(pref_name.c_str());
181 pref_service->ScheduleSavePersistentPrefs();
182
183 if (!metric.empty())
184 UserMetricsRecordAction(UserMetricsAction(metric.c_str()));
185 }
186
ProcessUserMetric(const Value * value,const std::string & metric)187 void CoreOptionsHandler::ProcessUserMetric(const Value* value,
188 const std::string& metric) {
189 if (metric.empty())
190 return;
191
192 std::string metric_string = metric;
193 if (value->IsType(Value::TYPE_BOOLEAN)) {
194 bool bool_value;
195 CHECK(value->GetAsBoolean(&bool_value));
196 metric_string += bool_value ? "_Enable" : "_Disable";
197 }
198
199 UserMetricsRecordAction(UserMetricsAction(metric_string.c_str()));
200 }
201
StopObservingPref(const std::string & path)202 void CoreOptionsHandler::StopObservingPref(const std::string& path) {
203 registrar_.Remove(path.c_str(), this);
204 }
205
HandleFetchPrefs(const ListValue * args)206 void CoreOptionsHandler::HandleFetchPrefs(const ListValue* args) {
207 // First param is name of callback function, so, there needs to be at least
208 // one more element for the actual preference identifier.
209 DCHECK_GE(static_cast<int>(args->GetSize()), 2);
210
211 // Get callback JS function name.
212 Value* callback;
213 if (!args->Get(0, &callback) || !callback->IsType(Value::TYPE_STRING))
214 return;
215
216 string16 callback_function;
217 if (!callback->GetAsString(&callback_function))
218 return;
219
220 // Get the list of name for prefs to build the response dictionary.
221 DictionaryValue result_value;
222 Value* list_member;
223
224 for (size_t i = 1; i < args->GetSize(); i++) {
225 if (!args->Get(i, &list_member))
226 break;
227
228 if (!list_member->IsType(Value::TYPE_STRING))
229 continue;
230
231 std::string pref_name;
232 if (!list_member->GetAsString(&pref_name))
233 continue;
234
235 result_value.Set(pref_name.c_str(), FetchPref(pref_name));
236 }
237 web_ui_->CallJavascriptFunction(UTF16ToASCII(callback_function),
238 result_value);
239 }
240
HandleObservePrefs(const ListValue * args)241 void CoreOptionsHandler::HandleObservePrefs(const ListValue* args) {
242 // First param is name is JS callback function name, the rest are pref
243 // identifiers that we are observing.
244 DCHECK_GE(static_cast<int>(args->GetSize()), 2);
245
246 // Get preference change callback function name.
247 string16 callback_func_name;
248 if (!args->GetString(0, &callback_func_name))
249 return;
250
251 // Get all other parameters - pref identifiers.
252 for (size_t i = 1; i < args->GetSize(); i++) {
253 Value* list_member;
254 if (!args->Get(i, &list_member))
255 break;
256
257 // Just ignore bad pref identifiers for now.
258 std::string pref_name;
259 if (!list_member->IsType(Value::TYPE_STRING) ||
260 !list_member->GetAsString(&pref_name))
261 continue;
262
263 if (pref_callback_map_.find(pref_name) == pref_callback_map_.end())
264 ObservePref(pref_name);
265
266 pref_callback_map_.insert(
267 PreferenceCallbackMap::value_type(pref_name,
268 UTF16ToWideHack(callback_func_name)));
269 }
270 }
271
HandleSetBooleanPref(const ListValue * args)272 void CoreOptionsHandler::HandleSetBooleanPref(const ListValue* args) {
273 HandleSetPref(args, Value::TYPE_BOOLEAN);
274 }
275
HandleSetIntegerPref(const ListValue * args)276 void CoreOptionsHandler::HandleSetIntegerPref(const ListValue* args) {
277 HandleSetPref(args, Value::TYPE_INTEGER);
278 }
279
HandleSetDoublePref(const ListValue * args)280 void CoreOptionsHandler::HandleSetDoublePref(const ListValue* args) {
281 HandleSetPref(args, Value::TYPE_DOUBLE);
282 }
283
HandleSetStringPref(const ListValue * args)284 void CoreOptionsHandler::HandleSetStringPref(const ListValue* args) {
285 HandleSetPref(args, Value::TYPE_STRING);
286 }
287
HandleSetListPref(const ListValue * args)288 void CoreOptionsHandler::HandleSetListPref(const ListValue* args) {
289 HandleSetPref(args, Value::TYPE_LIST);
290 }
291
HandleSetPref(const ListValue * args,Value::ValueType type)292 void CoreOptionsHandler::HandleSetPref(const ListValue* args,
293 Value::ValueType type) {
294 DCHECK_GT(static_cast<int>(args->GetSize()), 1);
295
296 std::string pref_name;
297 if (!args->GetString(0, &pref_name))
298 return;
299
300 Value* value;
301 if (!args->Get(1, &value))
302 return;
303
304 scoped_ptr<Value> temp_value;
305
306 // In JS all numbers are doubles.
307 if (type == Value::TYPE_INTEGER) {
308 double double_value;
309 CHECK(value->GetAsDouble(&double_value));
310 temp_value.reset(Value::CreateIntegerValue(static_cast<int>(double_value)));
311 value = temp_value.get();
312
313 // In case we have a List pref we got a JSON string.
314 } else if (type == Value::TYPE_LIST) {
315 std::string json_string;
316 CHECK(value->GetAsString(&json_string));
317 temp_value.reset(
318 base::JSONReader().JsonToValue(json_string,
319 false, // no check_root
320 false)); // no trailing comma
321 value = temp_value.get();
322 }
323
324 CHECK_EQ(type, value->GetType());
325
326 std::string metric;
327 if (args->GetSize() > 2)
328 args->GetString(2, &metric);
329
330 SetPref(pref_name, value, metric);
331 }
332
HandleClearPref(const ListValue * args)333 void CoreOptionsHandler::HandleClearPref(const ListValue* args) {
334 DCHECK_GT(static_cast<int>(args->GetSize()), 0);
335
336 std::string pref_name;
337 if (!args->GetString(0, &pref_name))
338 return;
339
340 std::string metric;
341 if (args->GetSize() > 1)
342 args->GetString(1, &metric);
343
344 ClearPref(pref_name, metric);
345 }
346
HandleUserMetricsAction(const ListValue * args)347 void CoreOptionsHandler::HandleUserMetricsAction(const ListValue* args) {
348 std::string metric = UTF16ToUTF8(ExtractStringValue(args));
349 if (!metric.empty())
350 UserMetricsRecordAction(UserMetricsAction(metric.c_str()));
351 }
352
UpdateClearPluginLSOData()353 void CoreOptionsHandler::UpdateClearPluginLSOData() {
354 scoped_ptr<Value> enabled(
355 Value::CreateBooleanValue(clear_plugin_lso_data_enabled_.GetValue()));
356 web_ui_->CallJavascriptFunction(
357 "OptionsPage.setClearPluginLSODataEnabled", *enabled);
358 }
359
NotifyPrefChanged(const std::string * pref_name)360 void CoreOptionsHandler::NotifyPrefChanged(const std::string* pref_name) {
361 if (*pref_name == prefs::kClearPluginLSODataEnabled) {
362 // This preference is stored in Local State, not in the user preferences.
363 UpdateClearPluginLSOData();
364 return;
365 }
366
367 PrefService* pref_service = web_ui_->GetProfile()->GetPrefs();
368 const PrefService::Preference* pref =
369 pref_service->FindPreference(pref_name->c_str());
370 if (pref) {
371 for (PreferenceCallbackMap::const_iterator iter =
372 pref_callback_map_.find(*pref_name);
373 iter != pref_callback_map_.end(); ++iter) {
374 const std::wstring& callback_function = iter->second;
375 ListValue result_value;
376 result_value.Append(Value::CreateStringValue(pref_name->c_str()));
377
378 DictionaryValue* dict = new DictionaryValue;
379 dict->Set("value", pref->GetValue()->DeepCopy());
380 dict->SetBoolean("managed", pref->IsManaged());
381 result_value.Append(dict);
382
383 web_ui_->CallJavascriptFunction(WideToASCII(callback_function),
384 result_value);
385 }
386 }
387 }
388