| OLD | NEW |
| 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 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/autocomplete/autocomplete_edit.h" | 5 #include "chrome/browser/autocomplete/autocomplete_edit.h" |
| 6 | 6 |
| 7 #include <string> | 7 #include <string> |
| 8 | 8 |
| 9 #include "base/basictypes.h" | 9 #include "base/basictypes.h" |
| 10 #include "base/metrics/histogram.h" | 10 #include "base/metrics/histogram.h" |
| (...skipping 364 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 375 keyword_.clear(); | 375 keyword_.clear(); |
| 376 is_keyword_hint_ = false; | 376 is_keyword_hint_ = false; |
| 377 has_temporary_text_ = false; | 377 has_temporary_text_ = false; |
| 378 view_->SetWindowTextAndCaretPos(permanent_text_, | 378 view_->SetWindowTextAndCaretPos(permanent_text_, |
| 379 has_focus_ ? permanent_text_.length() : 0); | 379 has_focus_ ? permanent_text_.length() : 0); |
| 380 } | 380 } |
| 381 | 381 |
| 382 void AutocompleteEditModel::StartAutocomplete( | 382 void AutocompleteEditModel::StartAutocomplete( |
| 383 bool has_selected_text, | 383 bool has_selected_text, |
| 384 bool prevent_inline_autocomplete) const { | 384 bool prevent_inline_autocomplete) const { |
| 385 ResetCurrentMatchKeywordMode(); |
| 386 |
| 385 bool keyword_is_selected = KeywordIsSelected(); | 387 bool keyword_is_selected = KeywordIsSelected(); |
| 386 popup_->SetHoveredLine(AutocompletePopupModel::kNoMatch); | 388 popup_->SetHoveredLine(AutocompletePopupModel::kNoMatch); |
| 387 // We don't explicitly clear AutocompletePopupModel::manually_selected_match, | 389 // We don't explicitly clear AutocompletePopupModel::manually_selected_match, |
| 388 // as Start ends up invoking AutocompletePopupModel::OnResultChanged which | 390 // as Start ends up invoking AutocompletePopupModel::OnResultChanged which |
| 389 // clears it. | 391 // clears it. |
| 390 autocomplete_controller_->Start( | 392 autocomplete_controller_->Start( |
| 391 user_text_, GetDesiredTLD(), | 393 user_text_, GetDesiredTLD(), |
| 392 prevent_inline_autocomplete || just_deleted_text_ || | 394 prevent_inline_autocomplete || just_deleted_text_ || |
| 393 (has_selected_text && inline_autocomplete_text_.empty()) || | 395 (has_selected_text && inline_autocomplete_text_.empty()) || |
| 394 (paste_state_ != NONE), keyword_is_selected, | 396 (paste_state_ != NONE), keyword_is_selected, |
| (...skipping 113 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 508 // these. | 510 // these. |
| 509 if (template_url && template_url->IsExtensionKeyword()) { | 511 if (template_url && template_url->IsExtensionKeyword()) { |
| 510 AutocompleteMatch current_match; | 512 AutocompleteMatch current_match; |
| 511 GetInfoForCurrentText(¤t_match, NULL); | 513 GetInfoForCurrentText(¤t_match, NULL); |
| 512 | 514 |
| 513 const AutocompleteMatch& match = | 515 const AutocompleteMatch& match = |
| 514 index == AutocompletePopupModel::kNoMatch ? | 516 index == AutocompletePopupModel::kNoMatch ? |
| 515 current_match : result().match_at(index); | 517 current_match : result().match_at(index); |
| 516 | 518 |
| 517 // Strip the keyword + leading space off the input. | 519 // Strip the keyword + leading space off the input. |
| 518 size_t prefix_length = match.template_url->keyword().size() + 1; | 520 size_t prefix_length = match.keyword_url->keyword().size() + 1; |
| 519 ExtensionOmniboxEventRouter::OnInputEntered( | 521 ExtensionOmniboxEventRouter::OnInputEntered( |
| 520 profile_, match.template_url->GetExtensionId(), | 522 profile_, match.keyword_url->GetExtensionId(), |
| 521 UTF16ToUTF8(match.fill_into_edit.substr(prefix_length))); | 523 UTF16ToUTF8(match.fill_into_edit.substr(prefix_length))); |
| 522 view_->RevertAll(); | 524 view_->RevertAll(); |
| 523 return; | 525 return; |
| 524 } | 526 } |
| 525 | 527 |
| 526 if (template_url) { | 528 if (template_url) { |
| 527 UserMetrics::RecordAction(UserMetricsAction("AcceptedKeyword"), profile_); | 529 UserMetrics::RecordAction(UserMetricsAction("AcceptedKeyword"), profile_); |
| 528 template_url_model->IncrementUsageCount(template_url); | 530 template_url_model->IncrementUsageCount(template_url); |
| 529 } | 531 } |
| 530 | 532 |
| (...skipping 10 matching lines...) Expand all Loading... |
| 541 | 543 |
| 542 InstantController* instant = controller_->GetInstant(); | 544 InstantController* instant = controller_->GetInstant(); |
| 543 if (instant && !popup_->IsOpen()) | 545 if (instant && !popup_->IsOpen()) |
| 544 instant->DestroyPreviewContents(); | 546 instant->DestroyPreviewContents(); |
| 545 update_instant_ = true; | 547 update_instant_ = true; |
| 546 } | 548 } |
| 547 | 549 |
| 548 bool AutocompleteEditModel::AcceptKeyword() { | 550 bool AutocompleteEditModel::AcceptKeyword() { |
| 549 DCHECK(is_keyword_hint_ && !keyword_.empty()); | 551 DCHECK(is_keyword_hint_ && !keyword_.empty()); |
| 550 | 552 |
| 551 view_->OnBeforePossibleChange(); | 553 autocomplete_controller_->Stop(false); |
| 552 view_->SetWindowTextAndCaretPos(string16(), 0); | |
| 553 is_keyword_hint_ = false; | 554 is_keyword_hint_ = false; |
| 554 view_->OnAfterPossibleChange(); | 555 |
| 555 just_deleted_text_ = false; // OnAfterPossibleChange() erroneously sets this | 556 if (popup_->IsOpen()) { |
| 556 // since the edit contents have disappeared. It | 557 AutocompleteMatch& match = const_cast<AutocompleteMatch&>(result(). |
| 557 // doesn't really matter, but we clear it to be | 558 match_at(popup_->selected_line())); |
| 558 // consistent. | 559 |
| 560 match.keyword_state = AutocompleteMatch::DUAL_SHOWING_KEYWORD; |
| 561 popup_->view()->InvalidateLine(popup_->selected_line()); |
| 562 } |
| 563 |
| 564 view_->SetUserText(string16(), string16(), false); |
| 565 |
| 559 UserMetrics::RecordAction(UserMetricsAction("AcceptedKeywordHint"), profile_); | 566 UserMetrics::RecordAction(UserMetricsAction("AcceptedKeywordHint"), profile_); |
| 560 return true; | 567 return true; |
| 561 } | 568 } |
| 562 | 569 |
| 563 void AutocompleteEditModel::ClearKeyword(const string16& visible_text) { | 570 void AutocompleteEditModel::ClearKeyword(const string16& visible_text) { |
| 564 view_->OnBeforePossibleChange(); | 571 autocomplete_controller_->Stop(false); |
| 572 ResetCurrentMatchKeywordMode(); |
| 573 |
| 565 const string16 window_text(keyword_ + visible_text); | 574 const string16 window_text(keyword_ + visible_text); |
| 566 view_->SetWindowTextAndCaretPos(window_text.c_str(), keyword_.length()); | 575 |
| 567 keyword_.clear(); | 576 // Only reset the result if the edit text has changed since the |
| 568 is_keyword_hint_ = false; | 577 // keyword was accepted. |
| 569 view_->OnAfterPossibleChange(); | 578 if (just_deleted_text_) { |
| 570 just_deleted_text_ = true; // OnAfterPossibleChange() fails to clear this | 579 view_->OnBeforePossibleChange(); |
| 571 // since the edit contents have actually grown | 580 view_->SetWindowTextAndCaretPos(window_text.c_str(), keyword_.length()); |
| 572 // longer. | 581 keyword_.clear(); |
| 582 is_keyword_hint_ = false; |
| 583 view_->OnAfterPossibleChange(); |
| 584 just_deleted_text_ = true; // OnAfterPossibleChange() fails to clear this |
| 585 // since the edit contents have actually grown |
| 586 // longer. |
| 587 } else { |
| 588 view_->SetUserText(window_text, window_text, false); |
| 589 |
| 590 is_keyword_hint_ = visible_text.empty(); |
| 591 if (!is_keyword_hint_) |
| 592 keyword_.clear(); |
| 593 |
| 594 OnChanged(); |
| 595 } |
| 596 } |
| 597 |
| 598 void AutocompleteEditModel::ResetCurrentMatchKeywordMode() const { |
| 599 if (popup_->IsOpen()) { |
| 600 AutocompleteMatch& match = const_cast<AutocompleteMatch&>(result(). |
| 601 match_at(popup_->selected_line())); |
| 602 |
| 603 if (match.keyword_state == AutocompleteMatch::DUAL_SHOWING_KEYWORD) { |
| 604 match.keyword_state = AutocompleteMatch::DUAL_SHOWING_NON_KEYWORD; |
| 605 popup_->view()->InvalidateLine(popup_->selected_line()); |
| 606 } |
| 607 } |
| 573 } | 608 } |
| 574 | 609 |
| 575 const AutocompleteResult& AutocompleteEditModel::result() const { | 610 const AutocompleteResult& AutocompleteEditModel::result() const { |
| 576 return autocomplete_controller_->result(); | 611 return autocomplete_controller_->result(); |
| 577 } | 612 } |
| 578 | 613 |
| 579 void AutocompleteEditModel::OnSetFocus(bool control_down) { | 614 void AutocompleteEditModel::OnSetFocus(bool control_down) { |
| 580 has_focus_ = true; | 615 has_focus_ = true; |
| 581 control_key_state_ = control_down ? DOWN_WITHOUT_CHANGE : UP; | 616 control_key_state_ = control_down ? DOWN_WITHOUT_CHANGE : UP; |
| 582 NotificationService::current()->Notify( | 617 NotificationService::current()->Notify( |
| (...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 661 if (!user_input_in_progress_) | 696 if (!user_input_in_progress_) |
| 662 InternalSetUserText(permanent_text_); | 697 InternalSetUserText(permanent_text_); |
| 663 view_->UpdatePopup(); | 698 view_->UpdatePopup(); |
| 664 } else { | 699 } else { |
| 665 // TODO(pkasting): The popup is working on a query but is not open. We | 700 // TODO(pkasting): The popup is working on a query but is not open. We |
| 666 // should force it to open immediately. | 701 // should force it to open immediately. |
| 667 } | 702 } |
| 668 } else { | 703 } else { |
| 669 // The popup is open, so the user should be able to interact with it | 704 // The popup is open, so the user should be able to interact with it |
| 670 // normally. | 705 // normally. |
| 706 if (popup_->IsOpen()) { |
| 707 AutocompleteMatch match = CurrentMatch(); |
| 708 |
| 709 if (match.keyword_state == AutocompleteMatch::DUAL_SHOWING_KEYWORD) |
| 710 ClearKeyword(string16()); |
| 711 } |
| 712 |
| 671 popup_->Move(count); | 713 popup_->Move(count); |
| 672 } | 714 } |
| 673 } | 715 } |
| 674 | 716 |
| 675 void AutocompleteEditModel::OnPopupDataChanged( | 717 void AutocompleteEditModel::OnPopupDataChanged( |
| 676 const string16& text, | 718 const string16& text, |
| 677 GURL* destination_for_temporary_text_change, | 719 GURL* destination_for_temporary_text_change, |
| 678 const string16& keyword, | 720 const string16& keyword, |
| 679 bool is_keyword_hint) { | 721 bool is_keyword_hint) { |
| 680 // Update keyword/hint-related local state. | 722 // Update keyword/hint-related local state. |
| (...skipping 165 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 846 if (!match->destination_url.SchemeIs(chrome::kExtensionScheme)) { | 888 if (!match->destination_url.SchemeIs(chrome::kExtensionScheme)) { |
| 847 // Warm up DNS Prefetch cache, or preconnect to a search service. | 889 // Warm up DNS Prefetch cache, or preconnect to a search service. |
| 848 chrome_browser_net::AnticipateOmniboxUrl(match->destination_url, | 890 chrome_browser_net::AnticipateOmniboxUrl(match->destination_url, |
| 849 IsPreconnectable(match->type)); | 891 IsPreconnectable(match->type)); |
| 850 } | 892 } |
| 851 | 893 |
| 852 // We could prefetch the alternate nav URL, if any, but because there | 894 // We could prefetch the alternate nav URL, if any, but because there |
| 853 // can be many of these as a user types an initial series of characters, | 895 // can be many of these as a user types an initial series of characters, |
| 854 // the OS DNS cache could suffer eviction problems for minimal gain. | 896 // the OS DNS cache could suffer eviction problems for minimal gain. |
| 855 | 897 |
| 856 is_keyword_hint = popup_->GetKeywordForMatch(*match, &keyword); | 898 keyword = match->keyword; |
| 899 is_keyword_hint = match->has_keyword_hint(); |
| 857 } | 900 } |
| 901 |
| 858 popup_->OnResultChanged(); | 902 popup_->OnResultChanged(); |
| 859 OnPopupDataChanged(inline_autocomplete_text, NULL, keyword, | 903 OnPopupDataChanged(inline_autocomplete_text, NULL, keyword, |
| 860 is_keyword_hint); | 904 is_keyword_hint); |
| 861 } else { | 905 } else { |
| 862 popup_->OnResultChanged(); | 906 popup_->OnResultChanged(); |
| 863 } | 907 } |
| 864 | 908 |
| 865 if (popup_->IsOpen()) { | 909 if (popup_->IsOpen()) { |
| 866 PopupBoundsChangedTo(popup_->view()->GetTargetBounds()); | 910 PopupBoundsChangedTo(popup_->view()->GetTargetBounds()); |
| 867 } else if (was_open) { | 911 } else if (was_open) { |
| (...skipping 123 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 991 old_user_text.length() - caret_position + 1)) { | 1035 old_user_text.length() - caret_position + 1)) { |
| 992 return false; | 1036 return false; |
| 993 } | 1037 } |
| 994 | 1038 |
| 995 // Then check if the text before the inserted space matches a keyword. | 1039 // Then check if the text before the inserted space matches a keyword. |
| 996 string16 keyword; | 1040 string16 keyword; |
| 997 TrimWhitespace(new_user_text.substr(0, caret_position - 1), | 1041 TrimWhitespace(new_user_text.substr(0, caret_position - 1), |
| 998 TRIM_LEADING, &keyword); | 1042 TRIM_LEADING, &keyword); |
| 999 | 1043 |
| 1000 // Only allow exact keyword match if |keyword| represents a keyword hint. | 1044 // Only allow exact keyword match if |keyword| represents a keyword hint. |
| 1001 return keyword.length() && popup_->GetKeywordForText(keyword, &keyword); | 1045 return keyword.length() && |
| 1046 !autocomplete_controller_->GetKeywordForText(keyword).empty(); |
| 1002 } | 1047 } |
| 1003 | 1048 |
| 1004 // static | 1049 // static |
| 1005 bool AutocompleteEditModel::IsSpaceCharForAcceptingKeyword(wchar_t c) { | 1050 bool AutocompleteEditModel::IsSpaceCharForAcceptingKeyword(wchar_t c) { |
| 1006 switch (c) { | 1051 switch (c) { |
| 1007 case 0x0020: // Space | 1052 case 0x0020: // Space |
| 1008 case 0x3000: // Ideographic Space | 1053 case 0x3000: // Ideographic Space |
| 1009 return true; | 1054 return true; |
| 1010 default: | 1055 default: |
| 1011 return false; | 1056 return false; |
| 1012 } | 1057 } |
| 1013 } | 1058 } |
| OLD | NEW |