1// Copyright 2013 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/webui/translate_internals/translate_internals_handler.h"
6
7#include <map>
8#include <vector>
9
10#include "base/bind.h"
11#include "base/bind_helpers.h"
12#include "base/prefs/pref_service.h"
13#include "base/values.h"
14#include "chrome/browser/chrome_notification_types.h"
15#include "chrome/browser/profiles/profile.h"
16#include "chrome/browser/translate/chrome_translate_client.h"
17#include "chrome/browser/translate/translate_service.h"
18#include "chrome/common/pref_names.h"
19#include "components/translate/core/browser/translate_download_manager.h"
20#include "components/translate/core/browser/translate_error_details.h"
21#include "components/translate/core/browser/translate_event_details.h"
22#include "components/translate/core/browser/translate_prefs.h"
23#include "components/translate/core/common/language_detection_details.h"
24#include "components/translate/core/common/translate_pref_names.h"
25#include "content/public/browser/notification_details.h"
26#include "content/public/browser/notification_service.h"
27#include "content/public/browser/notification_source.h"
28#include "content/public/browser/notification_types.h"
29#include "content/public/browser/web_contents.h"
30#include "content/public/browser/web_ui.h"
31
32TranslateInternalsHandler::TranslateInternalsHandler() {
33  notification_registrar_.Add(this,
34                              chrome::NOTIFICATION_TAB_LANGUAGE_DETERMINED,
35                              content::NotificationService::AllSources());
36
37  error_subscription_ =
38      translate::TranslateManager::RegisterTranslateErrorCallback(
39          base::Bind(&TranslateInternalsHandler::OnTranslateError,
40                     base::Unretained(this)));
41
42  translate::TranslateLanguageList* language_list =
43      translate::TranslateDownloadManager::GetInstance()->language_list();
44  if (!language_list) {
45    NOTREACHED();
46    return;
47  }
48
49  event_subscription_ = language_list->RegisterEventCallback(base::Bind(
50      &TranslateInternalsHandler::OnTranslateEvent, base::Unretained(this)));
51}
52
53TranslateInternalsHandler::~TranslateInternalsHandler() {
54  // |event_subscription_| and |error_subscription_| are deleted automatically
55  // and un-register the callbacks automatically.
56}
57
58void TranslateInternalsHandler::RegisterMessages() {
59  web_ui()->RegisterMessageCallback("removePrefItem", base::Bind(
60      &TranslateInternalsHandler::OnRemovePrefItem, base::Unretained(this)));
61  web_ui()->RegisterMessageCallback("requestInfo", base::Bind(
62      &TranslateInternalsHandler::OnRequestInfo, base::Unretained(this)));
63}
64
65void TranslateInternalsHandler::Observe(
66    int type,
67    const content::NotificationSource& source,
68    const content::NotificationDetails& details) {
69  DCHECK_EQ(chrome::NOTIFICATION_TAB_LANGUAGE_DETERMINED, type);
70  const translate::LanguageDetectionDetails* language_detection_details =
71      content::Details<const translate::LanguageDetectionDetails>(details)
72          .ptr();
73  content::WebContents* web_contents =
74      content::Source<content::WebContents>(source).ptr();
75
76  if (web_contents->GetBrowserContext()->IsOffTheRecord() ||
77      !TranslateService::IsTranslatableURL(language_detection_details->url)) {
78    return;
79  }
80
81  base::DictionaryValue dict;
82  dict.Set(
83      "time",
84      new base::FundamentalValue(language_detection_details->time.ToJsTime()));
85  dict.Set("url",
86           new base::StringValue(language_detection_details->url.spec()));
87  dict.Set("content_language",
88           new base::StringValue(language_detection_details->content_language));
89  dict.Set("cld_language",
90           new base::StringValue(language_detection_details->cld_language));
91  dict.Set(
92      "is_cld_reliable",
93      new base::FundamentalValue(language_detection_details->is_cld_reliable));
94  dict.Set(
95      "html_root_language",
96      new base::StringValue(language_detection_details->html_root_language));
97  dict.Set("adopted_language",
98           new base::StringValue(language_detection_details->adopted_language));
99  dict.Set("content",
100           new base::StringValue(language_detection_details->contents));
101  SendMessageToJs("languageDetectionInfoAdded", dict);
102}
103
104void TranslateInternalsHandler::OnTranslateError(
105    const translate::TranslateErrorDetails& details) {
106  base::DictionaryValue dict;
107  dict.Set("time",
108           new base::FundamentalValue(details.time.ToJsTime()));
109  dict.Set("url",
110           new base::StringValue(details.url.spec()));
111  dict.Set("error",
112           new base::FundamentalValue(details.error));
113  SendMessageToJs("translateErrorDetailsAdded", dict);
114}
115
116void TranslateInternalsHandler::OnTranslateEvent(
117    const translate::TranslateEventDetails& details) {
118  base::DictionaryValue dict;
119  dict.Set("time", new base::FundamentalValue(details.time.ToJsTime()));
120  dict.Set("filename", new base::StringValue(details.filename));
121  dict.Set("line", new base::FundamentalValue(details.line));
122  dict.Set("message", new base::StringValue(details.message));
123  SendMessageToJs("translateEventDetailsAdded", dict);
124}
125
126void TranslateInternalsHandler::OnRemovePrefItem(const base::ListValue* args) {
127  content::WebContents* web_contents = web_ui()->GetWebContents();
128  Profile* profile =
129      Profile::FromBrowserContext(web_contents->GetBrowserContext());
130  PrefService* prefs = profile->GetOriginalProfile()->GetPrefs();
131  scoped_ptr<translate::TranslatePrefs> translate_prefs(
132      ChromeTranslateClient::CreateTranslatePrefs(prefs));
133
134  std::string pref_name;
135  if (!args->GetString(0, &pref_name))
136    return;
137
138  if (pref_name == "blocked_languages") {
139    std::string language;
140    if (!args->GetString(1, &language))
141      return;
142    translate_prefs->UnblockLanguage(language);
143  } else if (pref_name == "language_blacklist") {
144    std::string language;
145    if (!args->GetString(1, &language))
146      return;
147    translate_prefs->RemoveLanguageFromLegacyBlacklist(language);
148  } else if (pref_name == "site_blacklist") {
149    std::string site;
150    if (!args->GetString(1, &site))
151      return;
152    translate_prefs->RemoveSiteFromBlacklist(site);
153  } else if (pref_name == "whitelists") {
154    std::string from, to;
155    if (!args->GetString(1, &from))
156      return;
157    if (!args->GetString(2, &to))
158      return;
159    translate_prefs->RemoveLanguagePairFromWhitelist(from, to);
160  } else if (pref_name == "too_often_denied") {
161    translate_prefs->ResetDenialState();
162  } else {
163    return;
164  }
165
166  SendPrefsToJs();
167}
168
169void TranslateInternalsHandler::OnRequestInfo(const base::ListValue* /*args*/) {
170  SendPrefsToJs();
171  SendSupportedLanguagesToJs();
172}
173
174void TranslateInternalsHandler::SendMessageToJs(const std::string& message,
175                                                const base::Value& value) {
176  const char func[] = "cr.translateInternals.messageHandler";
177  base::StringValue message_data(message);
178  web_ui()->CallJavascriptFunction(func, message_data, value);
179}
180
181void TranslateInternalsHandler::SendPrefsToJs() {
182  content::WebContents* web_contents = web_ui()->GetWebContents();
183  Profile* profile =
184      Profile::FromBrowserContext(web_contents->GetBrowserContext());
185  PrefService* prefs = profile->GetOriginalProfile()->GetPrefs();
186
187  base::DictionaryValue dict;
188
189  std::vector<std::string> keys;
190  keys.push_back(prefs::kEnableTranslate);
191
192  keys.push_back(translate::TranslatePrefs::kPrefTranslateBlockedLanguages);
193  keys.push_back(translate::TranslatePrefs::kPrefTranslateLanguageBlacklist);
194  keys.push_back(translate::TranslatePrefs::kPrefTranslateSiteBlacklist);
195  keys.push_back(translate::TranslatePrefs::kPrefTranslateWhitelists);
196  keys.push_back(translate::TranslatePrefs::kPrefTranslateDeniedCount);
197  keys.push_back(translate::TranslatePrefs::kPrefTranslateAcceptedCount);
198  keys.push_back(translate::TranslatePrefs::kPrefTranslateLastDeniedTime);
199  keys.push_back(translate::TranslatePrefs::kPrefTranslateTooOftenDenied);
200
201  for (std::vector<std::string>::const_iterator it = keys.begin();
202       it != keys.end(); ++it) {
203    const std::string& key = *it;
204    const PrefService::Preference* pref = prefs->FindPreference(key.c_str());
205    if (pref)
206      dict.Set(key, pref->GetValue()->DeepCopy());
207  }
208
209  SendMessageToJs("prefsUpdated", dict);
210}
211
212void TranslateInternalsHandler::SendSupportedLanguagesToJs() {
213  base::DictionaryValue dict;
214
215  std::vector<std::string> languages;
216  translate::TranslateDownloadManager::GetSupportedLanguages(&languages);
217  base::Time last_updated =
218      translate::TranslateDownloadManager::GetSupportedLanguagesLastUpdated();
219
220  base::ListValue* languages_list = new base::ListValue();
221  base::ListValue* alpha_languages_list = new base::ListValue();
222  for (std::vector<std::string>::iterator it = languages.begin();
223       it != languages.end(); ++it) {
224    const std::string& lang = *it;
225    languages_list->Append(new base::StringValue(lang));
226    if (translate::TranslateDownloadManager::IsAlphaLanguage(lang))
227      alpha_languages_list->Append(new base::StringValue(lang));
228  }
229
230  dict.Set("languages", languages_list);
231  dict.Set("alpha_languages", alpha_languages_list);
232  dict.Set("last_updated",
233           new base::FundamentalValue(last_updated.ToJsTime()));
234  SendMessageToJs("supportedLanguagesUpdated", dict);
235}
236