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