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

Side by Side Diff: chrome/browser/download/download_status_updater_mac.mm

Issue 10827207: Mountain Lion: use the system download progress. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: fixed up and ready to go Created 8 years, 4 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
(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 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698