1 // Copyright (c) 2012 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_bubble_controller.h"
9 #import <AppKit/AppKit.h>
11 #include "base/strings/string_number_conversions.h"
12 #include "base/strings/sys_string_conversions.h"
13 #import "chrome/browser/certificate_viewer.h"
14 #include "chrome/browser/infobars/infobar_service.h"
15 #import "chrome/browser/ui/browser_dialogs.h"
16 #import "chrome/browser/ui/cocoa/browser_window_controller.h"
17 #import "chrome/browser/ui/cocoa/info_bubble_view.h"
18 #import "chrome/browser/ui/cocoa/info_bubble_window.h"
19 #import "chrome/browser/ui/cocoa/location_bar/location_bar_view_mac.h"
20 #include "chrome/browser/ui/website_settings/website_settings_utils.h"
21 #include "chrome/common/url_constants.h"
22 #include "content/public/browser/cert_store.h"
23 #include "content/public/browser/page_navigator.h"
24 #include "content/public/browser/user_metrics.h"
25 #include "content/public/browser/web_contents.h"
26 #include "grit/chromium_strings.h"
27 #include "grit/generated_resources.h"
28 #include "grit/theme_resources.h"
29 #include "grit/ui_resources.h"
30 #import "third_party/google_toolbox_for_mac/src/AppKit/GTMUILocalizerAndLayoutTweaker.h"
31 #import "ui/base/cocoa/controls/hyperlink_button_cell.h"
32 #import "ui/base/cocoa/flipped_view.h"
33 #include "ui/base/l10n/l10n_util.h"
34 #include "ui/base/resource/resource_bundle.h"
35 #include "ui/gfx/scoped_ns_graphics_context_save_gstate_mac.h"
39 // The default width of the window, in view coordinates. It may be larger to
41 const CGFloat kDefaultWindowWidth = 310;
43 // Spacing in between sections.
44 const CGFloat kVerticalSpacing = 10;
46 // Padding between the window frame and content.
47 const CGFloat kFramePadding = 20;
49 // Padding between the window frame and content for the internal page bubble.
50 const CGFloat kInternalPageFramePadding = 10;
52 // Spacing between the headlines and description text on the Connection tab.
53 const CGFloat kConnectionHeadlineSpacing = 2;
55 // Spacing between images on the Connection tab and the text.
56 const CGFloat kConnectionImageSpacing = 10;
58 // Spacing between the image and text for internal pages.
59 const CGFloat kInternalPageImageSpacing = 10;
61 // Square size of the images on the Connections tab.
62 const CGFloat kConnectionImageSize = 30;
64 // Square size of the image that is shown for internal pages.
65 const CGFloat kInternalPageImageSize = 26;
67 // Square size of the permission images.
68 const CGFloat kPermissionImageSize = 19;
70 // Vertical adjustment for the permission images.
71 // They have an extra pixel of padding on the bottom edge.
72 const CGFloat kPermissionImageYAdjust = 1;
74 // Spacing between a permission image and the text.
75 const CGFloat kPermissionImageSpacing = 3;
77 // The spacing between individual items in the Permissions tab.
78 const CGFloat kPermissionsTabSpacing = 12;
80 // Extra spacing after a headline on the Permissions tab.
81 const CGFloat kPermissionsHeadlineSpacing = 2;
83 // The amount of horizontal space between a permission label and the popup.
84 const CGFloat kPermissionPopUpXSpacing = 3;
86 // The amount of horizontal space between the permission popup title and the
88 const CGFloat kPermissionButtonTitleRightPadding = 4;
90 // The extra space to the left of the first tab in the tab strip.
91 const CGFloat kTabStripXPadding = kFramePadding;
93 // The amount of space between the visual borders of adjacent tabs.
94 const CGFloat kTabSpacing = 4;
96 // The amount of space above the tab strip.
97 const CGFloat kTabStripTopSpacing = 14;
99 // The height of the clickable area of the tab.
100 const CGFloat kTabHeight = 28;
102 // The amount of space above tab labels.
103 const CGFloat kTabLabelTopPadding = 6;
105 // The amount of padding to leave on either side of the tab label.
106 const CGFloat kTabLabelXPadding = 12;
108 // Return the text color to use for the indentity status when the site's
109 // identity has been verified.
110 NSColor* IdentityVerifiedTextColor() {
111 // RGB components are specified using integer RGB [0-255] values for easy
112 // comparison to other platforms.
113 return [NSColor colorWithCalibratedRed:0x07/255.0
121 @interface WebsiteSettingsTabSegmentedCell : NSSegmentedCell {
123 base::scoped_nsobject<NSImage> tabstripCenterImage_;
124 base::scoped_nsobject<NSImage> tabstripLeftImage_;
125 base::scoped_nsobject<NSImage> tabstripRightImage_;
127 base::scoped_nsobject<NSImage> tabCenterImage_;
128 base::scoped_nsobject<NSImage> tabLeftImage_;
129 base::scoped_nsobject<NSImage> tabRightImage_;
131 // Key track of the index of segment which has keyboard focus. This is not
132 // the same as the currently selected segment.
133 NSInteger keySegment_;
137 @implementation WebsiteSettingsTabSegmentedCell
139 if ((self = [super init])) {
140 ResourceBundle& rb = ResourceBundle::GetSharedInstance();
141 tabstripCenterImage_.reset(rb.GetNativeImageNamed(
142 IDR_WEBSITE_SETTINGS_TABSTRIP_CENTER).CopyNSImage());
143 tabstripLeftImage_.reset(rb.GetNativeImageNamed(
144 IDR_WEBSITE_SETTINGS_TABSTRIP_LEFT).CopyNSImage());
145 tabstripRightImage_.reset(rb.GetNativeImageNamed(
146 IDR_WEBSITE_SETTINGS_TABSTRIP_RIGHT).CopyNSImage());
148 tabCenterImage_.reset(
149 rb.GetNativeImageNamed(IDR_WEBSITE_SETTINGS_TAB_CENTER2).CopyNSImage());
151 rb.GetNativeImageNamed(IDR_WEBSITE_SETTINGS_TAB_LEFT2).CopyNSImage());
152 tabRightImage_.reset(
153 rb.GetNativeImageNamed(IDR_WEBSITE_SETTINGS_TAB_RIGHT2).CopyNSImage());
158 // Called when keyboard focus in the segmented control is moved forward.
159 - (void)makeNextSegmentKey {
160 [super makeNextSegmentKey];
161 keySegment_ = (keySegment_ + 1) % [self segmentCount];
164 // Called when keyboard focus in the segmented control is moved backwards.
165 - (void)makePreviousSegmentKey {
166 [super makePreviousSegmentKey];
167 if (--keySegment_ < 0)
168 keySegment_ += [self segmentCount];
171 - (void)setSelectedSegment:(NSInteger)selectedSegment {
172 keySegment_ = selectedSegment;
173 [super setSelectedSegment:selectedSegment];
176 - (void)drawWithFrame:(NSRect)cellFrame inView:(NSView*)controlView {
177 CGFloat tabstripHeight = [tabCenterImage_ size].height;
179 // Draw the tab for the selected segment.
180 NSRect tabRect = [self hitRectForSegment:[self selectedSegment]];
181 tabRect.origin.y = 0;
182 tabRect.size.height = tabstripHeight;
184 NSDrawThreePartImage(tabRect,
189 NSCompositeSourceOver,
193 // Draw the background to the left of the selected tab.
194 NSRect backgroundRect = NSMakeRect(0, 0, NSMinX(tabRect), tabstripHeight);
195 NSDrawThreePartImage(backgroundRect,
197 tabstripCenterImage_,
200 NSCompositeSourceOver,
204 // Draw the background to the right of the selected tab.
205 backgroundRect.origin.x = NSMaxX(tabRect);
206 backgroundRect.size.width = NSMaxX(cellFrame) - NSMaxX(tabRect);
207 NSDrawThreePartImage(backgroundRect,
209 tabstripCenterImage_,
212 NSCompositeSourceOver,
216 // Call the superclass method to trigger drawing of the tab labels.
217 [self drawInteriorWithFrame:cellFrame inView:controlView];
218 if ([[controlView window] firstResponder] == controlView)
219 [self drawFocusRect];
222 - (void)drawFocusRect {
223 gfx::ScopedNSGraphicsContextSaveGState scoped_state;
224 NSSetFocusRingStyle(NSFocusRingOnly);
225 [[NSColor keyboardFocusIndicatorColor] set];
226 NSFrameRect([self hitRectForSegment:keySegment_]);
229 // Return the hit rect (i.e., the visual bounds of the tab) for
230 // the given segment.
231 - (NSRect)hitRectForSegment:(NSInteger)segment {
232 CGFloat tabstripHeight = [tabCenterImage_ size].height;
233 DCHECK_GT(tabstripHeight, kTabHeight);
235 NSRect rect = NSMakeRect(0, tabstripHeight - kTabHeight,
236 [self widthForSegment:segment], kTabHeight);
237 for (NSInteger i = 0; i < segment; ++i) {
238 rect.origin.x += [self widthForSegment:i];
240 int xAdjust = segment == 0 ? kTabStripXPadding : 0;
241 rect.size.width = std::floor(
242 [self widthForSegment:segment] - kTabSpacing - xAdjust);
243 rect.origin.x = std::floor(rect.origin.x + kTabSpacing / 2 + xAdjust);
248 - (void)drawSegment:(NSInteger)segment
249 inFrame:(NSRect)frame
250 withView:(NSView*)controlView {
251 // Call the superclass to draw the label, adjusting the rectangle so that
252 // the label appears centered in the tab.
254 frame.origin.x += kTabStripXPadding / 2;
255 frame.size.width -= kTabStripXPadding;
257 frame.origin.y += kTabLabelTopPadding;
258 frame.size.height -= kTabLabelTopPadding;
259 [super drawSegment:segment inFrame:frame withView:controlView];
262 // Overrides the default tracking behavior to only respond to clicks inside the
263 // visual borders of the tab.
264 - (BOOL)startTrackingAt:(NSPoint)startPoint inView:(NSView *)controlView {
265 NSInteger segmentCount = [self segmentCount];
266 for (NSInteger i = 0; i < segmentCount; ++i) {
267 if (NSPointInRect(startPoint, [self hitRectForSegment:i]))
273 // Overrides the default cell height to take up the full height of the
274 // segmented control. Otherwise, clicks on the lower part of a tab will be
276 - (NSSize)cellSizeForBounds:(NSRect)aRect {
277 return NSMakeSize([super cellSizeForBounds:aRect].width,
278 [tabstripCenterImage_ size].height);
281 // Returns the minimum size required to display this cell.
282 // It should always be exactly as tall as the tabstrip background image.
284 return NSMakeSize([super cellSize].width,
285 [tabstripCenterImage_ size].height);
289 @implementation WebsiteSettingsBubbleController
291 - (CGFloat)defaultWindowWidth {
292 return kDefaultWindowWidth;
295 - (id)initWithParentWindow:(NSWindow*)parentWindow
296 websiteSettingsUIBridge:(WebsiteSettingsUIBridge*)bridge
297 webContents:(content::WebContents*)webContents
298 isInternalPage:(BOOL)isInternalPage {
299 DCHECK(parentWindow);
301 webContents_ = webContents;
303 // Use an arbitrary height; it will be changed in performLayout.
304 NSRect contentRect = NSMakeRect(0, 0, [self defaultWindowWidth], 1);
305 // Create an empty window into which content is placed.
306 base::scoped_nsobject<InfoBubbleWindow> window(
307 [[InfoBubbleWindow alloc] initWithContentRect:contentRect
308 styleMask:NSBorderlessWindowMask
309 backing:NSBackingStoreBuffered
312 if ((self = [super initWithWindow:window.get()
313 parentWindow:parentWindow
314 anchoredAt:NSZeroPoint])) {
315 [[self bubble] setArrowLocation:info_bubble::kTopLeft];
317 // Create the container view that uses flipped coordinates.
318 NSRect contentFrame = NSMakeRect(0, 0, [self defaultWindowWidth], 300);
320 [[FlippedView alloc] initWithFrame:contentFrame]);
322 // Replace the window's content.
323 [[[self window] contentView] setSubviews:
324 [NSArray arrayWithObject:contentView_.get()]];
327 [self initializeContentsForInternalPage];
329 [self initializeContents];
331 bridge_.reset(bridge);
332 bridge_->set_bubble_controller(self);
337 - (void)windowWillClose:(NSNotification*)notification {
338 if (presenter_.get())
339 presenter_->OnUIClosing();
340 [super windowWillClose:notification];
343 - (void)setPresenter:(WebsiteSettings*)presenter {
344 presenter_.reset(presenter);
347 // Create the subviews for the bubble for internal Chrome pages.
348 - (void)initializeContentsForInternalPage {
349 ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
351 NSPoint controlOrigin = NSMakePoint(
352 kInternalPageFramePadding,
353 kInternalPageFramePadding + info_bubble::kBubbleArrowHeight);
354 NSSize imageSize = NSMakeSize(kInternalPageImageSize,
355 kInternalPageImageSize);
356 NSImageView* imageView = [self addImageWithSize:imageSize
358 atPoint:controlOrigin];
359 [imageView setImage:rb.GetNativeImageNamed(IDR_PRODUCT_LOGO_26).ToNSImage()];
361 controlOrigin.x += NSWidth([imageView frame]) + kInternalPageImageSpacing;
362 base::string16 text = l10n_util::GetStringUTF16(IDS_PAGE_INFO_INTERNAL_PAGE);
363 NSTextField* textField = [self addText:text
364 withSize:[NSFont smallSystemFontSize]
367 atPoint:controlOrigin];
368 // Center the text vertically with the image.
369 NSRect textFrame = [textField frame];
370 textFrame.origin.y += (imageSize.height - NSHeight(textFrame)) / 2;
371 [textField setFrame:textFrame];
373 // Adjust the contentView to fit everything.
374 CGFloat maxY = std::max(NSMaxY([imageView frame]), NSMaxY(textFrame));
375 [contentView_ setFrame:NSMakeRect(
376 0, 0, [self defaultWindowWidth], maxY + kInternalPageFramePadding)];
378 [self sizeAndPositionWindow];
381 // Create the subviews for the website settings bubble.
382 - (void)initializeContents {
383 // Keeps track of the position that the next control should be drawn at.
384 NSPoint controlOrigin = NSMakePoint(
386 kFramePadding + info_bubble::kBubbleArrowHeight);
388 // Create a text field (empty for now) to show the site identity.
389 identityField_ = [self addText:base::string16()
390 withSize:[NSFont systemFontSize]
393 atPoint:controlOrigin];
395 NSHeight([identityField_ frame]) + kConnectionHeadlineSpacing;
397 // Create a text field to identity status (e.g. verified, not verified).
398 identityStatusField_ = [self addText:base::string16()
399 withSize:[NSFont smallSystemFontSize]
402 atPoint:controlOrigin];
404 // Create the tab view and its two tabs.
406 base::scoped_nsobject<WebsiteSettingsTabSegmentedCell> cell(
407 [[WebsiteSettingsTabSegmentedCell alloc] init]);
408 CGFloat tabstripHeight = [cell cellSize].height;
409 NSRect tabstripFrame = NSMakeRect(
410 0, 0, [self defaultWindowWidth], tabstripHeight);
411 segmentedControl_.reset(
412 [[NSSegmentedControl alloc] initWithFrame:tabstripFrame]);
413 [segmentedControl_ setCell:cell];
414 [segmentedControl_ setSegmentCount:WebsiteSettingsUI::NUM_TAB_IDS];
415 [segmentedControl_ setTarget:self];
416 [segmentedControl_ setAction:@selector(tabSelected:)];
417 [segmentedControl_ setAutoresizingMask:NSViewWidthSizable];
419 NSFont* smallSystemFont =
420 [NSFont systemFontOfSize:[NSFont smallSystemFontSize]];
421 NSDictionary* textAttributes =
422 [NSDictionary dictionaryWithObject:smallSystemFont
423 forKey:NSFontAttributeName];
425 // Create the "Permissions" tab.
426 NSString* label = l10n_util::GetNSString(
427 IDS_WEBSITE_SETTINGS_TAB_LABEL_PERMISSIONS);
428 [segmentedControl_ setLabel:label
429 forSegment:WebsiteSettingsUI::TAB_ID_PERMISSIONS];
430 NSSize textSize = [label sizeWithAttributes:textAttributes];
431 CGFloat tabWidth = textSize.width + 2 * kTabLabelXPadding;
432 [segmentedControl_ setWidth:tabWidth + kTabStripXPadding
433 forSegment:WebsiteSettingsUI::TAB_ID_PERMISSIONS];
435 // Create the "Connection" tab.
436 label = l10n_util::GetNSString(IDS_WEBSITE_SETTINGS_TAB_LABEL_CONNECTION);
437 textSize = [label sizeWithAttributes:textAttributes];
438 [segmentedControl_ setLabel:label
439 forSegment:WebsiteSettingsUI::TAB_ID_CONNECTION];
441 DCHECK_EQ([segmentedControl_ segmentCount], WebsiteSettingsUI::NUM_TAB_IDS);
443 // Make both tabs the width of the widest. The first segment has some
444 // additional padding that is not part of the tab, which is used for drawing
445 // the background of the tab strip.
446 tabWidth = std::max(tabWidth,
447 textSize.width + 2 * kTabLabelXPadding);
448 [segmentedControl_ setWidth:tabWidth + kTabStripXPadding
449 forSegment:WebsiteSettingsUI::TAB_ID_PERMISSIONS];
450 [segmentedControl_ setWidth:tabWidth
451 forSegment:WebsiteSettingsUI::TAB_ID_CONNECTION];
453 [segmentedControl_ setFont:smallSystemFont];
454 [contentView_ addSubview:segmentedControl_];
456 NSRect tabFrame = NSMakeRect(0, 0, [self defaultWindowWidth], 300);
457 tabView_.reset([[NSTabView alloc] initWithFrame:tabFrame]);
458 [tabView_ setTabViewType:NSNoTabsNoBorder];
459 [tabView_ setDrawsBackground:NO];
460 [tabView_ setControlSize:NSSmallControlSize];
461 [contentView_ addSubview:tabView_.get()];
463 permissionsTabContentView_ = [self addPermissionsTabToTabView:tabView_];
464 connectionTabContentView_ = [self addConnectionTabToTabView:tabView_];
465 [self setSelectedTab:WebsiteSettingsUI::TAB_ID_PERMISSIONS];
467 [self performLayout];
470 // Create the contents of the Permissions tab and add it to the given tab view.
471 // Returns a weak reference to the tab view item's view.
472 - (NSView*)addPermissionsTabToTabView:(NSTabView*)tabView {
473 base::scoped_nsobject<NSTabViewItem> item([[NSTabViewItem alloc] init]);
474 [tabView_ insertTabViewItem:item.get()
475 atIndex:WebsiteSettingsUI::TAB_ID_PERMISSIONS];
476 base::scoped_nsobject<NSView> contentView(
477 [[FlippedView alloc] initWithFrame:[tabView_ contentRect]]);
478 [contentView setAutoresizingMask:NSViewWidthSizable];
479 [item setView:contentView.get()];
481 // Initialize the two containers that hold the controls. The initial frames
482 // are arbitrary, and will be adjusted after the controls are laid out.
483 cookiesView_ = [[[FlippedView alloc]
484 initWithFrame:[tabView_ contentRect]] autorelease];
485 [cookiesView_ setAutoresizingMask:NSViewWidthSizable];
487 permissionsView_ = [[[FlippedView alloc]
488 initWithFrame:[tabView_ contentRect]] autorelease];
490 [contentView addSubview:cookiesView_];
491 [contentView addSubview:permissionsView_];
493 // Create the link button to view cookies and site data.
494 // Its position will be set in performLayout.
495 NSString* cookieButtonText = l10n_util::GetNSString(
496 IDS_WEBSITE_SETTINGS_SHOW_SITE_DATA);
497 cookiesButton_ = [self addLinkButtonWithText:cookieButtonText
499 [cookiesButton_ setTarget:self];
500 [cookiesButton_ setAction:@selector(showCookiesAndSiteData:)];
502 return contentView.get();
505 // Handler for the link button below the list of cookies.
506 - (void)showCookiesAndSiteData:(id)sender {
507 DCHECK(webContents_);
508 content::RecordAction(
509 base::UserMetricsAction("WebsiteSettings_CookiesDialogOpened"));
510 chrome::ShowCollectedCookiesDialog(webContents_);
513 // Handler for the link button to show certificate information.
514 - (void)showCertificateInfo:(id)sender {
515 DCHECK(certificateId_);
516 ShowCertificateViewerByID(webContents_, [self parentWindow], certificateId_);
519 // Handler for the link to show help information about the connection tab.
520 - (void)showHelpPage:(id)sender {
521 webContents_->OpenURL(content::OpenURLParams(
522 GURL(chrome::kPageInfoHelpCenterURL), content::Referrer(),
523 NEW_FOREGROUND_TAB, content::PAGE_TRANSITION_LINK, false));
526 // Create the contents of the Connection tab and add it to the given tab view.
527 // Returns a weak reference to the tab view item's view.
528 - (NSView*)addConnectionTabToTabView:(NSTabView*)tabView {
529 base::scoped_nsobject<NSTabViewItem> item([[NSTabViewItem alloc] init]);
530 base::scoped_nsobject<NSView> contentView(
531 [[FlippedView alloc] initWithFrame:[tabView_ contentRect]]);
532 [contentView setAutoresizingMask:NSViewWidthSizable];
534 // Place all the text and images at the same position. The positions will be
535 // adjusted in performLayout.
536 NSPoint textPosition = NSMakePoint(
537 kFramePadding + kConnectionImageSize + kConnectionImageSpacing,
539 NSPoint imagePosition = NSMakePoint(kFramePadding, kFramePadding);
540 NSSize imageSize = NSMakeSize(kConnectionImageSize, kConnectionImageSize);
542 identityStatusIcon_ = [self addImageWithSize:imageSize
544 atPoint:imagePosition];
545 identityStatusDescriptionField_ =
546 [self addText:base::string16()
547 withSize:[NSFont smallSystemFontSize]
549 toView:contentView.get()
550 atPoint:textPosition];
552 separatorAfterIdentity_ = [self addSeparatorToView:contentView];
553 [separatorAfterIdentity_ setAutoresizingMask:NSViewWidthSizable];
555 connectionStatusIcon_ = [self addImageWithSize:imageSize
557 atPoint:imagePosition];
558 connectionStatusDescriptionField_ =
559 [self addText:base::string16()
560 withSize:[NSFont smallSystemFontSize]
562 toView:contentView.get()
563 atPoint:textPosition];
564 certificateInfoButton_ = nil; // This will be created only if necessary.
565 separatorAfterConnection_ = [self addSeparatorToView:contentView];
566 [separatorAfterConnection_ setAutoresizingMask:NSViewWidthSizable];
568 firstVisitIcon_ = [self addImageWithSize:imageSize
570 atPoint:imagePosition];
571 firstVisitHeaderField_ =
572 [self addText:l10n_util::GetStringUTF16(IDS_PAGE_INFO_SITE_INFO_TITLE)
573 withSize:[NSFont smallSystemFontSize]
575 toView:contentView.get()
576 atPoint:textPosition];
577 firstVisitDescriptionField_ =
578 [self addText:base::string16()
579 withSize:[NSFont smallSystemFontSize]
581 toView:contentView.get()
582 atPoint:textPosition];
584 separatorAfterFirstVisit_ = [self addSeparatorToView:contentView];
585 [separatorAfterFirstVisit_ setAutoresizingMask:NSViewWidthSizable];
587 NSString* helpButtonText = l10n_util::GetNSString(
588 IDS_PAGE_INFO_HELP_CENTER_LINK);
589 helpButton_ = [self addLinkButtonWithText:helpButtonText
591 [helpButton_ setTarget:self];
592 [helpButton_ setAction:@selector(showHelpPage:)];
594 [item setView:contentView.get()];
595 [tabView_ insertTabViewItem:item.get()
596 atIndex:WebsiteSettingsUI::TAB_ID_CONNECTION];
598 return contentView.get();
601 // Set the Y position of |view| to the given position, and return the position
602 // of its bottom edge.
603 - (CGFloat)setYPositionOfView:(NSView*)view to:(CGFloat)position {
604 NSRect frame = [view frame];
605 frame.origin.y = position;
606 [view setFrame:frame];
607 return position + NSHeight(frame);
610 - (void)setWidthOfView:(NSView*)view to:(CGFloat)width {
611 [view setFrameSize:NSMakeSize(width, NSHeight([view frame]))];
614 // Layout all of the controls in the window. This should be called whenever
615 // the content has changed.
616 - (void)performLayout {
617 // Make the content at least as wide as the permissions view.
618 CGFloat contentWidth = std::max([self defaultWindowWidth],
619 NSWidth([permissionsView_ frame]));
621 // Set the width of the content view now, so that all the text fields will
622 // be sized to fit before their heights and vertical positions are adjusted.
623 // The tab view will only resize the currently selected tab, so resize both
624 // tab content views manually.
625 [self setWidthOfView:contentView_ to:contentWidth];
626 [self setWidthOfView:permissionsTabContentView_ to:contentWidth];
627 [self setWidthOfView:connectionTabContentView_ to:contentWidth];
629 // Place the identity status immediately below the identity.
630 [self sizeTextFieldHeightToFit:identityField_];
631 [self sizeTextFieldHeightToFit:identityStatusField_];
632 CGFloat yPos = NSMaxY([identityField_ frame]) + kConnectionHeadlineSpacing;
633 yPos = [self setYPositionOfView:identityStatusField_ to:yPos];
635 // Lay out the Permissions tab.
637 yPos = [self setYPositionOfView:cookiesView_ to:kFramePadding];
639 // Put the link button for cookies and site data just below the cookie info.
640 NSRect cookiesButtonFrame = [cookiesButton_ frame];
641 cookiesButtonFrame.origin.y = yPos;
642 cookiesButtonFrame.origin.x = kFramePadding;
643 [cookiesButton_ setFrame:cookiesButtonFrame];
645 // Put the permission info just below the link button.
646 [self setYPositionOfView:permissionsView_
647 to:NSMaxY(cookiesButtonFrame) + kFramePadding];
649 // Lay out the Connection tab.
651 // Lay out the identity status section.
652 [self sizeTextFieldHeightToFit:identityStatusDescriptionField_];
653 yPos = std::max(NSMaxY([identityStatusDescriptionField_ frame]),
654 NSMaxY([identityStatusIcon_ frame]));
655 if (certificateInfoButton_) {
656 NSRect certificateButtonFrame = [certificateInfoButton_ frame];
657 certificateButtonFrame.origin.x = NSMinX(
658 [identityStatusDescriptionField_ frame]);
659 certificateButtonFrame.origin.y = yPos + kVerticalSpacing;
660 [certificateInfoButton_ setFrame:certificateButtonFrame];
661 yPos = NSMaxY(certificateButtonFrame);
663 yPos = [self setYPositionOfView:separatorAfterIdentity_
664 to:yPos + kVerticalSpacing];
665 yPos += kVerticalSpacing;
667 // Lay out the connection status section.
668 [self sizeTextFieldHeightToFit:connectionStatusDescriptionField_];
669 [self setYPositionOfView:connectionStatusIcon_ to:yPos];
670 [self setYPositionOfView:connectionStatusDescriptionField_ to:yPos];
671 yPos = std::max(NSMaxY([connectionStatusDescriptionField_ frame]),
672 NSMaxY([connectionStatusIcon_ frame]));
673 yPos = [self setYPositionOfView:separatorAfterConnection_
674 to:yPos + kVerticalSpacing];
675 yPos += kVerticalSpacing;
677 // Lay out the last visit section.
678 [self setYPositionOfView:firstVisitIcon_ to:yPos];
679 [self sizeTextFieldHeightToFit:firstVisitHeaderField_];
680 yPos = [self setYPositionOfView:firstVisitHeaderField_ to:yPos];
681 yPos += kConnectionHeadlineSpacing;
682 [self sizeTextFieldHeightToFit:firstVisitDescriptionField_];
683 yPos = [self setYPositionOfView:firstVisitDescriptionField_ to:yPos];
684 yPos = [self setYPositionOfView:separatorAfterFirstVisit_
685 to:yPos + kVerticalSpacing];
686 yPos += kVerticalSpacing;
687 [self setYPositionOfView:helpButton_ to:yPos];
689 // Adjust the tab view size and place it below the identity status.
691 yPos = NSMaxY([identityStatusField_ frame]) + kTabStripTopSpacing;
692 yPos = [self setYPositionOfView:segmentedControl_ to:yPos];
694 CGFloat connectionTabHeight = NSMaxY([helpButton_ frame]) + kVerticalSpacing;
696 NSRect tabViewFrame = [tabView_ frame];
697 tabViewFrame.origin.y = yPos;
698 tabViewFrame.size.height =
699 std::max(connectionTabHeight, NSMaxY([permissionsView_ frame]));
700 tabViewFrame.size.width = contentWidth;
701 [tabView_ setFrame:tabViewFrame];
703 // Adjust the contentView to fit everything.
704 [contentView_ setFrame:NSMakeRect(
705 0, 0, NSWidth(tabViewFrame), NSMaxY(tabViewFrame))];
707 [self sizeAndPositionWindow];
710 // Adjust the size of the window to match the size of the content, and position
711 // the bubble anchor appropriately.
712 - (void)sizeAndPositionWindow {
713 NSRect windowFrame = [contentView_ frame];
714 windowFrame.size = [[[self window] contentView] convertSize:windowFrame.size
716 // Adjust the origin by the difference in height.
717 windowFrame.origin = [[self window] frame].origin;
718 windowFrame.origin.y -= NSHeight(windowFrame) -
719 NSHeight([[self window] frame]);
721 // Resize the window. Only animate if the window is visible, otherwise it
722 // could be "growing" while it's opening, looking awkward.
723 [[self window] setFrame:windowFrame
725 animate:[[self window] isVisible]];
727 // Adjust the anchor for the bubble.
728 NSPoint anchorPoint =
729 [self anchorPointForWindowWithHeight:NSHeight(windowFrame)
730 parentWindow:[self parentWindow]];
731 [self setAnchorPoint:anchorPoint];
734 // Takes in the bubble's height and the parent window, which should be a
735 // BrowserWindow, and gets the proper anchor point for the bubble. The returned
736 // point is in screen coordinates.
737 - (NSPoint)anchorPointForWindowWithHeight:(CGFloat)bubbleHeight
738 parentWindow:(NSWindow*)parent {
739 BrowserWindowController* controller = [parent windowController];
740 NSPoint origin = NSZeroPoint;
741 if ([controller isKindOfClass:[BrowserWindowController class]]) {
742 LocationBarViewMac* locationBar = [controller locationBarBridge];
744 NSPoint bubblePoint = locationBar->GetPageInfoBubblePoint();
745 origin = [parent convertBaseToScreen:bubblePoint];
751 // Sets properties on the given |field| to act as the title or description
752 // labels in the bubble.
753 - (void)configureTextFieldAsLabel:(NSTextField*)textField {
754 [textField setEditable:NO];
755 [textField setSelectable:YES];
756 [textField setDrawsBackground:NO];
757 [textField setBezeled:NO];
760 // Adjust the height of the given text field to match its text.
761 - (void)sizeTextFieldHeightToFit:(NSTextField*)textField {
762 NSRect frame = [textField frame];
764 [GTMUILocalizerAndLayoutTweaker sizeToFitFixedWidthTextField:
766 [textField setFrame:frame];
769 // Create a new text field and add it to the given array of subviews.
770 // The array will retain a reference to the object.
771 - (NSTextField*)addText:(const base::string16&)text
772 withSize:(CGFloat)fontSize
775 atPoint:(NSPoint)point {
776 // Size the text to take up the full available width, with some padding.
777 // The height is arbitrary as it will be adjusted later.
778 CGFloat width = NSWidth([view frame]) - point.x - kFramePadding;
779 NSRect frame = NSMakeRect(point.x, point.y, width, 100);
780 base::scoped_nsobject<NSTextField> textField(
781 [[NSTextField alloc] initWithFrame:frame]);
782 [self configureTextFieldAsLabel:textField.get()];
783 [textField setStringValue:base::SysUTF16ToNSString(text)];
784 NSFont* font = bold ? [NSFont boldSystemFontOfSize:fontSize]
785 : [NSFont systemFontOfSize:fontSize];
786 [textField setFont:font];
787 [self sizeTextFieldHeightToFit:textField];
788 [textField setAutoresizingMask:NSViewWidthSizable];
789 [view addSubview:textField.get()];
790 return textField.get();
793 // Add an image as a subview of the given view, placed at a pre-determined x
794 // position and the given y position. Return the new NSImageView.
795 - (NSImageView*)addImageWithSize:(NSSize)size
797 atPoint:(NSPoint)point {
798 NSRect frame = NSMakeRect(point.x, point.y, size.width, size.height);
799 base::scoped_nsobject<NSImageView> imageView(
800 [[NSImageView alloc] initWithFrame:frame]);
801 [imageView setImageFrameStyle:NSImageFrameNone];
802 [view addSubview:imageView.get()];
803 return imageView.get();
806 // Add a separator as a subview of the given view. Return the new view.
807 - (NSView*)addSeparatorToView:(NSView*)view {
808 // Take up almost the full width of the container's frame.
809 CGFloat width = NSWidth([view frame]) - 2 * kFramePadding;
811 // Use an arbitrary position; it will be adjusted in performLayout.
813 [self separatorWithFrame:NSMakeRect(kFramePadding, 0, width, 0)];
814 [view addSubview:spacer];
818 // Add a link button with the given text to |view|.
819 - (NSButton*)addLinkButtonWithText:(NSString*)text toView:(NSView*)view {
820 // Frame size is arbitrary; it will be adjusted by the layout tweaker.
821 NSRect frame = NSMakeRect(kFramePadding, 0, 100, 10);
822 base::scoped_nsobject<NSButton> button(
823 [[NSButton alloc] initWithFrame:frame]);
824 base::scoped_nsobject<HyperlinkButtonCell> cell(
825 [[HyperlinkButtonCell alloc] initTextCell:text]);
826 [cell setControlSize:NSSmallControlSize];
827 [button setCell:cell.get()];
828 [button setButtonType:NSMomentaryPushInButton];
829 [button setBezelStyle:NSRegularSquareBezelStyle];
830 [view addSubview:button.get()];
832 [GTMUILocalizerAndLayoutTweaker sizeToFitView:button.get()];
836 // Determine the size of a popup button with the given title.
837 - (NSSize)sizeForPopUpButton:(NSPopUpButton*)button
838 withTitle:(NSString*)title {
839 NSDictionary* textAttributes =
840 [NSDictionary dictionaryWithObject:[button font]
841 forKey:NSFontAttributeName];
842 NSSize titleSize = [title sizeWithAttributes:textAttributes];
844 NSRect buttonFrame = [button frame];
845 NSRect titleRect = [[button cell] titleRectForBounds:buttonFrame];
846 CGFloat width = titleSize.width + NSWidth(buttonFrame) - NSWidth(titleRect);
848 return NSMakeSize(width + kPermissionButtonTitleRightPadding,
849 NSHeight(buttonFrame));
852 // Add a pop-up button for |permissionInfo| to the given view.
853 - (NSPopUpButton*)addPopUpButtonForPermission:
854 (const WebsiteSettingsUI::PermissionInfo&)permissionInfo
856 atPoint:(NSPoint)point {
857 // Use an arbitrary width and height; it will be sized to fit.
858 NSRect frame = NSMakeRect(point.x, point.y, 1, 1);
859 base::scoped_nsobject<NSPopUpButton> button(
860 [[NSPopUpButton alloc] initWithFrame:frame pullsDown:NO]);
861 [button setFont:[NSFont systemFontOfSize:[NSFont smallSystemFontSize]]];
862 [button setBordered:NO];
863 [[button cell] setControlSize:NSSmallControlSize];
864 [button setTag:permissionInfo.type];
865 [button setAction:@selector(permissionValueChanged:)];
866 [button setTarget:self];
868 // Create the popup menu.
869 // TODO(dubroy): Refactor this code to use PermissionMenuModel.
871 // Media stream permission only support "Always allow" for https.
872 if (permissionInfo.type != CONTENT_SETTINGS_TYPE_MEDIASTREAM ||
873 (webContents_ && webContents_->GetURL().SchemeIsSecure())) {
874 [button addItemWithTitle:
875 l10n_util::GetNSString(IDS_WEBSITE_SETTINGS_MENU_ITEM_ALLOW)];
876 [[button lastItem] setTag:CONTENT_SETTING_ALLOW];
879 // Fullscreen does not support "Always block".
880 if (permissionInfo.type != CONTENT_SETTINGS_TYPE_FULLSCREEN) {
881 [button addItemWithTitle:
882 l10n_util::GetNSString(IDS_WEBSITE_SETTINGS_MENU_ITEM_BLOCK)];
883 [[button lastItem] setTag:CONTENT_SETTING_BLOCK];
886 [button addItemWithTitle:l10n_util::GetNSStringF(
887 IDS_WEBSITE_SETTINGS_DEFAULT_PERMISSION_LABEL,
888 WebsiteSettingsUI::PermissionValueToUIString(
889 permissionInfo.default_setting))];
890 [[button lastItem] setTag:CONTENT_SETTING_DEFAULT];
892 [button selectItemWithTag:permissionInfo.setting];
894 // Set the button title.
895 base::scoped_nsobject<NSMenuItem> titleItem([[NSMenuItem alloc] init]);
896 base::string16 buttonTitle = WebsiteSettingsUI::PermissionActionToUIString(
897 permissionInfo.setting,
898 permissionInfo.default_setting,
899 permissionInfo.source);
900 [titleItem setTitle:base::SysUTF16ToNSString(buttonTitle)];
901 [[button cell] setUsesItemFromMenu:NO];
902 [[button cell] setMenuItem:titleItem.get()];
905 // Determine the largest possible size for this button.
906 CGFloat maxTitleWidth = 0;
907 for (NSInteger i = 0; i < [button numberOfItems]; ++i) {
908 base::string16 title = WebsiteSettingsUI::PermissionActionToUIString(
909 static_cast<ContentSetting>([[button itemAtIndex:i] tag]),
910 permissionInfo.default_setting,
911 content_settings::SETTING_SOURCE_USER);
912 NSSize size = [self sizeForPopUpButton:button
913 withTitle:base::SysUTF16ToNSString(title)];
914 maxTitleWidth = std::max(maxTitleWidth, size.width);
916 // Ensure the containing view is large enough to contain the button with its
917 // widest possible title.
918 NSRect containerFrame = [view frame];
919 containerFrame.size.width = std::max(
920 NSWidth(containerFrame), point.x + maxTitleWidth + kFramePadding);
921 [view setFrame:containerFrame];
923 // Size the button to just fit the title.
924 [button setFrameSize:[self sizeForPopUpButton:button
925 withTitle:[button title]]];
927 [view addSubview:button.get()];
931 // Called when the user changes the selected segment in the segmented control.
932 - (void)tabSelected:(id)sender {
933 [tabView_ selectTabViewItemAtIndex:[segmentedControl_ selectedSegment]];
936 // Handler for the permission-changing menus.
937 - (void)permissionValueChanged:(id)sender {
938 DCHECK([sender isKindOfClass:[NSPopUpButton class]]);
939 NSPopUpButton* button = static_cast<NSPopUpButton*>(sender);
940 ContentSettingsType type = static_cast<ContentSettingsType>([button tag]);
941 ContentSetting newSetting = static_cast<ContentSetting>(
942 [[button selectedItem] tag]);
943 if (presenter_.get())
944 presenter_->OnSitePermissionChanged(type, newSetting);
947 // Adds a new row to the UI listing the permissions. Returns the amount of
948 // vertical space that was taken up by the row.
949 - (NSPoint)addPermission:
950 (const WebsiteSettingsUI::PermissionInfo&)permissionInfo
952 atPoint:(NSPoint)point {
953 // TODO(dubroy): Remove this check by refactoring GetPermissionIcon to take
954 // the PermissionInfo object as its argument.
955 ContentSetting setting = permissionInfo.setting == CONTENT_SETTING_DEFAULT ?
956 permissionInfo.default_setting : permissionInfo.setting;
957 NSImage* image = WebsiteSettingsUI::GetPermissionIcon(
958 permissionInfo.type, setting).ToNSImage();
959 NSImageView* imageView = [self addImageWithSize:[image size]
962 [imageView setImage:image];
963 point.x += kPermissionImageSize + kPermissionImageSpacing;
965 base::string16 labelText =
966 WebsiteSettingsUI::PermissionTypeToUIString(permissionInfo.type) +
967 base::ASCIIToUTF16(":");
969 NSTextField* label = [self addText:labelText
970 withSize:[NSFont smallSystemFontSize]
975 NSPoint popUpPosition = NSMakePoint(NSMaxX([label frame]), point.y);
976 NSPopUpButton* button = [self addPopUpButtonForPermission:permissionInfo
978 atPoint:popUpPosition];
980 // Adjust the vertical position of the button so that its title text is
981 // aligned with the label. Assumes that the text is the same size in both.
982 // Also adjust the horizontal position to remove excess space due to the
984 NSRect titleRect = [[button cell] titleRectForBounds:[button bounds]];
985 popUpPosition.x -= titleRect.origin.x - kPermissionPopUpXSpacing;
986 popUpPosition.y -= titleRect.origin.y;
987 [button setFrameOrigin:popUpPosition];
989 // Align the icon with the text.
990 [self alignPermissionIcon:imageView withTextField:label];
992 // Permissions specified by policy or an extension cannot be changed.
993 if (permissionInfo.source == content_settings::SETTING_SOURCE_EXTENSION ||
994 permissionInfo.source == content_settings::SETTING_SOURCE_POLICY) {
995 [button setEnabled:NO];
998 NSRect buttonFrame = [button frame];
999 return NSMakePoint(NSMaxX(buttonFrame), NSMaxY(buttonFrame));
1002 // Align an image with a text field by vertically centering the image on
1003 // the cap height of the first line of text.
1004 - (void)alignPermissionIcon:(NSImageView*)imageView
1005 withTextField:(NSTextField*)textField {
1006 NSFont* font = [textField font];
1008 // Calculate the offset from the top of the text field.
1009 CGFloat capHeight = [font capHeight];
1010 CGFloat offset = (kPermissionImageSize - capHeight) / 2 -
1011 ([font ascender] - capHeight) - kPermissionImageYAdjust;
1013 NSRect frame = [imageView frame];
1014 frame.origin.y -= offset;
1015 [imageView setFrame:frame];
1018 - (CGFloat)addCookieInfo:
1019 (const WebsiteSettingsUI::CookieInfo&)cookieInfo
1020 toView:(NSView*)view
1021 atPoint:(NSPoint)point {
1022 NSImage* image = WebsiteSettingsUI::GetPermissionIcon(
1023 CONTENT_SETTINGS_TYPE_COOKIES, CONTENT_SETTING_ALLOW).ToNSImage();
1024 NSImageView* imageView = [self addImageWithSize:[image size]
1027 [imageView setImage:image];
1028 point.x += kPermissionImageSize + kPermissionImageSpacing;
1030 base::string16 labelText = l10n_util::GetStringFUTF16(
1031 IDS_WEBSITE_SETTINGS_SITE_DATA_STATS_LINE,
1032 base::UTF8ToUTF16(cookieInfo.cookie_source),
1033 base::IntToString16(cookieInfo.allowed),
1034 base::IntToString16(cookieInfo.blocked));
1036 NSTextField* label = [self addText:labelText
1037 withSize:[NSFont smallSystemFontSize]
1042 // Align the icon with the text.
1043 [self alignPermissionIcon:imageView withTextField:label];
1045 return NSHeight([label frame]);
1048 // Set the content of the identity and identity status fields.
1049 - (void)setIdentityInfo:(const WebsiteSettingsUI::IdentityInfo&)identityInfo {
1050 [identityField_ setStringValue:
1051 base::SysUTF8ToNSString(identityInfo.site_identity)];
1052 [identityStatusField_ setStringValue:
1053 base::SysUTF16ToNSString(identityInfo.GetIdentityStatusText())];
1055 WebsiteSettings::SiteIdentityStatus status = identityInfo.identity_status;
1056 if (status == WebsiteSettings::SITE_IDENTITY_STATUS_CERT ||
1057 status == WebsiteSettings::SITE_IDENTITY_STATUS_EV_CERT) {
1058 [identityStatusField_ setTextColor:IdentityVerifiedTextColor()];
1060 // If there is a certificate, add a button for viewing the certificate info.
1061 certificateId_ = identityInfo.cert_id;
1062 if (certificateId_) {
1063 if (!certificateInfoButton_) {
1064 NSString* text = l10n_util::GetNSString(IDS_PAGEINFO_CERT_INFO_BUTTON);
1065 certificateInfoButton_ = [self addLinkButtonWithText:text
1066 toView:connectionTabContentView_];
1068 [certificateInfoButton_ setTarget:self];
1069 [certificateInfoButton_ setAction:@selector(showCertificateInfo:)];
1072 certificateInfoButton_ = nil;
1075 [identityStatusIcon_ setImage:WebsiteSettingsUI::GetIdentityIcon(
1076 identityInfo.identity_status).ToNSImage()];
1077 [identityStatusDescriptionField_ setStringValue:
1078 base::SysUTF8ToNSString(identityInfo.identity_status_description)];
1080 [connectionStatusIcon_ setImage:WebsiteSettingsUI::GetConnectionIcon(
1081 identityInfo.connection_status).ToNSImage()];
1082 [connectionStatusDescriptionField_ setStringValue:
1083 base::SysUTF8ToNSString(identityInfo.connection_status_description)];
1085 [self performLayout];
1088 - (void)setCookieInfo:(const CookieInfoList&)cookieInfoList {
1089 // The contents of the permissions view can cause the whole window to get
1090 // bigger, but currently permissions are always set before cookie info.
1091 // Check to make sure that's still the case.
1092 DCHECK_GT([[permissionsView_ subviews] count], 0U);
1094 [cookiesView_ setSubviews:[NSArray array]];
1095 NSPoint controlOrigin = NSMakePoint(kFramePadding, 0);
1097 base::string16 sectionTitle = l10n_util::GetStringUTF16(
1098 IDS_WEBSITE_SETTINGS_TITLE_SITE_DATA);
1099 NSTextField* header = [self addText:sectionTitle
1100 withSize:[NSFont smallSystemFontSize]
1103 atPoint:controlOrigin];
1104 controlOrigin.y += NSHeight([header frame]) + kPermissionsHeadlineSpacing;
1106 for (CookieInfoList::const_iterator it = cookieInfoList.begin();
1107 it != cookieInfoList.end();
1109 controlOrigin.y += kPermissionsTabSpacing;
1110 CGFloat rowHeight = [self addCookieInfo:*it
1112 atPoint:controlOrigin];
1113 controlOrigin.y += rowHeight;
1116 controlOrigin.y += kPermissionsTabSpacing;
1117 [cookiesView_ setFrameSize:
1118 NSMakeSize(NSWidth([cookiesView_ frame]), controlOrigin.y)];
1120 [self performLayout];
1123 - (void)setPermissionInfo:(const PermissionInfoList&)permissionInfoList {
1124 [permissionsView_ setSubviews:[NSArray array]];
1125 NSPoint controlOrigin = NSMakePoint(kFramePadding, 0);
1127 base::string16 sectionTitle = l10n_util::GetStringUTF16(
1128 IDS_WEBSITE_SETTINGS_TITLE_SITE_PERMISSIONS);
1129 NSTextField* header = [self addText:sectionTitle
1130 withSize:[NSFont smallSystemFontSize]
1132 toView:permissionsView_
1133 atPoint:controlOrigin];
1134 [self sizeTextFieldHeightToFit:header];
1135 controlOrigin.y += NSHeight([header frame]) + kPermissionsHeadlineSpacing;
1137 for (PermissionInfoList::const_iterator permission =
1138 permissionInfoList.begin();
1139 permission != permissionInfoList.end();
1141 controlOrigin.y += kPermissionsTabSpacing;
1142 NSPoint rowBottomRight = [self addPermission:*permission
1143 toView:permissionsView_
1144 atPoint:controlOrigin];
1145 controlOrigin.y = rowBottomRight.y;
1147 controlOrigin.y += kFramePadding;
1148 [permissionsView_ setFrameSize:
1149 NSMakeSize(NSWidth([permissionsView_ frame]), controlOrigin.y)];
1150 [self performLayout];
1153 - (void)setFirstVisit:(const base::string16&)firstVisit {
1154 [firstVisitIcon_ setImage:
1155 WebsiteSettingsUI::GetFirstVisitIcon(firstVisit).ToNSImage()];
1156 [firstVisitDescriptionField_ setStringValue:
1157 base::SysUTF16ToNSString(firstVisit)];
1158 [self performLayout];
1161 - (void)setSelectedTab:(WebsiteSettingsUI::TabId)tabId {
1162 NSInteger index = static_cast<NSInteger>(tabId);
1163 [segmentedControl_ setSelectedSegment:index];
1164 [tabView_ selectTabViewItemAtIndex:index];
1169 WebsiteSettingsUIBridge::WebsiteSettingsUIBridge()
1170 : bubble_controller_(nil) {
1173 WebsiteSettingsUIBridge::~WebsiteSettingsUIBridge() {
1176 void WebsiteSettingsUIBridge::set_bubble_controller(
1177 WebsiteSettingsBubbleController* controller) {
1178 bubble_controller_ = controller;
1181 void WebsiteSettingsUIBridge::Show(gfx::NativeWindow parent,
1183 content::WebContents* web_contents,
1185 const content::SSLStatus& ssl) {
1186 bool is_internal_page = InternalChromePage(url);
1188 // Create the bridge. This will be owned by the bubble controller.
1189 WebsiteSettingsUIBridge* bridge = new WebsiteSettingsUIBridge();
1191 // Create the bubble controller. It will dealloc itself when it closes.
1192 WebsiteSettingsBubbleController* bubble_controller =
1193 [[WebsiteSettingsBubbleController alloc]
1194 initWithParentWindow:parent
1195 websiteSettingsUIBridge:bridge
1196 webContents:web_contents
1197 isInternalPage:is_internal_page];
1199 if (!is_internal_page) {
1200 // Initialize the presenter, which holds the model and controls the UI.
1201 // This is also owned by the bubble controller.
1202 WebsiteSettings* presenter = new WebsiteSettings(
1205 TabSpecificContentSettings::FromWebContents(web_contents),
1206 InfoBarService::FromWebContents(web_contents),
1209 content::CertStore::GetInstance());
1210 [bubble_controller setPresenter:presenter];
1213 [bubble_controller showWindow:nil];
1216 void WebsiteSettingsUIBridge::SetIdentityInfo(
1217 const WebsiteSettingsUI::IdentityInfo& identity_info) {
1218 [bubble_controller_ setIdentityInfo:identity_info];
1221 void WebsiteSettingsUIBridge::SetCookieInfo(
1222 const CookieInfoList& cookie_info_list) {
1223 [bubble_controller_ setCookieInfo:cookie_info_list];
1226 void WebsiteSettingsUIBridge::SetPermissionInfo(
1227 const PermissionInfoList& permission_info_list) {
1228 [bubble_controller_ setPermissionInfo:permission_info_list];
1231 void WebsiteSettingsUIBridge::SetFirstVisit(const base::string16& first_visit) {
1232 [bubble_controller_ setFirstVisit:first_visit];
1235 void WebsiteSettingsUIBridge::SetSelectedTab(TabId tab_id) {
1236 [bubble_controller_ setSelectedTab:tab_id];