| 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 65c7409ffad8c9e68e444ba952e237477f5978bc..3e1a25649732c4c077d3635670891d411858d5d2 100644
|
| --- a/chrome/browser/ui/cocoa/download/download_shelf_controller.mm
|
| +++ b/chrome/browser/ui/cocoa/download/download_shelf_controller.mm
|
| @@ -31,7 +31,7 @@ using content::DownloadItem;
|
| // Download shelf autoclose behavior:
|
| //
|
| // The download shelf autocloses if all of this is true:
|
| -// 1) An item on the shelf has just been opened.
|
| +// 1) An item on the shelf has just been opened or removed.
|
| // 2) All remaining items on the shelf have been opened in the past.
|
| // 3) The mouse leaves the shelf and remains off the shelf for 5 seconds.
|
| //
|
| @@ -71,13 +71,17 @@ const NSSize kHoverCloseButtonDefaultSize = { 18, 18 };
|
| } // namespace
|
|
|
| @interface DownloadShelfController(Private)
|
| +- (void)removeDownload:(DownloadItemController*)download
|
| + isShelfClosing:(BOOL)isShelfClosing;
|
| - (void)layoutItems:(BOOL)skipFirst;
|
| - (void)closed;
|
| - (void)maybeAutoCloseAfterDelay;
|
| +- (void)scheduleAutoClose;
|
| +- (void)cancelAutoClose;
|
| - (void)autoClose;
|
| - (void)viewFrameDidChange:(NSNotification*)notification;
|
| - (void)installTrackingArea;
|
| -- (void)cancelAutoCloseAndRemoveTrackingArea;
|
| +- (void)removeTrackingArea;
|
| - (void)willEnterFullscreen;
|
| - (void)willLeaveFullscreen;
|
| - (void)updateCloseButton;
|
| @@ -136,11 +140,12 @@ const NSSize kHoverCloseButtonDefaultSize = { 18, 18 };
|
| selector:@selector(willLeaveFullscreen)
|
| name:kWillLeaveFullscreenNotification
|
| object:nil];
|
| + [self installTrackingArea];
|
| }
|
|
|
| - (void)dealloc {
|
| [[NSNotificationCenter defaultCenter] removeObserver:self];
|
| - [self cancelAutoCloseAndRemoveTrackingArea];
|
| + [self removeTrackingArea];
|
|
|
| // The controllers will unregister themselves as observers when they are
|
| // deallocated. No need to do that here.
|
| @@ -177,6 +182,12 @@ const NSSize kHoverCloseButtonDefaultSize = { 18, 18 };
|
| }
|
|
|
| - (void)remove:(DownloadItemController*)download {
|
| + [self removeDownload:download
|
| + isShelfClosing:NO];
|
| +}
|
| +
|
| +- (void)removeDownload:(DownloadItemController*)download
|
| + isShelfClosing:(BOOL)isShelfClosing {
|
| // 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
|
| @@ -187,11 +198,14 @@ const NSSize kHoverCloseButtonDefaultSize = { 18, 18 };
|
| [[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];
|
| + if (!isShelfClosing) {
|
| + [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 {
|
| @@ -204,17 +218,22 @@ const NSSize kHoverCloseButtonDefaultSize = { 18, 18 };
|
| // to remove themselves as observers before the remaining shutdown happens.
|
| - (void)exiting {
|
| [[self animatableView] stopAnimation];
|
| - [self cancelAutoCloseAndRemoveTrackingArea];
|
| + [self removeTrackingArea];
|
| + while ([downloadItemControllers_ count] > 0) {
|
| + [self removeDownload:[downloadItemControllers_ lastObject]
|
| + isShelfClosing:YES];
|
| + }
|
| downloadItemControllers_.reset();
|
| }
|
|
|
| - (void)showDownloadShelf:(BOOL)show
|
| isUserAction:(BOOL)isUserAction {
|
| + shouldCloseOnMouseExit_ = NO;
|
| +
|
| 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())
|
| @@ -277,16 +296,20 @@ const NSSize kHoverCloseButtonDefaultSize = { 18, 18 };
|
|
|
| - (void)addDownloadItem:(DownloadItem*)downloadItem {
|
| DCHECK([NSThread isMainThread]);
|
| - [self cancelAutoCloseAndRemoveTrackingArea];
|
| -
|
| - // Insert new item at the left.
|
| scoped_nsobject<DownloadItemController> controller(
|
| [[DownloadItemController alloc] initWithDownload:downloadItem
|
| shelf:self
|
| navigator:navigator_]);
|
| + [self add:controller.get()];
|
| +}
|
| +
|
| +- (void)add:(DownloadItemController*)controller {
|
| + DCHECK([NSThread isMainThread]);
|
| + shouldCloseOnMouseExit_ = NO;
|
|
|
| + // Insert new item at the left.
|
| // Adding at index 0 in NSMutableArrays is O(1).
|
| - [downloadItemControllers_ insertObject:controller.get() atIndex:0];
|
| + [downloadItemControllers_ insertObject:controller atIndex:0];
|
|
|
| [itemContainerView_ addSubview:[controller view]];
|
|
|
| @@ -324,7 +347,8 @@ const NSSize kHoverCloseButtonDefaultSize = { 18, 18 };
|
| // Since no user will ever see the item being removed (needs a horizontal
|
| // screen resolution greater than 3200 at 16 items at 200 pixels each),
|
| // there's no point in animating the removal.
|
| - [self remove:[downloadItemControllers_ lastObject]];
|
| + [self removeDownload:[downloadItemControllers_ lastObject]
|
| + isShelfClosing:NO];
|
| }
|
|
|
| // Finally, move the remaining items to the right. Skip the first item when
|
| @@ -347,7 +371,8 @@ const NSSize kHoverCloseButtonDefaultSize = { 18, 18 };
|
| download->IsCancelled() ||
|
| download->IsInterrupted();
|
| if (isTransferDone && !download->IsDangerous()) {
|
| - [self remove:itemController];
|
| + [self removeDownload:itemController
|
| + isShelfClosing:YES];
|
| } else {
|
| // Treat the item as opened when we close. This way if we get shown again
|
| // the user need not open this item for the shelf to auto-close.
|
| @@ -358,16 +383,24 @@ const NSSize kHoverCloseButtonDefaultSize = { 18, 18 };
|
| }
|
|
|
| - (void)mouseEntered:(NSEvent*)event {
|
| + isMouseInsideView_ = YES;
|
| // If the mouse re-enters the download shelf, cancel the auto-close. Further
|
| - // mouse exits should not trigger autoclose, so also remove the tracking area.
|
| - [self cancelAutoCloseAndRemoveTrackingArea];
|
| + // mouse exits should not trigger autoclose.
|
| + if (shouldCloseOnMouseExit_) {
|
| + [self cancelAutoClose];
|
| + shouldCloseOnMouseExit_ = NO;
|
| + }
|
| }
|
|
|
| - (void)mouseExited:(NSEvent*)event {
|
| + isMouseInsideView_ = NO;
|
| + if (shouldCloseOnMouseExit_)
|
| + [self scheduleAutoClose];
|
| +}
|
| +
|
| +- (void)scheduleAutoClose {
|
| // Cancel any previous hide requests, just to be safe.
|
| - [NSObject cancelPreviousPerformRequestsWithTarget:self
|
| - selector:@selector(autoClose)
|
| - object:nil];
|
| + [self cancelAutoClose];
|
|
|
| // 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.
|
| @@ -376,6 +409,12 @@ const NSSize kHoverCloseButtonDefaultSize = { 18, 18 };
|
| afterDelay:kAutoCloseDelaySeconds];
|
| }
|
|
|
| +- (void)cancelAutoClose {
|
| + [NSObject cancelPreviousPerformRequestsWithTarget:self
|
| + selector:@selector(autoClose)
|
| + object:nil];
|
| +}
|
| +
|
| - (void)maybeAutoCloseAfterDelay {
|
| // We can close the shelf automatically if all the downloads on the shelf have
|
| // been opened.
|
| @@ -386,14 +425,12 @@ const NSSize kHoverCloseButtonDefaultSize = { 18, 18 };
|
| return;
|
| }
|
|
|
| - 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. Note that
|
| - // the mouse might not be over the shelf. In this case, the shelf will not
|
| - // auto close.
|
| - // TODO(asanka): Don't install a tracking area if the mouse isn't over the
|
| - // shelf. Autoclose instead.
|
| - [self installTrackingArea];
|
| + if ([self isVisible] && [downloadItemControllers_ count] > 0 &&
|
| + isMouseInsideView_) {
|
| + // If there are download items on the shelf and the user is potentially stil
|
| + // interacting with them, schedule an auto close after the user moves the
|
| + // mouse off the shelf.
|
| + shouldCloseOnMouseExit_ = YES;
|
| } 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
|
| @@ -408,28 +445,23 @@ const NSSize kHoverCloseButtonDefaultSize = { 18, 18 };
|
| }
|
|
|
| - (void)installTrackingArea {
|
| - // Install the tracking area to listen for mouseExited messages and trigger
|
| - // the shelf autoclose.
|
| - if (trackingArea_.get())
|
| - return;
|
| + // Install the tracking area to listen for mouseEntered and mouseExited
|
| + // messages.
|
| + DCHECK(!trackingArea_.get());
|
|
|
| - trackingArea_.reset([[NSTrackingArea alloc]
|
| + trackingArea_.reset([[CrTrackingArea alloc]
|
| initWithRect:[[self view] bounds]
|
| options:NSTrackingMouseEnteredAndExited |
|
| NSTrackingActiveAlways |
|
| NSTrackingInVisibleRect
|
| owner:self
|
| userInfo:nil]);
|
| - [[self view] addTrackingArea:trackingArea_];
|
| + [[self view] addTrackingArea:trackingArea_.get()];
|
| }
|
|
|
| -- (void)cancelAutoCloseAndRemoveTrackingArea {
|
| - [NSObject cancelPreviousPerformRequestsWithTarget:self
|
| - selector:@selector(autoClose)
|
| - object:nil];
|
| -
|
| +- (void)removeTrackingArea {
|
| if (trackingArea_.get()) {
|
| - [[self view] removeTrackingArea:trackingArea_];
|
| + [[self view] removeTrackingArea:trackingArea_.get()];
|
| trackingArea_.reset(nil);
|
| }
|
| }
|
|
|