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