1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #import "chrome/browser/ui/cocoa/website_settings/website_settings_bubble_controller.h"
9 #import <AppKit/AppKit.h>
11 #include "base/mac/bind_objc_block.h"
12 #include "base/strings/string_number_conversions.h"
13 #include "base/strings/sys_string_conversions.h"
14 #import "chrome/browser/certificate_viewer.h"
15 #include "chrome/browser/infobars/infobar_service.h"
16 #include "chrome/browser/ssl/chrome_ssl_host_state_delegate.h"
17 #import "chrome/browser/ui/browser_dialogs.h"
18 #import "chrome/browser/ui/cocoa/browser_window_controller.h"
19 #import "chrome/browser/ui/cocoa/info_bubble_view.h"
20 #import "chrome/browser/ui/cocoa/info_bubble_window.h"
21 #import "chrome/browser/ui/cocoa/location_bar/location_bar_view_mac.h"
22 #import "chrome/browser/ui/cocoa/website_settings/permission_selector_button.h"
23 #include "chrome/browser/ui/website_settings/permission_menu_model.h"
24 #include "chrome/browser/ui/website_settings/website_settings_utils.h"
25 #include "chrome/common/url_constants.h"
26 #include "content/public/browser/cert_store.h"
27 #include "content/public/browser/page_navigator.h"
28 #include "content/public/browser/ssl_host_state_delegate.h"
29 #include "content/public/browser/user_metrics.h"
30 #include "content/public/browser/web_contents.h"
31 #include "grit/chromium_strings.h"
32 #include "grit/generated_resources.h"
33 #include "grit/theme_resources.h"
34 #include "grit/ui_resources.h"
35 #import "third_party/google_toolbox_for_mac/src/AppKit/GTMUILocalizerAndLayoutTweaker.h"
36 #import "ui/base/cocoa/controls/hyperlink_button_cell.h"
37 #import "ui/base/cocoa/flipped_view.h"
38 #include "ui/base/l10n/l10n_util.h"
39 #include "ui/base/resource/resource_bundle.h"
40 #include "ui/gfx/scoped_ns_graphics_context_save_gstate_mac.h"
44 // The default width of the window, in view coordinates. It may be larger to
46 const CGFloat kDefaultWindowWidth = 310;
48 // Spacing in between sections.
49 const CGFloat kVerticalSpacing = 10;
51 // Padding between the window frame and content.
52 const CGFloat kFramePadding = 20;
54 // Padding between the window frame and content for the internal page bubble.
55 const CGFloat kInternalPageFramePadding = 10;
57 // Spacing between the headlines and description text on the Connection tab.
58 const CGFloat kConnectionHeadlineSpacing = 2;
60 // Spacing between images on the Connection tab and the text.
61 const CGFloat kConnectionImageSpacing = 10;
63 // Spacing between the image and text for internal pages.
64 const CGFloat kInternalPageImageSpacing = 10;
66 // Square size of the images on the Connections tab.
67 const CGFloat kConnectionImageSize = 30;
69 // Square size of the image that is shown for internal pages.
70 const CGFloat kInternalPageImageSize = 26;
72 // Square size of the permission images.
73 const CGFloat kPermissionImageSize = 19;
75 // Vertical adjustment for the permission images.
76 // They have an extra pixel of padding on the bottom edge.
77 const CGFloat kPermissionImageYAdjust = 1;
79 // Spacing between a permission image and the text.
80 const CGFloat kPermissionImageSpacing = 3;
82 // The spacing between individual items in the Permissions tab.
83 const CGFloat kPermissionsTabSpacing = 12;
85 // Extra spacing after a headline on the Permissions tab.
86 const CGFloat kPermissionsHeadlineSpacing = 2;
88 // The amount of horizontal space between a permission label and the popup.
89 const CGFloat kPermissionPopUpXSpacing = 3;
91 // The extra space to the left of the first tab in the tab strip.
92 const CGFloat kTabStripXPadding = kFramePadding;
94 // The amount of space between the visual borders of adjacent tabs.
95 const CGFloat kTabSpacing = 4;
97 // The amount of space above the tab strip.
98 const CGFloat kTabStripTopSpacing = 14;
100 // The height of the clickable area of the tab.
101 const CGFloat kTabHeight = 28;
103 // The amount of space above tab labels.
104 const CGFloat kTabLabelTopPadding = 6;
106 // The amount of padding to leave on either side of the tab label.
107 const CGFloat kTabLabelXPadding = 12;
109 // Return the text color to use for the indentity status when the site's
110 // identity has been verified.
111 NSColor* IdentityVerifiedTextColor() {
112 // RGB components are specified using integer RGB [0-255] values for easy
113 // comparison to other platforms.
114 return [NSColor colorWithCalibratedRed:0x07/255.0
122 @interface WebsiteSettingsTabSegmentedCell : NSSegmentedCell {
124 base::scoped_nsobject<NSImage> tabstripCenterImage_;
125 base::scoped_nsobject<NSImage> tabstripLeftImage_;
126 base::scoped_nsobject<NSImage> tabstripRightImage_;
128 base::scoped_nsobject<NSImage> tabCenterImage_;
129 base::scoped_nsobject<NSImage> tabLeftImage_;
130 base::scoped_nsobject<NSImage> tabRightImage_;
132 // Key track of the index of segment which has keyboard focus. This is not
133 // the same as the currently selected segment.
134 NSInteger keySegment_;
138 @implementation WebsiteSettingsTabSegmentedCell
140 if ((self = [super init])) {
141 ResourceBundle& rb = ResourceBundle::GetSharedInstance();
142 tabstripCenterImage_.reset(rb.GetNativeImageNamed(
143 IDR_WEBSITE_SETTINGS_TABSTRIP_CENTER).CopyNSImage());
144 tabstripLeftImage_.reset(rb.GetNativeImageNamed(
145 IDR_WEBSITE_SETTINGS_TABSTRIP_LEFT).CopyNSImage());
146 tabstripRightImage_.reset(rb.GetNativeImageNamed(
147 IDR_WEBSITE_SETTINGS_TABSTRIP_RIGHT).CopyNSImage());
149 tabCenterImage_.reset(
150 rb.GetNativeImageNamed(IDR_WEBSITE_SETTINGS_TAB_CENTER2).CopyNSImage());
152 rb.GetNativeImageNamed(IDR_WEBSITE_SETTINGS_TAB_LEFT2).CopyNSImage());
153 tabRightImage_.reset(
154 rb.GetNativeImageNamed(IDR_WEBSITE_SETTINGS_TAB_RIGHT2).CopyNSImage());
159 // Called when keyboard focus in the segmented control is moved forward.
160 - (void)makeNextSegmentKey {
161 [super makeNextSegmentKey];
162 keySegment_ = (keySegment_ + 1) % [self segmentCount];
165 // Called when keyboard focus in the segmented control is moved backwards.
166 - (void)makePreviousSegmentKey {
167 [super makePreviousSegmentKey];
168 if (--keySegment_ < 0)
169 keySegment_ += [self segmentCount];
172 - (void)setSelectedSegment:(NSInteger)selectedSegment {
173 keySegment_ = selectedSegment;
174 [super setSelectedSegment:selectedSegment];
177 - (void)drawWithFrame:(NSRect)cellFrame inView:(NSView*)controlView {
178 CGFloat tabstripHeight = [tabCenterImage_ size].height;
180 // Draw the tab for the selected segment.
181 NSRect tabRect = [self hitRectForSegment:[self selectedSegment]];
182 tabRect.origin.y = 0;
183 tabRect.size.height = tabstripHeight;
185 NSDrawThreePartImage(tabRect,
190 NSCompositeSourceOver,
194 // Draw the background to the left of the selected tab.
195 NSRect backgroundRect = NSMakeRect(0, 0, NSMinX(tabRect), tabstripHeight);
196 NSDrawThreePartImage(backgroundRect,
198 tabstripCenterImage_,
201 NSCompositeSourceOver,
205 // Draw the background to the right of the selected tab.
206 backgroundRect.origin.x = NSMaxX(tabRect);
207 backgroundRect.size.width = NSMaxX(cellFrame) - NSMaxX(tabRect);
208 NSDrawThreePartImage(backgroundRect,
210 tabstripCenterImage_,
213 NSCompositeSourceOver,
217 // Call the superclass method to trigger drawing of the tab labels.
218 [self drawInteriorWithFrame:cellFrame inView:controlView];
219 if ([[controlView window] firstResponder] == controlView)
220 [self drawFocusRect];
223 - (void)drawFocusRect {
224 gfx::ScopedNSGraphicsContextSaveGState scoped_state;
225 NSSetFocusRingStyle(NSFocusRingOnly);
226 [[NSColor keyboardFocusIndicatorColor] set];
227 NSFrameRect([self hitRectForSegment:keySegment_]);
230 // Return the hit rect (i.e., the visual bounds of the tab) for
231 // the given segment.
232 - (NSRect)hitRectForSegment:(NSInteger)segment {
233 CGFloat tabstripHeight = [tabCenterImage_ size].height;
234 DCHECK_GT(tabstripHeight, kTabHeight);
236 NSRect rect = NSMakeRect(0, tabstripHeight - kTabHeight,
237 [self widthForSegment:segment], kTabHeight);
238 for (NSInteger i = 0; i < segment; ++i) {
239 rect.origin.x += [self widthForSegment:i];
241 int xAdjust = segment == 0 ? kTabStripXPadding : 0;
242 rect.size.width = std::floor(
243 [self widthForSegment:segment] - kTabSpacing - xAdjust);
244 rect.origin.x = std::floor(rect.origin.x + kTabSpacing / 2 + xAdjust);
249 - (void)drawSegment:(NSInteger)segment
250 inFrame:(NSRect)frame
251 withView:(NSView*)controlView {
252 // Call the superclass to draw the label, adjusting the rectangle so that
253 // the label appears centered in the tab.
255 frame.origin.x += kTabStripXPadding / 2;
256 frame.size.width -= kTabStripXPadding;
258 frame.origin.y += kTabLabelTopPadding;
259 frame.size.height -= kTabLabelTopPadding;
260 [super drawSegment:segment inFrame:frame withView:controlView];
263 // Overrides the default tracking behavior to only respond to clicks inside the
264 // visual borders of the tab.
265 - (BOOL)startTrackingAt:(NSPoint)startPoint inView:(NSView *)controlView {
266 NSInteger segmentCount = [self segmentCount];
267 for (NSInteger i = 0; i < segmentCount; ++i) {
268 if (NSPointInRect(startPoint, [self hitRectForSegment:i]))
274 // Overrides the default cell height to take up the full height of the
275 // segmented control. Otherwise, clicks on the lower part of a tab will be
277 - (NSSize)cellSizeForBounds:(NSRect)aRect {
278 return NSMakeSize([super cellSizeForBounds:aRect].width,
279 [tabstripCenterImage_ size].height);
282 // Returns the minimum size required to display this cell.
283 // It should always be exactly as tall as the tabstrip background image.
285 return NSMakeSize([super cellSize].width,
286 [tabstripCenterImage_ size].height);
290 @implementation WebsiteSettingsBubbleController
292 - (CGFloat)defaultWindowWidth {
293 return kDefaultWindowWidth;
296 - (id)initWithParentWindow:(NSWindow*)parentWindow
297 websiteSettingsUIBridge:(WebsiteSettingsUIBridge*)bridge
298 webContents:(content::WebContents*)webContents
299 isInternalPage:(BOOL)isInternalPage {
300 DCHECK(parentWindow);
302 webContents_ = webContents;
304 // Use an arbitrary height; it will be changed in performLayout.
305 NSRect contentRect = NSMakeRect(0, 0, [self defaultWindowWidth], 1);
306 // Create an empty window into which content is placed.
307 base::scoped_nsobject<InfoBubbleWindow> window(
308 [[InfoBubbleWindow alloc] initWithContentRect:contentRect
309 styleMask:NSBorderlessWindowMask
310 backing:NSBackingStoreBuffered
313 if ((self = [super initWithWindow:window.get()
314 parentWindow:parentWindow
315 anchoredAt:NSZeroPoint])) {
316 [[self bubble] setArrowLocation:info_bubble::kTopLeft];
318 // Create the container view that uses flipped coordinates.
319 NSRect contentFrame = NSMakeRect(0, 0, [self defaultWindowWidth], 300);
321 [[FlippedView alloc] initWithFrame:contentFrame]);
323 // Replace the window's content.
324 [[[self window] contentView] setSubviews:
325 [NSArray arrayWithObject:contentView_.get()]];
328 [self initializeContentsForInternalPage];
330 [self initializeContents];
332 bridge_.reset(bridge);
333 bridge_->set_bubble_controller(self);
338 - (void)windowWillClose:(NSNotification*)notification {
339 if (presenter_.get())
340 presenter_->OnUIClosing();
341 [super windowWillClose:notification];
344 - (void)setPresenter:(WebsiteSettings*)presenter {
345 presenter_.reset(presenter);
348 // Create the subviews for the bubble for internal Chrome pages.
349 - (void)initializeContentsForInternalPage {
350 ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
352 NSPoint controlOrigin = NSMakePoint(
353 kInternalPageFramePadding,
354 kInternalPageFramePadding + info_bubble::kBubbleArrowHeight);
355 NSSize imageSize = NSMakeSize(kInternalPageImageSize,
356 kInternalPageImageSize);
357 NSImageView* imageView = [self addImageWithSize:imageSize
359 atPoint:controlOrigin];
360 [imageView setImage:rb.GetNativeImageNamed(IDR_PRODUCT_LOGO_26).ToNSImage()];
362 controlOrigin.x += NSWidth([imageView frame]) + kInternalPageImageSpacing;
363 base::string16 text = l10n_util::GetStringUTF16(IDS_PAGE_INFO_INTERNAL_PAGE);
364 NSTextField* textField = [self addText:text
365 withSize:[NSFont smallSystemFontSize]
368 atPoint:controlOrigin];
369 // Center the text vertically with the image.
370 NSRect textFrame = [textField frame];
371 textFrame.origin.y += (imageSize.height - NSHeight(textFrame)) / 2;
372 [textField setFrame:textFrame];
374 // Adjust the contentView to fit everything.
375 CGFloat maxY = std::max(NSMaxY([imageView frame]), NSMaxY(textFrame));
376 [contentView_ setFrame:NSMakeRect(
377 0, 0, [self defaultWindowWidth], maxY + kInternalPageFramePadding)];
379 [self sizeAndPositionWindow];
382 // Create the subviews for the website settings bubble.
383 - (void)initializeContents {
384 // Keeps track of the position that the next control should be drawn at.
385 NSPoint controlOrigin = NSMakePoint(
387 kFramePadding + info_bubble::kBubbleArrowHeight);
389 // Create a text field (empty for now) to show the site identity.
390 identityField_ = [self addText:base::string16()
391 withSize:[NSFont systemFontSize]
394 atPoint:controlOrigin];
396 NSHeight([identityField_ frame]) + kConnectionHeadlineSpacing;
398 // Create a text field to identity status (e.g. verified, not verified).
399 identityStatusField_ = [self addText:base::string16()
400 withSize:[NSFont smallSystemFontSize]
403 atPoint:controlOrigin];
405 // Create the tab view and its two tabs.
407 base::scoped_nsobject<WebsiteSettingsTabSegmentedCell> cell(
408 [[WebsiteSettingsTabSegmentedCell alloc] init]);
409 CGFloat tabstripHeight = [cell cellSize].height;
410 NSRect tabstripFrame = NSMakeRect(
411 0, 0, [self defaultWindowWidth], tabstripHeight);
412 segmentedControl_.reset(
413 [[NSSegmentedControl alloc] initWithFrame:tabstripFrame]);
414 [segmentedControl_ setCell:cell];
415 [segmentedControl_ setSegmentCount:WebsiteSettingsUI::NUM_TAB_IDS];
416 [segmentedControl_ setTarget:self];
417 [segmentedControl_ setAction:@selector(tabSelected:)];
418 [segmentedControl_ setAutoresizingMask:NSViewWidthSizable];
420 NSFont* smallSystemFont =
421 [NSFont systemFontOfSize:[NSFont smallSystemFontSize]];
422 NSDictionary* textAttributes =
423 [NSDictionary dictionaryWithObject:smallSystemFont
424 forKey:NSFontAttributeName];
426 // Create the "Permissions" tab.
427 NSString* label = l10n_util::GetNSString(
428 IDS_WEBSITE_SETTINGS_TAB_LABEL_PERMISSIONS);
429 [segmentedControl_ setLabel:label
430 forSegment:WebsiteSettingsUI::TAB_ID_PERMISSIONS];
431 NSSize textSize = [label sizeWithAttributes:textAttributes];
432 CGFloat tabWidth = textSize.width + 2 * kTabLabelXPadding;
433 [segmentedControl_ setWidth:tabWidth + kTabStripXPadding
434 forSegment:WebsiteSettingsUI::TAB_ID_PERMISSIONS];
436 // Create the "Connection" tab.
437 label = l10n_util::GetNSString(IDS_WEBSITE_SETTINGS_TAB_LABEL_CONNECTION);
438 textSize = [label sizeWithAttributes:textAttributes];
439 [segmentedControl_ setLabel:label
440 forSegment:WebsiteSettingsUI::TAB_ID_CONNECTION];
442 DCHECK_EQ([segmentedControl_ segmentCount], WebsiteSettingsUI::NUM_TAB_IDS);
444 // Make both tabs the width of the widest. The first segment has some
445 // additional padding that is not part of the tab, which is used for drawing
446 // the background of the tab strip.
447 tabWidth = std::max(tabWidth,
448 textSize.width + 2 * kTabLabelXPadding);
449 [segmentedControl_ setWidth:tabWidth + kTabStripXPadding
450 forSegment:WebsiteSettingsUI::TAB_ID_PERMISSIONS];
451 [segmentedControl_ setWidth:tabWidth
452 forSegment:WebsiteSettingsUI::TAB_ID_CONNECTION];
454 [segmentedControl_ setFont:smallSystemFont];
455 [contentView_ addSubview:segmentedControl_];
457 NSRect tabFrame = NSMakeRect(0, 0, [self defaultWindowWidth], 300);
458 tabView_.reset([[NSTabView alloc] initWithFrame:tabFrame]);
459 [tabView_ setTabViewType:NSNoTabsNoBorder];
460 [tabView_ setDrawsBackground:NO];
461 [tabView_ setControlSize:NSSmallControlSize];
462 [contentView_ addSubview:tabView_.get()];
464 permissionsTabContentView_ = [self addPermissionsTabToTabView:tabView_];
465 connectionTabContentView_ = [self addConnectionTabToTabView:tabView_];
466 [self setSelectedTab:WebsiteSettingsUI::TAB_ID_PERMISSIONS];
468 [self performLayout];
471 // Create the contents of the Permissions tab and add it to the given tab view.
472 // Returns a weak reference to the tab view item's view.
473 - (NSView*)addPermissionsTabToTabView:(NSTabView*)tabView {
474 base::scoped_nsobject<NSTabViewItem> item([[NSTabViewItem alloc] init]);
475 [tabView_ insertTabViewItem:item.get()
476 atIndex:WebsiteSettingsUI::TAB_ID_PERMISSIONS];
477 base::scoped_nsobject<NSView> contentView(
478 [[FlippedView alloc] initWithFrame:[tabView_ contentRect]]);
479 [contentView setAutoresizingMask:NSViewWidthSizable];
480 [item setView:contentView.get()];
482 // Initialize the two containers that hold the controls. The initial frames
483 // are arbitrary, and will be adjusted after the controls are laid out.
484 cookiesView_ = [[[FlippedView alloc]
485 initWithFrame:[tabView_ contentRect]] autorelease];
486 [cookiesView_ setAutoresizingMask:NSViewWidthSizable];
488 permissionsView_ = [[[FlippedView alloc]
489 initWithFrame:[tabView_ contentRect]] autorelease];
491 [contentView addSubview:cookiesView_];
492 [contentView addSubview:permissionsView_];
494 // Create the link button to view cookies and site data.
495 // Its position will be set in performLayout.
496 NSString* cookieButtonText = l10n_util::GetNSString(
497 IDS_WEBSITE_SETTINGS_SHOW_SITE_DATA);
498 cookiesButton_ = [self addLinkButtonWithText:cookieButtonText
500 [cookiesButton_ setTarget:self];
501 [cookiesButton_ setAction:@selector(showCookiesAndSiteData:)];
503 return contentView.get();
506 // Handler for the link button below the list of cookies.
507 - (void)showCookiesAndSiteData:(id)sender {
508 DCHECK(webContents_);
509 content::RecordAction(
510 base::UserMetricsAction("WebsiteSettings_CookiesDialogOpened"));
511 chrome::ShowCollectedCookiesDialog(webContents_);
514 // Handler for the link button to show certificate information.
515 - (void)showCertificateInfo:(id)sender {
516 DCHECK(certificateId_);
517 ShowCertificateViewerByID(webContents_, [self parentWindow], certificateId_);
520 // Handler for the link button to revoke user certificate decisions.
521 - (void)resetCertificateDecisions:(id)sender {
522 DCHECK(resetDecisionsButton_);
523 ChromeSSLHostStateDelegate* delegate =
524 presenter_->chrome_ssl_host_state_delegate();
526 delegate->RevokeUserDecisionsHard(presenter_->site_url().host());
530 // Handler for the link to show help information about the connection tab.
531 - (void)showHelpPage:(id)sender {
532 webContents_->OpenURL(content::OpenURLParams(
533 GURL(chrome::kPageInfoHelpCenterURL), content::Referrer(),
534 NEW_FOREGROUND_TAB, content::PAGE_TRANSITION_LINK, false));
537 // Create the contents of the Connection tab and add it to the given tab view.
538 // Returns a weak reference to the tab view item's view.
539 - (NSView*)addConnectionTabToTabView:(NSTabView*)tabView {
540 base::scoped_nsobject<NSTabViewItem> item([[NSTabViewItem alloc] init]);
541 base::scoped_nsobject<NSView> contentView(
542 [[FlippedView alloc] initWithFrame:[tabView_ contentRect]]);
543 [contentView setAutoresizingMask:NSViewWidthSizable];
545 // Place all the text and images at the same position. The positions will be
546 // adjusted in performLayout.
547 NSPoint textPosition = NSMakePoint(
548 kFramePadding + kConnectionImageSize + kConnectionImageSpacing,
550 NSPoint imagePosition = NSMakePoint(kFramePadding, kFramePadding);
551 NSSize imageSize = NSMakeSize(kConnectionImageSize, kConnectionImageSize);
553 identityStatusIcon_ = [self addImageWithSize:imageSize
555 atPoint:imagePosition];
556 identityStatusDescriptionField_ =
557 [self addText:base::string16()
558 withSize:[NSFont smallSystemFontSize]
560 toView:contentView.get()
561 atPoint:textPosition];
563 separatorAfterIdentity_ = [self addSeparatorToView:contentView];
564 [separatorAfterIdentity_ setAutoresizingMask:NSViewWidthSizable];
566 connectionStatusIcon_ = [self addImageWithSize:imageSize
568 atPoint:imagePosition];
569 connectionStatusDescriptionField_ =
570 [self addText:base::string16()
571 withSize:[NSFont smallSystemFontSize]
573 toView:contentView.get()
574 atPoint:textPosition];
575 certificateInfoButton_ = nil; // This will be created only if necessary.
576 resetDecisionsButton_ = nil; // This will be created only if necessary.
577 separatorAfterConnection_ = [self addSeparatorToView:contentView];
578 [separatorAfterConnection_ setAutoresizingMask:NSViewWidthSizable];
580 firstVisitIcon_ = [self addImageWithSize:imageSize
582 atPoint:imagePosition];
583 firstVisitHeaderField_ =
584 [self addText:l10n_util::GetStringUTF16(IDS_PAGE_INFO_SITE_INFO_TITLE)
585 withSize:[NSFont smallSystemFontSize]
587 toView:contentView.get()
588 atPoint:textPosition];
589 firstVisitDescriptionField_ =
590 [self addText:base::string16()
591 withSize:[NSFont smallSystemFontSize]
593 toView:contentView.get()
594 atPoint:textPosition];
596 separatorAfterFirstVisit_ = [self addSeparatorToView:contentView];
597 [separatorAfterFirstVisit_ setAutoresizingMask:NSViewWidthSizable];
599 NSString* helpButtonText = l10n_util::GetNSString(
600 IDS_PAGE_INFO_HELP_CENTER_LINK);
601 helpButton_ = [self addLinkButtonWithText:helpButtonText
603 [helpButton_ setTarget:self];
604 [helpButton_ setAction:@selector(showHelpPage:)];
606 [item setView:contentView.get()];
607 [tabView_ insertTabViewItem:item.get()
608 atIndex:WebsiteSettingsUI::TAB_ID_CONNECTION];
610 return contentView.get();
613 // Set the Y position of |view| to the given position, and return the position
614 // of its bottom edge.
615 - (CGFloat)setYPositionOfView:(NSView*)view to:(CGFloat)position {
616 NSRect frame = [view frame];
617 frame.origin.y = position;
618 [view setFrame:frame];
619 return position + NSHeight(frame);
622 - (void)setWidthOfView:(NSView*)view to:(CGFloat)width {
623 [view setFrameSize:NSMakeSize(width, NSHeight([view frame]))];
626 // Layout all of the controls in the window. This should be called whenever
627 // the content has changed.
628 - (void)performLayout {
629 // Make the content at least as wide as the permissions view.
630 CGFloat contentWidth = std::max([self defaultWindowWidth],
631 NSWidth([permissionsView_ frame]));
633 // Set the width of the content view now, so that all the text fields will
634 // be sized to fit before their heights and vertical positions are adjusted.
635 // The tab view will only resize the currently selected tab, so resize both
636 // tab content views manually.
637 [self setWidthOfView:contentView_ to:contentWidth];
638 [self setWidthOfView:permissionsTabContentView_ to:contentWidth];
639 [self setWidthOfView:connectionTabContentView_ to:contentWidth];
641 // Place the identity status immediately below the identity.
642 [self sizeTextFieldHeightToFit:identityField_];
643 [self sizeTextFieldHeightToFit:identityStatusField_];
644 CGFloat yPos = NSMaxY([identityField_ frame]) + kConnectionHeadlineSpacing;
645 yPos = [self setYPositionOfView:identityStatusField_ to:yPos];
647 // Lay out the Permissions tab.
649 yPos = [self setYPositionOfView:cookiesView_ to:kFramePadding];
651 // Put the link button for cookies and site data just below the cookie info.
652 NSRect cookiesButtonFrame = [cookiesButton_ frame];
653 cookiesButtonFrame.origin.y = yPos;
654 cookiesButtonFrame.origin.x = kFramePadding;
655 [cookiesButton_ setFrame:cookiesButtonFrame];
657 // Put the permission info just below the link button.
658 [self setYPositionOfView:permissionsView_
659 to:NSMaxY(cookiesButtonFrame) + kFramePadding];
661 // Lay out the Connection tab.
663 // Lay out the identity status section.
664 [self sizeTextFieldHeightToFit:identityStatusDescriptionField_];
665 yPos = std::max(NSMaxY([identityStatusDescriptionField_ frame]),
666 NSMaxY([identityStatusIcon_ frame]));
667 if (certificateInfoButton_) {
668 NSRect certificateButtonFrame = [certificateInfoButton_ frame];
669 certificateButtonFrame.origin.x = NSMinX(
670 [identityStatusDescriptionField_ frame]);
671 certificateButtonFrame.origin.y = yPos + kVerticalSpacing;
672 [certificateInfoButton_ setFrame:certificateButtonFrame];
673 yPos = NSMaxY(certificateButtonFrame);
675 if (resetDecisionsButton_) {
676 NSRect resetDecisionsButtonFrame = [resetDecisionsButton_ frame];
677 resetDecisionsButtonFrame.origin.x =
678 NSMinX([identityStatusDescriptionField_ frame]);
679 resetDecisionsButtonFrame.origin.y = yPos + kVerticalSpacing;
680 [resetDecisionsButton_ setFrame:resetDecisionsButtonFrame];
681 yPos = NSMaxY(resetDecisionsButtonFrame);
683 yPos = [self setYPositionOfView:separatorAfterIdentity_
684 to:yPos + kVerticalSpacing];
685 yPos += kVerticalSpacing;
687 // Lay out the connection status section.
688 [self sizeTextFieldHeightToFit:connectionStatusDescriptionField_];
689 [self setYPositionOfView:connectionStatusIcon_ to:yPos];
690 [self setYPositionOfView:connectionStatusDescriptionField_ to:yPos];
691 yPos = std::max(NSMaxY([connectionStatusDescriptionField_ frame]),
692 NSMaxY([connectionStatusIcon_ frame]));
693 yPos = [self setYPositionOfView:separatorAfterConnection_
694 to:yPos + kVerticalSpacing];
695 yPos += kVerticalSpacing;
697 // Lay out the last visit section.
698 [self setYPositionOfView:firstVisitIcon_ to:yPos];
699 [self sizeTextFieldHeightToFit:firstVisitHeaderField_];
700 yPos = [self setYPositionOfView:firstVisitHeaderField_ to:yPos];
701 yPos += kConnectionHeadlineSpacing;
702 [self sizeTextFieldHeightToFit:firstVisitDescriptionField_];
703 yPos = [self setYPositionOfView:firstVisitDescriptionField_ to:yPos];
704 yPos = [self setYPositionOfView:separatorAfterFirstVisit_
705 to:yPos + kVerticalSpacing];
706 yPos += kVerticalSpacing;
707 [self setYPositionOfView:helpButton_ to:yPos];
709 // Adjust the tab view size and place it below the identity status.
711 yPos = NSMaxY([identityStatusField_ frame]) + kTabStripTopSpacing;
712 yPos = [self setYPositionOfView:segmentedControl_ to:yPos];
714 CGFloat connectionTabHeight = NSMaxY([helpButton_ frame]) + kVerticalSpacing;
716 NSRect tabViewFrame = [tabView_ frame];
717 tabViewFrame.origin.y = yPos;
718 tabViewFrame.size.height =
719 std::max(connectionTabHeight, NSMaxY([permissionsView_ frame]));
720 tabViewFrame.size.width = contentWidth;
721 [tabView_ setFrame:tabViewFrame];
723 // Adjust the contentView to fit everything.
724 [contentView_ setFrame:NSMakeRect(
725 0, 0, NSWidth(tabViewFrame), NSMaxY(tabViewFrame))];
727 [self sizeAndPositionWindow];
730 // Adjust the size of the window to match the size of the content, and position
731 // the bubble anchor appropriately.
732 - (void)sizeAndPositionWindow {
733 NSRect windowFrame = [contentView_ frame];
734 windowFrame.size = [[[self window] contentView] convertSize:windowFrame.size
736 // Adjust the origin by the difference in height.
737 windowFrame.origin = [[self window] frame].origin;
738 windowFrame.origin.y -= NSHeight(windowFrame) -
739 NSHeight([[self window] frame]);
741 // Resize the window. Only animate if the window is visible, otherwise it
742 // could be "growing" while it's opening, looking awkward.
743 [[self window] setFrame:windowFrame
745 animate:[[self window] isVisible]];
747 // Adjust the anchor for the bubble.
748 NSPoint anchorPoint =
749 [self anchorPointForWindowWithHeight:NSHeight(windowFrame)
750 parentWindow:[self parentWindow]];
751 [self setAnchorPoint:anchorPoint];
754 // Takes in the bubble's height and the parent window, which should be a
755 // BrowserWindow, and gets the proper anchor point for the bubble. The returned
756 // point is in screen coordinates.
757 - (NSPoint)anchorPointForWindowWithHeight:(CGFloat)bubbleHeight
758 parentWindow:(NSWindow*)parent {
759 BrowserWindowController* controller = [parent windowController];
760 NSPoint origin = NSZeroPoint;
761 if ([controller isKindOfClass:[BrowserWindowController class]]) {
762 LocationBarViewMac* locationBar = [controller locationBarBridge];
764 NSPoint bubblePoint = locationBar->GetPageInfoBubblePoint();
765 origin = [parent convertBaseToScreen:bubblePoint];
771 // Sets properties on the given |field| to act as the title or description
772 // labels in the bubble.
773 - (void)configureTextFieldAsLabel:(NSTextField*)textField {
774 [textField setEditable:NO];
775 [textField setSelectable:YES];
776 [textField setDrawsBackground:NO];
777 [textField setBezeled:NO];
780 // Adjust the height of the given text field to match its text.
781 - (void)sizeTextFieldHeightToFit:(NSTextField*)textField {
782 NSRect frame = [textField frame];
784 [GTMUILocalizerAndLayoutTweaker sizeToFitFixedWidthTextField:
786 [textField setFrame:frame];
789 // Create a new text field and add it to the given array of subviews.
790 // The array will retain a reference to the object.
791 - (NSTextField*)addText:(const base::string16&)text
792 withSize:(CGFloat)fontSize
795 atPoint:(NSPoint)point {
796 // Size the text to take up the full available width, with some padding.
797 // The height is arbitrary as it will be adjusted later.
798 CGFloat width = NSWidth([view frame]) - point.x - kFramePadding;
799 NSRect frame = NSMakeRect(point.x, point.y, width, 100);
800 base::scoped_nsobject<NSTextField> textField(
801 [[NSTextField alloc] initWithFrame:frame]);
802 [self configureTextFieldAsLabel:textField.get()];
803 [textField setStringValue:base::SysUTF16ToNSString(text)];
804 NSFont* font = bold ? [NSFont boldSystemFontOfSize:fontSize]
805 : [NSFont systemFontOfSize:fontSize];
806 [textField setFont:font];
807 [self sizeTextFieldHeightToFit:textField];
808 [textField setAutoresizingMask:NSViewWidthSizable];
809 [view addSubview:textField.get()];
810 return textField.get();
813 // Add an image as a subview of the given view, placed at a pre-determined x
814 // position and the given y position. Return the new NSImageView.
815 - (NSImageView*)addImageWithSize:(NSSize)size
817 atPoint:(NSPoint)point {
818 NSRect frame = NSMakeRect(point.x, point.y, size.width, size.height);
819 base::scoped_nsobject<NSImageView> imageView(
820 [[NSImageView alloc] initWithFrame:frame]);
821 [imageView setImageFrameStyle:NSImageFrameNone];
822 [view addSubview:imageView.get()];
823 return imageView.get();
826 // Add a separator as a subview of the given view. Return the new view.
827 - (NSView*)addSeparatorToView:(NSView*)view {
828 // Take up almost the full width of the container's frame.
829 CGFloat width = NSWidth([view frame]) - 2 * kFramePadding;
831 // Use an arbitrary position; it will be adjusted in performLayout.
832 NSBox* spacer = [self horizontalSeparatorWithFrame:NSMakeRect(
833 kFramePadding, 0, width, 0)];
834 [view addSubview:spacer];
838 // Add a link button with the given text to |view|.
839 - (NSButton*)addLinkButtonWithText:(NSString*)text toView:(NSView*)view {
840 // Frame size is arbitrary; it will be adjusted by the layout tweaker.
841 NSRect frame = NSMakeRect(kFramePadding, 0, 100, 10);
842 base::scoped_nsobject<NSButton> button(
843 [[NSButton alloc] initWithFrame:frame]);
844 base::scoped_nsobject<HyperlinkButtonCell> cell(
845 [[HyperlinkButtonCell alloc] initTextCell:text]);
846 [cell setControlSize:NSSmallControlSize];
847 [button setCell:cell.get()];
848 [button setButtonType:NSMomentaryPushInButton];
849 [button setBezelStyle:NSRegularSquareBezelStyle];
850 [view addSubview:button.get()];
852 [GTMUILocalizerAndLayoutTweaker sizeToFitView:button.get()];
856 // Add a button with the given text to |view| setting the max size appropriately
857 // for the connection info section.
858 - (NSButton*)addButtonWithTextToConnectionSection:(NSString*)text
859 toView:(NSView*)view {
860 NSRect containerFrame = [view frame];
861 // Frame size is arbitrary; it will be adjusted by the layout tweaker.
862 NSRect frame = NSMakeRect(kFramePadding, 0, 100, 10);
863 base::scoped_nsobject<NSButton> button(
864 [[NSButton alloc] initWithFrame:frame]);
866 // Determine the largest possible size for this button. The size is the width
867 // of the connection section minus the padding on both sides minus the
868 // connection image size and spacing.
869 CGFloat maxTitleWidth = containerFrame.size.width - kFramePadding * 2 -
870 kConnectionImageSize - kConnectionImageSpacing;
872 base::scoped_nsobject<NSButtonCell> cell(
873 [[NSButtonCell alloc] initTextCell:text]);
874 [button setCell:cell.get()];
875 [GTMUILocalizerAndLayoutTweaker sizeToFitView:button.get()];
877 // Ensure the containing view is large enough to contain the button with its
878 // widest possible title.
879 NSRect buttonFrame = [button frame];
880 buttonFrame.size.width = maxTitleWidth;
882 [button setFrame:buttonFrame];
883 [button setButtonType:NSMomentaryPushInButton];
884 [button setBezelStyle:NSRegularSquareBezelStyle];
885 [view addSubview:button.get()];
890 // Add a pop-up button for |permissionInfo| to the given view.
891 - (NSPopUpButton*)addPopUpButtonForPermission:
892 (const WebsiteSettingsUI::PermissionInfo&)permissionInfo
894 atPoint:(NSPoint)point {
896 GURL url = webContents_ ? webContents_->GetURL() : GURL();
897 __block WebsiteSettingsBubbleController* weakSelf = self;
898 PermissionMenuModel::ChangeCallback callback =
899 base::BindBlock(^(const WebsiteSettingsUI::PermissionInfo& permission) {
900 [weakSelf onPermissionChanged:permission.type to:permission.setting];
902 base::scoped_nsobject<PermissionSelectorButton> button(
903 [[PermissionSelectorButton alloc] initWithPermissionInfo:permissionInfo
905 withCallback:callback]);
906 // Determine the largest possible size for this button.
907 CGFloat maxTitleWidth =
908 [button maxTitleWidthWithDefaultSetting:permissionInfo.default_setting];
910 // Ensure the containing view is large enough to contain the button with its
911 // widest possible title.
912 NSRect containerFrame = [view frame];
913 containerFrame.size.width = std::max(
914 NSWidth(containerFrame), point.x + maxTitleWidth + kFramePadding);
915 [view setFrame:containerFrame];
916 [view addSubview:button.get()];
920 // Called when the user changes the setting of a permission.
921 - (void)onPermissionChanged:(ContentSettingsType)permissionType
922 to:(ContentSetting)newSetting {
924 presenter_->OnSitePermissionChanged(permissionType, newSetting);
927 // Called when the user changes the selected segment in the segmented control.
928 - (void)tabSelected:(id)sender {
929 [tabView_ selectTabViewItemAtIndex:[segmentedControl_ selectedSegment]];
932 // Adds a new row to the UI listing the permissions. Returns the amount of
933 // vertical space that was taken up by the row.
934 - (NSPoint)addPermission:
935 (const WebsiteSettingsUI::PermissionInfo&)permissionInfo
937 atPoint:(NSPoint)point {
938 base::scoped_nsobject<NSImage> image(
939 [WebsiteSettingsUI::GetPermissionIcon(permissionInfo).ToNSImage()
941 NSImageView* imageView = [self addImageWithSize:[image size]
944 [imageView setImage:image];
945 point.x += kPermissionImageSize + kPermissionImageSpacing;
947 base::string16 labelText =
948 WebsiteSettingsUI::PermissionTypeToUIString(permissionInfo.type) +
949 base::ASCIIToUTF16(":");
951 NSTextField* label = [self addText:labelText
952 withSize:[NSFont smallSystemFontSize]
957 NSPoint popUpPosition = NSMakePoint(NSMaxX([label frame]), point.y);
958 NSPopUpButton* button = [self addPopUpButtonForPermission:permissionInfo
960 atPoint:popUpPosition];
962 // Adjust the vertical position of the button so that its title text is
963 // aligned with the label. Assumes that the text is the same size in both.
964 // Also adjust the horizontal position to remove excess space due to the
966 NSRect titleRect = [[button cell] titleRectForBounds:[button bounds]];
967 popUpPosition.x -= titleRect.origin.x - kPermissionPopUpXSpacing;
968 popUpPosition.y -= titleRect.origin.y;
969 [button setFrameOrigin:popUpPosition];
971 // Align the icon with the text.
972 [self alignPermissionIcon:imageView withTextField:label];
974 // Permissions specified by policy or an extension cannot be changed.
975 if (permissionInfo.source == content_settings::SETTING_SOURCE_EXTENSION ||
976 permissionInfo.source == content_settings::SETTING_SOURCE_POLICY) {
977 [button setEnabled:NO];
980 NSRect buttonFrame = [button frame];
981 return NSMakePoint(NSMaxX(buttonFrame), NSMaxY(buttonFrame));
984 // Align an image with a text field by vertically centering the image on
985 // the cap height of the first line of text.
986 - (void)alignPermissionIcon:(NSImageView*)imageView
987 withTextField:(NSTextField*)textField {
988 NSFont* font = [textField font];
990 // Calculate the offset from the top of the text field.
991 CGFloat capHeight = [font capHeight];
992 CGFloat offset = (kPermissionImageSize - capHeight) / 2 -
993 ([font ascender] - capHeight) - kPermissionImageYAdjust;
995 NSRect frame = [imageView frame];
996 frame.origin.y -= offset;
997 [imageView setFrame:frame];
1000 - (CGFloat)addCookieInfo:
1001 (const WebsiteSettingsUI::CookieInfo&)cookieInfo
1002 toView:(NSView*)view
1003 atPoint:(NSPoint)point {
1004 WebsiteSettingsUI::PermissionInfo info;
1005 info.type = CONTENT_SETTINGS_TYPE_COOKIES;
1006 info.setting = CONTENT_SETTING_ALLOW;
1007 NSImage* image = WebsiteSettingsUI::GetPermissionIcon(info).ToNSImage();
1008 NSImageView* imageView = [self addImageWithSize:[image size]
1011 [imageView setImage:image];
1012 point.x += kPermissionImageSize + kPermissionImageSpacing;
1014 base::string16 labelText = l10n_util::GetStringFUTF16(
1015 IDS_WEBSITE_SETTINGS_SITE_DATA_STATS_LINE,
1016 base::UTF8ToUTF16(cookieInfo.cookie_source),
1017 base::IntToString16(cookieInfo.allowed),
1018 base::IntToString16(cookieInfo.blocked));
1020 NSTextField* label = [self addText:labelText
1021 withSize:[NSFont smallSystemFontSize]
1026 // Align the icon with the text.
1027 [self alignPermissionIcon:imageView withTextField:label];
1029 return NSHeight([label frame]);
1032 // Set the content of the identity and identity status fields.
1033 - (void)setIdentityInfo:(const WebsiteSettingsUI::IdentityInfo&)identityInfo {
1034 [identityField_ setStringValue:
1035 base::SysUTF8ToNSString(identityInfo.site_identity)];
1036 [identityStatusField_ setStringValue:
1037 base::SysUTF16ToNSString(identityInfo.GetIdentityStatusText())];
1039 WebsiteSettings::SiteIdentityStatus status = identityInfo.identity_status;
1040 if (status == WebsiteSettings::SITE_IDENTITY_STATUS_CERT ||
1041 status == WebsiteSettings::SITE_IDENTITY_STATUS_EV_CERT) {
1042 [identityStatusField_ setTextColor:IdentityVerifiedTextColor()];
1044 // If there is a certificate, add a button for viewing the certificate info.
1045 certificateId_ = identityInfo.cert_id;
1046 if (certificateId_) {
1047 if (!certificateInfoButton_) {
1048 NSString* text = l10n_util::GetNSString(IDS_PAGEINFO_CERT_INFO_BUTTON);
1049 certificateInfoButton_ = [self addLinkButtonWithText:text
1050 toView:connectionTabContentView_];
1052 [certificateInfoButton_ setTarget:self];
1053 [certificateInfoButton_ setAction:@selector(showCertificateInfo:)];
1056 // Check if a security decision has been made, and if so, add a button to
1057 // allow the user to retract their decision.
1058 if (identityInfo.show_ssl_decision_revoke_button) {
1059 NSString* text = l10n_util::GetNSString(
1060 IDS_PAGEINFO_RESET_INVALID_CERTIFICATE_DECISIONS_BUTTON);
1061 resetDecisionsButton_ =
1062 [self addButtonWithTextToConnectionSection:text
1063 toView:connectionTabContentView_];
1064 [resetDecisionsButton_ setTarget:self];
1065 [resetDecisionsButton_ setAction:@selector(resetCertificateDecisions:)];
1068 certificateInfoButton_ = nil;
1071 [identityStatusIcon_ setImage:WebsiteSettingsUI::GetIdentityIcon(
1072 identityInfo.identity_status).ToNSImage()];
1073 [identityStatusDescriptionField_ setStringValue:
1074 base::SysUTF8ToNSString(identityInfo.identity_status_description)];
1076 [connectionStatusIcon_ setImage:WebsiteSettingsUI::GetConnectionIcon(
1077 identityInfo.connection_status).ToNSImage()];
1078 [connectionStatusDescriptionField_ setStringValue:
1079 base::SysUTF8ToNSString(identityInfo.connection_status_description)];
1081 [self performLayout];
1084 - (void)setCookieInfo:(const CookieInfoList&)cookieInfoList {
1085 // The contents of the permissions view can cause the whole window to get
1086 // bigger, but currently permissions are always set before cookie info.
1087 // Check to make sure that's still the case.
1088 DCHECK_GT([[permissionsView_ subviews] count], 0U);
1090 [cookiesView_ setSubviews:[NSArray array]];
1091 NSPoint controlOrigin = NSMakePoint(kFramePadding, 0);
1093 base::string16 sectionTitle = l10n_util::GetStringUTF16(
1094 IDS_WEBSITE_SETTINGS_TITLE_SITE_DATA);
1095 NSTextField* header = [self addText:sectionTitle
1096 withSize:[NSFont smallSystemFontSize]
1099 atPoint:controlOrigin];
1100 controlOrigin.y += NSHeight([header frame]) + kPermissionsHeadlineSpacing;
1102 for (CookieInfoList::const_iterator it = cookieInfoList.begin();
1103 it != cookieInfoList.end();
1105 controlOrigin.y += kPermissionsTabSpacing;
1106 CGFloat rowHeight = [self addCookieInfo:*it
1108 atPoint:controlOrigin];
1109 controlOrigin.y += rowHeight;
1112 controlOrigin.y += kPermissionsTabSpacing;
1113 [cookiesView_ setFrameSize:
1114 NSMakeSize(NSWidth([cookiesView_ frame]), controlOrigin.y)];
1116 [self performLayout];
1119 - (void)setPermissionInfo:(const PermissionInfoList&)permissionInfoList {
1120 [permissionsView_ setSubviews:[NSArray array]];
1121 NSPoint controlOrigin = NSMakePoint(kFramePadding, 0);
1123 base::string16 sectionTitle = l10n_util::GetStringUTF16(
1124 IDS_WEBSITE_SETTINGS_TITLE_SITE_PERMISSIONS);
1125 NSTextField* header = [self addText:sectionTitle
1126 withSize:[NSFont smallSystemFontSize]
1128 toView:permissionsView_
1129 atPoint:controlOrigin];
1130 [self sizeTextFieldHeightToFit:header];
1131 controlOrigin.y += NSHeight([header frame]) + kPermissionsHeadlineSpacing;
1133 for (PermissionInfoList::const_iterator permission =
1134 permissionInfoList.begin();
1135 permission != permissionInfoList.end();
1137 controlOrigin.y += kPermissionsTabSpacing;
1138 NSPoint rowBottomRight = [self addPermission:*permission
1139 toView:permissionsView_
1140 atPoint:controlOrigin];
1141 controlOrigin.y = rowBottomRight.y;
1143 controlOrigin.y += kFramePadding;
1144 [permissionsView_ setFrameSize:
1145 NSMakeSize(NSWidth([permissionsView_ frame]), controlOrigin.y)];
1146 [self performLayout];
1149 - (void)setFirstVisit:(const base::string16&)firstVisit {
1150 [firstVisitIcon_ setImage:
1151 WebsiteSettingsUI::GetFirstVisitIcon(firstVisit).ToNSImage()];
1152 [firstVisitDescriptionField_ setStringValue:
1153 base::SysUTF16ToNSString(firstVisit)];
1154 [self performLayout];
1157 - (void)setSelectedTab:(WebsiteSettingsUI::TabId)tabId {
1158 NSInteger index = static_cast<NSInteger>(tabId);
1159 [segmentedControl_ setSelectedSegment:index];
1160 [tabView_ selectTabViewItemAtIndex:index];
1165 WebsiteSettingsUIBridge::WebsiteSettingsUIBridge()
1166 : bubble_controller_(nil) {
1169 WebsiteSettingsUIBridge::~WebsiteSettingsUIBridge() {
1172 void WebsiteSettingsUIBridge::set_bubble_controller(
1173 WebsiteSettingsBubbleController* controller) {
1174 bubble_controller_ = controller;
1177 void WebsiteSettingsUIBridge::Show(gfx::NativeWindow parent,
1179 content::WebContents* web_contents,
1181 const content::SSLStatus& ssl) {
1182 bool is_internal_page = InternalChromePage(url);
1184 // Create the bridge. This will be owned by the bubble controller.
1185 WebsiteSettingsUIBridge* bridge = new WebsiteSettingsUIBridge();
1187 // Create the bubble controller. It will dealloc itself when it closes.
1188 WebsiteSettingsBubbleController* bubble_controller =
1189 [[WebsiteSettingsBubbleController alloc]
1190 initWithParentWindow:parent
1191 websiteSettingsUIBridge:bridge
1192 webContents:web_contents
1193 isInternalPage:is_internal_page];
1195 if (!is_internal_page) {
1196 // Initialize the presenter, which holds the model and controls the UI.
1197 // This is also owned by the bubble controller.
1198 WebsiteSettings* presenter = new WebsiteSettings(
1201 TabSpecificContentSettings::FromWebContents(web_contents),
1202 InfoBarService::FromWebContents(web_contents),
1205 content::CertStore::GetInstance());
1206 [bubble_controller setPresenter:presenter];
1209 [bubble_controller showWindow:nil];
1212 void WebsiteSettingsUIBridge::SetIdentityInfo(
1213 const WebsiteSettingsUI::IdentityInfo& identity_info) {
1214 [bubble_controller_ setIdentityInfo:identity_info];
1217 void WebsiteSettingsUIBridge::SetCookieInfo(
1218 const CookieInfoList& cookie_info_list) {
1219 [bubble_controller_ setCookieInfo:cookie_info_list];
1222 void WebsiteSettingsUIBridge::SetPermissionInfo(
1223 const PermissionInfoList& permission_info_list) {
1224 [bubble_controller_ setPermissionInfo:permission_info_list];
1227 void WebsiteSettingsUIBridge::SetFirstVisit(const base::string16& first_visit) {
1228 [bubble_controller_ setFirstVisit:first_visit];
1231 void WebsiteSettingsUIBridge::SetSelectedTab(TabId tab_id) {
1232 [bubble_controller_ setSelectedTab:tab_id];