1 // Copyright 2014 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 #ifndef COMPONENTS_TRANSLATE_CORE_BROWSER_TRANSLATE_INFOBAR_DELEGATE_H_
6 #define COMPONENTS_TRANSLATE_CORE_BROWSER_TRANSLATE_INFOBAR_DELEGATE_H_
7 
8 #include <stddef.h>
9 
10 #include <memory>
11 #include <string>
12 #include <utility>
13 #include <vector>
14 
15 #include "base/feature_list.h"
16 #include "base/macros.h"
17 #include "base/memory/weak_ptr.h"
18 #include "base/observer_list.h"
19 #include "base/observer_list_types.h"
20 #include "build/build_config.h"
21 #include "components/infobars/core/infobar_delegate.h"
22 #include "components/translate/core/browser/translate_prefs.h"
23 #include "components/translate/core/browser/translate_step.h"
24 #include "components/translate/core/browser/translate_ui_delegate.h"
25 #include "components/translate/core/common/translate_constants.h"
26 #include "components/translate/core/common/translate_errors.h"
27 
28 namespace infobars {
29 class InfoBarManager;
30 }
31 
32 namespace translate {
33 
34 // Feature flag used to control the auto-always and auto-never snackbar
35 // parameters (i.e. threshold and maximum-number-of).
36 extern const base::Feature kTranslateAutoSnackbars;
37 
38 // Feature flag for "Translate Compact Infobar UI" project.
39 extern const base::Feature kTranslateCompactUI;
40 
41 class TranslateDriver;
42 class TranslateManager;
43 
44 class TranslateInfoBarDelegate : public infobars::InfoBarDelegate {
45  public:
46   // An observer to handle different translate steps' UI changes.
47   class Observer : public base::CheckedObserver {
48    public:
49     // Handles UI changes on the translate step given.
50     virtual void OnTranslateStepChanged(translate::TranslateStep step,
51                                         TranslateErrors::Type error_type) = 0;
52     // Handles UI changes when the target language is updated.
53     virtual void OnTargetLanguageChanged(
54         const std::string& target_language_code) = 0;
55     // Return whether user declined translate service.
56     virtual bool IsDeclinedByUser() = 0;
57     // Called when the TranslateInfoBarDelegate instance is destroyed.
58     virtual void OnTranslateInfoBarDelegateDestroyed(
59         TranslateInfoBarDelegate* delegate) = 0;
60   };
61 
62   static const size_t kNoIndex;
63 
64   // Get the threshold and maximum number of occurences that parameterize
65   // automatic always- and never-translate.
66   static int GetAutoAlwaysThreshold();
67   static int GetAutoNeverThreshold();
68   static int GetMaximumNumberOfAutoAlways();
69   static int GetMaximumNumberOfAutoNever();
70 
71   ~TranslateInfoBarDelegate() override;
72 
73   // Factory method to create a translate infobar.  |error_type| must be
74   // specified iff |step| == TRANSLATION_ERROR.  For other translate steps,
75   // |original_language| and |target_language| must be ASCII language codes
76   // (e.g. "en", "fr", etc.) for languages the TranslateManager supports
77   // translating.  The lone exception is when the user initiates translation
78   // from the context menu, in which case it's legal to call this with
79   // |step| == TRANSLATING and |original_language| == kUnknownLanguageCode.
80   //
81   // If |replace_existing_infobar| is true, the infobar is created and added to
82   // the infobar manager, replacing any other translate infobar already present
83   // there.  Otherwise, the infobar will only be added if there is no other
84   // translate infobar already present.
85   static void Create(bool replace_existing_infobar,
86                      const base::WeakPtr<TranslateManager>& translate_manager,
87                      infobars::InfoBarManager* infobar_manager,
88                      bool is_off_the_record,
89                      translate::TranslateStep step,
90                      const std::string& original_language,
91                      const std::string& target_language,
92                      TranslateErrors::Type error_type,
93                      bool triggered_from_menu);
94 
95   // Returns the number of languages supported.
96   virtual size_t num_languages() const;
97 
98   // Returns the ISO code for the language at |index|.
99   virtual std::string language_code_at(size_t index) const;
100 
101   // Returns the displayable name for the language at |index|.
102   virtual base::string16 language_name_at(size_t index) const;
103 
translate_step()104   translate::TranslateStep translate_step() const { return step_; }
105 
is_off_the_record()106   bool is_off_the_record() { return is_off_the_record_; }
107 
error_type()108   TranslateErrors::Type error_type() const { return error_type_; }
109 
original_language_code()110   std::string original_language_code() const {
111     return ui_delegate_.GetOriginalLanguageCode();
112   }
113 
114   virtual base::string16 original_language_name() const;
115 
116   virtual void UpdateOriginalLanguage(const std::string& language_code);
117 
target_language_code()118   std::string target_language_code() const {
119     return ui_delegate_.GetTargetLanguageCode();
120   }
121 
122   virtual base::string16 target_language_name() const;
123 
124   virtual void UpdateTargetLanguage(const std::string& language_code);
125 
126   // Returns true if the current infobar indicates an error (in which case it
127   // should get a yellow background instead of a blue one).
is_error()128   bool is_error() const {
129     return step_ == translate::TRANSLATE_STEP_TRANSLATE_ERROR;
130   }
131 
132   void OnErrorShown(TranslateErrors::Type error_type);
133 
134   // Return true if the translation was triggered by a menu entry instead of
135   // via an infobar/bubble or preference.
triggered_from_menu()136   bool triggered_from_menu() const {
137     return triggered_from_menu_;
138   }
139 
140   virtual void Translate();
141   virtual void RevertTranslation();
142   virtual void RevertWithoutClosingInfobar();
143   void ReportLanguageDetectionError();
144 
145   // Called when the user declines to translate a page, by either closing the
146   // infobar or pressing the "Don't translate" button.
147   virtual void TranslationDeclined();
148 
149   // Methods called by the Options menu delegate.
150   virtual bool IsTranslatableLanguageByPrefs() const;
151   virtual void ToggleTranslatableLanguageByPrefs();
152   virtual bool IsSiteBlacklisted() const;
153   virtual void ToggleSiteBlacklist();
154   virtual bool ShouldAlwaysTranslate() const;
155   virtual void ToggleAlwaysTranslate();
156 
157   // Methods called by the extra-buttons that can appear on the "before
158   // translate" infobar (when the user has accepted/declined the translation
159   // several times).
160   void AlwaysTranslatePageLanguage();
161   void NeverTranslatePageLanguage();
162 
163   int GetTranslationAcceptedCount();
164   int GetTranslationDeniedCount();
165 
166   void ResetTranslationAcceptedCount();
167   void ResetTranslationDeniedCount();
168 
169   // Returns whether "Always Translate Language" should automatically trigger.
170   // If true, this method has the side effect of mutating some prefs.
171   bool ShouldAutoAlwaysTranslate();
172   // Returns whether "Never Translate Language" should automatically trigger.
173   // If true, this method has the side effect of mutating some prefs.
174   bool ShouldAutoNeverTranslate();
175 
176   int GetTranslationAutoAlwaysCount();
177   int GetTranslationAutoNeverCount();
178 
179   void IncrementTranslationAutoAlwaysCount();
180   void IncrementTranslationAutoNeverCount();
181 
182   // The following methods are called by the infobar that displays the status
183   // while translating and also the one displaying the error message.
184   base::string16 GetMessageInfoBarButtonText();
185   void MessageInfoBarButtonPressed();
186   bool ShouldShowMessageInfoBarButton();
187 
188   // Returns true if the infobar should offer a (platform-specific) shortcut to
189   // allow the user to always/never translate the language, when we think the
190   // user wants that functionality.
191   bool ShouldShowAlwaysTranslateShortcut();
192   bool ShouldShowNeverTranslateShortcut();
193 
194 #if defined(OS_IOS)
195   // Shows the Infobar offering to never translate the language or the site.
196   void ShowNeverTranslateInfobar();
197 #endif
198 
199   // Adds the strings that should be displayed in the after translate infobar to
200   // |strings|. If |autodetermined_source_language| is false, the text in that
201   // infobar is:
202   // "The page has been translated from <lang1> to <lang2>."
203   // Otherwise:
204   // "The page has been translated to <lang1>."
205   // Because <lang1>, or <lang1> and <lang2> are displayed in menu buttons, the
206   // text is split in 2 or 3 chunks. |swap_languages| is set to true if
207   // |autodetermined_source_language| is false, and <lang1> and <lang2>
208   // should be inverted (some languages express the sentense as "The page has
209   // been translate to <lang2> from <lang1>."). It is ignored if
210   // |autodetermined_source_language| is true.
211   static void GetAfterTranslateStrings(std::vector<base::string16>* strings,
212                                        bool* swap_languages,
213                                        bool autodetermined_source_language);
214 
215   // Gets the TranslateDriver associated with this object.
216   // May return NULL if the driver has been destroyed.
217   TranslateDriver* GetTranslateDriver();
218 
219   // Add an observer.
220   virtual void AddObserver(Observer* observer);
221 
222   // Remove an observer.
223   virtual void RemoveObserver(Observer* observer);
224 
225   // Handles when the user closes the translate infobar. This includes when: the
226   // user presses the 'x' button, the user selects to never translate the site,
227   // and the user selects to never translate the language.
228   void OnInfoBarClosedByUser();
229 
230   // InfoBarDelegate:
231   infobars::InfoBarDelegate::InfoBarIdentifier GetIdentifier() const override;
232   int GetIconId() const override;
233   void InfoBarDismissed() override;
234   TranslateInfoBarDelegate* AsTranslateInfoBarDelegate() override;
235 
236  protected:
237   TranslateInfoBarDelegate(
238       const base::WeakPtr<TranslateManager>& translate_manager,
239       bool is_off_the_record,
240       translate::TranslateStep step,
241       const std::string& original_language,
242       const std::string& target_language,
243       TranslateErrors::Type error_type,
244       bool triggered_from_menu);
245 
246  private:
247   friend class TranslationInfoBarTest;
248   typedef std::pair<std::string, base::string16> LanguageNamePair;
249 
250   bool is_off_the_record_;
251   translate::TranslateStep step_;
252 
253   TranslateUIDelegate ui_delegate_;
254   base::WeakPtr<TranslateManager> translate_manager_;
255 
256   // The error that occurred when trying to translate (NONE if no error).
257   TranslateErrors::Type error_type_;
258 
259   // The translation related preferences.
260   std::unique_ptr<TranslatePrefs> prefs_;
261 
262   // Whether the translation was triggered via a menu click vs automatically
263   // (due to language detection, preferences...)
264   bool triggered_from_menu_;
265 
266   // Observers to handle front-end changes on different steps.
267   // It's only used when we try to reuse the existing UI.
268   base::ObserverList<Observer> observers_;
269 
270   DISALLOW_COPY_AND_ASSIGN(TranslateInfoBarDelegate);
271 };
272 
273 }  // namespace translate
274 
275 #endif  // COMPONENTS_TRANSLATE_CORE_BROWSER_TRANSLATE_INFOBAR_DELEGATE_H_
276