• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2011 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/memory/scoped_ptr.h"
16 #include "base/observer_list.h"
17 #include "chrome/browser/search_engines/search_host_to_urls_map.h"
18 #include "chrome/browser/search_engines/template_url_id.h"
19 #include "chrome/browser/webdata/web_data_service.h"
20 #include "content/common/notification_observer.h"
21 #include "content/common/notification_registrar.h"
22 
23 class GURL;
24 class Extension;
25 class PrefService;
26 class Profile;
27 class PrefSetObserver;
28 class SearchHostToURLsMap;
29 class SearchTermsData;
30 class TemplateURLModelObserver;
31 class TemplateURLRef;
32 
33 namespace history {
34 struct 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 its
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 
58 class TemplateURLModel : public WebDataServiceConsumer,
59                          public NotificationObserver {
60  public:
61   typedef std::map<std::string, std::string> QueryTerms;
62   typedef std::vector<const TemplateURL*> TemplateURLVector;
63 
64   // Struct used for initializing the data store with fake data.
65   // Each initializer is mapped to a TemplateURL.
66   struct Initializer {
67     const char* const keyword;
68     const char* const url;
69     const char* const content;
70   };
71 
72   explicit TemplateURLModel(Profile* profile);
73   // The following is for testing.
74   TemplateURLModel(const Initializer* initializers, const int count);
75   virtual ~TemplateURLModel();
76 
77   // Generates a suitable keyword for the specified url.  Returns an empty
78   // string if a keyword couldn't be generated.  If |autodetected| is true, we
79   // don't generate keywords for a variety of situations where we would probably
80   // not want to auto-add keywords, such as keywords for searches on pages that
81   // themselves come from form submissions.
82   static string16 GenerateKeyword(const GURL& url, bool autodetected);
83 
84   // Removes any unnecessary characters from a user input keyword.
85   // This removes the leading scheme, "www." and any trailing slash.
86   static string16 CleanUserInputKeyword(const string16& keyword);
87 
88   // Returns the search url for t_url.  Returns an empty GURL if t_url has no
89   // url().
90   static GURL GenerateSearchURL(const TemplateURL* t_url);
91 
92   // Just like GenerateSearchURL except that it takes SearchTermsData to supply
93   // the data for some search terms. Most of the time GenerateSearchURL should
94   // be called.
95   static GURL GenerateSearchURLUsingTermsData(
96       const TemplateURL* t_url,
97       const SearchTermsData& search_terms_data);
98 
99   // Returns true if there is no TemplateURL that conflicts with the
100   // keyword/url pair, or there is one but it can be replaced. If there is an
101   // existing keyword that can be replaced and template_url_to_replace is
102   // non-NULL, template_url_to_replace is set to the keyword to replace.
103   //
104   // url gives the url of the search query. The url is used to avoid generating
105   // a TemplateURL for an existing TemplateURL that shares the same host.
106   bool CanReplaceKeyword(const string16& keyword,
107                          const GURL& url,
108                          const TemplateURL** template_url_to_replace);
109 
110   // Returns (in |matches|) all keywords beginning with |prefix|, sorted
111   // shortest-first. If support_replacement_only is true, only keywords that
112   // support replacement are returned.
113   void FindMatchingKeywords(const string16& prefix,
114                             bool support_replacement_only,
115                             std::vector<string16>* matches) const;
116 
117   // Looks up |keyword| and returns the element it maps to.  Returns NULL if
118   // the keyword was not found.
119   // The caller should not try to delete the returned pointer; the data store
120   // retains ownership of it.
121   const TemplateURL* GetTemplateURLForKeyword(const string16& 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(const Extension* extension);
148 
149   // Removes the TemplateURL containing the keyword for the given extension,
150   // if any.
151   void UnregisterExtensionKeyword(const 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(
157       const Extension* extension) const;
158 
159   // Returns the set of URLs describing the keywords. The elements are owned
160   // by TemplateURLModel and should not be deleted.
161   TemplateURLVector GetTemplateURLs() const;
162 
163   // Increment the usage count of a keyword.
164   // Called when a URL is loaded that was generated from a keyword.
165   void IncrementUsageCount(const TemplateURL* url);
166 
167   // Resets the title, keyword and search url of the specified TemplateURL.
168   // The TemplateURL is marked as not replaceable.
169   void ResetTemplateURL(const TemplateURL* url,
170                         const string16& title,
171                         const string16& keyword,
172                         const std::string& search_url);
173 
174   // Return true if the given |url| can be made the default.
175   bool CanMakeDefault(const TemplateURL* url);
176 
177   // Set the default search provider.  |url| may be null.
178   // This will assert if the default search is managed; the UI should not be
179   // invoking this method in that situation.
180   void SetDefaultSearchProvider(const TemplateURL* url);
181 
182   // Returns the default search provider. If the TemplateURLModel hasn't been
183   // loaded, the default search provider is pulled from preferences.
184   //
185   // NOTE: At least in unittest mode, this may return NULL.
186   const TemplateURL* GetDefaultSearchProvider();
187 
188   // Returns true if the default search is managed through group policy.
is_default_search_managed()189   bool is_default_search_managed() const { return is_default_search_managed_; }
190 
191   // Observers used to listen for changes to the model.
192   // TemplateURLModel does NOT delete the observers when deleted.
193   void AddObserver(TemplateURLModelObserver* observer);
194   void RemoveObserver(TemplateURLModelObserver* observer);
195 
196   // Loads the keywords. This has no effect if the keywords have already been
197   // loaded.
198   // Observers are notified when loading completes via the method
199   // OnTemplateURLModelChanged.
200   void Load();
201 
202   // Whether or not the keywords have been loaded.
loaded()203   bool loaded() { return loaded_; }
204 
205   // Notification that the keywords have been loaded.
206   // This is invoked from WebDataService, and should not be directly
207   // invoked.
208   virtual void OnWebDataServiceRequestDone(WebDataService::Handle h,
209                                            const WDTypedResult* result);
210 
211   // Returns the locale-direction-adjusted short name for the given keyword.
212   // Also sets the out param to indicate whether the keyword belongs to an
213   // extension.
214   string16 GetKeywordShortName(const string16& keyword,
215                                bool* is_extension_keyword);
216 
217   // NotificationObserver method. TemplateURLModel listens for three
218   // notification types:
219   // . NOTIFY_HISTORY_URL_VISITED: adds keyword search terms if the visit
220   //   corresponds to a keyword.
221   // . NOTIFY_GOOGLE_URL_UPDATED: updates mapping for any keywords containing
222   //   a google base url replacement term.
223   // . PREF_CHANGED: checks whether the default search engine has changed.
224   virtual void Observe(NotificationType type,
225                        const NotificationSource& source,
226                        const NotificationDetails& details);
227 
profile()228   Profile* profile() const { return profile_; }
229 
SetSearchEngineDialogSlot(int slot)230   void SetSearchEngineDialogSlot(int slot) {
231     search_engine_dialog_chosen_slot_ = slot;
232   }
233 
GetSearchEngineDialogSlot()234   int GetSearchEngineDialogSlot() const {
235     return search_engine_dialog_chosen_slot_;
236   }
237 
238   // Registers the preferences used to save a TemplateURL to prefs.
239   static void RegisterUserPrefs(PrefService* prefs);
240 
241  protected:
242   // Cover method for the method of the same name on the HistoryService.
243   // url is the one that was visited with the given search terms.
244   //
245   // This exists and is virtual for testing.
246   virtual void SetKeywordSearchTermsForURL(const TemplateURL* t_url,
247                                            const GURL& url,
248                                            const string16& term);
249 
250  private:
251   FRIEND_TEST_ALL_PREFIXES(TemplateURLModelTest, BuildQueryTerms);
252   FRIEND_TEST_ALL_PREFIXES(TemplateURLModelTest, TestManagedDefaultSearch);
253   FRIEND_TEST_ALL_PREFIXES(TemplateURLModelTest,
254                            UpdateKeywordSearchTermsForURL);
255   FRIEND_TEST_ALL_PREFIXES(TemplateURLModelTest,
256                            DontUpdateKeywordSearchForNonReplaceable);
257   FRIEND_TEST_ALL_PREFIXES(TemplateURLModelTest, ChangeGoogleBaseValue);
258   FRIEND_TEST_ALL_PREFIXES(TemplateURLModelTest, MergeDeletesUnusedProviders);
259   friend class TemplateURLModelTestUtil;
260 
261   typedef std::map<string16, const TemplateURL*> KeywordToTemplateMap;
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