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