Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(218)

Side by Side Diff: chrome/browser/ui/gtk/first_run_dialog.cc

Issue 9285002: Remove the first-run search engine dialog/ballot. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Sync and merge. Created 8 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « chrome/browser/ui/gtk/first_run_dialog.h ('k') | chrome/browser/ui/views/first_run_bubble.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "chrome/browser/ui/gtk/first_run_dialog.h" 5 #include "chrome/browser/ui/gtk/first_run_dialog.h"
6 6
7 #include <string> 7 #include <string>
8 #include <vector> 8 #include <vector>
9 9
10 #include "base/i18n/rtl.h" 10 #include "base/i18n/rtl.h"
11 #include "base/message_loop.h" 11 #include "base/message_loop.h"
12 #include "base/utf_string_conversions.h" 12 #include "base/utf_string_conversions.h"
13 #include "chrome/browser/first_run/first_run_dialog.h" 13 #include "chrome/browser/first_run/first_run_dialog.h"
14 #include "chrome/browser/google/google_util.h" 14 #include "chrome/browser/google/google_util.h"
15 #include "chrome/browser/platform_util.h" 15 #include "chrome/browser/platform_util.h"
16 #include "chrome/browser/process_singleton.h" 16 #include "chrome/browser/process_singleton.h"
17 #include "chrome/browser/profiles/profile.h"
18 #include "chrome/browser/search_engines/template_url.h"
19 #include "chrome/browser/search_engines/template_url_service.h"
20 #include "chrome/browser/search_engines/template_url_service_factory.h"
21 #include "chrome/browser/shell_integration.h" 17 #include "chrome/browser/shell_integration.h"
22 #include "chrome/browser/ui/gtk/gtk_chrome_link_button.h" 18 #include "chrome/browser/ui/gtk/gtk_chrome_link_button.h"
23 #include "chrome/browser/ui/gtk/gtk_util.h" 19 #include "chrome/browser/ui/gtk/gtk_util.h"
24 #include "chrome/common/pref_names.h" 20 #include "chrome/common/pref_names.h"
25 #include "chrome/common/url_constants.h" 21 #include "chrome/common/url_constants.h"
26 #include "chrome/installer/util/google_update_settings.h" 22 #include "chrome/installer/util/google_update_settings.h"
27 #include "grit/chromium_strings.h" 23 #include "grit/chromium_strings.h"
28 #include "grit/generated_resources.h" 24 #include "grit/generated_resources.h"
29 #include "grit/locale_settings.h" 25 #include "grit/locale_settings.h"
30 #include "grit/theme_resources.h" 26 #include "grit/theme_resources.h"
31 #include "ui/base/gtk/gtk_floating_container.h" 27 #include "ui/base/gtk/gtk_floating_container.h"
32 #include "ui/base/gtk/gtk_hig_constants.h" 28 #include "ui/base/gtk/gtk_hig_constants.h"
33 #include "ui/base/l10n/l10n_util.h" 29 #include "ui/base/l10n/l10n_util.h"
34 #include "ui/base/resource/resource_bundle.h" 30 #include "ui/base/resource/resource_bundle.h"
35 #include "ui/gfx/image/image.h"
36 31
37 #if defined(USE_LINUX_BREAKPAD) 32 #if defined(USE_LINUX_BREAKPAD)
38 #include "chrome/app/breakpad_linux.h" 33 #include "chrome/app/breakpad_linux.h"
39 #endif 34 #endif
40 35
41 #if defined(GOOGLE_CHROME_BUILD) 36 #if defined(GOOGLE_CHROME_BUILD)
42 #include "chrome/browser/browser_process.h" 37 #include "chrome/browser/browser_process.h"
43 #include "chrome/browser/prefs/pref_service.h" 38 #include "chrome/browser/prefs/pref_service.h"
44 #endif 39 #endif
45 40
46 namespace { 41 namespace {
47 42
48 const gchar* kSearchEngineKey = "template-url-search-engine";
49
50 // Height of the label that displays the search engine's logo (in lieu of the
51 // actual logo) in chromium.
52 const int kLogoLabelHeight = 100;
53
54 // Size of the small logo (for when we show 4 search engines).
55 const int kLogoLabelWidthSmall = 132;
56 const int kLogoLabelHeightSmall = 88;
57
58 // The number of search engine options we normally show. It may be less than
59 // this number if there are not enough search engines for the current locale,
60 // or more if the user's imported default is not one of the top search engines
61 // for the current locale.
62 const size_t kNormalBallotSize = 3;
63
64 // The width of the explanatory label. The 180 is the width of the large images.
65 const int kExplanationWidth = kNormalBallotSize * 180;
66
67 // Horizontal spacing between search engine choices.
68 const int kSearchEngineSpacing = 6;
69
70 // Set the (x, y) coordinates of the welcome message (which floats on top of 43 // Set the (x, y) coordinates of the welcome message (which floats on top of
71 // the omnibox image at the top of the first run dialog). 44 // the omnibox image at the top of the first run dialog).
72 void SetWelcomePosition(GtkFloatingContainer* container, 45 void SetWelcomePosition(GtkFloatingContainer* container,
73 GtkAllocation* allocation, 46 GtkAllocation* allocation,
74 GtkWidget* label) { 47 GtkWidget* label) {
75 GValue value = { 0, }; 48 GValue value = { 0, };
76 g_value_init(&value, G_TYPE_INT); 49 g_value_init(&value, G_TYPE_INT);
77 50
78 GtkRequisition req; 51 GtkRequisition req;
79 gtk_widget_size_request(label, &req); 52 gtk_widget_size_request(label, &req);
80 53
81 int x = base::i18n::IsRTL() ? 54 int x = base::i18n::IsRTL() ?
82 allocation->width - req.width - ui::kContentAreaSpacing : 55 allocation->width - req.width - ui::kContentAreaSpacing :
83 ui::kContentAreaSpacing; 56 ui::kContentAreaSpacing;
84 g_value_set_int(&value, x); 57 g_value_set_int(&value, x);
85 gtk_container_child_set_property(GTK_CONTAINER(container), 58 gtk_container_child_set_property(GTK_CONTAINER(container),
86 label, "x", &value); 59 label, "x", &value);
87 60
88 int y = allocation->height / 2 - req.height / 2; 61 int y = allocation->height / 2 - req.height / 2;
89 g_value_set_int(&value, y); 62 g_value_set_int(&value, y);
90 gtk_container_child_set_property(GTK_CONTAINER(container), 63 gtk_container_child_set_property(GTK_CONTAINER(container),
91 label, "y", &value); 64 label, "y", &value);
92 g_value_unset(&value); 65 g_value_unset(&value);
93 } 66 }
94 67
95 } // namespace 68 } // namespace
96 69
97 namespace first_run { 70 namespace first_run {
98 71
99 void ShowFirstRunDialog(Profile* profile, 72 void ShowFirstRunDialog(Profile* profile) {
100 bool randomize_search_engine_order) { 73 FirstRunDialog::Show();
101 FirstRunDialog::Show(profile, randomize_search_engine_order);
102 } 74 }
103 75
104 } // namespace first_run 76 } // namespace first_run
105 77
106 // static 78 // static
107 bool FirstRunDialog::Show(Profile* profile, 79 bool FirstRunDialog::Show() {
108 bool randomize_search_engine_order) {
109 // Figure out which dialogs we will show.
110 // If the default search is managed via policy, we won't ask.
111 const TemplateURLService* search_engines_model =
112 TemplateURLServiceFactory::GetForProfile(profile);
113 bool show_search_engines_dialog =
114 first_run::ShouldShowSearchEngineSelector(search_engines_model);
115
116 #if defined(GOOGLE_CHROME_BUILD) 80 #if defined(GOOGLE_CHROME_BUILD)
117 // If the metrics reporting is managed, we won't ask. 81 // If the metrics reporting is managed, we won't ask.
118 const PrefService::Preference* metrics_reporting_pref = 82 const PrefService::Preference* metrics_reporting_pref =
119 g_browser_process->local_state()->FindPreference( 83 g_browser_process->local_state()->FindPreference(
120 prefs::kMetricsReportingEnabled); 84 prefs::kMetricsReportingEnabled);
121 bool show_reporting_dialog = !metrics_reporting_pref || 85 bool show_reporting_dialog = !metrics_reporting_pref ||
122 !metrics_reporting_pref->IsManaged(); 86 !metrics_reporting_pref->IsManaged();
123 #else 87 #else
124 bool show_reporting_dialog = false; 88 bool show_reporting_dialog = false;
125 #endif 89 #endif
126 90
127 if (!show_search_engines_dialog && !show_reporting_dialog) 91 if (!show_reporting_dialog)
128 return true; // Nothing to do 92 return true; // Nothing to do
129 93
130 int response = -1; 94 int response = -1;
131 // Object deletes itself. 95 // Object deletes itself.
132 new FirstRunDialog(profile, 96 new FirstRunDialog(show_reporting_dialog, &response);
133 show_reporting_dialog,
134 show_search_engines_dialog,
135 &response);
136 97
137 // TODO(port): it should be sufficient to just run the dialog: 98 // TODO(port): it should be sufficient to just run the dialog:
138 // int response = gtk_dialog_run(GTK_DIALOG(dialog)); 99 // int response = gtk_dialog_run(GTK_DIALOG(dialog));
139 // but that spins a nested message loop and hoses us. :( 100 // but that spins a nested message loop and hoses us. :(
140 // http://code.google.com/p/chromium/issues/detail?id=12552 101 // http://code.google.com/p/chromium/issues/detail?id=12552
141 // Instead, run a loop and extract the response manually. 102 // Instead, run a loop and extract the response manually.
142 MessageLoop::current()->Run(); 103 MessageLoop::current()->Run();
143 104
144 return (response == GTK_RESPONSE_ACCEPT); 105 return (response == GTK_RESPONSE_ACCEPT);
145 } 106 }
146 107
147 FirstRunDialog::FirstRunDialog(Profile* profile, 108 FirstRunDialog::FirstRunDialog(bool show_reporting_dialog, int* response)
148 bool show_reporting_dialog, 109 : dialog_(NULL),
149 bool show_search_engines_dialog,
150 int* response)
151 : search_engine_window_(NULL),
152 dialog_(NULL),
153 report_crashes_(NULL), 110 report_crashes_(NULL),
154 make_default_(NULL), 111 make_default_(NULL),
155 profile_(profile),
156 chosen_search_engine_(NULL),
157 show_reporting_dialog_(show_reporting_dialog), 112 show_reporting_dialog_(show_reporting_dialog),
158 response_(response) { 113 response_(response) {
159 if (!show_search_engines_dialog) { 114 ShowReportingDialog();
160 ShowReportingDialog();
161 return;
162 }
163 search_engines_model_ = TemplateURLServiceFactory::GetForProfile(profile_);
164
165 ShowSearchEngineWindow();
166
167 search_engines_model_->AddObserver(this);
168 if (search_engines_model_->loaded())
169 OnTemplateURLServiceChanged();
170 else
171 search_engines_model_->Load();
172 } 115 }
173 116
174 FirstRunDialog::~FirstRunDialog() { 117 FirstRunDialog::~FirstRunDialog() {
175 } 118 }
176 119
177 void FirstRunDialog::ShowSearchEngineWindow() {
178 search_engine_window_ = gtk_window_new(GTK_WINDOW_TOPLEVEL);
179 gtk_window_set_deletable(GTK_WINDOW(search_engine_window_), FALSE);
180 gtk_window_set_title(
181 GTK_WINDOW(search_engine_window_),
182 l10n_util::GetStringUTF8(IDS_FIRSTRUN_DLG_TITLE).c_str());
183 gtk_window_set_resizable(GTK_WINDOW(search_engine_window_), FALSE);
184 g_signal_connect(search_engine_window_, "destroy",
185 G_CALLBACK(OnSearchEngineWindowDestroyThunk), this);
186 GtkWidget* content_area = gtk_vbox_new(FALSE, 0);
187 gtk_container_add(GTK_CONTAINER(search_engine_window_), content_area);
188
189 GdkPixbuf* pixbuf =
190 ui::ResourceBundle::GetSharedInstance().GetRTLEnabledPixbufNamed(
191 IDR_SEARCH_ENGINE_DIALOG_TOP);
192 GtkWidget* top_image = gtk_image_new_from_pixbuf(pixbuf);
193 // Right align the image.
194 gtk_misc_set_alignment(GTK_MISC(top_image), 1, 0);
195 gtk_widget_set_size_request(top_image, 0, -1);
196
197 GtkWidget* welcome_message = gtk_util::CreateBoldLabel(
198 l10n_util::GetStringUTF8(IDS_FR_SEARCH_MAIN_LABEL));
199 // Force the font size to make sure the label doesn't overlap the image.
200 // 13.4px == 10pt @ 96dpi
201 gtk_util::ForceFontSizePixels(welcome_message, 13.4);
202
203 GtkWidget* top_area = gtk_floating_container_new();
204 gtk_container_add(GTK_CONTAINER(top_area), top_image);
205 gtk_floating_container_add_floating(GTK_FLOATING_CONTAINER(top_area),
206 welcome_message);
207 g_signal_connect(top_area, "set-floating-position",
208 G_CALLBACK(SetWelcomePosition), welcome_message);
209
210 gtk_box_pack_start(GTK_BOX(content_area), top_area,
211 FALSE, FALSE, 0);
212
213 GtkWidget* bubble_area_background = gtk_event_box_new();
214 gtk_widget_modify_bg(bubble_area_background,
215 GTK_STATE_NORMAL, &ui::kGdkWhite);
216
217 GtkWidget* bubble_area_box = gtk_vbox_new(FALSE, 0);
218 gtk_container_set_border_width(GTK_CONTAINER(bubble_area_box),
219 ui::kContentAreaSpacing);
220 gtk_container_add(GTK_CONTAINER(bubble_area_background),
221 bubble_area_box);
222
223 GtkWidget* explanation = gtk_label_new(
224 l10n_util::GetStringFUTF8(IDS_FR_SEARCH_TEXT,
225 l10n_util::GetStringUTF16(IDS_PRODUCT_NAME)).c_str());
226 gtk_util::SetLabelColor(explanation, &ui::kGdkBlack);
227 gtk_util::SetLabelWidth(explanation, kExplanationWidth);
228 gtk_box_pack_start(GTK_BOX(bubble_area_box), explanation, FALSE, FALSE, 0);
229
230 // We will fill this in after the TemplateURLService has loaded.
231 // GtkHButtonBox because we want all children to have the same size.
232 search_engine_hbox_ = gtk_hbutton_box_new();
233 gtk_box_set_spacing(GTK_BOX(search_engine_hbox_), kSearchEngineSpacing);
234 gtk_box_pack_start(GTK_BOX(bubble_area_box), search_engine_hbox_,
235 FALSE, FALSE, 0);
236
237 gtk_box_pack_start(GTK_BOX(content_area), bubble_area_background,
238 TRUE, TRUE, 0);
239
240 gtk_widget_show_all(content_area);
241 gtk_window_present(GTK_WINDOW(search_engine_window_));
242 }
243
244 void FirstRunDialog::ShowReportingDialog() { 120 void FirstRunDialog::ShowReportingDialog() {
245 // The purpose of the dialog is to ask the user to enable stats and crash 121 // The purpose of the dialog is to ask the user to enable stats and crash
246 // reporting. This setting may be controlled through configuration management 122 // reporting. This setting may be controlled through configuration management
247 // in enterprise scenarios. If that is the case, skip the dialog entirely, 123 // in enterprise scenarios. If that is the case, skip the dialog entirely,
248 // it's not worth bothering the user for only the default browser question 124 // it's not worth bothering the user for only the default browser question
249 // (which is likely to be forced in enterprise deployments anyway). 125 // (which is likely to be forced in enterprise deployments anyway).
250 if (!show_reporting_dialog_) { 126 if (!show_reporting_dialog_) {
251 OnResponseDialog(NULL, GTK_RESPONSE_ACCEPT); 127 OnResponseDialog(NULL, GTK_RESPONSE_ACCEPT);
252 return; 128 return;
253 } 129 }
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after
292 g_signal_connect(learn_more_link, "clicked", 168 g_signal_connect(learn_more_link, "clicked",
293 G_CALLBACK(OnLearnMoreLinkClickedThunk), this); 169 G_CALLBACK(OnLearnMoreLinkClickedThunk), this);
294 170
295 gtk_box_pack_start(GTK_BOX(content_area), learn_more_vbox, FALSE, FALSE, 0); 171 gtk_box_pack_start(GTK_BOX(content_area), learn_more_vbox, FALSE, FALSE, 0);
296 172
297 g_signal_connect(dialog_, "response", 173 g_signal_connect(dialog_, "response",
298 G_CALLBACK(OnResponseDialogThunk), this); 174 G_CALLBACK(OnResponseDialogThunk), this);
299 gtk_widget_show_all(dialog_); 175 gtk_widget_show_all(dialog_);
300 } 176 }
301 177
302 void FirstRunDialog::OnTemplateURLServiceChanged() {
303 // We only watch the search engine model change once, on load. Remove
304 // observer so we don't try to redraw if engines change under us.
305 search_engines_model_->RemoveObserver(this);
306
307 // Add search engines in |search_engines_model_| to buttons list.
308 std::vector<const TemplateURL*> ballot_engines =
309 search_engines_model_->GetTemplateURLs();
310 // Drop any not in the first 3.
311 if (ballot_engines.size() > kNormalBallotSize)
312 ballot_engines.resize(kNormalBallotSize);
313
314 const TemplateURL* default_search_engine =
315 search_engines_model_->GetDefaultSearchProvider();
316 if (std::find(ballot_engines.begin(),
317 ballot_engines.end(),
318 default_search_engine) ==
319 ballot_engines.end()) {
320 ballot_engines.push_back(default_search_engine);
321 }
322
323 std::string choose_text = l10n_util::GetStringUTF8(IDS_FR_SEARCH_CHOOSE);
324 for (std::vector<const TemplateURL*>::iterator search_engine_iter =
325 ballot_engines.begin();
326 search_engine_iter < ballot_engines.end();
327 ++search_engine_iter) {
328 // Create a container for the search engine widgets.
329 GtkWidget* vbox = gtk_vbox_new(FALSE, ui::kControlSpacing);
330
331 // We show text on Chromium and images on Google Chrome.
332 bool show_images = false;
333 #if defined(GOOGLE_CHROME_BUILD)
334 show_images = true;
335 #endif
336
337 // Create the image (maybe).
338 int logo_id = (*search_engine_iter)->logo_id();
339 if (show_images && logo_id > 0) {
340 GdkPixbuf* pixbuf =
341 ui::ResourceBundle::GetSharedInstance().GetNativeImageNamed(logo_id);
342 if (ballot_engines.size() > kNormalBallotSize) {
343 GdkPixbuf* old = pixbuf;
344 pixbuf = gdk_pixbuf_scale_simple(pixbuf,
345 kLogoLabelWidthSmall,
346 kLogoLabelHeightSmall,
347 GDK_INTERP_HYPER);
348 g_object_unref(old);
349 } else {
350 g_object_ref(pixbuf);
351 }
352
353 GtkWidget* image = gtk_image_new_from_pixbuf(pixbuf);
354 gtk_box_pack_start(GTK_BOX(vbox), image, FALSE, FALSE, 0);
355 g_object_unref(pixbuf);
356 } else {
357 GtkWidget* logo_label = gtk_label_new(NULL);
358 char* markup = g_markup_printf_escaped(
359 "<span weight='bold' size='x-large' color='black'>%s</span>",
360 UTF16ToUTF8((*search_engine_iter)->short_name()).c_str());
361 gtk_label_set_markup(GTK_LABEL(logo_label), markup);
362 g_free(markup);
363 gtk_widget_set_size_request(logo_label, -1,
364 ballot_engines.size() > kNormalBallotSize ? kLogoLabelHeightSmall :
365 kLogoLabelHeight);
366 gtk_box_pack_start(GTK_BOX(vbox), logo_label, FALSE, FALSE, 0);
367 }
368
369 // Create the button.
370 GtkWidget* button = gtk_button_new_with_label(choose_text.c_str());
371 g_signal_connect(button, "clicked",
372 G_CALLBACK(OnSearchEngineButtonClickedThunk), this);
373 g_object_set_data(G_OBJECT(button), kSearchEngineKey,
374 const_cast<TemplateURL*>(*search_engine_iter));
375
376 GtkWidget* button_centerer = gtk_hbox_new(FALSE, 0);
377 gtk_box_pack_start(GTK_BOX(button_centerer), button, TRUE, FALSE, 0);
378 gtk_box_pack_start(GTK_BOX(vbox), button_centerer, FALSE, FALSE, 0);
379
380 gtk_container_add(GTK_CONTAINER(search_engine_hbox_), vbox);
381 gtk_widget_show_all(search_engine_hbox_);
382 }
383 }
384
385 void FirstRunDialog::OnSearchEngineButtonClicked(GtkWidget* sender) {
386 chosen_search_engine_ = static_cast<TemplateURL*>(
387 g_object_get_data(G_OBJECT(sender), kSearchEngineKey));
388 gtk_widget_destroy(search_engine_window_);
389 }
390
391 void FirstRunDialog::OnSearchEngineWindowDestroy(GtkWidget* sender) {
392 search_engine_window_ = NULL;
393 if (chosen_search_engine_) {
394 search_engines_model_->SetDefaultSearchProvider(chosen_search_engine_);
395 ShowReportingDialog();
396 } else {
397 FirstRunDone();
398 }
399 }
400
401 void FirstRunDialog::OnResponseDialog(GtkWidget* widget, int response) { 178 void FirstRunDialog::OnResponseDialog(GtkWidget* widget, int response) {
402 if (dialog_) 179 if (dialog_)
403 gtk_widget_hide_all(dialog_); 180 gtk_widget_hide_all(dialog_);
404 *response_ = response; 181 *response_ = response;
405 182
406 // Mark that first run has ran. 183 // Mark that first run has ran.
407 first_run::CreateSentinel(); 184 first_run::CreateSentinel();
408 185
409 // Check if user has opted into reporting. 186 // Check if user has opted into reporting.
410 if (report_crashes_ && 187 if (report_crashes_ &&
(...skipping 21 matching lines...) Expand all
432 } 209 }
433 210
434 void FirstRunDialog::FirstRunDone() { 211 void FirstRunDialog::FirstRunDone() {
435 first_run::SetShowWelcomePagePref(); 212 first_run::SetShowWelcomePagePref();
436 213
437 if (dialog_) 214 if (dialog_)
438 gtk_widget_destroy(dialog_); 215 gtk_widget_destroy(dialog_);
439 MessageLoop::current()->Quit(); 216 MessageLoop::current()->Quit();
440 delete this; 217 delete this;
441 } 218 }
OLDNEW
« no previous file with comments | « chrome/browser/ui/gtk/first_run_dialog.h ('k') | chrome/browser/ui/views/first_run_bubble.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698