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 |