diff options
author | sky@chromium.org <sky@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-04-14 17:16:24 +0000 |
---|---|---|
committer | sky@chromium.org <sky@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-04-14 17:16:24 +0000 |
commit | 257ab718488a1cdb46a2423464e17933c8339a01 (patch) | |
tree | b36111115dd00a00da78113758424603b45cb818 /chrome | |
parent | 3f85caafb239d5725ec85af9b8ce9f1b1de15770 (diff) | |
download | chromium_src-257ab718488a1cdb46a2423464e17933c8339a01.zip chromium_src-257ab718488a1cdb46a2423464e17933c8339a01.tar.gz chromium_src-257ab718488a1cdb46a2423464e17933c8339a01.tar.bz2 |
Makes the omnibox show past searches and suggestions for keywords.
We talked about primary and secondary, but after doing it all I felt
keyword and default better portrayed what is going on.
After trying this out I think we need to tune relevancy. But that
can be done later
BUG=3636
TEST=make sure omnibox isn't broken.
Review URL: http://codereview.chromium.org/66073
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@13668 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome')
-rw-r--r-- | chrome/browser/autocomplete/autocomplete.h | 61 | ||||
-rw-r--r-- | chrome/browser/autocomplete/autocomplete_popup_model.cc | 6 | ||||
-rw-r--r-- | chrome/browser/autocomplete/keyword_provider.cc | 44 | ||||
-rw-r--r-- | chrome/browser/autocomplete/keyword_provider.h | 19 | ||||
-rw-r--r-- | chrome/browser/autocomplete/search_provider.cc | 395 | ||||
-rw-r--r-- | chrome/browser/autocomplete/search_provider.h | 176 | ||||
-rw-r--r-- | chrome/browser/importer/importer.cc | 3 | ||||
-rw-r--r-- | chrome/browser/search_engines/template_url.cc | 5 | ||||
-rw-r--r-- | chrome/browser/search_engines/template_url.h | 4 | ||||
-rw-r--r-- | chrome/browser/views/keyword_editor_view.cc | 2 |
10 files changed, 526 insertions, 189 deletions
diff --git a/chrome/browser/autocomplete/autocomplete.h b/chrome/browser/autocomplete/autocomplete.h index 6f84f02..4ff9394 100644 --- a/chrome/browser/autocomplete/autocomplete.h +++ b/chrome/browser/autocomplete/autocomplete.h @@ -45,35 +45,43 @@ // --------------------------------------------------------------------|----- // Keyword (non-substituting or in keyword UI mode, exact match) | 1500 // HistoryURL (exact or inline autocomplete match) | 1400 -// Search (what you typed) | 1300 +// Search Primary Provider (what you typed) | 1300 // HistoryURL (what you typed) | 1200 // Keyword (substituting, exact match) | 1100 -// Search (past query in history) | 1050-- +// Search Primary Provider (past query in history) | 1050-- // HistoryContents (any match in title of starred page) | 1000++ // HistoryURL (inexact match) | 900++ -// Search (navigational suggestion) | 800++ +// Search Primary Provider (navigational suggestion) | 800++ // HistoryContents (any match in title of nonstarred page) | 700++ -// Search (suggestion) | 600++ +// Search Primary Provider (suggestion) | 600++ // HistoryContents (any match in body of starred page) | 550++ // HistoryContents (any match in body of nonstarred page) | 500++ // Keyword (inexact match) | 450 +// Search Secondary Provider (what you typed) | 250 +// Search Secondary Provider (past query in history) | 200-- +// Search Secondary Provider (navigational suggestion) | 150++ +// Search Secondary Provider (suggestion) | 100++ // // REQUESTED_URL input type: // --------------------------------------------------------------------|----- // Keyword (non-substituting or in keyword UI mode, exact match) | 1500 // HistoryURL (exact or inline autocomplete match) | 1400 // HistoryURL (what you typed) | 1300 -// Search (what you typed) | 1200 +// Search Primary Provider (what you typed) | 1200 // Keyword (substituting, exact match) | 1100 -// Search (past query in history) | 1050-- +// Search Primary Provider (past query in history) | 1050-- // HistoryContents (any match in title of starred page) | 1000++ // HistoryURL (inexact match) | 900++ -// Search (navigational suggestion) | 800++ +// Search Primary Provider (navigational suggestion) | 800++ // HistoryContents (any match in title of nonstarred page) | 700++ -// Search (suggestion) | 600++ +// Search Primary Provider (suggestion) | 600++ // HistoryContents (any match in body of starred page) | 550++ // HistoryContents (any match in body of nonstarred page) | 500++ // Keyword (inexact match) | 450 +// Search Secondary Provider (what you typed) | 250 +// Search Secondary Provider (past query in history) | 200-- +// Search Secondary Provider (navigational suggestion) | 150++ +// Search Secondary Provider (suggestion) | 100++ // // URL input type: // --------------------------------------------------------------------|----- @@ -82,40 +90,53 @@ // HistoryURL (what you typed) | 1200 // Keyword (substituting, exact match) | 1100 // HistoryURL (inexact match) | 900++ -// Search (what you typed) | 850 -// Search (navigational suggestion) | 800++ -// Search (past query in history) | 750-- +// Search Primary Provider (what you typed) | 850 +// Search Primary Provider (navigational suggestion) | 800++ +// Search Primary Provider (past query in history) | 750-- // Keyword (inexact match) | 700 -// Search (suggestion) | 300++ +// Search Primary Provider (suggestion) | 300++ +// Search Secondary Provider (what you typed) | 250 +// Search Secondary Provider (past query in history) | 200-- +// Search Secondary Provider (navigational suggestion) | 150++ +// Search Secondary Provider (suggestion) | 100++ // // QUERY input type: // --------------------------------------------------------------------|----- // Keyword (non-substituting or in keyword UI mode, exact match) | 1500 // Keyword (substituting, exact match) | 1400 -// Search (what you typed) | 1300 -// Search (past query in history) | 1250-- +// Search Primary Provider (what you typed) | 1300 +// Search Primary Provider (past query in history) | 1250-- // HistoryContents (any match in title of starred page) | 1200++ -// Search (navigational suggestion) | 1000++ +// Search Primary Provider (navigational suggestion) | 1000++ // HistoryContents (any match in title of nonstarred page) | 900++ -// Search (suggestion) | 800++ +// Search Primary Provider (suggestion) | 800++ // HistoryContents (any match in body of starred page) | 750++ // HistoryContents (any match in body of nonstarred page) | 700++ // Keyword (inexact match) | 650 +// Search Secondary Provider (what you typed) | 250 +// Search Secondary Provider (past query in history) | 200-- +// Search Secondary Provider (navigational suggestion) | 150++ +// Search Secondary Provider (suggestion) | 100++ // // FORCED_QUERY input type: // --------------------------------------------------------------------|----- -// Search (what you typed) | 1500 -// Search (past query in history) | 1250-- +// Search Primary Provider (what you typed) | 1500 +// Search Primary Provider (past query in history) | 1250-- // HistoryContents (any match in title of starred page) | 1200++ -// Search (navigational suggestion) | 1000++ +// Search Primary Provider (navigational suggestion) | 1000++ // HistoryContents (any match in title of nonstarred page) | 900++ -// Search (suggestion) | 800++ +// Search Primary Provider (suggestion) | 800++ // HistoryContents (any match in body of starred page) | 750++ // HistoryContents (any match in body of nonstarred page) | 700++ // // (A search keyword is a keyword with a replacement string; a bookmark keyword // is a keyword with no replacement string, that is, a shortcut for a URL.) // +// There are two possible providers for search suggestions. If the user has +// typed a keyword, then the primary provider is the keyword provider and the +// secondary provider is the default provider. If the user has not typed a +// keyword, then the primary provider corresponds to the default provider. +// // The value column gives the ranking returned from the various providers. // ++: a series of results with relevance from n up to (n + max_matches). // --: relevance score falls off over time (discounted 50 points @ 15 minutes, diff --git a/chrome/browser/autocomplete/autocomplete_popup_model.cc b/chrome/browser/autocomplete/autocomplete_popup_model.cc index 8cc5ced..46bd01c 100644 --- a/chrome/browser/autocomplete/autocomplete_popup_model.cc +++ b/chrome/browser/autocomplete/autocomplete_popup_model.cc @@ -212,8 +212,7 @@ bool AutocompletePopupModel::GetKeywordForMatch(const AutocompleteMatch& match, keyword->clear(); // If the current match is a keyword, return that as the selected keyword. - if (match.template_url && match.template_url->url() && - match.template_url->url()->SupportsReplacement()) { + if (TemplateURL::SupportsReplacement(match.template_url)) { keyword->assign(match.template_url->keyword()); return false; } @@ -230,8 +229,7 @@ bool AutocompletePopupModel::GetKeywordForMatch(const AutocompleteMatch& match, // Don't provide a hint if this keyword doesn't support replacement. const TemplateURL* const template_url = profile_->GetTemplateURLModel()->GetTemplateURLForKeyword(keyword_hint); - if (!template_url || !template_url->url() || - !template_url->url()->SupportsReplacement()) + if (!TemplateURL::SupportsReplacement(template_url)) return false; keyword->assign(keyword_hint); diff --git a/chrome/browser/autocomplete/keyword_provider.cc b/chrome/browser/autocomplete/keyword_provider.cc index 92ee1de..67f4edd 100644 --- a/chrome/browser/autocomplete/keyword_provider.cc +++ b/chrome/browser/autocomplete/keyword_provider.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. +// Copyright (c) 2009 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -61,14 +61,29 @@ class CompareQuality { } // namespace +// static +const TemplateURL* KeywordProvider::GetSubstitutingTemplateURLForInput( + Profile* profile, + const AutocompleteInput& input, + std::wstring* remaining_input) { + std::wstring keyword; + if (!ExtractKeywordFromInput(input, &keyword, remaining_input)) + return NULL; + + // Make sure the model is loaded. This is cheap and quickly bails out if + // the model is already loaded. + TemplateURLModel* model = profile->GetTemplateURLModel(); + DCHECK(model); + model->Load(); + + const TemplateURL* template_url = model->GetTemplateURLForKeyword(keyword); + return TemplateURL::SupportsReplacement(template_url) ? template_url : NULL; +} + void KeywordProvider::Start(const AutocompleteInput& input, bool minimal_changes) { matches_.clear(); - if ((input.type() == AutocompleteInput::INVALID) || - (input.type() == AutocompleteInput::FORCED_QUERY)) - return; - // Split user input into a keyword and some query input. // // We want to suggest keywords even when users have started typing URLs, on @@ -82,10 +97,8 @@ void KeywordProvider::Start(const AutocompleteInput& input, // keywords, we might suggest keywords that haven't even been partially typed, // if the user uses them enough and isn't obviously typing something else. In // this case we'd consider all input here to be query input. - std::wstring remaining_input; - std::wstring keyword(TemplateURLModel::CleanUserInputKeyword( - SplitKeywordFromInput(input.text(), &remaining_input))); - if (keyword.empty()) + std::wstring keyword, remaining_input; + if (!ExtractKeywordFromInput(input, &keyword, &remaining_input)) return; // Make sure the model is loaded. This is cheap and quickly bails out if @@ -134,6 +147,19 @@ void KeywordProvider::Start(const AutocompleteInput& input, } // static +bool KeywordProvider::ExtractKeywordFromInput(const AutocompleteInput& input, + std::wstring* keyword, + std::wstring* remaining_input) { + if ((input.type() == AutocompleteInput::INVALID) || + (input.type() == AutocompleteInput::FORCED_QUERY)) + return false; + + *keyword = TemplateURLModel::CleanUserInputKeyword( + SplitKeywordFromInput(input.text(), remaining_input)); + return !keyword->empty(); +} + +// static std::wstring KeywordProvider::SplitKeywordFromInput( const std::wstring& input, std::wstring* remaining_input) { diff --git a/chrome/browser/autocomplete/keyword_provider.h b/chrome/browser/autocomplete/keyword_provider.h index 4c8acc7..6caa2b1 100644 --- a/chrome/browser/autocomplete/keyword_provider.h +++ b/chrome/browser/autocomplete/keyword_provider.h @@ -1,4 +1,4 @@ -// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. +// Copyright (c) 2009 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // @@ -57,11 +57,28 @@ class KeywordProvider : public AutocompleteProvider { static std::wstring SplitReplacementStringFromInput( const std::wstring& input); + // Returns the matching substituting keyword for |input|, or NULL if there + // is no keyword for the specified input. + static const TemplateURL* GetSubstitutingTemplateURLForInput( + Profile* profile, + const AutocompleteInput& input, + std::wstring* remaining_input); + // AutocompleteProvider virtual void Start(const AutocompleteInput& input, bool minimal_changes); private: + // Extracts the keyword from |input| into |keyword|. Any remaining characters + // after the keyword are placed in |remaining_input|. Returns true if |input| + // is valid and has a keyword. This makes use of SplitKeywordFromInput to + // extract the keyword and remaining string, and uses + // TemplateURLModel::CleanUserInputKeyword to remove unnecessary characters. + // In general use this instead of SplitKeywordFromInput. + static bool ExtractKeywordFromInput(const AutocompleteInput& input, + std::wstring* keyword, + std::wstring* remaining_input); + // Extracts the next whitespace-delimited token from input and returns it. // Sets |remaining_input| to everything after the first token (skipping over // intervening whitespace). diff --git a/chrome/browser/autocomplete/search_provider.cc b/chrome/browser/autocomplete/search_provider.cc index d462480..1c1dccdf 100644 --- a/chrome/browser/autocomplete/search_provider.cc +++ b/chrome/browser/autocomplete/search_provider.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. +// Copyright (c) 2009 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -6,6 +6,7 @@ #include "base/message_loop.h" #include "base/string_util.h" +#include "chrome/browser/autocomplete/keyword_provider.h" #include "chrome/browser/browser_process.h" #include "chrome/browser/google_util.h" #include "chrome/browser/net/url_fixer_upper.h" @@ -25,6 +26,19 @@ using base::Time; using base::TimeDelta; +void SearchProvider::Providers::Set(const TemplateURL* default_provider, + const TemplateURL* keyword_provider) { + // TODO(pkasting): http://b/1162970 We shouldn't need to structure-copy + // this. Nor should we need |default_provider_| and |keyword_provider_| + // just to know whether the provider changed. + default_provider_ = default_provider; + if (default_provider) + cached_default_provider_ = *default_provider; + keyword_provider_ = keyword_provider; + if (keyword_provider) + cached_keyword_provider_ = *keyword_provider; +} + void SearchProvider::Start(const AutocompleteInput& input, bool minimal_changes) { matches_.clear(); @@ -35,42 +49,53 @@ void SearchProvider::Start(const AutocompleteInput& input, return; } - // Can't search without a default provider. - const TemplateURL* const current_default_provider = + keyword_input_text_.clear(); + const TemplateURL* keyword_provider = + KeywordProvider::GetSubstitutingTemplateURLForInput(profile_, input, + &keyword_input_text_); + if (!TemplateURL::SupportsReplacement(keyword_provider) || + keyword_input_text_.empty()) { + keyword_provider = NULL; + } + + const TemplateURL* default_provider = profile_->GetTemplateURLModel()->GetDefaultSearchProvider(); - // TODO(pkasting): http://b/1155786 Eventually we should not need all these - // checks. - if (!current_default_provider || !current_default_provider->url() || - !current_default_provider->url()->SupportsReplacement()) { + if (!TemplateURL::SupportsReplacement(default_provider)) + default_provider = NULL; + + if (keyword_provider == default_provider) + keyword_provider = NULL; // No use in querying the same provider twice. + + if (!default_provider && !keyword_provider) { + // No valid providers. Stop(); return; } // If we're still running an old query but have since changed the query text - // or the default provider, abort the query. + // or the providers, abort the query. if (!done_ && (!minimal_changes || - (last_default_provider_ != current_default_provider))) + !providers_.equals(default_provider, keyword_provider))) { Stop(); + } - // TODO(pkasting): http://b/1162970 We shouldn't need to structure-copy this. - // Nor should we need |last_default_provider_| just to know whether the - // provider changed. - default_provider_ = *current_default_provider; - last_default_provider_ = current_default_provider; + providers_.Set(default_provider, keyword_provider); if (input.text().empty()) { // User typed "?" alone. Give them a placeholder result indicating what // this syntax does. - AutocompleteMatch match(this, 0, false, - AutocompleteMatch::SEARCH_WHAT_YOU_TYPED); - static const std::wstring kNoQueryInput( - l10n_util::GetString(IDS_AUTOCOMPLETE_NO_QUERY)); - match.contents.assign(l10n_util::GetStringF( - IDS_AUTOCOMPLETE_SEARCH_CONTENTS, default_provider_.short_name(), - kNoQueryInput)); - match.contents_class.push_back( - ACMatchClassification(0, ACMatchClassification::DIM)); - matches_.push_back(match); + if (default_provider) { + AutocompleteMatch match(this, 0, false, + AutocompleteMatch::SEARCH_WHAT_YOU_TYPED); + static const std::wstring kNoQueryInput( + l10n_util::GetString(IDS_AUTOCOMPLETE_NO_QUERY)); + match.contents.assign(l10n_util::GetStringF( + IDS_AUTOCOMPLETE_SEARCH_CONTENTS, default_provider->short_name(), + kNoQueryInput)); + match.contents_class.push_back( + ACMatchClassification(0, ACMatchClassification::DIM)); + matches_.push_back(match); + } Stop(); return; } @@ -85,15 +110,21 @@ void SearchProvider::Start(const AutocompleteInput& input, void SearchProvider::Run() { // Start a new request with the current input. DCHECK(!done_); - const TemplateURLRef* const suggestions_url = - default_provider_.suggestions_url(); - DCHECK(suggestions_url->SupportsReplacement()); - fetcher_.reset(new URLFetcher(suggestions_url->ReplaceSearchTerms( - default_provider_, input_.text(), - TemplateURLRef::NO_SUGGESTIONS_AVAILABLE, std::wstring()), - URLFetcher::GET, this)); - fetcher_->set_request_context(profile_->GetRequestContext()); - fetcher_->Start(); + suggest_results_pending_ = 0; + if (providers_.valid_suggest_for_keyword_provider()) { + suggest_results_pending_++; + keyword_fetcher_.reset( + CreateSuggestFetcher(providers_.keyword_provider(), + keyword_input_text_)); + } + if (providers_.valid_suggest_for_default_provider()) { + suggest_results_pending_++; + default_fetcher_.reset( + CreateSuggestFetcher(providers_.default_provider(), input_.text())); + } + // We should only get here if we have a suggest url for the keyword or default + // providers. + DCHECK(suggest_results_pending_ > 0); } void SearchProvider::Stop() { @@ -109,9 +140,8 @@ void SearchProvider::OnURLFetchComplete(const URLFetcher* source, const ResponseCookies& cookie, const std::string& data) { DCHECK(!done_); - suggest_results_pending_ = false; - suggest_results_.clear(); - navigation_results_.clear(); + suggest_results_pending_--; + DCHECK(suggest_results_pending_ >= 0); // Should never go negative. const net::HttpResponseHeaders* const response_headers = source->response_headers(); std::string json_data(data); @@ -129,16 +159,24 @@ void SearchProvider::OnURLFetchComplete(const URLFetcher* source, } } + bool is_keyword_results = (source == keyword_fetcher_.get()); + SuggestResults* suggest_results = is_keyword_results ? + &keyword_suggest_results_ : &default_suggest_results_; + if (status.is_success() && response_code == 200) { JSONStringValueSerializer deserializer(json_data); deserializer.set_allow_trailing_comma(true); scoped_ptr<Value> root_val(deserializer.Deserialize(NULL)); + const std::wstring& input_text = + is_keyword_results ? keyword_input_text_ : input_.text(); have_suggest_results_ = - root_val.get() && ParseSuggestResults(root_val.get()); + root_val.get() && + ParseSuggestResults(root_val.get(), is_keyword_results, input_text, + suggest_results); } ConvertResultsToAutocompleteMatches(); - listener_->OnProviderUpdate(!suggest_results_.empty()); + listener_->OnProviderUpdate(!suggest_results->empty()); } void SearchProvider::StartOrStopHistoryQuery(bool minimal_changes) { @@ -156,14 +194,15 @@ void SearchProvider::StartOrStopHistoryQuery(bool minimal_changes) { if (input_.synchronous_only()) return; - // Start the history query. - HistoryService* const history_service = - profile_->GetHistoryService(Profile::EXPLICIT_ACCESS); - history_service->GetMostRecentKeywordSearchTerms(default_provider_.id(), - input_.text(), static_cast<int>(max_matches()), - &history_request_consumer_, - NewCallback(this, &SearchProvider::OnGotMostRecentKeywordSearchTerms)); - history_request_pending_ = true; + // Request history for both the keyword and default provider. + if (providers_.valid_keyword_provider()) { + ScheduleHistoryQuery(providers_.keyword_provider().id(), + keyword_input_text_); + } + if (providers_.valid_default_provider()) { + ScheduleHistoryQuery(providers_.default_provider().id(), + input_.text()); + } } void SearchProvider::StartOrStopSuggestQuery(bool minimal_changes) { @@ -191,11 +230,14 @@ void SearchProvider::StartOrStopSuggestQuery(bool minimal_changes) { if (input_.synchronous_only()) return; + // We'll have at least one pending fetch. Set it to 1 now, but the value is + // correctly set in Run. As Run isn't invoked immediately we need to set this + // now, else we won't think we're waiting on results from the server when we + // really are. + suggest_results_pending_ = 1; + // Kick off a timer that will start the URL fetch if it completes before // the user types another character. - suggest_results_pending_ = true; - - timer_.Stop(); timer_.Start(TimeDelta::FromMilliseconds(kQueryDelayMs), this, &SearchProvider::Run); } @@ -204,7 +246,8 @@ bool SearchProvider::IsQuerySuitableForSuggest() const { // Don't run Suggest when off the record, the engine doesn't support it, or // the user has disabled it. if (profile_->IsOffTheRecord() || - !default_provider_.suggestions_url() || + (!providers_.valid_suggest_for_keyword_provider() && + !providers_.valid_suggest_for_default_provider()) || !profile_->GetPrefs()->GetBoolean(prefs::kSearchSuggestEnabled)) return false; @@ -243,29 +286,80 @@ bool SearchProvider::IsQuerySuitableForSuggest() const { void SearchProvider::StopHistory() { history_request_consumer_.CancelAllRequests(); history_request_pending_ = false; - history_results_.clear(); + keyword_history_results_.clear(); + default_history_results_.clear(); have_history_results_ = false; } void SearchProvider::StopSuggest() { - suggest_results_pending_ = false; + suggest_results_pending_ = 0; timer_.Stop(); - fetcher_.reset(); // Stop any in-progress URL fetch. - suggest_results_.clear(); + // Stop any in-progress URL fetches. + keyword_fetcher_.reset(); + default_fetcher_.reset(); + keyword_suggest_results_.clear(); + default_suggest_results_.clear(); + keyword_navigation_results_.clear(); + default_navigation_results_.clear(); have_suggest_results_ = false; } +void SearchProvider::ScheduleHistoryQuery(TemplateURL::IDType search_id, + const std::wstring& text) { + DCHECK(!text.empty()); + HistoryService* const history_service = + profile_->GetHistoryService(Profile::EXPLICIT_ACCESS); + HistoryService::Handle request_handle = + history_service->GetMostRecentKeywordSearchTerms( + search_id, text, static_cast<int>(max_matches()), + &history_request_consumer_, + NewCallback(this, + &SearchProvider::OnGotMostRecentKeywordSearchTerms)); + history_request_consumer_.SetClientData(history_service, request_handle, + search_id); + history_request_pending_ = true; +} + void SearchProvider::OnGotMostRecentKeywordSearchTerms( CancelableRequestProvider::Handle handle, HistoryResults* results) { - history_request_pending_ = false; - have_history_results_ = true; - history_results_ = *results; + HistoryService* history_service = + profile_->GetHistoryService(Profile::EXPLICIT_ACCESS); + DCHECK(history_service); + if (providers_.valid_keyword_provider() && + (providers_.keyword_provider().id() == + history_request_consumer_.GetClientData(history_service, handle))) { + keyword_history_results_ = *results; + } else { + default_history_results_ = *results; + } ConvertResultsToAutocompleteMatches(); - listener_->OnProviderUpdate(!history_results_.empty()); + listener_->OnProviderUpdate(!results->empty()); + + if (history_request_consumer_.PendingRequestCount() == 1) { + // Requests are removed AFTER the callback is invoked. If the count == 1, + // it means no more history requests are pending. + history_request_pending_ = false; + have_history_results_ = true; + } +} + +URLFetcher* SearchProvider::CreateSuggestFetcher(const TemplateURL& provider, + const std::wstring& text) { + const TemplateURLRef* const suggestions_url = provider.suggestions_url(); + DCHECK(suggestions_url->SupportsReplacement()); + URLFetcher* fetcher = new URLFetcher(suggestions_url->ReplaceSearchTerms( + provider, text, TemplateURLRef::NO_SUGGESTIONS_AVAILABLE, std::wstring()), + URLFetcher::GET, this); + fetcher->set_request_context(profile_->GetRequestContext()); + fetcher->Start(); + return fetcher; } -bool SearchProvider::ParseSuggestResults(Value* root_val) { +bool SearchProvider::ParseSuggestResults(Value* root_val, + bool is_keyword, + const std::wstring& input_text, + SuggestResults* suggest_results) { if (!root_val->IsType(Value::TYPE_LIST)) return false; ListValue* root_list = static_cast<ListValue*>(root_val); @@ -274,7 +368,7 @@ bool SearchProvider::ParseSuggestResults(Value* root_val) { std::wstring query_str; Value* result_val; if ((root_list->GetSize() < 2) || !root_list->Get(0, &query_val) || - !query_val->GetAsString(&query_str) || (query_str != input_.text()) || + !query_val->GetAsString(&query_str) || (query_str != input_text) || !root_list->Get(1, &result_val) || !result_val->IsType(Value::TYPE_LIST)) return false; @@ -322,7 +416,10 @@ bool SearchProvider::ParseSuggestResults(Value* root_val) { type_val->GetAsString(&type_str) && (type_str == L"NAVIGATION")) { Value* site_val; std::wstring site_name; - if ((navigation_results_.size() < max_matches()) && + NavigationResults& navigation_results = + is_keyword ? keyword_navigation_results_ : + default_navigation_results_; + if ((navigation_results.size() < max_matches()) && description_list && description_list->Get(i, &site_val) && site_val->IsType(Value::TYPE_STRING) && site_val->GetAsString(&site_name)) { @@ -330,16 +427,14 @@ bool SearchProvider::ParseSuggestResults(Value* root_val) { GURL result_url = GURL(URLFixerUpper::FixupURL(WideToUTF8(suggestion_str), std::string())); - if (result_url.is_valid()) { - navigation_results_.push_back(NavigationResult(result_url, - site_name)); - } + if (result_url.is_valid()) + navigation_results.push_back(NavigationResult(result_url, site_name)); } } else { // TODO(kochi): Currently we treat a calculator result as a query, but it // is better to have better presentation for caluculator results. - if (suggest_results_.size() < max_matches()) - suggest_results_.push_back(suggestion_str); + if (suggest_results->size() < max_matches()) + suggest_results->push_back(suggestion_str); } } @@ -350,39 +445,38 @@ void SearchProvider::ConvertResultsToAutocompleteMatches() { // Convert all the results to matches and add them to a map, so we can keep // the most relevant match for each result. MatchMap map; - const int did_not_accept_suggestion = suggest_results_.empty() ? + const Time no_time; + int did_not_accept_keyword_suggestion = keyword_suggest_results_.empty() ? TemplateURLRef::NO_SUGGESTIONS_AVAILABLE : TemplateURLRef::NO_SUGGESTION_CHOSEN; - const Time no_time; - AddMatchToMap(input_.text(), CalculateRelevanceForWhatYouTyped(), - AutocompleteMatch::SEARCH_WHAT_YOU_TYPED, - did_not_accept_suggestion, &map); - - for (HistoryResults::const_iterator i(history_results_.begin()); - i != history_results_.end(); ++i) { - AddMatchToMap(i->term, CalculateRelevanceForHistory(i->time), - AutocompleteMatch::SEARCH_HISTORY, did_not_accept_suggestion, - &map); + // Keyword what you typed results are handled by the KeywordProvider. + + int did_not_accept_default_suggestion = default_suggest_results_.empty() ? + TemplateURLRef::NO_SUGGESTIONS_AVAILABLE : + TemplateURLRef::NO_SUGGESTION_CHOSEN; + if (providers_.valid_default_provider()) { + AddMatchToMap(input_.text(), CalculateRelevanceForWhatYouTyped(), + AutocompleteMatch::SEARCH_WHAT_YOU_TYPED, + did_not_accept_default_suggestion, false, &map); } - for (size_t i = 0; i < suggest_results_.size(); ++i) { - AddMatchToMap(suggest_results_[i], CalculateRelevanceForSuggestion(i), - AutocompleteMatch::SEARCH_SUGGEST, - static_cast<int>(i), &map); - } + AddHistoryResultsToMap(keyword_history_results_, true, + did_not_accept_keyword_suggestion, &map); + AddHistoryResultsToMap(default_history_results_, false, + did_not_accept_default_suggestion, &map); + + AddSuggestResultsToMap(keyword_suggest_results_, true, + did_not_accept_keyword_suggestion, &map); + AddSuggestResultsToMap(default_suggest_results_, false, + did_not_accept_default_suggestion, &map); // Now add the most relevant matches from the map to |matches_|. matches_.clear(); for (MatchMap::const_iterator i(map.begin()); i != map.end(); ++i) matches_.push_back(i->second); - if (!navigation_results_.empty()) { - // TODO(kochi): http://b/1170574 We add only one results for navigational - // suggestions. If we can get more useful information about the score, - // consider adding more results. - matches_.push_back(NavigationToMatch(navigation_results_.front(), - CalculateRelevanceForNavigation(0))); - } + AddNavigationResultsToMatches(keyword_navigation_results_, true); + AddNavigationResultsToMatches(default_navigation_results_, false); const size_t max_total_matches = max_matches() + 1; // 1 for "what you typed" std::partial_sort(matches_.begin(), @@ -399,26 +493,65 @@ void SearchProvider::ConvertResultsToAutocompleteMatches() { // callback has returned, but we've reached here from inside that callback. // HasPendingRequests() would therefore return true, and if this is the last // thing left to calculate for this query, we'll never mark the query "done". - done_ = !history_request_pending_ && - !suggest_results_pending_; + done_ = !history_request_pending_ && !suggest_results_pending_; +} + +void SearchProvider::AddNavigationResultsToMatches( + const NavigationResults& navigation_results, + bool is_keyword) { + if (!navigation_results.empty()) { + // TODO(kochi): http://b/1170574 We add only one results for navigational + // suggestions. If we can get more useful information about the score, + // consider adding more results. + matches_.push_back( + NavigationToMatch(navigation_results.front(), + CalculateRelevanceForNavigation(0, is_keyword), + is_keyword)); + } +} + +void SearchProvider::AddHistoryResultsToMap(const HistoryResults& results, + bool is_keyword, + int did_not_accept_suggestion, + MatchMap* map) { + for (HistoryResults::const_iterator i(results.begin()); i != results.end(); + ++i) { + AddMatchToMap(i->term, CalculateRelevanceForHistory(i->time, is_keyword), + AutocompleteMatch::SEARCH_HISTORY, did_not_accept_suggestion, + is_keyword, map); + } +} + +void SearchProvider::AddSuggestResultsToMap( + const SuggestResults& suggest_results, + bool is_keyword, + int did_not_accept_suggestion, + MatchMap* map) { + for (size_t i = 0; i < suggest_results.size(); ++i) { + AddMatchToMap(suggest_results[i], + CalculateRelevanceForSuggestion(suggest_results, i, + is_keyword), + AutocompleteMatch::SEARCH_SUGGEST, + static_cast<int>(i), is_keyword, map); + } } int SearchProvider::CalculateRelevanceForWhatYouTyped() const { switch (input_.type()) { case AutocompleteInput::UNKNOWN: - return 1300; + return providers_.valid_keyword_provider() ? 250 : 1300; case AutocompleteInput::REQUESTED_URL: - return 1200; + return providers_.valid_keyword_provider() ? 250 : 1200; case AutocompleteInput::URL: - return 850; + return providers_.valid_keyword_provider() ? 250 : 850; case AutocompleteInput::QUERY: - return 1300; + return providers_.valid_keyword_provider() ? 250 : 1300; case AutocompleteInput::FORCED_QUERY: - return 1500; + return providers_.valid_keyword_provider() ? 250 : 1500; default: NOTREACHED(); @@ -426,7 +559,8 @@ int SearchProvider::CalculateRelevanceForWhatYouTyped() const { } } -int SearchProvider::CalculateRelevanceForHistory(const Time& time) const { +int SearchProvider::CalculateRelevanceForHistory(const Time& time, + bool is_keyword) const { // The relevance of past searches falls off over time. This curve is chosen // so that the relevance of a search 15 minutes ago is discounted about 50 // points, while the relevance of a search two weeks ago is discounted about @@ -437,19 +571,20 @@ int SearchProvider::CalculateRelevanceForHistory(const Time& time) const { // Don't let scores go below 0. Negative relevance scores are meaningful in // a different way. int base_score; + bool is_primary = providers_.is_primary_provider(is_keyword); switch (input_.type()) { case AutocompleteInput::UNKNOWN: case AutocompleteInput::REQUESTED_URL: - base_score = 1050; + base_score = is_primary ? 1050 : 200; break; case AutocompleteInput::URL: - base_score = 750; + base_score = is_primary ? 750 : 200; break; case AutocompleteInput::QUERY: case AutocompleteInput::FORCED_QUERY: - base_score = 1250; + base_score = is_primary ? 1250 : 200; break; default: @@ -461,21 +596,24 @@ int SearchProvider::CalculateRelevanceForHistory(const Time& time) const { } int SearchProvider::CalculateRelevanceForSuggestion( - size_t suggestion_number) const { - DCHECK(suggestion_number < suggest_results_.size()); + const SuggestResults& suggest_results, + size_t suggestion_number, + bool is_keyword) const { + DCHECK(suggestion_number < suggest_results.size()); + bool is_primary = providers_.is_primary_provider(is_keyword); const int suggestion_value = - static_cast<int>(suggest_results_.size() - 1 - suggestion_number); + static_cast<int>(suggest_results.size() - 1 - suggestion_number); switch (input_.type()) { case AutocompleteInput::UNKNOWN: case AutocompleteInput::REQUESTED_URL: - return 600 + suggestion_value; + return suggestion_value + (is_primary ? 600 : 100); case AutocompleteInput::URL: - return 300 + suggestion_value; + return suggestion_value + (is_primary ? 300 : 100); case AutocompleteInput::QUERY: case AutocompleteInput::FORCED_QUERY: - return 800 + suggestion_value; + return suggestion_value + (is_primary ? 800 : 100); default: NOTREACHED(); @@ -484,17 +622,21 @@ int SearchProvider::CalculateRelevanceForSuggestion( } int SearchProvider::CalculateRelevanceForNavigation( - size_t suggestion_number) const { - DCHECK(suggestion_number < navigation_results_.size()); + size_t suggestion_number, + bool is_keyword) const { + DCHECK( + (is_keyword && suggestion_number < keyword_navigation_results_.size()) || + (!is_keyword && suggestion_number < default_navigation_results_.size())); // TODO(kochi): http://b/784900 Use relevance score from the NavSuggest // server if possible. + bool is_primary = providers_.is_primary_provider(is_keyword); switch (input_.type()) { case AutocompleteInput::QUERY: case AutocompleteInput::FORCED_QUERY: - return 1000 + static_cast<int>(suggestion_number); + return static_cast<int>(suggestion_number) + (is_primary ? 1000 : 150); default: - return 800 + static_cast<int>(suggestion_number); + return static_cast<int>(suggestion_number) + (is_primary ? 800 : 150); } } @@ -502,11 +644,16 @@ void SearchProvider::AddMatchToMap(const std::wstring& query_string, int relevance, AutocompleteMatch::Type type, int accepted_suggestion, + bool is_keyword, MatchMap* map) { + const std::wstring& input_text = + is_keyword ? keyword_input_text_ : input_.text(); AutocompleteMatch match(this, relevance, false, type); std::vector<size_t> content_param_offsets; + const TemplateURL& provider = is_keyword ? providers_.keyword_provider() : + providers_.default_provider(); match.contents.assign(l10n_util::GetStringF(IDS_AUTOCOMPLETE_SEARCH_CONTENTS, - default_provider_.short_name(), + provider.short_name(), query_string, &content_param_offsets)); if (content_param_offsets.size() == 2) { @@ -539,16 +686,16 @@ void SearchProvider::AddMatchToMap(const std::wstring& query_string, // NOTE: All Google suggestions currently start with the original input, but // not all Yahoo! suggestions do. if (!input_.prevent_inline_autocomplete() && - !match.fill_into_edit.compare(search_start, input_.text().length(), - input_.text())) - match.inline_autocomplete_offset = search_start + input_.text().length(); + !match.fill_into_edit.compare(search_start, input_text.length(), + input_text)) + match.inline_autocomplete_offset = search_start + input_text.length(); - const TemplateURLRef* const search_url = default_provider_.url(); + const TemplateURLRef* const search_url = provider.url(); DCHECK(search_url->SupportsReplacement()); - match.destination_url = search_url->ReplaceSearchTerms(default_provider_, + match.destination_url = search_url->ReplaceSearchTerms(provider, query_string, accepted_suggestion, - input_.text()); + input_text); // Search results don't look like URLs. match.transition = PageTransition::GENERATED; @@ -573,22 +720,24 @@ void SearchProvider::AddMatchToMap(const std::wstring& query_string, AutocompleteMatch SearchProvider::NavigationToMatch( const NavigationResult& navigation, - int relevance) { + int relevance, + bool is_keyword) { + const std::wstring& input_text = + is_keyword ? keyword_input_text_ : input_.text(); AutocompleteMatch match(this, relevance, false, AutocompleteMatch::NAVSUGGEST); match.destination_url = navigation.url; match.contents = StringForURLDisplay(navigation.url, true); // TODO(kochi): Consider moving HistoryURLProvider::TrimHttpPrefix() to some // public utility function. - if (!url_util::FindAndCompareScheme(WideToUTF8(input_.text()), - "http", NULL)) + if (!url_util::FindAndCompareScheme(WideToUTF8(input_text), "http", NULL)) TrimHttpPrefix(&match.contents); - AutocompleteMatch::ClassifyMatchInString(input_.text(), match.contents, + AutocompleteMatch::ClassifyMatchInString(input_text, match.contents, ACMatchClassification::URL, &match.contents_class); match.description = navigation.site_name; - AutocompleteMatch::ClassifyMatchInString(input_.text(), navigation.site_name, + AutocompleteMatch::ClassifyMatchInString(input_text, navigation.site_name, ACMatchClassification::NONE, &match.description_class); diff --git a/chrome/browser/autocomplete/search_provider.h b/chrome/browser/autocomplete/search_provider.h index 45fd1b3..06e0352 100644 --- a/chrome/browser/autocomplete/search_provider.h +++ b/chrome/browser/autocomplete/search_provider.h @@ -1,4 +1,4 @@ -// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. +// Copyright (c) 2009 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // @@ -42,11 +42,9 @@ class SearchProvider : public AutocompleteProvider, public: SearchProvider(ACProviderListener* listener, Profile* profile) : AutocompleteProvider(listener, profile, "Search"), - last_default_provider_(NULL), have_history_results_(false), history_request_pending_(false), - suggest_results_pending_(false), - fetcher_(NULL), + suggest_results_pending_(0), have_suggest_results_(false) { } @@ -64,6 +62,73 @@ class SearchProvider : public AutocompleteProvider, const std::string& data); private: + // Manages the providers (TemplateURLs) used by SearchProvider. Two providers + // may be used: + // . The default provider. This corresponds to the user's default search + // engine. This is always used, except for the rare case of no default + // engine. + // . The keyword provider. This is used if the user has typed in a keyword. + class Providers { + public: + Providers() : default_provider_(NULL), keyword_provider_(NULL) {} + + // Returns true if the specified providers match the two providers managed + // by this class. + bool equals(const TemplateURL* default_provider, + const TemplateURL* keyword_provider) { + return (default_provider == default_provider_ && + keyword_provider == keyword_provider_); + } + + // Resets the providers. + void Set(const TemplateURL* default_provider, + const TemplateURL* keyword_provider); + + const TemplateURL& default_provider() const { + DCHECK(valid_default_provider()); + return cached_default_provider_; + } + + const TemplateURL& keyword_provider() const { + DCHECK(valid_keyword_provider()); + return cached_keyword_provider_; + } + + // Returns true of the keyword provider is valid. + bool valid_keyword_provider() const { return !!keyword_provider_; } + + // Returns true if the keyword provider is valid and has a valid suggest + // url. + bool valid_suggest_for_keyword_provider() const { + return keyword_provider_ && cached_keyword_provider_.suggestions_url(); + } + + // Returns true of the default provider is valid. + bool valid_default_provider() const { return !!default_provider_; } + + // Returns true if the default provider is valid and has a valid suggest + // url. + bool valid_suggest_for_default_provider() const { + return default_provider_ && cached_default_provider_.suggestions_url(); + } + + // Returns true if |from_keyword_provider| is true, or + // the keyword provider is not valid. + bool is_primary_provider(bool from_keyword_provider) const { + return from_keyword_provider || !valid_keyword_provider(); + } + + private: + // Cached across the life of a query so we behave consistently even if the + // user changes their default while the query is running. + TemplateURL cached_default_provider_; + TemplateURL cached_keyword_provider_; + + // TODO(pkasting): http://b/1162970 We shouldn't need these. + const TemplateURL* default_provider_; + const TemplateURL* keyword_provider_; + }; + struct NavigationResult { NavigationResult(const GURL& url, const std::wstring& site_name) : url(url), @@ -101,31 +166,72 @@ class SearchProvider : public AutocompleteProvider, void StopHistory(); void StopSuggest(); + // Schedules a history query requesting past searches against the engine + // whose id is |search_id| and whose text starts with |text|. + void ScheduleHistoryQuery(TemplateURL::IDType search_id, + const std::wstring& text); + // Called back by the history system to return searches that begin with the // input text. void OnGotMostRecentKeywordSearchTerms( CancelableRequestProvider::Handle handle, HistoryResults* results); + // Creates a URLFetcher requesting suggest results for the specified + // TemplateURL. Ownership of the returned URLFetchet passes to the caller. + URLFetcher* CreateSuggestFetcher(const TemplateURL& provider, + const std::wstring& text); + // Parses the results from the Suggest server and stores up to kMaxMatches of // them in server_results_. Returns whether parsing succeeded. - bool ParseSuggestResults(Value* root_val); + bool ParseSuggestResults(Value* root_val, + bool is_keyword, + const std::wstring& input_text, + SuggestResults* suggest_results); // Converts the parsed server results in server_results_ to a set of // AutocompleteMatches and adds them to |matches_|. This also sets |done_| // correctly. void ConvertResultsToAutocompleteMatches(); + // Converts the first navigation result in |navigation_results| to an + // AutocompleteMatch and adds it to |matches_|. + void AddNavigationResultsToMatches( + const NavigationResults& navigation_results, + bool is_keyword); + + // Adds a match for each result in |results| to |map|. |is_keyword| indicates + // whether the results correspond to the keyword provider or default provider. + void AddHistoryResultsToMap(const HistoryResults& results, + bool is_keyword, + int did_not_accept_suggestion, + MatchMap* map); + + // Adds a match for each result in |suggest_results| to |map|. |is_keyword| + // indicates whether the results correspond to the keyword provider or default + // provider. + void AddSuggestResultsToMap(const SuggestResults& suggest_results, + bool is_keyword, + int did_not_accept_suggestion, + MatchMap* map); + // Determines the relevance for a particular match. We use different scoring // algorithms for the different types of matches. int CalculateRelevanceForWhatYouTyped() const; - // |time| is the time at which this query was last seen. - int CalculateRelevanceForHistory(const base::Time& time) const; - // |suggestion_value| is which suggestion this is in the list returned from - // the server; the best suggestion is suggestion number 0. - int CalculateRelevanceForSuggestion(size_t suggestion_value) const; - // |suggestion_value| is same as above. - int CalculateRelevanceForNavigation(size_t suggestion_value) const; + // |time| is the time at which this query was last seen. |is_keyword| is true + // if the search is from the keyword provider. + int CalculateRelevanceForHistory(const base::Time& time, + bool is_keyword) const; + // |suggestion_value| is the index of the suggestion in |suggest_results| that + // was returned from the server; the best suggestion is suggestion number 0. + // |is_keyword| is true if the search is from the keyword provider. + int CalculateRelevanceForSuggestion(const SuggestResults& suggest_results, + size_t suggestion_number, + bool is_keyword) const; + // |suggestion_value| is same as above. |is_keyword| is true if the navigation + // result was suggested by the keyword provider. + int CalculateRelevanceForNavigation(size_t suggestion_value, + bool is_keyword) const; // Creates an AutocompleteMatch for "Search <engine> for |query_string|" with // the supplied relevance. Adds this match to |map|; if such a match already @@ -134,31 +240,37 @@ class SearchProvider : public AutocompleteProvider, int relevance, AutocompleteMatch::Type type, int accepted_suggestion, + bool is_keyword, MatchMap* map); // Returns an AutocompleteMatch for a navigational suggestion. AutocompleteMatch NavigationToMatch(const NavigationResult& query_string, - int relevance); + int relevance, + bool is_keyword); // Trims "http:" and up to two subsequent slashes from |url|. Returns the // number of characters that were trimmed. // TODO(kochi): this is duplicate from history_autocomplete static size_t TrimHttpPrefix(std::wstring* url); + // Maintains the TemplateURLs used. + Providers providers_; + // The user's input. AutocompleteInput input_; - // Cached across the life of a query so we behave consistently even if the - // user changes their default while the query is running. - TemplateURL default_provider_; - - // TODO(pkasting): http://b/1162970 We shouldn't need this. - const TemplateURL* last_default_provider_; + // Input text when searching against the keyword provider. + std::wstring keyword_input_text_; - // An object we can use to cancel history requests. - CancelableRequestConsumer history_request_consumer_; + // An object we can use to cancel history requests. The client data + // corresponds to the id of the search engine and is used in the callback to + // determine whether the request corresponds to the keyword of default + // provider. + CancelableRequestConsumerTSimple<TemplateURL::IDType> + history_request_consumer_; // Searches in the user's history that begin with the input text. - HistoryResults history_results_; + HistoryResults keyword_history_results_; + HistoryResults default_history_results_; // Whether history_results_ is valid (so we can tell invalid apart from // empty). @@ -167,22 +279,28 @@ class SearchProvider : public AutocompleteProvider, // Whether we are waiting for a history request to finish. bool history_request_pending_; - // True if we're expecting suggest results that haven't yet arrived. This - // could be because either |timer_| or |fetcher| is still running (see below). - bool suggest_results_pending_; + // Number of suggest results that haven't yet arrived. If greater than 0 it + // indicates either |timer_| or one of the URLFetchers is still running. + int suggest_results_pending_; // A timer to start a query to the suggest server after the user has stopped // typing for long enough. base::OneShotTimer<SearchProvider> timer_; - // The fetcher that retrieves suggest results from the server. - scoped_ptr<URLFetcher> fetcher_; + // The fetcher that retrieves suggest results for the keyword from the server. + scoped_ptr<URLFetcher> keyword_fetcher_; + + // The fetcher that retrieves suggest results for the default engine from the + // server. + scoped_ptr<URLFetcher> default_fetcher_; // Suggestions returned by the Suggest server for the input text. - SuggestResults suggest_results_; + SuggestResults keyword_suggest_results_; + SuggestResults default_suggest_results_; // Navigational suggestions returned by the server. - NavigationResults navigation_results_; + NavigationResults keyword_navigation_results_; + NavigationResults default_navigation_results_; // Whether suggest_results_ is valid. bool have_suggest_results_; diff --git a/chrome/browser/importer/importer.cc b/chrome/browser/importer/importer.cc index e0df1f7..6e29b59 100644 --- a/chrome/browser/importer/importer.cc +++ b/chrome/browser/importer/importer.cc @@ -277,8 +277,7 @@ void ProfileWriter::AddKeywords(const std::vector<TemplateURL*>& template_urls, } if (t_url->url() && t_url->url()->IsValid()) { model->Add(t_url); - if (default_keyword && t_url->url() && - t_url->url()->SupportsReplacement()) + if (default_keyword && TemplateURL::SupportsReplacement(t_url)) model->SetDefaultSearchProvider(t_url); } else { // Don't add invalid TemplateURLs to the model. diff --git a/chrome/browser/search_engines/template_url.cc b/chrome/browser/search_engines/template_url.cc index bd6c115..72ffc6d 100644 --- a/chrome/browser/search_engines/template_url.cc +++ b/chrome/browser/search_engines/template_url.cc @@ -491,6 +491,11 @@ GURL TemplateURL::GenerateFaviconURL(const GURL& url) { return url.ReplaceComponents(rep); } +// static +bool TemplateURL::SupportsReplacement(const TemplateURL* turl) { + return turl && turl->url() && turl->url()->SupportsReplacement(); +} + void TemplateURL::SetSuggestionsURL(const std::wstring& suggestions_url, int index_offset, int page_offset) { diff --git a/chrome/browser/search_engines/template_url.h b/chrome/browser/search_engines/template_url.h index c9b36c4..983621a 100644 --- a/chrome/browser/search_engines/template_url.h +++ b/chrome/browser/search_engines/template_url.h @@ -250,6 +250,10 @@ class TemplateURL { // Generates a favicon URL from the specified url. static GURL GenerateFaviconURL(const GURL& url); + // Returns true if |true| is non-null and has a search URL that supports + // replacement. + static bool SupportsReplacement(const TemplateURL* turl); + TemplateURL() : autogenerate_keyword_(false), show_in_default_list_(false), diff --git a/chrome/browser/views/keyword_editor_view.cc b/chrome/browser/views/keyword_editor_view.cc index 3018cfa..4a4f064 100644 --- a/chrome/browser/views/keyword_editor_view.cc +++ b/chrome/browser/views/keyword_editor_view.cc @@ -414,7 +414,7 @@ void KeywordEditorView::ModifyTemplateURL(const TemplateURL* template_url, url_model_->RemoveObserver(this); url_model_->ResetTemplateURL(template_url, title, keyword, url); if (url_model_->GetDefaultSearchProvider() == template_url && - (!template_url->url() || !template_url->url()->SupportsReplacement())) { + !TemplateURL::SupportsReplacement(template_url)) { // The entry was the default search provider, but the url has been modified // so that it no longer supports replacement. Reset the default search // provider so that it doesn't point to a bogus entry. |