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