Home | History | Annotate | Download | only in autocomplete
      1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #ifndef CHROME_BROWSER_AUTOCOMPLETE_AUTOCOMPLETE_RESULT_H_
      6 #define CHROME_BROWSER_AUTOCOMPLETE_AUTOCOMPLETE_RESULT_H_
      7 
      8 #include <stddef.h>
      9 
     10 #include <map>
     11 
     12 #include "base/basictypes.h"
     13 #include "chrome/browser/autocomplete/autocomplete_input.h"
     14 #include "chrome/browser/autocomplete/autocomplete_match.h"
     15 #include "components/metrics/proto/omnibox_event.pb.h"
     16 #include "url/gurl.h"
     17 
     18 class AutocompleteProvider;
     19 class Profile;
     20 
     21 // All matches from all providers for a particular query.  This also tracks
     22 // what the default match should be if the user doesn't manually select another
     23 // match.
     24 class AutocompleteResult {
     25  public:
     26   typedef ACMatches::const_iterator const_iterator;
     27   typedef ACMatches::iterator iterator;
     28 
     29   // The "Selection" struct is the information we need to select the same match
     30   // in one result set that was selected in another.
     31   struct Selection {
     32     Selection()
     33         : provider_affinity(NULL),
     34           is_history_what_you_typed_match(false) {
     35     }
     36 
     37     // Clear the selection entirely.
     38     void Clear();
     39 
     40     // True when the selection is empty.
     41     bool empty() const {
     42       return destination_url.is_empty() && !provider_affinity &&
     43           !is_history_what_you_typed_match;
     44     }
     45 
     46     // The desired destination URL.
     47     GURL destination_url;
     48 
     49     // The desired provider.  If we can't find a match with the specified
     50     // |destination_url|, we'll use the best match from this provider.
     51     const AutocompleteProvider* provider_affinity;
     52 
     53     // True when this is the HistoryURLProvider's "what you typed" match.  This
     54     // can't be tracked using |destination_url| because its URL changes on every
     55     // keystroke, so if this is set, we'll preserve the selection by simply
     56     // choosing the new "what you typed" entry and ignoring |destination_url|.
     57     bool is_history_what_you_typed_match;
     58   };
     59 
     60   // Max number of matches we'll show from the various providers.
     61   static const size_t kMaxMatches;
     62 
     63   AutocompleteResult();
     64   ~AutocompleteResult();
     65 
     66   // Copies matches from |old_matches| to provide a consistant result set. See
     67   // comments in code for specifics.
     68   void CopyOldMatches(const AutocompleteInput& input,
     69                       const AutocompleteResult& old_matches,
     70                       Profile* profile);
     71 
     72   // Adds a new set of matches to the result set.  Does not re-sort.
     73   void AppendMatches(const ACMatches& matches);
     74 
     75   // Removes duplicates, puts the list in sorted order and culls to leave only
     76   // the best kMaxMatches matches.  Sets the default match to the best match
     77   // and updates the alternate nav URL.
     78   void SortAndCull(const AutocompleteInput& input, Profile* profile);
     79 
     80   // Returns true if at least one match was copied from the last result.
     81   bool HasCopiedMatches() const;
     82 
     83   // Vector-style accessors/operators.
     84   size_t size() const;
     85   bool empty() const;
     86   const_iterator begin() const;
     87   iterator begin();
     88   const_iterator end() const;
     89   iterator end();
     90 
     91   // Returns the match at the given index.
     92   const AutocompleteMatch& match_at(size_t index) const;
     93   AutocompleteMatch* match_at(size_t index);
     94 
     95   // Get the default match for the query (not necessarily the first).  Returns
     96   // end() if there is no default match.
     97   const_iterator default_match() const { return default_match_; }
     98 
     99   // Returns true if the top match is a verbatim search or URL match (see
    100   // IsVerbatimType() in autocomplete_match.h), and the next match is not also
    101   // some kind of verbatim match.  In this case, the top match will be hidden,
    102   // and nothing in the dropdown will appear selected by default; hitting enter
    103   // will navigate to the (hidden) default match, while pressing the down arrow
    104   // key will select the first visible match, which is actually the second match
    105   // in the result set.
    106   //
    107   // Hiding the top match in these cases is possible because users should
    108   // already know what will happen on hitting enter from the omnibox text
    109   // itself, without needing to see the same text appear again, selected, just
    110   // below their typing.  Instead, by hiding the verbatim match, there is one
    111   // less line to skip over in order to visually scan downwards to see other
    112   // suggested matches.  This makes it more likely that users will see and
    113   // select useful non-verbatim matches.  (Note that hiding the verbatim match
    114   // this way is similar to how most other browsers' address bars behave.)
    115   //
    116   // We avoid hiding when the top two matches are both verbatim in order to
    117   // avoid potential confusion if a user were to see the second match just below
    118   // their typing and assume it would be the default action.
    119   //
    120   // Note that if the top match should be hidden and it is the only match,
    121   // the dropdown should be closed.
    122   bool ShouldHideTopMatch() const;
    123 
    124   // Returns true if the top match is a verbatim search or URL match (see
    125   // IsVerbatimType() in autocomplete_match.h), and the next match is not also
    126   // some kind of verbatim match.
    127   bool TopMatchIsStandaloneVerbatimMatch() const;
    128 
    129   const GURL& alternate_nav_url() const { return alternate_nav_url_; }
    130 
    131   // Clears the matches for this result set.
    132   void Reset();
    133 
    134   void Swap(AutocompleteResult* other);
    135 
    136 #ifndef NDEBUG
    137   // Does a data integrity check on this result.
    138   void Validate() const;
    139 #endif
    140 
    141   // Compute the "alternate navigation URL" for a given match. This is obtained
    142   // by interpreting the user input directly as a URL. See comments on
    143   // |alternate_nav_url_|.
    144   static GURL ComputeAlternateNavUrl(const AutocompleteInput& input,
    145                                      const AutocompleteMatch& match);
    146 
    147   // Sort |matches| by destination, taking into account demotions based on
    148   // |page_classification| when resolving ties about which of several
    149   // duplicates to keep.  The matches are also deduplicated.  If
    150   // |set_duplicate_matches| is true, the duplicate matches are stored in the
    151   // |duplicate_matches| vector of the corresponding AutocompleteMatch.
    152   static void DedupMatchesByDestination(
    153       metrics::OmniboxEventProto::PageClassification page_classification,
    154       bool set_duplicate_matches,
    155       ACMatches* matches);
    156 
    157  private:
    158   friend class AutocompleteProviderTest;
    159 
    160   typedef std::map<AutocompleteProvider*, ACMatches> ProviderToMatches;
    161 
    162 #if defined(OS_ANDROID)
    163   // iterator::difference_type is not defined in the STL that we compile with on
    164   // Android.
    165   typedef int matches_difference_type;
    166 #else
    167   typedef ACMatches::iterator::difference_type matches_difference_type;
    168 #endif
    169 
    170   // Returns true if |matches| contains a match with the same destination as
    171   // |match|.
    172   static bool HasMatchByDestination(const AutocompleteMatch& match,
    173                                     const ACMatches& matches);
    174 
    175   // operator=() by another name.
    176   void CopyFrom(const AutocompleteResult& rhs);
    177 
    178   // Populates |provider_to_matches| from |matches_|.
    179   void BuildProviderToMatches(ProviderToMatches* provider_to_matches) const;
    180 
    181   // Copies matches into this result. |old_matches| gives the matches from the
    182   // last result, and |new_matches| the results from this result.
    183   void MergeMatchesByProvider(
    184       metrics::OmniboxEventProto::PageClassification page_classification,
    185       const ACMatches& old_matches,
    186       const ACMatches& new_matches);
    187 
    188   ACMatches matches_;
    189 
    190   const_iterator default_match_;
    191 
    192   // The "alternate navigation URL", if any, for this result set.  This is a URL
    193   // to try offering as a navigational option in case the user navigated to the
    194   // URL of the default match but intended something else.  For example, if the
    195   // user's local intranet contains site "foo", and the user types "foo", we
    196   // default to searching for "foo" when the user may have meant to navigate
    197   // there.  In cases like this, the default match will point to the "search for
    198   // 'foo'" result, and this will contain "http://foo/".
    199   GURL alternate_nav_url_;
    200 
    201   DISALLOW_COPY_AND_ASSIGN(AutocompleteResult);
    202 };
    203 
    204 #endif  // CHROME_BROWSER_AUTOCOMPLETE_AUTOCOMPLETE_RESULT_H_
    205