diff options
author | droger@chromium.org <droger@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-06-02 16:01:29 +0000 |
---|---|---|
committer | droger@chromium.org <droger@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-06-02 16:01:29 +0000 |
commit | dbe9bfab6e9b264b1b339e8c1c422f0b5dfa2a6c (patch) | |
tree | e644b6d42f97c38a12541ac8a2f13fcb849725fe /components | |
parent | 603ed1e862e48615acadc96724749529487f8947 (diff) | |
download | chromium_src-dbe9bfab6e9b264b1b339e8c1c422f0b5dfa2a6c.zip chromium_src-dbe9bfab6e9b264b1b339e8c1c422f0b5dfa2a6c.tar.gz chromium_src-dbe9bfab6e9b264b1b339e8c1c422f0b5dfa2a6c.tar.bz2 |
Move TranslateInfoBarDelegate and OptionsMenuModel to the Translate component.
To solve the dependency on chrome_command_ids, this CL removes the
IDC_OPTIONS_TRANSLATE_* constants and instead defines the command IDs
locally in the file, which is an approach already used at several other places in
the code.
To solve the dependency on themes, the icon ID for the translate infobar is no
longer hardcoded, but fetched from the translate client instead.
BUG=371845
TBR=estade, joaodasilva
Review URL: https://codereview.chromium.org/284313008
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@274252 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'components')
-rw-r--r-- | components/infobars.gypi | 1 | ||||
-rw-r--r-- | components/infobars/core/infobar_android.cc | 15 | ||||
-rw-r--r-- | components/translate.gypi | 7 | ||||
-rw-r--r-- | components/translate/DEPS | 1 | ||||
-rw-r--r-- | components/translate/core/browser/options_menu_model.cc | 137 | ||||
-rw-r--r-- | components/translate/core/browser/options_menu_model.h | 43 | ||||
-rw-r--r-- | components/translate/core/browser/translate_client.h | 13 | ||||
-rw-r--r-- | components/translate/core/browser/translate_infobar_delegate.cc | 372 | ||||
-rw-r--r-- | components/translate/core/browser/translate_infobar_delegate.h | 221 |
9 files changed, 810 insertions, 0 deletions
diff --git a/components/infobars.gypi b/components/infobars.gypi index 07522b9..cb9c2b1 100644 --- a/components/infobars.gypi +++ b/components/infobars.gypi @@ -21,6 +21,7 @@ 'infobars/core/confirm_infobar_delegate.h', 'infobars/core/infobar.cc', 'infobars/core/infobar.h', + 'infobars/core/infobar_android.cc', 'infobars/core/infobar_container.cc', 'infobars/core/infobar_container.h', 'infobars/core/infobar_delegate.cc', diff --git a/components/infobars/core/infobar_android.cc b/components/infobars/core/infobar_android.cc new file mode 100644 index 0000000..60258f8 --- /dev/null +++ b/components/infobars/core/infobar_android.cc @@ -0,0 +1,15 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "components/infobars/core/infobar.h" + +// Static constants defined in infobar.h. We don't really use them for anything +// but they are required. The values are copied from the GTK implementation. +const int infobars::InfoBar::kSeparatorLineHeight = 1; +const int infobars::InfoBar::kDefaultArrowTargetHeight = 9; +const int infobars::InfoBar::kMaximumArrowTargetHeight = 24; +const int infobars::InfoBar::kDefaultArrowTargetHalfWidth = + kDefaultArrowTargetHeight; +const int infobars::InfoBar::kMaximumArrowTargetHalfWidth = 14; +const int infobars::InfoBar::kDefaultBarTargetHeight = 36; diff --git a/components/translate.gypi b/components/translate.gypi index 00ec959..5a15611 100644 --- a/components/translate.gypi +++ b/components/translate.gypi @@ -9,11 +9,14 @@ 'type': 'static_library', 'dependencies': [ '../base/base.gyp:base', + '../base/base.gyp:base_i18n', '../google_apis/google_apis.gyp:google_apis', '../net/net.gyp:net', '../ui/base/ui_base.gyp:ui_base', '../url/url.gyp:url_lib', 'components_resources.gyp:components_resources', + 'components_strings.gyp:components_strings', + 'infobars_core', 'language_usage_metrics', 'pref_registry', 'translate_core_common', @@ -24,6 +27,8 @@ 'sources': [ 'translate/core/browser/language_state.cc', 'translate/core/browser/language_state.h', + 'translate/core/browser/options_menu_model.cc', + 'translate/core/browser/options_menu_model.h', 'translate/core/browser/page_translated_details.h', 'translate/core/browser/translate_accept_languages.cc', 'translate/core/browser/translate_accept_languages.h', @@ -36,6 +41,8 @@ 'translate/core/browser/translate_error_details.h', 'translate/core/browser/translate_event_details.cc', 'translate/core/browser/translate_event_details.h', + 'translate/core/browser/translate_infobar_delegate.cc', + 'translate/core/browser/translate_infobar_delegate.h', 'translate/core/browser/translate_language_list.cc', 'translate/core/browser/translate_language_list.h', 'translate/core/browser/translate_manager.cc', diff --git a/components/translate/DEPS b/components/translate/DEPS index e13509a..2497825 100644 --- a/components/translate/DEPS +++ b/components/translate/DEPS @@ -1,4 +1,5 @@ include_rules = [ + "+components/infobars", "+components/language_usage_metrics", "+components/pref_registry", "+google_apis", diff --git a/components/translate/core/browser/options_menu_model.cc b/components/translate/core/browser/options_menu_model.cc new file mode 100644 index 0000000..1bed639 --- /dev/null +++ b/components/translate/core/browser/options_menu_model.cc @@ -0,0 +1,137 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "components/translate/core/browser/options_menu_model.h" + +#include "base/metrics/histogram.h" +#include "components/translate/core/browser/translate_driver.h" +#include "components/translate/core/browser/translate_infobar_delegate.h" +#include "grit/components_strings.h" +#include "ui/base/l10n/l10n_util.h" + +namespace { + +const char kAboutGoogleTranslateURL[] = +#if defined(OS_CHROMEOS) + "https://support.google.com/chromeos/?p=ib_translation_bar"; +#else + "https://support.google.com/chrome/?p=ib_translation_bar"; +#endif + +} // namespace + +OptionsMenuModel::OptionsMenuModel(TranslateInfoBarDelegate* translate_delegate) + : ui::SimpleMenuModel(this), + translate_infobar_delegate_(translate_delegate) { + // |translate_delegate| must already be owned. + DCHECK(translate_infobar_delegate_->GetTranslateDriver()); + + base::string16 original_language = translate_delegate->language_name_at( + translate_delegate->original_language_index()); + base::string16 target_language = translate_delegate->language_name_at( + translate_delegate->target_language_index()); + + bool autodetermined_source_language = + translate_delegate->original_language_index() == + TranslateInfoBarDelegate::kNoIndex; + + // Populate the menu. + // Incognito mode does not get any preferences related items. + if (!translate_delegate->is_off_the_record()) { + if (!autodetermined_source_language) { + AddCheckItem(ALWAYS_TRANSLATE, + l10n_util::GetStringFUTF16(IDS_TRANSLATE_INFOBAR_OPTIONS_ALWAYS, + original_language, target_language)); + AddCheckItem(NEVER_TRANSLATE_LANGUAGE, + l10n_util::GetStringFUTF16( + IDS_TRANSLATE_INFOBAR_OPTIONS_NEVER_TRANSLATE_LANG, + original_language)); + } + AddCheckItem(NEVER_TRANSLATE_SITE, + l10n_util::GetStringUTF16( + IDS_TRANSLATE_INFOBAR_OPTIONS_NEVER_TRANSLATE_SITE)); + AddSeparator(ui::NORMAL_SEPARATOR); + } + if (!autodetermined_source_language) { + AddItem(REPORT_BAD_DETECTION, + l10n_util::GetStringFUTF16(IDS_TRANSLATE_INFOBAR_OPTIONS_REPORT_ERROR, + original_language)); + } + AddItemWithStringId(ABOUT_TRANSLATE, IDS_TRANSLATE_INFOBAR_OPTIONS_ABOUT); +} + +OptionsMenuModel::~OptionsMenuModel() { +} + +bool OptionsMenuModel::IsCommandIdChecked(int command_id) const { + switch (command_id) { + case NEVER_TRANSLATE_LANGUAGE: + return !translate_infobar_delegate_->IsTranslatableLanguageByPrefs(); + + case NEVER_TRANSLATE_SITE: + return translate_infobar_delegate_->IsSiteBlacklisted(); + + case ALWAYS_TRANSLATE: + return translate_infobar_delegate_->ShouldAlwaysTranslate(); + + default: + NOTREACHED() << "Invalid command_id from menu"; + break; + } + return false; +} + +bool OptionsMenuModel::IsCommandIdEnabled(int command_id) const { + switch (command_id) { + case NEVER_TRANSLATE_LANGUAGE: + case NEVER_TRANSLATE_SITE: + return !translate_infobar_delegate_->ShouldAlwaysTranslate(); + + case ALWAYS_TRANSLATE: + return (translate_infobar_delegate_->IsTranslatableLanguageByPrefs() && + !translate_infobar_delegate_->IsSiteBlacklisted()); + + default: + break; + } + return true; +} + +bool OptionsMenuModel::GetAcceleratorForCommandId( + int command_id, + ui::Accelerator* accelerator) { + return false; +} + +void OptionsMenuModel::ExecuteCommand(int command_id, int event_flags) { + switch (command_id) { + case NEVER_TRANSLATE_LANGUAGE: + translate_infobar_delegate_->ToggleTranslatableLanguageByPrefs(); + break; + + case NEVER_TRANSLATE_SITE: + translate_infobar_delegate_->ToggleSiteBlacklist(); + break; + + case ALWAYS_TRANSLATE: + translate_infobar_delegate_->ToggleAlwaysTranslate(); + break; + + case REPORT_BAD_DETECTION: + translate_infobar_delegate_->ReportLanguageDetectionError(); + break; + + case ABOUT_TRANSLATE: { + TranslateDriver* translate_driver = + translate_infobar_delegate_->GetTranslateDriver(); + if (translate_driver) + translate_driver->OpenUrlInNewTab(GURL(kAboutGoogleTranslateURL)); + break; + } + + default: + NOTREACHED() << "Invalid command id from menu."; + break; + } +} diff --git a/components/translate/core/browser/options_menu_model.h b/components/translate/core/browser/options_menu_model.h new file mode 100644 index 0000000..7cb65b8 --- /dev/null +++ b/components/translate/core/browser/options_menu_model.h @@ -0,0 +1,43 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef COMPONENTS_TRANSLATE_CORE_BROWSER_OPTIONS_MENU_MODEL_H_ +#define COMPONENTS_TRANSLATE_CORE_BROWSER_OPTIONS_MENU_MODEL_H_ + +#include "ui/base/models/simple_menu_model.h" + +class TranslateInfoBarDelegate; + +// A menu model that builds the contents of the options menu in the translate +// infobar. This menu has only one level (no submenus). +class OptionsMenuModel : public ui::SimpleMenuModel, + public ui::SimpleMenuModel::Delegate { + public: + // Command IDs of the items in this menu; exposed for testing. + enum CommandID { + ABOUT_TRANSLATE = 0, + ALWAYS_TRANSLATE, + NEVER_TRANSLATE_LANGUAGE, + NEVER_TRANSLATE_SITE, + REPORT_BAD_DETECTION + }; + + explicit OptionsMenuModel(TranslateInfoBarDelegate* translate_delegate); + virtual ~OptionsMenuModel(); + + // ui::SimpleMenuModel::Delegate implementation: + virtual bool IsCommandIdChecked(int command_id) const OVERRIDE; + virtual bool IsCommandIdEnabled(int command_id) const OVERRIDE; + virtual bool GetAcceleratorForCommandId( + int command_id, + ui::Accelerator* accelerator) OVERRIDE; + virtual void ExecuteCommand(int command_id, int event_flags) OVERRIDE; + + private: + TranslateInfoBarDelegate* translate_infobar_delegate_; + + DISALLOW_COPY_AND_ASSIGN(OptionsMenuModel); +}; + +#endif // COMPONENTS_TRANSLATE_CORE_BROWSER_OPTIONS_MENU_MODEL_H_ diff --git a/components/translate/core/browser/translate_client.h b/components/translate/core/browser/translate_client.h index 6a2c377..38fcdea 100644 --- a/components/translate/core/browser/translate_client.h +++ b/components/translate/core/browser/translate_client.h @@ -8,6 +8,7 @@ #include <string> #include "base/memory/ref_counted.h" +#include "base/memory/scoped_ptr.h" #include "components/translate/core/browser/translate_prefs.h" #include "components/translate/core/browser/translate_step.h" #include "components/translate/core/common/translate_errors.h" @@ -16,6 +17,11 @@ class GURL; class PrefService; class TranslateAcceptLanguages; class TranslateDriver; +class TranslateInfoBarDelegate; + +namespace infobars { +class InfoBar; +} // A client interface that needs to be supplied to TranslateManager by the // embedder. @@ -36,6 +42,13 @@ class TranslateClient { // Returns the associated TranslateAcceptLanguages. virtual TranslateAcceptLanguages* GetTranslateAcceptLanguages() = 0; + // Returns the resource ID of the icon to be shown for the Translate infobars. + virtual int GetInfobarIconID() const = 0; + + // Returns a translate infobar that owns |delegate|. + virtual scoped_ptr<infobars::InfoBar> CreateInfoBar( + scoped_ptr<TranslateInfoBarDelegate> delegate) const = 0; + // Called when the embedder should present UI to the user corresponding to the // user's current |step|. virtual void ShowTranslateUI(translate::TranslateStep step, diff --git a/components/translate/core/browser/translate_infobar_delegate.cc b/components/translate/core/browser/translate_infobar_delegate.cc new file mode 100644 index 0000000..69ff12a --- /dev/null +++ b/components/translate/core/browser/translate_infobar_delegate.cc @@ -0,0 +1,372 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "components/translate/core/browser/translate_infobar_delegate.h" + +#include <algorithm> + +#include "base/i18n/string_compare.h" +#include "base/metrics/histogram.h" +#include "components/infobars/core/infobar.h" +#include "components/infobars/core/infobar_manager.h" +#include "components/translate/core/browser/language_state.h" +#include "components/translate/core/browser/translate_accept_languages.h" +#include "components/translate/core/browser/translate_client.h" +#include "components/translate/core/browser/translate_download_manager.h" +#include "components/translate/core/browser/translate_driver.h" +#include "components/translate/core/browser/translate_manager.h" +#include "components/translate/core/common/translate_constants.h" +#include "grit/components_strings.h" +#include "ui/base/l10n/l10n_util.h" + +namespace { + +// Counts used to decide whether infobars should be shown. +// Android and iOS implementations do not offer a drop down (for space reasons), +// so we are more aggressive about showing the shortcut to never translate. +// The "Always Translate" option is always shown on iOS and Android. +#if defined(OS_ANDROID) +const int kAlwaysTranslateMinCount = 1; +const int kNeverTranslateMinCount = 1; +#elif defined(OS_IOS) +// The iOS implementation, like the Android implementation, shows the "Never +// translate" infobar after two denials. There is an offset of one because on +// Android the last event is not counted. +const int kAlwaysTranslateMinCount = 1; +const int kNeverTranslateMinCount = 2; +#else +const int kAlwaysTranslateMinCount = 3; +const int kNeverTranslateMinCount = 3; +#endif + +} // namespace + +const size_t TranslateInfoBarDelegate::kNoIndex = TranslateUIDelegate::NO_INDEX; + +TranslateInfoBarDelegate::~TranslateInfoBarDelegate() { +} + +// static +void TranslateInfoBarDelegate::Create( + bool replace_existing_infobar, + const base::WeakPtr<TranslateManager>& translate_manager, + infobars::InfoBarManager* infobar_manager, + bool is_off_the_record, + translate::TranslateStep step, + const std::string& original_language, + const std::string& target_language, + TranslateErrors::Type error_type, + bool triggered_from_menu) { + DCHECK(translate_manager); + DCHECK(infobar_manager); + + // Check preconditions. + if (step != translate::TRANSLATE_STEP_TRANSLATE_ERROR) { + DCHECK(TranslateDownloadManager::IsSupportedLanguage(target_language)); + if (!TranslateDownloadManager::IsSupportedLanguage(original_language)) { + // The original language can only be "unknown" for the "translating" + // infobar, which is the case when the user started a translation from the + // context menu. + DCHECK(step == translate::TRANSLATE_STEP_TRANSLATING || + step == translate::TRANSLATE_STEP_AFTER_TRANSLATE); + DCHECK_EQ(translate::kUnknownLanguageCode, original_language); + } + } + + // Do not create the after translate infobar if we are auto translating. + TranslateClient* translate_client = translate_manager->translate_client(); + if (((step == translate::TRANSLATE_STEP_AFTER_TRANSLATE) || + (step == translate::TRANSLATE_STEP_TRANSLATING)) && + translate_client->GetTranslateDriver()->GetLanguageState() + .InTranslateNavigation()) { + return; + } + + // Find any existing translate infobar delegate. + infobars::InfoBar* old_infobar = NULL; + TranslateInfoBarDelegate* old_delegate = NULL; + for (size_t i = 0; i < infobar_manager->infobar_count(); ++i) { + old_infobar = infobar_manager->infobar_at(i); + old_delegate = old_infobar->delegate()->AsTranslateInfoBarDelegate(); + if (old_delegate) { + if (!replace_existing_infobar) + return; + break; + } + } + + // Add the new delegate. + scoped_ptr<infobars::InfoBar> infobar(translate_client->CreateInfoBar( + scoped_ptr<TranslateInfoBarDelegate>(new TranslateInfoBarDelegate( + translate_manager, is_off_the_record, step, old_delegate, + original_language, target_language, error_type, + triggered_from_menu)))); + if (old_delegate) + infobar_manager->ReplaceInfoBar(old_infobar, infobar.Pass()); + else + infobar_manager->AddInfoBar(infobar.Pass()); +} + +void TranslateInfoBarDelegate::UpdateOriginalLanguageIndex( + size_t language_index) { + ui_delegate_.UpdateOriginalLanguageIndex(language_index); +} + +void TranslateInfoBarDelegate::UpdateTargetLanguageIndex( + size_t language_index) { + ui_delegate_.UpdateTargetLanguageIndex(language_index); +} + +void TranslateInfoBarDelegate::Translate() { + ui_delegate_.Translate(); +} + +void TranslateInfoBarDelegate::RevertTranslation() { + ui_delegate_.RevertTranslation(); + infobar()->RemoveSelf(); +} + +void TranslateInfoBarDelegate::ReportLanguageDetectionError() { + if (translate_manager_) + translate_manager_->ReportLanguageDetectionError(); +} + +void TranslateInfoBarDelegate::TranslationDeclined() { + ui_delegate_.TranslationDeclined(false); +} + +bool TranslateInfoBarDelegate::IsTranslatableLanguageByPrefs() { + TranslateClient* client = translate_manager_->translate_client(); + scoped_ptr<TranslatePrefs> translate_prefs(client->GetTranslatePrefs()); + TranslateAcceptLanguages* accept_languages = + client->GetTranslateAcceptLanguages(); + return translate_prefs->CanTranslateLanguage(accept_languages, + original_language_code()); +} + +void TranslateInfoBarDelegate::ToggleTranslatableLanguageByPrefs() { + if (ui_delegate_.IsLanguageBlocked()) { + ui_delegate_.SetLanguageBlocked(false); + } else { + ui_delegate_.SetLanguageBlocked(true); + infobar()->RemoveSelf(); + } +} + +bool TranslateInfoBarDelegate::IsSiteBlacklisted() { + return ui_delegate_.IsSiteBlacklisted(); +} + +void TranslateInfoBarDelegate::ToggleSiteBlacklist() { + if (ui_delegate_.IsSiteBlacklisted()) { + ui_delegate_.SetSiteBlacklist(false); + } else { + ui_delegate_.SetSiteBlacklist(true); + infobar()->RemoveSelf(); + } +} + +bool TranslateInfoBarDelegate::ShouldAlwaysTranslate() { + return ui_delegate_.ShouldAlwaysTranslate(); +} + +void TranslateInfoBarDelegate::ToggleAlwaysTranslate() { + ui_delegate_.SetAlwaysTranslate(!ui_delegate_.ShouldAlwaysTranslate()); +} + +void TranslateInfoBarDelegate::AlwaysTranslatePageLanguage() { + DCHECK(!ui_delegate_.ShouldAlwaysTranslate()); + ui_delegate_.SetAlwaysTranslate(true); + Translate(); +} + +void TranslateInfoBarDelegate::NeverTranslatePageLanguage() { + DCHECK(!ui_delegate_.IsLanguageBlocked()); + ui_delegate_.SetLanguageBlocked(true); + infobar()->RemoveSelf(); +} + +base::string16 TranslateInfoBarDelegate::GetMessageInfoBarText() { + if (step_ == translate::TRANSLATE_STEP_TRANSLATING) { + base::string16 target_language_name = + language_name_at(target_language_index()); + return l10n_util::GetStringFUTF16(IDS_TRANSLATE_INFOBAR_TRANSLATING_TO, + target_language_name); + } + + DCHECK_EQ(translate::TRANSLATE_STEP_TRANSLATE_ERROR, step_); + UMA_HISTOGRAM_ENUMERATION("Translate.ShowErrorInfobar", + error_type_, + TranslateErrors::TRANSLATE_ERROR_MAX); + ui_delegate_.OnErrorShown(error_type_); + switch (error_type_) { + case TranslateErrors::NETWORK: + return l10n_util::GetStringUTF16( + IDS_TRANSLATE_INFOBAR_ERROR_CANT_CONNECT); + case TranslateErrors::INITIALIZATION_ERROR: + case TranslateErrors::TRANSLATION_ERROR: + return l10n_util::GetStringUTF16( + IDS_TRANSLATE_INFOBAR_ERROR_CANT_TRANSLATE); + case TranslateErrors::UNKNOWN_LANGUAGE: + return l10n_util::GetStringUTF16( + IDS_TRANSLATE_INFOBAR_UNKNOWN_PAGE_LANGUAGE); + case TranslateErrors::UNSUPPORTED_LANGUAGE: + return l10n_util::GetStringFUTF16( + IDS_TRANSLATE_INFOBAR_UNSUPPORTED_PAGE_LANGUAGE, + language_name_at(target_language_index())); + case TranslateErrors::IDENTICAL_LANGUAGES: + return l10n_util::GetStringFUTF16( + IDS_TRANSLATE_INFOBAR_ERROR_SAME_LANGUAGE, + language_name_at(target_language_index())); + default: + NOTREACHED(); + return base::string16(); + } +} + +base::string16 TranslateInfoBarDelegate::GetMessageInfoBarButtonText() { + if (step_ != translate::TRANSLATE_STEP_TRANSLATE_ERROR) { + DCHECK_EQ(translate::TRANSLATE_STEP_TRANSLATING, step_); + } else if ((error_type_ != TranslateErrors::IDENTICAL_LANGUAGES) && + (error_type_ != TranslateErrors::UNKNOWN_LANGUAGE)) { + return l10n_util::GetStringUTF16( + (error_type_ == TranslateErrors::UNSUPPORTED_LANGUAGE) ? + IDS_TRANSLATE_INFOBAR_REVERT : IDS_TRANSLATE_INFOBAR_RETRY); + } + return base::string16(); +} + +void TranslateInfoBarDelegate::MessageInfoBarButtonPressed() { + DCHECK_EQ(translate::TRANSLATE_STEP_TRANSLATE_ERROR, step_); + if (error_type_ == TranslateErrors::UNSUPPORTED_LANGUAGE) { + RevertTranslation(); + return; + } + // This is the "Try again..." case. + DCHECK(translate_manager_); + translate_manager_->TranslatePage( + original_language_code(), target_language_code(), false); +} + +bool TranslateInfoBarDelegate::ShouldShowMessageInfoBarButton() { + return !GetMessageInfoBarButtonText().empty(); +} + +bool TranslateInfoBarDelegate::ShouldShowNeverTranslateShortcut() { + DCHECK_EQ(translate::TRANSLATE_STEP_BEFORE_TRANSLATE, step_); + return !is_off_the_record_ && + (prefs_->GetTranslationDeniedCount(original_language_code()) >= + kNeverTranslateMinCount); +} + +bool TranslateInfoBarDelegate::ShouldShowAlwaysTranslateShortcut() { + DCHECK_EQ(translate::TRANSLATE_STEP_BEFORE_TRANSLATE, step_); + return !is_off_the_record_ && + (prefs_->GetTranslationAcceptedCount(original_language_code()) >= + kAlwaysTranslateMinCount); +} + +// static +void TranslateInfoBarDelegate::GetAfterTranslateStrings( + std::vector<base::string16>* strings, + bool* swap_languages, + bool autodetermined_source_language) { + DCHECK(strings); + + if (autodetermined_source_language) { + size_t offset; + base::string16 text = l10n_util::GetStringFUTF16( + IDS_TRANSLATE_INFOBAR_AFTER_MESSAGE_AUTODETERMINED_SOURCE_LANGUAGE, + base::string16(), + &offset); + + strings->push_back(text.substr(0, offset)); + strings->push_back(text.substr(offset)); + return; + } + DCHECK(swap_languages); + + std::vector<size_t> offsets; + base::string16 text = l10n_util::GetStringFUTF16( + IDS_TRANSLATE_INFOBAR_AFTER_MESSAGE, base::string16(), base::string16(), + &offsets); + DCHECK_EQ(2U, offsets.size()); + + *swap_languages = (offsets[0] > offsets[1]); + if (*swap_languages) + std::swap(offsets[0], offsets[1]); + + strings->push_back(text.substr(0, offsets[0])); + strings->push_back(text.substr(offsets[0], offsets[1] - offsets[0])); + strings->push_back(text.substr(offsets[1])); +} + +TranslateDriver* TranslateInfoBarDelegate::GetTranslateDriver() { + if (!translate_manager_) + return NULL; + + return translate_manager_->translate_client()->GetTranslateDriver(); +} + +TranslateInfoBarDelegate::TranslateInfoBarDelegate( + const base::WeakPtr<TranslateManager>& translate_manager, + bool is_off_the_record, + translate::TranslateStep step, + TranslateInfoBarDelegate* old_delegate, + const std::string& original_language, + const std::string& target_language, + TranslateErrors::Type error_type, + bool triggered_from_menu) + : infobars::InfoBarDelegate(), + is_off_the_record_(is_off_the_record), + step_(step), + background_animation_(NONE), + ui_delegate_(translate_manager->translate_client(), + translate_manager.get(), + original_language, + target_language), + translate_manager_(translate_manager), + error_type_(error_type), + prefs_(translate_manager->translate_client()->GetTranslatePrefs()), + triggered_from_menu_(triggered_from_menu) { + DCHECK_NE((step_ == translate::TRANSLATE_STEP_TRANSLATE_ERROR), + (error_type_ == TranslateErrors::NONE)); + DCHECK(translate_manager_); + + if (old_delegate && (old_delegate->is_error() != is_error())) + background_animation_ = is_error() ? NORMAL_TO_ERROR : ERROR_TO_NORMAL; +} + +void TranslateInfoBarDelegate::InfoBarDismissed() { + if (step_ != translate::TRANSLATE_STEP_BEFORE_TRANSLATE) + return; + + // The user closed the infobar without clicking the translate button. + TranslationDeclined(); + UMA_HISTOGRAM_BOOLEAN("Translate.DeclineTranslateCloseInfobar", true); +} + +int TranslateInfoBarDelegate::GetIconID() const { + return translate_manager_->translate_client()->GetInfobarIconID(); +} + +infobars::InfoBarDelegate::Type TranslateInfoBarDelegate::GetInfoBarType() + const { + return PAGE_ACTION_TYPE; +} + +bool TranslateInfoBarDelegate::ShouldExpire( + const NavigationDetails& details) const { + // Note: we allow closing this infobar even if the main frame navigation + // was programmatic and not initiated by the user - crbug.com/70261 . + if (!details.is_navigation_to_different_page && !details.is_main_frame) + return false; + + return infobars::InfoBarDelegate::ShouldExpireInternal(details); +} + +TranslateInfoBarDelegate* + TranslateInfoBarDelegate::AsTranslateInfoBarDelegate() { + return this; +} diff --git a/components/translate/core/browser/translate_infobar_delegate.h b/components/translate/core/browser/translate_infobar_delegate.h new file mode 100644 index 0000000..cf53825 --- /dev/null +++ b/components/translate/core/browser/translate_infobar_delegate.h @@ -0,0 +1,221 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef COMPONENTS_TRANSLATE_CORE_BROWSER_TRANSLATE_INFOBAR_DELEGATE_H_ +#define COMPONENTS_TRANSLATE_CORE_BROWSER_TRANSLATE_INFOBAR_DELEGATE_H_ + +#include <string> +#include <utility> +#include <vector> + +#include "base/logging.h" +#include "base/memory/scoped_ptr.h" +#include "base/memory/weak_ptr.h" +#include "components/infobars/core/infobar_delegate.h" +#include "components/translate/core/browser/translate_prefs.h" +#include "components/translate/core/browser/translate_step.h" +#include "components/translate/core/browser/translate_ui_delegate.h" +#include "components/translate/core/common/translate_constants.h" +#include "components/translate/core/common/translate_errors.h" + +class TranslateClient; +class TranslateDriver; +class TranslateManager; + +namespace infobars { +class InfoBarManager; +} + +class TranslateInfoBarDelegate : public infobars::InfoBarDelegate { + public: + // The types of background color animations. + enum BackgroundAnimationType { + NONE, + NORMAL_TO_ERROR, + ERROR_TO_NORMAL + }; + + static const size_t kNoIndex; + + virtual ~TranslateInfoBarDelegate(); + + // Factory method to create a translate infobar. |error_type| must be + // specified iff |step| == TRANSLATION_ERROR. For other translate steps, + // |original_language| and |target_language| must be ASCII language codes + // (e.g. "en", "fr", etc.) for languages the TranslateManager supports + // translating. The lone exception is when the user initiates translation + // from the context menu, in which case it's legal to call this with + // |step| == TRANSLATING and |original_language| == kUnknownLanguageCode. + // + // If |replace_existing_infobar| is true, the infobar is created and added to + // the infobar manager, replacing any other translate infobar already present + // there. Otherwise, the infobar will only be added if there is no other + // translate infobar already present. + static void Create(bool replace_existing_infobar, + const base::WeakPtr<TranslateManager>& translate_manager, + infobars::InfoBarManager* infobar_manager, + bool is_off_the_record, + translate::TranslateStep step, + const std::string& original_language, + const std::string& target_language, + TranslateErrors::Type error_type, + bool triggered_from_menu); + + // Returns the number of languages supported. + size_t num_languages() const { return ui_delegate_.GetNumberOfLanguages(); } + + // Returns the ISO code for the language at |index|. + std::string language_code_at(size_t index) const { + return ui_delegate_.GetLanguageCodeAt(index); + } + + // Returns the displayable name for the language at |index|. + base::string16 language_name_at(size_t index) const { + return ui_delegate_.GetLanguageNameAt(index); + } + + translate::TranslateStep translate_step() const { return step_; } + + bool is_off_the_record() { return is_off_the_record_; } + + TranslateErrors::Type error_type() const { return error_type_; } + + size_t original_language_index() const { + return ui_delegate_.GetOriginalLanguageIndex(); + } + void UpdateOriginalLanguageIndex(size_t language_index); + + size_t target_language_index() const { + return ui_delegate_.GetTargetLanguageIndex(); + } + void UpdateTargetLanguageIndex(size_t language_index); + + // Convenience methods. + std::string original_language_code() const { + return ui_delegate_.GetOriginalLanguageCode(); + } + std::string target_language_code() const { + return ui_delegate_.GetTargetLanguageCode(); + } + + // Returns true if the current infobar indicates an error (in which case it + // should get a yellow background instead of a blue one). + bool is_error() const { + return step_ == translate::TRANSLATE_STEP_TRANSLATE_ERROR; + } + + // Return true if the translation was triggered by a menu entry instead of + // via an infobar/bubble or preference. + bool triggered_from_menu() const { + return triggered_from_menu_; + } + + // Returns what kind of background fading effect the infobar should use when + // its is shown. + BackgroundAnimationType background_animation_type() const { + return background_animation_; + } + + virtual void Translate(); + virtual void RevertTranslation(); + void ReportLanguageDetectionError(); + + // Called when the user declines to translate a page, by either closing the + // infobar or pressing the "Don't translate" button. + virtual void TranslationDeclined(); + + // Methods called by the Options menu delegate. + virtual bool IsTranslatableLanguageByPrefs(); + virtual void ToggleTranslatableLanguageByPrefs(); + virtual bool IsSiteBlacklisted(); + virtual void ToggleSiteBlacklist(); + virtual bool ShouldAlwaysTranslate(); + virtual void ToggleAlwaysTranslate(); + + // Methods called by the extra-buttons that can appear on the "before + // translate" infobar (when the user has accepted/declined the translation + // several times). + void AlwaysTranslatePageLanguage(); + void NeverTranslatePageLanguage(); + + // The following methods are called by the infobar that displays the status + // while translating and also the one displaying the error message. + base::string16 GetMessageInfoBarText(); + base::string16 GetMessageInfoBarButtonText(); + void MessageInfoBarButtonPressed(); + bool ShouldShowMessageInfoBarButton(); + + // Called by the before translate infobar to figure-out if it should show + // an extra shortcut to let the user black-list/white-list that language + // (based on how many times the user accepted/declined translation). + // The shortcut itself is platform specific, it can be a button or a new bar + // for example. + bool ShouldShowNeverTranslateShortcut(); + bool ShouldShowAlwaysTranslateShortcut(); + + // Adds the strings that should be displayed in the after translate infobar to + // |strings|. If |autodetermined_source_language| is false, the text in that + // infobar is: + // "The page has been translated from <lang1> to <lang2>." + // Otherwise: + // "The page has been translated to <lang1>." + // Because <lang1>, or <lang1> and <lang2> are displayed in menu buttons, the + // text is split in 2 or 3 chunks. |swap_languages| is set to true if + // |autodetermined_source_language| is false, and <lang1> and <lang2> + // should be inverted (some languages express the sentense as "The page has + // been translate to <lang2> from <lang1>."). It is ignored if + // |autodetermined_source_language| is true. + static void GetAfterTranslateStrings(std::vector<base::string16>* strings, + bool* swap_languages, + bool autodetermined_source_language); + + // Gets the TranslateDriver associated with this object. + // May return NULL if the driver has been destroyed. + TranslateDriver* GetTranslateDriver(); + + protected: + TranslateInfoBarDelegate( + const base::WeakPtr<TranslateManager>& translate_manager, + bool is_off_the_record, + translate::TranslateStep step, + TranslateInfoBarDelegate* old_delegate, + const std::string& original_language, + const std::string& target_language, + TranslateErrors::Type error_type, + bool triggered_from_menu); + + private: + friend class TranslationInfoBarTest; + typedef std::pair<std::string, base::string16> LanguageNamePair; + + // InfoBarDelegate: + virtual void InfoBarDismissed() OVERRIDE; + virtual int GetIconID() const OVERRIDE; + virtual infobars::InfoBarDelegate::Type GetInfoBarType() const OVERRIDE; + virtual bool ShouldExpire(const NavigationDetails& details) const OVERRIDE; + virtual TranslateInfoBarDelegate* AsTranslateInfoBarDelegate() OVERRIDE; + + bool is_off_the_record_; + translate::TranslateStep step_; + + // The type of fading animation if any that should be used when showing this + // infobar. + BackgroundAnimationType background_animation_; + + TranslateUIDelegate ui_delegate_; + base::WeakPtr<TranslateManager> translate_manager_; + + // The error that occurred when trying to translate (NONE if no error). + TranslateErrors::Type error_type_; + + // The translation related preferences. + scoped_ptr<TranslatePrefs> prefs_; + + // Whether the translation was triggered via a menu click vs automatically + // (due to language detection, preferences...) + bool triggered_from_menu_; + DISALLOW_COPY_AND_ASSIGN(TranslateInfoBarDelegate); +}; + +#endif // COMPONENTS_TRANSLATE_CORE_BROWSER_TRANSLATE_INFOBAR_DELEGATE_H_ |