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/browser_options_handler.h"
6
7 #include "base/basictypes.h"
8 #include "base/memory/scoped_ptr.h"
9 #include "base/memory/singleton.h"
10 #include "base/string_number_conversions.h"
11 #include "base/utf_string_conversions.h"
12 #include "base/values.h"
13 #include "chrome/browser/autocomplete/autocomplete.h"
14 #include "chrome/browser/autocomplete/autocomplete_match.h"
15 #include "chrome/browser/browser_process.h"
16 #include "chrome/browser/custom_home_pages_table_model.h"
17 #include "chrome/browser/instant/instant_confirm_dialog.h"
18 #include "chrome/browser/metrics/user_metrics.h"
19 #include "chrome/browser/net/url_fixer_upper.h"
20 #include "chrome/browser/prefs/pref_service.h"
21 #include "chrome/browser/prefs/session_startup_pref.h"
22 #include "chrome/browser/profiles/profile.h"
23 #include "chrome/browser/search_engines/template_url.h"
24 #include "chrome/browser/search_engines/template_url_model.h"
25 #include "chrome/browser/ui/options/options_window.h"
26 #include "chrome/browser/ui/webui/favicon_source.h"
27 #include "chrome/browser/ui/webui/options/options_managed_banner_handler.h"
28 #include "chrome/common/pref_names.h"
29 #include "chrome/installer/util/browser_distribution.h"
30 #include "content/browser/browser_thread.h"
31 #include "content/common/notification_service.h"
32 #include "content/common/notification_source.h"
33 #include "content/common/notification_type.h"
34 #include "grit/chromium_strings.h"
35 #include "grit/generated_resources.h"
36 #include "ui/base/l10n/l10n_util.h"
37
BrowserOptionsHandler()38 BrowserOptionsHandler::BrowserOptionsHandler()
39 : template_url_model_(NULL), startup_custom_pages_table_model_(NULL) {
40 #if !defined(OS_MACOSX)
41 default_browser_worker_ = new ShellIntegration::DefaultBrowserWorker(this);
42 #endif
43 }
44
~BrowserOptionsHandler()45 BrowserOptionsHandler::~BrowserOptionsHandler() {
46 if (default_browser_worker_.get())
47 default_browser_worker_->ObserverDestroyed();
48 if (template_url_model_)
49 template_url_model_->RemoveObserver(this);
50 }
51
GetLocalizedValues(DictionaryValue * localized_strings)52 void BrowserOptionsHandler::GetLocalizedValues(
53 DictionaryValue* localized_strings) {
54 DCHECK(localized_strings);
55
56 static OptionsStringResource resources[] = {
57 { "startupGroupName", IDS_OPTIONS_STARTUP_GROUP_NAME },
58 { "startupShowDefaultAndNewTab",
59 IDS_OPTIONS_STARTUP_SHOW_DEFAULT_AND_NEWTAB},
60 { "startupShowLastSession", IDS_OPTIONS_STARTUP_SHOW_LAST_SESSION },
61 { "startupShowPages", IDS_OPTIONS_STARTUP_SHOW_PAGES },
62 { "startupAddLabel", IDS_OPTIONS_STARTUP_ADD_LABEL },
63 { "startupUseCurrent", IDS_OPTIONS_STARTUP_USE_CURRENT },
64 { "homepageGroupName", IDS_OPTIONS_HOMEPAGE_GROUP_NAME },
65 { "homepageUseNewTab", IDS_OPTIONS_HOMEPAGE_USE_NEWTAB },
66 { "homepageUseURL", IDS_OPTIONS_HOMEPAGE_USE_URL },
67 { "toolbarGroupName", IDS_OPTIONS_TOOLBAR_GROUP_NAME },
68 { "toolbarShowHomeButton", IDS_OPTIONS_TOOLBAR_SHOW_HOME_BUTTON },
69 { "toolbarShowBookmarksBar", IDS_OPTIONS_TOOLBAR_SHOW_BOOKMARKS_BAR },
70 { "defaultSearchGroupName", IDS_OPTIONS_DEFAULTSEARCH_GROUP_NAME },
71 { "defaultSearchManageEngines", IDS_OPTIONS_DEFAULTSEARCH_MANAGE_ENGINES },
72 { "instantName", IDS_INSTANT_PREF },
73 { "instantWarningText", IDS_INSTANT_PREF_WARNING },
74 { "instantConfirmTitle", IDS_INSTANT_OPT_IN_TITLE },
75 { "instantConfirmMessage", IDS_INSTANT_OPT_IN_MESSAGE },
76 { "defaultBrowserGroupName", IDS_OPTIONS_DEFAULTBROWSER_GROUP_NAME },
77 };
78
79 RegisterStrings(localized_strings, resources, arraysize(resources));
80 RegisterTitle(localized_strings, "browserPage",
81 IDS_OPTIONS_GENERAL_TAB_LABEL);
82
83 localized_strings->SetString("instantLearnMoreLink",
84 ASCIIToUTF16(browser::InstantLearnMoreURL().spec()));
85 localized_strings->SetString("defaultBrowserUnknown",
86 l10n_util::GetStringFUTF16(IDS_OPTIONS_DEFAULTBROWSER_UNKNOWN,
87 l10n_util::GetStringUTF16(IDS_PRODUCT_NAME)));
88 localized_strings->SetString("defaultBrowserUseAsDefault",
89 l10n_util::GetStringFUTF16(IDS_OPTIONS_DEFAULTBROWSER_USEASDEFAULT,
90 l10n_util::GetStringUTF16(IDS_PRODUCT_NAME)));
91 }
92
RegisterMessages()93 void BrowserOptionsHandler::RegisterMessages() {
94 web_ui_->RegisterMessageCallback(
95 "setHomePage",
96 NewCallback(this, &BrowserOptionsHandler::SetHomePage));
97 web_ui_->RegisterMessageCallback(
98 "becomeDefaultBrowser",
99 NewCallback(this, &BrowserOptionsHandler::BecomeDefaultBrowser));
100 web_ui_->RegisterMessageCallback(
101 "setDefaultSearchEngine",
102 NewCallback(this, &BrowserOptionsHandler::SetDefaultSearchEngine));
103 web_ui_->RegisterMessageCallback(
104 "removeStartupPages",
105 NewCallback(this, &BrowserOptionsHandler::RemoveStartupPages));
106 web_ui_->RegisterMessageCallback(
107 "addStartupPage",
108 NewCallback(this, &BrowserOptionsHandler::AddStartupPage));
109 web_ui_->RegisterMessageCallback(
110 "editStartupPage",
111 NewCallback(this, &BrowserOptionsHandler::EditStartupPage));
112 web_ui_->RegisterMessageCallback(
113 "setStartupPagesToCurrentPages",
114 NewCallback(this, &BrowserOptionsHandler::SetStartupPagesToCurrentPages));
115 web_ui_->RegisterMessageCallback(
116 "requestAutocompleteSuggestions",
117 NewCallback(this,
118 &BrowserOptionsHandler::RequestAutocompleteSuggestions));
119 web_ui_->RegisterMessageCallback(
120 "toggleShowBookmarksBar",
121 NewCallback(this, &BrowserOptionsHandler::ToggleShowBookmarksBar));
122 }
123
Initialize()124 void BrowserOptionsHandler::Initialize() {
125 Profile* profile = web_ui_->GetProfile();
126
127 // Create our favicon data source.
128 profile->GetChromeURLDataManager()->AddDataSource(
129 new FaviconSource(profile));
130
131 homepage_.Init(prefs::kHomePage, profile->GetPrefs(), NULL);
132 default_browser_policy_.Init(prefs::kDefaultBrowserSettingEnabled,
133 g_browser_process->local_state(),
134 this);
135 UpdateDefaultBrowserState();
136 UpdateStartupPages();
137 UpdateSearchEngines();
138 banner_handler_.reset(
139 new OptionsManagedBannerHandler(web_ui_,
140 ASCIIToUTF16("BrowserOptions"),
141 OPTIONS_PAGE_GENERAL));
142
143 autocomplete_controller_.reset(new AutocompleteController(profile, this));
144 }
145
SetHomePage(const ListValue * args)146 void BrowserOptionsHandler::SetHomePage(const ListValue* args) {
147 std::string url_string;
148 std::string do_fixup_string;
149 int do_fixup;
150 CHECK_EQ(args->GetSize(), 2U);
151 CHECK(args->GetString(0, &url_string));
152 CHECK(args->GetString(1, &do_fixup_string));
153 CHECK(base::StringToInt(do_fixup_string, &do_fixup));
154
155 if (do_fixup) {
156 GURL fixed_url = URLFixerUpper::FixupURL(url_string, std::string());
157 url_string = fixed_url.spec();
158 }
159 homepage_.SetValueIfNotManaged(url_string);
160 }
161
UpdateDefaultBrowserState()162 void BrowserOptionsHandler::UpdateDefaultBrowserState() {
163 #if defined(OS_WIN)
164 // Check for side-by-side first.
165 if (!BrowserDistribution::GetDistribution()->CanSetAsDefault()) {
166 SetDefaultBrowserUIString(IDS_OPTIONS_DEFAULTBROWSER_SXS);
167 return;
168 }
169 #endif
170
171 #if defined(OS_MACOSX)
172 ShellIntegration::DefaultBrowserState state =
173 ShellIntegration::IsDefaultBrowser();
174 int status_string_id;
175 if (state == ShellIntegration::IS_DEFAULT_BROWSER)
176 status_string_id = IDS_OPTIONS_DEFAULTBROWSER_DEFAULT;
177 else if (state == ShellIntegration::NOT_DEFAULT_BROWSER)
178 status_string_id = IDS_OPTIONS_DEFAULTBROWSER_NOTDEFAULT;
179 else
180 status_string_id = IDS_OPTIONS_DEFAULTBROWSER_UNKNOWN;
181
182 SetDefaultBrowserUIString(status_string_id);
183 #else
184 default_browser_worker_->StartCheckDefaultBrowser();
185 #endif
186 }
187
BecomeDefaultBrowser(const ListValue * args)188 void BrowserOptionsHandler::BecomeDefaultBrowser(const ListValue* args) {
189 // If the default browser setting is managed then we should not be able to
190 // call this function.
191 if (default_browser_policy_.IsManaged())
192 return;
193
194 UserMetricsRecordAction(UserMetricsAction("Options_SetAsDefaultBrowser"));
195 #if defined(OS_MACOSX)
196 if (ShellIntegration::SetAsDefaultBrowser())
197 UpdateDefaultBrowserState();
198 #else
199 default_browser_worker_->StartSetAsDefaultBrowser();
200 // Callback takes care of updating UI.
201 #endif
202
203 // If the user attempted to make Chrome the default browser, then he/she
204 // arguably wants to be notified when that changes.
205 PrefService* prefs = web_ui_->GetProfile()->GetPrefs();
206 prefs->SetBoolean(prefs::kCheckDefaultBrowser, true);
207 }
208
StatusStringIdForState(ShellIntegration::DefaultBrowserState state)209 int BrowserOptionsHandler::StatusStringIdForState(
210 ShellIntegration::DefaultBrowserState state) {
211 if (state == ShellIntegration::IS_DEFAULT_BROWSER)
212 return IDS_OPTIONS_DEFAULTBROWSER_DEFAULT;
213 if (state == ShellIntegration::NOT_DEFAULT_BROWSER)
214 return IDS_OPTIONS_DEFAULTBROWSER_NOTDEFAULT;
215 return IDS_OPTIONS_DEFAULTBROWSER_UNKNOWN;
216 }
217
SetDefaultBrowserUIState(ShellIntegration::DefaultBrowserUIState state)218 void BrowserOptionsHandler::SetDefaultBrowserUIState(
219 ShellIntegration::DefaultBrowserUIState state) {
220 int status_string_id;
221 if (state == ShellIntegration::STATE_IS_DEFAULT)
222 status_string_id = IDS_OPTIONS_DEFAULTBROWSER_DEFAULT;
223 else if (state == ShellIntegration::STATE_NOT_DEFAULT)
224 status_string_id = IDS_OPTIONS_DEFAULTBROWSER_NOTDEFAULT;
225 else if (state == ShellIntegration::STATE_UNKNOWN)
226 status_string_id = IDS_OPTIONS_DEFAULTBROWSER_UNKNOWN;
227 else
228 return; // Still processing.
229
230 SetDefaultBrowserUIString(status_string_id);
231 }
232
SetDefaultBrowserUIString(int status_string_id)233 void BrowserOptionsHandler::SetDefaultBrowserUIString(int status_string_id) {
234 scoped_ptr<Value> status_string(Value::CreateStringValue(
235 l10n_util::GetStringFUTF16(status_string_id,
236 l10n_util::GetStringUTF16(IDS_PRODUCT_NAME))));
237
238 scoped_ptr<Value> is_default(Value::CreateBooleanValue(
239 status_string_id == IDS_OPTIONS_DEFAULTBROWSER_DEFAULT));
240
241 scoped_ptr<Value> can_be_default(Value::CreateBooleanValue(
242 !default_browser_policy_.IsManaged() &&
243 (status_string_id == IDS_OPTIONS_DEFAULTBROWSER_DEFAULT ||
244 status_string_id == IDS_OPTIONS_DEFAULTBROWSER_NOTDEFAULT)));
245
246 web_ui_->CallJavascriptFunction("BrowserOptions.updateDefaultBrowserState",
247 *(status_string.get()),
248 *(is_default.get()),
249 *(can_be_default.get()));
250 }
251
OnTemplateURLModelChanged()252 void BrowserOptionsHandler::OnTemplateURLModelChanged() {
253 if (!template_url_model_ || !template_url_model_->loaded())
254 return;
255
256 const TemplateURL* default_url =
257 template_url_model_->GetDefaultSearchProvider();
258
259 int default_index = 0;
260 ListValue search_engines;
261 std::vector<const TemplateURL*> model_urls =
262 template_url_model_->GetTemplateURLs();
263 for (size_t i = 0; i < model_urls.size(); ++i) {
264 if (!model_urls[i]->ShowInDefaultList())
265 continue;
266
267 DictionaryValue* entry = new DictionaryValue();
268 entry->SetString("name", model_urls[i]->short_name());
269 entry->SetInteger("index", i);
270 search_engines.Append(entry);
271 if (model_urls[i] == default_url)
272 default_index = i;
273 }
274
275 scoped_ptr<Value> default_value(Value::CreateIntegerValue(default_index));
276
277 web_ui_->CallJavascriptFunction("BrowserOptions.updateSearchEngines",
278 search_engines, *(default_value.get()));
279 }
280
SetDefaultSearchEngine(const ListValue * args)281 void BrowserOptionsHandler::SetDefaultSearchEngine(const ListValue* args) {
282 int selected_index = -1;
283 if (!ExtractIntegerValue(args, &selected_index)) {
284 NOTREACHED();
285 return;
286 }
287
288 std::vector<const TemplateURL*> model_urls =
289 template_url_model_->GetTemplateURLs();
290 if (selected_index >= 0 &&
291 selected_index < static_cast<int>(model_urls.size()))
292 template_url_model_->SetDefaultSearchProvider(model_urls[selected_index]);
293
294 UserMetricsRecordAction(UserMetricsAction("Options_SearchEngineChanged"));
295 }
296
UpdateSearchEngines()297 void BrowserOptionsHandler::UpdateSearchEngines() {
298 template_url_model_ = web_ui_->GetProfile()->GetTemplateURLModel();
299 if (template_url_model_) {
300 template_url_model_->Load();
301 template_url_model_->AddObserver(this);
302 OnTemplateURLModelChanged();
303 }
304 }
305
UpdateStartupPages()306 void BrowserOptionsHandler::UpdateStartupPages() {
307 Profile* profile = web_ui_->GetProfile();
308 startup_custom_pages_table_model_.reset(
309 new CustomHomePagesTableModel(profile));
310 startup_custom_pages_table_model_->SetObserver(this);
311
312 const SessionStartupPref startup_pref =
313 SessionStartupPref::GetStartupPref(profile->GetPrefs());
314 startup_custom_pages_table_model_->SetURLs(startup_pref.urls);
315 }
316
OnModelChanged()317 void BrowserOptionsHandler::OnModelChanged() {
318 ListValue startup_pages;
319 int page_count = startup_custom_pages_table_model_->RowCount();
320 std::vector<GURL> urls = startup_custom_pages_table_model_->GetURLs();
321 for (int i = 0; i < page_count; ++i) {
322 DictionaryValue* entry = new DictionaryValue();
323 entry->SetString("title", startup_custom_pages_table_model_->GetText(i, 0));
324 entry->SetString("url", urls[i].spec());
325 entry->SetString("tooltip",
326 startup_custom_pages_table_model_->GetTooltip(i));
327 entry->SetString("modelIndex", base::IntToString(i));
328 startup_pages.Append(entry);
329 }
330
331 web_ui_->CallJavascriptFunction("BrowserOptions.updateStartupPages",
332 startup_pages);
333 }
334
OnItemsChanged(int start,int length)335 void BrowserOptionsHandler::OnItemsChanged(int start, int length) {
336 OnModelChanged();
337 }
338
OnItemsAdded(int start,int length)339 void BrowserOptionsHandler::OnItemsAdded(int start, int length) {
340 OnModelChanged();
341 }
342
OnItemsRemoved(int start,int length)343 void BrowserOptionsHandler::OnItemsRemoved(int start, int length) {
344 OnModelChanged();
345 }
346
Observe(NotificationType type,const NotificationSource & source,const NotificationDetails & details)347 void BrowserOptionsHandler::Observe(NotificationType type,
348 const NotificationSource& source,
349 const NotificationDetails& details) {
350 UpdateDefaultBrowserState();
351 }
352
SetStartupPagesToCurrentPages(const ListValue * args)353 void BrowserOptionsHandler::SetStartupPagesToCurrentPages(
354 const ListValue* args) {
355 startup_custom_pages_table_model_->SetToCurrentlyOpenPages();
356 SaveStartupPagesPref();
357 }
358
RemoveStartupPages(const ListValue * args)359 void BrowserOptionsHandler::RemoveStartupPages(const ListValue* args) {
360 for (int i = args->GetSize() - 1; i >= 0; --i) {
361 std::string string_value;
362 CHECK(args->GetString(i, &string_value));
363
364 int selected_index;
365 base::StringToInt(string_value, &selected_index);
366 if (selected_index < 0 ||
367 selected_index >= startup_custom_pages_table_model_->RowCount()) {
368 NOTREACHED();
369 return;
370 }
371 startup_custom_pages_table_model_->Remove(selected_index);
372 }
373
374 SaveStartupPagesPref();
375 }
376
AddStartupPage(const ListValue * args)377 void BrowserOptionsHandler::AddStartupPage(const ListValue* args) {
378 std::string url_string;
379 CHECK_EQ(args->GetSize(), 1U);
380 CHECK(args->GetString(0, &url_string));
381
382 GURL url = URLFixerUpper::FixupURL(url_string, std::string());
383 int index = startup_custom_pages_table_model_->RowCount();
384 startup_custom_pages_table_model_->Add(index, url);
385 SaveStartupPagesPref();
386 }
387
EditStartupPage(const ListValue * args)388 void BrowserOptionsHandler::EditStartupPage(const ListValue* args) {
389 std::string url_string;
390 std::string index_string;
391 int index;
392 CHECK_EQ(args->GetSize(), 2U);
393 CHECK(args->GetString(0, &index_string));
394 CHECK(base::StringToInt(index_string, &index));
395 CHECK(args->GetString(1, &url_string));
396
397 if (index < 0 || index > startup_custom_pages_table_model_->RowCount()) {
398 NOTREACHED();
399 return;
400 }
401
402 std::vector<GURL> urls = startup_custom_pages_table_model_->GetURLs();
403 urls[index] = URLFixerUpper::FixupURL(url_string, std::string());
404 startup_custom_pages_table_model_->SetURLs(urls);
405 }
406
SaveStartupPagesPref()407 void BrowserOptionsHandler::SaveStartupPagesPref() {
408 PrefService* prefs = web_ui_->GetProfile()->GetPrefs();
409
410 SessionStartupPref pref = SessionStartupPref::GetStartupPref(prefs);
411 pref.urls = startup_custom_pages_table_model_->GetURLs();
412
413 SessionStartupPref::SetStartupPref(prefs, pref);
414 }
415
RequestAutocompleteSuggestions(const ListValue * args)416 void BrowserOptionsHandler::RequestAutocompleteSuggestions(
417 const ListValue* args) {
418 string16 input;
419 CHECK_EQ(args->GetSize(), 1U);
420 CHECK(args->GetString(0, &input));
421
422 autocomplete_controller_->Start(input, string16(), true, false, false,
423 AutocompleteInput::ALL_MATCHES);
424 }
425
ToggleShowBookmarksBar(const ListValue * args)426 void BrowserOptionsHandler::ToggleShowBookmarksBar(const ListValue* args) {
427 Source<Profile> source(web_ui_->GetProfile());
428 NotificationService::current()->Notify(
429 NotificationType::BOOKMARK_BAR_VISIBILITY_PREF_CHANGED,
430 source,
431 NotificationService::NoDetails());
432 }
433
OnResultChanged(bool default_match_changed)434 void BrowserOptionsHandler::OnResultChanged(bool default_match_changed) {
435 const AutocompleteResult& result = autocomplete_controller_->result();
436 ListValue suggestions;
437 for (size_t i = 0; i < result.size(); ++i) {
438 const AutocompleteMatch& match = result.match_at(i);
439 AutocompleteMatch::Type type = match.type;
440 if (type != AutocompleteMatch::HISTORY_URL &&
441 type != AutocompleteMatch::HISTORY_TITLE &&
442 type != AutocompleteMatch::HISTORY_BODY &&
443 type != AutocompleteMatch::HISTORY_KEYWORD &&
444 type != AutocompleteMatch::NAVSUGGEST)
445 continue;
446 DictionaryValue* entry = new DictionaryValue();
447 entry->SetString("title", match.description);
448 entry->SetString("displayURL", match.contents);
449 entry->SetString("url", match.destination_url.spec());
450 suggestions.Append(entry);
451 }
452
453 web_ui_->CallJavascriptFunction(
454 "BrowserOptions.updateAutocompleteSuggestions", suggestions);
455 }
456