Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(64)

Side by Side Diff: chrome/browser/search_engines/template_url_service.cc

Issue 10381016: Remove the "autogenerate keyword" bit on TemplateURL. (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: Created 8 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "chrome/browser/search_engines/template_url_service.h" 5 #include "chrome/browser/search_engines/template_url_service.h"
6 6
7 #include "base/auto_reset.h" 7 #include "base/auto_reset.h"
8 #include "base/command_line.h" 8 #include "base/command_line.h"
9 #include "base/environment.h" 9 #include "base/environment.h"
10 #include "base/i18n/case_conversion.h" 10 #include "base/i18n/case_conversion.h"
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after
63 // the rare case the term replaces the URL it's unlikely another keyword would 63 // the rare case the term replaces the URL it's unlikely another keyword would
64 // have the same url. 64 // have the same url.
65 const char kReplacementTerm[] = "blah.blah.blah.blah.blah"; 65 const char kReplacementTerm[] = "blah.blah.blah.blah.blah";
66 66
67 bool TemplateURLsHaveSamePrefs(const TemplateURL* url1, 67 bool TemplateURLsHaveSamePrefs(const TemplateURL* url1,
68 const TemplateURL* url2) { 68 const TemplateURL* url2) {
69 if (url1 == url2) 69 if (url1 == url2)
70 return true; 70 return true;
71 return (url1 != NULL) && (url2 != NULL) && 71 return (url1 != NULL) && (url2 != NULL) &&
72 (url1->short_name() == url2->short_name()) && 72 (url1->short_name() == url2->short_name()) &&
73 (url1->keyword() == url2->keyword()) && 73 url1->HasSameKeywordAs(*url2) &&
74 (url1->url() == url2->url()) && 74 (url1->url() == url2->url()) &&
75 (url1->suggestions_url() == url2->suggestions_url()) && 75 (url1->suggestions_url() == url2->suggestions_url()) &&
76 (url1->instant_url() == url2->instant_url()) && 76 (url1->instant_url() == url2->instant_url()) &&
77 (url1->favicon_url() == url2->favicon_url()) && 77 (url1->favicon_url() == url2->favicon_url()) &&
78 (url1->safe_for_autoreplace() == url2->safe_for_autoreplace()) && 78 (url1->safe_for_autoreplace() == url2->safe_for_autoreplace()) &&
79 (url1->show_in_default_list() == url2->show_in_default_list()) && 79 (url1->show_in_default_list() == url2->show_in_default_list()) &&
80 (url1->input_encodings() == url2->input_encodings()); 80 (url1->input_encodings() == url2->input_encodings());
81 } 81 }
82 82
83 TemplateURL* FirstPotentialDefaultEngine( 83 TemplateURL* FirstPotentialDefaultEngine(
84 const TemplateURLService::TemplateURLVector& template_urls) { 84 const TemplateURLService::TemplateURLVector& template_urls) {
85 for (TemplateURLService::TemplateURLVector::const_iterator i( 85 for (TemplateURLService::TemplateURLVector::const_iterator i(
86 template_urls.begin()); i != template_urls.end(); ++i) { 86 template_urls.begin()); i != template_urls.end(); ++i) {
87 if (!(*i)->IsExtensionKeyword() && (*i)->SupportsReplacement()) 87 if (!(*i)->IsExtensionKeyword() && (*i)->SupportsReplacement())
88 return *i; 88 return *i;
89 } 89 }
90 return NULL; 90 return NULL;
91 } 91 }
92 92
93 // If |change_list| contains ACTION_UPDATEs followed by more ACTION_UPDATEs or
94 // ACTION_ADDs for the same GUID, remove all but the last one.
95 //
96 // Removing UPDATE before ADD is important. This can happen if
97 // ResolveSyncKeywordConflict() changes a local TemplateURL that hasn't actually
98 // been seen by the server yet. In this case sending the UPDATE first might
99 // confuse the sync server.
100 //
101 // Removing UPDATE before UPDATE, OTOH, is not really necessary as the server
102 // will coalesce these before other clients see them; however it's easy to do in
103 // conjunction with the filtering for UPDATE-before-ADD and saves bandwidth.
104 void PreventDuplicateGUIDUpdates(SyncChangeList* change_list) {
105 for (size_t i = change_list->size(); i > 1; ) {
106 --i; // Prevent underflow that could occur if we did this in the loop body.
107 const SyncChange& change_i = (*change_list)[i];
108 if ((change_i.change_type() != SyncChange::ACTION_ADD) &&
109 (change_i.change_type() != SyncChange::ACTION_UPDATE))
110 continue;
111 std::string guid(
112 change_i.sync_data().GetSpecifics().search_engine().sync_guid());
113 for (size_t j = 0; j < i; ) {
114 const SyncChange& change_j = (*change_list)[j];
115 if ((change_j.change_type() == SyncChange::ACTION_UPDATE) &&
116 (change_j.sync_data().GetSpecifics().search_engine().sync_guid() ==
117 guid)) {
118 change_list->erase(change_list->begin() + j);
119 --i;
120 } else {
121 ++j;
122 }
123 }
124 }
125 }
126
93 } // namespace 127 } // namespace
94 128
95 129
96 class TemplateURLService::LessWithPrefix { 130 class TemplateURLService::LessWithPrefix {
97 public: 131 public:
98 // We want to find the set of keywords that begin with a prefix. The STL 132 // We want to find the set of keywords that begin with a prefix. The STL
99 // algorithms will return the set of elements that are "equal to" the 133 // algorithms will return the set of elements that are "equal to" the
100 // prefix, where "equal(x, y)" means "!(cmp(x, y) || cmp(y, x))". When 134 // prefix, where "equal(x, y)" means "!(cmp(x, y) || cmp(y, x))". When
101 // cmp() is the typical std::less<>, this results in lexicographic equality; 135 // cmp() is the typical std::less<>, this results in lexicographic equality;
102 // we need to extend this to mark a prefix as "not less than" a keyword it 136 // we need to extend this to mark a prefix as "not less than" a keyword it
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after
153 TemplateURLService::~TemplateURLService() { 187 TemplateURLService::~TemplateURLService() {
154 if (load_handle_) { 188 if (load_handle_) {
155 DCHECK(service_.get()); 189 DCHECK(service_.get());
156 service_->CancelRequest(load_handle_); 190 service_->CancelRequest(load_handle_);
157 } 191 }
158 192
159 STLDeleteElements(&template_urls_); 193 STLDeleteElements(&template_urls_);
160 } 194 }
161 195
162 // static 196 // static
163 string16 TemplateURLService::GenerateKeyword(const GURL& url, 197 string16 TemplateURLService::GenerateKeyword(const GURL& url) {
164 bool autodetected) { 198 DCHECK(url.is_valid());
165 // Don't autogenerate keywords for referrers that are the result of a form
166 // submission (TODO: right now we approximate this by checking for the URL
167 // having a query, but we should replace this with a call to WebCore to see if
168 // the originating page was actually a form submission), anything other than
169 // http, or referrers with a path.
170 //
171 // If we relax the path constraint, we need to be sure to sanitize the path
172 // elements and update AutocompletePopup to look for keywords using the path.
173 // See http://b/issue?id=863583.
174 if (!url.is_valid() ||
175 (autodetected && (url.has_query() || !url.SchemeIs(chrome::kHttpScheme) ||
176 ((url.path() != "") && (url.path() != "/")))))
177 return string16();
178
179 // Strip "www." off the front of the keyword; otherwise the keyword won't work 199 // Strip "www." off the front of the keyword; otherwise the keyword won't work
180 // properly. See http://code.google.com/p/chromium/issues/detail?id=6984 . 200 // properly. See http://code.google.com/p/chromium/issues/detail?id=6984 .
181 // Special case: if the host was exactly "www." (not sure this can happen but 201 // Special case: if the host was exactly "www." (not sure this can happen but
182 // perhaps with some weird intranet and custom DNS server?), ensure we at 202 // perhaps with some weird intranet and custom DNS server?), ensure we at
183 // least don't return the empty string. 203 // least don't return the empty string.
184 string16 keyword(net::StripWWW(UTF8ToUTF16(url.host()))); 204 string16 keyword(net::StripWWW(UTF8ToUTF16(url.host())));
185 return keyword.empty() ? ASCIIToUTF16("www") : keyword; 205 return keyword.empty() ? ASCIIToUTF16("www") : keyword;
186 } 206 }
187 207
188 // static 208 // static
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
224 DCHECK(t_url); 244 DCHECK(t_url);
225 UIThreadSearchTermsData search_terms_data; 245 UIThreadSearchTermsData search_terms_data;
226 return GenerateSearchURLUsingTermsData(t_url, search_terms_data); 246 return GenerateSearchURLUsingTermsData(t_url, search_terms_data);
227 } 247 }
228 248
229 // static 249 // static
230 GURL TemplateURLService::GenerateSearchURLUsingTermsData( 250 GURL TemplateURLService::GenerateSearchURLUsingTermsData(
231 const TemplateURL* t_url, 251 const TemplateURL* t_url,
232 const SearchTermsData& search_terms_data) { 252 const SearchTermsData& search_terms_data) {
233 DCHECK(t_url); 253 DCHECK(t_url);
254 DCHECK(!t_url->IsExtensionKeyword());
255
234 const TemplateURLRef& search_ref = t_url->url_ref(); 256 const TemplateURLRef& search_ref = t_url->url_ref();
235 // Extension keywords don't have host-based search URLs. 257 if (!search_ref.IsValidUsingTermsData(search_terms_data))
236 if (!search_ref.IsValidUsingTermsData(search_terms_data) ||
237 t_url->IsExtensionKeyword())
238 return GURL(); 258 return GURL();
239 259
240 if (!search_ref.SupportsReplacementUsingTermsData(search_terms_data)) 260 if (!search_ref.SupportsReplacementUsingTermsData(search_terms_data))
241 return GURL(t_url->url()); 261 return GURL(t_url->url());
242 262
243 return GURL(search_ref.ReplaceSearchTermsUsingTermsData( 263 return GURL(search_ref.ReplaceSearchTermsUsingTermsData(
244 ASCIIToUTF16(kReplacementTerm), TemplateURLRef::NO_SUGGESTIONS_AVAILABLE, 264 ASCIIToUTF16(kReplacementTerm), TemplateURLRef::NO_SUGGESTIONS_AVAILABLE,
245 string16(), search_terms_data)); 265 string16(), search_terms_data));
246 } 266 }
247 267
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after
300 matches->push_back(i->first); 320 matches->push_back(i->first);
301 } 321 }
302 } 322 }
303 323
304 TemplateURL* TemplateURLService::GetTemplateURLForKeyword( 324 TemplateURL* TemplateURLService::GetTemplateURLForKeyword(
305 const string16& keyword) { 325 const string16& keyword) {
306 KeywordToTemplateMap::const_iterator elem( 326 KeywordToTemplateMap::const_iterator elem(
307 keyword_to_template_map_.find(keyword)); 327 keyword_to_template_map_.find(keyword));
308 if (elem != keyword_to_template_map_.end()) 328 if (elem != keyword_to_template_map_.end())
309 return elem->second; 329 return elem->second;
310 return (initial_default_search_provider_.get() && 330 return ((!loaded_ || load_failed_) &&
331 initial_default_search_provider_.get() &&
311 (initial_default_search_provider_->keyword() == keyword)) ? 332 (initial_default_search_provider_->keyword() == keyword)) ?
312 initial_default_search_provider_.get() : NULL; 333 initial_default_search_provider_.get() : NULL;
313 } 334 }
314 335
315 TemplateURL* TemplateURLService::GetTemplateURLForGUID( 336 TemplateURL* TemplateURLService::GetTemplateURLForGUID(
316 const std::string& sync_guid) { 337 const std::string& sync_guid) {
317 GUIDToTemplateMap::const_iterator elem( 338 GUIDToTemplateMap::const_iterator elem(guid_to_template_map_.find(sync_guid));
318 guid_to_template_map_.find(sync_guid));
319 if (elem != guid_to_template_map_.end()) 339 if (elem != guid_to_template_map_.end())
320 return elem->second; 340 return elem->second;
321 return (initial_default_search_provider_.get() && 341 return ((!loaded_ || load_failed_) &&
342 initial_default_search_provider_.get() &&
322 (initial_default_search_provider_->sync_guid() == sync_guid)) ? 343 (initial_default_search_provider_->sync_guid() == sync_guid)) ?
323 initial_default_search_provider_.get() : NULL; 344 initial_default_search_provider_.get() : NULL;
324 } 345 }
325 346
326 TemplateURL* TemplateURLService::GetTemplateURLForHost( 347 TemplateURL* TemplateURLService::GetTemplateURLForHost(
327 const std::string& host) { 348 const std::string& host) {
328 TemplateURL* t_url = provider_map_->GetTemplateURLForHost(host); 349 TemplateURL* t_url = provider_map_->GetTemplateURLForHost(host);
329 if (t_url) 350 if (t_url)
330 return t_url; 351 return t_url;
331 return (initial_default_search_provider_.get() && 352 return ((!loaded_ || load_failed_) &&
353 initial_default_search_provider_.get() &&
332 (GenerateSearchURL(initial_default_search_provider_.get()).host() == 354 (GenerateSearchURL(initial_default_search_provider_.get()).host() ==
333 host)) ? initial_default_search_provider_.get() : NULL; 355 host)) ? initial_default_search_provider_.get() : NULL;
334 } 356 }
335 357
336 void TemplateURLService::Add(TemplateURL* template_url) { 358 void TemplateURLService::Add(TemplateURL* template_url) {
337 AddNoNotify(template_url, true); 359 if (AddNoNotify(template_url, true))
338 NotifyObservers(); 360 NotifyObservers();
339 } 361 }
340 362
341 void TemplateURLService::AddAndSetProfile(TemplateURL* template_url, 363 void TemplateURLService::AddAndSetProfile(TemplateURL* template_url,
342 Profile* profile) { 364 Profile* profile) {
343 template_url->profile_ = profile; 365 template_url->profile_ = profile;
344 Add(template_url); 366 Add(template_url);
345 } 367 }
346 368
347 void TemplateURLService::AddWithOverrides(TemplateURL* template_url, 369 void TemplateURLService::AddWithOverrides(TemplateURL* template_url,
348 const string16& short_name, 370 const string16& short_name,
349 const string16& keyword, 371 const string16& keyword,
350 const std::string& url) { 372 const std::string& url) {
373 DCHECK(!keyword.empty());
351 DCHECK(!url.empty()); 374 DCHECK(!url.empty());
352 template_url->data_.short_name = short_name; 375 template_url->data_.short_name = short_name;
353 template_url->data_.SetKeyword(keyword); 376 template_url->data_.SetKeyword(keyword);
354 template_url->SetURL(url); 377 template_url->SetURL(url);
355 Add(template_url); 378 Add(template_url);
356 } 379 }
357 380
358 void TemplateURLService::Remove(TemplateURL* template_url) { 381 void TemplateURLService::Remove(TemplateURL* template_url) {
359 RemoveNoNotify(template_url); 382 RemoveNoNotify(template_url);
360 NotifyObservers(); 383 NotifyObservers();
(...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after
440 } 463 }
441 464
442 return NULL; 465 return NULL;
443 } 466 }
444 467
445 TemplateURLService::TemplateURLVector TemplateURLService::GetTemplateURLs() { 468 TemplateURLService::TemplateURLVector TemplateURLService::GetTemplateURLs() {
446 return template_urls_; 469 return template_urls_;
447 } 470 }
448 471
449 void TemplateURLService::IncrementUsageCount(TemplateURL* url) { 472 void TemplateURLService::IncrementUsageCount(TemplateURL* url) {
450 DCHECK(url && std::find(template_urls_.begin(), template_urls_.end(), url) != 473 DCHECK(url);
451 template_urls_.end()); 474 if (std::find(template_urls_.begin(), template_urls_.end(), url) ==
475 template_urls_.end())
476 return;
452 ++url->data_.usage_count; 477 ++url->data_.usage_count;
453 // Extension keywords are not persisted. 478 // Extension keywords are not persisted.
454 // TODO(mpcomplete): If we allow editing extension keywords, then those should 479 // TODO(mpcomplete): If we allow editing extension keywords, then those should
455 // be persisted to disk and synced. 480 // be persisted to disk and synced.
456 if (service_.get() && !url->IsExtensionKeyword()) 481 if (service_.get() && !url->IsExtensionKeyword())
457 service_.get()->UpdateKeyword(*url); 482 service_.get()->UpdateKeyword(url->data());
458 } 483 }
459 484
460 void TemplateURLService::ResetTemplateURL(TemplateURL* url, 485 void TemplateURLService::ResetTemplateURL(TemplateURL* url,
461 const string16& title, 486 const string16& title,
462 const string16& keyword, 487 const string16& keyword,
463 const std::string& search_url) { 488 const std::string& search_url) {
489 if (!loaded_)
490 return;
491 DCHECK(!keyword.empty());
464 DCHECK(!search_url.empty()); 492 DCHECK(!search_url.empty());
465 TemplateURLData data(url->data()); 493 TemplateURLData data(url->data());
466 data.short_name = title; 494 data.short_name = title;
467 data.SetKeyword(keyword); 495 data.SetKeyword(keyword);
468 if (search_url != data.url()) { 496 if (search_url != data.url()) {
469 data.SetURL(search_url); 497 data.SetURL(search_url);
470 // The urls have changed, reset the favicon url. 498 // The urls have changed, reset the favicon url.
471 data.favicon_url = GURL(); 499 data.favicon_url = GURL();
472 } 500 }
473 data.safe_for_autoreplace = false; 501 data.safe_for_autoreplace = false;
474 data.last_modified = time_provider_(); 502 data.last_modified = time_provider_();
475 TemplateURL new_url(url->profile(), data); 503 TemplateURL new_url(url->profile(), data);
476 UpdateNoNotify(url, new_url); 504 if (UpdateNoNotify(url, new_url))
477 NotifyObservers(); 505 NotifyObservers();
478 } 506 }
479 507
480 bool TemplateURLService::CanMakeDefault(const TemplateURL* url) { 508 bool TemplateURLService::CanMakeDefault(const TemplateURL* url) {
481 return url != GetDefaultSearchProvider() && 509 return url != GetDefaultSearchProvider() &&
482 url->url_ref().SupportsReplacement() && !is_default_search_managed(); 510 url->url_ref().SupportsReplacement() && !is_default_search_managed();
483 } 511 }
484 512
485 void TemplateURLService::SetDefaultSearchProvider(TemplateURL* url) { 513 void TemplateURLService::SetDefaultSearchProvider(TemplateURL* url) {
486 DCHECK(!is_default_search_managed_); 514 DCHECK(!is_default_search_managed_);
487 // Extension keywords cannot be made default, as they are inherently async. 515 // Extension keywords cannot be made default, as they are inherently async.
488 DCHECK(!url || !url->IsExtensionKeyword()); 516 DCHECK(!url || !url->IsExtensionKeyword());
489 517
490 // Always persist the setting in the database, that way if the backup 518 // Always persist the setting in the database, that way if the backup
491 // signature has changed out from under us it gets reset correctly. 519 // signature has changed out from under us it gets reset correctly.
492 SetDefaultSearchProviderNoNotify(url); 520 if (SetDefaultSearchProviderNoNotify(url))
493 NotifyObservers(); 521 NotifyObservers();
494 } 522 }
495 523
496 TemplateURL* TemplateURLService::GetDefaultSearchProvider() { 524 TemplateURL* TemplateURLService::GetDefaultSearchProvider() {
497 if (loaded_ && !load_failed_) 525 if (loaded_ && !load_failed_)
498 return default_search_provider_; 526 return default_search_provider_;
499 527
500 // We're not loaded, rely on the default search provider stored in prefs. 528 // We're not loaded, rely on the default search provider stored in prefs.
501 return initial_default_search_provider_.get(); 529 return initial_default_search_provider_.get();
502 } 530 }
503 531
(...skipping 100 matching lines...) Expand 10 before | Expand all | Expand 10 after
604 // The value from the preferences was previously stored in the database. 632 // The value from the preferences was previously stored in the database.
605 // Reuse it. 633 // Reuse it.
606 } else { 634 } else {
607 // The value from the preferences takes over. 635 // The value from the preferences takes over.
608 default_search_provider = NULL; 636 default_search_provider = NULL;
609 if (default_from_prefs.get()) { 637 if (default_from_prefs.get()) {
610 TemplateURLData data(default_from_prefs->data()); 638 TemplateURLData data(default_from_prefs->data());
611 data.created_by_policy = true; 639 data.created_by_policy = true;
612 data.id = kInvalidTemplateURLID; 640 data.id = kInvalidTemplateURLID;
613 default_search_provider = new TemplateURL(profile_, data); 641 default_search_provider = new TemplateURL(profile_, data);
614 AddNoNotify(default_search_provider, true); 642 if (!AddNoNotify(default_search_provider, true))
643 default_search_provider = NULL;
615 } 644 }
616 } 645 }
617 // Note that this saves the default search provider to prefs. 646 // Note that this saves the default search provider to prefs.
618 if (!default_search_provider || 647 if (!default_search_provider ||
619 (!default_search_provider->IsExtensionKeyword() && 648 (!default_search_provider->IsExtensionKeyword() &&
620 default_search_provider->SupportsReplacement())) 649 default_search_provider->SupportsReplacement())) {
621 SetDefaultSearchProviderNoNotify(default_search_provider); 650 bool success = SetDefaultSearchProviderNoNotify(default_search_provider);
651 DCHECK(success);
652 }
622 } else { 653 } else {
623 // If we had a managed default, replace it with the synced default if 654 // If we had a managed default, replace it with the synced default if
624 // applicable, or the first provider of the list. 655 // applicable, or the first provider of the list.
625 TemplateURL* synced_default = GetPendingSyncedDefaultSearchProvider(); 656 TemplateURL* synced_default = GetPendingSyncedDefaultSearchProvider();
626 if (synced_default) { 657 if (synced_default) {
627 default_search_provider = synced_default; 658 default_search_provider = synced_default;
628 pending_synced_default_search_ = false; 659 pending_synced_default_search_ = false;
629 } else if (database_specified_a_default && 660 } else if (database_specified_a_default &&
630 default_search_provider == NULL) { 661 default_search_provider == NULL) {
631 default_search_provider = FirstPotentialDefaultEngine(template_urls); 662 default_search_provider = FirstPotentialDefaultEngine(template_urls);
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after
692 check_if_default_search_valid = false; 723 check_if_default_search_valid = false;
693 } 724 }
694 #endif 725 #endif
695 726
696 if (check_if_default_search_valid) { 727 if (check_if_default_search_valid) {
697 bool has_default_search_provider = default_search_provider_ != NULL && 728 bool has_default_search_provider = default_search_provider_ != NULL &&
698 default_search_provider_->SupportsReplacement(); 729 default_search_provider_->SupportsReplacement();
699 UMA_HISTOGRAM_BOOLEAN("Search.HasDefaultSearchProvider", 730 UMA_HISTOGRAM_BOOLEAN("Search.HasDefaultSearchProvider",
700 has_default_search_provider); 731 has_default_search_provider);
701 // Ensure that default search provider exists. See http://crbug.com/116952. 732 // Ensure that default search provider exists. See http://crbug.com/116952.
702 if (!has_default_search_provider) 733 if (!has_default_search_provider) {
703 SetDefaultSearchProviderNoNotify(FindNewDefaultSearchProvider()); 734 bool success =
735 SetDefaultSearchProviderNoNotify(FindNewDefaultSearchProvider());
736 DCHECK(success);
737 }
704 } 738 }
705 739
706 NotifyObservers(); 740 NotifyObservers();
707 NotifyLoaded(); 741 NotifyLoaded();
708 } 742 }
709 743
710 string16 TemplateURLService::GetKeywordShortName(const string16& keyword, 744 string16 TemplateURLService::GetKeywordShortName(const string16& keyword,
711 bool* is_extension_keyword) { 745 bool* is_extension_keyword) {
712 const TemplateURL* template_url = GetTemplateURLForKeyword(keyword); 746 const TemplateURL* template_url = GetTemplateURLForKeyword(keyword);
713 747
714 // TODO(sky): Once LocationBarView adds a listener to the TemplateURLService 748 // TODO(sky): Once LocationBarView adds a listener to the TemplateURLService
715 // to track changes to the model, this should become a DCHECK. 749 // to track changes to the model, this should become a DCHECK.
716 if (template_url) { 750 if (template_url) {
717 *is_extension_keyword = template_url->IsExtensionKeyword(); 751 *is_extension_keyword = template_url->IsExtensionKeyword();
718 return template_url->AdjustedShortNameForLocaleDirection(); 752 return template_url->AdjustedShortNameForLocaleDirection();
719 } 753 }
720 *is_extension_keyword = false; 754 *is_extension_keyword = false;
721 return string16(); 755 return string16();
722 } 756 }
723 757
724 void TemplateURLService::Observe(int type, 758 void TemplateURLService::Observe(int type,
725 const content::NotificationSource& source, 759 const content::NotificationSource& source,
726 const content::NotificationDetails& details) { 760 const content::NotificationDetails& details) {
727 if (type == chrome::NOTIFICATION_HISTORY_URL_VISITED) { 761 if (type == chrome::NOTIFICATION_HISTORY_URL_VISITED) {
728 content::Details<history::URLVisitedDetails> visit_details(details); 762 content::Details<history::URLVisitedDetails> visit_details(details);
729 if (!loaded()) 763 if (!loaded_)
730 visits_to_add_.push_back(*visit_details.ptr()); 764 visits_to_add_.push_back(*visit_details.ptr());
731 else 765 else
732 UpdateKeywordSearchTermsForURL(*visit_details.ptr()); 766 UpdateKeywordSearchTermsForURL(*visit_details.ptr());
733 } else if (type == chrome::NOTIFICATION_DEFAULT_SEARCH_POLICY_CHANGED) { 767 } else if (type == chrome::NOTIFICATION_DEFAULT_SEARCH_POLICY_CHANGED) {
734 // Policy has been updated, so the default search prefs may be different. 768 // Policy has been updated, so the default search prefs may be different.
735 // Reload the default search provider from them. 769 // Reload the default search provider from them.
736 // TODO(pkasting): Rather than communicating via prefs, we should eventually 770 // TODO(pkasting): Rather than communicating via prefs, we should eventually
737 // observe policy changes directly. 771 // observe policy changes directly.
738 UpdateDefaultSearch(); 772 UpdateDefaultSearch();
739 } else if (type == chrome::NOTIFICATION_GOOGLE_URL_UPDATED) { 773 } else if (type == chrome::NOTIFICATION_GOOGLE_URL_UPDATED) {
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after
785 } 819 }
786 820
787 SyncError TemplateURLService::ProcessSyncChanges( 821 SyncError TemplateURLService::ProcessSyncChanges(
788 const tracked_objects::Location& from_here, 822 const tracked_objects::Location& from_here,
789 const SyncChangeList& change_list) { 823 const SyncChangeList& change_list) {
790 if (!models_associated_) { 824 if (!models_associated_) {
791 SyncError error(FROM_HERE, "Models not yet associated.", 825 SyncError error(FROM_HERE, "Models not yet associated.",
792 syncable::SEARCH_ENGINES); 826 syncable::SEARCH_ENGINES);
793 return error; 827 return error;
794 } 828 }
829 DCHECK(loaded_);
795 830
796 AutoReset<bool> processing_changes(&processing_syncer_changes_, true); 831 AutoReset<bool> processing_changes(&processing_syncer_changes_, true);
797 832
798 SyncChangeList new_changes; 833 SyncChangeList new_changes;
799 SyncError error; 834 SyncError error;
800 for (SyncChangeList::const_iterator iter = change_list.begin(); 835 for (SyncChangeList::const_iterator iter = change_list.begin();
801 iter != change_list.end(); ++iter) { 836 iter != change_list.end(); ++iter) {
802 DCHECK_EQ(syncable::SEARCH_ENGINES, iter->sync_data().GetDataType()); 837 DCHECK_EQ(syncable::SEARCH_ENGINES, iter->sync_data().GetDataType());
803 838
804 std::string guid = 839 std::string guid =
805 iter->sync_data().GetSpecifics().search_engine().sync_guid(); 840 iter->sync_data().GetSpecifics().search_engine().sync_guid();
806 TemplateURL* existing_turl = GetTemplateURLForGUID(guid); 841 TemplateURL* existing_turl = GetTemplateURLForGUID(guid);
807 scoped_ptr<TemplateURL> turl(CreateTemplateURLFromTemplateURLAndSyncData( 842 scoped_ptr<TemplateURL> turl(CreateTemplateURLFromTemplateURLAndSyncData(
808 profile_, existing_turl, iter->sync_data(), &new_changes)); 843 profile_, existing_turl, iter->sync_data(), &new_changes));
809 if (!turl.get()) 844 if (!turl.get())
810 continue; 845 continue;
811 846
847 // Explicitly don't check for conflicts against extension keywords; in this
848 // case the functions which modify the keyword map know how to handle the
849 // conflicts.
850 // TODO(mpcomplete): If we allow editing extension keywords, then those will
851 // need to undergo conflict resolution.
812 TemplateURL* existing_keyword_turl = 852 TemplateURL* existing_keyword_turl =
813 GetTemplateURLForKeyword(turl->keyword()); 853 FindNonExtensionTemplateURLForKeyword(turl->keyword());
814
815 if (iter->change_type() == SyncChange::ACTION_DELETE && existing_turl) { 854 if (iter->change_type() == SyncChange::ACTION_DELETE && existing_turl) {
816 bool delete_default = (existing_turl == GetDefaultSearchProvider()); 855 bool delete_default = (existing_turl == GetDefaultSearchProvider());
817 856
818 if (delete_default && is_default_search_managed_) { 857 if (delete_default && is_default_search_managed_) {
819 NOTREACHED() << "Tried to delete managed default search provider"; 858 NOTREACHED() << "Tried to delete managed default search provider";
820 } else { 859 } else {
821 if (delete_default) 860 if (delete_default)
822 default_search_provider_ = NULL; 861 default_search_provider_ = NULL;
823 862
824 Remove(existing_turl); 863 Remove(existing_turl);
825 864
826 if (delete_default) 865 if (delete_default)
827 SetDefaultSearchProvider(FindNewDefaultSearchProvider()); 866 SetDefaultSearchProvider(FindNewDefaultSearchProvider());
828 } 867 }
829 } else if (iter->change_type() == SyncChange::ACTION_ADD && 868 } else if (iter->change_type() == SyncChange::ACTION_ADD &&
830 !existing_turl) { 869 !existing_turl) {
831 std::string guid = turl->sync_guid(); 870 std::string guid = turl->sync_guid();
832 if (existing_keyword_turl) 871 if (existing_keyword_turl) {
833 ResolveSyncKeywordConflict(turl.get(), &new_changes); 872 ResolveSyncKeywordConflict(turl.get(), existing_keyword_turl,
873 &new_changes);
874 }
834 // Force the local ID to kInvalidTemplateURLID so we can add it. 875 // Force the local ID to kInvalidTemplateURLID so we can add it.
835 TemplateURLData data(turl->data()); 876 TemplateURLData data(turl->data());
836 data.id = kInvalidTemplateURLID; 877 data.id = kInvalidTemplateURLID;
837 Add(new TemplateURL(profile_, data)); 878 Add(new TemplateURL(profile_, data));
838 879
839 // Possibly set the newly added |turl| as the default search provider. 880 // Possibly set the newly added |turl| as the default search provider.
840 SetDefaultSearchProviderIfNewlySynced(guid); 881 SetDefaultSearchProviderIfNewlySynced(guid);
841 } else if (iter->change_type() == SyncChange::ACTION_UPDATE && 882 } else if (iter->change_type() == SyncChange::ACTION_UPDATE &&
842 existing_turl) { 883 existing_turl) {
843 // Possibly resolve a keyword conflict if they have the same keywords but 884 // Possibly resolve a keyword conflict if they have the same keywords but
844 // are not the same entry. 885 // are not the same entry.
845 if (existing_keyword_turl && existing_keyword_turl != existing_turl) 886 if (existing_keyword_turl && existing_keyword_turl != existing_turl) {
846 ResolveSyncKeywordConflict(turl.get(), &new_changes); 887 ResolveSyncKeywordConflict(turl.get(), existing_keyword_turl,
847 UpdateNoNotify(existing_turl, *turl); 888 &new_changes);
848 NotifyObservers(); 889 }
890 if (UpdateNoNotify(existing_turl, *turl))
891 NotifyObservers();
849 } else { 892 } else {
850 // Something really unexpected happened. Either we received an 893 // Something really unexpected happened. Either we received an
851 // ACTION_INVALID, or Sync is in a crazy state: 894 // ACTION_INVALID, or Sync is in a crazy state:
852 // . Trying to DELETE or UPDATE a non-existent search engine. 895 // . Trying to DELETE or UPDATE a non-existent search engine.
853 // . Trying to ADD a search engine that already exists. 896 // . Trying to ADD a search engine that already exists.
854 NOTREACHED() << "Unexpected sync change state."; 897 NOTREACHED() << "Unexpected sync change state.";
855 error = sync_error_factory_->CreateAndUploadError( 898 error = sync_error_factory_->CreateAndUploadError(
856 FROM_HERE, 899 FROM_HERE,
857 "ProcessSyncChanges failed on ChangeType " + 900 "ProcessSyncChanges failed on ChangeType " +
858 SyncChange::ChangeTypeToString(iter->change_type())); 901 SyncChange::ChangeTypeToString(iter->change_type()));
859 } 902 }
860 } 903 }
904 PreventDuplicateGUIDUpdates(&new_changes);
861 905
862 // If something went wrong, we want to prematurely exit to avoid pushing 906 // If something went wrong, we want to prematurely exit to avoid pushing
863 // inconsistent data to Sync. We return the last error we received. 907 // inconsistent data to Sync. We return the last error we received.
864 if (error.IsSet()) 908 if (error.IsSet())
865 return error; 909 return error;
866 910
867 error = sync_processor_->ProcessSyncChanges(from_here, new_changes); 911 error = sync_processor_->ProcessSyncChanges(from_here, new_changes);
868 912
869 return error; 913 return error;
870 } 914 }
871 915
872 SyncError TemplateURLService::MergeDataAndStartSyncing( 916 SyncError TemplateURLService::MergeDataAndStartSyncing(
873 syncable::ModelType type, 917 syncable::ModelType type,
874 const SyncDataList& initial_sync_data, 918 const SyncDataList& initial_sync_data,
875 scoped_ptr<SyncChangeProcessor> sync_processor, 919 scoped_ptr<SyncChangeProcessor> sync_processor,
876 scoped_ptr<SyncErrorFactory> sync_error_factory) { 920 scoped_ptr<SyncErrorFactory> sync_error_factory) {
877 DCHECK(loaded()); 921 DCHECK(loaded_);
878 DCHECK_EQ(type, syncable::SEARCH_ENGINES); 922 DCHECK_EQ(type, syncable::SEARCH_ENGINES);
879 DCHECK(!sync_processor_.get()); 923 DCHECK(!sync_processor_.get());
880 DCHECK(sync_processor.get()); 924 DCHECK(sync_processor.get());
881 DCHECK(sync_error_factory.get()); 925 DCHECK(sync_error_factory.get());
882 sync_processor_ = sync_processor.Pass(); 926 sync_processor_ = sync_processor.Pass();
883 sync_error_factory_ = sync_error_factory.Pass(); 927 sync_error_factory_ = sync_error_factory.Pass();
884 928
885 // We just started syncing, so set our wait-for-default flag if we are 929 // We just started syncing, so set our wait-for-default flag if we are
886 // expecting a default from Sync. 930 // expecting a default from Sync.
887 if (GetPrefs()) { 931 if (GetPrefs()) {
(...skipping 29 matching lines...) Expand all
917 if (local_turl) { 961 if (local_turl) {
918 // This local search engine is already synced. If the timestamp differs 962 // This local search engine is already synced. If the timestamp differs
919 // from Sync, we need to update locally or to the cloud. Note that if the 963 // from Sync, we need to update locally or to the cloud. Note that if the
920 // timestamps are equal, we touch neither. 964 // timestamps are equal, we touch neither.
921 if (sync_turl->last_modified() > local_turl->last_modified()) { 965 if (sync_turl->last_modified() > local_turl->last_modified()) {
922 // We've received an update from Sync. We should replace all synced 966 // We've received an update from Sync. We should replace all synced
923 // fields in the local TemplateURL. Note that this includes the 967 // fields in the local TemplateURL. Note that this includes the
924 // TemplateURLID and the TemplateURL may have to be reparsed. This 968 // TemplateURLID and the TemplateURL may have to be reparsed. This
925 // also makes the local data's last_modified timestamp equal to Sync's, 969 // also makes the local data's last_modified timestamp equal to Sync's,
926 // avoiding an Update on the next MergeData call. 970 // avoiding an Update on the next MergeData call.
927 UpdateNoNotify(local_turl, *sync_turl); 971 if (UpdateNoNotify(local_turl, *sync_turl))
928 NotifyObservers(); 972 NotifyObservers();
929 } else if (sync_turl->last_modified() < local_turl->last_modified()) { 973 } else if (sync_turl->last_modified() < local_turl->last_modified()) {
930 // Otherwise, we know we have newer data, so update Sync with our 974 // Otherwise, we know we have newer data, so update Sync with our
931 // data fields. 975 // data fields.
932 new_changes.push_back(SyncChange(SyncChange::ACTION_UPDATE, 976 new_changes.push_back(SyncChange(SyncChange::ACTION_UPDATE,
933 local_data_map[local_turl->sync_guid()])); 977 local_data_map[local_turl->sync_guid()]));
934 } 978 }
935 local_data_map.erase(iter->first); 979 local_data_map.erase(iter->first);
936 } else { 980 } else {
937 // The search engine from the cloud has not been synced locally, but there 981 // The search engine from the cloud has not been synced locally, but there
938 // might be a local search engine that is a duplicate that needs to be 982 // might be a local search engine that is a duplicate that needs to be
939 // merged. 983 // merged.
940 TemplateURL* dupe_turl = FindDuplicateOfSyncTemplateURL(*sync_turl); 984 TemplateURL* dupe_turl = FindDuplicateOfSyncTemplateURL(*sync_turl);
941 if (dupe_turl) { 985 if (dupe_turl) {
942 // Merge duplicates and remove the processed local TURL from the map. 986 // Merge duplicates and remove the processed local TURL from the map.
943 std::string old_guid = dupe_turl->sync_guid(); 987 std::string old_guid = dupe_turl->sync_guid();
944 MergeSyncAndLocalURLDuplicates(sync_turl.release(), dupe_turl, 988 MergeSyncAndLocalURLDuplicates(sync_turl.release(), dupe_turl,
945 &new_changes); 989 &new_changes);
946 local_data_map.erase(old_guid); 990 local_data_map.erase(old_guid);
947 } else { 991 } else {
948 std::string guid = sync_turl->sync_guid(); 992 std::string guid = sync_turl->sync_guid();
949 // Keyword conflict is possible in this case. Resolve it first before 993 // Keyword conflict is possible in this case. Resolve it first before
950 // adding the new TemplateURL. Note that we don't remove the local TURL 994 // adding the new TemplateURL. Note that we don't remove the local TURL
951 // from local_data_map in this case as it may still need to be pushed to 995 // from local_data_map in this case as it may still need to be pushed to
952 // the cloud. 996 // the cloud. We also explicitly don't resolve conflicts against
953 ResolveSyncKeywordConflict(sync_turl.get(), &new_changes); 997 // extension keywords; see comments in ProcessSyncChanges().
998 TemplateURL* existing_keyword_turl =
999 FindNonExtensionTemplateURLForKeyword(sync_turl->keyword());
1000 if (existing_keyword_turl) {
1001 ResolveSyncKeywordConflict(sync_turl.get(), existing_keyword_turl,
1002 &new_changes);
1003 }
954 // Force the local ID to kInvalidTemplateURLID so we can add it. 1004 // Force the local ID to kInvalidTemplateURLID so we can add it.
955 TemplateURLData data(sync_turl->data()); 1005 TemplateURLData data(sync_turl->data());
956 data.id = kInvalidTemplateURLID; 1006 data.id = kInvalidTemplateURLID;
957 Add(new TemplateURL(profile_, data)); 1007 Add(new TemplateURL(profile_, data));
958 1008
959 // Possibly set the newly added |turl| as the default search provider. 1009 // Possibly set the newly added |turl| as the default search provider.
960 SetDefaultSearchProviderIfNewlySynced(guid); 1010 SetDefaultSearchProviderIfNewlySynced(guid);
961 } 1011 }
962 } 1012 }
963 } 1013 }
964 1014
965 // The remaining SyncData in local_data_map should be everything that needs to 1015 // The remaining SyncData in local_data_map should be everything that needs to
966 // be pushed as ADDs to sync. 1016 // be pushed as ADDs to sync.
967 for (SyncDataMap::const_iterator iter = local_data_map.begin(); 1017 for (SyncDataMap::const_iterator iter = local_data_map.begin();
968 iter != local_data_map.end(); ++iter) { 1018 iter != local_data_map.end(); ++iter) {
969 new_changes.push_back(SyncChange(SyncChange::ACTION_ADD, iter->second)); 1019 new_changes.push_back(SyncChange(SyncChange::ACTION_ADD, iter->second));
970 } 1020 }
971 1021
1022 PreventDuplicateGUIDUpdates(&new_changes);
1023
972 SyncError error = sync_processor_->ProcessSyncChanges(FROM_HERE, new_changes); 1024 SyncError error = sync_processor_->ProcessSyncChanges(FROM_HERE, new_changes);
973 if (error.IsSet()) 1025 if (error.IsSet())
974 return error; 1026 return error;
975 1027
976 models_associated_ = true; 1028 models_associated_ = true;
977 return SyncError(); 1029 return SyncError();
978 } 1030 }
979 1031
980 void TemplateURLService::StopSyncing(syncable::ModelType type) { 1032 void TemplateURLService::StopSyncing(syncable::ModelType type) {
981 DCHECK_EQ(type, syncable::SEARCH_ENGINES); 1033 DCHECK_EQ(type, syncable::SEARCH_ENGINES);
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after
1024 se_specifics->set_keyword(UTF16ToUTF8(turl.keyword())); 1076 se_specifics->set_keyword(UTF16ToUTF8(turl.keyword()));
1025 se_specifics->set_favicon_url(turl.favicon_url().spec()); 1077 se_specifics->set_favicon_url(turl.favicon_url().spec());
1026 se_specifics->set_url(turl.url()); 1078 se_specifics->set_url(turl.url());
1027 se_specifics->set_safe_for_autoreplace(turl.safe_for_autoreplace()); 1079 se_specifics->set_safe_for_autoreplace(turl.safe_for_autoreplace());
1028 se_specifics->set_originating_url(turl.originating_url().spec()); 1080 se_specifics->set_originating_url(turl.originating_url().spec());
1029 se_specifics->set_date_created(turl.date_created().ToInternalValue()); 1081 se_specifics->set_date_created(turl.date_created().ToInternalValue());
1030 se_specifics->set_input_encodings(JoinString(turl.input_encodings(), ';')); 1082 se_specifics->set_input_encodings(JoinString(turl.input_encodings(), ';'));
1031 se_specifics->set_show_in_default_list(turl.show_in_default_list()); 1083 se_specifics->set_show_in_default_list(turl.show_in_default_list());
1032 se_specifics->set_suggestions_url(turl.suggestions_url()); 1084 se_specifics->set_suggestions_url(turl.suggestions_url());
1033 se_specifics->set_prepopulate_id(turl.prepopulate_id()); 1085 se_specifics->set_prepopulate_id(turl.prepopulate_id());
1034 se_specifics->set_autogenerate_keyword(turl.autogenerate_keyword());
1035 se_specifics->set_instant_url(turl.instant_url()); 1086 se_specifics->set_instant_url(turl.instant_url());
1036 se_specifics->set_last_modified(turl.last_modified().ToInternalValue()); 1087 se_specifics->set_last_modified(turl.last_modified().ToInternalValue());
1037 se_specifics->set_sync_guid(turl.sync_guid()); 1088 se_specifics->set_sync_guid(turl.sync_guid());
1038 return SyncData::CreateLocalData(se_specifics->sync_guid(), 1089 return SyncData::CreateLocalData(se_specifics->sync_guid(),
1039 se_specifics->keyword(), 1090 se_specifics->keyword(),
1040 specifics); 1091 specifics);
1041 } 1092 }
1042 1093
1043 // static 1094 // static
1044 TemplateURL* TemplateURLService::CreateTemplateURLFromTemplateURLAndSyncData( 1095 TemplateURL* TemplateURLService::CreateTemplateURLFromTemplateURLAndSyncData(
1045 Profile* profile, 1096 Profile* profile,
1046 TemplateURL* existing_turl, 1097 TemplateURL* existing_turl,
1047 const SyncData& sync_data, 1098 const SyncData& sync_data,
1048 SyncChangeList* change_list) { 1099 SyncChangeList* change_list) {
1049 DCHECK(change_list); 1100 DCHECK(change_list);
1050 1101
1051 sync_pb::SearchEngineSpecifics specifics = 1102 sync_pb::SearchEngineSpecifics specifics =
1052 sync_data.GetSpecifics().search_engine(); 1103 sync_data.GetSpecifics().search_engine();
1053 1104
1054 // Past bugs might have caused either of these fields to be empty. Just 1105 // Past bugs might have caused either of these fields to be empty. Just
1055 // delete this data off the server. 1106 // delete this data off the server.
1056 if (specifics.url().empty() || specifics.sync_guid().empty()) { 1107 if (specifics.url().empty() || specifics.sync_guid().empty()) {
1057 change_list->push_back(SyncChange(SyncChange::ACTION_DELETE, sync_data)); 1108 change_list->push_back(SyncChange(SyncChange::ACTION_DELETE, sync_data));
1058 return NULL; 1109 return NULL;
1059 } 1110 }
1060 1111
1061 TemplateURLData data; 1112 TemplateURLData data;
1062 data.short_name = UTF8ToUTF16(specifics.short_name()); 1113 data.short_name = UTF8ToUTF16(specifics.short_name());
1063 data.originating_url = GURL(specifics.originating_url()); 1114 data.originating_url = GURL(specifics.originating_url());
1064 data.SetKeyword(UTF8ToUTF16(specifics.keyword())); 1115 string16 keyword(UTF8ToUTF16(specifics.keyword()));
1065 data.SetAutogenerateKeyword(specifics.autogenerate_keyword()); 1116 // NOTE: Once this code has shipped in a couple of stable releases, we can
1117 // probably remove the migration portion, comment out the
1118 // "autogenerate_keyword" field entirely in the .proto file, and fold the
1119 // empty keyword case into the "delete data" block above.
1120 bool reset_keyword =
1121 specifics.autogenerate_keyword() || specifics.keyword().empty();
1122 if (reset_keyword)
1123 keyword = ASCIIToUTF16("dummy"); // Will be replaced below.
1124 DCHECK(!keyword.empty());
1125 data.SetKeyword(keyword);
1066 data.SetURL(specifics.url()); 1126 data.SetURL(specifics.url());
1067 data.suggestions_url = specifics.suggestions_url(); 1127 data.suggestions_url = specifics.suggestions_url();
1068 data.instant_url = specifics.instant_url(); 1128 data.instant_url = specifics.instant_url();
1069 data.favicon_url = GURL(specifics.favicon_url()); 1129 data.favicon_url = GURL(specifics.favicon_url());
1070 data.show_in_default_list = specifics.show_in_default_list(); 1130 data.show_in_default_list = specifics.show_in_default_list();
1071 data.safe_for_autoreplace = specifics.safe_for_autoreplace(); 1131 data.safe_for_autoreplace = specifics.safe_for_autoreplace();
1072 base::SplitString(specifics.input_encodings(), ';', &data.input_encodings); 1132 base::SplitString(specifics.input_encodings(), ';', &data.input_encodings);
1073 data.date_created = base::Time::FromInternalValue(specifics.date_created()); 1133 data.date_created = base::Time::FromInternalValue(specifics.date_created());
1074 data.last_modified = base::Time::FromInternalValue(specifics.last_modified()); 1134 data.last_modified = base::Time::FromInternalValue(specifics.last_modified());
1075 data.prepopulate_id = specifics.prepopulate_id(); 1135 data.prepopulate_id = specifics.prepopulate_id();
1076 data.sync_guid = specifics.sync_guid(); 1136 data.sync_guid = specifics.sync_guid();
1077 if (existing_turl) { 1137 if (existing_turl) {
1078 data.id = existing_turl->id(); 1138 data.id = existing_turl->id();
1079 data.created_by_policy = existing_turl->created_by_policy(); 1139 data.created_by_policy = existing_turl->created_by_policy();
1080 data.usage_count = existing_turl->usage_count(); 1140 data.usage_count = existing_turl->usage_count();
1081 } 1141 }
1082 1142
1083 TemplateURL* turl = new TemplateURL(profile, data); 1143 TemplateURL* turl = new TemplateURL(profile, data);
1084 DCHECK(!turl->IsExtensionKeyword()); 1144 DCHECK(!turl->IsExtensionKeyword());
1145 if (reset_keyword) {
1146 turl->ResetKeywordIfNecessary(true);
1147 SyncData sync_data = CreateSyncDataFromTemplateURL(*turl);
1148 change_list->push_back(SyncChange(SyncChange::ACTION_UPDATE, sync_data));
1149 }
1085 return turl; 1150 return turl;
1086 } 1151 }
1087 1152
1088 // static 1153 // static
1089 SyncDataMap TemplateURLService::CreateGUIDToSyncDataMap( 1154 SyncDataMap TemplateURLService::CreateGUIDToSyncDataMap(
1090 const SyncDataList& sync_data) { 1155 const SyncDataList& sync_data) {
1091 SyncDataMap data_map; 1156 SyncDataMap data_map;
1092 for (SyncDataList::const_iterator i(sync_data.begin()); i != sync_data.end(); 1157 for (SyncDataList::const_iterator i(sync_data.begin()); i != sync_data.end();
1093 ++i) 1158 ++i)
1094 data_map[i->GetSpecifics().search_engine().sync_guid()] = *i; 1159 data_map[i->GetSpecifics().search_engine().sync_guid()] = *i;
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after
1160 if (initial_default_search_provider_.get() && 1225 if (initial_default_search_provider_.get() &&
1161 initial_default_search_provider_->url_ref().HasGoogleBaseURLs()) { 1226 initial_default_search_provider_->url_ref().HasGoogleBaseURLs()) {
1162 scoped_ptr<base::Environment> env(base::Environment::Create()); 1227 scoped_ptr<base::Environment> env(base::Environment::Create());
1163 if (!env->HasVar(env_vars::kHeadless) && 1228 if (!env->HasVar(env_vars::kHeadless) &&
1164 !CommandLine::ForCurrentProcess()->HasSwitch(switches::kChromeFrame)) 1229 !CommandLine::ForCurrentProcess()->HasSwitch(switches::kChromeFrame))
1165 GoogleURLTracker::RequestServerCheck(); 1230 GoogleURLTracker::RequestServerCheck();
1166 } 1231 }
1167 } 1232 }
1168 1233
1169 void TemplateURLService::RemoveFromMaps(TemplateURL* template_url) { 1234 void TemplateURLService::RemoveFromMaps(TemplateURL* template_url) {
1170 if (!template_url->keyword().empty()) 1235 const string16& keyword = template_url->keyword();
1171 keyword_to_template_map_.erase(template_url->keyword()); 1236 DCHECK_NE(0U, keyword_to_template_map_.count(keyword));
1237 if (keyword_to_template_map_[keyword] == template_url) {
1238 // We need to check whether the keyword can now be provided by another
1239 // TemplateURL. See the comments in AddToMaps() for more information on
1240 // extension keywords and how they can coexist with non-extension keywords.
1241 // In the case of more than one extension, we use the most recently
1242 // installed (which will be the most recently added, which will have the
1243 // highest ID).
1244 TemplateURL* best_fallback = NULL;
1245 for (TemplateURLVector::const_iterator i(template_urls_.begin());
1246 i != template_urls_.end(); ++i) {
1247 TemplateURL* turl = *i;
1248 // This next statement relies on the fact that there can only be one
1249 // non-extension TemplateURL with a given keyword.
1250 if ((turl != template_url) && (turl->keyword() == keyword) &&
1251 (!best_fallback || !best_fallback->IsExtensionKeyword() ||
1252 (turl->IsExtensionKeyword() && (turl->id() > best_fallback->id()))))
1253 best_fallback = turl;
1254 }
1255 if (best_fallback)
1256 keyword_to_template_map_[keyword] = best_fallback;
1257 else
1258 keyword_to_template_map_.erase(keyword);
1259 }
1172 1260
1173 // If the keyword we're removing is from an extension, we're now done, since 1261 // If the keyword we're removing is from an extension, we're now done, since
1174 // it won't be synced or stored in the provider map. 1262 // it won't be synced or stored in the provider map.
1175 // TODO(mpcomplete): If we allow editing extension keywords, then those should 1263 // TODO(mpcomplete): If we allow editing extension keywords, then those should
1176 // be synced. 1264 // be synced.
1177 if (template_url->IsExtensionKeyword()) 1265 if (template_url->IsExtensionKeyword())
1178 return; 1266 return;
1179 1267
1180 if (!template_url->sync_guid().empty()) 1268 if (!template_url->sync_guid().empty())
1181 guid_to_template_map_.erase(template_url->sync_guid()); 1269 guid_to_template_map_.erase(template_url->sync_guid());
1182 if (loaded_) 1270 if (loaded_)
1183 provider_map_->Remove(template_url); 1271 provider_map_->Remove(template_url);
1184 } 1272 }
1185 1273
1186 void TemplateURLService::RemoveFromKeywordMapByPointer( 1274 void TemplateURLService::RemoveFromKeywordMapByPointer(
1187 TemplateURL* template_url) { 1275 TemplateURL* template_url) {
1188 DCHECK(template_url); 1276 DCHECK(template_url);
1189 for (KeywordToTemplateMap::iterator i = keyword_to_template_map_.begin(); 1277 for (KeywordToTemplateMap::iterator i = keyword_to_template_map_.begin();
1190 i != keyword_to_template_map_.end(); ++i) { 1278 i != keyword_to_template_map_.end(); ++i) {
1191 if (i->second == template_url) { 1279 if (i->second == template_url) {
1192 keyword_to_template_map_.erase(i); 1280 keyword_to_template_map_.erase(i);
1193 // A given TemplateURL only occurs once in the map. As soon as we find the 1281 // A given TemplateURL only occurs once in the map. As soon as we find the
1194 // entry, stop. 1282 // entry, stop.
1195 break; 1283 break;
1196 } 1284 }
1197 } 1285 }
1198 } 1286 }
1199 1287
1200 void TemplateURLService::AddToMaps(TemplateURL* template_url) { 1288 void TemplateURLService::AddToMaps(TemplateURL* template_url) {
1201 if (!template_url->keyword().empty()) 1289 bool template_extension = template_url->IsExtensionKeyword();
1202 keyword_to_template_map_[template_url->keyword()] = template_url; 1290 const string16& keyword = template_url->keyword();
1291 KeywordToTemplateMap::const_iterator i =
1292 keyword_to_template_map_.find(keyword);
1293 if (i == keyword_to_template_map_.end()) {
1294 keyword_to_template_map_[keyword] = template_url;
1295 } else {
1296 const TemplateURL* existing_url = i->second;
1297 // We should only have overlapping keywords when at least one comes from
1298 // an extension. In that case, the ranking order is:
1299 // Manually-modified keywords > extension keywords > replaceable keywords
1300 // When there are multiple extensions, the last-added wins.
1301 bool existing_extension = existing_url->IsExtensionKeyword();
1302 DCHECK(existing_extension || template_extension);
1303 if (existing_extension ?
1304 !CanReplace(template_url) : CanReplace(existing_url))
1305 keyword_to_template_map_[keyword] = template_url;
1306 }
1203 1307
1204 // Extension keywords are not synced, so they don't go into the GUID map, 1308 // Extension keywords are not synced, so they don't go into the GUID map,
1205 // and do not use host-based search URLs, so they don't go into the provider 1309 // and do not use host-based search URLs, so they don't go into the provider
1206 // map, so at this point we're done. 1310 // map, so at this point we're done.
1207 // TODO(mpcomplete): If we allow editing extension keywords, then those should 1311 // TODO(mpcomplete): If we allow editing extension keywords, then those should
1208 // be persisted to disk and synced. 1312 // be persisted to disk and synced.
1209 if (template_url->IsExtensionKeyword()) 1313 if (template_extension)
1210 return; 1314 return;
1211 1315
1212 if (!template_url->sync_guid().empty()) 1316 if (!template_url->sync_guid().empty())
1213 guid_to_template_map_[template_url->sync_guid()] = template_url; 1317 guid_to_template_map_[template_url->sync_guid()] = template_url;
1214 if (loaded_) { 1318 if (loaded_) {
1215 UIThreadSearchTermsData search_terms_data; 1319 UIThreadSearchTermsData search_terms_data;
1216 provider_map_->Add(template_url, search_terms_data); 1320 provider_map_->Add(template_url, search_terms_data);
1217 } 1321 }
1218 } 1322 }
1219 1323
(...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after
1319 if (!prefs->GetBoolean(prefs::kDefaultSearchProviderEnabled)) { 1423 if (!prefs->GetBoolean(prefs::kDefaultSearchProviderEnabled)) {
1320 // The user doesn't want a default search provider. 1424 // The user doesn't want a default search provider.
1321 default_provider->reset(NULL); 1425 default_provider->reset(NULL);
1322 return true; 1426 return true;
1323 } 1427 }
1324 1428
1325 string16 name = 1429 string16 name =
1326 UTF8ToUTF16(prefs->GetString(prefs::kDefaultSearchProviderName)); 1430 UTF8ToUTF16(prefs->GetString(prefs::kDefaultSearchProviderName));
1327 string16 keyword = 1431 string16 keyword =
1328 UTF8ToUTF16(prefs->GetString(prefs::kDefaultSearchProviderKeyword)); 1432 UTF8ToUTF16(prefs->GetString(prefs::kDefaultSearchProviderKeyword));
1433 // Force keyword to be non-empty.
1434 // TODO(pkasting): This is only necessary as long as we're potentially loading
1435 // older prefs where empty keywords are theoretically possible. Eventually
1436 // this code can be replaced with a DCHECK(!keyword.empty());.
1437 bool update_keyword = keyword.empty();
1438 if (update_keyword)
1439 keyword = ASCIIToUTF16("dummy");
1329 std::string search_url = 1440 std::string search_url =
1330 prefs->GetString(prefs::kDefaultSearchProviderSearchURL); 1441 prefs->GetString(prefs::kDefaultSearchProviderSearchURL);
1331 // Force URL to be non-empty. We've never supported this case, but past bugs 1442 // Force URL to be non-empty. We've never supported this case, but past bugs
1332 // might have resulted in it slipping through; eventually this code can be 1443 // might have resulted in it slipping through; eventually this code can be
1333 // replaced with a DCHECK(!search_url.empty());. 1444 // replaced with a DCHECK(!search_url.empty());.
1334 if (search_url.empty()) 1445 if (search_url.empty())
1335 return false; 1446 return false;
1336 std::string suggest_url = 1447 std::string suggest_url =
1337 prefs->GetString(prefs::kDefaultSearchProviderSuggestURL); 1448 prefs->GetString(prefs::kDefaultSearchProviderSuggestURL);
1338 std::string instant_url = 1449 std::string instant_url =
(...skipping 20 matching lines...) Expand all
1359 base::StringToInt64(id_string, &value); 1470 base::StringToInt64(id_string, &value);
1360 data.id = value; 1471 data.id = value;
1361 } 1472 }
1362 if (!prepopulate_id.empty() && !*is_managed) { 1473 if (!prepopulate_id.empty() && !*is_managed) {
1363 int value; 1474 int value;
1364 base::StringToInt(prepopulate_id, &value); 1475 base::StringToInt(prepopulate_id, &value);
1365 data.prepopulate_id = value; 1476 data.prepopulate_id = value;
1366 } 1477 }
1367 default_provider->reset(new TemplateURL(profile_, data)); 1478 default_provider->reset(new TemplateURL(profile_, data));
1368 DCHECK(!(*default_provider)->IsExtensionKeyword()); 1479 DCHECK(!(*default_provider)->IsExtensionKeyword());
1480 if (update_keyword)
1481 (*default_provider)->ResetKeywordIfNecessary(true);
1369 return true; 1482 return true;
1370 } 1483 }
1371 1484
1372 bool TemplateURLService::CanReplaceKeywordForHost( 1485 bool TemplateURLService::CanReplaceKeywordForHost(
1373 const std::string& host, 1486 const std::string& host,
1374 TemplateURL** to_replace) { 1487 TemplateURL** to_replace) {
1375 DCHECK(!to_replace || !*to_replace); 1488 DCHECK(!to_replace || !*to_replace);
1376 const TemplateURLSet* urls = provider_map_->GetURLsForHost(host); 1489 const TemplateURLSet* urls = provider_map_->GetURLsForHost(host);
1377 if (!urls) 1490 if (!urls)
1378 return true; 1491 return true;
1379 for (TemplateURLSet::const_iterator i(urls->begin()); i != urls->end(); ++i) { 1492 for (TemplateURLSet::const_iterator i(urls->begin()); i != urls->end(); ++i) {
1380 if (CanReplace(*i)) { 1493 if (CanReplace(*i)) {
1381 if (to_replace) 1494 if (to_replace)
1382 *to_replace = *i; 1495 *to_replace = *i;
1383 return true; 1496 return true;
1384 } 1497 }
1385 } 1498 }
1386 return false; 1499 return false;
1387 } 1500 }
1388 1501
1389 bool TemplateURLService::CanReplace(const TemplateURL* t_url) { 1502 bool TemplateURLService::CanReplace(const TemplateURL* t_url) {
1390 return (t_url != default_search_provider_ && !t_url->show_in_default_list() && 1503 return (t_url != default_search_provider_ && !t_url->show_in_default_list() &&
1391 t_url->safe_for_autoreplace()); 1504 t_url->safe_for_autoreplace());
1392 } 1505 }
1393 1506
1394 void TemplateURLService::UpdateNoNotify(TemplateURL* existing_turl, 1507 TemplateURL* TemplateURLService::FindNonExtensionTemplateURLForKeyword(
1508 const string16& keyword) {
1509 TemplateURL* keyword_turl = GetTemplateURLForKeyword(keyword);
1510 if (!keyword_turl || !keyword_turl->IsExtensionKeyword())
1511 return keyword_turl;
1512 // The extension keyword in the model may be hiding a replaceable
1513 // non-extension keyword. Look for it.
1514 for (TemplateURLVector::const_iterator i(template_urls_.begin());
1515 i != template_urls_.end(); ++i) {
1516 if (!(*i)->IsExtensionKeyword() && ((*i)->keyword() == keyword))
1517 return *i;
1518 }
1519 return NULL;
1520 }
1521
1522 bool TemplateURLService::UpdateNoNotify(TemplateURL* existing_turl,
1395 const TemplateURL& new_values) { 1523 const TemplateURL& new_values) {
1396 DCHECK(loaded_); 1524 DCHECK(loaded_);
1397 DCHECK(existing_turl); 1525 DCHECK(existing_turl);
1398 DCHECK(std::find(template_urls_.begin(), template_urls_.end(), 1526 if (std::find(template_urls_.begin(), template_urls_.end(), existing_turl) ==
1399 existing_turl) != template_urls_.end()); 1527 template_urls_.end())
1528 return false;
1400 1529
1401 // TODO(mpcomplete): If we allow editing extension keywords, then those should 1530 // TODO(mpcomplete): If we allow editing extension keywords, then those should
1402 // be persisted to disk and synced. In this case this DCHECK should be 1531 // be persisted to disk and synced. In this case this DCHECK should be
1403 // removed. 1532 // removed.
1404 DCHECK(!existing_turl->IsExtensionKeyword()); 1533 DCHECK(!existing_turl->IsExtensionKeyword());
1405 1534
1406 string16 old_keyword(existing_turl->keyword()); 1535 string16 old_keyword(existing_turl->keyword());
1407 if (!old_keyword.empty()) 1536 keyword_to_template_map_.erase(old_keyword);
1408 keyword_to_template_map_.erase(old_keyword);
1409 if (!existing_turl->sync_guid().empty()) 1537 if (!existing_turl->sync_guid().empty())
1410 guid_to_template_map_.erase(existing_turl->sync_guid()); 1538 guid_to_template_map_.erase(existing_turl->sync_guid());
1411 1539
1412 provider_map_->Remove(existing_turl); 1540 provider_map_->Remove(existing_turl);
1413 TemplateURLID previous_id = existing_turl->id(); 1541 TemplateURLID previous_id = existing_turl->id();
1414 *existing_turl = new_values; 1542 *existing_turl = new_values;
1415 existing_turl->data_.id = previous_id; 1543 existing_turl->data_.id = previous_id;
1416 UIThreadSearchTermsData search_terms_data; 1544 UIThreadSearchTermsData search_terms_data;
1417 provider_map_->Add(existing_turl, search_terms_data); 1545 provider_map_->Add(existing_turl, search_terms_data);
1418 1546
1419 const string16& keyword = existing_turl->keyword(); 1547 const string16& keyword = existing_turl->keyword();
1420 if (!keyword.empty()) 1548 KeywordToTemplateMap::const_iterator i =
1549 keyword_to_template_map_.find(keyword);
1550 if (i == keyword_to_template_map_.end()) {
1421 keyword_to_template_map_[keyword] = existing_turl; 1551 keyword_to_template_map_[keyword] = existing_turl;
1552 } else {
1553 // We can theoretically reach here in two cases:
1554 // * There is an existing extension keyword and sync brings in a rename of
1555 // a non-extension keyword to match. In this case we just need to pick
1556 // which keyword has priority to update the keyword map.
1557 // * Autogeneration of the keyword for a Google default search provider
1558 // at load time causes it to conflict with an existing keyword. In this
1559 // case we delete the existing keyword if it's replaceable, or else undo
1560 // the change in keyword for |existing_turl|.
1561 DCHECK(!existing_turl->IsExtensionKeyword());
1562 TemplateURL* existing_keyword_turl = i->second;
1563 if (existing_keyword_turl->IsExtensionKeyword()) {
1564 if (!CanReplace(existing_turl))
1565 keyword_to_template_map_[keyword] = existing_turl;
1566 } else {
1567 if (CanReplace(existing_keyword_turl)) {
1568 RemoveNoNotify(existing_keyword_turl);
1569 } else {
1570 existing_turl->data_.SetKeyword(old_keyword);
1571 keyword_to_template_map_[old_keyword] = existing_turl;
1572 }
1573 }
1574 }
1422 if (!existing_turl->sync_guid().empty()) 1575 if (!existing_turl->sync_guid().empty())
1423 guid_to_template_map_[existing_turl->sync_guid()] = existing_turl; 1576 guid_to_template_map_[existing_turl->sync_guid()] = existing_turl;
1424 1577
1425 if (service_.get()) 1578 if (service_.get())
1426 service_->UpdateKeyword(*existing_turl); 1579 service_->UpdateKeyword(existing_turl->data());
1427 1580
1428 // Inform sync of the update. 1581 // Inform sync of the update.
1429 ProcessTemplateURLChange(existing_turl, SyncChange::ACTION_UPDATE); 1582 ProcessTemplateURLChange(existing_turl, SyncChange::ACTION_UPDATE);
1430 1583
1431 if (default_search_provider_ == existing_turl) 1584 if (default_search_provider_ == existing_turl) {
1432 SetDefaultSearchProviderNoNotify(existing_turl); 1585 bool success = SetDefaultSearchProviderNoNotify(existing_turl);
1586 DCHECK(success);
1587 }
1588 return true;
1433 } 1589 }
1434 1590
1435 PrefService* TemplateURLService::GetPrefs() { 1591 PrefService* TemplateURLService::GetPrefs() {
1436 return profile_ ? profile_->GetPrefs() : NULL; 1592 return profile_ ? profile_->GetPrefs() : NULL;
1437 } 1593 }
1438 1594
1439 void TemplateURLService::UpdateKeywordSearchTermsForURL( 1595 void TemplateURLService::UpdateKeywordSearchTermsForURL(
1440 const history::URLVisitedDetails& details) { 1596 const history::URLVisitedDetails& details) {
1441 const history::URLRow& row = details.row; 1597 const history::URLRow& row = details.row;
1442 if (!row.url().is_valid() || 1598 if (!row.url().is_valid() ||
(...skipping 114 matching lines...) Expand 10 before | Expand all | Expand 10 after
1557 bool something_changed = false; 1713 bool something_changed = false;
1558 for (TemplateURLVector::iterator i(template_urls_.begin()); 1714 for (TemplateURLVector::iterator i(template_urls_.begin());
1559 i != template_urls_.end(); ++i) { 1715 i != template_urls_.end(); ++i) {
1560 TemplateURL* t_url = *i; 1716 TemplateURL* t_url = *i;
1561 if (t_url->url_ref().HasGoogleBaseURLs() || 1717 if (t_url->url_ref().HasGoogleBaseURLs() ||
1562 t_url->suggestions_url_ref().HasGoogleBaseURLs()) { 1718 t_url->suggestions_url_ref().HasGoogleBaseURLs()) {
1563 something_changed = true; 1719 something_changed = true;
1564 string16 original_keyword(t_url->keyword()); 1720 string16 original_keyword(t_url->keyword());
1565 t_url->InvalidateCachedValues(); 1721 t_url->InvalidateCachedValues();
1566 const string16& new_keyword(t_url->keyword()); 1722 const string16& new_keyword(t_url->keyword());
1723 KeywordToTemplateMap::const_iterator i =
1724 keyword_to_template_map_.find(new_keyword);
1725 if ((i != keyword_to_template_map_.end()) && (i->second != t_url)) {
1726 // The new autogenerated keyword conflicts with another TemplateURL.
1727 // Overwrite it if it's replaceable; otherwise just reset |t_url|'s
1728 // keyword. (This will not prevent |t_url| from auto-updating the
1729 // keyword in the future if the conflicting TemplateURL disappears.)
1730 if (!CanReplace(i->second)) {
1731 t_url->data_.SetKeyword(original_keyword);
1732 continue;
1733 }
1734 RemoveNoNotify(i->second);
1735 }
1567 RemoveFromKeywordMapByPointer(t_url); 1736 RemoveFromKeywordMapByPointer(t_url);
1568 if (!new_keyword.empty()) 1737 keyword_to_template_map_[new_keyword] = t_url;
1569 keyword_to_template_map_[new_keyword] = t_url;
1570 } 1738 }
1571 } 1739 }
1572 1740
1573 if (something_changed && loaded_) { 1741 if (something_changed && loaded_) {
1574 UIThreadSearchTermsData search_terms_data; 1742 UIThreadSearchTermsData search_terms_data;
1575 provider_map_->UpdateGoogleBaseURLs(search_terms_data); 1743 provider_map_->UpdateGoogleBaseURLs(search_terms_data);
1576 NotifyObservers(); 1744 NotifyObservers();
1577 } 1745 }
1578 } 1746 }
1579 1747
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
1611 // if it has changed; we don't want to respond to changes triggered by 1779 // if it has changed; we don't want to respond to changes triggered by
1612 // SaveDefaultSearchProviderToPrefs. 1780 // SaveDefaultSearchProviderToPrefs.
1613 if (TemplateURLsHaveSamePrefs(default_search_provider_, 1781 if (TemplateURLsHaveSamePrefs(default_search_provider_,
1614 new_default_from_prefs.get())) 1782 new_default_from_prefs.get()))
1615 return; 1783 return;
1616 if (new_default_from_prefs.get() == NULL) { 1784 if (new_default_from_prefs.get() == NULL) {
1617 // default_search_provider_ can't be NULL otherwise 1785 // default_search_provider_ can't be NULL otherwise
1618 // TemplateURLsHaveSamePrefs would have returned true. Remove this now 1786 // TemplateURLsHaveSamePrefs would have returned true. Remove this now
1619 // invalid value. 1787 // invalid value.
1620 TemplateURL* old_default = default_search_provider_; 1788 TemplateURL* old_default = default_search_provider_;
1621 SetDefaultSearchProviderNoNotify(NULL); 1789 bool success = SetDefaultSearchProviderNoNotify(NULL);
1790 DCHECK(success);
1622 RemoveNoNotify(old_default); 1791 RemoveNoNotify(old_default);
1623 } else if (default_search_provider_) { 1792 } else if (default_search_provider_) {
1624 TemplateURLData data(new_default_from_prefs->data()); 1793 TemplateURLData data(new_default_from_prefs->data());
1625 data.created_by_policy = true; 1794 data.created_by_policy = true;
1626 TemplateURL new_values(profile_, data); 1795 TemplateURL new_values(profile_, data);
1627 UpdateNoNotify(default_search_provider_, new_values); 1796 UpdateNoNotify(default_search_provider_, new_values);
1628 } else { 1797 } else {
1629 TemplateURL* new_template = NULL; 1798 TemplateURL* new_template = NULL;
1630 if (new_default_from_prefs.get()) { 1799 if (new_default_from_prefs.get()) {
1631 TemplateURLData data(new_default_from_prefs->data()); 1800 TemplateURLData data(new_default_from_prefs->data());
1632 data.created_by_policy = true; 1801 data.created_by_policy = true;
1633 new_template = new TemplateURL(profile_, data); 1802 new_template = new TemplateURL(profile_, data);
1634 AddNoNotify(new_template, true); 1803 if (!AddNoNotify(new_template, true))
1804 return;
1635 } 1805 }
1636 SetDefaultSearchProviderNoNotify(new_template); 1806 bool success = SetDefaultSearchProviderNoNotify(new_template);
1807 DCHECK(success);
1637 } 1808 }
1638 } else if (!is_default_search_managed_ && new_is_default_managed) { 1809 } else if (!is_default_search_managed_ && new_is_default_managed) {
1639 // The default used to be unmanaged and is now managed. Add the new 1810 // The default used to be unmanaged and is now managed. Add the new
1640 // managed default to the list of URLs and set it as default. 1811 // managed default to the list of URLs and set it as default.
1641 is_default_search_managed_ = new_is_default_managed; 1812 is_default_search_managed_ = new_is_default_managed;
1642 TemplateURL* new_template = NULL; 1813 TemplateURL* new_template = NULL;
1643 if (new_default_from_prefs.get()) { 1814 if (new_default_from_prefs.get()) {
1644 TemplateURLData data(new_default_from_prefs->data()); 1815 TemplateURLData data(new_default_from_prefs->data());
1645 data.created_by_policy = true; 1816 data.created_by_policy = true;
1646 new_template = new TemplateURL(profile_, data); 1817 new_template = new TemplateURL(profile_, data);
1647 AddNoNotify(new_template, true); 1818 if (!AddNoNotify(new_template, true))
1819 return;
1648 } 1820 }
1649 SetDefaultSearchProviderNoNotify(new_template); 1821 bool success = SetDefaultSearchProviderNoNotify(new_template);
1822 DCHECK(success);
1650 } else { 1823 } else {
1651 // The default was managed and is no longer. 1824 // The default was managed and is no longer.
1652 DCHECK(is_default_search_managed_ && !new_is_default_managed); 1825 DCHECK(is_default_search_managed_ && !new_is_default_managed);
1653 is_default_search_managed_ = new_is_default_managed; 1826 is_default_search_managed_ = new_is_default_managed;
1654 // If we had a default, delete the previous default if created by policy 1827 // If we had a default, delete the previous default if created by policy
1655 // and set a likely default. 1828 // and set a likely default.
1656 if ((default_search_provider_ != NULL) && 1829 if ((default_search_provider_ != NULL) &&
1657 default_search_provider_->created_by_policy()) { 1830 default_search_provider_->created_by_policy()) {
1658 TemplateURL* old_default = default_search_provider_; 1831 TemplateURL* old_default = default_search_provider_;
1659 default_search_provider_ = NULL; 1832 default_search_provider_ = NULL;
1660 RemoveNoNotify(old_default); 1833 RemoveNoNotify(old_default);
1661 } 1834 }
1662 1835
1663 // The likely default should be from Sync if we were waiting on Sync. 1836 // The likely default should be from Sync if we were waiting on Sync.
1664 // Otherwise, it should be FindNewDefaultSearchProvider. 1837 // Otherwise, it should be FindNewDefaultSearchProvider.
1665 TemplateURL* synced_default = GetPendingSyncedDefaultSearchProvider(); 1838 TemplateURL* synced_default = GetPendingSyncedDefaultSearchProvider();
1666 if (synced_default) 1839 if (synced_default)
1667 pending_synced_default_search_ = false; 1840 pending_synced_default_search_ = false;
1668 SetDefaultSearchProviderNoNotify(synced_default ? synced_default : 1841 SetDefaultSearchProviderNoNotify(synced_default ? synced_default :
1669 FindNewDefaultSearchProvider()); 1842 FindNewDefaultSearchProvider());
1670 } 1843 }
1671 NotifyObservers(); 1844 NotifyObservers();
1672 } 1845 }
1673 1846
1674 void TemplateURLService::SetDefaultSearchProviderNoNotify(TemplateURL* url) { 1847 bool TemplateURLService::SetDefaultSearchProviderNoNotify(TemplateURL* url) {
1675 if (url) { 1848 if (url) {
1676 DCHECK(std::find(template_urls_.begin(), template_urls_.end(), url) != 1849 if (std::find(template_urls_.begin(), template_urls_.end(), url) ==
1677 template_urls_.end()); 1850 template_urls_.end())
1851 return false;
1678 // Extension keywords cannot be made default, as they're inherently async. 1852 // Extension keywords cannot be made default, as they're inherently async.
1679 DCHECK(!url->IsExtensionKeyword()); 1853 DCHECK(!url->IsExtensionKeyword());
1680 } 1854 }
1681 1855
1682 default_search_provider_ = url; 1856 default_search_provider_ = url;
1683 1857
1684 if (url) { 1858 if (url) {
1685 // Don't mark the url as edited, otherwise we won't be able to rev the 1859 // Don't mark the url as edited, otherwise we won't be able to rev the
1686 // template urls we ship with. 1860 // template urls we ship with.
1687 url->data_.show_in_default_list = true; 1861 url->data_.show_in_default_list = true;
1688 if (service_.get()) 1862 if (service_.get())
1689 service_->UpdateKeyword(*url); 1863 service_->UpdateKeyword(url->data());
1690 1864
1691 if (url->url_ref().HasGoogleBaseURLs()) { 1865 if (url->url_ref().HasGoogleBaseURLs()) {
1692 GoogleURLTracker::RequestServerCheck(); 1866 GoogleURLTracker::RequestServerCheck();
1693 #if defined(ENABLE_RLZ) 1867 #if defined(ENABLE_RLZ)
1694 // Needs to be evaluated. See http://crbug.com/62328. 1868 // Needs to be evaluated. See http://crbug.com/62328.
1695 base::ThreadRestrictions::ScopedAllowIO allow_io; 1869 base::ThreadRestrictions::ScopedAllowIO allow_io;
1696 RLZTracker::RecordProductEvent(rlz_lib::CHROME, 1870 RLZTracker::RecordProductEvent(rlz_lib::CHROME,
1697 rlz_lib::CHROME_OMNIBOX, 1871 rlz_lib::CHROME_OMNIBOX,
1698 rlz_lib::SET_TO_GOOGLE); 1872 rlz_lib::SET_TO_GOOGLE);
1699 #endif 1873 #endif
(...skipping 11 matching lines...) Expand all
1711 url->sync_guid()); 1885 url->sync_guid());
1712 } 1886 }
1713 } 1887 }
1714 1888
1715 if (service_.get()) 1889 if (service_.get())
1716 service_->SetDefaultSearchProvider(url); 1890 service_->SetDefaultSearchProvider(url);
1717 1891
1718 // Inform sync the change to the show_in_default_list flag. 1892 // Inform sync the change to the show_in_default_list flag.
1719 if (url) 1893 if (url)
1720 ProcessTemplateURLChange(url, SyncChange::ACTION_UPDATE); 1894 ProcessTemplateURLChange(url, SyncChange::ACTION_UPDATE);
1895 return true;
1721 } 1896 }
1722 1897
1723 void TemplateURLService::AddNoNotify(TemplateURL* template_url, 1898 bool TemplateURLService::AddNoNotify(TemplateURL* template_url,
1724 bool newly_adding) { 1899 bool newly_adding) {
1725 DCHECK(template_url); 1900 DCHECK(template_url);
1726 1901
1727 if (newly_adding) { 1902 if (newly_adding) {
1728 DCHECK_EQ(kInvalidTemplateURLID, template_url->id()); 1903 DCHECK_EQ(kInvalidTemplateURLID, template_url->id());
1729 DCHECK(std::find(template_urls_.begin(), template_urls_.end(), 1904 DCHECK(std::find(template_urls_.begin(), template_urls_.end(),
1730 template_url) == template_urls_.end()); 1905 template_url) == template_urls_.end());
1731 template_url->data_.id = ++next_id_; 1906 template_url->data_.id = ++next_id_;
1732 } 1907 }
1733 1908
1909 template_url->ResetKeywordIfNecessary(false);
1910 if (!template_url->IsExtensionKeyword()) {
1911 // Check whether |template_url|'s keyword conflicts with any already in the
1912 // model.
1913 TemplateURL* existing_keyword_turl =
1914 FindNonExtensionTemplateURLForKeyword(template_url->keyword());
1915 if (existing_keyword_turl != NULL) {
1916 DCHECK_NE(existing_keyword_turl, template_url);
1917 if (CanReplace(existing_keyword_turl)) {
1918 RemoveNoNotify(existing_keyword_turl);
1919 } else if (CanReplace(template_url)) {
1920 delete template_url;
1921 return false;
1922 } else {
1923 string16 new_keyword = UniquifyKeyword(*existing_keyword_turl);
1924 ResetTemplateURL(existing_keyword_turl,
1925 existing_keyword_turl->short_name(), new_keyword,
1926 existing_keyword_turl->url());
1927 }
1928 }
1929 }
1734 template_urls_.push_back(template_url); 1930 template_urls_.push_back(template_url);
1735 AddToMaps(template_url); 1931 AddToMaps(template_url);
1736 1932
1737 if (newly_adding) { 1933 if (newly_adding) {
1738 // Don't persist extension keywords to disk. They'll get re-added on each 1934 // Don't persist extension keywords to disk. They'll get re-added on each
1739 // launch as the extensions are loaded. 1935 // launch as the extensions are loaded.
1740 // TODO(mpcomplete): If we allow editing extension keywords, then those 1936 // TODO(mpcomplete): If we allow editing extension keywords, then those
1741 // should be persisted to disk and synced. 1937 // should be persisted to disk and synced.
1742 if (service_.get() && !template_url->IsExtensionKeyword()) 1938 if (service_.get() && !template_url->IsExtensionKeyword())
1743 service_->AddKeyword(*template_url); 1939 service_->AddKeyword(template_url->data());
1744 1940
1745 // Inform sync of the addition. Note that this will assign a GUID to 1941 // Inform sync of the addition. Note that this will assign a GUID to
1746 // template_url and add it to the guid_to_template_map_. 1942 // template_url and add it to the guid_to_template_map_.
1747 ProcessTemplateURLChange(template_url, SyncChange::ACTION_ADD); 1943 ProcessTemplateURLChange(template_url, SyncChange::ACTION_ADD);
1748 } 1944 }
1945
1946 return true;
1749 } 1947 }
1750 1948
1751 void TemplateURLService::RemoveNoNotify(TemplateURL* template_url) { 1949 void TemplateURLService::RemoveNoNotify(TemplateURL* template_url) {
1752 TemplateURLVector::iterator i = 1950 TemplateURLVector::iterator i =
1753 std::find(template_urls_.begin(), template_urls_.end(), template_url); 1951 std::find(template_urls_.begin(), template_urls_.end(), template_url);
1754 if (i == template_urls_.end()) 1952 if (i == template_urls_.end())
1755 return; 1953 return;
1756 1954
1757 if (template_url == default_search_provider_) { 1955 if (template_url == default_search_provider_) {
1758 // Should never delete the default search provider. 1956 // Should never delete the default search provider.
(...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after
1840 service_->RemoveKeyword(template_url->id()); 2038 service_->RemoveKeyword(template_url->id());
1841 delete template_url; 2039 delete template_url;
1842 } else { 2040 } else {
1843 ++i; 2041 ++i;
1844 } 2042 }
1845 } 2043 }
1846 } 2044 }
1847 2045
1848 void TemplateURLService::ResetTemplateURLGUID(TemplateURL* url, 2046 void TemplateURLService::ResetTemplateURLGUID(TemplateURL* url,
1849 const std::string& guid) { 2047 const std::string& guid) {
2048 DCHECK(loaded_);
1850 DCHECK(!guid.empty()); 2049 DCHECK(!guid.empty());
1851 2050
1852 TemplateURLData data(url->data()); 2051 TemplateURLData data(url->data());
1853 data.sync_guid = guid; 2052 data.sync_guid = guid;
1854 TemplateURL new_url(url->profile(), data); 2053 TemplateURL new_url(url->profile(), data);
1855 UpdateNoNotify(url, new_url); 2054 UpdateNoNotify(url, new_url);
1856 } 2055 }
1857 2056
1858 string16 TemplateURLService::UniquifyKeyword(const TemplateURL& turl) { 2057 string16 TemplateURLService::UniquifyKeyword(const TemplateURL& turl) {
1859 // Already unique. 2058 // Already unique.
1860 if (!GetTemplateURLForKeyword(turl.keyword())) 2059 if (!GetTemplateURLForKeyword(turl.keyword()))
1861 return turl.keyword(); 2060 return turl.keyword();
1862 2061
1863 // First, try to return the generated keyword for the TemplateURL. 2062 // First, try to return the generated keyword for the TemplateURL.
1864 GURL gurl(turl.url()); 2063 GURL gurl(turl.url());
1865 if (gurl.is_valid()) { 2064 if (gurl.is_valid()) {
1866 string16 keyword_candidate = GenerateKeyword(gurl, true); 2065 string16 keyword_candidate = GenerateKeyword(gurl);
1867 if (!GetTemplateURLForKeyword(keyword_candidate) && 2066 if (!GetTemplateURLForKeyword(keyword_candidate))
1868 !keyword_candidate.empty())
1869 return keyword_candidate; 2067 return keyword_candidate;
1870 } 2068 }
1871 2069
1872 // We try to uniquify the keyword by appending a special character to the end. 2070 // We try to uniquify the keyword by appending a special character to the end.
1873 // This is a best-effort approach where we try to preserve the original 2071 // This is a best-effort approach where we try to preserve the original
1874 // keyword and let the user do what they will after our attempt. 2072 // keyword and let the user do what they will after our attempt.
1875 string16 keyword_candidate(turl.keyword()); 2073 string16 keyword_candidate(turl.keyword());
1876 do { 2074 do {
1877 keyword_candidate.append(ASCIIToUTF16("_")); 2075 keyword_candidate.append(ASCIIToUTF16("_"));
1878 } while (GetTemplateURLForKeyword(keyword_candidate)); 2076 } while (GetTemplateURLForKeyword(keyword_candidate));
1879 2077
1880 return keyword_candidate; 2078 return keyword_candidate;
1881 } 2079 }
1882 2080
1883 bool TemplateURLService::ResolveSyncKeywordConflict( 2081 void TemplateURLService::ResolveSyncKeywordConflict(
1884 TemplateURL* sync_turl, 2082 TemplateURL* sync_turl,
2083 TemplateURL* local_turl,
1885 SyncChangeList* change_list) { 2084 SyncChangeList* change_list) {
2085 DCHECK(loaded_);
1886 DCHECK(sync_turl); 2086 DCHECK(sync_turl);
2087 DCHECK(local_turl);
2088 DCHECK(sync_turl->sync_guid() != local_turl->sync_guid());
2089 DCHECK(!local_turl->IsExtensionKeyword());
1887 DCHECK(change_list); 2090 DCHECK(change_list);
1888 2091
1889 TemplateURL* existing_turl = 2092 if (local_turl->last_modified() > sync_turl->last_modified() ||
1890 GetTemplateURLForKeyword(sync_turl->keyword()); 2093 local_turl->created_by_policy()) {
1891 // If there is no conflict, or it's just conflicting with itself, return.
1892 if (!existing_turl || existing_turl->sync_guid() == sync_turl->sync_guid())
1893 return false;
1894
1895 if (existing_turl->last_modified() > sync_turl->last_modified() ||
1896 existing_turl->created_by_policy()) {
1897 string16 new_keyword = UniquifyKeyword(*sync_turl); 2094 string16 new_keyword = UniquifyKeyword(*sync_turl);
1898 DCHECK(!GetTemplateURLForKeyword(new_keyword)); 2095 DCHECK(!GetTemplateURLForKeyword(new_keyword));
1899 sync_turl->data_.SetKeyword(new_keyword); 2096 sync_turl->data_.SetKeyword(new_keyword);
1900 // If we update the cloud TURL, we need to push an update back to sync 2097 // If we update the cloud TURL, we need to push an update back to sync
1901 // informing it that something has changed. 2098 // informing it that something has changed.
1902 SyncData sync_data = CreateSyncDataFromTemplateURL(*sync_turl); 2099 SyncData sync_data = CreateSyncDataFromTemplateURL(*sync_turl);
1903 change_list->push_back(SyncChange(SyncChange::ACTION_UPDATE, sync_data)); 2100 change_list->push_back(SyncChange(SyncChange::ACTION_UPDATE, sync_data));
1904 } else { 2101 } else {
1905 string16 new_keyword = UniquifyKeyword(*existing_turl); 2102 string16 new_keyword = UniquifyKeyword(*local_turl);
1906 TemplateURLData data(existing_turl->data()); 2103 TemplateURLData data(local_turl->data());
1907 data.SetKeyword(new_keyword); 2104 data.SetKeyword(new_keyword);
1908 TemplateURL new_turl(existing_turl->profile(), data); 2105 TemplateURL new_turl(local_turl->profile(), data);
1909 UpdateNoNotify(existing_turl, new_turl); 2106 if (UpdateNoNotify(local_turl, new_turl))
1910 NotifyObservers(); 2107 NotifyObservers();
2108 if (!models_associated_) {
2109 // We're doing our initial sync, so UpdateNoNotify() won't have generated
2110 // an ACTION_UPDATE. If this local URL is one that was just newly brought
2111 // down from the sync server, we need to go ahead and generate an update
2112 // for it. If it was pre-existing, then this is unnecessary (and in fact
2113 // wrong) because MergeDataAndStartSyncing() will later add an ACTION_ADD
2114 // for this URL; but in this case, PreventDuplicateGUIDUpdates() will
2115 // prune out the ACTION_UPDATE we create here.
2116 SyncData sync_data = CreateSyncDataFromTemplateURL(*local_turl);
2117 change_list->push_back(SyncChange(SyncChange::ACTION_UPDATE, sync_data));
2118 }
1911 } 2119 }
1912 return true;
1913 } 2120 }
1914 2121
1915 TemplateURL* TemplateURLService::FindDuplicateOfSyncTemplateURL( 2122 TemplateURL* TemplateURLService::FindDuplicateOfSyncTemplateURL(
1916 const TemplateURL& sync_turl) { 2123 const TemplateURL& sync_turl) {
1917 TemplateURL* existing_turl = GetTemplateURLForKeyword(sync_turl.keyword()); 2124 TemplateURL* existing_turl = GetTemplateURLForKeyword(sync_turl.keyword());
1918 return existing_turl && (existing_turl->url() == sync_turl.url()) ? 2125 return existing_turl && (existing_turl->url() == sync_turl.url()) ?
1919 existing_turl : NULL; 2126 existing_turl : NULL;
1920 } 2127 }
1921 2128
1922 void TemplateURLService::MergeSyncAndLocalURLDuplicates( 2129 void TemplateURLService::MergeSyncAndLocalURLDuplicates(
1923 TemplateURL* sync_turl, 2130 TemplateURL* sync_turl,
1924 TemplateURL* local_turl, 2131 TemplateURL* local_turl,
1925 SyncChangeList* change_list) { 2132 SyncChangeList* change_list) {
2133 DCHECK(loaded_);
1926 DCHECK(sync_turl); 2134 DCHECK(sync_turl);
1927 DCHECK(local_turl); 2135 DCHECK(local_turl);
1928 DCHECK(change_list); 2136 DCHECK(change_list);
1929 scoped_ptr<TemplateURL> scoped_sync_turl(sync_turl); 2137 scoped_ptr<TemplateURL> scoped_sync_turl(sync_turl);
1930 if (sync_turl->last_modified() > local_turl->last_modified()) { 2138 if (sync_turl->last_modified() > local_turl->last_modified()) {
1931 // Fully replace local_url with Sync's copy. Note that because use Add 2139 // Fully replace local_url with Sync's copy. Note that because use Add
1932 // rather than ResetTemplateURL, |sync_url| is added with a fresh 2140 // rather than ResetTemplateURL, |sync_url| is added with a fresh
1933 // TemplateURLID. We don't need to sync the new ID back to the server since 2141 // TemplateURLID. We don't need to sync the new ID back to the server since
1934 // it's only relevant locally. 2142 // it's only relevant locally.
1935 bool delete_default = (local_turl == GetDefaultSearchProvider()); 2143 bool delete_default = (local_turl == GetDefaultSearchProvider());
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after
1990 i != template_urls->end(); ++i) { 2198 i != template_urls->end(); ++i) {
1991 TemplateURL* template_url = *i; 2199 TemplateURL* template_url = *i;
1992 DCHECK(template_url); 2200 DCHECK(template_url);
1993 // Extension keywords are never synced. 2201 // Extension keywords are never synced.
1994 // TODO(mpcomplete): If we allow editing extension keywords, then those 2202 // TODO(mpcomplete): If we allow editing extension keywords, then those
1995 // should be persisted to disk and synced. 2203 // should be persisted to disk and synced.
1996 if (template_url->sync_guid().empty() && 2204 if (template_url->sync_guid().empty() &&
1997 !template_url->IsExtensionKeyword()) { 2205 !template_url->IsExtensionKeyword()) {
1998 template_url->data_.sync_guid = guid::GenerateGUID(); 2206 template_url->data_.sync_guid = guid::GenerateGUID();
1999 if (service_.get()) 2207 if (service_.get())
2000 service_->UpdateKeyword(*template_url); 2208 service_->UpdateKeyword(template_url->data());
2001 } 2209 }
2002 } 2210 }
2003 } 2211 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698