| 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" |
| 11 #include "base/metrics/histogram.h" | 11 #include "base/metrics/histogram.h" |
| 12 #include "base/prefs/pref_service.h" | 12 #include "base/prefs/pref_service.h" |
| 13 #include "base/strings/string_number_conversions.h" | 13 #include "base/strings/string_number_conversions.h" |
| 14 #include "base/strings/string_util.h" | 14 #include "base/strings/string_util.h" |
| 15 #include "base/strings/stringprintf.h" | 15 #include "base/strings/stringprintf.h" |
| 16 #include "base/strings/utf_string_conversions.h" | 16 #include "base/strings/utf_string_conversions.h" |
| 17 #include "chrome/app/chrome_command_ids.h" | 17 #include "chrome/app/chrome_command_ids.h" |
| 18 #include "chrome/browser/autocomplete/autocomplete_classifier.h" | 18 #include "chrome/browser/autocomplete/autocomplete_classifier.h" |
| 19 #include "chrome/browser/autocomplete/autocomplete_classifier_factory.h" | 19 #include "chrome/browser/autocomplete/autocomplete_classifier_factory.h" |
| 20 #include "chrome/browser/autocomplete/autocomplete_input.h" | |
| 21 #include "chrome/browser/autocomplete/autocomplete_provider.h" | 20 #include "chrome/browser/autocomplete/autocomplete_provider.h" |
| 22 #include "chrome/browser/autocomplete/extension_app_provider.h" | 21 #include "chrome/browser/autocomplete/extension_app_provider.h" |
| 23 #include "chrome/browser/autocomplete/history_url_provider.h" | 22 #include "chrome/browser/autocomplete/history_url_provider.h" |
| 24 #include "chrome/browser/autocomplete/keyword_provider.h" | 23 #include "chrome/browser/autocomplete/keyword_provider.h" |
| 25 #include "chrome/browser/autocomplete/search_provider.h" | 24 #include "chrome/browser/autocomplete/search_provider.h" |
| 26 #include "chrome/browser/bookmarks/bookmark_stats.h" | 25 #include "chrome/browser/bookmarks/bookmark_stats.h" |
| 27 #include "chrome/browser/chrome_notification_types.h" | 26 #include "chrome/browser/chrome_notification_types.h" |
| 28 #include "chrome/browser/command_updater.h" | 27 #include "chrome/browser/command_updater.h" |
| 29 #include "chrome/browser/extensions/api/omnibox/omnibox_api.h" | 28 #include "chrome/browser/extensions/api/omnibox/omnibox_api.h" |
| 30 #include "chrome/browser/favicon/favicon_tab_helper.h" | 29 #include "chrome/browser/favicon/favicon_tab_helper.h" |
| (...skipping 137 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 168 | 167 |
| 169 // OmniboxEditModel::State ---------------------------------------------------- | 168 // OmniboxEditModel::State ---------------------------------------------------- |
| 170 | 169 |
| 171 OmniboxEditModel::State::State(bool user_input_in_progress, | 170 OmniboxEditModel::State::State(bool user_input_in_progress, |
| 172 const base::string16& user_text, | 171 const base::string16& user_text, |
| 173 const base::string16& gray_text, | 172 const base::string16& gray_text, |
| 174 const base::string16& keyword, | 173 const base::string16& keyword, |
| 175 bool is_keyword_hint, | 174 bool is_keyword_hint, |
| 176 bool url_replacement_enabled, | 175 bool url_replacement_enabled, |
| 177 OmniboxFocusState focus_state, | 176 OmniboxFocusState focus_state, |
| 178 FocusSource focus_source) | 177 FocusSource focus_source, |
| 178 const AutocompleteInput& autocomplete_input) |
| 179 : user_input_in_progress(user_input_in_progress), | 179 : user_input_in_progress(user_input_in_progress), |
| 180 user_text(user_text), | 180 user_text(user_text), |
| 181 gray_text(gray_text), | 181 gray_text(gray_text), |
| 182 keyword(keyword), | 182 keyword(keyword), |
| 183 is_keyword_hint(is_keyword_hint), | 183 is_keyword_hint(is_keyword_hint), |
| 184 url_replacement_enabled(url_replacement_enabled), | 184 url_replacement_enabled(url_replacement_enabled), |
| 185 focus_state(focus_state), | 185 focus_state(focus_state), |
| 186 focus_source(focus_source) { | 186 focus_source(focus_source), |
| 187 autocomplete_input(autocomplete_input) { |
| 187 } | 188 } |
| 188 | 189 |
| 189 OmniboxEditModel::State::~State() { | 190 OmniboxEditModel::State::~State() { |
| 190 } | 191 } |
| 191 | 192 |
| 192 | 193 |
| 193 // OmniboxEditModel ----------------------------------------------------------- | 194 // OmniboxEditModel ----------------------------------------------------------- |
| 194 | 195 |
| 195 OmniboxEditModel::OmniboxEditModel(OmniboxView* view, | 196 OmniboxEditModel::OmniboxEditModel(OmniboxView* view, |
| 196 OmniboxEditController* controller, | 197 OmniboxEditController* controller, |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 233 InternalSetUserText(user_text); | 234 InternalSetUserText(user_text); |
| 234 } | 235 } |
| 235 } | 236 } |
| 236 | 237 |
| 237 UMA_HISTOGRAM_BOOLEAN("Omnibox.SaveStateForTabSwitch.UserInputInProgress", | 238 UMA_HISTOGRAM_BOOLEAN("Omnibox.SaveStateForTabSwitch.UserInputInProgress", |
| 238 user_input_in_progress_); | 239 user_input_in_progress_); |
| 239 return State( | 240 return State( |
| 240 user_input_in_progress_, user_text_, view_->GetGrayTextAutocompletion(), | 241 user_input_in_progress_, user_text_, view_->GetGrayTextAutocompletion(), |
| 241 keyword_, is_keyword_hint_, | 242 keyword_, is_keyword_hint_, |
| 242 controller_->GetToolbarModel()->url_replacement_enabled(), | 243 controller_->GetToolbarModel()->url_replacement_enabled(), |
| 243 focus_state_, focus_source_); | 244 focus_state_, focus_source_, input_); |
| 244 } | 245 } |
| 245 | 246 |
| 246 void OmniboxEditModel::RestoreState(const State* state) { | 247 void OmniboxEditModel::RestoreState(const State* state) { |
| 247 // We need to update the permanent text correctly and revert the view | 248 // We need to update the permanent text correctly and revert the view |
| 248 // regardless of whether there is saved state. | 249 // regardless of whether there is saved state. |
| 249 controller_->GetToolbarModel()->set_url_replacement_enabled( | 250 controller_->GetToolbarModel()->set_url_replacement_enabled( |
| 250 !state || state->url_replacement_enabled); | 251 !state || state->url_replacement_enabled); |
| 251 permanent_text_ = controller_->GetToolbarModel()->GetText(); | 252 permanent_text_ = controller_->GetToolbarModel()->GetText(); |
| 252 // Don't muck with the search term replacement state, as we've just set it | 253 // Don't muck with the search term replacement state, as we've just set it |
| 253 // correctly. | 254 // correctly. |
| 254 view_->RevertWithoutResettingSearchTermReplacement(); | 255 view_->RevertWithoutResettingSearchTermReplacement(); |
| 256 // Restore the autocomplete controller's input, or clear it if this is a new |
| 257 // tab. |
| 258 input_ = state ? state->autocomplete_input : AutocompleteInput(); |
| 255 if (!state) | 259 if (!state) |
| 256 return; | 260 return; |
| 257 | 261 |
| 258 SetFocusState(state->focus_state, OMNIBOX_FOCUS_CHANGE_TAB_SWITCH); | 262 SetFocusState(state->focus_state, OMNIBOX_FOCUS_CHANGE_TAB_SWITCH); |
| 259 focus_source_ = state->focus_source; | 263 focus_source_ = state->focus_source; |
| 260 // Restore any user editing. | 264 // Restore any user editing. |
| 261 if (state->user_input_in_progress) { | 265 if (state->user_input_in_progress) { |
| 262 // NOTE: Be sure and set keyword-related state BEFORE invoking | 266 // NOTE: Be sure and set keyword-related state BEFORE invoking |
| 263 // DisplayTextFromUserText(), as its result depends upon this state. | 267 // DisplayTextFromUserText(), as its result depends upon this state. |
| 264 keyword_ = state->keyword; | 268 keyword_ = state->keyword; |
| 265 is_keyword_hint_ = state->is_keyword_hint; | 269 is_keyword_hint_ = state->is_keyword_hint; |
| 266 view_->SetUserText(state->user_text, | 270 view_->SetUserText(state->user_text, |
| 267 DisplayTextFromUserText(state->user_text), false); | 271 DisplayTextFromUserText(state->user_text), false); |
| 268 view_->SetGrayTextAutocompletion(state->gray_text); | 272 view_->SetGrayTextAutocompletion(state->gray_text); |
| 269 } | 273 } |
| 270 } | 274 } |
| 271 | 275 |
| 272 AutocompleteMatch OmniboxEditModel::CurrentMatch( | 276 AutocompleteMatch OmniboxEditModel::CurrentMatch( |
| 273 GURL* alternate_nav_url) const { | 277 GURL* alternate_nav_url) const { |
| 274 // If we have a valid match use it. Otherwise get one for the current text. | 278 // If we have a valid match use it. Otherwise get one for the current text. |
| 275 AutocompleteMatch match = omnibox_controller_->current_match(); | 279 AutocompleteMatch match = omnibox_controller_->current_match(); |
| 276 | 280 |
| 277 if (!match.destination_url.is_valid()) { | 281 if (!match.destination_url.is_valid()) { |
| 278 GetInfoForCurrentText(&match, alternate_nav_url); | 282 GetInfoForCurrentText(&match, alternate_nav_url); |
| 279 } else if (alternate_nav_url) { | 283 } else if (alternate_nav_url) { |
| 280 *alternate_nav_url = AutocompleteResult::ComputeAlternateNavUrl( | 284 *alternate_nav_url = AutocompleteResult::ComputeAlternateNavUrl( |
| 281 autocomplete_controller()->input(), match); | 285 input_, match); |
| 282 } | 286 } |
| 283 return match; | 287 return match; |
| 284 } | 288 } |
| 285 | 289 |
| 286 bool OmniboxEditModel::UpdatePermanentText() { | 290 bool OmniboxEditModel::UpdatePermanentText() { |
| 287 SearchProvider* search_provider = | 291 SearchProvider* search_provider = |
| 288 autocomplete_controller()->search_provider(); | 292 autocomplete_controller()->search_provider(); |
| 289 if (search_provider && delegate_->CurrentPageExists()) | 293 if (search_provider && delegate_->CurrentPageExists()) |
| 290 search_provider->set_current_page_url(delegate_->GetURL()); | 294 search_provider->set_current_page_url(delegate_->GetURL()); |
| 291 | 295 |
| (...skipping 238 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 530 view_->SetWindowTextAndCaretPos(permanent_text_, | 534 view_->SetWindowTextAndCaretPos(permanent_text_, |
| 531 has_focus() ? permanent_text_.length() : 0, | 535 has_focus() ? permanent_text_.length() : 0, |
| 532 false, true); | 536 false, true); |
| 533 AutocompleteActionPredictor* action_predictor = | 537 AutocompleteActionPredictor* action_predictor = |
| 534 predictors::AutocompleteActionPredictorFactory::GetForProfile(profile_); | 538 predictors::AutocompleteActionPredictorFactory::GetForProfile(profile_); |
| 535 action_predictor->ClearTransitionalMatches(); | 539 action_predictor->ClearTransitionalMatches(); |
| 536 } | 540 } |
| 537 | 541 |
| 538 void OmniboxEditModel::StartAutocomplete( | 542 void OmniboxEditModel::StartAutocomplete( |
| 539 bool has_selected_text, | 543 bool has_selected_text, |
| 540 bool prevent_inline_autocomplete) const { | 544 bool prevent_inline_autocomplete) { |
| 541 size_t cursor_position; | 545 size_t cursor_position; |
| 542 if (inline_autocomplete_text_.empty()) { | 546 if (inline_autocomplete_text_.empty()) { |
| 543 // Cursor position is equivalent to the current selection's end. | 547 // Cursor position is equivalent to the current selection's end. |
| 544 size_t start; | 548 size_t start; |
| 545 view_->GetSelectionBounds(&start, &cursor_position); | 549 view_->GetSelectionBounds(&start, &cursor_position); |
| 546 // Adjust cursor position taking into account possible keyword in the user | 550 // Adjust cursor position taking into account possible keyword in the user |
| 547 // text. We rely on DisplayTextFromUserText() method which is consistent | 551 // text. We rely on DisplayTextFromUserText() method which is consistent |
| 548 // with keyword extraction done in KeywordProvider/SearchProvider. | 552 // with keyword extraction done in KeywordProvider/SearchProvider. |
| 549 const size_t cursor_offset = | 553 const size_t cursor_offset = |
| 550 user_text_.length() - DisplayTextFromUserText(user_text_).length(); | 554 user_text_.length() - DisplayTextFromUserText(user_text_).length(); |
| 551 cursor_position += cursor_offset; | 555 cursor_position += cursor_offset; |
| 552 } else { | 556 } else { |
| 553 // There are some cases where StartAutocomplete() may be called | 557 // There are some cases where StartAutocomplete() may be called |
| 554 // with non-empty |inline_autocomplete_text_|. In such cases, we cannot | 558 // with non-empty |inline_autocomplete_text_|. In such cases, we cannot |
| 555 // use the current selection, because it could result with the cursor | 559 // use the current selection, because it could result with the cursor |
| 556 // position past the last character from the user text. Instead, | 560 // position past the last character from the user text. Instead, |
| 557 // we assume that the cursor is simply at the end of input. | 561 // we assume that the cursor is simply at the end of input. |
| 558 // One example is when user presses Ctrl key while having a highlighted | 562 // One example is when user presses Ctrl key while having a highlighted |
| 559 // inline autocomplete text. | 563 // inline autocomplete text. |
| 560 // TODO: Rethink how we are going to handle this case to avoid | 564 // TODO: Rethink how we are going to handle this case to avoid |
| 561 // inconsistent behavior when user presses Ctrl key. | 565 // inconsistent behavior when user presses Ctrl key. |
| 562 // See http://crbug.com/165961 and http://crbug.com/165968 for more details. | 566 // See http://crbug.com/165961 and http://crbug.com/165968 for more details. |
| 563 cursor_position = user_text_.length(); | 567 cursor_position = user_text_.length(); |
| 564 } | 568 } |
| 565 | 569 |
| 566 GURL current_url = | 570 GURL current_url = |
| 567 (delegate_->CurrentPageExists() && view_->IsIndicatingQueryRefinement()) ? | 571 (delegate_->CurrentPageExists() && view_->IsIndicatingQueryRefinement()) ? |
| 568 delegate_->GetURL() : GURL(); | 572 delegate_->GetURL() : GURL(); |
| 569 bool keyword_is_selected = KeywordIsSelected(); | 573 bool keyword_is_selected = KeywordIsSelected(); |
| 570 omnibox_controller_->StartAutocomplete( | 574 input_ = AutocompleteInput( |
| 571 user_text_, | 575 user_text_, |
| 572 cursor_position, | 576 cursor_position, |
| 577 base::string16(), |
| 573 current_url, | 578 current_url, |
| 574 ClassifyPage(), | 579 ClassifyPage(), |
| 575 prevent_inline_autocomplete || just_deleted_text_ || | 580 prevent_inline_autocomplete || just_deleted_text_ || |
| 576 (has_selected_text && inline_autocomplete_text_.empty()) || | 581 (has_selected_text && inline_autocomplete_text_.empty()) || |
| 577 (paste_state_ != NONE), | 582 (paste_state_ != NONE), |
| 578 keyword_is_selected, | 583 keyword_is_selected, |
| 579 keyword_is_selected || allow_exact_keyword_match_); | 584 keyword_is_selected || allow_exact_keyword_match_, |
| 585 true); |
| 586 |
| 587 omnibox_controller_->StartAutocomplete(input_); |
| 580 } | 588 } |
| 581 | 589 |
| 582 void OmniboxEditModel::StopAutocomplete() { | 590 void OmniboxEditModel::StopAutocomplete() { |
| 583 autocomplete_controller()->Stop(true); | 591 autocomplete_controller()->Stop(true); |
| 584 } | 592 } |
| 585 | 593 |
| 586 bool OmniboxEditModel::CanPasteAndGo(const base::string16& text) const { | 594 bool OmniboxEditModel::CanPasteAndGo(const base::string16& text) const { |
| 587 if (!view_->command_updater()->IsCommandEnabled(IDC_OPEN_CURRENT_URL)) | 595 if (!view_->command_updater()->IsCommandEnabled(IDC_OPEN_CURRENT_URL)) |
| 588 return false; | 596 return false; |
| 589 | 597 |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 623 if (control_key_state_ == DOWN_WITHOUT_CHANGE && !KeywordIsSelected() && | 631 if (control_key_state_ == DOWN_WITHOUT_CHANGE && !KeywordIsSelected() && |
| 624 autocomplete_controller()->history_url_provider()) { | 632 autocomplete_controller()->history_url_provider()) { |
| 625 // Generate a new AutocompleteInput, copying the latest one but using "com" | 633 // Generate a new AutocompleteInput, copying the latest one but using "com" |
| 626 // as the desired TLD. Then use this autocomplete input to generate a | 634 // as the desired TLD. Then use this autocomplete input to generate a |
| 627 // URL_WHAT_YOU_TYPED AutocompleteMatch. Note that using the most recent | 635 // URL_WHAT_YOU_TYPED AutocompleteMatch. Note that using the most recent |
| 628 // input instead of the currently visible text means we'll ignore any | 636 // input instead of the currently visible text means we'll ignore any |
| 629 // visible inline autocompletion: if a user types "foo" and is autocompleted | 637 // visible inline autocompletion: if a user types "foo" and is autocompleted |
| 630 // to "foodnetwork.com", ctrl-enter will navigate to "foo.com", not | 638 // to "foodnetwork.com", ctrl-enter will navigate to "foo.com", not |
| 631 // "foodnetwork.com". At the time of writing, this behavior matches | 639 // "foodnetwork.com". At the time of writing, this behavior matches |
| 632 // Internet Explorer, but not Firefox. | 640 // Internet Explorer, but not Firefox. |
| 633 const AutocompleteInput& old_input = autocomplete_controller()->input(); | 641 input_ = AutocompleteInput( |
| 634 AutocompleteInput input( | |
| 635 has_temporary_text_ ? | 642 has_temporary_text_ ? |
| 636 UserTextFromDisplayText(view_->GetText()) : old_input.text(), | 643 UserTextFromDisplayText(view_->GetText()) : input_.text(), |
| 637 old_input.cursor_position(), base::ASCIIToUTF16("com"), | 644 input_.cursor_position(), base::ASCIIToUTF16("com"), |
| 638 GURL(), old_input.current_page_classification(), | 645 GURL(), input_.current_page_classification(), |
| 639 old_input.prevent_inline_autocomplete(), old_input.prefer_keyword(), | 646 input_.prevent_inline_autocomplete(), input_.prefer_keyword(), |
| 640 old_input.allow_exact_keyword_match(), | 647 input_.allow_exact_keyword_match(), |
| 641 old_input.want_asynchronous_matches()); | 648 input_.want_asynchronous_matches()); |
| 642 AutocompleteMatch url_match( | 649 AutocompleteMatch url_match( |
| 643 autocomplete_controller()->history_url_provider()->SuggestExactInput( | 650 autocomplete_controller()->history_url_provider()->SuggestExactInput( |
| 644 input.text(), input.canonicalized_url(), false)); | 651 input_.text(), input_.canonicalized_url(), false)); |
| 652 |
| 645 | 653 |
| 646 if (url_match.destination_url.is_valid()) { | 654 if (url_match.destination_url.is_valid()) { |
| 647 // We have a valid URL, we use this newly generated AutocompleteMatch. | 655 // We have a valid URL, we use this newly generated AutocompleteMatch. |
| 648 match = url_match; | 656 match = url_match; |
| 649 alternate_nav_url = GURL(); | 657 alternate_nav_url = GURL(); |
| 650 } | 658 } |
| 651 } | 659 } |
| 652 | 660 |
| 653 if (!match.destination_url.is_valid()) | 661 if (!match.destination_url.is_valid()) |
| 654 return; | 662 return; |
| (...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 716 (match.provider->type() == AutocompleteProvider::TYPE_ZERO_SUGGEST)) { | 724 (match.provider->type() == AutocompleteProvider::TYPE_ZERO_SUGGEST)) { |
| 717 elapsed_time_since_user_first_modified_omnibox = | 725 elapsed_time_since_user_first_modified_omnibox = |
| 718 base::TimeDelta::FromMilliseconds(-1); | 726 base::TimeDelta::FromMilliseconds(-1); |
| 719 elapsed_time_since_last_change_to_default_match = | 727 elapsed_time_since_last_change_to_default_match = |
| 720 base::TimeDelta::FromMilliseconds(-1); | 728 base::TimeDelta::FromMilliseconds(-1); |
| 721 } | 729 } |
| 722 DCHECK_NE(OmniboxPopupModel::kNoMatch, index); | 730 DCHECK_NE(OmniboxPopupModel::kNoMatch, index); |
| 723 OmniboxLog log( | 731 OmniboxLog log( |
| 724 input_text, | 732 input_text, |
| 725 just_deleted_text_, | 733 just_deleted_text_, |
| 726 autocomplete_controller()->input().type(), | 734 input_.type(), |
| 727 index, | 735 index, |
| 728 -1, // don't yet know tab ID; set later if appropriate | 736 -1, // don't yet know tab ID; set later if appropriate |
| 729 ClassifyPage(), | 737 ClassifyPage(), |
| 730 elapsed_time_since_user_first_modified_omnibox, | 738 elapsed_time_since_user_first_modified_omnibox, |
| 731 match.inline_autocompletion.length(), | 739 match.inline_autocompletion.length(), |
| 732 elapsed_time_since_last_change_to_default_match, | 740 elapsed_time_since_last_change_to_default_match, |
| 733 result()); | 741 result()); |
| 734 | 742 |
| 735 DCHECK(user_input_in_progress_ || (match.provider && | 743 DCHECK(user_input_in_progress_ || (match.provider && |
| 736 (match.provider->type() == AutocompleteProvider::TYPE_ZERO_SUGGEST))) | 744 (match.provider->type() == AutocompleteProvider::TYPE_ZERO_SUGGEST))) |
| (...skipping 706 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1443 // Update state and notify view if the omnibox has focus and the caret | 1451 // Update state and notify view if the omnibox has focus and the caret |
| 1444 // visibility changed. | 1452 // visibility changed. |
| 1445 const bool was_caret_visible = is_caret_visible(); | 1453 const bool was_caret_visible = is_caret_visible(); |
| 1446 focus_state_ = state; | 1454 focus_state_ = state; |
| 1447 if (focus_state_ != OMNIBOX_FOCUS_NONE && | 1455 if (focus_state_ != OMNIBOX_FOCUS_NONE && |
| 1448 is_caret_visible() != was_caret_visible) | 1456 is_caret_visible() != was_caret_visible) |
| 1449 view_->ApplyCaretVisibility(); | 1457 view_->ApplyCaretVisibility(); |
| 1450 | 1458 |
| 1451 delegate_->OnFocusChanged(focus_state_, reason); | 1459 delegate_->OnFocusChanged(focus_state_, reason); |
| 1452 } | 1460 } |
| OLD | NEW |