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 "base/basictypes.h"
      6 #include "base/compiler_specific.h"
      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/views/window.h"
     14 #include "chrome/common/extensions/extension.h"
     15 #include "grit/generated_resources.h"
     16 #include "ui/base/l10n/l10n_util.h"
     17 #include "views/controls/image_view.h"
     18 #include "views/controls/label.h"
     19 #include "views/layout/layout_constants.h"
     20 #include "views/view.h"
     21 #include "views/window/dialog_delegate.h"
     22 #include "views/window/window.h"
     23 
     24 namespace {
     25 
     26 // Size of extension icon in top left of dialog.
     27 const int kIconSize = 69;
     28 
     29 // Width of the white permission box. This also is the max width of all
     30 // elements in the right column of the dialog in the case where the extension
     31 // requests permissions.
     32 const int kPermissionBoxWidth = 270;
     33 
     34 // Width of the right column of the dialog when the extension requests no
     35 // permissions.
     36 const int kNoPermissionsRightColumnWidth = 210;
     37 
     38 // Width of the gray border around the permission box.
     39 const int kPermissionBoxBorderWidth = 1;
     40 
     41 // Width of the horizontal padding inside the permission box border.
     42 const int kPermissionBoxHorizontalPadding = 10;
     43 
     44 // Width of the vertical padding inside the permission box border.
     45 const int kPermissionBoxVerticalPadding = 11;
     46 
     47 // The max width of the individual permission strings inside the permission
     48 // box.
     49 const int kPermissionLabelWidth =
     50     kPermissionBoxWidth -
     51     kPermissionBoxBorderWidth * 2 -
     52     kPermissionBoxHorizontalPadding * 2;
     53 
     54 // Heading font size correction.
     55 #if defined(CROS_FONTS_USING_BCI)
     56 const int kHeadingFontSizeDelta = 0;
     57 #else
     58 const int kHeadingFontSizeDelta = 1;
     59 #endif
     60 
     61 }  // namespace
     62 
     63 // Implements the extension installation dialog for TOOLKIT_VIEWS.
     64 class ExtensionInstallDialogView : public views::View,
     65                                    public views::DialogDelegate {
     66  public:
     67   ExtensionInstallDialogView(ExtensionInstallUI::Delegate* delegate,
     68                              const Extension* extension,
     69                              SkBitmap* icon,
     70                              const std::vector<string16>& permissions,
     71                              ExtensionInstallUI::PromptType type);
     72   virtual ~ExtensionInstallDialogView();
     73 
     74  private:
     75   // views::View:
     76   virtual gfx::Size GetPreferredSize() OVERRIDE;
     77   virtual void Layout() OVERRIDE;
     78 
     79   // views::DialogDelegate:
     80   virtual std::wstring GetDialogButtonLabel(
     81       MessageBoxFlags::DialogButton button) const OVERRIDE;
     82   virtual int GetDefaultDialogButton() const OVERRIDE;
     83   virtual bool Cancel() OVERRIDE;
     84   virtual bool Accept() OVERRIDE;
     85 
     86   // views::WindowDelegate:
     87   virtual bool IsModal() const OVERRIDE;
     88   virtual std::wstring GetWindowTitle() const OVERRIDE;
     89   virtual views::View* GetContentsView() OVERRIDE;
     90 
     91   // The delegate that we will call back to when the user accepts or rejects
     92   // the installation.
     93   ExtensionInstallUI::Delegate* delegate_;
     94 
     95   // Displays the extension's icon.
     96   views::ImageView* icon_;
     97 
     98   // Displays the main heading "Install FooBar?".
     99   views::Label* heading_;
    100 
    101   // Displays the permission box header "The extension will have access to:".
    102   views::Label* will_have_access_to_;
    103 
    104   // The white box containing the list of permissions the extension requires.
    105   // This can be NULL if the extension requires no permissions.
    106   views::View* permission_box_;
    107 
    108   // The labels describing each of the permissions the extension requires.
    109   std::vector<views::Label*> permissions_;
    110 
    111   // The width of the right column of the dialog. Will be either
    112   // kPermissionBoxWidth or kNoPermissionsRightColumnWidth, depending on
    113   // whether the extension requires any permissions.
    114   int right_column_width_;
    115 
    116   // The type of install dialog, which must be INSTALL_PROMPT or
    117   // RE_ENABLE_PROMPT.
    118   ExtensionInstallUI::PromptType type_;
    119 
    120   DISALLOW_COPY_AND_ASSIGN(ExtensionInstallDialogView);
    121 };
    122 
    123 ExtensionInstallDialogView::ExtensionInstallDialogView(
    124     ExtensionInstallUI::Delegate* delegate,
    125     const Extension* extension,
    126     SkBitmap* icon,
    127     const std::vector<string16>& permissions,
    128     ExtensionInstallUI::PromptType type)
    129     : delegate_(delegate),
    130       icon_(NULL),
    131       heading_(NULL),
    132       will_have_access_to_(NULL),
    133       permission_box_(NULL),
    134       right_column_width_(0),
    135       type_(type) {
    136   // Scale down to icon size, but allow smaller icons (don't scale up).
    137   gfx::Size size(icon->width(), icon->height());
    138   if (size.width() > kIconSize || size.height() > kIconSize)
    139     size = gfx::Size(kIconSize, kIconSize);
    140   icon_ = new views::ImageView();
    141   icon_->SetImageSize(size);
    142   icon_->SetImage(*icon);
    143   icon_->SetHorizontalAlignment(views::ImageView::CENTER);
    144   icon_->SetVerticalAlignment(views::ImageView::CENTER);
    145   AddChildView(icon_);
    146 
    147   heading_ = new views::Label(UTF16ToWide(
    148       l10n_util::GetStringFUTF16(ExtensionInstallUI::kHeadingIds[type_],
    149                                  UTF8ToUTF16(extension->name()))));
    150   heading_->SetFont(heading_->font().DeriveFont(kHeadingFontSizeDelta,
    151                                                 gfx::Font::BOLD));
    152   heading_->SetMultiLine(true);
    153   heading_->SetHorizontalAlignment(views::Label::ALIGN_LEFT);
    154   AddChildView(heading_);
    155 
    156   if (permissions.empty()) {
    157     right_column_width_ = kNoPermissionsRightColumnWidth;
    158   } else {
    159     right_column_width_ = kPermissionBoxWidth;
    160     will_have_access_to_ = new views::Label(UTF16ToWide(
    161         l10n_util::GetStringUTF16(ExtensionInstallUI::kWarningIds[type_])));
    162     will_have_access_to_->SetMultiLine(true);
    163     will_have_access_to_->SetHorizontalAlignment(views::Label::ALIGN_LEFT);
    164     AddChildView(will_have_access_to_);
    165 
    166     permission_box_ = new views::View();
    167     permission_box_->set_background(
    168         views::Background::CreateSolidBackground(SK_ColorWHITE));
    169     permission_box_->set_border(
    170         views::Border::CreateSolidBorder(kPermissionBoxBorderWidth,
    171                                          SK_ColorLTGRAY));
    172     AddChildView(permission_box_);
    173   }
    174 
    175   for (size_t i = 0; i < permissions.size(); ++i) {
    176     views::Label* label = new views::Label(UTF16ToWide(permissions[i]));
    177     label->SetMultiLine(true);
    178     label->SetHorizontalAlignment(views::Label::ALIGN_LEFT);
    179     permission_box_->AddChildView(label);
    180     permissions_.push_back(label);
    181   }
    182 }
    183 
    184 ExtensionInstallDialogView::~ExtensionInstallDialogView() {
    185 }
    186 
    187 gfx::Size ExtensionInstallDialogView::GetPreferredSize() {
    188   int width = views::kPanelHorizMargin * 2;
    189   width += kIconSize;
    190   width += views::kPanelHorizMargin;  // Gutter.
    191   width += right_column_width_;
    192 
    193   int height = views::kPanelVertMargin * 2;
    194   height += heading_->GetHeightForWidth(right_column_width_);
    195 
    196   if (permission_box_) {
    197     height += views::kRelatedControlVerticalSpacing;
    198     height += will_have_access_to_->GetHeightForWidth(right_column_width_);
    199 
    200     height += views::kRelatedControlVerticalSpacing;
    201     height += kPermissionBoxBorderWidth * 2;
    202     height += kPermissionBoxVerticalPadding * 2;
    203 
    204     for (size_t i = 0; i < permissions_.size(); ++i) {
    205       if (i > 0)
    206         height += views::kRelatedControlVerticalSpacing;
    207       height += permissions_[0]->GetHeightForWidth(kPermissionLabelWidth);
    208     }
    209   }
    210 
    211   return gfx::Size(width,
    212                    std::max(height, kIconSize + views::kPanelVertMargin * 2));
    213 }
    214 
    215 void ExtensionInstallDialogView::Layout() {
    216   int x = views::kPanelHorizMargin;
    217   int y = views::kPanelVertMargin;
    218 
    219   icon_->SetBounds(x, y, kIconSize, kIconSize);
    220   x += kIconSize;
    221   x += views::kPanelHorizMargin;
    222 
    223   heading_->SizeToFit(right_column_width_);
    224   heading_->SetX(x);
    225 
    226   // If there's no special permissions, we do a slightly different layout with
    227   // the heading centered vertically wrt the icon.
    228   if (!permission_box_) {
    229     heading_->SetY((GetPreferredSize().height() - heading_->height()) / 2);
    230     return;
    231   }
    232 
    233   // Otherwise, do the layout with the permission box.
    234   heading_->SetY(y);
    235   y += heading_->height();
    236 
    237   y += views::kRelatedControlVerticalSpacing;
    238   will_have_access_to_->SizeToFit(right_column_width_);
    239   will_have_access_to_->SetX(x);
    240   will_have_access_to_->SetY(y);
    241   y += will_have_access_to_->height();
    242 
    243   y += views::kRelatedControlVerticalSpacing;
    244   permission_box_->SetX(x);
    245   permission_box_->SetY(y);
    246 
    247   // First we layout the labels inside the permission box, so that we know how
    248   // big the box will have to be.
    249   int label_x = kPermissionBoxBorderWidth + kPermissionBoxHorizontalPadding;
    250   int label_y = kPermissionBoxBorderWidth + kPermissionBoxVerticalPadding;
    251   int permission_box_height = kPermissionBoxBorderWidth * 2;
    252   permission_box_height += kPermissionBoxVerticalPadding * 2;
    253 
    254   for (size_t i = 0; i < permissions_.size(); ++i) {
    255     if (i > 0) {
    256       label_y += views::kRelatedControlVerticalSpacing;
    257       permission_box_height += views::kPanelVertMargin;
    258     }
    259 
    260     permissions_[i]->SizeToFit(kPermissionLabelWidth);
    261     permissions_[i]->SetX(label_x);
    262     permissions_[i]->SetY(label_y);
    263 
    264     label_y += permissions_[i]->height();
    265     permission_box_height += permissions_[i]->height();
    266   }
    267 
    268   // Now finally we can size the permission box itself.
    269   permission_box_->SetBounds(permission_box_->x(), permission_box_->y(),
    270                              right_column_width_, permission_box_height);
    271 }
    272 
    273 std::wstring ExtensionInstallDialogView::GetDialogButtonLabel(
    274     MessageBoxFlags::DialogButton button) const {
    275   switch (button) {
    276     case MessageBoxFlags::DIALOGBUTTON_OK:
    277       return UTF16ToWide(
    278           l10n_util::GetStringUTF16(ExtensionInstallUI::kButtonIds[type_]));
    279     case MessageBoxFlags::DIALOGBUTTON_CANCEL:
    280       return UTF16ToWide(l10n_util::GetStringUTF16(IDS_CANCEL));
    281     default:
    282       NOTREACHED();
    283       return std::wstring();
    284   }
    285 }
    286 
    287 int ExtensionInstallDialogView::GetDefaultDialogButton() const {
    288   return MessageBoxFlags::DIALOGBUTTON_CANCEL;
    289 }
    290 
    291 bool ExtensionInstallDialogView::Cancel() {
    292   delegate_->InstallUIAbort();
    293   return true;
    294 }
    295 
    296 bool ExtensionInstallDialogView::Accept() {
    297   delegate_->InstallUIProceed();
    298   return true;
    299 }
    300 
    301 bool ExtensionInstallDialogView::IsModal() const {
    302   return true;
    303 }
    304 
    305 std::wstring ExtensionInstallDialogView::GetWindowTitle() const {
    306   return UTF16ToWide(
    307       l10n_util::GetStringUTF16(ExtensionInstallUI::kTitleIds[type_]));
    308 }
    309 
    310 views::View* ExtensionInstallDialogView::GetContentsView() {
    311   return this;
    312 }
    313 
    314 void ShowExtensionInstallDialog(
    315     Profile* profile,
    316     ExtensionInstallUI::Delegate* delegate,
    317     const Extension* extension,
    318     SkBitmap* icon,
    319     const std::vector<string16>& permissions,
    320     ExtensionInstallUI::PromptType type) {
    321 #if defined(OS_CHROMEOS)
    322   // Use a normal browser window as parent on ChromeOS.
    323   Browser* browser = BrowserList::FindBrowserWithType(profile,
    324                                                       Browser::TYPE_NORMAL,
    325                                                       true);
    326 #else
    327   Browser* browser = BrowserList::GetLastActiveWithProfile(profile);
    328 #endif
    329   if (!browser) {
    330     delegate->InstallUIAbort();
    331     return;
    332   }
    333 
    334   BrowserWindow* browser_window = browser->window();
    335   if (!browser_window) {
    336     delegate->InstallUIAbort();
    337     return;
    338   }
    339 
    340   ExtensionInstallDialogView* dialog = new ExtensionInstallDialogView(
    341       delegate, extension, icon, permissions, type);
    342 
    343   views::Window* window =  browser::CreateViewsWindow(
    344       browser_window->GetNativeHandle(), gfx::Rect(), dialog);
    345 
    346   window->Show();
    347 }
    348