Upstream version 5.34.104.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / ui / views / translate / translate_bubble_view.cc
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
39 namespace {
40
41 views::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
50 views::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
60 void 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
86 class 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
130 TranslateBubbleView* TranslateBubbleView::translate_bubble_view_ = NULL;
131
132 TranslateBubbleView::~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
141 void 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
179 bool TranslateBubbleView::IsShowing() {
180   return translate_bubble_view_ != NULL;
181 }
182
183 // static
184 TranslateBubbleView* TranslateBubbleView::GetCurrentBubble() {
185   return translate_bubble_view_;
186 }
187
188 void 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
212 void TranslateBubbleView::ButtonPressed(views::Button* sender,
213                                         const ui::Event& event) {
214   HandleButtonPressed(static_cast<ButtonID>(sender->id()));
215 }
216
217 void 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
234 bool 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
266 gfx::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
276 void TranslateBubbleView::OnPerformAction(views::Combobox* combobox) {
277   HandleComboboxPerformAction(static_cast<ComboboxID>(combobox->id()));
278 }
279
280 void TranslateBubbleView::LinkClicked(views::Link* source, int event_flags) {
281   HandleLinkClicked(static_cast<LinkID>(source->id()));
282 }
283
284 void TranslateBubbleView::WebContentsDestroyed(
285     content::WebContents* web_contents) {
286   GetWidget()->CloseNow();
287 }
288
289 TranslateBubbleModel::ViewState TranslateBubbleView::GetViewState() const {
290   return model_->GetViewState();
291 }
292
293 TranslateBubbleView::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
329 views::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
346 void 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
392 void 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
413 void 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
458 void 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
465 views::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
522 views::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
565 views::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
610 views::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)
657 views::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
754 void 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
766 void TranslateBubbleView::SwitchToErrorView(TranslateErrors::Type error_type) {
767   SwitchView(TranslateBubbleModel::VIEW_STATE_ERROR);
768   error_type_ = error_type;
769   model_->ShowError(error_type);
770 }
771
772 void 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 }