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