Chromium Code Reviews| 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.h" | 5 #include "chrome/browser/autocomplete/autocomplete.h" |
| 6 | 6 |
| 7 #include <algorithm> | 7 #include <algorithm> |
| 8 #include <set> | |
| 9 #include <utility> | |
| 8 | 10 |
| 9 #include "base/basictypes.h" | 11 #include "base/basictypes.h" |
| 10 #include "base/command_line.h" | 12 #include "base/command_line.h" |
| 11 #include "base/i18n/number_formatting.h" | 13 #include "base/i18n/number_formatting.h" |
| 12 #include "base/metrics/histogram.h" | 14 #include "base/metrics/histogram.h" |
| 13 #include "base/string_number_conversions.h" | 15 #include "base/string_number_conversions.h" |
| 14 #include "base/string_util.h" | 16 #include "base/string_util.h" |
| 15 #include "base/utf_string_conversions.h" | 17 #include "base/utf_string_conversions.h" |
| 16 #include "chrome/browser/autocomplete/autocomplete_controller_delegate.h" | 18 #include "chrome/browser/autocomplete/autocomplete_controller_delegate.h" |
| 17 #include "chrome/browser/autocomplete/autocomplete_match.h" | 19 #include "chrome/browser/autocomplete/autocomplete_match.h" |
| 18 #include "chrome/browser/autocomplete/builtin_provider.h" | 20 #include "chrome/browser/autocomplete/builtin_provider.h" |
| 19 #include "chrome/browser/autocomplete/history_contents_provider.h" | 21 #include "chrome/browser/autocomplete/history_contents_provider.h" |
| 20 #include "chrome/browser/autocomplete/history_quick_provider.h" | 22 #include "chrome/browser/autocomplete/history_quick_provider.h" |
| 21 #include "chrome/browser/autocomplete/history_url_provider.h" | 23 #include "chrome/browser/autocomplete/history_url_provider.h" |
| 22 #include "chrome/browser/autocomplete/keyword_provider.h" | 24 #include "chrome/browser/autocomplete/keyword_provider.h" |
| 23 #include "chrome/browser/autocomplete/search_provider.h" | 25 #include "chrome/browser/autocomplete/search_provider.h" |
| 24 #include "chrome/browser/bookmarks/bookmark_model.h" | 26 #include "chrome/browser/bookmarks/bookmark_model.h" |
| 27 #include "chrome/browser/extensions/extension_service.h" | |
| 25 #include "chrome/browser/external_protocol_handler.h" | 28 #include "chrome/browser/external_protocol_handler.h" |
| 26 #include "chrome/browser/net/url_fixer_upper.h" | 29 #include "chrome/browser/net/url_fixer_upper.h" |
| 27 #include "chrome/browser/prefs/pref_service.h" | 30 #include "chrome/browser/prefs/pref_service.h" |
| 28 #include "chrome/browser/profiles/profile.h" | 31 #include "chrome/browser/profiles/profile.h" |
| 32 #include "chrome/browser/search_engines/template_url.h" | |
| 33 #include "chrome/browser/search_engines/template_url_model.h" | |
| 29 #include "chrome/browser/ui/webui/history_ui.h" | 34 #include "chrome/browser/ui/webui/history_ui.h" |
| 30 #include "chrome/common/chrome_switches.h" | 35 #include "chrome/common/chrome_switches.h" |
| 31 #include "chrome/common/pref_names.h" | 36 #include "chrome/common/pref_names.h" |
| 32 #include "chrome/common/url_constants.h" | 37 #include "chrome/common/url_constants.h" |
| 33 #include "content/common/notification_service.h" | 38 #include "content/common/notification_service.h" |
| 34 #include "googleurl/src/gurl.h" | 39 #include "googleurl/src/gurl.h" |
| 35 #include "googleurl/src/url_canon_ip.h" | 40 #include "googleurl/src/url_canon_ip.h" |
| 36 #include "googleurl/src/url_util.h" | 41 #include "googleurl/src/url_util.h" |
| 37 #include "grit/generated_resources.h" | 42 #include "grit/generated_resources.h" |
| 38 #include "grit/theme_resources.h" | 43 #include "grit/theme_resources.h" |
| (...skipping 595 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 634 std::upper_bound(begin(), end(), match, &AutocompleteMatch::MoreRelevant); | 639 std::upper_bound(begin(), end(), match, &AutocompleteMatch::MoreRelevant); |
| 635 ACMatches::iterator::difference_type default_offset = | 640 ACMatches::iterator::difference_type default_offset = |
| 636 default_match_ - begin(); | 641 default_match_ - begin(); |
| 637 if ((insertion_point - begin()) <= default_offset) | 642 if ((insertion_point - begin()) <= default_offset) |
| 638 ++default_offset; | 643 ++default_offset; |
| 639 matches_.insert(insertion_point, match); | 644 matches_.insert(insertion_point, match); |
| 640 default_match_ = begin() + default_offset; | 645 default_match_ = begin() + default_offset; |
| 641 } | 646 } |
| 642 | 647 |
| 643 void AutocompleteResult::SortAndCull(const AutocompleteInput& input) { | 648 void AutocompleteResult::SortAndCull(const AutocompleteInput& input) { |
| 649 for (ACMatches::iterator i = matches_.begin(); i != matches_.end(); ++i) | |
| 650 i->ComputeStrippedDestinationURL(); | |
| 651 | |
| 644 // Remove duplicates. | 652 // Remove duplicates. |
| 645 std::sort(matches_.begin(), matches_.end(), | 653 std::sort(matches_.begin(), matches_.end(), |
| 646 &AutocompleteMatch::DestinationSortFunc); | 654 &AutocompleteMatch::DestinationSortFunc); |
| 647 matches_.erase(std::unique(matches_.begin(), matches_.end(), | 655 matches_.erase(std::unique(matches_.begin(), matches_.end(), |
| 648 &AutocompleteMatch::DestinationsEqual), | 656 &AutocompleteMatch::DestinationsEqual), |
| 649 matches_.end()); | 657 matches_.end()); |
| 650 | 658 |
| 651 // Sort and trim to the most relevant kMaxMatches matches. | 659 // Sort and trim to the most relevant kMaxMatches matches. |
| 652 const size_t num_matches = std::min(kMaxMatches, matches_.size()); | 660 const size_t num_matches = std::min(kMaxMatches, matches_.size()); |
| 653 std::partial_sort(matches_.begin(), matches_.begin() + num_matches, | 661 std::partial_sort(matches_.begin(), matches_.begin() + num_matches, |
| (...skipping 123 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 777 // any copied entries. We do this from the time the user stopped typing as some | 785 // any copied entries. We do this from the time the user stopped typing as some |
| 778 // providers (such as SearchProvider) wait for the user to stop typing before | 786 // providers (such as SearchProvider) wait for the user to stop typing before |
| 779 // they initiate a query. | 787 // they initiate a query. |
| 780 static const int kExpireTimeMS = 500; | 788 static const int kExpireTimeMS = 500; |
| 781 | 789 |
| 782 AutocompleteController::AutocompleteController( | 790 AutocompleteController::AutocompleteController( |
| 783 Profile* profile, | 791 Profile* profile, |
| 784 AutocompleteControllerDelegate* delegate) | 792 AutocompleteControllerDelegate* delegate) |
| 785 : delegate_(delegate), | 793 : delegate_(delegate), |
| 786 done_(true), | 794 done_(true), |
| 787 in_start_(false) { | 795 in_start_(false), |
| 796 profile_(profile) { | |
| 788 search_provider_ = new SearchProvider(this, profile); | 797 search_provider_ = new SearchProvider(this, profile); |
| 789 providers_.push_back(search_provider_); | 798 providers_.push_back(search_provider_); |
| 790 if (!CommandLine::ForCurrentProcess()->HasSwitch( | 799 if (!CommandLine::ForCurrentProcess()->HasSwitch( |
| 791 switches::kDisableHistoryQuickProvider)) | 800 switches::kDisableHistoryQuickProvider)) |
| 792 providers_.push_back(new HistoryQuickProvider(this, profile)); | 801 providers_.push_back(new HistoryQuickProvider(this, profile)); |
| 793 if (!CommandLine::ForCurrentProcess()->HasSwitch( | 802 if (!CommandLine::ForCurrentProcess()->HasSwitch( |
| 794 switches::kDisableHistoryURLProvider)) | 803 switches::kDisableHistoryURLProvider)) |
| 795 providers_.push_back(new HistoryURLProvider(this, profile)); | 804 providers_.push_back(new HistoryURLProvider(this, profile)); |
| 796 providers_.push_back(new KeywordProvider(this, profile)); | 805 providers_.push_back(new KeywordProvider(this, profile)); |
| 797 providers_.push_back(new HistoryContentsProvider(this, profile)); | 806 providers_.push_back(new HistoryContentsProvider(this, profile)); |
| (...skipping 13 matching lines...) Expand all Loading... | |
| 811 Stop(false); | 820 Stop(false); |
| 812 | 821 |
| 813 for (ACProviders::iterator i(providers_.begin()); i != providers_.end(); ++i) | 822 for (ACProviders::iterator i(providers_.begin()); i != providers_.end(); ++i) |
| 814 (*i)->Release(); | 823 (*i)->Release(); |
| 815 | 824 |
| 816 providers_.clear(); // Not really necessary. | 825 providers_.clear(); // Not really necessary. |
| 817 } | 826 } |
| 818 | 827 |
| 819 void AutocompleteController::SetProfile(Profile* profile) { | 828 void AutocompleteController::SetProfile(Profile* profile) { |
| 820 Stop(true); | 829 Stop(true); |
| 830 profile_ = profile; | |
| 821 for (ACProviders::iterator i(providers_.begin()); i != providers_.end(); ++i) | 831 for (ACProviders::iterator i(providers_.begin()); i != providers_.end(); ++i) |
| 822 (*i)->SetProfile(profile); | 832 (*i)->SetProfile(profile); |
| 823 input_.Clear(); // Ensure we don't try to do a "minimal_changes" query on a | 833 input_.Clear(); // Ensure we don't try to do a "minimal_changes" query on a |
| 824 // different profile. | 834 // different profile. |
| 825 } | 835 } |
| 826 | 836 |
| 827 void AutocompleteController::Start( | 837 void AutocompleteController::Start( |
| 828 const string16& text, | 838 const string16& text, |
| 829 const string16& desired_tld, | 839 const string16& desired_tld, |
| 830 bool prevent_inline_autocomplete, | 840 bool prevent_inline_autocomplete, |
| (...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 923 AutocompleteResult last_result; | 933 AutocompleteResult last_result; |
| 924 last_result.Swap(&result_); | 934 last_result.Swap(&result_); |
| 925 | 935 |
| 926 for (ACProviders::const_iterator i(providers_.begin()); i != providers_.end(); | 936 for (ACProviders::const_iterator i(providers_.begin()); i != providers_.end(); |
| 927 ++i) | 937 ++i) |
| 928 result_.AppendMatches((*i)->matches()); | 938 result_.AppendMatches((*i)->matches()); |
| 929 | 939 |
| 930 // Sort the matches and trim to a small number of "best" matches. | 940 // Sort the matches and trim to a small number of "best" matches. |
| 931 result_.SortAndCull(input_); | 941 result_.SortAndCull(input_); |
| 932 | 942 |
| 943 std::set<string16> keywords; | |
| 944 for (ACMatches::iterator match(result_.begin()); match != result_.end(); | |
| 945 ++match) { | |
| 946 GetKeywordForMatch(&*match); | |
| 947 | |
| 948 if (match->keyword.get()) { | |
| 949 std::pair<std::set<string16>::iterator, bool> result = | |
| 950 keywords.insert(match->keyword->text); | |
| 951 | |
| 952 // If the match has a duplicate keyword with a | |
| 953 // more relevant match, don't show a hint. | |
| 954 if (match->keyword->is_keyword_hint && !result.second) { | |
| 955 match->keyword->is_keyword_hint = false; | |
| 956 match->keyword->text.clear(); | |
| 957 } | |
| 958 } | |
| 959 } | |
| 960 | |
| 933 // Need to validate before invoking CopyOldMatches as the old matches are not | 961 // Need to validate before invoking CopyOldMatches as the old matches are not |
| 934 // valid against the current input. | 962 // valid against the current input. |
| 935 #ifndef NDEBUG | 963 #ifndef NDEBUG |
| 936 result_.Validate(); | 964 result_.Validate(); |
| 937 #endif | 965 #endif |
| 938 | 966 |
| 939 if (!done_) { | 967 if (!done_) { |
| 940 // This conditional needs to match the conditional in Start that invokes | 968 // This conditional needs to match the conditional in Start that invokes |
| 941 // StartExpireTimer. | 969 // StartExpireTimer. |
| 942 result_.CopyOldMatches(input_, last_result); | 970 result_.CopyOldMatches(input_, last_result); |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 981 } | 1009 } |
| 982 } | 1010 } |
| 983 done_ = true; | 1011 done_ = true; |
| 984 } | 1012 } |
| 985 | 1013 |
| 986 void AutocompleteController::StartExpireTimer() { | 1014 void AutocompleteController::StartExpireTimer() { |
| 987 if (result_.HasCopiedMatches()) | 1015 if (result_.HasCopiedMatches()) |
| 988 expire_timer_.Start(base::TimeDelta::FromMilliseconds(kExpireTimeMS), | 1016 expire_timer_.Start(base::TimeDelta::FromMilliseconds(kExpireTimeMS), |
| 989 this, &AutocompleteController::ExpireCopiedEntries); | 1017 this, &AutocompleteController::ExpireCopiedEntries); |
| 990 } | 1018 } |
| 1019 | |
|
Peter Kasting
2011/04/07 20:19:21
Nit: Extra newline
| |
| 1020 | |
| 1021 void AutocompleteController::GetKeywordForMatch(AutocompleteMatch* match) const { | |
|
Peter Kasting
2011/04/07 20:19:21
Nit: Line too long; wrap after '('
| |
| 1022 // If the current match is a keyword, return that as the selected keyword. | |
| 1023 if (TemplateURL::SupportsReplacement(match->template_url)) { | |
| 1024 AutocompleteMatch::Keyword* keyword = new AutocompleteMatch::Keyword(); | |
| 1025 keyword->text.assign(match->template_url->keyword()); | |
| 1026 keyword->is_keyword_mode = true; | |
| 1027 match->keyword = keyword; | |
| 1028 return; | |
| 1029 } | |
| 1030 | |
| 1031 // See if the current match's fill_into_edit corresponds to a keyword. | |
| 1032 string16 keyword_text; | |
| 1033 if (GetKeywordForText(match->fill_into_edit, &keyword_text)) { | |
| 1034 AutocompleteMatch::Keyword* keyword = new AutocompleteMatch::Keyword(); | |
| 1035 keyword->is_keyword_hint = true; | |
| 1036 keyword->text = keyword_text; | |
| 1037 keyword->template_url = | |
| 1038 profile_->GetTemplateURLModel()->GetTemplateURLForKeyword(keyword_text); | |
| 1039 match->keyword = keyword; | |
| 1040 } | |
| 1041 } | |
| 1042 | |
| 1043 bool AutocompleteController::GetKeywordForText(const string16& text, | |
| 1044 string16* keyword) const { | |
| 1045 // Creates keyword_hint first in case |keyword| is a pointer to |text|. | |
| 1046 const string16 keyword_hint(TemplateURLModel::CleanUserInputKeyword(text)); | |
| 1047 | |
| 1048 // Assume we have no keyword until we find otherwise. | |
| 1049 keyword->clear(); | |
| 1050 | |
| 1051 if (keyword_hint.empty()) | |
| 1052 return false; | |
| 1053 if (!profile_->GetTemplateURLModel()) | |
| 1054 return false; | |
| 1055 profile_->GetTemplateURLModel()->Load(); | |
| 1056 | |
| 1057 // Don't provide a hint if this keyword doesn't support replacement. | |
| 1058 const TemplateURL* const template_url = | |
| 1059 profile_->GetTemplateURLModel()->GetTemplateURLForKeyword(keyword_hint); | |
| 1060 if (!TemplateURL::SupportsReplacement(template_url)) | |
| 1061 return false; | |
| 1062 | |
| 1063 // Don't provide a hint for inactive/disabled extension keywords. | |
| 1064 if (template_url->IsExtensionKeyword()) { | |
| 1065 const Extension* extension = profile_->GetExtensionService()-> | |
| 1066 GetExtensionById(template_url->GetExtensionId(), false); | |
| 1067 if (!extension || | |
|
Peter Kasting
2011/04/07 20:19:21
Nit: Indenting is one space short
| |
| 1068 (profile_->IsOffTheRecord() && | |
| 1069 !profile_->GetExtensionService()->IsIncognitoEnabled(extension->id()))) | |
| 1070 return false; | |
| 1071 } | |
| 1072 | |
| 1073 keyword->assign(keyword_hint); | |
| 1074 return true; | |
| 1075 } | |
|
Peter Kasting
2011/04/07 20:19:21
Nit: Make sure there's a newline character at the
| |
| OLD | NEW |