Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 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 | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 #include "chrome/browser/download/download_status_updater.h" | |
| 6 | |
| 7 #include "base/memory/scoped_nsobject.h" | |
| 8 #include "base/supports_user_data.h" | |
| 9 #include "base/sys_string_conversions.h" | |
| 10 #include "content/public/browser/download_item.h" | |
| 11 #include "googleurl/src/gurl.h" | |
| 12 | |
| 13 // --- Private 10.8 API for showing progress --- | |
|
Nico
2012/08/08 20:00:59
Can you file a rdar about turning this into public
Avi (use Gerrit)
2012/08/08 21:16:20
Done.
| |
| 14 | |
| 15 namespace { | |
| 16 | |
| 17 NSString* kNSProgressAppBundleIdentifierKey = | |
|
Nico
2012/08/08 20:00:59
NSString* const
Avi (use Gerrit)
2012/08/08 21:16:20
Done.
| |
| 18 @"NSProgressAppBundleIdentifierKey"; | |
| 19 NSString* kNSProgressEstimatedTimeKey = | |
| 20 @"NSProgressEstimatedTimeKey"; | |
| 21 NSString* kNSProgressFileCompletedCountKey = | |
| 22 @"NSProgressFileCompletedCountKey"; | |
| 23 NSString* kNSProgressFileContainerURLKey = | |
| 24 @"NSProgressFileContainerURLKey"; | |
| 25 NSString* kNSProgressFileDownloadingSourceURLKey = | |
| 26 @"NSProgressFileDownloadingSourceURLKey"; | |
| 27 NSString* kNSProgressFileIconKey = | |
| 28 @"NSProgressFileIconKey"; | |
| 29 NSString* kNSProgressFileIconOriginalRectKey = | |
| 30 @"NSProgressFileIconOriginalRectKey"; | |
| 31 NSString* kNSProgressFileLocationCanChangeKey = | |
| 32 @"NSProgressFileLocationCanChangeKey"; | |
| 33 NSString* kNSProgressFileOperationKindAirDropping = | |
| 34 @"NSProgressFileOperationKindAirDropping"; | |
| 35 NSString* kNSProgressFileOperationKindCopying = | |
| 36 @"NSProgressFileOperationKindCopying"; | |
| 37 NSString* kNSProgressFileOperationKindDecompressingAfterDownloading = | |
| 38 @"NSProgressFileOperationKindDecompressingAfterDownloading"; | |
| 39 NSString* kNSProgressFileOperationKindDownloading = | |
| 40 @"NSProgressFileOperationKindDownloading"; | |
| 41 NSString* kNSProgressFileOperationKindEncrypting = | |
| 42 @"NSProgressFileOperationKindEncrypting"; | |
| 43 NSString* kNSProgressFileOperationKindKey = | |
| 44 @"NSProgressFileOperationKindKey"; | |
| 45 NSString* kNSProgressFileTotalCountKey = | |
| 46 @"NSProgressFileTotalCountKey"; | |
| 47 NSString* kNSProgressFileURLKey = | |
| 48 @"NSProgressFileURLKey"; | |
| 49 NSString* kNSProgressIsWaitingKey = | |
| 50 @"NSProgressIsWaitingKey"; | |
| 51 NSString* kNSProgressKindFile = | |
| 52 @"NSProgressKindFile"; | |
| 53 NSString* kNSProgressThroughputKey = | |
| 54 @"NSProgressThroughputKey"; | |
| 55 | |
| 56 NSString* ProgressString(NSString* string) { | |
| 57 static NSMutableDictionary* cache; | |
| 58 if (!cache) | |
| 59 cache = [[NSMutableDictionary alloc] init]; | |
| 60 if (![cache objectForKey:string]) { | |
| 61 CFBundleRef foundation = CFBundleGetBundleWithIdentifier( | |
| 62 CFSTR("com.apple.Foundation")); | |
| 63 NSString** ref = static_cast<NSString**>( | |
| 64 CFBundleGetDataPointerForName(foundation, (CFStringRef)string)); | |
|
Nico
2012/08/08 20:00:59
we have a type-safe casting function somewhere in
Avi (use Gerrit)
2012/08/08 21:16:20
Done.
| |
| 65 if (ref) | |
| 66 [cache setObject:*ref | |
|
Nico
2012/08/08 20:00:59
1 line (or braces)
Avi (use Gerrit)
2012/08/08 21:16:20
Done.
| |
| 67 forKey:string]; | |
| 68 } | |
| 69 | |
| 70 return [cache objectForKey:string]; | |
|
Nico
2012/08/08 20:00:59
You can avoid the two cache lookups by writing it
Avi (use Gerrit)
2012/08/08 21:16:20
Done.
| |
| 71 } | |
| 72 | |
| 73 } // namespace | |
| 74 | |
| 75 @interface NSProgress : NSObject | |
| 76 | |
| 77 - (id)initWithParent:(id)parent userInfo:(NSDictionary*)info; | |
| 78 @property(copy) NSString *kind; | |
|
Nico
2012/08/08 20:00:59
space after *
Avi (use Gerrit)
2012/08/08 21:16:20
Done.
| |
| 79 | |
| 80 - (void)unpublish; | |
| 81 - (void)publish; | |
| 82 | |
| 83 - (void)setUserInfoObject:(id)object forKey:(NSString*)key; | |
| 84 - (NSDictionary*)userInfo; | |
| 85 | |
| 86 @property(readonly) double fractionCompleted; | |
| 87 // Set the totalUnitCount to -1 to indicate an indeterminate download. The dock | |
| 88 // shows a non-filling progress bar; the Finder is lame and draws its progress | |
| 89 // bar off the right side. | |
| 90 @property(readonly, getter=isIndeterminate) BOOL indeterminate; | |
| 91 @property long long completedUnitCount; | |
| 92 @property long long totalUnitCount; | |
| 93 | |
| 94 // Pausing appears to be unimplemented in 10.8.0. | |
| 95 - (void)pause; | |
| 96 @property(readonly, getter=isPaused) BOOL paused; | |
| 97 @property(getter=isPausable) BOOL pausable; | |
| 98 - (void)setPausingHandler:(id)blockOfUnknownSignature; | |
| 99 | |
| 100 - (void)cancel; | |
| 101 @property(readonly, getter=isCancelled) BOOL cancelled; | |
| 102 @property(getter=isCancellable) BOOL cancellable; | |
| 103 // Note that the cancellation handler block will be called on a random thread. | |
| 104 - (void)setCancellationHandler:(void (^)())block; | |
| 105 | |
| 106 // Allows other applications to provide feedback as to whether the progress is | |
| 107 // visible in that app. Note that the acknowledgement handler block will be | |
| 108 // called on a random thread. | |
| 109 // com.apple.dock => BOOL indicating whether the download target folder was | |
| 110 // successfully "flown to" at the beginning of the download. | |
| 111 // This primarily depends on whether the download target | |
| 112 // folder is in the dock. Note that if the download target | |
| 113 // folder is added or removed from the dock during the | |
| 114 // duration of the download, it will not trigger a callback. | |
| 115 // Note that if the "fly to the dock" keys were not set, the | |
| 116 // callback's parameter will always be NO. | |
| 117 // com.apple.Finder => always YES, no matter whether the download target | |
| 118 // folder's window is open. | |
| 119 - (void)handleAcknowledgementByAppWithBundleIdentifier:(NSString*)bundle | |
| 120 usingBlock:(void (^)(BOOL success))b lock; | |
|
Avi (use Gerrit)
2012/08/08 19:34:28
Yes, this is > 80. I can't think how to format it
Nico
2012/08/08 20:00:59
Just indent this line by 4 spaces instead. We do t
Avi (use Gerrit)
2012/08/08 21:16:20
Done.
| |
| 121 | |
| 122 @end | |
| 123 | |
| 124 // --- Private 10.8 API for showing progress --- | |
| 125 | |
| 126 namespace { | |
| 127 | |
| 128 bool NSProgressSupported() { | |
| 129 static bool supported; | |
| 130 static bool valid; | |
| 131 if (!valid) { | |
| 132 supported = NSClassFromString(@"NSProgress"); | |
| 133 valid = true; | |
| 134 } | |
| 135 | |
| 136 return supported; | |
| 137 } | |
| 138 | |
| 139 } // namespace | |
| 140 | |
| 141 const char kNSProgressUserDataKey[] = "NSProgressUserData"; | |
| 142 | |
| 143 class NSProgressUserData : public base::SupportsUserData::Data { | |
|
Nico
2012/08/08 20:00:59
CrNSProgessUserData?
Avi (use Gerrit)
2012/08/08 21:16:20
Moved to anon namespace.
Nico
2012/08/08 21:21:38
I'd still call it CrNSProgressUserData, I consider
Avi (use Gerrit)
2012/08/08 21:22:46
Even for C++ classes?
Nico
2012/08/08 21:27:23
Even for poetry.
| |
| 144 public: | |
| 145 NSProgressUserData(NSProgress* progress, const FilePath& target) | |
| 146 : target_(target) { | |
| 147 progress_.reset(progress); | |
| 148 } | |
| 149 virtual ~NSProgressUserData() {} | |
| 150 | |
| 151 NSProgress* progress() const { return progress_.get(); } | |
| 152 FilePath target() const { return target_; } | |
| 153 void setTarget(const FilePath& target) { target_ = target; } | |
| 154 | |
| 155 private: | |
| 156 scoped_nsobject<NSProgress> progress_; | |
| 157 FilePath target_; | |
| 158 }; | |
| 159 | |
| 160 void DownloadStatusUpdater::UpdateDownloadProgressForItemAdded( | |
| 161 content::DownloadItem* download) { | |
| 162 if (!NSProgressSupported()) | |
| 163 return; | |
| 164 | |
| 165 NSURL* source_url = [NSURL URLWithString: | |
| 166 base::SysUTF8ToNSString(download->GetURL().spec())]; | |
|
Nico
2012/08/08 20:00:59
Huh, amazing that we don't have something nicer fo
| |
| 167 FilePath destination_path = download->GetFullPath(); | |
| 168 NSURL* destination_url = [NSURL fileURLWithPath: | |
| 169 [NSString stringWithUTF8String:destination_path.value().c_str()]]; | |
|
Nico
2012/08/08 20:00:59
This gets a tiny bit shorter with base::mac::FileP
Avi (use Gerrit)
2012/08/08 21:16:20
Ooh!
| |
| 170 | |
| 171 // If there were an image to fly to the download folder in the dock, then | |
| 172 // the keys in the userInfo to set would be: | |
| 173 // - @"NSProgressFlyToImageKey" : NSImage | |
| 174 // - kNSProgressFileIconOriginalRectKey : NSValue of NSRect in global coords | |
| 175 | |
| 176 NSDictionary* user_info = @{ | |
| 177 ProgressString(kNSProgressFileDownloadingSourceURLKey) : source_url, | |
| 178 ProgressString(kNSProgressFileLocationCanChangeKey) : @true, | |
|
Avi (use Gerrit)
2012/08/08 19:34:28
@YES is broken for the SDK that we compile against
Nico
2012/08/08 20:00:59
@(YES) might work
(why "YES" though? Do you know
Avi (use Gerrit)
2012/08/08 21:16:20
Doesn't that determine at runtime what the type of
| |
| 179 ProgressString(kNSProgressFileOperationKindKey) : | |
| 180 ProgressString(kNSProgressFileOperationKindDownloading), | |
| 181 ProgressString(kNSProgressFileURLKey) : destination_url | |
| 182 }; | |
| 183 Class progress_class = NSClassFromString(@"NSProgress"); | |
| 184 NSProgress* progress = [progress_class performSelector:@selector(alloc)]; | |
| 185 progress = [progress performSelector:@selector(initWithParent:userInfo:) | |
| 186 withObject:nil | |
| 187 withObject:user_info]; | |
| 188 progress.kind = ProgressString(kNSProgressKindFile); | |
| 189 | |
| 190 progress.pausable = NO; | |
| 191 progress.cancellable = YES; | |
| 192 [progress setCancellationHandler:^{ | |
| 193 dispatch_async(dispatch_get_main_queue(), ^{ | |
| 194 download->Cancel(true); | |
|
Nico
2012/08/08 20:00:59
rdsmith: What are the guarantees for DownloadItem
Randy Smith (Not in Mondays)
2012/08/08 20:39:40
If you're an observer of the DownloadItem, you'll
Avi (use Gerrit)
2012/08/08 21:16:20
As you noted, the DSU code would need to be update
Randy Smith (Not in Mondays)
2012/08/08 21:27:42
A glitch in the DSU code update :-}. The DSU code
| |
| 195 }); | |
| 196 }]; | |
| 197 | |
| 198 progress.totalUnitCount = download->GetTotalBytes(); | |
| 199 progress.completedUnitCount = download->GetReceivedBytes(); | |
| 200 | |
| 201 [progress publish]; | |
| 202 | |
| 203 download->SetUserData(&kNSProgressUserDataKey, | |
| 204 new NSProgressUserData(progress, destination_path)); | |
| 205 } | |
| 206 | |
| 207 void DownloadStatusUpdater::UpdateDownloadProgressForItemProgressed( | |
| 208 content::DownloadItem* download) { | |
| 209 if (!NSProgressSupported()) | |
| 210 return; | |
| 211 | |
| 212 NSProgressUserData* progress_data = static_cast<NSProgressUserData*>( | |
| 213 download->GetUserData(&kNSProgressUserDataKey)); | |
| 214 if (!progress_data) | |
| 215 return; | |
| 216 | |
| 217 NSProgress* progress = progress_data->progress(); | |
| 218 progress.totalUnitCount = download->GetTotalBytes(); | |
| 219 progress.completedUnitCount = download->GetReceivedBytes(); | |
| 220 | |
| 221 FilePath download_path = download->GetFullPath(); | |
| 222 if (progress_data->target() != download_path) { | |
| 223 progress_data->setTarget(download_path); | |
| 224 NSURL* download_url = [NSURL fileURLWithPath: | |
| 225 [NSString stringWithUTF8String:download_path.value().c_str()]]; | |
|
Nico
2012/08/08 20:00:59
same as above
Avi (use Gerrit)
2012/08/08 21:16:20
Done.
| |
| 226 [progress setUserInfoObject:download_url | |
| 227 forKey:ProgressString(kNSProgressFileURLKey)]; | |
| 228 } | |
| 229 } | |
| 230 | |
| 231 void DownloadStatusUpdater::UpdateDownloadProgressForItemRemoved( | |
| 232 content::DownloadItem* download) { | |
| 233 if (!NSProgressSupported()) | |
| 234 return; | |
| 235 | |
| 236 NSProgressUserData* progress_data = static_cast<NSProgressUserData*>( | |
| 237 download->GetUserData(&kNSProgressUserDataKey)); | |
| 238 if (!progress_data) | |
| 239 return; | |
| 240 | |
| 241 NSProgress* progress = progress_data->progress(); | |
| 242 [progress unpublish]; | |
| 243 | |
| 244 download->RemoveUserData(&kNSProgressUserDataKey); | |
| 245 } | |
| OLD | NEW |