Index: chrome/browser/ui/cocoa/content_setting_bubble_cocoa.mm |
=================================================================== |
--- chrome/browser/ui/cocoa/content_setting_bubble_cocoa.mm (revision 71852) |
+++ chrome/browser/ui/cocoa/content_setting_bubble_cocoa.mm (working copy) |
@@ -1,489 +0,0 @@ |
-// Copyright (c) 2010 The Chromium Authors. All rights reserved. |
-// Use of this source code is governed by a BSD-style license that can be |
-// found in the LICENSE file. |
- |
-#import "chrome/browser/ui/cocoa/content_setting_bubble_cocoa.h" |
- |
-#include "app/l10n_util.h" |
-#include "base/command_line.h" |
-#include "base/logging.h" |
-#include "base/sys_string_conversions.h" |
-#include "base/utf_string_conversions.h" |
-#include "chrome/browser/blocked_content_container.h" |
-#include "chrome/browser/content_setting_bubble_model.h" |
-#include "chrome/browser/content_settings/host_content_settings_map.h" |
-#include "chrome/browser/plugin_updater.h" |
-#import "chrome/browser/ui/cocoa/hyperlink_button_cell.h" |
-#import "chrome/browser/ui/cocoa/info_bubble_view.h" |
-#import "chrome/browser/ui/cocoa/l10n_util.h" |
-#import "chrome/browser/ui/cocoa/options/content_settings_dialog_controller.h" |
-#include "grit/generated_resources.h" |
-#include "skia/ext/skia_utils_mac.h" |
-#import "third_party/GTM/AppKit/GTMUILocalizerAndLayoutTweaker.h" |
-#include "webkit/glue/plugins/plugin_list.h" |
- |
-namespace { |
- |
-// Must match the tag of the unblock radio button in the xib files. |
-const int kAllowTag = 1; |
- |
-// Must match the tag of the block radio button in the xib files. |
-const int kBlockTag = 2; |
- |
-// Height of one link in the popup list. |
-const int kLinkHeight = 16; |
- |
-// Space between two popup links. |
-const int kLinkPadding = 4; |
- |
-// Space taken in total by one popup link. |
-const int kLinkLineHeight = kLinkHeight + kLinkPadding; |
- |
-// Space between popup list and surrounding UI elements. |
-const int kLinkOuterPadding = 8; |
- |
-// Height of each of the labels in the geolocation bubble. |
-const int kGeoLabelHeight = 14; |
- |
-// Height of the "Clear" button in the geolocation bubble. |
-const int kGeoClearButtonHeight = 17; |
- |
-// Padding between radio buttons and "Load all plugins" button |
-// in the plugin bubble. |
-const int kLoadAllPluginsButtonVerticalPadding = 8; |
- |
-// General padding between elements in the geolocation bubble. |
-const int kGeoPadding = 8; |
- |
-// Padding between host names in the geolocation bubble. |
-const int kGeoHostPadding = 4; |
- |
-// Minimal padding between "Manage" and "Done" buttons. |
-const int kManageDonePadding = 8; |
- |
-void SetControlSize(NSControl* control, NSControlSize controlSize) { |
- CGFloat fontSize = [NSFont systemFontSizeForControlSize:controlSize]; |
- NSCell* cell = [control cell]; |
- NSFont* font = [NSFont fontWithName:[[cell font] fontName] size:fontSize]; |
- [cell setFont:font]; |
- [cell setControlSize:controlSize]; |
-} |
- |
-// Returns an autoreleased NSTextField that is configured to look like a Label |
-// looks in Interface Builder. |
-NSTextField* LabelWithFrame(NSString* text, const NSRect& frame) { |
- NSTextField* label = [[NSTextField alloc] initWithFrame:frame]; |
- [label setStringValue:text]; |
- [label setSelectable:NO]; |
- [label setBezeled:NO]; |
- return [label autorelease]; |
-} |
- |
-} // namespace |
- |
-@interface ContentSettingBubbleController(Private) |
-- (id)initWithModel:(ContentSettingBubbleModel*)settingsBubbleModel |
- parentWindow:(NSWindow*)parentWindow |
- anchoredAt:(NSPoint)anchoredAt; |
-- (NSButton*)hyperlinkButtonWithFrame:(NSRect)frame |
- title:(NSString*)title |
- icon:(NSImage*)icon |
- referenceFrame:(NSRect)referenceFrame; |
-- (void)initializeBlockedPluginsList; |
-- (void)initializeTitle; |
-- (void)initializeRadioGroup; |
-- (void)initializePopupList; |
-- (void)initializeGeoLists; |
-- (void)sizeToFitLoadPluginsButton; |
-- (void)sizeToFitManageDoneButtons; |
-- (void)removeInfoButton; |
-- (void)popupLinkClicked:(id)sender; |
-- (void)clearGeolocationForCurrentHost:(id)sender; |
-@end |
- |
-@implementation ContentSettingBubbleController |
- |
-+ (ContentSettingBubbleController*) |
- showForModel:(ContentSettingBubbleModel*)contentSettingBubbleModel |
- parentWindow:(NSWindow*)parentWindow |
- anchoredAt:(NSPoint)anchor { |
- // Autoreleases itself on bubble close. |
- return [[ContentSettingBubbleController alloc] |
- initWithModel:contentSettingBubbleModel |
- parentWindow:parentWindow |
- anchoredAt:anchor]; |
-} |
- |
-- (id)initWithModel:(ContentSettingBubbleModel*)contentSettingBubbleModel |
- parentWindow:(NSWindow*)parentWindow |
- anchoredAt:(NSPoint)anchoredAt { |
- // This method takes ownership of |contentSettingBubbleModel| in all cases. |
- scoped_ptr<ContentSettingBubbleModel> model(contentSettingBubbleModel); |
- DCHECK(model.get()); |
- |
- NSString* const nibPaths[] = { |
- @"ContentBlockedCookies", |
- @"ContentBlockedImages", |
- @"ContentBlockedJavaScript", |
- @"ContentBlockedPlugins", |
- @"ContentBlockedPopups", |
- @"ContentBubbleGeolocation", |
- @"", // Notifications do not have a bubble. |
- }; |
- COMPILE_ASSERT(arraysize(nibPaths) == CONTENT_SETTINGS_NUM_TYPES, |
- nibPaths_requires_an_entry_for_every_setting_type); |
- const int settingsType = model->content_type(); |
- // Nofifications do not have a bubble. |
- CHECK_NE(settingsType, CONTENT_SETTINGS_TYPE_NOTIFICATIONS); |
- DCHECK_LT(settingsType, CONTENT_SETTINGS_NUM_TYPES); |
- if ((self = [super initWithWindowNibPath:nibPaths[settingsType] |
- parentWindow:parentWindow |
- anchoredAt:anchoredAt])) { |
- contentSettingBubbleModel_.reset(model.release()); |
- [self showWindow:nil]; |
- } |
- return self; |
-} |
- |
-- (void)initializeTitle { |
- if (!titleLabel_) |
- return; |
- |
- NSString* label = base::SysUTF8ToNSString( |
- contentSettingBubbleModel_->bubble_content().title); |
- [titleLabel_ setStringValue:label]; |
- |
- // Layout title post-localization. |
- CGFloat deltaY = [GTMUILocalizerAndLayoutTweaker |
- sizeToFitFixedWidthTextField:titleLabel_]; |
- NSRect windowFrame = [[self window] frame]; |
- windowFrame.size.height += deltaY; |
- [[self window] setFrame:windowFrame display:NO]; |
- NSRect titleFrame = [titleLabel_ frame]; |
- titleFrame.origin.y -= deltaY; |
- [titleLabel_ setFrame:titleFrame]; |
-} |
- |
-- (void)initializeRadioGroup { |
- // Configure the radio group. For now, only deal with the |
- // strictly needed case of group containing 2 radio buttons. |
- const ContentSettingBubbleModel::RadioGroup& radio_group = |
- contentSettingBubbleModel_->bubble_content().radio_group; |
- |
- // Select appropriate radio button. |
- [allowBlockRadioGroup_ selectCellWithTag: |
- radio_group.default_item == 0 ? kAllowTag : kBlockTag]; |
- |
- const ContentSettingBubbleModel::RadioItems& radio_items = |
- radio_group.radio_items; |
- DCHECK_EQ(2u, radio_items.size()) << "Only 2 radio items per group supported"; |
- // Set radio group labels from model. |
- NSCell* radioCell = [allowBlockRadioGroup_ cellWithTag:kAllowTag]; |
- [radioCell setTitle:base::SysUTF8ToNSString(radio_items[0])]; |
- |
- radioCell = [allowBlockRadioGroup_ cellWithTag:kBlockTag]; |
- [radioCell setTitle:base::SysUTF8ToNSString(radio_items[1])]; |
- |
- // Layout radio group labels post-localization. |
- [GTMUILocalizerAndLayoutTweaker |
- wrapRadioGroupForWidth:allowBlockRadioGroup_]; |
- CGFloat radioDeltaY = [GTMUILocalizerAndLayoutTweaker |
- sizeToFitView:allowBlockRadioGroup_].height; |
- NSRect windowFrame = [[self window] frame]; |
- windowFrame.size.height += radioDeltaY; |
- [[self window] setFrame:windowFrame display:NO]; |
-} |
- |
-- (NSButton*)hyperlinkButtonWithFrame:(NSRect)frame |
- title:(NSString*)title |
- icon:(NSImage*)icon |
- referenceFrame:(NSRect)referenceFrame { |
- scoped_nsobject<HyperlinkButtonCell> cell([[HyperlinkButtonCell alloc] |
- initTextCell:title]); |
- [cell.get() setAlignment:NSNaturalTextAlignment]; |
- if (icon) { |
- [cell.get() setImagePosition:NSImageLeft]; |
- [cell.get() setImage:icon]; |
- } else { |
- [cell.get() setImagePosition:NSNoImage]; |
- } |
- [cell.get() setControlSize:NSSmallControlSize]; |
- |
- NSButton* button = [[[NSButton alloc] initWithFrame:frame] autorelease]; |
- // Cell must be set immediately after construction. |
- [button setCell:cell.get()]; |
- |
- // If the link text is too long, clamp it. |
- [button sizeToFit]; |
- int maxWidth = NSWidth([[self bubble] frame]) - 2 * NSMinX(referenceFrame); |
- NSRect buttonFrame = [button frame]; |
- if (NSWidth(buttonFrame) > maxWidth) { |
- buttonFrame.size.width = maxWidth; |
- [button setFrame:buttonFrame]; |
- } |
- |
- [button setTarget:self]; |
- [button setAction:@selector(popupLinkClicked:)]; |
- return button; |
-} |
- |
-- (void)initializeBlockedPluginsList { |
- NSMutableArray* pluginArray = [NSMutableArray array]; |
- const std::set<std::string>& plugins = |
- contentSettingBubbleModel_->bubble_content().resource_identifiers; |
- if (plugins.empty()) { |
- int delta = NSMinY([titleLabel_ frame]) - |
- NSMinY([blockedResourcesField_ frame]); |
- [blockedResourcesField_ removeFromSuperview]; |
- NSRect frame = [[self window] frame]; |
- frame.size.height -= delta; |
- [[self window] setFrame:frame display:NO]; |
- } else { |
- for (std::set<std::string>::iterator it = plugins.begin(); |
- it != plugins.end(); ++it) { |
- NSString* name = SysUTF16ToNSString( |
- NPAPI::PluginList::Singleton()->GetPluginGroupName(*it)); |
- if ([name length] == 0) |
- name = base::SysUTF8ToNSString(*it); |
- [pluginArray addObject:name]; |
- } |
- [blockedResourcesField_ |
- setStringValue:[pluginArray componentsJoinedByString:@"\n"]]; |
- [GTMUILocalizerAndLayoutTweaker |
- sizeToFitFixedWidthTextField:blockedResourcesField_]; |
- } |
-} |
- |
-- (void)initializePopupList { |
- // I didn't put the buttons into a NSMatrix because then they are only one |
- // entity in the key view loop. This way, one can tab through all of them. |
- const ContentSettingBubbleModel::PopupItems& popupItems = |
- contentSettingBubbleModel_->bubble_content().popup_items; |
- |
- // Get the pre-resize frame of the radio group. Its origin is where the |
- // popup list should go. |
- NSRect radioFrame = [allowBlockRadioGroup_ frame]; |
- |
- // Make room for the popup list. The bubble view and its subviews autosize |
- // themselves when the window is enlarged. |
- // Heading and radio box are already 1 * kLinkOuterPadding apart in the nib, |
- // so only 1 * kLinkOuterPadding more is needed. |
- int delta = popupItems.size() * kLinkLineHeight - kLinkPadding + |
- kLinkOuterPadding; |
- NSSize deltaSize = NSMakeSize(0, delta); |
- deltaSize = [[[self window] contentView] convertSize:deltaSize toView:nil]; |
- NSRect windowFrame = [[self window] frame]; |
- windowFrame.size.height += deltaSize.height; |
- [[self window] setFrame:windowFrame display:NO]; |
- |
- // Create popup list. |
- int topLinkY = NSMaxY(radioFrame) + delta - kLinkHeight; |
- int row = 0; |
- for (std::vector<ContentSettingBubbleModel::PopupItem>::const_iterator |
- it(popupItems.begin()); it != popupItems.end(); ++it, ++row) { |
- const SkBitmap& icon = it->bitmap; |
- NSImage* image = nil; |
- if (!icon.empty()) |
- image = gfx::SkBitmapToNSImage(icon); |
- |
- std::string title(it->title); |
- // The popup may not have committed a load yet, in which case it won't |
- // have a URL or title. |
- if (title.empty()) |
- title = l10n_util::GetStringUTF8(IDS_TAB_LOADING_TITLE); |
- |
- NSRect linkFrame = |
- NSMakeRect(NSMinX(radioFrame), topLinkY - kLinkLineHeight * row, |
- 200, kLinkHeight); |
- NSButton* button = [self |
- hyperlinkButtonWithFrame:linkFrame |
- title:base::SysUTF8ToNSString(title) |
- icon:image |
- referenceFrame:radioFrame]; |
- [[self bubble] addSubview:button]; |
- popupLinks_[button] = row; |
- } |
-} |
- |
-- (void)initializeGeoLists { |
- // Cocoa has its origin in the lower left corner. This means elements are |
- // added from bottom to top, which explains why loops run backwards and the |
- // order of operations is the other way than on Linux/Windows. |
- const ContentSettingBubbleModel::BubbleContent& content = |
- contentSettingBubbleModel_->bubble_content(); |
- NSRect containerFrame = [contentsContainer_ frame]; |
- NSRect frame = NSMakeRect(0, 0, NSWidth(containerFrame), kGeoLabelHeight); |
- |
- // "Clear" button / text field. |
- if (!content.custom_link.empty()) { |
- scoped_nsobject<NSControl> control; |
- if(content.custom_link_enabled) { |
- NSRect buttonFrame = NSMakeRect(0, 0, |
- NSWidth(containerFrame), |
- kGeoClearButtonHeight); |
- NSButton* button = [[NSButton alloc] initWithFrame:buttonFrame]; |
- control.reset(button); |
- [button setTitle:base::SysUTF8ToNSString(content.custom_link)]; |
- [button setTarget:self]; |
- [button setAction:@selector(clearGeolocationForCurrentHost:)]; |
- [button setBezelStyle:NSRoundRectBezelStyle]; |
- SetControlSize(button, NSSmallControlSize); |
- [button sizeToFit]; |
- } else { |
- // Add the notification that settings will be cleared on next reload. |
- control.reset([LabelWithFrame( |
- base::SysUTF8ToNSString(content.custom_link), frame) retain]); |
- SetControlSize(control.get(), NSSmallControlSize); |
- } |
- |
- // If the new control is wider than the container, widen the window. |
- CGFloat controlWidth = NSWidth([control frame]); |
- if (controlWidth > NSWidth(containerFrame)) { |
- NSRect windowFrame = [[self window] frame]; |
- windowFrame.size.width += controlWidth - NSWidth(containerFrame); |
- [[self window] setFrame:windowFrame display:NO]; |
- // Fetch the updated sizes. |
- containerFrame = [contentsContainer_ frame]; |
- frame = NSMakeRect(0, 0, NSWidth(containerFrame), kGeoLabelHeight); |
- } |
- |
- DCHECK(control); |
- [contentsContainer_ addSubview:control]; |
- frame.origin.y = NSMaxY([control frame]) + kGeoPadding; |
- } |
- |
- typedef |
- std::vector<ContentSettingBubbleModel::DomainList>::const_reverse_iterator |
- GeolocationGroupIterator; |
- for (GeolocationGroupIterator i = content.domain_lists.rbegin(); |
- i != content.domain_lists.rend(); ++i) { |
- // Add all hosts in the current domain list. |
- for (std::set<std::string>::const_reverse_iterator j = i->hosts.rbegin(); |
- j != i->hosts.rend(); ++j) { |
- NSTextField* title = LabelWithFrame(base::SysUTF8ToNSString(*j), frame); |
- SetControlSize(title, NSSmallControlSize); |
- [contentsContainer_ addSubview:title]; |
- |
- frame.origin.y = NSMaxY(frame) + kGeoHostPadding + |
- [GTMUILocalizerAndLayoutTweaker sizeToFitFixedWidthTextField:title]; |
- } |
- if (!i->hosts.empty()) |
- frame.origin.y += kGeoPadding - kGeoHostPadding; |
- |
- // Add the domain list's title. |
- NSTextField* title = |
- LabelWithFrame(base::SysUTF8ToNSString(i->title), frame); |
- SetControlSize(title, NSSmallControlSize); |
- [contentsContainer_ addSubview:title]; |
- |
- frame.origin.y = NSMaxY(frame) + kGeoPadding + |
- [GTMUILocalizerAndLayoutTweaker sizeToFitFixedWidthTextField:title]; |
- } |
- |
- CGFloat containerHeight = frame.origin.y; |
- // Undo last padding. |
- if (!content.domain_lists.empty()) |
- containerHeight -= kGeoPadding; |
- |
- // Resize container to fit its subviews, and window to fit the container. |
- NSRect windowFrame = [[self window] frame]; |
- windowFrame.size.height += containerHeight - NSHeight(containerFrame); |
- [[self window] setFrame:windowFrame display:NO]; |
- containerFrame.size.height = containerHeight; |
- [contentsContainer_ setFrame:containerFrame]; |
-} |
- |
-- (void)sizeToFitLoadPluginsButton { |
- const ContentSettingBubbleModel::BubbleContent& content = |
- contentSettingBubbleModel_->bubble_content(); |
- [loadAllPluginsButton_ setEnabled:content.custom_link_enabled]; |
- |
- // Resize horizontally to fit button if necessary. |
- NSRect windowFrame = [[self window] frame]; |
- int widthNeeded = NSWidth([loadAllPluginsButton_ frame]) + |
- 2 * NSMinX([loadAllPluginsButton_ frame]); |
- if (NSWidth(windowFrame) < widthNeeded) { |
- windowFrame.size.width = widthNeeded; |
- [[self window] setFrame:windowFrame display:NO]; |
- } |
-} |
- |
-- (void)sizeToFitManageDoneButtons { |
- CGFloat actualWidth = NSWidth([[[self window] contentView] frame]); |
- CGFloat requiredWidth = NSMaxX([manageButton_ frame]) + kManageDonePadding + |
- NSWidth([[doneButton_ superview] frame]) - NSMinX([doneButton_ frame]); |
- if (requiredWidth <= actualWidth || !doneButton_ || !manageButton_) |
- return; |
- |
- // Resize window, autoresizing takes care of the rest. |
- NSSize size = NSMakeSize(requiredWidth - actualWidth, 0); |
- size = [[[self window] contentView] convertSize:size toView:nil]; |
- NSRect frame = [[self window] frame]; |
- frame.origin.x -= size.width; |
- frame.size.width += size.width; |
- [[self window] setFrame:frame display:NO]; |
-} |
- |
-- (void)awakeFromNib { |
- [super awakeFromNib]; |
- |
- [[self bubble] setArrowLocation:info_bubble::kTopRight]; |
- |
- // Adapt window size to bottom buttons. Do this before all other layouting. |
- [self sizeToFitManageDoneButtons]; |
- |
- [self initializeTitle]; |
- |
- ContentSettingsType type = contentSettingBubbleModel_->content_type(); |
- if (type == CONTENT_SETTINGS_TYPE_PLUGINS) { |
- [self sizeToFitLoadPluginsButton]; |
- [self initializeBlockedPluginsList]; |
- } |
- if (allowBlockRadioGroup_) // not bound in cookie bubble xib |
- [self initializeRadioGroup]; |
- |
- if (type == CONTENT_SETTINGS_TYPE_POPUPS) |
- [self initializePopupList]; |
- if (type == CONTENT_SETTINGS_TYPE_GEOLOCATION) |
- [self initializeGeoLists]; |
-} |
- |
-/////////////////////////////////////////////////////////////////////////////// |
-// Actual application logic |
- |
-- (IBAction)allowBlockToggled:(id)sender { |
- NSButtonCell *selectedCell = [sender selectedCell]; |
- contentSettingBubbleModel_->OnRadioClicked( |
- [selectedCell tag] == kAllowTag ? 0 : 1); |
-} |
- |
-- (void)popupLinkClicked:(id)sender { |
- content_setting_bubble::PopupLinks::iterator i(popupLinks_.find(sender)); |
- DCHECK(i != popupLinks_.end()); |
- contentSettingBubbleModel_->OnPopupClicked(i->second); |
-} |
- |
-- (void)clearGeolocationForCurrentHost:(id)sender { |
- contentSettingBubbleModel_->OnCustomLinkClicked(); |
- [self close]; |
-} |
- |
-- (IBAction)showMoreInfo:(id)sender { |
- contentSettingBubbleModel_->OnCustomLinkClicked(); |
- [self close]; |
-} |
- |
-- (IBAction)loadAllPlugins:(id)sender { |
- contentSettingBubbleModel_->OnCustomLinkClicked(); |
- [self close]; |
-} |
- |
-- (IBAction)manageBlocking:(id)sender { |
- contentSettingBubbleModel_->OnManageLinkClicked(); |
-} |
- |
-- (IBAction)closeBubble:(id)sender { |
- [self close]; |
-} |
- |
-@end // ContentSettingBubbleController |