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