Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(95)

Side by Side Diff: chrome/browser/ui/views/extensions/extension_installed_bubble_view.cc

Issue 1503583002: [Extensions Views] Update the extension installed bubble's sync promo (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Latest master Created 5 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2013 The Chromium Authors. All rights reserved. 1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "chrome/browser/ui/views/extensions/extension_installed_bubble_view.h" 5 #include "chrome/browser/ui/views/extensions/extension_installed_bubble_view.h"
6 6
7 #include <algorithm> 7 #include <algorithm>
8 #include <string> 8 #include <string>
9 9
10 #include "chrome/browser/extensions/extension_action_manager.h" 10 #include "chrome/browser/extensions/extension_action_manager.h"
11 #include "chrome/browser/profiles/profile.h" 11 #include "chrome/browser/profiles/profile.h"
12 #include "chrome/browser/ui/browser.h" 12 #include "chrome/browser/ui/browser.h"
13 #include "chrome/browser/ui/browser_window.h" 13 #include "chrome/browser/ui/browser_window.h"
14 #include "chrome/browser/ui/chrome_pages.h" 14 #include "chrome/browser/ui/chrome_pages.h"
15 #include "chrome/browser/ui/singleton_tabs.h" 15 #include "chrome/browser/ui/singleton_tabs.h"
16 #include "chrome/browser/ui/sync/sync_promo_ui.h" 16 #include "chrome/browser/ui/sync/sync_promo_ui.h"
17 #include "chrome/browser/ui/views/frame/browser_view.h" 17 #include "chrome/browser/ui/views/frame/browser_view.h"
18 #include "chrome/browser/ui/views/location_bar/location_bar_view.h" 18 #include "chrome/browser/ui/views/location_bar/location_bar_view.h"
19 #include "chrome/browser/ui/views/location_bar/page_action_with_badge_view.h" 19 #include "chrome/browser/ui/views/location_bar/page_action_with_badge_view.h"
20 #include "chrome/browser/ui/views/sync/bubble_sync_promo_view.h"
20 #include "chrome/browser/ui/views/toolbar/app_menu_button.h" 21 #include "chrome/browser/ui/views/toolbar/app_menu_button.h"
21 #include "chrome/browser/ui/views/toolbar/browser_actions_container.h" 22 #include "chrome/browser/ui/views/toolbar/browser_actions_container.h"
22 #include "chrome/browser/ui/views/toolbar/toolbar_view.h" 23 #include "chrome/browser/ui/views/toolbar/toolbar_view.h"
23 #include "chrome/common/extensions/sync_helper.h" 24 #include "chrome/common/extensions/sync_helper.h"
24 #include "chrome/common/url_constants.h" 25 #include "chrome/common/url_constants.h"
25 #include "chrome/grit/chromium_strings.h" 26 #include "chrome/grit/chromium_strings.h"
26 #include "chrome/grit/generated_resources.h" 27 #include "chrome/grit/generated_resources.h"
27 #include "components/bubble/bubble_controller.h" 28 #include "components/bubble/bubble_controller.h"
28 #include "components/bubble/bubble_ui.h" 29 #include "components/bubble/bubble_ui.h"
29 #include "extensions/common/extension.h" 30 #include "extensions/common/extension.h"
30 #include "extensions/common/feature_switch.h" 31 #include "extensions/common/feature_switch.h"
31 #include "ui/base/l10n/l10n_util.h" 32 #include "ui/base/l10n/l10n_util.h"
32 #include "ui/base/resource/resource_bundle.h" 33 #include "ui/base/resource/resource_bundle.h"
33 #include "ui/gfx/render_text.h" 34 #include "ui/gfx/render_text.h"
34 #include "ui/gfx/text_elider.h" 35 #include "ui/gfx/text_elider.h"
35 #include "ui/resources/grit/ui_resources.h" 36 #include "ui/resources/grit/ui_resources.h"
37 #include "ui/views/bubble/bubble_frame_view.h"
36 #include "ui/views/controls/button/image_button.h" 38 #include "ui/views/controls/button/image_button.h"
37 #include "ui/views/controls/image_view.h" 39 #include "ui/views/controls/image_view.h"
38 #include "ui/views/controls/label.h" 40 #include "ui/views/controls/label.h"
39 #include "ui/views/controls/link.h" 41 #include "ui/views/controls/link.h"
40 #include "ui/views/controls/link_listener.h" 42 #include "ui/views/controls/link_listener.h"
43 #include "ui/views/layout/box_layout.h"
41 #include "ui/views/layout/fill_layout.h" 44 #include "ui/views/layout/fill_layout.h"
45 #include "ui/views/layout/grid_layout.h"
42 #include "ui/views/layout/layout_constants.h" 46 #include "ui/views/layout/layout_constants.h"
43 47
44 using extensions::Extension; 48 using extensions::Extension;
45 49
46 namespace { 50 namespace {
47 51
48 const int kIconSize = 43; 52 const int kIconSize = 43;
49 53
50 const int kRightColumnWidth = 285; 54 const int kRightColumnWidth = 285;
51 55
52 // The Bubble uses a BubbleBorder which adds about 6 pixels of whitespace 56 views::Label* CreateLabel(const base::string16& text,
53 // around the content view. We compensate by reducing our outer borders by this 57 const gfx::FontList& font) {
54 // amount + 4px. 58 views::Label* label = new views::Label(text, font);
55 const int kOuterMarginInset = 10; 59 label->SetMultiLine(true);
56 const int kHorizOuterMargin = views::kPanelHorizMargin - kOuterMarginInset; 60 label->SetHorizontalAlignment(gfx::ALIGN_LEFT);
57 const int kVertOuterMargin = views::kPanelVertMargin - kOuterMarginInset; 61 return label;
58 62 }
59 // Interior vertical margin is 8px smaller than standard
60 const int kVertInnerMargin = views::kPanelVertMargin - 8;
61
62 // We want to shift the right column (which contains the header and text) up
63 // 4px to align with icon.
64 const int kRightcolumnVerticalShift = -4;
65 63
66 } // namespace 64 } // namespace
67 65
68 ExtensionInstalledBubbleView::ExtensionInstalledBubbleView( 66 ExtensionInstalledBubbleView::ExtensionInstalledBubbleView(
69 ExtensionInstalledBubble* bubble, 67 ExtensionInstalledBubble* bubble,
70 BubbleReference bubble_reference) 68 BubbleReference bubble_reference)
71 : bubble_reference_(bubble_reference), 69 : bubble_reference_(bubble_reference),
72 extension_(bubble->extension()), 70 extension_(bubble->extension()),
73 browser_(bubble->browser()), 71 browser_(bubble->browser()),
74 type_(bubble->type()) {} 72 type_(bubble->type()),
73 options_(NONE),
74 sync_promo_(nullptr),
75 close_(nullptr),
76 manage_shortcut_(nullptr) {}
75 77
76 ExtensionInstalledBubbleView::~ExtensionInstalledBubbleView() {} 78 ExtensionInstalledBubbleView::~ExtensionInstalledBubbleView() {}
77 79
78 void ExtensionInstalledBubbleView::UpdateAnchorView() { 80 void ExtensionInstalledBubbleView::UpdateAnchorView() {
79 BrowserView* browser_view = BrowserView::GetBrowserViewForBrowser(browser_); 81 BrowserView* browser_view = BrowserView::GetBrowserViewForBrowser(browser_);
80 82
81 views::View* reference_view = nullptr; 83 views::View* reference_view = nullptr;
82 if (type_ == ExtensionInstalledBubble::BROWSER_ACTION || 84 if (type_ == ExtensionInstalledBubble::BROWSER_ACTION ||
83 extensions::FeatureSwitch::extension_action_redesign()->IsEnabled()) { 85 extensions::FeatureSwitch::extension_action_redesign()->IsEnabled()) {
84 BrowserActionsContainer* container = 86 BrowserActionsContainer* container =
(...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after
158 bool ExtensionInstalledBubbleView::AcceleratorPressed( 160 bool ExtensionInstalledBubbleView::AcceleratorPressed(
159 const ui::Accelerator& accelerator) { 161 const ui::Accelerator& accelerator) {
160 if (!close_on_esc() || accelerator.key_code() != ui::VKEY_ESCAPE) 162 if (!close_on_esc() || accelerator.key_code() != ui::VKEY_ESCAPE)
161 return false; 163 return false;
162 DCHECK(bubble_reference_); 164 DCHECK(bubble_reference_);
163 bool did_close = bubble_reference_->CloseBubble(BUBBLE_CLOSE_USER_DISMISSED); 165 bool did_close = bubble_reference_->CloseBubble(BUBBLE_CLOSE_USER_DISMISSED);
164 DCHECK(did_close); 166 DCHECK(did_close);
165 return true; 167 return true;
166 } 168 }
167 169
168 // Views specific implementation. 170 void ExtensionInstalledBubbleView::OnSignInLinkClicked() {
169 bool ExtensionInstalledBubble::ShouldShow() { 171 GetWidget()->Close();
170 if (type() == BROWSER_ACTION || 172 chrome::ShowBrowserSignin(
171 extensions::FeatureSwitch::extension_action_redesign()->IsEnabled()) { 173 browser_,
172 BrowserActionsContainer* container = 174 signin_metrics::AccessPoint::ACCESS_POINT_EXTENSION_INSTALL_BUBBLE);
173 BrowserView::GetBrowserViewForBrowser(browser())
174 ->GetToolbarView()
175 ->browser_actions();
176 return !container->animating();
177 }
178 return true;
179 } 175 }
180 176
181 class ExtensionInstalledBubbleUi : public BubbleUi { 177 void ExtensionInstalledBubbleView::ButtonPressed(views::Button* sender,
182 public: 178 const ui::Event& event) {
183 explicit ExtensionInstalledBubbleUi(ExtensionInstalledBubble* bubble); 179 DCHECK_EQ(sender, close_);
184 ~ExtensionInstalledBubbleUi() override; 180 GetWidget()->Close();
185
186 private:
187 // BubbleUi:
188 void Show(BubbleReference bubble_reference) override;
189 void Close() override;
190 void UpdateAnchorPosition() override;
191
192 ExtensionInstalledBubble* bubble_;
193 ExtensionInstalledBubbleView* delegate_view_;
194
195 DISALLOW_COPY_AND_ASSIGN(ExtensionInstalledBubbleUi);
196 };
197
198 // Implemented here to create the platform specific instance of the BubbleUi.
199 scoped_ptr<BubbleUi> ExtensionInstalledBubble::BuildBubbleUi() {
200 return make_scoped_ptr(new ExtensionInstalledBubbleUi(this));
201 } 181 }
202 182
203 // InstalledBubbleContent is the content view which is placed in the 183 void ExtensionInstalledBubbleView::LinkClicked(views::Link* source,
204 // ExtensionInstalledBubbleView. It displays the install icon and explanatory 184 int event_flags) {
205 // text about the installed extension. 185 DCHECK_EQ(manage_shortcut_, source);
206 class InstalledBubbleContent : public views::View, 186 GetWidget()->Close();
207 public views::ButtonListener,
208 public views::LinkListener {
209 public:
210 InstalledBubbleContent(const ExtensionInstalledBubble& bubble,
211 const BubbleReference& bubble_reference,
212 Browser* browser);
213 187
214 // Overridden from views::ButtonListener. 188 std::string configure_url = chrome::kChromeUIExtensionsURL;
215 void ButtonPressed(views::Button* sender, const ui::Event& event) override; 189 configure_url += chrome::kExtensionConfigureCommandsSubPage;
190 chrome::NavigateParams params(
191 chrome::GetSingletonTabNavigateParams(browser_, GURL(configure_url)));
192 chrome::Navigate(&params);
193 }
216 194
217 // Overriden from views::LinkListener. 195 void ExtensionInstalledBubbleView::InitLayout(
218 void LinkClicked(views::Link* source, int event_flags) override; 196 const ExtensionInstalledBubble& bubble) {
219
220 private:
221 enum Flavors {
222 NONE = 0,
223 HOW_TO_USE = 1 << 0,
224 HOW_TO_MANAGE = 1 << 1,
225 SHOW_KEYBINDING = 1 << 2,
226 SIGN_IN_PROMO = 1 << 3,
227 };
228
229 // Layout the signin promo at coordinates |offset_x| and |offset_y|. Returns
230 // the height (in pixels) of the promo UI.
231 int LayoutSigninPromo(int offset_x, int offset_y);
232
233 // Overriden from views::View.
234 gfx::Size GetPreferredSize() const override;
235 void Layout() override;
236 void OnPaint(gfx::Canvas* canvas) override;
237
238 // The browser we're associated with.
239 Browser* browser_;
240
241 // A reference to the bubble to send close events to.
242 BubbleReference bubble_reference_;
243
244 // The string that contains the link text at the beginning of the sign-in
245 // promo text.
246 base::string16 signin_promo_link_text_;
247 // The remaining text of the sign-in promo text.
248 base::string16 signin_promo_text_;
249
250 // A vector of RenderText objects representing the full sign-in promo
251 // paragraph as layed out within the bubble, but has the text of the link
252 // whited out so the link can be drawn in its place.
253 ScopedVector<gfx::RenderText> sign_in_promo_lines_;
254
255 // A bitmask containing the various flavors of bubble sections to show.
256 int flavors_;
257
258 // The height, in pixels, of the sign-in promo.
259 size_t height_of_signin_promo_;
260
261 views::ImageView* icon_;
262 views::Label* heading_;
263 views::Label* how_to_use_;
264 views::Link* sign_in_link_;
265 views::Label* manage_;
266 views::Link* manage_shortcut_;
267 views::ImageButton* close_button_;
268
269 DISALLOW_COPY_AND_ASSIGN(InstalledBubbleContent);
270 };
271
272 InstalledBubbleContent::InstalledBubbleContent(
273 const ExtensionInstalledBubble& bubble,
274 const BubbleReference& bubble_reference,
275 Browser* browser)
276 : browser_(browser),
277 bubble_reference_(bubble_reference),
278 flavors_(NONE),
279 height_of_signin_promo_(0u),
280 how_to_use_(nullptr),
281 sign_in_link_(nullptr),
282 manage_(nullptr),
283 manage_shortcut_(nullptr) {
284 // The Extension Installed bubble takes on various forms, depending on the 197 // The Extension Installed bubble takes on various forms, depending on the
285 // type of extension installed. In general, though, they are all similar: 198 // type of extension installed. In general, though, they are all similar:
286 // 199 //
287 // ------------------------- 200 // -------------------------
288 // | | Heading [X] | 201 // | | Heading [X] |
289 // | Icon | Info | 202 // | Icon | Info |
290 // | | Extra info | 203 // | | Extra info |
291 // ------------------------- 204 // -------------------------
292 // 205 //
293 // Icon and Heading are always shown (as well as the close button). 206 // Icon and Heading are always shown (as well as the close button).
294 // Info is shown for browser actions, page actions and Omnibox keyword 207 // Info is shown for browser actions, page actions and Omnibox keyword
295 // extensions and might list keyboard shorcut for the former two types. 208 // extensions and might list keyboard shorcut for the former two types.
296 // Extra info is... 209 // Extra info is...
297 // ... for other types, either a description of how to manage the extension 210 // ... for other types, either a description of how to manage the extension
298 // or a link to configure the keybinding shortcut (if one exists). 211 // or a link to configure the keybinding shortcut (if one exists).
299 // Extra info can include a promo for signing into sync. 212 // Extra info can include a promo for signing into sync.
300 213
301 const Extension* extension = bubble.extension(); 214 set_margins(gfx::Insets(views::kPanelVertMargin, 0, 0, 0));
302 if (extensions::sync_helper::IsSyncable(extension) &&
303 SyncPromoUI::ShouldShowSyncPromo(browser->profile()))
304 flavors_ |= SIGN_IN_PROMO;
305 215
306 // Determine the bubble flavor we want, based on the extension type. 216 if (extensions::sync_helper::IsSyncable(extension_) &&
307 switch (bubble.type()) { 217 SyncPromoUI::ShouldShowSyncPromo(browser_->profile()))
218 options_ |= SIGN_IN_PROMO;
219
220 // The number of rows in the content section of the bubble.
221 int main_content_row_count = 1;
222 // Determine the bubble option we want, based on the extension type.
223 switch (type_) {
308 case ExtensionInstalledBubble::BROWSER_ACTION: 224 case ExtensionInstalledBubble::BROWSER_ACTION:
309 case ExtensionInstalledBubble::PAGE_ACTION: 225 case ExtensionInstalledBubble::PAGE_ACTION:
310 flavors_ |= HOW_TO_USE; 226 options_ |= HOW_TO_USE;
311 if (bubble.has_command_keybinding()) { 227 if (bubble.has_command_keybinding()) {
312 flavors_ |= SHOW_KEYBINDING; 228 options_ |= SHOW_KEYBINDING;
313 } else { 229 } else {
314 // The How-To-Use text makes the bubble seem a little crowded when the 230 // The How-To-Use text makes the bubble seem a little crowded when the
315 // extension has a keybinding, so the How-To-Manage text is not shown 231 // extension has a keybinding, so the How-To-Manage text is not shown
316 // in those cases. 232 // in those cases.
317 flavors_ |= HOW_TO_MANAGE; 233 options_ |= HOW_TO_MANAGE;
318 } 234 }
235 main_content_row_count += 2;
319 break; 236 break;
320 case ExtensionInstalledBubble::OMNIBOX_KEYWORD: 237 case ExtensionInstalledBubble::OMNIBOX_KEYWORD:
321 flavors_ |= HOW_TO_USE | HOW_TO_MANAGE; 238 options_ |= HOW_TO_USE | HOW_TO_MANAGE;
239 main_content_row_count += 2;
322 break; 240 break;
323 case ExtensionInstalledBubble::GENERIC: 241 case ExtensionInstalledBubble::GENERIC:
324 break; 242 break;
325 default: 243 default:
326 // When adding a new bubble type, the flavor needs to be set. 244 // When adding a new bubble type, the option needs to be set.
327 static_assert(ExtensionInstalledBubble::GENERIC == 3, 245 static_assert(ExtensionInstalledBubble::GENERIC == 3,
328 "kBubbleType enum has changed, this switch statement must " 246 "kBubbleType enum has changed, this switch statement must "
329 "be updateed"); 247 "be updateed");
330 break; 248 break;
331 } 249 }
332 250
251 views::GridLayout* layout = new views::GridLayout(this);
252 SetLayoutManager(layout);
253
254 enum ColumnSetId {
255 MAIN_COLUMN_SET = 0,
256 SYNC_PROMO_COLUMN_SET,
257 };
258
259 views::ColumnSet* main_cs = layout->AddColumnSet(MAIN_COLUMN_SET);
260 // Note: the left padding column is set to kUnrelatedControlHorizontalSpacing
261 // so that the distance between the left edge and the icon matches the
262 // distance between the icon and the content.
263 main_cs->AddPaddingColumn(0 /* not resizable */,
264 views::kUnrelatedControlHorizontalSpacing);
265 // Icon column.
266 main_cs->AddColumn(views::GridLayout::CENTER, views::GridLayout::LEADING, 0,
267 views::GridLayout::USE_PREF, 0, 0);
268 main_cs->AddPaddingColumn(0, views::kUnrelatedControlHorizontalSpacing);
269 // Heading column:
270 main_cs->AddColumn(views::GridLayout::LEADING, views::GridLayout::LEADING, 0,
271 views::GridLayout::FIXED, kRightColumnWidth, 0);
272 main_cs->AddPaddingColumn(0 /* not resizable */,
273 views::kUnrelatedControlHorizontalSpacing);
274
333 ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance(); 275 ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
334 const gfx::FontList& font_list = 276 const gfx::FontList& font_list = rb.GetFontList(ui::ResourceBundle::BaseFont);
335 rb.GetFontList(ui::ResourceBundle::BaseFont);
336 277
337 const SkBitmap& icon = bubble.icon(); 278 const SkBitmap& bitmap = bubble.icon();
338 // Add the icon (for all flavors). 279 // Add the icon (for all options).
339 // Scale down to 43x43, but allow smaller icons (don't scale up). 280 // Scale down to 43x43, but allow smaller icons (don't scale up).
340 gfx::Size size(icon.width(), icon.height()); 281 gfx::Size size(bitmap.width(), bitmap.height());
341 if (size.width() > kIconSize || size.height() > kIconSize) 282 if (size.width() > kIconSize || size.height() > kIconSize)
342 size = gfx::Size(kIconSize, kIconSize); 283 size = gfx::Size(kIconSize, kIconSize);
343 icon_ = new views::ImageView(); 284 views::ImageView* icon = new views::ImageView();
344 icon_->SetImageSize(size); 285 icon->SetImageSize(size);
345 icon_->SetImage(gfx::ImageSkia::CreateFrom1xBitmap(icon)); 286 icon->SetImage(gfx::ImageSkia::CreateFrom1xBitmap(bitmap));
346 AddChildView(icon_);
347 287
348 // Add the heading (for all flavors). 288 layout->StartRow(0, MAIN_COLUMN_SET);
349 base::string16 extension_name = base::UTF8ToUTF16(extension->name()); 289 layout->AddView(icon, 1, main_content_row_count);
290
291 // Add the heading (for all options).
292 base::string16 extension_name = base::UTF8ToUTF16(extension_->name());
350 base::i18n::AdjustStringForLocaleDirection(&extension_name); 293 base::i18n::AdjustStringForLocaleDirection(&extension_name);
351 heading_ = new views::Label(l10n_util::GetStringFUTF16( 294 views::Label* heading =
352 IDS_EXTENSION_INSTALLED_HEADING, extension_name)); 295 CreateLabel(l10n_util::GetStringFUTF16(IDS_EXTENSION_INSTALLED_HEADING,
353 heading_->SetFontList(rb.GetFontList(ui::ResourceBundle::MediumFont)); 296 extension_name),
354 heading_->SetMultiLine(true); 297 rb.GetFontList(ui::ResourceBundle::MediumFont));
355 heading_->SetHorizontalAlignment(gfx::ALIGN_LEFT);
356 AddChildView(heading_);
357 298
358 if (flavors_ & HOW_TO_USE) { 299 close_ = views::BubbleFrameView::CreateCloseButton(this);
359 how_to_use_ = new views::Label(bubble.GetHowToUseDescription()); 300
360 how_to_use_->SetFontList(font_list); 301 views::View* heading_and_close = new views::View();
361 how_to_use_->SetMultiLine(true); 302 views::BoxLayout* heading_and_close_layout =
362 how_to_use_->SetHorizontalAlignment(gfx::ALIGN_LEFT); 303 new views::BoxLayout(views::BoxLayout::kHorizontal, 0, 0,
363 AddChildView(how_to_use_); 304 views::kUnrelatedControlHorizontalSpacing);
305 heading_and_close_layout->set_cross_axis_alignment(
306 views::BoxLayout::CROSS_AXIS_ALIGNMENT_START);
307 heading_and_close->SetLayoutManager(heading_and_close_layout);
308 heading_and_close->AddChildView(heading);
309 heading_and_close->AddChildView(close_);
310
311 layout->AddView(heading_and_close);
312 layout->AddPaddingRow(0, views::kRelatedControlVerticalSpacing);
313
314 auto add_content_view = [&layout](views::View* view) {
315 layout->StartRow(0, MAIN_COLUMN_SET);
316 // Skip the icon column.
317 layout->SkipColumns(1);
318 layout->AddView(view);
319 layout->AddPaddingRow(0, views::kRelatedControlVerticalSpacing);
320 };
321
322 if (options_ & HOW_TO_USE) {
323 add_content_view(CreateLabel(bubble.GetHowToUseDescription(), font_list));
364 } 324 }
365 325
366 if (flavors_ & SHOW_KEYBINDING) { 326 if (options_ & SHOW_KEYBINDING) {
367 manage_shortcut_ = new views::Link( 327 manage_shortcut_ = new views::Link(
368 l10n_util::GetStringUTF16(IDS_EXTENSION_INSTALLED_MANAGE_SHORTCUTS)); 328 l10n_util::GetStringUTF16(IDS_EXTENSION_INSTALLED_MANAGE_SHORTCUTS));
369 manage_shortcut_->set_listener(this); 329 manage_shortcut_->set_listener(this);
370 AddChildView(manage_shortcut_); 330 manage_shortcut_->SetUnderline(false);
331 add_content_view(manage_shortcut_);
371 } 332 }
372 333
373 if (flavors_ & HOW_TO_MANAGE) { 334 if (options_ & HOW_TO_MANAGE) {
374 manage_ = new views::Label(l10n_util::GetStringUTF16( 335 add_content_view(CreateLabel(
375 IDS_EXTENSION_INSTALLED_MANAGE_INFO)); 336 l10n_util::GetStringUTF16(IDS_EXTENSION_INSTALLED_MANAGE_INFO),
376 manage_->SetFontList(font_list); 337 font_list));
377 manage_->SetMultiLine(true);
378 manage_->SetHorizontalAlignment(gfx::ALIGN_LEFT);
379 AddChildView(manage_);
380 } 338 }
381 339
382 if (flavors_ & SIGN_IN_PROMO) { 340 if (options_ & SIGN_IN_PROMO) {
383 signin_promo_text_ = 341 views::ColumnSet* sync_cs = layout->AddColumnSet(SYNC_PROMO_COLUMN_SET);
384 l10n_util::GetStringUTF16(IDS_EXTENSION_INSTALLED_SIGNIN_PROMO); 342 sync_cs->AddColumn(views::GridLayout::FILL, views::GridLayout::FILL, 1,
385 343 views::GridLayout::USE_PREF, 0, 0);
386 signin_promo_link_text_ = 344 layout->StartRow(0, SYNC_PROMO_COLUMN_SET);
387 l10n_util::GetStringUTF16(IDS_EXTENSION_INSTALLED_SIGNIN_PROMO_LINK); 345 sync_promo_ = new BubbleSyncPromoView(
388 sign_in_link_ = new views::Link(signin_promo_link_text_); 346 this, IDS_EXTENSION_INSTALLED_SYNC_PROMO_LINK_NEW,
389 sign_in_link_->SetFontList(font_list); 347 IDS_EXTENSION_INSTALLED_SYNC_PROMO_NEW);
390 sign_in_link_->set_listener(this); 348 layout->AddView(sync_promo_);
391 AddChildView(sign_in_link_);
392 } 349 }
393
394 // Add the Close button (for all flavors).
395 close_button_ = new views::ImageButton(this);
396 close_button_->SetImage(views::CustomButton::STATE_NORMAL,
397 rb.GetImageSkiaNamed(IDR_CLOSE_2));
398 close_button_->SetImage(views::CustomButton::STATE_HOVERED,
399 rb.GetImageSkiaNamed(IDR_CLOSE_2_H));
400 close_button_->SetImage(views::CustomButton::STATE_PRESSED,
401 rb.GetImageSkiaNamed(IDR_CLOSE_2_P));
402 AddChildView(close_button_);
403 } 350 }
404 351
405 void InstalledBubbleContent::ButtonPressed(views::Button* sender, 352 // Views specific implementation.
406 const ui::Event& event) { 353 bool ExtensionInstalledBubble::ShouldShow() {
407 DCHECK_EQ(sender, close_button_); 354 if (type() == BROWSER_ACTION ||
408 DCHECK(bubble_reference_); 355 extensions::FeatureSwitch::extension_action_redesign()->IsEnabled()) {
409 bool did_close = bubble_reference_->CloseBubble(BUBBLE_CLOSE_USER_DISMISSED); 356 BrowserActionsContainer* container =
410 DCHECK(did_close); 357 BrowserView::GetBrowserViewForBrowser(browser())
358 ->GetToolbarView()
359 ->browser_actions();
360 return !container->animating();
361 }
362 return true;
411 } 363 }
412 364
413 void InstalledBubbleContent::LinkClicked(views::Link* source, int event_flags) { 365 class ExtensionInstalledBubbleUi : public BubbleUi {
414 DCHECK(bubble_reference_); 366 public:
415 bool did_close = bubble_reference_->CloseBubble(BUBBLE_CLOSE_ACCEPTED); 367 explicit ExtensionInstalledBubbleUi(ExtensionInstalledBubble* bubble);
416 DCHECK(did_close); 368 ~ExtensionInstalledBubbleUi() override;
417 369
418 if (source == sign_in_link_) { 370 private:
419 #if defined(OS_ANDROID) 371 // BubbleUi:
420 // TODO(bshe): Figure out what to do on Android platform. See 372 void Show(BubbleReference bubble_reference) override;
421 // crbug.com/559340. 373 void Close() override;
422 NOTIMPLEMENTED(); 374 void UpdateAnchorPosition() override;
423 #else
424 chrome::ShowBrowserSignin(
425 browser_,
426 signin_metrics::AccessPoint::ACCESS_POINT_EXTENSION_INSTALL_BUBBLE);
427 #endif
428 return;
429 }
430 375
431 DCHECK_EQ(manage_shortcut_, source); 376 ExtensionInstalledBubble* bubble_;
377 ExtensionInstalledBubbleView* delegate_view_;
432 378
433 std::string configure_url = chrome::kChromeUIExtensionsURL; 379 DISALLOW_COPY_AND_ASSIGN(ExtensionInstalledBubbleUi);
434 configure_url += chrome::kExtensionConfigureCommandsSubPage; 380 };
435 chrome::NavigateParams params(chrome::GetSingletonTabNavigateParams(
436 browser_, GURL(configure_url)));
437 chrome::Navigate(&params);
438 }
439 381
440 int InstalledBubbleContent::LayoutSigninPromo(int offset_x, int offset_y) { 382 // Implemented here to create the platform specific instance of the BubbleUi.
441 sign_in_promo_lines_.clear(); 383 scoped_ptr<BubbleUi> ExtensionInstalledBubble::BuildBubbleUi() {
442 int height = 0; 384 return make_scoped_ptr(new ExtensionInstalledBubbleUi(this));
443 gfx::Rect contents_area = GetContentsBounds();
444 if (contents_area.IsEmpty())
445 return height;
446 contents_area.set_width(kRightColumnWidth);
447
448 base::string16 full_text = signin_promo_link_text_ + signin_promo_text_;
449
450 // The link is the first item in the text.
451 const gfx::Size link_size = sign_in_link_->GetPreferredSize();
452 sign_in_link_->SetBounds(
453 offset_x, offset_y, link_size.width(), link_size.height());
454
455 // Word-wrap the full label text.
456 const gfx::FontList font_list;
457 std::vector<base::string16> lines;
458 gfx::ElideRectangleText(full_text, font_list, contents_area.width(),
459 contents_area.height(), gfx::ELIDE_LONG_WORDS,
460 &lines);
461
462 gfx::Point position = gfx::Point(
463 contents_area.origin().x() + offset_x,
464 contents_area.origin().y() + offset_y + 1);
465 if (base::i18n::IsRTL()) {
466 position -= gfx::Vector2d(
467 2 * views::kPanelHorizMargin + kHorizOuterMargin, 0);
468 }
469
470 // Loop through the lines, creating a renderer for each.
471 for (std::vector<base::string16>::const_iterator it = lines.begin();
472 it != lines.end(); ++it) {
473 gfx::RenderText* line = gfx::RenderText::CreateInstance();
474 line->SetDirectionalityMode(gfx::DIRECTIONALITY_FROM_UI);
475 line->SetText(*it);
476 const gfx::Size size(contents_area.width(),
477 line->GetStringSize().height());
478 line->SetDisplayRect(gfx::Rect(position, size));
479 position.set_y(position.y() + size.height());
480 sign_in_promo_lines_.push_back(line);
481 height += size.height();
482 }
483
484 // The link is drawn separately; make it transparent here to only draw once.
485 // The link always leads other text and is assumed to fit on the first line.
486 sign_in_promo_lines_.front()->ApplyColor(SK_ColorTRANSPARENT,
487 gfx::Range(0, signin_promo_link_text_.size()));
488
489 return height;
490 }
491
492 gfx::Size InstalledBubbleContent::GetPreferredSize() const {
493 int width = kHorizOuterMargin;
494 width += kIconSize;
495 width += views::kPanelHorizMargin;
496 width += kRightColumnWidth;
497 width += 2 * views::kPanelHorizMargin;
498 width += kHorizOuterMargin;
499
500 int height = kVertOuterMargin;
501 height += heading_->GetHeightForWidth(kRightColumnWidth);
502 height += kVertInnerMargin;
503
504 if (flavors_ & HOW_TO_USE) {
505 height += how_to_use_->GetHeightForWidth(kRightColumnWidth);
506 height += kVertInnerMargin;
507 }
508
509 if (flavors_ & HOW_TO_MANAGE) {
510 height += manage_->GetHeightForWidth(kRightColumnWidth);
511 height += kVertInnerMargin;
512 }
513
514 if (flavors_ & SIGN_IN_PROMO && height_of_signin_promo_ > 0u) {
515 height += height_of_signin_promo_;
516 height += kVertInnerMargin;
517 }
518
519 if (flavors_ & SHOW_KEYBINDING) {
520 height += manage_shortcut_->GetHeightForWidth(kRightColumnWidth);
521 height += kVertInnerMargin;
522 }
523
524 return gfx::Size(width, std::max(height, kIconSize + 2 * kVertOuterMargin));
525 }
526
527 void InstalledBubbleContent::Layout() {
528 int x = kHorizOuterMargin;
529 int y = kVertOuterMargin;
530
531 icon_->SetBounds(x, y, kIconSize, kIconSize);
532 x += kIconSize;
533 x += views::kPanelHorizMargin;
534
535 y += kRightcolumnVerticalShift;
536 heading_->SizeToFit(kRightColumnWidth);
537 heading_->SetX(x);
538 heading_->SetY(y);
539 y += heading_->height();
540 y += kVertInnerMargin;
541
542 if (flavors_ & HOW_TO_USE) {
543 how_to_use_->SizeToFit(kRightColumnWidth);
544 how_to_use_->SetX(x);
545 how_to_use_->SetY(y);
546 y += how_to_use_->height();
547 y += kVertInnerMargin;
548 }
549
550 if (flavors_ & HOW_TO_MANAGE) {
551 manage_->SizeToFit(kRightColumnWidth);
552 manage_->SetX(x);
553 manage_->SetY(y);
554 y += manage_->height();
555 y += kVertInnerMargin;
556 }
557
558 if (flavors_ & SIGN_IN_PROMO) {
559 height_of_signin_promo_ = LayoutSigninPromo(x, y);
560 y += height_of_signin_promo_;
561 y += kVertInnerMargin;
562 }
563
564 if (flavors_ & SHOW_KEYBINDING) {
565 gfx::Size sz = manage_shortcut_->GetPreferredSize();
566 manage_shortcut_->SetBounds(width() - 2 * kHorizOuterMargin - sz.width(),
567 y,
568 sz.width(),
569 sz.height());
570 y += manage_shortcut_->height();
571 y += kVertInnerMargin;
572 }
573
574 gfx::Size sz;
575 x += kRightColumnWidth + 2 * views::kPanelHorizMargin + kHorizOuterMargin -
576 close_button_->GetPreferredSize().width();
577 y = kVertOuterMargin;
578 sz = close_button_->GetPreferredSize();
579 // x-1 & y-1 is just slop to get the close button visually aligned with the
580 // title text and bubble arrow.
581 close_button_->SetBounds(x - 1, y - 1, sz.width(), sz.height());
582 }
583
584 void InstalledBubbleContent::OnPaint(gfx::Canvas* canvas) {
585 for (ScopedVector<gfx::RenderText>::const_iterator it =
586 sign_in_promo_lines_.begin();
587 it != sign_in_promo_lines_.end(); ++it)
588 (*it)->Draw(canvas);
589
590 views::View::OnPaint(canvas);
591 } 385 }
592 386
593 ExtensionInstalledBubbleUi::ExtensionInstalledBubbleUi( 387 ExtensionInstalledBubbleUi::ExtensionInstalledBubbleUi(
594 ExtensionInstalledBubble* bubble) 388 ExtensionInstalledBubble* bubble)
595 : bubble_(bubble), delegate_view_(nullptr) { 389 : bubble_(bubble), delegate_view_(nullptr) {
596 DCHECK(bubble_); 390 DCHECK(bubble_);
597 } 391 }
598 392
599 ExtensionInstalledBubbleUi::~ExtensionInstalledBubbleUi() {} 393 ExtensionInstalledBubbleUi::~ExtensionInstalledBubbleUi() {}
600 394
601 void ExtensionInstalledBubbleUi::Show(BubbleReference bubble_reference) { 395 void ExtensionInstalledBubbleUi::Show(BubbleReference bubble_reference) {
602 // Owned by widget. 396 // Owned by widget.
603 delegate_view_ = new ExtensionInstalledBubbleView(bubble_, bubble_reference); 397 delegate_view_ = new ExtensionInstalledBubbleView(bubble_, bubble_reference);
604 delegate_view_->UpdateAnchorView(); 398 delegate_view_->UpdateAnchorView();
605 399
606 delegate_view_->set_arrow(bubble_->type() == bubble_->OMNIBOX_KEYWORD 400 delegate_view_->set_arrow(bubble_->type() == bubble_->OMNIBOX_KEYWORD
607 ? views::BubbleBorder::TOP_LEFT 401 ? views::BubbleBorder::TOP_LEFT
608 : views::BubbleBorder::TOP_RIGHT); 402 : views::BubbleBorder::TOP_RIGHT);
609 delegate_view_->SetLayoutManager(new views::FillLayout()); 403
610 delegate_view_->AddChildView(new InstalledBubbleContent( 404 delegate_view_->InitLayout(*bubble_);
611 *bubble_, bubble_reference, bubble_->browser()));
612 405
613 views::BubbleDelegateView::CreateBubble(delegate_view_)->Show(); 406 views::BubbleDelegateView::CreateBubble(delegate_view_)->Show();
614 } 407 }
615 408
616 void ExtensionInstalledBubbleUi::Close() { 409 void ExtensionInstalledBubbleUi::Close() {
617 if (delegate_view_) { 410 if (delegate_view_) {
618 delegate_view_->GetWidget()->Close(); 411 delegate_view_->GetWidget()->Close();
619 delegate_view_ = nullptr; 412 delegate_view_ = nullptr;
620 } 413 }
621 } 414 }
622 415
623 void ExtensionInstalledBubbleUi::UpdateAnchorPosition() { 416 void ExtensionInstalledBubbleUi::UpdateAnchorPosition() {
624 DCHECK(delegate_view_); 417 DCHECK(delegate_view_);
625 delegate_view_->UpdateAnchorView(); 418 delegate_view_->UpdateAnchorView();
626 } 419 }
OLDNEW
« no previous file with comments | « chrome/browser/ui/views/extensions/extension_installed_bubble_view.h ('k') | chrome/browser/ui/views/frame/browser_view.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698