Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(450)

Side by Side Diff: chrome/browser/ui/cocoa/infobars/infobar_controller.mm

Issue 7981045: Make infobars ignore button clicks when closing. (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: '' Created 9 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2011 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 <Cocoa/Cocoa.h> 5 #import <Cocoa/Cocoa.h>
6 6
7 #include "base/logging.h" // for NOTREACHED() 7 #include "base/logging.h" // for NOTREACHED()
8 #include "base/mac/mac_util.h" 8 #include "base/mac/mac_util.h"
9 #include "base/sys_string_conversions.h" 9 #include "base/sys_string_conversions.h"
10 #include "chrome/browser/infobars/infobar_tab_helper.h" 10 #include "chrome/browser/infobars/infobar_tab_helper.h"
(...skipping 16 matching lines...) Expand all
27 namespace { 27 namespace {
28 // Durations set to match the default SlideAnimation duration. 28 // Durations set to match the default SlideAnimation duration.
29 const float kAnimateOpenDuration = 0.12; 29 const float kAnimateOpenDuration = 0.12;
30 const float kAnimateCloseDuration = 0.12; 30 const float kAnimateCloseDuration = 0.12;
31 } 31 }
32 32
33 @interface InfoBarController (PrivateMethods) 33 @interface InfoBarController (PrivateMethods)
34 // Sets |label_| based on |labelPlaceholder_|, sets |labelPlaceholder_| to nil. 34 // Sets |label_| based on |labelPlaceholder_|, sets |labelPlaceholder_| to nil.
35 - (void)initializeLabel; 35 - (void)initializeLabel;
36 36
37 // Asks the container controller to remove the infobar for this delegate. This
38 // call will trigger a notification that starts the infobar animating closed.
39 - (void)removeSelf;
40
41 // Performs final cleanup after an animation is finished or stopped, including 37 // Performs final cleanup after an animation is finished or stopped, including
42 // notifying the InfoBarDelegate that the infobar was closed and removing the 38 // notifying the InfoBarDelegate that the infobar was closed and removing the
43 // infobar from its container, if necessary. 39 // infobar from its container, if necessary.
44 - (void)cleanUpAfterAnimation:(BOOL)finished; 40 - (void)cleanUpAfterAnimation:(BOOL)finished;
45 41
46 // Returns the point, in gradient view coordinates, at which the apex of the 42 // Returns the point, in gradient view coordinates, at which the apex of the
47 // infobar tip should be drawn. 43 // infobar tip should be drawn.
48 - (NSPoint)pointForTipApex; 44 - (NSPoint)pointForTipApex;
49 @end 45 @end
50 46
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after
98 94
99 // Called when someone clicks on the embedded link. 95 // Called when someone clicks on the embedded link.
100 - (BOOL) textView:(NSTextView*)textView 96 - (BOOL) textView:(NSTextView*)textView
101 clickedOnLink:(id)link 97 clickedOnLink:(id)link
102 atIndex:(NSUInteger)charIndex { 98 atIndex:(NSUInteger)charIndex {
103 if ([self respondsToSelector:@selector(linkClicked)]) 99 if ([self respondsToSelector:@selector(linkClicked)])
104 [self performSelector:@selector(linkClicked)]; 100 [self performSelector:@selector(linkClicked)];
105 return YES; 101 return YES;
106 } 102 }
107 103
104 - (BOOL)owned {
105 return !!owner_;
106 }
107
108 // Called when someone clicks on the ok button. 108 // Called when someone clicks on the ok button.
109 - (void)ok:(id)sender { 109 - (void)ok:(id)sender {
110 // Subclasses must override this method if they do not hide the ok button. 110 // Subclasses must override this method if they do not hide the ok button.
111 NOTREACHED(); 111 NOTREACHED();
112 } 112 }
113 113
114 // Called when someone clicks on the cancel button. 114 // Called when someone clicks on the cancel button.
115 - (void)cancel:(id)sender { 115 - (void)cancel:(id)sender {
116 // Subclasses must override this method if they do not hide the cancel button. 116 // Subclasses must override this method if they do not hide the cancel button.
117 NOTREACHED(); 117 NOTREACHED();
118 } 118 }
119 119
120 // Called when someone clicks on the close button. 120 // Called when someone clicks on the close button.
121 - (void)dismiss:(id)sender { 121 - (void)dismiss:(id)sender {
122 if (delegate_) 122 if (![self owned])
123 delegate_->InfoBarDismissed(); 123 return;
124 delegate_->InfoBarDismissed();
125 [self removeSelf];
126 }
124 127
125 [self removeSelf]; 128 - (void)removeSelf {
129 DCHECK(owner_);
130 owner_->infobar_tab_helper()->RemoveInfoBar(delegate_);
126 } 131 }
127 132
128 - (AnimatableView*)animatableView { 133 - (AnimatableView*)animatableView {
129 return static_cast<AnimatableView*>([self view]); 134 return static_cast<AnimatableView*>([self view]);
130 } 135 }
131 136
132 - (void)open { 137 - (void)open {
133 // Simply reset the frame size to its opened size, forcing a relayout. 138 // Simply reset the frame size to its opened size, forcing a relayout.
134 CGFloat finalHeight = [[self view] frame].size.height; 139 CGFloat finalHeight = [[self view] frame].size.height;
135 [[self animatableView] setHeight:finalHeight]; 140 [[self animatableView] setHeight:finalHeight];
(...skipping 22 matching lines...) Expand all
158 163
159 // Start animating closed. We will receive a notification when the animation 164 // Start animating closed. We will receive a notification when the animation
160 // is done, at which point we can remove our view from the hierarchy and 165 // is done, at which point we can remove our view from the hierarchy and
161 // notify the delegate that the infobar was closed. 166 // notify the delegate that the infobar was closed.
162 [[self animatableView] animateToNewHeight:0 duration:kAnimateCloseDuration]; 167 [[self animatableView] animateToNewHeight:0 duration:kAnimateCloseDuration];
163 168
164 // The above call may trigger an animationDidStop: notification for any 169 // The above call may trigger an animationDidStop: notification for any
165 // currently-running animations, so do not set |infoBarClosing_| until after 170 // currently-running animations, so do not set |infoBarClosing_| until after
166 // starting the animation. 171 // starting the animation.
167 infoBarClosing_ = YES; 172 infoBarClosing_ = YES;
168
169 // The owner called this method to close the infobar, so there will
170 // be no need to forward future remove events to the owner.
171 owner_ = NULL;
172 } 173 }
173 174
174 - (void)addAdditionalControls { 175 - (void)addAdditionalControls {
175 // Default implementation does nothing. 176 // Default implementation does nothing.
176 } 177 }
177 178
178 - (void)infobarWillClose { 179 - (void)infobarWillClose {
179 // Default implementation does nothing. 180 owner_ = NULL;
180 } 181 }
181 182
182 - (void)removeButtons { 183 - (void)removeButtons {
183 // Extend the label all the way across. 184 // Extend the label all the way across.
184 NSRect labelFrame = [label_.get() frame]; 185 NSRect labelFrame = [label_.get() frame];
185 labelFrame.size.width = NSMaxX([cancelButton_ frame]) - NSMinX(labelFrame); 186 labelFrame.size.width = NSMaxX([cancelButton_ frame]) - NSMinX(labelFrame);
186 [okButton_ removeFromSuperview]; 187 [okButton_ removeFromSuperview];
187 okButton_ = nil; 188 okButton_ = nil;
188 [cancelButton_ removeFromSuperview]; 189 [cancelButton_ removeFromSuperview];
189 cancelButton_ = nil; 190 cancelButton_ = nil;
190 [label_.get() setFrame:labelFrame]; 191 [label_.get() setFrame:labelFrame];
191 } 192 }
192 193
194 - (void)disablePopUpMenu:(NSMenu*)menu {
195 // Remove the menu if visible.
196 [menu cancelTracking];
197
198 // If the menu is re-opened, prevent queries to update items.
199 [menu setDelegate:nil];
200
201 // Prevent target/action messages to the controller.
202 for (NSMenuItem* item in [menu itemArray]) {
203 [item setEnabled:NO];
204 [item setTarget:nil];
205 }
206 }
207
193 @end 208 @end
194 209
195 @implementation InfoBarController (PrivateMethods) 210 @implementation InfoBarController (PrivateMethods)
196 211
197 - (void)initializeLabel { 212 - (void)initializeLabel {
198 // Replace the label placeholder NSTextField with the real label NSTextView. 213 // Replace the label placeholder NSTextField with the real label NSTextView.
199 // The former doesn't show links in a nice way, but the latter can't be added 214 // The former doesn't show links in a nice way, but the latter can't be added
200 // in IB without a containing scroll view, so create the NSTextView 215 // in IB without a containing scroll view, so create the NSTextView
201 // programmatically. 216 // programmatically.
202 label_.reset([[HyperlinkTextView alloc] 217 label_.reset([[HyperlinkTextView alloc]
203 initWithFrame:[labelPlaceholder_ frame]]); 218 initWithFrame:[labelPlaceholder_ frame]]);
204 [label_.get() setAutoresizingMask:[labelPlaceholder_ autoresizingMask]]; 219 [label_.get() setAutoresizingMask:[labelPlaceholder_ autoresizingMask]];
205 [[labelPlaceholder_ superview] 220 [[labelPlaceholder_ superview]
206 replaceSubview:labelPlaceholder_ with:label_.get()]; 221 replaceSubview:labelPlaceholder_ with:label_.get()];
207 labelPlaceholder_ = nil; // Now released. 222 labelPlaceholder_ = nil; // Now released.
208 [label_.get() setDelegate:self]; 223 [label_.get() setDelegate:self];
209 } 224 }
210 225
211 - (void)removeSelf {
212 // TODO(rohitrao): This method can be called even if the infobar has already
213 // been removed and |delegate_| is NULL. Is there a way to rewrite the code
214 // so that inner event loops don't cause us to try and remove the infobar
215 // twice? http://crbug.com/54253
216 if (owner_)
217 owner_->infobar_tab_helper()->RemoveInfoBar(delegate_);
218 owner_ = NULL;
219 }
220
221 - (void)cleanUpAfterAnimation:(BOOL)finished { 226 - (void)cleanUpAfterAnimation:(BOOL)finished {
222 // Don't need to do any cleanup if the bar was animating open. 227 // Don't need to do any cleanup if the bar was animating open.
223 if (!infoBarClosing_) 228 if (!infoBarClosing_)
224 return; 229 return;
225 230
226 // Notify the delegate that the infobar was closed. The delegate will delete 231 // Notify the delegate that the infobar was closed. The delegate will delete
227 // itself as a result of InfoBarClosed(), so we null out its pointer. 232 // itself as a result of InfoBarClosed(), so we null out its pointer.
228 if (delegate_) { 233 if (delegate_) {
229 delegate_->InfoBarClosed(); 234 delegate_->InfoBarClosed();
230 delegate_ = NULL; 235 delegate_ = NULL;
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after
291 atOffset:offset 296 atOffset:offset
292 font:font 297 font:font
293 messageColor:[NSColor blackColor] 298 messageColor:[NSColor blackColor]
294 linkColor:[NSColor blueColor]]; 299 linkColor:[NSColor blueColor]];
295 } 300 }
296 301
297 // Called when someone clicks on the link in the infobar. This method 302 // Called when someone clicks on the link in the infobar. This method
298 // is called by the InfobarTextField on its delegate (the 303 // is called by the InfobarTextField on its delegate (the
299 // LinkInfoBarController). 304 // LinkInfoBarController).
300 - (void)linkClicked { 305 - (void)linkClicked {
306 if (![self owned])
307 return;
301 WindowOpenDisposition disposition = 308 WindowOpenDisposition disposition =
302 event_utils::WindowOpenDispositionFromNSEvent([NSApp currentEvent]); 309 event_utils::WindowOpenDispositionFromNSEvent([NSApp currentEvent]);
303 if (delegate_ && 310 if (delegate_->AsLinkInfoBarDelegate()->LinkClicked(disposition))
304 delegate_->AsLinkInfoBarDelegate()->LinkClicked(disposition)) { 311 [self removeSelf];
305 // Call |-removeSelf| on the outermost runloop to force a delay. As shown in
306 // <http://crbug.com/87201>, the second click event can be delivered after
307 // the animation finishes (and this gets released and deallocated), which
308 // leads to zombie messaging. Unfortunately, the order between the animation
309 // finishing and the click event being delivered is nondeterministic, so
310 // this hack is the best that can be done.
311 [self performSelector:@selector(removeSelf)
312 withObject:nil
313 afterDelay:0.0];
314 }
315 } 312 }
316 313
317 @end 314 @end
318 315
319 316
320 ///////////////////////////////////////////////////////////////////////// 317 /////////////////////////////////////////////////////////////////////////
321 // ConfirmInfoBarController implementation 318 // ConfirmInfoBarController implementation
322 319
323 @implementation ConfirmInfoBarController 320 @implementation ConfirmInfoBarController
324 321
325 // Called when someone clicks on the "OK" button. 322 // Called when someone clicks on the "OK" button.
326 - (IBAction)ok:(id)sender { 323 - (IBAction)ok:(id)sender {
327 if (delegate_ && delegate_->AsConfirmInfoBarDelegate()->Accept()) 324 if (![self owned])
325 return;
326 if (delegate_->AsConfirmInfoBarDelegate()->Accept())
328 [self removeSelf]; 327 [self removeSelf];
329 } 328 }
330 329
331 // Called when someone clicks on the "Cancel" button. 330 // Called when someone clicks on the "Cancel" button.
332 - (IBAction)cancel:(id)sender { 331 - (IBAction)cancel:(id)sender {
333 if (delegate_ && delegate_->AsConfirmInfoBarDelegate()->Cancel()) 332 if (![self owned])
333 return;
334 if (delegate_->AsConfirmInfoBarDelegate()->Cancel())
334 [self removeSelf]; 335 [self removeSelf];
335 } 336 }
336 337
337 // Confirm infobars can have OK and/or cancel buttons, depending on 338 // Confirm infobars can have OK and/or cancel buttons, depending on
338 // the return value of GetButtons(). We create each button if 339 // the return value of GetButtons(). We create each button if
339 // required and position them to the left of the close button. 340 // required and position them to the left of the close button.
340 - (void)addAdditionalControls { 341 - (void)addAdditionalControls {
341 ConfirmInfoBarDelegate* delegate = delegate_->AsConfirmInfoBarDelegate(); 342 ConfirmInfoBarDelegate* delegate = delegate_->AsConfirmInfoBarDelegate();
342 DCHECK(delegate); 343 DCHECK(delegate);
343 int visibleButtons = delegate->GetButtons(); 344 int visibleButtons = delegate->GetButtons();
(...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after
422 atOffset:[message length] 423 atOffset:[message length]
423 font:font 424 font:font
424 messageColor:[NSColor blackColor] 425 messageColor:[NSColor blackColor]
425 linkColor:[NSColor blueColor]]; 426 linkColor:[NSColor blueColor]];
426 } 427 }
427 428
428 // Called when someone clicks on the link in the infobar. This method 429 // Called when someone clicks on the link in the infobar. This method
429 // is called by the InfobarTextField on its delegate (the 430 // is called by the InfobarTextField on its delegate (the
430 // LinkInfoBarController). 431 // LinkInfoBarController).
431 - (void)linkClicked { 432 - (void)linkClicked {
433 if (![self owned])
434 return;
432 WindowOpenDisposition disposition = 435 WindowOpenDisposition disposition =
433 event_utils::WindowOpenDispositionFromNSEvent([NSApp currentEvent]); 436 event_utils::WindowOpenDispositionFromNSEvent([NSApp currentEvent]);
434 if (delegate_ && 437 if (delegate_->AsConfirmInfoBarDelegate()->LinkClicked(disposition))
435 delegate_->AsConfirmInfoBarDelegate()->LinkClicked(disposition))
436 [self removeSelf]; 438 [self removeSelf];
437 } 439 }
438 440
439 @end 441 @end
440 442
441 443
442 ////////////////////////////////////////////////////////////////////////// 444 //////////////////////////////////////////////////////////////////////////
443 // CreateInfoBar() implementations 445 // CreateInfoBar() implementations
444 446
445 InfoBar* LinkInfoBarDelegate::CreateInfoBar(TabContentsWrapper* owner) { 447 InfoBar* LinkInfoBarDelegate::CreateInfoBar(TabContentsWrapper* owner) {
446 LinkInfoBarController* controller = 448 LinkInfoBarController* controller =
447 [[LinkInfoBarController alloc] initWithDelegate:this owner:owner]; 449 [[LinkInfoBarController alloc] initWithDelegate:this owner:owner];
448 return new InfoBar(controller, this); 450 return new InfoBar(controller, this);
449 } 451 }
450 452
451 InfoBar* ConfirmInfoBarDelegate::CreateInfoBar(TabContentsWrapper* owner) { 453 InfoBar* ConfirmInfoBarDelegate::CreateInfoBar(TabContentsWrapper* owner) {
452 ConfirmInfoBarController* controller = 454 ConfirmInfoBarController* controller =
453 [[ConfirmInfoBarController alloc] initWithDelegate:this owner:owner]; 455 [[ConfirmInfoBarController alloc] initWithDelegate:this owner:owner];
454 return new InfoBar(controller, this); 456 return new InfoBar(controller, this);
455 } 457 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698