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/translate/translate_prefs.h"
6
7#include "base/string_util.h"
8#include "chrome/browser/prefs/pref_service.h"
9#include "chrome/browser/prefs/scoped_user_pref_update.h"
10
11const char TranslatePrefs::kPrefTranslateLanguageBlacklist[] =
12    "translate_language_blacklist";
13const char TranslatePrefs::kPrefTranslateSiteBlacklist[] =
14    "translate_site_blacklist";
15const char TranslatePrefs::kPrefTranslateWhitelists[] =
16    "translate_whitelists";
17const char TranslatePrefs::kPrefTranslateDeniedCount[] =
18    "translate_denied_count";
19const char TranslatePrefs::kPrefTranslateAcceptedCount[] =
20    "translate_accepted_count";
21
22// TranslatePrefs: public: -----------------------------------------------------
23
24TranslatePrefs::TranslatePrefs(PrefService* user_prefs)
25    : prefs_(user_prefs) {
26}
27
28bool TranslatePrefs::IsLanguageBlacklisted(
29    const std::string& original_language) {
30  return IsValueBlacklisted(kPrefTranslateLanguageBlacklist, original_language);
31}
32
33void TranslatePrefs::BlacklistLanguage(const std::string& original_language) {
34  BlacklistValue(kPrefTranslateLanguageBlacklist, original_language);
35}
36
37void TranslatePrefs::RemoveLanguageFromBlacklist(
38    const std::string& original_language) {
39  RemoveValueFromBlacklist(kPrefTranslateLanguageBlacklist, original_language);
40}
41
42bool TranslatePrefs::IsSiteBlacklisted(const std::string& site) {
43  return IsValueBlacklisted(kPrefTranslateSiteBlacklist, site);
44}
45
46void TranslatePrefs::BlacklistSite(const std::string& site) {
47  BlacklistValue(kPrefTranslateSiteBlacklist, site);
48}
49
50void TranslatePrefs::RemoveSiteFromBlacklist(const std::string& site) {
51  RemoveValueFromBlacklist(kPrefTranslateSiteBlacklist, site);
52}
53
54bool TranslatePrefs::IsLanguagePairWhitelisted(
55    const std::string& original_language,
56    const std::string& target_language) {
57  const DictionaryValue* dict = prefs_->GetDictionary(kPrefTranslateWhitelists);
58  if (dict && !dict->empty()) {
59    std::string auto_target_lang;
60    if (dict->GetString(original_language, &auto_target_lang) &&
61        auto_target_lang == target_language)
62      return true;
63  }
64  return false;
65}
66
67void TranslatePrefs::WhitelistLanguagePair(
68    const std::string& original_language,
69    const std::string& target_language) {
70  DictionaryPrefUpdate update(prefs_, kPrefTranslateWhitelists);
71  DictionaryValue* dict = update.Get();
72  if (!dict) {
73    NOTREACHED() << "Unregistered translate whitelist pref";
74    return;
75  }
76  dict->SetString(original_language, target_language);
77  prefs_->ScheduleSavePersistentPrefs();
78}
79
80void TranslatePrefs::RemoveLanguagePairFromWhitelist(
81    const std::string& original_language,
82    const std::string& target_language) {
83  DictionaryPrefUpdate update(prefs_, kPrefTranslateWhitelists);
84  DictionaryValue* dict = update.Get();
85  if (!dict) {
86    NOTREACHED() << "Unregistered translate whitelist pref";
87    return;
88  }
89  if (dict->Remove(original_language, NULL))
90    prefs_->ScheduleSavePersistentPrefs();
91}
92
93int TranslatePrefs::GetTranslationDeniedCount(const std::string& language) {
94  const DictionaryValue* dict =
95      prefs_->GetDictionary(kPrefTranslateDeniedCount);
96  int count = 0;
97  return dict->GetInteger(language, &count) ? count : 0;
98}
99
100void TranslatePrefs::IncrementTranslationDeniedCount(
101    const std::string& language) {
102  DictionaryPrefUpdate update(prefs_, kPrefTranslateDeniedCount);
103  DictionaryValue* dict = update.Get();
104
105  int count = 0;
106  dict->GetInteger(language, &count);
107  dict->SetInteger(language, count + 1);
108}
109
110void TranslatePrefs::ResetTranslationDeniedCount(const std::string& language) {
111  DictionaryPrefUpdate update(prefs_, kPrefTranslateDeniedCount);
112  update.Get()->SetInteger(language, 0);
113}
114
115int TranslatePrefs::GetTranslationAcceptedCount(const std::string& language) {
116  const DictionaryValue* dict =
117      prefs_->GetDictionary(kPrefTranslateAcceptedCount);
118  int count = 0;
119  return dict->GetInteger(language, &count) ? count : 0;
120}
121
122void TranslatePrefs::IncrementTranslationAcceptedCount(
123    const std::string& language) {
124  DictionaryPrefUpdate update(prefs_, kPrefTranslateAcceptedCount);
125  DictionaryValue* dict = update.Get();
126  int count = 0;
127  dict->GetInteger(language, &count);
128  dict->SetInteger(language, count + 1);
129}
130
131void TranslatePrefs::ResetTranslationAcceptedCount(
132    const std::string& language) {
133  DictionaryPrefUpdate update(prefs_, kPrefTranslateAcceptedCount);
134  update.Get()->SetInteger(language, 0);
135}
136
137// TranslatePrefs: public, static: ---------------------------------------------
138
139bool TranslatePrefs::CanTranslate(PrefService* user_prefs,
140    const std::string& original_language, const GURL& url) {
141  TranslatePrefs prefs(user_prefs);
142  if (prefs.IsSiteBlacklisted(url.HostNoBrackets()))
143    return false;
144  return (!prefs.IsLanguageBlacklisted(original_language));
145}
146
147bool TranslatePrefs::ShouldAutoTranslate(PrefService* user_prefs,
148    const std::string& original_language, std::string* target_language) {
149  TranslatePrefs prefs(user_prefs);
150  return prefs.IsLanguageWhitelisted(original_language, target_language);
151}
152
153void TranslatePrefs::RegisterUserPrefs(PrefService* user_prefs) {
154  if (!user_prefs->FindPreference(kPrefTranslateLanguageBlacklist))
155    user_prefs->RegisterListPref(kPrefTranslateLanguageBlacklist);
156  if (!user_prefs->FindPreference(kPrefTranslateSiteBlacklist))
157    user_prefs->RegisterListPref(kPrefTranslateSiteBlacklist);
158  if (!user_prefs->FindPreference(kPrefTranslateWhitelists)) {
159    user_prefs->RegisterDictionaryPref(kPrefTranslateWhitelists);
160    MigrateTranslateWhitelists(user_prefs);
161  }
162  if (!user_prefs->FindPreference(kPrefTranslateDeniedCount))
163    user_prefs->RegisterDictionaryPref(kPrefTranslateDeniedCount);
164  if (!user_prefs->FindPreference(kPrefTranslateAcceptedCount))
165    user_prefs->RegisterDictionaryPref(kPrefTranslateAcceptedCount);
166}
167
168// TranslatePrefs: private, static: --------------------------------------------
169
170void TranslatePrefs::MigrateTranslateWhitelists(PrefService* user_prefs) {
171  // Old format of kPrefTranslateWhitelists
172  // - original language -> list of target langs to auto-translate
173  // - list of langs is in order of being enabled i.e. last in list is the
174  //   most recent language that user enabled via
175  //   Always translate |source_lang| to |target_lang|"
176  // - this results in a one-to-n relationship between source lang and target
177  //   langs.
178  // New format:
179  // - original language -> one target language to auto-translate
180  // - each time that the user enables the "Always translate..." option, that
181  //   target lang overwrites the previous one.
182  // - this results in a one-to-one relationship between source lang and target
183  //   lang
184  // - we replace old list of target langs with the last target lang in list,
185  //   assuming the last (i.e. most recent) target lang is what user wants to
186  //   keep auto-translated.
187  DictionaryPrefUpdate update(user_prefs, kPrefTranslateWhitelists);
188  DictionaryValue* dict = update.Get();
189  if (!dict || dict->empty())
190    return;
191  bool save_prefs = false;
192  for (DictionaryValue::key_iterator iter(dict->begin_keys());
193       iter != dict->end_keys(); ++iter) {
194    ListValue* list = NULL;
195    if (!dict->GetList(*iter, &list) || !list)
196      break;  // Dictionary has either been migrated or new format.
197    save_prefs = true;
198    std::string target_lang;
199    if (list->empty() || !list->GetString(list->GetSize() - 1, &target_lang) ||
200        target_lang.empty())
201      dict->Remove(*iter, NULL);
202     else
203      dict->SetString(*iter, target_lang);
204  }
205  if (!save_prefs)
206    return;
207  user_prefs->ScheduleSavePersistentPrefs();
208}
209
210// TranslatePrefs: private: ----------------------------------------------------
211
212bool TranslatePrefs::IsValueInList(const ListValue* list,
213    const std::string& in_value) {
214  for (size_t i = 0; i < list->GetSize(); ++i) {
215    std::string value;
216    if (list->GetString(i, &value) && value == in_value)
217      return true;
218  }
219  return false;
220}
221
222bool TranslatePrefs::IsValueBlacklisted(const char* pref_id,
223    const std::string& value) {
224  const ListValue* blacklist = prefs_->GetList(pref_id);
225  return (blacklist && !blacklist->empty() && IsValueInList(blacklist, value));
226}
227
228void TranslatePrefs::BlacklistValue(const char* pref_id,
229    const std::string& value) {
230  {
231    ListPrefUpdate update(prefs_, pref_id);
232    ListValue* blacklist = update.Get();
233    if (!blacklist) {
234      NOTREACHED() << "Unregistered translate blacklist pref";
235      return;
236    }
237    blacklist->Append(new StringValue(value));
238  }
239  prefs_->ScheduleSavePersistentPrefs();
240}
241
242void TranslatePrefs::RemoveValueFromBlacklist(const char* pref_id,
243    const std::string& value) {
244  bool schedule_save = false;
245  {
246    ListPrefUpdate update(prefs_, pref_id);
247    ListValue* blacklist = update.Get();
248    if (!blacklist) {
249      NOTREACHED() << "Unregistered translate blacklist pref";
250      return;
251    }
252    StringValue string_value(value);
253    schedule_save = blacklist->Remove(string_value) != -1;
254  }
255  if (schedule_save)
256    prefs_->ScheduleSavePersistentPrefs();
257}
258
259bool TranslatePrefs::IsLanguageWhitelisted(
260    const std::string& original_language, std::string* target_language) {
261  const DictionaryValue* dict = prefs_->GetDictionary(kPrefTranslateWhitelists);
262  if (dict && dict->GetString(original_language, target_language)) {
263    DCHECK(!target_language->empty());
264    return !target_language->empty();
265  }
266  return false;
267}
268