Home | History | Annotate | Download | only in extensions
      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
      3 // found in the LICENSE file.
      4 
      5 #include "base/i18n/rtl.h"
      6 #include "base/strings/utf_string_conversions.h"
      7 #include "chrome/browser/extensions/bundle_installer.h"
      8 #include "chrome/browser/ui/browser.h"
      9 #include "chrome/browser/ui/views/frame/browser_view.h"
     10 #include "chrome/browser/ui/views/toolbar/toolbar_view.h"
     11 #include "chrome/grit/generated_resources.h"
     12 #include "ui/base/l10n/l10n_util.h"
     13 #include "ui/base/resource/resource_bundle.h"
     14 #include "ui/resources/grit/ui_resources.h"
     15 #include "ui/views/bubble/bubble_delegate.h"
     16 #include "ui/views/controls/button/image_button.h"
     17 #include "ui/views/controls/image_view.h"
     18 #include "ui/views/controls/label.h"
     19 #include "ui/views/layout/grid_layout.h"
     20 #include "ui/views/layout/layout_constants.h"
     21 
     22 using extensions::BundleInstaller;
     23 using views::GridLayout;
     24 
     25 namespace {
     26 
     27 // The ID of the column set for the bubble.
     28 const int kColumnSetId = 0;
     29 
     30 // The width of the left column.
     31 const int kLeftColumnWidth = 325;
     32 
     33 class BundleInstalledBubble : public views::BubbleDelegateView,
     34                               public views::ButtonListener {
     35  public:
     36   BundleInstalledBubble(const BundleInstaller* bundle,
     37                         View* anchor_view,
     38                         views::BubbleBorder::Arrow arrow)
     39       : views::BubbleDelegateView(anchor_view, arrow) {
     40     GridLayout* layout = GridLayout::CreatePanel(this);
     41     SetLayoutManager(layout);
     42     views::ColumnSet* column_set = layout->AddColumnSet(kColumnSetId);
     43 
     44     column_set->AddColumn(GridLayout::LEADING,
     45                           GridLayout::FILL,
     46                           0,  // no resizing
     47                           GridLayout::USE_PREF,
     48                           0,  // no fixed with
     49                           kLeftColumnWidth);
     50     column_set->AddPaddingColumn(0, views::kPanelHorizMargin);
     51     column_set->AddColumn(GridLayout::LEADING,
     52                           GridLayout::LEADING,
     53                           0,  // no resizing
     54                           GridLayout::USE_PREF,
     55                           0,  // no fixed width
     56                           0); // no min width (only holds close button)
     57 
     58     layout->StartRow(0, kColumnSetId);
     59 
     60     AddContent(layout, bundle);
     61   }
     62 
     63   virtual ~BundleInstalledBubble() {}
     64 
     65  private:
     66   void AddContent(GridLayout* layout, const BundleInstaller* bundle) {
     67     base::string16 installed_heading = bundle->GetHeadingTextFor(
     68         BundleInstaller::Item::STATE_INSTALLED);
     69     base::string16 failed_heading = bundle->GetHeadingTextFor(
     70         BundleInstaller::Item::STATE_FAILED);
     71 
     72     // Insert the list of installed items.
     73     if (!installed_heading.empty()) {
     74       layout->StartRow(0, kColumnSetId);
     75       AddHeading(layout, installed_heading);
     76       AddCloseButton(layout, this);
     77       AddItemList(layout, bundle->GetItemsWithState(
     78           BundleInstaller::Item::STATE_INSTALLED));
     79 
     80       // Insert a line of padding if we're showing both sections.
     81       if (!failed_heading.empty())
     82         layout->AddPaddingRow(0, views::kRelatedControlVerticalSpacing);
     83     }
     84 
     85     // Insert the list of failed items.
     86     if (!failed_heading.empty()) {
     87       layout->StartRow(0, kColumnSetId);
     88       AddHeading(layout, failed_heading);
     89 
     90       // The close button should be in the second column of the first row, so
     91       // we add it here if there was no installed items section.
     92       if (installed_heading.empty())
     93         AddCloseButton(layout, this);
     94 
     95       AddItemList(layout, bundle->GetItemsWithState(
     96           BundleInstaller::Item::STATE_FAILED));
     97     }
     98 
     99     views::BubbleDelegateView::CreateBubble(this)->Show();
    100   }
    101 
    102   void AddItemList(GridLayout* layout, const BundleInstaller::ItemList& items) {
    103     for (size_t i = 0; i < items.size(); ++i) {
    104       base::string16 extension_name =
    105           base::UTF8ToUTF16(items[i].localized_name);
    106       base::i18n::AdjustStringForLocaleDirection(&extension_name);
    107       layout->AddPaddingRow(0, views::kRelatedControlVerticalSpacing);
    108       layout->StartRow(0, kColumnSetId);
    109       views::Label* extension_label = new views::Label(
    110           l10n_util::GetStringFUTF16(
    111               IDS_EXTENSION_PERMISSION_LINE, extension_name));
    112       extension_label->SetMultiLine(true);
    113       extension_label->SetHorizontalAlignment(gfx::ALIGN_LEFT);
    114       extension_label->SizeToFit(kLeftColumnWidth);
    115       layout->AddView(extension_label);
    116     }
    117   }
    118 
    119   void AddCloseButton(GridLayout* layout, views::ButtonListener* listener) {
    120     ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
    121 
    122     views::ImageButton* button = new views::ImageButton(listener);
    123     button->SetImage(views::CustomButton::STATE_NORMAL,
    124                      rb.GetImageSkiaNamed(IDR_CLOSE_2));
    125     button->SetImage(views::CustomButton::STATE_HOVERED,
    126                      rb.GetImageSkiaNamed(IDR_CLOSE_2_H));
    127     button->SetImage(views::CustomButton::STATE_PRESSED,
    128                      rb.GetImageSkiaNamed(IDR_CLOSE_2_P));
    129     layout->AddView(button);
    130   }
    131 
    132   void AddHeading(GridLayout* layout, const base::string16& heading) {
    133     ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
    134     views::Label* heading_label = new views::Label(
    135         heading, rb.GetFontList(ui::ResourceBundle::MediumFont));
    136     heading_label->SetMultiLine(true);
    137     heading_label->SetHorizontalAlignment(gfx::ALIGN_LEFT);
    138     heading_label->SizeToFit(kLeftColumnWidth);
    139     layout->AddView(heading_label);
    140   }
    141 
    142   // views::ButtonListener implementation:
    143   virtual void ButtonPressed(views::Button* sender,
    144                              const ui::Event& event) OVERRIDE {
    145     GetWidget()->Close();
    146   }
    147 
    148   DISALLOW_COPY_AND_ASSIGN(BundleInstalledBubble);
    149 };
    150 
    151 }  // namespace
    152 
    153 void BundleInstaller::ShowInstalledBubble(
    154     const BundleInstaller* bundle, Browser* browser) {
    155   BrowserView* browser_view = BrowserView::GetBrowserViewForBrowser(browser);
    156   views::View* anchor = browser_view->GetToolbarView()->app_menu();
    157   new BundleInstalledBubble(bundle, anchor, views::BubbleBorder::TOP_RIGHT);
    158 }
    159