1// Copyright (c) 2011 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "chrome/browser/ui/gtk/infobars/translate_infobar_base_gtk.h"
6
7#include "base/utf_string_conversions.h"
8#include "chrome/browser/translate/options_menu_model.h"
9#include "chrome/browser/translate/translate_infobar_delegate.h"
10#include "chrome/browser/ui/gtk/gtk_util.h"
11#include "chrome/browser/ui/gtk/infobars/after_translate_infobar_gtk.h"
12#include "chrome/browser/ui/gtk/infobars/before_translate_infobar_gtk.h"
13#include "chrome/browser/ui/gtk/infobars/translate_message_infobar_gtk.h"
14#include "chrome/browser/ui/gtk/menu_gtk.h"
15#include "grit/generated_resources.h"
16#include "ui/base/animation/slide_animation.h"
17#include "ui/base/l10n/l10n_util.h"
18#include "ui/gfx/canvas.h"
19
20namespace {
21
22// To be able to map from language id <-> entry in the combo box, we
23// store the language id in the combo box data model in addition to the
24// displayed name.
25enum {
26  LANGUAGE_COMBO_COLUMN_ID,
27  LANGUAGE_COMBO_COLUMN_NAME,
28  LANGUAGE_COMBO_COLUMN_COUNT
29};
30
31}  // namespace
32
33TranslateInfoBarBase::TranslateInfoBarBase(TranslateInfoBarDelegate* delegate)
34    : InfoBar(delegate) {
35  TranslateInfoBarDelegate::BackgroundAnimationType animation =
36      delegate->background_animation_type();
37  if (animation != TranslateInfoBarDelegate::NONE) {
38    background_color_animation_.reset(new ui::SlideAnimation(this));
39    background_color_animation_->SetTweenType(ui::Tween::LINEAR);
40    background_color_animation_->SetSlideDuration(500);
41    if (animation == TranslateInfoBarDelegate::NORMAL_TO_ERROR) {
42      background_color_animation_->Show();
43    } else {
44      DCHECK_EQ(TranslateInfoBarDelegate::ERROR_TO_NORMAL, animation);
45      // Hide() runs the animation in reverse.
46      background_color_animation_->Reset(1.0);
47      background_color_animation_->Hide();
48    }
49  } else {
50    background_error_percent_ = delegate->IsError() ? 1 : 0;
51  }
52}
53
54TranslateInfoBarBase::~TranslateInfoBarBase() {
55}
56
57void TranslateInfoBarBase::Init() {
58  if (!ShowOptionsMenuButton())
59    return;
60
61  // The options button sits outside the translate_box so that it can be end
62  // packed in hbox_.
63  GtkWidget* options_menu_button = BuildOptionsMenuButton();
64  g_signal_connect(options_menu_button, "clicked",
65                   G_CALLBACK(&OnOptionsClickedThunk), this);
66  gtk_widget_show_all(options_menu_button);
67  gtk_util::CenterWidgetInHBox(hbox_, options_menu_button, true, 0);
68}
69
70void TranslateInfoBarBase::GetTopColor(InfoBarDelegate::Type type,
71                                       double* r, double* g, double *b) {
72  if (background_error_percent_ <= 0) {
73    InfoBar::GetTopColor(InfoBarDelegate::PAGE_ACTION_TYPE, r, g, b);
74  } else if (background_error_percent_ >= 1) {
75    InfoBar::GetTopColor(InfoBarDelegate::WARNING_TYPE, r, g, b);
76  } else {
77    double normal_r, normal_g, normal_b;
78    InfoBar::GetTopColor(InfoBarDelegate::PAGE_ACTION_TYPE,
79                         &normal_r, &normal_g, &normal_b);
80
81    double error_r, error_g, error_b;
82    InfoBar::GetTopColor(InfoBarDelegate::WARNING_TYPE,
83                         &error_r, &error_g, &error_b);
84
85    double offset_r = error_r - normal_r;
86    double offset_g = error_g - normal_g;
87    double offset_b = error_b - normal_b;
88
89    *r = normal_r + (background_error_percent_ * offset_r);
90    *g = normal_g + (background_error_percent_ * offset_g);
91    *b = normal_b + (background_error_percent_ * offset_b);
92  }
93}
94
95void TranslateInfoBarBase::GetBottomColor(InfoBarDelegate::Type type,
96                                          double* r, double* g, double *b) {
97  if (background_error_percent_ <= 0) {
98    InfoBar::GetBottomColor(InfoBarDelegate::PAGE_ACTION_TYPE, r, g, b);
99  } else if (background_error_percent_ >= 1) {
100    InfoBar::GetBottomColor(InfoBarDelegate::WARNING_TYPE, r, g, b);
101  } else {
102    double normal_r, normal_g, normal_b;
103    InfoBar::GetBottomColor(InfoBarDelegate::PAGE_ACTION_TYPE,
104                            &normal_r, &normal_g, &normal_b);
105
106    double error_r, error_g, error_b;
107    InfoBar::GetBottomColor(InfoBarDelegate::WARNING_TYPE,
108                            &error_r, &error_g, &error_b);
109
110    double offset_r = error_r - normal_r;
111    double offset_g = error_g - normal_g;
112    double offset_b = error_b - normal_b;
113
114    *r = normal_r + (background_error_percent_ * offset_r);
115    *g = normal_g + (background_error_percent_ * offset_g);
116    *b = normal_b + (background_error_percent_ * offset_b);
117  }
118}
119
120void TranslateInfoBarBase::AnimationProgressed(const ui::Animation* animation) {
121  DCHECK(animation == background_color_animation_.get());
122  background_error_percent_ = animation->GetCurrentValue();
123  // Queue the info bar widget for redisplay so it repaints its background.
124  gtk_widget_queue_draw(widget());
125}
126
127bool TranslateInfoBarBase::ShowOptionsMenuButton() const {
128  return false;
129}
130
131GtkWidget* TranslateInfoBarBase::CreateLabel(const std::string& text) {
132  GtkWidget* label = gtk_label_new(text.c_str());
133  gtk_widget_modify_fg(label, GTK_STATE_NORMAL, &gtk_util::kGdkBlack);
134  return label;
135}
136
137GtkWidget* TranslateInfoBarBase::CreateLanguageCombobox(
138    size_t selected_language,
139    size_t exclude_language) {
140  GtkListStore* model = gtk_list_store_new(LANGUAGE_COMBO_COLUMN_COUNT,
141                                           G_TYPE_INT, G_TYPE_STRING);
142  bool set_selection = false;
143  GtkTreeIter selected_iter;
144  TranslateInfoBarDelegate* delegate = GetDelegate();
145  for (size_t i = 0; i < delegate->GetLanguageCount(); ++i) {
146    if (i == exclude_language)
147      continue;
148    GtkTreeIter tree_iter;
149    const string16& name = delegate->GetLanguageDisplayableNameAt(i);
150
151    gtk_list_store_append(model, &tree_iter);
152    gtk_list_store_set(model, &tree_iter,
153                       LANGUAGE_COMBO_COLUMN_ID, i,
154                       LANGUAGE_COMBO_COLUMN_NAME, UTF16ToUTF8(name).c_str(),
155                       -1);
156    if (i == selected_language) {
157      selected_iter = tree_iter;
158      set_selection = true;
159    }
160  }
161
162  GtkWidget* combobox = gtk_combo_box_new_with_model(GTK_TREE_MODEL(model));
163  if (set_selection)
164    gtk_combo_box_set_active_iter(GTK_COMBO_BOX(combobox), &selected_iter);
165  g_object_unref(model);
166  GtkCellRenderer* renderer = gtk_cell_renderer_text_new();
167  gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(combobox), renderer, TRUE);
168  gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(combobox), renderer,
169                                 "text", LANGUAGE_COMBO_COLUMN_NAME,
170                                 NULL);
171  return combobox;
172}
173
174// static
175size_t TranslateInfoBarBase::GetLanguageComboboxActiveId(GtkComboBox* combo) {
176  GtkTreeIter iter;
177  if (!gtk_combo_box_get_active_iter(combo, &iter))
178    return 0;
179
180  gint id = 0;
181  gtk_tree_model_get(gtk_combo_box_get_model(combo), &iter,
182                     LANGUAGE_COMBO_COLUMN_ID, &id,
183                     -1);
184  return static_cast<size_t>(id);
185}
186
187TranslateInfoBarDelegate* TranslateInfoBarBase::GetDelegate() const {
188  return static_cast<TranslateInfoBarDelegate*>(delegate());
189}
190
191// static
192GtkWidget* TranslateInfoBarBase::BuildOptionsMenuButton() {
193  GtkWidget* button = gtk_button_new();
194  GtkWidget* former_child = gtk_bin_get_child(GTK_BIN(button));
195  if (former_child)
196    gtk_container_remove(GTK_CONTAINER(button), former_child);
197
198  GtkWidget* hbox = gtk_hbox_new(FALSE, 0);
199
200  GtkWidget* label = gtk_label_new(
201      l10n_util::GetStringUTF8(IDS_TRANSLATE_INFOBAR_OPTIONS).c_str());
202  gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
203
204  GtkWidget* arrow = gtk_arrow_new(GTK_ARROW_DOWN, GTK_SHADOW_NONE);
205  gtk_box_pack_start(GTK_BOX(hbox), arrow, FALSE, FALSE, 0);
206
207  gtk_container_add(GTK_CONTAINER(button), hbox);
208
209  return button;
210}
211
212void TranslateInfoBarBase::OnOptionsClicked(GtkWidget* sender) {
213  if (!options_menu_model_.get()) {
214    options_menu_model_.reset(new OptionsMenuModel(GetDelegate()));
215    options_menu_menu_.reset(new MenuGtk(NULL, options_menu_model_.get()));
216  }
217  options_menu_menu_->PopupForWidget(sender, 1, gtk_get_current_event_time());
218}
219
220// TranslateInfoBarDelegate specific method:
221InfoBar* TranslateInfoBarDelegate::CreateInfoBar() {
222  TranslateInfoBarBase* infobar = NULL;
223  switch (type_) {
224    case BEFORE_TRANSLATE:
225      infobar = new BeforeTranslateInfoBar(this);
226      break;
227    case AFTER_TRANSLATE:
228      infobar = new AfterTranslateInfoBar(this);
229      break;
230    case TRANSLATING:
231    case TRANSLATION_ERROR:
232      infobar = new TranslateMessageInfoBar(this);
233      break;
234    default:
235      NOTREACHED();
236  }
237  infobar->Init();
238  return infobar;
239}
240