| 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" | 9 #include "base/mac_util.h" |
| 10 #include "base/string_util.h" | 10 #include "base/string_util.h" |
| (...skipping 23 matching lines...) Expand all Loading... |
| 34 | 34 |
| 35 // Space between two popup links. | 35 // Space between two popup links. |
| 36 const int kLinkPadding = 4; | 36 const int kLinkPadding = 4; |
| 37 | 37 |
| 38 // Space taken in total by one popup link. | 38 // Space taken in total by one popup link. |
| 39 const int kLinkLineHeight = kLinkHeight + kLinkPadding; | 39 const int kLinkLineHeight = kLinkHeight + kLinkPadding; |
| 40 | 40 |
| 41 // Space between popup list and surrounding UI elements. | 41 // Space between popup list and surrounding UI elements. |
| 42 const int kLinkOuterPadding = 8; | 42 const int kLinkOuterPadding = 8; |
| 43 | 43 |
| 44 // Height of each of the labels in the geolocation bubble. |
| 45 const int kGeoLabelHeight = 14; |
| 46 |
| 47 // Height of the "Clear" button in the geolocation bubble. |
| 48 const int kGeoClearButtonHeight = 17; |
| 49 |
| 50 // General padding between elements in the geolocation bubble. |
| 51 const int kGeoPadding = 8; |
| 52 |
| 53 // Padding between host names in the geolocation bubble. |
| 54 const int kGeoHostPadding = 4; |
| 55 |
| 56 |
| 44 // Like |ReplaceStringPlaceholders(const string16&, const string16&, size_t*)|, | 57 // Like |ReplaceStringPlaceholders(const string16&, const string16&, size_t*)|, |
| 45 // but for a NSString formatString. | 58 // but for a NSString formatString. |
| 46 NSString* ReplaceNSStringPlaceholders(NSString* formatString, | 59 NSString* ReplaceNSStringPlaceholders(NSString* formatString, |
| 47 const string16& a, | 60 const string16& a, |
| 48 size_t* offset) { | 61 size_t* offset) { |
| 49 return base::SysUTF16ToNSString( | 62 return base::SysUTF16ToNSString( |
| 50 ReplaceStringPlaceholders(base::SysNSStringToUTF16(formatString), | 63 ReplaceStringPlaceholders(base::SysNSStringToUTF16(formatString), |
| 51 a, | 64 a, |
| 52 offset)); | 65 offset)); |
| 53 } | 66 } |
| 54 | 67 |
| 68 void SetControlSize(NSControl* control, NSControlSize controlSize) { |
| 69 CGFloat fontSize = [NSFont systemFontSizeForControlSize:controlSize]; |
| 70 NSCell* cell = [control cell]; |
| 71 NSFont* font = [NSFont fontWithName:[[cell font] fontName] size:fontSize]; |
| 72 [cell setFont:font]; |
| 73 [cell setControlSize:controlSize]; |
| 74 } |
| 75 |
| 76 // Returns an autoreleased NSTextField that is configured to look like a Label |
| 77 // looks in Interface Builder. |
| 78 NSTextField* LabelWithFrame(NSString* text, const NSRect& frame) { |
| 79 NSTextField* label = [[NSTextField alloc] initWithFrame:frame]; |
| 80 [label setStringValue:text]; |
| 81 [label setSelectable:NO]; |
| 82 [label setBezeled:NO]; |
| 83 return [label autorelease]; |
| 84 } |
| 85 |
| 55 } // namespace | 86 } // namespace |
| 56 | 87 |
| 57 @interface ContentBlockedBubbleController(Private) | 88 @interface ContentBlockedBubbleController(Private) |
| 58 - (id)initWithModel:(ContentSettingBubbleModel*)settingsBubbleModel | 89 - (id)initWithModel:(ContentSettingBubbleModel*)settingsBubbleModel |
| 59 parentWindow:(NSWindow*)parentWindow | 90 parentWindow:(NSWindow*)parentWindow |
| 60 anchoredAt:(NSPoint)anchoredAt; | 91 anchoredAt:(NSPoint)anchoredAt; |
| 61 - (NSButton*)hyperlinkButtonWithFrame:(NSRect)frame | 92 - (NSButton*)hyperlinkButtonWithFrame:(NSRect)frame |
| 62 title:(NSString*)title | 93 title:(NSString*)title |
| 63 icon:(NSImage*)icon | 94 icon:(NSImage*)icon |
| 64 referenceFrame:(NSRect)referenceFrame; | 95 referenceFrame:(NSRect)referenceFrame; |
| 65 - (void)initializeTitle; | 96 - (void)initializeTitle; |
| 66 - (void)initializeRadioGroup; | 97 - (void)initializeRadioGroup; |
| 67 - (void)initializePopupList; | 98 - (void)initializePopupList; |
| 99 - (void)initializeGeoLists; |
| 68 - (void)popupLinkClicked:(id)sender; | 100 - (void)popupLinkClicked:(id)sender; |
| 101 - (void)clearGeolocationForCurrentHost:(id)sender; |
| 69 @end | 102 @end |
| 70 | 103 |
| 71 @implementation ContentBlockedBubbleController | 104 @implementation ContentBlockedBubbleController |
| 72 | 105 |
| 73 + (ContentBlockedBubbleController*) | 106 + (ContentBlockedBubbleController*) |
| 74 showForModel:(ContentSettingBubbleModel*)contentSettingBubbleModel | 107 showForModel:(ContentSettingBubbleModel*)contentSettingBubbleModel |
| 75 parentWindow:(NSWindow*)parentWindow | 108 parentWindow:(NSWindow*)parentWindow |
| 76 anchoredAt:(NSPoint)anchor { | 109 anchoredAt:(NSPoint)anchor { |
| 77 // Autoreleases itself on bubble close. | 110 // Autoreleases itself on bubble close. |
| 78 return [[ContentBlockedBubbleController alloc] | 111 return [[ContentBlockedBubbleController alloc] |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 113 [center addObserver:self | 146 [center addObserver:self |
| 114 selector:@selector(parentWindowWillClose:) | 147 selector:@selector(parentWindowWillClose:) |
| 115 name:NSWindowWillCloseNotification | 148 name:NSWindowWillCloseNotification |
| 116 object:parentWindow_]; | 149 object:parentWindow_]; |
| 117 } | 150 } |
| 118 return self; | 151 return self; |
| 119 } | 152 } |
| 120 | 153 |
| 121 - (void)initializeTitle { | 154 - (void)initializeTitle { |
| 122 if (!titleLabel_) | 155 if (!titleLabel_) |
| 123 return; // Make valgrind happy for now. | 156 return; |
| 124 | 157 |
| 125 // Layout title post-localization. | 158 // Layout title post-localization. |
| 126 CGFloat titleDeltaY = [GTMUILocalizerAndLayoutTweaker | 159 CGFloat deltaY = [GTMUILocalizerAndLayoutTweaker |
| 127 sizeToFitFixedWidthTextField:titleLabel_]; | 160 sizeToFitFixedWidthTextField:titleLabel_]; |
| 128 NSRect windowFrame = [[self window] frame]; | 161 NSRect windowFrame = [[self window] frame]; |
| 129 windowFrame.size.height += titleDeltaY; | 162 windowFrame.size.height += deltaY; |
| 130 [[self window] setFrame:windowFrame display:NO]; | 163 [[self window] setFrame:windowFrame display:NO]; |
| 131 NSRect titleFrame = [titleLabel_ frame]; | 164 NSRect titleFrame = [titleLabel_ frame]; |
| 132 titleFrame.origin.y -= titleDeltaY; | 165 titleFrame.origin.y -= deltaY; |
| 133 [titleLabel_ setFrame:titleFrame]; | 166 [titleLabel_ setFrame:titleFrame]; |
| 134 } | 167 } |
| 135 | 168 |
| 136 - (void)initializeRadioGroup { | 169 - (void)initializeRadioGroup { |
| 137 // Configure the radio group. For now, only deal with the | 170 // Configure the radio group. For now, only deal with the |
| 138 // strictly needed case of 1 radio group (containing 2 radio buttons). | 171 // strictly needed case of 1 radio group (containing 2 radio buttons). |
| 139 // TODO(joth): Implement the generic case, getting localized strings from the | 172 // TODO(joth): Implement the generic case, getting localized strings from the |
| 140 // bubble model instead of the xib, or remove it if it's never needed. | 173 // bubble model instead of the xib, or remove it if it's never needed. |
| 141 // http://crbug.com/38432 | 174 // http://crbug.com/38432 |
| 142 const ContentSettingBubbleModel::RadioGroups& radioGroups = | 175 const ContentSettingBubbleModel::RadioGroups& radioGroups = |
| (...skipping 98 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 241 NSButton* button = [self | 274 NSButton* button = [self |
| 242 hyperlinkButtonWithFrame:linkFrame | 275 hyperlinkButtonWithFrame:linkFrame |
| 243 title:base::SysUTF8ToNSString(title) | 276 title:base::SysUTF8ToNSString(title) |
| 244 icon:image | 277 icon:image |
| 245 referenceFrame:radioFrame]; | 278 referenceFrame:radioFrame]; |
| 246 [bubble_ addSubview:button]; | 279 [bubble_ addSubview:button]; |
| 247 popupLinks_[button] = row; | 280 popupLinks_[button] = row; |
| 248 } | 281 } |
| 249 } | 282 } |
| 250 | 283 |
| 284 - (void)initializeGeoLists { |
| 285 // 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 |
| 287 // order of operations is the other way than on Linux/Windows. |
| 288 const ContentSettingBubbleModel::BubbleContent& content = |
| 289 contentSettingBubbleModel_->bubble_content(); |
| 290 NSRect containerFrame = [contentsContainer_ frame]; |
| 291 NSRect frame = NSMakeRect(0, 0, containerFrame.size.width, kGeoLabelHeight); |
| 292 |
| 293 // "Clear" button. |
| 294 if (!content.clear_link.empty()) { |
| 295 NSRect buttonFrame = NSMakeRect(0, 0, |
| 296 containerFrame.size.width, |
| 297 kGeoClearButtonHeight); |
| 298 NSButton* button = [[NSButton alloc] initWithFrame:buttonFrame]; |
| 299 [button setTitle:base::SysUTF8ToNSString(content.clear_link)]; |
| 300 [button setTarget:self]; |
| 301 [button setAction:@selector(clearGeolocationForCurrentHost:)]; |
| 302 [button setBezelStyle:NSRoundRectBezelStyle]; |
| 303 SetControlSize(button, NSSmallControlSize); |
| 304 [button sizeToFit]; |
| 305 [contentsContainer_ addSubview:button]; |
| 306 |
| 307 frame.origin.y = NSMaxY([button frame]) + kGeoPadding; |
| 308 } |
| 309 |
| 310 typedef |
| 311 std::vector<ContentSettingBubbleModel::DomainList>::const_reverse_iterator |
| 312 GeolocationGroupIterator; |
| 313 for (GeolocationGroupIterator i = content.domain_lists.rbegin(); |
| 314 i != content.domain_lists.rend(); ++i) { |
| 315 // Add all hosts in the current domain list. |
| 316 for (std::set<std::string>::const_reverse_iterator j = i->hosts.rbegin(); |
| 317 j != i->hosts.rend(); ++j) { |
| 318 NSTextField* title = LabelWithFrame(base::SysUTF8ToNSString(*j), frame); |
| 319 SetControlSize(title, NSSmallControlSize); |
| 320 [contentsContainer_ addSubview:title]; |
| 321 |
| 322 frame.origin.y += [GTMUILocalizerAndLayoutTweaker |
| 323 sizeToFitFixedWidthTextField:title]; |
| 324 frame.origin.y = NSMaxY(frame) + kGeoHostPadding; |
| 325 } |
| 326 if (!i->hosts.empty()) |
| 327 frame.origin.y += kGeoPadding - kGeoHostPadding; |
| 328 |
| 329 // Add the domain list's title. |
| 330 NSTextField* title = |
| 331 LabelWithFrame(base::SysUTF8ToNSString(i->title), frame); |
| 332 SetControlSize(title, NSSmallControlSize); |
| 333 [contentsContainer_ addSubview:title]; |
| 334 |
| 335 frame.origin.y += [GTMUILocalizerAndLayoutTweaker |
| 336 sizeToFitFixedWidthTextField:title]; |
| 337 frame.origin.y = NSMaxY(frame) + kGeoPadding; |
| 338 } |
| 339 |
| 340 CGFloat containerHeight = frame.origin.y; |
| 341 // Undo last padding. |
| 342 if (!content.domain_lists.empty()) |
| 343 containerHeight -= kGeoPadding; |
| 344 |
| 345 // Resize container to fit its subviews, and window to fit the container. |
| 346 NSRect windowFrame = [[self window] frame]; |
| 347 windowFrame.size.height += containerHeight - containerFrame.size.height; |
| 348 [[self window] setFrame:windowFrame display:NO]; |
| 349 containerFrame.size.height = containerHeight; |
| 350 [contentsContainer_ setFrame:containerFrame]; |
| 351 } |
| 352 |
| 251 - (void)awakeFromNib { | 353 - (void)awakeFromNib { |
| 252 DCHECK([self window]); | 354 DCHECK([self window]); |
| 253 DCHECK_EQ(self, [[self window] delegate]); | 355 DCHECK_EQ(self, [[self window] delegate]); |
| 254 | 356 |
| 255 [bubble_ setBubbleType:kWhiteInfoBubble]; | 357 [bubble_ setBubbleType:kWhiteInfoBubble]; |
| 256 [bubble_ setArrowLocation:kTopRight]; | 358 [bubble_ setArrowLocation:kTopRight]; |
| 257 | 359 |
| 258 [self initializeTitle]; | 360 [self initializeTitle]; |
| 259 if (allowBlockRadioGroup_) // not bound in cookie bubble xib | 361 if (allowBlockRadioGroup_) // not bound in cookie bubble xib |
| 260 [self initializeRadioGroup]; | 362 [self initializeRadioGroup]; |
| 261 if (contentSettingBubbleModel_->content_type() | 363 if (contentSettingBubbleModel_->content_type() == |
| 262 == CONTENT_SETTINGS_TYPE_POPUPS) | 364 CONTENT_SETTINGS_TYPE_POPUPS) |
| 263 [self initializePopupList]; | 365 [self initializePopupList]; |
| 366 if (contentSettingBubbleModel_->content_type() == |
| 367 CONTENT_SETTINGS_TYPE_GEOLOCATION) |
| 368 [self initializeGeoLists]; |
| 264 } | 369 } |
| 265 | 370 |
| 266 /////////////////////////////////////////////////////////////////////////////// | 371 /////////////////////////////////////////////////////////////////////////////// |
| 267 // Bubble-management related stuff | 372 // Bubble-management related stuff |
| 268 | 373 |
| 269 // TODO(thakis): All that junk below should be in some superclass that all the | 374 // TODO(thakis): All that junk below should be in some superclass that all the |
| 270 // bubble controllers (bookmark bubble, extension installed bubble, page/browser | 375 // bubble controllers (bookmark bubble, extension installed bubble, page/browser |
| 271 // action bubble, content blocked bubble) derive from -- http://crbug.com/36366 | 376 // action bubble, content blocked bubble) derive from -- http://crbug.com/36366 |
| 272 | 377 |
| 273 - (void)dealloc { | 378 - (void)dealloc { |
| (...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 346 - (IBAction)manageBlocking:(id)sender { | 451 - (IBAction)manageBlocking:(id)sender { |
| 347 contentSettingBubbleModel_->OnManageLinkClicked(); | 452 contentSettingBubbleModel_->OnManageLinkClicked(); |
| 348 } | 453 } |
| 349 | 454 |
| 350 - (void)popupLinkClicked:(id)sender { | 455 - (void)popupLinkClicked:(id)sender { |
| 351 content_blocked_bubble::PopupLinks::iterator i(popupLinks_.find(sender)); | 456 content_blocked_bubble::PopupLinks::iterator i(popupLinks_.find(sender)); |
| 352 DCHECK(i != popupLinks_.end()); | 457 DCHECK(i != popupLinks_.end()); |
| 353 contentSettingBubbleModel_->OnPopupClicked(i->second); | 458 contentSettingBubbleModel_->OnPopupClicked(i->second); |
| 354 } | 459 } |
| 355 | 460 |
| 461 - (void)clearGeolocationForCurrentHost:(id)sender { |
| 462 contentSettingBubbleModel_->OnClearLinkClicked(); |
| 463 [self close]; |
| 464 } |
| 465 |
| 356 @end // ContentBlockedBubbleController | 466 @end // ContentBlockedBubbleController |
| OLD | NEW |