| OLD | NEW |
| (Empty) |
| 1 // Copyright (c) 2010 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 "chrome/browser/gtk/create_application_shortcuts_dialog_gtk.h" | |
| 6 | |
| 7 #include <string> | |
| 8 | |
| 9 #include "app/l10n_util.h" | |
| 10 #include "base/environment.h" | |
| 11 #include "base/utf_string_conversions.h" | |
| 12 #include "chrome/browser/browser_thread.h" | |
| 13 #include "chrome/browser/gtk/gtk_util.h" | |
| 14 #include "chrome/browser/shell_integration.h" | |
| 15 #include "chrome/browser/tab_contents/tab_contents.h" | |
| 16 #include "chrome/browser/tab_contents/tab_contents_delegate.h" | |
| 17 #include "chrome/browser/web_applications/web_app.h" | |
| 18 #include "chrome/common/extensions/extension.h" | |
| 19 #include "chrome/common/extensions/extension_resource.h" | |
| 20 #include "gfx/gtk_util.h" | |
| 21 #include "grit/chromium_strings.h" | |
| 22 #include "grit/generated_resources.h" | |
| 23 #include "grit/locale_settings.h" | |
| 24 | |
| 25 namespace { | |
| 26 | |
| 27 // Size (in pixels) of the icon preview. | |
| 28 const int kIconPreviewSizePixels = 32; | |
| 29 | |
| 30 // Height (in lines) of the shortcut description label. | |
| 31 const int kDescriptionLabelHeightLines = 3; | |
| 32 | |
| 33 } // namespace | |
| 34 | |
| 35 // static | |
| 36 void CreateWebApplicationShortcutsDialogGtk::Show(GtkWindow* parent, | |
| 37 TabContents* tab_contents) { | |
| 38 new CreateWebApplicationShortcutsDialogGtk(parent, tab_contents); | |
| 39 } | |
| 40 | |
| 41 void CreateChromeApplicationShortcutsDialogGtk::Show(GtkWindow* parent, | |
| 42 const Extension* app) { | |
| 43 new CreateChromeApplicationShortcutsDialogGtk(parent, app); | |
| 44 } | |
| 45 | |
| 46 | |
| 47 CreateApplicationShortcutsDialogGtk::CreateApplicationShortcutsDialogGtk( | |
| 48 GtkWindow* parent) | |
| 49 : parent_(parent), | |
| 50 error_dialog_(NULL) { | |
| 51 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
| 52 | |
| 53 // Will be balanced by Release later. | |
| 54 AddRef(); | |
| 55 } | |
| 56 | |
| 57 void CreateApplicationShortcutsDialogGtk::CreateIconPixBuf( | |
| 58 const SkBitmap& bitmap) { | |
| 59 // Prepare the icon. Try to scale it if it's too small, otherwise it would | |
| 60 // look weird. | |
| 61 GdkPixbuf* pixbuf = gfx::GdkPixbufFromSkBitmap(&shortcut_info_.favicon); | |
| 62 int pixbuf_width = gdk_pixbuf_get_width(pixbuf); | |
| 63 int pixbuf_height = gdk_pixbuf_get_height(pixbuf); | |
| 64 if (pixbuf_width == pixbuf_height && pixbuf_width < kIconPreviewSizePixels) { | |
| 65 // Only scale the pixbuf if it's a square (for simplicity). | |
| 66 // Generally it should be square, if it's a favicon or app icon. | |
| 67 // Use the highest quality interpolation. The scaling is | |
| 68 // going to have low quality anyway, because the initial image | |
| 69 // is likely small. | |
| 70 favicon_pixbuf_ = gdk_pixbuf_scale_simple(pixbuf, | |
| 71 kIconPreviewSizePixels, | |
| 72 kIconPreviewSizePixels, | |
| 73 GDK_INTERP_HYPER); | |
| 74 g_object_unref(pixbuf); | |
| 75 } else { | |
| 76 favicon_pixbuf_ = pixbuf; | |
| 77 } | |
| 78 } | |
| 79 | |
| 80 void CreateApplicationShortcutsDialogGtk::CreateDialogBox(GtkWindow* parent) { | |
| 81 // Build the dialog. | |
| 82 create_dialog_ = gtk_dialog_new_with_buttons( | |
| 83 l10n_util::GetStringUTF8(IDS_CREATE_SHORTCUTS_TITLE).c_str(), | |
| 84 parent, | |
| 85 (GtkDialogFlags) (GTK_DIALOG_MODAL | GTK_DIALOG_NO_SEPARATOR), | |
| 86 GTK_STOCK_CANCEL, | |
| 87 GTK_RESPONSE_REJECT, | |
| 88 NULL); | |
| 89 gtk_widget_realize(create_dialog_); | |
| 90 gtk_window_set_resizable(GTK_WINDOW(create_dialog_), false); | |
| 91 gtk_util::AddButtonToDialog(create_dialog_, | |
| 92 l10n_util::GetStringUTF8(IDS_CREATE_SHORTCUTS_COMMIT).c_str(), | |
| 93 GTK_STOCK_APPLY, GTK_RESPONSE_ACCEPT); | |
| 94 | |
| 95 GtkWidget* content_area = GTK_DIALOG(create_dialog_)->vbox; | |
| 96 gtk_box_set_spacing(GTK_BOX(content_area), gtk_util::kContentAreaSpacing); | |
| 97 | |
| 98 GtkWidget* vbox = gtk_vbox_new(FALSE, gtk_util::kControlSpacing); | |
| 99 gtk_container_add(GTK_CONTAINER(content_area), vbox); | |
| 100 | |
| 101 // Create a box containing basic information about the new shortcut: an image | |
| 102 // on the left, and a description on the right. | |
| 103 GtkWidget* hbox = gtk_hbox_new(FALSE, gtk_util::kControlSpacing); | |
| 104 gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0); | |
| 105 gtk_container_set_border_width(GTK_CONTAINER(hbox), | |
| 106 gtk_util::kControlSpacing); | |
| 107 | |
| 108 // Put the icon preview in place. | |
| 109 GtkWidget* favicon_image = gtk_image_new_from_pixbuf(favicon_pixbuf_); | |
| 110 gtk_box_pack_start(GTK_BOX(hbox), favicon_image, FALSE, FALSE, 0); | |
| 111 | |
| 112 // Create the label with application shortcut description. | |
| 113 GtkWidget* description_label = gtk_label_new(NULL); | |
| 114 gtk_box_pack_start(GTK_BOX(hbox), description_label, FALSE, FALSE, 0); | |
| 115 gtk_label_set_line_wrap(GTK_LABEL(description_label), TRUE); | |
| 116 gtk_widget_realize(description_label); | |
| 117 | |
| 118 // Set the size request on the label so it knows where to line wrap. The width | |
| 119 // is the desired size of the dialog less the space reserved for padding and | |
| 120 // the image. | |
| 121 int label_width, label_height; | |
| 122 gtk_util::GetWidgetSizeFromResources( | |
| 123 description_label, | |
| 124 IDS_CREATE_SHORTCUTS_DIALOG_WIDTH_CHARS, -1, &label_width, NULL); | |
| 125 label_width -= gtk_util::kControlSpacing * 3 + | |
| 126 gdk_pixbuf_get_width(favicon_pixbuf_); | |
| 127 gtk_util::GetWidgetSizeFromCharacters( | |
| 128 description_label, -1, kDescriptionLabelHeightLines, NULL, &label_height); | |
| 129 gtk_widget_set_size_request(description_label, label_width, label_height); | |
| 130 gtk_misc_set_alignment(GTK_MISC(description_label), 0, 0.5); | |
| 131 std::string description(UTF16ToUTF8(shortcut_info_.description)); | |
| 132 std::string title(UTF16ToUTF8(shortcut_info_.title)); | |
| 133 gtk_label_set_text(GTK_LABEL(description_label), | |
| 134 (description.empty() ? title : description).c_str()); | |
| 135 | |
| 136 // Label on top of the checkboxes. | |
| 137 GtkWidget* checkboxes_label = gtk_label_new( | |
| 138 l10n_util::GetStringUTF8(IDS_CREATE_SHORTCUTS_LABEL).c_str()); | |
| 139 gtk_misc_set_alignment(GTK_MISC(checkboxes_label), 0, 0); | |
| 140 gtk_box_pack_start(GTK_BOX(vbox), checkboxes_label, FALSE, FALSE, 0); | |
| 141 | |
| 142 // Desktop checkbox. | |
| 143 desktop_checkbox_ = gtk_check_button_new_with_label( | |
| 144 l10n_util::GetStringUTF8(IDS_CREATE_SHORTCUTS_DESKTOP_CHKBOX).c_str()); | |
| 145 gtk_box_pack_start(GTK_BOX(vbox), desktop_checkbox_, FALSE, FALSE, 0); | |
| 146 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(desktop_checkbox_), true); | |
| 147 g_signal_connect(desktop_checkbox_, "toggled", | |
| 148 G_CALLBACK(OnToggleCheckboxThunk), this); | |
| 149 | |
| 150 // Menu checkbox. | |
| 151 menu_checkbox_ = gtk_check_button_new_with_label( | |
| 152 l10n_util::GetStringUTF8(IDS_CREATE_SHORTCUTS_MENU_CHKBOX).c_str()); | |
| 153 gtk_box_pack_start(GTK_BOX(vbox), menu_checkbox_, FALSE, FALSE, 0); | |
| 154 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(menu_checkbox_), false); | |
| 155 g_signal_connect(menu_checkbox_, "toggled", | |
| 156 G_CALLBACK(OnToggleCheckboxThunk), this); | |
| 157 | |
| 158 g_signal_connect(create_dialog_, "response", | |
| 159 G_CALLBACK(OnCreateDialogResponseThunk), this); | |
| 160 gtk_widget_show_all(create_dialog_); | |
| 161 } | |
| 162 | |
| 163 CreateApplicationShortcutsDialogGtk::~CreateApplicationShortcutsDialogGtk() { | |
| 164 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
| 165 | |
| 166 gtk_widget_destroy(create_dialog_); | |
| 167 | |
| 168 if (error_dialog_) | |
| 169 gtk_widget_destroy(error_dialog_); | |
| 170 | |
| 171 g_object_unref(favicon_pixbuf_); | |
| 172 } | |
| 173 | |
| 174 void CreateApplicationShortcutsDialogGtk::OnCreateDialogResponse( | |
| 175 GtkWidget* widget, int response) { | |
| 176 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
| 177 | |
| 178 if (response == GTK_RESPONSE_ACCEPT) { | |
| 179 shortcut_info_.create_on_desktop = | |
| 180 gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(desktop_checkbox_)); | |
| 181 shortcut_info_.create_in_applications_menu = | |
| 182 gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(menu_checkbox_)); | |
| 183 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE, | |
| 184 NewRunnableMethod(this, | |
| 185 &CreateApplicationShortcutsDialogGtk::CreateDesktopShortcut, | |
| 186 shortcut_info_)); | |
| 187 | |
| 188 OnCreatedShortcut(); | |
| 189 } else { | |
| 190 Release(); | |
| 191 } | |
| 192 } | |
| 193 | |
| 194 void CreateApplicationShortcutsDialogGtk::OnErrorDialogResponse( | |
| 195 GtkWidget* widget, int response) { | |
| 196 Release(); | |
| 197 } | |
| 198 | |
| 199 void CreateApplicationShortcutsDialogGtk::CreateDesktopShortcut( | |
| 200 const ShellIntegration::ShortcutInfo& shortcut_info) { | |
| 201 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); | |
| 202 | |
| 203 scoped_ptr<base::Environment> env(base::Environment::Create()); | |
| 204 | |
| 205 std::string shortcut_template; | |
| 206 if (ShellIntegration::GetDesktopShortcutTemplate(env.get(), | |
| 207 &shortcut_template)) { | |
| 208 ShellIntegration::CreateDesktopShortcut(shortcut_info, | |
| 209 shortcut_template); | |
| 210 Release(); | |
| 211 } else { | |
| 212 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, | |
| 213 NewRunnableMethod(this, | |
| 214 &CreateApplicationShortcutsDialogGtk::ShowErrorDialog)); | |
| 215 } | |
| 216 } | |
| 217 | |
| 218 void CreateApplicationShortcutsDialogGtk::ShowErrorDialog() { | |
| 219 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
| 220 | |
| 221 // Hide the create dialog so that the user can no longer interact with it. | |
| 222 gtk_widget_hide(create_dialog_); | |
| 223 | |
| 224 error_dialog_ = gtk_dialog_new_with_buttons( | |
| 225 l10n_util::GetStringUTF8(IDS_CREATE_SHORTCUTS_ERROR_TITLE).c_str(), | |
| 226 NULL, | |
| 227 (GtkDialogFlags) (GTK_DIALOG_NO_SEPARATOR), | |
| 228 GTK_STOCK_OK, | |
| 229 GTK_RESPONSE_ACCEPT, | |
| 230 NULL); | |
| 231 gtk_widget_realize(error_dialog_); | |
| 232 gtk_util::SetWindowSizeFromResources( | |
| 233 GTK_WINDOW(error_dialog_), | |
| 234 IDS_CREATE_SHORTCUTS_ERROR_DIALOG_WIDTH_CHARS, | |
| 235 IDS_CREATE_SHORTCUTS_ERROR_DIALOG_HEIGHT_LINES, | |
| 236 false); // resizable | |
| 237 GtkWidget* content_area = GTK_DIALOG(error_dialog_)->vbox; | |
| 238 gtk_box_set_spacing(GTK_BOX(content_area), gtk_util::kContentAreaSpacing); | |
| 239 | |
| 240 GtkWidget* vbox = gtk_vbox_new(FALSE, gtk_util::kControlSpacing); | |
| 241 gtk_container_add(GTK_CONTAINER(content_area), vbox); | |
| 242 | |
| 243 // Label on top of the checkboxes. | |
| 244 GtkWidget* description = gtk_label_new( | |
| 245 l10n_util::GetStringFUTF8( | |
| 246 IDS_CREATE_SHORTCUTS_ERROR_LABEL, | |
| 247 l10n_util::GetStringUTF16(IDS_PRODUCT_NAME)).c_str()); | |
| 248 gtk_label_set_line_wrap(GTK_LABEL(description), TRUE); | |
| 249 gtk_misc_set_alignment(GTK_MISC(description), 0, 0); | |
| 250 gtk_box_pack_start(GTK_BOX(vbox), description, FALSE, FALSE, 0); | |
| 251 | |
| 252 g_signal_connect(error_dialog_, "response", | |
| 253 G_CALLBACK(OnErrorDialogResponseThunk), this); | |
| 254 gtk_widget_show_all(error_dialog_); | |
| 255 } | |
| 256 | |
| 257 void CreateApplicationShortcutsDialogGtk::OnToggleCheckbox(GtkWidget* sender) { | |
| 258 gboolean can_accept = FALSE; | |
| 259 | |
| 260 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(desktop_checkbox_)) || | |
| 261 gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(menu_checkbox_))) { | |
| 262 can_accept = TRUE; | |
| 263 } | |
| 264 | |
| 265 gtk_dialog_set_response_sensitive(GTK_DIALOG(create_dialog_), | |
| 266 GTK_RESPONSE_ACCEPT, | |
| 267 can_accept); | |
| 268 } | |
| 269 | |
| 270 CreateWebApplicationShortcutsDialogGtk::CreateWebApplicationShortcutsDialogGtk( | |
| 271 GtkWindow* parent, | |
| 272 TabContents* tab_contents) | |
| 273 : CreateApplicationShortcutsDialogGtk(parent), | |
| 274 tab_contents_(tab_contents) { | |
| 275 | |
| 276 // Get shortcut information now, it's needed for our UI. | |
| 277 web_app::GetShortcutInfoForTab(tab_contents_, &shortcut_info_); | |
| 278 CreateIconPixBuf(shortcut_info_.favicon); | |
| 279 | |
| 280 CreateDialogBox(parent); | |
| 281 } | |
| 282 | |
| 283 void CreateWebApplicationShortcutsDialogGtk::OnCreatedShortcut() { | |
| 284 if (tab_contents_->delegate()) | |
| 285 tab_contents_->delegate()->ConvertContentsToApplication(tab_contents_); | |
| 286 } | |
| 287 | |
| 288 CreateChromeApplicationShortcutsDialogGtk:: | |
| 289 CreateChromeApplicationShortcutsDialogGtk( | |
| 290 GtkWindow* parent, | |
| 291 const Extension* app) | |
| 292 : CreateApplicationShortcutsDialogGtk(parent), | |
| 293 app_(app), | |
| 294 ALLOW_THIS_IN_INITIALIZER_LIST(tracker_(this)) { | |
| 295 | |
| 296 // Get shortcut information now, it's needed for our UI. | |
| 297 shortcut_info_.extension_id = UTF8ToUTF16(app_->id()); | |
| 298 shortcut_info_.url = GURL(app_->launch_web_url()); | |
| 299 shortcut_info_.title = UTF8ToUTF16(app_->name()); | |
| 300 shortcut_info_.description = UTF8ToUTF16(app_->description()); | |
| 301 | |
| 302 // Get the icon. | |
| 303 const gfx::Size max_size(kIconPreviewSizePixels, kIconPreviewSizePixels); | |
| 304 ExtensionResource icon_resource = app_->GetIconResource( | |
| 305 kIconPreviewSizePixels, ExtensionIconSet::MATCH_BIGGER); | |
| 306 | |
| 307 // If no icon exists that is the desired size or larger, get the | |
| 308 // largest icon available: | |
| 309 if (icon_resource.empty()) | |
| 310 icon_resource = app_->GetIconResource( | |
| 311 kIconPreviewSizePixels, ExtensionIconSet::MATCH_SMALLER); | |
| 312 | |
| 313 tracker_.LoadImage(app_, | |
| 314 icon_resource, | |
| 315 max_size, | |
| 316 ImageLoadingTracker::DONT_CACHE); | |
| 317 } | |
| 318 | |
| 319 // Called by tracker_ when the app's icon is loaded. | |
| 320 void CreateChromeApplicationShortcutsDialogGtk::OnImageLoaded( | |
| 321 SkBitmap* image, ExtensionResource resource, int index) { | |
| 322 if (image->isNull()) { | |
| 323 NOTREACHED() << "Corrupt image in profile?"; | |
| 324 return; | |
| 325 } | |
| 326 shortcut_info_.favicon = *image; | |
| 327 | |
| 328 CreateIconPixBuf(*image); | |
| 329 CreateDialogBox(parent_); | |
| 330 } | |
| OLD | NEW |