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