blob: 4011cbd2b4e4f96bb56c73b24c9227c0ac395b2f [file] [log] [blame]
// Copyright (c) 2010 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.
#ifndef CHROME_BROWSER_AUTOCOMPLETE_AUTOCOMPLETE_H_
#define CHROME_BROWSER_AUTOCOMPLETE_AUTOCOMPLETE_H_
#include <string>
#include <vector>
#include "base/logging.h"
#include "base/ref_counted.h"
#include "base/timer.h"
#include "chrome/common/page_transition_types.h"
#include "googleurl/src/gurl.h"
#include "googleurl/src/url_parse.h"
// The AutocompleteController is the center of the autocomplete system. A
// class creates an instance of the controller, which in turn creates a set of
// AutocompleteProviders to serve it. The owning class can ask the controller
// to Start() a query; the controller in turn passes this call down to the
// providers, each of which keeps track of its own matches and whether it has
// finished processing the query. When a provider gets more matches or finishes
// processing, it notifies the controller, which merges the combined matches
// together and makes the result available to interested observers.
//
// The owner may also cancel the current query by calling Stop(), which the
// controller will in turn communicate to all the providers. No callbacks will
// happen after a request has been stopped.
//
// IMPORTANT: There is NO THREAD SAFETY built into this portion of the
// autocomplete system. All calls to and from the AutocompleteController should
// happen on the same thread. AutocompleteProviders are responsible for doing
// their own thread management when they need to return matches asynchronously.
//
// The AutocompleteProviders each return different kinds of matches, such as
// history or search matches. These matches are given "relevance" scores.
// Higher scores are better matches than lower scores. The relevance scores and
// classes providing the respective matches are as follows:
//
// UNKNOWN input type:
// --------------------------------------------------------------------|-----
// Keyword (non-substituting or in keyword UI mode, exact match) | 1500
// HistoryURL (exact or inline autocomplete match) | 1400
// Search Primary Provider (what you typed) | 1300
// HistoryURL (what you typed) | 1200
// Keyword (substituting, exact match) | 1100
// Search Primary Provider (past query in history) | 1050--
// HistoryContents (any match in title of starred page) | 1000++
// HistoryURL (inexact match) | 900++
// Search Primary Provider (navigational suggestion) | 800++
// HistoryContents (any match in title of nonstarred page) | 700++
// 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) | 1200
// Search Primary Provider (what you typed) | 1150
// Keyword (substituting, exact match) | 1100
// Search Primary Provider (past query in history) | 1050--
// HistoryContents (any match in title of starred page) | 1000++
// HistoryURL (inexact match) | 900++
// Search Primary Provider (navigational suggestion) | 800++
// HistoryContents (any match in title of nonstarred page) | 700++
// 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:
// --------------------------------------------------------------------|-----
// Keyword (non-substituting or in keyword UI mode, exact match) | 1500
// HistoryURL (exact or inline autocomplete match) | 1400
// HistoryURL (what you typed) | 1200
// Keyword (substituting, exact match) | 1100
// HistoryURL (inexact match) | 900++
// 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 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) | 1450
// HistoryURL (exact or inline autocomplete match) | 1400
// Search Primary Provider (what you typed) | 1300
// Search Primary Provider (past query in history) | 1050--
// HistoryContents (any match in title of starred page) | 1000++
// HistoryURL (inexact match) | 900++
// Search Primary Provider (navigational suggestion) | 800++
// HistoryContents (any match in title of nonstarred page) | 700++
// 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++
//
// FORCED_QUERY input type:
// --------------------------------------------------------------------|-----
// Search Primary Provider (what you typed) | 1300
// Search Primary Provider (past query in history) | 1050--
// HistoryContents (any match in title of starred page) | 1000++
// Search Primary Provider (navigational suggestion) | 800++
// HistoryContents (any match in title of nonstarred page) | 700++
// Search Primary Provider (suggestion) | 600++
// HistoryContents (any match in body of starred page) | 550++
// HistoryContents (any match in body of nonstarred page) | 500++
//
// (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 matches with relevance from n up to (n + max_matches).
// --: relevance score falls off over time (discounted 50 points @ 15 minutes,
// 450 points @ two weeks)
class AutocompleteInput;
struct AutocompleteMatch;
class AutocompleteProvider;
class AutocompleteResult;
class AutocompleteController;
class HistoryContentsProvider;
class KeywordProvider;
class Profile;
class TemplateURL;
typedef std::vector<AutocompleteMatch> ACMatches;
typedef std::vector<AutocompleteProvider*> ACProviders;
// AutocompleteInput ----------------------------------------------------------
// The user input for an autocomplete query. Allows copying.
class AutocompleteInput {
public:
// Note that the type below may be misleading. For example, "http:/" alone
// cannot be opened as a URL, so it is marked as a QUERY; yet the user
// probably intends to type more and have it eventually become a URL, so we
// need to make sure we still run it through inline autocomplete.
enum Type {
INVALID, // Empty input
UNKNOWN, // Valid input whose type cannot be determined
REQUESTED_URL, // Input autodetected as UNKNOWN, which the user wants to
// treat as an URL by specifying a desired_tld
URL, // Input autodetected as a URL
QUERY, // Input autodetected as a query
FORCED_QUERY, // Input forced to be a query by an initial '?'
};
AutocompleteInput();
AutocompleteInput(const std::wstring& text,
const std::wstring& desired_tld,
bool prevent_inline_autocomplete,
bool prefer_keyword,
bool synchronous_only);
~AutocompleteInput();
// Converts |type| to a string representation. Used in logging.
static std::string TypeToString(Type type);
// Parses |text| and returns the type of input this will be interpreted as.
// The components of the input are stored in the output parameter |parts|, if
// it is non-NULL.
static Type Parse(const std::wstring& text,
const std::wstring& desired_tld,
url_parse::Parsed* parts,
std::wstring* scheme);
// Parses |text| and fill |scheme| and |host| by the positions of them.
// The results are almost as same as the result of Parse(), but if the scheme
// is view-source, this function returns the positions of scheme and host
// in the URL qualified by "view-source:" prefix.
static void ParseForEmphasizeComponents(const std::wstring& text,
const std::wstring& desired_tld,
url_parse::Component* scheme,
url_parse::Component* host);
// Code that wants to format URLs with a format flag including
// net::kFormatUrlOmitTrailingSlashOnBareHostname risk changing the meaning if
// the result is then parsed as AutocompleteInput. Such code can call this
// function with the URL and its formatted string, and it will return a
// formatted string with the same meaning as the original URL (i.e. it will
// re-append a slash if necessary).
static std::wstring FormattedStringWithEquivalentMeaning(
const GURL& url,
const std::wstring& formatted_url);
// User-provided text to be completed.
const std::wstring& text() const { return text_; }
// Use of this setter is risky, since no other internal state is updated
// besides |text_|. Only callers who know that they're not changing the
// type/scheme/etc. should use this.
void set_text(const std::wstring& text) { text_ = text; }
// User's desired TLD, if one is not already present in the text to
// autocomplete. When this is non-empty, it also implies that "www." should
// be prepended to the domain where possible. This should not have a leading
// '.' (use "com" instead of ".com").
const std::wstring& desired_tld() const { return desired_tld_; }
// The type of input supplied.
Type type() const { return type_; }
// Returns parsed URL components.
const url_parse::Parsed& parts() const { return parts_; }
// The scheme parsed from the provided text; only meaningful when type_ is
// URL.
const std::wstring& scheme() const { return scheme_; }
// The input as an URL to navigate to, if possible.
const GURL& canonicalized_url() const { return canonicalized_url_; }
// Returns whether inline autocompletion should be prevented.
bool prevent_inline_autocomplete() const {
return prevent_inline_autocomplete_;
}
// Returns whether, given an input string consisting solely of a substituting
// keyword, we should score it like a non-substituting keyword.
bool prefer_keyword() const { return prefer_keyword_; }
// Returns whether providers should avoid scheduling asynchronous work. If
// this is true, providers should stop after returning all the
// synchronously-available matches. This also means any in-progress
// asynchronous work should be canceled, so no later callbacks are fired.
bool synchronous_only() const { return synchronous_only_; }
// operator==() by another name.
bool Equals(const AutocompleteInput& other) const;
// Resets all internal variables to the null-constructed state.
void Clear();
private:
std::wstring text_;
std::wstring desired_tld_;
Type type_;
url_parse::Parsed parts_;
std::wstring scheme_;
GURL canonicalized_url_;
bool prevent_inline_autocomplete_;
bool prefer_keyword_;
bool synchronous_only_;
};
// AutocompleteMatch ----------------------------------------------------------
// A single result line with classified spans. The autocomplete popup displays
// the 'contents' and the 'description' (the description is optional) in the
// autocomplete dropdown, and fills in 'fill_into_edit' into the textbox when
// that line is selected. fill_into_edit may be the same as 'description' for
// things like URLs, but may be different for searches or other providers. For
// example, a search result may say "Search for asdf" as the description, but
// "asdf" should appear in the box.
struct AutocompleteMatch {
// Autocomplete matches contain strings that are classified according to a
// separate vector of styles. This vector associates flags with particular
// string segments, and must be in sorted order. All text must be associated
// with some kind of classification. Even if a match has no distinct
// segments, its vector should contain an entry at offset 0 with no flags.
//
// Example: The user typed "goog"
// http://www.google.com/ Google
// ^ ^ ^ ^ ^
// 0, | 15, | 4,
// 11,match 0,match
//
// This structure holds the classification information for each span.
struct ACMatchClassification {
// The values in here are not mutually exclusive -- use them like a
// bitfield. This also means we use "int" instead of this enum type when
// passing the values around, so the compiler doesn't complain.
enum Style {
NONE = 0,
URL = 1 << 0, // A URL
MATCH = 1 << 1, // A match for the user's search term
DIM = 1 << 2, // "Helper text"
};
ACMatchClassification(size_t offset, int style)
: offset(offset),
style(style) {
}
// Offset within the string that this classification starts
size_t offset;
int style;
};
typedef std::vector<ACMatchClassification> ACMatchClassifications;
// The type of this match.
enum Type {
URL_WHAT_YOU_TYPED = 0, // The input as a URL.
HISTORY_URL, // A past page whose URL contains the input.
HISTORY_TITLE, // A past page whose title contains the input.
HISTORY_BODY, // A past page whose body contains the input.
HISTORY_KEYWORD, // A past page whose keyword contains the input.
NAVSUGGEST, // A suggested URL.
SEARCH_WHAT_YOU_TYPED, // The input as a search query (with the default
// engine).
SEARCH_HISTORY, // A past search (with the default engine)
// containing the input.
SEARCH_SUGGEST, // A suggested search (with the default engine).
SEARCH_OTHER_ENGINE, // A search with a non-default engine.
OPEN_HISTORY_PAGE, // A synthetic result that opens the history page
// to search for the input.
NUM_TYPES,
};
AutocompleteMatch();
AutocompleteMatch(AutocompleteProvider* provider,
int relevance,
bool deletable,
Type type);
~AutocompleteMatch();
// Converts |type| to a string representation. Used in logging.
static std::string TypeToString(Type type);
// Converts |type| to a resource identifier for the appropriate icon for this
// type.
static int TypeToIcon(Type type);
// Comparison function for determining when one match is better than another.
static bool MoreRelevant(const AutocompleteMatch& elem1,
const AutocompleteMatch& elem2);
// Comparison functions for removing matches with duplicate destinations.
static bool DestinationSortFunc(const AutocompleteMatch& elem1,
const AutocompleteMatch& elem2);
static bool DestinationsEqual(const AutocompleteMatch& elem1,
const AutocompleteMatch& elem2);
// Helper functions for classes creating matches:
// Fills in the classifications for |text|, using |style| as the base style
// and marking the first instance of |find_text| as a match. (This match
// will also not be dimmed, if |style| has DIM set.)
static void ClassifyMatchInString(const std::wstring& find_text,
const std::wstring& text,
int style,
ACMatchClassifications* classifications);
// Similar to ClassifyMatchInString(), but for cases where the range to mark
// as matching is already known (avoids calling find()). This can be helpful
// when find() would be misleading (e.g. you want to mark the second match in
// a string instead of the first).
static void ClassifyLocationInString(size_t match_location,
size_t match_length,
size_t overall_length,
int style,
ACMatchClassifications* classifications);
// The provider of this match, used to remember which provider the user had
// selected when the input changes. This may be NULL, in which case there is
// no provider (or memory of the user's selection).
AutocompleteProvider* provider;
// The relevance of this match. See table above for scores returned by
// various providers. This is used to rank matches among all responding
// providers, so different providers must be carefully tuned to supply
// matches with appropriate relevance.
//
// If the relevance is negative, it will only be displayed if there are not
// enough non-negative items in all the providers to max out the popup. In
// this case, the relevance of the additional items will be inverted so they
// can be mixed in with the rest of the relevances. This allows a provider
// to group its matches, having the added items appear intermixed with its
// other matches.
//
// TODO(pkasting): http://b/1111299 This should be calculated algorithmically,
// rather than being a fairly fixed value defined by the table above.
int relevance;
// True if the user should be able to delete this match.
bool deletable;
// This string is loaded into the location bar when the item is selected
// by pressing the arrow keys. This may be different than a URL, for example,
// for search suggestions, this would just be the search terms.
std::wstring fill_into_edit;
// The position within fill_into_edit from which we'll display the inline
// autocomplete string. This will be std::wstring::npos if this match should
// not be inline autocompleted.
size_t inline_autocomplete_offset;
// The URL to actually load when the autocomplete item is selected. This URL
// should be canonical so we can compare URLs with strcmp to avoid dupes.
// It may be empty if there is no possible navigation.
GURL destination_url;
// The main text displayed in the address bar dropdown.
std::wstring contents;
ACMatchClassifications contents_class;
// Additional helper text for each entry, such as a title or description.
std::wstring description;
ACMatchClassifications description_class;
// The transition type to use when the user opens this match. By default
// this is TYPED. Providers whose matches do not look like URLs should set
// it to GENERATED.
PageTransition::Type transition;
// True when this match is the "what you typed" match from the history
// system.
bool is_history_what_you_typed_match;
// Type of this match.
Type type;
// If this match corresponds to a keyword, this is the TemplateURL the
// keyword was obtained from.
const TemplateURL* template_url;
// True if the user has starred the destination URL.
bool starred;
#ifndef NDEBUG
// Does a data integrity check on this match.
void Validate() const;
// Checks one text/classifications pair for valid values.
void ValidateClassifications(
const std::wstring& text,
const ACMatchClassifications& classifications) const;
#endif
};
typedef AutocompleteMatch::ACMatchClassification ACMatchClassification;
typedef std::vector<ACMatchClassification> ACMatchClassifications;
// AutocompleteProvider -------------------------------------------------------
// A single result provider for the autocomplete system. Given user input, the
// provider decides what (if any) matches to return, their relevance, and their
// classifications.
class AutocompleteProvider
: public base::RefCountedThreadSafe<AutocompleteProvider> {
public:
class ACProviderListener {
public:
// Called by a provider as a notification that something has changed.
// |updated_matches| should be true iff the matches have changed in some
// way (they may not have changed if, for example, the provider did an
// asynchronous query to get more matches, came up with none, and is now
// giving up).
//
// NOTE: Providers MUST only call this method while processing asynchronous
// queries. Do not call this for a synchronous query.
//
// NOTE: There's no parameter to tell the listener _which_ provider is
// calling it. Because the AutocompleteController (the typical listener)
// doesn't cache the providers' individual matches locally, it has to get
// them all again when this is called anyway, so such a parameter wouldn't
// actually be useful.
virtual void OnProviderUpdate(bool updated_matches) = 0;
protected:
virtual ~ACProviderListener();
};
AutocompleteProvider(ACProviderListener* listener,
Profile* profile,
const char* name);
// Invoked when the profile changes.
// NOTE: Do not access any previous Profile* at this point as it may have
// already been deleted.
void SetProfile(Profile* profile);
// Called to start an autocomplete query. The provider is responsible for
// tracking its matches for this query and whether it is done processing the
// query. When new matches are available or the provider finishes, it
// calls the controller's OnProviderUpdate() method. The controller can then
// get the new matches using the provider's accessors.
// Exception: Matches available immediately after starting the query (that
// is, synchronously) do not cause any notifications to be sent. The
// controller is expected to check for these without prompting (since
// otherwise, starting each provider running would result in a flurry of
// notifications).
//
// Once Stop() has been called, no more notifications should be sent.
//
// |minimal_changes| is an optimization that lets the provider do less work
// when the |input|'s text hasn't changed. See the body of
// AutocompletePopupModel::StartAutocomplete().
virtual void Start(const AutocompleteInput& input,
bool minimal_changes) = 0;
// Called when a provider must not make any more callbacks for the current
// query. This will be called regardless of whether the provider is already
// done.
virtual void Stop();
// Returns the set of matches for the current query.
const ACMatches& matches() const { return matches_; }
// Returns whether the provider is done processing the query.
bool done() const { return done_; }
// Returns the name of this provider.
const char* name() const { return name_; }
// Called to delete a match and the backing data that produced it. This
// match should not appear again in this or future queries. This can only be
// called for matches the provider marks as deletable. This should only be
// called when no query is running.
// NOTE: Remember to call OnProviderUpdate() if matches_ is updated.
virtual void DeleteMatch(const AutocompleteMatch& match);
// A suggested upper bound for how many matches a provider should return.
// TODO(pkasting): http://b/1111299 , http://b/933133 This should go away once
// we have good relevance heuristics; the controller should handle all
// culling.
static const size_t kMaxMatches;
protected:
friend class base::RefCountedThreadSafe<AutocompleteProvider>;
virtual ~AutocompleteProvider();
// Returns whether |input| begins "http:" or "view-source:http:".
static bool HasHTTPScheme(const std::wstring& input);
// Updates the starred state of each of the matches in matches_ from the
// profile's bookmark bar model.
void UpdateStarredStateOfMatches();
// A convenience function to call net::FormatUrl() with the current set of
// "Accept Languages" when check_accept_lang is true. Otherwise, it's called
// with an empty list.
std::wstring StringForURLDisplay(const GURL& url,
bool check_accept_lang,
bool trim_http) const;
// The profile associated with the AutocompleteProvider. Reference is not
// owned by us.
Profile* profile_;
ACProviderListener* listener_;
ACMatches matches_;
bool done_;
// The name of this provider. Used for logging.
const char* name_;
private:
DISALLOW_COPY_AND_ASSIGN(AutocompleteProvider);
};
typedef AutocompleteProvider::ACProviderListener ACProviderListener;
// AutocompleteResult ---------------------------------------------------------
// All matches from all providers for a particular query. This also tracks
// what the default match should be if the user doesn't manually select another
// match.
class AutocompleteResult {
public:
typedef ACMatches::const_iterator const_iterator;
typedef ACMatches::iterator iterator;
// The "Selection" struct is the information we need to select the same match
// in one result set that was selected in another.
struct Selection {
Selection()
: provider_affinity(NULL),
is_history_what_you_typed_match(false) {
}
// Clear the selection entirely.
void Clear();
// True when the selection is empty.
bool empty() const {
return destination_url.is_empty() && !provider_affinity &&
!is_history_what_you_typed_match;
}
// The desired destination URL.
GURL destination_url;
// The desired provider. If we can't find a match with the specified
// |destination_url|, we'll use the best match from this provider.
const AutocompleteProvider* provider_affinity;
// True when this is the HistoryURLProvider's "what you typed" match. This
// can't be tracked using |destination_url| because its URL changes on every
// keystroke, so if this is set, we'll preserve the selection by simply
// choosing the new "what you typed" entry and ignoring |destination_url|.
bool is_history_what_you_typed_match;
};
AutocompleteResult();
// operator=() by another name.
void CopyFrom(const AutocompleteResult& rhs);
// Adds a single match. The match is inserted at the appropriate position
// based on relevancy and display order. This is ONLY for use after
// SortAndCull() has been invoked, and preserves default_match_.
void AddMatch(const AutocompleteMatch& match);
// Adds a new set of matches to the result set. Does not re-sort.
void AppendMatches(const ACMatches& matches);
// Removes duplicates, puts the list in sorted order and culls to leave only
// the best kMaxMatches matches. Sets the default match to the best match
// and updates the alternate nav URL.
void SortAndCull(const AutocompleteInput& input);
// Vector-style accessors/operators.
size_t size() const { return matches_.size(); }
bool empty() const { return matches_.empty(); }
const_iterator begin() const { return matches_.begin(); }
iterator begin() { return matches_.begin(); }
const_iterator end() const { return matches_.end(); }
iterator end() { return matches_.end(); }
// Returns the match at the given index.
const AutocompleteMatch& match_at(size_t index) const {
DCHECK(index < matches_.size());
return matches_[index];
}
// Get the default match for the query (not necessarily the first). Returns
// end() if there is no default match.
const_iterator default_match() const { return default_match_; }
GURL alternate_nav_url() const { return alternate_nav_url_; }
// Clears the matches for this result set.
void Reset() {
matches_.clear();
default_match_ = end();
}
#ifndef NDEBUG
// Does a data integrity check on this result.
void Validate() const;
#endif
// Max number of matches we'll show from the various providers. We may end
// up showing an additional shortcut for Destinations->History, see
// AddHistoryContentsShortcut.
static const size_t kMaxMatches;
private:
ACMatches matches_;
const_iterator default_match_;
// The "alternate navigation URL", if any, for this result set. This is a URL
// to try offering as a navigational option in case the user navigated to the
// URL of the default match but intended something else. For example, if the
// user's local intranet contains site "foo", and the user types "foo", we
// default to searching for "foo" when the user may have meant to navigate
// there. In cases like this, the default match will point to the "search for
// 'foo'" result, and this will contain "http://foo/".
GURL alternate_nav_url_;
DISALLOW_COPY_AND_ASSIGN(AutocompleteResult);
};
// AutocompleteController -----------------------------------------------------
// The coordinator for autocomplete queries, responsible for combining the
// matches from a series of providers into one AutocompleteResult.
class AutocompleteController : public ACProviderListener {
public:
// Used to indicate an index that is not selected in a call to Update().
static const int kNoItemSelected;
// Normally, you will call the first constructor. Unit tests can use the
// second to set the providers to some known testing providers. The default
// providers will be overridden and the controller will take ownership of the
// providers, Release()ing them on destruction.
explicit AutocompleteController(Profile* profile);
#ifdef UNIT_TEST
explicit AutocompleteController(const ACProviders& providers)
: providers_(providers),
history_contents_provider_(NULL),
updated_latest_result_(false),
delay_interval_has_passed_(false),
have_committed_during_this_query_(false),
done_(true) {
}
#endif
~AutocompleteController();
// Invoked when the profile changes. This forwards the call down to all
// the AutocompleteProviders.
void SetProfile(Profile* profile);
// Starts an autocomplete query, which continues until all providers are
// done or the query is Stop()ed. It is safe to Start() a new query without
// Stop()ing the previous one.
//
// See AutocompleteInput::desired_tld() for meaning of |desired_tld|.
//
// |prevent_inline_autocomplete| is true if the generated result set should
// not require inline autocomplete for the default match. This is difficult
// to explain in the abstract; the practical use case is that after the user
// deletes text in the edit, the HistoryURLProvider should make sure not to
// promote a match requiring inline autocomplete too highly.
//
// |prefer_keyword| should be true when the keyword UI is onscreen; this will
// bias the autocomplete result set toward the keyword provider when the input
// string is a bare keyword.
//
// If |synchronous_only| is true, the controller asks the providers to only
// return matches which are synchronously available, which should mean that
// all providers will be done immediately.
//
// The controller will fire
// AUTOCOMPLETE_CONTROLLER_SYNCHRONOUS_MATCHES_AVAILABLE from inside this
// call, and unless the query is stopped, will fire at least one (and perhaps
// more) AUTOCOMPLETE_CONTROLLER_RESULT_UPDATED later as more matches come in
// (even if the query completes synchronously). Listeners should use the
// result set provided in the accompanying Details object to update
// themselves.
void Start(const std::wstring& text,
const std::wstring& desired_tld,
bool prevent_inline_autocomplete,
bool prefer_keyword,
bool synchronous_only);
// Cancels the current query, ensuring there will be no future notifications
// fired. If new matches have come in since the most recent notification was
// fired, they will be discarded.
//
// If |clear_result| is true, the controller will also erase the result set.
void Stop(bool clear_result);
// Asks the relevant provider to delete |match|, and ensures observers are
// notified of resulting changes immediately. This should only be called when
// no query is running.
void DeleteMatch(const AutocompleteMatch& match);
// Commits the results for the current query if they've never been committed.
// This is used by the popup to ensure it's not showing an out-of-date query.
void CommitIfQueryHasNeverBeenCommitted();
// Getters
const AutocompleteInput& input() const { return input_; }
const AutocompleteResult& result() const { return result_; }
// This next is temporary and should go away when
// AutocompletePopup::InfoForCurrentSelection() moves to the controller.
const AutocompleteResult& latest_result() const { return latest_result_; }
bool done() const { return done_ && !update_delay_timer_.IsRunning(); }
// From AutocompleteProvider::Listener
virtual void OnProviderUpdate(bool updated_matches);
private:
// Updates |latest_result_| and |done_| to reflect the current provider state.
// Resets timers and fires notifications as necessary. |is_synchronous_pass|
// is true only when Start() is calling this to get the synchronous result.
void UpdateLatestResult(bool is_synchronous_pass);
// Callback for when |max_delay_timer_| fires; this notes that the delay
// interval has passed and commits the result, if it's changed.
void DelayTimerFired();
// Copies |latest_result_| to |result_| and notifies observers of updates.
// |notify_default_match| should normally be true; if it's false, we don't
// send an AUTOCOMPLETE_CONTROLLER_DEFAULT_MATCH_UPDATED notification. This
// is a hack to avoid updating the edit with out-of-date data.
// TODO(pkasting): Don't hardcode assumptions about who listens to these
// notificiations.
void CommitResult(bool notify_default_match);
// Returns the matches from |provider| whose destination urls are not in
// |latest_result_|.
ACMatches GetMatchesNotInLatestResult(
const AutocompleteProvider* provider) const;
// If the HistoryContentsAutocomplete provider is done and there are more
// matches in the database than currently shown, an entry is added to
// |latest_result_| to show all history matches.
void AddHistoryContentsShortcut();
// Updates |done_| to be accurate with respect to current providers' statuses.
void CheckIfDone();
// A list of all providers.
ACProviders providers_;
HistoryContentsProvider* history_contents_provider_;
// Input passed to Start.
AutocompleteInput input_;
// Data from the autocomplete query.
AutocompleteResult result_;
// The latest result available from the autocomplete providers. This may be
// different than |result_| if we've gotten matches from our providers that we
// haven't yet shown the user. If there aren't yet as many matches as in
// |result|, we'll wait to display these in hopes of minimizing flicker in GUI
// observers.
AutocompleteResult latest_result_;
// True if |latest_result_| has been updated since it was last committed to
// |result_|. Used to determine whether we need to commit any changes.
bool updated_latest_result_;
// True when it's been at least one interval of the delay timer since we
// committed any updates. This is used to allow a new update to be committed
// immediately.
//
// NOTE: This can never be true when |have_committed_during_this_query_| is
// false (except transiently while processing the timer firing).
bool delay_interval_has_passed_;
// True when we've committed a result set at least once during this query.
// When this is false, we commit immediately when |done_| is set, since there
// are no more updates to come and thus no possible flicker due to committing
// immediately.
//
// NOTE: This can never be false when |delay_interval_has_passed_| is true
// (except transiently while processing the timer firing).
bool have_committed_during_this_query_;
// True if a query is not currently running.
bool done_;
// Timer that tracks how long it's been since the last time we sent our
// observers a new result set. This is used both to enforce a lower bound on
// the delay between most commits (to reduce flicker), and ensure that updates
// eventually get committed no matter what delays occur between them or how
// fast or continuously the user is typing.
base::RepeatingTimer<AutocompleteController> update_delay_timer_;
DISALLOW_COPY_AND_ASSIGN(AutocompleteController);
};
// AutocompleteLog ------------------------------------------------------------
// The data to log (via the metrics service) when the user selects an item
// from the omnibox popup.
struct AutocompleteLog {
AutocompleteLog(std::wstring text,
AutocompleteInput::Type input_type,
size_t selected_index,
size_t inline_autocompleted_length,
const AutocompleteResult& result)
: text(text),
input_type(input_type),
selected_index(selected_index),
inline_autocompleted_length(inline_autocompleted_length),
result(result) {
}
// The user's input text in the omnibox.
std::wstring text;
// The detected type of the user's input.
AutocompleteInput::Type input_type;
// Selected index (if selected) or -1 (AutocompletePopupModel::kNoMatch).
size_t selected_index;
// Inline autocompleted length (if displayed).
size_t inline_autocompleted_length;
// Result set.
const AutocompleteResult& result;
};
#endif // CHROME_BROWSER_AUTOCOMPLETE_AUTOCOMPLETE_H_