Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / chrome / browser / ui / views / translate / translate_bubble_view.cc
bloba1a8448bf2cceb0df67c3e562767296e352e8681
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.
5 #include "chrome/browser/ui/views/translate/translate_bubble_view.h"
7 #include <algorithm>
8 #include <string>
9 #include <vector>
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 "chrome/grit/generated_resources.h"
24 #include "components/translate/core/browser/translate_download_manager.h"
25 #include "components/translate/core/browser/translate_manager.h"
26 #include "components/translate/core/browser/translate_ui_delegate.h"
27 #include "content/public/browser/web_contents.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/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"
41 namespace {
43 enum DenialComboboxIndexes {
44 INDEX_NOPE = 0,
45 INDEX_NEVER_TRANSLATE_LANGUAGE = 2,
46 INDEX_NEVER_TRANSLATE_SITE = 4,
49 views::LabelButton* CreateLabelButton(views::ButtonListener* listener,
50 const base::string16& label,
51 int id) {
52 views::LabelButton* button = new views::LabelButton(listener, label);
53 button->set_id(id);
54 button->SetStyle(views::Button::STYLE_BUTTON);
55 return button;
58 views::Link* CreateLink(views::LinkListener* listener,
59 int resource_id,
60 int id) {
61 views::Link* link = new views::Link(
62 l10n_util::GetStringUTF16(resource_id));
63 link->set_listener(listener);
64 link->set_id(id);
65 return link;
68 } // namespace
70 // static
71 TranslateBubbleView* TranslateBubbleView::translate_bubble_view_ = NULL;
73 TranslateBubbleView::~TranslateBubbleView() {
74 // A child view could refer to a model which is owned by this class when
75 // the child view is destructed. For example, |source_language_combobx_model_|
76 // is referred by Combobox's destructor. Before destroying the models,
77 // removing the child views is needed.
78 RemoveAllChildViews(true);
81 // static
82 void TranslateBubbleView::ShowBubble(
83 views::View* anchor_view,
84 content::WebContents* web_contents,
85 translate::TranslateStep step,
86 translate::TranslateErrors::Type error_type,
87 bool is_user_gesture) {
88 if (translate_bubble_view_) {
89 // When the user reads the advanced setting panel, the bubble should not be
90 // changed because they are focusing on the bubble.
91 if (translate_bubble_view_->web_contents() == web_contents &&
92 translate_bubble_view_->model()->GetViewState() ==
93 TranslateBubbleModel::VIEW_STATE_ADVANCED) {
94 return;
96 if (step != translate::TRANSLATE_STEP_TRANSLATE_ERROR) {
97 TranslateBubbleModel::ViewState state =
98 TranslateBubbleModelImpl::TranslateStepToViewState(step);
99 translate_bubble_view_->SwitchView(state);
100 } else {
101 translate_bubble_view_->SwitchToErrorView(error_type);
103 return;
104 } else {
105 if (step == translate::TRANSLATE_STEP_AFTER_TRANSLATE &&
106 !is_user_gesture) {
107 return;
111 std::string source_language;
112 std::string target_language;
113 ChromeTranslateClient::GetTranslateLanguages(
114 web_contents, &source_language, &target_language);
116 scoped_ptr<translate::TranslateUIDelegate> ui_delegate(
117 new translate::TranslateUIDelegate(
118 ChromeTranslateClient::GetManagerFromWebContents(web_contents)
119 ->GetWeakPtr(),
120 source_language,
121 target_language));
122 scoped_ptr<TranslateBubbleModel> model(
123 new TranslateBubbleModelImpl(step, ui_delegate.Pass()));
124 TranslateBubbleView* view = new TranslateBubbleView(anchor_view,
125 model.Pass(),
126 error_type,
127 web_contents);
128 if (is_user_gesture)
129 views::BubbleDelegateView::CreateBubble(view)->Show();
130 else
131 views::BubbleDelegateView::CreateBubble(view)->ShowInactive();
134 // static
135 void TranslateBubbleView::CloseBubble() {
136 if (!translate_bubble_view_)
137 return;
139 translate_bubble_view_->GetWidget()->Close();
142 // static
143 TranslateBubbleView* TranslateBubbleView::GetCurrentBubble() {
144 return translate_bubble_view_;
147 void TranslateBubbleView::Init() {
148 SetLayoutManager(new views::BoxLayout(views::BoxLayout::kVertical,
149 0, 0, 0));
151 before_translate_view_ = CreateViewBeforeTranslate();
152 translating_view_ = CreateViewTranslating();
153 after_translate_view_ = CreateViewAfterTranslate();
154 error_view_ = CreateViewError();
155 advanced_view_ = CreateViewAdvanced();
157 AddChildView(before_translate_view_);
158 AddChildView(translating_view_);
159 AddChildView(after_translate_view_);
160 AddChildView(error_view_);
161 AddChildView(advanced_view_);
163 AddAccelerator(ui::Accelerator(ui::VKEY_RETURN, ui::EF_NONE));
165 UpdateChildVisibilities();
167 if (model_->GetViewState() == TranslateBubbleModel::VIEW_STATE_ERROR)
168 model_->ShowError(error_type_);
171 void TranslateBubbleView::ButtonPressed(views::Button* sender,
172 const ui::Event& event) {
173 HandleButtonPressed(static_cast<ButtonID>(sender->id()));
176 void TranslateBubbleView::WindowClosing() {
177 // The operations for |model_| are valid only when a WebContents is alive.
178 // TODO(hajimehoshi): TranslateBubbleViewModel(Impl) should not hold a
179 // WebContents as a member variable because the WebContents might be destroyed
180 // while the TranslateBubbleViewModel(Impl) is still alive. Instead,
181 // TranslateBubbleViewModel should take a reference of a WebContents at each
182 // method. (crbug/320497)
183 if (!translate_executed_ && web_contents())
184 model_->TranslationDeclined(denial_button_clicked_);
186 // We have to reset |translate_bubble_view_| here, not in our destructor,
187 // because we'll be destroyed asynchronously and the shown state will be
188 // checked before then.
189 DCHECK_EQ(translate_bubble_view_, this);
190 translate_bubble_view_ = NULL;
193 bool TranslateBubbleView::AcceleratorPressed(
194 const ui::Accelerator& accelerator) {
195 switch (model_->GetViewState()) {
196 case TranslateBubbleModel::VIEW_STATE_BEFORE_TRANSLATE: {
197 if (accelerator.key_code() == ui::VKEY_RETURN) {
198 HandleButtonPressed(BUTTON_ID_TRANSLATE);
199 return true;
201 break;
203 case TranslateBubbleModel::VIEW_STATE_TRANSLATING:
204 break;
205 case TranslateBubbleModel::VIEW_STATE_AFTER_TRANSLATE: {
206 if (accelerator.key_code() == ui::VKEY_RETURN) {
207 HandleButtonPressed(BUTTON_ID_SHOW_ORIGINAL);
208 return true;
210 break;
212 case TranslateBubbleModel::VIEW_STATE_ERROR:
213 break;
214 case TranslateBubbleModel::VIEW_STATE_ADVANCED: {
215 if (accelerator.key_code() == ui::VKEY_RETURN) {
216 HandleButtonPressed(BUTTON_ID_DONE);
217 return true;
219 break;
222 return BubbleDelegateView::AcceleratorPressed(accelerator);
225 gfx::Size TranslateBubbleView::GetPreferredSize() const {
226 int width = 0;
227 for (int i = 0; i < child_count(); i++) {
228 const views::View* child = child_at(i);
229 width = std::max(width, child->GetPreferredSize().width());
231 int height = GetCurrentView()->GetPreferredSize().height();
232 return gfx::Size(width, height);
235 void TranslateBubbleView::OnPerformAction(views::Combobox* combobox) {
236 HandleComboboxPerformAction(static_cast<ComboboxID>(combobox->id()));
239 void TranslateBubbleView::LinkClicked(views::Link* source, int event_flags) {
240 HandleLinkClicked(static_cast<LinkID>(source->id()));
243 void TranslateBubbleView::WebContentsDestroyed() {
244 GetWidget()->CloseNow();
247 TranslateBubbleModel::ViewState TranslateBubbleView::GetViewState() const {
248 return model_->GetViewState();
251 TranslateBubbleView::TranslateBubbleView(
252 views::View* anchor_view,
253 scoped_ptr<TranslateBubbleModel> model,
254 translate::TranslateErrors::Type error_type,
255 content::WebContents* web_contents)
256 : ManagedFullScreenBubbleDelegateView(anchor_view, web_contents),
257 WebContentsObserver(web_contents),
258 before_translate_view_(NULL),
259 translating_view_(NULL),
260 after_translate_view_(NULL),
261 error_view_(NULL),
262 advanced_view_(NULL),
263 denial_combobox_(NULL),
264 source_language_combobox_(NULL),
265 target_language_combobox_(NULL),
266 always_translate_checkbox_(NULL),
267 advanced_cancel_button_(NULL),
268 advanced_done_button_(NULL),
269 model_(model.Pass()),
270 error_type_(error_type),
271 is_in_incognito_window_(
272 web_contents ? web_contents->GetBrowserContext()->IsOffTheRecord()
273 : false),
274 translate_executed_(false),
275 denial_button_clicked_(false) {
276 if (model_->GetViewState() !=
277 TranslateBubbleModel::VIEW_STATE_BEFORE_TRANSLATE) {
278 translate_executed_ = true;
281 set_margins(gfx::Insets(views::kPanelVertMargin, views::kPanelHorizMargin,
282 views::kPanelVertMargin, views::kPanelHorizMargin));
284 translate_bubble_view_ = this;
287 views::View* TranslateBubbleView::GetCurrentView() const {
288 switch (model_->GetViewState()) {
289 case TranslateBubbleModel::VIEW_STATE_BEFORE_TRANSLATE:
290 return before_translate_view_;
291 case TranslateBubbleModel::VIEW_STATE_TRANSLATING:
292 return translating_view_;
293 case TranslateBubbleModel::VIEW_STATE_AFTER_TRANSLATE:
294 return after_translate_view_;
295 case TranslateBubbleModel::VIEW_STATE_ERROR:
296 return error_view_;
297 case TranslateBubbleModel::VIEW_STATE_ADVANCED:
298 return advanced_view_;
300 NOTREACHED();
301 return NULL;
304 void TranslateBubbleView::HandleButtonPressed(
305 TranslateBubbleView::ButtonID sender_id) {
306 switch (sender_id) {
307 case BUTTON_ID_TRANSLATE: {
308 translate_executed_ = true;
309 model_->Translate();
310 break;
312 case BUTTON_ID_DONE: {
313 if (always_translate_checkbox_)
314 model_->SetAlwaysTranslate(always_translate_checkbox_->checked());
315 if (model_->IsPageTranslatedInCurrentLanguages()) {
316 model_->GoBackFromAdvanced();
317 UpdateChildVisibilities();
318 SizeToContents();
319 } else {
320 translate_executed_ = true;
321 model_->Translate();
322 SwitchView(TranslateBubbleModel::VIEW_STATE_TRANSLATING);
324 break;
326 case BUTTON_ID_CANCEL: {
327 model_->GoBackFromAdvanced();
328 UpdateChildVisibilities();
329 SizeToContents();
330 break;
332 case BUTTON_ID_TRY_AGAIN: {
333 translate_executed_ = true;
334 model_->Translate();
335 break;
337 case BUTTON_ID_SHOW_ORIGINAL: {
338 model_->RevertTranslation();
339 GetWidget()->Close();
340 break;
342 case BUTTON_ID_ALWAYS_TRANSLATE: {
343 // Do nothing. The state of the checkbox affects only when the 'Done'
344 // button is pressed.
345 break;
350 void TranslateBubbleView::HandleLinkClicked(
351 TranslateBubbleView::LinkID sender_id) {
352 switch (sender_id) {
353 case LINK_ID_ADVANCED: {
354 SwitchView(TranslateBubbleModel::VIEW_STATE_ADVANCED);
355 break;
357 case LINK_ID_LANGUAGE_SETTINGS: {
358 GURL url = chrome::GetSettingsUrl(chrome::kLanguageOptionsSubPage);
359 web_contents()->OpenURL(content::OpenURLParams(
360 url,
361 content::Referrer(),
362 NEW_FOREGROUND_TAB,
363 ui::PAGE_TRANSITION_LINK,
364 false));
365 break;
370 void TranslateBubbleView::HandleComboboxPerformAction(
371 TranslateBubbleView::ComboboxID sender_id) {
372 switch (sender_id) {
373 case COMBOBOX_ID_DENIAL: {
374 denial_button_clicked_ = true;
375 int index = denial_combobox_->selected_index();
376 switch (index) {
377 case INDEX_NOPE:
378 break;
379 case INDEX_NEVER_TRANSLATE_LANGUAGE:
380 model_->SetNeverTranslateLanguage(true);
381 break;
382 case INDEX_NEVER_TRANSLATE_SITE:
383 model_->SetNeverTranslateSite(true);
384 break;
385 default:
386 NOTREACHED();
387 break;
389 GetWidget()->Close();
390 break;
392 case COMBOBOX_ID_SOURCE_LANGUAGE: {
393 if (model_->GetOriginalLanguageIndex() ==
394 source_language_combobox_->selected_index()) {
395 break;
397 model_->UpdateOriginalLanguageIndex(
398 source_language_combobox_->selected_index());
399 UpdateAdvancedView();
400 break;
402 case COMBOBOX_ID_TARGET_LANGUAGE: {
403 if (model_->GetTargetLanguageIndex() ==
404 target_language_combobox_->selected_index()) {
405 break;
407 model_->UpdateTargetLanguageIndex(
408 target_language_combobox_->selected_index());
409 UpdateAdvancedView();
410 break;
415 void TranslateBubbleView::UpdateChildVisibilities() {
416 for (int i = 0; i < child_count(); i++) {
417 views::View* view = child_at(i);
418 view->SetVisible(view == GetCurrentView());
422 views::View* TranslateBubbleView::CreateViewBeforeTranslate() {
423 views::Label* message_label = new views::Label(
424 l10n_util::GetStringUTF16(IDS_TRANSLATE_BUBBLE_BEFORE_TRANSLATE));
426 base::string16 original_language_name =
427 model_->GetLanguageNameAt(model_->GetOriginalLanguageIndex());
429 std::vector<base::string16> items;
430 items.push_back(l10n_util::GetStringUTF16(IDS_TRANSLATE_BUBBLE_DENY));
431 items.push_back(l10n_util::GetStringFUTF16(
432 IDS_TRANSLATE_BUBBLE_NEVER_TRANSLATE_LANG,
433 original_language_name));
434 items.push_back(base::string16());
435 items.push_back(l10n_util::GetStringUTF16(
436 IDS_TRANSLATE_BUBBLE_NEVER_TRANSLATE_SITE));
438 denial_combobox_model_.reset(new ui::SimpleComboboxModel(items));
439 denial_combobox_ = new views::Combobox(denial_combobox_model_.get());
440 denial_combobox_->set_id(COMBOBOX_ID_DENIAL);
441 denial_combobox_->set_listener(this);
442 denial_combobox_->SetStyle(views::Combobox::STYLE_ACTION);
444 views::View* view = new views::View();
445 views::GridLayout* layout = new views::GridLayout(view);
446 view->SetLayoutManager(layout);
448 using views::GridLayout;
450 enum {
451 COLUMN_SET_ID_MESSAGE,
452 COLUMN_SET_ID_CONTENT,
455 views::ColumnSet* cs = layout->AddColumnSet(COLUMN_SET_ID_MESSAGE);
456 cs->AddColumn(GridLayout::LEADING, GridLayout::CENTER,
457 0, GridLayout::USE_PREF, 0, 0);
458 cs->AddPaddingColumn(0, views::kRelatedButtonHSpacing);
459 cs->AddColumn(GridLayout::LEADING, GridLayout::CENTER,
460 0, GridLayout::USE_PREF, 0, 0);
461 cs->AddPaddingColumn(1, 0);
463 cs = layout->AddColumnSet(COLUMN_SET_ID_CONTENT);
464 cs->AddPaddingColumn(1, 0);
465 cs->AddColumn(GridLayout::LEADING, GridLayout::CENTER,
466 0, GridLayout::USE_PREF, 0, 0);
467 cs->AddPaddingColumn(0, views::kRelatedButtonHSpacing);
468 cs->AddColumn(GridLayout::LEADING, GridLayout::CENTER,
469 0, GridLayout::USE_PREF, 0, 0);
471 layout->StartRow(0, COLUMN_SET_ID_MESSAGE);
472 layout->AddView(message_label);
473 layout->AddView(CreateLink(this,
474 IDS_TRANSLATE_BUBBLE_ADVANCED,
475 LINK_ID_ADVANCED));
477 layout->AddPaddingRow(0, views::kUnrelatedControlVerticalSpacing);
479 layout->StartRow(0, COLUMN_SET_ID_CONTENT);
480 views::LabelButton* accept_button = CreateLabelButton(
481 this,
482 l10n_util::GetStringUTF16(IDS_TRANSLATE_BUBBLE_ACCEPT),
483 BUTTON_ID_TRANSLATE);
484 layout->AddView(accept_button);
485 accept_button->SetIsDefault(true);
486 layout->AddView(denial_combobox_);
488 return view;
491 views::View* TranslateBubbleView::CreateViewTranslating() {
492 base::string16 target_language_name =
493 model_->GetLanguageNameAt(model_->GetTargetLanguageIndex());
494 views::Label* label = new views::Label(
495 l10n_util::GetStringUTF16(IDS_TRANSLATE_BUBBLE_TRANSLATING));
497 views::View* view = new views::View();
498 views::GridLayout* layout = new views::GridLayout(view);
499 view->SetLayoutManager(layout);
501 using views::GridLayout;
503 enum {
504 COLUMN_SET_ID_MESSAGE,
505 COLUMN_SET_ID_CONTENT,
508 views::ColumnSet* cs = layout->AddColumnSet(COLUMN_SET_ID_MESSAGE);
509 cs->AddColumn(GridLayout::LEADING, GridLayout::CENTER,
510 0, views::GridLayout::USE_PREF, 0, 0);
511 cs->AddPaddingColumn(1, 0);
513 cs = layout->AddColumnSet(COLUMN_SET_ID_CONTENT);
514 cs->AddPaddingColumn(1, 0);
515 cs->AddColumn(GridLayout::LEADING, GridLayout::CENTER,
516 0, GridLayout::USE_PREF, 0, 0);
518 layout->StartRow(0, COLUMN_SET_ID_MESSAGE);
519 layout->AddView(label);
521 layout->AddPaddingRow(0, views::kUnrelatedControlVerticalSpacing);
523 layout->StartRow(0, COLUMN_SET_ID_CONTENT);
524 views::LabelButton* revert_button = CreateLabelButton(
525 this,
526 l10n_util::GetStringUTF16(IDS_TRANSLATE_BUBBLE_REVERT),
527 BUTTON_ID_SHOW_ORIGINAL);
528 revert_button->SetEnabled(false);
529 layout->AddView(revert_button);
531 return view;
534 views::View* TranslateBubbleView::CreateViewAfterTranslate() {
535 views::Label* label = new views::Label(
536 l10n_util::GetStringUTF16(IDS_TRANSLATE_BUBBLE_TRANSLATED));
538 views::View* view = new views::View();
539 views::GridLayout* layout = new views::GridLayout(view);
540 view->SetLayoutManager(layout);
542 using views::GridLayout;
544 enum {
545 COLUMN_SET_ID_MESSAGE,
546 COLUMN_SET_ID_CONTENT,
549 views::ColumnSet* cs = layout->AddColumnSet(COLUMN_SET_ID_MESSAGE);
550 cs->AddColumn(GridLayout::LEADING, GridLayout::CENTER,
551 0, views::GridLayout::USE_PREF, 0, 0);
552 cs->AddPaddingColumn(0, views::kRelatedButtonHSpacing);
553 cs->AddColumn(GridLayout::LEADING, GridLayout::CENTER,
554 0, views::GridLayout::USE_PREF, 0, 0);
555 cs->AddPaddingColumn(1, 0);
557 cs = layout->AddColumnSet(COLUMN_SET_ID_CONTENT);
558 cs->AddPaddingColumn(1, 0);
559 cs->AddColumn(GridLayout::LEADING, GridLayout::CENTER,
560 0, GridLayout::USE_PREF, 0, 0);
562 layout->StartRow(0, COLUMN_SET_ID_MESSAGE);
563 layout->AddView(label);
564 layout->AddView(CreateLink(this,
565 IDS_TRANSLATE_BUBBLE_ADVANCED,
566 LINK_ID_ADVANCED));
568 layout->AddPaddingRow(0, views::kUnrelatedControlVerticalSpacing);
570 layout->StartRow(0, COLUMN_SET_ID_CONTENT);
571 layout->AddView(CreateLabelButton(
572 this,
573 l10n_util::GetStringUTF16(IDS_TRANSLATE_BUBBLE_REVERT),
574 BUTTON_ID_SHOW_ORIGINAL));
576 return view;
579 views::View* TranslateBubbleView::CreateViewError() {
580 views::Label* label = new views::Label(
581 l10n_util::GetStringUTF16(IDS_TRANSLATE_BUBBLE_COULD_NOT_TRANSLATE));
583 views::View* view = new views::View();
584 views::GridLayout* layout = new views::GridLayout(view);
585 view->SetLayoutManager(layout);
587 using views::GridLayout;
589 enum {
590 COLUMN_SET_ID_MESSAGE,
591 COLUMN_SET_ID_CONTENT,
594 views::ColumnSet* cs = layout->AddColumnSet(COLUMN_SET_ID_MESSAGE);
595 cs->AddColumn(GridLayout::LEADING, GridLayout::CENTER,
596 0, GridLayout::USE_PREF, 0, 0);
597 cs->AddPaddingColumn(0, views::kRelatedButtonHSpacing);
598 cs->AddColumn(GridLayout::LEADING, GridLayout::CENTER,
599 0, GridLayout::USE_PREF, 0, 0);
600 cs->AddPaddingColumn(1, 0);
602 cs = layout->AddColumnSet(COLUMN_SET_ID_CONTENT);
603 cs->AddPaddingColumn(1, 0);
604 cs->AddColumn(GridLayout::LEADING, GridLayout::CENTER,
605 0, GridLayout::USE_PREF, 0, 0);
607 layout->StartRow(0, COLUMN_SET_ID_MESSAGE);
608 layout->AddView(label);
609 layout->AddView(CreateLink(this,
610 IDS_TRANSLATE_BUBBLE_ADVANCED,
611 LINK_ID_ADVANCED));
613 layout->AddPaddingRow(0, views::kUnrelatedControlVerticalSpacing);
615 layout->StartRow(0, COLUMN_SET_ID_CONTENT);
616 layout->AddView(CreateLabelButton(
617 this,
618 l10n_util::GetStringUTF16(IDS_TRANSLATE_BUBBLE_TRY_AGAIN),
619 BUTTON_ID_TRY_AGAIN));
621 return view;
624 // TODO(hajimehoshi): Revice this later to show a specific message for each
625 // error. (crbug/307350)
626 views::View* TranslateBubbleView::CreateViewAdvanced() {
627 views::Label* source_language_label = new views::Label(
628 l10n_util::GetStringUTF16(IDS_TRANSLATE_BUBBLE_PAGE_LANGUAGE));
630 views::Label* target_language_label = new views::Label(
631 l10n_util::GetStringUTF16(IDS_TRANSLATE_BUBBLE_TRANSLATION_LANGUAGE));
633 int source_default_index = model_->GetOriginalLanguageIndex();
634 source_language_combobox_model_.reset(
635 new LanguageComboboxModel(source_default_index, model_.get()));
636 source_language_combobox_ =
637 new views::Combobox(source_language_combobox_model_.get());
639 source_language_combobox_->set_id(COMBOBOX_ID_SOURCE_LANGUAGE);
640 source_language_combobox_->set_listener(this);
642 int target_default_index = model_->GetTargetLanguageIndex();
643 target_language_combobox_model_.reset(
644 new LanguageComboboxModel(target_default_index, model_.get()));
645 target_language_combobox_ =
646 new views::Combobox(target_language_combobox_model_.get());
648 target_language_combobox_->set_id(COMBOBOX_ID_TARGET_LANGUAGE);
649 target_language_combobox_->set_listener(this);
651 // In an incognito window, "Always translate" checkbox shouldn't be shown.
652 if (!is_in_incognito_window_) {
653 always_translate_checkbox_ = new views::Checkbox(base::string16());
654 always_translate_checkbox_->set_id(BUTTON_ID_ALWAYS_TRANSLATE);
655 always_translate_checkbox_->set_listener(this);
658 views::View* view = new views::View();
659 views::GridLayout* layout = new views::GridLayout(view);
660 view->SetLayoutManager(layout);
662 using views::GridLayout;
664 enum {
665 COLUMN_SET_ID_LANGUAGES,
666 COLUMN_SET_ID_BUTTONS,
669 views::ColumnSet* cs = layout->AddColumnSet(COLUMN_SET_ID_LANGUAGES);
670 cs->AddColumn(GridLayout::TRAILING, GridLayout::CENTER,
671 0, GridLayout::USE_PREF, 0, 0);
672 cs->AddPaddingColumn(0, views::kRelatedControlHorizontalSpacing);
673 cs->AddColumn(GridLayout::FILL, GridLayout::CENTER,
674 0, GridLayout::USE_PREF, 0, 0);
675 cs->AddPaddingColumn(1, 0);
677 cs = layout->AddColumnSet(COLUMN_SET_ID_BUTTONS);
678 cs->AddColumn(GridLayout::LEADING, GridLayout::CENTER,
679 0, GridLayout::USE_PREF, 0, 0);
680 cs->AddPaddingColumn(1, views::kUnrelatedControlHorizontalSpacing);
681 cs->AddColumn(GridLayout::LEADING, GridLayout::CENTER,
682 0, GridLayout::USE_PREF, 0, 0);
683 cs->AddPaddingColumn(0, views::kRelatedButtonHSpacing);
684 cs->AddColumn(GridLayout::LEADING, GridLayout::CENTER,
685 0, GridLayout::USE_PREF, 0, 0);
687 layout->StartRow(0, COLUMN_SET_ID_LANGUAGES);
688 layout->AddView(source_language_label);
689 layout->AddView(source_language_combobox_);
691 layout->AddPaddingRow(0, views::kRelatedControlVerticalSpacing);
693 layout->StartRow(0, COLUMN_SET_ID_LANGUAGES);
694 layout->AddView(target_language_label);
695 layout->AddView(target_language_combobox_);
697 if (!is_in_incognito_window_) {
698 layout->AddPaddingRow(0, views::kRelatedControlVerticalSpacing);
699 layout->StartRow(0, COLUMN_SET_ID_LANGUAGES);
700 layout->SkipColumns(1);
701 layout->AddView(always_translate_checkbox_);
704 layout->AddPaddingRow(0, views::kUnrelatedControlVerticalSpacing);
706 layout->StartRow(0, COLUMN_SET_ID_BUTTONS);
707 layout->AddView(CreateLink(this,
708 IDS_TRANSLATE_BUBBLE_LANGUAGE_SETTINGS,
709 LINK_ID_LANGUAGE_SETTINGS));
710 advanced_done_button_ = CreateLabelButton(
711 this, l10n_util::GetStringUTF16(IDS_DONE), BUTTON_ID_DONE);
712 advanced_done_button_->SetIsDefault(true);
713 advanced_cancel_button_ = CreateLabelButton(
714 this, l10n_util::GetStringUTF16(IDS_CANCEL), BUTTON_ID_CANCEL);
715 layout->AddView(advanced_done_button_);
716 layout->AddView(advanced_cancel_button_);
718 UpdateAdvancedView();
720 return view;
723 void TranslateBubbleView::SwitchView(
724 TranslateBubbleModel::ViewState view_state) {
725 if (model_->GetViewState() == view_state)
726 return;
728 model_->SetViewState(view_state);
729 UpdateChildVisibilities();
730 if (view_state == TranslateBubbleModel::VIEW_STATE_ADVANCED)
731 UpdateAdvancedView();
732 SizeToContents();
735 void TranslateBubbleView::SwitchToErrorView(
736 translate::TranslateErrors::Type error_type) {
737 SwitchView(TranslateBubbleModel::VIEW_STATE_ERROR);
738 error_type_ = error_type;
739 model_->ShowError(error_type);
742 void TranslateBubbleView::UpdateAdvancedView() {
743 DCHECK(source_language_combobox_);
744 DCHECK(target_language_combobox_);
745 DCHECK(advanced_done_button_);
747 base::string16 source_language_name =
748 model_->GetLanguageNameAt(model_->GetOriginalLanguageIndex());
749 base::string16 target_language_name =
750 model_->GetLanguageNameAt(model_->GetTargetLanguageIndex());
752 // "Always translate" checkbox doesn't exist in an incognito window.
753 if (always_translate_checkbox_) {
754 always_translate_checkbox_->SetText(
755 l10n_util::GetStringUTF16(IDS_TRANSLATE_BUBBLE_ALWAYS));
756 always_translate_checkbox_->SetChecked(
757 model_->ShouldAlwaysTranslate());
760 base::string16 label;
761 if (model_->IsPageTranslatedInCurrentLanguages())
762 label = l10n_util::GetStringUTF16(IDS_DONE);
763 else
764 label = l10n_util::GetStringUTF16(IDS_TRANSLATE_BUBBLE_ACCEPT);
765 advanced_done_button_->SetText(label);
766 advanced_done_button_->SizeToPreferredSize();
767 if (advanced_view_)
768 advanced_view_->Layout();