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 |