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

Side by Side Diff: chrome/browser/ui/cocoa/page_info/website_settings_bubble_controller.mm

Issue 2754383004: Rename WebsiteSettings code to PageInfo. (Closed)
Patch Set: Upload missing comment fix for WebSettingsUI -> PageInfoUI. Created 3 years, 9 months 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
(Empty)
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.
4
5 #import "chrome/browser/ui/cocoa/page_info/website_settings_bubble_controller.h"
6
7 #import <AppKit/AppKit.h>
8
9 #include <cmath>
10
11 #include "base/i18n/rtl.h"
12 #include "base/mac/bind_objc_block.h"
13 #include "base/memory/ptr_util.h"
14 #include "base/strings/sys_string_conversions.h"
15 #import "chrome/browser/certificate_viewer.h"
16 #include "chrome/browser/infobars/infobar_service.h"
17 #include "chrome/browser/profiles/profile.h"
18 #include "chrome/browser/ui/browser_dialogs.h"
19 #import "chrome/browser/ui/cocoa/browser_window_controller.h"
20 #import "chrome/browser/ui/cocoa/info_bubble_view.h"
21 #import "chrome/browser/ui/cocoa/info_bubble_window.h"
22 #import "chrome/browser/ui/cocoa/location_bar/location_bar_view_mac.h"
23 #import "chrome/browser/ui/cocoa/page_info/permission_selector_button.h"
24 #include "chrome/browser/ui/page_info/permission_menu_model.h"
25 #import "chrome/browser/ui/tab_dialogs.h"
26 #include "chrome/common/url_constants.h"
27 #include "chrome/grit/chromium_strings.h"
28 #include "chrome/grit/generated_resources.h"
29 #include "chrome/grit/theme_resources.h"
30 #include "components/strings/grit/components_chromium_strings.h"
31 #include "components/strings/grit/components_strings.h"
32 #include "content/public/browser/page_navigator.h"
33 #include "content/public/browser/ssl_host_state_delegate.h"
34 #include "content/public/browser/user_metrics.h"
35 #include "content/public/browser/web_contents.h"
36 #include "content/public/common/url_constants.h"
37 #include "extensions/common/constants.h"
38 #include "skia/ext/skia_utils_mac.h"
39 #import "third_party/google_toolbox_for_mac/src/AppKit/GTMUILocalizerAndLayoutTw eaker.h"
40 #import "ui/base/cocoa/a11y_util.h"
41 #include "ui/base/cocoa/cocoa_base_utils.h"
42 #import "ui/base/cocoa/controls/hyperlink_button_cell.h"
43 #import "ui/base/cocoa/flipped_view.h"
44 #import "ui/base/cocoa/hover_image_button.h"
45 #include "ui/base/l10n/l10n_util.h"
46 #include "ui/base/material_design/material_design_controller.h"
47 #include "ui/base/resource/resource_bundle.h"
48 #import "ui/gfx/mac/coordinate_conversion.h"
49 #include "ui/gfx/scoped_ns_graphics_context_save_gstate_mac.h"
50 #include "ui/resources/grit/ui_resources.h"
51
52 using ChosenObjectInfoPtr =
53 std::unique_ptr<WebsiteSettingsUI::ChosenObjectInfo>;
54 using ChosenObjectDeleteCallback =
55 base::Callback<void(const WebsiteSettingsUI::ChosenObjectInfo&)>;
56
57 namespace {
58
59 // General ---------------------------------------------------------------------
60
61 // The default width of the window, in view coordinates. It may be larger to
62 // fit the content.
63 const CGFloat kDefaultWindowWidth = 320;
64
65 // Padding around each section
66 const CGFloat kSectionVerticalPadding = 20;
67 const CGFloat kSectionHorizontalPadding = 16;
68
69 // Links are buttons with invisible padding, so we need to move them back to
70 // align with other text.
71 const CGFloat kLinkButtonXAdjustment = 1;
72
73 // Built-in margin for NSButton to take into account.
74 const CGFloat kNSButtonBuiltinMargin = 4;
75
76 // Security Section ------------------------------------------------------------
77
78 // Spacing between security summary, security details, and cert decisions text.
79 const CGFloat kSecurityParagraphSpacing = 12;
80
81 // Site Settings Section -------------------------------------------------------
82
83 // Square size of the permission images.
84 const CGFloat kPermissionImageSize = 16;
85
86 // Spacing between a permission image and the text.
87 const CGFloat kPermissionImageSpacing = 6;
88
89 // Minimum distance between the label and its corresponding menu.
90 const CGFloat kMinSeparationBetweenLabelAndMenu = 16;
91
92 // Square size of the permission delete button image.
93 const CGFloat kPermissionDeleteImageSize = 16;
94
95 // The spacing between individual permissions.
96 const CGFloat kPermissionsVerticalSpacing = 16;
97
98 // Amount to lower each permission icon to align the icon baseline with the
99 // label text.
100 const CGFloat kPermissionIconYAdjustment = 1;
101
102 // Amount to lower each permission popup button to make its text align with the
103 // permission label.
104 const CGFloat kPermissionPopupButtonYAdjustment = 3;
105
106 // Internal Page Bubble --------------------------------------------------------
107
108 // Padding between the window frame and content for the internal page bubble.
109 const CGFloat kInternalPageFramePadding = 10;
110
111 // Spacing between the image and text for internal pages.
112 const CGFloat kInternalPageImageSpacing = 10;
113
114 // -----------------------------------------------------------------------------
115
116 // NOTE: This assumes that there will never be more than one website settings
117 // popup shown, and that the one that is shown is associated with the current
118 // window. This matches the behaviour in views: see WebsiteSettingsPopupView.
119 bool g_is_popup_showing = false;
120
121 // Takes in the parent window, which should be a BrowserWindow, and gets the
122 // proper anchor point for the bubble. The returned point is in screen
123 // coordinates.
124 NSPoint AnchorPointForWindow(NSWindow* parent) {
125 BrowserWindowController* controller = [parent windowController];
126 NSPoint origin = NSZeroPoint;
127 if ([controller isKindOfClass:[BrowserWindowController class]]) {
128 LocationBarViewMac* location_bar = [controller locationBarBridge];
129 if (location_bar) {
130 NSPoint bubble_point = location_bar->GetPageInfoBubblePoint();
131 origin = ui::ConvertPointFromWindowToScreen(parent, bubble_point);
132 }
133 }
134 return origin;
135 }
136
137 } // namespace
138
139 @interface ChosenObjectDeleteButton : HoverImageButton {
140 @private
141 ChosenObjectInfoPtr objectInfo_;
142 ChosenObjectDeleteCallback callback_;
143 }
144
145 // Designated initializer. Takes ownership of |objectInfo|.
146 - (instancetype)initWithChosenObject:(ChosenObjectInfoPtr)objectInfo
147 atPoint:(NSPoint)point
148 withCallback:(ChosenObjectDeleteCallback)callback;
149
150 // Action when the button is clicked.
151 - (void)deleteClicked:(id)sender;
152
153 @end
154
155 @implementation ChosenObjectDeleteButton
156
157 - (instancetype)initWithChosenObject:(ChosenObjectInfoPtr)objectInfo
158 atPoint:(NSPoint)point
159 withCallback:(ChosenObjectDeleteCallback)callback {
160 NSRect frame = NSMakeRect(point.x, point.y, kPermissionDeleteImageSize,
161 kPermissionDeleteImageSize);
162 if (self = [super initWithFrame:frame]) {
163 ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
164 [self setDefaultImage:rb.GetNativeImageNamed(IDR_CLOSE_2).ToNSImage()];
165 [self setHoverImage:rb.GetNativeImageNamed(IDR_CLOSE_2_H).ToNSImage()];
166 [self setPressedImage:rb.GetNativeImageNamed(IDR_CLOSE_2_P).ToNSImage()];
167 [self setBordered:NO];
168 [self setToolTip:l10n_util::GetNSString(
169 objectInfo->ui_info.delete_tooltip_string_id)];
170 [self setTarget:self];
171 [self setAction:@selector(deleteClicked:)];
172 objectInfo_ = std::move(objectInfo);
173 callback_ = callback;
174 }
175 return self;
176 }
177
178 - (void)deleteClicked:(id)sender {
179 callback_.Run(*objectInfo_);
180 }
181
182 @end
183
184 @implementation WebsiteSettingsBubbleController
185
186 - (CGFloat)defaultWindowWidth {
187 return kDefaultWindowWidth;
188 }
189
190 bool IsInternalURL(const GURL& url) {
191 return url.SchemeIs(content::kChromeUIScheme) ||
192 url.SchemeIs(content::kChromeDevToolsScheme) ||
193 url.SchemeIs(extensions::kExtensionScheme) ||
194 url.SchemeIs(content::kViewSourceScheme);
195 }
196
197 - (id)initWithParentWindow:(NSWindow*)parentWindow
198 websiteSettingsUIBridge:(WebsiteSettingsUIBridge*)bridge
199 webContents:(content::WebContents*)webContents
200 url:(const GURL&)url {
201 DCHECK(parentWindow);
202
203 webContents_ = webContents;
204 permissionsPresent_ = NO;
205 url_ = url;
206
207 // Use an arbitrary height; it will be changed in performLayout.
208 NSRect contentRect = NSMakeRect(0, 0, [self defaultWindowWidth], 1);
209 // Create an empty window into which content is placed.
210 base::scoped_nsobject<InfoBubbleWindow> window([[InfoBubbleWindow alloc]
211 initWithContentRect:contentRect
212 styleMask:NSBorderlessWindowMask
213 backing:NSBackingStoreBuffered
214 defer:NO]);
215
216 if ((self = [super initWithWindow:window.get()
217 parentWindow:parentWindow
218 anchoredAt:NSZeroPoint])) {
219 [[self bubble] setArrowLocation:info_bubble::kTopLeading];
220
221 // Create the container view that uses flipped coordinates.
222 NSRect contentFrame = NSMakeRect(0, 0, [self defaultWindowWidth], 300);
223 contentView_.reset([[FlippedView alloc] initWithFrame:contentFrame]);
224
225 // Replace the window's content.
226 [[[self window] contentView]
227 setSubviews:[NSArray arrayWithObject:contentView_.get()]];
228
229 if (IsInternalURL(url_)) {
230 [self initializeContentsForInternalPage:url_];
231 } else {
232 [self initializeContents];
233 }
234
235 bridge_.reset(bridge);
236 bridge_->set_bubble_controller(self);
237 }
238 return self;
239 }
240
241 - (LocationBarDecoration*)decorationForBubble {
242 BrowserWindowController* controller = [[self parentWindow] windowController];
243 LocationBarViewMac* location_bar = [controller locationBarBridge];
244 return location_bar ? location_bar->GetPageInfoDecoration() : nullptr;
245 }
246
247 - (Profile*)profile {
248 return Profile::FromBrowserContext(webContents_->GetBrowserContext());
249 }
250
251 - (void)windowWillClose:(NSNotification*)notification {
252 if (presenter_.get())
253 presenter_->OnUIClosing();
254 presenter_.reset();
255 [super windowWillClose:notification];
256 }
257
258 - (void)setPresenter:(WebsiteSettings*)presenter {
259 presenter_.reset(presenter);
260 }
261
262 // Create the subviews for the bubble for internal Chrome pages.
263 - (void)initializeContentsForInternalPage:(const GURL&)url {
264 ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
265
266 int text = IDS_PAGE_INFO_INTERNAL_PAGE;
267 int icon = IDR_PRODUCT_LOGO_16;
268 if (url.SchemeIs(extensions::kExtensionScheme)) {
269 text = IDS_PAGE_INFO_EXTENSION_PAGE;
270 icon = IDR_PLUGINS_FAVICON;
271 } else if (url.SchemeIs(content::kViewSourceScheme)) {
272 text = IDS_PAGE_INFO_VIEW_SOURCE_PAGE;
273 // view-source scheme uses the same icon as chrome:// pages.
274 icon = IDR_PRODUCT_LOGO_16;
275 } else if (!url.SchemeIs(content::kChromeUIScheme) &&
276 !url.SchemeIs(content::kChromeDevToolsScheme)) {
277 NOTREACHED();
278 }
279
280 NSPoint controlOrigin =
281 NSMakePoint(kInternalPageFramePadding,
282 kInternalPageFramePadding + info_bubble::kBubbleArrowHeight);
283 NSImage* productLogoImage = rb.GetNativeImageNamed(icon).ToNSImage();
284 NSImageView* imageView = [self addImageWithSize:[productLogoImage size]
285 toView:contentView_
286 atPoint:controlOrigin];
287 [imageView setImage:productLogoImage];
288
289 NSRect imageFrame = [imageView frame];
290 controlOrigin.x += NSWidth(imageFrame) + kInternalPageImageSpacing;
291 NSTextField* textField = [self addText:l10n_util::GetStringUTF16(text)
292 withSize:[NSFont smallSystemFontSize]
293 bold:NO
294 toView:contentView_
295 atPoint:controlOrigin];
296 // Center the image vertically with the text. Previously this code centered
297 // the text vertically while holding the image in place. That produced correct
298 // results when the image, at 26x26, was taller than (or just slightly
299 // shorter) than the text, but produced incorrect results once the icon
300 // shrank to 16x16. The icon should now always be shorter than the text.
301 // See crbug.com/572044 .
302 NSRect textFrame = [textField frame];
303 imageFrame.origin.y += (NSHeight(textFrame) - NSHeight(imageFrame)) / 2;
304 [imageView setFrame:imageFrame];
305
306 // Adjust the contentView to fit everything.
307 CGFloat maxY = std::max(NSMaxY(imageFrame), NSMaxY(textFrame));
308 [contentView_ setFrame:NSMakeRect(0, 0, [self defaultWindowWidth],
309 maxY + kInternalPageFramePadding)];
310
311 [self sizeAndPositionWindow];
312 }
313
314 // Create the subviews for the website settings bubble.
315 - (void)initializeContents {
316 securitySectionView_ = [self addSecuritySectionToView:contentView_];
317 separatorAfterSecuritySection_ = [self addSeparatorToView:contentView_];
318 siteSettingsSectionView_ = [self addSiteSettingsSectionToView:contentView_];
319
320 [self performLayout];
321 }
322
323 // Create and return a subview for the security section and add it to the given
324 // |superview|. |superview| retains the new view.
325 - (NSView*)addSecuritySectionToView:(NSView*)superview {
326 base::scoped_nsobject<NSView> securitySectionView(
327 [[FlippedView alloc] initWithFrame:[superview frame]]);
328 [superview addSubview:securitySectionView];
329
330 // Create a controlOrigin to place the text fields. The y value doesn't
331 // matter, because the correct value is calculated in -performLayout.
332 NSPoint controlOrigin = NSMakePoint(kSectionHorizontalPadding, 0);
333
334 // Create a text field for the security summary (private/not private/etc.).
335 securitySummaryField_ = [self addText:base::string16()
336 withSize:[NSFont systemFontSize]
337 bold:NO
338 toView:securitySectionView
339 atPoint:controlOrigin];
340
341 securityDetailsField_ = [self addText:base::string16()
342 withSize:[NSFont smallSystemFontSize]
343 bold:NO
344 toView:securitySectionView
345 atPoint:controlOrigin];
346
347 // These will be created only if necessary.
348 resetDecisionsField_ = nil;
349 resetDecisionsButton_ = nil;
350
351 NSString* connectionHelpButtonText = l10n_util::GetNSString(IDS_LEARN_MORE);
352 connectionHelpButton_ = [self addLinkButtonWithText:connectionHelpButtonText
353 toView:securitySectionView];
354 [connectionHelpButton_ setTarget:self];
355 [connectionHelpButton_ setAction:@selector(openConnectionHelp:)];
356
357 return securitySectionView.get();
358 }
359
360 // Create and return a subview for the site settings and add it to the given
361 // |superview|. |superview| retains the new view.
362 - (NSView*)addSiteSettingsSectionToView:(NSView*)superview {
363 base::scoped_nsobject<NSView> siteSettingsSectionView(
364 [[FlippedView alloc] initWithFrame:[superview frame]]);
365 [superview addSubview:siteSettingsSectionView];
366
367 // Initialize the two containers that hold the controls. The initial frames
368 // are arbitrary, and will be adjusted after the controls are laid out.
369 cookiesView_ =
370 [[[FlippedView alloc] initWithFrame:[superview frame]] autorelease];
371 [cookiesView_ setAutoresizingMask:NSViewWidthSizable];
372 [siteSettingsSectionView addSubview:cookiesView_];
373
374 permissionsView_ =
375 [[[FlippedView alloc] initWithFrame:[superview frame]] autorelease];
376 [siteSettingsSectionView addSubview:permissionsView_];
377
378 // Create the link button to view site settings. Its position will be set in
379 // performLayout.
380 NSString* siteSettingsButtonText =
381 l10n_util::GetNSString(IDS_PAGE_INFO_SITE_SETTINGS_LINK);
382 siteSettingsButton_ = [self addButtonWithText:siteSettingsButtonText
383 toView:siteSettingsSectionView];
384 [GTMUILocalizerAndLayoutTweaker sizeToFitView:siteSettingsButton_];
385
386 [siteSettingsButton_ setTarget:self];
387 [siteSettingsButton_ setAction:@selector(showSiteSettingsData:)];
388
389 return siteSettingsSectionView.get();
390 }
391
392 // Handler for the link button below the list of cookies.
393 - (void)showCookiesAndSiteData:(id)sender {
394 DCHECK(webContents_);
395 DCHECK(presenter_);
396 presenter_->RecordWebsiteSettingsAction(
397 WebsiteSettings::WEBSITE_SETTINGS_COOKIES_DIALOG_OPENED);
398 TabDialogs::FromWebContents(webContents_)->ShowCollectedCookies();
399 }
400
401 // Handler for the site settings button below the list of permissions.
402 - (void)showSiteSettingsData:(id)sender {
403 DCHECK(webContents_);
404 DCHECK(presenter_);
405 presenter_->RecordWebsiteSettingsAction(
406 WebsiteSettings::WEBSITE_SETTINGS_SITE_SETTINGS_OPENED);
407 webContents_->OpenURL(content::OpenURLParams(
408 GURL(chrome::kChromeUIContentSettingsURL), content::Referrer(),
409 WindowOpenDisposition::NEW_FOREGROUND_TAB, ui::PAGE_TRANSITION_LINK,
410 false));
411 }
412
413 // TODO(lgarron): Move some of this to the presenter for separation of concerns
414 // and platform unification. (https://crbug.com/571533)
415 - (void)openConnectionHelp:(id)sender {
416 DCHECK(webContents_);
417 DCHECK(presenter_);
418 presenter_->RecordWebsiteSettingsAction(
419 WebsiteSettings::WEBSITE_SETTINGS_CONNECTION_HELP_OPENED);
420 webContents_->OpenURL(content::OpenURLParams(
421 GURL(chrome::kPageInfoHelpCenterURL), content::Referrer(),
422 WindowOpenDisposition::NEW_FOREGROUND_TAB, ui::PAGE_TRANSITION_LINK,
423 false));
424 }
425
426 // Handler for the link button to show certificate information.
427 - (void)showCertificateInfo:(id)sender {
428 DCHECK(certificate_.get());
429 DCHECK(presenter_);
430 presenter_->RecordWebsiteSettingsAction(
431 WebsiteSettings::WEBSITE_SETTINGS_CERTIFICATE_DIALOG_OPENED);
432 ShowCertificateViewer(webContents_, [self parentWindow], certificate_.get());
433 }
434
435 // Handler for the link button to revoke user certificate decisions.
436 - (void)resetCertificateDecisions:(id)sender {
437 DCHECK(resetDecisionsButton_);
438 presenter_->OnRevokeSSLErrorBypassButtonPressed();
439 [self close];
440 }
441
442 - (CGFloat)layoutViewAtRTLStart:(NSView*)view withYPosition:(CGFloat)yPos {
443 CGFloat xPos;
444 if (base::i18n::IsRTL()) {
445 xPos = kDefaultWindowWidth - kSectionHorizontalPadding -
446 NSWidth([view frame]) + kNSButtonBuiltinMargin;
447 } else {
448 xPos = kSectionHorizontalPadding - kNSButtonBuiltinMargin;
449 }
450 [view setFrameOrigin:NSMakePoint(xPos, yPos - kNSButtonBuiltinMargin)];
451 return yPos + NSHeight([view frame]) - kNSButtonBuiltinMargin;
452 }
453
454 // Set the Y position of |view| to the given position, and return the position
455 // of its bottom edge.
456 - (CGFloat)setYPositionOfView:(NSView*)view to:(CGFloat)position {
457 NSRect frame = [view frame];
458 frame.origin.y = position;
459 [view setFrame:frame];
460 return position + NSHeight(frame);
461 }
462
463 - (void)setWidthOfView:(NSView*)view to:(CGFloat)width {
464 [view setFrameSize:NSMakeSize(width, NSHeight([view frame]))];
465 }
466
467 - (void)setHeightOfView:(NSView*)view to:(CGFloat)height {
468 [view setFrameSize:NSMakeSize(NSWidth([view frame]), height)];
469 }
470
471 // Layout all of the controls in the window. This should be called whenever
472 // the content has changed.
473 - (void)performLayout {
474 // Make the content at least as wide as the permissions view.
475 CGFloat contentWidth =
476 std::max([self defaultWindowWidth], NSWidth([permissionsView_ frame]));
477
478 // Set the width of the content view now, so that all the text fields will
479 // be sized to fit before their heights and vertical positions are adjusted.
480 [self setWidthOfView:contentView_ to:contentWidth];
481 [self setWidthOfView:securitySectionView_ to:contentWidth];
482 [self setWidthOfView:siteSettingsSectionView_ to:contentWidth];
483
484 CGFloat yPos = 0;
485
486 [self layoutSecuritySection];
487 yPos = [self setYPositionOfView:securitySectionView_ to:yPos];
488
489 yPos = [self setYPositionOfView:separatorAfterSecuritySection_ to:yPos];
490
491 [self layoutSiteSettingsSection];
492 yPos = [self setYPositionOfView:siteSettingsSectionView_ to:yPos];
493
494 [contentView_ setFrame:NSMakeRect(0, 0, NSWidth([contentView_ frame]), yPos)];
495
496 [self sizeAndPositionWindow];
497 }
498
499 - (void)layoutSecuritySection {
500 // Start the layout with the first element. Margins are handled by the caller.
501 CGFloat yPos = 0;
502
503 [self sizeTextFieldHeightToFit:securitySummaryField_];
504 yPos = [self setYPositionOfView:securitySummaryField_
505 to:yPos + kSectionVerticalPadding];
506
507 [self sizeTextFieldHeightToFit:securityDetailsField_];
508 yPos = [self setYPositionOfView:securityDetailsField_
509 to:yPos + kSecurityParagraphSpacing];
510
511 [connectionHelpButton_ setFrameOrigin:NSMakePoint(kSectionHorizontalPadding -
512 kLinkButtonXAdjustment,
513 yPos)];
514 yPos = NSMaxY([connectionHelpButton_ frame]);
515
516 if (resetDecisionsButton_) {
517 DCHECK(resetDecisionsField_);
518 yPos = [self setYPositionOfView:resetDecisionsField_
519 to:yPos + kSecurityParagraphSpacing];
520 [resetDecisionsButton_
521 setFrameOrigin:NSMakePoint(NSMinX([resetDecisionsButton_ frame]) -
522 kLinkButtonXAdjustment,
523 yPos)];
524 yPos = NSMaxY([resetDecisionsButton_ frame]);
525 }
526
527 // Resize the height based on contents.
528 [self setHeightOfView:securitySectionView_ to:yPos + kSectionVerticalPadding];
529 }
530
531 - (void)layoutSiteSettingsSection {
532 // Start the layout with the first element. Margins are handled by the caller.
533 CGFloat yPos = 0;
534
535 yPos =
536 [self setYPositionOfView:cookiesView_ to:yPos + kSectionVerticalPadding];
537
538 if (permissionsPresent_) {
539 // Put the permission info just below the link button.
540 yPos = [self setYPositionOfView:permissionsView_ to:yPos];
541 }
542
543 yPos = [self layoutViewAtRTLStart:siteSettingsButton_ withYPosition:yPos];
544
545 // Resize the height based on contents.
546 [self setHeightOfView:siteSettingsSectionView_
547 to:yPos + kSectionVerticalPadding];
548 }
549
550 // Adjust the size of the window to match the size of the content, and position
551 // the bubble anchor appropriately.
552 - (void)sizeAndPositionWindow {
553 NSRect windowFrame = [contentView_ frame];
554 windowFrame.size =
555 [[[self window] contentView] convertSize:windowFrame.size toView:nil];
556 // Adjust the origin by the difference in height.
557 windowFrame.origin = [[self window] frame].origin;
558 windowFrame.origin.y -=
559 NSHeight(windowFrame) - NSHeight([[self window] frame]);
560
561 // Resize the window. Only animate if the window is visible, otherwise it
562 // could be "growing" while it's opening, looking awkward.
563 [[self window] setFrame:windowFrame
564 display:YES
565 animate:[[self window] isVisible]];
566
567 // Adjust the anchor for the bubble.
568 [self setAnchorPoint:AnchorPointForWindow([self parentWindow])];
569 }
570
571 // Sets properties on the given |field| to act as the title or description
572 // labels in the bubble.
573 - (void)configureTextFieldAsLabel:(NSTextField*)textField {
574 [textField setEditable:NO];
575 [textField setSelectable:YES];
576 [textField setDrawsBackground:NO];
577 [textField setBezeled:NO];
578 }
579
580 // Adjust the height of the given text field to match its text.
581 - (void)sizeTextFieldHeightToFit:(NSTextField*)textField {
582 NSRect frame = [textField frame];
583 frame.size.height +=
584 [GTMUILocalizerAndLayoutTweaker sizeToFitFixedWidthTextField:textField];
585 [textField setFrame:frame];
586 }
587
588 // Create a new text field and add it to the given array of subviews.
589 // The array will retain a reference to the object.
590 - (NSTextField*)addText:(const base::string16&)text
591 withSize:(CGFloat)fontSize
592 bold:(BOOL)bold
593 toView:(NSView*)view
594 atPoint:(NSPoint)point {
595 // Size the text to take up the full available width, with some padding.
596 // The height is arbitrary as it will be adjusted later.
597 CGFloat width = NSWidth([view frame]) - point.x - kSectionHorizontalPadding;
598 NSRect frame = NSMakeRect(point.x, point.y, width, 100);
599 base::scoped_nsobject<NSTextField> textField(
600 [[NSTextField alloc] initWithFrame:frame]);
601 [self configureTextFieldAsLabel:textField.get()];
602 [textField setStringValue:base::SysUTF16ToNSString(text)];
603 NSFont* font = bold ? [NSFont boldSystemFontOfSize:fontSize]
604 : [NSFont systemFontOfSize:fontSize];
605 [textField setFont:font];
606 [self sizeTextFieldHeightToFit:textField];
607 [textField setAutoresizingMask:NSViewWidthSizable];
608 [view addSubview:textField.get()];
609 return textField.get();
610 }
611
612 // Add an image as a subview of the given view, placed at a pre-determined x
613 // position and the given y position. The image is not in the accessibility
614 // order, since the image is always accompanied by text in this bubble. Return
615 // the new NSImageView.
616 - (NSImageView*)addImageWithSize:(NSSize)size
617 toView:(NSView*)view
618 atPoint:(NSPoint)point {
619 NSRect frame = NSMakeRect(point.x, point.y, size.width, size.height);
620 base::scoped_nsobject<NSImageView> imageView(
621 [[NSImageView alloc] initWithFrame:frame]);
622 ui::a11y_util::HideImageFromAccessibilityOrder(imageView);
623 [imageView setImageFrameStyle:NSImageFrameNone];
624 [view addSubview:imageView.get()];
625 return imageView.get();
626 }
627
628 // Add a separator as a subview of the given view. Return the new view.
629 - (NSView*)addSeparatorToView:(NSView*)view {
630 // Use an arbitrary position; it will be adjusted in performLayout.
631 NSBox* spacer = [self
632 horizontalSeparatorWithFrame:NSMakeRect(0, 0, NSWidth([view frame]), 0)];
633 [view addSubview:spacer];
634 return spacer;
635 }
636
637 // Add a link button with the given text to |view|.
638 - (NSButton*)addLinkButtonWithText:(NSString*)text toView:(NSView*)view {
639 // Frame size is arbitrary; it will be adjusted by the layout tweaker.
640 NSRect frame = NSMakeRect(kSectionHorizontalPadding, 0, 100, 10);
641 base::scoped_nsobject<NSButton> button(
642 [[NSButton alloc] initWithFrame:frame]);
643 base::scoped_nsobject<HyperlinkButtonCell> cell(
644 [[HyperlinkButtonCell alloc] initTextCell:text]);
645 [cell setControlSize:NSSmallControlSize];
646 [button setCell:cell.get()];
647 [button setButtonType:NSMomentaryPushInButton];
648 [button setBezelStyle:NSRegularSquareBezelStyle];
649 [view addSubview:button.get()];
650
651 [GTMUILocalizerAndLayoutTweaker sizeToFitView:button.get()];
652 return button.get();
653 }
654
655 // Create and return a button with the specified text and add it to the given
656 // |view|. |view| retains the new button.
657 - (NSButton*)addButtonWithText:(NSString*)text toView:(NSView*)view {
658 NSRect containerFrame = [view frame];
659 // Frame size is arbitrary; it will be adjusted by the layout tweaker.
660 NSRect frame = NSMakeRect(kSectionHorizontalPadding, 0, 100, 10);
661 base::scoped_nsobject<NSButton> button(
662 [[NSButton alloc] initWithFrame:frame]);
663
664 // Determine the largest possible size for this button. The size is the width
665 // of the connection section minus the padding on both sides minus the
666 // connection image size and spacing.
667 // TODO(lgarron): handle this sizing in -performLayout.
668 CGFloat maxTitleWidth =
669 containerFrame.size.width - kSectionHorizontalPadding * 2;
670
671 base::scoped_nsobject<NSButtonCell> cell(
672 [[NSButtonCell alloc] initTextCell:text]);
673 [button setCell:cell.get()];
674 [GTMUILocalizerAndLayoutTweaker sizeToFitView:button.get()];
675
676 // Ensure the containing view is large enough to contain the button with its
677 // widest possible title.
678 NSRect buttonFrame = [button frame];
679 buttonFrame.size.width = maxTitleWidth;
680
681 [button setFrame:buttonFrame];
682 [button setButtonType:NSMomentaryPushInButton];
683 [button setBezelStyle:NSRegularSquareBezelStyle];
684 [view addSubview:button.get()];
685
686 return button.get();
687 }
688
689 // Set the content of the identity and identity status fields.
690 - (void)setIdentityInfo:(const WebsiteSettingsUI::IdentityInfo&)identityInfo {
691 std::unique_ptr<WebsiteSettingsUI::SecurityDescription> security_description =
692 identityInfo.GetSecurityDescription();
693 [securitySummaryField_
694 setStringValue:base::SysUTF16ToNSString(security_description->summary)];
695
696 [securityDetailsField_
697 setStringValue:SysUTF16ToNSString(security_description->details)];
698
699 certificate_ = identityInfo.certificate;
700
701 if (certificate_ && identityInfo.show_ssl_decision_revoke_button) {
702 resetDecisionsField_ =
703 [self addText:base::string16()
704 withSize:[NSFont smallSystemFontSize]
705 bold:NO
706 toView:securitySectionView_
707 atPoint:NSMakePoint(kSectionHorizontalPadding, 0)];
708 [resetDecisionsField_
709 setStringValue:l10n_util::GetNSString(
710 IDS_PAGEINFO_INVALID_CERTIFICATE_DESCRIPTION)];
711 [self sizeTextFieldHeightToFit:resetDecisionsField_];
712
713 resetDecisionsButton_ =
714 [self addLinkButtonWithText:
715 l10n_util::GetNSString(
716 IDS_PAGEINFO_RESET_INVALID_CERTIFICATE_DECISIONS_BUTTON)
717 toView:securitySectionView_];
718 [resetDecisionsButton_ setTarget:self];
719 [resetDecisionsButton_ setAction:@selector(resetCertificateDecisions:)];
720 }
721
722 [self performLayout];
723 }
724
725 // Add a pop-up button for |permissionInfo| to the given view.
726 - (NSPopUpButton*)addPopUpButtonForPermission:
727 (const WebsiteSettingsUI::PermissionInfo&)permissionInfo
728 toView:(NSView*)view
729 atPoint:(NSPoint)point {
730 GURL url = webContents_ ? webContents_->GetURL() : GURL();
731 __block WebsiteSettingsBubbleController* weakSelf = self;
732 PermissionMenuModel::ChangeCallback callback =
733 base::BindBlock(^(const WebsiteSettingsUI::PermissionInfo& permission) {
734 [weakSelf onPermissionChanged:permission.type to:permission.setting];
735 });
736 base::scoped_nsobject<PermissionSelectorButton> button(
737 [[PermissionSelectorButton alloc] initWithPermissionInfo:permissionInfo
738 forURL:url
739 withCallback:callback
740 profile:[self profile]]);
741
742 // Determine the largest possible size for this button.
743 CGFloat maxTitleWidth =
744 [button maxTitleWidthForContentSettingsType:permissionInfo.type
745 withDefaultSetting:permissionInfo.default_setting
746 profile:[self profile]];
747
748 // Ensure the containing view is large enough to contain the button with its
749 // widest possible title.
750 NSRect containerFrame = [view frame];
751 containerFrame.size.width =
752 std::max(NSWidth(containerFrame),
753 point.x + maxTitleWidth + kSectionHorizontalPadding);
754 [view setFrame:containerFrame];
755 [view addSubview:button.get()];
756 return button.get();
757 }
758
759 // Add a delete button for |objectInfo| to the given view.
760 - (NSButton*)addDeleteButtonForChosenObject:(ChosenObjectInfoPtr)objectInfo
761 toView:(NSView*)view
762 atPoint:(NSPoint)point {
763 __block WebsiteSettingsBubbleController* weakSelf = self;
764 auto callback =
765 base::BindBlock(^(const WebsiteSettingsUI::ChosenObjectInfo& objectInfo) {
766 [weakSelf onChosenObjectDeleted:objectInfo];
767 });
768 base::scoped_nsobject<ChosenObjectDeleteButton> button(
769 [[ChosenObjectDeleteButton alloc]
770 initWithChosenObject:std::move(objectInfo)
771 atPoint:point
772 withCallback:callback]);
773
774 // Ensure the containing view is large enough to contain the button.
775 NSRect containerFrame = [view frame];
776 containerFrame.size.width =
777 std::max(NSWidth(containerFrame), point.x + kPermissionDeleteImageSize +
778 kSectionHorizontalPadding);
779 [view setFrame:containerFrame];
780 [view addSubview:button.get()];
781 return button.get();
782 }
783
784 // Called when the user changes the setting of a permission.
785 - (void)onPermissionChanged:(ContentSettingsType)permissionType
786 to:(ContentSetting)newSetting {
787 if (presenter_)
788 presenter_->OnSitePermissionChanged(permissionType, newSetting);
789 }
790
791 // Called when the user revokes permission for a previously chosen object.
792 - (void)onChosenObjectDeleted:(const WebsiteSettingsUI::ChosenObjectInfo&)info {
793 if (presenter_)
794 presenter_->OnSiteChosenObjectDeleted(info.ui_info, *info.object);
795 }
796
797 // Adds a new row to the UI listing the permissions. Returns the NSPoint of the
798 // last UI element added (either the permission button, in LTR, or the text
799 // label, in RTL).
800 - (NSPoint)addPermission:
801 (const WebsiteSettingsUI::PermissionInfo&)permissionInfo
802 toView:(NSView*)view
803 atPoint:(NSPoint)point {
804 base::string16 labelText =
805 WebsiteSettingsUI::PermissionTypeToUIString(permissionInfo.type);
806 bool isRTL = base::i18n::IsRTL();
807 base::scoped_nsobject<NSImage> image(
808 [WebsiteSettingsUI::GetPermissionIcon(permissionInfo)
809 .ToNSImage() retain]);
810
811 NSPoint position;
812 NSImageView* imageView;
813 NSPopUpButton* button;
814 NSTextField* label;
815
816 CGFloat viewWidth = NSWidth([view frame]);
817
818 if (isRTL) {
819 point.x = NSWidth([view frame]) - kPermissionImageSize -
820 kSectionHorizontalPadding;
821 imageView = [self addImageWithSize:[image size] toView:view atPoint:point];
822 [imageView setImage:image];
823 point.x -= kPermissionImageSpacing;
824
825 label = [self addText:labelText
826 withSize:[NSFont systemFontSize]
827 bold:NO
828 toView:view
829 atPoint:point];
830 [label sizeToFit];
831 point.x -= NSWidth([label frame]);
832 [label setFrameOrigin:point];
833
834 position =
835 NSMakePoint(point.x, point.y + kPermissionPopupButtonYAdjustment);
836 button = [self addPopUpButtonForPermission:permissionInfo
837 toView:view
838 atPoint:position];
839 position.x -= NSWidth([button frame]);
840 [button setFrameOrigin:position];
841 } else {
842 imageView = [self addImageWithSize:[image size] toView:view atPoint:point];
843 [imageView setImage:image];
844 point.x += kPermissionImageSize + kPermissionImageSpacing;
845
846 label = [self addText:labelText
847 withSize:[NSFont systemFontSize]
848 bold:NO
849 toView:view
850 atPoint:point];
851 [label sizeToFit];
852
853 position = NSMakePoint(NSMaxX([label frame]),
854 point.y + kPermissionPopupButtonYAdjustment);
855
856 button = [self addPopUpButtonForPermission:permissionInfo
857 toView:view
858 atPoint:position];
859 }
860 [label setToolTip:base::SysUTF16ToNSString(labelText)];
861
862 [view setFrameSize:NSMakeSize(viewWidth, NSHeight([view frame]))];
863
864 // Adjust the vertical position of the button so that its title text is
865 // aligned with the label. Assumes that the text is the same size in both.
866 // Also adjust the horizontal position to remove excess space due to the
867 // invisible bezel.
868 NSRect titleRect = [[button cell] titleRectForBounds:[button bounds]];
869 if (isRTL) {
870 position.x = kSectionHorizontalPadding;
871 } else {
872 position.x = kDefaultWindowWidth - kSectionHorizontalPadding -
873 [button frame].size.width;
874 }
875 position.y -= titleRect.origin.y;
876 [button setFrameOrigin:position];
877
878 // Truncate the label if it's too wide.
879 // This is a workaround for https://crbug.com/654268 until MacViews ships.
880 NSRect labelFrame = [label frame];
881 if (isRTL) {
882 CGFloat maxLabelWidth = NSMaxX(labelFrame) - NSMaxX([button frame]) -
883 kMinSeparationBetweenLabelAndMenu;
884 if (NSWidth(labelFrame) > maxLabelWidth) {
885 labelFrame.origin.x = NSMaxX(labelFrame) - maxLabelWidth;
886 labelFrame.size.width = maxLabelWidth;
887 [label setFrame:labelFrame];
888 [[label cell] setLineBreakMode:NSLineBreakByTruncatingTail];
889 }
890 } else {
891 CGFloat maxLabelWidth = NSMinX([button frame]) - NSMinX(labelFrame) -
892 kMinSeparationBetweenLabelAndMenu;
893 if (NSWidth(labelFrame) > maxLabelWidth) {
894 labelFrame.size.width = maxLabelWidth;
895 [label setFrame:labelFrame];
896 [[label cell] setLineBreakMode:NSLineBreakByTruncatingTail];
897 }
898 }
899
900 // Align the icon with the text.
901 [self alignPermissionIcon:imageView withTextField:label];
902
903 // Permissions specified by policy or an extension cannot be changed.
904 if (permissionInfo.source == content_settings::SETTING_SOURCE_EXTENSION ||
905 permissionInfo.source == content_settings::SETTING_SOURCE_POLICY) {
906 [button setEnabled:NO];
907 }
908
909 NSRect buttonFrame = [button frame];
910 return NSMakePoint(NSMaxX(buttonFrame), NSMaxY(buttonFrame));
911 }
912
913 // Adds a new row to the UI listing the permissions. Returns the NSPoint of the
914 // last UI element added (either the permission button, in LTR, or the text
915 // label, in RTL).
916 - (NSPoint)addChosenObject:(ChosenObjectInfoPtr)objectInfo
917 toView:(NSView*)view
918 atPoint:(NSPoint)point {
919 base::string16 labelText = l10n_util::GetStringFUTF16(
920 objectInfo->ui_info.label_string_id,
921 WebsiteSettingsUI::ChosenObjectToUIString(*objectInfo));
922 bool isRTL = base::i18n::IsRTL();
923 base::scoped_nsobject<NSImage> image(
924 [WebsiteSettingsUI::GetChosenObjectIcon(*objectInfo, false)
925 .ToNSImage() retain]);
926
927 NSPoint position;
928 NSImageView* imageView;
929 NSButton* button;
930 NSTextField* label;
931
932 CGFloat viewWidth = NSWidth([view frame]);
933
934 if (isRTL) {
935 point.x = NSWidth([view frame]) - kPermissionImageSize -
936 kPermissionImageSpacing - kSectionHorizontalPadding;
937 imageView = [self addImageWithSize:[image size] toView:view atPoint:point];
938 [imageView setImage:image];
939 point.x -= kPermissionImageSpacing;
940
941 label = [self addText:labelText
942 withSize:[NSFont systemFontSize]
943 bold:NO
944 toView:view
945 atPoint:point];
946 [label sizeToFit];
947 point.x -= NSWidth([label frame]);
948 [label setFrameOrigin:point];
949
950 position = NSMakePoint(point.x, point.y);
951 button = [self addDeleteButtonForChosenObject:std::move(objectInfo)
952 toView:view
953 atPoint:position];
954 position.x -= NSWidth([button frame]);
955 [button setFrameOrigin:position];
956 } else {
957 imageView = [self addImageWithSize:[image size] toView:view atPoint:point];
958 [imageView setImage:image];
959 point.x += kPermissionImageSize + kPermissionImageSpacing;
960
961 label = [self addText:labelText
962 withSize:[NSFont systemFontSize]
963 bold:NO
964 toView:view
965 atPoint:point];
966 [label sizeToFit];
967
968 position = NSMakePoint(NSMaxX([label frame]), point.y);
969 button = [self addDeleteButtonForChosenObject:std::move(objectInfo)
970 toView:view
971 atPoint:position];
972 }
973
974 [view setFrameSize:NSMakeSize(viewWidth, NSHeight([view frame]))];
975
976 // Adjust the vertical position of the button so that its title text is
977 // aligned with the label. Assumes that the text is the same size in both.
978 // Also adjust the horizontal position to remove excess space due to the
979 // invisible bezel.
980 NSRect titleRect = [[button cell] titleRectForBounds:[button bounds]];
981 position.y -= titleRect.origin.y;
982 [button setFrameOrigin:position];
983
984 // Align the icon with the text.
985 [self alignPermissionIcon:imageView withTextField:label];
986
987 NSRect buttonFrame = [button frame];
988 return NSMakePoint(NSMaxX(buttonFrame), NSMaxY(buttonFrame));
989 }
990
991 // Align an image with a text field by vertically centering the image on
992 // the cap height of the first line of text.
993 - (void)alignPermissionIcon:(NSImageView*)imageView
994 withTextField:(NSTextField*)textField {
995 NSRect frame = [imageView frame];
996 frame.origin.y += kPermissionIconYAdjustment;
997 [imageView setFrame:frame];
998 }
999
1000 - (void)setCookieInfo:(const CookieInfoList&)cookieInfoList {
1001 // A result of re-ordering of the permissions (crbug.com/444244) is
1002 // that sometimes permissions may not be displayed at all, so it's
1003 // incorrect to check they are set before the cookie info.
1004
1005 // |cookieInfoList| should only ever have 2 items: first- and third-party
1006 // cookies.
1007 DCHECK_EQ(cookieInfoList.size(), 2u);
1008
1009 int totalAllowed = 0;
1010 for (const auto& i : cookieInfoList) {
1011 totalAllowed += i.allowed;
1012 }
1013 base::string16 label_text = l10n_util::GetPluralStringFUTF16(
1014 IDS_WEBSITE_SETTINGS_NUM_COOKIES, totalAllowed);
1015
1016 base::string16 sectionTitle =
1017 l10n_util::GetStringUTF16(IDS_WEBSITE_SETTINGS_TITLE_SITE_DATA);
1018 bool isRTL = base::i18n::IsRTL();
1019
1020 [cookiesView_ setSubviews:[NSArray array]];
1021 NSPoint controlOrigin = NSMakePoint(kSectionHorizontalPadding, 0);
1022
1023 CGFloat viewWidth = NSWidth([cookiesView_ frame]);
1024
1025 // Reset X for the cookie image.
1026 if (isRTL) {
1027 controlOrigin.x = viewWidth - kPermissionImageSize -
1028 kPermissionImageSpacing - kSectionHorizontalPadding;
1029 }
1030
1031 WebsiteSettingsUI::PermissionInfo info;
1032 info.type = CONTENT_SETTINGS_TYPE_COOKIES;
1033 info.setting = CONTENT_SETTING_ALLOW;
1034 // info.default_setting, info.source, and info.is_incognito have not been set,
1035 // but GetPermissionIcon doesn't use any of those.
1036 NSImage* image = WebsiteSettingsUI::GetPermissionIcon(info).ToNSImage();
1037 NSImageView* imageView = [self addImageWithSize:[image size]
1038 toView:cookiesView_
1039 atPoint:controlOrigin];
1040 [imageView setImage:image];
1041
1042 NSButton* cookiesButton =
1043 [self addLinkButtonWithText:base::SysUTF16ToNSString(label_text)
1044 toView:cookiesView_];
1045 [cookiesButton setTarget:self];
1046 [cookiesButton setAction:@selector(showCookiesAndSiteData:)];
1047
1048 if (isRTL) {
1049 controlOrigin.x -= kPermissionImageSpacing;
1050 NSTextField* cookiesLabel =
1051 [self addText:l10n_util::GetStringUTF16(IDS_PAGE_INFO_COOKIES)
1052 withSize:[NSFont systemFontSize]
1053 bold:NO
1054 toView:cookiesView_
1055 atPoint:controlOrigin];
1056 [cookiesLabel sizeToFit];
1057
1058 NSPoint cookiesLabelOrigin = [cookiesLabel frame].origin;
1059 cookiesLabelOrigin.x -= NSWidth([cookiesLabel frame]);
1060 [cookiesLabel setFrameOrigin:cookiesLabelOrigin];
1061
1062 // Align the icon with the text.
1063 [self alignPermissionIcon:imageView withTextField:cookiesLabel];
1064
1065 controlOrigin.y += NSHeight([cookiesLabel frame]);
1066 controlOrigin.x -= NSWidth([cookiesButton frame]) - kLinkButtonXAdjustment;
1067 [cookiesButton setFrameOrigin:controlOrigin];
1068 } else {
1069 controlOrigin.x += kPermissionImageSize + kPermissionImageSpacing;
1070 NSTextField* cookiesLabel =
1071 [self addText:l10n_util::GetStringUTF16(IDS_PAGE_INFO_COOKIES)
1072 withSize:[NSFont systemFontSize]
1073 bold:NO
1074 toView:cookiesView_
1075 atPoint:controlOrigin];
1076 [cookiesLabel sizeToFit];
1077
1078 controlOrigin.y += NSHeight([cookiesLabel frame]);
1079 controlOrigin.x -= kLinkButtonXAdjustment;
1080 [cookiesButton setFrameOrigin:controlOrigin];
1081
1082 // Align the icon with the text.
1083 [self alignPermissionIcon:imageView withTextField:cookiesLabel];
1084 }
1085
1086 controlOrigin.y += NSHeight([cookiesButton frame]);
1087 [cookiesView_
1088 setFrameSize:NSMakeSize(NSWidth([cookiesView_ frame]), controlOrigin.y)];
1089
1090 [self performLayout];
1091 }
1092
1093 - (void)setPermissionInfo:(const PermissionInfoList&)permissionInfoList
1094 andChosenObjects:(ChosenObjectInfoList)chosenObjectInfoList {
1095 [permissionsView_ setSubviews:[NSArray array]];
1096 NSPoint controlOrigin = NSMakePoint(kSectionHorizontalPadding, 0);
1097
1098 permissionsPresent_ = YES;
1099
1100 if (permissionInfoList.size() > 0 || chosenObjectInfoList.size() > 0) {
1101 base::string16 sectionTitle =
1102 l10n_util::GetStringUTF16(IDS_WEBSITE_SETTINGS_TITLE_SITE_PERMISSIONS);
1103
1104 for (const auto& permission : permissionInfoList) {
1105 controlOrigin.y += kPermissionsVerticalSpacing;
1106 NSPoint rowBottomRight = [self addPermission:permission
1107 toView:permissionsView_
1108 atPoint:controlOrigin];
1109 controlOrigin.y = rowBottomRight.y;
1110 }
1111
1112 for (auto& object : chosenObjectInfoList) {
1113 controlOrigin.y += kPermissionsVerticalSpacing;
1114 NSPoint rowBottomRight = [self addChosenObject:std::move(object)
1115 toView:permissionsView_
1116 atPoint:controlOrigin];
1117 controlOrigin.y = rowBottomRight.y;
1118 }
1119
1120 controlOrigin.y += kPermissionsVerticalSpacing;
1121 }
1122
1123 [permissionsView_ setFrameSize:NSMakeSize(NSWidth([permissionsView_ frame]),
1124 controlOrigin.y)];
1125 [self performLayout];
1126 }
1127
1128 @end
1129
1130 WebsiteSettingsUIBridge::WebsiteSettingsUIBridge(
1131 content::WebContents* web_contents)
1132 : content::WebContentsObserver(web_contents),
1133 web_contents_(web_contents),
1134 bubble_controller_(nil) {
1135 DCHECK(!g_is_popup_showing);
1136 g_is_popup_showing = true;
1137 }
1138
1139 WebsiteSettingsUIBridge::~WebsiteSettingsUIBridge() {
1140 DCHECK(g_is_popup_showing);
1141 g_is_popup_showing = false;
1142 }
1143
1144 void WebsiteSettingsUIBridge::set_bubble_controller(
1145 WebsiteSettingsBubbleController* controller) {
1146 bubble_controller_ = controller;
1147 }
1148
1149 void WebsiteSettingsUIBridge::Show(
1150 gfx::NativeWindow parent,
1151 Profile* profile,
1152 content::WebContents* web_contents,
1153 const GURL& virtual_url,
1154 const security_state::SecurityInfo& security_info) {
1155 if (ui::MaterialDesignController::IsSecondaryUiMaterial()) {
1156 chrome::ShowWebsiteSettingsBubbleViewsAtPoint(
1157 gfx::ScreenPointFromNSPoint(AnchorPointForWindow(parent)), profile,
1158 web_contents, virtual_url, security_info);
1159 return;
1160 }
1161
1162 // Don't show the popup if it's already being shown. Since this method is
1163 // called each time the location icon is clicked, each click toggles the popup
1164 // in and out.
1165 if (g_is_popup_showing)
1166 return;
1167
1168 // Create the bridge. This will be owned by the bubble controller.
1169 WebsiteSettingsUIBridge* bridge = new WebsiteSettingsUIBridge(web_contents);
1170
1171 // Create the bubble controller. It will dealloc itself when it closes,
1172 // resetting |g_is_popup_showing|.
1173 WebsiteSettingsBubbleController* bubble_controller = [
1174 [WebsiteSettingsBubbleController alloc] initWithParentWindow:parent
1175 websiteSettingsUIBridge:bridge
1176 webContents:web_contents
1177 url:virtual_url];
1178
1179 if (!IsInternalURL(virtual_url)) {
1180 // Initialize the presenter, which holds the model and controls the UI.
1181 // This is also owned by the bubble controller.
1182 WebsiteSettings* presenter = new WebsiteSettings(
1183 bridge, profile,
1184 TabSpecificContentSettings::FromWebContents(web_contents), web_contents,
1185 virtual_url, security_info);
1186 [bubble_controller setPresenter:presenter];
1187 }
1188
1189 [bubble_controller showWindow:nil];
1190 }
1191
1192 void WebsiteSettingsUIBridge::SetIdentityInfo(
1193 const WebsiteSettingsUI::IdentityInfo& identity_info) {
1194 [bubble_controller_ setIdentityInfo:identity_info];
1195 }
1196
1197 void WebsiteSettingsUIBridge::RenderFrameDeleted(
1198 content::RenderFrameHost* render_frame_host) {
1199 if (render_frame_host == web_contents_->GetMainFrame()) {
1200 [bubble_controller_ close];
1201 }
1202 }
1203
1204 void WebsiteSettingsUIBridge::SetCookieInfo(
1205 const CookieInfoList& cookie_info_list) {
1206 [bubble_controller_ setCookieInfo:cookie_info_list];
1207 }
1208
1209 void WebsiteSettingsUIBridge::SetPermissionInfo(
1210 const PermissionInfoList& permission_info_list,
1211 ChosenObjectInfoList chosen_object_info_list) {
1212 [bubble_controller_ setPermissionInfo:permission_info_list
1213 andChosenObjects:std::move(chosen_object_info_list)];
1214 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698