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