1 // Copyright 2014 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/ui/views/extensions/bookmark_app_bubble_view.h"
7 #include "base/strings/string16.h"
8 #include "base/strings/utf_string_conversions.h"
9 #include "chrome/browser/extensions/app_icon_loader_impl.h"
10 #include "chrome/browser/extensions/bookmark_app_helper.h"
11 #include "chrome/browser/extensions/extension_service.h"
12 #include "chrome/browser/extensions/launch_util.h"
13 #include "chrome/browser/profiles/profile.h"
14 #include "extensions/browser/pref_names.h"
15 #include "grit/generated_resources.h"
16 #include "grit/theme_resources.h"
17 #include "ui/base/l10n/l10n_util.h"
18 #include "ui/base/resource/resource_bundle.h"
19 #include "ui/events/keycodes/keyboard_codes.h"
20 #include "ui/views/controls/button/checkbox.h"
21 #include "ui/views/controls/button/label_button.h"
22 #include "ui/views/controls/image_view.h"
23 #include "ui/views/controls/label.h"
24 #include "ui/views/controls/textfield/textfield.h"
25 #include "ui/views/layout/grid_layout.h"
26 #include "ui/views/layout/layout_constants.h"
27 #include "ui/views/widget/widget.h"
29 using views::ColumnSet
;
30 using views::GridLayout
;
34 // Minimum width of the the bubble.
35 const int kMinBubbleWidth
= 300;
36 // Minimum width of the the textfield.
37 const int kMinTextfieldWidth
= 200;
39 const int kIconSize
= extension_misc::EXTENSION_ICON_MEDIUM
;
43 BookmarkAppBubbleView
* BookmarkAppBubbleView::bookmark_app_bubble_
= NULL
;
45 BookmarkAppBubbleView::~BookmarkAppBubbleView() {
49 void BookmarkAppBubbleView::ShowBubble(views::View
* anchor_view
,
51 const WebApplicationInfo
& web_app_info
,
52 const std::string
& extension_id
) {
53 if (bookmark_app_bubble_
!= NULL
)
56 bookmark_app_bubble_
= new BookmarkAppBubbleView(
57 anchor_view
, profile
, web_app_info
, extension_id
);
58 views::BubbleDelegateView::CreateBubble(bookmark_app_bubble_
)->Show();
59 // Select the entire title textfield contents when the bubble is first shown.
60 bookmark_app_bubble_
->title_tf_
->SelectAll(true);
61 bookmark_app_bubble_
->SetArrowPaintType(views::BubbleBorder::PAINT_NONE
);
64 BookmarkAppBubbleView::BookmarkAppBubbleView(
65 views::View
* anchor_view
,
67 const WebApplicationInfo
& web_app_info
,
68 const std::string
& extension_id
)
69 : BubbleDelegateView(anchor_view
, views::BubbleBorder::TOP_RIGHT
),
71 web_app_info_(web_app_info
),
72 extension_id_(extension_id
),
75 open_as_tab_checkbox_(NULL
),
78 app_icon_loader_(new extensions::AppIconLoaderImpl(profile
,
81 const SkColor background_color
= GetNativeTheme()->GetSystemColor(
82 ui::NativeTheme::kColorId_DialogBackground
);
83 set_arrow(views::BubbleBorder::TOP_CENTER
);
84 set_color(background_color
);
85 set_background(views::Background::CreateSolidBackground(background_color
));
86 set_margins(gfx::Insets(views::kPanelVertMargin
, 0, 0, 0));
89 void BookmarkAppBubbleView::Init() {
90 views::Label
* title_label
= new views::Label(
91 l10n_util::GetStringUTF16(IDS_BOOKMARK_APP_BUBBLE_TITLE
));
92 ui::ResourceBundle
* rb
= &ui::ResourceBundle::GetSharedInstance();
93 title_label
->SetFontList(rb
->GetFontList(ui::ResourceBundle::MediumFont
));
94 title_label
->SetHorizontalAlignment(gfx::ALIGN_LEFT
);
97 new views::LabelButton(this, l10n_util::GetStringUTF16(IDS_ADD
));
98 add_button_
->SetStyle(views::Button::STYLE_BUTTON
);
99 add_button_
->SetIsDefault(true);
102 new views::LabelButton(this, l10n_util::GetStringUTF16(IDS_CANCEL
));
103 cancel_button_
->SetStyle(views::Button::STYLE_BUTTON
);
105 GridLayout
* layout
= new GridLayout(this);
106 SetLayoutManager(layout
);
108 // Column sets used in the layout of the bubble.
111 TITLE_TEXT_COLUMN_SET_ID
,
112 CONTENT_COLUMN_SET_ID
115 // The column layout used for the title and checkbox.
116 ColumnSet
* cs
= layout
->AddColumnSet(TITLE_COLUMN_SET_ID
);
117 cs
->AddPaddingColumn(0, views::kButtonHEdgeMarginNew
);
119 GridLayout::LEADING
, GridLayout::CENTER
, 0, GridLayout::USE_PREF
, 0, 0);
120 cs
->AddPaddingColumn(0, views::kButtonHEdgeMarginNew
);
122 // The column layout used for the icon and text box.
123 cs
= layout
->AddColumnSet(TITLE_TEXT_COLUMN_SET_ID
);
124 cs
->AddPaddingColumn(0, views::kButtonHEdgeMarginNew
);
125 cs
->AddColumn(GridLayout::LEADING
,
128 GridLayout::USE_PREF
,
131 cs
->AddPaddingColumn(0, views::kButtonHEdgeMarginNew
);
132 cs
->AddColumn(GridLayout::FILL
,
135 GridLayout::USE_PREF
,
138 cs
->AddPaddingColumn(0, views::kButtonHEdgeMarginNew
);
140 // The column layout used for the row with buttons.
141 cs
= layout
->AddColumnSet(CONTENT_COLUMN_SET_ID
);
142 cs
->AddPaddingColumn(0, views::kButtonHEdgeMarginNew
);
144 GridLayout::LEADING
, GridLayout::CENTER
, 0, GridLayout::USE_PREF
, 0, 0);
145 cs
->AddPaddingColumn(1, views::kUnrelatedControlHorizontalSpacing
);
147 GridLayout::LEADING
, GridLayout::CENTER
, 0, GridLayout::USE_PREF
, 0, 0);
148 cs
->AddPaddingColumn(0, views::kRelatedButtonHSpacing
);
150 GridLayout::LEADING
, GridLayout::CENTER
, 0, GridLayout::USE_PREF
, 0, 0);
151 cs
->AddPaddingColumn(0, views::kButtonHEdgeMarginNew
);
153 layout
->StartRow(0, TITLE_COLUMN_SET_ID
);
154 layout
->AddView(title_label
);
155 layout
->AddPaddingRow(0, views::kRelatedControlVerticalSpacing
);
157 const extensions::Extension
* extension
=
158 profile_
->GetExtensionService()->GetInstalledExtension(extension_id_
);
160 layout
->StartRow(0, TITLE_TEXT_COLUMN_SET_ID
);
161 icon_image_view_
= new views::ImageView();
162 icon_image_view_
->SetImageSize(gfx::Size(kIconSize
, kIconSize
));
163 layout
->AddView(icon_image_view_
);
164 app_icon_loader_
->FetchImage(extension_id_
);
166 title_tf_
= new views::Textfield();
167 title_tf_
->SetText(extension
? base::UTF8ToUTF16(extension
->name())
168 : web_app_info_
.title
);
169 layout
->AddView(title_tf_
);
170 layout
->AddPaddingRow(0, views::kRelatedControlVerticalSpacing
);
172 layout
->StartRow(0, CONTENT_COLUMN_SET_ID
);
173 open_as_tab_checkbox_
= new views::Checkbox(
174 l10n_util::GetStringUTF16(IDS_BOOKMARK_APP_BUBBLE_OPEN_AS_TAB
));
175 open_as_tab_checkbox_
->SetChecked(
176 profile_
->GetPrefs()->GetInteger(
177 extensions::pref_names::kBookmarkAppCreationLaunchType
) ==
178 extensions::LAUNCH_TYPE_REGULAR
);
179 layout
->AddView(open_as_tab_checkbox_
);
180 layout
->AddView(add_button_
);
181 layout
->AddView(cancel_button_
);
182 layout
->AddPaddingRow(0, views::kUnrelatedControlVerticalSpacing
);
184 AddAccelerator(ui::Accelerator(ui::VKEY_RETURN
, ui::EF_NONE
));
187 views::View
* BookmarkAppBubbleView::GetInitiallyFocusedView() {
191 void BookmarkAppBubbleView::WindowClosing() {
192 // We have to reset |bookmark_app_bubble_| here, not in our destructor,
193 // because we'll be destroyed asynchronously and the shown state will be
194 // checked before then.
195 DCHECK_EQ(bookmark_app_bubble_
, this);
196 bookmark_app_bubble_
= NULL
;
199 profile_
->GetExtensionService()->UninstallExtension(
200 extension_id_
, false, NULL
);
206 bool BookmarkAppBubbleView::AcceleratorPressed(
207 const ui::Accelerator
& accelerator
) {
208 if (accelerator
.key_code() == ui::VKEY_RETURN
) {
209 HandleButtonPressed(add_button_
);
212 return BubbleDelegateView::AcceleratorPressed(accelerator
);
215 gfx::Size
BookmarkAppBubbleView::GetMinimumSize() {
216 gfx::Size
size(views::BubbleDelegateView::GetPreferredSize());
217 size
.SetToMax(gfx::Size(kMinBubbleWidth
, 0));
221 void BookmarkAppBubbleView::ButtonPressed(views::Button
* sender
,
222 const ui::Event
& event
) {
223 HandleButtonPressed(sender
);
226 void BookmarkAppBubbleView::SetAppImage(const std::string
& id
,
227 const gfx::ImageSkia
& image
) {
228 DCHECK_EQ(extension_id_
, id
);
229 icon_image_view_
->SetImage(image
);
232 void BookmarkAppBubbleView::HandleButtonPressed(views::Button
* sender
) {
233 // Unset |remove_app_| so we don't delete the bookmark after the window
235 if (sender
== add_button_
)
238 GetWidget()->Close();
241 void BookmarkAppBubbleView::ApplyEdits() {
242 // Set the launch type based on the checkbox.
243 extensions::LaunchType launch_type
= open_as_tab_checkbox_
->checked()
244 ? extensions::LAUNCH_TYPE_REGULAR
245 : extensions::LAUNCH_TYPE_WINDOW
;
246 profile_
->GetPrefs()->SetInteger(
247 extensions::pref_names::kBookmarkAppCreationLaunchType
, launch_type
);
248 extensions::SetLaunchType(profile_
->GetExtensionService(),
252 const extensions::Extension
* extension
=
253 profile_
->GetExtensionService()->GetInstalledExtension(extension_id_
);
254 if (extension
&& base::UTF8ToUTF16(extension
->name()) == title_tf_
->text())
257 // Reinstall the app with an updated name.
258 WebApplicationInfo
install_info(web_app_info_
);
259 install_info
.title
= title_tf_
->text();
261 extensions::CreateOrUpdateBookmarkApp(profile_
->GetExtensionService(),