| OLD | NEW |
| 1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #import "chrome/browser/cocoa/content_blocked_bubble_controller.h" | 5 #import "chrome/browser/cocoa/content_blocked_bubble_controller.h" |
| 6 | 6 |
| 7 #include "app/l10n_util.h" | 7 #include "app/l10n_util.h" |
| 8 #include "base/logging.h" | 8 #include "base/logging.h" |
| 9 #include "base/mac_util.h" | |
| 10 #include "base/string_util.h" | |
| 11 #include "base/sys_string_conversions.h" | 9 #include "base/sys_string_conversions.h" |
| 12 #include "chrome/browser/blocked_popup_container.h" | 10 #include "chrome/browser/blocked_popup_container.h" |
| 13 #import "chrome/browser/cocoa/content_settings_dialog_controller.h" | 11 #import "chrome/browser/cocoa/content_settings_dialog_controller.h" |
| 14 #import "chrome/browser/cocoa/hyperlink_button_cell.h" | 12 #import "chrome/browser/cocoa/hyperlink_button_cell.h" |
| 15 #import "chrome/browser/cocoa/info_bubble_view.h" | 13 #import "chrome/browser/cocoa/info_bubble_view.h" |
| 14 #import "chrome/browser/cocoa/l10n_util.h" |
| 16 #include "chrome/browser/content_setting_bubble_model.h" | 15 #include "chrome/browser/content_setting_bubble_model.h" |
| 17 #include "chrome/browser/host_content_settings_map.h" | 16 #include "chrome/browser/host_content_settings_map.h" |
| 18 #include "chrome/common/notification_service.h" | |
| 19 #include "chrome/common/notification_type.h" | |
| 20 #include "grit/generated_resources.h" | 17 #include "grit/generated_resources.h" |
| 21 #include "skia/ext/skia_utils_mac.h" | 18 #include "skia/ext/skia_utils_mac.h" |
| 22 #import "third_party/GTM/AppKit/GTMUILocalizerAndLayoutTweaker.h" | 19 #import "third_party/GTM/AppKit/GTMUILocalizerAndLayoutTweaker.h" |
| 23 | 20 |
| 24 namespace { | 21 namespace { |
| 25 | 22 |
| 26 // Must match the tag of the unblock radio button in the xib files. | 23 // Must match the tag of the unblock radio button in the xib files. |
| 27 const int kAllowTag = 1; | 24 const int kAllowTag = 1; |
| 28 | 25 |
| 29 // Must match the tag of the block radio button in the xib files. | 26 // Must match the tag of the block radio button in the xib files. |
| (...skipping 19 matching lines...) Expand all Loading... |
| 49 | 46 |
| 50 // General padding between elements in the geolocation bubble. | 47 // General padding between elements in the geolocation bubble. |
| 51 const int kGeoPadding = 8; | 48 const int kGeoPadding = 8; |
| 52 | 49 |
| 53 // Padding between host names in the geolocation bubble. | 50 // Padding between host names in the geolocation bubble. |
| 54 const int kGeoHostPadding = 4; | 51 const int kGeoHostPadding = 4; |
| 55 | 52 |
| 56 // Minimal padding between "Manage" and "Done" buttons. | 53 // Minimal padding between "Manage" and "Done" buttons. |
| 57 const int kManageDonePadding = 8; | 54 const int kManageDonePadding = 8; |
| 58 | 55 |
| 59 // Like |ReplaceStringPlaceholders(const string16&, const string16&, size_t*)|, | |
| 60 // but for a NSString formatString. | |
| 61 NSString* ReplaceNSStringPlaceholders(NSString* formatString, | |
| 62 const string16& a, | |
| 63 size_t* offset) { | |
| 64 return base::SysUTF16ToNSString( | |
| 65 ReplaceStringPlaceholders(base::SysNSStringToUTF16(formatString), | |
| 66 a, | |
| 67 offset)); | |
| 68 } | |
| 69 | |
| 70 void SetControlSize(NSControl* control, NSControlSize controlSize) { | 56 void SetControlSize(NSControl* control, NSControlSize controlSize) { |
| 71 CGFloat fontSize = [NSFont systemFontSizeForControlSize:controlSize]; | 57 CGFloat fontSize = [NSFont systemFontSizeForControlSize:controlSize]; |
| 72 NSCell* cell = [control cell]; | 58 NSCell* cell = [control cell]; |
| 73 NSFont* font = [NSFont fontWithName:[[cell font] fontName] size:fontSize]; | 59 NSFont* font = [NSFont fontWithName:[[cell font] fontName] size:fontSize]; |
| 74 [cell setFont:font]; | 60 [cell setFont:font]; |
| 75 [cell setControlSize:controlSize]; | 61 [cell setControlSize:controlSize]; |
| 76 } | 62 } |
| 77 | 63 |
| 78 // Returns an autoreleased NSTextField that is configured to look like a Label | 64 // Returns an autoreleased NSTextField that is configured to look like a Label |
| 79 // looks in Interface Builder. | 65 // looks in Interface Builder. |
| (...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 129 @"ContentBlockedImages", | 115 @"ContentBlockedImages", |
| 130 @"ContentBlockedJavaScript", | 116 @"ContentBlockedJavaScript", |
| 131 @"ContentBlockedPlugins", | 117 @"ContentBlockedPlugins", |
| 132 @"ContentBlockedPopups", | 118 @"ContentBlockedPopups", |
| 133 @"ContentBubbleGeolocation", | 119 @"ContentBubbleGeolocation", |
| 134 }; | 120 }; |
| 135 COMPILE_ASSERT(arraysize(nibPaths) == CONTENT_SETTINGS_NUM_TYPES, | 121 COMPILE_ASSERT(arraysize(nibPaths) == CONTENT_SETTINGS_NUM_TYPES, |
| 136 nibPaths_requires_an_entry_for_every_setting_type); | 122 nibPaths_requires_an_entry_for_every_setting_type); |
| 137 const int settingsType = model->content_type(); | 123 const int settingsType = model->content_type(); |
| 138 DCHECK_LT(settingsType, CONTENT_SETTINGS_NUM_TYPES); | 124 DCHECK_LT(settingsType, CONTENT_SETTINGS_NUM_TYPES); |
| 139 NSString* nibPath = | 125 if ((self = [super initWithWindowNibPath:nibPaths[settingsType] |
| 140 [mac_util::MainAppBundle() pathForResource:nibPaths[settingsType] | 126 parentWindow:parentWindow |
| 141 ofType:@"nib"]; | 127 anchoredAt:anchoredAt])) { |
| 142 if ((self = [super initWithWindowNibPath:nibPath owner:self])) { | |
| 143 parentWindow_ = parentWindow; | |
| 144 anchor_ = anchoredAt; | |
| 145 contentSettingBubbleModel_.reset(model.release()); | 128 contentSettingBubbleModel_.reset(model.release()); |
| 146 | 129 [self showWindow:nil]; |
| 147 // Watch to see if the parent window closes, and if so, close this one. | |
| 148 NSNotificationCenter* center = [NSNotificationCenter defaultCenter]; | |
| 149 [center addObserver:self | |
| 150 selector:@selector(parentWindowWillClose:) | |
| 151 name:NSWindowWillCloseNotification | |
| 152 object:parentWindow_]; | |
| 153 } | 130 } |
| 154 return self; | 131 return self; |
| 155 } | 132 } |
| 156 | 133 |
| 157 - (void)initializeTitle { | 134 - (void)initializeTitle { |
| 158 if (!titleLabel_) | 135 if (!titleLabel_) |
| 159 return; | 136 return; |
| 160 | 137 |
| 161 // Layout title post-localization. | 138 // Layout title post-localization. |
| 162 CGFloat deltaY = [GTMUILocalizerAndLayoutTweaker | 139 CGFloat deltaY = [GTMUILocalizerAndLayoutTweaker |
| (...skipping 14 matching lines...) Expand all Loading... |
| 177 // http://crbug.com/38432 | 154 // http://crbug.com/38432 |
| 178 const ContentSettingBubbleModel::RadioGroup& radioGroup = | 155 const ContentSettingBubbleModel::RadioGroup& radioGroup = |
| 179 contentSettingBubbleModel_->bubble_content().radio_group; | 156 contentSettingBubbleModel_->bubble_content().radio_group; |
| 180 | 157 |
| 181 // Select appropriate radio button. | 158 // Select appropriate radio button. |
| 182 [allowBlockRadioGroup_ selectCellWithTag: | 159 [allowBlockRadioGroup_ selectCellWithTag: |
| 183 radioGroup.default_item == 0 ? kAllowTag : kBlockTag]; | 160 radioGroup.default_item == 0 ? kAllowTag : kBlockTag]; |
| 184 | 161 |
| 185 // Copy |host_| into radio group label. | 162 // Copy |host_| into radio group label. |
| 186 NSCell* radioCell = [allowBlockRadioGroup_ cellWithTag:kAllowTag]; | 163 NSCell* radioCell = [allowBlockRadioGroup_ cellWithTag:kAllowTag]; |
| 187 [radioCell setTitle:ReplaceNSStringPlaceholders( | 164 [radioCell setTitle:cocoa_l10n_util::ReplaceNSStringPlaceholders( |
| 188 [radioCell title], UTF8ToUTF16(radioGroup.url.host()), NULL)]; | 165 [radioCell title], UTF8ToUTF16(radioGroup.url.host()), NULL)]; |
| 189 | 166 |
| 190 // Layout radio group labels post-localization. | 167 // Layout radio group labels post-localization. |
| 191 [GTMUILocalizerAndLayoutTweaker | 168 [GTMUILocalizerAndLayoutTweaker |
| 192 wrapRadioGroupForWidth:allowBlockRadioGroup_]; | 169 wrapRadioGroupForWidth:allowBlockRadioGroup_]; |
| 193 CGFloat radioDeltaY = [GTMUILocalizerAndLayoutTweaker | 170 CGFloat radioDeltaY = [GTMUILocalizerAndLayoutTweaker |
| 194 sizeToFitView:allowBlockRadioGroup_].height; | 171 sizeToFitView:allowBlockRadioGroup_].height; |
| 195 NSRect windowFrame = [[self window] frame]; | 172 NSRect windowFrame = [[self window] frame]; |
| 196 windowFrame.size.height += radioDeltaY; | 173 windowFrame.size.height += radioDeltaY; |
| 197 [[self window] setFrame:windowFrame display:NO]; | 174 [[self window] setFrame:windowFrame display:NO]; |
| (...skipping 13 matching lines...) Expand all Loading... |
| 211 [cell.get() setImagePosition:NSNoImage]; | 188 [cell.get() setImagePosition:NSNoImage]; |
| 212 } | 189 } |
| 213 [cell.get() setControlSize:NSSmallControlSize]; | 190 [cell.get() setControlSize:NSSmallControlSize]; |
| 214 | 191 |
| 215 NSButton* button = [[[NSButton alloc] initWithFrame:frame] autorelease]; | 192 NSButton* button = [[[NSButton alloc] initWithFrame:frame] autorelease]; |
| 216 // Cell must be set immediately after construction. | 193 // Cell must be set immediately after construction. |
| 217 [button setCell:cell.get()]; | 194 [button setCell:cell.get()]; |
| 218 | 195 |
| 219 // If the link text is too long, clamp it. | 196 // If the link text is too long, clamp it. |
| 220 [button sizeToFit]; | 197 [button sizeToFit]; |
| 221 int maxWidth = NSWidth([bubble_ frame]) - 2 * NSMinX(referenceFrame); | 198 int maxWidth = NSWidth([[self bubble] frame]) - 2 * NSMinX(referenceFrame); |
| 222 NSRect buttonFrame = [button frame]; | 199 NSRect buttonFrame = [button frame]; |
| 223 if (NSWidth(buttonFrame) > maxWidth) { | 200 if (NSWidth(buttonFrame) > maxWidth) { |
| 224 buttonFrame.size.width = maxWidth; | 201 buttonFrame.size.width = maxWidth; |
| 225 [button setFrame:buttonFrame]; | 202 [button setFrame:buttonFrame]; |
| 226 } | 203 } |
| 227 | 204 |
| 228 [button setTarget:self]; | 205 [button setTarget:self]; |
| 229 [button setAction:@selector(popupLinkClicked:)]; | 206 [button setAction:@selector(popupLinkClicked:)]; |
| 230 return button; | 207 return button; |
| 231 } | 208 } |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 269 title = l10n_util::GetStringUTF8(IDS_TAB_LOADING_TITLE); | 246 title = l10n_util::GetStringUTF8(IDS_TAB_LOADING_TITLE); |
| 270 | 247 |
| 271 NSRect linkFrame = | 248 NSRect linkFrame = |
| 272 NSMakeRect(NSMinX(radioFrame), topLinkY - kLinkLineHeight * row, | 249 NSMakeRect(NSMinX(radioFrame), topLinkY - kLinkLineHeight * row, |
| 273 200, kLinkHeight); | 250 200, kLinkHeight); |
| 274 NSButton* button = [self | 251 NSButton* button = [self |
| 275 hyperlinkButtonWithFrame:linkFrame | 252 hyperlinkButtonWithFrame:linkFrame |
| 276 title:base::SysUTF8ToNSString(title) | 253 title:base::SysUTF8ToNSString(title) |
| 277 icon:image | 254 icon:image |
| 278 referenceFrame:radioFrame]; | 255 referenceFrame:radioFrame]; |
| 279 [bubble_ addSubview:button]; | 256 [[self bubble] addSubview:button]; |
| 280 popupLinks_[button] = row; | 257 popupLinks_[button] = row; |
| 281 } | 258 } |
| 282 } | 259 } |
| 283 | 260 |
| 284 - (void)initializeGeoLists { | 261 - (void)initializeGeoLists { |
| 285 // Cocoa has its origin in the lower left corner. This means elements are | 262 // Cocoa has its origin in the lower left corner. This means elements are |
| 286 // added from bottom to top, which explains why loops run backwards and the | 263 // added from bottom to top, which explains why loops run backwards and the |
| 287 // order of operations is the other way than on Linux/Windows. | 264 // order of operations is the other way than on Linux/Windows. |
| 288 const ContentSettingBubbleModel::BubbleContent& content = | 265 const ContentSettingBubbleModel::BubbleContent& content = |
| 289 contentSettingBubbleModel_->bubble_content(); | 266 contentSettingBubbleModel_->bubble_content(); |
| (...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 372 // Resize window, autoresizing takes care of the rest. | 349 // Resize window, autoresizing takes care of the rest. |
| 373 NSSize size = NSMakeSize(requiredWidth - actualWidth, 0); | 350 NSSize size = NSMakeSize(requiredWidth - actualWidth, 0); |
| 374 size = [[[self window] contentView] convertSize:size toView:nil]; | 351 size = [[[self window] contentView] convertSize:size toView:nil]; |
| 375 NSRect frame = [[self window] frame]; | 352 NSRect frame = [[self window] frame]; |
| 376 frame.origin.x -= size.width; | 353 frame.origin.x -= size.width; |
| 377 frame.size.width += size.width; | 354 frame.size.width += size.width; |
| 378 [[self window] setFrame:frame display:NO]; | 355 [[self window] setFrame:frame display:NO]; |
| 379 } | 356 } |
| 380 | 357 |
| 381 - (void)awakeFromNib { | 358 - (void)awakeFromNib { |
| 382 DCHECK([self window]); | 359 [[self bubble] setBubbleType:info_bubble::kWhiteInfoBubble]; |
| 383 DCHECK_EQ(self, [[self window] delegate]); | 360 [[self bubble] setArrowLocation:info_bubble::kTopRight]; |
| 384 | |
| 385 [bubble_ setBubbleType:info_bubble::kWhiteInfoBubble]; | |
| 386 [bubble_ setArrowLocation:info_bubble::kTopRight]; | |
| 387 | 361 |
| 388 // Adapt window size to bottom buttons. Do this before all other layouting. | 362 // Adapt window size to bottom buttons. Do this before all other layouting. |
| 389 [self sizeToFitManageDoneButtons]; | 363 [self sizeToFitManageDoneButtons]; |
| 390 | 364 |
| 391 [self initializeTitle]; | 365 [self initializeTitle]; |
| 392 if (allowBlockRadioGroup_) // not bound in cookie bubble xib | 366 if (allowBlockRadioGroup_) // not bound in cookie bubble xib |
| 393 [self initializeRadioGroup]; | 367 [self initializeRadioGroup]; |
| 394 if (contentSettingBubbleModel_->content_type() == | 368 if (contentSettingBubbleModel_->content_type() == |
| 395 CONTENT_SETTINGS_TYPE_POPUPS) | 369 CONTENT_SETTINGS_TYPE_POPUPS) |
| 396 [self initializePopupList]; | 370 [self initializePopupList]; |
| 397 if (contentSettingBubbleModel_->content_type() == | 371 if (contentSettingBubbleModel_->content_type() == |
| 398 CONTENT_SETTINGS_TYPE_GEOLOCATION) | 372 CONTENT_SETTINGS_TYPE_GEOLOCATION) |
| 399 [self initializeGeoLists]; | 373 [self initializeGeoLists]; |
| 400 } | 374 } |
| 401 | 375 |
| 402 /////////////////////////////////////////////////////////////////////////////// | 376 /////////////////////////////////////////////////////////////////////////////// |
| 403 // Bubble-management related stuff | |
| 404 | |
| 405 // TODO(thakis): All that junk below should be in some superclass that all the | |
| 406 // bubble controllers (bookmark bubble, extension installed bubble, page/browser | |
| 407 // action bubble, content blocked bubble) derive from -- http://crbug.com/36366 | |
| 408 | |
| 409 - (void)dealloc { | |
| 410 [[NSNotificationCenter defaultCenter] removeObserver:self]; | |
| 411 [super dealloc]; | |
| 412 } | |
| 413 | |
| 414 - (void)parentWindowWillClose:(NSNotification*)notification { | |
| 415 [self close]; | |
| 416 } | |
| 417 | |
| 418 - (void)windowWillClose:(NSNotification*)notification { | |
| 419 // We caught a close so we don't need to watch for the parent closing. | |
| 420 [[NSNotificationCenter defaultCenter] removeObserver:self]; | |
| 421 [self autorelease]; | |
| 422 } | |
| 423 | |
| 424 // We want this to be a child of a browser window. addChildWindow: | |
| 425 // (called from this function) will bring the window on-screen; | |
| 426 // unfortunately, [NSWindowController showWindow:] will also bring it | |
| 427 // on-screen (but will cause unexpected changes to the window's | |
| 428 // position). We cannot have an addChildWindow: and a subsequent | |
| 429 // showWindow:. Thus, we have our own version. | |
| 430 - (void)showWindow:(id)sender { | |
| 431 NSWindow* window = [self window]; // completes nib load | |
| 432 | |
| 433 NSPoint origin = anchor_; | |
| 434 NSSize offsets = NSMakeSize(info_bubble::kBubbleArrowXOffset + | |
| 435 info_bubble::kBubbleArrowWidth / 2.0, 0); | |
| 436 offsets = [[parentWindow_ contentView] convertSize:offsets toView:nil]; | |
| 437 origin.x -= NSWidth([window frame]) - offsets.width; | |
| 438 origin.y -= NSHeight([window frame]); | |
| 439 [window setFrameOrigin:origin]; | |
| 440 [parentWindow_ addChildWindow:window ordered:NSWindowAbove]; | |
| 441 [window makeKeyAndOrderFront:self]; | |
| 442 } | |
| 443 | |
| 444 - (void)close { | |
| 445 [parentWindow_ removeChildWindow:[self window]]; | |
| 446 [super close]; | |
| 447 } | |
| 448 | |
| 449 // The controller is the delegate of the window so it receives did resign key | |
| 450 // notifications. When key is resigned mirror Windows behavior and close the | |
| 451 // window. | |
| 452 - (void)windowDidResignKey:(NSNotification*)notification { | |
| 453 NSWindow* window = [self window]; | |
| 454 DCHECK_EQ([notification object], window); | |
| 455 if ([window isVisible]) { | |
| 456 // If the window isn't visible, it is already closed, and this notification | |
| 457 // has been sent as part of the closing operation, so no need to close. | |
| 458 [self close]; | |
| 459 } | |
| 460 } | |
| 461 | |
| 462 // By implementing this, ESC causes the window to go away. | |
| 463 - (IBAction)cancel:(id)sender { | |
| 464 // This is not a "real" cancel as potential changes to the radio group are not | |
| 465 // undone. That's ok. | |
| 466 [self close]; | |
| 467 } | |
| 468 | |
| 469 /////////////////////////////////////////////////////////////////////////////// | |
| 470 // Actual application logic | 377 // Actual application logic |
| 471 | 378 |
| 472 - (IBAction)allowBlockToggled:(id)sender { | 379 - (IBAction)allowBlockToggled:(id)sender { |
| 473 NSButtonCell *selectedCell = [sender selectedCell]; | 380 NSButtonCell *selectedCell = [sender selectedCell]; |
| 474 contentSettingBubbleModel_->OnRadioClicked( | 381 contentSettingBubbleModel_->OnRadioClicked( |
| 475 [selectedCell tag] == kAllowTag ? 0 : 1); | 382 [selectedCell tag] == kAllowTag ? 0 : 1); |
| 476 } | 383 } |
| 477 | 384 |
| 478 - (IBAction)closeBubble:(id)sender { | 385 - (IBAction)closeBubble:(id)sender { |
| 479 [self close]; | 386 [self close]; |
| 480 } | 387 } |
| 481 | 388 |
| 482 - (IBAction)manageBlocking:(id)sender { | 389 - (IBAction)manageBlocking:(id)sender { |
| 483 contentSettingBubbleModel_->OnManageLinkClicked(); | 390 contentSettingBubbleModel_->OnManageLinkClicked(); |
| 484 } | 391 } |
| 485 | 392 |
| 486 - (void)popupLinkClicked:(id)sender { | 393 - (void)popupLinkClicked:(id)sender { |
| 487 content_blocked_bubble::PopupLinks::iterator i(popupLinks_.find(sender)); | 394 content_blocked_bubble::PopupLinks::iterator i(popupLinks_.find(sender)); |
| 488 DCHECK(i != popupLinks_.end()); | 395 DCHECK(i != popupLinks_.end()); |
| 489 contentSettingBubbleModel_->OnPopupClicked(i->second); | 396 contentSettingBubbleModel_->OnPopupClicked(i->second); |
| 490 } | 397 } |
| 491 | 398 |
| 492 - (void)clearGeolocationForCurrentHost:(id)sender { | 399 - (void)clearGeolocationForCurrentHost:(id)sender { |
| 493 contentSettingBubbleModel_->OnClearLinkClicked(); | 400 contentSettingBubbleModel_->OnClearLinkClicked(); |
| 494 [self close]; | 401 [self close]; |
| 495 } | 402 } |
| 496 | 403 |
| 497 @end // ContentBlockedBubbleController | 404 @end // ContentBlockedBubbleController |
| OLD | NEW |