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