172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen// Copyright (c) 2011 The Chromium Authors. All rights reserved. 2c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Use of this source code is governed by a BSD-style license that can be 3c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// found in the LICENSE file. 4c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 5dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#include "chrome/browser/ui/search_engines/edit_search_engine_controller.h" 6c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 7c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/string_util.h" 8c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/utf_string_conversions.h" 9c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/metrics/user_metrics.h" 10c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/net/url_fixer_upper.h" 1121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen#include "chrome/browser/profiles/profile.h" 12c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/search_engines/template_url.h" 13c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/search_engines/template_url_model.h" 14c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "googleurl/src/gurl.h" 15c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 16c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochEditSearchEngineController::EditSearchEngineController( 17c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const TemplateURL* template_url, 18c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch EditSearchEngineControllerDelegate* edit_keyword_delegate, 19c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch Profile* profile) 20c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch : template_url_(template_url), 21c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch edit_keyword_delegate_(edit_keyword_delegate), 22c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch profile_(profile) { 23c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DCHECK(profile_); 24c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 25c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 26c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool EditSearchEngineController::IsTitleValid( 273345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick const string16& title_input) const { 28c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return !CollapseWhitespace(title_input, true).empty(); 29c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 30c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 31c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool EditSearchEngineController::IsURLValid( 32c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const std::string& url_input) const { 33c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch std::string url = GetFixedUpURL(url_input); 34c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (url.empty()) 35c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return false; 36c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 37c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Use TemplateURLRef to extract the search placeholder. 38c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch TemplateURLRef template_ref(url, 0, 0); 39c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!template_ref.IsValid()) 40c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return false; 41c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 42c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!template_ref.SupportsReplacement()) { 43c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // If this is the default search engine, there must be a search term 44c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // placeholder. 45c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (template_url_ == 46c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch profile_->GetTemplateURLModel()->GetDefaultSearchProvider()) 47c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return false; 48c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return GURL(url).is_valid(); 49c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 50c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 51c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // If the url has a search term, replace it with a random string and make 52c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // sure the resulting URL is valid. We don't check the validity of the url 53c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // with the search term as that is not necessarily valid. 5472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen return GURL(template_ref.ReplaceSearchTerms(TemplateURL(), ASCIIToUTF16("a"), 5572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen TemplateURLRef::NO_SUGGESTIONS_AVAILABLE, string16())).is_valid(); 56c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 57c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 58c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool EditSearchEngineController::IsKeywordValid( 593345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick const string16& keyword_input) const { 603345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick string16 keyword_input_trimmed(CollapseWhitespace(keyword_input, true)); 61c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (keyword_input_trimmed.empty()) 62c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return false; // Do not allow empty keyword. 63c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const TemplateURL* turl_with_keyword = 64c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch profile_->GetTemplateURLModel()->GetTemplateURLForKeyword( 6572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen keyword_input_trimmed); 66c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return (turl_with_keyword == NULL || turl_with_keyword == template_url_); 67c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 68c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 69c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid EditSearchEngineController::AcceptAddOrEdit( 703345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick const string16& title_input, 713345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick const string16& keyword_input, 72c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const std::string& url_input) { 73c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch std::string url_string = GetFixedUpURL(url_input); 74c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DCHECK(!url_string.empty()); 75c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 76c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const TemplateURL* existing = 773345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick profile_->GetTemplateURLModel()->GetTemplateURLForKeyword( 7872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen keyword_input); 79c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (existing && 80c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch (!edit_keyword_delegate_ || existing != template_url_)) { 81c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // An entry may have been added with the same keyword string while the 82c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // user edited the dialog, either automatically or by the user (if we're 83c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // confirming a JS addition, they could have the Options dialog open at the 84c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // same time). If so, just ignore this add. 85c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // TODO(pamg): Really, we should modify the entry so this later one 86c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // overwrites it. But we don't expect this case to be common. 87c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch CleanUpCancelledAdd(); 88c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return; 89c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 90c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 91c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!edit_keyword_delegate_) { 92c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Confiming an entry we got from JS. We have a template_url_, but it 93c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // hasn't yet been added to the model. 94c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DCHECK(template_url_); 95c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // const_cast is ugly, but this is the same thing the TemplateURLModel 96c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // does in a similar situation (updating an existing TemplateURL with 97c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // data from a new one). 98c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch TemplateURL* modifiable_url = const_cast<TemplateURL*>(template_url_); 9972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen modifiable_url->set_short_name(title_input); 10072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen modifiable_url->set_keyword(keyword_input); 101c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch modifiable_url->SetURL(url_string, 0, 0); 102c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // TemplateURLModel takes ownership of template_url_. 103c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch profile_->GetTemplateURLModel()->Add(modifiable_url); 104c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch UserMetrics::RecordAction(UserMetricsAction("KeywordEditor_AddKeywordJS"), 105c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch profile_); 106c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } else { 107c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Adding or modifying an entry via the Delegate. 108c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch edit_keyword_delegate_->OnEditedKeyword(template_url_, 109c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch title_input, 110c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch keyword_input, 111c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch url_string); 112c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 113c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 114c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 115c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid EditSearchEngineController::CleanUpCancelledAdd() { 116c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!edit_keyword_delegate_ && template_url_) { 117c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // When we have no Delegate, we know that the template_url_ hasn't yet been 118c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // added to the model, so we need to clean it up. 119c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch delete template_url_; 120c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch template_url_ = NULL; 121c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 122c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 123c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 124c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochstd::string EditSearchEngineController::GetFixedUpURL( 125c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const std::string& url_input) const { 126c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch std::string url; 12772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen TrimWhitespace(TemplateURLRef::DisplayURLToURLRef(UTF8ToUTF16(url_input)), 128c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch TRIM_ALL, &url); 129c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (url.empty()) 130c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return url; 131c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 132c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Parse the string as a URL to determine the scheme. If we need to, add the 133c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // scheme. As the scheme may be expanded (as happens with {google:baseURL}) 134c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // we need to replace the search terms before testing for the scheme. 135c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch TemplateURL t_url; 136c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch t_url.SetURL(url, 0, 0); 137c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch std::string expanded_url = 13872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen t_url.url()->ReplaceSearchTerms(t_url, ASCIIToUTF16("x"), 0, string16()); 139c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch url_parse::Parsed parts; 140c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch std::string scheme( 141c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch URLFixerUpper::SegmentURL(expanded_url, &parts)); 142c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!parts.scheme.is_valid()) { 143c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch scheme.append("://"); 144c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch url.insert(0, scheme); 145c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 146c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 147c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return url; 148c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 149c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 150