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