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 "chrome/browser/extensions/bundle_installer.h"
6 #include "chrome/browser/ui/browser.h"
7 #include "chrome/browser/ui/views/frame/browser_view.h"
8 #include "chrome/browser/ui/views/toolbar/toolbar_view.h"
9 #include "chrome/browser/ui/views/toolbar/wrench_toolbar_button.h"
10 #include "ui/base/resource/resource_bundle.h"
11 #include "ui/resources/grit/ui_resources.h"
12 #include "ui/views/bubble/bubble_delegate.h"
13 #include "ui/views/controls/button/image_button.h"
14 #include "ui/views/controls/label.h"
15 #include "ui/views/layout/grid_layout.h"
16 #include "ui/views/layout/layout_constants.h"
18 using extensions::BundleInstaller
;
19 using views::GridLayout
;
23 // The ID of the column set that holds the headings and the close button.
24 const int kHeadingColumnSetId
= 0;
26 // The width of the columns that hold the heading texts and extension names.
27 const int kTextColumnWidth
= 325;
29 // The ID of the column set that holds extension icons and names.
30 const int kItemsColumnSetId
= 1;
32 // The size of extension icons, and width of the corresponding column.
33 const int kIconSize
= 32;
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
);
45 views::ColumnSet
* heading_column_set
=
46 layout
->AddColumnSet(kHeadingColumnSetId
);
47 heading_column_set
->AddColumn(GridLayout::LEADING
,
49 100.0f
, // take all available space
53 heading_column_set
->AddPaddingColumn(0, views::kPanelHorizMargin
);
54 heading_column_set
->AddColumn(GridLayout::TRAILING
,
59 0); // no min width (only holds close button)
61 views::ColumnSet
* items_column_set
=
62 layout
->AddColumnSet(kItemsColumnSetId
);
63 items_column_set
->AddColumn(GridLayout::CENTER
,
69 items_column_set
->AddPaddingColumn(0, views::kPanelHorizMargin
);
70 items_column_set
->AddColumn(GridLayout::LEADING
,
72 100.0f
, // take all available space
77 AddContent(layout
, bundle
);
80 ~BundleInstalledBubble() override
{}
83 void AddContent(GridLayout
* layout
, const BundleInstaller
* bundle
) {
84 bool has_installed_items
= bundle
->HasItemWithState(
85 BundleInstaller::Item::STATE_INSTALLED
);
86 bool has_failed_items
= bundle
->HasItemWithState(
87 BundleInstaller::Item::STATE_FAILED
);
89 // Insert the list of installed items.
90 if (has_installed_items
) {
91 layout
->StartRow(0, kHeadingColumnSetId
);
92 AddHeading(layout
, bundle
->GetHeadingTextFor(
93 BundleInstaller::Item::STATE_INSTALLED
));
94 AddCloseButton(layout
, this);
95 AddItemList(layout
, bundle
->GetItemsWithState(
96 BundleInstaller::Item::STATE_INSTALLED
));
98 // Insert a line of padding if we're showing both sections.
100 layout
->AddPaddingRow(0, views::kRelatedControlVerticalSpacing
);
103 // Insert the list of failed items.
104 if (has_failed_items
) {
105 layout
->StartRow(0, kHeadingColumnSetId
);
106 AddHeading(layout
, bundle
->GetHeadingTextFor(
107 BundleInstaller::Item::STATE_FAILED
));
109 // The close button should be in the second column of the first row, so
110 // we add it here if there was no installed items section.
111 if (!has_installed_items
)
112 AddCloseButton(layout
, this);
114 AddItemList(layout
, bundle
->GetItemsWithState(
115 BundleInstaller::Item::STATE_FAILED
));
118 views::BubbleDelegateView::CreateBubble(this)->Show();
121 void AddItemList(GridLayout
* layout
, const BundleInstaller::ItemList
& items
) {
122 for (const BundleInstaller::Item
& item
: items
) {
123 layout
->AddPaddingRow(0, views::kRelatedControlVerticalSpacing
);
124 layout
->StartRow(0, kItemsColumnSetId
);
125 gfx::ImageSkia image
= gfx::ImageSkia::CreateFrom1xBitmap(item
.icon
);
126 gfx::Size
size(image
.width(), image
.height());
127 if (size
.width() > kIconSize
|| size
.height() > kIconSize
)
128 size
= gfx::Size(kIconSize
, kIconSize
);
129 views::ImageView
* image_view
= new views::ImageView
;
130 image_view
->SetImage(image
);
131 image_view
->SetImageSize(size
);
132 layout
->AddView(image_view
);
134 views::Label
* extension_label
=
135 new views::Label(item
.GetNameForDisplay());
136 extension_label
->SetMultiLine(true);
137 extension_label
->SetHorizontalAlignment(gfx::ALIGN_LEFT
);
138 extension_label
->SizeToFit(kTextColumnWidth
);
139 layout
->AddView(extension_label
);
143 void AddCloseButton(GridLayout
* layout
, views::ButtonListener
* listener
) {
144 ui::ResourceBundle
& rb
= ui::ResourceBundle::GetSharedInstance();
146 views::ImageButton
* button
= new views::ImageButton(listener
);
147 button
->SetImage(views::CustomButton::STATE_NORMAL
,
148 rb
.GetImageSkiaNamed(IDR_CLOSE_2
));
149 button
->SetImage(views::CustomButton::STATE_HOVERED
,
150 rb
.GetImageSkiaNamed(IDR_CLOSE_2_H
));
151 button
->SetImage(views::CustomButton::STATE_PRESSED
,
152 rb
.GetImageSkiaNamed(IDR_CLOSE_2_P
));
153 layout
->AddView(button
);
156 void AddHeading(GridLayout
* layout
, const base::string16
& heading
) {
157 ui::ResourceBundle
& rb
= ui::ResourceBundle::GetSharedInstance();
158 views::Label
* heading_label
= new views::Label(
159 heading
, rb
.GetFontList(ui::ResourceBundle::MediumFont
));
160 heading_label
->SetMultiLine(true);
161 heading_label
->SetHorizontalAlignment(gfx::ALIGN_LEFT
);
162 heading_label
->SizeToFit(kTextColumnWidth
);
163 layout
->AddView(heading_label
);
166 // views::ButtonListener implementation:
167 void ButtonPressed(views::Button
* sender
, const ui::Event
& event
) override
{
168 GetWidget()->Close();
171 DISALLOW_COPY_AND_ASSIGN(BundleInstalledBubble
);
176 void BundleInstaller::ShowInstalledBubble(
177 const BundleInstaller
* bundle
, Browser
* browser
) {
178 BrowserView
* browser_view
= BrowserView::GetBrowserViewForBrowser(browser
);
179 views::View
* anchor
= browser_view
->GetToolbarView()->app_menu();
180 new BundleInstalledBubble(bundle
, anchor
, views::BubbleBorder::TOP_RIGHT
);