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 102 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
113 OmniboxEditModel::State::~State() { | 113 OmniboxEditModel::State::~State() { |
114 } | 114 } |
115 | 115 |
116 /////////////////////////////////////////////////////////////////////////////// | 116 /////////////////////////////////////////////////////////////////////////////// |
117 // OmniboxEditModel | 117 // OmniboxEditModel |
118 | 118 |
119 OmniboxEditModel::OmniboxEditModel(OmniboxView* view, | 119 OmniboxEditModel::OmniboxEditModel(OmniboxView* view, |
120 OmniboxEditController* controller, | 120 OmniboxEditController* controller, |
121 Profile* profile) | 121 Profile* profile) |
122 : view_(view), | 122 : view_(view), |
123 popup_(NULL), | |
124 controller_(controller), | 123 controller_(controller), |
125 focus_state_(OMNIBOX_FOCUS_NONE), | 124 focus_state_(OMNIBOX_FOCUS_NONE), |
126 user_input_in_progress_(false), | 125 user_input_in_progress_(false), |
127 just_deleted_text_(false), | 126 just_deleted_text_(false), |
128 has_temporary_text_(false), | 127 has_temporary_text_(false), |
129 is_temporary_text_set_by_instant_(false), | 128 is_temporary_text_set_by_instant_(false), |
130 paste_state_(NONE), | 129 paste_state_(NONE), |
131 control_key_state_(UP), | 130 control_key_state_(UP), |
132 is_keyword_hint_(false), | 131 is_keyword_hint_(false), |
133 profile_(profile), | 132 profile_(profile), |
(...skipping 90 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
224 | 223 |
225 void OmniboxEditModel::FinalizeInstantQuery(const string16& input_text, | 224 void OmniboxEditModel::FinalizeInstantQuery(const string16& input_text, |
226 const InstantSuggestion& suggestion, | 225 const InstantSuggestion& suggestion, |
227 bool skip_inline_autocomplete) { | 226 bool skip_inline_autocomplete) { |
228 if (skip_inline_autocomplete) { | 227 if (skip_inline_autocomplete) { |
229 const string16 final_text = input_text + suggestion.text; | 228 const string16 final_text = input_text + suggestion.text; |
230 view_->OnBeforePossibleChange(); | 229 view_->OnBeforePossibleChange(); |
231 view_->SetWindowTextAndCaretPos(final_text, final_text.length(), false, | 230 view_->SetWindowTextAndCaretPos(final_text, final_text.length(), false, |
232 false); | 231 false); |
233 view_->OnAfterPossibleChange(); | 232 view_->OnAfterPossibleChange(); |
234 } else if (popup_->IsOpen()) { | 233 } else if (popup_model()->IsOpen()) { |
235 SearchProvider* search_provider = | 234 SearchProvider* search_provider = |
236 autocomplete_controller()->search_provider(); | 235 autocomplete_controller()->search_provider(); |
237 // There may be no providers during testing; guard against that. | 236 // There may be no providers during testing; guard against that. |
238 if (search_provider) | 237 if (search_provider) |
239 search_provider->FinalizeInstantQuery(input_text, suggestion); | 238 search_provider->FinalizeInstantQuery(input_text, suggestion); |
240 } | 239 } |
241 } | 240 } |
242 | 241 |
243 void OmniboxEditModel::SetInstantSuggestion( | 242 void OmniboxEditModel::SetInstantSuggestion( |
244 const InstantSuggestion& suggestion) { | 243 const InstantSuggestion& suggestion) { |
(...skipping 90 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
335 // has been closed or on return from a sleep state. | 334 // has been closed or on return from a sleep state. |
336 // (http://crbug.com/105689) | 335 // (http://crbug.com/105689) |
337 if (!delegate_->CurrentPageExists()) | 336 if (!delegate_->CurrentPageExists()) |
338 break; | 337 break; |
339 // Ask for prerendering if the destination URL is different than the | 338 // Ask for prerendering if the destination URL is different than the |
340 // current URL. | 339 // current URL. |
341 if (current_match.destination_url != PermanentURL()) | 340 if (current_match.destination_url != PermanentURL()) |
342 delegate_->DoPrerender(current_match); | 341 delegate_->DoPrerender(current_match); |
343 break; | 342 break; |
344 case AutocompleteActionPredictor::ACTION_PRECONNECT: | 343 case AutocompleteActionPredictor::ACTION_PRECONNECT: |
345 DoPreconnect(current_match); | 344 omnibox_controller_->DoPreconnect(current_match); |
346 break; | 345 break; |
347 case AutocompleteActionPredictor::ACTION_NONE: | 346 case AutocompleteActionPredictor::ACTION_NONE: |
348 break; | 347 break; |
349 } | 348 } |
350 | 349 |
351 controller_->OnChanged(); | 350 controller_->OnChanged(); |
352 } | 351 } |
353 | 352 |
354 void OmniboxEditModel::GetDataForURLExport(GURL* url, | 353 void OmniboxEditModel::GetDataForURLExport(GURL* url, |
355 string16* title, | 354 string16* title, |
(...skipping 18 matching lines...) Expand all Loading... |
374 #endif | 373 #endif |
375 | 374 |
376 // The value of input.prevent_inline_autocomplete() is determined by the | 375 // The value of input.prevent_inline_autocomplete() is determined by the |
377 // following conditions: | 376 // following conditions: |
378 // 1. If the caret is at the end of the text. | 377 // 1. If the caret is at the end of the text. |
379 // 2. If it's in IME composition mode. | 378 // 2. If it's in IME composition mode. |
380 // We send the caret position to Instant (so it can determine #1 itself), and | 379 // We send the caret position to Instant (so it can determine #1 itself), and |
381 // we use a separated widget for displaying the Instant suggest (so it doesn't | 380 // we use a separated widget for displaying the Instant suggest (so it doesn't |
382 // interfere with #2). So, we don't need to care about the value of | 381 // interfere with #2). So, we don't need to care about the value of |
383 // input.prevent_inline_autocomplete() here. | 382 // input.prevent_inline_autocomplete() here. |
384 return view_->DeleteAtEndPressed() || popup_->selected_line() != 0 || | 383 return view_->DeleteAtEndPressed() || popup_model()->selected_line() != 0 || |
385 just_deleted_text_; | 384 just_deleted_text_; |
386 } | 385 } |
387 | 386 |
388 bool OmniboxEditModel::CurrentTextIsURL() const { | 387 bool OmniboxEditModel::CurrentTextIsURL() const { |
389 if (view_->toolbar_model()->WouldReplaceSearchURLWithSearchTerms()) | 388 if (view_->toolbar_model()->WouldReplaceSearchURLWithSearchTerms()) |
390 return false; | 389 return false; |
391 | 390 |
392 // If current text is not composed of replaced search terms and | 391 // If current text is not composed of replaced search terms and |
393 // !user_input_in_progress_, then permanent text is showing and should be a | 392 // !user_input_in_progress_, then permanent text is showing and should be a |
394 // URL, so no further checking is needed. By avoiding checking in this case, | 393 // URL, so no further checking is needed. By avoiding checking in this case, |
(...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
487 if (action_predictor) | 486 if (action_predictor) |
488 action_predictor->ClearTransitionalMatches(); | 487 action_predictor->ClearTransitionalMatches(); |
489 } | 488 } |
490 | 489 |
491 void OmniboxEditModel::StartAutocomplete( | 490 void OmniboxEditModel::StartAutocomplete( |
492 bool has_selected_text, | 491 bool has_selected_text, |
493 bool prevent_inline_autocomplete) const { | 492 bool prevent_inline_autocomplete) const { |
494 ClearPopupKeywordMode(); | 493 ClearPopupKeywordMode(); |
495 | 494 |
496 bool keyword_is_selected = KeywordIsSelected(); | 495 bool keyword_is_selected = KeywordIsSelected(); |
497 popup_->SetHoveredLine(OmniboxPopupModel::kNoMatch); | 496 popup_model()->SetHoveredLine(OmniboxPopupModel::kNoMatch); |
498 | 497 |
499 size_t cursor_position; | 498 size_t cursor_position; |
500 if (inline_autocomplete_text_.empty()) { | 499 if (inline_autocomplete_text_.empty()) { |
501 // Cursor position is equivalent to the current selection's end. | 500 // Cursor position is equivalent to the current selection's end. |
502 size_t start; | 501 size_t start; |
503 view_->GetSelectionBounds(&start, &cursor_position); | 502 view_->GetSelectionBounds(&start, &cursor_position); |
504 // Adjust cursor position taking into account possible keyword in the user | 503 // Adjust cursor position taking into account possible keyword in the user |
505 // text. We rely on DisplayTextFromUserText() method which is consistent | 504 // text. We rely on DisplayTextFromUserText() method which is consistent |
506 // with keyword extraction done in KeywordProvider/SearchProvider. | 505 // with keyword extraction done in KeywordProvider/SearchProvider. |
507 const size_t cursor_offset = | 506 const size_t cursor_offset = |
(...skipping 121 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
629 view_->OpenMatch(match, disposition, alternate_nav_url, | 628 view_->OpenMatch(match, disposition, alternate_nav_url, |
630 OmniboxPopupModel::kNoMatch); | 629 OmniboxPopupModel::kNoMatch); |
631 } | 630 } |
632 | 631 |
633 void OmniboxEditModel::OpenMatch(const AutocompleteMatch& match, | 632 void OmniboxEditModel::OpenMatch(const AutocompleteMatch& match, |
634 WindowOpenDisposition disposition, | 633 WindowOpenDisposition disposition, |
635 const GURL& alternate_nav_url, | 634 const GURL& alternate_nav_url, |
636 size_t index) { | 635 size_t index) { |
637 // We only care about cases where there is a selection (i.e. the popup is | 636 // We only care about cases where there is a selection (i.e. the popup is |
638 // open). | 637 // open). |
639 if (popup_->IsOpen()) { | 638 if (popup_model()->IsOpen()) { |
640 const base::TimeTicks& now(base::TimeTicks::Now()); | 639 const base::TimeTicks& now(base::TimeTicks::Now()); |
641 // TODO(sreeram): Handle is_temporary_text_set_by_instant_ correctly. | 640 // TODO(sreeram): Handle is_temporary_text_set_by_instant_ correctly. |
642 AutocompleteLog log( | 641 AutocompleteLog log( |
643 autocomplete_controller()->input().text(), | 642 autocomplete_controller()->input().text(), |
644 just_deleted_text_, | 643 just_deleted_text_, |
645 autocomplete_controller()->input().type(), | 644 autocomplete_controller()->input().type(), |
646 popup_->selected_line(), | 645 popup_model()->selected_line(), |
647 -1, // don't yet know tab ID; set later if appropriate | 646 -1, // don't yet know tab ID; set later if appropriate |
648 delegate_->CurrentPageExists() ? ClassifyPage(delegate_->GetURL()) : | 647 delegate_->CurrentPageExists() ? ClassifyPage(delegate_->GetURL()) : |
649 metrics::OmniboxEventProto_PageClassification_OTHER, | 648 metrics::OmniboxEventProto_PageClassification_OTHER, |
650 now - time_user_first_modified_omnibox_, | 649 now - time_user_first_modified_omnibox_, |
651 string16::npos, // completed_length; possibly set later | 650 string16::npos, // completed_length; possibly set later |
652 now - autocomplete_controller()->last_time_default_match_changed(), | 651 now - autocomplete_controller()->last_time_default_match_changed(), |
653 result()); | 652 result()); |
654 DCHECK(user_input_in_progress_ || | 653 DCHECK(user_input_in_progress_ || |
655 match.provider->type() == AutocompleteProvider::TYPE_ZERO_SUGGEST) | 654 match.provider->type() == AutocompleteProvider::TYPE_ZERO_SUGGEST) |
656 << "We didn't get here through the expected series of calls. " | 655 << "We didn't get here through the expected series of calls. " |
(...skipping 97 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
754 if (match.starred) | 753 if (match.starred) |
755 bookmark_utils::RecordBookmarkLaunch(bookmark_utils::LAUNCH_OMNIBOX); | 754 bookmark_utils::RecordBookmarkLaunch(bookmark_utils::LAUNCH_OMNIBOX); |
756 } | 755 } |
757 | 756 |
758 bool OmniboxEditModel::AcceptKeyword(EnteredKeywordModeMethod entered_method) { | 757 bool OmniboxEditModel::AcceptKeyword(EnteredKeywordModeMethod entered_method) { |
759 DCHECK(is_keyword_hint_ && !keyword_.empty()); | 758 DCHECK(is_keyword_hint_ && !keyword_.empty()); |
760 | 759 |
761 autocomplete_controller()->Stop(false); | 760 autocomplete_controller()->Stop(false); |
762 is_keyword_hint_ = false; | 761 is_keyword_hint_ = false; |
763 | 762 |
764 if (popup_->IsOpen()) | 763 if (popup_model()->IsOpen()) |
765 popup_->SetSelectedLineState(OmniboxPopupModel::KEYWORD); | 764 popup_model()->SetSelectedLineState(OmniboxPopupModel::KEYWORD); |
766 else | 765 else |
767 StartAutocomplete(false, true); | 766 StartAutocomplete(false, true); |
768 | 767 |
769 // Ensure the current selection is saved before showing keyword mode | 768 // Ensure the current selection is saved before showing keyword mode |
770 // so that moving to another line and then reverting the text will restore | 769 // so that moving to another line and then reverting the text will restore |
771 // the current state properly. | 770 // the current state properly. |
772 bool save_original_selection = !has_temporary_text_; | 771 bool save_original_selection = !has_temporary_text_; |
773 has_temporary_text_ = true; | 772 has_temporary_text_ = true; |
774 is_temporary_text_set_by_instant_ = false; | 773 is_temporary_text_set_by_instant_ = false; |
775 view_->OnTemporaryTextMaybeChanged( | 774 view_->OnTemporaryTextMaybeChanged( |
776 DisplayTextFromUserText(CurrentMatch().fill_into_edit), | 775 DisplayTextFromUserText(CurrentMatch().fill_into_edit), |
777 save_original_selection, true); | 776 save_original_selection, true); |
778 | 777 |
779 content::RecordAction(UserMetricsAction("AcceptedKeywordHint")); | 778 content::RecordAction(UserMetricsAction("AcceptedKeywordHint")); |
780 UMA_HISTOGRAM_ENUMERATION(kEnteredKeywordModeHistogram, entered_method, | 779 UMA_HISTOGRAM_ENUMERATION(kEnteredKeywordModeHistogram, entered_method, |
781 ENTERED_KEYWORD_MODE_NUM_ITEMS); | 780 ENTERED_KEYWORD_MODE_NUM_ITEMS); |
782 | 781 |
783 return true; | 782 return true; |
784 } | 783 } |
785 | 784 |
| 785 void OmniboxEditModel::AcceptTemporaryTextAsUserText() { |
| 786 InternalSetUserText(UserTextFromDisplayText(view_->GetText())); |
| 787 has_temporary_text_ = false; |
| 788 is_temporary_text_set_by_instant_ = false; |
| 789 OnPopupBoundsChanged(gfx::Rect()); |
| 790 delegate_->NotifySearchTabHelper(user_input_in_progress_, !in_revert_); |
| 791 } |
| 792 |
786 void OmniboxEditModel::ClearKeyword(const string16& visible_text) { | 793 void OmniboxEditModel::ClearKeyword(const string16& visible_text) { |
787 autocomplete_controller()->Stop(false); | 794 autocomplete_controller()->Stop(false); |
788 ClearPopupKeywordMode(); | 795 ClearPopupKeywordMode(); |
789 | 796 |
790 const string16 window_text(keyword_ + visible_text); | 797 const string16 window_text(keyword_ + visible_text); |
791 | 798 |
792 // Only reset the result if the edit text has changed since the | 799 // Only reset the result if the edit text has changed since the |
793 // keyword was accepted, or if the popup is closed. | 800 // keyword was accepted, or if the popup is closed. |
794 if (just_deleted_text_ || !visible_text.empty() || !popup_->IsOpen()) { | 801 if (just_deleted_text_ || !visible_text.empty() || !popup_model()->IsOpen()) { |
795 view_->OnBeforePossibleChange(); | 802 view_->OnBeforePossibleChange(); |
796 view_->SetWindowTextAndCaretPos(window_text.c_str(), keyword_.length(), | 803 view_->SetWindowTextAndCaretPos(window_text.c_str(), keyword_.length(), |
797 false, false); | 804 false, false); |
798 keyword_.clear(); | 805 keyword_.clear(); |
799 is_keyword_hint_ = false; | 806 is_keyword_hint_ = false; |
800 view_->OnAfterPossibleChange(); | 807 view_->OnAfterPossibleChange(); |
801 just_deleted_text_ = true; // OnAfterPossibleChange() fails to clear this | 808 just_deleted_text_ = true; // OnAfterPossibleChange() fails to clear this |
802 // since the edit contents have actually grown | 809 // since the edit contents have actually grown |
803 // longer. | 810 // longer. |
804 } else { | 811 } else { |
805 is_keyword_hint_ = true; | 812 is_keyword_hint_ = true; |
806 view_->SetWindowTextAndCaretPos(window_text.c_str(), keyword_.length(), | 813 view_->SetWindowTextAndCaretPos(window_text.c_str(), keyword_.length(), |
807 false, true); | 814 false, true); |
808 } | 815 } |
809 } | 816 } |
810 | 817 |
811 const AutocompleteResult& OmniboxEditModel::result() const { | |
812 return autocomplete_controller()->result(); | |
813 } | |
814 | |
815 void OmniboxEditModel::OnSetFocus(bool control_down) { | 818 void OmniboxEditModel::OnSetFocus(bool control_down) { |
816 // If the omnibox lost focus while the caret was hidden and then regained | 819 // If the omnibox lost focus while the caret was hidden and then regained |
817 // focus, OnSetFocus() is called and should restore visibility. Note that | 820 // focus, OnSetFocus() is called and should restore visibility. Note that |
818 // focus can be regained without an accompanying call to | 821 // focus can be regained without an accompanying call to |
819 // OmniboxView::SetFocus(), e.g. by tabbing in. | 822 // OmniboxView::SetFocus(), e.g. by tabbing in. |
820 SetFocusState(OMNIBOX_FOCUS_VISIBLE, OMNIBOX_FOCUS_CHANGE_EXPLICIT); | 823 SetFocusState(OMNIBOX_FOCUS_VISIBLE, OMNIBOX_FOCUS_CHANGE_EXPLICIT); |
821 control_key_state_ = control_down ? DOWN_WITHOUT_CHANGE : UP; | 824 control_key_state_ = control_down ? DOWN_WITHOUT_CHANGE : UP; |
822 | 825 |
823 if (delegate_->CurrentPageExists()) { | 826 if (delegate_->CurrentPageExists()) { |
824 // TODO(jered): We may want to merge this into Start() and just call that | 827 // TODO(jered): We may want to merge this into Start() and just call that |
(...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
905 if (pressed == (control_key_state_ == UP)) { | 908 if (pressed == (control_key_state_ == UP)) { |
906 ControlKeyState old_state = control_key_state_; | 909 ControlKeyState old_state = control_key_state_; |
907 control_key_state_ = pressed ? DOWN_WITHOUT_CHANGE : UP; | 910 control_key_state_ = pressed ? DOWN_WITHOUT_CHANGE : UP; |
908 if ((control_key_state_ == DOWN_WITHOUT_CHANGE) && has_temporary_text_) { | 911 if ((control_key_state_ == DOWN_WITHOUT_CHANGE) && has_temporary_text_) { |
909 // Arrowing down and then hitting control accepts the temporary text as | 912 // Arrowing down and then hitting control accepts the temporary text as |
910 // the input text. | 913 // the input text. |
911 InternalSetUserText(UserTextFromDisplayText(view_->GetText())); | 914 InternalSetUserText(UserTextFromDisplayText(view_->GetText())); |
912 has_temporary_text_ = false; | 915 has_temporary_text_ = false; |
913 is_temporary_text_set_by_instant_ = false; | 916 is_temporary_text_set_by_instant_ = false; |
914 } | 917 } |
915 if ((old_state != DOWN_WITH_CHANGE) && popup_->IsOpen()) { | 918 if ((old_state != DOWN_WITH_CHANGE) && popup_model()->IsOpen()) { |
916 // Autocomplete history provider results may change, so refresh the | 919 // Autocomplete history provider results may change, so refresh the |
917 // popup. This will force user_input_in_progress_ to true, but if the | 920 // popup. This will force user_input_in_progress_ to true, but if the |
918 // popup is open, that should have already been the case. | 921 // popup is open, that should have already been the case. |
919 view_->UpdatePopup(); | 922 view_->UpdatePopup(); |
920 } | 923 } |
921 } | 924 } |
922 } | 925 } |
923 | 926 |
924 void OmniboxEditModel::OnUpOrDownKeyPressed(int count) { | 927 void OmniboxEditModel::OnUpOrDownKeyPressed(int count) { |
925 // NOTE: This purposefully doesn't trigger any code that resets paste_state_. | 928 // NOTE: This purposefully doesn't trigger any code that resets paste_state_. |
926 if (!popup_->IsOpen()) { | 929 if (!popup_model()->IsOpen()) { |
927 if (!query_in_progress()) { | 930 if (!query_in_progress()) { |
928 // The popup is neither open nor working on a query already. So, start an | 931 // The popup is neither open nor working on a query already. So, start an |
929 // autocomplete query for the current text. This also sets | 932 // autocomplete query for the current text. This also sets |
930 // user_input_in_progress_ to true, which we want: if the user has started | 933 // user_input_in_progress_ to true, which we want: if the user has started |
931 // to interact with the popup, changing the permanent_text_ shouldn't | 934 // to interact with the popup, changing the permanent_text_ shouldn't |
932 // change the displayed text. | 935 // change the displayed text. |
933 // Note: This does not force the popup to open immediately. | 936 // Note: This does not force the popup to open immediately. |
934 // TODO(pkasting): We should, in fact, force this particular query to open | 937 // TODO(pkasting): We should, in fact, force this particular query to open |
935 // the popup immediately. | 938 // the popup immediately. |
936 if (!user_input_in_progress_) | 939 if (!user_input_in_progress_) |
937 InternalSetUserText(permanent_text_); | 940 InternalSetUserText(permanent_text_); |
938 view_->UpdatePopup(); | 941 view_->UpdatePopup(); |
939 } else { | 942 } else { |
940 // TODO(pkasting): The popup is working on a query but is not open. We | 943 // TODO(pkasting): The popup is working on a query but is not open. We |
941 // should force it to open immediately. | 944 // should force it to open immediately. |
942 } | 945 } |
943 } else { | 946 } else { |
944 InstantController* instant = controller_->GetInstant(); | 947 InstantController* instant = controller_->GetInstant(); |
945 if (instant && instant->OnUpOrDownKeyPressed(count)) { | 948 if (instant && instant->OnUpOrDownKeyPressed(count)) { |
946 // If Instant handles the key press, it's showing a list of suggestions | 949 // If Instant handles the key press, it's showing a list of suggestions |
947 // that it's stepping through. In that case, our popup model is | 950 // that it's stepping through. In that case, our popup model is |
948 // irrelevant, so don't process the key press ourselves. However, do stop | 951 // irrelevant, so don't process the key press ourselves. However, do stop |
949 // the autocomplete system from changing the results. | 952 // the autocomplete system from changing the results. |
950 autocomplete_controller()->Stop(false); | 953 autocomplete_controller()->Stop(false); |
951 } else { | 954 } else { |
952 // The popup is open, so the user should be able to interact with it | 955 // The popup is open, so the user should be able to interact with it |
953 // normally. | 956 // normally. |
954 popup_->Move(count); | 957 popup_model()->Move(count); |
955 } | 958 } |
956 } | 959 } |
957 } | 960 } |
958 | 961 |
959 void OmniboxEditModel::OnPopupDataChanged( | 962 void OmniboxEditModel::OnPopupDataChanged( |
960 const string16& text, | 963 const string16& text, |
961 GURL* destination_for_temporary_text_change, | 964 GURL* destination_for_temporary_text_change, |
962 const string16& keyword, | 965 const string16& keyword, |
963 bool is_keyword_hint) { | 966 bool is_keyword_hint) { |
964 // Update keyword/hint-related local state. | 967 // Update keyword/hint-related local state. |
(...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1064 // Modifying the selection counts as accepting the autocompleted text. | 1067 // Modifying the selection counts as accepting the autocompleted text. |
1065 const bool user_text_changed = | 1068 const bool user_text_changed = |
1066 text_differs || (selection_differs && !inline_autocomplete_text_.empty()); | 1069 text_differs || (selection_differs && !inline_autocomplete_text_.empty()); |
1067 | 1070 |
1068 // If something has changed while the control key is down, prevent | 1071 // If something has changed while the control key is down, prevent |
1069 // "ctrl-enter" until the control key is released. When we do this, we need | 1072 // "ctrl-enter" until the control key is released. When we do this, we need |
1070 // to update the popup if it's open, since the desired_tld will have changed. | 1073 // to update the popup if it's open, since the desired_tld will have changed. |
1071 if ((text_differs || selection_differs) && | 1074 if ((text_differs || selection_differs) && |
1072 (control_key_state_ == DOWN_WITHOUT_CHANGE)) { | 1075 (control_key_state_ == DOWN_WITHOUT_CHANGE)) { |
1073 control_key_state_ = DOWN_WITH_CHANGE; | 1076 control_key_state_ = DOWN_WITH_CHANGE; |
1074 if (!text_differs && !popup_->IsOpen()) | 1077 if (!text_differs && !popup_model()->IsOpen()) |
1075 return false; // Don't open the popup for no reason. | 1078 return false; // Don't open the popup for no reason. |
1076 } else if (!user_text_changed) { | 1079 } else if (!user_text_changed) { |
1077 return false; | 1080 return false; |
1078 } | 1081 } |
1079 | 1082 |
1080 // If the user text has not changed, we do not want to change the model's | 1083 // If the user text has not changed, we do not want to change the model's |
1081 // state associated with the text. Otherwise, we can get surprising behavior | 1084 // state associated with the text. Otherwise, we can get surprising behavior |
1082 // where the autocompleted text unexpectedly reappears, e.g. crbug.com/55983 | 1085 // where the autocompleted text unexpectedly reappears, e.g. crbug.com/55983 |
1083 if (user_text_changed) { | 1086 if (user_text_changed) { |
1084 InternalSetUserText(UserTextFromDisplayText(new_text)); | 1087 InternalSetUserText(UserTextFromDisplayText(new_text)); |
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1135 MaybeAcceptKeywordBySpace(user_text_)); | 1138 MaybeAcceptKeywordBySpace(user_text_)); |
1136 } | 1139 } |
1137 | 1140 |
1138 void OmniboxEditModel::OnPopupBoundsChanged(const gfx::Rect& bounds) { | 1141 void OmniboxEditModel::OnPopupBoundsChanged(const gfx::Rect& bounds) { |
1139 InstantController* instant = controller_->GetInstant(); | 1142 InstantController* instant = controller_->GetInstant(); |
1140 if (instant) | 1143 if (instant) |
1141 instant->SetPopupBounds(bounds); | 1144 instant->SetPopupBounds(bounds); |
1142 } | 1145 } |
1143 | 1146 |
1144 void OmniboxEditModel::OnResultChanged(bool default_match_changed) { | 1147 void OmniboxEditModel::OnResultChanged(bool default_match_changed) { |
1145 const bool was_open = popup_->IsOpen(); | |
1146 if (default_match_changed) { | |
1147 string16 inline_autocomplete_text; | |
1148 string16 keyword; | |
1149 bool is_keyword_hint = false; | |
1150 const AutocompleteResult& result = this->result(); | |
1151 const AutocompleteResult::const_iterator match(result.default_match()); | |
1152 if (match != result.end()) { | |
1153 if ((match->inline_autocomplete_offset != string16::npos) && | |
1154 (match->inline_autocomplete_offset < | |
1155 match->fill_into_edit.length())) { | |
1156 inline_autocomplete_text = | |
1157 match->fill_into_edit.substr(match->inline_autocomplete_offset); | |
1158 } | |
1159 | |
1160 if (!prerender::IsOmniboxEnabled(profile_)) | |
1161 DoPreconnect(*match); | |
1162 | |
1163 // We could prefetch the alternate nav URL, if any, but because there | |
1164 // can be many of these as a user types an initial series of characters, | |
1165 // the OS DNS cache could suffer eviction problems for minimal gain. | |
1166 | |
1167 match->GetKeywordUIState(profile_, &keyword, &is_keyword_hint); | |
1168 } | |
1169 | |
1170 popup_->OnResultChanged(); | |
1171 OnPopupDataChanged(inline_autocomplete_text, NULL, keyword, | |
1172 is_keyword_hint); | |
1173 } else { | |
1174 popup_->OnResultChanged(); | |
1175 } | |
1176 | |
1177 if (popup_->IsOpen()) { | |
1178 OnPopupBoundsChanged(popup_->view()->GetTargetBounds()); | |
1179 | |
1180 InstantController* instant = controller_->GetInstant(); | |
1181 if (instant && !in_revert_) { | |
1182 instant->HandleAutocompleteResults( | |
1183 *autocomplete_controller_->providers()); | |
1184 } | |
1185 } else if (was_open) { | |
1186 // Accepts the temporary text as the user text, because it makes little | |
1187 // sense to have temporary text when the popup is closed. | |
1188 InternalSetUserText(UserTextFromDisplayText(view_->GetText())); | |
1189 has_temporary_text_ = false; | |
1190 is_temporary_text_set_by_instant_ = false; | |
1191 OnPopupBoundsChanged(gfx::Rect()); | |
1192 delegate_->NotifySearchTabHelper(user_input_in_progress_, !in_revert_); | |
1193 } | |
1194 } | 1148 } |
1195 | 1149 |
1196 bool OmniboxEditModel::query_in_progress() const { | 1150 bool OmniboxEditModel::query_in_progress() const { |
1197 return !autocomplete_controller()->done(); | 1151 return !autocomplete_controller()->done(); |
1198 } | 1152 } |
1199 | 1153 |
1200 void OmniboxEditModel::InternalSetUserText(const string16& text) { | 1154 void OmniboxEditModel::InternalSetUserText(const string16& text) { |
1201 user_text_ = text; | 1155 user_text_ = text; |
1202 just_deleted_text_ = false; | 1156 just_deleted_text_ = false; |
1203 inline_autocomplete_text_.clear(); | 1157 inline_autocomplete_text_.clear(); |
1204 } | 1158 } |
1205 | 1159 |
1206 bool OmniboxEditModel::KeywordIsSelected() const { | 1160 bool OmniboxEditModel::KeywordIsSelected() const { |
1207 return !is_keyword_hint_ && !keyword_.empty(); | 1161 return !is_keyword_hint_ && !keyword_.empty(); |
1208 } | 1162 } |
1209 | 1163 |
1210 void OmniboxEditModel::ClearPopupKeywordMode() const { | |
1211 if (popup_->IsOpen() && | |
1212 popup_->selected_line_state() == OmniboxPopupModel::KEYWORD) | |
1213 popup_->SetSelectedLineState(OmniboxPopupModel::NORMAL); | |
1214 } | |
1215 | |
1216 string16 OmniboxEditModel::DisplayTextFromUserText(const string16& text) const { | 1164 string16 OmniboxEditModel::DisplayTextFromUserText(const string16& text) const { |
1217 return KeywordIsSelected() ? | 1165 return KeywordIsSelected() ? |
1218 KeywordProvider::SplitReplacementStringFromInput(text, false) : text; | 1166 KeywordProvider::SplitReplacementStringFromInput(text, false) : text; |
1219 } | 1167 } |
1220 | 1168 |
1221 string16 OmniboxEditModel::UserTextFromDisplayText(const string16& text) const { | 1169 string16 OmniboxEditModel::UserTextFromDisplayText(const string16& text) const { |
1222 return KeywordIsSelected() ? (keyword_ + char16(' ') + text) : text; | 1170 return KeywordIsSelected() ? (keyword_ + char16(' ') + text) : text; |
1223 } | 1171 } |
1224 | 1172 |
1225 void OmniboxEditModel::InfoForCurrentSelection(AutocompleteMatch* match, | |
1226 GURL* alternate_nav_url) const { | |
1227 DCHECK(match != NULL); | |
1228 const AutocompleteResult& result = this->result(); | |
1229 if (!autocomplete_controller()->done()) { | |
1230 // It's technically possible for |result| to be empty if no provider returns | |
1231 // a synchronous result but the query has not completed synchronously; | |
1232 // pratically, however, that should never actually happen. | |
1233 if (result.empty()) | |
1234 return; | |
1235 // The user cannot have manually selected a match, or the query would have | |
1236 // stopped. So the default match must be the desired selection. | |
1237 *match = *result.default_match(); | |
1238 } else { | |
1239 CHECK(popup_->IsOpen()); | |
1240 // If there are no results, the popup should be closed (so we should have | |
1241 // failed the CHECK above), and URLsForDefaultMatch() should have been | |
1242 // called instead. | |
1243 CHECK(!result.empty()); | |
1244 CHECK(popup_->selected_line() < result.size()); | |
1245 *match = result.match_at(popup_->selected_line()); | |
1246 } | |
1247 if (alternate_nav_url && popup_->manually_selected_match().empty()) | |
1248 *alternate_nav_url = result.alternate_nav_url(); | |
1249 } | |
1250 | |
1251 void OmniboxEditModel::GetInfoForCurrentText(AutocompleteMatch* match, | 1173 void OmniboxEditModel::GetInfoForCurrentText(AutocompleteMatch* match, |
1252 GURL* alternate_nav_url) const { | 1174 GURL* alternate_nav_url) const { |
1253 // If there's temporary text and it has been set by Instant, we won't find it | 1175 // If there's temporary text and it has been set by Instant, we won't find it |
1254 // in the popup model, so classify the text anew. | 1176 // in the popup model, so classify the text anew. |
1255 if ((popup_->IsOpen() || query_in_progress()) && | 1177 if ((popup_model()->IsOpen() || query_in_progress()) && |
1256 !is_temporary_text_set_by_instant_) { | 1178 !is_temporary_text_set_by_instant_) { |
1257 InfoForCurrentSelection(match, alternate_nav_url); | 1179 InfoForCurrentSelection(match, alternate_nav_url); |
1258 } else { | 1180 } else { |
1259 AutocompleteClassifierFactory::GetForProfile(profile_)->Classify( | 1181 AutocompleteClassifierFactory::GetForProfile(profile_)->Classify( |
1260 UserTextFromDisplayText(view_->GetText()), KeywordIsSelected(), true, | 1182 UserTextFromDisplayText(view_->GetText()), KeywordIsSelected(), true, |
1261 match, alternate_nav_url); | 1183 match, alternate_nav_url); |
1262 } | 1184 } |
1263 } | 1185 } |
1264 | 1186 |
1265 void OmniboxEditModel::RevertTemporaryText(bool revert_popup) { | 1187 void OmniboxEditModel::RevertTemporaryText(bool revert_popup) { |
(...skipping 17 matching lines...) Expand all Loading... |
1283 // The two "false" arguments make sure that our shenanigans don't cause any | 1205 // The two "false" arguments make sure that our shenanigans don't cause any |
1284 // previously saved selection to be erased nor OnChanged() to be called. | 1206 // previously saved selection to be erased nor OnChanged() to be called. |
1285 view_->OnTemporaryTextMaybeChanged(user_text_ + inline_autocomplete_text_, | 1207 view_->OnTemporaryTextMaybeChanged(user_text_ + inline_autocomplete_text_, |
1286 false, false); | 1208 false, false); |
1287 AutocompleteResult::const_iterator match(result().default_match()); | 1209 AutocompleteResult::const_iterator match(result().default_match()); |
1288 instant->OnCancel(match != result().end() ? *match : AutocompleteMatch(), | 1210 instant->OnCancel(match != result().end() ? *match : AutocompleteMatch(), |
1289 user_text_, | 1211 user_text_, |
1290 user_text_ + inline_autocomplete_text_); | 1212 user_text_ + inline_autocomplete_text_); |
1291 } | 1213 } |
1292 if (revert_popup) | 1214 if (revert_popup) |
1293 popup_->ResetToDefaultMatch(); | 1215 popup_model()->ResetToDefaultMatch(); |
1294 view_->OnRevertTemporaryText(); | 1216 view_->OnRevertTemporaryText(); |
1295 } | 1217 } |
1296 | 1218 |
1297 bool OmniboxEditModel::MaybeAcceptKeywordBySpace(const string16& new_text) { | 1219 bool OmniboxEditModel::MaybeAcceptKeywordBySpace(const string16& new_text) { |
1298 size_t keyword_length = new_text.length() - 1; | 1220 size_t keyword_length = new_text.length() - 1; |
1299 return (paste_state_ == NONE) && is_keyword_hint_ && !keyword_.empty() && | 1221 return (paste_state_ == NONE) && is_keyword_hint_ && !keyword_.empty() && |
1300 inline_autocomplete_text_.empty() && | 1222 inline_autocomplete_text_.empty() && |
1301 (keyword_.length() == keyword_length) && | 1223 (keyword_.length() == keyword_length) && |
1302 IsSpaceCharForAcceptingKeyword(new_text[keyword_length]) && | 1224 IsSpaceCharForAcceptingKeyword(new_text[keyword_length]) && |
1303 !new_text.compare(0, keyword_length, keyword_, 0, keyword_length) && | 1225 !new_text.compare(0, keyword_length, keyword_, 0, keyword_length) && |
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1354 // Remove "?" if we're in forced query mode. | 1276 // Remove "?" if we're in forced query mode. |
1355 AutocompleteInput::RemoveForcedQueryStringIfNecessary( | 1277 AutocompleteInput::RemoveForcedQueryStringIfNecessary( |
1356 autocomplete_controller()->input().type(), &user_text); | 1278 autocomplete_controller()->input().type(), &user_text); |
1357 AutocompleteInput::RemoveForcedQueryStringIfNecessary( | 1279 AutocompleteInput::RemoveForcedQueryStringIfNecessary( |
1358 autocomplete_controller()->input().type(), &full_text); | 1280 autocomplete_controller()->input().type(), &full_text); |
1359 | 1281 |
1360 size_t start, end; | 1282 size_t start, end; |
1361 view_->GetSelectionBounds(&start, &end); | 1283 view_->GetSelectionBounds(&start, &end); |
1362 | 1284 |
1363 return instant->Update(match, user_text, full_text, start, end, | 1285 return instant->Update(match, user_text, full_text, start, end, |
1364 UseVerbatimInstant(), user_input_in_progress_, popup_->IsOpen(), | 1286 UseVerbatimInstant(), user_input_in_progress_, popup_model()->IsOpen(), |
1365 in_escape_handler_, KeywordIsSelected()); | 1287 in_escape_handler_, KeywordIsSelected()); |
1366 } | 1288 } |
1367 | 1289 |
1368 void OmniboxEditModel::DoPreconnect(const AutocompleteMatch& match) { | |
1369 if (!match.destination_url.SchemeIs(extensions::kExtensionScheme)) { | |
1370 // Warm up DNS Prefetch cache, or preconnect to a search service. | |
1371 UMA_HISTOGRAM_ENUMERATION("Autocomplete.MatchType", match.type, | |
1372 AutocompleteMatch::NUM_TYPES); | |
1373 if (profile_->GetNetworkPredictor()) { | |
1374 profile_->GetNetworkPredictor()->AnticipateOmniboxUrl( | |
1375 match.destination_url, | |
1376 AutocompleteActionPredictor::IsPreconnectable(match)); | |
1377 } | |
1378 // We could prefetch the alternate nav URL, if any, but because there | |
1379 // can be many of these as a user types an initial series of characters, | |
1380 // the OS DNS cache could suffer eviction problems for minimal gain. | |
1381 } | |
1382 } | |
1383 | |
1384 // static | 1290 // static |
1385 bool OmniboxEditModel::IsSpaceCharForAcceptingKeyword(wchar_t c) { | 1291 bool OmniboxEditModel::IsSpaceCharForAcceptingKeyword(wchar_t c) { |
1386 switch (c) { | 1292 switch (c) { |
1387 case 0x0020: // Space | 1293 case 0x0020: // Space |
1388 case 0x3000: // Ideographic Space | 1294 case 0x3000: // Ideographic Space |
1389 return true; | 1295 return true; |
1390 default: | 1296 default: |
1391 return false; | 1297 return false; |
1392 } | 1298 } |
1393 } | 1299 } |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1425 instant->OmniboxFocusChanged(state, reason, NULL); | 1331 instant->OmniboxFocusChanged(state, reason, NULL); |
1426 | 1332 |
1427 // Update state and notify view if the omnibox has focus and the caret | 1333 // Update state and notify view if the omnibox has focus and the caret |
1428 // visibility changed. | 1334 // visibility changed. |
1429 const bool was_caret_visible = is_caret_visible(); | 1335 const bool was_caret_visible = is_caret_visible(); |
1430 focus_state_ = state; | 1336 focus_state_ = state; |
1431 if (focus_state_ != OMNIBOX_FOCUS_NONE && | 1337 if (focus_state_ != OMNIBOX_FOCUS_NONE && |
1432 is_caret_visible() != was_caret_visible) | 1338 is_caret_visible() != was_caret_visible) |
1433 view_->ApplyCaretVisibility(); | 1339 view_->ApplyCaretVisibility(); |
1434 } | 1340 } |
OLD | NEW |