Index: chrome/browser/cocoa/infobar_controller.mm |
=================================================================== |
--- chrome/browser/cocoa/infobar_controller.mm (revision 30850) |
+++ chrome/browser/cocoa/infobar_controller.mm (working copy) |
@@ -7,6 +7,7 @@ |
#include "base/logging.h" // for NOTREACHED() |
#include "base/mac_util.h" |
#include "base/sys_string_conversions.h" |
+#import "chrome/browser/cocoa/animatable_view.h" |
#include "chrome/browser/cocoa/event_utils.h" |
#include "chrome/browser/cocoa/infobar.h" |
#import "chrome/browser/cocoa/infobar_container_controller.h" |
@@ -16,14 +17,22 @@ |
#include "third_party/GTM/AppKit/GTMUILocalizerAndLayoutTweaker.h" |
#include "webkit/glue/window_open_disposition.h" |
+namespace { |
+// Durations set to match the default SlideAnimation duration. |
+const float kAnimateOpenDuration = 0.12; |
+const float kAnimateCloseDuration = 0.12; |
+} |
@interface InfoBarController (PrivateMethods) |
-// Closes the infobar by calling RemoveDelegate on the container. |
-// This will remove the infobar from its associated TabContents as |
-// well as trigger the deletion of this InfoBarController. Once the |
-// delegate is removed from the container, it is no longer needed, so |
-// we ask it to delete itself. |
-- (void)closeInfoBar; |
+// Asks the container controller to remove the infobar for this delegate. This |
+// call will trigger a notification that starts the infobar animating closed. |
+- (void)removeInfoBar; |
+ |
+// Performs final cleanup after an animation is finished or stopped, including |
+// notifying the InfoBarDelegate that the infobar was closed and removing the |
+// infobar from its container, if necessary. |
+- (void)cleanUpAfterAnimation:(BOOL)finished; |
+ |
// Removes the ok and cancel buttons, and resizes the textfield to use the |
// space. |
- (void)removeButtons; |
@@ -76,9 +85,46 @@ |
// Called when someone clicks on the close button. |
- (void)dismiss:(id)sender { |
- [self closeInfoBar]; |
+ [self removeInfoBar]; |
} |
+- (AnimatableView*)animatableView { |
+ return static_cast<AnimatableView*>([self view]); |
+} |
+ |
+- (void)open { |
+ // Simply reset the frame size to its opened size, forcing a relayout. |
+ CGFloat finalHeight = [[self view] frame].size.height; |
+ [[self animatableView] setHeight:finalHeight]; |
+} |
+ |
+- (void)animateOpen { |
+ // Force the frame size to be 0 and then start an animation. |
+ NSRect frame = [[self view] frame]; |
+ CGFloat finalHeight = frame.size.height; |
+ frame.size.height = 0; |
+ [[self view] setFrame:frame]; |
+ [[self animatableView] animateToNewHeight:finalHeight |
+ duration:kAnimateOpenDuration]; |
+} |
+ |
+- (void)close { |
+ infoBarClosing_ = YES; |
+ [self cleanUpAfterAnimation:YES]; |
+} |
+ |
+- (void)animateClosed { |
+ // Start animating closed. We will receive a notification when the animation |
+ // is done, at which point we can remove our view from the hierarchy and |
+ // notify the delegate that the infobar was closed. |
+ [[self animatableView] animateToNewHeight:0 duration:kAnimateCloseDuration]; |
+ |
+ // The above call may trigger an animationDidStop: notification for any |
+ // currently-running animations, so do not set |infoBarClosing_| until after |
+ // starting the animation. |
+ infoBarClosing_ = YES; |
+} |
+ |
- (void)addAdditionalControls { |
// Default implementation does nothing. |
} |
@@ -87,14 +133,9 @@ |
@implementation InfoBarController (PrivateMethods) |
-- (void)closeInfoBar { |
- // Calling RemoveDelegate() triggers notifications which will remove |
- // the infobar view from the infobar container. At that point it is |
- // safe to ask the delegate to delete itself. |
+- (void)removeInfoBar { |
DCHECK(delegate_); |
[containerController_ removeDelegate:delegate_]; |
- delegate_->InfoBarClosed(); |
- delegate_ = NULL; |
} |
- (void)removeButtons { |
@@ -107,6 +148,32 @@ |
[label_ setFrame:labelFrame]; |
} |
+- (void)cleanUpAfterAnimation:(BOOL)finished { |
+ // Don't need to do any cleanup if the bar was animating open. |
+ if (!infoBarClosing_) |
+ return; |
+ |
+ // Notify the delegate that the infobar was closed. The delegate may delete |
+ // itself as a result of InfoBarClosed(), so we null out its pointer. |
+ delegate_->InfoBarClosed(); |
+ delegate_ = NULL; |
+ |
+ // If the animation ran to completion, then we need to remove ourselves from |
+ // the container. If the animation was interrupted, then the container will |
+ // take care of removing us. |
+ // TODO(rohitrao): UGH! This works for now, but should be cleaner. |
+ if (finished) |
+ [containerController_ removeController:self]; |
+} |
+ |
+- (void)animationDidStop:(NSAnimation*)animation { |
+ [self cleanUpAfterAnimation:NO]; |
+} |
+ |
+- (void)animationDidEnd:(NSAnimation*)animation { |
+ [self cleanUpAfterAnimation:YES]; |
+} |
+ |
@end |
@@ -203,7 +270,7 @@ |
WindowOpenDisposition disposition = |
event_utils::WindowOpenDispositionFromNSEvent([NSApp currentEvent]); |
if (delegate_->AsLinkInfoBarDelegate()->LinkClicked(disposition)) |
- [self closeInfoBar]; |
+ [self removeInfoBar]; |
} |
@end |
@@ -217,13 +284,13 @@ |
// Called when someone clicks on the "OK" button. |
- (IBAction)ok:(id)sender { |
if (delegate_->AsConfirmInfoBarDelegate()->Accept()) |
- [self closeInfoBar]; |
+ [self removeInfoBar]; |
} |
// Called when someone clicks on the "Cancel" button. |
- (IBAction)cancel:(id)sender { |
if (delegate_->AsConfirmInfoBarDelegate()->Cancel()) |
- [self closeInfoBar]; |
+ [self removeInfoBar]; |
} |
// Confirm infobars can have OK and/or cancel buttons, depending on |