Disable view source for Developer Tools.
[chromium-blink-merge.git] / chrome / browser / ui / webui / omnibox / omnibox_ui_handler.cc
blob33c324a89b100784b2f47fa2c1e13acab267bf6b
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.
5 #include "chrome/browser/ui/webui/omnibox/omnibox_ui_handler.h"
7 #include <string>
9 #include "base/auto_reset.h"
10 #include "base/bind.h"
11 #include "base/strings/string16.h"
12 #include "base/strings/stringprintf.h"
13 #include "base/strings/utf_string_conversions.h"
14 #include "base/time/time.h"
15 #include "base/values.h"
16 #include "chrome/browser/autocomplete/autocomplete_classifier.h"
17 #include "chrome/browser/autocomplete/autocomplete_controller.h"
18 #include "chrome/browser/autocomplete/autocomplete_input.h"
19 #include "chrome/browser/autocomplete/autocomplete_match.h"
20 #include "chrome/browser/autocomplete/autocomplete_provider.h"
21 #include "chrome/browser/history/history_service.h"
22 #include "chrome/browser/history/history_service_factory.h"
23 #include "chrome/browser/history/url_database.h"
24 #include "chrome/browser/search/search.h"
25 #include "chrome/browser/search_engines/template_url.h"
26 #include "content/public/browser/web_ui.h"
28 OmniboxUIHandler::OmniboxUIHandler(Profile* profile): profile_(profile) {
29 ResetController();
32 OmniboxUIHandler::~OmniboxUIHandler() {}
34 void OmniboxUIHandler::RegisterMessages() {
35 web_ui()->RegisterMessageCallback("startOmniboxQuery",
36 base::Bind(&OmniboxUIHandler::StartOmniboxQuery,
37 base::Unretained(this)));
40 // This function gets called when the AutocompleteController possibly
41 // has new results. We package those results in a DictionaryValue
42 // object result_to_output and call the javascript function
43 // handleNewAutocompleteResult. Here's an example populated
44 // result_to_output object:
45 // {
46 // 'done': false,
47 // 'time_since_omnibox_started_ms': 15,
48 // 'host': 'mai',
49 // 'is_typed_host': false,
50 // 'combined_results' : {
51 // 'num_items': 4,
52 // 'item_0': {
53 // 'destination_url': 'http://mail.google.com',
54 // 'provider_name': 'HistoryURL',
55 // 'relevance': 1410,
56 // ...
57 // }
58 // 'item_1: {
59 // ...
60 // }
61 // ...
62 // }
63 // 'results_by_provider': {
64 // 'HistoryURL' : {
65 // 'num_items': 3,
66 // ...
67 // }
68 // 'Search' : {
69 // 'num_items': 1,
70 // ...
71 // }
72 // ...
73 // }
74 // }
75 // For reference, the javascript code that unpacks this object and
76 // displays it is in chrome/browser/resources/omnibox.js
77 void OmniboxUIHandler::OnResultChanged(bool default_match_changed) {
78 base::DictionaryValue result_to_output;
79 // Fill in general information.
80 result_to_output.SetBoolean("done", controller_->done());
81 result_to_output.SetInteger("time_since_omnibox_started_ms",
82 (base::Time::Now() - time_omnibox_started_).InMilliseconds());
83 const base::string16& host = controller_->input().text().substr(
84 controller_->input().parts().host.begin,
85 controller_->input().parts().host.len);
86 result_to_output.SetString("host", host);
87 bool is_typed_host;
88 if (LookupIsTypedHost(host, &is_typed_host)) {
89 // If we successfully looked up whether the host part of the omnibox
90 // input (this interprets the input as a host plus optional path) as
91 // a typed host, then record this information in the output.
92 result_to_output.SetBoolean("is_typed_host", is_typed_host);
94 // Fill in the merged/combined results the controller has provided.
95 AddResultToDictionary("combined_results", controller_->result().begin(),
96 controller_->result().end(), &result_to_output);
97 // Fill results from each individual provider as well.
98 for (ACProviders::const_iterator it(controller_->providers()->begin());
99 it != controller_->providers()->end(); ++it) {
100 AddResultToDictionary(
101 std::string("results_by_provider.") + (*it)->GetName(),
102 (*it)->matches().begin(), (*it)->matches().end(), &result_to_output);
104 // Add done; send the results.
105 web_ui()->CallJavascriptFunction("omniboxDebug.handleNewAutocompleteResult",
106 result_to_output);
109 // For details on the format of the DictionaryValue that this function
110 // populates, see the comments by OnResultChanged().
111 void OmniboxUIHandler::AddResultToDictionary(const std::string& prefix,
112 ACMatches::const_iterator it,
113 ACMatches::const_iterator end,
114 base::DictionaryValue* output) {
115 int i = 0;
116 for (; it != end; ++it, ++i) {
117 std::string item_prefix(prefix + base::StringPrintf(".item_%d", i));
118 if (it->provider != NULL) {
119 output->SetString(item_prefix + ".provider_name",
120 it->provider->GetName());
121 output->SetBoolean(item_prefix + ".provider_done", it->provider->done());
123 output->SetInteger(item_prefix + ".relevance", it->relevance);
124 output->SetBoolean(item_prefix + ".deletable", it->deletable);
125 output->SetString(item_prefix + ".fill_into_edit", it->fill_into_edit);
126 output->SetString(item_prefix + ".inline_autocompletion",
127 it->inline_autocompletion);
128 output->SetString(item_prefix + ".destination_url",
129 it->destination_url.spec());
130 output->SetString(item_prefix + ".contents", it->contents);
131 // At this time, we're not bothering to send along the long vector that
132 // represent contents classification. i.e., for each character, what
133 // type of text it is.
134 output->SetString(item_prefix + ".description", it->description);
135 // At this time, we're not bothering to send along the long vector that
136 // represents description classification. i.e., for each character, what
137 // type of text it is.
138 output->SetInteger(item_prefix + ".transition", it->transition);
139 output->SetBoolean(item_prefix + ".is_history_what_you_typed_match",
140 it->is_history_what_you_typed_match);
141 output->SetBoolean(item_prefix + ".allowed_to_be_default_match",
142 it->allowed_to_be_default_match);
143 output->SetString(item_prefix + ".type",
144 AutocompleteMatchType::ToString(it->type));
145 if (it->associated_keyword.get() != NULL) {
146 output->SetString(item_prefix + ".associated_keyword",
147 it->associated_keyword->keyword);
149 output->SetString(item_prefix + ".keyword", it->keyword);
150 output->SetBoolean(item_prefix + ".starred", it->starred);
151 output->SetBoolean(item_prefix + ".from_previous", it->from_previous);
152 for (AutocompleteMatch::AdditionalInfo::const_iterator j =
153 it->additional_info.begin(); j != it->additional_info.end(); ++j) {
154 output->SetString(item_prefix + ".additional_info." + j->first,
155 j->second);
158 output->SetInteger(prefix + ".num_items", i);
161 bool OmniboxUIHandler::LookupIsTypedHost(const base::string16& host,
162 bool* is_typed_host) const {
163 HistoryService* const history_service =
164 HistoryServiceFactory::GetForProfile(profile_,
165 Profile::EXPLICIT_ACCESS);
166 if (!history_service)
167 return false;
168 history::URLDatabase* url_db = history_service->InMemoryDatabase();
169 if (!url_db)
170 return false;
171 *is_typed_host = url_db->IsTypedHost(base::UTF16ToUTF8(host));
172 return true;
175 void OmniboxUIHandler::StartOmniboxQuery(const base::ListValue* input) {
176 DCHECK_EQ(4u, input->GetSize());
177 base::string16 input_string;
178 bool return_val = input->GetString(0, &input_string);
179 DCHECK(return_val);
180 int cursor_position;
181 return_val = input->GetInteger(1, &cursor_position);
182 DCHECK(return_val);
183 bool prevent_inline_autocomplete;
184 return_val = input->GetBoolean(2, &prevent_inline_autocomplete);
185 DCHECK(return_val);
186 bool prefer_keyword;
187 return_val = input->GetBoolean(3, &prefer_keyword);
188 DCHECK(return_val);
189 // Reset the controller. If we don't do this, then the
190 // AutocompleteController might inappropriately set its |minimal_changes|
191 // variable (or something else) and some providers will short-circuit
192 // important logic and return stale results. In short, we want the
193 // actual results to not depend on the state of the previous request.
194 ResetController();
195 time_omnibox_started_ = base::Time::Now();
196 controller_->Start(AutocompleteInput(
197 input_string,
198 cursor_position,
199 base::string16(), // user's desired tld (top-level domain)
200 GURL(),
201 AutocompleteInput::INVALID_SPEC,
202 prevent_inline_autocomplete,
203 prefer_keyword,
204 true, // allow exact keyword matches
205 AutocompleteInput::ALL_MATCHES)); // want all matches
208 void OmniboxUIHandler::ResetController() {
209 controller_.reset(new AutocompleteController(profile_, this,
210 AutocompleteClassifier::kDefaultOmniboxProviders));