Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 2013 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "chrome/browser/ui/omnibox/omnibox_controller.h" | 5 #include "chrome/browser/ui/omnibox/omnibox_controller.h" |
| 6 | 6 |
| 7 #include "base/metrics/histogram.h" | 7 #include "base/metrics/histogram.h" |
| 8 #include "chrome/browser/autocomplete/autocomplete_classifier.h" | 8 #include "chrome/browser/autocomplete/autocomplete_classifier.h" |
| 9 #include "chrome/browser/autocomplete/autocomplete_match.h" | 9 #include "chrome/browser/autocomplete/autocomplete_match.h" |
| 10 #include "chrome/browser/autocomplete/search_provider.h" | 10 #include "chrome/browser/autocomplete/search_provider.h" |
| 11 #include "chrome/browser/net/predictor.h" | 11 #include "chrome/browser/net/predictor.h" |
| 12 #include "chrome/browser/predictors/autocomplete_action_predictor.h" | 12 #include "chrome/browser/predictors/autocomplete_action_predictor.h" |
| 13 #include "chrome/browser/prerender/prerender_field_trial.h" | 13 #include "chrome/browser/prerender/prerender_field_trial.h" |
| 14 #include "chrome/browser/prerender/prerender_manager.h" | 14 #include "chrome/browser/prerender/prerender_manager.h" |
| 15 #include "chrome/browser/prerender/prerender_manager_factory.h" | 15 #include "chrome/browser/prerender/prerender_manager_factory.h" |
| 16 #include "chrome/browser/profiles/profile.h" | 16 #include "chrome/browser/profiles/profile.h" |
| 17 #include "chrome/browser/search/search.h" | 17 #include "chrome/browser/search/search.h" |
| 18 #include "chrome/browser/search_engines/template_url_service.h" | |
| 19 #include "chrome/browser/search_engines/template_url_service_factory.h" | |
| 18 #include "chrome/browser/ui/omnibox/omnibox_edit_controller.h" | 20 #include "chrome/browser/ui/omnibox/omnibox_edit_controller.h" |
| 19 #include "chrome/browser/ui/omnibox/omnibox_edit_model.h" | 21 #include "chrome/browser/ui/omnibox/omnibox_edit_model.h" |
| 20 #include "chrome/browser/ui/omnibox/omnibox_popup_model.h" | 22 #include "chrome/browser/ui/omnibox/omnibox_popup_model.h" |
| 21 #include "chrome/browser/ui/omnibox/omnibox_popup_view.h" | 23 #include "chrome/browser/ui/omnibox/omnibox_popup_view.h" |
| 22 #include "chrome/browser/ui/search/instant_controller.h" | 24 #include "chrome/browser/ui/search/instant_controller.h" |
| 23 #include "extensions/common/constants.h" | 25 #include "extensions/common/constants.h" |
| 24 #include "ui/gfx/rect.h" | 26 #include "ui/gfx/rect.h" |
| 25 | 27 |
| 26 using predictors::AutocompleteActionPredictor; | 28 using predictors::AutocompleteActionPredictor; |
| 27 | 29 |
| 30 namespace { | |
| 31 | |
| 32 string16 GetDefaultSearchProviderKeyword(Profile* profile) { | |
| 33 TemplateURLService* template_url_service = | |
| 34 TemplateURLServiceFactory::GetForProfile(profile); | |
| 35 if (template_url_service) { | |
| 36 TemplateURL* template_url = | |
| 37 template_url_service->GetDefaultSearchProvider(); | |
| 38 if (template_url) | |
| 39 return template_url->keyword(); | |
| 40 } | |
| 41 return string16(); | |
| 42 } | |
| 43 | |
| 44 } // namespace | |
| 28 | 45 |
| 29 OmniboxController::OmniboxController(OmniboxEditModel* omnibox_edit_model, | 46 OmniboxController::OmniboxController(OmniboxEditModel* omnibox_edit_model, |
| 30 Profile* profile) | 47 Profile* profile) |
| 31 : omnibox_edit_model_(omnibox_edit_model), | 48 : omnibox_edit_model_(omnibox_edit_model), |
| 32 profile_(profile) { | 49 profile_(profile) { |
| 33 autocomplete_controller_.reset(new AutocompleteController(profile, this, | 50 autocomplete_controller_.reset(new AutocompleteController(profile, this, |
| 34 chrome::IsInstantExtendedAPIEnabled() ? | 51 chrome::IsInstantExtendedAPIEnabled() ? |
| 35 AutocompleteClassifier::kInstantExtendedOmniboxProviders : | 52 AutocompleteClassifier::kInstantExtendedOmniboxProviders : |
| 36 AutocompleteClassifier::kDefaultOmniboxProviders)); | 53 AutocompleteClassifier::kDefaultOmniboxProviders)); |
| 37 } | 54 } |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 69 AutocompleteInput::ALL_MATCHES)); | 86 AutocompleteInput::ALL_MATCHES)); |
| 70 } | 87 } |
| 71 | 88 |
| 72 void OmniboxController::OnResultChanged(bool default_match_changed) { | 89 void OmniboxController::OnResultChanged(bool default_match_changed) { |
| 73 // TODO(beaudoin): There should be no need to access the popup when using | 90 // TODO(beaudoin): There should be no need to access the popup when using |
| 74 // instant extended, remove this reference. | 91 // instant extended, remove this reference. |
| 75 const bool was_open = popup_->IsOpen(); | 92 const bool was_open = popup_->IsOpen(); |
| 76 if (default_match_changed) { | 93 if (default_match_changed) { |
| 77 // The default match has changed, we need to let the OmniboxEditModel know | 94 // The default match has changed, we need to let the OmniboxEditModel know |
| 78 // about new inline autocomplete text (blue highlight). | 95 // about new inline autocomplete text (blue highlight). |
| 79 string16 inline_autocomplete_text; | |
| 80 string16 keyword; | |
| 81 bool is_keyword_hint = false; | |
| 82 const AutocompleteResult& result = this->result(); | 96 const AutocompleteResult& result = this->result(); |
| 83 const AutocompleteResult::const_iterator match(result.default_match()); | 97 const AutocompleteResult::const_iterator match(result.default_match()); |
| 84 if (match != result.end()) { | 98 if (match != result.end()) { |
| 99 current_match_ = *match; | |
| 100 // The |fill_into_edit| we get may not match what we have in the view at | |
| 101 // that time. We're only interested in the inline_autocomplete part, so | |
| 102 // update this here. | |
| 103 current_match_.fill_into_edit = omnibox_edit_model_->user_text(); | |
|
Peter Kasting
2013/06/11 22:42:55
I confess, I have no idea what you're doing here.
beaudoin
2013/06/14 21:39:38
This is the "blue text" completion path. In an ide
Peter Kasting
2013/06/15 00:29:21
It seems like the reason we need to change this is
beaudoin
2013/06/17 17:22:33
Yes, I think it would make it easier to understand
| |
| 85 if ((match->inline_autocomplete_offset != string16::npos) && | 104 if ((match->inline_autocomplete_offset != string16::npos) && |
|
Peter Kasting
2013/06/11 22:42:55
Nit: First condition not necessary, see comments i
beaudoin
2013/06/14 21:39:38
Done.
| |
| 86 (match->inline_autocomplete_offset < | 105 (match->inline_autocomplete_offset < |
| 87 match->fill_into_edit.length())) { | 106 match->fill_into_edit.length())) { |
| 88 inline_autocomplete_text = | 107 current_match_.inline_autocomplete_offset = |
| 89 match->fill_into_edit.substr(match->inline_autocomplete_offset); | 108 current_match_.fill_into_edit.length(); |
| 109 current_match_.fill_into_edit += match->fill_into_edit.substr( | |
| 110 match->inline_autocomplete_offset); | |
| 111 } else { | |
| 112 current_match_.inline_autocomplete_offset = string16::npos; | |
| 90 } | 113 } |
| 91 | 114 |
| 92 if (!prerender::IsOmniboxEnabled(profile_)) | 115 if (!prerender::IsOmniboxEnabled(profile_)) |
| 93 DoPreconnect(*match); | 116 DoPreconnect(*match); |
| 94 | 117 omnibox_edit_model_->OnCurrentMatchChanged(false); |
| 95 // We could prefetch the alternate nav URL, if any, but because there | 118 } else { |
| 96 // can be many of these as a user types an initial series of characters, | 119 InvalidateCurrentMatch(); |
| 97 // the OS DNS cache could suffer eviction problems for minimal gain. | 120 popup_->OnResultChanged(); |
| 98 | 121 omnibox_edit_model_->OnPopupDataChanged(string16(), NULL, string16(), |
| 99 match->GetKeywordUIState(profile_, &keyword, &is_keyword_hint); | 122 false); |
| 100 } | 123 } |
| 101 | |
| 102 popup_->OnResultChanged(); | |
| 103 omnibox_edit_model_->OnPopupDataChanged(inline_autocomplete_text, NULL, | |
| 104 keyword, is_keyword_hint); | |
| 105 } else { | 124 } else { |
| 106 popup_->OnResultChanged(); | 125 popup_->OnResultChanged(); |
| 107 } | 126 } |
| 108 | 127 |
| 128 // TODO(beaudoin): This may no longer be needed now that instant classic is | |
| 129 // gone. | |
| 109 if (popup_->IsOpen()) { | 130 if (popup_->IsOpen()) { |
| 110 // The popup size may have changed, let instant know. | 131 // The popup size may have changed, let instant know. |
| 111 OnPopupBoundsChanged(popup_->view()->GetTargetBounds()); | 132 OnPopupBoundsChanged(popup_->view()->GetTargetBounds()); |
| 112 | 133 |
| 113 InstantController* instant_controller = GetInstantController(); | 134 InstantController* instant_controller = GetInstantController(); |
| 114 if (instant_controller && !omnibox_edit_model_->in_revert()) { | 135 if (instant_controller && !omnibox_edit_model_->in_revert()) { |
| 115 instant_controller->HandleAutocompleteResults( | 136 instant_controller->HandleAutocompleteResults( |
| 116 *autocomplete_controller_->providers(), | 137 *autocomplete_controller_->providers(), |
| 117 autocomplete_controller_->result()); | 138 autocomplete_controller_->result()); |
| 118 } | 139 } |
| (...skipping 23 matching lines...) Expand all Loading... | |
| 142 AutocompleteInput::RemoveForcedQueryStringIfNecessary( | 163 AutocompleteInput::RemoveForcedQueryStringIfNecessary( |
| 143 autocomplete_controller_->input().type(), &user_text); | 164 autocomplete_controller_->input().type(), &user_text); |
| 144 AutocompleteInput::RemoveForcedQueryStringIfNecessary( | 165 AutocompleteInput::RemoveForcedQueryStringIfNecessary( |
| 145 autocomplete_controller_->input().type(), &full_text); | 166 autocomplete_controller_->input().type(), &full_text); |
| 146 return instant_controller->Update( | 167 return instant_controller->Update( |
| 147 match, user_text, full_text, selection_start, selection_end, | 168 match, user_text, full_text, selection_start, selection_end, |
| 148 UseVerbatimInstant(just_deleted_text), user_input_in_progress, | 169 UseVerbatimInstant(just_deleted_text), user_input_in_progress, |
| 149 popup_->IsOpen(), in_escape_handler, keyword_is_selected); | 170 popup_->IsOpen(), in_escape_handler, keyword_is_selected); |
| 150 } | 171 } |
| 151 | 172 |
| 173 void OmniboxController::FinalizeInstantQuery( | |
| 174 const string16& input_text, | |
| 175 const InstantSuggestion& suggestion) { | |
| 176 if (!popup_model()->result().empty()) { | |
| 177 // When a IME is active and a candidate window is open, we don't show | |
| 178 // the omnibox popup, though |result()| may be available. Thus we check | |
| 179 // whether result().empty() or not instead of whether IsOpen() or not. | |
| 180 // We need the finalization of instant query when result() is available. | |
|
Peter Kasting
2013/06/11 22:42:55
Nit: This last sentence isn't grammatical and I do
beaudoin
2013/06/14 21:39:38
Clarified, to the best of my understanding.
Done.
| |
| 181 SearchProvider* search_provider = | |
| 182 autocomplete_controller_->search_provider(); | |
| 183 // There may be no providers during testing; guard against that. | |
| 184 if (search_provider) | |
| 185 search_provider->FinalizeInstantQuery(input_text, suggestion); | |
| 186 } | |
| 187 } | |
| 188 | |
| 189 void OmniboxController::SetInstantSuggestion( | |
| 190 const InstantSuggestion& suggestion) { | |
| 191 switch (suggestion.behavior) { | |
| 192 | |
|
Peter Kasting
2013/06/11 22:42:55
Nit: Extra newline
beaudoin
2013/06/14 21:39:38
Done.
| |
| 193 case INSTANT_COMPLETE_NOW: | |
| 194 // Set blue suggestion text. | |
| 195 // TODO(beaudoin): This currently go to the SearchProvider. Instead we | |
|
Peter Kasting
2013/06/11 22:42:55
Nit: go -> goes
beaudoin
2013/06/14 21:39:38
Done.
| |
| 196 // should just create a valid current_match_ and call | |
| 197 // omnibox_edit_model_->OnCurrentMatchChanged. This way we can get rid of | |
| 198 // FinalizeInstantQuery entirely. | |
| 199 if (!suggestion.text.empty()) | |
| 200 FinalizeInstantQuery(omnibox_edit_model_->GetViewText(), suggestion); | |
| 201 break; | |
|
Peter Kasting
2013/06/11 22:42:55
Nit: Prefer return to break when they'd do the sam
beaudoin
2013/06/14 21:39:38
Done.
| |
| 202 | |
| 203 case INSTANT_COMPLETE_NEVER: { | |
| 204 DCHECK_EQ(INSTANT_SUGGESTION_SEARCH, suggestion.type); | |
| 205 | |
| 206 // Set gray suggestion text. | |
| 207 // Remove "?" if we're in forced query mode. | |
| 208 string16 view_text = omnibox_edit_model_->GetViewText(); | |
| 209 AutocompleteInput::RemoveForcedQueryStringIfNecessary( | |
| 210 autocomplete_controller_->input().type(), &view_text); | |
|
beaudoin
2013/06/06 14:15:00
Sreeram: I'm using autocomplete_controller->input(
sreeram
2013/06/06 23:32:23
No, not kosher. The gray text is set asynchronousl
beaudoin
2013/06/14 21:39:38
Done.
| |
| 211 CreateAndSetInstantMatch(view_text, view_text, | |
| 212 AutocompleteMatchType::SEARCH_SUGGEST); | |
| 213 current_match_.gray_suggestion = suggestion.text; | |
| 214 | |
| 215 // TODO(beaudoin): The following should no longer be needed. | |
| 216 SearchProvider* search_provider = | |
| 217 autocomplete_controller_->search_provider(); | |
| 218 if (search_provider) | |
| 219 search_provider->ClearInstantSuggestion(); | |
| 220 | |
| 221 omnibox_edit_model_->OnCurrentMatchChanged(false); | |
| 222 break; | |
| 223 } | |
| 224 | |
| 225 case INSTANT_COMPLETE_REPLACE: | |
| 226 // Replace the entire omnibox text by the suggestion the user just arrowed | |
| 227 // into. | |
|
Peter Kasting
2013/06/11 22:42:55
Nit: into -> to
beaudoin
2013/06/14 21:39:38
Done.
| |
| 228 CreateAndSetInstantMatch(suggestion.text, suggestion.text, | |
| 229 suggestion.type == INSTANT_SUGGESTION_SEARCH ? | |
| 230 AutocompleteMatchType::SEARCH_SUGGEST : | |
| 231 AutocompleteMatchType::URL_WHAT_YOU_TYPED); | |
| 232 | |
| 233 omnibox_edit_model_->OnCurrentMatchChanged(true); | |
| 234 break; | |
| 235 } | |
| 236 } | |
| 237 | |
| 238 void OmniboxController::InvalidateCurrentMatch() { | |
| 239 current_match_ = AutocompleteMatch(); | |
| 240 } | |
| 241 | |
| 152 void OmniboxController::ClearPopupKeywordMode() const { | 242 void OmniboxController::ClearPopupKeywordMode() const { |
| 153 if (popup_->IsOpen() && | 243 if (popup_->IsOpen() && |
| 154 popup_->selected_line_state() == OmniboxPopupModel::KEYWORD) | 244 popup_->selected_line_state() == OmniboxPopupModel::KEYWORD) |
| 155 popup_->SetSelectedLineState(OmniboxPopupModel::NORMAL); | 245 popup_->SetSelectedLineState(OmniboxPopupModel::NORMAL); |
| 156 } | 246 } |
| 157 | 247 |
| 158 void OmniboxController::DoPreconnect(const AutocompleteMatch& match) { | 248 void OmniboxController::DoPreconnect(const AutocompleteMatch& match) { |
| 159 if (!match.destination_url.SchemeIs(extensions::kExtensionScheme)) { | 249 if (!match.destination_url.SchemeIs(extensions::kExtensionScheme)) { |
| 160 // Warm up DNS Prefetch cache, or preconnect to a search service. | 250 // Warm up DNS Prefetch cache, or preconnect to a search service. |
| 161 UMA_HISTOGRAM_ENUMERATION("Autocomplete.MatchType", match.type, | 251 UMA_HISTOGRAM_ENUMERATION("Autocomplete.MatchType", match.type, |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 193 // We send the caret position to Instant (so it can determine #1 itself), and | 283 // We send the caret position to Instant (so it can determine #1 itself), and |
| 194 // we use a separated widget for displaying the Instant suggest (so it doesn't | 284 // we use a separated widget for displaying the Instant suggest (so it doesn't |
| 195 // interfere with #2). So, we don't need to care about the value of | 285 // interfere with #2). So, we don't need to care about the value of |
| 196 // input.prevent_inline_autocomplete() here. | 286 // input.prevent_inline_autocomplete() here. |
| 197 return just_deleted_text || popup_->selected_line() != 0; | 287 return just_deleted_text || popup_->selected_line() != 0; |
| 198 } | 288 } |
| 199 | 289 |
| 200 InstantController* OmniboxController::GetInstantController() const { | 290 InstantController* OmniboxController::GetInstantController() const { |
| 201 return omnibox_edit_model_->GetInstantController(); | 291 return omnibox_edit_model_->GetInstantController(); |
| 202 } | 292 } |
| 293 | |
| 294 void OmniboxController::CreateAndSetInstantMatch( | |
| 295 string16 query_string, | |
| 296 string16 input_text, | |
| 297 AutocompleteMatchType::Type match_type) { | |
| 298 string16 keyword = GetDefaultSearchProviderKeyword(profile_); | |
| 299 if (keyword.empty()) | |
| 300 return; // CreateSearchSuggestion needs a keyword. | |
| 301 | |
| 302 current_match_ = SearchProvider::CreateSearchSuggestion( | |
| 303 profile_, | |
| 304 NULL, // autocomplete_provider | |
|
Peter Kasting
2013/06/11 22:42:55
Nit: I don't really like commenting particular arg
beaudoin
2013/06/14 21:39:38
Done.
| |
| 305 AutocompleteInput(), | |
| 306 query_string, | |
| 307 input_text, | |
| 308 0, // relevance | |
| 309 match_type, | |
| 310 0, // accepted_suggestion | |
| 311 false, // is_keyword | |
| 312 keyword); | |
| 313 } | |
| OLD | NEW |