Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(185)

Side by Side Diff: chrome/browser/autocomplete/zerosuggest_provider.cc

Issue 10832256: Experimental AutocompleteProvider for zerosuggest. (Closed) Base URL: http://git.chromium.org/chromium/src.git@master
Patch Set: Created 8 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
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/autocomplete/zerosuggest_provider.h"
6
7 #include "base/callback.h"
8 #include "base/i18n/icu_string_conversions.h"
9 #include "base/json/json_string_value_serializer.h"
10 #include "base/string16.h"
11 #include "base/string_util.h"
12 #include "base/time.h"
13 #include "base/utf_string_conversions.h"
14 #include "chrome/browser/autocomplete/autocomplete_input.h"
15 #include "chrome/browser/autocomplete/autocomplete_match.h"
16 #include "chrome/browser/autocomplete/autocomplete_provider_listener.h"
17 #include "chrome/browser/profiles/profile.h"
18 #include "chrome/browser/search_engines/template_url_service.h"
19 #include "chrome/browser/search_engines/template_url_service_factory.h"
20 #include "chrome/common/url_constants.h"
21 #include "googleurl/src/gurl.h"
22 #include "net/base/load_flags.h"
23 #include "net/http/http_response_headers.h"
24 #include "net/url_request/url_fetcher.h"
25 #include "net/url_request/url_request_status.h"
26 #include "ui/base/l10n/l10n_util.h"
27
28 ZerosuggestProvider::ZerosuggestProvider(
29 AutocompleteProviderListener* listener,
30 Profile* profile,
31 const std::string& url_prefix)
32 : AutocompleteProvider(listener, profile, "Zerosuggest"),
33 url_prefix_(url_prefix),
34 template_url_service_(TemplateURLServiceFactory::GetForProfile(profile)) {
35 }
36
37 void ZerosuggestProvider::Start(const AutocompleteInput& input,
38 bool /*minimal_changes*/) {
39 UpdateMatches(input.text());
40 }
41
42 void ZerosuggestProvider::StartZerosuggest(
43 const GURL& url,
44 const string16& user_text) {
45 const std::string& spec = url.possibly_invalid_spec();
46 if (spec.empty() || url.scheme() != chrome::kHttpScheme)
47 // Do not query empty URLs nor non-http URLs. There will be no useful
48 // suggestions for https or chrome URLs.
49 return;
50 matches_.clear();
51 done_ = false;
52 user_text_ = user_text;
53 current_query_ = spec;
54 current_query_text_ = ASCIIToUTF16(spec);
55 // When navigating on Mac, the omnibox first gains then immediately loses
56 // focus. This is difficult to distinguish from user-initiated focus. Wait
57 // a while before fetching, and if the omnibox is immediately unfocused,
58 // Stop() should cancel this timer.
Peter Kasting 2012/08/10 21:33:33 Find a different solution. Providers must not kno
Jered 2012/08/10 23:05:23 Done. This problem vanished after my rebase. Lucky
59 const int kFetchDelayMS = 10;
60 timer_.Start(FROM_HERE,
61 base::TimeDelta::FromMilliseconds(kFetchDelayMS),
62 this, &ZerosuggestProvider::Run);
63 }
64
65 void ZerosuggestProvider::Stop(bool clear_cached_results) {
66 timer_.Stop();
67 fetcher_.reset();
68 done_ = true;
69 if (clear_cached_results) {
70 results_.clear();
71 current_query_.clear();
72 current_query_text_.clear();
73 }
74 }
75
76 void ZerosuggestProvider::OnURLFetchComplete(const net::URLFetcher* source) {
77 const net::HttpResponseHeaders* const response_headers =
78 source->GetResponseHeaders();
79 std::string json_data;
80 source->GetResponseAsString(&json_data);
81 if (response_headers) {
82 std::string charset;
83 if (response_headers->GetCharset(&charset)) {
84 string16 data_16;
85 if (base::CodepageToUTF16(json_data, charset.c_str(),
86 base::OnStringConversionError::FAIL,
87 &data_16))
88 json_data = UTF16ToUTF8(data_16);
89 }
90 }
91 const bool request_succeeded =
92 source->GetStatus().is_success() && source->GetResponseCode() == 200;
93
94 bool results_updated = false;
95 if (request_succeeded) {
96 JSONStringValueSerializer deserializer(json_data);
97 deserializer.set_allow_trailing_comma(true);
98 scoped_ptr<Value> data(deserializer.Deserialize(NULL, NULL));
99 results_updated = data.get() && ParseSuggestResults(data.get());
100 }
101 done_ = true;
102
103 ConvertResultsToAutocompleteMatches();
104 if (results_updated)
105 listener_->OnProviderUpdate(results_updated);
106 }
107
108 ZerosuggestProvider::~ZerosuggestProvider() {
109 }
110
111 void ZerosuggestProvider::Run() {
112 const int kFetcherID = 1;
113 fetcher_.reset(
114 net::URLFetcher::Create(kFetcherID,
115 GURL(url_prefix_ + current_query_),
116 net::URLFetcher::GET, this));
117 fetcher_->SetRequestContext(profile_->GetRequestContext());
118 fetcher_->SetLoadFlags(net::LOAD_DO_NOT_SAVE_COOKIES);
119 fetcher_->Start();
120 }
121
122 void ZerosuggestProvider::UpdateMatches(const string16& user_text) {
123 user_text_ = user_text;
124 const size_t prev_num_matches = matches_.size();
125 ConvertResultsToAutocompleteMatches();
126 if (matches_.size() != prev_num_matches)
127 listener_->OnProviderUpdate(true);
128 }
129
130 bool ZerosuggestProvider::ParseSuggestResults(Value* root_val) {
131 std::string query;
132 ListValue* root_list = NULL;
133 ListValue* results = NULL;
134 if (!root_val->GetAsList(&root_list) || !root_list->GetString(0, &query) ||
135 (query != current_query_) || !root_list->GetList(1, &results))
136 return false;
137
138 results_.clear();
139 ListValue* one_result = NULL;
140 for (size_t index = 0; results->GetList(index, &one_result); ++index) {
141 string16 result;
142 one_result->GetString(0, &result);
143 if (result.empty())
144 continue;
145 results_.push_back(result);
146 }
147
148 return true;
149 }
150
151 void ZerosuggestProvider::ConvertResultsToAutocompleteMatches() {
152 const TemplateURL* search_provider =
153 template_url_service_->GetDefaultSearchProvider();
154 if (search_provider == NULL || !search_provider->SupportsReplacement())
155 // Fail if we can't set the clickthrough URL for query suggestions.
156 return;
157 matches_.clear();
158 if (results_.empty())
159 // Do not add anything if there are no results for this URL.
160 return;
161 AddMatchForCurrentURL();
162 for (size_t i = 0; i < results_.size(); ++i)
163 AddMatchForResult(search_provider, i, results_[i]);
164 }
165
166 void ZerosuggestProvider::AddMatchForCurrentURL() {
167 // If the user has typed something besides the current url, they probably
168 // don't intend to refresh it.
169 const bool user_text_is_url = user_text_ == current_query_text_;
170 if (user_text_.empty() || user_text_is_url) {
171 AutocompleteMatch match(this, 2000, false,
172 AutocompleteMatch::SEARCH_ZEROSUGGEST_URL);
173 match.destination_url = GURL(current_query_);
174 match.contents = current_query_text_;
175 if (!user_text_is_url) {
176 match.fill_into_edit = current_query_text_;
177 match.inline_autocomplete_offset = 0;
178 }
179 AutocompleteMatch::ClassifyLocationInString(0, current_query_.size(),
180 match.contents.length(), ACMatchClassification::URL,
181 &match.contents_class);
182 matches_.push_back(match);
183 }
184 }
185
186 void ZerosuggestProvider::AddMatchForResult(
187 const TemplateURL* search_provider,
188 size_t result_index,
189 const string16& result) {
190 const bool user_text_is_url = user_text_ == current_query_text_;
191 const bool kCaseInsensitve = false;
192 if (!user_text_.empty() && !user_text_is_url &&
193 !StartsWith(result, user_text_, kCaseInsensitve))
194 // This suggestion isn't relevant for the current prefix.
195 return;
196 const int kRelevance = 1999;
197 AutocompleteMatch match(this, kRelevance, false,
198 AutocompleteMatch::SEARCH_ZEROSUGGEST);
199 match.contents = result;
200 match.fill_into_edit = result;
201 if (!user_text_is_url && user_text_ != result)
202 match.inline_autocomplete_offset = user_text_.length();
203
204 // Build a URL for this query using the default search provider.
205 const TemplateURLRef& search_url = search_provider->url_ref();
206 DCHECK(search_url.SupportsReplacement());
207 match.search_terms_args.reset(
208 new TemplateURLRef::SearchTermsArgs(result));
209 match.search_terms_args->original_query = string16();
210 match.search_terms_args->accepted_suggestion = result_index;
211 match.destination_url =
212 GURL(search_url.ReplaceSearchTerms(*match.search_terms_args.get()));
213
214 if (user_text_.empty() || user_text_is_url || user_text_ == result) {
215 match.contents_class.push_back(
216 ACMatchClassification(0, ACMatchClassification::NONE));
217 } else {
218 // Style to look like normal search suggestions.
219 match.contents_class.push_back(
220 ACMatchClassification(0, ACMatchClassification::DIM));
221 match.contents_class.push_back(
222 ACMatchClassification(user_text_.length(), ACMatchClassification::NONE));
223 }
224 match.transition = content::PAGE_TRANSITION_GENERATED;
225
226 matches_.push_back(match);
227 }
OLDNEW
« no previous file with comments | « chrome/browser/autocomplete/zerosuggest_provider.h ('k') | chrome/browser/ui/omnibox/omnibox_edit_model.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698