From f97021d319fa120d0bd0a071f2b3f98b3680df68 Mon Sep 17 00:00:00 2001 From: steedos Date: Fri, 11 Apr 2014 23:46:50 +0800 Subject: [PATCH] Add download support for MacGap Shows downloads progress in Finder and the Downloads stack --- MacGap.xcodeproj/project.pbxproj | 18 +++++-- MacGap/Classes/ContentView.h | 3 ++ MacGap/Classes/ContentView.m | 6 ++- MacGap/Classes/DownloadDelegate.h | 17 +++++++ MacGap/Classes/DownloadDelegate.m | 83 +++++++++++++++++++++++++++++++ MacGap/Classes/DownloadInfo.h | 19 +++++++ MacGap/Classes/DownloadInfo.m | 24 +++++++++ MacGap/Classes/WebViewDelegate.m | 23 ++++++++- 8 files changed, 187 insertions(+), 6 deletions(-) create mode 100755 MacGap/Classes/DownloadDelegate.h create mode 100755 MacGap/Classes/DownloadDelegate.m create mode 100755 MacGap/Classes/DownloadInfo.h create mode 100755 MacGap/Classes/DownloadInfo.m diff --git a/MacGap.xcodeproj/project.pbxproj b/MacGap.xcodeproj/project.pbxproj index 5beb851..c8b2b5e 100644 --- a/MacGap.xcodeproj/project.pbxproj +++ b/MacGap.xcodeproj/project.pbxproj @@ -8,12 +8,14 @@ /* Begin PBXBuildFile section */ 1495814F15C15CCC00E1CFE5 /* Notice.m in Sources */ = {isa = PBXBuildFile; fileRef = 1495814E15C15CCC00E1CFE5 /* Notice.m */; }; - 6FD6E4ED18C2D48C00DFFBE6 /* fonts.m in Sources */ = {isa = PBXBuildFile; fileRef = 6FD6E4EC18C2D48C00DFFBE6 /* fonts.m */; }; + 24E5CE5718F83217006CC84A /* DownloadDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 24E5CE5618F83217006CC84A /* DownloadDelegate.m */; }; + 24E5CE5A18F8417A006CC84A /* DownloadInfo.m in Sources */ = {isa = PBXBuildFile; fileRef = 24E5CE5918F8417A006CC84A /* DownloadInfo.m */; }; 6F169DA718CC332E005EDDF3 /* Command.m in Sources */ = {isa = PBXBuildFile; fileRef = 6F169DA618CC332E005EDDF3 /* Command.m */; }; 6F169DAA18CC35FD005EDDF3 /* CallbackDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 6F169DA918CC35FD005EDDF3 /* CallbackDelegate.m */; }; 6F169DAC18CD8A4A005EDDF3 /* JavaScriptCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6F169DAB18CD8A4A005EDDF3 /* JavaScriptCore.framework */; }; 6F169DB118CD906F005EDDF3 /* MenuItemProxy.m in Sources */ = {isa = PBXBuildFile; fileRef = 6F169DAE18CD906F005EDDF3 /* MenuItemProxy.m */; }; 6F169DB218CD906F005EDDF3 /* MenuProxy.m in Sources */ = {isa = PBXBuildFile; fileRef = 6F169DB018CD906F005EDDF3 /* MenuProxy.m */; }; + 6FD6E4ED18C2D48C00DFFBE6 /* fonts.m in Sources */ = {isa = PBXBuildFile; fileRef = 6FD6E4EC18C2D48C00DFFBE6 /* fonts.m */; }; 88746BEE14CCA435001E160E /* JSEventHelper.m in Sources */ = {isa = PBXBuildFile; fileRef = 88746BED14CCA435001E160E /* JSEventHelper.m */; }; 88C0646014BDE10A00E4BCE2 /* Window.m in Sources */ = {isa = PBXBuildFile; fileRef = 88C0645F14BDE10A00E4BCE2 /* Window.m */; }; 88C0646614BDEC5800E4BCE2 /* Window.xib in Resources */ = {isa = PBXBuildFile; fileRef = 88C0646414BDEC5800E4BCE2 /* Window.xib */; }; @@ -56,8 +58,10 @@ /* Begin PBXFileReference section */ 1495814D15C15CCC00E1CFE5 /* Notice.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Notice.h; path = Classes/Commands/Notice.h; sourceTree = ""; }; 1495814E15C15CCC00E1CFE5 /* Notice.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = Notice.m; path = Classes/Commands/Notice.m; sourceTree = ""; }; - 6FD6E4EB18C2D48200DFFBE6 /* fonts.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = fonts.h; path = Classes/Commands/fonts.h; sourceTree = ""; }; - 6FD6E4EC18C2D48C00DFFBE6 /* fonts.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = fonts.m; path = Classes/Commands/fonts.m; sourceTree = ""; }; + 24E5CE5518F83217006CC84A /* DownloadDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DownloadDelegate.h; path = Classes/DownloadDelegate.h; sourceTree = ""; }; + 24E5CE5618F83217006CC84A /* DownloadDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = DownloadDelegate.m; path = Classes/DownloadDelegate.m; sourceTree = ""; }; + 24E5CE5818F8417A006CC84A /* DownloadInfo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DownloadInfo.h; path = Classes/DownloadInfo.h; sourceTree = ""; }; + 24E5CE5918F8417A006CC84A /* DownloadInfo.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = DownloadInfo.m; path = Classes/DownloadInfo.m; sourceTree = ""; }; 6F169DA518CC332E005EDDF3 /* Command.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Command.h; path = Classes/Commands/Command.h; sourceTree = ""; }; 6F169DA618CC332E005EDDF3 /* Command.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = Command.m; path = Classes/Commands/Command.m; sourceTree = ""; }; 6F169DA818CC35FD005EDDF3 /* CallbackDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CallbackDelegate.h; path = Classes/CallbackDelegate.h; sourceTree = ""; }; @@ -67,6 +71,8 @@ 6F169DAE18CD906F005EDDF3 /* MenuItemProxy.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = MenuItemProxy.m; path = Classes/Commands/MenuItemProxy.m; sourceTree = ""; }; 6F169DAF18CD906F005EDDF3 /* MenuProxy.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = MenuProxy.h; path = Classes/Commands/MenuProxy.h; sourceTree = ""; }; 6F169DB018CD906F005EDDF3 /* MenuProxy.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = MenuProxy.m; path = Classes/Commands/MenuProxy.m; sourceTree = ""; }; + 6FD6E4EB18C2D48200DFFBE6 /* fonts.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = fonts.h; path = Classes/Commands/fonts.h; sourceTree = ""; }; + 6FD6E4EC18C2D48C00DFFBE6 /* fonts.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = fonts.m; path = Classes/Commands/fonts.m; sourceTree = ""; }; 88746BEC14CCA435001E160E /* JSEventHelper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = JSEventHelper.h; path = Classes/JSEventHelper.h; sourceTree = ""; }; 88746BED14CCA435001E160E /* JSEventHelper.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = JSEventHelper.m; path = Classes/JSEventHelper.m; sourceTree = ""; }; 88C0645E14BDE10A00E4BCE2 /* Window.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Window.h; path = Classes/Window.h; sourceTree = ""; }; @@ -132,6 +138,10 @@ FA3250E014BA87B800BF0781 /* Classes */ = { isa = PBXGroup; children = ( + 24E5CE5818F8417A006CC84A /* DownloadInfo.h */, + 24E5CE5918F8417A006CC84A /* DownloadInfo.m */, + 24E5CE5518F83217006CC84A /* DownloadDelegate.h */, + 24E5CE5618F83217006CC84A /* DownloadDelegate.m */, FA3250E114BA87DD00BF0781 /* Commands */, FA3250BA14BA85E700BF0781 /* Constants.h */, 6F169DA818CC35FD005EDDF3 /* CallbackDelegate.h */, @@ -320,9 +330,11 @@ 6F169DAA18CC35FD005EDDF3 /* CallbackDelegate.m in Sources */, FA3250D314BA860800BF0781 /* App.m in Sources */, FA3250D514BA860800BF0781 /* Dock.m in Sources */, + 24E5CE5718F83217006CC84A /* DownloadDelegate.m in Sources */, FA3250D714BA860800BF0781 /* Growl.m in Sources */, FA3250D914BA860800BF0781 /* Path.m in Sources */, FA3250DB14BA860800BF0781 /* Sound.m in Sources */, + 24E5CE5A18F8417A006CC84A /* DownloadInfo.m in Sources */, FA3250C314BA85E700BF0781 /* ContentView.m in Sources */, FA3250C514BA85E700BF0781 /* Utils.m in Sources */, FA3250C714BA85E700BF0781 /* WebViewDelegate.m in Sources */, diff --git a/MacGap/Classes/ContentView.h b/MacGap/Classes/ContentView.h index 65890a5..00bb809 100644 --- a/MacGap/Classes/ContentView.h +++ b/MacGap/Classes/ContentView.h @@ -1,15 +1,18 @@ #import #import +#import "DownloadDelegate.h" @class WebViewDelegate; @interface ContentView : NSView { IBOutlet WebView* webView; WebViewDelegate* delegate; + DownloadDelegate* downloadDelegate; } @property (retain) WebView* webView; @property (retain) WebViewDelegate* delegate; +@property (retain) DownloadDelegate* downloadDelegate; @property (strong) IBOutlet NSMenu *mainMenu; @end diff --git a/MacGap/Classes/ContentView.m b/MacGap/Classes/ContentView.m index 24e58cd..8256e84 100644 --- a/MacGap/Classes/ContentView.m +++ b/MacGap/Classes/ContentView.m @@ -2,6 +2,7 @@ #import "WebViewDelegate.h" #import "AppDelegate.h" #import "JSEventHelper.h" +#import "DownloadDelegate.h" @interface WebPreferences (WebPreferencesPrivate) - (void)_setLocalStorageDatabasePath:(NSString *)path; @@ -14,7 +15,7 @@ - (void) setOfflineWebApplicationCacheEnabled:(BOOL)offlineWebApplicationCacheEn @implementation ContentView -@synthesize webView, delegate, mainMenu; +@synthesize webView, delegate, downloadDelegate, mainMenu; - (void) awakeFromNib { @@ -39,10 +40,11 @@ - (void) awakeFromNib [self.webView setApplicationNameForUserAgent: @"MacGap"]; self.delegate = [[WebViewDelegate alloc] initWithMenu:[NSApp mainMenu]]; + self.downloadDelegate = [[DownloadDelegate alloc] init]; [self.webView setFrameLoadDelegate:self.delegate]; [self.webView setUIDelegate:self.delegate]; [self.webView setResourceLoadDelegate:self.delegate]; - [self.webView setDownloadDelegate:self.delegate]; + [self.webView setDownloadDelegate:self.downloadDelegate]; [self.webView setPolicyDelegate:self.delegate]; [self.webView setDrawsBackground:NO]; [self.webView setShouldCloseWithWindow:NO]; diff --git a/MacGap/Classes/DownloadDelegate.h b/MacGap/Classes/DownloadDelegate.h new file mode 100755 index 0000000..f87df83 --- /dev/null +++ b/MacGap/Classes/DownloadDelegate.h @@ -0,0 +1,17 @@ +// +// DownloadDelegate.h +// MacGap +// +// Created by Jack Zhuang on 4/11/2014. +// Copyright (c) 2014 SteedOS Inc. All rights reserved. +// + +#import + +@interface DownloadDelegate : NSObject { + NSString *suggestedFilename; + + NSSavePanel *panel; +} + +@end diff --git a/MacGap/Classes/DownloadDelegate.m b/MacGap/Classes/DownloadDelegate.m new file mode 100755 index 0000000..35d05ea --- /dev/null +++ b/MacGap/Classes/DownloadDelegate.m @@ -0,0 +1,83 @@ +// +// DownloadDelegate.m +// MacGap +// +// Created by Jack Zhuang on 4/11/2014. +// Copyright (c) 2014 SteedOS Inc. All rights reserved. +// + +#import "DownloadDelegate.h" +#import "DownloadInfo.h" + + +@implementation DownloadDelegate { + NSMapTable *downloads; +} + +- (id)init +{ + self = [super init]; + if (self && NSClassFromString(@"NSProgress")) { + downloads = [NSMapTable weakToStrongObjectsMapTable]; + } + return self; +} + + +- (void)download:(NSURLDownload *)download decideDestinationWithSuggestedFilename:(NSString *)filename +{ + NSString *downloadDir = [NSSearchPathForDirectoriesInDomains(NSDownloadsDirectory, NSUserDomainMask, YES) objectAtIndex:0]; + NSString *destinationFilename = [downloadDir stringByAppendingPathComponent:filename]; + [download setDestination:destinationFilename allowOverwrite:NO]; +} + +-(void)download:(NSURLDownload *)download didCreateDestination:(NSString *)path +{ + if (downloads) { + NSURL *downloadUrl = [NSURL fileURLWithPath:path]; + DownloadInfo *info = [downloads objectForKey:download]; + [info setFilename:path]; + + NSDictionary *userInfo = [NSDictionary dictionaryWithObjectsAndKeys: + NSProgressFileOperationKindDownloading, + NSProgressFileOperationKindKey, + nil]; + NSProgress *progress = [NSProgress progressWithTotalUnitCount:0]; + progress = [progress initWithParent:nil userInfo:userInfo]; + [progress setKind:NSProgressKindFile]; + [progress setUserInfoObject:downloadUrl forKey:NSProgressFileURLKey]; + [progress publish]; + [info setProgress:progress]; + } +} + +- (void)download:(NSURLDownload *)download didReceiveResponse:(NSURLResponse *)response +{ + if (downloads) { + DownloadInfo *info = [[DownloadInfo alloc] init]; + [info setResponse:response]; + [downloads setObject:info forKey:download]; + } +} + +- (void)download:(NSURLDownload *)download didReceiveDataOfLength:(unsigned)length { + if (downloads) { + DownloadInfo *info = [downloads objectForKey:download]; + long long expectedLength = [[info response] expectedContentLength]; + int64_t completed = [[info progress] completedUnitCount]; + [[info progress] setCompletedUnitCount:(completed + length)]; + if (expectedLength != NSURLResponseUnknownLength) [[info progress] setTotalUnitCount:expectedLength]; + } +} + +- (void)downloadDidFinish:(NSURLDownload *)download { + if (downloads) { + DownloadInfo *info = [downloads objectForKey:download]; + [[info progress] unpublish]; + [[NSDistributedNotificationCenter defaultCenter] postNotificationName:@"com.apple.DownloadFileFinished" object:[info filename]]; + [downloads removeObjectForKey:download]; + } +} + + +@end diff --git a/MacGap/Classes/DownloadInfo.h b/MacGap/Classes/DownloadInfo.h new file mode 100755 index 0000000..98bcf2a --- /dev/null +++ b/MacGap/Classes/DownloadInfo.h @@ -0,0 +1,19 @@ +// +// A wrapper class for storing all the information relevant to a particular download. +// +// Created by Jack Zhuang on 4/11/2014. +// Copyright (c) 2014 SteedOS Inc. All rights reserved. +// + + +#import + +@interface DownloadInfo : NSObject + +@property NSProgress *progress; +@property NSURLResponse *response; +@property NSString *filename; + +- (id)copyWithZone:(NSZone *)zone; + +@end diff --git a/MacGap/Classes/DownloadInfo.m b/MacGap/Classes/DownloadInfo.m new file mode 100755 index 0000000..c82d19e --- /dev/null +++ b/MacGap/Classes/DownloadInfo.m @@ -0,0 +1,24 @@ +// +// Created by Jack Zhuang on 4/11/2014. +// Copyright (c) 2014 SteedOS Inc. All rights reserved. +// + + +#import "DownloadInfo.h" + +@implementation DownloadInfo + +- (id)copyWithZone:(NSZone *)zone +{ + DownloadInfo *copy = [[[self class] alloc] init]; + + if (copy) { + copy.progress = self.progress; + copy.response = self.response; + copy.filename = self.filename; + } + + return copy; +} + +@end diff --git a/MacGap/Classes/WebViewDelegate.m b/MacGap/Classes/WebViewDelegate.m index 9a629a0..dc88357 100644 --- a/MacGap/Classes/WebViewDelegate.m +++ b/MacGap/Classes/WebViewDelegate.m @@ -149,7 +149,7 @@ - (NSArray *)webView:(WebView *)sender contextMenuItemsForElement:(NSDictionary switch (tag) { case WebMenuItemTagOpenLinkInNewWindow: - case WebMenuItemTagDownloadLinkToDisk: + //case WebMenuItemTagDownloadLinkToDisk: case WebMenuItemTagCopyLinkToClipboard: case WebMenuItemTagOpenImageInNewWindow: case WebMenuItemTagDownloadImageToDisk: @@ -196,4 +196,25 @@ + (BOOL) isKeyExcludedFromWebScript:(const char*)name } +/* + * Download everything except HTML pages. + */ +- (void)webView:(WebView *)webView decidePolicyForMIMEType:(NSString *)type + request:(NSURLRequest *)request + frame:(WebFrame *)frame +decisionListener:(id < WebPolicyDecisionListener >)listener +{ + NSLog (@"%@", type); + if([type isEqualToString:@"text/html"]) + { + + [listener use]; + } + else{ + [listener download]; + }; +} + + + @end