| OLD | NEW |
| (Empty) |
| 1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. | |
| 2 // Use of this source code is governed by a BSD-style license that can be | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 #import "chrome/browser/ui/cocoa/content_setting_bubble_cocoa.h" | |
| 6 | |
| 7 #include "app/l10n_util.h" | |
| 8 #include "base/command_line.h" | |
| 9 #include "base/logging.h" | |
| 10 #include "base/sys_string_conversions.h" | |
| 11 #include "base/utf_string_conversions.h" | |
| 12 #include "chrome/browser/blocked_content_container.h" | |
| 13 #include "chrome/browser/content_setting_bubble_model.h" | |
| 14 #include "chrome/browser/content_settings/host_content_settings_map.h" | |
| 15 #include "chrome/browser/plugin_updater.h" | |
| 16 #import "chrome/browser/ui/cocoa/hyperlink_button_cell.h" | |
| 17 #import "chrome/browser/ui/cocoa/info_bubble_view.h" | |
| 18 #import "chrome/browser/ui/cocoa/l10n_util.h" | |
| 19 #import "chrome/browser/ui/cocoa/options/content_settings_dialog_controller.h" | |
| 20 #include "grit/generated_resources.h" | |
| 21 #include "skia/ext/skia_utils_mac.h" | |
| 22 #import "third_party/GTM/AppKit/GTMUILocalizerAndLayoutTweaker.h" | |
| 23 #include "webkit/glue/plugins/plugin_list.h" | |
| 24 | |
| 25 namespace { | |
| 26 | |
| 27 // Must match the tag of the unblock radio button in the xib files. | |
| 28 const int kAllowTag = 1; | |
| 29 | |
| 30 // Must match the tag of the block radio button in the xib files. | |
| 31 const int kBlockTag = 2; | |
| 32 | |
| 33 // Height of one link in the popup list. | |
| 34 const int kLinkHeight = 16; | |
| 35 | |
| 36 // Space between two popup links. | |
| 37 const int kLinkPadding = 4; | |
| 38 | |
| 39 // Space taken in total by one popup link. | |
| 40 const int kLinkLineHeight = kLinkHeight + kLinkPadding; | |
| 41 | |
| 42 // Space between popup list and surrounding UI elements. | |
| 43 const int kLinkOuterPadding = 8; | |
| 44 | |
| 45 // Height of each of the labels in the geolocation bubble. | |
| 46 const int kGeoLabelHeight = 14; | |
| 47 | |
| 48 // Height of the "Clear" button in the geolocation bubble. | |
| 49 const int kGeoClearButtonHeight = 17; | |
| 50 | |
| 51 // Padding between radio buttons and "Load all plugins" button | |
| 52 // in the plugin bubble. | |
| 53 const int kLoadAllPluginsButtonVerticalPadding = 8; | |
| 54 | |
| 55 // General padding between elements in the geolocation bubble. | |
| 56 const int kGeoPadding = 8; | |
| 57 | |
| 58 // Padding between host names in the geolocation bubble. | |
| 59 const int kGeoHostPadding = 4; | |
| 60 | |
| 61 // Minimal padding between "Manage" and "Done" buttons. | |
| 62 const int kManageDonePadding = 8; | |
| 63 | |
| 64 void SetControlSize(NSControl* control, NSControlSize controlSize) { | |
| 65 CGFloat fontSize = [NSFont systemFontSizeForControlSize:controlSize]; | |
| 66 NSCell* cell = [control cell]; | |
| 67 NSFont* font = [NSFont fontWithName:[[cell font] fontName] size:fontSize]; | |
| 68 [cell setFont:font]; | |
| 69 [cell setControlSize:controlSize]; | |
| 70 } | |
| 71 | |
| 72 // Returns an autoreleased NSTextField that is configured to look like a Label | |
| 73 // looks in Interface Builder. | |
| 74 NSTextField* LabelWithFrame(NSString* text, const NSRect& frame) { | |
| 75 NSTextField* label = [[NSTextField alloc] initWithFrame:frame]; | |
| 76 [label setStringValue:text]; | |
| 77 [label setSelectable:NO]; | |
| 78 [label setBezeled:NO]; | |
| 79 return [label autorelease]; | |
| 80 } | |
| 81 | |
| 82 } // namespace | |
| 83 | |
| 84 @interface ContentSettingBubbleController(Private) | |
| 85 - (id)initWithModel:(ContentSettingBubbleModel*)settingsBubbleModel | |
| 86 parentWindow:(NSWindow*)parentWindow | |
| 87 anchoredAt:(NSPoint)anchoredAt; | |
| 88 - (NSButton*)hyperlinkButtonWithFrame:(NSRect)frame | |
| 89 title:(NSString*)title | |
| 90 icon:(NSImage*)icon | |
| 91 referenceFrame:(NSRect)referenceFrame; | |
| 92 - (void)initializeBlockedPluginsList; | |
| 93 - (void)initializeTitle; | |
| 94 - (void)initializeRadioGroup; | |
| 95 - (void)initializePopupList; | |
| 96 - (void)initializeGeoLists; | |
| 97 - (void)sizeToFitLoadPluginsButton; | |
| 98 - (void)sizeToFitManageDoneButtons; | |
| 99 - (void)removeInfoButton; | |
| 100 - (void)popupLinkClicked:(id)sender; | |
| 101 - (void)clearGeolocationForCurrentHost:(id)sender; | |
| 102 @end | |
| 103 | |
| 104 @implementation ContentSettingBubbleController | |
| 105 | |
| 106 + (ContentSettingBubbleController*) | |
| 107 showForModel:(ContentSettingBubbleModel*)contentSettingBubbleModel | |
| 108 parentWindow:(NSWindow*)parentWindow | |
| 109 anchoredAt:(NSPoint)anchor { | |
| 110 // Autoreleases itself on bubble close. | |
| 111 return [[ContentSettingBubbleController alloc] | |
| 112 initWithModel:contentSettingBubbleModel | |
| 113 parentWindow:parentWindow | |
| 114 anchoredAt:anchor]; | |
| 115 } | |
| 116 | |
| 117 - (id)initWithModel:(ContentSettingBubbleModel*)contentSettingBubbleModel | |
| 118 parentWindow:(NSWindow*)parentWindow | |
| 119 anchoredAt:(NSPoint)anchoredAt { | |
| 120 // This method takes ownership of |contentSettingBubbleModel| in all cases. | |
| 121 scoped_ptr<ContentSettingBubbleModel> model(contentSettingBubbleModel); | |
| 122 DCHECK(model.get()); | |
| 123 | |
| 124 NSString* const nibPaths[] = { | |
| 125 @"ContentBlockedCookies", | |
| 126 @"ContentBlockedImages", | |
| 127 @"ContentBlockedJavaScript", | |
| 128 @"ContentBlockedPlugins", | |
| 129 @"ContentBlockedPopups", | |
| 130 @"ContentBubbleGeolocation", | |
| 131 @"", // Notifications do not have a bubble. | |
| 132 }; | |
| 133 COMPILE_ASSERT(arraysize(nibPaths) == CONTENT_SETTINGS_NUM_TYPES, | |
| 134 nibPaths_requires_an_entry_for_every_setting_type); | |
| 135 const int settingsType = model->content_type(); | |
| 136 // Nofifications do not have a bubble. | |
| 137 CHECK_NE(settingsType, CONTENT_SETTINGS_TYPE_NOTIFICATIONS); | |
| 138 DCHECK_LT(settingsType, CONTENT_SETTINGS_NUM_TYPES); | |
| 139 if ((self = [super initWithWindowNibPath:nibPaths[settingsType] | |
| 140 parentWindow:parentWindow | |
| 141 anchoredAt:anchoredAt])) { | |
| 142 contentSettingBubbleModel_.reset(model.release()); | |
| 143 [self showWindow:nil]; | |
| 144 } | |
| 145 return self; | |
| 146 } | |
| 147 | |
| 148 - (void)initializeTitle { | |
| 149 if (!titleLabel_) | |
| 150 return; | |
| 151 | |
| 152 NSString* label = base::SysUTF8ToNSString( | |
| 153 contentSettingBubbleModel_->bubble_content().title); | |
| 154 [titleLabel_ setStringValue:label]; | |
| 155 | |
| 156 // Layout title post-localization. | |
| 157 CGFloat deltaY = [GTMUILocalizerAndLayoutTweaker | |
| 158 sizeToFitFixedWidthTextField:titleLabel_]; | |
| 159 NSRect windowFrame = [[self window] frame]; | |
| 160 windowFrame.size.height += deltaY; | |
| 161 [[self window] setFrame:windowFrame display:NO]; | |
| 162 NSRect titleFrame = [titleLabel_ frame]; | |
| 163 titleFrame.origin.y -= deltaY; | |
| 164 [titleLabel_ setFrame:titleFrame]; | |
| 165 } | |
| 166 | |
| 167 - (void)initializeRadioGroup { | |
| 168 // Configure the radio group. For now, only deal with the | |
| 169 // strictly needed case of group containing 2 radio buttons. | |
| 170 const ContentSettingBubbleModel::RadioGroup& radio_group = | |
| 171 contentSettingBubbleModel_->bubble_content().radio_group; | |
| 172 | |
| 173 // Select appropriate radio button. | |
| 174 [allowBlockRadioGroup_ selectCellWithTag: | |
| 175 radio_group.default_item == 0 ? kAllowTag : kBlockTag]; | |
| 176 | |
| 177 const ContentSettingBubbleModel::RadioItems& radio_items = | |
| 178 radio_group.radio_items; | |
| 179 DCHECK_EQ(2u, radio_items.size()) << "Only 2 radio items per group supported"; | |
| 180 // Set radio group labels from model. | |
| 181 NSCell* radioCell = [allowBlockRadioGroup_ cellWithTag:kAllowTag]; | |
| 182 [radioCell setTitle:base::SysUTF8ToNSString(radio_items[0])]; | |
| 183 | |
| 184 radioCell = [allowBlockRadioGroup_ cellWithTag:kBlockTag]; | |
| 185 [radioCell setTitle:base::SysUTF8ToNSString(radio_items[1])]; | |
| 186 | |
| 187 // Layout radio group labels post-localization. | |
| 188 [GTMUILocalizerAndLayoutTweaker | |
| 189 wrapRadioGroupForWidth:allowBlockRadioGroup_]; | |
| 190 CGFloat radioDeltaY = [GTMUILocalizerAndLayoutTweaker | |
| 191 sizeToFitView:allowBlockRadioGroup_].height; | |
| 192 NSRect windowFrame = [[self window] frame]; | |
| 193 windowFrame.size.height += radioDeltaY; | |
| 194 [[self window] setFrame:windowFrame display:NO]; | |
| 195 } | |
| 196 | |
| 197 - (NSButton*)hyperlinkButtonWithFrame:(NSRect)frame | |
| 198 title:(NSString*)title | |
| 199 icon:(NSImage*)icon | |
| 200 referenceFrame:(NSRect)referenceFrame { | |
| 201 scoped_nsobject<HyperlinkButtonCell> cell([[HyperlinkButtonCell alloc] | |
| 202 initTextCell:title]); | |
| 203 [cell.get() setAlignment:NSNaturalTextAlignment]; | |
| 204 if (icon) { | |
| 205 [cell.get() setImagePosition:NSImageLeft]; | |
| 206 [cell.get() setImage:icon]; | |
| 207 } else { | |
| 208 [cell.get() setImagePosition:NSNoImage]; | |
| 209 } | |
| 210 [cell.get() setControlSize:NSSmallControlSize]; | |
| 211 | |
| 212 NSButton* button = [[[NSButton alloc] initWithFrame:frame] autorelease]; | |
| 213 // Cell must be set immediately after construction. | |
| 214 [button setCell:cell.get()]; | |
| 215 | |
| 216 // If the link text is too long, clamp it. | |
| 217 [button sizeToFit]; | |
| 218 int maxWidth = NSWidth([[self bubble] frame]) - 2 * NSMinX(referenceFrame); | |
| 219 NSRect buttonFrame = [button frame]; | |
| 220 if (NSWidth(buttonFrame) > maxWidth) { | |
| 221 buttonFrame.size.width = maxWidth; | |
| 222 [button setFrame:buttonFrame]; | |
| 223 } | |
| 224 | |
| 225 [button setTarget:self]; | |
| 226 [button setAction:@selector(popupLinkClicked:)]; | |
| 227 return button; | |
| 228 } | |
| 229 | |
| 230 - (void)initializeBlockedPluginsList { | |
| 231 NSMutableArray* pluginArray = [NSMutableArray array]; | |
| 232 const std::set<std::string>& plugins = | |
| 233 contentSettingBubbleModel_->bubble_content().resource_identifiers; | |
| 234 if (plugins.empty()) { | |
| 235 int delta = NSMinY([titleLabel_ frame]) - | |
| 236 NSMinY([blockedResourcesField_ frame]); | |
| 237 [blockedResourcesField_ removeFromSuperview]; | |
| 238 NSRect frame = [[self window] frame]; | |
| 239 frame.size.height -= delta; | |
| 240 [[self window] setFrame:frame display:NO]; | |
| 241 } else { | |
| 242 for (std::set<std::string>::iterator it = plugins.begin(); | |
| 243 it != plugins.end(); ++it) { | |
| 244 NSString* name = SysUTF16ToNSString( | |
| 245 NPAPI::PluginList::Singleton()->GetPluginGroupName(*it)); | |
| 246 if ([name length] == 0) | |
| 247 name = base::SysUTF8ToNSString(*it); | |
| 248 [pluginArray addObject:name]; | |
| 249 } | |
| 250 [blockedResourcesField_ | |
| 251 setStringValue:[pluginArray componentsJoinedByString:@"\n"]]; | |
| 252 [GTMUILocalizerAndLayoutTweaker | |
| 253 sizeToFitFixedWidthTextField:blockedResourcesField_]; | |
| 254 } | |
| 255 } | |
| 256 | |
| 257 - (void)initializePopupList { | |
| 258 // I didn't put the buttons into a NSMatrix because then they are only one | |
| 259 // entity in the key view loop. This way, one can tab through all of them. | |
| 260 const ContentSettingBubbleModel::PopupItems& popupItems = | |
| 261 contentSettingBubbleModel_->bubble_content().popup_items; | |
| 262 | |
| 263 // Get the pre-resize frame of the radio group. Its origin is where the | |
| 264 // popup list should go. | |
| 265 NSRect radioFrame = [allowBlockRadioGroup_ frame]; | |
| 266 | |
| 267 // Make room for the popup list. The bubble view and its subviews autosize | |
| 268 // themselves when the window is enlarged. | |
| 269 // Heading and radio box are already 1 * kLinkOuterPadding apart in the nib, | |
| 270 // so only 1 * kLinkOuterPadding more is needed. | |
| 271 int delta = popupItems.size() * kLinkLineHeight - kLinkPadding + | |
| 272 kLinkOuterPadding; | |
| 273 NSSize deltaSize = NSMakeSize(0, delta); | |
| 274 deltaSize = [[[self window] contentView] convertSize:deltaSize toView:nil]; | |
| 275 NSRect windowFrame = [[self window] frame]; | |
| 276 windowFrame.size.height += deltaSize.height; | |
| 277 [[self window] setFrame:windowFrame display:NO]; | |
| 278 | |
| 279 // Create popup list. | |
| 280 int topLinkY = NSMaxY(radioFrame) + delta - kLinkHeight; | |
| 281 int row = 0; | |
| 282 for (std::vector<ContentSettingBubbleModel::PopupItem>::const_iterator | |
| 283 it(popupItems.begin()); it != popupItems.end(); ++it, ++row) { | |
| 284 const SkBitmap& icon = it->bitmap; | |
| 285 NSImage* image = nil; | |
| 286 if (!icon.empty()) | |
| 287 image = gfx::SkBitmapToNSImage(icon); | |
| 288 | |
| 289 std::string title(it->title); | |
| 290 // The popup may not have committed a load yet, in which case it won't | |
| 291 // have a URL or title. | |
| 292 if (title.empty()) | |
| 293 title = l10n_util::GetStringUTF8(IDS_TAB_LOADING_TITLE); | |
| 294 | |
| 295 NSRect linkFrame = | |
| 296 NSMakeRect(NSMinX(radioFrame), topLinkY - kLinkLineHeight * row, | |
| 297 200, kLinkHeight); | |
| 298 NSButton* button = [self | |
| 299 hyperlinkButtonWithFrame:linkFrame | |
| 300 title:base::SysUTF8ToNSString(title) | |
| 301 icon:image | |
| 302 referenceFrame:radioFrame]; | |
| 303 [[self bubble] addSubview:button]; | |
| 304 popupLinks_[button] = row; | |
| 305 } | |
| 306 } | |
| 307 | |
| 308 - (void)initializeGeoLists { | |
| 309 // Cocoa has its origin in the lower left corner. This means elements are | |
| 310 // added from bottom to top, which explains why loops run backwards and the | |
| 311 // order of operations is the other way than on Linux/Windows. | |
| 312 const ContentSettingBubbleModel::BubbleContent& content = | |
| 313 contentSettingBubbleModel_->bubble_content(); | |
| 314 NSRect containerFrame = [contentsContainer_ frame]; | |
| 315 NSRect frame = NSMakeRect(0, 0, NSWidth(containerFrame), kGeoLabelHeight); | |
| 316 | |
| 317 // "Clear" button / text field. | |
| 318 if (!content.custom_link.empty()) { | |
| 319 scoped_nsobject<NSControl> control; | |
| 320 if(content.custom_link_enabled) { | |
| 321 NSRect buttonFrame = NSMakeRect(0, 0, | |
| 322 NSWidth(containerFrame), | |
| 323 kGeoClearButtonHeight); | |
| 324 NSButton* button = [[NSButton alloc] initWithFrame:buttonFrame]; | |
| 325 control.reset(button); | |
| 326 [button setTitle:base::SysUTF8ToNSString(content.custom_link)]; | |
| 327 [button setTarget:self]; | |
| 328 [button setAction:@selector(clearGeolocationForCurrentHost:)]; | |
| 329 [button setBezelStyle:NSRoundRectBezelStyle]; | |
| 330 SetControlSize(button, NSSmallControlSize); | |
| 331 [button sizeToFit]; | |
| 332 } else { | |
| 333 // Add the notification that settings will be cleared on next reload. | |
| 334 control.reset([LabelWithFrame( | |
| 335 base::SysUTF8ToNSString(content.custom_link), frame) retain]); | |
| 336 SetControlSize(control.get(), NSSmallControlSize); | |
| 337 } | |
| 338 | |
| 339 // If the new control is wider than the container, widen the window. | |
| 340 CGFloat controlWidth = NSWidth([control frame]); | |
| 341 if (controlWidth > NSWidth(containerFrame)) { | |
| 342 NSRect windowFrame = [[self window] frame]; | |
| 343 windowFrame.size.width += controlWidth - NSWidth(containerFrame); | |
| 344 [[self window] setFrame:windowFrame display:NO]; | |
| 345 // Fetch the updated sizes. | |
| 346 containerFrame = [contentsContainer_ frame]; | |
| 347 frame = NSMakeRect(0, 0, NSWidth(containerFrame), kGeoLabelHeight); | |
| 348 } | |
| 349 | |
| 350 DCHECK(control); | |
| 351 [contentsContainer_ addSubview:control]; | |
| 352 frame.origin.y = NSMaxY([control frame]) + kGeoPadding; | |
| 353 } | |
| 354 | |
| 355 typedef | |
| 356 std::vector<ContentSettingBubbleModel::DomainList>::const_reverse_iterator | |
| 357 GeolocationGroupIterator; | |
| 358 for (GeolocationGroupIterator i = content.domain_lists.rbegin(); | |
| 359 i != content.domain_lists.rend(); ++i) { | |
| 360 // Add all hosts in the current domain list. | |
| 361 for (std::set<std::string>::const_reverse_iterator j = i->hosts.rbegin(); | |
| 362 j != i->hosts.rend(); ++j) { | |
| 363 NSTextField* title = LabelWithFrame(base::SysUTF8ToNSString(*j), frame); | |
| 364 SetControlSize(title, NSSmallControlSize); | |
| 365 [contentsContainer_ addSubview:title]; | |
| 366 | |
| 367 frame.origin.y = NSMaxY(frame) + kGeoHostPadding + | |
| 368 [GTMUILocalizerAndLayoutTweaker sizeToFitFixedWidthTextField:title]; | |
| 369 } | |
| 370 if (!i->hosts.empty()) | |
| 371 frame.origin.y += kGeoPadding - kGeoHostPadding; | |
| 372 | |
| 373 // Add the domain list's title. | |
| 374 NSTextField* title = | |
| 375 LabelWithFrame(base::SysUTF8ToNSString(i->title), frame); | |
| 376 SetControlSize(title, NSSmallControlSize); | |
| 377 [contentsContainer_ addSubview:title]; | |
| 378 | |
| 379 frame.origin.y = NSMaxY(frame) + kGeoPadding + | |
| 380 [GTMUILocalizerAndLayoutTweaker sizeToFitFixedWidthTextField:title]; | |
| 381 } | |
| 382 | |
| 383 CGFloat containerHeight = frame.origin.y; | |
| 384 // Undo last padding. | |
| 385 if (!content.domain_lists.empty()) | |
| 386 containerHeight -= kGeoPadding; | |
| 387 | |
| 388 // Resize container to fit its subviews, and window to fit the container. | |
| 389 NSRect windowFrame = [[self window] frame]; | |
| 390 windowFrame.size.height += containerHeight - NSHeight(containerFrame); | |
| 391 [[self window] setFrame:windowFrame display:NO]; | |
| 392 containerFrame.size.height = containerHeight; | |
| 393 [contentsContainer_ setFrame:containerFrame]; | |
| 394 } | |
| 395 | |
| 396 - (void)sizeToFitLoadPluginsButton { | |
| 397 const ContentSettingBubbleModel::BubbleContent& content = | |
| 398 contentSettingBubbleModel_->bubble_content(); | |
| 399 [loadAllPluginsButton_ setEnabled:content.custom_link_enabled]; | |
| 400 | |
| 401 // Resize horizontally to fit button if necessary. | |
| 402 NSRect windowFrame = [[self window] frame]; | |
| 403 int widthNeeded = NSWidth([loadAllPluginsButton_ frame]) + | |
| 404 2 * NSMinX([loadAllPluginsButton_ frame]); | |
| 405 if (NSWidth(windowFrame) < widthNeeded) { | |
| 406 windowFrame.size.width = widthNeeded; | |
| 407 [[self window] setFrame:windowFrame display:NO]; | |
| 408 } | |
| 409 } | |
| 410 | |
| 411 - (void)sizeToFitManageDoneButtons { | |
| 412 CGFloat actualWidth = NSWidth([[[self window] contentView] frame]); | |
| 413 CGFloat requiredWidth = NSMaxX([manageButton_ frame]) + kManageDonePadding + | |
| 414 NSWidth([[doneButton_ superview] frame]) - NSMinX([doneButton_ frame]); | |
| 415 if (requiredWidth <= actualWidth || !doneButton_ || !manageButton_) | |
| 416 return; | |
| 417 | |
| 418 // Resize window, autoresizing takes care of the rest. | |
| 419 NSSize size = NSMakeSize(requiredWidth - actualWidth, 0); | |
| 420 size = [[[self window] contentView] convertSize:size toView:nil]; | |
| 421 NSRect frame = [[self window] frame]; | |
| 422 frame.origin.x -= size.width; | |
| 423 frame.size.width += size.width; | |
| 424 [[self window] setFrame:frame display:NO]; | |
| 425 } | |
| 426 | |
| 427 - (void)awakeFromNib { | |
| 428 [super awakeFromNib]; | |
| 429 | |
| 430 [[self bubble] setArrowLocation:info_bubble::kTopRight]; | |
| 431 | |
| 432 // Adapt window size to bottom buttons. Do this before all other layouting. | |
| 433 [self sizeToFitManageDoneButtons]; | |
| 434 | |
| 435 [self initializeTitle]; | |
| 436 | |
| 437 ContentSettingsType type = contentSettingBubbleModel_->content_type(); | |
| 438 if (type == CONTENT_SETTINGS_TYPE_PLUGINS) { | |
| 439 [self sizeToFitLoadPluginsButton]; | |
| 440 [self initializeBlockedPluginsList]; | |
| 441 } | |
| 442 if (allowBlockRadioGroup_) // not bound in cookie bubble xib | |
| 443 [self initializeRadioGroup]; | |
| 444 | |
| 445 if (type == CONTENT_SETTINGS_TYPE_POPUPS) | |
| 446 [self initializePopupList]; | |
| 447 if (type == CONTENT_SETTINGS_TYPE_GEOLOCATION) | |
| 448 [self initializeGeoLists]; | |
| 449 } | |
| 450 | |
| 451 /////////////////////////////////////////////////////////////////////////////// | |
| 452 // Actual application logic | |
| 453 | |
| 454 - (IBAction)allowBlockToggled:(id)sender { | |
| 455 NSButtonCell *selectedCell = [sender selectedCell]; | |
| 456 contentSettingBubbleModel_->OnRadioClicked( | |
| 457 [selectedCell tag] == kAllowTag ? 0 : 1); | |
| 458 } | |
| 459 | |
| 460 - (void)popupLinkClicked:(id)sender { | |
| 461 content_setting_bubble::PopupLinks::iterator i(popupLinks_.find(sender)); | |
| 462 DCHECK(i != popupLinks_.end()); | |
| 463 contentSettingBubbleModel_->OnPopupClicked(i->second); | |
| 464 } | |
| 465 | |
| 466 - (void)clearGeolocationForCurrentHost:(id)sender { | |
| 467 contentSettingBubbleModel_->OnCustomLinkClicked(); | |
| 468 [self close]; | |
| 469 } | |
| 470 | |
| 471 - (IBAction)showMoreInfo:(id)sender { | |
| 472 contentSettingBubbleModel_->OnCustomLinkClicked(); | |
| 473 [self close]; | |
| 474 } | |
| 475 | |
| 476 - (IBAction)loadAllPlugins:(id)sender { | |
| 477 contentSettingBubbleModel_->OnCustomLinkClicked(); | |
| 478 [self close]; | |
| 479 } | |
| 480 | |
| 481 - (IBAction)manageBlocking:(id)sender { | |
| 482 contentSettingBubbleModel_->OnManageLinkClicked(); | |
| 483 } | |
| 484 | |
| 485 - (IBAction)closeBubble:(id)sender { | |
| 486 [self close]; | |
| 487 } | |
| 488 | |
| 489 @end // ContentSettingBubbleController | |
| OLD | NEW |