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