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