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