summaryrefslogtreecommitdiffstats
path: root/chrome
diff options
context:
space:
mode:
authorsky@chromium.org <sky@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-04-14 17:16:24 +0000
committersky@chromium.org <sky@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-04-14 17:16:24 +0000
commit257ab718488a1cdb46a2423464e17933c8339a01 (patch)
treeb36111115dd00a00da78113758424603b45cb818 /chrome
parent3f85caafb239d5725ec85af9b8ce9f1b1de15770 (diff)
downloadchromium_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.h61
-rw-r--r--chrome/browser/autocomplete/autocomplete_popup_model.cc6
-rw-r--r--chrome/browser/autocomplete/keyword_provider.cc44
-rw-r--r--chrome/browser/autocomplete/keyword_provider.h19
-rw-r--r--chrome/browser/autocomplete/search_provider.cc395
-rw-r--r--chrome/browser/autocomplete/search_provider.h176
-rw-r--r--chrome/browser/importer/importer.cc3
-rw-r--r--chrome/browser/search_engines/template_url.cc5
-rw-r--r--chrome/browser/search_engines/template_url.h4
-rw-r--r--chrome/browser/views/keyword_editor_view.cc2
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.