| OLD | NEW |
| (Empty) |
| 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/gtk/one_click_signin_bubble_gtk.h" | |
| 6 | |
| 7 #include <gtk/gtk.h> | |
| 8 | |
| 9 #include "base/callback_helpers.h" | |
| 10 #include "base/i18n/rtl.h" | |
| 11 #include "base/logging.h" | |
| 12 #include "base/message_loop/message_loop.h" | |
| 13 #include "base/strings/utf_string_conversions.h" | |
| 14 #include "chrome/browser/ui/browser.h" | |
| 15 #include "chrome/browser/ui/browser_finder.h" | |
| 16 #include "chrome/browser/ui/gtk/browser_toolbar_gtk.h" | |
| 17 #include "chrome/browser/ui/gtk/browser_window_gtk.h" | |
| 18 #include "chrome/browser/ui/gtk/gtk_theme_service.h" | |
| 19 #include "chrome/browser/ui/gtk/gtk_util.h" | |
| 20 #include "chrome/browser/ui/gtk/tabs/tab_strip_gtk.h" | |
| 21 #include "chrome/browser/ui/sync/one_click_signin_helper.h" | |
| 22 #include "chrome/browser/ui/sync/one_click_signin_histogram.h" | |
| 23 #include "chrome/common/url_constants.h" | |
| 24 #include "grit/chromium_strings.h" | |
| 25 #include "grit/generated_resources.h" | |
| 26 #include "ui/base/gtk/gtk_hig_constants.h" | |
| 27 #include "ui/base/l10n/l10n_util.h" | |
| 28 | |
| 29 static const int kModalDialogMessageWidth = 400; | |
| 30 | |
| 31 OneClickSigninBubbleGtk::OneClickSigninBubbleGtk( | |
| 32 BrowserWindowGtk* browser_window_gtk, | |
| 33 BrowserWindow::OneClickSigninBubbleType type, | |
| 34 const base::string16& email, | |
| 35 const base::string16& error_message, | |
| 36 const BrowserWindow::StartSyncCallback& start_sync_callback) | |
| 37 : bubble_(NULL), | |
| 38 email_(email), | |
| 39 error_message_(error_message), | |
| 40 start_sync_callback_(start_sync_callback), | |
| 41 is_sync_dialog_(type!=BrowserWindow::ONE_CLICK_SIGNIN_BUBBLE_TYPE_BUBBLE), | |
| 42 message_label_(NULL), | |
| 43 advanced_link_(NULL), | |
| 44 ok_button_(NULL), | |
| 45 undo_button_(NULL), | |
| 46 learn_more_(NULL), | |
| 47 header_label_(NULL), | |
| 48 clicked_learn_more_(false) { | |
| 49 InitializeWidgets(browser_window_gtk); | |
| 50 ShowWidget(browser_window_gtk, LayoutWidgets()); | |
| 51 } | |
| 52 | |
| 53 void OneClickSigninBubbleGtk::BubbleClosing( | |
| 54 BubbleGtk* bubble, bool closed_by_escape) { | |
| 55 // If we get here and |start_sync_callback_| is not null, act like this is | |
| 56 // an undo. All actions that start sign in are explicitly handled below. | |
| 57 if (is_sync_dialog_ && !start_sync_callback_.is_null()) { | |
| 58 base::ResetAndReturn(&start_sync_callback_).Run( | |
| 59 OneClickSigninSyncStarter::UNDO_SYNC); | |
| 60 } | |
| 61 | |
| 62 // The bubble needs to close and remove the widgets from the window before | |
| 63 // |close_button_| (which is a CustomDrawButton) can be destroyed, because it | |
| 64 // depends on all references being cleared for the GtkWidget before it is | |
| 65 // destroyed. | |
| 66 base::MessageLoopForUI::current()->DeleteSoon(FROM_HERE, | |
| 67 close_button_.release()); | |
| 68 | |
| 69 delete this; | |
| 70 } | |
| 71 | |
| 72 void OneClickSigninBubbleGtk::OnClickAdvancedLink(GtkWidget* link) { | |
| 73 if (is_sync_dialog_) { | |
| 74 OneClickSigninHelper::LogConfirmHistogramValue( | |
| 75 clicked_learn_more_ ? | |
| 76 one_click_signin::HISTOGRAM_CONFIRM_LEARN_MORE_ADVANCED : | |
| 77 one_click_signin::HISTOGRAM_CONFIRM_ADVANCED); | |
| 78 | |
| 79 base::ResetAndReturn(&start_sync_callback_).Run( | |
| 80 OneClickSigninSyncStarter::CONFIGURE_SYNC_FIRST); | |
| 81 } else { | |
| 82 Browser* browser = chrome::FindBrowserWithWindow( | |
| 83 gtk_window_get_transient_for(bubble_->GetNativeWindow())); | |
| 84 DCHECK(browser); | |
| 85 chrome::NavigateParams params(browser, GURL(chrome::kChromeUISettingsURL), | |
| 86 content::PAGE_TRANSITION_LINK); | |
| 87 params.disposition = CURRENT_TAB; | |
| 88 chrome::Navigate(¶ms); | |
| 89 } | |
| 90 bubble_->Close(); | |
| 91 } | |
| 92 | |
| 93 void OneClickSigninBubbleGtk::OnClickOK(GtkWidget* link) { | |
| 94 if (is_sync_dialog_) { | |
| 95 OneClickSigninHelper::LogConfirmHistogramValue( | |
| 96 clicked_learn_more_ ? | |
| 97 one_click_signin::HISTOGRAM_CONFIRM_LEARN_MORE_OK : | |
| 98 one_click_signin::HISTOGRAM_CONFIRM_OK); | |
| 99 | |
| 100 base::ResetAndReturn(&start_sync_callback_).Run( | |
| 101 OneClickSigninSyncStarter::SYNC_WITH_DEFAULT_SETTINGS); | |
| 102 } | |
| 103 bubble_->Close(); | |
| 104 } | |
| 105 | |
| 106 void OneClickSigninBubbleGtk::OnClickUndo(GtkWidget* link) { | |
| 107 if (is_sync_dialog_) { | |
| 108 OneClickSigninHelper::LogConfirmHistogramValue( | |
| 109 clicked_learn_more_ ? | |
| 110 one_click_signin::HISTOGRAM_CONFIRM_LEARN_MORE_UNDO : | |
| 111 one_click_signin::HISTOGRAM_CONFIRM_UNDO); | |
| 112 | |
| 113 base::ResetAndReturn(&start_sync_callback_).Run( | |
| 114 OneClickSigninSyncStarter::UNDO_SYNC); | |
| 115 } | |
| 116 bubble_->Close(); | |
| 117 } | |
| 118 | |
| 119 void OneClickSigninBubbleGtk::OnClickLearnMoreLink(GtkWidget* link) { | |
| 120 // We only want to log the Learn More click once per modal dialog instance. | |
| 121 if (is_sync_dialog_ && !clicked_learn_more_) { | |
| 122 OneClickSigninHelper::LogConfirmHistogramValue( | |
| 123 one_click_signin::HISTOGRAM_CONFIRM_LEARN_MORE); | |
| 124 clicked_learn_more_ = true; | |
| 125 } | |
| 126 Browser* browser = chrome::FindBrowserWithWindow( | |
| 127 gtk_window_get_transient_for(bubble_->GetNativeWindow())); | |
| 128 DCHECK(browser); | |
| 129 chrome::NavigateParams params(browser, GURL(chrome::kChromeSyncLearnMoreURL), | |
| 130 content::PAGE_TRANSITION_LINK); | |
| 131 params.disposition = NEW_WINDOW; | |
| 132 chrome::Navigate(¶ms); | |
| 133 | |
| 134 if (!is_sync_dialog_) { | |
| 135 bubble_->Close(); | |
| 136 } | |
| 137 } | |
| 138 | |
| 139 void OneClickSigninBubbleGtk::OnClickCloseButton(GtkWidget* button) { | |
| 140 DCHECK(is_sync_dialog_); | |
| 141 OneClickSigninHelper::LogConfirmHistogramValue( | |
| 142 clicked_learn_more_ ? | |
| 143 one_click_signin::HISTOGRAM_CONFIRM_LEARN_MORE_CLOSE : | |
| 144 one_click_signin::HISTOGRAM_CONFIRM_CLOSE); | |
| 145 base::ResetAndReturn(&start_sync_callback_).Run( | |
| 146 OneClickSigninSyncStarter::UNDO_SYNC); | |
| 147 bubble_->Close(); | |
| 148 } | |
| 149 | |
| 150 OneClickSigninBubbleGtk::~OneClickSigninBubbleGtk() { | |
| 151 } | |
| 152 | |
| 153 void OneClickSigninBubbleGtk::InitializeWidgets( | |
| 154 BrowserWindowGtk* browser_window_gtk) { | |
| 155 // Main dialog/bubble message. | |
| 156 std::string label_text; | |
| 157 if (is_sync_dialog_) { | |
| 158 label_text = | |
| 159 l10n_util::GetStringFUTF8(IDS_ONE_CLICK_SIGNIN_DIALOG_MESSAGE_NEW, | |
| 160 email_); | |
| 161 } else { | |
| 162 label_text = !error_message_.empty() ? base::UTF16ToUTF8(error_message_): | |
| 163 l10n_util::GetStringUTF8(IDS_ONE_CLICK_SIGNIN_BUBBLE_MESSAGE_FULL); | |
| 164 } | |
| 165 | |
| 166 message_label_ = gtk_label_new(label_text.c_str()); | |
| 167 gtk_label_set_line_wrap(GTK_LABEL(message_label_), TRUE); | |
| 168 gtk_misc_set_alignment(GTK_MISC(message_label_), 0.0, 0.5); | |
| 169 if (is_sync_dialog_) | |
| 170 gtk_widget_set_size_request(message_label_, kModalDialogMessageWidth, -1); | |
| 171 | |
| 172 GtkThemeService* const theme_provider = GtkThemeService::GetFrom( | |
| 173 browser_window_gtk->browser()->profile()); | |
| 174 | |
| 175 // Advanced link. Will not be displayed in the error bubble. | |
| 176 if (is_sync_dialog_ || error_message_.empty()) { | |
| 177 advanced_link_ = theme_provider->BuildChromeLinkButton( | |
| 178 l10n_util::GetStringUTF8( | |
| 179 IDS_ONE_CLICK_SIGNIN_DIALOG_ADVANCED)); | |
| 180 g_signal_connect(advanced_link_, "clicked", | |
| 181 G_CALLBACK(OnClickAdvancedLinkThunk), this); | |
| 182 } | |
| 183 | |
| 184 // The 'Learn More...' link. | |
| 185 learn_more_ = theme_provider->BuildChromeLinkButton( | |
| 186 l10n_util::GetStringUTF8(IDS_LEARN_MORE)); | |
| 187 g_signal_connect(learn_more_, "clicked", | |
| 188 G_CALLBACK(OnClickLearnMoreLinkThunk), this); | |
| 189 | |
| 190 // Make the OK and Undo buttons the same size horizontally. | |
| 191 GtkSizeGroup* size_group = gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL); | |
| 192 // OK Button. | |
| 193 ok_button_ = gtk_button_new_with_label(l10n_util::GetStringUTF8( | |
| 194 is_sync_dialog_ ? IDS_ONE_CLICK_SIGNIN_DIALOG_OK_BUTTON : | |
| 195 IDS_OK).c_str()); | |
| 196 g_signal_connect(ok_button_, "clicked", | |
| 197 G_CALLBACK(OnClickOKThunk), this); | |
| 198 gtk_size_group_add_widget(size_group, ok_button_); | |
| 199 | |
| 200 if (!is_sync_dialog_) | |
| 201 return; | |
| 202 | |
| 203 // The undo button is only in the modal dialog | |
| 204 undo_button_ = gtk_button_new_with_label(l10n_util::GetStringUTF8( | |
| 205 IDS_ONE_CLICK_SIGNIN_DIALOG_UNDO_BUTTON).c_str()); | |
| 206 g_signal_connect(undo_button_, "clicked", | |
| 207 G_CALLBACK(OnClickUndoThunk), this); | |
| 208 gtk_size_group_add_widget(size_group, undo_button_); | |
| 209 | |
| 210 g_object_unref(size_group); | |
| 211 | |
| 212 // The email is always set for the sync dialog. | |
| 213 header_label_ = theme_provider->BuildLabel( | |
| 214 l10n_util::GetStringUTF8(IDS_ONE_CLICK_SIGNIN_DIALOG_TITLE_NEW), | |
| 215 ui::kGdkBlack); | |
| 216 | |
| 217 PangoAttrList* attributes = pango_attr_list_new(); | |
| 218 pango_attr_list_insert(attributes, | |
| 219 pango_attr_weight_new(PANGO_WEIGHT_BOLD)); | |
| 220 gtk_label_set_attributes(GTK_LABEL(header_label_), attributes); | |
| 221 pango_attr_list_unref(attributes); | |
| 222 close_button_.reset(CustomDrawButton::CloseButtonBubble(theme_provider)); | |
| 223 g_signal_connect(close_button_->widget(), "clicked", | |
| 224 G_CALLBACK(OnClickCloseButtonThunk), this); | |
| 225 } | |
| 226 | |
| 227 GtkWidget* OneClickSigninBubbleGtk::LayoutWidgets() { | |
| 228 // Setup the BubbleGtk content. | |
| 229 GtkWidget* content_widget = gtk_vbox_new(FALSE, ui::kContentAreaSpacing); | |
| 230 gtk_container_set_border_width(GTK_CONTAINER(content_widget), | |
| 231 ui::kContentAreaBorder); | |
| 232 if (header_label_) { | |
| 233 GtkWidget* top_line = gtk_hbox_new(FALSE, ui::kControlSpacing); | |
| 234 gtk_box_pack_start(GTK_BOX(top_line), | |
| 235 header_label_, FALSE, FALSE, 0); | |
| 236 gtk_box_pack_end(GTK_BOX(top_line), | |
| 237 close_button_->widget(), FALSE, FALSE, 0); | |
| 238 gtk_box_pack_start(GTK_BOX(content_widget), | |
| 239 top_line, FALSE, FALSE, 0); | |
| 240 } | |
| 241 | |
| 242 gtk_box_pack_start(GTK_BOX(content_widget), | |
| 243 message_label_, FALSE, FALSE, 0); | |
| 244 | |
| 245 GtkWidget* box = gtk_hbox_new(FALSE, ui::kControlSpacing); | |
| 246 GtkWidget* bottom_line = gtk_hbox_new(FALSE, ui::kControlSpacing); | |
| 247 | |
| 248 if (is_sync_dialog_) { | |
| 249 gtk_box_pack_end(GTK_BOX(box), learn_more_, FALSE, FALSE, 0); | |
| 250 gtk_box_pack_start(GTK_BOX(content_widget), box, TRUE, TRUE, 0); | |
| 251 | |
| 252 gtk_box_pack_start(GTK_BOX(content_widget), bottom_line, FALSE, FALSE, 0); | |
| 253 gtk_box_pack_start(GTK_BOX(bottom_line), advanced_link_, FALSE, FALSE, 0); | |
| 254 gtk_box_pack_end(GTK_BOX(bottom_line), ok_button_, FALSE, FALSE, 0); | |
| 255 gtk_box_pack_end(GTK_BOX(bottom_line), undo_button_, FALSE, FALSE, 0); | |
| 256 } else { | |
| 257 gtk_box_pack_start(GTK_BOX(box), learn_more_, FALSE, FALSE, 0); | |
| 258 gtk_box_pack_start(GTK_BOX(content_widget), box, TRUE, TRUE, 0); | |
| 259 | |
| 260 // Don't display the Advanced link for the error bubble, and | |
| 261 // in this case align the OK button with the Learn More link. | |
| 262 if (error_message_.empty()) { | |
| 263 gtk_box_pack_start(GTK_BOX(bottom_line), advanced_link_, FALSE, FALSE, 0); | |
| 264 gtk_box_pack_end(GTK_BOX(bottom_line), ok_button_, FALSE, FALSE, 0); | |
| 265 gtk_box_pack_start(GTK_BOX(content_widget), bottom_line, FALSE, FALSE, 0); | |
| 266 } else { | |
| 267 gtk_box_pack_end(GTK_BOX(box), ok_button_, FALSE, FALSE, 0); | |
| 268 } | |
| 269 } | |
| 270 return content_widget; | |
| 271 } | |
| 272 | |
| 273 void OneClickSigninBubbleGtk::ShowWidget(BrowserWindowGtk* browser_window_gtk, | |
| 274 GtkWidget* content_widget) { | |
| 275 if (is_sync_dialog_) { | |
| 276 OneClickSigninHelper::LogConfirmHistogramValue( | |
| 277 one_click_signin::HISTOGRAM_CONFIRM_SHOWN); | |
| 278 } | |
| 279 | |
| 280 GtkThemeService* const theme_provider = GtkThemeService::GetFrom( | |
| 281 browser_window_gtk->browser()->profile()); | |
| 282 | |
| 283 GtkWidget* parent_widget = is_sync_dialog_ ? | |
| 284 browser_window_gtk->GetToolbar()->widget() : | |
| 285 browser_window_gtk->GetToolbar()->GetAppMenuButton(); | |
| 286 gfx::Rect bounds = gtk_util::WidgetBounds(parent_widget); | |
| 287 int flags = (is_sync_dialog_ ? BubbleGtk::NO_ACCELERATORS : | |
| 288 BubbleGtk::GRAB_INPUT) | | |
| 289 BubbleGtk::MATCH_SYSTEM_THEME | | |
| 290 BubbleGtk::POPUP_WINDOW; | |
| 291 bubble_ = BubbleGtk::Show(parent_widget, &bounds, content_widget, | |
| 292 is_sync_dialog_ ? BubbleGtk::CENTER_OVER_RECT : | |
| 293 BubbleGtk::ANCHOR_TOP_RIGHT, | |
| 294 flags, | |
| 295 theme_provider, this); | |
| 296 | |
| 297 gtk_window_set_transient_for(bubble_->GetNativeWindow(), | |
| 298 browser_window_gtk->GetNativeWindow()); | |
| 299 if (is_sync_dialog_) { | |
| 300 gtk_window_set_modal(bubble_->GetNativeWindow(), true); | |
| 301 gtk_window_set_focus(bubble_->GetNativeWindow(), ok_button_); | |
| 302 } else { | |
| 303 gtk_widget_grab_focus(ok_button_); | |
| 304 } | |
| 305 } | |
| OLD | NEW |