- add sources.
[platform/framework/web/crosswalk.git] / src / chrome / browser / translate / translate_infobar_delegate.cc
1 // Copyright (c) 2012 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_infobar_delegate.h"
6
7 #include <algorithm>
8
9 #include "base/i18n/string_compare.h"
10 #include "base/metrics/histogram.h"
11 #include "base/prefs/pref_service.h"
12 #include "chrome/browser/browser_process.h"
13 #include "chrome/browser/infobars/infobar_service.h"
14 #include "chrome/browser/profiles/profile.h"
15 #include "chrome/browser/translate/translate_accept_languages.h"
16 #include "chrome/browser/translate/translate_manager.h"
17 #include "chrome/browser/translate/translate_tab_helper.h"
18 #include "components/translate/common/translate_constants.h"
19 #include "content/public/browser/navigation_details.h"
20 #include "content/public/browser/navigation_entry.h"
21 #include "content/public/browser/web_contents.h"
22 #include "grit/generated_resources.h"
23 #include "grit/theme_resources.h"
24 #include "third_party/icu/source/i18n/unicode/coll.h"
25 #include "ui/base/l10n/l10n_util.h"
26
27 using content::NavigationEntry;
28
29 namespace {
30
31 // TODO(hajimehoshi): Remove this after crbug/283720 is solved.
32 const char kDeclineTranslate[] = "Translate.DeclineTranslate";
33
34 const char kCloseInfobar[] = "Translate.DeclineTranslateCloseInfobar";
35 const char kShowErrorInfobar[] = "Translate.ShowErrorInfobar";
36
37 }  // namespace
38
39 const size_t TranslateInfoBarDelegate::kNoIndex = TranslateUIDelegate::NO_INDEX;
40
41 TranslateInfoBarDelegate::~TranslateInfoBarDelegate() {
42 }
43
44 // static
45 void TranslateInfoBarDelegate::Create(
46     bool replace_existing_infobar,
47     InfoBarService* infobar_service,
48     Type infobar_type,
49     const std::string& original_language,
50     const std::string& target_language,
51     TranslateErrors::Type error_type,
52     PrefService* prefs,
53     const ShortcutConfiguration& shortcut_config) {
54   // Check preconditions.
55   if (infobar_type != TRANSLATION_ERROR) {
56     DCHECK(TranslateManager::IsSupportedLanguage(target_language));
57     if (!TranslateManager::IsSupportedLanguage(original_language)) {
58       // The original language can only be "unknown" for the "translating"
59       // infobar, which is the case when the user started a translation from the
60       // context menu.
61       DCHECK(infobar_type == TRANSLATING || infobar_type == AFTER_TRANSLATE);
62       DCHECK_EQ(translate::kUnknownLanguageCode, original_language);
63     }
64   }
65
66   // Find any existing translate infobar delegate.
67   TranslateInfoBarDelegate* old_delegate = NULL;
68   for (size_t i = 0; i < infobar_service->infobar_count(); ++i) {
69     old_delegate = infobar_service->infobar_at(i)->AsTranslateInfoBarDelegate();
70     if (old_delegate) {
71       if (!replace_existing_infobar)
72         return;
73       break;
74     }
75   }
76
77   // Create the new delegate.
78   scoped_ptr<TranslateInfoBarDelegate> infobar(
79       new TranslateInfoBarDelegate(infobar_service, infobar_type, old_delegate,
80                                    original_language, target_language,
81                                    error_type, prefs, shortcut_config));
82
83   // Do not create the after translate infobar if we are auto translating.
84   if ((infobar_type == TranslateInfoBarDelegate::AFTER_TRANSLATE) ||
85       (infobar_type == TranslateInfoBarDelegate::TRANSLATING)) {
86     TranslateTabHelper* translate_tab_helper =
87       TranslateTabHelper::FromWebContents(infobar_service->web_contents());
88     if (!translate_tab_helper ||
89          translate_tab_helper->language_state().InTranslateNavigation())
90       return;
91   }
92
93   // Add the new delegate if necessary.
94   if (!old_delegate) {
95     infobar_service->AddInfoBar(infobar.PassAs<InfoBarDelegate>());
96   } else {
97     DCHECK(replace_existing_infobar);
98     infobar_service->ReplaceInfoBar(old_delegate,
99                                     infobar.PassAs<InfoBarDelegate>());
100   }
101 }
102
103
104 void TranslateInfoBarDelegate::UpdateOriginalLanguageIndex(
105     size_t language_index) {
106   ui_delegate_.UpdateOriginalLanguageIndex(language_index);
107 }
108
109 void TranslateInfoBarDelegate::UpdateTargetLanguageIndex(
110     size_t language_index) {
111   ui_delegate_.UpdateTargetLanguageIndex(language_index);
112 }
113
114 void TranslateInfoBarDelegate::Translate() {
115   ui_delegate_.Translate();
116 }
117
118 void TranslateInfoBarDelegate::RevertTranslation() {
119   ui_delegate_.RevertTranslation();
120   RemoveSelf();
121 }
122
123 void TranslateInfoBarDelegate::ReportLanguageDetectionError() {
124   TranslateManager::GetInstance()->ReportLanguageDetectionError(
125       web_contents());
126 }
127
128 void TranslateInfoBarDelegate::TranslationDeclined() {
129   // TODO(miguelg) switch this back to just calling web_contents()
130   // once we've diagnosed crbug/283720
131   // TODO(hajimehoshi): Replace this implementstion with calling ui_delegate_.
132   // TranslationDeclined() after miguelg's investigating.
133   content::WebContents* contents = owner()->web_contents();
134   content::BrowserContext* context = contents->GetBrowserContext();
135   if (!context->IsOffTheRecord()) {
136     prefs_.ResetTranslationAcceptedCount(original_language_code());
137     prefs_.IncrementTranslationDeniedCount(original_language_code());
138   }
139
140   // Remember that the user declined the translation so as to prevent showing a
141   // translate infobar for that page again.  (TranslateManager initiates
142   // translations when getting a LANGUAGE_DETERMINED from the page, which
143   // happens when a load stops. That could happen multiple times, including
144   // after the user already declined the translation.)
145   TranslateTabHelper::FromWebContents(web_contents())->
146       language_state().set_translation_declined(true);
147
148   UMA_HISTOGRAM_BOOLEAN(kDeclineTranslate, true);
149 }
150
151 bool TranslateInfoBarDelegate::IsTranslatableLanguageByPrefs() {
152   Profile* profile =
153       Profile::FromBrowserContext(web_contents()->GetBrowserContext());
154   Profile* original_profile = profile->GetOriginalProfile();
155   return TranslatePrefs::CanTranslateLanguage(original_profile,
156                                               original_language_code());
157 }
158
159 void TranslateInfoBarDelegate::ToggleTranslatableLanguageByPrefs() {
160   if (ui_delegate_.IsLanguageBlocked()) {
161     ui_delegate_.SetLanguageBlocked(false);
162   } else {
163     ui_delegate_.SetLanguageBlocked(true);
164     RemoveSelf();
165   }
166 }
167
168 bool TranslateInfoBarDelegate::IsSiteBlacklisted() {
169   return ui_delegate_.IsSiteBlacklisted();
170 }
171
172 void TranslateInfoBarDelegate::ToggleSiteBlacklist() {
173   if (ui_delegate_.IsSiteBlacklisted()) {
174     ui_delegate_.SetSiteBlacklist(false);
175   } else {
176     ui_delegate_.SetSiteBlacklist(true);
177     RemoveSelf();
178   }
179 }
180
181 bool TranslateInfoBarDelegate::ShouldAlwaysTranslate() {
182   return ui_delegate_.ShouldAlwaysTranslate();
183 }
184
185 void TranslateInfoBarDelegate::ToggleAlwaysTranslate() {
186   ui_delegate_.SetAlwaysTranslate(!ui_delegate_.ShouldAlwaysTranslate());
187 }
188
189 void TranslateInfoBarDelegate::AlwaysTranslatePageLanguage() {
190   DCHECK(!ui_delegate_.ShouldAlwaysTranslate());
191   ui_delegate_.SetAlwaysTranslate(true);
192   Translate();
193 }
194
195 void TranslateInfoBarDelegate::NeverTranslatePageLanguage() {
196   DCHECK(!ui_delegate_.IsLanguageBlocked());
197   ui_delegate_.SetLanguageBlocked(true);
198   RemoveSelf();
199 }
200
201 string16 TranslateInfoBarDelegate::GetMessageInfoBarText() {
202   if (infobar_type_ == TRANSLATING) {
203     string16 target_language_name = language_name_at(target_language_index());
204     return l10n_util::GetStringFUTF16(IDS_TRANSLATE_INFOBAR_TRANSLATING_TO,
205                                       target_language_name);
206   }
207
208   DCHECK_EQ(TRANSLATION_ERROR, infobar_type_);
209   UMA_HISTOGRAM_ENUMERATION(kShowErrorInfobar,
210                             error_type_,
211                             TranslateErrors::TRANSLATE_ERROR_MAX);
212   switch (error_type_) {
213     case TranslateErrors::NETWORK:
214       return l10n_util::GetStringUTF16(
215           IDS_TRANSLATE_INFOBAR_ERROR_CANT_CONNECT);
216     case TranslateErrors::INITIALIZATION_ERROR:
217     case TranslateErrors::TRANSLATION_ERROR:
218       return l10n_util::GetStringUTF16(
219           IDS_TRANSLATE_INFOBAR_ERROR_CANT_TRANSLATE);
220     case TranslateErrors::UNKNOWN_LANGUAGE:
221       return l10n_util::GetStringUTF16(
222           IDS_TRANSLATE_INFOBAR_UNKNOWN_PAGE_LANGUAGE);
223     case TranslateErrors::UNSUPPORTED_LANGUAGE:
224       return l10n_util::GetStringFUTF16(
225           IDS_TRANSLATE_INFOBAR_UNSUPPORTED_PAGE_LANGUAGE,
226           language_name_at(target_language_index()));
227     case TranslateErrors::IDENTICAL_LANGUAGES:
228       return l10n_util::GetStringFUTF16(
229           IDS_TRANSLATE_INFOBAR_ERROR_SAME_LANGUAGE,
230           language_name_at(target_language_index()));
231     default:
232       NOTREACHED();
233       return string16();
234   }
235 }
236
237 string16 TranslateInfoBarDelegate::GetMessageInfoBarButtonText() {
238   if (infobar_type_ != TRANSLATION_ERROR) {
239     DCHECK_EQ(TRANSLATING, infobar_type_);
240   } else if ((error_type_ != TranslateErrors::IDENTICAL_LANGUAGES) &&
241              (error_type_ != TranslateErrors::UNKNOWN_LANGUAGE)) {
242     return l10n_util::GetStringUTF16(
243         (error_type_ == TranslateErrors::UNSUPPORTED_LANGUAGE) ?
244         IDS_TRANSLATE_INFOBAR_REVERT : IDS_TRANSLATE_INFOBAR_RETRY);
245   }
246   return string16();
247 }
248
249 void TranslateInfoBarDelegate::MessageInfoBarButtonPressed() {
250   DCHECK_EQ(TRANSLATION_ERROR, infobar_type_);
251   if (error_type_ == TranslateErrors::UNSUPPORTED_LANGUAGE) {
252     RevertTranslation();
253     return;
254   }
255   // This is the "Try again..." case.
256   TranslateManager::GetInstance()->TranslatePage(
257       web_contents(), original_language_code(), target_language_code());
258 }
259
260 bool TranslateInfoBarDelegate::ShouldShowMessageInfoBarButton() {
261   return !GetMessageInfoBarButtonText().empty();
262 }
263
264 bool TranslateInfoBarDelegate::ShouldShowNeverTranslateShortcut() {
265   DCHECK_EQ(BEFORE_TRANSLATE, infobar_type_);
266   return !web_contents()->GetBrowserContext()->IsOffTheRecord() &&
267       (prefs_.GetTranslationDeniedCount(original_language_code()) >=
268           shortcut_config_.never_translate_min_count);
269 }
270
271 bool TranslateInfoBarDelegate::ShouldShowAlwaysTranslateShortcut() {
272   DCHECK_EQ(BEFORE_TRANSLATE, infobar_type_);
273   return !web_contents()->GetBrowserContext()->IsOffTheRecord() &&
274       (prefs_.GetTranslationAcceptedCount(original_language_code()) >=
275           shortcut_config_.always_translate_min_count);
276 }
277
278 // static
279 string16 TranslateInfoBarDelegate::GetLanguageDisplayableName(
280     const std::string& language_code) {
281   return l10n_util::GetDisplayNameForLocale(
282       language_code, g_browser_process->GetApplicationLocale(), true);
283 }
284
285 // static
286 void TranslateInfoBarDelegate::GetAfterTranslateStrings(
287     std::vector<string16>* strings,
288     bool* swap_languages,
289     bool autodetermined_source_language) {
290   DCHECK(strings);
291
292   if (autodetermined_source_language) {
293     size_t offset;
294     string16 text = l10n_util::GetStringFUTF16(
295         IDS_TRANSLATE_INFOBAR_AFTER_MESSAGE_AUTODETERMINED_SOURCE_LANGUAGE,
296         string16(),
297         &offset);
298
299     strings->push_back(text.substr(0, offset));
300     strings->push_back(text.substr(offset));
301     return;
302   }
303   DCHECK(swap_languages);
304
305   std::vector<size_t> offsets;
306   string16 text = l10n_util::GetStringFUTF16(
307       IDS_TRANSLATE_INFOBAR_AFTER_MESSAGE, string16(), string16(), &offsets);
308   DCHECK_EQ(2U, offsets.size());
309
310   *swap_languages = (offsets[0] > offsets[1]);
311   if (*swap_languages)
312     std::swap(offsets[0], offsets[1]);
313
314   strings->push_back(text.substr(0, offsets[0]));
315   strings->push_back(text.substr(offsets[0], offsets[1] - offsets[0]));
316   strings->push_back(text.substr(offsets[1]));
317 }
318
319 TranslateInfoBarDelegate::TranslateInfoBarDelegate(
320     InfoBarService* infobar_service,
321     Type infobar_type,
322     TranslateInfoBarDelegate* old_delegate,
323     const std::string& original_language,
324     const std::string& target_language,
325     TranslateErrors::Type error_type,
326     PrefService* prefs,
327     ShortcutConfiguration shortcut_config)
328     : InfoBarDelegate(infobar_service),
329       infobar_type_(infobar_type),
330       background_animation_(NONE),
331       ui_delegate_(web_contents(), original_language, target_language),
332       error_type_(error_type),
333       prefs_(prefs),
334       shortcut_config_(shortcut_config) {
335   DCHECK_NE((infobar_type_ == TRANSLATION_ERROR),
336             (error_type_ == TranslateErrors::NONE));
337
338   if (old_delegate && (old_delegate->is_error() != is_error()))
339     background_animation_ = is_error() ? NORMAL_TO_ERROR : ERROR_TO_NORMAL;
340 }
341
342 void TranslateInfoBarDelegate::InfoBarDismissed() {
343   if (infobar_type_ != BEFORE_TRANSLATE)
344     return;
345
346   // The user closed the infobar without clicking the translate button.
347   TranslationDeclined();
348   UMA_HISTOGRAM_BOOLEAN(kCloseInfobar, true);
349 }
350
351 int TranslateInfoBarDelegate::GetIconID() const {
352   return IDR_INFOBAR_TRANSLATE;
353 }
354
355 InfoBarDelegate::Type TranslateInfoBarDelegate::GetInfoBarType() const {
356   return PAGE_ACTION_TYPE;
357 }
358
359 bool TranslateInfoBarDelegate::ShouldExpire(
360     const content::LoadCommittedDetails& details) const {
361   // Note: we allow closing this infobar even if the main frame navigation
362   // was programmatic and not initiated by the user - crbug.com/70261 .
363   if (!details.is_navigation_to_different_page() && !details.is_main_frame)
364     return false;
365
366   return InfoBarDelegate::ShouldExpireInternal(details);
367 }
368
369 TranslateInfoBarDelegate*
370     TranslateInfoBarDelegate::AsTranslateInfoBarDelegate() {
371   return this;
372 }