Home | History | Annotate | Download | only in extensions
      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