bundle_installed_bubble.cc revision 868fa2fe829687343ffae624259930155e16dbd8
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
24using extensions::BundleInstaller;
25using views::GridLayout;
26
27namespace {
28
29// The ID of the column set for the bubble.
30const int kColumnSetId = 0;
31
32// The width of the left column.
33const int kLeftColumnWidth = 325;
34
35class 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
155void 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