| 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/string_util.h" | 8 #include "base/string_util.h" |
| 8 #include "base/utf_string_conversions.h" | 9 #include "base/utf_string_conversions.h" |
| 10 #include "chrome/browser/extensions/bundle_installer.h" |
| 9 #include "chrome/browser/extensions/extension_install_dialog.h" | 11 #include "chrome/browser/extensions/extension_install_dialog.h" |
| 10 #include "chrome/browser/profiles/profile.h" | 12 #include "chrome/browser/profiles/profile.h" |
| 11 #include "chrome/browser/ui/browser_list.h" | 13 #include "chrome/browser/ui/browser_list.h" |
| 12 #include "chrome/browser/ui/browser_window.h" | 14 #include "chrome/browser/ui/browser_window.h" |
| 13 #include "chrome/browser/ui/gtk/browser_window_gtk.h" | 15 #include "chrome/browser/ui/gtk/browser_window_gtk.h" |
| 14 #include "chrome/browser/ui/gtk/gtk_chrome_link_button.h" | 16 #include "chrome/browser/ui/gtk/gtk_chrome_link_button.h" |
| 15 #include "chrome/browser/ui/gtk/gtk_util.h" | 17 #include "chrome/browser/ui/gtk/gtk_util.h" |
| 16 #include "chrome/common/extensions/extension.h" | 18 #include "chrome/common/extensions/extension.h" |
| 17 #include "grit/generated_resources.h" | 19 #include "grit/generated_resources.h" |
| 18 #include "skia/ext/image_operations.h" | 20 #include "skia/ext/image_operations.h" |
| 19 #include "ui/base/gtk/gtk_hig_constants.h" | 21 #include "ui/base/gtk/gtk_hig_constants.h" |
| 20 #include "ui/base/l10n/l10n_util.h" | 22 #include "ui/base/l10n/l10n_util.h" |
| 21 #include "ui/base/resource/resource_bundle.h" | 23 #include "ui/base/resource/resource_bundle.h" |
| 22 #include "ui/gfx/gtk_util.h" | 24 #include "ui/gfx/gtk_util.h" |
| 23 | 25 |
| 24 using content::OpenURLParams; | 26 using content::OpenURLParams; |
| 27 using extensions::BundleInstaller; |
| 25 | 28 |
| 26 namespace { | 29 namespace { |
| 27 | 30 |
| 28 const int kLeftColumnMinWidth = 250; | 31 const int kLeftColumnMinWidth = 250; |
| 29 const int kImageSize = 69; | 32 const int kImageSize = 69; |
| 30 | 33 |
| 31 // Additional padding (beyond on ui::kControlSpacing) all sides of each | 34 // Additional padding (beyond on ui::kControlSpacing) all sides of each |
| 32 // permission in the permissions list. | 35 // permission in the permissions list. |
| 33 const int kPermissionsPadding = 2; | 36 const int kPermissionsPadding = 2; |
| 37 const int kExtensionsPadding = kPermissionsPadding; |
| 34 | 38 |
| 35 const double kRatingTextSize = 12.1; // 12.1px = 9pt @ 96dpi | 39 const double kRatingTextSize = 12.1; // 12.1px = 9pt @ 96dpi |
| 36 | 40 |
| 37 // Adds a Skia image as an icon control to the given container. | 41 // Adds a Skia image as an icon control to the given container. |
| 38 void AddResourceIcon(const SkBitmap* icon, void* data) { | 42 void AddResourceIcon(const SkBitmap* icon, void* data) { |
| 39 GtkWidget* container = static_cast<GtkWidget*>(data); | 43 GtkWidget* container = static_cast<GtkWidget*>(data); |
| 40 GdkPixbuf* icon_pixbuf = gfx::GdkPixbufFromSkBitmap(icon); | 44 GdkPixbuf* icon_pixbuf = gfx::GdkPixbufFromSkBitmap(icon); |
| 41 GtkWidget* icon_widget = gtk_image_new_from_pixbuf(icon_pixbuf); | 45 GtkWidget* icon_widget = gtk_image_new_from_pixbuf(icon_pixbuf); |
| 42 g_object_unref(icon_pixbuf); | 46 g_object_unref(icon_pixbuf); |
| 43 gtk_box_pack_start(GTK_BOX(container), icon_widget, FALSE, FALSE, 0); | 47 gtk_box_pack_start(GTK_BOX(container), icon_widget, FALSE, FALSE, 0); |
| 44 } | 48 } |
| 45 | 49 |
| 46 // Displays the dialog when constructed, deletes itself when dialog is | 50 // Displays the dialog when constructed, deletes itself when dialog is |
| 47 // dismissed. Success/failure is passed back through the ExtensionInstallUI:: | 51 // dismissed. Success/failure is passed back through the ExtensionInstallUI:: |
| 48 // Delegate instance. | 52 // Delegate instance. |
| 49 class ExtensionInstallDialog { | 53 class ExtensionInstallDialog { |
| 50 public: | 54 public: |
| 51 ExtensionInstallDialog(GtkWindow* parent, | 55 ExtensionInstallDialog(GtkWindow* parent, |
| 52 ExtensionInstallUI::Delegate *delegate, | 56 ExtensionInstallUI::Delegate *delegate, |
| 53 const Extension* extension, | |
| 54 SkBitmap* skia_icon, | |
| 55 const ExtensionInstallUI::Prompt& prompt); | 57 const ExtensionInstallUI::Prompt& prompt); |
| 56 private: | 58 private: |
| 57 ~ExtensionInstallDialog(); | 59 ~ExtensionInstallDialog(); |
| 58 | 60 |
| 59 CHROMEGTK_CALLBACK_1(ExtensionInstallDialog, void, OnResponse, int); | 61 CHROMEGTK_CALLBACK_1(ExtensionInstallDialog, void, OnResponse, int); |
| 60 CHROMEGTK_CALLBACK_0(ExtensionInstallDialog, void, OnStoreLinkClick); | 62 CHROMEGTK_CALLBACK_0(ExtensionInstallDialog, void, OnStoreLinkClick); |
| 61 | 63 |
| 62 ExtensionInstallUI::Delegate* delegate_; | 64 ExtensionInstallUI::Delegate* delegate_; |
| 63 const Extension* extension_; | 65 std::string extension_id_; // Set for INLINE_INSTALL_PROMPT. |
| 64 GtkWidget* dialog_; | 66 GtkWidget* dialog_; |
| 65 }; | 67 }; |
| 66 | 68 |
| 67 ExtensionInstallDialog::ExtensionInstallDialog( | 69 ExtensionInstallDialog::ExtensionInstallDialog( |
| 68 GtkWindow* parent, | 70 GtkWindow* parent, |
| 69 ExtensionInstallUI::Delegate *delegate, | 71 ExtensionInstallUI::Delegate *delegate, |
| 70 const Extension* extension, | |
| 71 SkBitmap* skia_icon, | |
| 72 const ExtensionInstallUI::Prompt& prompt) | 72 const ExtensionInstallUI::Prompt& prompt) |
| 73 : delegate_(delegate), | 73 : delegate_(delegate), |
| 74 extension_(extension) { | 74 dialog_(NULL) { |
| 75 bool show_permissions = prompt.GetPermissionCount() > 0; | 75 bool show_permissions = prompt.GetPermissionCount() > 0; |
| 76 bool is_inline_install = | 76 bool is_inline_install = |
| 77 prompt.type() == ExtensionInstallUI::INLINE_INSTALL_PROMPT; | 77 prompt.type() == ExtensionInstallUI::INLINE_INSTALL_PROMPT; |
| 78 bool is_bundle_install = |
| 79 prompt.type() == ExtensionInstallUI::BUNDLE_INSTALL_PROMPT; |
| 80 |
| 81 if (is_inline_install) |
| 82 extension_id_ = prompt.extension()->id(); |
| 78 | 83 |
| 79 // Build the dialog. | 84 // Build the dialog. |
| 80 dialog_ = gtk_dialog_new_with_buttons( | 85 dialog_ = gtk_dialog_new_with_buttons( |
| 81 UTF16ToUTF8(prompt.GetDialogTitle(extension)).c_str(), | 86 UTF16ToUTF8(prompt.GetDialogTitle()).c_str(), |
| 82 parent, | 87 parent, |
| 83 GTK_DIALOG_MODAL, | 88 GTK_DIALOG_MODAL, |
| 84 NULL); | 89 NULL); |
| 85 GtkWidget* close_button = gtk_dialog_add_button( | 90 GtkWidget* close_button = gtk_dialog_add_button( |
| 86 GTK_DIALOG(dialog_), | 91 GTK_DIALOG(dialog_), |
| 87 prompt.HasAbortButtonLabel() ? | 92 prompt.HasAbortButtonLabel() ? |
| 88 UTF16ToUTF8(prompt.GetAbortButtonLabel()).c_str() : GTK_STOCK_CANCEL, | 93 UTF16ToUTF8(prompt.GetAbortButtonLabel()).c_str() : GTK_STOCK_CANCEL, |
| 89 GTK_RESPONSE_CLOSE); | 94 GTK_RESPONSE_CLOSE); |
| 90 gtk_dialog_add_button( | 95 gtk_dialog_add_button( |
| 91 GTK_DIALOG(dialog_), | 96 GTK_DIALOG(dialog_), |
| (...skipping 22 matching lines...) Expand all Loading... |
| 114 TRUE, TRUE, 0); | 119 TRUE, TRUE, 0); |
| 115 | 120 |
| 116 GtkWidget* heading_vbox = gtk_vbox_new(FALSE, 0); | 121 GtkWidget* heading_vbox = gtk_vbox_new(FALSE, 0); |
| 117 // If we are not going to show anything else, vertically center the title. | 122 // If we are not going to show anything else, vertically center the title. |
| 118 bool center_heading = !show_permissions && !is_inline_install; | 123 bool center_heading = !show_permissions && !is_inline_install; |
| 119 gtk_box_pack_start(GTK_BOX(left_column_area), heading_vbox, center_heading, | 124 gtk_box_pack_start(GTK_BOX(left_column_area), heading_vbox, center_heading, |
| 120 center_heading, 0); | 125 center_heading, 0); |
| 121 | 126 |
| 122 // Heading | 127 // Heading |
| 123 GtkWidget* heading_label = gtk_util::CreateBoldLabel( | 128 GtkWidget* heading_label = gtk_util::CreateBoldLabel( |
| 124 UTF16ToUTF8(prompt.GetHeading(extension_->name())).c_str()); | 129 UTF16ToUTF8(prompt.GetHeading().c_str())); |
| 125 gtk_label_set_line_wrap(GTK_LABEL(heading_label), true); | 130 gtk_label_set_line_wrap(GTK_LABEL(heading_label), true); |
| 126 gtk_misc_set_alignment(GTK_MISC(heading_label), 0.0, 0.5); | 131 gtk_misc_set_alignment(GTK_MISC(heading_label), 0.0, 0.5); |
| 127 gtk_box_pack_start(GTK_BOX(heading_vbox), heading_label, center_heading, | 132 gtk_box_pack_start(GTK_BOX(heading_vbox), heading_label, center_heading, |
| 128 center_heading, 0); | 133 center_heading, 0); |
| 129 | 134 |
| 130 if (is_inline_install) { | 135 if (is_inline_install) { |
| 131 // Average rating (as stars) and number of ratings. | 136 // Average rating (as stars) and number of ratings. |
| 132 GtkWidget* stars_hbox = gtk_hbox_new(FALSE, 0); | 137 GtkWidget* stars_hbox = gtk_hbox_new(FALSE, 0); |
| 133 gtk_box_pack_start(GTK_BOX(heading_vbox), stars_hbox, FALSE, FALSE, 0); | 138 gtk_box_pack_start(GTK_BOX(heading_vbox), stars_hbox, FALSE, FALSE, 0); |
| 134 prompt.AppendRatingStars(AddResourceIcon, stars_hbox); | 139 prompt.AppendRatingStars(AddResourceIcon, stars_hbox); |
| (...skipping 17 matching lines...) Expand all Loading... |
| 152 l10n_util::GetStringUTF8(IDS_EXTENSION_PROMPT_STORE_LINK).c_str()); | 157 l10n_util::GetStringUTF8(IDS_EXTENSION_PROMPT_STORE_LINK).c_str()); |
| 153 gtk_util::ForceFontSizePixels(store_link, kRatingTextSize); | 158 gtk_util::ForceFontSizePixels(store_link, kRatingTextSize); |
| 154 GtkWidget* store_link_hbox = gtk_hbox_new(FALSE, 0); | 159 GtkWidget* store_link_hbox = gtk_hbox_new(FALSE, 0); |
| 155 // Stick it in an hbox so it doesn't expand to the whole width. | 160 // Stick it in an hbox so it doesn't expand to the whole width. |
| 156 gtk_box_pack_start(GTK_BOX(store_link_hbox), store_link, FALSE, FALSE, 0); | 161 gtk_box_pack_start(GTK_BOX(store_link_hbox), store_link, FALSE, FALSE, 0); |
| 157 gtk_box_pack_start(GTK_BOX(heading_vbox), store_link_hbox, FALSE, FALSE, 0); | 162 gtk_box_pack_start(GTK_BOX(heading_vbox), store_link_hbox, FALSE, FALSE, 0); |
| 158 g_signal_connect(store_link, "clicked", | 163 g_signal_connect(store_link, "clicked", |
| 159 G_CALLBACK(OnStoreLinkClickThunk), this); | 164 G_CALLBACK(OnStoreLinkClickThunk), this); |
| 160 } | 165 } |
| 161 | 166 |
| 162 // Resize the icon if necessary. | 167 if (is_bundle_install) { |
| 163 SkBitmap scaled_icon = *skia_icon; | 168 // Add the list of extensions to be installed. |
| 164 if (scaled_icon.width() > kImageSize || scaled_icon.height() > kImageSize) { | 169 GtkWidget* extensions_vbox = gtk_vbox_new(FALSE, ui::kControlSpacing); |
| 165 scaled_icon = skia::ImageOperations::Resize(scaled_icon, | 170 gtk_box_pack_start(GTK_BOX(heading_vbox), extensions_vbox, FALSE, FALSE, |
| 166 skia::ImageOperations::RESIZE_LANCZOS3, | 171 ui::kControlSpacing); |
| 167 kImageSize, kImageSize); | 172 |
| 173 BundleInstaller::ItemList items = prompt.bundle()->GetItemsWithState( |
| 174 BundleInstaller::Item::STATE_PENDING); |
| 175 for (size_t i = 0; i < items.size(); ++i) { |
| 176 string16 extension_name = UTF8ToUTF16(items[i].localized_name); |
| 177 base::i18n::AdjustStringForLocaleDirection(&extension_name); |
| 178 |
| 179 GtkWidget* extension_label = gtk_label_new(UTF16ToUTF8( |
| 180 l10n_util::GetStringFUTF16( |
| 181 IDS_EXTENSION_PERMISSION_LINE, extension_name)).c_str()); |
| 182 gtk_util::SetLabelWidth(extension_label, kLeftColumnMinWidth); |
| 183 gtk_box_pack_start(GTK_BOX(extensions_vbox), extension_label, |
| 184 FALSE, FALSE, kExtensionsPadding); |
| 185 } |
| 168 } | 186 } |
| 169 | 187 |
| 170 // Put icon in the right column. | 188 if (!is_bundle_install) { |
| 171 GdkPixbuf* pixbuf = gfx::GdkPixbufFromSkBitmap(&scaled_icon); | 189 // Resize the icon if necessary. |
| 172 GtkWidget* icon = gtk_image_new_from_pixbuf(pixbuf); | 190 SkBitmap scaled_icon = prompt.icon(); |
| 173 g_object_unref(pixbuf); | 191 if (scaled_icon.width() > kImageSize || scaled_icon.height() > kImageSize) { |
| 174 gtk_box_pack_start(GTK_BOX(top_content_hbox), icon, FALSE, FALSE, 0); | 192 scaled_icon = skia::ImageOperations::Resize( |
| 175 // Top justify the image. | 193 scaled_icon, skia::ImageOperations::RESIZE_LANCZOS3, |
| 176 gtk_misc_set_alignment(GTK_MISC(icon), 0.5, 0.0); | 194 kImageSize, kImageSize); |
| 195 } |
| 196 |
| 197 // Put icon in the right column. |
| 198 GdkPixbuf* pixbuf = gfx::GdkPixbufFromSkBitmap(&scaled_icon); |
| 199 GtkWidget* icon = gtk_image_new_from_pixbuf(pixbuf); |
| 200 g_object_unref(pixbuf); |
| 201 gtk_box_pack_start(GTK_BOX(top_content_hbox), icon, FALSE, FALSE, 0); |
| 202 // Top justify the image. |
| 203 gtk_misc_set_alignment(GTK_MISC(icon), 0.5, 0.0); |
| 204 } |
| 177 | 205 |
| 178 // Permissions are shown separated by a divider for inline installs, or | 206 // Permissions are shown separated by a divider for inline installs, or |
| 179 // directly under the heading for regular installs (where we don't have | 207 // directly under the heading for regular installs (where we don't have |
| 180 // the store data) | 208 // the store data) |
| 181 if (show_permissions) { | 209 if (show_permissions) { |
| 182 GtkWidget* permissions_container; | 210 GtkWidget* permissions_container; |
| 183 if (is_inline_install) { | 211 if (is_inline_install) { |
| 184 permissions_container = content_vbox; | 212 permissions_container = content_vbox; |
| 185 gtk_box_pack_start(GTK_BOX(content_vbox), gtk_hseparator_new(), | 213 gtk_box_pack_start(GTK_BOX(content_vbox), gtk_hseparator_new(), |
| 186 FALSE, FALSE, ui::kControlSpacing); | 214 FALSE, FALSE, ui::kControlSpacing); |
| 187 } else { | 215 } else { |
| 188 permissions_container = left_column_area; | 216 permissions_container = left_column_area; |
| 189 } | 217 } |
| 190 | 218 |
| 191 GtkWidget* permissions_header = gtk_util::CreateBoldLabel( | 219 GtkWidget* permissions_header = gtk_util::CreateBoldLabel( |
| 192 UTF16ToUTF8(prompt.GetPermissionsHeader()).c_str()); | 220 UTF16ToUTF8(prompt.GetPermissionsHeading()).c_str()); |
| 193 gtk_util::SetLabelWidth(permissions_header, kLeftColumnMinWidth); | 221 gtk_util::SetLabelWidth(permissions_header, kLeftColumnMinWidth); |
| 194 gtk_box_pack_start(GTK_BOX(permissions_container), permissions_header, | 222 gtk_box_pack_start(GTK_BOX(permissions_container), permissions_header, |
| 195 FALSE, FALSE, 0); | 223 FALSE, FALSE, 0); |
| 196 | 224 |
| 197 for (size_t i = 0; i < prompt.GetPermissionCount(); ++i) { | 225 for (size_t i = 0; i < prompt.GetPermissionCount(); ++i) { |
| 198 GtkWidget* permission_label = gtk_label_new(UTF16ToUTF8( | 226 GtkWidget* permission_label = gtk_label_new(UTF16ToUTF8( |
| 199 prompt.GetPermission(i)).c_str()); | 227 prompt.GetPermission(i)).c_str()); |
| 200 gtk_util::SetLabelWidth(permission_label, kLeftColumnMinWidth); | 228 gtk_util::SetLabelWidth(permission_label, kLeftColumnMinWidth); |
| 201 gtk_box_pack_start(GTK_BOX(permissions_container), permission_label, | 229 gtk_box_pack_start(GTK_BOX(permissions_container), permission_label, |
| 202 FALSE, FALSE, kPermissionsPadding); | 230 FALSE, FALSE, kPermissionsPadding); |
| (...skipping 17 matching lines...) Expand all Loading... |
| 220 } else { | 248 } else { |
| 221 delegate_->InstallUIAbort(true); | 249 delegate_->InstallUIAbort(true); |
| 222 } | 250 } |
| 223 | 251 |
| 224 gtk_widget_destroy(dialog_); | 252 gtk_widget_destroy(dialog_); |
| 225 delete this; | 253 delete this; |
| 226 } | 254 } |
| 227 | 255 |
| 228 void ExtensionInstallDialog::OnStoreLinkClick(GtkWidget* sender) { | 256 void ExtensionInstallDialog::OnStoreLinkClick(GtkWidget* sender) { |
| 229 GURL store_url( | 257 GURL store_url( |
| 230 extension_urls::GetWebstoreItemDetailURLPrefix() + extension_->id()); | 258 extension_urls::GetWebstoreItemDetailURLPrefix() + extension_id_); |
| 231 BrowserList::GetLastActive()->OpenURL(OpenURLParams( | 259 BrowserList::GetLastActive()->OpenURL(OpenURLParams( |
| 232 store_url, content::Referrer(), NEW_FOREGROUND_TAB, | 260 store_url, content::Referrer(), NEW_FOREGROUND_TAB, |
| 233 content::PAGE_TRANSITION_LINK, false)); | 261 content::PAGE_TRANSITION_LINK, false)); |
| 234 | 262 |
| 235 OnResponse(dialog_, GTK_RESPONSE_CLOSE); | 263 OnResponse(dialog_, GTK_RESPONSE_CLOSE); |
| 236 } | 264 } |
| 237 | 265 |
| 238 } // namespace | 266 } // namespace |
| 239 | 267 |
| 240 void ShowExtensionInstallDialogImpl( | 268 void ShowExtensionInstallDialogImpl( |
| 241 Profile* profile, | 269 Profile* profile, |
| 242 ExtensionInstallUI::Delegate* delegate, | 270 ExtensionInstallUI::Delegate* delegate, |
| 243 const Extension* extension, | |
| 244 SkBitmap* icon, | |
| 245 const ExtensionInstallUI::Prompt& prompt) { | 271 const ExtensionInstallUI::Prompt& prompt) { |
| 246 Browser* browser = BrowserList::GetLastActiveWithProfile(profile); | 272 Browser* browser = BrowserList::GetLastActiveWithProfile(profile); |
| 247 if (!browser) { | 273 if (!browser) { |
| 248 delegate->InstallUIAbort(false); | 274 delegate->InstallUIAbort(false); |
| 249 return; | 275 return; |
| 250 } | 276 } |
| 251 | 277 |
| 252 BrowserWindowGtk* browser_window = static_cast<BrowserWindowGtk*>( | 278 BrowserWindowGtk* browser_window = static_cast<BrowserWindowGtk*>( |
| 253 browser->window()); | 279 browser->window()); |
| 254 if (!browser_window) { | 280 if (!browser_window) { |
| 255 delegate->InstallUIAbort(false); | 281 delegate->InstallUIAbort(false); |
| 256 return; | 282 return; |
| 257 } | 283 } |
| 258 | 284 |
| 259 new ExtensionInstallDialog(browser_window->window(), | 285 new ExtensionInstallDialog(browser_window->window(), delegate, prompt); |
| 260 delegate, | |
| 261 extension, | |
| 262 icon, | |
| 263 prompt); | |
| 264 } | 286 } |
| OLD | NEW |