| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 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_edit_model.h" | 5 #include "chrome/browser/ui/omnibox/omnibox_edit_model.h" |
| 6 | 6 |
| 7 #include <string> | 7 #include <string> |
| 8 | 8 |
| 9 #include "base/format_macros.h" | 9 #include "base/format_macros.h" |
| 10 #include "base/metrics/histogram.h" | 10 #include "base/metrics/histogram.h" |
| (...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 90 controller_(controller), | 90 controller_(controller), |
| 91 has_focus_(false), | 91 has_focus_(false), |
| 92 user_input_in_progress_(false), | 92 user_input_in_progress_(false), |
| 93 just_deleted_text_(false), | 93 just_deleted_text_(false), |
| 94 has_temporary_text_(false), | 94 has_temporary_text_(false), |
| 95 paste_state_(NONE), | 95 paste_state_(NONE), |
| 96 control_key_state_(UP), | 96 control_key_state_(UP), |
| 97 is_keyword_hint_(false), | 97 is_keyword_hint_(false), |
| 98 profile_(profile), | 98 profile_(profile), |
| 99 in_revert_(false), | 99 in_revert_(false), |
| 100 allow_exact_keyword_match_(false), | 100 allow_exact_keyword_match_(false) { |
| 101 instant_complete_behavior_(INSTANT_COMPLETE_DELAYED) { | |
| 102 } | 101 } |
| 103 | 102 |
| 104 OmniboxEditModel::~OmniboxEditModel() { | 103 OmniboxEditModel::~OmniboxEditModel() { |
| 105 } | 104 } |
| 106 | 105 |
| 107 const OmniboxEditModel::State OmniboxEditModel::GetStateForTabSwitch() { | 106 const OmniboxEditModel::State OmniboxEditModel::GetStateForTabSwitch() { |
| 108 // Like typing, switching tabs "accepts" the temporary text as the user | 107 // Like typing, switching tabs "accepts" the temporary text as the user |
| 109 // text, because it makes little sense to have temporary text when the | 108 // text, because it makes little sense to have temporary text when the |
| 110 // popup is closed. | 109 // popup is closed. |
| 111 if (user_input_in_progress_) { | 110 if (user_input_in_progress_) { |
| (...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 179 SearchProvider* search_provider = | 178 SearchProvider* search_provider = |
| 180 autocomplete_controller_->search_provider(); | 179 autocomplete_controller_->search_provider(); |
| 181 // There may be no providers during testing; guard against that. | 180 // There may be no providers during testing; guard against that. |
| 182 if (search_provider) | 181 if (search_provider) |
| 183 search_provider->FinalizeInstantQuery(input_text, suggest_text); | 182 search_provider->FinalizeInstantQuery(input_text, suggest_text); |
| 184 } | 183 } |
| 185 } | 184 } |
| 186 | 185 |
| 187 void OmniboxEditModel::SetSuggestedText(const string16& text, | 186 void OmniboxEditModel::SetSuggestedText(const string16& text, |
| 188 InstantCompleteBehavior behavior) { | 187 InstantCompleteBehavior behavior) { |
| 189 instant_complete_behavior_ = behavior; | 188 if (behavior == INSTANT_COMPLETE_NOW) { |
| 190 if (instant_complete_behavior_ == INSTANT_COMPLETE_NOW) { | |
| 191 if (!text.empty()) | 189 if (!text.empty()) |
| 192 FinalizeInstantQuery(view_->GetText(), text, false); | 190 FinalizeInstantQuery(view_->GetText(), text, false); |
| 193 else | 191 else |
| 194 view_->SetInstantSuggestion(text, false); | 192 view_->SetInstantSuggestion(text, false); |
| 195 } else { | 193 } else { |
| 196 DCHECK((behavior == INSTANT_COMPLETE_DELAYED) || | 194 DCHECK((behavior == INSTANT_COMPLETE_DELAYED) || |
| 197 (behavior == INSTANT_COMPLETE_NEVER)); | 195 (behavior == INSTANT_COMPLETE_NEVER)); |
| 198 view_->SetInstantSuggestion(text, behavior == INSTANT_COMPLETE_DELAYED); | 196 view_->SetInstantSuggestion(text, behavior == INSTANT_COMPLETE_DELAYED); |
| 199 } | 197 } |
| 200 } | 198 } |
| 201 | 199 |
| 202 bool OmniboxEditModel::CommitSuggestedText(bool skip_inline_autocomplete) { | 200 bool OmniboxEditModel::CommitSuggestedText(bool skip_inline_autocomplete) { |
| 203 if (!controller_->GetInstant()) | 201 if (!controller_->GetInstant()) |
| 204 return false; | 202 return false; |
| 205 | 203 |
| 206 const string16 suggestion = view_->GetInstantSuggestion(); | 204 const string16 suggestion = view_->GetInstantSuggestion(); |
| 207 if (suggestion.empty()) | 205 if (suggestion.empty()) |
| 208 return false; | 206 return false; |
| 209 | 207 |
| 210 FinalizeInstantQuery(view_->GetText(), suggestion, skip_inline_autocomplete); | 208 FinalizeInstantQuery(view_->GetText(), suggestion, skip_inline_autocomplete); |
| 211 return true; | 209 return true; |
| 212 } | 210 } |
| 213 | 211 |
| 214 bool OmniboxEditModel::AcceptCurrentInstantPreview() { | 212 bool OmniboxEditModel::AcceptCurrentInstantPreview() { |
| 215 InstantController* instant = controller_->GetInstant(); | 213 InstantController* instant = controller_->GetInstant(); |
| 216 return instant && instant->CommitIfCurrent(); | 214 return instant && instant->IsCurrent() && |
| 215 instant->CommitCurrentPreview(INSTANT_COMMIT_PRESSED_ENTER); |
| 217 } | 216 } |
| 218 | 217 |
| 219 void OmniboxEditModel::OnChanged() { | 218 void OmniboxEditModel::OnChanged() { |
| 220 // Don't call CurrentMatch() when there's no editing, as in this case we'll | 219 // Don't call CurrentMatch() when there's no editing, as in this case we'll |
| 221 // never actually use it. This avoids running the autocomplete providers (and | 220 // never actually use it. This avoids running the autocomplete providers (and |
| 222 // any systems they then spin up) during startup. | 221 // any systems they then spin up) during startup. |
| 223 const AutocompleteMatch& current_match = user_input_in_progress_ ? | 222 const AutocompleteMatch& current_match = user_input_in_progress_ ? |
| 224 CurrentMatch() : AutocompleteMatch(); | 223 CurrentMatch() : AutocompleteMatch(); |
| 225 | 224 |
| 226 AutocompleteActionPredictor::Action recommended_action = | 225 AutocompleteActionPredictor::Action recommended_action = |
| 227 AutocompleteActionPredictor::ACTION_NONE; | 226 AutocompleteActionPredictor::ACTION_NONE; |
| 228 AutocompleteActionPredictor* action_predictor = | 227 AutocompleteActionPredictor* action_predictor = |
| 229 user_input_in_progress_ ? | 228 user_input_in_progress_ ? |
| 230 AutocompleteActionPredictorFactory::GetForProfile(profile_) : NULL; | 229 AutocompleteActionPredictorFactory::GetForProfile(profile_) : NULL; |
| 231 if (action_predictor) { | 230 if (action_predictor) { |
| 232 action_predictor->RegisterTransitionalMatches(user_text_, result()); | 231 action_predictor->RegisterTransitionalMatches(user_text_, result()); |
| 233 // Confer with the AutocompleteActionPredictor to determine what action, if | 232 // Confer with the AutocompleteActionPredictor to determine what action, if |
| 234 // any, we should take. Get the recommended action here even if we don't | 233 // any, we should take. Get the recommended action here even if we don't |
| 235 // need it so we can get stats for anyone who is opted in to UMA, but only | 234 // need it so we can get stats for anyone who is opted in to UMA, but only |
| 236 // get it if the user has actually typed something to avoid constructing it | 235 // get it if the user has actually typed something to avoid constructing it |
| 237 // before it's needed. Note: This event is triggered as part of startup when | 236 // before it's needed. Note: This event is triggered as part of startup when |
| 238 // the initial tab transitions to the start page. | 237 // the initial tab transitions to the start page. |
| 239 recommended_action = | 238 recommended_action = |
| 240 action_predictor->RecommendAction(user_text_, current_match); | 239 action_predictor->RecommendAction(user_text_, current_match); |
| 241 } | 240 } |
| 242 | 241 |
| 243 UMA_HISTOGRAM_ENUMERATION("AutocompleteActionPredictor.Action", | 242 UMA_HISTOGRAM_ENUMERATION("AutocompleteActionPredictor.Action", |
| 244 recommended_action, | 243 recommended_action, |
| 245 AutocompleteActionPredictor::LAST_PREDICT_ACTION); | 244 AutocompleteActionPredictor::LAST_PREDICT_ACTION); |
| 245 |
| 246 string16 suggested_text; | 246 string16 suggested_text; |
| 247 InstantCompleteBehavior complete_behavior = INSTANT_COMPLETE_NOW; |
| 247 | 248 |
| 248 if (DoInstant(current_match, &suggested_text)) { | 249 if (DoInstant(current_match, &suggested_text, &complete_behavior)) { |
| 249 SetSuggestedText(suggested_text, instant_complete_behavior_); | 250 SetSuggestedText(suggested_text, complete_behavior); |
| 250 } else { | 251 } else { |
| 251 switch (recommended_action) { | 252 switch (recommended_action) { |
| 252 case AutocompleteActionPredictor::ACTION_PRERENDER: | 253 case AutocompleteActionPredictor::ACTION_PRERENDER: |
| 253 DoPrerender(current_match); | 254 DoPrerender(current_match); |
| 254 break; | 255 break; |
| 255 case AutocompleteActionPredictor::ACTION_PRECONNECT: | 256 case AutocompleteActionPredictor::ACTION_PRECONNECT: |
| 256 DoPreconnect(current_match); | 257 DoPreconnect(current_match); |
| 257 break; | 258 break; |
| 258 case AutocompleteActionPredictor::ACTION_NONE: | 259 case AutocompleteActionPredictor::ACTION_NONE: |
| 259 break; | 260 break; |
| (...skipping 175 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 435 (has_selected_text && inline_autocomplete_text_.empty()) || | 436 (has_selected_text && inline_autocomplete_text_.empty()) || |
| 436 (paste_state_ != NONE), keyword_is_selected, | 437 (paste_state_ != NONE), keyword_is_selected, |
| 437 keyword_is_selected || allow_exact_keyword_match_, | 438 keyword_is_selected || allow_exact_keyword_match_, |
| 438 AutocompleteInput::ALL_MATCHES); | 439 AutocompleteInput::ALL_MATCHES); |
| 439 } | 440 } |
| 440 | 441 |
| 441 void OmniboxEditModel::StopAutocomplete() { | 442 void OmniboxEditModel::StopAutocomplete() { |
| 442 if (popup_->IsOpen() && !in_revert_) { | 443 if (popup_->IsOpen() && !in_revert_) { |
| 443 InstantController* instant = controller_->GetInstant(); | 444 InstantController* instant = controller_->GetInstant(); |
| 444 if (instant && !instant->commit_on_pointer_release()) | 445 if (instant && !instant->commit_on_pointer_release()) |
| 445 instant->DestroyPreviewContents(); | 446 instant->Hide(); |
| 446 } | 447 } |
| 447 | 448 |
| 448 autocomplete_controller_->Stop(true); | 449 autocomplete_controller_->Stop(true); |
| 449 } | 450 } |
| 450 | 451 |
| 451 bool OmniboxEditModel::CanPasteAndGo(const string16& text) const { | 452 bool OmniboxEditModel::CanPasteAndGo(const string16& text) const { |
| 452 if (!view_->command_updater()->IsCommandEnabled(IDC_OPEN_CURRENT_URL)) | 453 if (!view_->command_updater()->IsCommandEnabled(IDC_OPEN_CURRENT_URL)) |
| 453 return false; | 454 return false; |
| 454 | 455 |
| 455 AutocompleteMatch match; | 456 AutocompleteMatch match; |
| (...skipping 167 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 623 } | 624 } |
| 624 controller_->OnAutocompleteAccept(destination_url, disposition, | 625 controller_->OnAutocompleteAccept(destination_url, disposition, |
| 625 match.transition, alternate_nav_url); | 626 match.transition, alternate_nav_url); |
| 626 } | 627 } |
| 627 | 628 |
| 628 if (match.starred) | 629 if (match.starred) |
| 629 bookmark_utils::RecordBookmarkLaunch(bookmark_utils::LAUNCH_OMNIBOX); | 630 bookmark_utils::RecordBookmarkLaunch(bookmark_utils::LAUNCH_OMNIBOX); |
| 630 | 631 |
| 631 InstantController* instant = controller_->GetInstant(); | 632 InstantController* instant = controller_->GetInstant(); |
| 632 if (instant && !popup_->IsOpen()) | 633 if (instant && !popup_->IsOpen()) |
| 633 instant->DestroyPreviewContents(); | 634 instant->Hide(); |
| 634 in_revert_ = false; | 635 in_revert_ = false; |
| 635 } | 636 } |
| 636 | 637 |
| 637 bool OmniboxEditModel::AcceptKeyword() { | 638 bool OmniboxEditModel::AcceptKeyword() { |
| 638 DCHECK(is_keyword_hint_ && !keyword_.empty()); | 639 DCHECK(is_keyword_hint_ && !keyword_.empty()); |
| 639 | 640 |
| 640 autocomplete_controller_->Stop(false); | 641 autocomplete_controller_->Stop(false); |
| 641 is_keyword_hint_ = false; | 642 is_keyword_hint_ = false; |
| 642 | 643 |
| 643 if (popup_->IsOpen()) | 644 if (popup_->IsOpen()) |
| (...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 693 InstantController* instant = controller_->GetInstant(); | 694 InstantController* instant = controller_->GetInstant(); |
| 694 if (instant) | 695 if (instant) |
| 695 instant->OnAutocompleteGotFocus(); | 696 instant->OnAutocompleteGotFocus(); |
| 696 | 697 |
| 697 NotifySearchTabHelper(); | 698 NotifySearchTabHelper(); |
| 698 } | 699 } |
| 699 | 700 |
| 700 void OmniboxEditModel::OnWillKillFocus(gfx::NativeView view_gaining_focus) { | 701 void OmniboxEditModel::OnWillKillFocus(gfx::NativeView view_gaining_focus) { |
| 701 SetSuggestedText(string16(), INSTANT_COMPLETE_NOW); | 702 SetSuggestedText(string16(), INSTANT_COMPLETE_NOW); |
| 702 | 703 |
| 703 InstantController* instant = controller_->GetInstant(); | 704 if (InstantController* instant = controller_->GetInstant()) |
| 704 if (instant) | |
| 705 instant->OnAutocompleteLostFocus(view_gaining_focus); | 705 instant->OnAutocompleteLostFocus(view_gaining_focus); |
| 706 | 706 |
| 707 NotifySearchTabHelper(); | 707 NotifySearchTabHelper(); |
| 708 } | 708 } |
| 709 | 709 |
| 710 void OmniboxEditModel::OnKillFocus() { | 710 void OmniboxEditModel::OnKillFocus() { |
| 711 has_focus_ = false; | 711 has_focus_ = false; |
| 712 control_key_state_ = UP; | 712 control_key_state_ = UP; |
| 713 paste_state_ = NONE; | 713 paste_state_ = NONE; |
| 714 } | 714 } |
| (...skipping 382 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1097 GetKeywordForText(keyword).empty(); | 1097 GetKeywordForText(keyword).empty(); |
| 1098 } | 1098 } |
| 1099 | 1099 |
| 1100 void OmniboxEditModel::NotifySearchTabHelper() { | 1100 void OmniboxEditModel::NotifySearchTabHelper() { |
| 1101 if (controller_->GetTabContents()) { | 1101 if (controller_->GetTabContents()) { |
| 1102 controller_->GetTabContents()->search_tab_helper()-> | 1102 controller_->GetTabContents()->search_tab_helper()-> |
| 1103 OmniboxEditModelChanged(this); | 1103 OmniboxEditModelChanged(this); |
| 1104 } | 1104 } |
| 1105 } | 1105 } |
| 1106 | 1106 |
| 1107 bool OmniboxEditModel::DoInstant(const AutocompleteMatch& match, | 1107 bool OmniboxEditModel::DoInstant( |
| 1108 string16* suggested_text) { | 1108 const AutocompleteMatch& match, |
| 1109 string16* suggested_text, |
| 1110 InstantCompleteBehavior* complete_behavior) { |
| 1109 DCHECK(suggested_text); | 1111 DCHECK(suggested_text); |
| 1112 DCHECK(complete_behavior); |
| 1110 | 1113 |
| 1111 if (in_revert_) | 1114 if (in_revert_) |
| 1112 return false; | 1115 return false; |
| 1113 | 1116 |
| 1114 InstantController* instant = controller_->GetInstant(); | 1117 InstantController* instant = controller_->GetInstant(); |
| 1115 | 1118 |
| 1116 if (!instant) | 1119 if (!instant) |
| 1117 return false; | 1120 return false; |
| 1118 | 1121 |
| 1119 if (user_input_in_progress_ && popup_->IsOpen()) { | 1122 if (user_input_in_progress_ && popup_->IsOpen()) { |
| 1120 return instant->Update(match, view_->GetText(), UseVerbatimInstant(), | 1123 string16 text = view_->GetText(); |
| 1121 suggested_text); | 1124 AutocompleteInput::RemoveForcedQueryStringIfNecessary( |
| 1125 autocomplete_controller_->input().type(), &text); |
| 1126 |
| 1127 // If there's any inline autocompletion, split it out from |text|. |
| 1128 if (!inline_autocomplete_text_.empty()) { |
| 1129 DCHECK_GE(text.size(), inline_autocomplete_text_.size()); |
| 1130 text.resize(text.size() - inline_autocomplete_text_.size()); |
| 1131 *suggested_text = inline_autocomplete_text_; |
| 1132 } |
| 1133 |
| 1134 return instant->Update(match, text, UseVerbatimInstant(), suggested_text, |
| 1135 complete_behavior); |
| 1122 } | 1136 } |
| 1123 | 1137 |
| 1124 // It's possible DoInstant() was called due to an OnChanged() event from the | 1138 // It's possible DoInstant() was called due to an OnChanged() event from the |
| 1125 // omnibox view if the user clicked the renderer while IME composition was | 1139 // omnibox view if the user clicked the renderer while IME composition was |
| 1126 // active. In that case we still want to commit on mouse up, so don't call | 1140 // active. In that case we still want to commit on mouse up, so don't call |
| 1127 // Hide(). | 1141 // Hide(). |
| 1128 if (!instant->commit_on_pointer_release()) | 1142 if (!instant->commit_on_pointer_release()) |
| 1129 instant->Hide(); | 1143 instant->Hide(); |
| 1130 return false; | 1144 return false; |
| 1131 } | 1145 } |
| (...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1191 } | 1205 } |
| 1192 | 1206 |
| 1193 void OmniboxEditModel::ClassifyStringForPasteAndGo( | 1207 void OmniboxEditModel::ClassifyStringForPasteAndGo( |
| 1194 const string16& text, | 1208 const string16& text, |
| 1195 AutocompleteMatch* match, | 1209 AutocompleteMatch* match, |
| 1196 GURL* alternate_nav_url) const { | 1210 GURL* alternate_nav_url) const { |
| 1197 DCHECK(match); | 1211 DCHECK(match); |
| 1198 AutocompleteClassifierFactory::GetForProfile(profile_)->Classify(text, | 1212 AutocompleteClassifierFactory::GetForProfile(profile_)->Classify(text, |
| 1199 string16(), false, false, match, alternate_nav_url); | 1213 string16(), false, false, match, alternate_nav_url); |
| 1200 } | 1214 } |
| OLD | NEW |