1 // Copyright (c) 2011 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/string_util.h" 8 #include "base/utf_string_conversions.h" 9 #include "chrome/browser/extensions/extension_install_dialog.h" 10 #include "chrome/browser/profiles/profile.h" 11 #include "chrome/browser/ui/browser_list.h" 12 #include "chrome/browser/ui/browser_window.h" 13 #include "chrome/browser/ui/gtk/browser_window_gtk.h" 14 #include "chrome/browser/ui/gtk/gtk_util.h" 15 #include "chrome/common/extensions/extension.h" 16 #include "grit/generated_resources.h" 17 #include "skia/ext/image_operations.h" 18 #include "ui/base/l10n/l10n_util.h" 19 #include "ui/gfx/gtk_util.h" 20 21 namespace { 22 23 const int kRightColumnMinWidth = 290; 24 const int kImageSize = 69; 25 26 // Padding on all sides of each permission in the permissions list. 27 const int kPermissionsPadding = 8; 28 29 // Make a GtkLabel with |str| as its text, using the formatting in |format|. 30 GtkWidget* MakeMarkupLabel(const char* format, const std::string& str) { 31 GtkWidget* label = gtk_label_new(NULL); 32 char* markup = g_markup_printf_escaped(format, str.c_str()); 33 gtk_label_set_markup(GTK_LABEL(label), markup); 34 g_free(markup); 35 36 // Left align it. 37 gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5); 38 39 return label; 40 } 41 42 void OnResponse(GtkWidget* dialog, int response_id, 43 ExtensionInstallUI::Delegate* delegate) { 44 if (response_id == GTK_RESPONSE_ACCEPT) { 45 delegate->InstallUIProceed(); 46 } else { 47 delegate->InstallUIAbort(); 48 } 49 50 gtk_widget_destroy(dialog); 51 } 52 53 void ShowInstallDialog(GtkWindow* parent, 54 SkBitmap* skia_icon, 55 const Extension* extension, 56 ExtensionInstallUI::Delegate *delegate, 57 const std::vector<string16>& permissions, 58 ExtensionInstallUI::PromptType type) { 59 // Build the dialog. 60 GtkWidget* dialog = gtk_dialog_new_with_buttons( 61 l10n_util::GetStringUTF8(ExtensionInstallUI::kTitleIds[type]).c_str(), 62 parent, 63 GTK_DIALOG_MODAL, 64 NULL); 65 GtkWidget* close_button = gtk_dialog_add_button(GTK_DIALOG(dialog), 66 GTK_STOCK_CANCEL, GTK_RESPONSE_CLOSE); 67 gtk_dialog_add_button( 68 GTK_DIALOG(dialog), 69 l10n_util::GetStringUTF8(ExtensionInstallUI::kButtonIds[type]).c_str(), 70 GTK_RESPONSE_ACCEPT); 71 gtk_dialog_set_has_separator(GTK_DIALOG(dialog), FALSE); 72 73 // Create a two column layout. 74 GtkWidget* content_area = GTK_DIALOG(dialog)->vbox; 75 gtk_box_set_spacing(GTK_BOX(content_area), gtk_util::kContentAreaSpacing); 76 77 GtkWidget* icon_hbox = gtk_hbox_new(FALSE, gtk_util::kContentAreaSpacing); 78 gtk_box_pack_start(GTK_BOX(content_area), icon_hbox, TRUE, TRUE, 0); 79 80 // Resize the icon if necessary. 81 SkBitmap scaled_icon = *skia_icon; 82 if (scaled_icon.width() > kImageSize || scaled_icon.height() > kImageSize) { 83 scaled_icon = skia::ImageOperations::Resize(scaled_icon, 84 skia::ImageOperations::RESIZE_LANCZOS3, 85 kImageSize, kImageSize); 86 } 87 88 // Put Icon in the left column. 89 GdkPixbuf* pixbuf = gfx::GdkPixbufFromSkBitmap(&scaled_icon); 90 GtkWidget* icon = gtk_image_new_from_pixbuf(pixbuf); 91 g_object_unref(pixbuf); 92 gtk_box_pack_start(GTK_BOX(icon_hbox), icon, FALSE, FALSE, 0); 93 // Top justify the image. 94 gtk_misc_set_alignment(GTK_MISC(icon), 0.5, 0.0); 95 96 // Create a new vbox for the right column. 97 GtkWidget* right_column_area = gtk_vbox_new(FALSE, gtk_util::kControlSpacing); 98 gtk_box_pack_start(GTK_BOX(icon_hbox), right_column_area, TRUE, TRUE, 0); 99 100 std::string heading_text = l10n_util::GetStringFUTF8( 101 ExtensionInstallUI::kHeadingIds[type], UTF8ToUTF16(extension->name())); 102 GtkWidget* heading_label = MakeMarkupLabel("<span weight=\"bold\">%s</span>", 103 heading_text); 104 gtk_label_set_line_wrap(GTK_LABEL(heading_label), true); 105 gtk_misc_set_alignment(GTK_MISC(heading_label), 0.0, 0.5); 106 bool show_permissions = !permissions.empty(); 107 // If we are not going to show the permissions, vertically center the title. 108 gtk_box_pack_start(GTK_BOX(right_column_area), heading_label, 109 !show_permissions, !show_permissions, 0); 110 111 if (show_permissions) { 112 GtkWidget* warning_label = gtk_label_new(l10n_util::GetStringUTF8( 113 ExtensionInstallUI::kWarningIds[type]).c_str()); 114 gtk_util::SetLabelWidth(warning_label, kRightColumnMinWidth); 115 116 gtk_box_pack_start(GTK_BOX(right_column_area), warning_label, 117 FALSE, FALSE, 0); 118 119 GtkWidget* frame = gtk_frame_new(NULL); 120 gtk_box_pack_start(GTK_BOX(right_column_area), frame, FALSE, FALSE, 0); 121 122 GtkWidget* text_view = gtk_text_view_new(); 123 gtk_container_add(GTK_CONTAINER(frame), text_view); 124 gtk_text_view_set_editable(GTK_TEXT_VIEW(text_view), FALSE); 125 gtk_text_view_set_left_margin(GTK_TEXT_VIEW(text_view), 126 kPermissionsPadding); 127 gtk_text_view_set_right_margin(GTK_TEXT_VIEW(text_view), 128 kPermissionsPadding); 129 gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(text_view), GTK_WRAP_WORD); 130 GtkTextBuffer* buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(text_view)); 131 GtkTextTagTable* tag_table = gtk_text_buffer_get_tag_table(buffer); 132 133 GtkTextTag* padding_below_tag = gtk_text_tag_new(NULL); 134 g_object_set(G_OBJECT(padding_below_tag), "pixels-below-lines", 135 kPermissionsPadding, NULL); 136 g_object_set(G_OBJECT(padding_below_tag), "pixels-below-lines-set", 137 TRUE, NULL); 138 gtk_text_tag_table_add(tag_table, padding_below_tag); 139 g_object_unref(padding_below_tag); 140 GtkTextTag* padding_above_tag = gtk_text_tag_new(NULL); 141 g_object_set(G_OBJECT(padding_above_tag), "pixels-above-lines", 142 kPermissionsPadding, NULL); 143 g_object_set(G_OBJECT(padding_above_tag), "pixels-above-lines-set", 144 TRUE, NULL); 145 gtk_text_tag_table_add(tag_table, padding_above_tag); 146 g_object_unref(padding_above_tag); 147 148 GtkTextIter end_iter; 149 gtk_text_buffer_get_end_iter(buffer, &end_iter); 150 for (std::vector<string16>::const_iterator iter = permissions.begin(); 151 iter != permissions.end(); ++iter) { 152 if (iter != permissions.begin()) 153 gtk_text_buffer_insert(buffer, &end_iter, "\n", -1); 154 gtk_text_buffer_insert_with_tags( 155 buffer, &end_iter, UTF16ToUTF8(*iter).c_str(), -1, 156 padding_below_tag, 157 iter == permissions.begin() ? padding_above_tag : NULL, 158 NULL); 159 } 160 } 161 162 g_signal_connect(dialog, "response", G_CALLBACK(OnResponse), delegate); 163 gtk_window_set_resizable(GTK_WINDOW(dialog), FALSE); 164 165 gtk_dialog_set_default_response(GTK_DIALOG(dialog), GTK_RESPONSE_CLOSE); 166 gtk_widget_show_all(dialog); 167 gtk_widget_grab_focus(close_button); 168 } 169 170 } // namespace 171 172 void ShowExtensionInstallDialog( 173 Profile* profile, 174 ExtensionInstallUI::Delegate* delegate, 175 const Extension* extension, 176 SkBitmap* icon, 177 const std::vector<string16>& permissions, 178 ExtensionInstallUI::PromptType type) { 179 Browser* browser = BrowserList::GetLastActiveWithProfile(profile); 180 if (!browser) { 181 delegate->InstallUIAbort(); 182 return; 183 } 184 185 BrowserWindowGtk* browser_window = static_cast<BrowserWindowGtk*>( 186 browser->window()); 187 if (!browser_window) { 188 delegate->InstallUIAbort(); 189 return; 190 } 191 192 ShowInstallDialog( 193 browser_window->window(), icon, extension, delegate, permissions, type); 194 } 195