template_url_model.h revision 3345a6884c488ff3a535c2c9acdd33d74b37e311
1// Copyright (c) 2010 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_SEARCH_ENGINES_TEMPLATE_URL_MODEL_H_
6#define CHROME_BROWSER_SEARCH_ENGINES_TEMPLATE_URL_MODEL_H_
7#pragma once
8
9#include <set>
10
11#include "base/gtest_prod_util.h"
12#include "base/observer_list.h"
13#include "base/scoped_ptr.h"
14#include "chrome/browser/search_engines/template_url_id.h"
15#include "chrome/browser/webdata/web_data_service.h"
16#include "chrome/browser/search_engines/search_host_to_urls_map.h"
17#include "chrome/common/notification_observer.h"
18#include "chrome/common/notification_registrar.h"
19
20class GURL;
21class Extension;
22class PrefService;
23class Profile;
24class SearchHostToURLsMap;
25class SearchTermsData;
26class TemplateURLModelObserver;
27
28namespace history {
29struct URLVisitedDetails;
30}
31
32// TemplateURLModel is the backend for keywords. It's used by
33// KeywordAutocomplete.
34//
35// TemplateURLModel stores a vector of TemplateURLs. The TemplateURLs are
36// persisted to the database maintained by WebDataService. *ALL* mutations
37// to the TemplateURLs must funnel through TemplateURLModel. This allows
38// TemplateURLModel to notify listeners of changes as well as keep the
39// database in sync.
40//
41// There is a TemplateURLModel per Profile.
42//
43// TemplateURLModel does not load the vector of TemplateURLs in it's
44// constructor (except for testing). Use the Load method to trigger a load.
45// When TemplateURLModel has completed loading, observers are notified via
46// OnTemplateURLModelChanged as well as the TEMPLATE_URL_MODEL_LOADED
47// notification message.
48//
49// TemplateURLModel takes ownership of any TemplateURL passed to it. If there
50// is a WebDataService, deletion is handled by WebDataService, otherwise
51// TemplateURLModel handles deletion.
52
53class TemplateURLModel : public WebDataServiceConsumer,
54                         public NotificationObserver {
55 public:
56  typedef std::map<std::string, std::string> QueryTerms;
57
58  // Struct used for initializing the data store with fake data.
59  // Each initializer is mapped to a TemplateURL.
60  struct Initializer {
61    const wchar_t* const keyword;
62    const char* const url;
63    const wchar_t* const content;
64  };
65
66  explicit TemplateURLModel(Profile* profile);
67  // The following is for testing.
68  TemplateURLModel(const Initializer* initializers, const int count);
69  virtual ~TemplateURLModel();
70
71  // Generates a suitable keyword for the specified url.  Returns an empty
72  // string if a keyword couldn't be generated.  If |autodetected| is true, we
73  // don't generate keywords for a variety of situations where we would probably
74  // not want to auto-add keywords, such as keywords for searches on pages that
75  // themselves come from form submissions.
76  static std::wstring GenerateKeyword(const GURL& url, bool autodetected);
77
78  // Removes any unnecessary characters from a user input keyword.
79  // This removes the leading scheme, "www." and any trailing slash.
80  static std::wstring CleanUserInputKeyword(const std::wstring& keyword);
81
82  // Returns the search url for t_url.  Returns an empty GURL if t_url has no
83  // url().
84  static GURL GenerateSearchURL(const TemplateURL* t_url);
85
86  // Just like GenerateSearchURL except that it takes SearchTermsData to supply
87  // the data for some search terms. Most of the time GenerateSearchURL should
88  // be called.
89  static GURL GenerateSearchURLUsingTermsData(
90      const TemplateURL* t_url,
91      const SearchTermsData& search_terms_data);
92
93  // Returns true if there is no TemplateURL that conflicts with the
94  // keyword/url pair, or there is one but it can be replaced. If there is an
95  // existing keyword that can be replaced and template_url_to_replace is
96  // non-NULL, template_url_to_replace is set to the keyword to replace.
97  //
98  // url gives the url of the search query. The url is used to avoid generating
99  // a TemplateURL for an existing TemplateURL that shares the same host.
100  bool CanReplaceKeyword(const std::wstring& keyword,
101                         const GURL& url,
102                         const TemplateURL** template_url_to_replace);
103
104  // Returns (in |matches|) all keywords beginning with |prefix|, sorted
105  // shortest-first. If support_replacement_only is true, only keywords that
106  // support replacement are returned.
107  void FindMatchingKeywords(const std::wstring& prefix,
108                            bool support_replacement_only,
109                            std::vector<std::wstring>* matches) const;
110
111  // Looks up |keyword| and returns the element it maps to.  Returns NULL if
112  // the keyword was not found.
113  // The caller should not try to delete the returned pointer; the data store
114  // retains ownership of it.
115  const TemplateURL* GetTemplateURLForKeyword(
116    const std::wstring& keyword) const;
117
118  // Returns the first TemplateURL found with a URL using the specified |host|,
119  // or NULL if there are no such TemplateURLs
120  const TemplateURL* GetTemplateURLForHost(const std::string& host) const;
121
122  // Adds a new TemplateURL to this model. TemplateURLModel will own the
123  // reference, and delete it when the TemplateURL is removed.
124  void Add(TemplateURL* template_url);
125
126  // Removes the keyword from the model. This deletes the supplied TemplateURL.
127  // This fails if the supplied template_url is the default search provider.
128  void Remove(const TemplateURL* template_url);
129
130  // Removes all auto-generated keywords that were created in the specified
131  // range.
132  void RemoveAutoGeneratedBetween(base::Time created_after,
133                                  base::Time created_before);
134
135  // Removes all auto-generated keywords that were created on or after the
136  // date passed in.
137  void RemoveAutoGeneratedSince(base::Time created_after);
138
139  // If the given extension has an omnibox keyword, adds a TemplateURL for that
140  // keyword. Only 1 keyword is allowed for a given extension. If the keyword
141  // already exists for this extension, does nothing.
142  void RegisterExtensionKeyword(Extension* extension);
143
144  // Removes the TemplateURL containing the keyword for the given extension,
145  // if any.
146  void UnregisterExtensionKeyword(Extension* extension);
147
148  // Returns the TemplateURL associated with the keyword for this extension.
149  // This works by checking the extension ID, not the keyword, so it will work
150  // even if the user changed the keyword.
151  const TemplateURL* GetTemplateURLForExtension(Extension* extension) const;
152
153  // Returns the set of URLs describing the keywords. The elements are owned
154  // by TemplateURLModel and should not be deleted.
155  std::vector<const TemplateURL*> GetTemplateURLs() const;
156
157  // Increment the usage count of a keyword.
158  // Called when a URL is loaded that was generated from a keyword.
159  void IncrementUsageCount(const TemplateURL* url);
160
161  // Resets the title, keyword and search url of the specified TemplateURL.
162  // The TemplateURL is marked as not replaceable.
163  void ResetTemplateURL(const TemplateURL* url,
164                        const std::wstring& title,
165                        const std::wstring& keyword,
166                        const std::string& search_url);
167
168  // The default search provider. This may be null.
169  void SetDefaultSearchProvider(const TemplateURL* url);
170
171  // Returns the default search provider. If the TemplateURLModel hasn't been
172  // loaded, the default search provider is pulled from preferences.
173  //
174  // NOTE: At least in unittest mode, this may return NULL.
175  const TemplateURL* GetDefaultSearchProvider();
176
177  // Returns true if the default search is managed through group policy.
178  bool IsDefaultSearchManaged();
179
180  // Observers used to listen for changes to the model.
181  // TemplateURLModel does NOT delete the observers when deleted.
182  void AddObserver(TemplateURLModelObserver* observer);
183  void RemoveObserver(TemplateURLModelObserver* observer);
184
185  // Loads the keywords. This has no effect if the keywords have already been
186  // loaded.
187  // Observers are notified when loading completes via the method
188  // OnTemplateURLModelChanged.
189  void Load();
190
191  // Whether or not the keywords have been loaded.
192  bool loaded() { return loaded_; }
193
194  // Notification that the keywords have been loaded.
195  // This is invoked from WebDataService, and should not be directly
196  // invoked.
197  virtual void OnWebDataServiceRequestDone(WebDataService::Handle h,
198                                           const WDTypedResult* result);
199
200  // Returns the locale-direction-adjusted short name for the given keyword.
201  // Also sets the out param to indicate whether the keyword belongs to an
202  // extension.
203  std::wstring GetKeywordShortName(const std::wstring& keyword,
204                                   bool* is_extension_keyword);
205
206  // NotificationObserver method. TemplateURLModel listens for three
207  // notification types:
208  // . NOTIFY_HISTORY_URL_VISITED: adds keyword search terms if the visit
209  //   corresponds to a keyword.
210  // . NOTIFY_GOOGLE_URL_UPDATED: updates mapping for any keywords containing
211  //   a google base url replacement term.
212  virtual void Observe(NotificationType type,
213                       const NotificationSource& source,
214                       const NotificationDetails& details);
215
216  Profile* profile() const { return profile_; }
217
218  void SetSearchEngineDialogSlot(int slot) {
219    search_engine_dialog_chosen_slot_ = slot;
220  }
221
222  int GetSearchEngineDialogSlot() const {
223    return search_engine_dialog_chosen_slot_;
224  }
225
226 protected:
227  // Cover method for the method of the same name on the HistoryService.
228  // url is the one that was visited with the given search terms.
229  //
230  // This exists and is virtual for testing.
231  virtual void SetKeywordSearchTermsForURL(const TemplateURL* t_url,
232                                           const GURL& url,
233                                           const std::wstring& term);
234
235 private:
236  FRIEND_TEST_ALL_PREFIXES(TemplateURLModelTest, BuildQueryTerms);
237  FRIEND_TEST_ALL_PREFIXES(TemplateURLModelTest,
238                           UpdateKeywordSearchTermsForURL);
239  FRIEND_TEST_ALL_PREFIXES(TemplateURLModelTest,
240                           DontUpdateKeywordSearchForNonReplaceable);
241  FRIEND_TEST_ALL_PREFIXES(TemplateURLModelTest, ChangeGoogleBaseValue);
242  FRIEND_TEST_ALL_PREFIXES(TemplateURLModelTest, MergeDeletesUnusedProviders);
243  friend class TemplateURLModelTestUtil;
244
245  typedef std::map<std::wstring, const TemplateURL*> KeywordToTemplateMap;
246  typedef std::vector<const TemplateURL*> TemplateURLVector;
247
248  // Helper functor for FindMatchingKeywords(), for finding the range of
249  // keywords which begin with a prefix.
250  class LessWithPrefix;
251
252  void Init(const Initializer* initializers, int num_initializers);
253
254  void RemoveFromMaps(const TemplateURL* template_url);
255
256  // Removes the supplied template_url from the keyword maps. This searches
257  // through all entries in the keyword map and does not generate the host or
258  // keyword. This is used when the cached content of the TemplateURL changes.
259  void RemoveFromKeywordMapByPointer(const TemplateURL* template_url);
260
261  void AddToMaps(const TemplateURL* template_url);
262
263  // Sets the keywords. This is used once the keywords have been loaded.
264  // This does NOT notify the delegate or the database.
265  void SetTemplateURLs(const std::vector<TemplateURL*>& urls);
266
267  // Transitions to the loaded state.
268  void ChangeToLoadedState();
269
270  // If there is a notification service, sends TEMPLATE_URL_MODEL_LOADED
271  // notification.
272  void NotifyLoaded();
273
274  // Saves enough of url to preferences so that it can be loaded from
275  // preferences on start up.
276  void SaveDefaultSearchProviderToPrefs(const TemplateURL* url);
277
278  // Creates a TemplateURL that was previously saved to prefs via
279  // SaveDefaultSearchProviderToPrefs. Returns true if successful, false
280  // otherwise. This is used if GetDefaultSearchProvider is invoked before the
281  // TemplateURL has loaded. If the user has opted for no default search, this
282  // returns true but default_provider is set to NULL.
283  bool LoadDefaultSearchProviderFromPrefs(TemplateURL** default_provider);
284
285  // Registers the preferences used to save a TemplateURL to prefs.
286  void RegisterPrefs(PrefService* prefs);
287
288  // Returns true if there is no TemplateURL that has a search url with the
289  // specified host, or the only TemplateURLs matching the specified host can
290  // be replaced.
291  bool CanReplaceKeywordForHost(const std::string& host,
292                                const TemplateURL** to_replace);
293
294  // Returns true if the TemplateURL is replaceable. This doesn't look at the
295  // uniqueness of the keyword or host and is intended to be called after those
296  // checks have been done. This returns true if the TemplateURL doesn't appear
297  // in the default list and is marked as safe_for_autoreplace.
298  bool CanReplace(const TemplateURL* t_url);
299
300  // Updates the information in |existing_turl| using the information from
301  // |new_values|, but the ID for |existing_turl| is retained.
302  void Update(const TemplateURL* existing_turl,
303              const TemplateURL& new_values);
304
305  // Returns the preferences we use.
306  PrefService* GetPrefs();
307
308  // Iterates through the TemplateURLs to see if one matches the visited url.
309  // For each TemplateURL whose url matches the visited url
310  // SetKeywordSearchTermsForURL is invoked.
311  void UpdateKeywordSearchTermsForURL(
312      const history::URLVisitedDetails& details);
313
314  // If necessary, generates a visit for the site http:// + t_url.keyword().
315  void AddTabToSearchVisit(const TemplateURL& t_url);
316
317  // Adds each of the query terms in the specified url whose key and value are
318  // non-empty to query_terms. If a query key appears multiple times, the value
319  // is set to an empty string. Returns true if there is at least one key that
320  // does not occur multiple times.
321  static bool BuildQueryTerms(
322      const GURL& url,
323      std::map<std::string,std::string>* query_terms);
324
325  // Invoked when the Google base URL has changed. Updates the mapping for all
326  // TemplateURLs that have a replacement term of {google:baseURL} or
327  // {google:baseSuggestURL}.
328  void GoogleBaseURLChanged();
329
330  NotificationRegistrar registrar_;
331
332  // Mapping from keyword to the TemplateURL.
333  KeywordToTemplateMap keyword_to_template_map_;
334
335  TemplateURLVector template_urls_;
336
337  ObserverList<TemplateURLModelObserver> model_observers_;
338
339  // Maps from host to set of TemplateURLs whose search url host is host.
340  SearchHostToURLsMap provider_map_;
341
342  // Used to obtain the WebDataService.
343  // When Load is invoked, if we haven't yet loaded, the WebDataService is
344  // obtained from the Profile. This allows us to lazily access the database.
345  Profile* profile_;
346
347  // Whether the keywords have been loaded.
348  bool loaded_;
349
350  // Did loading fail? This is only valid if loaded_ is true.
351  bool load_failed_;
352
353  // If non-zero, we're waiting on a load.
354  WebDataService::Handle load_handle_;
355
356  // Service used to store entries.
357  scoped_refptr<WebDataService> service_;
358
359  // All visits that occurred before we finished loading. Once loaded
360  // UpdateKeywordSearchTermsForURL is invoked for each element of the vector.
361  std::vector<history::URLVisitedDetails> visits_to_add_;
362
363  const TemplateURL* default_search_provider_;
364
365  // Used for UX testing. Gives the slot in the search engine dialog that was
366  // chosen as the default search engine.
367  int search_engine_dialog_chosen_slot_;
368
369  // The default search provider from preferences. This is only valid if
370  // GetDefaultSearchProvider is invoked and we haven't been loaded or loading
371  // failed. If loading was successful this is not used.
372  scoped_ptr<TemplateURL> prefs_default_search_provider_;
373
374  // ID assigned to next TemplateURL added to this model. This is an ever
375  // increasing integer that is initialized from the database.
376  TemplateURLID next_id_;
377
378  // List of extension IDs waiting for Load to have keywords registered.
379  std::vector<std::string> pending_extension_ids_;
380
381  DISALLOW_COPY_AND_ASSIGN(TemplateURLModel);
382};
383
384#endif  // CHROME_BROWSER_SEARCH_ENGINES_TEMPLATE_URL_MODEL_H_
385