| 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 <gtk/gtk.h> | |
| 6 | |
| 7 #include "base/i18n/rtl.h" | |
| 8 #include "base/strings/string_util.h" | |
| 9 #include "base/strings/utf_string_conversions.h" | |
| 10 #include "chrome/browser/extensions/bundle_installer.h" | |
| 11 #include "chrome/browser/extensions/extension_install_prompt.h" | |
| 12 #include "chrome/browser/profiles/profile.h" | |
| 13 #include "chrome/browser/ui/gtk/browser_window_gtk.h" | |
| 14 #include "chrome/browser/ui/gtk/gtk_chrome_link_button.h" | |
| 15 #include "chrome/browser/ui/gtk/gtk_util.h" | |
| 16 #include "chrome/common/extensions/extension_constants.h" | |
| 17 #include "content/public/browser/page_navigator.h" | |
| 18 #include "content/public/browser/web_contents.h" | |
| 19 #include "content/public/browser/web_contents_view.h" | |
| 20 #include "extensions/common/extension.h" | |
| 21 #include "grit/generated_resources.h" | |
| 22 #include "skia/ext/image_operations.h" | |
| 23 #include "ui/base/gtk/gtk_hig_constants.h" | |
| 24 #include "ui/base/l10n/l10n_util.h" | |
| 25 #include "ui/base/resource/resource_bundle.h" | |
| 26 #include "ui/gfx/gtk_util.h" | |
| 27 | |
| 28 using content::OpenURLParams; | |
| 29 using extensions::BundleInstaller; | |
| 30 | |
| 31 namespace { | |
| 32 | |
| 33 const int kLeftColumnMinWidth = 250; | |
| 34 // External installs have more text, so use a wider dialog. | |
| 35 const int kExternalInstallLeftColumnWidth = 350; | |
| 36 const int kImageSize = 69; | |
| 37 const int kDetailIndent = 20; | |
| 38 | |
| 39 // Additional padding (beyond on ui::kControlSpacing) all sides of each | |
| 40 // permission in the permissions list. | |
| 41 const int kPermissionsPadding = 2; | |
| 42 const int kExtensionsPadding = kPermissionsPadding; | |
| 43 | |
| 44 const double kRatingTextSize = 12.1; // 12.1px = 9pt @ 96dpi | |
| 45 | |
| 46 // Adds a Skia image as an icon control to the given container. | |
| 47 void AddResourceIcon(const gfx::ImageSkia* icon, void* data) { | |
| 48 GtkWidget* container = static_cast<GtkWidget*>(data); | |
| 49 GdkPixbuf* icon_pixbuf = gfx::GdkPixbufFromSkBitmap(*icon->bitmap()); | |
| 50 GtkWidget* icon_widget = gtk_image_new_from_pixbuf(icon_pixbuf); | |
| 51 g_object_unref(icon_pixbuf); | |
| 52 gtk_box_pack_start(GTK_BOX(container), icon_widget, FALSE, FALSE, 0); | |
| 53 } | |
| 54 | |
| 55 // Returns an expander with the lines in |details|. | |
| 56 GtkWidget* CreateDetailsWidget(const std::vector<base::string16>& details, | |
| 57 int width, | |
| 58 bool show_bullets) { | |
| 59 GtkWidget* expander = gtk_expander_new( | |
| 60 l10n_util::GetStringUTF8(IDS_EXTENSIONS_DETAILS).c_str()); | |
| 61 GtkWidget* align = gtk_alignment_new(0.0, 0.0, 1.0, 1.0); | |
| 62 gtk_container_add(GTK_CONTAINER(expander), align); | |
| 63 GtkWidget* details_vbox = gtk_vbox_new(FALSE, kPermissionsPadding); | |
| 64 gtk_alignment_set_padding(GTK_ALIGNMENT(align), 0, 0, kDetailIndent, 0); | |
| 65 gtk_container_add(GTK_CONTAINER(align), details_vbox); | |
| 66 | |
| 67 for (size_t i = 0; i < details.size(); ++i) { | |
| 68 std::string detail = show_bullets ? | |
| 69 l10n_util::GetStringFUTF8(IDS_EXTENSION_PERMISSION_LINE, details[0]) : | |
| 70 base::UTF16ToUTF8(details[i]); | |
| 71 GtkWidget* detail_label = gtk_label_new(detail.c_str()); | |
| 72 gtk_label_set_line_wrap(GTK_LABEL(detail_label), true); | |
| 73 gtk_util::SetLabelWidth(detail_label, width - kDetailIndent); | |
| 74 gtk_box_pack_start( | |
| 75 GTK_BOX(details_vbox), detail_label, FALSE, FALSE, kPermissionsPadding); | |
| 76 } | |
| 77 return expander; | |
| 78 } | |
| 79 | |
| 80 } // namespace | |
| 81 | |
| 82 namespace chrome { | |
| 83 | |
| 84 // Displays the dialog when constructed, deletes itself when dialog is | |
| 85 // dismissed. Success/failure is passed back through the | |
| 86 // ExtensionInstallPrompt::Delegate instance. | |
| 87 class ExtensionInstallDialog { | |
| 88 public: | |
| 89 ExtensionInstallDialog(const ExtensionInstallPrompt::ShowParams& show_params, | |
| 90 ExtensionInstallPrompt::Delegate* delegate, | |
| 91 const ExtensionInstallPrompt::Prompt& prompt); | |
| 92 private: | |
| 93 ~ExtensionInstallDialog(); | |
| 94 | |
| 95 CHROMEGTK_CALLBACK_1(ExtensionInstallDialog, void, OnResponse, int); | |
| 96 CHROMEGTK_CALLBACK_0(ExtensionInstallDialog, void, OnStoreLinkClick); | |
| 97 | |
| 98 GtkWidget* CreateWidgetForIssueAdvice( | |
| 99 const IssueAdviceInfoEntry& issue_advice, int pixel_width); | |
| 100 | |
| 101 content::PageNavigator* navigator_; | |
| 102 ExtensionInstallPrompt::Delegate* delegate_; | |
| 103 std::string extension_id_; // Set for INLINE_INSTALL_PROMPT. | |
| 104 GtkWidget* dialog_; | |
| 105 }; | |
| 106 | |
| 107 ExtensionInstallDialog::ExtensionInstallDialog( | |
| 108 const ExtensionInstallPrompt::ShowParams& show_params, | |
| 109 ExtensionInstallPrompt::Delegate *delegate, | |
| 110 const ExtensionInstallPrompt::Prompt& prompt) | |
| 111 : navigator_(show_params.navigator), | |
| 112 delegate_(delegate), | |
| 113 dialog_(NULL) { | |
| 114 bool show_permissions = prompt.ShouldShowPermissions(); | |
| 115 bool show_oauth_issues = prompt.GetOAuthIssueCount() > 0; | |
| 116 bool show_retained_files = prompt.GetRetainedFileCount() > 0; | |
| 117 bool is_inline_install = | |
| 118 prompt.type() == ExtensionInstallPrompt::INLINE_INSTALL_PROMPT; | |
| 119 bool has_webstore_data = prompt.has_webstore_data(); | |
| 120 bool is_bundle_install = | |
| 121 prompt.type() == ExtensionInstallPrompt::BUNDLE_INSTALL_PROMPT; | |
| 122 bool is_external_install = | |
| 123 prompt.type() == ExtensionInstallPrompt::EXTERNAL_INSTALL_PROMPT; | |
| 124 | |
| 125 if (is_inline_install) | |
| 126 extension_id_ = prompt.extension()->id(); | |
| 127 | |
| 128 // Build the dialog. | |
| 129 gfx::NativeWindow parent = show_params.parent_window; | |
| 130 dialog_ = gtk_dialog_new_with_buttons( | |
| 131 base::UTF16ToUTF8(prompt.GetDialogTitle()).c_str(), | |
| 132 parent, | |
| 133 GTK_DIALOG_MODAL, | |
| 134 NULL); | |
| 135 GtkWidget* close_button = gtk_dialog_add_button( | |
| 136 GTK_DIALOG(dialog_), | |
| 137 prompt.HasAbortButtonLabel() ? | |
| 138 base::UTF16ToUTF8(prompt.GetAbortButtonLabel()).c_str() : | |
| 139 GTK_STOCK_CANCEL, | |
| 140 GTK_RESPONSE_CLOSE); | |
| 141 if (prompt.HasAcceptButtonLabel()) { | |
| 142 gtk_dialog_add_button( | |
| 143 GTK_DIALOG(dialog_), | |
| 144 base::UTF16ToUTF8(prompt.GetAcceptButtonLabel()).c_str(), | |
| 145 GTK_RESPONSE_ACCEPT); | |
| 146 } | |
| 147 #if !GTK_CHECK_VERSION(2, 22, 0) | |
| 148 gtk_dialog_set_has_separator(GTK_DIALOG(dialog_), FALSE); | |
| 149 #endif | |
| 150 | |
| 151 GtkWidget* scrolled_window = gtk_scrolled_window_new(NULL, NULL); | |
| 152 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_window), | |
| 153 GTK_POLICY_NEVER, | |
| 154 GTK_POLICY_AUTOMATIC); | |
| 155 GtkWidget* content_area = gtk_dialog_get_content_area(GTK_DIALOG(dialog_)); | |
| 156 gtk_box_set_spacing(GTK_BOX(content_area), ui::kContentAreaSpacing); | |
| 157 | |
| 158 // Divide the dialog vertically (item data and icon on the top, permissions | |
| 159 // on the bottom). | |
| 160 GtkWidget* content_vbox = gtk_vbox_new(FALSE, ui::kControlSpacing); | |
| 161 gtk_container_set_border_width(GTK_CONTAINER(content_vbox), | |
| 162 ui::kContentAreaBorder); | |
| 163 gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(scrolled_window), | |
| 164 content_vbox); | |
| 165 GtkWidget* viewport = gtk_bin_get_child(GTK_BIN(scrolled_window)); | |
| 166 gtk_viewport_set_shadow_type(GTK_VIEWPORT(viewport), GTK_SHADOW_NONE); | |
| 167 gtk_box_pack_start(GTK_BOX(content_area), scrolled_window, TRUE, TRUE, 0); | |
| 168 | |
| 169 // Create a two column layout for the top (item data on the left, icon on | |
| 170 // the right). | |
| 171 GtkWidget* top_content_hbox = gtk_hbox_new(FALSE, ui::kContentAreaSpacing); | |
| 172 gtk_box_pack_start(GTK_BOX(content_vbox), top_content_hbox, TRUE, TRUE, 0); | |
| 173 | |
| 174 // We don't show the image for bundle installs, so let the left column take | |
| 175 // up that space. | |
| 176 int left_column_min_width = kLeftColumnMinWidth; | |
| 177 if (is_bundle_install) | |
| 178 left_column_min_width += kImageSize; | |
| 179 if (is_external_install) | |
| 180 left_column_min_width = kExternalInstallLeftColumnWidth; | |
| 181 | |
| 182 // Create a new vbox for the left column. | |
| 183 GtkWidget* left_column_area = gtk_vbox_new(FALSE, ui::kControlSpacing); | |
| 184 gtk_box_pack_start(GTK_BOX(top_content_hbox), left_column_area, | |
| 185 TRUE, TRUE, 0); | |
| 186 gtk_widget_set_size_request(left_column_area, left_column_min_width, -1); | |
| 187 | |
| 188 GtkWidget* heading_vbox = gtk_vbox_new(FALSE, 0); | |
| 189 // If we are not going to show anything else, vertically center the title. | |
| 190 bool center_heading = !show_permissions && !show_oauth_issues && | |
| 191 !is_inline_install && !show_retained_files; | |
| 192 gtk_box_pack_start(GTK_BOX(left_column_area), heading_vbox, center_heading, | |
| 193 center_heading, 0); | |
| 194 | |
| 195 // Heading | |
| 196 GtkWidget* heading_label = gtk_util::CreateBoldLabel( | |
| 197 base::UTF16ToUTF8(prompt.GetHeading().c_str())); | |
| 198 gtk_util::SetLabelWidth(heading_label, left_column_min_width); | |
| 199 gtk_box_pack_start(GTK_BOX(heading_vbox), heading_label, center_heading, | |
| 200 center_heading, 0); | |
| 201 | |
| 202 if (has_webstore_data) { | |
| 203 // Average rating (as stars) and number of ratings. | |
| 204 GtkWidget* stars_hbox = gtk_hbox_new(FALSE, 0); | |
| 205 gtk_box_pack_start(GTK_BOX(heading_vbox), stars_hbox, FALSE, FALSE, 0); | |
| 206 prompt.AppendRatingStars(AddResourceIcon, stars_hbox); | |
| 207 GtkWidget* rating_label = gtk_label_new(base::UTF16ToUTF8( | |
| 208 prompt.GetRatingCount()).c_str()); | |
| 209 gtk_util::ForceFontSizePixels(rating_label, kRatingTextSize); | |
| 210 gtk_box_pack_start(GTK_BOX(stars_hbox), rating_label, | |
| 211 FALSE, FALSE, 3); | |
| 212 | |
| 213 // User count. | |
| 214 GtkWidget* users_label = gtk_label_new(base::UTF16ToUTF8( | |
| 215 prompt.GetUserCount()).c_str()); | |
| 216 gtk_util::SetLabelWidth(users_label, left_column_min_width); | |
| 217 gtk_util::SetLabelColor(users_label, &ui::kGdkGray); | |
| 218 gtk_util::ForceFontSizePixels(rating_label, kRatingTextSize); | |
| 219 gtk_box_pack_start(GTK_BOX(heading_vbox), users_label, | |
| 220 FALSE, FALSE, 0); | |
| 221 | |
| 222 // Store link. | |
| 223 GtkWidget* store_link = gtk_chrome_link_button_new( | |
| 224 l10n_util::GetStringUTF8(IDS_EXTENSION_PROMPT_STORE_LINK).c_str()); | |
| 225 gtk_util::ForceFontSizePixels(store_link, kRatingTextSize); | |
| 226 GtkWidget* store_link_hbox = gtk_hbox_new(FALSE, 0); | |
| 227 // Stick it in an hbox so it doesn't expand to the whole width. | |
| 228 gtk_box_pack_start(GTK_BOX(store_link_hbox), store_link, FALSE, FALSE, 0); | |
| 229 gtk_box_pack_start(GTK_BOX(heading_vbox), store_link_hbox, FALSE, FALSE, 0); | |
| 230 g_signal_connect(store_link, "clicked", | |
| 231 G_CALLBACK(OnStoreLinkClickThunk), this); | |
| 232 } | |
| 233 | |
| 234 if (is_bundle_install) { | |
| 235 // Add the list of extensions to be installed. | |
| 236 GtkWidget* extensions_vbox = gtk_vbox_new(FALSE, ui::kControlSpacing); | |
| 237 gtk_box_pack_start(GTK_BOX(heading_vbox), extensions_vbox, FALSE, FALSE, | |
| 238 ui::kControlSpacing); | |
| 239 | |
| 240 BundleInstaller::ItemList items = prompt.bundle()->GetItemsWithState( | |
| 241 BundleInstaller::Item::STATE_PENDING); | |
| 242 for (size_t i = 0; i < items.size(); ++i) { | |
| 243 GtkWidget* extension_label = gtk_label_new(base::UTF16ToUTF8( | |
| 244 items[i].GetNameForDisplay()).c_str()); | |
| 245 gtk_util::SetLabelWidth(extension_label, left_column_min_width); | |
| 246 gtk_box_pack_start(GTK_BOX(extensions_vbox), extension_label, | |
| 247 FALSE, FALSE, kExtensionsPadding); | |
| 248 } | |
| 249 } else { | |
| 250 // Resize the icon if necessary. | |
| 251 SkBitmap scaled_icon = *prompt.icon().ToSkBitmap(); | |
| 252 if (scaled_icon.width() > kImageSize || scaled_icon.height() > kImageSize) { | |
| 253 scaled_icon = skia::ImageOperations::Resize( | |
| 254 scaled_icon, skia::ImageOperations::RESIZE_LANCZOS3, | |
| 255 kImageSize, kImageSize); | |
| 256 } | |
| 257 | |
| 258 // Put icon in the right column. | |
| 259 GdkPixbuf* pixbuf = gfx::GdkPixbufFromSkBitmap(scaled_icon); | |
| 260 GtkWidget* icon = gtk_image_new_from_pixbuf(pixbuf); | |
| 261 g_object_unref(pixbuf); | |
| 262 gtk_box_pack_start(GTK_BOX(top_content_hbox), icon, FALSE, FALSE, 0); | |
| 263 // Top justify the image. | |
| 264 gtk_misc_set_alignment(GTK_MISC(icon), 0.5, 0.0); | |
| 265 } | |
| 266 | |
| 267 // Permissions are shown separated by a divider for inline installs, or | |
| 268 // directly under the heading for regular installs (where we don't have | |
| 269 // the store data) | |
| 270 if (show_permissions) { | |
| 271 GtkWidget* permissions_container; | |
| 272 if (is_inline_install) { | |
| 273 permissions_container = content_vbox; | |
| 274 gtk_box_pack_start(GTK_BOX(content_vbox), gtk_hseparator_new(), | |
| 275 FALSE, FALSE, ui::kControlSpacing); | |
| 276 } else { | |
| 277 permissions_container = left_column_area; | |
| 278 } | |
| 279 | |
| 280 if (prompt.GetPermissionCount() > 0) { | |
| 281 GtkWidget* permissions_header = gtk_util::CreateBoldLabel( | |
| 282 base::UTF16ToUTF8(prompt.GetPermissionsHeading()).c_str()); | |
| 283 gtk_util::SetLabelWidth(permissions_header, left_column_min_width); | |
| 284 gtk_box_pack_start(GTK_BOX(permissions_container), permissions_header, | |
| 285 FALSE, FALSE, 0); | |
| 286 | |
| 287 for (size_t i = 0; i < prompt.GetPermissionCount(); ++i) { | |
| 288 GtkWidget* permission_vbox = gtk_vbox_new(FALSE, 0); | |
| 289 std::string permission = l10n_util::GetStringFUTF8( | |
| 290 IDS_EXTENSION_PERMISSION_LINE, prompt.GetPermission(i)); | |
| 291 GtkWidget* permission_label = gtk_label_new(permission.c_str()); | |
| 292 gtk_util::SetLabelWidth(permission_label, left_column_min_width); | |
| 293 gtk_box_pack_start(GTK_BOX(permission_vbox), permission_label, | |
| 294 FALSE, FALSE, 0); | |
| 295 if (!prompt.GetPermissionsDetails(i).empty()) { | |
| 296 std::vector<base::string16> details; | |
| 297 details.push_back(prompt.GetPermissionsDetails(i)); | |
| 298 gtk_box_pack_start( | |
| 299 GTK_BOX(permission_vbox), | |
| 300 CreateDetailsWidget(details, left_column_min_width, false), | |
| 301 FALSE, | |
| 302 FALSE, | |
| 303 0); | |
| 304 } | |
| 305 gtk_box_pack_start(GTK_BOX(permissions_container), permission_vbox, | |
| 306 FALSE, FALSE, kPermissionsPadding); | |
| 307 } | |
| 308 } else { | |
| 309 GtkWidget* permission_label = gtk_label_new(l10n_util::GetStringUTF8( | |
| 310 IDS_EXTENSION_NO_SPECIAL_PERMISSIONS).c_str()); | |
| 311 gtk_util::SetLabelWidth(permission_label, left_column_min_width); | |
| 312 gtk_box_pack_start(GTK_BOX(permissions_container), permission_label, | |
| 313 FALSE, FALSE, kPermissionsPadding); | |
| 314 } | |
| 315 } | |
| 316 | |
| 317 if (show_oauth_issues) { | |
| 318 // If permissions are shown, then the scopes will go below them and take | |
| 319 // up the entire width of the dialog. Otherwise the scopes will go where | |
| 320 // the permissions usually go. | |
| 321 GtkWidget* oauth_issues_container = | |
| 322 show_permissions ? content_vbox : left_column_area; | |
| 323 int pixel_width = left_column_min_width + | |
| 324 (show_permissions ? kImageSize : 0); | |
| 325 | |
| 326 GtkWidget* oauth_issues_header = gtk_util::CreateBoldLabel( | |
| 327 base::UTF16ToUTF8(prompt.GetOAuthHeading()).c_str()); | |
| 328 gtk_util::SetLabelWidth(oauth_issues_header, pixel_width); | |
| 329 gtk_box_pack_start(GTK_BOX(oauth_issues_container), oauth_issues_header, | |
| 330 FALSE, FALSE, 0); | |
| 331 | |
| 332 for (size_t i = 0; i < prompt.GetOAuthIssueCount(); ++i) { | |
| 333 GtkWidget* issue_advice_widget = | |
| 334 CreateWidgetForIssueAdvice(prompt.GetOAuthIssue(i), pixel_width); | |
| 335 gtk_box_pack_start(GTK_BOX(oauth_issues_container), issue_advice_widget, | |
| 336 FALSE, FALSE, kPermissionsPadding); | |
| 337 } | |
| 338 } | |
| 339 | |
| 340 if (show_retained_files) { | |
| 341 GtkWidget* retained_files_container = | |
| 342 (show_permissions || show_oauth_issues) ? content_vbox | |
| 343 : left_column_area; | |
| 344 int pixel_width = | |
| 345 left_column_min_width + | |
| 346 ((show_permissions || show_oauth_issues) ? kImageSize : 0); | |
| 347 | |
| 348 GtkWidget* retained_files_header = gtk_util::CreateBoldLabel( | |
| 349 base::UTF16ToUTF8(prompt.GetRetainedFilesHeading()).c_str()); | |
| 350 gtk_util::SetLabelWidth(retained_files_header, pixel_width); | |
| 351 gtk_box_pack_start(GTK_BOX(retained_files_container), retained_files_header, | |
| 352 FALSE, FALSE, 0); | |
| 353 | |
| 354 std::vector<base::string16> paths; | |
| 355 for (size_t i = 0; i < prompt.GetRetainedFileCount(); ++i) { | |
| 356 paths.push_back(prompt.GetRetainedFile(i)); | |
| 357 } | |
| 358 gtk_box_pack_start(GTK_BOX(retained_files_container), | |
| 359 CreateDetailsWidget(paths, pixel_width, false), | |
| 360 FALSE, | |
| 361 FALSE, | |
| 362 kPermissionsPadding); | |
| 363 } | |
| 364 | |
| 365 g_signal_connect(dialog_, "response", G_CALLBACK(OnResponseThunk), this); | |
| 366 gtk_window_set_resizable(GTK_WINDOW(dialog_), FALSE); | |
| 367 | |
| 368 gtk_dialog_set_default_response(GTK_DIALOG(dialog_), GTK_RESPONSE_CLOSE); | |
| 369 gtk_widget_show_all(dialog_); | |
| 370 | |
| 371 gtk_container_set_border_width(GTK_CONTAINER(content_area), 0); | |
| 372 gtk_container_set_border_width( | |
| 373 GTK_CONTAINER(gtk_dialog_get_action_area(GTK_DIALOG(dialog_))), | |
| 374 ui::kContentAreaBorder); | |
| 375 gtk_box_set_spacing(GTK_BOX(gtk_bin_get_child(GTK_BIN(dialog_))), 0); | |
| 376 GtkRequisition requisition; | |
| 377 gtk_widget_size_request(content_vbox, &requisition); | |
| 378 gtk_widget_set_size_request( | |
| 379 scrolled_window, requisition.width, requisition.height); | |
| 380 gtk_widget_grab_focus(close_button); | |
| 381 } | |
| 382 | |
| 383 ExtensionInstallDialog::~ExtensionInstallDialog() { | |
| 384 } | |
| 385 | |
| 386 void ExtensionInstallDialog::OnResponse(GtkWidget* dialog, int response_id) { | |
| 387 if (response_id == GTK_RESPONSE_ACCEPT) | |
| 388 delegate_->InstallUIProceed(); | |
| 389 else | |
| 390 delegate_->InstallUIAbort(true); | |
| 391 | |
| 392 gtk_widget_destroy(dialog_); | |
| 393 delete this; | |
| 394 } | |
| 395 | |
| 396 void ExtensionInstallDialog::OnStoreLinkClick(GtkWidget* sender) { | |
| 397 GURL store_url( | |
| 398 extension_urls::GetWebstoreItemDetailURLPrefix() + extension_id_); | |
| 399 navigator_->OpenURL(OpenURLParams( | |
| 400 store_url, content::Referrer(), NEW_FOREGROUND_TAB, | |
| 401 content::PAGE_TRANSITION_LINK, false)); | |
| 402 | |
| 403 OnResponse(dialog_, GTK_RESPONSE_CLOSE); | |
| 404 } | |
| 405 | |
| 406 GtkWidget* ExtensionInstallDialog::CreateWidgetForIssueAdvice( | |
| 407 const IssueAdviceInfoEntry& issue_advice, int pixel_width) { | |
| 408 GtkWidget* box = gtk_vbox_new(FALSE, 0); | |
| 409 GtkWidget* label = gtk_label_new(l10n_util::GetStringFUTF8( | |
| 410 IDS_EXTENSION_PERMISSION_LINE, issue_advice.description).c_str()); | |
| 411 gtk_util::SetLabelWidth(label, pixel_width); | |
| 412 gtk_box_pack_start(GTK_BOX(box), label, TRUE, TRUE, 0); | |
| 413 | |
| 414 if (!issue_advice.details.empty()) { | |
| 415 gtk_box_pack_start( | |
| 416 GTK_BOX(box), | |
| 417 CreateDetailsWidget(issue_advice.details, pixel_width, true), | |
| 418 TRUE, | |
| 419 TRUE, | |
| 420 0); | |
| 421 } | |
| 422 return box; | |
| 423 } | |
| 424 | |
| 425 } // namespace chrome | |
| 426 | |
| 427 namespace { | |
| 428 | |
| 429 void ShowExtensionInstallDialogImpl( | |
| 430 const ExtensionInstallPrompt::ShowParams& show_params, | |
| 431 ExtensionInstallPrompt::Delegate* delegate, | |
| 432 const ExtensionInstallPrompt::Prompt& prompt) { | |
| 433 new chrome::ExtensionInstallDialog(show_params, delegate, prompt); | |
| 434 } | |
| 435 | |
| 436 } // namespace | |
| 437 | |
| 438 // static | |
| 439 ExtensionInstallPrompt::ShowDialogCallback | |
| 440 ExtensionInstallPrompt::GetDefaultShowDialogCallback() { | |
| 441 return base::Bind(&ShowExtensionInstallDialogImpl); | |
| 442 } | |
| OLD | NEW |