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