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