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

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, 3 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 37 // Called when someone clicks on the close button. Dismisses the
38 // call will trigger a notification that starts the infobar animating closed. 38 // infobar without taking any action.
39 - (void)removeSelf; 39 - (IBAction)dismiss:(id)sender;
40 40
41 // Performs final cleanup after an animation is finished or stopped, including 41 // Performs final cleanup after an animation is finished or stopped, including
42 // notifying the InfoBarDelegate that the infobar was closed and removing the 42 // notifying the InfoBarDelegate that the infobar was closed and removing the
43 // infobar from its container, if necessary. 43 // infobar from its container, if necessary.
44 - (void)cleanUpAfterAnimation:(BOOL)finished; 44 - (void)cleanUpAfterAnimation:(BOOL)finished;
45 45
46 // Returns the point, in gradient view coordinates, at which the apex of the 46 // Returns the point, in gradient view coordinates, at which the apex of the
47 // infobar tip should be drawn. 47 // infobar tip should be drawn.
48 - (NSPoint)pointForTipApex; 48 - (NSPoint)pointForTipApex;
49 @end 49 @end
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after
98 98
99 // Called when someone clicks on the embedded link. 99 // Called when someone clicks on the embedded link.
100 - (BOOL) textView:(NSTextView*)textView 100 - (BOOL) textView:(NSTextView*)textView
101 clickedOnLink:(id)link 101 clickedOnLink:(id)link
102 atIndex:(NSUInteger)charIndex { 102 atIndex:(NSUInteger)charIndex {
103 if ([self respondsToSelector:@selector(linkClicked)]) 103 if ([self respondsToSelector:@selector(linkClicked)])
104 [self performSelector:@selector(linkClicked)]; 104 [self performSelector:@selector(linkClicked)];
105 return YES; 105 return YES;
106 } 106 }
107 107
108 - (bool)owned {
109 return !!owner_;
110 }
111
108 // Called when someone clicks on the ok button. 112 // Called when someone clicks on the ok button.
109 - (void)ok:(id)sender { 113 - (void)ok:(id)sender {
110 // Subclasses must override this method if they do not hide the ok button. 114 // Subclasses must override this method if they do not hide the ok button.
111 NOTREACHED(); 115 NOTREACHED();
112 } 116 }
113 117
114 // Called when someone clicks on the cancel button. 118 // Called when someone clicks on the cancel button.
115 - (void)cancel:(id)sender { 119 - (void)cancel:(id)sender {
116 // Subclasses must override this method if they do not hide the cancel button. 120 // Subclasses must override this method if they do not hide the cancel button.
117 NOTREACHED(); 121 NOTREACHED();
118 } 122 }
119 123
120 // Called when someone clicks on the close button. 124 - (void)removeSelf {
121 - (void)dismiss:(id)sender { 125 DCHECK(owner_);
122 if (delegate_) 126 owner_->infobar_tab_helper()->RemoveInfoBar(delegate_);
123 delegate_->InfoBarDismissed();
124
125 [self removeSelf];
126 } 127 }
127 128
128 - (AnimatableView*)animatableView { 129 - (AnimatableView*)animatableView {
129 return static_cast<AnimatableView*>([self view]); 130 return static_cast<AnimatableView*>([self view]);
130 } 131 }
131 132
132 - (void)open { 133 - (void)open {
133 // Simply reset the frame size to its opened size, forcing a relayout. 134 // Simply reset the frame size to its opened size, forcing a relayout.
134 CGFloat finalHeight = [[self view] frame].size.height; 135 CGFloat finalHeight = [[self view] frame].size.height;
135 [[self animatableView] setHeight:finalHeight]; 136 [[self animatableView] setHeight:finalHeight];
(...skipping 22 matching lines...) Expand all
158 159
159 // Start animating closed. We will receive a notification when the animation 160 // 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 161 // is done, at which point we can remove our view from the hierarchy and
161 // notify the delegate that the infobar was closed. 162 // notify the delegate that the infobar was closed.
162 [[self animatableView] animateToNewHeight:0 duration:kAnimateCloseDuration]; 163 [[self animatableView] animateToNewHeight:0 duration:kAnimateCloseDuration];
163 164
164 // The above call may trigger an animationDidStop: notification for any 165 // The above call may trigger an animationDidStop: notification for any
165 // currently-running animations, so do not set |infoBarClosing_| until after 166 // currently-running animations, so do not set |infoBarClosing_| until after
166 // starting the animation. 167 // starting the animation.
167 infoBarClosing_ = YES; 168 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 } 169 }
173 170
174 - (void)addAdditionalControls { 171 - (void)addAdditionalControls {
175 // Default implementation does nothing. 172 // Default implementation does nothing.
176 } 173 }
177 174
178 - (void)infobarWillClose { 175 - (void)infobarWillClose {
179 // Default implementation does nothing. 176 owner_ = NULL;
180 } 177 }
181 178
182 - (void)removeButtons { 179 - (void)removeButtons {
183 // Extend the label all the way across. 180 // Extend the label all the way across.
184 NSRect labelFrame = [label_.get() frame]; 181 NSRect labelFrame = [label_.get() frame];
185 labelFrame.size.width = NSMaxX([cancelButton_ frame]) - NSMinX(labelFrame); 182 labelFrame.size.width = NSMaxX([cancelButton_ frame]) - NSMinX(labelFrame);
186 [okButton_ removeFromSuperview]; 183 [okButton_ removeFromSuperview];
187 okButton_ = nil; 184 okButton_ = nil;
188 [cancelButton_ removeFromSuperview]; 185 [cancelButton_ removeFromSuperview];
189 cancelButton_ = nil; 186 cancelButton_ = nil;
(...skipping 11 matching lines...) Expand all
201 // programmatically. 198 // programmatically.
202 label_.reset([[HyperlinkTextView alloc] 199 label_.reset([[HyperlinkTextView alloc]
203 initWithFrame:[labelPlaceholder_ frame]]); 200 initWithFrame:[labelPlaceholder_ frame]]);
204 [label_.get() setAutoresizingMask:[labelPlaceholder_ autoresizingMask]]; 201 [label_.get() setAutoresizingMask:[labelPlaceholder_ autoresizingMask]];
205 [[labelPlaceholder_ superview] 202 [[labelPlaceholder_ superview]
206 replaceSubview:labelPlaceholder_ with:label_.get()]; 203 replaceSubview:labelPlaceholder_ with:label_.get()];
207 labelPlaceholder_ = nil; // Now released. 204 labelPlaceholder_ = nil; // Now released.
208 [label_.get() setDelegate:self]; 205 [label_.get() setDelegate:self];
209 } 206 }
210 207
211 - (void)removeSelf { 208 // Called when someone clicks on the close button.
212 // TODO(rohitrao): This method can be called even if the infobar has already 209 - (void)dismiss:(id)sender {
213 // been removed and |delegate_| is NULL. Is there a way to rewrite the code 210 if (![self owned])
214 // so that inner event loops don't cause us to try and remove the infobar 211 return; // We're closing; don't call anything, it might access the owner.
215 // twice? http://crbug.com/54253 212 delegate_->InfoBarDismissed();
216 if (owner_) 213 [self removeSelf];
217 owner_->infobar_tab_helper()->RemoveInfoBar(delegate_);
218 owner_ = NULL;
219 } 214 }
220 215
221 - (void)cleanUpAfterAnimation:(BOOL)finished { 216 - (void)cleanUpAfterAnimation:(BOOL)finished {
222 // Don't need to do any cleanup if the bar was animating open. 217 // Don't need to do any cleanup if the bar was animating open.
223 if (!infoBarClosing_) 218 if (!infoBarClosing_)
224 return; 219 return;
225 220
226 // Notify the delegate that the infobar was closed. The delegate will delete 221 // 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. 222 // itself as a result of InfoBarClosed(), so we null out its pointer.
228 if (delegate_) { 223 if (delegate_) {
(...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after
291 atOffset:offset 286 atOffset:offset
292 font:font 287 font:font
293 messageColor:[NSColor blackColor] 288 messageColor:[NSColor blackColor]
294 linkColor:[NSColor blueColor]]; 289 linkColor:[NSColor blueColor]];
295 } 290 }
296 291
297 // Called when someone clicks on the link in the infobar. This method 292 // Called when someone clicks on the link in the infobar. This method
298 // is called by the InfobarTextField on its delegate (the 293 // is called by the InfobarTextField on its delegate (the
299 // LinkInfoBarController). 294 // LinkInfoBarController).
300 - (void)linkClicked { 295 - (void)linkClicked {
296 if (![self owned])
297 return; // We're closing; don't call anything, it might access the owner.
301 WindowOpenDisposition disposition = 298 WindowOpenDisposition disposition =
302 event_utils::WindowOpenDispositionFromNSEvent([NSApp currentEvent]); 299 event_utils::WindowOpenDispositionFromNSEvent([NSApp currentEvent]);
303 if (delegate_ && 300 if (delegate_->AsLinkInfoBarDelegate()->LinkClicked(disposition))
304 delegate_->AsLinkInfoBarDelegate()->LinkClicked(disposition)) { 301 [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 } 302 }
316 303
317 @end 304 @end
318 305
319 306
320 ///////////////////////////////////////////////////////////////////////// 307 /////////////////////////////////////////////////////////////////////////
321 // ConfirmInfoBarController implementation 308 // ConfirmInfoBarController implementation
322 309
323 @implementation ConfirmInfoBarController 310 @implementation ConfirmInfoBarController
324 311
325 // Called when someone clicks on the "OK" button. 312 // Called when someone clicks on the "OK" button.
326 - (IBAction)ok:(id)sender { 313 - (IBAction)ok:(id)sender {
327 if (delegate_ && delegate_->AsConfirmInfoBarDelegate()->Accept()) 314 if (![self owned])
315 return; // We're closing; don't call anything, it might access the owner.
316 if (delegate_->AsConfirmInfoBarDelegate()->Accept())
328 [self removeSelf]; 317 [self removeSelf];
329 } 318 }
330 319
331 // Called when someone clicks on the "Cancel" button. 320 // Called when someone clicks on the "Cancel" button.
332 - (IBAction)cancel:(id)sender { 321 - (IBAction)cancel:(id)sender {
333 if (delegate_ && delegate_->AsConfirmInfoBarDelegate()->Cancel()) 322 if (![self owned])
323 return; // We're closing; don't call anything, it might access the owner.
324 if (delegate_->AsConfirmInfoBarDelegate()->Cancel())
334 [self removeSelf]; 325 [self removeSelf];
335 } 326 }
336 327
337 // Confirm infobars can have OK and/or cancel buttons, depending on 328 // Confirm infobars can have OK and/or cancel buttons, depending on
338 // the return value of GetButtons(). We create each button if 329 // the return value of GetButtons(). We create each button if
339 // required and position them to the left of the close button. 330 // required and position them to the left of the close button.
340 - (void)addAdditionalControls { 331 - (void)addAdditionalControls {
341 ConfirmInfoBarDelegate* delegate = delegate_->AsConfirmInfoBarDelegate(); 332 ConfirmInfoBarDelegate* delegate = delegate_->AsConfirmInfoBarDelegate();
342 DCHECK(delegate); 333 DCHECK(delegate);
343 int visibleButtons = delegate->GetButtons(); 334 int visibleButtons = delegate->GetButtons();
(...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after
422 atOffset:[message length] 413 atOffset:[message length]
423 font:font 414 font:font
424 messageColor:[NSColor blackColor] 415 messageColor:[NSColor blackColor]
425 linkColor:[NSColor blueColor]]; 416 linkColor:[NSColor blueColor]];
426 } 417 }
427 418
428 // Called when someone clicks on the link in the infobar. This method 419 // Called when someone clicks on the link in the infobar. This method
429 // is called by the InfobarTextField on its delegate (the 420 // is called by the InfobarTextField on its delegate (the
430 // LinkInfoBarController). 421 // LinkInfoBarController).
431 - (void)linkClicked { 422 - (void)linkClicked {
423 if (![self owned])
424 return; // We're closing; don't call anything, it might access the owner.
432 WindowOpenDisposition disposition = 425 WindowOpenDisposition disposition =
433 event_utils::WindowOpenDispositionFromNSEvent([NSApp currentEvent]); 426 event_utils::WindowOpenDispositionFromNSEvent([NSApp currentEvent]);
434 if (delegate_ && 427 if (delegate_->AsConfirmInfoBarDelegate()->LinkClicked(disposition))
435 delegate_->AsConfirmInfoBarDelegate()->LinkClicked(disposition))
436 [self removeSelf]; 428 [self removeSelf];
437 } 429 }
438 430
439 @end 431 @end
440 432
441 433
442 ////////////////////////////////////////////////////////////////////////// 434 //////////////////////////////////////////////////////////////////////////
443 // CreateInfoBar() implementations 435 // CreateInfoBar() implementations
444 436
445 InfoBar* LinkInfoBarDelegate::CreateInfoBar(TabContentsWrapper* owner) { 437 InfoBar* LinkInfoBarDelegate::CreateInfoBar(TabContentsWrapper* owner) {
446 LinkInfoBarController* controller = 438 LinkInfoBarController* controller =
447 [[LinkInfoBarController alloc] initWithDelegate:this owner:owner]; 439 [[LinkInfoBarController alloc] initWithDelegate:this owner:owner];
448 return new InfoBar(controller, this); 440 return new InfoBar(controller, this);
449 } 441 }
450 442
451 InfoBar* ConfirmInfoBarDelegate::CreateInfoBar(TabContentsWrapper* owner) { 443 InfoBar* ConfirmInfoBarDelegate::CreateInfoBar(TabContentsWrapper* owner) {
452 ConfirmInfoBarController* controller = 444 ConfirmInfoBarController* controller =
453 [[ConfirmInfoBarController alloc] initWithDelegate:this owner:owner]; 445 [[ConfirmInfoBarController alloc] initWithDelegate:this owner:owner];
454 return new InfoBar(controller, this); 446 return new InfoBar(controller, this);
455 } 447 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698