translate_bubble_view.cc revision 8bcbed890bc3ce4d7a057a8f32cab53fa534672e
1// Copyright 2013 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/views/translate/translate_bubble_view.h"
6
7#include <algorithm>
8#include <string>
9#include <vector>
10
11#include "base/i18n/string_compare.h"
12#include "base/memory/singleton.h"
13#include "base/metrics/histogram.h"
14#include "base/prefs/pref_service.h"
15#include "base/strings/utf_string_conversions.h"
16#include "chrome/browser/browser_process.h"
17#include "chrome/browser/profiles/profile.h"
18#include "chrome/browser/translate/translate_manager.h"
19#include "chrome/browser/translate/translate_tab_helper.h"
20#include "chrome/browser/translate/translate_ui_delegate.h"
21#include "chrome/browser/ui/browser.h"
22#include "chrome/browser/ui/translate/translate_bubble_model_impl.h"
23#include "chrome/common/url_constants.h"
24#include "content/public/browser/web_contents.h"
25#include "grit/generated_resources.h"
26#include "ui/base/l10n/l10n_util.h"
27#include "ui/base/models/combobox_model.h"
28#include "ui/base/resource/resource_bundle.h"
29#include "ui/views/controls/button/checkbox.h"
30#include "ui/views/controls/button/label_button.h"
31#include "ui/views/controls/combobox/combobox.h"
32#include "ui/views/controls/label.h"
33#include "ui/views/controls/link.h"
34#include "ui/views/layout/box_layout.h"
35#include "ui/views/layout/grid_layout.h"
36#include "ui/views/layout/layout_constants.h"
37#include "ui/views/widget/widget.h"
38
39namespace {
40
41views::LabelButton* CreateLabelButton(views::ButtonListener* listener,
42                                      const string16& label, int id) {
43  views::LabelButton* button = new views::LabelButton(listener, label);
44  button->set_id(id);
45  button->SetStyle(views::Button::STYLE_NATIVE_TEXTBUTTON);
46  return button;
47}
48
49views::Link* CreateLink(views::LinkListener* listener,
50                        int resource_id,
51                        int id) {
52  views::Link* link = new views::Link(
53      l10n_util::GetStringUTF16(resource_id));
54  link->set_listener(listener);
55  link->set_id(id);
56  return link;
57}
58
59void GetTranslateLanguages(content::WebContents* web_contents,
60                           std::string* source,
61                           std::string* target) {
62  DCHECK(source != NULL);
63  DCHECK(target != NULL);
64
65  TranslateTabHelper* translate_tab_helper =
66      TranslateTabHelper::FromWebContents(web_contents);
67  *source = translate_tab_helper->language_state().original_language();
68  *target = TranslateManager::GetLanguageCode(
69      g_browser_process->GetApplicationLocale());
70}
71
72// TODO(hajimehoshi): The interface to offer denial choices should be another
73// control instead of Combobox. See crbug/305494.
74class TranslateDenialComboboxModel : public ui::ComboboxModel {
75 public:
76  enum {
77    INDEX_NOPE = 0,
78    INDEX_NEVER_TRANSLATE_LANGUAGE = 2,
79    INDEX_NEVER_TRANSLATE_SITE = 4,
80  };
81
82  explicit TranslateDenialComboboxModel(
83      const string16& original_language_name) {
84    items_.push_back(l10n_util::GetStringUTF16(IDS_TRANSLATE_BUBBLE_DENY));
85    items_.push_back(string16());
86    items_.push_back(l10n_util::GetStringFUTF16(
87        IDS_TRANSLATE_BUBBLE_NEVER_TRANSLATE_LANG,
88        original_language_name));
89    items_.push_back(string16());
90    items_.push_back(l10n_util::GetStringUTF16(
91        IDS_TRANSLATE_BUBBLE_NEVER_TRANSLATE_SITE));
92  }
93  virtual ~TranslateDenialComboboxModel() {}
94
95 private:
96  // Overridden from ui::ComboboxModel:
97  virtual int GetItemCount() const OVERRIDE {
98    return items_.size();
99  }
100  virtual string16 GetItemAt(int index) OVERRIDE {
101    return items_[index];
102  }
103  virtual bool IsItemSeparatorAt(int index) OVERRIDE {
104    return items_[index].empty();
105  }
106  virtual int GetDefaultIndex() const OVERRIDE {
107    return 0;
108  }
109
110  std::vector<string16> items_;
111
112  DISALLOW_COPY_AND_ASSIGN(TranslateDenialComboboxModel);
113};
114
115const char* kUMATranslateModifyOriginalLang = "Translate.ModifyOriginalLang";
116const char* kUMATranslateModifyTargetLang = "Translate.ModifyTargetLang";
117
118}  // namespace
119
120// static
121TranslateBubbleView* TranslateBubbleView::translate_bubble_view_ = NULL;
122
123TranslateBubbleView::~TranslateBubbleView() {
124  // A child view could refer to a model which is owned by this class when
125  // the child view is destructed. For example, |source_language_combobx_model_|
126  // is referred by Combobox's destructor. Before destroying the models,
127  // removing the child views is needed.
128  RemoveAllChildViews(true);
129}
130
131// static
132void TranslateBubbleView::ShowBubble(views::View* anchor_view,
133                                     content::WebContents* web_contents,
134                                     TranslateBubbleModel::ViewState type,
135                                     Browser* browser) {
136  if (IsShowing()) {
137    translate_bubble_view_->SwitchView(type);
138    return;
139  }
140
141  std::string source_language;
142  std::string target_language;
143  GetTranslateLanguages(web_contents, &source_language, &target_language);
144
145  scoped_ptr<TranslateUIDelegate> ui_delegate(
146      new TranslateUIDelegate(web_contents, source_language, target_language));
147  scoped_ptr<TranslateBubbleModel> model(
148      new TranslateBubbleModelImpl(type, ui_delegate.Pass()));
149  bool is_in_incognito_window =
150      web_contents->GetBrowserContext()->IsOffTheRecord();
151  TranslateBubbleView* view = new TranslateBubbleView(anchor_view,
152                                                      model.Pass(),
153                                                      is_in_incognito_window,
154                                                      browser);
155  views::BubbleDelegateView::CreateBubble(view)->Show();
156}
157
158// static
159bool TranslateBubbleView::IsShowing() {
160  return translate_bubble_view_ != NULL;
161}
162
163void TranslateBubbleView::Init() {
164  SetLayoutManager(new views::BoxLayout(views::BoxLayout::kVertical,
165                                        0, 0, 0));
166
167  before_translate_view_ = CreateViewBeforeTranslate();
168  translating_view_ = CreateViewTranslating();
169  after_translate_view_ = CreateViewAfterTranslate();
170  error_view_ = CreateViewError();
171  advanced_view_ = CreateViewAdvanced();
172
173  AddChildView(before_translate_view_);
174  AddChildView(translating_view_);
175  AddChildView(after_translate_view_);
176  AddChildView(error_view_);
177  AddChildView(advanced_view_);
178
179  AddAccelerator(ui::Accelerator(ui::VKEY_RETURN, ui::EF_NONE));
180
181  UpdateChildVisibilities();
182}
183
184void TranslateBubbleView::ButtonPressed(views::Button* sender,
185                                        const ui::Event& event) {
186  HandleButtonPressed(static_cast<ButtonID>(sender->id()));
187}
188
189void TranslateBubbleView::WindowClosing() {
190  if (!translate_executed_)
191    model_->TranslationDeclined();
192
193  // We have to reset |translate_bubble_view_| here, not in our destructor,
194  // because we'll be destroyed asynchronously and the shown state will be
195  // checked before then.
196  DCHECK_EQ(translate_bubble_view_, this);
197  translate_bubble_view_ = NULL;
198}
199
200bool TranslateBubbleView::AcceleratorPressed(
201    const ui::Accelerator& accelerator) {
202  switch (model_->GetViewState()) {
203    case TranslateBubbleModel::VIEW_STATE_BEFORE_TRANSLATE: {
204      if (accelerator.key_code() == ui::VKEY_RETURN) {
205        HandleButtonPressed(BUTTON_ID_TRANSLATE);
206        return true;
207      }
208      break;
209    }
210    case TranslateBubbleModel::VIEW_STATE_TRANSLATING:
211      break;
212    case TranslateBubbleModel::VIEW_STATE_AFTER_TRANSLATE: {
213      if (accelerator.key_code() == ui::VKEY_RETURN) {
214        HandleButtonPressed(BUTTON_ID_SHOW_ORIGINAL);
215        return true;
216      }
217      break;
218    }
219    case TranslateBubbleModel::VIEW_STATE_ERROR:
220      break;
221    case TranslateBubbleModel::VIEW_STATE_ADVANCED: {
222      if (accelerator.key_code() == ui::VKEY_RETURN) {
223        HandleButtonPressed(BUTTON_ID_DONE);
224        return true;
225      }
226      break;
227    }
228  }
229  return BubbleDelegateView::AcceleratorPressed(accelerator);
230}
231
232gfx::Size TranslateBubbleView::GetPreferredSize() {
233  int width = 0;
234  for (int i = 0; i < child_count(); i++) {
235    views::View* child = child_at(i);
236    width = std::max(width, child->GetPreferredSize().width());
237  }
238  int height = GetCurrentView()->GetPreferredSize().height();
239  return gfx::Size(width, height);
240}
241
242void TranslateBubbleView::OnSelectedIndexChanged(views::Combobox* combobox) {
243  switch (static_cast<ComboboxID>(combobox->id())) {
244    case COMBOBOX_ID_DENIAL: {
245      int index = combobox->selected_index();
246      switch (index) {
247        case TranslateDenialComboboxModel::INDEX_NOPE:
248          if (!translate_executed_)
249            model_->TranslationDeclined();
250          StartFade(false);
251          break;
252        case TranslateDenialComboboxModel::INDEX_NEVER_TRANSLATE_LANGUAGE:
253          model_->SetNeverTranslateLanguage(true);
254          StartFade(false);
255          break;
256        case TranslateDenialComboboxModel::INDEX_NEVER_TRANSLATE_SITE:
257          model_->SetNeverTranslateSite(true);
258          StartFade(false);
259          break;
260        default:
261          NOTREACHED();
262          break;
263      }
264      break;
265    }
266    case COMBOBOX_ID_SOURCE_LANGUAGE: {
267      // TODO(hajimehoshi): This UMA should be counted at a model or a delegate
268      // not to dependent on platforms. However, this UMA has not been used at
269      // some platforms. See crbug/306365.
270      UMA_HISTOGRAM_BOOLEAN(kUMATranslateModifyOriginalLang, true);
271      UpdateAdvancedView();
272      break;
273    }
274    case COMBOBOX_ID_TARGET_LANGUAGE: {
275      // TODO(hajimehoshi): Ditto.
276      UMA_HISTOGRAM_BOOLEAN(kUMATranslateModifyTargetLang, true);
277      UpdateAdvancedView();
278      break;
279    }
280  }
281}
282
283void TranslateBubbleView::LinkClicked(views::Link* source, int event_flags) {
284  HandleLinkClicked(static_cast<LinkID>(source->id()));
285}
286
287TranslateBubbleModel::ViewState TranslateBubbleView::GetViewState() const {
288  return model_->GetViewState();
289}
290
291TranslateBubbleView::TranslateBubbleView(
292    views::View* anchor_view,
293    scoped_ptr<TranslateBubbleModel> model,
294    bool is_in_incognito_window,
295    Browser* browser)
296    : BubbleDelegateView(anchor_view, views::BubbleBorder::TOP_RIGHT),
297      source_language_combobox_(NULL),
298      target_language_combobox_(NULL),
299      always_translate_checkbox_(NULL),
300      model_(model.Pass()),
301      is_in_incognito_window_(is_in_incognito_window),
302      browser_(browser),
303      translate_executed_(false) {
304  if (model_->GetViewState() !=
305      TranslateBubbleModel::VIEW_STATE_BEFORE_TRANSLATE) {
306    translate_executed_ = true;
307  }
308
309  set_margins(gfx::Insets(views::kPanelVertMargin, views::kPanelHorizMargin,
310                          views::kPanelVertMargin, views::kPanelHorizMargin));
311
312  translate_bubble_view_ = this;
313}
314
315views::View* TranslateBubbleView::GetCurrentView() {
316  switch (model_->GetViewState()) {
317    case TranslateBubbleModel::VIEW_STATE_BEFORE_TRANSLATE:
318      return before_translate_view_;
319    case TranslateBubbleModel::VIEW_STATE_TRANSLATING:
320      return translating_view_;
321    case TranslateBubbleModel::VIEW_STATE_AFTER_TRANSLATE:
322      return after_translate_view_;
323    case TranslateBubbleModel::VIEW_STATE_ERROR:
324      return error_view_;
325    case TranslateBubbleModel::VIEW_STATE_ADVANCED:
326      return advanced_view_;
327  }
328  NOTREACHED();
329  return NULL;
330}
331
332void TranslateBubbleView::HandleButtonPressed(
333    TranslateBubbleView::ButtonID sender_id) {
334  switch (sender_id) {
335    case BUTTON_ID_TRANSLATE: {
336      translate_executed_ = true;
337      model_->Translate();
338      break;
339    }
340    case BUTTON_ID_DONE: {
341      translate_executed_ = true;
342      DCHECK(source_language_combobox_);
343      DCHECK(target_language_combobox_);
344
345      model_->SetOriginalLanguageIndex(
346          source_language_combobox_->selected_index());
347      model_->SetTargetLanguageIndex(
348          target_language_combobox_->selected_index());
349      model_->Translate();
350      break;
351    }
352    case BUTTON_ID_CANCEL: {
353      model_->GoBackFromAdvanced();
354      UpdateChildVisibilities();
355      SizeToContents();
356      break;
357    }
358    case BUTTON_ID_TRY_AGAIN: {
359      translate_executed_ = true;
360      model_->Translate();
361      break;
362    }
363    case BUTTON_ID_SHOW_ORIGINAL: {
364      model_->RevertTranslation();
365      StartFade(false);
366      break;
367    }
368    case BUTTON_ID_ALWAYS_TRANSLATE: {
369      DCHECK(always_translate_checkbox_);
370      model_->SetAlwaysTranslate(always_translate_checkbox_->checked());
371      UpdateAdvancedView();
372      break;
373    }
374  }
375}
376
377void TranslateBubbleView::HandleLinkClicked(
378    TranslateBubbleView::LinkID sender_id) {
379  switch (sender_id) {
380    case LINK_ID_ADVANCED: {
381      SwitchView(TranslateBubbleModel::VIEW_STATE_ADVANCED);
382      break;
383    }
384    case LINK_ID_LEARN_MORE: {
385      browser_->OpenURL(content::OpenURLParams(
386          GURL(chrome::kAboutGoogleTranslateURL),
387          content::Referrer(),
388          NEW_FOREGROUND_TAB,
389          content::PAGE_TRANSITION_LINK,
390          false));
391      break;
392    }
393  }
394}
395
396void TranslateBubbleView::UpdateChildVisibilities() {
397  for (int i = 0; i < child_count(); i++) {
398    views::View* view = child_at(i);
399    view->SetVisible(view == GetCurrentView());
400  }
401}
402
403views::View* TranslateBubbleView::CreateViewBeforeTranslate() {
404  views::Label* message_label = new views::Label(
405      l10n_util::GetStringUTF16(IDS_TRANSLATE_BUBBLE_BEFORE_TRANSLATE));
406
407  string16 original_language_name =
408      model_->GetLanguageNameAt(model_->GetOriginalLanguageIndex());
409  views::Combobox* denial_combobox = new views::Combobox(
410      new TranslateDenialComboboxModel(original_language_name));
411  denial_combobox->set_id(COMBOBOX_ID_DENIAL);
412  denial_combobox->set_listener(this);
413
414  views::View* view = new views::View();
415  views::GridLayout* layout = new views::GridLayout(view);
416  view->SetLayoutManager(layout);
417
418  using views::GridLayout;
419
420  enum {
421    COLUMN_SET_ID_MESSAGE,
422    COLUMN_SET_ID_CONTENT,
423  };
424
425  views::ColumnSet* cs = layout->AddColumnSet(COLUMN_SET_ID_MESSAGE);
426  cs->AddColumn(GridLayout::LEADING, GridLayout::CENTER,
427                0, GridLayout::USE_PREF, 0, 0);
428  cs->AddPaddingColumn(0, views::kRelatedButtonHSpacing);
429  cs->AddColumn(GridLayout::LEADING, GridLayout::CENTER,
430                0, GridLayout::USE_PREF, 0, 0);
431  cs->AddPaddingColumn(1, 0);
432
433  cs = layout->AddColumnSet(COLUMN_SET_ID_CONTENT);
434  cs->AddColumn(GridLayout::LEADING, GridLayout::CENTER,
435                0, GridLayout::USE_PREF, 0, 0);
436  cs->AddPaddingColumn(1, views::kUnrelatedControlHorizontalSpacing);
437  cs->AddColumn(GridLayout::LEADING, GridLayout::CENTER,
438                0, GridLayout::USE_PREF, 0, 0);
439  cs->AddPaddingColumn(0, views::kRelatedButtonHSpacing);
440  cs->AddColumn(GridLayout::LEADING, GridLayout::CENTER,
441                0, GridLayout::USE_PREF, 0, 0);
442
443  layout->StartRow(0, COLUMN_SET_ID_MESSAGE);
444  layout->AddView(message_label);
445  layout->AddView(CreateLink(this,
446                             IDS_TRANSLATE_BUBBLE_ADVANCED,
447                             LINK_ID_ADVANCED));
448
449  layout->AddPaddingRow(0, views::kUnrelatedControlVerticalSpacing);
450
451  layout->StartRow(0, COLUMN_SET_ID_CONTENT);
452  layout->AddView(CreateLink(this,
453                             IDS_TRANSLATE_BUBBLE_LEARN_MORE,
454                             LINK_ID_LEARN_MORE));
455  layout->AddView(denial_combobox);
456  layout->AddView(CreateLabelButton(
457      this,
458      l10n_util::GetStringUTF16(IDS_TRANSLATE_BUBBLE_ACCEPT),
459      BUTTON_ID_TRANSLATE));
460
461  return view;
462}
463
464views::View* TranslateBubbleView::CreateViewTranslating() {
465  string16 target_language_name =
466      model_->GetLanguageNameAt(model_->GetTargetLanguageIndex());
467  views::Label* label = new views::Label(
468      l10n_util::GetStringUTF16(IDS_TRANSLATE_BUBBLE_TRANSLATING));
469
470  views::View* view = new views::View();
471  views::GridLayout* layout = new views::GridLayout(view);
472  view->SetLayoutManager(layout);
473
474  using views::GridLayout;
475
476  enum {
477    COLUMN_SET_ID_MESSAGE,
478    COLUMN_SET_ID_CONTENT,
479  };
480
481  views::ColumnSet* cs = layout->AddColumnSet(COLUMN_SET_ID_MESSAGE);
482  cs->AddColumn(GridLayout::LEADING, GridLayout::CENTER,
483                0, views::GridLayout::USE_PREF, 0, 0);
484  cs->AddPaddingColumn(1, 0);
485
486  cs = layout->AddColumnSet(COLUMN_SET_ID_CONTENT);
487  cs->AddColumn(GridLayout::LEADING, GridLayout::CENTER,
488                0, GridLayout::USE_PREF, 0, 0);
489  cs->AddPaddingColumn(1, views::kUnrelatedControlHorizontalSpacing);
490  cs->AddColumn(GridLayout::LEADING, GridLayout::CENTER,
491                0, GridLayout::USE_PREF, 0, 0);
492
493  layout->StartRow(0, COLUMN_SET_ID_MESSAGE);
494  layout->AddView(label);
495
496  layout->AddPaddingRow(0, views::kUnrelatedControlVerticalSpacing);
497
498  layout->StartRow(0, COLUMN_SET_ID_CONTENT);
499  layout->AddView(CreateLink(this,
500                             IDS_TRANSLATE_BUBBLE_LEARN_MORE,
501                             LINK_ID_LEARN_MORE));
502  views::LabelButton* revert_button = CreateLabelButton(
503      this,
504      l10n_util::GetStringUTF16(IDS_TRANSLATE_BUBBLE_REVERT),
505      BUTTON_ID_SHOW_ORIGINAL);
506  revert_button->SetEnabled(false);
507  layout->AddView(revert_button);
508
509  return view;
510}
511
512views::View* TranslateBubbleView::CreateViewAfterTranslate() {
513  views::Label* label = new views::Label(
514      l10n_util::GetStringUTF16(IDS_TRANSLATE_BUBBLE_TRANSLATED));
515
516  views::View* view = new views::View();
517  views::GridLayout* layout = new views::GridLayout(view);
518  view->SetLayoutManager(layout);
519
520  using views::GridLayout;
521
522  enum {
523    COLUMN_SET_ID_MESSAGE,
524    COLUMN_SET_ID_CONTENT,
525  };
526
527  views::ColumnSet* cs = layout->AddColumnSet(COLUMN_SET_ID_MESSAGE);
528  cs->AddColumn(GridLayout::LEADING, GridLayout::CENTER,
529                0, views::GridLayout::USE_PREF, 0, 0);
530  cs->AddPaddingColumn(0, views::kRelatedButtonHSpacing);
531  cs->AddColumn(GridLayout::LEADING, GridLayout::CENTER,
532                0, views::GridLayout::USE_PREF, 0, 0);
533  cs->AddPaddingColumn(1, 0);
534
535  cs = layout->AddColumnSet(COLUMN_SET_ID_CONTENT);
536  cs->AddColumn(GridLayout::LEADING, GridLayout::CENTER,
537                0, GridLayout::USE_PREF, 0, 0);
538  cs->AddPaddingColumn(1, views::kUnrelatedControlHorizontalSpacing);
539  cs->AddColumn(GridLayout::LEADING, GridLayout::CENTER,
540                0, GridLayout::USE_PREF, 0, 0);
541
542  layout->StartRow(0, COLUMN_SET_ID_MESSAGE);
543  layout->AddView(label);
544  layout->AddView(CreateLink(this,
545                             IDS_TRANSLATE_BUBBLE_ADVANCED,
546                             LINK_ID_ADVANCED));
547
548  layout->AddPaddingRow(0, views::kUnrelatedControlVerticalSpacing);
549
550  layout->StartRow(0, COLUMN_SET_ID_CONTENT);
551  layout->AddView(CreateLink(this,
552                             IDS_TRANSLATE_BUBBLE_LEARN_MORE,
553                             LINK_ID_LEARN_MORE));
554  layout->AddView(CreateLabelButton(
555      this,
556      l10n_util::GetStringUTF16(IDS_TRANSLATE_BUBBLE_REVERT),
557      BUTTON_ID_SHOW_ORIGINAL));
558
559  return view;
560}
561
562views::View* TranslateBubbleView::CreateViewError() {
563  views::Label* label = new views::Label(
564      l10n_util::GetStringUTF16(IDS_TRANSLATE_BUBBLE_COULD_NOT_TRANSLATE));
565
566  views::View* view = new views::View();
567  views::GridLayout* layout = new views::GridLayout(view);
568  view->SetLayoutManager(layout);
569
570  using views::GridLayout;
571
572  enum {
573    COLUMN_SET_ID_MESSAGE,
574    COLUMN_SET_ID_CONTENT,
575  };
576
577  views::ColumnSet* cs = layout->AddColumnSet(COLUMN_SET_ID_MESSAGE);
578  cs->AddColumn(GridLayout::LEADING, GridLayout::CENTER,
579                0, GridLayout::USE_PREF, 0, 0);
580  cs->AddPaddingColumn(0, views::kRelatedButtonHSpacing);
581  cs->AddColumn(GridLayout::LEADING, GridLayout::CENTER,
582                0, GridLayout::USE_PREF, 0, 0);
583  cs->AddPaddingColumn(1, 0);
584
585  cs = layout->AddColumnSet(COLUMN_SET_ID_CONTENT);
586  cs->AddColumn(GridLayout::LEADING, GridLayout::CENTER,
587                0, GridLayout::USE_PREF, 0, 0);
588  cs->AddPaddingColumn(1, views::kUnrelatedControlHorizontalSpacing);
589  cs->AddColumn(GridLayout::LEADING, GridLayout::CENTER,
590                0, GridLayout::USE_PREF, 0, 0);
591
592  layout->StartRow(0, COLUMN_SET_ID_MESSAGE);
593  layout->AddView(label);
594  layout->AddView(CreateLink(this,
595                             IDS_TRANSLATE_BUBBLE_ADVANCED,
596                             LINK_ID_ADVANCED));
597
598  layout->AddPaddingRow(0, views::kUnrelatedControlVerticalSpacing);
599
600  layout->StartRow(0, COLUMN_SET_ID_CONTENT);
601  layout->AddView(CreateLink(this,
602                             IDS_TRANSLATE_BUBBLE_LEARN_MORE,
603                             LINK_ID_LEARN_MORE));
604  layout->AddView(CreateLabelButton(
605      this,
606      l10n_util::GetStringUTF16(IDS_TRANSLATE_BUBBLE_TRY_AGAIN),
607      BUTTON_ID_TRY_AGAIN));
608
609  return view;
610}
611
612// TODO(hajimehoshi): Revice this later to show a specific message for each
613// error. (crbug/307350)
614views::View* TranslateBubbleView::CreateViewAdvanced() {
615  views::Label* source_language_label = new views::Label(
616      l10n_util::GetStringUTF16(IDS_TRANSLATE_BUBBLE_PAGE_LANGUAGE));
617
618  views::Label* target_language_label = new views::Label(
619      l10n_util::GetStringUTF16(IDS_TRANSLATE_BUBBLE_TRANSLATION_LANGUAGE));
620
621  int source_default_index = model_->GetOriginalLanguageIndex();
622  source_language_combobox_model_.reset(
623      new LanguageComboboxModel(source_default_index, model_.get()));
624  source_language_combobox_ =
625      new views::Combobox(source_language_combobox_model_.get());
626
627  source_language_combobox_->set_id(COMBOBOX_ID_SOURCE_LANGUAGE);
628  source_language_combobox_->set_listener(this);
629
630  int target_default_index = model_->GetTargetLanguageIndex();
631  target_language_combobox_model_.reset(
632      new LanguageComboboxModel(target_default_index, model_.get()));
633  target_language_combobox_ =
634      new views::Combobox(target_language_combobox_model_.get());
635
636  target_language_combobox_->set_id(COMBOBOX_ID_TARGET_LANGUAGE);
637  target_language_combobox_->set_listener(this);
638
639  // In an incognito window, "Always translate" checkbox shouldn't be shown.
640  if (!is_in_incognito_window_) {
641    always_translate_checkbox_ = new views::Checkbox(string16());
642    always_translate_checkbox_->set_id(BUTTON_ID_ALWAYS_TRANSLATE);
643    always_translate_checkbox_->set_listener(this);
644  }
645
646  views::View* view = new views::View();
647  views::GridLayout* layout = new views::GridLayout(view);
648  view->SetLayoutManager(layout);
649
650  using views::GridLayout;
651
652  enum {
653    COLUMN_SET_ID_LANGUAGES,
654    COLUMN_SET_ID_ALWAYS_TRANSLATE,
655    COLUMN_SET_ID_BUTTONS,
656  };
657
658  views::ColumnSet* cs = layout->AddColumnSet(COLUMN_SET_ID_LANGUAGES);
659  cs->AddColumn(GridLayout::TRAILING, GridLayout::CENTER,
660                0, GridLayout::USE_PREF, 0, 0);
661  cs->AddPaddingColumn(0, views::kRelatedControlHorizontalSpacing);
662  cs->AddColumn(GridLayout::FILL, GridLayout::CENTER,
663                0, GridLayout::USE_PREF, 0, 0);
664  cs->AddPaddingColumn(1, 0);
665
666  if (!is_in_incognito_window_) {
667    cs = layout->AddColumnSet(COLUMN_SET_ID_ALWAYS_TRANSLATE);
668    cs->AddColumn(GridLayout::LEADING, GridLayout::CENTER,
669                  0, GridLayout::USE_PREF, 0, 0);
670    cs->AddPaddingColumn(1, 0);
671  }
672
673  cs = layout->AddColumnSet(COLUMN_SET_ID_BUTTONS);
674  cs->AddColumn(GridLayout::LEADING, GridLayout::CENTER,
675                0, GridLayout::USE_PREF, 0, 0);
676  cs->AddPaddingColumn(1, views::kUnrelatedControlHorizontalSpacing);
677  cs->AddColumn(GridLayout::LEADING, GridLayout::CENTER,
678                0, GridLayout::USE_PREF, 0, 0);
679  cs->AddPaddingColumn(0, views::kRelatedButtonHSpacing);
680  cs->AddColumn(GridLayout::LEADING, GridLayout::CENTER,
681                0, GridLayout::USE_PREF, 0, 0);
682
683  layout->StartRow(0, COLUMN_SET_ID_LANGUAGES);
684  layout->AddView(source_language_label);
685  layout->AddView(source_language_combobox_);
686
687  layout->AddPaddingRow(0, views::kRelatedControlVerticalSpacing);
688
689  layout->StartRow(0, COLUMN_SET_ID_LANGUAGES);
690  layout->AddView(target_language_label);
691  layout->AddView(target_language_combobox_);
692
693  if (!is_in_incognito_window_) {
694    layout->AddPaddingRow(0, views::kUnrelatedControlVerticalSpacing);
695
696    layout->StartRow(0, COLUMN_SET_ID_ALWAYS_TRANSLATE);
697    layout->AddView(always_translate_checkbox_);
698  }
699
700  layout->AddPaddingRow(0, views::kUnrelatedControlVerticalSpacing);
701
702  layout->StartRow(0, COLUMN_SET_ID_BUTTONS);
703  layout->AddView(CreateLink(this,
704                             IDS_TRANSLATE_BUBBLE_LEARN_MORE,
705                             LINK_ID_LEARN_MORE));
706  views::LabelButton* cancel_button = CreateLabelButton(
707      this, l10n_util::GetStringUTF16(IDS_CANCEL), BUTTON_ID_CANCEL);
708  layout->AddView(cancel_button);
709  views::LabelButton* done_button = CreateLabelButton(
710      this, l10n_util::GetStringUTF16(IDS_DONE), BUTTON_ID_DONE);
711  done_button->SetIsDefault(true);
712  layout->AddView(done_button);
713
714  UpdateAdvancedView();
715
716  return view;
717}
718
719void TranslateBubbleView::SwitchView(
720    TranslateBubbleModel::ViewState view_state) {
721  if (model_->GetViewState() == view_state)
722    return;
723
724  model_->SetViewState(view_state);
725  UpdateChildVisibilities();
726  SizeToContents();
727}
728
729void TranslateBubbleView::UpdateAdvancedView() {
730  DCHECK(source_language_combobox_);
731  DCHECK(target_language_combobox_);
732
733  model_->SetOriginalLanguageIndex(
734      source_language_combobox_->selected_index());
735  model_->SetTargetLanguageIndex(
736      target_language_combobox_->selected_index());
737
738  string16 source_language_name =
739      model_->GetLanguageNameAt(model_->GetOriginalLanguageIndex());
740  string16 target_language_name =
741      model_->GetLanguageNameAt(model_->GetTargetLanguageIndex());
742
743  string16 message =
744      l10n_util::GetStringFUTF16(IDS_TRANSLATE_BUBBLE_ALWAYS,
745                                 source_language_name,
746                                 target_language_name);
747  // "Always translate" checkbox doesn't exist in an incognito window.
748  if (always_translate_checkbox_) {
749    always_translate_checkbox_->SetText(message);
750    always_translate_checkbox_->SetChecked(
751        model_->ShouldAlwaysTranslate());
752  }
753}
754