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

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

Powered by Google App Engine
This is Rietveld 408576698