blob: 61c926dd378df414bafed32d4dc05999633a64ce [file] [log] [blame]
// Copyright 2013 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/ui/views/translate/translate_bubble_view.h"
#include <stddef.h>
#include <algorithm>
#include <memory>
#include <string>
#include <thread>
#include <utility>
#include <vector>
#include "base/i18n/string_compare.h"
#include "base/memory/singleton.h"
#include "base/metrics/field_trial_params.h"
#include "base/metrics/histogram_macros.h"
#include "base/strings/utf_string_conversions.h"
#include "build/branding_buildflags.h"
#include "build/build_config.h"
#include "chrome/app/vector_icons/vector_icons.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/platform_util.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/translate/chrome_translate_client.h"
#include "chrome/browser/translate/translate_service.h"
#include "chrome/browser/ui/actions/chrome_action_id.h"
#include "chrome/browser/ui/browser_actions.h"
#include "chrome/browser/ui/chrome_pages.h"
#include "chrome/browser/ui/scoped_tabbed_browser_displayer.h"
#include "chrome/browser/ui/translate/translate_bubble_model_impl.h"
#include "chrome/browser/ui/ui_features.h"
#include "chrome/browser/ui/views/chrome_layout_provider.h"
#include "chrome/browser/ui/views/translate/translate_icon_view.h"
#include "chrome/common/url_constants.h"
#include "chrome/grit/generated_resources.h"
#include "chrome/grit/theme_resources.h"
#include "components/language_detection/core/constants.h"
#include "components/prefs/pref_service.h"
#include "components/strings/grit/components_strings.h"
#include "components/translate/core/browser/translate_download_manager.h"
#include "components/translate/core/browser/translate_manager.h"
#include "components/translate/core/browser/translate_metrics_logger.h"
#include "components/translate/core/browser/translate_prefs.h"
#include "components/translate/core/browser/translate_ui_delegate.h"
#include "components/vector_icons/vector_icons.h"
#include "content/public/browser/web_contents.h"
#include "ui/base/interaction/element_identifier.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/base/metadata/metadata_header_macros.h"
#include "ui/base/metadata/metadata_impl_macros.h"
#include "ui/base/models/combobox_model.h"
#include "ui/base/models/simple_combobox_model.h"
#include "ui/base/mojom/dialog_button.mojom.h"
#include "ui/base/mojom/menu_source_type.mojom.h"
#include "ui/base/resource/resource_bundle.h"
#include "ui/gfx/geometry/insets.h"
#include "ui/gfx/paint_vector_icon.h"
#include "ui/strings/grit/ui_strings.h"
#include "ui/views/accessibility/view_accessibility.h"
#include "ui/views/border.h"
#include "ui/views/bubble/bubble_frame_view.h"
#include "ui/views/controls/button/checkbox.h"
#include "ui/views/controls/button/image_button.h"
#include "ui/views/controls/button/image_button_factory.h"
#include "ui/views/controls/button/label_button.h"
#include "ui/views/controls/button/md_text_button.h"
#include "ui/views/controls/button/md_text_button_with_down_arrow.h"
#include "ui/views/controls/button/menu_button.h"
#include "ui/views/controls/combobox/combobox.h"
#include "ui/views/controls/highlight_path_generator.h"
#include "ui/views/controls/label.h"
#include "ui/views/controls/link.h"
#include "ui/views/controls/styled_label.h"
#include "ui/views/controls/tabbed_pane/tabbed_pane.h"
#include "ui/views/controls/throbber.h"
#include "ui/views/layout/box_layout.h"
#include "ui/views/layout/box_layout_view.h"
#include "ui/views/layout/flex_layout_types.h"
#include "ui/views/style/platform_style.h"
#include "ui/views/view_class_properties.h"
#include "ui/views/widget/widget.h"
namespace {
bool UseGoogleTranslateBranding() {
// Only use Google Translate branding in Chrome branded builds.
#if BUILDFLAG(GOOGLE_CHROME_BRANDING)
return true;
#else
return false;
#endif
}
std::unique_ptr<views::View> CreateWordmarkView() {
#if BUILDFLAG(GOOGLE_CHROME_BRANDING)
auto view = std::make_unique<views::View>();
view->SetLayoutManager(std::make_unique<views::BoxLayout>());
// Translate icon
std::unique_ptr<views::ImageView> translate_icon =
std::make_unique<views::ImageView>();
translate_icon->SetImage(
ui::ImageModel::FromResourceId(IDR_TRANSLATE_TAB_WORDMARK));
view->AddChildView(std::move(translate_icon));
return view;
#else
return nullptr;
#endif
}
void OpenLanguageSettings(TranslateBubbleModel* model_,
content::WebContents* web_contents_) {
model_->ReportUIInteraction(translate::UIInteraction::kOpenLanguageSettings);
Profile* profile =
Profile::FromBrowserContext(web_contents_->GetBrowserContext());
if (!profile) {
return;
}
chrome::ScopedTabbedBrowserDisplayer displayer(profile);
Browser* browser = displayer.browser();
if (!browser) {
return;
}
chrome::ShowSettingsSubPage(browser, chrome::kLanguageOptionsSubPage);
return;
}
} // namespace
TranslateBubbleView::TranslateBubbleView(
base::WeakPtr<actions::ActionItem> action_item,
views::View* anchor_view,
std::unique_ptr<TranslateBubbleModel> model,
translate::TranslateErrors error_type,
content::WebContents* web_contents,
base::OnceClosure on_closing)
: LocationBarBubbleDelegateView(anchor_view,
web_contents,
/*autosize=*/true),
model_(std::move(model)),
error_type_(error_type),
translate_action_item_(action_item),
is_in_incognito_window_(
web_contents && web_contents->GetBrowserContext()->IsOffTheRecord()),
on_closing_(std::move(on_closing)) {
UpdateInsets(TranslateBubbleModel::VIEW_STATE_BEFORE_TRANSLATE);
if (web_contents) { // web_contents can be null in unit_tests.
mouse_handler_ =
std::make_unique<WebContentMouseHandler>(this, web_contents);
}
SetButtons(static_cast<int>(ui::mojom::DialogButton::kNone));
SetFootnoteView(CreateWordmarkView());
SetProperty(views::kElementIdentifierKey, kIdentifier);
}
TranslateBubbleView::~TranslateBubbleView() {
// A child view could refer to a model which is owned by this class when
// the child view is destructed. For example, `source_language_combobox_` has
// a pointer to `model_`. Before destroying the models, removing the child
// views is needed.
translate_view_ = nullptr;
error_view_ = nullptr;
advanced_view_source_ = nullptr;
advanced_view_target_ = nullptr;
source_language_combobox_ = nullptr;
target_language_combobox_ = nullptr;
always_translate_checkbox_ = nullptr;
advanced_always_translate_checkbox_ = nullptr;
tabbed_pane_ = nullptr;
advanced_reset_button_source_ = nullptr;
advanced_reset_button_target_ = nullptr;
advanced_done_button_source_ = nullptr;
advanced_done_button_target_ = nullptr;
RemoveAllChildViews();
if (translate_action_item_.get()) {
translate_action_item_.get()->SetIsShowingBubble(false);
}
}
DEFINE_CLASS_ELEMENT_IDENTIFIER_VALUE(TranslateBubbleView, kIdentifier);
DEFINE_CLASS_ELEMENT_IDENTIFIER_VALUE(TranslateBubbleView, kSourceLanguageTab);
DEFINE_CLASS_ELEMENT_IDENTIFIER_VALUE(TranslateBubbleView, kTargetLanguageTab);
DEFINE_CLASS_ELEMENT_IDENTIFIER_VALUE(TranslateBubbleView, kCloseButton);
DEFINE_CLASS_ELEMENT_IDENTIFIER_VALUE(TranslateBubbleView, kOptionsMenuButton);
DEFINE_CLASS_ELEMENT_IDENTIFIER_VALUE(TranslateBubbleView,
kChangeTargetLanguage);
DEFINE_CLASS_ELEMENT_IDENTIFIER_VALUE(TranslateBubbleView,
kTargetLanguageCombobox);
DEFINE_CLASS_ELEMENT_IDENTIFIER_VALUE(TranslateBubbleView,
kTargetLanguageDoneButton);
DEFINE_CLASS_ELEMENT_IDENTIFIER_VALUE(TranslateBubbleView,
kChangeSourceLanguage);
DEFINE_CLASS_ELEMENT_IDENTIFIER_VALUE(TranslateBubbleView,
kSourceLanguageCombobox);
DEFINE_CLASS_ELEMENT_IDENTIFIER_VALUE(TranslateBubbleView,
kSourceLanguageDoneButton);
DEFINE_CLASS_ELEMENT_IDENTIFIER_VALUE(TranslateBubbleView, kErrorMessage);
DEFINE_CLASS_ELEMENT_IDENTIFIER_VALUE(TranslateBubbleView,
kOpenLanguageSettings);
void TranslateBubbleView::CloseBubble() {
mouse_handler_.reset();
LocationBarBubbleDelegateView::CloseBubble();
}
void TranslateBubbleView::TabSelectedAt(int index) {
// Tabbed pane is indexed from left to right starting at 0.
if (!model_->IsPageTranslatedInCurrentLanguages() && index == 1) {
Translate();
} else if (index == 0) {
ShowOriginal();
}
}
void TranslateBubbleView::Init() {
SetLayoutManager(std::make_unique<views::BoxLayout>(
views::BoxLayout::Orientation::kVertical));
should_always_translate_ = model_->ShouldAlwaysTranslate();
should_never_translate_language_ = model_->ShouldNeverTranslateLanguage();
should_never_translate_site_ = model_->ShouldNeverTranslateSite();
translate_view_ = AddChildView(CreateView());
advanced_view_source_ = AddChildView(CreateViewAdvancedSource());
advanced_view_target_ = AddChildView(CreateViewAdvancedTarget());
error_view_ = AddChildView(CreateViewError());
AddAccelerator(ui::Accelerator(ui::VKEY_RETURN, ui::EF_NONE));
UpdateChildVisibilities();
if (GetViewState() == TranslateBubbleModel::VIEW_STATE_ERROR) {
model_->ShowError(error_type_);
}
if (translate_action_item_.get()) {
translate_action_item_->SetIsShowingBubble(true);
}
}
views::View* TranslateBubbleView::GetInitiallyFocusedView() {
return GetCurrentView()->GetNextFocusableView();
}
bool TranslateBubbleView::ShouldShowCloseButton() const {
return false;
}
bool TranslateBubbleView::ShouldShowWindowTitle() const {
return false;
}
bool TranslateBubbleView::DidLanguageSelectionChange(
TranslateBubbleModel::ViewState view_state) {
if (view_state == TranslateBubbleModel::VIEW_STATE_SOURCE_LANGUAGE) {
return source_language_combobox_->GetSelectedIndex() !=
previous_source_language_index_;
} else {
return target_language_combobox_->GetSelectedIndex() !=
previous_target_language_index_;
}
}
void TranslateBubbleView::ResetLanguage() {
if (GetViewState() == TranslateBubbleModel::VIEW_STATE_SOURCE_LANGUAGE) {
source_language_combobox_->SetSelectedIndex(
previous_source_language_index_);
model_->UpdateSourceLanguageIndex(
source_language_combobox_->GetSelectedIndex().value());
} else {
target_language_combobox_->SetSelectedIndex(
previous_target_language_index_);
model_->UpdateTargetLanguageIndex(
target_language_combobox_->GetSelectedIndex().value());
}
UpdateAdvancedView();
}
void TranslateBubbleView::WindowClosing() {
// The operations for |model_| are valid only when a WebContents is alive.
// TODO(crbug.com/40341719): TranslateBubbleViewModel(Impl) should not hold a
// WebContents as a member variable because the WebContents might be destroyed
// while the TranslateBubbleViewModel(Impl) is still alive. Instead,
// TranslateBubbleViewModel should take a reference of a WebContents at each
// method.
if (web_contents()) {
model_->OnBubbleClosing();
}
// We have to reset the controller reference to the view here, not in our
// destructor, because we'll be destroyed asynchronously and the shown state
// will be checked before then.
if (on_closing_) {
std::move(on_closing_).Run();
}
}
bool TranslateBubbleView::AcceleratorPressed(
const ui::Accelerator& accelerator) {
switch (GetViewState()) {
case TranslateBubbleModel::VIEW_STATE_BEFORE_TRANSLATE: {
if (accelerator.key_code() == ui::VKEY_RETURN) {
Translate();
return true;
}
break;
}
case TranslateBubbleModel::VIEW_STATE_TRANSLATING:
case TranslateBubbleModel::VIEW_STATE_AFTER_TRANSLATE: {
if (accelerator.key_code() == ui::VKEY_RETURN) {
ShowOriginal();
return true;
}
break;
}
case TranslateBubbleModel::VIEW_STATE_ERROR:
break;
case TranslateBubbleModel::VIEW_STATE_TARGET_LANGUAGE:
break;
case TranslateBubbleModel::VIEW_STATE_SOURCE_LANGUAGE:
break;
}
return BubbleDialogDelegateView::AcceleratorPressed(accelerator);
}
gfx::Size TranslateBubbleView::CalculatePreferredSize(
const views::SizeBounds& available_size) const {
int width = 0;
for (const views::View* child : children()) {
width = std::max(width, child->GetPreferredSize().width());
}
return gfx::Size(width, GetCurrentView()->GetPreferredSize().height());
}
// Create the menu items for the dropdown options menu under TAB UI.
void TranslateBubbleView::ShowOptionsMenu(views::Button* source) {
// Recreate the menu model as translated languages can change while the menu
// is not showing, which invalidates these text strings.
options_menu_model_ = std::make_unique<ui::SimpleMenuModel>(this);
options_menu_model_->AddItemWithStringId(
OptionsMenuItem::CHANGE_TARGET_LANGUAGE,
IDS_TRANSLATE_BUBBLE_CHANGE_TARGET_LANGUAGE);
options_menu_model_->SetElementIdentifierAt(
options_menu_model_->GetItemCount() - 1, kChangeTargetLanguage);
auto source_language_code = model_->GetSourceLanguageCode();
auto source_language =
model_->GetSourceLanguageNameAt(model_->GetSourceLanguageIndex());
// Don't show "Always translate <language>" in incognito mode, because it
// doesn't do anything anyways. Don't show if the source language is unknown.
if (!is_in_incognito_window_ &&
source_language_code != language_detection::kUnknownLanguageCode) {
options_menu_model_->AddCheckItem(
OptionsMenuItem::ALWAYS_TRANSLATE_LANGUAGE,
l10n_util::GetStringFUTF16(IDS_TRANSLATE_BUBBLE_ALWAYS_TRANSLATE_LANG,
source_language));
}
if (source_language_code != language_detection::kUnknownLanguageCode) {
options_menu_model_->AddCheckItem(
OptionsMenuItem::NEVER_TRANSLATE_LANGUAGE,
l10n_util::GetStringFUTF16(IDS_TRANSLATE_BUBBLE_NEVER_TRANSLATE_LANG,
source_language));
}
if (model_->CanAddSiteToNeverPromptList()) {
options_menu_model_->AddCheckItem(
OptionsMenuItem::NEVER_TRANSLATE_SITE,
l10n_util::GetStringUTF16(IDS_TRANSLATE_BUBBLE_NEVER_TRANSLATE_SITE));
}
options_menu_model_->AddItem(
OptionsMenuItem::CHANGE_SOURCE_LANGUAGE,
l10n_util::GetStringFUTF16(IDS_TRANSLATE_BUBBLE_CHANGE_SOURCE_LANGUAGE,
source_language));
options_menu_model_->SetElementIdentifierAt(
options_menu_model_->GetItemCount() - 1, kChangeSourceLanguage);
if (!is_in_incognito_window_ &&
base::FeatureList::IsEnabled(language::kTranslateOpenSettings)) {
options_menu_model_->AddItem(
OptionsMenuItem::OPEN_LANGUAGE_SETTINGS,
l10n_util::GetStringUTF16(IDS_TRANSLATE_BUBBLE_OPEN_LANGUAGE_SETTINGS));
options_menu_model_->SetElementIdentifierAt(
options_menu_model_->GetItemCount() - 1, kOpenLanguageSettings);
}
options_menu_runner_ = std::make_unique<views::MenuRunner>(
options_menu_model_.get(), views::MenuRunner::COMBOBOX);
gfx::Rect screen_bounds = source->GetAnchorBoundsInScreen();
options_menu_runner_->RunMenuAt(source->GetWidget(), nullptr, screen_bounds,
views::MenuAnchorPosition::kTopRight,
ui::mojom::MenuSourceType::kMouse);
}
bool TranslateBubbleView::IsCommandIdChecked(int command_id) const {
switch (command_id) {
case OptionsMenuItem::NEVER_TRANSLATE_LANGUAGE:
return should_never_translate_language_;
case OptionsMenuItem::NEVER_TRANSLATE_SITE:
return should_never_translate_site_;
case OptionsMenuItem::ALWAYS_TRANSLATE_LANGUAGE:
return should_always_translate_;
default:
NOTREACHED();
}
}
bool TranslateBubbleView::IsCommandIdEnabled(int command_id) const {
return true;
}
void TranslateBubbleView::ExecuteCommand(int command_id, int event_flags) {
switch (command_id) {
case OptionsMenuItem::ALWAYS_TRANSLATE_LANGUAGE:
should_always_translate_ = !should_always_translate_;
model_->SetAlwaysTranslate(should_always_translate_);
if (should_always_translate_) {
should_never_translate_language_ = false;
model_->SetNeverTranslateLanguage(should_never_translate_language_);
if (GetViewState() ==
TranslateBubbleModel::VIEW_STATE_BEFORE_TRANSLATE) {
model_->Translate();
SwitchView(TranslateBubbleModel::VIEW_STATE_TRANSLATING);
}
}
UpdateChildVisibilities();
break;
case OptionsMenuItem::NEVER_TRANSLATE_LANGUAGE:
should_never_translate_language_ = !should_never_translate_language_;
if (should_never_translate_language_) {
should_always_translate_ = false;
model_->SetAlwaysTranslate(should_always_translate_);
model_->SetNeverTranslateLanguage(true);
RevertOrDeclineTranslation();
} else {
model_->SetNeverTranslateLanguage(false);
}
break;
case OptionsMenuItem::NEVER_TRANSLATE_SITE:
should_never_translate_site_ = !should_never_translate_site_;
if (should_never_translate_site_) {
model_->SetNeverTranslateSite(true);
RevertOrDeclineTranslation();
} else {
model_->SetNeverTranslateSite(false);
}
break;
case OptionsMenuItem::CHANGE_TARGET_LANGUAGE:
SwitchView(TranslateBubbleModel::VIEW_STATE_TARGET_LANGUAGE);
break;
case OptionsMenuItem::CHANGE_SOURCE_LANGUAGE:
SwitchView(TranslateBubbleModel::VIEW_STATE_SOURCE_LANGUAGE);
break;
case OptionsMenuItem::OPEN_LANGUAGE_SETTINGS:
OpenLanguageSettings(model(), web_contents());
break;
default:
NOTREACHED();
}
}
void TranslateBubbleView::OnWidgetClosing(views::Widget* widget) {
if (GetBubbleFrameView()->GetWidget()->closed_reason() ==
views::Widget::ClosedReason::kCloseButtonClicked) {
model_->DeclineTranslation();
model_->ReportUIInteraction(translate::UIInteraction::kCloseUIExplicitly);
} else {
model_->ReportUIInteraction(translate::UIInteraction::kCloseUILostFocus);
}
}
TranslateBubbleModel::ViewState TranslateBubbleView::GetViewState() const {
return model_->GetViewState();
}
void TranslateBubbleView::SetViewState(translate::TranslateStep step,
translate::TranslateErrors error_type) {
if (step == translate::TRANSLATE_STEP_TRANSLATE_ERROR) {
SwitchToErrorView(error_type);
} else {
TranslateBubbleModel::ViewState state =
TranslateBubbleModelImpl::TranslateStepToViewState(step);
SwitchView(state);
}
}
views::View* TranslateBubbleView::GetCurrentView() const {
switch (GetViewState()) {
case TranslateBubbleModel::VIEW_STATE_BEFORE_TRANSLATE:
case TranslateBubbleModel::VIEW_STATE_TRANSLATING:
case TranslateBubbleModel::VIEW_STATE_AFTER_TRANSLATE:
return translate_view_;
case TranslateBubbleModel::VIEW_STATE_ERROR:
return error_view_;
case TranslateBubbleModel::VIEW_STATE_SOURCE_LANGUAGE:
return advanced_view_source_;
case TranslateBubbleModel::VIEW_STATE_TARGET_LANGUAGE:
return advanced_view_target_;
}
NOTREACHED();
}
void TranslateBubbleView::Translate() {
model_->ReportUIInteraction(translate::UIInteraction::kTranslate);
model_->Translate();
SwitchView(TranslateBubbleModel::VIEW_STATE_TRANSLATING);
}
void TranslateBubbleView::ShowOriginal() {
model_->ReportUIInteraction(translate::UIInteraction::kRevert);
model_->RevertTranslation();
SwitchView(TranslateBubbleModel::VIEW_STATE_BEFORE_TRANSLATE);
}
void TranslateBubbleView::ConfirmAdvancedOptions() {
model_->SetAlwaysTranslate(should_always_translate_);
if (model_->IsPageTranslatedInCurrentLanguages()) {
SwitchView(TranslateBubbleModel::VIEW_STATE_AFTER_TRANSLATE);
} else {
std::u16string source_language_name;
std::u16string target_language_name;
DCHECK(tabbed_pane_);
UpdateLanguageNames(&source_language_name, &target_language_name);
tabbed_pane_->GetTabAt(0)->SetTitleText(source_language_name);
tabbed_pane_->GetTabAt(1)->SetTitleText(target_language_name);
model_->Translate();
tabbed_pane_->SelectTabAt(1);
SwitchView(TranslateBubbleModel::VIEW_STATE_AFTER_TRANSLATE);
}
}
void TranslateBubbleView::SourceLanguageChanged() {
model_->ReportUIInteraction(translate::UIInteraction::kChangeSourceLanguage);
model_->UpdateSourceLanguageIndex(
source_language_combobox_->GetSelectedIndex().value());
UpdateAdvancedView();
}
void TranslateBubbleView::TargetLanguageChanged() {
model_->ReportUIInteraction(translate::UIInteraction::kChangeTargetLanguage);
model_->UpdateTargetLanguageIndex(
target_language_combobox_->GetSelectedIndex().value());
UpdateAdvancedView();
}
void TranslateBubbleView::AlwaysTranslatePressed() {
should_always_translate_ = GetAlwaysTranslateCheckbox()->GetChecked();
// In the tab UI the always translate button should apply immediately
// except for in an advanced view.
if (GetViewState() != TranslateBubbleModel::VIEW_STATE_SOURCE_LANGUAGE) {
model_->SetAlwaysTranslate(should_always_translate_);
if (!model_->IsPageTranslatedInCurrentLanguages() &&
should_always_translate_) {
Translate();
}
}
}
void TranslateBubbleView::UpdateChildVisibilities() {
// Update the state of the always translate checkbox
if (advanced_always_translate_checkbox_) {
advanced_always_translate_checkbox_->SetChecked(should_always_translate_);
}
if (always_translate_checkbox_) {
always_translate_checkbox_->SetText(l10n_util::GetStringFUTF16(
IDS_TRANSLATE_BUBBLE_ALWAYS_TRANSLATE_LANG,
model_->GetSourceLanguageNameAt(model_->GetSourceLanguageIndex())));
always_translate_checkbox_->SetChecked(should_always_translate_);
}
for (views::View* view : children()) {
view->SetVisible(view == GetCurrentView());
}
}
std::unique_ptr<views::View> TranslateBubbleView::CreateEmptyPane() {
auto pane = std::make_unique<views::View>();
pane->SetBorder(
views::CreateEmptyBorder(ChromeLayoutProvider::Get()->GetInsetsMetric(
views::INSETS_DIALOG_SUBSECTION)));
return pane;
}
std::unique_ptr<views::View> TranslateBubbleView::CreateView() {
std::u16string source_language_name;
std::u16string target_language_name;
UpdateLanguageNames(&source_language_name, &target_language_name);
ChromeLayoutProvider* provider = ChromeLayoutProvider::Get();
auto view = std::make_unique<views::View>();
view->SetLayoutManager(std::make_unique<views::FlexLayout>())
->SetOrientation(views::LayoutOrientation::kVertical);
auto inner_view = std::make_unique<views::View>();
inner_view->SetLayoutManager(std::make_unique<views::FlexLayout>())
->SetOrientation(views::LayoutOrientation::kHorizontal);
auto* horizontal_view = view->AddChildView(std::move(inner_view));
views::View* icon = nullptr;
if (!UseGoogleTranslateBranding()) {
icon = horizontal_view->AddChildView(CreateTranslateIcon());
}
// Tabbed pane for language selection. Can't use unique_ptr because
// tabs have to be added after the tabbed_pane is added to the parent,
// when we release ownership of the unique_ptr.
auto tabbed_pane = std::make_unique<views::TabbedPane>();
tabbed_pane_ = horizontal_view->AddChildView(std::move(tabbed_pane));
// NOTE: Panes must be added after |tabbed_pane| has been added to its
// parent.
tabbed_pane_->AddTab(source_language_name, CreateEmptyPane());
tabbed_pane_->AddTab(target_language_name, CreateEmptyPane());
tabbed_pane_->GetTabAt(0)->SetProperty(views::kElementIdentifierKey,
kSourceLanguageTab);
tabbed_pane_->GetTabAt(1)->SetProperty(views::kElementIdentifierKey,
kTargetLanguageTab);
tabbed_pane_->GetTabAt(0)->SetBorder(
views::CreateEmptyBorder(gfx::Insets::VH(2, 20)));
tabbed_pane_->GetTabAt(1)->SetBorder(
views::CreateEmptyBorder(gfx::Insets::VH(2, 20)));
tabbed_pane_->SetListener(this);
auto* padding_view =
horizontal_view->AddChildView(std::make_unique<views::View>());
auto* options_menu = horizontal_view->AddChildView(CreateOptionsMenuButton());
horizontal_view->AddChildView(CreateCloseButton());
// Don't show the the always translate checkbox if the source language is
// unknown.
auto source_language_code = model_->GetSourceLanguageCode();
if (model_->ShouldShowAlwaysTranslateShortcut() &&
source_language_code != language_detection::kUnknownLanguageCode) {
auto before_always_translate_checkbox = std::make_unique<views::Checkbox>(
l10n_util::GetStringFUTF16(
IDS_TRANSLATE_BUBBLE_ALWAYS_TRANSLATE_LANG,
model_->GetSourceLanguageNameAt(model_->GetSourceLanguageIndex())),
base::BindRepeating(&TranslateBubbleView::AlwaysTranslatePressed,
base::Unretained(this)));
before_always_translate_checkbox->SetID(BUTTON_ID_ALWAYS_TRANSLATE);
always_translate_checkbox_ =
view->AddChildView(std::move(before_always_translate_checkbox));
}
const int button_horizontal_spacing =
provider->GetDistanceMetric(views::DISTANCE_RELATED_BUTTON_HORIZONTAL);
if (icon) {
icon->SetProperty(views::kMarginsKey,
gfx::Insets().set_right(button_horizontal_spacing));
}
tabbed_pane_->SetProperty(
views::kFlexBehaviorKey,
views::FlexSpecification(views::MinimumFlexSizeRule::kScaleToMinimum,
views::MaximumFlexSizeRule::kPreferred));
padding_view->SetProperty(
views::kFlexBehaviorKey,
views::FlexSpecification(views::LayoutOrientation::kHorizontal,
views::MinimumFlexSizeRule::kScaleToZero,
views::MaximumFlexSizeRule::kUnbounded)
.WithOrder(2));
options_menu->SetProperty(views::kElementIdentifierKey, kOptionsMenuButton);
options_menu->SetProperty(views::kMarginsKey,
gfx::Insets::VH(0, button_horizontal_spacing));
if (always_translate_checkbox_) {
horizontal_view->SetProperty(
views::kMarginsKey,
gfx::Insets::TLBR(0, 0,
provider->GetDistanceMetric(
views::DISTANCE_RELATED_CONTROL_VERTICAL),
0));
always_translate_checkbox_->SetProperty(views::kMarginsKey,
gfx::Insets::VH(2, 0));
}
return view;
}
// TODO(crbug.com/40336858): Revise this later to show a specific message for
// each error.
std::unique_ptr<views::View> TranslateBubbleView::CreateViewError() {
auto translate_options_button =
std::make_unique<views::MdTextButtonWithDownArrow>(
views::Button::PressedCallback(),
l10n_util::GetStringUTF16(IDS_TRANSLATE_BUBBLE_OPTIONS_MENU_BUTTON));
translate_options_button->SetCallback(base::BindRepeating(
&TranslateBubbleView::ShowOptionsMenu, base::Unretained(this),
base::Unretained(translate_options_button.get())));
std::u16string translate_options_button_label(
l10n_util::GetStringUTF16(IDS_TRANSLATE_BUBBLE_OPTIONS_MENU_BUTTON));
translate_options_button->GetViewAccessibility().SetName(
translate_options_button_label);
translate_options_button->SetTooltipText(translate_options_button_label);
translate_options_button->SetID(BUTTON_ID_OPTIONS_MENU);
translate_options_button->SetRequestFocusOnPress(true);
return CreateViewErrorNoTitle(std::move(translate_options_button));
}
std::unique_ptr<views::View> TranslateBubbleView::CreateViewErrorNoTitle(
std::unique_ptr<views::Button> advanced_button) {
const ChromeLayoutProvider* provider = ChromeLayoutProvider::Get();
auto view = std::make_unique<views::View>();
views::BoxLayout* layout =
view->SetLayoutManager(std::make_unique<views::BoxLayout>(
views::BoxLayout::Orientation::kVertical));
layout->set_between_child_spacing(
provider->GetDistanceMetric(views::DISTANCE_UNRELATED_CONTROL_VERTICAL));
// Title row.
auto title_row = std::make_unique<views::View>();
title_row->SetLayoutManager(std::make_unique<views::FlexLayout>());
int error_message_id = IDS_TRANSLATE_BUBBLE_COULD_NOT_TRANSLATE_TITLE;
auto error_message_label = std::make_unique<views::Label>(
l10n_util::GetStringUTF16(error_message_id),
views::style::CONTEXT_DIALOG_TITLE, views::style::STYLE_PRIMARY);
const int vertical_spacing =
provider->GetDistanceMetric(views::DISTANCE_RELATED_CONTROL_VERTICAL);
error_message_label->SetLineHeight(vertical_spacing * 5);
error_message_label->SetHorizontalAlignment(
gfx::HorizontalAlignment::ALIGN_LEFT);
error_message_label->SetProperty(views::kElementIdentifierKey, kErrorMessage);
error_message_label->SetProperty(
views::kFlexBehaviorKey,
views::FlexSpecification(views::LayoutOrientation::kHorizontal,
views::MinimumFlexSizeRule::kScaleToZero,
views::MaximumFlexSizeRule::kUnbounded));
title_row->AddChildView(std::move(error_message_label));
title_row->AddChildView(CreateCloseButton());
view->AddChildView(std::move(title_row));
// Button row.
auto button_row = std::make_unique<views::BoxLayoutView>();
button_row->SetMainAxisAlignment(views::BoxLayout::MainAxisAlignment::kEnd);
button_row->SetBetweenChildSpacing(
provider->GetDistanceMetric(views::DISTANCE_RELATED_BUTTON_HORIZONTAL));
auto try_again_button = std::make_unique<views::MdTextButton>(
base::BindRepeating(
[](TranslateBubbleModel* model) { model->Translate(); },
base::Unretained(model_.get())),
l10n_util::GetStringUTF16(IDS_TRANSLATE_BUBBLE_TRY_AGAIN));
try_again_button->SetID(BUTTON_ID_TRY_AGAIN);
button_row->AddChildView(std::move(try_again_button));
button_row->AddChildView(std::move(advanced_button));
view->AddChildView(std::move(button_row));
return view;
}
std::unique_ptr<views::View> TranslateBubbleView::CreateViewAdvancedSource() {
// Bubble title
std::unique_ptr<views::Label> source_language_title_label =
std::make_unique<views::Label>(
l10n_util::GetStringUTF16(IDS_TRANSLATE_BUBBLE_ADVANCED_SOURCE),
views::style::CONTEXT_DIALOG_TITLE);
// Language icon
int source_default_index = model_->GetSourceLanguageIndex();
auto source_language_combobox_model =
std::make_unique<SourceLanguageComboboxModel>(source_default_index,
model_.get());
auto source_language_combobox = std::make_unique<views::Combobox>(
std::move(source_language_combobox_model));
source_language_combobox->SetProperty(views::kElementIdentifierKey,
kSourceLanguageCombobox);
// In an incognito window or when the source language is unknown, "Always
// translate" checkbox shouldn't be shown.
std::unique_ptr<views::Checkbox> advanced_always_translate_checkbox;
auto source_language_code = model_->GetSourceLanguageCode();
if (!is_in_incognito_window_ &&
source_language_code != language_detection::kUnknownLanguageCode) {
advanced_always_translate_checkbox = std::make_unique<views::Checkbox>(
l10n_util::GetStringUTF16(IDS_TRANSLATE_BUBBLE_ALWAYS),
base::BindRepeating(&TranslateBubbleView::AlwaysTranslatePressed,
base::Unretained(this)));
advanced_always_translate_checkbox->SetID(BUTTON_ID_ALWAYS_TRANSLATE);
}
source_language_combobox->SetCallback(base::BindRepeating(
&TranslateBubbleView::SourceLanguageChanged, base::Unretained(this)));
source_language_combobox->GetViewAccessibility().SetName(
l10n_util::GetStringUTF16(
IDS_TRANSLATE_BUBBLE_SOURCE_LANG_COMBOBOX_ACCNAME));
source_language_combobox_ = source_language_combobox.get();
auto advanced_reset_button = std::make_unique<views::MdTextButton>(
base::BindRepeating(&TranslateBubbleView::ResetLanguage,
base::Unretained(this)),
l10n_util::GetStringUTF16(IDS_TRANSLATE_BUBBLE_RESET));
advanced_reset_button->SetID(BUTTON_ID_RESET);
advanced_reset_button_source_ = advanced_reset_button.get();
auto advanced_done_button = std::make_unique<views::MdTextButton>(
base::BindRepeating(&TranslateBubbleView::ConfirmAdvancedOptions,
base::Unretained(this)),
l10n_util::GetStringUTF16(IDS_DONE));
advanced_done_button->SetID(BUTTON_ID_DONE);
advanced_done_button->SetIsDefault(true);
advanced_done_button_source_ = advanced_done_button.get();
advanced_done_button_source_->SetProperty(views::kElementIdentifierKey,
kSourceLanguageDoneButton);
return CreateViewAdvanced(std::move(source_language_combobox),
std::move(source_language_title_label),
std::move(advanced_reset_button),
std::move(advanced_done_button),
std::move(advanced_always_translate_checkbox));
}
std::unique_ptr<views::View> TranslateBubbleView::CreateViewAdvancedTarget() {
// Bubble title
std::unique_ptr<views::Label> target_language_title_label =
std::make_unique<views::Label>(
l10n_util::GetStringUTF16(IDS_TRANSLATE_BUBBLE_ADVANCED_TARGET),
views::style::CONTEXT_DIALOG_TITLE);
int target_default_index = model_->GetTargetLanguageIndex();
auto target_language_combobox_model =
std::make_unique<TargetLanguageComboboxModel>(target_default_index,
model_.get());
auto target_language_combobox = std::make_unique<views::Combobox>(
std::move(target_language_combobox_model));
target_language_combobox->SetProperty(views::kElementIdentifierKey,
kTargetLanguageCombobox);
target_language_combobox->SetCallback(base::BindRepeating(
&TranslateBubbleView::TargetLanguageChanged, base::Unretained(this)));
target_language_combobox->GetViewAccessibility().SetName(
l10n_util::GetStringUTF16(
IDS_TRANSLATE_BUBBLE_TARGET_LANG_COMBOBOX_ACCNAME));
target_language_combobox_ = target_language_combobox.get();
auto advanced_reset_button = std::make_unique<views::MdTextButton>(
base::BindRepeating(&TranslateBubbleView::ResetLanguage,
base::Unretained(this)),
l10n_util::GetStringUTF16(IDS_TRANSLATE_BUBBLE_RESET));
advanced_reset_button->SetID(BUTTON_ID_RESET);
advanced_reset_button_target_ = advanced_reset_button.get();
auto advanced_done_button = std::make_unique<views::MdTextButton>(
base::BindRepeating(&TranslateBubbleView::ConfirmAdvancedOptions,
base::Unretained(this)),
l10n_util::GetStringUTF16(IDS_DONE));
advanced_done_button->SetID(BUTTON_ID_DONE);
advanced_done_button->SetIsDefault(true);
advanced_done_button_target_ = advanced_done_button.get();
advanced_done_button_target_->SetProperty(views::kElementIdentifierKey,
kTargetLanguageDoneButton);
return CreateViewAdvanced(std::move(target_language_combobox),
std::move(target_language_title_label),
std::move(advanced_reset_button),
std::move(advanced_done_button), nullptr);
}
std::unique_ptr<views::View> TranslateBubbleView::CreateViewAdvanced(
std::unique_ptr<views::Combobox> combobox,
std::unique_ptr<views::Label> language_title_label,
std::unique_ptr<views::Button> advanced_reset_button,
std::unique_ptr<views::Button> advanced_done_button,
std::unique_ptr<views::Checkbox> advanced_always_translate_checkbox) {
const ChromeLayoutProvider* provider = ChromeLayoutProvider::Get();
const int vertical_spacing =
provider->GetDistanceMetric(views::DISTANCE_RELATED_CONTROL_VERTICAL);
const int horizontal_spacing =
provider->GetDistanceMetric(views::DISTANCE_RELATED_CONTROL_HORIZONTAL);
auto view = std::make_unique<views::BoxLayoutView>();
view->SetBetweenChildSpacing(horizontal_spacing);
std::unique_ptr<views::ImageView> language_icon = CreateTranslateIcon();
if (!UseGoogleTranslateBranding()) {
// If the bottom branding isn't showing, display the leading Translate
// icon otherwise it's not obvious what the bubble is about. This should
// only happen on non-Chrome-branded builds.
auto* icon_view =
view->AddChildView(std::make_unique<views::BoxLayoutView>());
icon_view->SetCrossAxisAlignment(
views::BoxLayout::CrossAxisAlignment::kStart);
icon_view->SetOrientation(views::BoxLayout::Orientation::kVertical);
icon_view->AddChildView(std::move(language_icon));
icon_view->SetProperty(views::kMarginsKey,
gfx::Insets::VH(vertical_spacing, 0));
}
auto* form_view = view->AddChildView(
views::Builder<views::BoxLayoutView>()
.SetOrientation(views::BoxLayout::Orientation::kVertical)
.SetBetweenChildSpacing(vertical_spacing)
.Build());
// Stretch |form_view| to fit the rest of bubble's width. Note that because no
// other view has flex set, the flex argument here can be any positive
// integer.
view->SetFlexForView(form_view, 1);
language_title_label->SetProperty(
views::kMarginsKey,
gfx::Insets::TLBR(vertical_spacing, 0, vertical_spacing,
horizontal_spacing * 4));
language_title_label->SetProperty(views::kCrossAxisAlignmentKey,
views::LayoutAlignment::kStart);
auto* title_row = form_view->AddChildView(std::make_unique<views::View>());
title_row->SetLayoutManager(std::make_unique<views::FlexLayout>());
auto* title_label = title_row->AddChildView(std::move(language_title_label));
auto* padding_view = title_row->AddChildView(std::make_unique<views::View>());
title_row->AddChildView(CreateCloseButton());
// Set flex specifications for |title_row| views.
title_label->SetProperty(
views::kFlexBehaviorKey,
views::FlexSpecification(views::MinimumFlexSizeRule::kScaleToMinimum,
views::MaximumFlexSizeRule::kPreferred));
// |padding_view| is unbounded so that the close button stays right aligned
// when the bubble expands.
padding_view->SetProperty(
views::kFlexBehaviorKey,
views::FlexSpecification(views::LayoutOrientation::kHorizontal,
views::MinimumFlexSizeRule::kScaleToZero,
views::MaximumFlexSizeRule::kUnbounded)
.WithOrder(2));
form_view->AddChildView(std::move(combobox));
auto button_row = std::make_unique<views::BoxLayoutView>();
if (advanced_always_translate_checkbox) {
advanced_always_translate_checkbox_ =
form_view->AddChildView(std::move(advanced_always_translate_checkbox));
button_row->SetProperty(views::kMarginsKey,
gfx::Insets().set_top(vertical_spacing));
} else {
button_row->SetProperty(views::kMarginsKey,
gfx::Insets().set_top(2 * vertical_spacing));
}
button_row->SetMainAxisAlignment(views::BoxLayout::MainAxisAlignment::kEnd);
button_row->SetBetweenChildSpacing(
provider->GetDistanceMetric(views::DISTANCE_RELATED_BUTTON_HORIZONTAL));
button_row->AddChildView(std::move(advanced_reset_button));
button_row->AddChildView(std::move(advanced_done_button));
form_view->AddChildView(std::move(button_row));
UpdateAdvancedView();
return view;
}
std::unique_ptr<views::ImageView> TranslateBubbleView::CreateTranslateIcon() {
const int language_icon_id = IDR_TRANSLATE_BUBBLE_ICON;
std::unique_ptr<views::ImageView> language_icon =
std::make_unique<views::ImageView>();
language_icon->SetImage(ui::ImageModel::FromResourceId(language_icon_id));
return language_icon;
}
std::unique_ptr<views::Button> TranslateBubbleView::CreateOptionsMenuButton() {
// Three dots options menu button
auto tab_translate_options_button =
views::CreateVectorImageButtonWithNativeTheme(
views::Button::PressedCallback(), kBrowserToolsIcon);
tab_translate_options_button->SetCallback(base::BindRepeating(
&TranslateBubbleView::ShowOptionsMenu, base::Unretained(this),
base::Unretained(tab_translate_options_button.get())));
InstallCircleHighlightPathGenerator(tab_translate_options_button.get());
std::u16string translate_options_button_label(
l10n_util::GetStringUTF16(IDS_TRANSLATE_BUBBLE_OPTIONS_MENU_BUTTON));
tab_translate_options_button->GetViewAccessibility().SetName(
translate_options_button_label);
tab_translate_options_button->SetTooltipText(translate_options_button_label);
tab_translate_options_button->SetRequestFocusOnPress(true);
tab_translate_options_button->SetVisible(true);
tab_translate_options_button->SetID(BUTTON_ID_OPTIONS_MENU);
return tab_translate_options_button;
}
std::unique_ptr<views::Button> TranslateBubbleView::CreateCloseButton() {
auto close_button =
views::BubbleFrameView::CreateCloseButton(base::BindRepeating(
[](View* view) {
view->GetWidget()->CloseWithReason(
views::Widget::ClosedReason::kCloseButtonClicked);
},
base::Unretained(this)));
close_button->SetProperty(views::kElementIdentifierKey, kCloseButton);
close_button->SetVisible(true);
close_button->SetID(BUTTON_ID_CLOSE);
return close_button;
}
views::Checkbox* TranslateBubbleView::GetAlwaysTranslateCheckbox() {
const TranslateBubbleModel::ViewState state = GetViewState();
if (state == TranslateBubbleModel::VIEW_STATE_SOURCE_LANGUAGE ||
state == TranslateBubbleModel::VIEW_STATE_TARGET_LANGUAGE) {
return advanced_always_translate_checkbox_;
}
CHECK(state == TranslateBubbleModel::VIEW_STATE_BEFORE_TRANSLATE ||
state == TranslateBubbleModel::VIEW_STATE_TRANSLATING ||
state == TranslateBubbleModel::VIEW_STATE_AFTER_TRANSLATE);
return always_translate_checkbox_;
}
void TranslateBubbleView::SetWindowTitle(
TranslateBubbleModel::ViewState view_state) {
switch (view_state) {
case TranslateBubbleModel::VIEW_STATE_BEFORE_TRANSLATE:
SetTitle(IDS_TRANSLATE_BUBBLE_BEFORE_TRANSLATE_TITLE);
break;
case TranslateBubbleModel::VIEW_STATE_TRANSLATING:
SetTitle(IDS_TRANSLATE_BUBBLE_TRANSLATING);
break;
case TranslateBubbleModel::VIEW_STATE_AFTER_TRANSLATE:
SetTitle(IDS_TRANSLATE_BUBBLE_TRANSLATED_TITLE);
break;
case TranslateBubbleModel::VIEW_STATE_ERROR:
SetTitle(IDS_TRANSLATE_BUBBLE_COULD_NOT_TRANSLATE_TITLE);
break;
case TranslateBubbleModel::VIEW_STATE_SOURCE_LANGUAGE:
SetTitle(IDS_TRANSLATE_BUBBLE_ADVANCED_SOURCE);
break;
case TranslateBubbleModel::VIEW_STATE_TARGET_LANGUAGE:
SetTitle(IDS_TRANSLATE_BUBBLE_ADVANCED_TARGET);
break;
}
}
void TranslateBubbleView::UpdateViewState(
TranslateBubbleModel::ViewState view_state) {
model_->SetViewState(view_state);
SetWindowTitle(view_state);
}
void TranslateBubbleView::SwitchView(
TranslateBubbleModel::ViewState view_state) {
UpdateInsets(view_state);
if (view_state == TranslateBubbleModel::VIEW_STATE_SOURCE_LANGUAGE ||
view_state == TranslateBubbleModel::VIEW_STATE_TARGET_LANGUAGE) {
GetBubbleFrameView()->SetFootnoteView(nullptr);
} else {
GetBubbleFrameView()->SetFootnoteView(CreateWordmarkView());
}
SwitchTabForViewState(view_state);
UpdateViewState(view_state);
if (view_state == TranslateBubbleModel::VIEW_STATE_SOURCE_LANGUAGE ||
view_state == TranslateBubbleModel::VIEW_STATE_TARGET_LANGUAGE) {
UpdateAdvancedView();
}
UpdateChildVisibilities();
if (view_state == TranslateBubbleModel::VIEW_STATE_AFTER_TRANSLATE) {
AnnounceTextToScreenReader(l10n_util::GetStringFUTF16(
IDS_TRANSLATE_BUBBLE_TRANSLATION_COMPLETE_ANNOUNCEMENT,
model_->GetTargetLanguageNameAt(model_->GetTargetLanguageIndex())));
} else if (view_state == TranslateBubbleModel::VIEW_STATE_ERROR) {
AnnounceTextToScreenReader(l10n_util::GetStringUTF16(
IDS_TRANSLATE_BUBBLE_COULD_NOT_TRANSLATE_TITLE));
}
}
void TranslateBubbleView::AnnounceTextToScreenReader(
const std::u16string& announcement_text) {
GetViewAccessibility().AnnounceText(announcement_text);
}
void TranslateBubbleView::SwitchTabForViewState(
TranslateBubbleModel::ViewState view_state) {
if ((view_state == TranslateBubbleModel::VIEW_STATE_AFTER_TRANSLATE ||
view_state == TranslateBubbleModel::VIEW_STATE_TRANSLATING) &&
tabbed_pane_->GetSelectedTabIndex() != 1) {
// When switching to "after" or "during" translate view from something
// other than user interaction, |this| needs to unregister from listening
// to the tabbed pane events otherwise it'll trigger an additional
// translation as if the user had clicked the tabs.
tabbed_pane_->SetListener(nullptr);
tabbed_pane_->SelectTabAt(1, false);
tabbed_pane_->SetListener(this);
} else if (view_state == TranslateBubbleModel::VIEW_STATE_BEFORE_TRANSLATE &&
tabbed_pane_->GetSelectedTabIndex() != 0) {
tabbed_pane_->SelectTabAt(0);
}
}
void TranslateBubbleView::SwitchToErrorView(
translate::TranslateErrors error_type) {
SwitchView(TranslateBubbleModel::VIEW_STATE_ERROR);
error_type_ = error_type;
model_->ShowError(error_type);
}
void TranslateBubbleView::UpdateAdvancedView() {
if (advanced_done_button_source_) {
advanced_done_button_source_->SetText(
l10n_util::GetStringUTF16(model_->IsPageTranslatedInCurrentLanguages()
? IDS_DONE
: IDS_TRANSLATE_BUBBLE_ACCEPT));
advanced_reset_button_source_->SetEnabled(DidLanguageSelectionChange(
TranslateBubbleModel::VIEW_STATE_SOURCE_LANGUAGE));
}
if (advanced_done_button_target_) {
advanced_done_button_target_->SetText(
l10n_util::GetStringUTF16(model_->IsPageTranslatedInCurrentLanguages()
? IDS_DONE
: IDS_TRANSLATE_BUBBLE_ACCEPT));
advanced_reset_button_target_->SetEnabled(DidLanguageSelectionChange(
TranslateBubbleModel::VIEW_STATE_TARGET_LANGUAGE));
}
DeprecatedLayoutImmediately();
}
void TranslateBubbleView::UpdateLanguageNames(
std::u16string* source_language_name,
std::u16string* target_language_name) {
DCHECK(source_language_name && target_language_name);
previous_source_language_index_ = model_->GetSourceLanguageIndex();
*source_language_name =
model_->GetSourceLanguageNameAt(previous_source_language_index_);
previous_target_language_index_ = model_->GetTargetLanguageIndex();
*target_language_name =
model_->GetTargetLanguageNameAt(previous_target_language_index_);
}
void TranslateBubbleView::UpdateInsets(TranslateBubbleModel::ViewState state) {
ChromeLayoutProvider* provider = ChromeLayoutProvider::Get();
const int horizontal_spacing =
provider->GetDistanceMetric(views::DISTANCE_RELATED_CONTROL_HORIZONTAL);
gfx::Insets kTabStateMargins =
gfx::Insets::TLBR(7, horizontal_spacing, 8, horizontal_spacing);
gfx::Insets kDialogStateMargins =
gfx::Insets::TLBR(2, horizontal_spacing, 16, horizontal_spacing);
if (state == TranslateBubbleModel::VIEW_STATE_BEFORE_TRANSLATE ||
state == TranslateBubbleModel::VIEW_STATE_TRANSLATING ||
state == TranslateBubbleModel::VIEW_STATE_AFTER_TRANSLATE) {
set_margins(kTabStateMargins);
} else {
set_margins(kDialogStateMargins);
}
}
void TranslateBubbleView::RevertOrDeclineTranslation() {
if (model_->IsPageTranslatedInCurrentLanguages()) {
model_->RevertTranslation();
} else {
model_->DeclineTranslation();
}
GetWidget()->Close();
}
BEGIN_METADATA(TranslateBubbleView)
END_METADATA