OLD | NEW |
1 // Copyright 2012 The Chromium Authors. All rights reserved. | 1 // Copyright 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/auto_reset.h" | 9 #include "base/auto_reset.h" |
10 #include "base/format_macros.h" | 10 #include "base/format_macros.h" |
(...skipping 109 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
120 | 120 |
121 OmniboxEditModel::OmniboxEditModel(OmniboxView* view, | 121 OmniboxEditModel::OmniboxEditModel(OmniboxView* view, |
122 OmniboxEditController* controller, | 122 OmniboxEditController* controller, |
123 Profile* profile) | 123 Profile* profile) |
124 : view_(view), | 124 : view_(view), |
125 controller_(controller), | 125 controller_(controller), |
126 focus_state_(OMNIBOX_FOCUS_NONE), | 126 focus_state_(OMNIBOX_FOCUS_NONE), |
127 user_input_in_progress_(false), | 127 user_input_in_progress_(false), |
128 just_deleted_text_(false), | 128 just_deleted_text_(false), |
129 has_temporary_text_(false), | 129 has_temporary_text_(false), |
130 is_temporary_text_set_by_instant_(false), | |
131 selected_instant_autocomplete_match_index_(OmniboxPopupModel::kNoMatch), | |
132 is_instant_temporary_text_a_search_query_(false), | |
133 paste_state_(NONE), | 130 paste_state_(NONE), |
134 control_key_state_(UP), | 131 control_key_state_(UP), |
135 is_keyword_hint_(false), | 132 is_keyword_hint_(false), |
136 profile_(profile), | 133 profile_(profile), |
137 in_revert_(false), | 134 in_revert_(false), |
138 in_escape_handler_(false), | |
139 allow_exact_keyword_match_(false) { | 135 allow_exact_keyword_match_(false) { |
140 omnibox_controller_.reset(new OmniboxController(this, profile)); | 136 omnibox_controller_.reset(new OmniboxController(this, profile)); |
141 delegate_.reset(new OmniboxCurrentPageDelegateImpl(controller, profile)); | 137 delegate_.reset(new OmniboxCurrentPageDelegateImpl(controller, profile)); |
142 } | 138 } |
143 | 139 |
144 OmniboxEditModel::~OmniboxEditModel() { | 140 OmniboxEditModel::~OmniboxEditModel() { |
145 } | 141 } |
146 | 142 |
147 const OmniboxEditModel::State OmniboxEditModel::GetStateForTabSwitch() { | 143 const OmniboxEditModel::State OmniboxEditModel::GetStateForTabSwitch() { |
148 // Like typing, switching tabs "accepts" the temporary text as the user | 144 // Like typing, switching tabs "accepts" the temporary text as the user |
(...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
225 GURL OmniboxEditModel::PermanentURL() { | 221 GURL OmniboxEditModel::PermanentURL() { |
226 return URLFixerUpper::FixupURL(UTF16ToUTF8(permanent_text_), std::string()); | 222 return URLFixerUpper::FixupURL(UTF16ToUTF8(permanent_text_), std::string()); |
227 } | 223 } |
228 | 224 |
229 void OmniboxEditModel::SetUserText(const string16& text) { | 225 void OmniboxEditModel::SetUserText(const string16& text) { |
230 SetInputInProgress(true); | 226 SetInputInProgress(true); |
231 InternalSetUserText(text); | 227 InternalSetUserText(text); |
232 omnibox_controller_->InvalidateCurrentMatch(); | 228 omnibox_controller_->InvalidateCurrentMatch(); |
233 paste_state_ = NONE; | 229 paste_state_ = NONE; |
234 has_temporary_text_ = false; | 230 has_temporary_text_ = false; |
235 is_temporary_text_set_by_instant_ = false; | |
236 selected_instant_autocomplete_match_index_ = OmniboxPopupModel::kNoMatch; | |
237 is_instant_temporary_text_a_search_query_ = false; | |
238 } | 231 } |
239 | 232 |
240 void OmniboxEditModel::SetInstantSuggestion( | 233 void OmniboxEditModel::SetInstantSuggestion( |
241 const InstantSuggestion& suggestion) { | 234 const InstantSuggestion& suggestion) { |
242 // Should only get called for the HTML popup. | |
243 #if defined(HTML_INSTANT_EXTENDED_POPUP) | |
244 omnibox_controller_->SetInstantSuggestion(suggestion); | |
245 #endif | |
246 } | 235 } |
247 | 236 |
248 bool OmniboxEditModel::CommitSuggestedText() { | 237 bool OmniboxEditModel::CommitSuggestedText() { |
249 const string16 suggestion = view_->GetInstantSuggestion(); | 238 const string16 suggestion = view_->GetInstantSuggestion(); |
250 if (suggestion.empty()) | 239 if (suggestion.empty()) |
251 return false; | 240 return false; |
252 | 241 |
253 // Assume that the gray text we are committing is a search suggestion. | 242 // Assume that the gray text we are committing is a search suggestion. |
254 const string16 final_text = view_->GetText() + suggestion; | 243 const string16 final_text = view_->GetText() + suggestion; |
255 view_->OnBeforePossibleChange(); | 244 view_->OnBeforePossibleChange(); |
(...skipping 24 matching lines...) Expand all Loading... |
280 // before it's needed. Note: This event is triggered as part of startup when | 269 // before it's needed. Note: This event is triggered as part of startup when |
281 // the initial tab transitions to the start page. | 270 // the initial tab transitions to the start page. |
282 recommended_action = | 271 recommended_action = |
283 action_predictor->RecommendAction(user_text_, current_match); | 272 action_predictor->RecommendAction(user_text_, current_match); |
284 } | 273 } |
285 | 274 |
286 UMA_HISTOGRAM_ENUMERATION("AutocompleteActionPredictor.Action", | 275 UMA_HISTOGRAM_ENUMERATION("AutocompleteActionPredictor.Action", |
287 recommended_action, | 276 recommended_action, |
288 AutocompleteActionPredictor::LAST_PREDICT_ACTION); | 277 AutocompleteActionPredictor::LAST_PREDICT_ACTION); |
289 | 278 |
290 // Do not perform instant if we're currently reverting or the change is the | 279 // Hide any suggestions we might be showing. |
291 // result of an INSTANT_COMPLETE_REPLACE instant suggestion. | 280 view_->SetInstantSuggestion(string16()); |
292 bool performed_instant = false; | |
293 if (!in_revert_ && !is_temporary_text_set_by_instant_) { | |
294 size_t start, end; | |
295 view_->GetSelectionBounds(&start, &end); | |
296 string16 user_text = DisplayTextFromUserText(user_text_); | |
297 performed_instant = omnibox_controller_->DoInstant( | |
298 current_match, user_text, view_->GetText(), start, end, | |
299 user_input_in_progress_, in_escape_handler_, | |
300 view_->DeleteAtEndPressed() || just_deleted_text_, | |
301 KeywordIsSelected()); | |
302 } | |
303 | |
304 if (!performed_instant) { | |
305 // Hide any suggestions we might be showing. | |
306 view_->SetInstantSuggestion(string16()); | |
307 } | |
308 | 281 |
309 switch (recommended_action) { | 282 switch (recommended_action) { |
310 case AutocompleteActionPredictor::ACTION_PRERENDER: | 283 case AutocompleteActionPredictor::ACTION_PRERENDER: |
311 // It's possible that there is no current page, for instance if the tab | 284 // It's possible that there is no current page, for instance if the tab |
312 // has been closed or on return from a sleep state. | 285 // has been closed or on return from a sleep state. |
313 // (http://crbug.com/105689) | 286 // (http://crbug.com/105689) |
314 if (!delegate_->CurrentPageExists()) | 287 if (!delegate_->CurrentPageExists()) |
315 break; | 288 break; |
316 // Ask for prerendering if the destination URL is different than the | 289 // Ask for prerendering if the destination URL is different than the |
317 // current URL. | 290 // current URL. |
(...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
422 popup_model()->IsOpen(), user_text_.empty()); | 395 popup_model()->IsOpen(), user_text_.empty()); |
423 } | 396 } |
424 | 397 |
425 void OmniboxEditModel::Revert() { | 398 void OmniboxEditModel::Revert() { |
426 SetInputInProgress(false); | 399 SetInputInProgress(false); |
427 paste_state_ = NONE; | 400 paste_state_ = NONE; |
428 InternalSetUserText(string16()); | 401 InternalSetUserText(string16()); |
429 keyword_.clear(); | 402 keyword_.clear(); |
430 is_keyword_hint_ = false; | 403 is_keyword_hint_ = false; |
431 has_temporary_text_ = false; | 404 has_temporary_text_ = false; |
432 is_temporary_text_set_by_instant_ = false; | |
433 selected_instant_autocomplete_match_index_ = OmniboxPopupModel::kNoMatch; | |
434 is_instant_temporary_text_a_search_query_ = false; | |
435 view_->SetWindowTextAndCaretPos(permanent_text_, | 405 view_->SetWindowTextAndCaretPos(permanent_text_, |
436 has_focus() ? permanent_text_.length() : 0, | 406 has_focus() ? permanent_text_.length() : 0, |
437 false, true); | 407 false, true); |
438 AutocompleteActionPredictor* action_predictor = | 408 AutocompleteActionPredictor* action_predictor = |
439 AutocompleteActionPredictorFactory::GetForProfile(profile_); | 409 AutocompleteActionPredictorFactory::GetForProfile(profile_); |
440 if (action_predictor) | 410 if (action_predictor) |
441 action_predictor->ClearTransitionalMatches(); | 411 action_predictor->ClearTransitionalMatches(); |
442 } | 412 } |
443 | 413 |
444 void OmniboxEditModel::StartAutocomplete( | 414 void OmniboxEditModel::StartAutocomplete( |
(...skipping 153 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
598 // (because the user does not modify the omnibox for ZeroSuggest), so for | 568 // (because the user does not modify the omnibox for ZeroSuggest), so for |
599 // those we set the elapsed times to something that will be ignored by | 569 // those we set the elapsed times to something that will be ignored by |
600 // metrics_log.cc. | 570 // metrics_log.cc. |
601 if (match.provider && | 571 if (match.provider && |
602 match.provider->type() == AutocompleteProvider::TYPE_ZERO_SUGGEST) { | 572 match.provider->type() == AutocompleteProvider::TYPE_ZERO_SUGGEST) { |
603 elapsed_time_since_user_first_modified_omnibox = | 573 elapsed_time_since_user_first_modified_omnibox = |
604 base::TimeDelta::FromMilliseconds(-1); | 574 base::TimeDelta::FromMilliseconds(-1); |
605 elapsed_time_since_last_change_to_default_match = | 575 elapsed_time_since_last_change_to_default_match = |
606 base::TimeDelta::FromMilliseconds(-1); | 576 base::TimeDelta::FromMilliseconds(-1); |
607 } | 577 } |
608 // TODO(sreeram): Handle is_temporary_text_set_by_instant_ correctly. | |
609 OmniboxLog log( | 578 OmniboxLog log( |
610 autocomplete_controller()->input().text(), | 579 autocomplete_controller()->input().text(), |
611 just_deleted_text_, | 580 just_deleted_text_, |
612 autocomplete_controller()->input().type(), | 581 autocomplete_controller()->input().type(), |
613 popup_model()->selected_line(), | 582 popup_model()->selected_line(), |
614 -1, // don't yet know tab ID; set later if appropriate | 583 -1, // don't yet know tab ID; set later if appropriate |
615 delegate_->CurrentPageExists() ? ClassifyPage(delegate_->GetURL()) : | 584 delegate_->CurrentPageExists() ? ClassifyPage(delegate_->GetURL()) : |
616 metrics::OmniboxEventProto_PageClassification_OTHER, | 585 metrics::OmniboxEventProto_PageClassification_OTHER, |
617 elapsed_time_since_user_first_modified_omnibox, | 586 elapsed_time_since_user_first_modified_omnibox, |
618 string16::npos, // completed_length; possibly set later | 587 string16::npos, // completed_length; possibly set later |
(...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
704 | 673 |
705 // Track whether the destination URL sends us to a search results page | 674 // Track whether the destination URL sends us to a search results page |
706 // using the default search provider. | 675 // using the default search provider. |
707 TemplateURL* default_provider = | 676 TemplateURL* default_provider = |
708 TemplateURLServiceFactory::GetForProfile(profile_)-> | 677 TemplateURLServiceFactory::GetForProfile(profile_)-> |
709 GetDefaultSearchProvider(); | 678 GetDefaultSearchProvider(); |
710 if (default_provider && default_provider->IsSearchURL(destination_url)) | 679 if (default_provider && default_provider->IsSearchURL(destination_url)) |
711 content::RecordAction(UserMetricsAction( | 680 content::RecordAction(UserMetricsAction( |
712 "OmniboxDestinationURLMatchesDefaultSearchProvider")); | 681 "OmniboxDestinationURLMatchesDefaultSearchProvider")); |
713 | 682 |
714 #if defined(HTML_INSTANT_EXTENDED_POPUP) | |
715 // If running with instant, notify the instant controller that a navigation | |
716 // is about to take place if we are navigating to a URL. This can be | |
717 // determined by inspecting the transition type. To ensure that this is only | |
718 // done on Enter key press, check that the disposition is CURRENT_TAB. This | |
719 // is the same heuristic used by BrowserInstantController::OpenInstant | |
720 if (match.transition == content::PAGE_TRANSITION_TYPED && | |
721 disposition == CURRENT_TAB) { | |
722 InstantController* instant = GetInstantController(); | |
723 if (instant) | |
724 instant->OmniboxNavigateToURL(); | |
725 } | |
726 #endif | |
727 | |
728 // This calls RevertAll again. | 683 // This calls RevertAll again. |
729 base::AutoReset<bool> tmp(&in_revert_, true); | 684 base::AutoReset<bool> tmp(&in_revert_, true); |
730 controller_->OnAutocompleteAccept(destination_url, disposition, | 685 controller_->OnAutocompleteAccept(destination_url, disposition, |
731 match.transition, alternate_nav_url); | 686 match.transition, alternate_nav_url); |
732 } | 687 } |
733 | 688 |
734 if (match.starred) | 689 if (match.starred) |
735 bookmark_utils::RecordBookmarkLaunch(bookmark_utils::LAUNCH_OMNIBOX); | 690 bookmark_utils::RecordBookmarkLaunch(bookmark_utils::LAUNCH_OMNIBOX); |
736 } | 691 } |
737 | 692 |
738 bool OmniboxEditModel::AcceptKeyword(EnteredKeywordModeMethod entered_method) { | 693 bool OmniboxEditModel::AcceptKeyword(EnteredKeywordModeMethod entered_method) { |
739 DCHECK(is_keyword_hint_ && !keyword_.empty()); | 694 DCHECK(is_keyword_hint_ && !keyword_.empty()); |
740 | 695 |
741 autocomplete_controller()->Stop(false); | 696 autocomplete_controller()->Stop(false); |
742 is_keyword_hint_ = false; | 697 is_keyword_hint_ = false; |
743 | 698 |
744 if (popup_model()->IsOpen()) | 699 if (popup_model()->IsOpen()) |
745 popup_model()->SetSelectedLineState(OmniboxPopupModel::KEYWORD); | 700 popup_model()->SetSelectedLineState(OmniboxPopupModel::KEYWORD); |
746 else | 701 else |
747 StartAutocomplete(false, true); | 702 StartAutocomplete(false, true); |
748 | 703 |
749 // Ensure the current selection is saved before showing keyword mode | 704 // Ensure the current selection is saved before showing keyword mode |
750 // so that moving to another line and then reverting the text will restore | 705 // so that moving to another line and then reverting the text will restore |
751 // the current state properly. | 706 // the current state properly. |
752 bool save_original_selection = !has_temporary_text_; | 707 bool save_original_selection = !has_temporary_text_; |
753 has_temporary_text_ = true; | 708 has_temporary_text_ = true; |
754 is_temporary_text_set_by_instant_ = false; | |
755 selected_instant_autocomplete_match_index_ = OmniboxPopupModel::kNoMatch; | |
756 is_instant_temporary_text_a_search_query_ = false; | |
757 view_->OnTemporaryTextMaybeChanged( | 709 view_->OnTemporaryTextMaybeChanged( |
758 DisplayTextFromUserText(CurrentMatch(NULL).fill_into_edit), | 710 DisplayTextFromUserText(CurrentMatch(NULL).fill_into_edit), |
759 save_original_selection, true); | 711 save_original_selection, true); |
760 | 712 |
761 content::RecordAction(UserMetricsAction("AcceptedKeywordHint")); | 713 content::RecordAction(UserMetricsAction("AcceptedKeywordHint")); |
762 UMA_HISTOGRAM_ENUMERATION(kEnteredKeywordModeHistogram, entered_method, | 714 UMA_HISTOGRAM_ENUMERATION(kEnteredKeywordModeHistogram, entered_method, |
763 ENTERED_KEYWORD_MODE_NUM_ITEMS); | 715 ENTERED_KEYWORD_MODE_NUM_ITEMS); |
764 | 716 |
765 return true; | 717 return true; |
766 } | 718 } |
767 | 719 |
768 void OmniboxEditModel::AcceptTemporaryTextAsUserText() { | 720 void OmniboxEditModel::AcceptTemporaryTextAsUserText() { |
769 InternalSetUserText(UserTextFromDisplayText(view_->GetText())); | 721 InternalSetUserText(UserTextFromDisplayText(view_->GetText())); |
770 has_temporary_text_ = false; | 722 has_temporary_text_ = false; |
771 is_temporary_text_set_by_instant_ = false; | |
772 selected_instant_autocomplete_match_index_ = OmniboxPopupModel::kNoMatch; | |
773 is_instant_temporary_text_a_search_query_ = false; | |
774 OnPopupBoundsChanged(gfx::Rect()); | |
775 delegate_->NotifySearchTabHelper(user_input_in_progress_, !in_revert_, | 723 delegate_->NotifySearchTabHelper(user_input_in_progress_, !in_revert_, |
776 popup_model()->IsOpen(), user_text_.empty()); | 724 popup_model()->IsOpen(), user_text_.empty()); |
777 } | 725 } |
778 | 726 |
779 void OmniboxEditModel::ClearKeyword(const string16& visible_text) { | 727 void OmniboxEditModel::ClearKeyword(const string16& visible_text) { |
780 autocomplete_controller()->Stop(false); | 728 autocomplete_controller()->Stop(false); |
781 omnibox_controller_->ClearPopupKeywordMode(); | 729 omnibox_controller_->ClearPopupKeywordMode(); |
782 | 730 |
783 const string16 window_text(keyword_ + visible_text); | 731 const string16 window_text(keyword_ + visible_text); |
784 | 732 |
(...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
870 } | 818 } |
871 | 819 |
872 // If the user wasn't editing, but merely had focus in the edit, allow <esc> | 820 // If the user wasn't editing, but merely had focus in the edit, allow <esc> |
873 // to be processed as an accelerator, so it can still be used to stop a load. | 821 // to be processed as an accelerator, so it can still be used to stop a load. |
874 // When the permanent text isn't all selected we still fall through to the | 822 // When the permanent text isn't all selected we still fall through to the |
875 // SelectAll() call below so users can arrow around in the text and then hit | 823 // SelectAll() call below so users can arrow around in the text and then hit |
876 // <esc> to quickly replace all the text; this matches IE. | 824 // <esc> to quickly replace all the text; this matches IE. |
877 if (!user_input_in_progress_ && view_->IsSelectAll()) | 825 if (!user_input_in_progress_ && view_->IsSelectAll()) |
878 return false; | 826 return false; |
879 | 827 |
880 in_escape_handler_ = true; | |
881 if (!user_text_.empty()) { | 828 if (!user_text_.empty()) { |
882 UMA_HISTOGRAM_ENUMERATION(kOmniboxUserTextClearedHistogram, | 829 UMA_HISTOGRAM_ENUMERATION(kOmniboxUserTextClearedHistogram, |
883 OMNIBOX_USER_TEXT_CLEARED_WITH_ESCAPE, | 830 OMNIBOX_USER_TEXT_CLEARED_WITH_ESCAPE, |
884 OMNIBOX_USER_TEXT_CLEARED_NUM_OF_ITEMS); | 831 OMNIBOX_USER_TEXT_CLEARED_NUM_OF_ITEMS); |
885 } | 832 } |
886 view_->RevertAll(); | 833 view_->RevertAll(); |
887 in_escape_handler_ = false; | |
888 view_->SelectAll(true); | 834 view_->SelectAll(true); |
889 return true; | 835 return true; |
890 } | 836 } |
891 | 837 |
892 void OmniboxEditModel::OnControlKeyChanged(bool pressed) { | 838 void OmniboxEditModel::OnControlKeyChanged(bool pressed) { |
893 if (pressed == (control_key_state_ == UP)) | 839 if (pressed == (control_key_state_ == UP)) |
894 control_key_state_ = pressed ? DOWN_WITHOUT_CHANGE : UP; | 840 control_key_state_ = pressed ? DOWN_WITHOUT_CHANGE : UP; |
895 } | 841 } |
896 | 842 |
897 void OmniboxEditModel::OnUpOrDownKeyPressed(int count) { | 843 void OmniboxEditModel::OnUpOrDownKeyPressed(int count) { |
898 // NOTE: This purposefully doesn't trigger any code that resets paste_state_. | 844 // NOTE: This purposefully doesn't trigger any code that resets paste_state_. |
899 if (popup_model()->IsOpen()) { | 845 if (popup_model()->IsOpen()) { |
900 #if defined(HTML_INSTANT_EXTENDED_POPUP) | |
901 InstantController* instant = GetInstantController(); | |
902 if (instant && instant->OnUpOrDownKeyPressed(count)) { | |
903 // If Instant handles the key press, it's showing a list of suggestions | |
904 // that it's stepping through. In that case, our popup model is | |
905 // irrelevant, so don't process the key press ourselves. However, do stop | |
906 // the autocomplete system from changing the results. | |
907 autocomplete_controller()->Stop(false); | |
908 return; | |
909 } | |
910 #endif | |
911 | |
912 // The popup is open, so the user should be able to interact with it | 846 // The popup is open, so the user should be able to interact with it |
913 // normally. | 847 // normally. |
914 popup_model()->Move(count); | 848 popup_model()->Move(count); |
915 return; | 849 return; |
916 } | 850 } |
917 | 851 |
918 if (!query_in_progress()) { | 852 if (!query_in_progress()) { |
919 // The popup is neither open nor working on a query already. So, start an | 853 // The popup is neither open nor working on a query already. So, start an |
920 // autocomplete query for the current text. This also sets | 854 // autocomplete query for the current text. This also sets |
921 // user_input_in_progress_ to true, which we want: if the user has started | 855 // user_input_in_progress_ to true, which we want: if the user has started |
(...skipping 30 matching lines...) Expand all Loading... |
952 // |is_keyword_hint_| should always be false if |keyword_| is empty. | 886 // |is_keyword_hint_| should always be false if |keyword_| is empty. |
953 DCHECK(!keyword_.empty() || !is_keyword_hint_); | 887 DCHECK(!keyword_.empty() || !is_keyword_hint_); |
954 } | 888 } |
955 | 889 |
956 // Handle changes to temporary text. | 890 // Handle changes to temporary text. |
957 if (destination_for_temporary_text_change != NULL) { | 891 if (destination_for_temporary_text_change != NULL) { |
958 const bool save_original_selection = !has_temporary_text_; | 892 const bool save_original_selection = !has_temporary_text_; |
959 if (save_original_selection) { | 893 if (save_original_selection) { |
960 // Save the original selection and URL so it can be reverted later. | 894 // Save the original selection and URL so it can be reverted later. |
961 has_temporary_text_ = true; | 895 has_temporary_text_ = true; |
962 is_temporary_text_set_by_instant_ = false; | |
963 selected_instant_autocomplete_match_index_ = OmniboxPopupModel::kNoMatch; | |
964 is_instant_temporary_text_a_search_query_ = false; | |
965 original_url_ = *destination_for_temporary_text_change; | 896 original_url_ = *destination_for_temporary_text_change; |
966 inline_autocomplete_text_.clear(); | 897 inline_autocomplete_text_.clear(); |
967 } | 898 } |
968 if (control_key_state_ == DOWN_WITHOUT_CHANGE) { | 899 if (control_key_state_ == DOWN_WITHOUT_CHANGE) { |
969 // Arrowing around the popup cancels control-enter. | 900 // Arrowing around the popup cancels control-enter. |
970 control_key_state_ = DOWN_WITH_CHANGE; | 901 control_key_state_ = DOWN_WITH_CHANGE; |
971 // Now things are a bit screwy: the desired_tld has changed, but if we | 902 // Now things are a bit screwy: the desired_tld has changed, but if we |
972 // update the popup, the new order of entries won't match the old, so the | 903 // update the popup, the new order of entries won't match the old, so the |
973 // user's selection gets screwy; and if we don't update the popup, and the | 904 // user's selection gets screwy; and if we don't update the popup, and the |
974 // user reverts, then the selected item will be as if control is still | 905 // user reverts, then the selected item will be as if control is still |
(...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1060 } else if (!user_text_changed) { | 991 } else if (!user_text_changed) { |
1061 return false; | 992 return false; |
1062 } | 993 } |
1063 | 994 |
1064 // If the user text has not changed, we do not want to change the model's | 995 // If the user text has not changed, we do not want to change the model's |
1065 // state associated with the text. Otherwise, we can get surprising behavior | 996 // state associated with the text. Otherwise, we can get surprising behavior |
1066 // where the autocompleted text unexpectedly reappears, e.g. crbug.com/55983 | 997 // where the autocompleted text unexpectedly reappears, e.g. crbug.com/55983 |
1067 if (user_text_changed) { | 998 if (user_text_changed) { |
1068 InternalSetUserText(UserTextFromDisplayText(new_text)); | 999 InternalSetUserText(UserTextFromDisplayText(new_text)); |
1069 has_temporary_text_ = false; | 1000 has_temporary_text_ = false; |
1070 is_temporary_text_set_by_instant_ = false; | |
1071 selected_instant_autocomplete_match_index_ = OmniboxPopupModel::kNoMatch; | |
1072 is_instant_temporary_text_a_search_query_ = false; | |
1073 | 1001 |
1074 // Track when the user has deleted text so we won't allow inline | 1002 // Track when the user has deleted text so we won't allow inline |
1075 // autocomplete. | 1003 // autocomplete. |
1076 just_deleted_text_ = just_deleted_text; | 1004 just_deleted_text_ = just_deleted_text; |
1077 | 1005 |
1078 if (user_input_in_progress_ && user_text_.empty()) { | 1006 if (user_input_in_progress_ && user_text_.empty()) { |
1079 // Log cases where the user started editing and then subsequently cleared | 1007 // Log cases where the user started editing and then subsequently cleared |
1080 // all the text. Note that this explicitly doesn't catch cases like | 1008 // all the text. Note that this explicitly doesn't catch cases like |
1081 // "hit ctrl-l to select whole edit contents, then hit backspace", because | 1009 // "hit ctrl-l to select whole edit contents, then hit backspace", because |
1082 // in such cases, |user_input_in_progress| won't be true here. | 1010 // in such cases, |user_input_in_progress| won't be true here. |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1114 // determine what keyword, if any, is applicable. | 1042 // determine what keyword, if any, is applicable. |
1115 // | 1043 // |
1116 // If MaybeAcceptKeywordBySpace() accepts the keyword and returns true, that | 1044 // If MaybeAcceptKeywordBySpace() accepts the keyword and returns true, that |
1117 // will have updated our state already, so in that case we don't also return | 1045 // will have updated our state already, so in that case we don't also return |
1118 // true from this function. | 1046 // true from this function. |
1119 return !(text_differs && allow_keyword_ui_change && !just_deleted_text && | 1047 return !(text_differs && allow_keyword_ui_change && !just_deleted_text && |
1120 no_selection && (selection_start == user_text_.length()) && | 1048 no_selection && (selection_start == user_text_.length()) && |
1121 MaybeAcceptKeywordBySpace(user_text_)); | 1049 MaybeAcceptKeywordBySpace(user_text_)); |
1122 } | 1050 } |
1123 | 1051 |
1124 void OmniboxEditModel::OnCurrentMatchChanged(bool is_temporary_set_by_instant) { | 1052 void OmniboxEditModel::OnCurrentMatchChanged() { |
1125 has_temporary_text_ = is_temporary_set_by_instant; | 1053 has_temporary_text_ = false; |
1126 is_temporary_text_set_by_instant_ = is_temporary_set_by_instant; | |
1127 | 1054 |
1128 const AutocompleteMatch& match = omnibox_controller_->current_match(); | 1055 const AutocompleteMatch& match = omnibox_controller_->current_match(); |
1129 | 1056 |
1130 if (is_temporary_set_by_instant) { | 1057 // We store |keyword| and |is_keyword_hint| in temporary variables since |
1131 view_->OnTemporaryTextMaybeChanged( | 1058 // OnPopupDataChanged use their previous state to detect changes. |
1132 DisplayTextFromUserText(match.fill_into_edit), !has_temporary_text_, | 1059 string16 keyword; |
1133 false); | 1060 bool is_keyword_hint; |
1134 } else { | 1061 match.GetKeywordUIState(profile_, &keyword, &is_keyword_hint); |
1135 // We store |keyword| and |is_keyword_hint| in temporary variables since | 1062 string16 inline_autocomplete_text; |
1136 // OnPopupDataChanged use their previous state to detect changes. | 1063 if (match.inline_autocomplete_offset < match.fill_into_edit.length()) { |
1137 string16 keyword; | 1064 // We have blue text, go through OnPopupDataChanged. |
1138 bool is_keyword_hint; | 1065 // TODO(beaudoin): Merge OnPopupDataChanged with this method once the |
1139 match.GetKeywordUIState(profile_, &keyword, &is_keyword_hint); | 1066 // popup handling has completely migrated to omnibox_controller. |
1140 string16 inline_autocomplete_text; | 1067 inline_autocomplete_text = |
1141 if (match.inline_autocomplete_offset < match.fill_into_edit.length()) { | 1068 match.fill_into_edit.substr(match.inline_autocomplete_offset); |
1142 // We have blue text, go through OnPopupDataChanged. | |
1143 // TODO(beaudoin): Merge OnPopupDataChanged with this method once the | |
1144 // popup handling has completely migrated to omnibox_controller. | |
1145 inline_autocomplete_text = | |
1146 match.fill_into_edit.substr(match.inline_autocomplete_offset); | |
1147 } | |
1148 popup_model()->OnResultChanged(); | |
1149 OnPopupDataChanged(inline_autocomplete_text, NULL, keyword, | |
1150 is_keyword_hint); | |
1151 } | 1069 } |
1152 } | 1070 popup_model()->OnResultChanged(); |
1153 | 1071 OnPopupDataChanged(inline_autocomplete_text, NULL, keyword, |
1154 void OmniboxEditModel::OnGrayTextChanged() { | 1072 is_keyword_hint); |
1155 view_->SetInstantSuggestion(omnibox_controller_->gray_suggestion()); | |
1156 } | 1073 } |
1157 | 1074 |
1158 string16 OmniboxEditModel::GetViewText() const { | 1075 string16 OmniboxEditModel::GetViewText() const { |
1159 return view_->GetText(); | 1076 return view_->GetText(); |
1160 } | 1077 } |
1161 | 1078 |
1162 InstantController* OmniboxEditModel::GetInstantController() const { | 1079 InstantController* OmniboxEditModel::GetInstantController() const { |
1163 return controller_->GetInstant(); | 1080 return controller_->GetInstant(); |
1164 } | 1081 } |
1165 | 1082 |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1203 // explicitly set up a match that will reload here. | 1120 // explicitly set up a match that will reload here. |
1204 | 1121 |
1205 // It's important that we fetch the current visible URL to reload instead of | 1122 // It's important that we fetch the current visible URL to reload instead of |
1206 // just getting a "search what you typed" URL from | 1123 // just getting a "search what you typed" URL from |
1207 // SearchProvider::CreateSearchSuggestion(), since the user may be in a | 1124 // SearchProvider::CreateSearchSuggestion(), since the user may be in a |
1208 // non-default search mode such as image search. | 1125 // non-default search mode such as image search. |
1209 match->type = AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED; | 1126 match->type = AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED; |
1210 match->destination_url = | 1127 match->destination_url = |
1211 delegate_->GetNavigationController().GetVisibleEntry()->GetURL(); | 1128 delegate_->GetNavigationController().GetVisibleEntry()->GetURL(); |
1212 match->transition = content::PAGE_TRANSITION_RELOAD; | 1129 match->transition = content::PAGE_TRANSITION_RELOAD; |
1213 #if defined(HTML_INSTANT_EXTENDED_POPUP) | |
1214 } else if (is_temporary_text_set_by_instant_) { | |
1215 // If there's temporary text and it has been set by Instant, we won't find | |
1216 // it in the popup model, so create the match based on the type Instant told | |
1217 // us (SWYT for queries and UWYT for URLs). We do this instead of | |
1218 // classifying the text ourselves because the text may look like a URL, but | |
1219 // Instant may expect it to be a search (e.g.: a query for "amazon.com"). | |
1220 if (selected_instant_autocomplete_match_index_ != | |
1221 OmniboxPopupModel::kNoMatch) { | |
1222 // Great, we know the exact match struct. Just use that. | |
1223 const AutocompleteResult& result = this->result(); | |
1224 *match = result.match_at(selected_instant_autocomplete_match_index_); | |
1225 } else { | |
1226 const string16& text = view_->GetText(); | |
1227 AutocompleteInput input(text, string16::npos, string16(), GURL(), false, | |
1228 false, false, AutocompleteInput::BEST_MATCH); | |
1229 // Only the destination_url and the transition of the match will be be | |
1230 // used (to either navigate to the URL or let Instant commit its preview). | |
1231 // The match won't be used for logging, displaying in the dropdown, etc. | |
1232 // So, it's okay to pass in mostly bogus params (such as relevance = 0). | |
1233 // TODO(sreeram): Always using NO_SUGGESTIONS_AVAILABLE is wrong when | |
1234 // Instant is using the local fallback overlay. Fix. | |
1235 if (is_instant_temporary_text_a_search_query_) { | |
1236 const TemplateURL* default_provider = | |
1237 TemplateURLServiceFactory::GetForProfile(profile_)-> | |
1238 GetDefaultSearchProvider(); | |
1239 if (default_provider && default_provider->SupportsReplacement()) { | |
1240 *match = SearchProvider::CreateSearchSuggestion( | |
1241 autocomplete_controller()->search_provider(), 0, | |
1242 AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED, default_provider, | |
1243 text, text, input, false, | |
1244 TemplateURLRef::NO_SUGGESTIONS_AVAILABLE, | |
1245 controller_->GetOmniboxBounds().x(), true); | |
1246 } else { | |
1247 // Can't create a new search match. Leave |match| as is, with an | |
1248 // invalid destination_url. This shouldn't ever happen. For example, | |
1249 // even if a group policy update in the midst of interacting with | |
1250 // Instant leaves us without a valid search provider, Instant | |
1251 // should've observed the update and reset | |
1252 // |is_temporary_text_set_by_instant_|, so we still shouldn't get | |
1253 // here. However, as protection against the unknowns and Instant | |
1254 // regressions, we simply return an invalid match instead of crashing | |
1255 // (hence no DCHECK). | |
1256 } | |
1257 } else { | |
1258 *match = HistoryURLProvider::SuggestExactInput( | |
1259 autocomplete_controller()->history_url_provider(), input, false); | |
1260 } | |
1261 } | |
1262 #endif | |
1263 } else if (popup_model()->IsOpen() || query_in_progress()) { | 1130 } else if (popup_model()->IsOpen() || query_in_progress()) { |
1264 if (query_in_progress()) { | 1131 if (query_in_progress()) { |
1265 // It's technically possible for |result| to be empty if no provider | 1132 // It's technically possible for |result| to be empty if no provider |
1266 // returns a synchronous result but the query has not completed | 1133 // returns a synchronous result but the query has not completed |
1267 // synchronously; pratically, however, that should never actually happen. | 1134 // synchronously; pratically, however, that should never actually happen. |
1268 if (result().empty()) | 1135 if (result().empty()) |
1269 return; | 1136 return; |
1270 // The user cannot have manually selected a match, or the query would have | 1137 // The user cannot have manually selected a match, or the query would have |
1271 // stopped. So the default match must be the desired selection. | 1138 // stopped. So the default match must be the desired selection. |
1272 *match = *result().default_match(); | 1139 *match = *result().default_match(); |
(...skipping 10 matching lines...) Expand all Loading... |
1283 AutocompleteClassifierFactory::GetForProfile(profile_)->Classify( | 1150 AutocompleteClassifierFactory::GetForProfile(profile_)->Classify( |
1284 UserTextFromDisplayText(view_->GetText()), KeywordIsSelected(), true, | 1151 UserTextFromDisplayText(view_->GetText()), KeywordIsSelected(), true, |
1285 match, alternate_nav_url); | 1152 match, alternate_nav_url); |
1286 } | 1153 } |
1287 } | 1154 } |
1288 | 1155 |
1289 void OmniboxEditModel::RevertTemporaryText(bool revert_popup) { | 1156 void OmniboxEditModel::RevertTemporaryText(bool revert_popup) { |
1290 // The user typed something, then selected a different item. Restore the | 1157 // The user typed something, then selected a different item. Restore the |
1291 // text they typed and change back to the default item. | 1158 // text they typed and change back to the default item. |
1292 // NOTE: This purposefully does not reset paste_state_. | 1159 // NOTE: This purposefully does not reset paste_state_. |
1293 #if defined(HTML_INSTANT_EXTENDED_POPUP) | |
1294 bool notify_instant = is_temporary_text_set_by_instant_; | |
1295 #endif | |
1296 just_deleted_text_ = false; | 1160 just_deleted_text_ = false; |
1297 has_temporary_text_ = false; | 1161 has_temporary_text_ = false; |
1298 is_temporary_text_set_by_instant_ = false; | |
1299 selected_instant_autocomplete_match_index_ = OmniboxPopupModel::kNoMatch; | |
1300 is_instant_temporary_text_a_search_query_ = false; | |
1301 | 1162 |
1302 #if defined(HTML_INSTANT_EXTENDED_POPUP) | |
1303 InstantController* instant = GetInstantController(); | |
1304 if (instant && notify_instant) { | |
1305 // Normally, popup_model()->ResetToDefaultMatch() will cause the view text | |
1306 // to be updated. In Instant Extended mode however, the popup_model() is | |
1307 // not used, so it won't do anything. So, update the view ourselves. Even | |
1308 // if Instant is not in extended mode (i.e., it's enabled in non-extended | |
1309 // mode, or disabled altogether), this is okay to do, since the call to | |
1310 // popup_model()->ResetToDefaultMatch() will just override whatever we do | |
1311 // here. | |
1312 // | |
1313 // The two "false" arguments make sure that our shenanigans don't cause any | |
1314 // previously saved selection to be erased nor OnChanged() to be called. | |
1315 view_->OnTemporaryTextMaybeChanged(user_text_ + inline_autocomplete_text_, | |
1316 false, false); | |
1317 AutocompleteResult::const_iterator match(result().default_match()); | |
1318 instant->OnCancel(match != result().end() ? *match : AutocompleteMatch(), | |
1319 user_text_, | |
1320 user_text_ + inline_autocomplete_text_); | |
1321 } | |
1322 #endif | |
1323 if (revert_popup) | 1163 if (revert_popup) |
1324 popup_model()->ResetToDefaultMatch(); | 1164 popup_model()->ResetToDefaultMatch(); |
1325 view_->OnRevertTemporaryText(); | 1165 view_->OnRevertTemporaryText(); |
1326 } | 1166 } |
1327 | 1167 |
1328 bool OmniboxEditModel::MaybeAcceptKeywordBySpace(const string16& new_text) { | 1168 bool OmniboxEditModel::MaybeAcceptKeywordBySpace(const string16& new_text) { |
1329 size_t keyword_length = new_text.length() - 1; | 1169 size_t keyword_length = new_text.length() - 1; |
1330 return (paste_state_ == NONE) && is_keyword_hint_ && !keyword_.empty() && | 1170 return (paste_state_ == NONE) && is_keyword_hint_ && !keyword_.empty() && |
1331 inline_autocomplete_text_.empty() && | 1171 inline_autocomplete_text_.empty() && |
1332 (keyword_.length() == keyword_length) && | 1172 (keyword_.length() == keyword_length) && |
(...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1410 instant->OmniboxFocusChanged(state, reason, NULL); | 1250 instant->OmniboxFocusChanged(state, reason, NULL); |
1411 | 1251 |
1412 // Update state and notify view if the omnibox has focus and the caret | 1252 // Update state and notify view if the omnibox has focus and the caret |
1413 // visibility changed. | 1253 // visibility changed. |
1414 const bool was_caret_visible = is_caret_visible(); | 1254 const bool was_caret_visible = is_caret_visible(); |
1415 focus_state_ = state; | 1255 focus_state_ = state; |
1416 if (focus_state_ != OMNIBOX_FOCUS_NONE && | 1256 if (focus_state_ != OMNIBOX_FOCUS_NONE && |
1417 is_caret_visible() != was_caret_visible) | 1257 is_caret_visible() != was_caret_visible) |
1418 view_->ApplyCaretVisibility(); | 1258 view_->ApplyCaretVisibility(); |
1419 } | 1259 } |
OLD | NEW |