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