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