summaryrefslogtreecommitdiffstats
path: root/chrome/browser/ui/search_engines/edit_search_engine_controller.cc
blob: 26a2d40cba7bd05a093fab3e613fd09a60a111ce (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/ui/search_engines/edit_search_engine_controller.h"

#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/search_engines/template_url_service.h"
#include "chrome/browser/search_engines/template_url_service_factory.h"
#include "components/search_engines/template_url.h"
#include "components/url_fixer/url_fixer.h"
#include "content/public/browser/user_metrics.h"
#include "url/gurl.h"

using base::UserMetricsAction;

EditSearchEngineController::EditSearchEngineController(
    TemplateURL* template_url,
    EditSearchEngineControllerDelegate* edit_keyword_delegate,
    Profile* profile)
    : template_url_(template_url),
      edit_keyword_delegate_(edit_keyword_delegate),
      profile_(profile) {
  DCHECK(profile_);
}

bool EditSearchEngineController::IsTitleValid(
    const base::string16& title_input) const {
  return !base::CollapseWhitespace(title_input, true).empty();
}

bool EditSearchEngineController::IsURLValid(
    const std::string& url_input) const {
  std::string url = GetFixedUpURL(url_input);
  if (url.empty())
    return false;

  // Convert |url| to a TemplateURLRef so we can check its validity even if it
  // contains replacement strings.  We do this by constructing a dummy
  // TemplateURL owner because |template_url_| might be NULL and we can't call
  // TemplateURLRef::IsValid() when its owner is NULL.
  TemplateURLData data;
  data.SetURL(url);
  TemplateURL t_url(data);
  const TemplateURLRef& template_ref = t_url.url_ref();
  TemplateURLService* service =
      TemplateURLServiceFactory::GetForProfile(profile_);
  if (!template_ref.IsValid(service->search_terms_data()))
    return false;

  // If this is going to be the default search engine, it must support
  // replacement.
  if (!template_ref.SupportsReplacement(service->search_terms_data()) &&
      template_url_ &&
      template_url_ == service->GetDefaultSearchProvider())
    return false;

  // Replace any search term with a placeholder string and make sure the
  // resulting URL is valid.
  return GURL(template_ref.ReplaceSearchTerms(
      TemplateURLRef::SearchTermsArgs(base::ASCIIToUTF16("x")),
      service->search_terms_data())).is_valid();
}

bool EditSearchEngineController::IsKeywordValid(
    const base::string16& keyword_input) const {
  base::string16 keyword_input_trimmed(
      base::CollapseWhitespace(keyword_input, true));
  if (keyword_input_trimmed.empty())
    return false;  // Do not allow empty keyword.
  const TemplateURL* turl_with_keyword =
      TemplateURLServiceFactory::GetForProfile(profile_)->
      GetTemplateURLForKeyword(keyword_input_trimmed);
  return (turl_with_keyword == NULL || turl_with_keyword == template_url_);
}

void EditSearchEngineController::AcceptAddOrEdit(
    const base::string16& title_input,
    const base::string16& keyword_input,
    const std::string& url_input) {
  DCHECK(!keyword_input.empty());
  std::string url_string = GetFixedUpURL(url_input);
  DCHECK(!url_string.empty());

  TemplateURLService* template_url_service =
      TemplateURLServiceFactory::GetForProfile(profile_);
  TemplateURL* existing =
      template_url_service->GetTemplateURLForKeyword(keyword_input);
  if (existing && (!edit_keyword_delegate_ || existing != template_url_)) {
    // An entry may have been added with the same keyword string while the
    // user edited the dialog, either automatically or by the user (if we're
    // confirming a JS addition, they could have the Options dialog open at the
    // same time). If so, just ignore this add.
    // TODO(pamg): Really, we should modify the entry so this later one
    // overwrites it. But we don't expect this case to be common.
    CleanUpCancelledAdd();
    return;
  }

  if (!edit_keyword_delegate_) {
    // Confiming an entry we got from JS. We have a template_url_, but it
    // hasn't yet been added to the model.
    DCHECK(template_url_);
    // TemplateURLService takes ownership of template_url_.
    template_url_service->AddWithOverrides(template_url_, title_input,
                                           keyword_input, url_string);
    content::RecordAction(UserMetricsAction("KeywordEditor_AddKeywordJS"));
  } else {
    // Adding or modifying an entry via the Delegate.
    edit_keyword_delegate_->OnEditedKeyword(template_url_, title_input,
                                            keyword_input, url_string);
  }
}

void EditSearchEngineController::CleanUpCancelledAdd() {
  if (!edit_keyword_delegate_ && template_url_) {
    // When we have no Delegate, we know that the template_url_ hasn't yet been
    // added to the model, so we need to clean it up.
    delete template_url_;
    template_url_ = NULL;
  }
}

std::string EditSearchEngineController::GetFixedUpURL(
    const std::string& url_input) const {
  std::string url;
  base::TrimWhitespace(TemplateURLRef::DisplayURLToURLRef(
                           base::UTF8ToUTF16(url_input)),
                       base::TRIM_ALL, &url);
  if (url.empty())
    return url;

  // Parse the string as a URL to determine the scheme. If we need to, add the
  // scheme. As the scheme may be expanded (as happens with {google:baseURL})
  // we need to replace the search terms before testing for the scheme.
  TemplateURLData data;
  data.SetURL(url);
  TemplateURL t_url(data);
  std::string expanded_url(t_url.url_ref().ReplaceSearchTerms(
      TemplateURLRef::SearchTermsArgs(base::ASCIIToUTF16("x")),
      TemplateURLServiceFactory::GetForProfile(profile_)->search_terms_data()));
  url::Parsed parts;
  std::string scheme(url_fixer::SegmentURL(expanded_url, &parts));
  if (!parts.scheme.is_valid())
    url.insert(0, scheme + "://");

  return url;
}