| OLD | NEW |
| 1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2009 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/cocoa/download_shelf_controller.h" | 5 #import "chrome/browser/cocoa/download_shelf_controller.h" |
| 6 | 6 |
| 7 #include "app/l10n_util.h" | 7 #include "app/l10n_util.h" |
| 8 #include "base/mac_util.h" | 8 #include "base/mac_util.h" |
| 9 #include "base/sys_string_conversions.h" | 9 #include "base/sys_string_conversions.h" |
| 10 #include "chrome/browser/browser.h" | 10 #include "chrome/browser/browser.h" |
| 11 #import "chrome/browser/cocoa/browser_window_controller.h" | 11 #import "chrome/browser/cocoa/browser_window_controller.h" |
| 12 #include "chrome/browser/cocoa/browser_window_cocoa.h" | 12 #include "chrome/browser/cocoa/browser_window_cocoa.h" |
| 13 #include "chrome/browser/cocoa/download_item_controller.h" | 13 #include "chrome/browser/cocoa/download_item_controller.h" |
| 14 #include "chrome/browser/cocoa/download_shelf_mac.h" | 14 #include "chrome/browser/cocoa/download_shelf_mac.h" |
| 15 #import "chrome/browser/cocoa/download_shelf_view.h" | 15 #import "chrome/browser/cocoa/download_shelf_view.h" |
| 16 #include "grit/generated_resources.h" | 16 #include "grit/generated_resources.h" |
| 17 | 17 |
| 18 namespace { | 18 namespace { |
| 19 | 19 |
| 20 // Max number of download views we'll contain. Any time a view is added and | 20 // Max number of download views we'll contain. Any time a view is added and |
| 21 // we already have this many download views, one is removed. | 21 // we already have this many download views, one is removed. |
| 22 const size_t kMaxDownloadItemCount = 16; | 22 const size_t kMaxDownloadItemCount = 16; |
| 23 | 23 |
| 24 // Border padding of a download item. | 24 // Border padding of a download item. |
| 25 const int kDownloadItemBorderPadding = 3; | 25 const int kDownloadItemBorderPadding = 3; |
| 26 | 26 |
| 27 // Width of a download item, must match width in DownloadItem.xib. | |
| 28 const int kDownloadItemWidth = 200; | |
| 29 | |
| 30 // Height of a download item, must match height in DownloadItem.xib. | |
| 31 const int kDownloadItemHeight = 34; | |
| 32 | |
| 33 // Horizontal padding between two download items. | 27 // Horizontal padding between two download items. |
| 34 const int kDownloadItemPadding = 10; | 28 const int kDownloadItemPadding = 10; |
| 35 | 29 |
| 36 // Duration for the open-new-leftmost-item animation, in seconds. | 30 // Duration for the open-new-leftmost-item animation, in seconds. |
| 37 const NSTimeInterval kDownloadItemOpenDuration = 0.8; | 31 const NSTimeInterval kDownloadItemOpenDuration = 0.8; |
| 38 | 32 |
| 39 } // namespace | 33 } // namespace |
| 40 | 34 |
| 41 @interface DownloadShelfController(Private) | 35 @interface DownloadShelfController(Private) |
| 42 - (void)applyContentAreaOffset:(BOOL)apply; | 36 - (void)applyContentAreaOffset:(BOOL)apply; |
| 43 - (void)showDownloadShelf:(BOOL)enable; | 37 - (void)showDownloadShelf:(BOOL)enable; |
| 44 - (void)resizeDownloadLinkToFit; | 38 - (void)resizeDownloadLinkToFit; |
| 39 - (void)layoutItems:(BOOL)skipFirst; |
| 45 @end | 40 @end |
| 46 | 41 |
| 47 | 42 |
| 48 @implementation DownloadShelfController | 43 @implementation DownloadShelfController |
| 49 | 44 |
| 50 - (id)initWithBrowser:(Browser*)browser | 45 - (id)initWithBrowser:(Browser*)browser |
| 51 resizeDelegate:(id<ViewResizer>)resizeDelegate { | 46 resizeDelegate:(id<ViewResizer>)resizeDelegate { |
| 52 if ((self = [super initWithNibName:@"DownloadShelf" | 47 if ((self = [super initWithNibName:@"DownloadShelf" |
| 53 bundle:mac_util::MainAppBundle()])) { | 48 bundle:mac_util::MainAppBundle()])) { |
| 54 resizeDelegate_ = resizeDelegate; | 49 resizeDelegate_ = resizeDelegate; |
| 55 shelfHeight_ = [[self view] bounds].size.height; | 50 shelfHeight_ = [[self view] bounds].size.height; |
| 56 | 51 |
| 57 // Reset the download shelf's frame to zero. It will be properly positioned | 52 // Reset the download shelf's frame to zero. It will be properly positioned |
| 58 // and sized the first time we try to set its height. | 53 // and sized the first time we try to set its height. |
| 59 [[self view] setFrame:NSZeroRect]; | 54 [[self view] setFrame:NSZeroRect]; |
| 60 | 55 |
| 61 downloadItemControllers_.reset([[NSMutableArray alloc] init]); | 56 downloadItemControllers_.reset([[NSMutableArray alloc] init]); |
| 62 | 57 |
| 63 // This calls show:, so it needs to be last. | 58 // This calls show:, so it needs to be last. |
| 64 bridge_.reset(new DownloadShelfMac(browser, self)); | 59 bridge_.reset(new DownloadShelfMac(browser, self)); |
| 65 } | 60 } |
| 66 return self; | 61 return self; |
| 67 } | 62 } |
| 68 | 63 |
| 69 - (void)awakeFromNib { | 64 - (void)awakeFromNib { |
| 70 // Initialize "Show all downloads" link. | 65 // Initialize "Show all downloads" link. |
| 71 | 66 |
| 72 scoped_nsobject<NSMutableParagraphStyle> paragraphStyle( | 67 scoped_nsobject<NSMutableParagraphStyle> paragraphStyle( |
| 73 [[NSParagraphStyle defaultParagraphStyle] mutableCopy]); | 68 [[NSParagraphStyle defaultParagraphStyle] mutableCopy]); |
| 74 // TODO(thakis): left-align for RTL languages? | |
| 75 [paragraphStyle.get() setAlignment:NSRightTextAlignment]; | 69 [paragraphStyle.get() setAlignment:NSRightTextAlignment]; |
| 76 | 70 |
| 77 NSDictionary* linkAttributes = [NSDictionary dictionaryWithObjectsAndKeys: | 71 NSDictionary* linkAttributes = [NSDictionary dictionaryWithObjectsAndKeys: |
| 78 @"", NSLinkAttributeName, | 72 @"", NSLinkAttributeName, |
| 79 [NSCursor pointingHandCursor], NSCursorAttributeName, | 73 [NSCursor pointingHandCursor], NSCursorAttributeName, |
| 80 paragraphStyle.get(), NSParagraphStyleAttributeName, | 74 paragraphStyle.get(), NSParagraphStyleAttributeName, |
| 81 nil]; | 75 nil]; |
| 82 NSString* text = | 76 NSString* text = |
| 83 base::SysWideToNSString(l10n_util::GetString(IDS_SHOW_ALL_DOWNLOADS)); | 77 base::SysWideToNSString(l10n_util::GetString(IDS_SHOW_ALL_DOWNLOADS)); |
| 84 scoped_nsobject<NSAttributedString> linkText([[NSAttributedString alloc] | 78 scoped_nsobject<NSAttributedString> linkText([[NSAttributedString alloc] |
| (...skipping 10 matching lines...) Expand all Loading... |
| 95 in downloadItemControllers_.get()) { | 89 in downloadItemControllers_.get()) { |
| 96 [[NSNotificationCenter defaultCenter] removeObserver:itemController]; | 90 [[NSNotificationCenter defaultCenter] removeObserver:itemController]; |
| 97 } | 91 } |
| 98 [super dealloc]; | 92 [super dealloc]; |
| 99 } | 93 } |
| 100 | 94 |
| 101 - (void)resizeDownloadLinkToFit { | 95 - (void)resizeDownloadLinkToFit { |
| 102 // Get width required by localized download link text. | 96 // Get width required by localized download link text. |
| 103 // http://developer.apple.com/documentation/Cocoa/Conceptual/TextLayout/Tasks/
StringHeight.html | 97 // http://developer.apple.com/documentation/Cocoa/Conceptual/TextLayout/Tasks/
StringHeight.html |
| 104 [[showAllDownloadsLink_ textContainer] setLineFragmentPadding:0.0]; | 98 [[showAllDownloadsLink_ textContainer] setLineFragmentPadding:0.0]; |
| 105 (void)[[showAllDownloadsLink_ layoutManager]glyphRangeForTextContainer: | 99 (void)[[showAllDownloadsLink_ layoutManager] glyphRangeForTextContainer: |
| 106 [showAllDownloadsLink_ textContainer]]; | 100 [showAllDownloadsLink_ textContainer]]; |
| 107 NSRect textRect = [[showAllDownloadsLink_ layoutManager] | 101 NSRect textRect = [[showAllDownloadsLink_ layoutManager] |
| 108 usedRectForTextContainer:[showAllDownloadsLink_ textContainer]]; | 102 usedRectForTextContainer:[showAllDownloadsLink_ textContainer]]; |
| 109 | 103 |
| 110 int offsetX = [showAllDownloadsLink_ frame].size.width - textRect.size.width; | 104 int offsetX = [showAllDownloadsLink_ frame].size.width - textRect.size.width; |
| 111 | 105 |
| 112 // Fit link itself. | 106 // Fit link itself. |
| 113 NSRect linkFrame = [linkContainer_ frame]; | 107 NSRect linkFrame = [linkContainer_ frame]; |
| 114 linkFrame.origin.x += offsetX; | 108 linkFrame.origin.x += offsetX; |
| 115 linkFrame.size.width -= offsetX; | 109 linkFrame.size.width -= offsetX; |
| (...skipping 22 matching lines...) Expand all Loading... |
| 138 | 132 |
| 139 - (void)remove:(DownloadItemController*)download { | 133 - (void)remove:(DownloadItemController*)download { |
| 140 // Look for the download in our controller array and remove it. This will | 134 // Look for the download in our controller array and remove it. This will |
| 141 // explicity release it so that it removes itself as an Observer of the | 135 // explicity release it so that it removes itself as an Observer of the |
| 142 // DownloadItem. We don't want to wait for autorelease since the DownloadItem | 136 // DownloadItem. We don't want to wait for autorelease since the DownloadItem |
| 143 // we are observing will likely be gone by then. | 137 // we are observing will likely be gone by then. |
| 144 [[NSNotificationCenter defaultCenter] removeObserver:download]; | 138 [[NSNotificationCenter defaultCenter] removeObserver:download]; |
| 145 [[download view] removeFromSuperview]; | 139 [[download view] removeFromSuperview]; |
| 146 [downloadItemControllers_ removeObject:download]; | 140 [downloadItemControllers_ removeObject:download]; |
| 147 | 141 |
| 148 // TODO(thakis): Need to relayout the remaining item views here ( | 142 [self layoutItems]; |
| 149 // crbug.com/17831 ). | |
| 150 | 143 |
| 151 // Check to see if we have any downloads remaining and if not, hide the shelf. | 144 // Check to see if we have any downloads remaining and if not, hide the shelf. |
| 152 if (![downloadItemControllers_ count]) | 145 if (![downloadItemControllers_ count]) |
| 153 [self showDownloadShelf:NO]; | 146 [self showDownloadShelf:NO]; |
| 154 } | 147 } |
| 155 | 148 |
| 156 // We need to explicitly release our download controllers here since they need | 149 // We need to explicitly release our download controllers here since they need |
| 157 // to remove themselves as observers before the remaining shutdown happens. | 150 // to remove themselves as observers before the remaining shutdown happens. |
| 158 - (void)exiting { | 151 - (void)exiting { |
| 159 downloadItemControllers_.reset(); | 152 downloadItemControllers_.reset(); |
| (...skipping 29 matching lines...) Expand all Loading... |
| 189 if (sender) | 182 if (sender) |
| 190 bridge_->Close(); | 183 bridge_->Close(); |
| 191 else | 184 else |
| 192 [self showDownloadShelf:NO]; | 185 [self showDownloadShelf:NO]; |
| 193 } | 186 } |
| 194 | 187 |
| 195 - (float)height { | 188 - (float)height { |
| 196 return shelfHeight_; | 189 return shelfHeight_; |
| 197 } | 190 } |
| 198 | 191 |
| 199 - (void)addDownloadItem:(BaseDownloadItemModel*)model { | 192 // If |skipFirst| is true, the frame of the leftmost item is not set. |
| 200 // TODO(thakis): RTL support? | 193 - (void)layoutItems:(BOOL)skipFirst { |
| 201 // (l10n_util::GetTextDirection() == l10n_util::RIGHT_TO_LEFT) | 194 CGFloat currentX = 0; |
| 202 // Shift all existing items to the right | |
| 203 for (DownloadItemController* itemController | 195 for (DownloadItemController* itemController |
| 204 in downloadItemControllers_.get()) { | 196 in downloadItemControllers_.get()) { |
| 205 NSRect frame = [[itemController view] frame]; | 197 NSRect frame = [[itemController view] frame]; |
| 206 frame.origin.x += kDownloadItemWidth + kDownloadItemPadding; | 198 frame.origin.x = currentX; |
| 207 [[[itemController view] animator] setFrame:frame]; | 199 frame.size.width = [itemController preferredSize].width; |
| 200 if (!skipFirst) |
| 201 [[[itemController view] animator] setFrame:frame]; |
| 202 currentX += frame.size.width + kDownloadItemPadding; |
| 203 skipFirst = NO; |
| 208 } | 204 } |
| 205 } |
| 209 | 206 |
| 207 - (void)layoutItems { |
| 208 [self layoutItems:NO]; |
| 209 } |
| 210 |
| 211 - (void)addDownloadItem:(BaseDownloadItemModel*)model { |
| 210 // Insert new item at the left. | 212 // Insert new item at the left. |
| 211 // Start at width 0... | |
| 212 NSRect position = NSMakeRect(0, kDownloadItemBorderPadding, | |
| 213 0, kDownloadItemHeight); | |
| 214 scoped_nsobject<DownloadItemController> controller( | 213 scoped_nsobject<DownloadItemController> controller( |
| 215 [[DownloadItemController alloc] initWithFrame:position | 214 [[DownloadItemController alloc] initWithModel:model shelf:self]); |
| 216 model:model | 215 |
| 217 shelf:self]); | 216 // Adding at index 0 in NSMutableArrays is O(1). |
| 218 [downloadItemControllers_ addObject:controller.get()]; | 217 [downloadItemControllers_ insertObject:controller.get() atIndex:0]; |
| 219 | 218 |
| 220 [itemContainerView_ addSubview:[controller.get() view]]; | 219 [itemContainerView_ addSubview:[controller.get() view]]; |
| 221 | 220 |
| 222 [[NSNotificationCenter defaultCenter] | 221 [[NSNotificationCenter defaultCenter] |
| 223 addObserver:controller | 222 addObserver:controller |
| 224 selector:@selector(updateVisibility:) | 223 selector:@selector(updateVisibility:) |
| 225 name:NSViewFrameDidChangeNotification | 224 name:NSViewFrameDidChangeNotification |
| 226 object:[controller view]]; | 225 object:[controller view]]; |
| 227 [[NSNotificationCenter defaultCenter] | 226 [[NSNotificationCenter defaultCenter] |
| 228 addObserver:controller | 227 addObserver:controller |
| 229 selector:@selector(updateVisibility:) | 228 selector:@selector(updateVisibility:) |
| 230 name:NSViewFrameDidChangeNotification | 229 name:NSViewFrameDidChangeNotification |
| 231 object:itemContainerView_]; | 230 object:itemContainerView_]; |
| 232 | 231 |
| 232 // Start at width 0... |
| 233 NSSize size = [controller.get() preferredSize]; |
| 234 NSRect frame = NSMakeRect(0, kDownloadItemBorderPadding, 0, size.height); |
| 235 [[controller.get() view] setFrame:frame]; |
| 236 |
| 233 // ...then animate in | 237 // ...then animate in |
| 234 NSRect frame = [[controller.get() view] frame]; | 238 frame.size.width = size.width; |
| 235 frame.size.width = kDownloadItemWidth; | |
| 236 | |
| 237 [NSAnimationContext beginGrouping]; | 239 [NSAnimationContext beginGrouping]; |
| 238 [[NSAnimationContext currentContext] setDuration:kDownloadItemOpenDuration]; | 240 [[NSAnimationContext currentContext] setDuration:kDownloadItemOpenDuration]; |
| 239 [[[controller.get() view] animator] setFrame:frame]; | 241 [[[controller.get() view] animator] setFrame:frame]; |
| 240 [NSAnimationContext endGrouping]; | 242 [NSAnimationContext endGrouping]; |
| 241 | 243 |
| 242 // Keep only a limited number of items in the shelf. | 244 // Keep only a limited number of items in the shelf. |
| 243 if ([downloadItemControllers_ count] > kMaxDownloadItemCount) { | 245 if ([downloadItemControllers_ count] > kMaxDownloadItemCount) { |
| 244 DCHECK(kMaxDownloadItemCount > 0); | 246 DCHECK(kMaxDownloadItemCount > 0); |
| 245 | 247 |
| 246 // Since no user will ever see the item being removed (needs a horizontal | 248 // Since no user will ever see the item being removed (needs a horizontal |
| 247 // screen resolution greater than 3200 at 16 items at 200 pixels each), | 249 // screen resolution greater than 3200 at 16 items at 200 pixels each), |
| 248 // there's no point in animating the removal. | 250 // there's no point in animating the removal. |
| 249 [self remove:[downloadItemControllers_ objectAtIndex:0]]; | 251 [self remove:[downloadItemControllers_ lastObject]]; |
| 250 } | 252 } |
| 253 |
| 254 // Finally, move the remaining items to the right. Skip the first item when |
| 255 // laying out the items, so that the longer animation duration we set up above |
| 256 // is not overwritten. |
| 257 [self layoutItems:YES]; |
| 251 } | 258 } |
| 252 | 259 |
| 253 @end | 260 @end |
| OLD | NEW |