1// Copyright (c) 2012 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/startup_pages_handler.h"
6
7#include "base/bind.h"
8#include "base/bind_helpers.h"
9#include "base/prefs/pref_service.h"
10#include "chrome/browser/autocomplete/autocomplete_classifier.h"
11#include "chrome/browser/autocomplete/autocomplete_controller.h"
12#include "chrome/browser/autocomplete/chrome_autocomplete_scheme_classifier.h"
13#include "chrome/browser/chrome_notification_types.h"
14#include "chrome/browser/custom_home_pages_table_model.h"
15#include "chrome/browser/prefs/session_startup_pref.h"
16#include "chrome/browser/profiles/profile.h"
17#include "chrome/browser/search_engines/template_url_service_factory.h"
18#include "chrome/common/pref_names.h"
19#include "chrome/grit/generated_resources.h"
20#include "components/metrics/proto/omnibox_event.pb.h"
21#include "components/omnibox/autocomplete_input.h"
22#include "components/omnibox/autocomplete_result.h"
23#include "components/url_fixer/url_fixer.h"
24#include "content/public/browser/notification_details.h"
25#include "content/public/browser/web_ui.h"
26
27namespace options {
28
29StartupPagesHandler::StartupPagesHandler() {
30}
31
32StartupPagesHandler::~StartupPagesHandler() {
33}
34
35void StartupPagesHandler::GetLocalizedValues(
36    base::DictionaryValue* localized_strings) {
37  DCHECK(localized_strings);
38
39  static OptionsStringResource resources[] = {
40    { "startupAddLabel", IDS_OPTIONS_STARTUP_ADD_LABEL },
41    { "startupUseCurrent", IDS_OPTIONS_STARTUP_USE_CURRENT },
42    { "startupPagesPlaceholder", IDS_OPTIONS_STARTUP_PAGES_PLACEHOLDER },
43  };
44
45  RegisterStrings(localized_strings, resources, arraysize(resources));
46  RegisterTitle(localized_strings, "startupPagesOverlay",
47                IDS_OPTIONS_STARTUP_PAGES_DIALOG_TITLE);
48}
49
50void StartupPagesHandler::RegisterMessages() {
51  // Guest profiles should never have been displayed the option to set these
52  // values.
53  if (Profile::FromWebUI(web_ui())->IsOffTheRecord())
54    return;
55
56  web_ui()->RegisterMessageCallback("removeStartupPages",
57      base::Bind(&StartupPagesHandler::RemoveStartupPages,
58                 base::Unretained(this)));
59  web_ui()->RegisterMessageCallback("addStartupPage",
60      base::Bind(&StartupPagesHandler::AddStartupPage,
61                 base::Unretained(this)));
62  web_ui()->RegisterMessageCallback("editStartupPage",
63      base::Bind(&StartupPagesHandler::EditStartupPage,
64                 base::Unretained(this)));
65  web_ui()->RegisterMessageCallback("setStartupPagesToCurrentPages",
66      base::Bind(&StartupPagesHandler::SetStartupPagesToCurrentPages,
67                 base::Unretained(this)));
68  web_ui()->RegisterMessageCallback("dragDropStartupPage",
69      base::Bind(&StartupPagesHandler::DragDropStartupPage,
70                 base::Unretained(this)));
71  web_ui()->RegisterMessageCallback(
72      "requestAutocompleteSuggestionsForStartupPages",
73      base::Bind(&StartupPagesHandler::RequestAutocompleteSuggestions,
74                 base::Unretained(this)));
75  web_ui()->RegisterMessageCallback("commitStartupPrefChanges",
76      base::Bind(&StartupPagesHandler::CommitChanges,
77                 base::Unretained(this)));
78  web_ui()->RegisterMessageCallback("cancelStartupPrefChanges",
79      base::Bind(&StartupPagesHandler::CancelChanges,
80                 base::Unretained(this)));
81}
82
83void StartupPagesHandler::UpdateStartupPages() {
84  Profile* profile = Profile::FromWebUI(web_ui());
85  const SessionStartupPref startup_pref =
86      SessionStartupPref::GetStartupPref(profile->GetPrefs());
87  startup_custom_pages_table_model_->SetURLs(startup_pref.urls);
88}
89
90void StartupPagesHandler::InitializeHandler() {
91  Profile* profile = Profile::FromWebUI(web_ui());
92
93  startup_custom_pages_table_model_.reset(
94      new CustomHomePagesTableModel(profile));
95  startup_custom_pages_table_model_->SetObserver(this);
96
97  pref_change_registrar_.Init(profile->GetPrefs());
98  pref_change_registrar_.Add(
99      prefs::kURLsToRestoreOnStartup,
100      base::Bind(&StartupPagesHandler::UpdateStartupPages,
101                 base::Unretained(this)));
102
103  autocomplete_controller_.reset(new AutocompleteController(profile,
104      TemplateURLServiceFactory::GetForProfile(profile), this,
105      AutocompleteClassifier::kDefaultOmniboxProviders));
106}
107
108void StartupPagesHandler::InitializePage() {
109  UpdateStartupPages();
110}
111
112void StartupPagesHandler::OnModelChanged() {
113  base::ListValue startup_pages;
114  int page_count = startup_custom_pages_table_model_->RowCount();
115  std::vector<GURL> urls = startup_custom_pages_table_model_->GetURLs();
116  for (int i = 0; i < page_count; ++i) {
117    base::DictionaryValue* entry = new base::DictionaryValue();
118    entry->SetString("title", startup_custom_pages_table_model_->GetText(i, 0));
119    entry->SetString("url", urls[i].spec());
120    entry->SetString("tooltip",
121                     startup_custom_pages_table_model_->GetTooltip(i));
122    entry->SetInteger("modelIndex", i);
123    startup_pages.Append(entry);
124  }
125
126  web_ui()->CallJavascriptFunction("StartupOverlay.updateStartupPages",
127                                   startup_pages);
128}
129
130void StartupPagesHandler::OnItemsChanged(int start, int length) {
131  OnModelChanged();
132}
133
134void StartupPagesHandler::OnItemsAdded(int start, int length) {
135  OnModelChanged();
136}
137
138void StartupPagesHandler::OnItemsRemoved(int start, int length) {
139  OnModelChanged();
140}
141
142void StartupPagesHandler::SetStartupPagesToCurrentPages(
143    const base::ListValue* args) {
144  startup_custom_pages_table_model_->SetToCurrentlyOpenPages();
145}
146
147void StartupPagesHandler::RemoveStartupPages(const base::ListValue* args) {
148  for (int i = args->GetSize() - 1; i >= 0; --i) {
149    int selected_index;
150    CHECK(args->GetInteger(i, &selected_index));
151
152    if (selected_index < 0 ||
153        selected_index >= startup_custom_pages_table_model_->RowCount()) {
154      NOTREACHED();
155      return;
156    }
157    startup_custom_pages_table_model_->Remove(selected_index);
158  }
159}
160
161void StartupPagesHandler::AddStartupPage(const base::ListValue* args) {
162  std::string url_string;
163  CHECK(args->GetString(0, &url_string));
164
165  GURL url = url_fixer::FixupURL(url_string, std::string());
166  if (!url.is_valid())
167    return;
168
169  int row_count = startup_custom_pages_table_model_->RowCount();
170  int index;
171  if (!args->GetInteger(1, &index) || index > row_count)
172    index = row_count;
173
174  startup_custom_pages_table_model_->Add(index, url);
175}
176
177void StartupPagesHandler::EditStartupPage(const base::ListValue* args) {
178  std::string url_string;
179  GURL fixed_url;
180  int index;
181  CHECK_EQ(args->GetSize(), 2U);
182  CHECK(args->GetInteger(0, &index));
183  CHECK(args->GetString(1, &url_string));
184
185  if (index < 0 || index > startup_custom_pages_table_model_->RowCount()) {
186    NOTREACHED();
187    return;
188  }
189
190  fixed_url = url_fixer::FixupURL(url_string, std::string());
191  if (!fixed_url.is_empty()) {
192    std::vector<GURL> urls = startup_custom_pages_table_model_->GetURLs();
193    urls[index] = fixed_url;
194    startup_custom_pages_table_model_->SetURLs(urls);
195  } else {
196    startup_custom_pages_table_model_->Remove(index);
197  }
198}
199
200void StartupPagesHandler::DragDropStartupPage(const base::ListValue* args) {
201  CHECK_EQ(args->GetSize(), 2U);
202
203  int to_index;
204
205  CHECK(args->GetInteger(0, &to_index));
206
207  const base::ListValue* selected;
208  CHECK(args->GetList(1, &selected));
209
210  std::vector<int> index_list;
211  for (size_t i = 0; i < selected->GetSize(); ++i) {
212    int index;
213    CHECK(selected->GetInteger(i, &index));
214    index_list.push_back(index);
215  }
216
217  startup_custom_pages_table_model_->MoveURLs(to_index, index_list);
218}
219
220void StartupPagesHandler::SaveStartupPagesPref() {
221  PrefService* prefs = Profile::FromWebUI(web_ui())->GetPrefs();
222
223  SessionStartupPref pref = SessionStartupPref::GetStartupPref(prefs);
224  pref.urls = startup_custom_pages_table_model_->GetURLs();
225
226  if (pref.urls.empty())
227    pref.type = SessionStartupPref::DEFAULT;
228
229  SessionStartupPref::SetStartupPref(prefs, pref);
230}
231
232void StartupPagesHandler::CommitChanges(const base::ListValue* args) {
233  SaveStartupPagesPref();
234}
235
236void StartupPagesHandler::CancelChanges(const base::ListValue* args) {
237  UpdateStartupPages();
238}
239
240void StartupPagesHandler::RequestAutocompleteSuggestions(
241    const base::ListValue* args) {
242  base::string16 input;
243  CHECK_EQ(args->GetSize(), 1U);
244  CHECK(args->GetString(0, &input));
245
246  autocomplete_controller_->Start(AutocompleteInput(
247      input, base::string16::npos, base::string16(), GURL(),
248      metrics::OmniboxEventProto::INVALID_SPEC, true, false, false, true,
249      ChromeAutocompleteSchemeClassifier(Profile::FromWebUI(web_ui()))));
250}
251
252void StartupPagesHandler::OnResultChanged(bool default_match_changed) {
253  const AutocompleteResult& result = autocomplete_controller_->result();
254  base::ListValue suggestions;
255  OptionsUI::ProcessAutocompleteSuggestions(result, &suggestions);
256  web_ui()->CallJavascriptFunction(
257      "StartupOverlay.updateAutocompleteSuggestions", suggestions);
258}
259
260}  // namespace options
261