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