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

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

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

Powered by Google App Engine
This is Rietveld 408576698