Chromium Code Reviews| Index: chrome/browser/ui/cocoa/download/download_shelf_controller.mm |
| diff --git a/chrome/browser/ui/cocoa/download/download_shelf_controller.mm b/chrome/browser/ui/cocoa/download/download_shelf_controller.mm |
| index 16ea814138133fb0a5a7335bf60b4bd9ccc94fc5..9c66a90aa6329203c015dc71bcd3fb712edc07f4 100644 |
| --- a/chrome/browser/ui/cocoa/download/download_shelf_controller.mm |
| +++ b/chrome/browser/ui/cocoa/download/download_shelf_controller.mm |
| @@ -71,16 +71,13 @@ const NSSize kHoverCloseButtonDefaultSize = { 18, 18 }; |
| } // namespace |
| @interface DownloadShelfController(Private) |
| -- (void)showDownloadShelf:(BOOL)enable; |
| +- (void)viewFrameDidChange:(NSNotification*)notification; |
| - (void)layoutItems:(BOOL)skipFirst; |
| - (void)closed; |
| -- (BOOL)canAutoClose; |
| - |
| -- (void)viewFrameDidChange:(NSNotification*)notification; |
| - |
| +- (void)maybeAutoCloseAfterDelay; |
| +- (void)autoClose; |
| - (void)installTrackingArea; |
| - (void)cancelAutoCloseAndRemoveTrackingArea; |
| - |
| - (void)willEnterFullscreen; |
| - (void)willLeaveFullscreen; |
| - (void)updateCloseButton; |
| @@ -150,144 +147,44 @@ const NSSize kHoverCloseButtonDefaultSize = { 18, 18 }; |
| [super dealloc]; |
| } |
| -// Called after the frame's rect has changed; usually when the height is |
| -// animated. |
| -- (void)viewFrameDidChange:(NSNotification*)notification { |
|
asanka
2013/03/22 20:11:01
Methods were re-ordered to match declaration order
Nico
2013/03/22 20:24:11
Can you land that part as a separate CL? That woul
asanka
2013/03/22 21:22:13
I undid the re-ordering. I see the point about mes
|
| - // Anchor subviews at the top of |view|, so that it looks like the shelf |
| - // is sliding out. |
| - CGFloat newShelfHeight = NSHeight([[self view] frame]); |
| - if (newShelfHeight == currentShelfHeight_) |
| - return; |
| - |
| - for (NSView* view in [[self view] subviews]) { |
| - NSRect frame = [view frame]; |
| - frame.origin.y -= currentShelfHeight_ - newShelfHeight; |
| - [view setFrame:frame]; |
| - } |
| - currentShelfHeight_ = newShelfHeight; |
| -} |
| - |
| -- (AnimatableView*)animatableView { |
| - return static_cast<AnimatableView*>([self view]); |
| -} |
| - |
| -- (void)showDownloadsTab:(id)sender { |
| +- (IBAction)showDownloadsTab:(id)sender { |
| chrome::ShowDownloads(bridge_->browser()); |
| } |
| -- (void)remove:(DownloadItemController*)download { |
| - // Look for the download in our controller array and remove it. This will |
| - // explicity release it so that it removes itself as an Observer of the |
| - // DownloadItem. We don't want to wait for autorelease since the DownloadItem |
| - // we are observing will likely be gone by then. |
| - [[NSNotificationCenter defaultCenter] removeObserver:download]; |
| - |
| - // TODO(dmaclach): Remove -- http://crbug.com/25845 |
| - [[download view] removeFromSuperview]; |
| - |
| - [downloadItemControllers_ removeObject:download]; |
| - |
| - [self layoutItems]; |
| - |
| - // Check to see if we have any downloads remaining and if not, hide the shelf. |
| - if (![downloadItemControllers_ count]) |
| - [self showDownloadShelf:NO]; |
| -} |
| - |
| -- (void)downloadWasOpened:(DownloadItemController*)item_controller { |
| - // This should only be called on the main thead. |
| - DCHECK([NSThread isMainThread]); |
| - |
| - if ([self canAutoClose]) |
| - [self installTrackingArea]; |
| +- (IBAction)handleClose:(id)sender { |
| + bridge_->Close(DownloadShelf::USER_ACTION); |
| } |
| -// We need to explicitly release our download controllers here since they need |
| -// to remove themselves as observers before the remaining shutdown happens. |
| -- (void)exiting { |
| - [[self animatableView] stopAnimation]; |
| - [self cancelAutoCloseAndRemoveTrackingArea]; |
| - downloadItemControllers_.reset(); |
| -} |
| - |
| -// Show or hide the bar based on the value of |enable|. Handles animating the |
| -// resize of the content view. |
| -- (void)showDownloadShelf:(BOOL)enable { |
| - if ([self isVisible] == enable) |
| +- (void)showDownloadShelf:(BOOL)show |
| + isUserAction:(BOOL)isUserAction { |
| + if ([self isVisible] == show) |
| return; |
| + if (!show) { |
| + [self cancelAutoCloseAndRemoveTrackingArea]; |
| + int numInProgress = 0; |
| + for (NSUInteger i = 0; i < [downloadItemControllers_ count]; ++i) { |
| + if ([[downloadItemControllers_ objectAtIndex:i]download]->IsInProgress()) |
| + ++numInProgress; |
| + } |
| + download_util::RecordShelfClose( |
| + [downloadItemControllers_ count], numInProgress, !isUserAction); |
| + } |
| // Animate the shelf out, but not in. |
| // TODO(rohitrao): We do not animate on the way in because Cocoa is already |
| // doing a lot of work to set up the download arrow animation. I've chosen to |
| // do no animation over janky animation. Find a way to make animating in |
| // smoother. |
| AnimatableView* view = [self animatableView]; |
| - if (enable) |
| + if (show) |
| [view setHeight:maxShelfHeight_]; |
| else |
| [view animateToNewHeight:0 duration:kDownloadShelfCloseDuration]; |
| - barIsVisible_ = enable; |
| + barIsVisible_ = show; |
| [self updateCloseButton]; |
| } |
| -- (DownloadShelf*)bridge { |
| - return bridge_.get(); |
| -} |
| - |
| -- (BOOL)isVisible { |
| - return barIsVisible_; |
| -} |
| - |
| -- (void)show:(id)sender { |
| - [self showDownloadShelf:YES]; |
| -} |
| - |
| -- (void)hide:(id)sender { |
| - [self cancelAutoCloseAndRemoveTrackingArea]; |
| - |
| - // If |sender| isn't nil, then we're being closed from the UI by the user and |
| - // we need to tell our shelf implementation to close. Otherwise, we're being |
| - // closed programmatically by our shelf implementation. |
| - bool auto_closed = (sender == nil); |
| - |
| - int numInProgress = 0; |
| - for (NSUInteger i = 0; i < [downloadItemControllers_ count]; ++i) { |
| - if ([[downloadItemControllers_ objectAtIndex:i]download]->IsInProgress()) |
| - ++numInProgress; |
| - } |
| - download_util::RecordShelfClose( |
| - [downloadItemControllers_ count], numInProgress, auto_closed); |
| - if (auto_closed) |
| - [self showDownloadShelf:NO]; |
| - else |
| - bridge_->Close(); |
| -} |
| - |
| -- (void)animationDidEnd:(NSAnimation*)animation { |
| - if (![self isVisible]) |
| - [self closed]; |
| -} |
| - |
| -- (float)height { |
| - return maxShelfHeight_; |
| -} |
| - |
| -// If |skipFirst| is true, the frame of the leftmost item is not set. |
| -- (void)layoutItems:(BOOL)skipFirst { |
| - CGFloat currentX = 0; |
| - for (DownloadItemController* itemController |
| - in downloadItemControllers_.get()) { |
| - NSRect frame = [[itemController view] frame]; |
| - frame.origin.x = currentX; |
| - frame.size.width = [itemController preferredSize].width; |
| - if (!skipFirst) |
| - [[[itemController view] animator] setFrame:frame]; |
| - currentX += frame.size.width + kDownloadItemPadding; |
| - skipFirst = NO; |
| - } |
| -} |
| - |
| - (void)layoutItems { |
| [self layoutItems:NO]; |
| } |
| @@ -350,6 +247,91 @@ const NSSize kHoverCloseButtonDefaultSize = { 18, 18 }; |
| [self layoutItems:YES]; |
| } |
| +- (void)remove:(DownloadItemController*)download { |
| + // Look for the download in our controller array and remove it. This will |
| + // explicity release it so that it removes itself as an Observer of the |
| + // DownloadItem. We don't want to wait for autorelease since the DownloadItem |
| + // we are observing will likely be gone by then. |
| + [[NSNotificationCenter defaultCenter] removeObserver:download]; |
| + |
| + // TODO(dmaclach): Remove -- http://crbug.com/25845 |
| + [[download view] removeFromSuperview]; |
| + |
| + [downloadItemControllers_ removeObject:download]; |
| + [self layoutItems]; |
| + |
| + // If there are no more downloads or if all the remaining downloads have been |
| + // opened, we can close the shelf. |
| + [self maybeAutoCloseAfterDelay]; |
| +} |
| + |
| +- (void)downloadWasOpened:(DownloadItemController*)item_controller { |
| + // This should only be called on the main thead. |
| + DCHECK([NSThread isMainThread]); |
| + [self maybeAutoCloseAfterDelay]; |
| +} |
| + |
| +// We need to explicitly release our download controllers here since they need |
| +// to remove themselves as observers before the remaining shutdown happens. |
| +- (void)exiting { |
| + [[self animatableView] stopAnimation]; |
| + [self cancelAutoCloseAndRemoveTrackingArea]; |
| + downloadItemControllers_.reset(); |
| +} |
| + |
| +- (AnimatableView*)animatableView { |
| + return static_cast<AnimatableView*>([self view]); |
| +} |
| + |
| +- (DownloadShelf*)bridge { |
| + return bridge_.get(); |
| +} |
| + |
| +- (BOOL)isVisible { |
| + return barIsVisible_; |
| +} |
| + |
| +- (float)height { |
| + return maxShelfHeight_; |
| +} |
| + |
| +// Called after the frame's rect has changed; usually when the height is |
| +// animated. |
| +- (void)viewFrameDidChange:(NSNotification*)notification { |
| + // Anchor subviews at the top of |view|, so that it looks like the shelf |
| + // is sliding out. |
| + CGFloat newShelfHeight = NSHeight([[self view] frame]); |
| + if (newShelfHeight == currentShelfHeight_) |
| + return; |
| + |
| + for (NSView* view in [[self view] subviews]) { |
| + NSRect frame = [view frame]; |
| + frame.origin.y -= currentShelfHeight_ - newShelfHeight; |
| + [view setFrame:frame]; |
| + } |
| + currentShelfHeight_ = newShelfHeight; |
| +} |
| + |
| +- (void)animationDidEnd:(NSAnimation*)animation { |
| + if (![self isVisible]) |
| + [self closed]; |
| +} |
| + |
| +// If |skipFirst| is true, the frame of the leftmost item is not set. |
| +- (void)layoutItems:(BOOL)skipFirst { |
| + CGFloat currentX = 0; |
| + for (DownloadItemController* itemController |
| + in downloadItemControllers_.get()) { |
| + NSRect frame = [[itemController view] frame]; |
| + frame.origin.x = currentX; |
| + frame.size.width = [itemController preferredSize].width; |
| + if (!skipFirst) |
| + [[[itemController view] animator] setFrame:frame]; |
| + currentX += frame.size.width + kDownloadItemPadding; |
| + skipFirst = NO; |
| + } |
| +} |
| + |
| - (void)closed { |
| // Don't remove completed downloads if the shelf is just being auto-hidden |
| // rather than explicitly closed by the user. |
| @@ -383,24 +365,41 @@ const NSSize kHoverCloseButtonDefaultSize = { 18, 18 }; |
| - (void)mouseExited:(NSEvent*)event { |
| // Cancel any previous hide requests, just to be safe. |
| [NSObject cancelPreviousPerformRequestsWithTarget:self |
| - selector:@selector(hide:) |
| - object:self]; |
| + selector:@selector(autoClose) |
| + object:nil]; |
| // Schedule an autoclose after a delay. If the mouse is moved back into the |
| // view, or if an item is added to the shelf, the timer will be canceled. |
| - [self performSelector:@selector(hide:) |
| - withObject:self |
| + [self performSelector:@selector(autoClose) |
| + withObject:nil |
| afterDelay:kAutoCloseDelaySeconds]; |
| } |
| -- (BOOL)canAutoClose { |
| +- (void)maybeAutoCloseAfterDelay { |
| + // We can close the shelf automatically if all the downloads on the shelf have |
| + // been opened. |
| for (NSUInteger i = 0; i < [downloadItemControllers_ count]; ++i) { |
| DownloadItemController* itemController = |
| [downloadItemControllers_ objectAtIndex:i]; |
| if (![itemController download]->GetOpened()) |
| - return NO; |
| + return; |
| } |
| - return YES; |
| + |
| + if ([self isVisible] && [downloadItemControllers_ count] > 0) { |
| + // If the shelf is visible and has download items remaining on it, close the |
| + // shelf after the user moves the mouse out of the download shelf. |
| + [self installTrackingArea]; |
| + } else { |
| + // We notify the DownloadShelf of our intention to close even if the shelf |
| + // is currently hidden. If the shelf was temporarily hidden (e.g. because |
| + // the browser window entered fullscreen mode), then this prevents the shelf |
| + // from being shown again when the browser exits fullscreen mode. |
| + [self autoClose]; |
| + } |
| +} |
| + |
| +- (void)autoClose { |
| + bridge_->Close(DownloadShelf::AUTOMATIC); |
| } |
| - (void)installTrackingArea { |
| @@ -420,8 +419,8 @@ const NSSize kHoverCloseButtonDefaultSize = { 18, 18 }; |
| - (void)cancelAutoCloseAndRemoveTrackingArea { |
| [NSObject cancelPreviousPerformRequestsWithTarget:self |
| - selector:@selector(hide:) |
| - object:self]; |
| + selector:@selector(autoClose) |
| + object:nil]; |
| if (trackingArea_.get()) { |
| [[self view] removeTrackingArea:trackingArea_]; |