| // Copyright (c) 2011 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. |
| // |
| // This file contains the Search autocomplete provider. This provider is |
| // responsible for all non-keyword autocomplete entries that start with |
| // "Search <engine> for ...", including searching for the current input string, |
| // search history, and search suggestions. An instance of it gets created and |
| // managed by the autocomplete controller. |
| // |
| // For more information on the autocomplete system in general, including how |
| // the autocomplete controller and autocomplete providers work, see |
| // chrome/browser/autocomplete.h. |
| |
| #ifndef CHROME_BROWSER_AUTOCOMPLETE_SEARCH_PROVIDER_H_ |
| #define CHROME_BROWSER_AUTOCOMPLETE_SEARCH_PROVIDER_H_ |
| #pragma once |
| |
| #include <map> |
| #include <string> |
| #include <vector> |
| |
| #include "base/memory/scoped_ptr.h" |
| #include "chrome/browser/autocomplete/autocomplete.h" |
| #include "chrome/browser/autocomplete/autocomplete_match.h" |
| #include "chrome/browser/history/history_types.h" |
| #include "chrome/browser/search_engines/template_url.h" |
| #include "chrome/browser/search_engines/template_url_id.h" |
| #include "chrome/common/net/url_fetcher.h" |
| |
| class Profile; |
| class Value; |
| |
| // Autocomplete provider for searches and suggestions from a search engine. |
| // |
| // After construction, the autocomplete controller repeatedly calls Start() |
| // with some user input, each time expecting to receive a small set of the best |
| // matches (either synchronously or asynchronously). |
| // |
| // Initially the provider creates a match that searches for the current input |
| // text. It also starts a task to query the Suggest servers. When that data |
| // comes back, the provider creates and returns matches for the best |
| // suggestions. |
| class SearchProvider : public AutocompleteProvider, |
| public URLFetcher::Delegate { |
| public: |
| SearchProvider(ACProviderListener* listener, Profile* profile); |
| |
| #if defined(UNIT_TEST) |
| static void set_query_suggest_immediately(bool value) { |
| query_suggest_immediately_ = value; |
| } |
| #endif |
| |
| // Marks the instant query as done. If |input_text| is non-empty this changes |
| // the 'search what you typed' results text to |input_text| + |suggest_text|. |
| // |input_text| is the text the user input into the edit. |input_text| differs |
| // from |input_.text()| if the input contained whitespace. |
| // |
| // This method also marks the search provider as no longer needing to wait for |
| // the instant result. |
| void FinalizeInstantQuery(const string16& input_text, |
| const string16& suggest_text); |
| |
| // AutocompleteProvider |
| virtual void Start(const AutocompleteInput& input, |
| bool minimal_changes); |
| virtual void Stop(); |
| |
| // URLFetcher::Delegate |
| virtual void OnURLFetchComplete(const URLFetcher* source, |
| const GURL& url, |
| const net::URLRequestStatus& status, |
| int response_code, |
| const ResponseCookies& cookies, |
| const std::string& data); |
| |
| // ID used in creating URLFetcher for default provider's suggest results. |
| static const int kDefaultProviderURLFetcherID; |
| |
| // ID used in creating URLFetcher for keyword provider's suggest results. |
| static const int kKeywordProviderURLFetcherID; |
| |
| private: |
| ~SearchProvider(); |
| |
| // 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 string16& site_name) |
| : url(url), |
| site_name(site_name) { |
| } |
| |
| // The URL. |
| GURL url; |
| |
| // Name for the site. |
| string16 site_name; |
| }; |
| |
| typedef std::vector<string16> SuggestResults; |
| typedef std::vector<NavigationResult> NavigationResults; |
| typedef std::vector<history::KeywordSearchTermVisit> HistoryResults; |
| typedef std::map<string16, AutocompleteMatch> MatchMap; |
| |
| // Called when timer_ expires. |
| void Run(); |
| |
| // Runs the history query, if necessary. The history query is synchronous. |
| // This does not update |done_|. |
| void DoHistoryQuery(bool minimal_changes); |
| |
| // Determines whether an asynchronous subcomponent query should run for the |
| // current input. If so, starts it if necessary; otherwise stops it. |
| // NOTE: This function does not update |done_|. Callers must do so. |
| void StartOrStopSuggestQuery(bool minimal_changes); |
| |
| // Returns true when the current query can be sent to the Suggest service. |
| // This will be false e.g. when Suggest is disabled, the query contains |
| // potentially private data, etc. |
| bool IsQuerySuitableForSuggest() const; |
| |
| // Stops the suggest query. |
| // NOTE: This does not update |done_|. Callers must do so. |
| void StopSuggest(); |
| |
| // Creates a URLFetcher requesting suggest results for the specified |
| // TemplateURL. Ownership of the returned URLFetchet passes to the caller. |
| URLFetcher* CreateSuggestFetcher(int id, |
| const TemplateURL& provider, |
| const string16& 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 is_keyword, |
| const string16& 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. |is_keyword| is true |
| // if the search is from the keyword provider. |looks_like_url| is true if the |
| // search term would be treated as a URL if typed into the omnibox. |
| int CalculateRelevanceForHistory(const base::Time& time, |
| bool looks_like_url, |
| bool is_keyword) const; |
| // |result_number| is the index of the suggestion in the result set from the |
| // server; the best suggestion is suggestion number 0. |is_keyword| is true |
| // if the search is from the keyword provider. |
| int CalculateRelevanceForSuggestion(size_t num_results, |
| size_t result_number, |
| bool is_keyword) const; |
| // |result_number| is same as above. |is_keyword| is true if the navigation |
| // result was suggested by the keyword provider. |
| int CalculateRelevanceForNavigation(size_t num_results, |
| size_t result_number, |
| 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 |
| // exists, whichever one has lower relevance is eliminated. |
| void AddMatchToMap(const string16& query_string, |
| const string16& input_text, |
| int relevance, |
| AutocompleteMatch::Type type, |
| int accepted_suggestion, |
| bool is_keyword, |
| bool prevent_inline_autocomplete, |
| MatchMap* map); |
| |
| // Returns an AutocompleteMatch for a navigational suggestion. |
| AutocompleteMatch NavigationToMatch(const NavigationResult& query_string, |
| int relevance, |
| bool is_keyword); |
| |
| // Updates the value of |done_| from the internal state. |
| void UpdateDone(); |
| |
| // Updates the description/description_class of the first search match. |
| void UpdateFirstSearchMatchDescription(); |
| |
| // Should we query for suggest results immediately? This is normally false, |
| // but may be set to true during testing. |
| static bool query_suggest_immediately_; |
| |
| // Maintains the TemplateURLs used. |
| Providers providers_; |
| |
| // The user's input. |
| AutocompleteInput input_; |
| |
| // Input text when searching against the keyword provider. |
| string16 keyword_input_text_; |
| |
| // Searches in the user's history that begin with the input text. |
| HistoryResults keyword_history_results_; |
| HistoryResults default_history_results_; |
| |
| // 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 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 keyword_suggest_results_; |
| SuggestResults default_suggest_results_; |
| |
| // Navigational suggestions returned by the server. |
| NavigationResults keyword_navigation_results_; |
| NavigationResults default_navigation_results_; |
| |
| // Whether suggest_results_ is valid. |
| bool have_suggest_results_; |
| |
| // Has FinalizeInstantQuery been invoked since the last |Start|? |
| bool instant_finalized_; |
| |
| // The |suggest_text| parameter passed to FinalizeInstantQuery. |
| string16 default_provider_suggest_text_; |
| |
| DISALLOW_COPY_AND_ASSIGN(SearchProvider); |
| }; |
| |
| #endif // CHROME_BROWSER_AUTOCOMPLETE_SEARCH_PROVIDER_H_ |