OLD | NEW |
1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. Use of this | 1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. Use of this |
2 // source code is governed by a BSD-style license that can be found in the | 2 // source code is governed by a BSD-style license that can be found in the |
3 // LICENSE file. | 3 // LICENSE file. |
4 | 4 |
5 #import "chrome/browser/cocoa/blocked_popup_container_controller.h" | 5 #import "chrome/browser/cocoa/blocked_popup_container_controller.h" |
6 | 6 |
7 #include "app/l10n_util.h" | 7 #include "app/l10n_util.h" |
8 #include "base/sys_string_conversions.h" | 8 #include "base/sys_string_conversions.h" |
9 #include "chrome/browser/tab_contents/tab_contents.h" | 9 #include "chrome/browser/tab_contents/tab_contents.h" |
10 #include "chrome/browser/tab_contents/tab_contents_view.h" | 10 #include "chrome/browser/tab_contents/tab_contents_view.h" |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
43 if ((self = [super init])) { | 43 if ((self = [super init])) { |
44 container_ = container; | 44 container_ = container; |
45 bridge_.reset(new BlockedPopupContainerViewBridge(self)); | 45 bridge_.reset(new BlockedPopupContainerViewBridge(self)); |
46 [self initPopupView]; | 46 [self initPopupView]; |
47 } | 47 } |
48 return self; | 48 return self; |
49 } | 49 } |
50 | 50 |
51 - (void)dealloc { | 51 - (void)dealloc { |
52 [view_ removeFromSuperview]; | 52 [view_ removeFromSuperview]; |
| 53 [[NSNotificationCenter defaultCenter] removeObserver:self]; |
53 [super dealloc]; | 54 [super dealloc]; |
54 } | 55 } |
55 | 56 |
56 - (IBAction)closePopup:(id)sender { | 57 - (IBAction)closePopup:(id)sender { |
57 container_->set_dismissed(); | 58 container_->set_dismissed(); |
58 container_->CloseAll(); | 59 container_->CloseAll(); |
59 } | 60 } |
60 | 61 |
61 // Create and initialize the popup view and its label, close box, etc. | 62 // Create and initialize the popup view and its label, close box, etc. |
62 - (void)initPopupView { | 63 - (void)initPopupView { |
63 static const float kWidth = 200.0; | 64 static const float kWidth = 200.0; |
64 static const float kHeight = 20.0; | 65 static const float kHeight = 20.0; |
65 static const float kCloseBoxSize = 16.0; | 66 static const float kCloseBoxSize = 16.0; |
66 static const float kCloseBoxPaddingY = 2.0; | 67 static const float kCloseBoxPaddingY = 2.0; |
67 static const float kLabelPaddingX = 5.0; | 68 static const float kLabelPaddingX = 5.0; |
68 | 69 |
69 // Create it below the parent's bottom edge so we can animate it into place. | 70 // Create it below the parent's bottom edge so we can animate it into place. |
70 NSRect startFrame = NSMakeRect(0.0, -kHeight, kWidth, kHeight); | 71 NSRect startFrame = NSMakeRect(0.0, -kHeight, kWidth, kHeight); |
71 view_.reset([[BackgroundGradientView alloc] initWithFrame:startFrame]); | 72 view_.reset([[BackgroundGradientView alloc] initWithFrame:startFrame]); |
72 [view_ setAutoresizingMask:NSViewMinXMargin | NSViewMaxYMargin]; | 73 [view_ setAutoresizingMask:NSViewMinXMargin | NSViewMaxYMargin]; |
73 | 74 |
74 // Create the text label and position it. We'll resize it later when the | 75 // Create the text label and position it. We'll resize it later when the |
75 // label gets updated. The view owns the label, we only hold a weak reference. | 76 // label gets updated. The view owns the label, we only hold a weak reference. |
76 NSRect labelFrame = NSMakeRect(kLabelPaddingX, | 77 NSRect labelFrame = NSMakeRect(kLabelPaddingX, |
77 0, | 78 0, |
78 startFrame.size.width - kCloseBoxSize, | 79 startFrame.size.width - kCloseBoxSize, |
79 startFrame.size.height); | 80 startFrame.size.height); |
80 label_ = [[[NSTextField alloc] initWithFrame:labelFrame] autorelease]; | 81 popupButton_ = [[[NSPopUpButton alloc] initWithFrame:labelFrame] autorelease]; |
81 [label_ setSelectable:NO]; | 82 [popupButton_ setAutoresizingMask:NSViewWidthSizable]; |
82 [label_ setAutoresizingMask:NSViewWidthSizable]; | 83 [popupButton_ setBordered:NO]; |
83 [label_ setBordered:NO]; | 84 [popupButton_ setBezelStyle:NSTexturedRoundedBezelStyle]; |
84 [label_ setBezeled:NO]; | 85 [popupButton_ setPullsDown:YES]; |
85 [label_ setDrawsBackground:NO]; | 86 // TODO(pinkerton): this doesn't work, not sure why. |
86 [view_ addSubview:label_]; | 87 [popupButton_ setPreferredEdge:NSMaxYEdge]; |
| 88 // TODO(pinkerton): no matter what, the arrows always draw in the middle |
| 89 // of the button. We can turn off the arrows entirely, but then will the |
| 90 // user ever know to click it? Leave them on for now. |
| 91 //[[popupButton_ cell] setArrowPosition:NSPopUpNoArrow]; |
| 92 [[popupButton_ cell] setAltersStateOfSelectedItem:NO]; |
| 93 // If we don't add this, no title will ever display. |
| 94 [popupButton_ addItemWithTitle:@"placeholder"]; |
| 95 [view_ addSubview:popupButton_]; |
| 96 |
| 97 // Register for notifications that the menu is about to display so we can |
| 98 // fill it in lazily |
| 99 [[NSNotificationCenter defaultCenter] |
| 100 addObserver:self |
| 101 selector:@selector(showMenu:) |
| 102 name:NSPopUpButtonCellWillPopUpNotification |
| 103 object:nil]; |
87 | 104 |
88 // Create the close box and position at the left of the view. | 105 // Create the close box and position at the left of the view. |
89 NSRect closeFrame = NSMakeRect(startFrame.size.width - kCloseBoxSize, | 106 NSRect closeFrame = NSMakeRect(startFrame.size.width - kCloseBoxSize, |
90 kCloseBoxPaddingY, | 107 kCloseBoxPaddingY, |
91 kCloseBoxSize, | 108 kCloseBoxSize, |
92 kCloseBoxSize); | 109 kCloseBoxSize); |
93 NSButton* close = [[[NSButton alloc] initWithFrame:closeFrame] autorelease]; | 110 NSButton* close = [[[NSButton alloc] initWithFrame:closeFrame] autorelease]; |
94 [close setAutoresizingMask:NSViewMinXMargin]; | 111 [close setAutoresizingMask:NSViewMinXMargin]; |
95 [close setImage:[NSImage imageNamed:@"close_bar"]]; | 112 [close setImage:[NSImage imageNamed:@"close_bar"]]; |
96 [close setAlternateImage:[NSImage imageNamed:@"close_bar_p"]]; | 113 [close setAlternateImage:[NSImage imageNamed:@"close_bar_p"]]; |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
132 [[view_ animator] setFrame:frame]; | 149 [[view_ animator] setFrame:frame]; |
133 } | 150 } |
134 | 151 |
135 - (void)hide { | 152 - (void)hide { |
136 [view_ removeFromSuperview]; | 153 [view_ removeFromSuperview]; |
137 } | 154 } |
138 | 155 |
139 // Resize the view based on the new label contents. The autoresize mask will | 156 // Resize the view based on the new label contents. The autoresize mask will |
140 // take care of resizing everything else. | 157 // take care of resizing everything else. |
141 - (void)resizeWithLabel:(NSString*)label { | 158 - (void)resizeWithLabel:(NSString*)label { |
| 159 // TODO(pinkerton): fix this so that it measures the text so that it can |
| 160 // be localized. |
142 #if 0 | 161 #if 0 |
143 // TODO(pinkerton): fix this once the popup gets put in. | 162 NSDictionary* attributes = |
144 NSSize stringSize = [label sizeWithAttributes:nil]; | 163 [NSDictionary dictionaryWithObjectsAndKeys: |
| 164 NSFontAttributeName, [NSFont systemFontOfSize:25], |
| 165 nil]; |
| 166 NSSize stringSize = [label sizeWithAttributes:attributes]; |
145 NSRect frame = [view_ frame]; | 167 NSRect frame = [view_ frame]; |
146 float originalWidth = frame.size.width; | 168 float originalWidth = frame.size.width; |
147 frame.size.width = stringSize.width + 16 + 5; | 169 frame.size.width = stringSize.width + 16 + 5; |
148 frame.origin.x -= frame.size.width - originalWidth; | 170 frame.origin.x -= frame.size.width - originalWidth; |
149 [view_ setFrame:frame]; | 171 [view_ setFrame:frame]; |
150 #endif | 172 #endif |
151 } | 173 } |
152 | 174 |
153 - (void)update { | 175 - (void)update { |
154 size_t blockedPopups = container_->GetBlockedPopupCount(); | 176 size_t blockedPopups = container_->GetBlockedPopupCount(); |
155 NSString* label = nil; | 177 NSString* label = nil; |
156 if (blockedPopups) { | 178 if (blockedPopups) { |
157 label = base::SysUTF16ToNSString( | 179 label = base::SysUTF16ToNSString( |
158 l10n_util::GetStringFUTF16(IDS_POPUPS_BLOCKED_COUNT, | 180 l10n_util::GetStringFUTF16(IDS_POPUPS_BLOCKED_COUNT, |
159 UintToString16(blockedPopups))); | 181 UintToString16(blockedPopups))); |
160 } else { | 182 } else { |
161 label = base::SysUTF16ToNSString( | 183 label = base::SysUTF16ToNSString( |
162 l10n_util::GetStringUTF16(IDS_POPUPS_UNBLOCKED)); | 184 l10n_util::GetStringUTF16(IDS_POPUPS_UNBLOCKED)); |
163 } | 185 } |
164 [self resizeWithLabel:label]; | 186 [self resizeWithLabel:label]; |
165 [label_ setStringValue:label]; | 187 [popupButton_ setTitle:label]; |
| 188 } |
| 189 |
| 190 // Called when the user selects an item from the popup menu. The tag, if below |
| 191 // |kImpossibleNumberOfPopups| will be the index into the container's popup |
| 192 // array. In that case, we should display the popup. If >= |
| 193 // |kImpossibleNumberOfPopups|, it represents a host that we should whitelist. |
| 194 // |sender| is the NSMenuItem that was chosen. |
| 195 - (void)menuAction:(id)sender { |
| 196 size_t tag = static_cast<size_t>([sender tag]); |
| 197 if (tag < BlockedPopupContainer::kImpossibleNumberOfPopups) { |
| 198 container_->LaunchPopupAtIndex(tag); |
| 199 } else { |
| 200 size_t hostIndex = tag - BlockedPopupContainer::kImpossibleNumberOfPopups; |
| 201 container_->ToggleWhitelistingForHost(hostIndex); |
| 202 } |
| 203 } |
| 204 |
| 205 namespace { |
| 206 void GetURLAndTitleForPopup( |
| 207 const BlockedPopupContainer* container, |
| 208 size_t index, |
| 209 string16* url, |
| 210 string16* title) { |
| 211 DCHECK(url); |
| 212 DCHECK(title); |
| 213 TabContents* tab_contents = container->GetTabContentsAt(index); |
| 214 const GURL& tab_contents_url = tab_contents->GetURL().GetOrigin(); |
| 215 *url = UTF8ToUTF16(tab_contents_url.possibly_invalid_spec()); |
| 216 *title = tab_contents->GetTitle(); |
| 217 } |
| 218 } // namespace |
| 219 |
| 220 // Build a new popup menu from scratch. The menu contains the blocked popups |
| 221 // (tags being the popup's index), followed by the list of hosts from which |
| 222 // the popups were blocked (tags being |kImpossibleNumberOfPopups| + host |
| 223 // index). The hosts are used to toggle whitelisting for a site. |
| 224 - (NSMenu*)buildMenu { |
| 225 NSMenu* menu = [[[NSMenu alloc] init] autorelease]; |
| 226 |
| 227 // For pop-down menus, the first item is what is displayed while tracking the |
| 228 // menu and it remains there if nothing is selected. Set it to the |
| 229 // current title. |
| 230 NSString* currentTitle = [popupButton_ title]; |
| 231 scoped_nsobject<NSMenuItem> dummy( |
| 232 [[NSMenuItem alloc] initWithTitle:currentTitle |
| 233 action:nil |
| 234 keyEquivalent:@""]); |
| 235 [menu addItem:dummy.get()]; |
| 236 |
| 237 // Add the list of blocked popups titles to the menu. We set the array index |
| 238 // as the tag for use in the menu action rather than relying on the menu item |
| 239 // index. |
| 240 const size_t count = container_->GetBlockedPopupCount(); |
| 241 for (size_t i = 0; i < count; ++i) { |
| 242 string16 url, title; |
| 243 GetURLAndTitleForPopup(container_, i, &url, &title); |
| 244 NSString* titleStr = base::SysUTF16ToNSString( |
| 245 l10n_util::GetStringFUTF16(IDS_POPUP_TITLE_FORMAT, url, title)); |
| 246 scoped_nsobject<NSMenuItem> item( |
| 247 [[NSMenuItem alloc] initWithTitle:titleStr |
| 248 action:@selector(menuAction:) |
| 249 keyEquivalent:@""]); |
| 250 [item setTag:i]; |
| 251 [item setTarget:self]; |
| 252 [menu addItem:item.get()]; |
| 253 } |
| 254 |
| 255 // Add the list of hosts. We begin tagging these at |
| 256 // |kImpossibleNumberOfPopups|. If whitelisting has already been enabled |
| 257 // for a site, mark it with a checkmark. |
| 258 std::vector<std::string> hosts(container_->GetHosts()); |
| 259 if (!hosts.empty() && count) |
| 260 [menu addItem:[NSMenuItem separatorItem]]; |
| 261 for (size_t i = 0; i < hosts.size(); ++i) { |
| 262 NSString* titleStr = base::SysUTF8ToNSString( |
| 263 l10n_util::GetStringFUTF8(IDS_POPUP_HOST_FORMAT, |
| 264 UTF8ToUTF16(hosts[i]))); |
| 265 scoped_nsobject<NSMenuItem> item( |
| 266 [[NSMenuItem alloc] initWithTitle:titleStr |
| 267 action:@selector(menuAction:) |
| 268 keyEquivalent:@""]); |
| 269 if (container_->IsHostWhitelisted(i)) |
| 270 [item setState:NSOnState]; |
| 271 [item setTag:BlockedPopupContainer::kImpossibleNumberOfPopups + i]; |
| 272 [item setTarget:self]; |
| 273 [menu addItem:item.get()]; |
| 274 } |
| 275 |
| 276 return menu; |
| 277 } |
| 278 |
| 279 // Called when the popup button is about to display the menu, giving us a |
| 280 // chance to fill in the contents. |
| 281 - (void)showMenu:(NSNotification*)notify { |
| 282 NSMenu* menu = [self buildMenu]; |
| 283 [[notify object] setMenu:menu]; |
166 } | 284 } |
167 | 285 |
168 - (NSView*)view { | 286 - (NSView*)view { |
169 return view_.get(); | 287 return view_.get(); |
170 } | 288 } |
171 | 289 |
172 - (NSView*)label { | 290 - (NSPopUpButton*)popupButton { |
173 return label_; | 291 return popupButton_; |
| 292 } |
| 293 |
| 294 // Only used for testing. |
| 295 - (void)setContainer:(BlockedPopupContainer*)container { |
| 296 container_ = container; |
174 } | 297 } |
175 | 298 |
176 @end | 299 @end |
177 | 300 |
178 //--------------------------------------------------------------------------- | 301 //--------------------------------------------------------------------------- |
179 | 302 |
180 BlockedPopupContainerView* BlockedPopupContainerView::Create( | 303 BlockedPopupContainerView* BlockedPopupContainerView::Create( |
181 BlockedPopupContainer* container) { | 304 BlockedPopupContainer* container) { |
182 // We "leak" |blocker| for now, we'll release it when the bridge class | 305 // We "leak" |blocker| for now, we'll release it when the bridge class |
183 // gets a Destroy() message. | 306 // gets a Destroy() message. |
(...skipping 23 matching lines...) Expand all Loading... |
207 [controller_ update]; | 330 [controller_ update]; |
208 } | 331 } |
209 | 332 |
210 void BlockedPopupContainerViewBridge::HideView() { | 333 void BlockedPopupContainerViewBridge::HideView() { |
211 [controller_ hide]; | 334 [controller_ hide]; |
212 } | 335 } |
213 | 336 |
214 void BlockedPopupContainerViewBridge::Destroy() { | 337 void BlockedPopupContainerViewBridge::Destroy() { |
215 [controller_ autorelease]; | 338 [controller_ autorelease]; |
216 } | 339 } |
OLD | NEW |