OLD | NEW |
1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2009 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/gtk/about_chrome_dialog.h" | 5 #include "chrome/browser/gtk/about_chrome_dialog.h" |
6 | 6 |
7 #include <gtk/gtk.h> | 7 #include <gtk/gtk.h> |
8 #include <wchar.h> | |
9 | 8 |
10 #include "app/l10n_util.h" | 9 #include "app/l10n_util.h" |
11 #include "app/resource_bundle.h" | 10 #include "app/resource_bundle.h" |
12 #include "base/file_version_info.h" | 11 #include "base/file_version_info.h" |
13 #include "base/gfx/gtk_util.h" | 12 #include "base/gfx/gtk_util.h" |
| 13 #include "chrome/browser/browser_list.h" |
| 14 #include "chrome/browser/gtk/gtk_chrome_link_button.h" |
| 15 #include "chrome/browser/profile.h" |
14 #include "chrome/common/chrome_constants.h" | 16 #include "chrome/common/chrome_constants.h" |
15 #include "chrome/browser/profile.h" | |
16 #include "chrome/common/gtk_util.h" | 17 #include "chrome/common/gtk_util.h" |
17 #include "grit/chromium_strings.h" | 18 #include "grit/chromium_strings.h" |
18 #include "grit/generated_resources.h" | 19 #include "grit/generated_resources.h" |
19 #include "grit/locale_settings.h" | 20 #include "grit/locale_settings.h" |
20 #include "grit/theme_resources.h" | 21 #include "grit/theme_resources.h" |
21 #include "webkit/glue/webkit_glue.h" | 22 #include "webkit/glue/webkit_glue.h" |
22 | 23 |
23 namespace { | 24 namespace { |
24 // The pixel width of the version text field. Ideally, we'd like to have the | |
25 // bounds set to the edge of the icon. However, the icon is not a view but a | |
26 // part of the background, so we have to hard code the width to make sure | |
27 // the version field doesn't overlap it. | |
28 const int kVersionFieldWidth = 195; | |
29 | 25 |
30 // The URLs that you navigate to when clicking the links in the About dialog. | 26 // The URLs that you navigate to when clicking the links in the About dialog. |
31 const wchar_t* const kChromiumUrl = L"http://www.chromium.org/"; | 27 const char* const kAcknowledgements = "about:credits"; |
32 const wchar_t* const kAcknowledgements = L"about:credits"; | 28 const char* const kTOS = "about:terms"; |
33 const wchar_t* const kTOS = L"about:terms"; | |
34 | 29 |
35 // Left or right margin. | 30 // Left or right margin. |
36 const int kPanelHorizMargin = 13; | 31 const int kPanelHorizMargin = 13; |
37 | 32 |
38 // Top or bottom margin. | 33 // Top or bottom margin. |
39 const int kPanelVertMargin = 13; | 34 const int kPanelVertMargin = 20; |
| 35 |
| 36 // Extra spacing between product name and version number. |
| 37 const int kExtraLineSpacing = 5; |
40 | 38 |
41 // These are used as placeholder text around the links in the text in the about | 39 // These are used as placeholder text around the links in the text in the about |
42 // dialog. | 40 // dialog. |
43 const wchar_t* kBeginLinkChr = L"BEGIN_LINK_CHR"; | 41 const char* kBeginLinkChr = "BEGIN_LINK_CHR"; |
44 const wchar_t* kBeginLinkOss = L"BEGIN_LINK_OSS"; | 42 const char* kBeginLinkOss = "BEGIN_LINK_OSS"; |
45 const wchar_t* kEndLinkChr = L"END_LINK_CHR"; | 43 // We don't actually use this one. |
46 const wchar_t* kEndLinkOss = L"END_LINK_OSS"; | 44 // const char* kEndLinkChr = "END_LINK_CHR"; |
47 const wchar_t* kBeginLink = L"BEGIN_LINK"; | 45 const char* kEndLinkOss = "END_LINK_OSS"; |
48 const wchar_t* kEndLink = L"END_LINK"; | 46 const char* kBeginLink = "BEGIN_LINK"; |
49 | 47 const char* kEndLink = "END_LINK"; |
50 void RemoveText(std::wstring* text, const wchar_t* to_remove) { | |
51 size_t start = text->find(to_remove, 0); | |
52 if (start != std::string::npos) { | |
53 size_t length = wcslen(to_remove); | |
54 *text = text->substr(0, start) + text->substr(start + length); | |
55 } | |
56 } | |
57 | 48 |
58 void OnDialogResponse(GtkDialog* dialog, int response_id) { | 49 void OnDialogResponse(GtkDialog* dialog, int response_id) { |
59 // We're done. | 50 // We're done. |
60 gtk_widget_destroy(GTK_WIDGET(dialog)); | 51 gtk_widget_destroy(GTK_WIDGET(dialog)); |
61 } | 52 } |
62 | 53 |
63 void FixLabelWrappingCallback(GtkWidget *label, | 54 void FixLabelWrappingCallback(GtkWidget *label, |
64 GtkAllocation *allocation, | 55 GtkAllocation *allocation, |
65 gpointer data) { | 56 gpointer data) { |
66 gtk_widget_set_size_request(label, allocation->width, -1); | 57 gtk_widget_set_size_request(label, allocation->width, -1); |
67 } | 58 } |
68 | 59 |
69 GtkWidget* MakeMarkupLabel(const char* format, const std::wstring& str) { | 60 GtkWidget* MakeMarkupLabel(const char* format, const std::string& str) { |
70 GtkWidget* label = gtk_label_new(NULL); | 61 GtkWidget* label = gtk_label_new(NULL); |
71 char* markup = g_markup_printf_escaped( | 62 char* markup = g_markup_printf_escaped(format, str.c_str()); |
72 format, WideToUTF8(str).c_str()); | |
73 gtk_label_set_markup(GTK_LABEL(label), markup); | 63 gtk_label_set_markup(GTK_LABEL(label), markup); |
74 g_free(markup); | 64 g_free(markup); |
75 | 65 |
| 66 // Left align it. |
| 67 gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5); |
| 68 |
76 return label; | 69 return label; |
77 } | 70 } |
78 | 71 |
| 72 void OnLinkButtonClick(GtkWidget* button, const char* url) { |
| 73 BrowserList::GetLastActive()-> |
| 74 OpenURL(GURL(url), GURL(), NEW_WINDOW, PageTransition::LINK); |
| 75 } |
| 76 |
| 77 const char* GetChromiumUrl() { |
| 78 static std::string url(l10n_util::GetStringUTF8(IDS_CHROMIUM_PROJECT_URL)); |
| 79 return url.c_str(); |
| 80 } |
| 81 |
79 } // namespace | 82 } // namespace |
80 | 83 |
81 void ShowAboutDialogForProfile(GtkWindow* parent, Profile* profile) { | 84 void ShowAboutDialogForProfile(GtkWindow* parent, Profile* profile) { |
82 ResourceBundle& rb = ResourceBundle::GetSharedInstance(); | 85 ResourceBundle& rb = ResourceBundle::GetSharedInstance(); |
83 static GdkPixbuf* background = rb.GetPixbufNamed(IDR_ABOUT_BACKGROUND); | 86 static GdkPixbuf* background = rb.GetPixbufNamed(IDR_ABOUT_BACKGROUND); |
84 scoped_ptr<FileVersionInfo> version_info( | 87 scoped_ptr<FileVersionInfo> version_info( |
85 FileVersionInfo::CreateFileVersionInfoForCurrentModule()); | 88 FileVersionInfo::CreateFileVersionInfoForCurrentModule()); |
86 std::wstring current_version = version_info->file_version(); | 89 std::wstring current_version = version_info->file_version(); |
87 #if !defined(GOOGLE_CHROME_BUILD) | 90 #if !defined(GOOGLE_CHROME_BUILD) |
88 current_version += L" ("; | 91 current_version += L" ("; |
(...skipping 20 matching lines...) Expand all Loading... |
109 GtkWidget* ebox = gtk_event_box_new(); | 112 GtkWidget* ebox = gtk_event_box_new(); |
110 gtk_widget_modify_bg(ebox, GTK_STATE_NORMAL, &gfx::kGdkWhite); | 113 gtk_widget_modify_bg(ebox, GTK_STATE_NORMAL, &gfx::kGdkWhite); |
111 | 114 |
112 GtkWidget* hbox = gtk_hbox_new(FALSE, 0); | 115 GtkWidget* hbox = gtk_hbox_new(FALSE, 0); |
113 | 116 |
114 GtkWidget* text_alignment = gtk_alignment_new(0.0, 0.0, 1.0, 1.0); | 117 GtkWidget* text_alignment = gtk_alignment_new(0.0, 0.0, 1.0, 1.0); |
115 gtk_alignment_set_padding(GTK_ALIGNMENT(text_alignment), | 118 gtk_alignment_set_padding(GTK_ALIGNMENT(text_alignment), |
116 kPanelVertMargin, kPanelVertMargin, | 119 kPanelVertMargin, kPanelVertMargin, |
117 kPanelHorizMargin, kPanelHorizMargin); | 120 kPanelHorizMargin, kPanelHorizMargin); |
118 | 121 |
119 GtkWidget* text_vbox = gtk_vbox_new(FALSE, 0); | 122 GtkWidget* text_vbox = gtk_vbox_new(FALSE, kExtraLineSpacing); |
120 | 123 |
121 GtkWidget* product_label = MakeMarkupLabel( | 124 GtkWidget* product_label = MakeMarkupLabel( |
122 "<span font_desc=\"18\" weight=\"bold\" style=\"normal\">%s</span>", | 125 "<span font_desc=\"18\" weight=\"bold\" style=\"normal\">%s</span>", |
123 l10n_util::GetString(IDS_PRODUCT_NAME)); | 126 l10n_util::GetStringUTF8(IDS_PRODUCT_NAME)); |
124 gtk_box_pack_start(GTK_BOX(text_vbox), product_label, FALSE, FALSE, 0); | 127 gtk_box_pack_start(GTK_BOX(text_vbox), product_label, FALSE, FALSE, 0); |
125 | 128 |
126 GtkWidget* version_label = MakeMarkupLabel( | 129 GtkWidget* version_label = gtk_label_new(WideToUTF8(current_version).c_str()); |
127 "<span style=\"italic\">%s</span>", | 130 gtk_misc_set_alignment(GTK_MISC(version_label), 0.0, 0.5); |
128 current_version); | |
129 gtk_label_set_selectable(GTK_LABEL(version_label), TRUE); | 131 gtk_label_set_selectable(GTK_LABEL(version_label), TRUE); |
130 gtk_box_pack_start(GTK_BOX(text_vbox), version_label, FALSE, FALSE, 0); | 132 gtk_box_pack_start(GTK_BOX(text_vbox), version_label, FALSE, FALSE, 0); |
131 | 133 |
132 gtk_container_add(GTK_CONTAINER(text_alignment), text_vbox); | 134 gtk_container_add(GTK_CONTAINER(text_alignment), text_vbox); |
133 gtk_box_pack_start(GTK_BOX(hbox), text_alignment, TRUE, FALSE, 0); | 135 gtk_box_pack_start(GTK_BOX(hbox), text_alignment, TRUE, TRUE, 0); |
134 | 136 |
135 GtkWidget* image_vbox = gtk_vbox_new(FALSE, 0); | 137 GtkWidget* image_vbox = gtk_vbox_new(FALSE, 0); |
136 gtk_box_pack_end(GTK_BOX(image_vbox), | 138 gtk_box_pack_end(GTK_BOX(image_vbox), |
137 gtk_image_new_from_pixbuf(background), | 139 gtk_image_new_from_pixbuf(background), |
138 FALSE, FALSE, 0); | 140 FALSE, FALSE, 0); |
139 | 141 |
140 gtk_box_pack_start(GTK_BOX(hbox), image_vbox, FALSE, FALSE, 0); | 142 gtk_box_pack_start(GTK_BOX(hbox), image_vbox, FALSE, FALSE, 0); |
141 gtk_container_add(GTK_CONTAINER(ebox), hbox); | 143 gtk_container_add(GTK_CONTAINER(ebox), hbox); |
142 gtk_box_pack_start(GTK_BOX(content_area), ebox, TRUE, TRUE, 0); | 144 gtk_box_pack_start(GTK_BOX(content_area), ebox, TRUE, TRUE, 0); |
143 | 145 |
144 // We use a separate box for the licensing etc. text. See the comment near | 146 // We use a separate box for the licensing etc. text. See the comment near |
145 // the top of this function about using a special layout for this dialog. | 147 // the top of this function about using a special layout for this dialog. |
146 GtkWidget* vbox = gtk_vbox_new(FALSE, gtk_util::kControlSpacing); | 148 GtkWidget* vbox = gtk_vbox_new(FALSE, gtk_util::kControlSpacing); |
147 gtk_container_set_border_width(GTK_CONTAINER(vbox), | 149 gtk_container_set_border_width(GTK_CONTAINER(vbox), |
148 gtk_util::kContentAreaBorder); | 150 gtk_util::kContentAreaBorder); |
149 | 151 |
150 GtkWidget* copyright_label = MakeMarkupLabel( | 152 GtkWidget* copyright_label = MakeMarkupLabel( |
151 "<span size=\"smaller\">%s</span>", | 153 "<span size=\"smaller\">%s</span>", |
152 l10n_util::GetString(IDS_ABOUT_VERSION_COPYRIGHT)); | 154 l10n_util::GetStringUTF8(IDS_ABOUT_VERSION_COPYRIGHT)); |
153 gtk_box_pack_start(GTK_BOX(vbox), copyright_label, TRUE, TRUE, 5); | 155 gtk_box_pack_start(GTK_BOX(vbox), copyright_label, TRUE, TRUE, 5); |
154 | 156 |
155 // TODO(erg): Figure out how to really insert links. We could just depend on | 157 std::string license = l10n_util::GetStringUTF8(IDS_ABOUT_VERSION_LICENSE); |
156 // (or include the source of) libsexy's SexyUrlLabel gtk widget... | 158 bool chromium_url_appears_first = |
157 std::wstring license = l10n_util::GetString(IDS_ABOUT_VERSION_LICENSE); | 159 license.find(kBeginLinkChr) < license.find(kBeginLinkOss); |
158 RemoveText(&license, kBeginLinkChr); | 160 size_t link1 = license.find(kBeginLink); |
159 RemoveText(&license, kBeginLinkOss); | 161 DCHECK(link1 != std::string::npos); |
160 RemoveText(&license, kBeginLink); | 162 size_t link1_end = license.find(kEndLink, link1); |
161 RemoveText(&license, kEndLinkChr); | 163 DCHECK(link1_end != std::string::npos); |
162 RemoveText(&license, kEndLinkOss); | 164 size_t link2 = license.find(kBeginLink, link1_end); |
163 RemoveText(&license, kEndLink); | 165 DCHECK(link2 != std::string::npos); |
| 166 size_t link2_end = license.find(kEndLink, link2); |
| 167 DCHECK(link1_end != std::string::npos); |
164 | 168 |
165 GtkWidget* license_label = MakeMarkupLabel( | 169 GtkWidget* license_chunk1 = MakeMarkupLabel( |
166 "<span size=\"smaller\">%s</span>", license); | 170 "<span size=\"smaller\">%s</span>", |
| 171 license.substr(0, link1)); |
| 172 GtkWidget* license_chunk2 = MakeMarkupLabel( |
| 173 "<span size=\"smaller\">%s</span>", |
| 174 license.substr(link1_end + strlen(kEndLinkOss), |
| 175 link2 - link1_end - strlen(kEndLinkOss))); |
| 176 GtkWidget* license_chunk3 = MakeMarkupLabel( |
| 177 "<span size=\"smaller\">%s</span>", |
| 178 license.substr(link2_end + strlen(kEndLinkOss))); |
167 | 179 |
168 gtk_label_set_line_wrap(GTK_LABEL(license_label), TRUE); | 180 std::string first_link_text = |
169 gtk_misc_set_alignment(GTK_MISC(license_label), 0, 0); | 181 std::string("<span size=\"smaller\">") + |
170 gtk_box_pack_start(GTK_BOX(vbox), license_label, TRUE, TRUE, 0); | 182 license.substr(link1 + strlen(kBeginLinkOss), |
| 183 link1_end - link1 - strlen(kBeginLinkOss)) + |
| 184 std::string("</span>"); |
| 185 std::string second_link_text = |
| 186 std::string("<span size=\"smaller\">") + |
| 187 license.substr(link2 + strlen(kBeginLinkOss), |
| 188 link2_end - link2 - strlen(kBeginLinkOss)) + |
| 189 std::string("</span>"); |
171 | 190 |
172 // Hack around Gtk's not-so-good label wrapping, as described here: | 191 GtkWidget* first_link = |
173 // http://blog.16software.com/dynamic-label-wrapping-in-gtk | 192 gtk_chrome_link_button_new_with_markup(first_link_text.c_str()); |
174 g_signal_connect(G_OBJECT(license_label), "size-allocate", | 193 GtkWidget* second_link = |
175 G_CALLBACK(FixLabelWrappingCallback), NULL); | 194 gtk_chrome_link_button_new_with_markup(second_link_text.c_str()); |
| 195 if (!chromium_url_appears_first) { |
| 196 GtkWidget* swap = second_link; |
| 197 second_link = first_link; |
| 198 first_link = swap; |
| 199 } |
176 | 200 |
| 201 g_signal_connect(chromium_url_appears_first ? first_link : second_link, |
| 202 "clicked", G_CALLBACK(OnLinkButtonClick), |
| 203 const_cast<char*>(GetChromiumUrl())); |
| 204 g_signal_connect(chromium_url_appears_first ? second_link : first_link, |
| 205 "clicked", G_CALLBACK(OnLinkButtonClick), |
| 206 const_cast<char*>(kAcknowledgements)); |
| 207 |
| 208 GtkWidget* license_hbox = gtk_hbox_new(FALSE, 0); |
| 209 gtk_box_pack_start(GTK_BOX(license_hbox), license_chunk1, |
| 210 FALSE, FALSE, 0); |
| 211 gtk_box_pack_start(GTK_BOX(license_hbox), first_link, |
| 212 FALSE, FALSE, 0); |
| 213 gtk_box_pack_start(GTK_BOX(license_hbox), license_chunk2, |
| 214 FALSE, FALSE, 0); |
| 215 |
| 216 // Since there's no good way to dynamically wrap the license block, force |
| 217 // a line break right before the second link (which matches en-US Windows |
| 218 // chromium). |
| 219 GtkWidget* license_hbox2 = gtk_hbox_new(FALSE, 0); |
| 220 gtk_box_pack_start(GTK_BOX(license_hbox2), second_link, |
| 221 FALSE, FALSE, 0); |
| 222 gtk_box_pack_start(GTK_BOX(license_hbox2), license_chunk3, |
| 223 FALSE, FALSE, 0); |
| 224 |
| 225 GtkWidget* license_vbox = gtk_vbox_new(FALSE, 0); |
| 226 gtk_box_pack_start(GTK_BOX(license_vbox), license_hbox, FALSE, FALSE, 0); |
| 227 gtk_box_pack_start(GTK_BOX(license_vbox), license_hbox2, FALSE, FALSE, 0); |
| 228 |
| 229 gtk_box_pack_start(GTK_BOX(vbox), license_vbox, TRUE, TRUE, 0); |
177 gtk_box_pack_start(GTK_BOX(content_area), vbox, TRUE, TRUE, 0); | 230 gtk_box_pack_start(GTK_BOX(content_area), vbox, TRUE, TRUE, 0); |
178 | 231 |
179 g_signal_connect(dialog, "response", G_CALLBACK(OnDialogResponse), NULL); | 232 g_signal_connect(dialog, "response", G_CALLBACK(OnDialogResponse), NULL); |
180 gtk_window_set_resizable(GTK_WINDOW(dialog), FALSE); | 233 gtk_window_set_resizable(GTK_WINDOW(dialog), FALSE); |
181 gtk_widget_show_all(dialog); | 234 gtk_widget_show_all(dialog); |
182 } | 235 } |
OLD | NEW |