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 |