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 #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 #import "chrome/browser/ui/cocoa/website_settings/permission_selector_button.h"
21 #import "chrome/browser/ui/tab_dialogs.h"
22 #include "chrome/browser/ui/website_settings/permission_menu_model.h"
23 #include "chrome/browser/ui/website_settings/website_settings_utils.h"
24 #include "chrome/common/url_constants.h"
25 #include "chrome/grit/chromium_strings.h"
26 #include "chrome/grit/generated_resources.h"
27 #include "content/public/browser/cert_store.h"
28 #include "content/public/browser/page_navigator.h"
29 #include "content/public/browser/ssl_host_state_delegate.h"
30 #include "content/public/browser/user_metrics.h"
31 #include "content/public/browser/web_contents.h"
32 #include "grit/theme_resources.h"
33 #import "third_party/google_toolbox_for_mac/src/AppKit/GTMUILocalizerAndLayoutTweaker.h"
34 #import "ui/base/cocoa/controls/hyperlink_button_cell.h"
35 #import "ui/base/cocoa/flipped_view.h"
36 #include "ui/base/l10n/l10n_util.h"
37 #include "ui/base/resource/resource_bundle.h"
38 #include "ui/gfx/scoped_ns_graphics_context_save_gstate_mac.h"
42 // The default width of the window, in view coordinates. It may be larger to
44 const CGFloat kDefaultWindowWidth = 310;
46 // Spacing in between sections.
47 const CGFloat kVerticalSpacing = 10;
49 // Padding between the window frame and content.
50 const CGFloat kFramePadding = 20;
52 // Padding between the window frame and content for the internal page bubble.
53 const CGFloat kInternalPageFramePadding = 10;
55 // Spacing between the headlines and description text on the Connection tab.
56 const CGFloat kConnectionHeadlineSpacing = 2;
58 // Spacing between images on the Connection tab and the text.
59 const CGFloat kConnectionImageSpacing = 10;
61 // Spacing between the image and text for internal pages.
62 const CGFloat kInternalPageImageSpacing = 10;
64 // Square size of the images on the Connections tab.
65 const CGFloat kConnectionImageSize = 30;
67 // Square size of the image that is shown for internal pages.
68 const CGFloat kInternalPageImageSize = 26;
70 // Square size of the permission images.
71 const CGFloat kPermissionImageSize = 19;
73 // Vertical adjustment for the permission images.
74 // They have an extra pixel of padding on the bottom edge.
75 const CGFloat kPermissionImageYAdjust = 1;
77 // Spacing between a permission image and the text.
78 const CGFloat kPermissionImageSpacing = 3;
80 // The spacing between individual items in the Permissions tab.
81 const CGFloat kPermissionsTabSpacing = 12;
83 // Extra spacing after a headline on the Permissions tab.
84 const CGFloat kPermissionsHeadlineSpacing = 2;
86 // The amount of horizontal space between a permission label and the popup.
87 const CGFloat kPermissionPopUpXSpacing = 3;
89 // The extra space to the left of the first tab in the tab strip.
90 const CGFloat kTabStripXPadding = kFramePadding;
92 // The amount of space between the visual borders of adjacent tabs.
93 const CGFloat kTabSpacing = 4;
95 // The amount of space above the tab strip.
96 const CGFloat kTabStripTopSpacing = 14;
98 // The height of the clickable area of the tab.
99 const CGFloat kTabHeight = 28;
101 // The amount of space above tab labels.
102 const CGFloat kTabLabelTopPadding = 6;
104 // The amount of padding to leave on either side of the tab label.
105 const CGFloat kTabLabelXPadding = 12;
107 // Return the text color to use for the identity status when the site's
108 // identity has been verified.
109 NSColor* IdentityVerifiedTextColor() {
110 // RGB components are specified using integer RGB [0-255] values for easy
111 // comparison to other platforms.
112 return [NSColor colorWithCalibratedRed:0x07/255.0
120 @interface WebsiteSettingsTabSegmentedCell : NSSegmentedCell {
122 base::scoped_nsobject<NSImage> tabstripCenterImage_;
123 base::scoped_nsobject<NSImage> tabstripLeftImage_;
124 base::scoped_nsobject<NSImage> tabstripRightImage_;
126 base::scoped_nsobject<NSImage> tabCenterImage_;
127 base::scoped_nsobject<NSImage> tabLeftImage_;
128 base::scoped_nsobject<NSImage> tabRightImage_;
130 // Key track of the index of segment which has keyboard focus. This is not
131 // the same as the currently selected segment.
132 NSInteger keySegment_;
135 // The text attributes to use for the tab labels.
136 + (NSDictionary*)textAttributes;
140 @implementation WebsiteSettingsTabSegmentedCell
142 + (NSDictionary*)textAttributes {
143 NSFont* smallSystemFont =
144 [NSFont systemFontOfSize:[NSFont smallSystemFontSize]];
145 return @{ NSFontAttributeName : smallSystemFont };
149 if ((self = [super init])) {
150 ResourceBundle& rb = ResourceBundle::GetSharedInstance();
151 tabstripCenterImage_.reset(rb.GetNativeImageNamed(
152 IDR_WEBSITE_SETTINGS_TABSTRIP_CENTER).CopyNSImage());
153 tabstripLeftImage_.reset(rb.GetNativeImageNamed(
154 IDR_WEBSITE_SETTINGS_TABSTRIP_LEFT).CopyNSImage());
155 tabstripRightImage_.reset(rb.GetNativeImageNamed(
156 IDR_WEBSITE_SETTINGS_TABSTRIP_RIGHT).CopyNSImage());
158 tabCenterImage_.reset(
159 rb.GetNativeImageNamed(IDR_WEBSITE_SETTINGS_TAB_CENTER2).CopyNSImage());
161 rb.GetNativeImageNamed(IDR_WEBSITE_SETTINGS_TAB_LEFT2).CopyNSImage());
162 tabRightImage_.reset(
163 rb.GetNativeImageNamed(IDR_WEBSITE_SETTINGS_TAB_RIGHT2).CopyNSImage());
168 // Called when keyboard focus in the segmented control is moved forward.
169 - (void)makeNextSegmentKey {
170 [super makeNextSegmentKey];
171 keySegment_ = (keySegment_ + 1) % [self segmentCount];
174 // Called when keyboard focus in the segmented control is moved backwards.
175 - (void)makePreviousSegmentKey {
176 [super makePreviousSegmentKey];
177 if (--keySegment_ < 0)
178 keySegment_ += [self segmentCount];
181 - (void)setSelectedSegment:(NSInteger)selectedSegment {
182 keySegment_ = selectedSegment;
183 [super setSelectedSegment:selectedSegment];
186 - (void)drawWithFrame:(NSRect)cellFrame inView:(NSView*)controlView {
187 CGFloat tabstripHeight = [tabCenterImage_ size].height;
189 // Draw the tab for the selected segment.
190 NSRect tabRect = [self hitRectForSegment:[self selectedSegment]];
191 tabRect.origin.y = 0;
192 tabRect.size.height = tabstripHeight;
194 NSDrawThreePartImage(tabRect,
199 NSCompositeSourceOver,
203 // Draw the background to the left of the selected tab.
204 NSRect backgroundRect = NSMakeRect(0, 0, NSMinX(tabRect), tabstripHeight);
205 NSDrawThreePartImage(backgroundRect,
207 tabstripCenterImage_,
210 NSCompositeSourceOver,
214 // Draw the background to the right of the selected tab.
215 backgroundRect.origin.x = NSMaxX(tabRect);
216 backgroundRect.size.width = NSMaxX(cellFrame) - NSMaxX(tabRect);
217 NSDrawThreePartImage(backgroundRect,
219 tabstripCenterImage_,
222 NSCompositeSourceOver,
226 // Call the superclass method to trigger drawing of the tab labels.
227 [self drawInteriorWithFrame:cellFrame inView:controlView];
228 if ([[controlView window] firstResponder] == controlView)
229 [self drawFocusRect];
232 - (void)drawFocusRect {
233 gfx::ScopedNSGraphicsContextSaveGState scoped_state;
234 NSSetFocusRingStyle(NSFocusRingOnly);
235 [[NSColor keyboardFocusIndicatorColor] set];
236 NSFrameRect([self hitRectForSegment:keySegment_]);
239 // Return the hit rect (i.e., the visual bounds of the tab) for
240 // the given segment.
241 - (NSRect)hitRectForSegment:(NSInteger)segment {
242 CGFloat tabstripHeight = [tabCenterImage_ size].height;
243 DCHECK_GT(tabstripHeight, kTabHeight);
245 NSRect rect = NSMakeRect(0, tabstripHeight - kTabHeight,
246 [self widthForSegment:segment], kTabHeight);
247 for (NSInteger i = 0; i < segment; ++i) {
248 rect.origin.x += [self widthForSegment:i];
250 int xAdjust = segment == 0 ? kTabStripXPadding : 0;
251 rect.size.width = std::floor(
252 [self widthForSegment:segment] - kTabSpacing - xAdjust);
253 rect.origin.x = std::floor(rect.origin.x + kTabSpacing / 2 + xAdjust);
258 - (void)drawSegment:(NSInteger)segment
259 inFrame:(NSRect)tabFrame
260 withView:(NSView*)controlView {
261 // Adjust the tab's frame so that the label appears centered in the tab.
263 tabFrame.origin.x += kTabStripXPadding;
264 tabFrame.size.width -= kTabStripXPadding;
266 tabFrame.origin.y += kTabLabelTopPadding;
267 tabFrame.size.height -= kTabLabelTopPadding;
269 // Center the label's frame in the tab's frame.
270 NSString* label = [self labelForSegment:segment];
271 NSDictionary* textAttributes =
272 [WebsiteSettingsTabSegmentedCell textAttributes];
273 NSSize textSize = [label sizeWithAttributes:textAttributes];
275 labelFrame.size = textSize;
276 labelFrame.origin.x =
277 tabFrame.origin.x + (NSWidth(tabFrame) - textSize.width) / 2.0;
278 labelFrame.origin.y =
279 tabFrame.origin.y + (NSHeight(tabFrame) - textSize.height) / 2.0;
281 [label drawInRect:labelFrame withAttributes:textAttributes];
284 // Overrides the default tracking behavior to only respond to clicks inside the
285 // visual borders of the tab.
286 - (BOOL)startTrackingAt:(NSPoint)startPoint inView:(NSView *)controlView {
287 NSInteger segmentCount = [self segmentCount];
288 for (NSInteger i = 0; i < segmentCount; ++i) {
289 if (NSPointInRect(startPoint, [self hitRectForSegment:i]))
295 // Overrides the default cell height to take up the full height of the
296 // segmented control. Otherwise, clicks on the lower part of a tab will be
298 - (NSSize)cellSizeForBounds:(NSRect)aRect {
299 return NSMakeSize([super cellSizeForBounds:aRect].width,
300 [tabstripCenterImage_ size].height);
303 // Returns the minimum size required to display this cell.
304 // It should always be exactly as tall as the tabstrip background image.
306 return NSMakeSize([super cellSize].width,
307 [tabstripCenterImage_ size].height);
311 @implementation WebsiteSettingsBubbleController
313 - (CGFloat)defaultWindowWidth {
314 return kDefaultWindowWidth;
317 - (id)initWithParentWindow:(NSWindow*)parentWindow
318 websiteSettingsUIBridge:(WebsiteSettingsUIBridge*)bridge
319 webContents:(content::WebContents*)webContents
320 isInternalPage:(BOOL)isInternalPage {
321 DCHECK(parentWindow);
323 webContents_ = webContents;
325 // Use an arbitrary height; it will be changed in performLayout.
326 NSRect contentRect = NSMakeRect(0, 0, [self defaultWindowWidth], 1);
327 // Create an empty window into which content is placed.
328 base::scoped_nsobject<InfoBubbleWindow> window(
329 [[InfoBubbleWindow alloc] initWithContentRect:contentRect
330 styleMask:NSBorderlessWindowMask
331 backing:NSBackingStoreBuffered
334 if ((self = [super initWithWindow:window.get()
335 parentWindow:parentWindow
336 anchoredAt:NSZeroPoint])) {
337 [[self bubble] setArrowLocation:info_bubble::kTopLeft];
339 // Create the container view that uses flipped coordinates.
340 NSRect contentFrame = NSMakeRect(0, 0, [self defaultWindowWidth], 300);
342 [[FlippedView alloc] initWithFrame:contentFrame]);
344 // Replace the window's content.
345 [[[self window] contentView] setSubviews:
346 [NSArray arrayWithObject:contentView_.get()]];
349 [self initializeContentsForInternalPage];
351 [self initializeContents];
353 bridge_.reset(bridge);
354 bridge_->set_bubble_controller(self);
359 - (void)windowWillClose:(NSNotification*)notification {
360 if (presenter_.get())
361 presenter_->OnUIClosing();
362 [super windowWillClose:notification];
365 - (void)setPresenter:(WebsiteSettings*)presenter {
366 presenter_.reset(presenter);
369 // Create the subviews for the bubble for internal Chrome pages.
370 - (void)initializeContentsForInternalPage {
371 ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
373 NSPoint controlOrigin = NSMakePoint(
374 kInternalPageFramePadding,
375 kInternalPageFramePadding + info_bubble::kBubbleArrowHeight);
376 NSSize imageSize = NSMakeSize(kInternalPageImageSize,
377 kInternalPageImageSize);
378 NSImageView* imageView = [self addImageWithSize:imageSize
380 atPoint:controlOrigin];
381 [imageView setImage:rb.GetNativeImageNamed(IDR_PRODUCT_LOGO_26).ToNSImage()];
383 controlOrigin.x += NSWidth([imageView frame]) + kInternalPageImageSpacing;
384 base::string16 text = l10n_util::GetStringUTF16(IDS_PAGE_INFO_INTERNAL_PAGE);
385 NSTextField* textField = [self addText:text
386 withSize:[NSFont smallSystemFontSize]
389 atPoint:controlOrigin];
390 // Center the text vertically with the image.
391 NSRect textFrame = [textField frame];
392 textFrame.origin.y += (imageSize.height - NSHeight(textFrame)) / 2;
393 [textField setFrame:textFrame];
395 // Adjust the contentView to fit everything.
396 CGFloat maxY = std::max(NSMaxY([imageView frame]), NSMaxY(textFrame));
397 [contentView_ setFrame:NSMakeRect(
398 0, 0, [self defaultWindowWidth], maxY + kInternalPageFramePadding)];
400 [self sizeAndPositionWindow];
403 // Create the subviews for the website settings bubble.
404 - (void)initializeContents {
405 // Keeps track of the position that the next control should be drawn at.
406 NSPoint controlOrigin = NSMakePoint(
408 kFramePadding + info_bubble::kBubbleArrowHeight);
410 // Create a text field (empty for now) to show the site identity.
411 identityField_ = [self addText:base::string16()
412 withSize:[NSFont systemFontSize]
415 atPoint:controlOrigin];
417 NSHeight([identityField_ frame]) + kConnectionHeadlineSpacing;
419 // Create a text field to identity status (e.g. verified, not verified).
420 identityStatusField_ = [self addText:base::string16()
421 withSize:[NSFont smallSystemFontSize]
424 atPoint:controlOrigin];
426 // Create the tab view and its two tabs.
428 base::scoped_nsobject<WebsiteSettingsTabSegmentedCell> cell(
429 [[WebsiteSettingsTabSegmentedCell alloc] init]);
430 CGFloat tabstripHeight = [cell cellSize].height;
431 NSRect tabstripFrame = NSMakeRect(
432 0, 0, [self defaultWindowWidth], tabstripHeight);
433 segmentedControl_.reset(
434 [[NSSegmentedControl alloc] initWithFrame:tabstripFrame]);
435 [segmentedControl_ setCell:cell];
436 [segmentedControl_ setSegmentCount:WebsiteSettingsUI::NUM_TAB_IDS];
437 [segmentedControl_ setTarget:self];
438 [segmentedControl_ setAction:@selector(tabSelected:)];
439 [segmentedControl_ setAutoresizingMask:NSViewWidthSizable];
441 NSDictionary* textAttributes =
442 [WebsiteSettingsTabSegmentedCell textAttributes];
444 // Create the "Permissions" tab.
445 NSString* label = l10n_util::GetNSString(
446 IDS_WEBSITE_SETTINGS_TAB_LABEL_PERMISSIONS);
447 [segmentedControl_ setLabel:label
448 forSegment:WebsiteSettingsUI::TAB_ID_PERMISSIONS];
449 NSSize textSize = [label sizeWithAttributes:textAttributes];
450 CGFloat tabWidth = textSize.width + 2 * kTabLabelXPadding;
452 // Create the "Connection" tab.
453 label = l10n_util::GetNSString(IDS_WEBSITE_SETTINGS_TAB_LABEL_CONNECTION);
454 textSize = [label sizeWithAttributes:textAttributes];
455 [segmentedControl_ setLabel:label
456 forSegment:WebsiteSettingsUI::TAB_ID_CONNECTION];
458 DCHECK_EQ([segmentedControl_ segmentCount], WebsiteSettingsUI::NUM_TAB_IDS);
460 // Make both tabs the width of the widest. The first segment has some
461 // additional padding that is not part of the tab, which is used for drawing
462 // the background of the tab strip.
463 tabWidth = std::max(tabWidth,
464 textSize.width + 2 * kTabLabelXPadding);
465 [segmentedControl_ setWidth:tabWidth + kTabStripXPadding
466 forSegment:WebsiteSettingsUI::TAB_ID_PERMISSIONS];
467 [segmentedControl_ setWidth:tabWidth
468 forSegment:WebsiteSettingsUI::TAB_ID_CONNECTION];
470 [segmentedControl_ setFont:[textAttributes objectForKey:NSFontAttributeName]];
471 [contentView_ addSubview:segmentedControl_];
473 NSRect tabFrame = NSMakeRect(0, 0, [self defaultWindowWidth], 300);
474 tabView_.reset([[NSTabView alloc] initWithFrame:tabFrame]);
475 [tabView_ setTabViewType:NSNoTabsNoBorder];
476 [tabView_ setDrawsBackground:NO];
477 [tabView_ setControlSize:NSSmallControlSize];
478 [contentView_ addSubview:tabView_.get()];
480 permissionsTabContentView_ = [self addPermissionsTabToTabView:tabView_];
481 connectionTabContentView_ = [self addConnectionTabToTabView:tabView_];
482 [self setSelectedTab:WebsiteSettingsUI::TAB_ID_PERMISSIONS];
484 [self performLayout];
487 // Create the contents of the Permissions tab and add it to the given tab view.
488 // Returns a weak reference to the tab view item's view.
489 - (NSView*)addPermissionsTabToTabView:(NSTabView*)tabView {
490 base::scoped_nsobject<NSTabViewItem> item([[NSTabViewItem alloc] init]);
491 [tabView_ insertTabViewItem:item.get()
492 atIndex:WebsiteSettingsUI::TAB_ID_PERMISSIONS];
493 base::scoped_nsobject<NSView> contentView(
494 [[FlippedView alloc] initWithFrame:[tabView_ contentRect]]);
495 [contentView setAutoresizingMask:NSViewWidthSizable];
496 [item setView:contentView.get()];
498 // Initialize the two containers that hold the controls. The initial frames
499 // are arbitrary, and will be adjusted after the controls are laid out.
500 cookiesView_ = [[[FlippedView alloc]
501 initWithFrame:[tabView_ contentRect]] autorelease];
502 [cookiesView_ setAutoresizingMask:NSViewWidthSizable];
504 permissionsView_ = [[[FlippedView alloc]
505 initWithFrame:[tabView_ contentRect]] autorelease];
507 [contentView addSubview:cookiesView_];
508 [contentView addSubview:permissionsView_];
510 // Create the link button to view cookies and site data.
511 // Its position will be set in performLayout.
512 NSString* cookieButtonText = l10n_util::GetNSString(
513 IDS_WEBSITE_SETTINGS_SHOW_SITE_DATA);
514 cookiesButton_ = [self addLinkButtonWithText:cookieButtonText
516 [cookiesButton_ setTarget:self];
517 [cookiesButton_ setAction:@selector(showCookiesAndSiteData:)];
519 return contentView.get();
522 // Handler for the link button below the list of cookies.
523 - (void)showCookiesAndSiteData:(id)sender {
524 DCHECK(webContents_);
525 presenter_->RecordWebsiteSettingsAction(
526 WebsiteSettings::WEBSITE_SETTINGS_COOKIES_DIALOG_OPENED);
527 TabDialogs::FromWebContents(webContents_)->ShowCollectedCookies();
530 // Handler for the link button to show certificate information.
531 - (void)showCertificateInfo:(id)sender {
532 DCHECK(certificateId_);
533 presenter_->RecordWebsiteSettingsAction(
534 WebsiteSettings::WEBSITE_SETTINGS_CERTIFICATE_DIALOG_OPENED);
535 ShowCertificateViewerByID(webContents_, [self parentWindow], certificateId_);
538 // Handler for the link button to revoke user certificate decisions.
539 - (void)resetCertificateDecisions:(id)sender {
540 DCHECK(resetDecisionsButton_);
541 presenter_->OnRevokeSSLErrorBypassButtonPressed();
545 // Handler for the link to show help information about the connection tab.
546 - (void)showHelpPage:(id)sender {
547 presenter_->RecordWebsiteSettingsAction(
548 WebsiteSettings::WEBSITE_SETTINGS_CONNECTION_HELP_OPENED);
549 webContents_->OpenURL(content::OpenURLParams(
550 GURL(chrome::kPageInfoHelpCenterURL), content::Referrer(),
551 NEW_FOREGROUND_TAB, ui::PAGE_TRANSITION_LINK, false));
554 // Create the contents of the Connection tab and add it to the given tab view.
555 // Returns a weak reference to the tab view item's view.
556 - (NSView*)addConnectionTabToTabView:(NSTabView*)tabView {
557 base::scoped_nsobject<NSTabViewItem> item([[NSTabViewItem alloc] init]);
558 base::scoped_nsobject<NSView> contentView(
559 [[FlippedView alloc] initWithFrame:[tabView_ contentRect]]);
560 [contentView setAutoresizingMask:NSViewWidthSizable];
562 // Place all the text and images at the same position. The positions will be
563 // adjusted in performLayout.
564 NSPoint textPosition = NSMakePoint(
565 kFramePadding + kConnectionImageSize + kConnectionImageSpacing,
567 NSPoint imagePosition = NSMakePoint(kFramePadding, kFramePadding);
568 NSSize imageSize = NSMakeSize(kConnectionImageSize, kConnectionImageSize);
570 identityStatusIcon_ = [self addImageWithSize:imageSize
572 atPoint:imagePosition];
573 identityStatusDescriptionField_ =
574 [self addText:base::string16()
575 withSize:[NSFont smallSystemFontSize]
577 toView:contentView.get()
578 atPoint:textPosition];
580 separatorAfterIdentity_ = [self addSeparatorToView:contentView];
581 [separatorAfterIdentity_ setAutoresizingMask:NSViewWidthSizable];
583 connectionStatusIcon_ = [self addImageWithSize:imageSize
585 atPoint:imagePosition];
586 connectionStatusDescriptionField_ =
587 [self addText:base::string16()
588 withSize:[NSFont smallSystemFontSize]
590 toView:contentView.get()
591 atPoint:textPosition];
592 certificateInfoButton_ = nil; // This will be created only if necessary.
593 resetDecisionsButton_ = nil; // This will be created only if necessary.
594 separatorAfterConnection_ = [self addSeparatorToView:contentView];
595 [separatorAfterConnection_ setAutoresizingMask:NSViewWidthSizable];
597 firstVisitIcon_ = [self addImageWithSize:imageSize
599 atPoint:imagePosition];
600 firstVisitHeaderField_ =
601 [self addText:l10n_util::GetStringUTF16(IDS_PAGE_INFO_SITE_INFO_TITLE)
602 withSize:[NSFont smallSystemFontSize]
604 toView:contentView.get()
605 atPoint:textPosition];
606 firstVisitDescriptionField_ =
607 [self addText:base::string16()
608 withSize:[NSFont smallSystemFontSize]
610 toView:contentView.get()
611 atPoint:textPosition];
613 separatorAfterFirstVisit_ = [self addSeparatorToView:contentView];
614 [separatorAfterFirstVisit_ setAutoresizingMask:NSViewWidthSizable];
616 NSString* helpButtonText = l10n_util::GetNSString(
617 IDS_PAGE_INFO_HELP_CENTER_LINK);
618 helpButton_ = [self addLinkButtonWithText:helpButtonText
620 [helpButton_ setTarget:self];
621 [helpButton_ setAction:@selector(showHelpPage:)];
623 [item setView:contentView.get()];
624 [tabView_ insertTabViewItem:item.get()
625 atIndex:WebsiteSettingsUI::TAB_ID_CONNECTION];
627 return contentView.get();
630 // Set the Y position of |view| to the given position, and return the position
631 // of its bottom edge.
632 - (CGFloat)setYPositionOfView:(NSView*)view to:(CGFloat)position {
633 NSRect frame = [view frame];
634 frame.origin.y = position;
635 [view setFrame:frame];
636 return position + NSHeight(frame);
639 - (void)setWidthOfView:(NSView*)view to:(CGFloat)width {
640 [view setFrameSize:NSMakeSize(width, NSHeight([view frame]))];
643 // Layout all of the controls in the window. This should be called whenever
644 // the content has changed.
645 - (void)performLayout {
646 // Make the content at least as wide as the permissions view.
647 CGFloat contentWidth = std::max([self defaultWindowWidth],
648 NSWidth([permissionsView_ frame]));
650 // Set the width of the content view now, so that all the text fields will
651 // be sized to fit before their heights and vertical positions are adjusted.
652 // The tab view will only resize the currently selected tab, so resize both
653 // tab content views manually.
654 [self setWidthOfView:contentView_ to:contentWidth];
655 [self setWidthOfView:permissionsTabContentView_ to:contentWidth];
656 [self setWidthOfView:connectionTabContentView_ to:contentWidth];
658 // Place the identity status immediately below the identity.
659 [self sizeTextFieldHeightToFit:identityField_];
660 [self sizeTextFieldHeightToFit:identityStatusField_];
661 CGFloat yPos = NSMaxY([identityField_ frame]) + kConnectionHeadlineSpacing;
662 yPos = [self setYPositionOfView:identityStatusField_ to:yPos];
664 // Lay out the Permissions tab.
666 yPos = [self setYPositionOfView:cookiesView_ to:kFramePadding];
668 // Put the link button for cookies and site data just below the cookie info.
669 NSRect cookiesButtonFrame = [cookiesButton_ frame];
670 cookiesButtonFrame.origin.y = yPos;
671 cookiesButtonFrame.origin.x = kFramePadding;
672 [cookiesButton_ setFrame:cookiesButtonFrame];
674 // Put the permission info just below the link button.
675 [self setYPositionOfView:permissionsView_
676 to:NSMaxY(cookiesButtonFrame) + kFramePadding];
678 // Lay out the Connection tab.
680 // Lay out the identity status section.
681 [self sizeTextFieldHeightToFit:identityStatusDescriptionField_];
682 yPos = std::max(NSMaxY([identityStatusDescriptionField_ frame]),
683 NSMaxY([identityStatusIcon_ frame]));
684 if (certificateInfoButton_) {
685 NSRect certificateButtonFrame = [certificateInfoButton_ frame];
686 certificateButtonFrame.origin.x = NSMinX(
687 [identityStatusDescriptionField_ frame]);
688 certificateButtonFrame.origin.y = yPos + kVerticalSpacing;
689 [certificateInfoButton_ setFrame:certificateButtonFrame];
690 yPos = NSMaxY(certificateButtonFrame);
692 if (resetDecisionsButton_) {
693 NSRect resetDecisionsButtonFrame = [resetDecisionsButton_ frame];
694 resetDecisionsButtonFrame.origin.x =
695 NSMinX([identityStatusDescriptionField_ frame]);
696 resetDecisionsButtonFrame.origin.y = yPos + kVerticalSpacing;
697 [resetDecisionsButton_ setFrame:resetDecisionsButtonFrame];
698 yPos = NSMaxY(resetDecisionsButtonFrame);
700 yPos = [self setYPositionOfView:separatorAfterIdentity_
701 to:yPos + kVerticalSpacing];
702 yPos += kVerticalSpacing;
704 // Lay out the connection status section.
705 [self sizeTextFieldHeightToFit:connectionStatusDescriptionField_];
706 [self setYPositionOfView:connectionStatusIcon_ to:yPos];
707 [self setYPositionOfView:connectionStatusDescriptionField_ to:yPos];
708 yPos = std::max(NSMaxY([connectionStatusDescriptionField_ frame]),
709 NSMaxY([connectionStatusIcon_ frame]));
710 yPos = [self setYPositionOfView:separatorAfterConnection_
711 to:yPos + kVerticalSpacing];
712 yPos += kVerticalSpacing;
714 // Lay out the last visit section.
715 [self setYPositionOfView:firstVisitIcon_ to:yPos];
716 [self sizeTextFieldHeightToFit:firstVisitHeaderField_];
717 yPos = [self setYPositionOfView:firstVisitHeaderField_ to:yPos];
718 yPos += kConnectionHeadlineSpacing;
719 [self sizeTextFieldHeightToFit:firstVisitDescriptionField_];
720 yPos = [self setYPositionOfView:firstVisitDescriptionField_ to:yPos];
721 yPos = [self setYPositionOfView:separatorAfterFirstVisit_
722 to:yPos + kVerticalSpacing];
723 yPos += kVerticalSpacing;
724 [self setYPositionOfView:helpButton_ to:yPos];
726 // Adjust the tab view size and place it below the identity status.
728 yPos = NSMaxY([identityStatusField_ frame]) + kTabStripTopSpacing;
729 yPos = [self setYPositionOfView:segmentedControl_ to:yPos];
731 CGFloat connectionTabHeight = NSMaxY([helpButton_ frame]) + kVerticalSpacing;
733 NSRect tabViewFrame = [tabView_ frame];
734 tabViewFrame.origin.y = yPos;
735 tabViewFrame.size.height =
736 std::max(connectionTabHeight, NSMaxY([permissionsView_ frame]));
737 tabViewFrame.size.width = contentWidth;
738 [tabView_ setFrame:tabViewFrame];
740 // Adjust the contentView to fit everything.
741 [contentView_ setFrame:NSMakeRect(
742 0, 0, NSWidth(tabViewFrame), NSMaxY(tabViewFrame))];
744 [self sizeAndPositionWindow];
747 // Adjust the size of the window to match the size of the content, and position
748 // the bubble anchor appropriately.
749 - (void)sizeAndPositionWindow {
750 NSRect windowFrame = [contentView_ frame];
751 windowFrame.size = [[[self window] contentView] convertSize:windowFrame.size
753 // Adjust the origin by the difference in height.
754 windowFrame.origin = [[self window] frame].origin;
755 windowFrame.origin.y -= NSHeight(windowFrame) -
756 NSHeight([[self window] frame]);
758 // Resize the window. Only animate if the window is visible, otherwise it
759 // could be "growing" while it's opening, looking awkward.
760 [[self window] setFrame:windowFrame
762 animate:[[self window] isVisible]];
764 // Adjust the anchor for the bubble.
765 NSPoint anchorPoint =
766 [self anchorPointForWindowWithHeight:NSHeight(windowFrame)
767 parentWindow:[self parentWindow]];
768 [self setAnchorPoint:anchorPoint];
771 // Takes in the bubble's height and the parent window, which should be a
772 // BrowserWindow, and gets the proper anchor point for the bubble. The returned
773 // point is in screen coordinates.
774 - (NSPoint)anchorPointForWindowWithHeight:(CGFloat)bubbleHeight
775 parentWindow:(NSWindow*)parent {
776 BrowserWindowController* controller = [parent windowController];
777 NSPoint origin = NSZeroPoint;
778 if ([controller isKindOfClass:[BrowserWindowController class]]) {
779 LocationBarViewMac* locationBar = [controller locationBarBridge];
781 NSPoint bubblePoint = locationBar->GetPageInfoBubblePoint();
782 origin = [parent convertBaseToScreen:bubblePoint];
788 // Sets properties on the given |field| to act as the title or description
789 // labels in the bubble.
790 - (void)configureTextFieldAsLabel:(NSTextField*)textField {
791 [textField setEditable:NO];
792 [textField setSelectable:YES];
793 [textField setDrawsBackground:NO];
794 [textField setBezeled:NO];
797 // Adjust the height of the given text field to match its text.
798 - (void)sizeTextFieldHeightToFit:(NSTextField*)textField {
799 NSRect frame = [textField frame];
801 [GTMUILocalizerAndLayoutTweaker sizeToFitFixedWidthTextField:
803 [textField setFrame:frame];
806 // Create a new text field and add it to the given array of subviews.
807 // The array will retain a reference to the object.
808 - (NSTextField*)addText:(const base::string16&)text
809 withSize:(CGFloat)fontSize
812 atPoint:(NSPoint)point {
813 // Size the text to take up the full available width, with some padding.
814 // The height is arbitrary as it will be adjusted later.
815 CGFloat width = NSWidth([view frame]) - point.x - kFramePadding;
816 NSRect frame = NSMakeRect(point.x, point.y, width, 100);
817 base::scoped_nsobject<NSTextField> textField(
818 [[NSTextField alloc] initWithFrame:frame]);
819 [self configureTextFieldAsLabel:textField.get()];
820 [textField setStringValue:base::SysUTF16ToNSString(text)];
821 NSFont* font = bold ? [NSFont boldSystemFontOfSize:fontSize]
822 : [NSFont systemFontOfSize:fontSize];
823 [textField setFont:font];
824 [self sizeTextFieldHeightToFit:textField];
825 [textField setAutoresizingMask:NSViewWidthSizable];
826 [view addSubview:textField.get()];
827 return textField.get();
830 // Add an image as a subview of the given view, placed at a pre-determined x
831 // position and the given y position. Return the new NSImageView.
832 - (NSImageView*)addImageWithSize:(NSSize)size
834 atPoint:(NSPoint)point {
835 NSRect frame = NSMakeRect(point.x, point.y, size.width, size.height);
836 base::scoped_nsobject<NSImageView> imageView(
837 [[NSImageView alloc] initWithFrame:frame]);
838 [imageView setImageFrameStyle:NSImageFrameNone];
839 [view addSubview:imageView.get()];
840 return imageView.get();
843 // Add a separator as a subview of the given view. Return the new view.
844 - (NSView*)addSeparatorToView:(NSView*)view {
845 // Take up almost the full width of the container's frame.
846 CGFloat width = NSWidth([view frame]) - 2 * kFramePadding;
848 // Use an arbitrary position; it will be adjusted in performLayout.
849 NSBox* spacer = [self horizontalSeparatorWithFrame:NSMakeRect(
850 kFramePadding, 0, width, 0)];
851 [view addSubview:spacer];
855 // Add a link button with the given text to |view|.
856 - (NSButton*)addLinkButtonWithText:(NSString*)text toView:(NSView*)view {
857 // Frame size is arbitrary; it will be adjusted by the layout tweaker.
858 NSRect frame = NSMakeRect(kFramePadding, 0, 100, 10);
859 base::scoped_nsobject<NSButton> button(
860 [[NSButton alloc] initWithFrame:frame]);
861 base::scoped_nsobject<HyperlinkButtonCell> cell(
862 [[HyperlinkButtonCell alloc] initTextCell:text]);
863 [cell setControlSize:NSSmallControlSize];
864 [button setCell:cell.get()];
865 [button setButtonType:NSMomentaryPushInButton];
866 [button setBezelStyle:NSRegularSquareBezelStyle];
867 [view addSubview:button.get()];
869 [GTMUILocalizerAndLayoutTweaker sizeToFitView:button.get()];
873 // Add a button with the given text to |view| setting the max size appropriately
874 // for the connection info section.
875 - (NSButton*)addButtonWithTextToConnectionSection:(NSString*)text
876 toView:(NSView*)view {
877 NSRect containerFrame = [view frame];
878 // Frame size is arbitrary; it will be adjusted by the layout tweaker.
879 NSRect frame = NSMakeRect(kFramePadding, 0, 100, 10);
880 base::scoped_nsobject<NSButton> button(
881 [[NSButton alloc] initWithFrame:frame]);
883 // Determine the largest possible size for this button. The size is the width
884 // of the connection section minus the padding on both sides minus the
885 // connection image size and spacing.
886 CGFloat maxTitleWidth = containerFrame.size.width - kFramePadding * 2 -
887 kConnectionImageSize - kConnectionImageSpacing;
889 base::scoped_nsobject<NSButtonCell> cell(
890 [[NSButtonCell alloc] initTextCell:text]);
891 [button setCell:cell.get()];
892 [GTMUILocalizerAndLayoutTweaker sizeToFitView:button.get()];
894 // Ensure the containing view is large enough to contain the button with its
895 // widest possible title.
896 NSRect buttonFrame = [button frame];
897 buttonFrame.size.width = maxTitleWidth;
899 [button setFrame:buttonFrame];
900 [button setButtonType:NSMomentaryPushInButton];
901 [button setBezelStyle:NSRegularSquareBezelStyle];
902 [view addSubview:button.get()];
907 // Add a pop-up button for |permissionInfo| to the given view.
908 - (NSPopUpButton*)addPopUpButtonForPermission:
909 (const WebsiteSettingsUI::PermissionInfo&)permissionInfo
911 atPoint:(NSPoint)point {
913 GURL url = webContents_ ? webContents_->GetURL() : GURL();
914 __block WebsiteSettingsBubbleController* weakSelf = self;
915 PermissionMenuModel::ChangeCallback callback =
916 base::BindBlock(^(const WebsiteSettingsUI::PermissionInfo& permission) {
917 [weakSelf onPermissionChanged:permission.type to:permission.setting];
919 base::scoped_nsobject<PermissionSelectorButton> button(
920 [[PermissionSelectorButton alloc] initWithPermissionInfo:permissionInfo
922 withCallback:callback]);
923 // Determine the largest possible size for this button.
924 CGFloat maxTitleWidth =
925 [button maxTitleWidthWithDefaultSetting:permissionInfo.default_setting];
927 // Ensure the containing view is large enough to contain the button with its
928 // widest possible title.
929 NSRect containerFrame = [view frame];
930 containerFrame.size.width = std::max(
931 NSWidth(containerFrame), point.x + maxTitleWidth + kFramePadding);
932 [view setFrame:containerFrame];
933 [view addSubview:button.get()];
937 // Called when the user changes the setting of a permission.
938 - (void)onPermissionChanged:(ContentSettingsType)permissionType
939 to:(ContentSetting)newSetting {
941 presenter_->OnSitePermissionChanged(permissionType, newSetting);
944 // Called when the user changes the selected segment in the segmented control.
945 - (void)tabSelected:(id)sender {
946 NSInteger index = [segmentedControl_ selectedSegment];
948 case WebsiteSettingsUI::TAB_ID_PERMISSIONS:
949 presenter_->RecordWebsiteSettingsAction(
950 WebsiteSettings::WEBSITE_SETTINGS_PERMISSIONS_TAB_SELECTED);
952 case WebsiteSettingsUI::TAB_ID_CONNECTION:
953 presenter_->RecordWebsiteSettingsAction(
954 WebsiteSettings::WEBSITE_SETTINGS_CONNECTION_TAB_SELECTED);
959 [tabView_ selectTabViewItemAtIndex:index];
962 // Adds a new row to the UI listing the permissions. Returns the amount of
963 // vertical space that was taken up by the row.
964 - (NSPoint)addPermission:
965 (const WebsiteSettingsUI::PermissionInfo&)permissionInfo
967 atPoint:(NSPoint)point {
968 base::scoped_nsobject<NSImage> image(
969 [WebsiteSettingsUI::GetPermissionIcon(permissionInfo).ToNSImage()
971 NSImageView* imageView = [self addImageWithSize:[image size]
974 [imageView setImage:image];
975 point.x += kPermissionImageSize + kPermissionImageSpacing;
977 base::string16 labelText =
978 WebsiteSettingsUI::PermissionTypeToUIString(permissionInfo.type) +
979 base::ASCIIToUTF16(":");
981 NSTextField* label = [self addText:labelText
982 withSize:[NSFont smallSystemFontSize]
987 NSPoint popUpPosition = NSMakePoint(NSMaxX([label frame]), point.y);
988 NSPopUpButton* button = [self addPopUpButtonForPermission:permissionInfo
990 atPoint:popUpPosition];
992 // Adjust the vertical position of the button so that its title text is
993 // aligned with the label. Assumes that the text is the same size in both.
994 // Also adjust the horizontal position to remove excess space due to the
996 NSRect titleRect = [[button cell] titleRectForBounds:[button bounds]];
997 popUpPosition.x -= titleRect.origin.x - kPermissionPopUpXSpacing;
998 popUpPosition.y -= titleRect.origin.y;
999 [button setFrameOrigin:popUpPosition];
1001 // Align the icon with the text.
1002 [self alignPermissionIcon:imageView withTextField:label];
1004 // Permissions specified by policy or an extension cannot be changed.
1005 if (permissionInfo.source == content_settings::SETTING_SOURCE_EXTENSION ||
1006 permissionInfo.source == content_settings::SETTING_SOURCE_POLICY) {
1007 [button setEnabled:NO];
1010 NSRect buttonFrame = [button frame];
1011 return NSMakePoint(NSMaxX(buttonFrame), NSMaxY(buttonFrame));
1014 // Align an image with a text field by vertically centering the image on
1015 // the cap height of the first line of text.
1016 - (void)alignPermissionIcon:(NSImageView*)imageView
1017 withTextField:(NSTextField*)textField {
1018 NSFont* font = [textField font];
1020 // Calculate the offset from the top of the text field.
1021 CGFloat capHeight = [font capHeight];
1022 CGFloat offset = (kPermissionImageSize - capHeight) / 2 -
1023 ([font ascender] - capHeight) - kPermissionImageYAdjust;
1025 NSRect frame = [imageView frame];
1026 frame.origin.y -= offset;
1027 [imageView setFrame:frame];
1030 - (CGFloat)addCookieInfo:
1031 (const WebsiteSettingsUI::CookieInfo&)cookieInfo
1032 toView:(NSView*)view
1033 atPoint:(NSPoint)point {
1034 WebsiteSettingsUI::PermissionInfo info;
1035 info.type = CONTENT_SETTINGS_TYPE_COOKIES;
1036 info.setting = CONTENT_SETTING_ALLOW;
1037 NSImage* image = WebsiteSettingsUI::GetPermissionIcon(info).ToNSImage();
1038 NSImageView* imageView = [self addImageWithSize:[image size]
1041 [imageView setImage:image];
1042 point.x += kPermissionImageSize + kPermissionImageSpacing;
1044 base::string16 labelText = l10n_util::GetStringFUTF16(
1045 IDS_WEBSITE_SETTINGS_SITE_DATA_STATS_LINE,
1046 base::UTF8ToUTF16(cookieInfo.cookie_source),
1047 base::IntToString16(cookieInfo.allowed),
1048 base::IntToString16(cookieInfo.blocked));
1050 NSTextField* label = [self addText:labelText
1051 withSize:[NSFont smallSystemFontSize]
1056 // Align the icon with the text.
1057 [self alignPermissionIcon:imageView withTextField:label];
1059 return NSHeight([label frame]);
1062 // Set the content of the identity and identity status fields.
1063 - (void)setIdentityInfo:(const WebsiteSettingsUI::IdentityInfo&)identityInfo {
1064 [identityField_ setStringValue:
1065 base::SysUTF8ToNSString(identityInfo.site_identity)];
1066 [identityStatusField_ setStringValue:
1067 base::SysUTF16ToNSString(identityInfo.GetIdentityStatusText())];
1069 WebsiteSettings::SiteIdentityStatus status = identityInfo.identity_status;
1070 if (status == WebsiteSettings::SITE_IDENTITY_STATUS_CERT ||
1071 status == WebsiteSettings::SITE_IDENTITY_STATUS_EV_CERT) {
1072 [identityStatusField_ setTextColor:IdentityVerifiedTextColor()];
1074 // If there is a certificate, add a button for viewing the certificate info.
1075 certificateId_ = identityInfo.cert_id;
1076 if (certificateId_) {
1077 if (!certificateInfoButton_) {
1078 NSString* text = l10n_util::GetNSString(IDS_PAGEINFO_CERT_INFO_BUTTON);
1079 certificateInfoButton_ = [self addLinkButtonWithText:text
1080 toView:connectionTabContentView_];
1082 [certificateInfoButton_ setTarget:self];
1083 [certificateInfoButton_ setAction:@selector(showCertificateInfo:)];
1086 // Check if a security decision has been made, and if so, add a button to
1087 // allow the user to retract their decision.
1088 if (identityInfo.show_ssl_decision_revoke_button) {
1089 NSString* text = l10n_util::GetNSString(
1090 IDS_PAGEINFO_RESET_INVALID_CERTIFICATE_DECISIONS_BUTTON);
1091 resetDecisionsButton_ =
1092 [self addButtonWithTextToConnectionSection:text
1093 toView:connectionTabContentView_];
1094 [resetDecisionsButton_ setTarget:self];
1095 [resetDecisionsButton_ setAction:@selector(resetCertificateDecisions:)];
1098 certificateInfoButton_ = nil;
1101 [identityStatusIcon_ setImage:WebsiteSettingsUI::GetIdentityIcon(
1102 identityInfo.identity_status).ToNSImage()];
1103 [identityStatusDescriptionField_ setStringValue:
1104 base::SysUTF8ToNSString(identityInfo.identity_status_description)];
1106 [connectionStatusIcon_ setImage:WebsiteSettingsUI::GetConnectionIcon(
1107 identityInfo.connection_status).ToNSImage()];
1108 [connectionStatusDescriptionField_ setStringValue:
1109 base::SysUTF8ToNSString(identityInfo.connection_status_description)];
1111 [self performLayout];
1114 - (void)setCookieInfo:(const CookieInfoList&)cookieInfoList {
1115 // The contents of the permissions view can cause the whole window to get
1116 // bigger, but currently permissions are always set before cookie info.
1117 // Check to make sure that's still the case.
1118 DCHECK_GT([[permissionsView_ subviews] count], 0U);
1120 [cookiesView_ setSubviews:[NSArray array]];
1121 NSPoint controlOrigin = NSMakePoint(kFramePadding, 0);
1123 base::string16 sectionTitle = l10n_util::GetStringUTF16(
1124 IDS_WEBSITE_SETTINGS_TITLE_SITE_DATA);
1125 NSTextField* header = [self addText:sectionTitle
1126 withSize:[NSFont smallSystemFontSize]
1129 atPoint:controlOrigin];
1130 controlOrigin.y += NSHeight([header frame]) + kPermissionsHeadlineSpacing;
1132 for (CookieInfoList::const_iterator it = cookieInfoList.begin();
1133 it != cookieInfoList.end();
1135 controlOrigin.y += kPermissionsTabSpacing;
1136 CGFloat rowHeight = [self addCookieInfo:*it
1138 atPoint:controlOrigin];
1139 controlOrigin.y += rowHeight;
1142 controlOrigin.y += kPermissionsTabSpacing;
1143 [cookiesView_ setFrameSize:
1144 NSMakeSize(NSWidth([cookiesView_ frame]), controlOrigin.y)];
1146 [self performLayout];
1149 - (void)setPermissionInfo:(const PermissionInfoList&)permissionInfoList {
1150 [permissionsView_ setSubviews:[NSArray array]];
1151 NSPoint controlOrigin = NSMakePoint(kFramePadding, 0);
1153 base::string16 sectionTitle = l10n_util::GetStringUTF16(
1154 IDS_WEBSITE_SETTINGS_TITLE_SITE_PERMISSIONS);
1155 NSTextField* header = [self addText:sectionTitle
1156 withSize:[NSFont smallSystemFontSize]
1158 toView:permissionsView_
1159 atPoint:controlOrigin];
1160 [self sizeTextFieldHeightToFit:header];
1161 controlOrigin.y += NSHeight([header frame]) + kPermissionsHeadlineSpacing;
1163 for (PermissionInfoList::const_iterator permission =
1164 permissionInfoList.begin();
1165 permission != permissionInfoList.end();
1167 controlOrigin.y += kPermissionsTabSpacing;
1168 NSPoint rowBottomRight = [self addPermission:*permission
1169 toView:permissionsView_
1170 atPoint:controlOrigin];
1171 controlOrigin.y = rowBottomRight.y;
1173 controlOrigin.y += kFramePadding;
1174 [permissionsView_ setFrameSize:
1175 NSMakeSize(NSWidth([permissionsView_ frame]), controlOrigin.y)];
1176 [self performLayout];
1179 - (void)setFirstVisit:(const base::string16&)firstVisit {
1180 [firstVisitIcon_ setImage:
1181 WebsiteSettingsUI::GetFirstVisitIcon(firstVisit).ToNSImage()];
1182 [firstVisitDescriptionField_ setStringValue:
1183 base::SysUTF16ToNSString(firstVisit)];
1184 [self performLayout];
1187 - (void)setSelectedTab:(WebsiteSettingsUI::TabId)tabId {
1188 NSInteger index = static_cast<NSInteger>(tabId);
1189 [segmentedControl_ setSelectedSegment:index];
1190 [tabView_ selectTabViewItemAtIndex:index];
1195 WebsiteSettingsUIBridge::WebsiteSettingsUIBridge()
1196 : bubble_controller_(nil) {
1199 WebsiteSettingsUIBridge::~WebsiteSettingsUIBridge() {
1202 void WebsiteSettingsUIBridge::set_bubble_controller(
1203 WebsiteSettingsBubbleController* controller) {
1204 bubble_controller_ = controller;
1207 void WebsiteSettingsUIBridge::Show(gfx::NativeWindow parent,
1209 content::WebContents* web_contents,
1211 const content::SSLStatus& ssl) {
1212 bool is_internal_page = InternalChromePage(url);
1214 // Create the bridge. This will be owned by the bubble controller.
1215 WebsiteSettingsUIBridge* bridge = new WebsiteSettingsUIBridge();
1217 // Create the bubble controller. It will dealloc itself when it closes.
1218 WebsiteSettingsBubbleController* bubble_controller =
1219 [[WebsiteSettingsBubbleController alloc]
1220 initWithParentWindow:parent
1221 websiteSettingsUIBridge:bridge
1222 webContents:web_contents
1223 isInternalPage:is_internal_page];
1225 if (!is_internal_page) {
1226 // Initialize the presenter, which holds the model and controls the UI.
1227 // This is also owned by the bubble controller.
1228 WebsiteSettings* presenter = new WebsiteSettings(
1231 TabSpecificContentSettings::FromWebContents(web_contents),
1232 InfoBarService::FromWebContents(web_contents),
1235 content::CertStore::GetInstance());
1236 [bubble_controller setPresenter:presenter];
1239 [bubble_controller showWindow:nil];
1242 void WebsiteSettingsUIBridge::SetIdentityInfo(
1243 const WebsiteSettingsUI::IdentityInfo& identity_info) {
1244 [bubble_controller_ setIdentityInfo:identity_info];
1247 void WebsiteSettingsUIBridge::SetCookieInfo(
1248 const CookieInfoList& cookie_info_list) {
1249 [bubble_controller_ setCookieInfo:cookie_info_list];
1252 void WebsiteSettingsUIBridge::SetPermissionInfo(
1253 const PermissionInfoList& permission_info_list) {
1254 [bubble_controller_ setPermissionInfo:permission_info_list];
1257 void WebsiteSettingsUIBridge::SetFirstVisit(const base::string16& first_visit) {
1258 [bubble_controller_ setFirstVisit:first_visit];
1261 void WebsiteSettingsUIBridge::SetSelectedTab(TabId tab_id) {
1262 [bubble_controller_ setSelectedTab:tab_id];