| OLD | NEW |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 } |
| OLD | NEW |