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 29 CoreOptionsHandler::CoreOptionsHandler() 30 : handlers_host_(NULL) { 31 } 32 33 CoreOptionsHandler::~CoreOptionsHandler() {} 34 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 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 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 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 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 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 128 void CoreOptionsHandler::HandleInitialize(const ListValue* args) { 129 DCHECK(handlers_host_); 130 handlers_host_->InitializeHandlers(); 131 } 132 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 151 void CoreOptionsHandler::ObservePref(const std::string& pref_name) { 152 registrar_.Add(pref_name.c_str(), this); 153 } 154 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 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 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 202 void CoreOptionsHandler::StopObservingPref(const std::string& path) { 203 registrar_.Remove(path.c_str(), this); 204 } 205 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 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 272 void CoreOptionsHandler::HandleSetBooleanPref(const ListValue* args) { 273 HandleSetPref(args, Value::TYPE_BOOLEAN); 274 } 275 276 void CoreOptionsHandler::HandleSetIntegerPref(const ListValue* args) { 277 HandleSetPref(args, Value::TYPE_INTEGER); 278 } 279 280 void CoreOptionsHandler::HandleSetDoublePref(const ListValue* args) { 281 HandleSetPref(args, Value::TYPE_DOUBLE); 282 } 283 284 void CoreOptionsHandler::HandleSetStringPref(const ListValue* args) { 285 HandleSetPref(args, Value::TYPE_STRING); 286 } 287 288 void CoreOptionsHandler::HandleSetListPref(const ListValue* args) { 289 HandleSetPref(args, Value::TYPE_LIST); 290 } 291 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 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 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 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 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