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