mirror of https://github.com/ksherlock/ample.git
improved download manager
a few rough edges left but it displays the list of ROMs and allows downloading individual items and viewing them in Finder.
This commit is contained in:
parent
26dbdae365
commit
ebdf8b9395
|
@ -12,6 +12,7 @@
|
|||
#import <Cocoa/Cocoa.h>
|
||||
|
||||
NSURL *SupportDirectory(void);
|
||||
NSString *SupportDirectoryPath(void);
|
||||
|
||||
/* NSUserDefaults keys */
|
||||
extern NSString *kUseCustomMame;
|
||||
|
|
|
@ -21,6 +21,17 @@ NSURL *SupportDirectory(void) {
|
|||
[fm createDirectoryAtURL: cached withIntermediateDirectories: YES attributes: nil error: &error];
|
||||
}
|
||||
return cached;
|
||||
|
||||
}
|
||||
|
||||
NSString *SupportDirectoryPath(void) {
|
||||
static NSString *cached = nil;
|
||||
|
||||
if (!cached) {
|
||||
NSURL *url = SupportDirectory();
|
||||
cached = [NSString stringWithCString: [url fileSystemRepresentation] encoding: NSUTF8StringEncoding];
|
||||
}
|
||||
return cached;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
<objects>
|
||||
<customObject id="-2" userLabel="File's Owner" customClass="DownloadWindowController">
|
||||
<connections>
|
||||
<outlet property="tableView" destination="FLX-Wt-y53" id="a4O-pk-EAt"/>
|
||||
<outlet property="window" destination="F0z-JX-Cv5" id="gIp-Ho-8D9"/>
|
||||
</connections>
|
||||
</customObject>
|
||||
|
@ -16,10 +17,10 @@
|
|||
<window title="Downloads" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" releasedWhenClosed="NO" animationBehavior="default" id="F0z-JX-Cv5">
|
||||
<windowStyleMask key="styleMask" titled="YES" closable="YES" miniaturizable="YES" resizable="YES"/>
|
||||
<windowPositionMask key="initialPositionMask" leftStrut="YES" rightStrut="YES" topStrut="YES" bottomStrut="YES"/>
|
||||
<rect key="contentRect" x="196" y="240" width="480" height="157"/>
|
||||
<rect key="contentRect" x="196" y="240" width="480" height="458"/>
|
||||
<rect key="screenRect" x="0.0" y="0.0" width="2560" height="1417"/>
|
||||
<view key="contentView" id="se5-gp-TjO">
|
||||
<rect key="frame" x="0.0" y="0.0" width="480" height="157"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="480" height="458"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<subviews>
|
||||
<button verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="rg5-Qf-4Mw">
|
||||
|
@ -32,11 +33,11 @@
|
|||
<modifierMask key="keyEquivalentModifierMask" command="YES"/>
|
||||
</buttonCell>
|
||||
<connections>
|
||||
<action selector="cancel:" target="-2" id="gJ0-aE-RVh"/>
|
||||
<action selector="cancelAll:" target="-2" id="ycl-eJ-ByB"/>
|
||||
</connections>
|
||||
</button>
|
||||
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="MWc-ih-Sp1">
|
||||
<rect key="frame" x="18" y="121" width="442" height="16"/>
|
||||
<rect key="frame" x="20" y="105" width="442" height="16"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES"/>
|
||||
<textFieldCell key="cell" lineBreakMode="clipping" title="Downloading" id="dZt-4d-PYZ">
|
||||
<font key="font" metaFont="system"/>
|
||||
|
@ -51,8 +52,108 @@
|
|||
</binding>
|
||||
</connections>
|
||||
</textField>
|
||||
<scrollView fixedFrame="YES" autohidesScrollers="YES" horizontalLineScroll="19" horizontalPageScroll="10" verticalLineScroll="19" verticalPageScroll="10" usesPredominantAxisScrolling="NO" translatesAutoresizingMaskIntoConstraints="NO" id="CMD-nT-mEa">
|
||||
<rect key="frame" x="0.0" y="129" width="482" height="330"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<clipView key="contentView" ambiguous="YES" drawsBackground="NO" id="Igp-aH-flp">
|
||||
<rect key="frame" x="1" y="1" width="480" height="328"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<tableView verticalHuggingPriority="750" ambiguous="YES" allowsExpansionToolTips="YES" columnAutoresizingStyle="lastColumnOnly" selectionHighlightStyle="none" alternatingRowBackgroundColors="YES" columnReordering="NO" columnResizing="NO" multipleSelection="NO" autosaveColumns="NO" rowSizeStyle="automatic" viewBased="YES" id="FLX-Wt-y53">
|
||||
<rect key="frame" x="0.0" y="0.0" width="480" height="328"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<size key="intercellSpacing" width="3" height="2"/>
|
||||
<color key="backgroundColor" name="controlBackgroundColor" catalog="System" colorSpace="catalog"/>
|
||||
<tableViewGridLines key="gridStyleMask" dashed="YES"/>
|
||||
<color key="gridColor" name="gridColor" catalog="System" colorSpace="catalog"/>
|
||||
<tableColumns>
|
||||
<tableColumn width="477" minWidth="40" maxWidth="1000" id="5jP-bY-fhI">
|
||||
<tableHeaderCell key="headerCell" lineBreakMode="truncatingTail" borderStyle="border">
|
||||
<font key="font" metaFont="smallSystem"/>
|
||||
<color key="textColor" name="headerTextColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="headerColor" catalog="System" colorSpace="catalog"/>
|
||||
</tableHeaderCell>
|
||||
<textFieldCell key="dataCell" lineBreakMode="truncatingTail" selectable="YES" editable="YES" title="Text Cell" id="VZP-ti-Ti8">
|
||||
<font key="font" metaFont="system"/>
|
||||
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="controlBackgroundColor" catalog="System" colorSpace="catalog"/>
|
||||
</textFieldCell>
|
||||
<tableColumnResizingMask key="resizingMask" resizeWithTable="YES"/>
|
||||
<prototypeCellViews>
|
||||
<tableCellView identifier="Cell" focusRingType="none" id="aBv-F5-XWo">
|
||||
<rect key="frame" x="1" y="1" width="477" height="17"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<textField verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="pWm-hb-BXB">
|
||||
<rect key="frame" x="0.0" y="0.0" width="477" height="17"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES"/>
|
||||
<textFieldCell key="cell" lineBreakMode="truncatingTail" sendsActionOnEndEditing="YES" title="Table View Cell" id="p71-gJ-vFV">
|
||||
<font key="font" metaFont="system"/>
|
||||
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
|
||||
</textFieldCell>
|
||||
</textField>
|
||||
</subviews>
|
||||
<connections>
|
||||
<outlet property="textField" destination="pWm-hb-BXB" id="NNG-rj-AAQ"/>
|
||||
</connections>
|
||||
</tableCellView>
|
||||
<tableCellView identifier="DownloadCell" focusRingType="none" id="onK-6l-2iV" customClass="DownloadTableCellView">
|
||||
<rect key="frame" x="1" y="20" width="477" height="49"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<textField verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="A44-us-TEl">
|
||||
<rect key="frame" x="25" y="28" width="451" height="17"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES"/>
|
||||
<textFieldCell key="cell" lineBreakMode="truncatingTail" sendsActionOnEndEditing="YES" title="Table View Cell" id="NSU-6I-nsG">
|
||||
<font key="font" metaFont="system"/>
|
||||
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
|
||||
</textFieldCell>
|
||||
</textField>
|
||||
<progressIndicator wantsLayer="YES" fixedFrame="YES" maxValue="100" displayedWhenStopped="NO" indeterminate="YES" controlSize="small" style="spinning" translatesAutoresizingMaskIntoConstraints="NO" id="jBN-UJ-tWi">
|
||||
<rect key="frame" x="3" y="29" width="16" height="16"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
</progressIndicator>
|
||||
<textField verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="hfu-hP-QAH">
|
||||
<rect key="frame" x="25" y="3" width="451" height="17"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES"/>
|
||||
<textFieldCell key="cell" lineBreakMode="truncatingTail" sendsActionOnEndEditing="YES" title="Table View Cell" id="1cQ-Zh-q0o">
|
||||
<font key="font" metaFont="system"/>
|
||||
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
|
||||
</textFieldCell>
|
||||
</textField>
|
||||
</subviews>
|
||||
<connections>
|
||||
<outlet property="activity" destination="jBN-UJ-tWi" id="ZwD-yU-Vne"/>
|
||||
<outlet property="statusTextField" destination="hfu-hP-QAH" id="8Hv-BB-kYA"/>
|
||||
<outlet property="textField" destination="A44-us-TEl" id="Ta5-nd-ed1"/>
|
||||
</connections>
|
||||
</tableCellView>
|
||||
</prototypeCellViews>
|
||||
</tableColumn>
|
||||
</tableColumns>
|
||||
<connections>
|
||||
<outlet property="dataSource" destination="-2" id="Ghf-k9-bRK"/>
|
||||
<outlet property="delegate" destination="-2" id="rpR-0W-4Nu"/>
|
||||
<outlet property="menu" destination="RJM-21-hjO" id="xpL-0n-1jm"/>
|
||||
</connections>
|
||||
</tableView>
|
||||
</subviews>
|
||||
<nil key="backgroundColor"/>
|
||||
</clipView>
|
||||
<scroller key="horizontalScroller" hidden="YES" wantsLayer="YES" verticalHuggingPriority="750" horizontal="YES" id="pcd-MD-gho">
|
||||
<rect key="frame" x="1" y="314" width="480" height="15"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
</scroller>
|
||||
<scroller key="verticalScroller" hidden="YES" wantsLayer="YES" verticalHuggingPriority="750" horizontal="NO" id="jGc-PE-vaF">
|
||||
<rect key="frame" x="224" y="17" width="15" height="102"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
</scroller>
|
||||
</scrollView>
|
||||
<progressIndicator wantsLayer="YES" fixedFrame="YES" maxValue="100" style="bar" translatesAutoresizingMaskIntoConstraints="NO" id="Odp-OZ-ggl">
|
||||
<rect key="frame" x="20" y="94" width="438" height="20"/>
|
||||
<rect key="frame" x="22" y="78" width="438" height="20"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES"/>
|
||||
<connections>
|
||||
<binding destination="-2" name="maxValue" keyPath="self.totalCount" id="hpx-zN-odo"/>
|
||||
|
@ -64,7 +165,33 @@
|
|||
<connections>
|
||||
<outlet property="delegate" destination="-2" id="0bl-1N-AYu"/>
|
||||
</connections>
|
||||
<point key="canvasLocation" x="135" y="85.5"/>
|
||||
<point key="canvasLocation" x="142" y="179"/>
|
||||
</window>
|
||||
<menu id="RJM-21-hjO">
|
||||
<items>
|
||||
<menuItem title="Show in Finder" tag="1" id="hDp-fh-9nU">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<connections>
|
||||
<action selector="showInFinder:" target="-2" id="ltL-yL-7EP"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem title="Download" tag="2" id="ree-Zg-jYB">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<connections>
|
||||
<action selector="download:" target="-2" id="2ua-nq-Zy1"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem title="Cancel" tag="3" id="7fY-83-Ads">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<connections>
|
||||
<action selector="cancel:" target="-2" id="cHE-Wq-jwc"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
</items>
|
||||
<connections>
|
||||
<outlet property="delegate" destination="-2" id="fC3-h6-xe2"/>
|
||||
</connections>
|
||||
<point key="canvasLocation" x="-348" y="164"/>
|
||||
</menu>
|
||||
</objects>
|
||||
</document>
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface DownloadWindowController : NSWindowController <NSURLSessionTaskDelegate, NSURLSessionDownloadDelegate>
|
||||
@interface DownloadWindowController : NSWindowController
|
||||
|
||||
@property NSString *currentROM;
|
||||
@property NSInteger currentCount;
|
||||
|
@ -20,4 +20,20 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
|
||||
@end
|
||||
|
||||
@interface DownloadWindowController (URL) <NSURLSessionTaskDelegate, NSURLSessionDownloadDelegate>
|
||||
@end
|
||||
|
||||
@interface DownloadWindowController (Table) <NSTableViewDelegate, NSTableViewDataSource>
|
||||
@end
|
||||
|
||||
@interface DownloadWindowController (Menu) <NSMenuDelegate, NSMenuItemValidation>
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@interface DownloadTableCellView : NSTableCellView
|
||||
@property (weak) IBOutlet NSTextField *statusTextField;
|
||||
@property (weak) IBOutlet NSProgressIndicator *activity;
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
|
|
|
@ -9,17 +9,47 @@
|
|||
#import "Ample.h"
|
||||
#import "DownloadWindowController.h"
|
||||
|
||||
enum {
|
||||
ItemMissing = 0,
|
||||
ItemFound,
|
||||
ItemDownloading,
|
||||
ItemDownloaded,
|
||||
ItemCanceled,
|
||||
ItemError
|
||||
};
|
||||
|
||||
@interface DownloadItem : NSObject
|
||||
|
||||
@property NSString *name;
|
||||
@property NSError *error;
|
||||
@property NSString *pathName;
|
||||
@property NSURLSessionDownloadTask *task;
|
||||
@property NSURL *localURL;
|
||||
|
||||
@property NSUInteger status;
|
||||
@property NSUInteger index;
|
||||
|
||||
|
||||
-(void)cancelDownload;
|
||||
-(void)beginDownloadWithTask:(NSURLSessionDownloadTask *)task;
|
||||
-(void)completeWithError: (NSError *)error;
|
||||
-(NSString *)statusDescription;
|
||||
@end
|
||||
|
||||
|
||||
|
||||
@interface DownloadWindowController ()
|
||||
@property (weak) IBOutlet NSTableView *tableView;
|
||||
|
||||
@end
|
||||
|
||||
@implementation DownloadWindowController {
|
||||
|
||||
NSArray *_roms;
|
||||
NSArray *_items;
|
||||
NSURL *_romFolder;
|
||||
NSURL *_sourceURL;
|
||||
NSURLSession *_session;
|
||||
NSMutableSet *_tasks;
|
||||
NSMutableDictionary *_taskIndex;
|
||||
}
|
||||
|
||||
-(NSString *)windowNibName {
|
||||
|
@ -40,40 +70,98 @@
|
|||
NSDictionary *d = [NSDictionary dictionaryWithContentsOfURL: url];
|
||||
|
||||
NSURL *sd = SupportDirectory();
|
||||
NSString *romdir = [SupportDirectoryPath() stringByAppendingPathComponent: @"roms"];
|
||||
|
||||
_romFolder = [sd URLByAppendingPathComponent: @"roms"];
|
||||
|
||||
[fm createDirectoryAtURL: _romFolder withIntermediateDirectories: YES attributes: nil error: &error];
|
||||
|
||||
|
||||
_roms = [d objectForKey: @"roms"];
|
||||
NSArray *roms = [d objectForKey: @"roms"];
|
||||
[self setCurrentROM: @""];
|
||||
[self setCurrentCount: 0];
|
||||
[self setTotalCount: [_roms count]];
|
||||
[self setTotalCount: [roms count]];
|
||||
[self setErrorCount: 0];
|
||||
_sourceURL = [NSURL URLWithString: @"https://archive.org/download/mame0224_rom"]; // hardcoded....
|
||||
|
||||
|
||||
[self download];
|
||||
NSMutableArray *tmp = [NSMutableArray arrayWithCapacity: [roms count]];
|
||||
unsigned ix = 0;
|
||||
for (NSString *name in roms) {
|
||||
|
||||
DownloadItem *item = [DownloadItem new];
|
||||
[item setName: name];
|
||||
[item setIndex: ix++];
|
||||
|
||||
[tmp addObject: item];
|
||||
|
||||
// check if the file exists.
|
||||
NSString *s = [romdir stringByAppendingPathComponent: name];
|
||||
NSString *path;
|
||||
|
||||
path = [s stringByAppendingPathExtension: @"zip"];
|
||||
if ([fm fileExistsAtPath: path]) {
|
||||
[item setStatus: ItemFound];
|
||||
[item setLocalURL: [NSURL fileURLWithPath: path]];
|
||||
continue;
|
||||
}
|
||||
path = [s stringByAppendingPathExtension: @"7z"];
|
||||
if ([fm fileExistsAtPath: path]) {
|
||||
[item setStatus: ItemFound];
|
||||
[item setLocalURL: [NSURL fileURLWithPath: path]];
|
||||
continue;
|
||||
}
|
||||
}
|
||||
_items = tmp;
|
||||
|
||||
NSURLSessionConfiguration *config = [NSURLSessionConfiguration defaultSessionConfiguration];
|
||||
_session = [NSURLSession sessionWithConfiguration: config delegate: self delegateQueue: nil];
|
||||
_taskIndex = [NSMutableDictionary dictionaryWithCapacity: [_items count]];
|
||||
|
||||
//[self download];
|
||||
}
|
||||
|
||||
-(void)downloadItem: (DownloadItem *)item {
|
||||
|
||||
if (!_session) {
|
||||
NSURLSessionConfiguration *config = [NSURLSessionConfiguration defaultSessionConfiguration];
|
||||
_session = [NSURLSession sessionWithConfiguration: config delegate: self delegateQueue: nil];
|
||||
}
|
||||
|
||||
NSURLSessionDownloadTask *task;
|
||||
NSString *s = [item name];
|
||||
NSString *path = [s stringByAppendingString: @".7z"]; // hardcoded.
|
||||
NSURL *url = [_sourceURL URLByAppendingPathComponent: path];
|
||||
|
||||
task = [_session downloadTaskWithURL: url];
|
||||
|
||||
[item beginDownloadWithTask: task];
|
||||
[_taskIndex setObject: item forKey: task];
|
||||
|
||||
[task resume];
|
||||
|
||||
}
|
||||
|
||||
-(void)download {
|
||||
|
||||
NSURLSessionConfiguration *config = [NSURLSessionConfiguration defaultSessionConfiguration];
|
||||
_session = [NSURLSession sessionWithConfiguration: config delegate: self delegateQueue: nil];
|
||||
_tasks = [NSMutableSet setWithCapacity: [_roms count]];
|
||||
|
||||
|
||||
// run in thread?
|
||||
//unsigned count = 0;
|
||||
for (NSString *s in _roms) {
|
||||
for (DownloadItem *item in _items) {
|
||||
|
||||
NSURLSessionDownloadTask *task;
|
||||
NSString *s = [item name];
|
||||
NSString *path = [s stringByAppendingString: @".7z"]; // hardcoded.
|
||||
NSURL *url = [_sourceURL URLByAppendingPathComponent: path];
|
||||
|
||||
task = [_session downloadTaskWithURL: url];
|
||||
[_tasks addObject: task];
|
||||
[task resume];
|
||||
[_taskIndex setObject: item forKey: task];
|
||||
|
||||
[item setTask: task];
|
||||
|
||||
[task resume];
|
||||
|
||||
//++count;
|
||||
//if (count >= 2) break;
|
||||
}
|
||||
|
@ -81,17 +169,62 @@
|
|||
|
||||
}
|
||||
|
||||
-(IBAction)cancel:(id)sender {
|
||||
-(DownloadItem *)clickedItem {
|
||||
NSInteger row = [_tableView clickedRow];
|
||||
if (row < 0 || row >= [_items count]) return nil;
|
||||
return [_items objectAtIndex: row];
|
||||
}
|
||||
-(void)redrawRow: (NSUInteger)row {
|
||||
|
||||
for (NSURLSessionTask *task in _tasks) {
|
||||
[task cancel];
|
||||
//NSRect r = [_tableView rectOfRow: row];
|
||||
//[_tableView setNeedsDisplayInRect: r];
|
||||
|
||||
NSIndexSet *rIx = [NSIndexSet indexSetWithIndex: row];
|
||||
NSIndexSet *cIx = [NSIndexSet indexSetWithIndex: 0];
|
||||
|
||||
[_tableView reloadDataForRowIndexes: rIx columnIndexes: cIx];
|
||||
}
|
||||
#pragma mark - IBActions
|
||||
|
||||
-(IBAction)cancelAll:(id)sender {
|
||||
|
||||
for (DownloadItem *item in _items) {
|
||||
[item cancelDownload];
|
||||
}
|
||||
|
||||
[_session invalidateAndCancel];
|
||||
_session = nil;
|
||||
_tasks = nil;
|
||||
[_taskIndex removeAllObjects];
|
||||
[self setCurrentCount: 0];
|
||||
[self setActive: NO];
|
||||
|
||||
|
||||
[_tableView reloadData];
|
||||
//[_tableView setNeedsDisplay: YES]; // doesn't work...
|
||||
}
|
||||
|
||||
- (IBAction)showInFinder:(id)sender {
|
||||
DownloadItem *item = [self clickedItem];
|
||||
if (!item) return;
|
||||
NSURL *url = [item localURL];
|
||||
if (!url) return;
|
||||
|
||||
NSWorkspace *ws = [NSWorkspace sharedWorkspace];
|
||||
[ws activateFileViewerSelectingURLs: @[url]];
|
||||
}
|
||||
|
||||
- (IBAction)download:(id)sender {
|
||||
DownloadItem *item = [self clickedItem];
|
||||
if (!item) return;
|
||||
|
||||
[self downloadItem: item];
|
||||
[self redrawRow: [item index]];
|
||||
}
|
||||
- (IBAction)cancel:(id)sender {
|
||||
DownloadItem *item = [self clickedItem];
|
||||
if (!item) return;
|
||||
|
||||
[item cancelDownload];
|
||||
[self redrawRow: [item index]];
|
||||
}
|
||||
|
||||
|
||||
|
@ -100,33 +233,185 @@
|
|||
-(void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error {
|
||||
|
||||
|
||||
|
||||
// not sure if strictly necessary but this happens in a background thread
|
||||
// and these are used in KVO binding. Also, main thread only
|
||||
// means no race conditions.
|
||||
dispatch_async(dispatch_get_main_queue(), ^(void){
|
||||
if (error)
|
||||
[self setErrorCount: self->_errorCount + 1];
|
||||
else
|
||||
[self setCurrentCount: self->_currentCount + 1];
|
||||
[self->_tasks removeObject: task];
|
||||
if (![self->_tasks anyObject]) {
|
||||
|
||||
NSMutableDictionary *taskIndex = self->_taskIndex;
|
||||
DownloadItem *item = [taskIndex objectForKey: task];
|
||||
[taskIndex removeObjectForKey: task];
|
||||
|
||||
if ([taskIndex count] == 0) {
|
||||
[self setActive: NO];
|
||||
}
|
||||
|
||||
if (item) {
|
||||
[item completeWithError: error];
|
||||
NSUInteger row = [item index];
|
||||
|
||||
[self redrawRow: row];
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
- (void)URLSession:(NSURLSession *)session downloadTask:(nonnull NSURLSessionDownloadTask *)downloadTask didFinishDownloadingToURL:(nonnull NSURL *)location {
|
||||
- (void)URLSession:(NSURLSession *)session downloadTask:(nonnull NSURLSessionDownloadTask *)task didFinishDownloadingToURL:(nonnull NSURL *)location {
|
||||
|
||||
|
||||
// need to move to the destination directory...
|
||||
// file deleted after this function returns, so can't move asynchronously.
|
||||
NSFileManager *fm = [NSFileManager defaultManager];
|
||||
NSURL *src = [[downloadTask originalRequest] URL];
|
||||
NSURL *src = [[task originalRequest] URL];
|
||||
NSURL *dest = [_romFolder URLByAppendingPathComponent: [src lastPathComponent]];
|
||||
NSError *error = nil;
|
||||
|
||||
[fm moveItemAtURL: location toURL: dest error: &error];
|
||||
|
||||
DownloadItem *item = [_taskIndex objectForKey: task];
|
||||
[item setLocalURL: dest];
|
||||
|
||||
/*
|
||||
dispatch_async(dispatch_get_main_queue(), ^(void){
|
||||
|
||||
|
||||
[item setLocalURL: dest];
|
||||
}
|
||||
*/
|
||||
NSLog(@"%@", src);
|
||||
}
|
||||
@end
|
||||
|
||||
@implementation DownloadWindowController (Table)
|
||||
|
||||
- (NSInteger)numberOfRowsInTableView:(NSTableView *)tableView {
|
||||
return [_items count];
|
||||
}
|
||||
|
||||
- (id)tableView:(NSTableView *)tableView objectValueForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row {
|
||||
|
||||
return [_items objectAtIndex: row];
|
||||
}
|
||||
|
||||
|
||||
- (NSView *)tableView:(NSTableView *)tableView viewForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row {
|
||||
|
||||
if (row == 51) { NSLog(@"viewForRow 51");}
|
||||
|
||||
DownloadItem *item = [_items objectAtIndex: row];
|
||||
DownloadTableCellView *v = [tableView makeViewWithIdentifier: @"DownloadCell" owner: self];
|
||||
|
||||
[[v textField] setObjectValue: [item name]];
|
||||
|
||||
NSTextField *tf = [v statusTextField];
|
||||
|
||||
[tf setObjectValue: [item statusDescription]];
|
||||
if ([item error]) {
|
||||
[tf setTextColor: [NSColor redColor]];
|
||||
} else {
|
||||
[tf setTextColor: [NSColor blackColor]];
|
||||
//if ([tableView isRowSelected: row]){
|
||||
//[tf setTextColor: [NSColor whiteColor]];
|
||||
//}
|
||||
}
|
||||
|
||||
if ([item task]) {
|
||||
[[v activity] startAnimation: nil];
|
||||
} else {
|
||||
[[v activity] stopAnimation: nil];
|
||||
}
|
||||
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@implementation DownloadTableCellView
|
||||
|
||||
@end
|
||||
|
||||
@implementation DownloadItem
|
||||
|
||||
-(void)beginDownloadWithTask:(NSURLSessionDownloadTask *)task {
|
||||
_task = task;
|
||||
_error = nil;
|
||||
if (task) _status = ItemDownloading;
|
||||
}
|
||||
|
||||
-(void)cancelDownload {
|
||||
if (!_task) return;
|
||||
[_task cancel];
|
||||
_task = nil;
|
||||
_status = ItemCanceled;
|
||||
}
|
||||
|
||||
-(void)completeWithError: (NSError *)error {
|
||||
_task = nil;
|
||||
if (error) {
|
||||
_error = error;
|
||||
_status = ItemError;
|
||||
} else {
|
||||
// what if there was an error moving it?
|
||||
_error = nil;
|
||||
_status = ItemDownloaded;
|
||||
}
|
||||
}
|
||||
|
||||
-(NSString *)statusDescription {
|
||||
|
||||
static NSString *Names[] = {
|
||||
@"ROM missing",
|
||||
@"ROM found",
|
||||
@"Downloading…",
|
||||
@"Downloaded",
|
||||
@"Canceled",
|
||||
@"Error"
|
||||
};
|
||||
if (_error) return [_error description];
|
||||
|
||||
if (_status > sizeof(Names)/sizeof(Names[0])) return @"Unknown";
|
||||
return Names[_status];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
|
||||
|
||||
@implementation DownloadWindowController (Menu)
|
||||
|
||||
enum {
|
||||
kOpenInFinder = 1,
|
||||
kDownload,
|
||||
kCancel,
|
||||
};
|
||||
|
||||
- (BOOL)validateMenuItem:(NSMenuItem *)menuItem {
|
||||
NSInteger row = [_tableView clickedRow];
|
||||
if (row < 0) return NO;
|
||||
DownloadItem *item = [_items objectAtIndex: row];
|
||||
|
||||
NSUInteger status = [item status];
|
||||
switch([menuItem tag]) {
|
||||
case kOpenInFinder:
|
||||
return status == ItemFound || status == ItemDownloaded;
|
||||
break;
|
||||
case kDownload:
|
||||
return YES;
|
||||
//return status == ItemMissing || status == ItemError || status == ItemCanceled;
|
||||
break;
|
||||
case kCancel:
|
||||
return status == ItemDownloading;
|
||||
break;
|
||||
|
||||
}
|
||||
return NO;
|
||||
}
|
||||
|
||||
@end
|
||||
|
|
Loading…
Reference in New Issue