translate_bubble_view.cc revision cedac228d2dd51db4b79ea1e72c7f249408ee061
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() const { 247 int width = 0; 248 for (int i = 0; i < child_count(); i++) { 249 const 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 GetWidget()->CloseNow(); 266} 267 268TranslateBubbleModel::ViewState TranslateBubbleView::GetViewState() const { 269 return model_->GetViewState(); 270} 271 272TranslateBubbleView::TranslateBubbleView( 273 views::View* anchor_view, 274 scoped_ptr<TranslateBubbleModel> model, 275 TranslateErrors::Type error_type, 276 content::WebContents* web_contents) 277 : BubbleDelegateView(anchor_view, views::BubbleBorder::TOP_RIGHT), 278 WebContentsObserver(web_contents), 279 before_translate_view_(NULL), 280 translating_view_(NULL), 281 after_translate_view_(NULL), 282 error_view_(NULL), 283 advanced_view_(NULL), 284 denial_combobox_(NULL), 285 source_language_combobox_(NULL), 286 target_language_combobox_(NULL), 287 always_translate_checkbox_(NULL), 288 advanced_cancel_button_(NULL), 289 advanced_done_button_(NULL), 290 model_(model.Pass()), 291 error_type_(error_type), 292 is_in_incognito_window_( 293 web_contents ? 294 web_contents->GetBrowserContext()->IsOffTheRecord() : false), 295 translate_executed_(false), 296 denial_button_clicked_(false) { 297 if (model_->GetViewState() != 298 TranslateBubbleModel::VIEW_STATE_BEFORE_TRANSLATE) { 299 translate_executed_ = true; 300 } 301 302 set_margins(gfx::Insets(views::kPanelVertMargin, views::kPanelHorizMargin, 303 views::kPanelVertMargin, views::kPanelHorizMargin)); 304 305 translate_bubble_view_ = this; 306} 307 308views::View* TranslateBubbleView::GetCurrentView() const { 309 switch (model_->GetViewState()) { 310 case TranslateBubbleModel::VIEW_STATE_BEFORE_TRANSLATE: 311 return before_translate_view_; 312 case TranslateBubbleModel::VIEW_STATE_TRANSLATING: 313 return translating_view_; 314 case TranslateBubbleModel::VIEW_STATE_AFTER_TRANSLATE: 315 return after_translate_view_; 316 case TranslateBubbleModel::VIEW_STATE_ERROR: 317 return error_view_; 318 case TranslateBubbleModel::VIEW_STATE_ADVANCED: 319 return advanced_view_; 320 } 321 NOTREACHED(); 322 return NULL; 323} 324 325void TranslateBubbleView::HandleButtonPressed( 326 TranslateBubbleView::ButtonID sender_id) { 327 switch (sender_id) { 328 case BUTTON_ID_TRANSLATE: { 329 translate_executed_ = true; 330 model_->Translate(); 331 break; 332 } 333 case BUTTON_ID_DONE: { 334 if (always_translate_checkbox_) 335 model_->SetAlwaysTranslate(always_translate_checkbox_->checked()); 336 if (model_->IsPageTranslatedInCurrentLanguages()) { 337 model_->GoBackFromAdvanced(); 338 UpdateChildVisibilities(); 339 SizeToContents(); 340 } else { 341 translate_executed_ = true; 342 model_->Translate(); 343 SwitchView(TranslateBubbleModel::VIEW_STATE_TRANSLATING); 344 } 345 break; 346 } 347 case BUTTON_ID_CANCEL: { 348 model_->GoBackFromAdvanced(); 349 UpdateChildVisibilities(); 350 SizeToContents(); 351 break; 352 } 353 case BUTTON_ID_TRY_AGAIN: { 354 translate_executed_ = true; 355 model_->Translate(); 356 break; 357 } 358 case BUTTON_ID_SHOW_ORIGINAL: { 359 model_->RevertTranslation(); 360 GetWidget()->Close(); 361 break; 362 } 363 case BUTTON_ID_ALWAYS_TRANSLATE: { 364 // Do nothing. The state of the checkbox affects only when the 'Done' 365 // button is pressed. 366 break; 367 } 368 } 369} 370 371void TranslateBubbleView::HandleLinkClicked( 372 TranslateBubbleView::LinkID sender_id) { 373 switch (sender_id) { 374 case LINK_ID_ADVANCED: { 375 SwitchView(TranslateBubbleModel::VIEW_STATE_ADVANCED); 376 break; 377 } 378 case LINK_ID_LANGUAGE_SETTINGS: { 379 GURL url = chrome::GetSettingsUrl(chrome::kLanguageOptionsSubPage); 380 web_contents()->OpenURL(content::OpenURLParams( 381 url, 382 content::Referrer(), 383 NEW_FOREGROUND_TAB, 384 content::PAGE_TRANSITION_LINK, 385 false)); 386 break; 387 } 388 } 389} 390 391void TranslateBubbleView::HandleComboboxPerformAction( 392 TranslateBubbleView::ComboboxID sender_id) { 393 switch (sender_id) { 394 case COMBOBOX_ID_DENIAL: { 395 denial_button_clicked_ = true; 396 int index = denial_combobox_->selected_index(); 397 switch (index) { 398 case TranslateDenialComboboxModel::INDEX_NOPE: 399 break; 400 case TranslateDenialComboboxModel::INDEX_NEVER_TRANSLATE_LANGUAGE: 401 model_->SetNeverTranslateLanguage(true); 402 break; 403 case TranslateDenialComboboxModel::INDEX_NEVER_TRANSLATE_SITE: 404 model_->SetNeverTranslateSite(true); 405 break; 406 default: 407 NOTREACHED(); 408 break; 409 } 410 GetWidget()->Close(); 411 break; 412 } 413 case COMBOBOX_ID_SOURCE_LANGUAGE: { 414 if (model_->GetOriginalLanguageIndex() == 415 source_language_combobox_->selected_index()) { 416 break; 417 } 418 model_->UpdateOriginalLanguageIndex( 419 source_language_combobox_->selected_index()); 420 UpdateAdvancedView(); 421 break; 422 } 423 case COMBOBOX_ID_TARGET_LANGUAGE: { 424 if (model_->GetTargetLanguageIndex() == 425 target_language_combobox_->selected_index()) { 426 break; 427 } 428 model_->UpdateTargetLanguageIndex( 429 target_language_combobox_->selected_index()); 430 UpdateAdvancedView(); 431 break; 432 } 433 } 434} 435 436void TranslateBubbleView::UpdateChildVisibilities() { 437 for (int i = 0; i < child_count(); i++) { 438 views::View* view = child_at(i); 439 view->SetVisible(view == GetCurrentView()); 440 } 441} 442 443views::View* TranslateBubbleView::CreateViewBeforeTranslate() { 444 views::Label* message_label = new views::Label( 445 l10n_util::GetStringUTF16(IDS_TRANSLATE_BUBBLE_BEFORE_TRANSLATE)); 446 447 base::string16 original_language_name = 448 model_->GetLanguageNameAt(model_->GetOriginalLanguageIndex()); 449 denial_combobox_ = new views::Combobox( 450 new TranslateDenialComboboxModel(original_language_name)); 451 denial_combobox_->set_id(COMBOBOX_ID_DENIAL); 452 denial_combobox_->set_listener(this); 453 denial_combobox_->SetStyle(views::Combobox::STYLE_ACTION); 454 455 views::View* view = new views::View(); 456 views::GridLayout* layout = new views::GridLayout(view); 457 view->SetLayoutManager(layout); 458 459 using views::GridLayout; 460 461 enum { 462 COLUMN_SET_ID_MESSAGE, 463 COLUMN_SET_ID_CONTENT, 464 }; 465 466 views::ColumnSet* cs = layout->AddColumnSet(COLUMN_SET_ID_MESSAGE); 467 cs->AddColumn(GridLayout::LEADING, GridLayout::CENTER, 468 0, GridLayout::USE_PREF, 0, 0); 469 cs->AddPaddingColumn(0, views::kRelatedButtonHSpacing); 470 cs->AddColumn(GridLayout::LEADING, GridLayout::CENTER, 471 0, GridLayout::USE_PREF, 0, 0); 472 cs->AddPaddingColumn(1, 0); 473 474 cs = layout->AddColumnSet(COLUMN_SET_ID_CONTENT); 475 cs->AddPaddingColumn(1, 0); 476 cs->AddColumn(GridLayout::LEADING, GridLayout::CENTER, 477 0, GridLayout::USE_PREF, 0, 0); 478 cs->AddPaddingColumn(0, views::kRelatedButtonHSpacing); 479 cs->AddColumn(GridLayout::LEADING, GridLayout::CENTER, 480 0, GridLayout::USE_PREF, 0, 0); 481 482 layout->StartRow(0, COLUMN_SET_ID_MESSAGE); 483 layout->AddView(message_label); 484 layout->AddView(CreateLink(this, 485 IDS_TRANSLATE_BUBBLE_ADVANCED, 486 LINK_ID_ADVANCED)); 487 488 layout->AddPaddingRow(0, views::kUnrelatedControlVerticalSpacing); 489 490 layout->StartRow(0, COLUMN_SET_ID_CONTENT); 491 layout->AddView(CreateLabelButton( 492 this, 493 l10n_util::GetStringUTF16(IDS_TRANSLATE_BUBBLE_ACCEPT), 494 BUTTON_ID_TRANSLATE)); 495 layout->AddView(denial_combobox_); 496 497 return view; 498} 499 500views::View* TranslateBubbleView::CreateViewTranslating() { 501 base::string16 target_language_name = 502 model_->GetLanguageNameAt(model_->GetTargetLanguageIndex()); 503 views::Label* label = new views::Label( 504 l10n_util::GetStringUTF16(IDS_TRANSLATE_BUBBLE_TRANSLATING)); 505 506 views::View* view = new views::View(); 507 views::GridLayout* layout = new views::GridLayout(view); 508 view->SetLayoutManager(layout); 509 510 using views::GridLayout; 511 512 enum { 513 COLUMN_SET_ID_MESSAGE, 514 COLUMN_SET_ID_CONTENT, 515 }; 516 517 views::ColumnSet* cs = layout->AddColumnSet(COLUMN_SET_ID_MESSAGE); 518 cs->AddColumn(GridLayout::LEADING, GridLayout::CENTER, 519 0, views::GridLayout::USE_PREF, 0, 0); 520 cs->AddPaddingColumn(1, 0); 521 522 cs = layout->AddColumnSet(COLUMN_SET_ID_CONTENT); 523 cs->AddPaddingColumn(1, 0); 524 cs->AddColumn(GridLayout::LEADING, GridLayout::CENTER, 525 0, GridLayout::USE_PREF, 0, 0); 526 527 layout->StartRow(0, COLUMN_SET_ID_MESSAGE); 528 layout->AddView(label); 529 530 layout->AddPaddingRow(0, views::kUnrelatedControlVerticalSpacing); 531 532 layout->StartRow(0, COLUMN_SET_ID_CONTENT); 533 views::LabelButton* revert_button = CreateLabelButton( 534 this, 535 l10n_util::GetStringUTF16(IDS_TRANSLATE_BUBBLE_REVERT), 536 BUTTON_ID_SHOW_ORIGINAL); 537 revert_button->SetEnabled(false); 538 layout->AddView(revert_button); 539 540 return view; 541} 542 543views::View* TranslateBubbleView::CreateViewAfterTranslate() { 544 views::Label* label = new views::Label( 545 l10n_util::GetStringUTF16(IDS_TRANSLATE_BUBBLE_TRANSLATED)); 546 547 views::View* view = new views::View(); 548 views::GridLayout* layout = new views::GridLayout(view); 549 view->SetLayoutManager(layout); 550 551 using views::GridLayout; 552 553 enum { 554 COLUMN_SET_ID_MESSAGE, 555 COLUMN_SET_ID_CONTENT, 556 }; 557 558 views::ColumnSet* cs = layout->AddColumnSet(COLUMN_SET_ID_MESSAGE); 559 cs->AddColumn(GridLayout::LEADING, GridLayout::CENTER, 560 0, views::GridLayout::USE_PREF, 0, 0); 561 cs->AddPaddingColumn(0, views::kRelatedButtonHSpacing); 562 cs->AddColumn(GridLayout::LEADING, GridLayout::CENTER, 563 0, views::GridLayout::USE_PREF, 0, 0); 564 cs->AddPaddingColumn(1, 0); 565 566 cs = layout->AddColumnSet(COLUMN_SET_ID_CONTENT); 567 cs->AddPaddingColumn(1, 0); 568 cs->AddColumn(GridLayout::LEADING, GridLayout::CENTER, 569 0, GridLayout::USE_PREF, 0, 0); 570 571 layout->StartRow(0, COLUMN_SET_ID_MESSAGE); 572 layout->AddView(label); 573 layout->AddView(CreateLink(this, 574 IDS_TRANSLATE_BUBBLE_ADVANCED, 575 LINK_ID_ADVANCED)); 576 577 layout->AddPaddingRow(0, views::kUnrelatedControlVerticalSpacing); 578 579 layout->StartRow(0, COLUMN_SET_ID_CONTENT); 580 layout->AddView(CreateLabelButton( 581 this, 582 l10n_util::GetStringUTF16(IDS_TRANSLATE_BUBBLE_REVERT), 583 BUTTON_ID_SHOW_ORIGINAL)); 584 585 return view; 586} 587 588views::View* TranslateBubbleView::CreateViewError() { 589 views::Label* label = new views::Label( 590 l10n_util::GetStringUTF16(IDS_TRANSLATE_BUBBLE_COULD_NOT_TRANSLATE)); 591 592 views::View* view = new views::View(); 593 views::GridLayout* layout = new views::GridLayout(view); 594 view->SetLayoutManager(layout); 595 596 using views::GridLayout; 597 598 enum { 599 COLUMN_SET_ID_MESSAGE, 600 COLUMN_SET_ID_CONTENT, 601 }; 602 603 views::ColumnSet* cs = layout->AddColumnSet(COLUMN_SET_ID_MESSAGE); 604 cs->AddColumn(GridLayout::LEADING, GridLayout::CENTER, 605 0, GridLayout::USE_PREF, 0, 0); 606 cs->AddPaddingColumn(0, views::kRelatedButtonHSpacing); 607 cs->AddColumn(GridLayout::LEADING, GridLayout::CENTER, 608 0, GridLayout::USE_PREF, 0, 0); 609 cs->AddPaddingColumn(1, 0); 610 611 cs = layout->AddColumnSet(COLUMN_SET_ID_CONTENT); 612 cs->AddPaddingColumn(1, 0); 613 cs->AddColumn(GridLayout::LEADING, GridLayout::CENTER, 614 0, GridLayout::USE_PREF, 0, 0); 615 616 layout->StartRow(0, COLUMN_SET_ID_MESSAGE); 617 layout->AddView(label); 618 layout->AddView(CreateLink(this, 619 IDS_TRANSLATE_BUBBLE_ADVANCED, 620 LINK_ID_ADVANCED)); 621 622 layout->AddPaddingRow(0, views::kUnrelatedControlVerticalSpacing); 623 624 layout->StartRow(0, COLUMN_SET_ID_CONTENT); 625 layout->AddView(CreateLabelButton( 626 this, 627 l10n_util::GetStringUTF16(IDS_TRANSLATE_BUBBLE_TRY_AGAIN), 628 BUTTON_ID_TRY_AGAIN)); 629 630 return view; 631} 632 633// TODO(hajimehoshi): Revice this later to show a specific message for each 634// error. (crbug/307350) 635views::View* TranslateBubbleView::CreateViewAdvanced() { 636 views::Label* source_language_label = new views::Label( 637 l10n_util::GetStringUTF16(IDS_TRANSLATE_BUBBLE_PAGE_LANGUAGE)); 638 639 views::Label* target_language_label = new views::Label( 640 l10n_util::GetStringUTF16(IDS_TRANSLATE_BUBBLE_TRANSLATION_LANGUAGE)); 641 642 int source_default_index = model_->GetOriginalLanguageIndex(); 643 source_language_combobox_model_.reset( 644 new LanguageComboboxModel(source_default_index, model_.get())); 645 source_language_combobox_ = 646 new views::Combobox(source_language_combobox_model_.get()); 647 648 source_language_combobox_->set_id(COMBOBOX_ID_SOURCE_LANGUAGE); 649 source_language_combobox_->set_listener(this); 650 651 int target_default_index = model_->GetTargetLanguageIndex(); 652 target_language_combobox_model_.reset( 653 new LanguageComboboxModel(target_default_index, model_.get())); 654 target_language_combobox_ = 655 new views::Combobox(target_language_combobox_model_.get()); 656 657 target_language_combobox_->set_id(COMBOBOX_ID_TARGET_LANGUAGE); 658 target_language_combobox_->set_listener(this); 659 660 // In an incognito window, "Always translate" checkbox shouldn't be shown. 661 if (!is_in_incognito_window_) { 662 always_translate_checkbox_ = new views::Checkbox(base::string16()); 663 always_translate_checkbox_->set_id(BUTTON_ID_ALWAYS_TRANSLATE); 664 always_translate_checkbox_->set_listener(this); 665 } 666 667 views::View* view = new views::View(); 668 views::GridLayout* layout = new views::GridLayout(view); 669 view->SetLayoutManager(layout); 670 671 using views::GridLayout; 672 673 enum { 674 COLUMN_SET_ID_LANGUAGES, 675 COLUMN_SET_ID_BUTTONS, 676 }; 677 678 views::ColumnSet* cs = layout->AddColumnSet(COLUMN_SET_ID_LANGUAGES); 679 cs->AddColumn(GridLayout::TRAILING, GridLayout::CENTER, 680 0, GridLayout::USE_PREF, 0, 0); 681 cs->AddPaddingColumn(0, views::kRelatedControlHorizontalSpacing); 682 cs->AddColumn(GridLayout::FILL, GridLayout::CENTER, 683 0, GridLayout::USE_PREF, 0, 0); 684 cs->AddPaddingColumn(1, 0); 685 686 cs = layout->AddColumnSet(COLUMN_SET_ID_BUTTONS); 687 cs->AddColumn(GridLayout::LEADING, GridLayout::CENTER, 688 0, GridLayout::USE_PREF, 0, 0); 689 cs->AddPaddingColumn(1, views::kUnrelatedControlHorizontalSpacing); 690 cs->AddColumn(GridLayout::LEADING, GridLayout::CENTER, 691 0, GridLayout::USE_PREF, 0, 0); 692 cs->AddPaddingColumn(0, views::kRelatedButtonHSpacing); 693 cs->AddColumn(GridLayout::LEADING, GridLayout::CENTER, 694 0, GridLayout::USE_PREF, 0, 0); 695 696 layout->StartRow(0, COLUMN_SET_ID_LANGUAGES); 697 layout->AddView(source_language_label); 698 layout->AddView(source_language_combobox_); 699 700 layout->AddPaddingRow(0, views::kRelatedControlVerticalSpacing); 701 702 layout->StartRow(0, COLUMN_SET_ID_LANGUAGES); 703 layout->AddView(target_language_label); 704 layout->AddView(target_language_combobox_); 705 706 if (!is_in_incognito_window_) { 707 layout->AddPaddingRow(0, views::kRelatedControlVerticalSpacing); 708 layout->StartRow(0, COLUMN_SET_ID_LANGUAGES); 709 layout->SkipColumns(1); 710 layout->AddView(always_translate_checkbox_); 711 } 712 713 layout->AddPaddingRow(0, views::kUnrelatedControlVerticalSpacing); 714 715 layout->StartRow(0, COLUMN_SET_ID_BUTTONS); 716 layout->AddView(CreateLink(this, 717 IDS_TRANSLATE_BUBBLE_LANGUAGE_SETTINGS, 718 LINK_ID_LANGUAGE_SETTINGS)); 719 advanced_done_button_ = CreateLabelButton( 720 this, l10n_util::GetStringUTF16(IDS_DONE), BUTTON_ID_DONE); 721 advanced_done_button_->SetIsDefault(true); 722 advanced_cancel_button_ = CreateLabelButton( 723 this, l10n_util::GetStringUTF16(IDS_CANCEL), BUTTON_ID_CANCEL); 724 layout->AddView(advanced_done_button_); 725 layout->AddView(advanced_cancel_button_); 726 727 UpdateAdvancedView(); 728 729 return view; 730} 731 732void TranslateBubbleView::SwitchView( 733 TranslateBubbleModel::ViewState view_state) { 734 if (model_->GetViewState() == view_state) 735 return; 736 737 model_->SetViewState(view_state); 738 UpdateChildVisibilities(); 739 if (view_state == TranslateBubbleModel::VIEW_STATE_ADVANCED) 740 UpdateAdvancedView(); 741 SizeToContents(); 742} 743 744void TranslateBubbleView::SwitchToErrorView(TranslateErrors::Type error_type) { 745 SwitchView(TranslateBubbleModel::VIEW_STATE_ERROR); 746 error_type_ = error_type; 747 model_->ShowError(error_type); 748} 749 750void TranslateBubbleView::UpdateAdvancedView() { 751 DCHECK(source_language_combobox_); 752 DCHECK(target_language_combobox_); 753 DCHECK(advanced_done_button_); 754 755 base::string16 source_language_name = 756 model_->GetLanguageNameAt(model_->GetOriginalLanguageIndex()); 757 base::string16 target_language_name = 758 model_->GetLanguageNameAt(model_->GetTargetLanguageIndex()); 759 760 // "Always translate" checkbox doesn't exist in an incognito window. 761 if (always_translate_checkbox_) { 762 always_translate_checkbox_->SetText( 763 l10n_util::GetStringUTF16(IDS_TRANSLATE_BUBBLE_ALWAYS)); 764 always_translate_checkbox_->SetChecked( 765 model_->ShouldAlwaysTranslate()); 766 } 767 768 base::string16 label; 769 if (model_->IsPageTranslatedInCurrentLanguages()) 770 label = l10n_util::GetStringUTF16(IDS_DONE); 771 else 772 label = l10n_util::GetStringUTF16(IDS_TRANSLATE_BUBBLE_ACCEPT); 773 advanced_done_button_->SetText(label); 774} 775