| OLD | NEW |
| 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 <gtk/gtk.h> | 5 #include <gtk/gtk.h> |
| 6 | 6 |
| 7 #include "base/i18n/rtl.h" | 7 #include "base/i18n/rtl.h" |
| 8 #include "base/string_util.h" | 8 #include "base/string_util.h" |
| 9 #include "base/utf_string_conversions.h" | 9 #include "base/utf_string_conversions.h" |
| 10 #include "chrome/browser/extensions/bundle_installer.h" | 10 #include "chrome/browser/extensions/bundle_installer.h" |
| (...skipping 13 matching lines...) Expand all Loading... |
| 24 #include "ui/base/resource/resource_bundle.h" | 24 #include "ui/base/resource/resource_bundle.h" |
| 25 #include "ui/gfx/gtk_util.h" | 25 #include "ui/gfx/gtk_util.h" |
| 26 | 26 |
| 27 using content::OpenURLParams; | 27 using content::OpenURLParams; |
| 28 using extensions::BundleInstaller; | 28 using extensions::BundleInstaller; |
| 29 | 29 |
| 30 namespace { | 30 namespace { |
| 31 | 31 |
| 32 const int kLeftColumnMinWidth = 250; | 32 const int kLeftColumnMinWidth = 250; |
| 33 const int kImageSize = 69; | 33 const int kImageSize = 69; |
| 34 const int kDetailIndent = 20; |
| 34 | 35 |
| 35 // Additional padding (beyond on ui::kControlSpacing) all sides of each | 36 // Additional padding (beyond on ui::kControlSpacing) all sides of each |
| 36 // permission in the permissions list. | 37 // permission in the permissions list. |
| 37 const int kPermissionsPadding = 2; | 38 const int kPermissionsPadding = 2; |
| 38 const int kExtensionsPadding = kPermissionsPadding; | 39 const int kExtensionsPadding = kPermissionsPadding; |
| 39 | 40 |
| 40 const double kRatingTextSize = 12.1; // 12.1px = 9pt @ 96dpi | 41 const double kRatingTextSize = 12.1; // 12.1px = 9pt @ 96dpi |
| 41 | 42 |
| 42 // Adds a Skia image as an icon control to the given container. | 43 // Adds a Skia image as an icon control to the given container. |
| 43 void AddResourceIcon(const gfx::ImageSkia* icon, void* data) { | 44 void AddResourceIcon(const gfx::ImageSkia* icon, void* data) { |
| 44 GtkWidget* container = static_cast<GtkWidget*>(data); | 45 GtkWidget* container = static_cast<GtkWidget*>(data); |
| 45 GdkPixbuf* icon_pixbuf = gfx::GdkPixbufFromSkBitmap(*icon); | 46 GdkPixbuf* icon_pixbuf = gfx::GdkPixbufFromSkBitmap(*icon); |
| 46 GtkWidget* icon_widget = gtk_image_new_from_pixbuf(icon_pixbuf); | 47 GtkWidget* icon_widget = gtk_image_new_from_pixbuf(icon_pixbuf); |
| 47 g_object_unref(icon_pixbuf); | 48 g_object_unref(icon_pixbuf); |
| 48 gtk_box_pack_start(GTK_BOX(container), icon_widget, FALSE, FALSE, 0); | 49 gtk_box_pack_start(GTK_BOX(container), icon_widget, FALSE, FALSE, 0); |
| 49 } | 50 } |
| 50 | 51 |
| 52 void OnZippyButtonRealize(GtkWidget* event_box, gpointer unused) { |
| 53 gdk_window_set_cursor(event_box->window, gfx::GetCursor(GDK_HAND2)); |
| 54 } |
| 55 |
| 56 gboolean OnZippyButtonRelease(GtkWidget* event_box, |
| 57 GdkEvent* event, |
| 58 GtkWidget* detail_box) { |
| 59 if (event->button.button != 1) |
| 60 return FALSE; |
| 61 |
| 62 GtkWidget* arrow = |
| 63 GTK_WIDGET(gtk_object_get_data(GTK_OBJECT(event_box), "arrow")); |
| 64 |
| 65 if (gtk_widget_get_visible(detail_box)) { |
| 66 gtk_widget_hide(detail_box); |
| 67 gtk_arrow_set(GTK_ARROW(arrow), GTK_ARROW_RIGHT, GTK_SHADOW_OUT); |
| 68 } else { |
| 69 gtk_widget_set_no_show_all(detail_box, FALSE); |
| 70 gtk_widget_show_all(detail_box); |
| 71 gtk_widget_set_no_show_all(detail_box, TRUE); |
| 72 gtk_arrow_set(GTK_ARROW(arrow), GTK_ARROW_DOWN, GTK_SHADOW_OUT); |
| 73 } |
| 74 |
| 75 return TRUE; |
| 76 } |
| 77 |
| 51 } // namespace | 78 } // namespace |
| 52 | 79 |
| 53 namespace browser { | 80 namespace browser { |
| 54 | 81 |
| 55 // Displays the dialog when constructed, deletes itself when dialog is | 82 // Displays the dialog when constructed, deletes itself when dialog is |
| 56 // dismissed. Success/failure is passed back through the | 83 // dismissed. Success/failure is passed back through the |
| 57 // ExtensionInstallPrompt::Delegate instance. | 84 // ExtensionInstallPrompt::Delegate instance. |
| 58 class ExtensionInstallDialog { | 85 class ExtensionInstallDialog { |
| 59 public: | 86 public: |
| 60 ExtensionInstallDialog(Browser* browser, | 87 ExtensionInstallDialog(Browser* browser, |
| 61 GtkWindow* parent, | 88 GtkWindow* parent, |
| 62 ExtensionInstallPrompt::Delegate *delegate, | 89 ExtensionInstallPrompt::Delegate *delegate, |
| 63 const ExtensionInstallPrompt::Prompt& prompt); | 90 const ExtensionInstallPrompt::Prompt& prompt); |
| 64 private: | 91 private: |
| 65 ~ExtensionInstallDialog(); | 92 ~ExtensionInstallDialog(); |
| 66 | 93 |
| 67 CHROMEGTK_CALLBACK_1(ExtensionInstallDialog, void, OnResponse, int); | 94 CHROMEGTK_CALLBACK_1(ExtensionInstallDialog, void, OnResponse, int); |
| 68 CHROMEGTK_CALLBACK_0(ExtensionInstallDialog, void, OnStoreLinkClick); | 95 CHROMEGTK_CALLBACK_0(ExtensionInstallDialog, void, OnStoreLinkClick); |
| 69 | 96 |
| 97 GtkWidget* CreateWidgetForIssueAdvice( |
| 98 const IssueAdviceInfoEntry& issue_advice, int pixel_width); |
| 99 |
| 70 Browser* browser_; | 100 Browser* browser_; |
| 71 ExtensionInstallPrompt::Delegate* delegate_; | 101 ExtensionInstallPrompt::Delegate* delegate_; |
| 72 std::string extension_id_; // Set for INLINE_INSTALL_PROMPT. | 102 std::string extension_id_; // Set for INLINE_INSTALL_PROMPT. |
| 73 GtkWidget* dialog_; | 103 GtkWidget* dialog_; |
| 74 }; | 104 }; |
| 75 | 105 |
| 76 ExtensionInstallDialog::ExtensionInstallDialog( | 106 ExtensionInstallDialog::ExtensionInstallDialog( |
| 77 Browser* browser, | 107 Browser* browser, |
| 78 GtkWindow* parent, | 108 GtkWindow* parent, |
| 79 ExtensionInstallPrompt::Delegate *delegate, | 109 ExtensionInstallPrompt::Delegate *delegate, |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 120 | 150 |
| 121 // Create a two column layout for the top (item data on the left, icon on | 151 // Create a two column layout for the top (item data on the left, icon on |
| 122 // the right). | 152 // the right). |
| 123 GtkWidget* top_content_hbox = gtk_hbox_new(FALSE, ui::kContentAreaSpacing); | 153 GtkWidget* top_content_hbox = gtk_hbox_new(FALSE, ui::kContentAreaSpacing); |
| 124 gtk_box_pack_start(GTK_BOX(content_vbox), top_content_hbox, TRUE, TRUE, 0); | 154 gtk_box_pack_start(GTK_BOX(content_vbox), top_content_hbox, TRUE, TRUE, 0); |
| 125 | 155 |
| 126 // Create a new vbox for the left column. | 156 // Create a new vbox for the left column. |
| 127 GtkWidget* left_column_area = gtk_vbox_new(FALSE, ui::kControlSpacing); | 157 GtkWidget* left_column_area = gtk_vbox_new(FALSE, ui::kControlSpacing); |
| 128 gtk_box_pack_start(GTK_BOX(top_content_hbox), left_column_area, | 158 gtk_box_pack_start(GTK_BOX(top_content_hbox), left_column_area, |
| 129 TRUE, TRUE, 0); | 159 TRUE, TRUE, 0); |
| 160 gtk_widget_set_size_request(left_column_area, kLeftColumnMinWidth, -1); |
| 130 | 161 |
| 131 GtkWidget* heading_vbox = gtk_vbox_new(FALSE, 0); | 162 GtkWidget* heading_vbox = gtk_vbox_new(FALSE, 0); |
| 132 // If we are not going to show anything else, vertically center the title. | 163 // If we are not going to show anything else, vertically center the title. |
| 133 bool center_heading = | 164 bool center_heading = |
| 134 !show_permissions && !show_oauth_issues && !is_inline_install; | 165 !show_permissions && !show_oauth_issues && !is_inline_install; |
| 135 gtk_box_pack_start(GTK_BOX(left_column_area), heading_vbox, center_heading, | 166 gtk_box_pack_start(GTK_BOX(left_column_area), heading_vbox, center_heading, |
| 136 center_heading, 0); | 167 center_heading, 0); |
| 137 | 168 |
| 138 // Heading | 169 // Heading |
| 139 GtkWidget* heading_label = gtk_util::CreateBoldLabel( | 170 GtkWidget* heading_label = gtk_util::CreateBoldLabel( |
| (...skipping 90 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 230 for (size_t i = 0; i < prompt.GetPermissionCount(); ++i) { | 261 for (size_t i = 0; i < prompt.GetPermissionCount(); ++i) { |
| 231 GtkWidget* permission_label = gtk_label_new(UTF16ToUTF8( | 262 GtkWidget* permission_label = gtk_label_new(UTF16ToUTF8( |
| 232 prompt.GetPermission(i)).c_str()); | 263 prompt.GetPermission(i)).c_str()); |
| 233 gtk_util::SetLabelWidth(permission_label, kLeftColumnMinWidth); | 264 gtk_util::SetLabelWidth(permission_label, kLeftColumnMinWidth); |
| 234 gtk_box_pack_start(GTK_BOX(permissions_container), permission_label, | 265 gtk_box_pack_start(GTK_BOX(permissions_container), permission_label, |
| 235 FALSE, FALSE, kPermissionsPadding); | 266 FALSE, FALSE, kPermissionsPadding); |
| 236 } | 267 } |
| 237 } | 268 } |
| 238 | 269 |
| 239 if (show_oauth_issues) { | 270 if (show_oauth_issues) { |
| 240 GtkWidget* oauth_issues_container; | 271 // If permissions are shown, then the scopes will go below them and take |
| 241 if (is_inline_install) { | 272 // up the entire width of the dialog. Otherwise the scopes will go where |
| 242 oauth_issues_container = content_vbox; | 273 // the permissions usually go. |
| 243 gtk_box_pack_start(GTK_BOX(content_vbox), gtk_hseparator_new(), | 274 GtkWidget* oauth_issues_container = |
| 244 FALSE, FALSE, ui::kControlSpacing); | 275 show_permissions ? content_vbox : left_column_area; |
| 245 } else { | 276 int pixel_width = kLeftColumnMinWidth + |
| 246 oauth_issues_container = left_column_area; | 277 (show_permissions ? kImageSize : 0); |
| 247 } | |
| 248 | 278 |
| 249 GtkWidget* oauth_issues_header = gtk_util::CreateBoldLabel( | 279 GtkWidget* oauth_issues_header = gtk_util::CreateBoldLabel( |
| 250 "The app wants these scopes:"); | 280 UTF16ToUTF8(prompt.GetOAuthHeading()).c_str()); |
| 251 gtk_util::SetLabelWidth(oauth_issues_header, kLeftColumnMinWidth); | 281 gtk_util::SetLabelWidth(oauth_issues_header, pixel_width); |
| 252 gtk_box_pack_start(GTK_BOX(oauth_issues_container), oauth_issues_header, | 282 gtk_box_pack_start(GTK_BOX(oauth_issues_container), oauth_issues_header, |
| 253 FALSE, FALSE, 0); | 283 FALSE, FALSE, 0); |
| 254 | 284 |
| 255 // TODO(estade): display the issue details under zippies. | 285 // TODO(estade): display the issue details under zippies. |
| 256 for (size_t i = 0; i < prompt.GetOAuthIssueCount(); ++i) { | 286 for (size_t i = 0; i < prompt.GetOAuthIssueCount(); ++i) { |
| 257 GtkWidget* label = gtk_label_new( | 287 GtkWidget* issue_advice_widget = |
| 258 prompt.GetOAuthIssue(i).description.c_str()); | 288 CreateWidgetForIssueAdvice(prompt.GetOAuthIssue(i), pixel_width); |
| 259 gtk_util::SetLabelWidth(label, kLeftColumnMinWidth); | 289 gtk_box_pack_start(GTK_BOX(oauth_issues_container), issue_advice_widget, |
| 260 gtk_box_pack_start(GTK_BOX(oauth_issues_container), label, | |
| 261 FALSE, FALSE, kPermissionsPadding); | 290 FALSE, FALSE, kPermissionsPadding); |
| 262 } | 291 } |
| 263 } | 292 } |
| 264 | 293 |
| 265 g_signal_connect(dialog_, "response", G_CALLBACK(OnResponseThunk), this); | 294 g_signal_connect(dialog_, "response", G_CALLBACK(OnResponseThunk), this); |
| 266 gtk_window_set_resizable(GTK_WINDOW(dialog_), FALSE); | 295 gtk_window_set_resizable(GTK_WINDOW(dialog_), FALSE); |
| 267 | 296 |
| 268 gtk_dialog_set_default_response(GTK_DIALOG(dialog_), GTK_RESPONSE_CLOSE); | 297 gtk_dialog_set_default_response(GTK_DIALOG(dialog_), GTK_RESPONSE_CLOSE); |
| 269 gtk_widget_show_all(dialog_); | 298 gtk_widget_show_all(dialog_); |
| 270 gtk_widget_grab_focus(close_button); | 299 gtk_widget_grab_focus(close_button); |
| 271 } | 300 } |
| 272 | 301 |
| 273 ExtensionInstallDialog::~ExtensionInstallDialog() { | 302 ExtensionInstallDialog::~ExtensionInstallDialog() { |
| 274 } | 303 } |
| 275 | 304 |
| 276 void ExtensionInstallDialog::OnResponse(GtkWidget* dialog, int response_id) { | 305 void ExtensionInstallDialog::OnResponse(GtkWidget* dialog, int response_id) { |
| 277 if (response_id == GTK_RESPONSE_ACCEPT) { | 306 if (response_id == GTK_RESPONSE_ACCEPT) |
| 278 delegate_->InstallUIProceed(); | 307 delegate_->InstallUIProceed(); |
| 279 } else { | 308 else |
| 280 delegate_->InstallUIAbort(true); | 309 delegate_->InstallUIAbort(true); |
| 281 } | |
| 282 | 310 |
| 283 gtk_widget_destroy(dialog_); | 311 gtk_widget_destroy(dialog_); |
| 284 delete this; | 312 delete this; |
| 285 } | 313 } |
| 286 | 314 |
| 287 void ExtensionInstallDialog::OnStoreLinkClick(GtkWidget* sender) { | 315 void ExtensionInstallDialog::OnStoreLinkClick(GtkWidget* sender) { |
| 288 GURL store_url( | 316 GURL store_url( |
| 289 extension_urls::GetWebstoreItemDetailURLPrefix() + extension_id_); | 317 extension_urls::GetWebstoreItemDetailURLPrefix() + extension_id_); |
| 290 browser_->OpenURL(OpenURLParams( | 318 browser_->OpenURL(OpenURLParams( |
| 291 store_url, content::Referrer(), NEW_FOREGROUND_TAB, | 319 store_url, content::Referrer(), NEW_FOREGROUND_TAB, |
| 292 content::PAGE_TRANSITION_LINK, false)); | 320 content::PAGE_TRANSITION_LINK, false)); |
| 293 | 321 |
| 294 OnResponse(dialog_, GTK_RESPONSE_CLOSE); | 322 OnResponse(dialog_, GTK_RESPONSE_CLOSE); |
| 295 } | 323 } |
| 296 | 324 |
| 325 GtkWidget* ExtensionInstallDialog::CreateWidgetForIssueAdvice( |
| 326 const IssueAdviceInfoEntry& issue_advice, int pixel_width) { |
| 327 GtkWidget* box = gtk_vbox_new(FALSE, ui::kControlSpacing); |
| 328 GtkWidget* header = gtk_hbox_new(FALSE, 0); |
| 329 GtkWidget* event_box = gtk_event_box_new(); |
| 330 gtk_container_add(GTK_CONTAINER(event_box), header); |
| 331 gtk_box_pack_start(GTK_BOX(box), event_box, FALSE, FALSE, |
| 332 kPermissionsPadding); |
| 333 |
| 334 GtkWidget* arrow = NULL; |
| 335 GtkWidget* label = NULL; |
| 336 int label_pixel_width = pixel_width; |
| 337 |
| 338 if (issue_advice.details.empty()) { |
| 339 label = gtk_label_new(l10n_util::GetStringFUTF8( |
| 340 IDS_EXTENSION_PERMISSION_LINE, |
| 341 UTF8ToUTF16(issue_advice.description)).c_str()); |
| 342 } else { |
| 343 arrow = gtk_arrow_new(GTK_ARROW_RIGHT, GTK_SHADOW_OUT); |
| 344 GtkRequisition req; |
| 345 gtk_widget_size_request(arrow, &req); |
| 346 label_pixel_width -= req.width; |
| 347 |
| 348 label = gtk_label_new(issue_advice.description.c_str()); |
| 349 |
| 350 GtkWidget* detail_box = gtk_vbox_new(FALSE, ui::kControlSpacing); |
| 351 gtk_box_pack_start(GTK_BOX(box), detail_box, FALSE, FALSE, 0); |
| 352 gtk_widget_set_no_show_all(detail_box, TRUE); |
| 353 gtk_object_set_data(GTK_OBJECT(event_box), "arrow", arrow); |
| 354 |
| 355 for (size_t i = 0; i < issue_advice.details.size(); ++i) { |
| 356 std::string text = l10n_util::GetStringFUTF8( |
| 357 IDS_EXTENSION_PERMISSION_LINE, UTF8ToUTF16(issue_advice.details[i])); |
| 358 GtkWidget* label = gtk_label_new(text.c_str()); |
| 359 gtk_util::SetLabelWidth(label, pixel_width - kDetailIndent); |
| 360 |
| 361 GtkWidget* align = gtk_alignment_new(0.0, 0.0, 1.0, 1.0); |
| 362 gtk_alignment_set_padding(GTK_ALIGNMENT(align), 0, 0, kDetailIndent, 0); |
| 363 gtk_container_add(GTK_CONTAINER(align), label); |
| 364 gtk_box_pack_start(GTK_BOX(detail_box), align, FALSE, FALSE, |
| 365 kPermissionsPadding); |
| 366 } |
| 367 |
| 368 g_signal_connect(event_box, "realize", |
| 369 G_CALLBACK(OnZippyButtonRealize), NULL); |
| 370 g_signal_connect(event_box, "button-release-event", |
| 371 G_CALLBACK(OnZippyButtonRelease), detail_box); |
| 372 } |
| 373 |
| 374 gtk_util::SetLabelWidth(label, label_pixel_width); |
| 375 if (arrow) |
| 376 gtk_box_pack_start(GTK_BOX(header), arrow, FALSE, FALSE, 0); |
| 377 gtk_box_pack_start(GTK_BOX(header), label, TRUE, TRUE, 0); |
| 378 |
| 379 return box; |
| 380 } |
| 381 |
| 297 } // namespace browser | 382 } // namespace browser |
| 298 | 383 |
| 299 void ShowExtensionInstallDialogImpl( | 384 void ShowExtensionInstallDialogImpl( |
| 300 Browser* browser, | 385 Browser* browser, |
| 301 ExtensionInstallPrompt::Delegate* delegate, | 386 ExtensionInstallPrompt::Delegate* delegate, |
| 302 const ExtensionInstallPrompt::Prompt& prompt) { | 387 const ExtensionInstallPrompt::Prompt& prompt) { |
| 303 BrowserWindowGtk* browser_window = static_cast<BrowserWindowGtk*>( | 388 BrowserWindowGtk* browser_window = static_cast<BrowserWindowGtk*>( |
| 304 browser->window()); | 389 browser->window()); |
| 305 if (!browser_window) { | 390 if (!browser_window) { |
| 306 delegate->InstallUIAbort(false); | 391 delegate->InstallUIAbort(false); |
| 307 return; | 392 return; |
| 308 } | 393 } |
| 309 | 394 |
| 310 new browser::ExtensionInstallDialog(browser, browser_window->window(), | 395 new browser::ExtensionInstallDialog(browser, browser_window->window(), |
| 311 delegate, prompt); | 396 delegate, prompt); |
| 312 } | 397 } |
| OLD | NEW |