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 "components/omnibox/browser/omnibox_edit_model.h" | 5 #include "components/omnibox/browser/omnibox_edit_model.h" |
6 | 6 |
7 #include <algorithm> | 7 #include <algorithm> |
8 #include <string> | 8 #include <string> |
9 #include <utility> | 9 #include <utility> |
10 | 10 |
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
64 const char kOmniboxUserTextClearedHistogram[] = "Omnibox.UserTextCleared"; | 64 const char kOmniboxUserTextClearedHistogram[] = "Omnibox.UserTextCleared"; |
65 | 65 |
66 enum UserTextClearedType { | 66 enum UserTextClearedType { |
67 OMNIBOX_USER_TEXT_CLEARED_BY_EDITING = 0, | 67 OMNIBOX_USER_TEXT_CLEARED_BY_EDITING = 0, |
68 OMNIBOX_USER_TEXT_CLEARED_WITH_ESCAPE = 1, | 68 OMNIBOX_USER_TEXT_CLEARED_WITH_ESCAPE = 1, |
69 OMNIBOX_USER_TEXT_CLEARED_NUM_OF_ITEMS, | 69 OMNIBOX_USER_TEXT_CLEARED_NUM_OF_ITEMS, |
70 }; | 70 }; |
71 | 71 |
72 // Histogram name which counts the number of times the user enters | 72 // Histogram name which counts the number of times the user enters |
73 // keyword hint mode and via what method. The possible values are listed | 73 // keyword hint mode and via what method. The possible values are listed |
74 // in the EnteredKeywordModeMethod enum which is defined in the .h file. | 74 // in the KeywordModeEntryMethod enum which is defined in the .h file. |
75 const char kEnteredKeywordModeHistogram[] = "Omnibox.EnteredKeywordMode"; | 75 const char kEnteredKeywordModeHistogram[] = "Omnibox.EnteredKeywordMode"; |
76 | 76 |
77 // Histogram name which counts the number of milliseconds a user takes | 77 // Histogram name which counts the number of milliseconds a user takes |
78 // between focusing and editing the omnibox. | 78 // between focusing and editing the omnibox. |
79 const char kFocusToEditTimeHistogram[] = "Omnibox.FocusToEditTime"; | 79 const char kFocusToEditTimeHistogram[] = "Omnibox.FocusToEditTime"; |
80 | 80 |
81 // Histogram name which counts the number of milliseconds a user takes | 81 // Histogram name which counts the number of milliseconds a user takes |
82 // between focusing and opening an omnibox match. | 82 // between focusing and opening an omnibox match. |
83 const char kFocusToOpenTimeHistogram[] = "Omnibox.FocusToOpenTimeAnyPopupState"; | 83 const char kFocusToOpenTimeHistogram[] = "Omnibox.FocusToOpenTimeAnyPopupState"; |
84 | 84 |
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
142 } // namespace | 142 } // namespace |
143 | 143 |
144 | 144 |
145 // OmniboxEditModel::State ---------------------------------------------------- | 145 // OmniboxEditModel::State ---------------------------------------------------- |
146 | 146 |
147 OmniboxEditModel::State::State(bool user_input_in_progress, | 147 OmniboxEditModel::State::State(bool user_input_in_progress, |
148 const base::string16& user_text, | 148 const base::string16& user_text, |
149 const base::string16& gray_text, | 149 const base::string16& gray_text, |
150 const base::string16& keyword, | 150 const base::string16& keyword, |
151 bool is_keyword_hint, | 151 bool is_keyword_hint, |
| 152 KeywordModeEntryMethod keyword_mode_entry_method, |
152 bool url_replacement_enabled, | 153 bool url_replacement_enabled, |
153 OmniboxFocusState focus_state, | 154 OmniboxFocusState focus_state, |
154 FocusSource focus_source, | 155 FocusSource focus_source, |
155 const AutocompleteInput& autocomplete_input) | 156 const AutocompleteInput& autocomplete_input) |
156 : user_input_in_progress(user_input_in_progress), | 157 : user_input_in_progress(user_input_in_progress), |
157 user_text(user_text), | 158 user_text(user_text), |
158 gray_text(gray_text), | 159 gray_text(gray_text), |
159 keyword(keyword), | 160 keyword(keyword), |
160 is_keyword_hint(is_keyword_hint), | 161 is_keyword_hint(is_keyword_hint), |
| 162 keyword_mode_entry_method(keyword_mode_entry_method), |
161 url_replacement_enabled(url_replacement_enabled), | 163 url_replacement_enabled(url_replacement_enabled), |
162 focus_state(focus_state), | 164 focus_state(focus_state), |
163 focus_source(focus_source), | 165 focus_source(focus_source), |
164 autocomplete_input(autocomplete_input) { | 166 autocomplete_input(autocomplete_input) { |
165 } | 167 } |
166 | 168 |
167 OmniboxEditModel::State::State(const State& other) = default; | 169 OmniboxEditModel::State::State(const State& other) = default; |
168 | 170 |
169 OmniboxEditModel::State::~State() { | 171 OmniboxEditModel::State::~State() { |
170 } | 172 } |
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
210 view_->SelectAll(true); | 212 view_->SelectAll(true); |
211 } else { | 213 } else { |
212 InternalSetUserText(display_text); | 214 InternalSetUserText(display_text); |
213 } | 215 } |
214 } | 216 } |
215 | 217 |
216 UMA_HISTOGRAM_BOOLEAN("Omnibox.SaveStateForTabSwitch.UserInputInProgress", | 218 UMA_HISTOGRAM_BOOLEAN("Omnibox.SaveStateForTabSwitch.UserInputInProgress", |
217 user_input_in_progress_); | 219 user_input_in_progress_); |
218 return State( | 220 return State( |
219 user_input_in_progress_, user_text_, view_->GetGrayTextAutocompletion(), | 221 user_input_in_progress_, user_text_, view_->GetGrayTextAutocompletion(), |
220 keyword_, is_keyword_hint_, | 222 keyword_, is_keyword_hint_, keyword_mode_entry_method_, |
221 controller_->GetToolbarModel()->url_replacement_enabled(), | 223 controller_->GetToolbarModel()->url_replacement_enabled(), |
222 focus_state_, focus_source_, input_); | 224 focus_state_, focus_source_, input_); |
223 } | 225 } |
224 | 226 |
225 void OmniboxEditModel::RestoreState(const State* state) { | 227 void OmniboxEditModel::RestoreState(const State* state) { |
226 // We need to update the permanent text correctly and revert the view | 228 // We need to update the permanent text correctly and revert the view |
227 // regardless of whether there is saved state. | 229 // regardless of whether there is saved state. |
228 bool url_replacement_enabled = !state || state->url_replacement_enabled; | 230 bool url_replacement_enabled = !state || state->url_replacement_enabled; |
229 controller_->GetToolbarModel()->set_url_replacement_enabled( | 231 controller_->GetToolbarModel()->set_url_replacement_enabled( |
230 url_replacement_enabled); | 232 url_replacement_enabled); |
231 permanent_text_ = controller_->GetToolbarModel()->GetText(); | 233 permanent_text_ = controller_->GetToolbarModel()->GetText(); |
232 // Don't muck with the search term replacement state, as we've just set it | 234 // Don't muck with the search term replacement state, as we've just set it |
233 // correctly. | 235 // correctly. |
234 view_->RevertWithoutResettingSearchTermReplacement(); | 236 view_->RevertWithoutResettingSearchTermReplacement(); |
235 // Restore the autocomplete controller's input, or clear it if this is a new | 237 // Restore the autocomplete controller's input, or clear it if this is a new |
236 // tab. | 238 // tab. |
237 input_ = state ? state->autocomplete_input : AutocompleteInput(); | 239 input_ = state ? state->autocomplete_input : AutocompleteInput(); |
238 if (!state) | 240 if (!state) |
239 return; | 241 return; |
240 | 242 |
241 SetFocusState(state->focus_state, OMNIBOX_FOCUS_CHANGE_TAB_SWITCH); | 243 SetFocusState(state->focus_state, OMNIBOX_FOCUS_CHANGE_TAB_SWITCH); |
242 focus_source_ = state->focus_source; | 244 focus_source_ = state->focus_source; |
243 // Restore any user editing. | 245 // Restore any user editing. |
244 if (state->user_input_in_progress) { | 246 if (state->user_input_in_progress) { |
245 // NOTE: Be sure and set keyword-related state AFTER invoking | 247 // NOTE: Be sure to set keyword-related state AFTER invoking |
246 // SetUserText(), as SetUserText() clears the keyword state. | 248 // SetUserText(), as SetUserText() clears the keyword state. |
247 view_->SetUserText(state->user_text, false); | 249 view_->SetUserText(state->user_text, false); |
248 keyword_ = state->keyword; | 250 keyword_ = state->keyword; |
249 is_keyword_hint_ = state->is_keyword_hint; | 251 is_keyword_hint_ = state->is_keyword_hint; |
| 252 keyword_mode_entry_method_ = state->keyword_mode_entry_method; |
250 view_->SetGrayTextAutocompletion(state->gray_text); | 253 view_->SetGrayTextAutocompletion(state->gray_text); |
251 } | 254 } |
252 } | 255 } |
253 | 256 |
254 AutocompleteMatch OmniboxEditModel::CurrentMatch( | 257 AutocompleteMatch OmniboxEditModel::CurrentMatch( |
255 GURL* alternate_nav_url) const { | 258 GURL* alternate_nav_url) const { |
256 // If we have a valid match use it. Otherwise get one for the current text. | 259 // If we have a valid match use it. Otherwise get one for the current text. |
257 AutocompleteMatch match = omnibox_controller_->current_match(); | 260 AutocompleteMatch match = omnibox_controller_->current_match(); |
258 | 261 |
259 if (!match.destination_url.is_valid()) { | 262 if (!match.destination_url.is_valid()) { |
(...skipping 358 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
618 match.transition = ui::PAGE_TRANSITION_LINK; | 621 match.transition = ui::PAGE_TRANSITION_LINK; |
619 } | 622 } |
620 | 623 |
621 client_->OnInputAccepted(match); | 624 client_->OnInputAccepted(match); |
622 | 625 |
623 DCHECK(popup_model()); | 626 DCHECK(popup_model()); |
624 view_->OpenMatch(match, disposition, alternate_nav_url, base::string16(), | 627 view_->OpenMatch(match, disposition, alternate_nav_url, base::string16(), |
625 popup_model()->selected_line()); | 628 popup_model()->selected_line()); |
626 } | 629 } |
627 | 630 |
| 631 void OmniboxEditModel::EnterKeywordModeForDefaultSearchProvider( |
| 632 KeywordModeEntryMethod entry_method) { |
| 633 autocomplete_controller()->Stop(false); |
| 634 |
| 635 user_input_in_progress_ = true; |
| 636 keyword_ = client_->GetTemplateURLService()-> |
| 637 GetDefaultSearchProvider()->keyword(); |
| 638 is_keyword_hint_ = false; |
| 639 keyword_mode_entry_method_ = entry_method; |
| 640 |
| 641 StartAutocomplete(false, false, true); |
| 642 |
| 643 UMA_HISTOGRAM_ENUMERATION( |
| 644 kEnteredKeywordModeHistogram, static_cast<int>(entry_method), |
| 645 static_cast<int>(KeywordModeEntryMethod::NUM_ITEMS)); |
| 646 } |
| 647 |
628 void OmniboxEditModel::OpenMatch(AutocompleteMatch match, | 648 void OmniboxEditModel::OpenMatch(AutocompleteMatch match, |
629 WindowOpenDisposition disposition, | 649 WindowOpenDisposition disposition, |
630 const GURL& alternate_nav_url, | 650 const GURL& alternate_nav_url, |
631 const base::string16& pasted_text, | 651 const base::string16& pasted_text, |
632 size_t index) { | 652 size_t index) { |
633 const base::TimeTicks& now(base::TimeTicks::Now()); | 653 const base::TimeTicks& now(base::TimeTicks::Now()); |
634 base::TimeDelta elapsed_time_since_user_first_modified_omnibox( | 654 base::TimeDelta elapsed_time_since_user_first_modified_omnibox( |
635 now - time_user_first_modified_omnibox_); | 655 now - time_user_first_modified_omnibox_); |
636 autocomplete_controller()->UpdateMatchDestinationURLWithQueryFormulationTime( | 656 autocomplete_controller()->UpdateMatchDestinationURLWithQueryFormulationTime( |
637 elapsed_time_since_user_first_modified_omnibox, &match); | 657 elapsed_time_since_user_first_modified_omnibox, &match); |
(...skipping 138 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
776 match.transition | ui::PAGE_TRANSITION_FROM_ADDRESS_BAR)); | 796 match.transition | ui::PAGE_TRANSITION_FROM_ADDRESS_BAR)); |
777 if (observer && observer->HasSeenPendingLoad()) | 797 if (observer && observer->HasSeenPendingLoad()) |
778 ignore_result(observer.release()); // The observer will delete itself. | 798 ignore_result(observer.release()); // The observer will delete itself. |
779 } | 799 } |
780 | 800 |
781 BookmarkModel* bookmark_model = client_->GetBookmarkModel(); | 801 BookmarkModel* bookmark_model = client_->GetBookmarkModel(); |
782 if (bookmark_model && bookmark_model->IsBookmarked(match.destination_url)) | 802 if (bookmark_model && bookmark_model->IsBookmarked(match.destination_url)) |
783 client_->OnBookmarkLaunched(); | 803 client_->OnBookmarkLaunched(); |
784 } | 804 } |
785 | 805 |
786 bool OmniboxEditModel::AcceptKeyword(EnteredKeywordModeMethod entered_method) { | 806 bool OmniboxEditModel::AcceptKeyword( |
| 807 KeywordModeEntryMethod entry_method) { |
787 DCHECK(is_keyword_hint_ && !keyword_.empty()); | 808 DCHECK(is_keyword_hint_ && !keyword_.empty()); |
788 | 809 |
789 autocomplete_controller()->Stop(false); | 810 autocomplete_controller()->Stop(false); |
| 811 |
790 is_keyword_hint_ = false; | 812 is_keyword_hint_ = false; |
| 813 keyword_mode_entry_method_ = entry_method; |
| 814 user_text_ = MaybeStripKeyword(user_text_); |
791 | 815 |
792 user_text_ = MaybeStripKeyword(user_text_); | 816 user_text_ = MaybeStripKeyword(user_text_); |
793 | 817 |
794 if (popup_model() && popup_model()->IsOpen()) | 818 if (popup_model() && popup_model()->IsOpen()) |
795 popup_model()->SetSelectedLineState(OmniboxPopupModel::KEYWORD); | 819 popup_model()->SetSelectedLineState(OmniboxPopupModel::KEYWORD); |
796 else | 820 else |
797 StartAutocomplete(false, true, true); | 821 StartAutocomplete(false, true, true); |
798 | 822 |
799 // When entering keyword mode via tab, the new text to show is whatever the | 823 // When entering keyword mode via tab, the new text to show is whatever the |
800 // newly-selected match in the dropdown is. When entering via space, however, | 824 // newly-selected match in the dropdown is. When entering via space, however, |
801 // we should make sure to use the actual |user_text_| as the basis for the new | 825 // we should make sure to use the actual |user_text_| as the basis for the new |
802 // text. This ensures that if the user types "<keyword><space>" and the | 826 // text. This ensures that if the user types "<keyword><space>" and the |
803 // default match would have inline autocompleted a further string (e.g. | 827 // default match would have inline autocompleted a further string (e.g. |
804 // because there's a past multi-word search beginning with this keyword), the | 828 // because there's a past multi-word search beginning with this keyword), the |
805 // inline autocompletion doesn't get filled in as the keyword search query | 829 // inline autocompletion doesn't get filled in as the keyword search query |
806 // text. | 830 // text. |
807 // | 831 // |
808 // We also treat tabbing into keyword mode like tabbing through the popup in | 832 // We also treat tabbing into keyword mode like tabbing through the popup in |
809 // that we set |has_temporary_text_|, whereas pressing space is treated like | 833 // that we set |has_temporary_text_|, whereas pressing space is treated like |
810 // a new keystroke that changes the current match instead of overlaying it | 834 // a new keystroke that changes the current match instead of overlaying it |
811 // with a temporary one. This is important because rerunning autocomplete | 835 // with a temporary one. This is important because rerunning autocomplete |
812 // after the user pressed space, which will have happened just before reaching | 836 // after the user pressed space, which will have happened just before reaching |
813 // here, may have generated a new match, which the user won't actually see and | 837 // here, may have generated a new match, which the user won't actually see and |
814 // which we don't want to switch back to when existing keyword mode; see | 838 // which we don't want to switch back to when existing keyword mode; see |
815 // comments in ClearKeyword(). | 839 // comments in ClearKeyword(). |
816 if (entered_method == ENTERED_KEYWORD_MODE_VIA_TAB) { | 840 if (entry_method == KeywordModeEntryMethod::TAB) { |
817 // Ensure the current selection is saved before showing keyword mode | 841 // Ensure the current selection is saved before showing keyword mode |
818 // so that moving to another line and then reverting the text will restore | 842 // so that moving to another line and then reverting the text will restore |
819 // the current state properly. | 843 // the current state properly. |
820 bool save_original_selection = !has_temporary_text_; | 844 bool save_original_selection = !has_temporary_text_; |
821 has_temporary_text_ = true; | 845 has_temporary_text_ = true; |
822 const AutocompleteMatch& match = CurrentMatch(NULL); | 846 const AutocompleteMatch& match = CurrentMatch(NULL); |
823 original_url_ = match.destination_url; | 847 original_url_ = match.destination_url; |
824 view_->OnTemporaryTextMaybeChanged( | 848 view_->OnTemporaryTextMaybeChanged( |
825 MaybeStripKeyword(match.fill_into_edit), save_original_selection, | 849 MaybeStripKeyword(match.fill_into_edit), save_original_selection, |
826 true); | 850 true); |
827 } else { | 851 } else { |
828 view_->OnTemporaryTextMaybeChanged(user_text_, false, true); | 852 view_->OnTemporaryTextMaybeChanged(user_text_, false, true); |
829 } | 853 } |
830 | 854 |
831 base::RecordAction(base::UserMetricsAction("AcceptedKeywordHint")); | 855 base::RecordAction(base::UserMetricsAction("AcceptedKeywordHint")); |
832 UMA_HISTOGRAM_ENUMERATION(kEnteredKeywordModeHistogram, entered_method, | 856 UMA_HISTOGRAM_ENUMERATION( |
833 ENTERED_KEYWORD_MODE_NUM_ITEMS); | 857 kEnteredKeywordModeHistogram, static_cast<int>(entry_method), |
| 858 static_cast<int>(KeywordModeEntryMethod::NUM_ITEMS)); |
834 | 859 |
835 return true; | 860 return true; |
836 } | 861 } |
837 | 862 |
838 void OmniboxEditModel::AcceptTemporaryTextAsUserText() { | 863 void OmniboxEditModel::AcceptTemporaryTextAsUserText() { |
839 InternalSetUserText(view_->GetText()); | 864 InternalSetUserText(view_->GetText()); |
840 has_temporary_text_ = false; | 865 has_temporary_text_ = false; |
841 | 866 |
842 if (user_input_in_progress_ || !in_revert_) | 867 if (user_input_in_progress_ || !in_revert_) |
843 client_->OnInputStateChanged(); | 868 client_->OnInputStateChanged(); |
(...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
907 // without re-enabling keyword mode. The common case is state 3, where | 932 // without re-enabling keyword mode. The common case is state 3, where |
908 // the user entered keyword mode unintentionally, so backspacing | 933 // the user entered keyword mode unintentionally, so backspacing |
909 // immediately out of keyword mode should keep the space. In states 1 and | 934 // immediately out of keyword mode should keep the space. In states 1 and |
910 // 2, having the space is "safer" behavior. For instance, if the user types | 935 // 2, having the space is "safer" behavior. For instance, if the user types |
911 // "google.com f" or "google.com<tab>f" in the omnibox, moves the cursor to | 936 // "google.com f" or "google.com<tab>f" in the omnibox, moves the cursor to |
912 // the left, and presses backspace to leave keyword mode (state 1), it's | 937 // the left, and presses backspace to leave keyword mode (state 1), it's |
913 // better to have the space because it may be what the user wanted. The | 938 // better to have the space because it may be what the user wanted. The |
914 // user can easily delete it. On the other hand, if there is no space and | 939 // user can easily delete it. On the other hand, if there is no space and |
915 // the user wants it, it's more work to add because typing the space will | 940 // the user wants it, it's more work to add because typing the space will |
916 // enter keyword mode, which then the user would have to leave again. | 941 // enter keyword mode, which then the user would have to leave again. |
917 const base::string16 window_text = | 942 |
918 keyword_ + base::ASCIIToUTF16(" ") + view_->GetText(); | 943 // If we entered keyword mode in a special way like using a keyboard |
919 view_->SetWindowTextAndCaretPos(window_text.c_str(), keyword_.length() + 1, | 944 // shortcut or typing a question mark in a blank omnibox, don't restore the |
920 false, false); | 945 // keyword. Instead, restore the question mark iff the user originally |
| 946 // typed one. |
| 947 base::string16 prefix; |
| 948 if (keyword_mode_entry_method_ == KeywordModeEntryMethod::QUESTION_MARK) |
| 949 prefix = base::ASCIIToUTF16("?"); |
| 950 else if (keyword_mode_entry_method_ != |
| 951 KeywordModeEntryMethod::KEYBOARD_SHORTCUT) |
| 952 prefix = keyword_ + base::ASCIIToUTF16(" "); |
| 953 |
921 keyword_.clear(); | 954 keyword_.clear(); |
922 is_keyword_hint_ = false; | 955 is_keyword_hint_ = false; |
| 956 |
| 957 view_->SetWindowTextAndCaretPos(prefix + view_->GetText(), prefix.length(), |
| 958 false, false); |
| 959 |
923 view_->OnAfterPossibleChange(false); | 960 view_->OnAfterPossibleChange(false); |
924 } | 961 } |
925 } | 962 } |
926 | 963 |
927 void OmniboxEditModel::OnSetFocus(bool control_down) { | 964 void OmniboxEditModel::OnSetFocus(bool control_down) { |
928 last_omnibox_focus_ = base::TimeTicks::Now(); | 965 last_omnibox_focus_ = base::TimeTicks::Now(); |
929 user_input_since_focus_ = false; | 966 user_input_since_focus_ = false; |
930 | 967 |
931 // If the omnibox lost focus while the caret was hidden and then regained | 968 // If the omnibox lost focus while the caret was hidden and then regained |
932 // focus, OnSetFocus() is called and should restore visibility. Note that | 969 // focus, OnSetFocus() is called and should restore visibility. Note that |
(...skipping 213 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1146 RevertTemporaryText(false); | 1183 RevertTemporaryText(false); |
1147 call_controller_onchanged = false; | 1184 call_controller_onchanged = false; |
1148 } | 1185 } |
1149 | 1186 |
1150 // We need to invoke OnChanged in case the destination url changed (as could | 1187 // We need to invoke OnChanged in case the destination url changed (as could |
1151 // happen when control is toggled). | 1188 // happen when control is toggled). |
1152 if (call_controller_onchanged) | 1189 if (call_controller_onchanged) |
1153 OnChanged(); | 1190 OnChanged(); |
1154 } | 1191 } |
1155 | 1192 |
1156 bool OmniboxEditModel::OnAfterPossibleChange(const base::string16& old_text, | 1193 bool OmniboxEditModel::OnAfterPossibleChange( |
1157 const base::string16& new_text, | 1194 const OmniboxView::StateChanges& state_changes, |
1158 size_t selection_start, | 1195 bool allow_keyword_ui_change) { |
1159 size_t selection_end, | |
1160 bool selection_differs, | |
1161 bool text_differs, | |
1162 bool just_deleted_text, | |
1163 bool allow_keyword_ui_change) { | |
1164 // Update the paste state as appropriate: if we're just finishing a paste | 1196 // Update the paste state as appropriate: if we're just finishing a paste |
1165 // that replaced all the text, preserve that information; otherwise, if we've | 1197 // that replaced all the text, preserve that information; otherwise, if we've |
1166 // made some other edit, clear paste tracking. | 1198 // made some other edit, clear paste tracking. |
1167 if (paste_state_ == PASTING) | 1199 if (paste_state_ == PASTING) |
1168 paste_state_ = PASTED; | 1200 paste_state_ = PASTED; |
1169 else if (text_differs) | 1201 else if (state_changes.text_differs) |
1170 paste_state_ = NONE; | 1202 paste_state_ = NONE; |
1171 | 1203 |
1172 if (text_differs || selection_differs) { | 1204 if (state_changes.text_differs || state_changes.selection_differs) { |
1173 // Record current focus state for this input if we haven't already. | 1205 // Record current focus state for this input if we haven't already. |
1174 if (focus_source_ == INVALID) { | 1206 if (focus_source_ == INVALID) { |
1175 // We should generally expect the omnibox to have focus at this point, but | 1207 // We should generally expect the omnibox to have focus at this point, but |
1176 // it doesn't always on Linux. This is because, unlike other platforms, | 1208 // it doesn't always on Linux. This is because, unlike other platforms, |
1177 // right clicking in the omnibox on Linux doesn't focus it. So pasting via | 1209 // right clicking in the omnibox on Linux doesn't focus it. So pasting via |
1178 // right-click can change the contents without focusing the omnibox. | 1210 // right-click can change the contents without focusing the omnibox. |
1179 // TODO(samarth): fix Linux focus behavior and add a DCHECK here to | 1211 // TODO(samarth): fix Linux focus behavior and add a DCHECK here to |
1180 // check that the omnibox does have focus. | 1212 // check that the omnibox does have focus. |
1181 focus_source_ = (focus_state_ == OMNIBOX_FOCUS_INVISIBLE) ? | 1213 focus_source_ = |
1182 FAKEBOX : OMNIBOX; | 1214 (focus_state_ == OMNIBOX_FOCUS_INVISIBLE) ? FAKEBOX : OMNIBOX; |
1183 } | 1215 } |
1184 | 1216 |
1185 // Restore caret visibility whenever the user changes text or selection in | 1217 // Restore caret visibility whenever the user changes text or selection in |
1186 // the omnibox. | 1218 // the omnibox. |
1187 SetFocusState(OMNIBOX_FOCUS_VISIBLE, OMNIBOX_FOCUS_CHANGE_TYPING); | 1219 SetFocusState(OMNIBOX_FOCUS_VISIBLE, OMNIBOX_FOCUS_CHANGE_TYPING); |
1188 } | 1220 } |
1189 | 1221 |
1190 // Modifying the selection counts as accepting the autocompleted text. | 1222 // Modifying the selection counts as accepting the autocompleted text. |
1191 const bool user_text_changed = | 1223 const bool user_state_changesd = |
1192 text_differs || (selection_differs && !inline_autocomplete_text_.empty()); | 1224 state_changes.text_differs || |
| 1225 (state_changes.selection_differs && !inline_autocomplete_text_.empty()); |
1193 | 1226 |
1194 // If something has changed while the control key is down, prevent | 1227 // If something has changed while the control key is down, prevent |
1195 // "ctrl-enter" until the control key is released. | 1228 // "ctrl-enter" until the control key is released. |
1196 if ((text_differs || selection_differs) && | 1229 if ((state_changes.text_differs || state_changes.selection_differs) && |
1197 (control_key_state_ == DOWN_WITHOUT_CHANGE)) | 1230 (control_key_state_ == DOWN_WITHOUT_CHANGE)) |
1198 control_key_state_ = DOWN_WITH_CHANGE; | 1231 control_key_state_ = DOWN_WITH_CHANGE; |
1199 | 1232 |
1200 if (!user_text_changed) | 1233 if (!user_state_changesd) { |
1201 return false; | 1234 if (state_changes.keyword_differs) { |
| 1235 // We won't need the below logic for creating a keyword by a space at the |
| 1236 // end or in the middle, or by typing a '?', but we do need to update the |
| 1237 // popup view because the keyword can change without the text changing, |
| 1238 // for example when the keyword is "youtube.com" and the user presses |
| 1239 // ctrl-k to change it to "google.com", or if the user text is empty and |
| 1240 // the user presses backspace. |
| 1241 view_->UpdatePopup(); |
| 1242 } |
| 1243 return state_changes.keyword_differs; |
| 1244 } |
1202 | 1245 |
1203 // If the user text has not changed, we do not want to change the model's | 1246 // If the user text has not changed, we do not want to change the model's |
1204 // state associated with the text. Otherwise, we can get surprising behavior | 1247 // state associated with the text. Otherwise, we can get surprising behavior |
1205 // where the autocompleted text unexpectedly reappears, e.g. crbug.com/55983 | 1248 // where the autocompleted text unexpectedly reappears, e.g. crbug.com/55983 |
1206 InternalSetUserText(new_text); | 1249 InternalSetUserText(*state_changes.new_text); |
1207 has_temporary_text_ = false; | 1250 has_temporary_text_ = false; |
1208 | 1251 |
1209 // Track when the user has deleted text so we won't allow inline | 1252 // Track when the user has deleted text so we won't allow inline |
1210 // autocomplete. | 1253 // autocomplete. |
1211 just_deleted_text_ = just_deleted_text; | 1254 just_deleted_text_ = state_changes.just_deleted_text; |
1212 | 1255 |
1213 if (user_input_in_progress_ && user_text_.empty()) { | 1256 if (user_input_in_progress_ && user_text_.empty()) { |
1214 // Log cases where the user started editing and then subsequently cleared | 1257 // Log cases where the user started editing and then subsequently cleared |
1215 // all the text. Note that this explicitly doesn't catch cases like | 1258 // all the text. Note that this explicitly doesn't catch cases like |
1216 // "hit ctrl-l to select whole edit contents, then hit backspace", because | 1259 // "hit ctrl-l to select whole edit contents, then hit backspace", because |
1217 // in such cases, |user_input_in_progress| won't be true here. | 1260 // in such cases, |user_input_in_progress| won't be true here. |
1218 UMA_HISTOGRAM_ENUMERATION(kOmniboxUserTextClearedHistogram, | 1261 UMA_HISTOGRAM_ENUMERATION(kOmniboxUserTextClearedHistogram, |
1219 OMNIBOX_USER_TEXT_CLEARED_BY_EDITING, | 1262 OMNIBOX_USER_TEXT_CLEARED_BY_EDITING, |
1220 OMNIBOX_USER_TEXT_CLEARED_NUM_OF_ITEMS); | 1263 OMNIBOX_USER_TEXT_CLEARED_NUM_OF_ITEMS); |
1221 } | 1264 } |
1222 | 1265 |
1223 const bool no_selection = selection_start == selection_end; | 1266 const bool no_selection = |
| 1267 state_changes.new_sel_start == state_changes.new_sel_end; |
1224 | 1268 |
1225 // Update the popup for the change, in the process changing to keyword mode | 1269 // Update the popup for the change, in the process changing to keyword mode |
1226 // if the user hit space in mid-string after a keyword. | 1270 // if the user hit space in mid-string after a keyword. |
1227 // |allow_exact_keyword_match_| will be used by StartAutocomplete() method, | 1271 // |allow_exact_keyword_match_| will be used by StartAutocomplete() method, |
1228 // which will be called by |view_->UpdatePopup()|; so after that returns we | 1272 // which will be called by |view_->UpdatePopup()|; so after that returns we |
1229 // can safely reset this flag. | 1273 // can safely reset this flag. |
1230 allow_exact_keyword_match_ = text_differs && allow_keyword_ui_change && | 1274 allow_exact_keyword_match_ = |
1231 !just_deleted_text && no_selection && | 1275 state_changes.text_differs && allow_keyword_ui_change && |
1232 CreatedKeywordSearchByInsertingSpaceInMiddle(old_text, user_text_, | 1276 !state_changes.just_deleted_text && no_selection && |
1233 selection_start); | 1277 CreatedKeywordSearchByInsertingSpaceInMiddle( |
| 1278 *state_changes.old_text, user_text_, state_changes.new_sel_start); |
1234 view_->UpdatePopup(); | 1279 view_->UpdatePopup(); |
1235 if (allow_exact_keyword_match_) { | 1280 if (allow_exact_keyword_match_) { |
1236 UMA_HISTOGRAM_ENUMERATION(kEnteredKeywordModeHistogram, | 1281 keyword_mode_entry_method_ = KeywordModeEntryMethod::SPACE_IN_MIDDLE; |
1237 ENTERED_KEYWORD_MODE_VIA_SPACE_IN_MIDDLE, | 1282 UMA_HISTOGRAM_ENUMERATION( |
1238 ENTERED_KEYWORD_MODE_NUM_ITEMS); | 1283 kEnteredKeywordModeHistogram, |
| 1284 static_cast<int>(KeywordModeEntryMethod::SPACE_IN_MIDDLE), |
| 1285 static_cast<int>(KeywordModeEntryMethod::NUM_ITEMS)); |
1239 allow_exact_keyword_match_ = false; | 1286 allow_exact_keyword_match_ = false; |
1240 } | 1287 } |
1241 | 1288 |
| 1289 if (!state_changes.text_differs || !allow_keyword_ui_change || |
| 1290 (state_changes.just_deleted_text && no_selection) || |
| 1291 is_keyword_selected() || (paste_state_ != NONE)) |
| 1292 return true; |
| 1293 |
| 1294 // If the user input a "?" at the beginning of the text, put them into |
| 1295 // keyword mode for their default search provider. |
| 1296 if ((state_changes.new_sel_start == 1) && (user_text_[0] == '?')) { |
| 1297 view_->SetUserText(user_text_.substr(1)); |
| 1298 EnterKeywordModeForDefaultSearchProvider( |
| 1299 KeywordModeEntryMethod::QUESTION_MARK); |
| 1300 // Set the caret position to 0 without changing the user text. |
| 1301 view_->SetWindowTextAndCaretPos(view_->GetText(), 0, false, false); |
| 1302 return false; |
| 1303 } |
| 1304 |
1242 // Change to keyword mode if the user is now pressing space after a keyword | 1305 // Change to keyword mode if the user is now pressing space after a keyword |
1243 // name. Note that if this is the case, then even if there was no keyword | 1306 // name. Note that if this is the case, then even if there was no keyword |
1244 // hint when we entered this function (e.g. if the user has used space to | 1307 // hint when we entered this function (e.g. if the user has used space to |
1245 // replace some selected text that was adjoined to this keyword), there will | 1308 // replace some selected text that was adjoined to this keyword), there will |
1246 // be one now because of the call to UpdatePopup() above; so it's safe for | 1309 // be one now because of the call to UpdatePopup() above; so it's safe for |
1247 // MaybeAcceptKeywordBySpace() to look at |keyword_| and |is_keyword_hint_| to | 1310 // MaybeAcceptKeywordBySpace() to look at |keyword_| and |is_keyword_hint_| |
1248 // determine what keyword, if any, is applicable. | 1311 // to determine what keyword, if any, is applicable. |
1249 // | 1312 // |
1250 // If MaybeAcceptKeywordBySpace() accepts the keyword and returns true, that | 1313 // If MaybeAcceptKeywordBySpace() accepts the keyword and returns true, that |
1251 // will have updated our state already, so in that case we don't also return | 1314 // will have updated our state already, so in that case we don't also return |
1252 // true from this function. | 1315 // true from this function. |
1253 return !(text_differs && allow_keyword_ui_change && !just_deleted_text && | 1316 return (state_changes.new_sel_start != user_text_.length()) || |
1254 no_selection && (selection_start == user_text_.length()) && | 1317 !MaybeAcceptKeywordBySpace(user_text_); |
1255 MaybeAcceptKeywordBySpace(user_text_)); | |
1256 } | 1318 } |
1257 | 1319 |
1258 // TODO(beaudoin): Merge OnPopupDataChanged with this method once the popup | 1320 // TODO(beaudoin): Merge OnPopupDataChanged with this method once the popup |
1259 // handling has completely migrated to omnibox_controller. | 1321 // handling has completely migrated to omnibox_controller. |
1260 void OmniboxEditModel::OnCurrentMatchChanged() { | 1322 void OmniboxEditModel::OnCurrentMatchChanged() { |
1261 has_temporary_text_ = false; | 1323 has_temporary_text_ = false; |
1262 | 1324 |
1263 const AutocompleteMatch& match = omnibox_controller_->current_match(); | 1325 const AutocompleteMatch& match = omnibox_controller_->current_match(); |
1264 | 1326 |
1265 client_->OnCurrentMatchChanged(match); | 1327 client_->OnCurrentMatchChanged(match); |
(...skipping 103 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1369 has_temporary_text_ = false; | 1431 has_temporary_text_ = false; |
1370 | 1432 |
1371 if (revert_popup && popup_model()) | 1433 if (revert_popup && popup_model()) |
1372 popup_model()->ResetToDefaultMatch(); | 1434 popup_model()->ResetToDefaultMatch(); |
1373 view_->OnRevertTemporaryText(); | 1435 view_->OnRevertTemporaryText(); |
1374 } | 1436 } |
1375 | 1437 |
1376 bool OmniboxEditModel::MaybeAcceptKeywordBySpace( | 1438 bool OmniboxEditModel::MaybeAcceptKeywordBySpace( |
1377 const base::string16& new_text) { | 1439 const base::string16& new_text) { |
1378 size_t keyword_length = new_text.length() - 1; | 1440 size_t keyword_length = new_text.length() - 1; |
1379 return (paste_state_ == NONE) && is_keyword_hint_ && | 1441 return is_keyword_hint_ && (keyword_.length() == keyword_length) && |
1380 (keyword_.length() == keyword_length) && | 1442 IsSpaceCharForAcceptingKeyword(new_text[keyword_length]) && |
1381 IsSpaceCharForAcceptingKeyword(new_text[keyword_length]) && | 1443 !new_text.compare(0, keyword_length, keyword_, 0, keyword_length) && |
1382 !new_text.compare(0, keyword_length, keyword_, 0, keyword_length) && | 1444 AcceptKeyword(KeywordModeEntryMethod::SPACE_AT_END); |
1383 AcceptKeyword(ENTERED_KEYWORD_MODE_VIA_SPACE_AT_END); | |
1384 } | 1445 } |
1385 | 1446 |
1386 bool OmniboxEditModel::CreatedKeywordSearchByInsertingSpaceInMiddle( | 1447 bool OmniboxEditModel::CreatedKeywordSearchByInsertingSpaceInMiddle( |
1387 const base::string16& old_text, | 1448 const base::string16& old_text, |
1388 const base::string16& new_text, | 1449 const base::string16& new_text, |
1389 size_t caret_position) const { | 1450 size_t caret_position) const { |
1390 DCHECK_GE(new_text.length(), caret_position); | 1451 DCHECK_GE(new_text.length(), caret_position); |
1391 | 1452 |
1392 // Check simple conditions first. | 1453 // Check simple conditions first. |
1393 if ((paste_state_ != NONE) || (caret_position < 2) || | 1454 if ((paste_state_ != NONE) || (caret_position < 2) || |
(...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1467 // Update state and notify view if the omnibox has focus and the caret | 1528 // Update state and notify view if the omnibox has focus and the caret |
1468 // visibility changed. | 1529 // visibility changed. |
1469 const bool was_caret_visible = is_caret_visible(); | 1530 const bool was_caret_visible = is_caret_visible(); |
1470 focus_state_ = state; | 1531 focus_state_ = state; |
1471 if (focus_state_ != OMNIBOX_FOCUS_NONE && | 1532 if (focus_state_ != OMNIBOX_FOCUS_NONE && |
1472 is_caret_visible() != was_caret_visible) | 1533 is_caret_visible() != was_caret_visible) |
1473 view_->ApplyCaretVisibility(); | 1534 view_->ApplyCaretVisibility(); |
1474 | 1535 |
1475 client_->OnFocusChanged(focus_state_, reason); | 1536 client_->OnFocusChanged(focus_state_, reason); |
1476 } | 1537 } |
OLD | NEW |