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