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.
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/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"
24 using extensions::BundleInstaller
;
25 using views::GridLayout
;
29 // The ID of the column set for the bubble.
30 const int kColumnSetId
= 0;
32 // The width of the left column.
33 const int kLeftColumnWidth
= 325;
35 class BundleInstalledBubble
: public views::BubbleDelegateView
,
36 public views::ButtonListener
{
38 BundleInstalledBubble(const BundleInstaller
* bundle
,
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
);
46 column_set
->AddColumn(GridLayout::LEADING
,
52 column_set
->AddPaddingColumn(0, views::kPanelHorizMargin
);
53 column_set
->AddColumn(GridLayout::LEADING
,
58 0); // no min width (only holds close button)
60 layout
->StartRow(0, kColumnSetId
);
62 AddContent(layout
, bundle
);
65 virtual ~BundleInstalledBubble() {}
68 void AddContent(GridLayout
* layout
, const BundleInstaller
* bundle
) {
69 base::string16 installed_heading
= bundle
->GetHeadingTextFor(
70 BundleInstaller::Item::STATE_INSTALLED
);
71 base::string16 failed_heading
= bundle
->GetHeadingTextFor(
72 BundleInstaller::Item::STATE_FAILED
);
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
));
82 // Insert a line of padding if we're showing both sections.
83 if (!failed_heading
.empty())
84 layout
->AddPaddingRow(0, views::kRelatedControlVerticalSpacing
);
87 // Insert the list of failed items.
88 if (!failed_heading
.empty()) {
89 layout
->StartRow(0, kColumnSetId
);
90 AddHeading(layout
, failed_heading
);
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);
97 AddItemList(layout
, bundle
->GetItemsWithState(
98 BundleInstaller::Item::STATE_FAILED
));
101 views::BubbleDelegateView::CreateBubble(this)->Show();
104 void AddItemList(GridLayout
* layout
, const BundleInstaller::ItemList
& items
) {
105 for (size_t i
= 0; i
< items
.size(); ++i
) {
106 base::string16 extension_name
=
107 base::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
);
121 void AddCloseButton(GridLayout
* layout
, views::ButtonListener
* listener
) {
122 ui::ResourceBundle
& rb
= ui::ResourceBundle::GetSharedInstance();
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
);
134 void AddHeading(GridLayout
* layout
, const base::string16
& heading
) {
135 ui::ResourceBundle
& rb
= ui::ResourceBundle::GetSharedInstance();
136 views::Label
* heading_label
= new views::Label(
137 heading
, rb
.GetFontList(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
);
144 // views::ButtonListener implementation:
145 virtual void ButtonPressed(views::Button
* sender
,
146 const ui::Event
& event
) OVERRIDE
{
147 GetWidget()->Close();
150 DISALLOW_COPY_AND_ASSIGN(BundleInstalledBubble
);
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
);