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