one_click_signin_bubble_view.cc revision 2a99a7e74a7f215066514fe81d2bfa6639d9eddd
1// Copyright (c) 2012 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/sync/one_click_signin_bubble_view.h" 6 7#include "base/callback_helpers.h" 8#include "base/logging.h" 9#include "base/message_loop.h" 10#include "chrome/browser/google/google_util.h" 11#include "chrome/browser/ui/browser.h" 12#include "chrome/common/url_constants.h" 13#include "content/public/browser/web_contents.h" 14#include "grit/chromium_strings.h" 15#include "grit/generated_resources.h" 16#include "grit/theme_resources.h" 17#include "grit/ui_resources.h" 18#include "ui/base/keycodes/keyboard_codes.h" 19#include "ui/base/l10n/l10n_util.h" 20#include "ui/base/resource/resource_bundle.h" 21#include "ui/views/controls/button/image_button.h" 22#include "ui/views/controls/button/text_button.h" 23#include "ui/views/controls/image_view.h" 24#include "ui/views/controls/label.h" 25#include "ui/views/controls/link.h" 26#include "ui/views/layout/grid_layout.h" 27#include "ui/views/layout/layout_constants.h" 28#include "ui/views/widget/widget.h" 29 30// Minimum width for the mutli-line label. 31const int kMinimumDialogLabelWidth = 400; 32const int kMinimumLabelWidth = 240; 33const int kDialogMargin = 16; 34 35namespace { 36 37// The column set constants that can be used in the InitContent() function 38// to layout views. 39enum OneClickSigninBubbleColumnTypes { 40 COLUMN_SET_FILL_ALIGN, 41 COLUMN_SET_CONTROLS, 42 COLUMN_SET_TITLE_BAR 43}; 44 45class OneClickSigninDialogView : public OneClickSigninBubbleView { 46 public: 47 OneClickSigninDialogView( 48 content::WebContents* web_content, 49 views::View* anchor_view, 50 const BrowserWindow::StartSyncCallback& start_sync_callback); 51 52 private: 53 // Overridden from views::WidgetDelegate: 54 virtual ui::ModalType GetModalType() const OVERRIDE; 55 56 // Overridden from OneClickSigninBubbleView: 57 virtual void InitContent(views::GridLayout* layout) OVERRIDE; 58 virtual void GetButtons(views::TextButton** ok_button, 59 views::TextButton** undo_button) OVERRIDE; 60 virtual views::Link* GetAdvancedLink() OVERRIDE; 61 62 // Overridden from views::LinkListener: 63 virtual void LinkClicked(views::Link* source, int event_flags) OVERRIDE; 64 65 content::WebContents* web_content_; 66 views::Link* learn_more_link_; 67 views::ImageButton* close_button_; 68 69 DISALLOW_COPY_AND_ASSIGN(OneClickSigninDialogView); 70}; 71 72OneClickSigninDialogView::OneClickSigninDialogView( 73 content::WebContents* web_content, 74 views::View* anchor_view, 75 const BrowserWindow::StartSyncCallback& start_sync_callback) 76 : OneClickSigninBubbleView(anchor_view, start_sync_callback), 77 web_content_(web_content), 78 learn_more_link_(NULL), 79 close_button_(NULL) { 80 set_arrow_location(views::BubbleBorder::NONE); 81 set_anchor_insets(gfx::Insets(0, 0, anchor_view->height() / 2, 0)); 82 set_close_on_deactivate(false); 83 set_margins(gfx::Insets(kDialogMargin, kDialogMargin, kDialogMargin, 84 kDialogMargin)); 85} 86 87ui::ModalType OneClickSigninDialogView::GetModalType() const { 88 return ui::MODAL_TYPE_CHILD; 89} 90 91void OneClickSigninDialogView::InitContent(views::GridLayout* layout) { 92 // Column set for title bar. 93 views::ColumnSet* cs = layout->AddColumnSet(COLUMN_SET_TITLE_BAR); 94 cs->AddColumn(views::GridLayout::LEADING, views::GridLayout::CENTER, 0, 95 views::GridLayout::USE_PREF, 0, 0); 96 cs->AddPaddingColumn(1, views::kUnrelatedControlHorizontalSpacing); 97 cs->AddColumn(views::GridLayout::TRAILING, views::GridLayout::CENTER, 0, 98 views::GridLayout::USE_PREF, 0, 0); 99 100 ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance(); 101 102 { 103 layout->StartRow(0, COLUMN_SET_TITLE_BAR); 104 105 views::Label* label = new views::Label( 106 l10n_util::GetStringUTF16(IDS_ONE_CLICK_SIGNIN_DIALOG_TITLE)); 107 label->SetHorizontalAlignment(gfx::ALIGN_LEFT); 108 label->SetFont(label->font().DeriveFont(3, gfx::Font::BOLD)); 109 layout->AddView(label); 110 111 close_button_ = new views::ImageButton(this); 112 close_button_->SetImage(views::ImageButton::STATE_NORMAL, 113 rb.GetImageNamed(IDR_CLOSE_BAR).ToImageSkia()); 114 close_button_->SetImage(views::ImageButton::STATE_HOVERED, 115 rb.GetImageNamed(IDR_CLOSE_BAR_H).ToImageSkia()); 116 close_button_->SetImage(views::ImageButton::STATE_PRESSED, 117 rb.GetImageNamed(IDR_CLOSE_BAR_P).ToImageSkia()); 118 layout->AddView(close_button_); 119 } 120 121 layout->AddPaddingRow(0, views::kUnrelatedControlVerticalSpacing); 122 123 { 124 layout->StartRow(0, COLUMN_SET_FILL_ALIGN); 125 126 views::Label* label = new views::Label( 127 l10n_util::GetStringUTF16(IDS_ONE_CLICK_SIGNIN_DIALOG_MESSAGE)); 128 label->SetMultiLine(true); 129 label->SetHorizontalAlignment(gfx::ALIGN_LEFT); 130 label->SizeToFit(kMinimumDialogLabelWidth); 131 layout->AddView(label); 132 133 layout->StartRow(0, COLUMN_SET_FILL_ALIGN); 134 135 learn_more_link_ = new views::Link( 136 l10n_util::GetStringUTF16(IDS_LEARN_MORE)); 137 learn_more_link_->set_listener(this); 138 learn_more_link_->SetHorizontalAlignment(gfx::ALIGN_LEFT); 139 layout->AddView(learn_more_link_, 1, 1, views::GridLayout::TRAILING, 140 views::GridLayout::CENTER); 141 } 142 143 layout->AddPaddingRow(0, views::kUnrelatedControlVerticalSpacing); 144} 145 146void OneClickSigninDialogView::GetButtons(views::TextButton** ok_button, 147 views::TextButton** undo_button) { 148 *ok_button = new views::NativeTextButton(this); 149 *undo_button = new views::NativeTextButton(this); 150 151 // The default size of the buttons is too large. To allow them to be smaller 152 // ignore the minimum default size. Furthermore, to make sure they are the 153 // same size, SetText() is called with both strings on both buttons. 154 (*ok_button)->set_ignore_minimum_size(true); 155 (*undo_button)->set_ignore_minimum_size(true); 156 string16 ok_label = 157 l10n_util::GetStringUTF16(IDS_ONE_CLICK_SIGNIN_DIALOG_OK_BUTTON); 158 string16 undo_label = 159 l10n_util::GetStringUTF16(IDS_ONE_CLICK_SIGNIN_DIALOG_UNDO_BUTTON); 160 (*ok_button)->SetText(undo_label); 161 (*ok_button)->SetText(ok_label); 162 (*undo_button)->SetText(ok_label); 163 (*undo_button)->SetText(undo_label); 164} 165 166views::Link* OneClickSigninDialogView::GetAdvancedLink() { 167 views::Link* advanced_link= new views::Link( 168 l10n_util::GetStringUTF16(IDS_ONE_CLICK_SIGNIN_DIALOG_ADVANCED)); 169 advanced_link->set_listener(this); 170 advanced_link->SetHorizontalAlignment(gfx::ALIGN_LEFT); 171 return advanced_link; 172} 173 174void OneClickSigninDialogView::LinkClicked(views::Link* source, 175 int event_flags) { 176 if (source == learn_more_link_) { 177 content::OpenURLParams params( 178 GURL(chrome::kChromeSyncLearnMoreURL), content::Referrer(), 179 NEW_WINDOW, content::PAGE_TRANSITION_LINK, false); 180 web_content_->OpenURL(params); 181 return; 182 } 183 184 OneClickSigninBubbleView::LinkClicked(source, event_flags); 185} 186 187} // namespace 188 189// OneClickSigninBubbleView ---------------------------------------------------- 190 191// static 192OneClickSigninBubbleView* OneClickSigninBubbleView::bubble_view_ = NULL; 193 194// static 195void OneClickSigninBubbleView::ShowBubble( 196 BrowserWindow::OneClickSigninBubbleType type, 197 ToolbarView* toolbar_view, 198 const BrowserWindow::StartSyncCallback& start_sync) { 199 if (IsShowing()) 200 return; 201 202 bubble_view_ = type == BrowserWindow::ONE_CLICK_SIGNIN_BUBBLE_TYPE_BUBBLE ? 203 new OneClickSigninBubbleView(toolbar_view->app_menu(), start_sync) : 204 new OneClickSigninDialogView(toolbar_view->GetWebContents(), 205 toolbar_view->location_bar(), start_sync); 206 207 views::BubbleDelegateView::CreateBubble(bubble_view_)->Show(); 208} 209 210// static 211bool OneClickSigninBubbleView::IsShowing() { 212 return bubble_view_ != NULL; 213} 214 215// static 216void OneClickSigninBubbleView::Hide() { 217 if (IsShowing()) 218 bubble_view_->GetWidget()->Close(); 219} 220 221OneClickSigninBubbleView::OneClickSigninBubbleView( 222 views::View* anchor_view, 223 const BrowserWindow::StartSyncCallback& start_sync_callback) 224 : BubbleDelegateView(anchor_view, views::BubbleBorder::TOP_RIGHT), 225 advanced_link_(NULL), 226 ok_button_(NULL), 227 undo_button_(NULL), 228 start_sync_callback_(start_sync_callback), 229 message_loop_for_testing_(NULL) { 230 DCHECK(!start_sync_callback_.is_null()); 231} 232 233OneClickSigninBubbleView::~OneClickSigninBubbleView() { 234} 235 236void OneClickSigninBubbleView::AnimationEnded(const ui::Animation* animation) { 237 views::BubbleDelegateView::AnimationEnded(animation); 238 if (message_loop_for_testing_) 239 message_loop_for_testing_->Quit(); 240} 241 242void OneClickSigninBubbleView::Init() { 243 views::GridLayout* layout = new views::GridLayout(this); 244 SetLayoutManager(layout); 245 set_border(views::Border::CreateEmptyBorder(8, 8, 8, 8)); 246 247 // Column set for descriptive text and link. 248 views::ColumnSet* cs = layout->AddColumnSet(COLUMN_SET_FILL_ALIGN); 249 cs->AddColumn(views::GridLayout::FILL, views::GridLayout::CENTER, 1, 250 views::GridLayout::USE_PREF, 0, 0); 251 252 // Column set for buttons at bottom of bubble. 253 cs = layout->AddColumnSet(COLUMN_SET_CONTROLS); 254 cs->AddColumn(views::GridLayout::LEADING, views::GridLayout::CENTER, 0, 255 views::GridLayout::USE_PREF, 0, 0); 256 cs->AddPaddingColumn(1, views::kUnrelatedControlHorizontalSpacing); 257 cs->AddColumn(views::GridLayout::TRAILING, views::GridLayout::CENTER, 0, 258 views::GridLayout::USE_PREF, 0, 0); 259 cs->AddPaddingColumn(0, views::kRelatedButtonHSpacing); 260 cs->AddColumn(views::GridLayout::TRAILING, views::GridLayout::CENTER, 0, 261 views::GridLayout::USE_PREF, 0, 0); 262 263 InitContent(layout); 264 265 // Add controls at the bottom. 266 advanced_link_= GetAdvancedLink(); 267 GetButtons(&ok_button_, &undo_button_); 268 ok_button_->SetIsDefault(true); 269 270 layout->StartRow(0, COLUMN_SET_CONTROLS); 271 layout->AddView(advanced_link_); 272 layout->AddView(ok_button_); 273 layout->AddView(undo_button_); 274 275 AddAccelerator(ui::Accelerator(ui::VKEY_RETURN, 0)); 276} 277 278void OneClickSigninBubbleView::InitContent(views::GridLayout* layout) { 279 // Add main text description. 280 views::Label* label = new views::Label( 281 l10n_util::GetStringUTF16(IDS_ONE_CLICK_SIGNIN_BUBBLE_MESSAGE)); 282 label->SetMultiLine(true); 283 label->SetHorizontalAlignment(gfx::ALIGN_LEFT); 284 label->SizeToFit(kMinimumLabelWidth); 285 286 layout->StartRow(0, COLUMN_SET_FILL_ALIGN); 287 layout->AddView(label); 288 289 layout->AddPaddingRow(0, views::kRelatedControlSmallVerticalSpacing); 290} 291 292void OneClickSigninBubbleView::GetButtons(views::TextButton** ok_button, 293 views::TextButton** undo_button) { 294 *ok_button = new views::NativeTextButton(this); 295 *undo_button = new views::NativeTextButton(this); 296 297 // The default size of the buttons is too large. To allow them to be smaller 298 // ignore the minimum default size. Furthermore, to make sure they are the 299 // same size, SetText() is called with both strings on both buttons. 300 (*ok_button)->set_ignore_minimum_size(true); 301 (*undo_button)->set_ignore_minimum_size(true); 302 string16 ok_label = l10n_util::GetStringUTF16(IDS_OK); 303 string16 undo_label = l10n_util::GetStringUTF16(IDS_ONE_CLICK_BUBBLE_UNDO); 304 (*ok_button)->SetText(undo_label); 305 (*ok_button)->SetText(ok_label); 306 (*undo_button)->SetText(ok_label); 307 (*undo_button)->SetText(undo_label); 308} 309 310views::Link* OneClickSigninBubbleView::GetAdvancedLink() { 311 views::Link* advanced_link= new views::Link( 312 l10n_util::GetStringUTF16(IDS_SYNC_PROMO_NTP_BUBBLE_ADVANCED)); 313 advanced_link->set_listener(this); 314 advanced_link->SetHorizontalAlignment(gfx::ALIGN_LEFT); 315 return advanced_link; 316} 317 318void OneClickSigninBubbleView::WindowClosing() { 319 // We have to reset |bubble_view_| here, not in our destructor, because 320 // we'll be destroyed asynchronously and the shown state will be checked 321 // before then. 322 DCHECK_EQ(bubble_view_, this); 323 bubble_view_ = NULL; 324 325 if (!start_sync_callback_.is_null()) { 326 base::ResetAndReturn(&start_sync_callback_).Run( 327 OneClickSigninSyncStarter::SYNC_WITH_DEFAULT_SETTINGS); 328 } 329} 330 331bool OneClickSigninBubbleView::AcceleratorPressed( 332 const ui::Accelerator& accelerator) { 333 if (accelerator.key_code() == ui::VKEY_RETURN || 334 accelerator.key_code() == ui::VKEY_ESCAPE) { 335 StartFade(false); 336 if (accelerator.key_code() == ui::VKEY_RETURN) { 337 base::ResetAndReturn(&start_sync_callback_).Run( 338 OneClickSigninSyncStarter::SYNC_WITH_DEFAULT_SETTINGS); 339 } else { 340 start_sync_callback_.Reset(); 341 } 342 343 return true; 344 } 345 346 return BubbleDelegateView::AcceleratorPressed(accelerator); 347} 348 349void OneClickSigninBubbleView::LinkClicked(views::Link* source, 350 int event_flags) { 351 StartFade(false); 352 base::ResetAndReturn(&start_sync_callback_).Run( 353 OneClickSigninSyncStarter::CONFIGURE_SYNC_FIRST); 354} 355 356void OneClickSigninBubbleView::ButtonPressed(views::Button* sender, 357 const ui::Event& event) { 358 StartFade(false); 359 base::ResetAndReturn(&start_sync_callback_).Run((sender == ok_button_) ? 360 OneClickSigninSyncStarter::SYNC_WITH_DEFAULT_SETTINGS : 361 OneClickSigninSyncStarter::UNDO_SYNC); 362} 363