diff options
Diffstat (limited to 'chrome/browser/gtk/translate_infobars.cc')
-rw-r--r-- | chrome/browser/gtk/translate_infobars.cc | 370 |
1 files changed, 370 insertions, 0 deletions
diff --git a/chrome/browser/gtk/translate_infobars.cc b/chrome/browser/gtk/translate_infobars.cc new file mode 100644 index 0000000..63ea67d --- /dev/null +++ b/chrome/browser/gtk/translate_infobars.cc @@ -0,0 +1,370 @@ +// Copyright (c) 2010 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 "chrome/browser/gtk/translate_infobars.h" + +#include "app/l10n_util.h" +#include "chrome/app/chrome_dll_resource.h" +#include "chrome/browser/gtk/gtk_util.h" +#include "chrome/browser/gtk/menu_gtk.h" +#include "chrome/browser/tab_contents/tab_contents.h" +#include "chrome/browser/translate/translate_infobars_delegates.h" +#include "chrome/browser/translate/options_menu_model.h" +#include "chrome/common/notification_service.h" +#include "grit/app_resources.h" +#include "grit/generated_resources.h" +#include "grit/locale_settings.h" +#include "grit/theme_resources.h" + +namespace { + +// Reorders the widgets in the NULL terminated array |widgets| that are all +// children of |box|. +void ReorderWidgetsTo(GtkWidget* box, GtkWidget** widgets) { + for (int count = 0; *widgets != NULL; widgets++) { + gtk_box_reorder_child(GTK_BOX(box), *widgets, count++); + gtk_widget_show_all(*widgets); + } +} + +// Creates a combobox set up to display text from a list of language codes +// (translating the codes into the display string). +GtkWidget* BuildLanguageComboboxFrom( + const std::vector<std::string>& languages) { + GtkListStore* model = gtk_list_store_new(1, G_TYPE_STRING); + for (std::vector<std::string>::const_iterator iter = languages.begin(); + iter != languages.end(); ++iter) { + GtkTreeIter tree_iter; + std::string name = UTF16ToUTF8( + TranslateInfoBarDelegate::GetDisplayNameForLocale(*iter)); + gtk_list_store_append(model, &tree_iter); + gtk_list_store_set(model, &tree_iter, 0, name.c_str(), -1); + } + + GtkWidget* combobox = gtk_combo_box_new_with_model(GTK_TREE_MODEL(model)); + g_object_unref(model); + GtkCellRenderer* renderer = gtk_cell_renderer_text_new(); + gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(combobox), renderer, TRUE); + gtk_cell_layout_set_attributes( + GTK_CELL_LAYOUT(combobox), renderer, "text", 0, NULL); + + return combobox; +} + +// Builds a button with an arrow in it to emulate the menu-button style from +// the windows version. +GtkWidget* BuildOptionsMenuButton() { + GtkWidget* button = gtk_button_new(); + GtkWidget* former_child = gtk_bin_get_child(GTK_BIN(button)); + if (former_child) + gtk_container_remove(GTK_CONTAINER(button), former_child); + + GtkWidget* hbox = gtk_hbox_new(FALSE, 0); + + GtkWidget* label = gtk_label_new( + l10n_util::GetStringUTF8(IDS_TRANSLATE_INFOBAR_OPTIONS).c_str()); + gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0); + + GtkWidget* arrow = gtk_arrow_new(GTK_ARROW_DOWN, GTK_SHADOW_NONE); + gtk_box_pack_start(GTK_BOX(hbox), arrow, FALSE, FALSE, 0); + + gtk_container_add(GTK_CONTAINER(button), hbox); + + return button; +} + +} // namespace + +TranslateInfoBar::TranslateInfoBar(TranslateInfoBarDelegate* delegate) + : InfoBar(delegate), + swapped_language_placeholders_(false) { + BuildWidgets(); + + // Register for PAGE_TRANSLATED notification. + notification_registrar_.Add(this, NotificationType::PAGE_TRANSLATED, + Source<TabContents>(GetDelegate()->tab_contents())); +} + +TranslateInfoBar::~TranslateInfoBar() { +} + +void TranslateInfoBar::Observe(NotificationType type, + const NotificationSource& source, const NotificationDetails& details) { + if (type.value == NotificationType::PAGE_TRANSLATED) { + TabContents* tab = Source<TabContents>(source).ptr(); + if (tab != GetDelegate()->tab_contents()) + return; + + UpdateState(TranslateInfoBarDelegate::kAfterTranslate); + } else { + InfoBar::Observe(type, source, details); + } +} + +bool TranslateInfoBar::IsCommandIdChecked(int command_id) const { + TranslateInfoBarDelegate* translate_delegate = GetDelegate(); + switch (command_id) { + case IDC_TRANSLATE_OPTIONS_NEVER_TRANSLATE_LANG : + return translate_delegate->IsLanguageBlacklisted(); + + case IDC_TRANSLATE_OPTIONS_NEVER_TRANSLATE_SITE : + return translate_delegate->IsSiteBlacklisted(); + + case IDC_TRANSLATE_OPTIONS_ALWAYS : + return translate_delegate->ShouldAlwaysTranslate(); + + default: + NOTREACHED() << "Invalid command_id from menu"; + break; + } + return false; +} + +bool TranslateInfoBar::IsCommandIdEnabled(int command_id) const { + return true; +} + +bool TranslateInfoBar::GetAcceleratorForCommandId(int command_id, + menus::Accelerator* accelerator) { + return false; +} + +void TranslateInfoBar::ExecuteCommand(int command_id) { + switch (command_id) { + case IDC_TRANSLATE_OPTIONS_NEVER_TRANSLATE_LANG: + GetDelegate()->ToggleLanguageBlacklist(); + break; + + case IDC_TRANSLATE_OPTIONS_NEVER_TRANSLATE_SITE: + GetDelegate()->ToggleSiteBlacklist(); + break; + + case IDC_TRANSLATE_OPTIONS_ALWAYS: + GetDelegate()->ToggleAlwaysTranslate(); + break; + + case IDC_TRANSLATE_OPTIONS_ABOUT: { + TabContents* tab_contents = GetDelegate()->tab_contents(); + if (tab_contents) { + string16 url = l10n_util::GetStringUTF16( + IDS_ABOUT_GOOGLE_TRANSLATE_URL); + tab_contents->OpenURL(GURL(url), GURL(), NEW_FOREGROUND_TAB, + PageTransition::LINK); + } + break; + } + + default: + NOTREACHED() << "Invalid command id from menu."; + break; + } +} + +void TranslateInfoBar::BuildWidgets() { + translate_box_ = gtk_hbox_new(FALSE, gtk_util::kControlSpacing); + gtk_widget_set_no_show_all(translate_box_, TRUE); + + // Add all labels to the translate_box_. Unlike views or cocoa, there's no + // concept of manual layout in GTK, so we'll manually reorder these widgets + // inside |translate_box_| and selectively show and hide them. + label_1_ = gtk_label_new(NULL); + gtk_box_pack_start(GTK_BOX(translate_box_), label_1_, FALSE, FALSE, 0); + + label_2_ = gtk_label_new(NULL); + gtk_box_pack_start(GTK_BOX(translate_box_), label_2_, FALSE, FALSE, 0); + + label_3_ = gtk_label_new(NULL); + gtk_box_pack_start(GTK_BOX(translate_box_), label_3_, FALSE, FALSE, 0); + + translating_label_ = gtk_label_new( + l10n_util::GetStringUTF8(IDS_TRANSLATE_INFOBAR_TRANSLATING).c_str()); + gtk_box_pack_start(GTK_BOX(translate_box_), translating_label_, + FALSE, FALSE, 0); + + accept_button_ = gtk_button_new_with_label( + l10n_util::GetStringUTF8(IDS_TRANSLATE_INFOBAR_ACCEPT).c_str()); + g_signal_connect(accept_button_, "clicked", + G_CALLBACK(&OnAcceptPressedThunk), this); + accept_button_vbox_ = gtk_util::CenterWidgetInHBox( + translate_box_, accept_button_, false, 0); + + deny_button_ = gtk_button_new_with_label( + l10n_util::GetStringUTF8(IDS_TRANSLATE_INFOBAR_DENY).c_str()); + g_signal_connect(deny_button_, "clicked", + G_CALLBACK(&OnDenyPressedThunk), this); + deny_button_vbox_ = gtk_util::CenterWidgetInHBox( + translate_box_, deny_button_, false, 0); + + std::vector<std::string> orig_languages; + GetDelegate()->GetAvailableOriginalLanguages(&orig_languages); + original_language_combobox_ = BuildLanguageComboboxFrom(orig_languages); + g_signal_connect(original_language_combobox_, "changed", + G_CALLBACK(&OnOriginalModifiedThunk), this); + original_language_combobox_vbox_ = gtk_util::CenterWidgetInHBox( + translate_box_, original_language_combobox_, false, 0); + + std::vector<std::string> target_languages; + GetDelegate()->GetAvailableTargetLanguages(&target_languages); + target_language_combobox_ = BuildLanguageComboboxFrom(target_languages); + g_signal_connect(target_language_combobox_, "changed", + G_CALLBACK(&OnTargetModifiedThunk), this); + target_language_combobox_vbox_ = gtk_util::CenterWidgetInHBox( + translate_box_, target_language_combobox_, false, 0); + + gtk_box_pack_start(GTK_BOX(hbox_), translate_box_, FALSE, FALSE, 0); + + // The options button sits outside the translate_box so that it can be end + // packed in hbox_. + options_menu_button_ = BuildOptionsMenuButton(); + g_signal_connect(options_menu_button_, "clicked", + G_CALLBACK(&OnOptionsClickedThunk), this); + gtk_widget_show_all(options_menu_button_); + gtk_util::CenterWidgetInHBox( + hbox_, options_menu_button_, true, 0); + + UpdateState(GetDelegate()->state()); + + gtk_widget_show_all(border_bin_.get()); +} + +void TranslateInfoBar::UpdateState( + TranslateInfoBarDelegate::TranslateState new_state) { + // Show the box... + gtk_widget_show(translate_box_); + // ...but hide all children of the translate box. They will be selectively + // unhidden and reordered based on the current translate state. + gtk_container_foreach( + GTK_CONTAINER(translate_box_), + reinterpret_cast<void (*)(GtkWidget*, void*)>(gtk_widget_hide_all), NULL); + + switch (new_state) { + case TranslateInfoBarDelegate::kBeforeTranslate: { + SetLabels(); + + GtkWidget* before_state[] = { + label_1_, + original_language_combobox_vbox_, + label_2_, + accept_button_vbox_, + deny_button_vbox_, + NULL + }; + ReorderWidgetsTo(translate_box_, before_state); + + gtk_combo_box_set_active(GTK_COMBO_BOX(original_language_combobox_), + GetDelegate()->original_lang_index()); + break; + } + case TranslateInfoBarDelegate::kTranslating: { + gtk_widget_show(translating_label_); + break; + } + case TranslateInfoBarDelegate::kAfterTranslate: { + SetLabels(); + GtkWidget* first_button_box = + swapped_language_placeholders_ ? + target_language_combobox_vbox_ : original_language_combobox_vbox_; + GtkWidget* second_button_box = + swapped_language_placeholders_ ? + original_language_combobox_vbox_ : target_language_combobox_vbox_; + + GtkWidget* after_state[] = { + label_1_, + first_button_box, + label_2_, + second_button_box, + label_3_, + NULL + }; + ReorderWidgetsTo(translate_box_, after_state); + + gtk_combo_box_set_active(GTK_COMBO_BOX(original_language_combobox_), + GetDelegate()->original_lang_index()); + gtk_combo_box_set_active(GTK_COMBO_BOX(target_language_combobox_), + GetDelegate()->target_lang_index()); + break; + } + default: { + NOTIMPLEMENTED() << "Received state " << new_state; + } + } + + // Clear options menu model so that it'll be created for new state. + options_menu_model_.reset(); +} + +void TranslateInfoBar::SetLabels() { + std::vector<size_t> offsets; + string16 message_text_utf16; + GetDelegate()->GetMessageText(&message_text_utf16, &offsets, + &swapped_language_placeholders_); + + string16 text = message_text_utf16.substr(0, offsets[0]); + gtk_label_set_text(GTK_LABEL(label_1_), UTF16ToUTF8(text).c_str()); + + text = message_text_utf16.substr(offsets[0], offsets[1] - offsets[0]); + gtk_label_set_text(GTK_LABEL(label_2_), UTF16ToUTF8(text).c_str()); + + if (offsets.size() == 3) { + text = message_text_utf16.substr(offsets[1], offsets[2] - offsets[1]); + gtk_label_set_text(GTK_LABEL(label_3_), UTF16ToUTF8(text).c_str()); + } +} + +TranslateInfoBarDelegate* TranslateInfoBar::GetDelegate() const { + return static_cast<TranslateInfoBarDelegate*>(delegate()); +} + +void TranslateInfoBar::LanguageModified() { + options_menu_model_.reset(); + + // Selecting an item from the "from language" menu in the before translate + // phase shouldn't trigger translation - http://crbug.com/36666 + if (GetDelegate()->state() == TranslateInfoBarDelegate::kAfterTranslate) + GetDelegate()->Translate(); +} + +void TranslateInfoBar::OnOriginalModified(GtkWidget* sender) { + int index = gtk_combo_box_get_active(GTK_COMBO_BOX(sender)); + if (index == GetDelegate()->original_lang_index()) + return; + + GetDelegate()->ModifyOriginalLanguage(index); + + LanguageModified(); +} + +void TranslateInfoBar::OnTargetModified(GtkWidget* sender) { + int index = gtk_combo_box_get_active(GTK_COMBO_BOX(sender)); + if (index == GetDelegate()->target_lang_index()) + return; + + GetDelegate()->ModifyTargetLanguage(index); + + LanguageModified(); +} + +void TranslateInfoBar::OnAcceptPressed(GtkWidget* sender) { + GetDelegate()->Translate(); + UpdateState(GetDelegate()->state()); +} + +void TranslateInfoBar::OnDenyPressed(GtkWidget* sender) { + GetDelegate()->TranslationDeclined(); + RemoveInfoBar(); +} + +void TranslateInfoBar::OnOptionsClicked(GtkWidget* sender) { + if (!options_menu_model_.get()) { + options_menu_model_.reset(new OptionsMenuModel(this, GetDelegate())); + options_menu_menu_.reset(new MenuGtk(this, options_menu_model_.get())); + } + options_menu_menu_->Popup(sender, 1, gtk_get_current_event_time()); +} + +// TranslateInfoBarDelegate, InfoBarDelegate overrides: ------------------ + +InfoBar* TranslateInfoBarDelegate::CreateInfoBar() { + return new TranslateInfoBar(this); +} |