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

Side by Side Diff: chrome/browser/ui/cocoa/download/download_shelf_controller.mm

Issue 12995025: [Mac] DownloadShelf should be notified when autoclosing. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Address comments. Undo re-ordering. Created 7 years, 9 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) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 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 "chrome/browser/ui/cocoa/download/download_shelf_controller.h" 5 #import "chrome/browser/ui/cocoa/download/download_shelf_controller.h"
6 6
7 #include "base/mac/bundle_locations.h" 7 #include "base/mac/bundle_locations.h"
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/download/download_util.h" 10 #include "chrome/browser/download/download_util.h"
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after
64 // Amount of time between when the mouse is moved off the shelf and the shelf is 64 // Amount of time between when the mouse is moved off the shelf and the shelf is
65 // autoclosed, in seconds. 65 // autoclosed, in seconds.
66 const NSTimeInterval kAutoCloseDelaySeconds = 5; 66 const NSTimeInterval kAutoCloseDelaySeconds = 5;
67 67
68 // The size of the x button by default. 68 // The size of the x button by default.
69 const NSSize kHoverCloseButtonDefaultSize = { 18, 18 }; 69 const NSSize kHoverCloseButtonDefaultSize = { 18, 18 };
70 70
71 } // namespace 71 } // namespace
72 72
73 @interface DownloadShelfController(Private) 73 @interface DownloadShelfController(Private)
74 - (void)showDownloadShelf:(BOOL)enable;
75 - (void)layoutItems:(BOOL)skipFirst; 74 - (void)layoutItems:(BOOL)skipFirst;
76 - (void)closed; 75 - (void)closed;
77 - (BOOL)canAutoClose; 76 - (void)maybeAutoCloseAfterDelay;
78 77 - (void)autoClose;
79 - (void)viewFrameDidChange:(NSNotification*)notification; 78 - (void)viewFrameDidChange:(NSNotification*)notification;
80
81 - (void)installTrackingArea; 79 - (void)installTrackingArea;
82 - (void)cancelAutoCloseAndRemoveTrackingArea; 80 - (void)cancelAutoCloseAndRemoveTrackingArea;
83
84 - (void)willEnterFullscreen; 81 - (void)willEnterFullscreen;
85 - (void)willLeaveFullscreen; 82 - (void)willLeaveFullscreen;
86 - (void)updateCloseButton; 83 - (void)updateCloseButton;
87 @end 84 @end
88 85
89 86
90 @implementation DownloadShelfController 87 @implementation DownloadShelfController
91 88
92 - (id)initWithBrowser:(Browser*)browser 89 - (id)initWithBrowser:(Browser*)browser
93 resizeDelegate:(id<ViewResizer>)resizeDelegate { 90 resizeDelegate:(id<ViewResizer>)resizeDelegate {
(...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after
164 frame.origin.y -= currentShelfHeight_ - newShelfHeight; 161 frame.origin.y -= currentShelfHeight_ - newShelfHeight;
165 [view setFrame:frame]; 162 [view setFrame:frame];
166 } 163 }
167 currentShelfHeight_ = newShelfHeight; 164 currentShelfHeight_ = newShelfHeight;
168 } 165 }
169 166
170 - (AnimatableView*)animatableView { 167 - (AnimatableView*)animatableView {
171 return static_cast<AnimatableView*>([self view]); 168 return static_cast<AnimatableView*>([self view]);
172 } 169 }
173 170
174 - (void)showDownloadsTab:(id)sender { 171 - (IBAction)showDownloadsTab:(id)sender {
175 chrome::ShowDownloads(bridge_->browser()); 172 chrome::ShowDownloads(bridge_->browser());
176 } 173 }
177 174
175 - (IBAction)handleClose:(id)sender {
176 bridge_->Close(DownloadShelf::USER_ACTION);
177 }
178
178 - (void)remove:(DownloadItemController*)download { 179 - (void)remove:(DownloadItemController*)download {
179 // Look for the download in our controller array and remove it. This will 180 // Look for the download in our controller array and remove it. This will
180 // explicity release it so that it removes itself as an Observer of the 181 // explicity release it so that it removes itself as an Observer of the
181 // DownloadItem. We don't want to wait for autorelease since the DownloadItem 182 // DownloadItem. We don't want to wait for autorelease since the DownloadItem
182 // we are observing will likely be gone by then. 183 // we are observing will likely be gone by then.
183 [[NSNotificationCenter defaultCenter] removeObserver:download]; 184 [[NSNotificationCenter defaultCenter] removeObserver:download];
184 185
185 // TODO(dmaclach): Remove -- http://crbug.com/25845 186 // TODO(dmaclach): Remove -- http://crbug.com/25845
186 [[download view] removeFromSuperview]; 187 [[download view] removeFromSuperview];
187 188
188 [downloadItemControllers_ removeObject:download]; 189 [downloadItemControllers_ removeObject:download];
189
190 [self layoutItems]; 190 [self layoutItems];
191 191
192 // Check to see if we have any downloads remaining and if not, hide the shelf. 192 // If there are no more downloads or if all the remaining downloads have been
193 if (![downloadItemControllers_ count]) 193 // opened, we can close the shelf.
194 [self showDownloadShelf:NO]; 194 [self maybeAutoCloseAfterDelay];
Nico 2013/03/22 21:29:17 maybeACAD installs a tracking area to check if the
asanka 2013/03/22 21:33:24 It's not a given. This is true for all calls of ma
195 } 195 }
196 196
197 - (void)downloadWasOpened:(DownloadItemController*)item_controller { 197 - (void)downloadWasOpened:(DownloadItemController*)item_controller {
198 // This should only be called on the main thead. 198 // This should only be called on the main thead.
199 DCHECK([NSThread isMainThread]); 199 DCHECK([NSThread isMainThread]);
200 200 [self maybeAutoCloseAfterDelay];
201 if ([self canAutoClose])
202 [self installTrackingArea];
203 } 201 }
204 202
205 // We need to explicitly release our download controllers here since they need 203 // We need to explicitly release our download controllers here since they need
206 // to remove themselves as observers before the remaining shutdown happens. 204 // to remove themselves as observers before the remaining shutdown happens.
207 - (void)exiting { 205 - (void)exiting {
208 [[self animatableView] stopAnimation]; 206 [[self animatableView] stopAnimation];
209 [self cancelAutoCloseAndRemoveTrackingArea]; 207 [self cancelAutoCloseAndRemoveTrackingArea];
210 downloadItemControllers_.reset(); 208 downloadItemControllers_.reset();
211 } 209 }
212 210
213 // Show or hide the bar based on the value of |enable|. Handles animating the 211 - (void)showDownloadShelf:(BOOL)show
214 // resize of the content view. 212 isUserAction:(BOOL)isUserAction {
215 - (void)showDownloadShelf:(BOOL)enable { 213 if ([self isVisible] == show)
216 if ([self isVisible] == enable)
217 return; 214 return;
218 215
216 if (!show) {
217 [self cancelAutoCloseAndRemoveTrackingArea];
218 int numInProgress = 0;
219 for (NSUInteger i = 0; i < [downloadItemControllers_ count]; ++i) {
220 if ([[downloadItemControllers_ objectAtIndex:i]download]->IsInProgress())
221 ++numInProgress;
222 }
223 download_util::RecordShelfClose(
224 [downloadItemControllers_ count], numInProgress, !isUserAction);
225 }
226
219 // Animate the shelf out, but not in. 227 // Animate the shelf out, but not in.
220 // TODO(rohitrao): We do not animate on the way in because Cocoa is already 228 // TODO(rohitrao): We do not animate on the way in because Cocoa is already
221 // doing a lot of work to set up the download arrow animation. I've chosen to 229 // doing a lot of work to set up the download arrow animation. I've chosen to
222 // do no animation over janky animation. Find a way to make animating in 230 // do no animation over janky animation. Find a way to make animating in
223 // smoother. 231 // smoother.
224 AnimatableView* view = [self animatableView]; 232 AnimatableView* view = [self animatableView];
225 if (enable) 233 if (show)
226 [view setHeight:maxShelfHeight_]; 234 [view setHeight:maxShelfHeight_];
227 else 235 else
228 [view animateToNewHeight:0 duration:kDownloadShelfCloseDuration]; 236 [view animateToNewHeight:0 duration:kDownloadShelfCloseDuration];
229 237
230 barIsVisible_ = enable; 238 barIsVisible_ = show;
231 [self updateCloseButton]; 239 [self updateCloseButton];
232 } 240 }
233 241
234 - (DownloadShelf*)bridge { 242 - (DownloadShelf*)bridge {
235 return bridge_.get(); 243 return bridge_.get();
236 } 244 }
237 245
238 - (BOOL)isVisible { 246 - (BOOL)isVisible {
239 return barIsVisible_; 247 return barIsVisible_;
240 } 248 }
241 249
242 - (void)show:(id)sender {
243 [self showDownloadShelf:YES];
244 }
245
246 - (void)hide:(id)sender {
247 [self cancelAutoCloseAndRemoveTrackingArea];
248
249 // If |sender| isn't nil, then we're being closed from the UI by the user and
250 // we need to tell our shelf implementation to close. Otherwise, we're being
251 // closed programmatically by our shelf implementation.
252 bool auto_closed = (sender == nil);
253
254 int numInProgress = 0;
255 for (NSUInteger i = 0; i < [downloadItemControllers_ count]; ++i) {
256 if ([[downloadItemControllers_ objectAtIndex:i]download]->IsInProgress())
257 ++numInProgress;
258 }
259 download_util::RecordShelfClose(
260 [downloadItemControllers_ count], numInProgress, auto_closed);
261 if (auto_closed)
262 [self showDownloadShelf:NO];
263 else
264 bridge_->Close();
265 }
266
267 - (void)animationDidEnd:(NSAnimation*)animation { 250 - (void)animationDidEnd:(NSAnimation*)animation {
268 if (![self isVisible]) 251 if (![self isVisible])
269 [self closed]; 252 [self closed];
270 } 253 }
271 254
272 - (float)height { 255 - (float)height {
273 return maxShelfHeight_; 256 return maxShelfHeight_;
274 } 257 }
275 258
276 // If |skipFirst| is true, the frame of the leftmost item is not set. 259 // If |skipFirst| is true, the frame of the leftmost item is not set.
(...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after
376 359
377 - (void)mouseEntered:(NSEvent*)event { 360 - (void)mouseEntered:(NSEvent*)event {
378 // If the mouse re-enters the download shelf, cancel the auto-close. Further 361 // If the mouse re-enters the download shelf, cancel the auto-close. Further
379 // mouse exits should not trigger autoclose, so also remove the tracking area. 362 // mouse exits should not trigger autoclose, so also remove the tracking area.
380 [self cancelAutoCloseAndRemoveTrackingArea]; 363 [self cancelAutoCloseAndRemoveTrackingArea];
381 } 364 }
382 365
383 - (void)mouseExited:(NSEvent*)event { 366 - (void)mouseExited:(NSEvent*)event {
384 // Cancel any previous hide requests, just to be safe. 367 // Cancel any previous hide requests, just to be safe.
385 [NSObject cancelPreviousPerformRequestsWithTarget:self 368 [NSObject cancelPreviousPerformRequestsWithTarget:self
386 selector:@selector(hide:) 369 selector:@selector(autoClose)
387 object:self]; 370 object:nil];
388 371
389 // Schedule an autoclose after a delay. If the mouse is moved back into the 372 // Schedule an autoclose after a delay. If the mouse is moved back into the
390 // view, or if an item is added to the shelf, the timer will be canceled. 373 // view, or if an item is added to the shelf, the timer will be canceled.
391 [self performSelector:@selector(hide:) 374 [self performSelector:@selector(autoClose)
392 withObject:self 375 withObject:nil
393 afterDelay:kAutoCloseDelaySeconds]; 376 afterDelay:kAutoCloseDelaySeconds];
394 } 377 }
395 378
396 - (BOOL)canAutoClose { 379 - (void)maybeAutoCloseAfterDelay {
380 // We can close the shelf automatically if all the downloads on the shelf have
381 // been opened.
397 for (NSUInteger i = 0; i < [downloadItemControllers_ count]; ++i) { 382 for (NSUInteger i = 0; i < [downloadItemControllers_ count]; ++i) {
398 DownloadItemController* itemController = 383 DownloadItemController* itemController =
399 [downloadItemControllers_ objectAtIndex:i]; 384 [downloadItemControllers_ objectAtIndex:i];
400 if (![itemController download]->GetOpened()) 385 if (![itemController download]->GetOpened())
401 return NO; 386 return;
402 } 387 }
403 return YES; 388
389 if ([self isVisible] && [downloadItemControllers_ count] > 0) {
390 // If the shelf is visible and has download items remaining on it, close the
391 // shelf after the user moves the mouse out of the download shelf.
Nico 2013/03/22 21:42:47 Might want to mention that this is somewhat optimi
asanka 2013/03/29 15:56:20 I added a comment describing the current behavior.
392 [self installTrackingArea];
393 } else {
394 // We notify the DownloadShelf of our intention to close even if the shelf
395 // is currently hidden. If the shelf was temporarily hidden (e.g. because
396 // the browser window entered fullscreen mode), then this prevents the shelf
397 // from being shown again when the browser exits fullscreen mode.
398 [self autoClose];
399 }
400 }
401
402 - (void)autoClose {
403 bridge_->Close(DownloadShelf::AUTOMATIC);
404 } 404 }
405 405
406 - (void)installTrackingArea { 406 - (void)installTrackingArea {
407 // Install the tracking area to listen for mouseExited messages and trigger 407 // Install the tracking area to listen for mouseExited messages and trigger
408 // the shelf autoclose. 408 // the shelf autoclose.
409 if (trackingArea_.get()) 409 if (trackingArea_.get())
410 return; 410 return;
411 411
412 trackingArea_.reset([[NSTrackingArea alloc] 412 trackingArea_.reset([[NSTrackingArea alloc]
413 initWithRect:[[self view] bounds] 413 initWithRect:[[self view] bounds]
414 options:NSTrackingMouseEnteredAndExited | 414 options:NSTrackingMouseEnteredAndExited |
415 NSTrackingActiveAlways 415 NSTrackingActiveAlways
Nico 2013/03/22 21:42:47 BTW: Do you to pass NSTrackingInVisibleRect here t
asanka 2013/03/29 15:56:20 Done.
416 owner:self 416 owner:self
417 userInfo:nil]); 417 userInfo:nil]);
418 [[self view] addTrackingArea:trackingArea_]; 418 [[self view] addTrackingArea:trackingArea_];
419 } 419 }
420 420
421 - (void)cancelAutoCloseAndRemoveTrackingArea { 421 - (void)cancelAutoCloseAndRemoveTrackingArea {
422 [NSObject cancelPreviousPerformRequestsWithTarget:self 422 [NSObject cancelPreviousPerformRequestsWithTarget:self
423 selector:@selector(hide:) 423 selector:@selector(autoClose)
424 object:self]; 424 object:nil];
425 425
426 if (trackingArea_.get()) { 426 if (trackingArea_.get()) {
427 [[self view] removeTrackingArea:trackingArea_]; 427 [[self view] removeTrackingArea:trackingArea_];
428 trackingArea_.reset(nil); 428 trackingArea_.reset(nil);
429 } 429 }
430 } 430 }
431 431
432 - (void)willEnterFullscreen { 432 - (void)willEnterFullscreen {
433 isFullscreen_ = YES; 433 isFullscreen_ = YES;
434 [self updateCloseButton]; 434 [self updateCloseButton];
(...skipping 24 matching lines...) Expand all
459 } 459 }
460 460
461 // Set the tracking off to create a new tracking area for the control. 461 // Set the tracking off to create a new tracking area for the control.
462 // When changing the bounds/frame on a HoverButton, the tracking isn't updated 462 // When changing the bounds/frame on a HoverButton, the tracking isn't updated
463 // correctly, it needs to be turned off and back on. 463 // correctly, it needs to be turned off and back on.
464 [hoverCloseButton_ setTrackingEnabled:NO]; 464 [hoverCloseButton_ setTrackingEnabled:NO];
465 [hoverCloseButton_ setFrame:bounds]; 465 [hoverCloseButton_ setFrame:bounds];
466 [hoverCloseButton_ setTrackingEnabled:YES]; 466 [hoverCloseButton_ setTrackingEnabled:YES];
467 } 467 }
468 @end 468 @end
OLDNEW
« no previous file with comments | « chrome/browser/ui/cocoa/download/download_shelf_controller.h ('k') | chrome/browser/ui/cocoa/download/download_shelf_mac.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698