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 |