• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2014 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 COMPONENTS_OMNIBOX_AUTOCOMPLETE_RESULT_H_
6 #define COMPONENTS_OMNIBOX_AUTOCOMPLETE_RESULT_H_
7 
8 #include <stddef.h>
9 
10 #include <map>
11 
12 #include "base/basictypes.h"
13 #include "components/metrics/proto/omnibox_event.pb.h"
14 #include "components/omnibox/autocomplete_match.h"
15 #include "url/gurl.h"
16 
17 class AutocompleteInput;
18 class AutocompleteProvider;
19 class TemplateURLService;
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 {
SelectionSelection32     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.
emptySelection41     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                       TemplateURLService* template_url_service);
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,
79                    TemplateURLService* template_url_service);
80 
81   // Returns true if at least one match was copied from the last result.
82   bool HasCopiedMatches() const;
83 
84   // Vector-style accessors/operators.
85   size_t size() const;
86   bool empty() const;
87   const_iterator begin() const;
88   iterator begin();
89   const_iterator end() const;
90   iterator end();
91 
92   // Returns the match at the given index.
93   const AutocompleteMatch& match_at(size_t index) const;
94   AutocompleteMatch* match_at(size_t index);
95 
96   // Get the default match for the query (not necessarily the first).  Returns
97   // end() if there is no default match.
default_match()98   const_iterator default_match() const { return default_match_; }
99 
100   // Returns true if the top match is a verbatim search or URL match (see
101   // IsVerbatimType() in autocomplete_match.h), and the next match is not also
102   // some kind of verbatim match.  In this case, the top match will be hidden,
103   // and nothing in the dropdown will appear selected by default; hitting enter
104   // will navigate to the (hidden) default match, while pressing the down arrow
105   // key will select the first visible match, which is actually the second match
106   // in the result set.
107   //
108   // Hiding the top match in these cases is possible because users should
109   // already know what will happen on hitting enter from the omnibox text
110   // itself, without needing to see the same text appear again, selected, just
111   // below their typing.  Instead, by hiding the verbatim match, there is one
112   // less line to skip over in order to visually scan downwards to see other
113   // suggested matches.  This makes it more likely that users will see and
114   // select useful non-verbatim matches.  (Note that hiding the verbatim match
115   // this way is similar to how most other browsers' address bars behave.)
116   //
117   // We avoid hiding when the top two matches are both verbatim in order to
118   // avoid potential confusion if a user were to see the second match just below
119   // their typing and assume it would be the default action.
120   //
121   // Note that if the top match should be hidden and it is the only match,
122   // the dropdown should be closed.
123   bool ShouldHideTopMatch() const;
124 
125   // Returns true if the top match is a verbatim search or URL match (see
126   // IsVerbatimType() in autocomplete_match.h), and the next match is not also
127   // some kind of verbatim match.
128   bool TopMatchIsStandaloneVerbatimMatch() const;
129 
alternate_nav_url()130   const GURL& alternate_nav_url() const { return alternate_nav_url_; }
131 
132   // Clears the matches for this result set.
133   void Reset();
134 
135   void Swap(AutocompleteResult* other);
136 
137 #ifndef NDEBUG
138   // Does a data integrity check on this result.
139   void Validate() const;
140 #endif
141 
142   // Compute the "alternate navigation URL" for a given match. This is obtained
143   // by interpreting the user input directly as a URL. See comments on
144   // |alternate_nav_url_|.
145   static GURL ComputeAlternateNavUrl(const AutocompleteInput& input,
146                                      const AutocompleteMatch& match);
147 
148   // Sort |matches| by destination, taking into account demotions based on
149   // |page_classification| when resolving ties about which of several
150   // duplicates to keep.  The matches are also deduplicated.  If
151   // |set_duplicate_matches| is true, the duplicate matches are stored in the
152   // |duplicate_matches| vector of the corresponding AutocompleteMatch.
153   static void DedupMatchesByDestination(
154       metrics::OmniboxEventProto::PageClassification page_classification,
155       bool set_duplicate_matches,
156       ACMatches* matches);
157 
158  private:
159   friend class AutocompleteProviderTest;
160 
161   typedef std::map<AutocompleteProvider*, ACMatches> ProviderToMatches;
162 
163 #if defined(OS_ANDROID)
164   // iterator::difference_type is not defined in the STL that we compile with on
165   // Android.
166   typedef int matches_difference_type;
167 #else
168   typedef ACMatches::iterator::difference_type matches_difference_type;
169 #endif
170 
171   // Returns true if |matches| contains a match with the same destination as
172   // |match|.
173   static bool HasMatchByDestination(const AutocompleteMatch& match,
174                                     const ACMatches& matches);
175 
176   // operator=() by another name.
177   void CopyFrom(const AutocompleteResult& rhs);
178 
179   // Populates |provider_to_matches| from |matches_|.
180   void BuildProviderToMatches(ProviderToMatches* provider_to_matches) const;
181 
182   // Copies matches into this result. |old_matches| gives the matches from the
183   // last result, and |new_matches| the results from this result.
184   void MergeMatchesByProvider(
185       metrics::OmniboxEventProto::PageClassification page_classification,
186       const ACMatches& old_matches,
187       const ACMatches& new_matches);
188 
189   ACMatches matches_;
190 
191   const_iterator default_match_;
192 
193   // The "alternate navigation URL", if any, for this result set.  This is a URL
194   // to try offering as a navigational option in case the user navigated to the
195   // URL of the default match but intended something else.  For example, if the
196   // user's local intranet contains site "foo", and the user types "foo", we
197   // default to searching for "foo" when the user may have meant to navigate
198   // there.  In cases like this, the default match will point to the "search for
199   // 'foo'" result, and this will contain "http://foo/".
200   GURL alternate_nav_url_;
201 
202   DISALLOW_COPY_AND_ASSIGN(AutocompleteResult);
203 };
204 
205 #endif  // COMPONENTS_OMNIBOX_AUTOCOMPLETE_RESULT_H_
206