double-clicking a recent disk image will try to put it in an appropriate location.

if the media class doesn't exist (eg, hard drive with no hard drive controller) it's added but not displayed.
This commit is contained in:
Kelvin Sherlock 2021-07-10 01:15:34 -04:00
parent abf4e027ee
commit 5a098b9d00
8 changed files with 146 additions and 28 deletions

View File

@ -40,6 +40,8 @@ extern NSString *kDownloadExtension;
extern NSString *kDefaultDownloadURL;
extern NSString *kDefaultDownloadExtension;
extern NSString *kNotificationDiskImageAdded;
extern NSString *kNotificationDiskImageMagicRoute;
@protocol Bookmark <NSObject>
-(BOOL)loadBookmark: (NSDictionary *)bookmark;

View File

@ -135,3 +135,6 @@ NSString *kDefaultDownloadExtension = @"DefaultDownloadExtension";
NSString *kDownloadURL = @"DownloadURL";
NSString *kDownloadExtension = @"DownloadExtension";
NSString *kNotificationDiskImageAdded = @"Disk Image Added";
NSString *kNotificationDiskImageMagicRoute = @"Disk Image Magic Route";

View File

@ -100,6 +100,7 @@
</tableColumn>
</tableColumns>
<connections>
<action trigger="doubleAction" selector="doubleClick:" target="-2" id="Zud-ke-iLR"/>
<binding destination="vmp-9h-Z5R" name="content" keyPath="arrangedObjects" id="GHn-tz-ash"/>
<outlet property="dataSource" destination="-2" id="PRV-Rt-UuC"/>
<outlet property="delegate" destination="-2" id="WuV-c9-o5I"/>

View File

@ -93,7 +93,7 @@
NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
[nc addObserver: self selector: @selector(diskImageAdded:) name: @"DiskImageAdded" object: nil];
[nc addObserver: self selector: @selector(diskImageAdded:) name: kNotificationDiskImageAdded object: nil];
[nc addObserver: self selector: @selector(willTerminate:) name: NSApplicationWillTerminateNotification object: nil];
}
@ -248,6 +248,15 @@
}
-(IBAction)doubleClick: (id)sender {
NSDictionary *d = [self clickedItem];
NSLog(@"%@", d);
NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
[nc postNotificationName: kNotificationDiskImageMagicRoute object: nil userInfo: d];
}
@end
@implementation DiskImagesWindowController (TableView)

View File

@ -22,12 +22,12 @@ typedef struct Media {
typedef enum {
MediaTypeErr = -1,
MediaTypeError = -1,
MediaTypeUnknown = 0,
MediaType_5_25,
MediaType_3_5,
MediaType_HardDisk,
MediaType_CD,
MediaType_CDROM,
MediaType_Cassette,
MediaType_Picture,
MediaType_MIDI,
@ -41,6 +41,6 @@ BOOL MediaEqual(const Media *lhs, const Media *rhs);
extern const Media EmptyMedia;
MediaType ClassifyMediaFile(NSString *file);
MediaType ClassifyMediaFile(id file);
#endif /* Media_h */

View File

@ -74,12 +74,12 @@ static unsigned hash(const char *cp) {
int i, shift;
if (!cp) return 0;
for (i = 0, shift = 0; i < 4; ++i, shift += 8) {
unsigned c = cp[0];
unsigned c = cp[i];
if (!c) break;
c = tolower(c);
rv |= (c << shift);
}
if (i > 4) return 0;
//if (i > 4) return 0; // .image is 5....
return rv;
}
@ -138,7 +138,7 @@ static MediaType is_woz(const uint8_t *buffer, size_t file_size) {
}
return MediaTypeUnknown;
}
return MediaTypeErr;
return MediaTypeError;
}
static MediaType is_dc42(const uint8_t *buffer, size_t file_size) {
@ -152,7 +152,7 @@ static MediaType is_dc42(const uint8_t *buffer, size_t file_size) {
}
}
return MediaTypeErr;
return MediaTypeError;
}
static MediaType is_2img(const uint8_t *buffer, size_t file_size) {
@ -169,7 +169,7 @@ static MediaType is_2img(const uint8_t *buffer, size_t file_size) {
//return MediaTypeUnknown;
}
return MediaTypeErr;
return MediaTypeError;
}
static MediaType is_chd(const uint8_t *buffer, size_t file_size) {
@ -185,18 +185,18 @@ static MediaType is_chd(const uint8_t *buffer, size_t file_size) {
}
return MediaTypeUnknown;
}
return MediaTypeErr;
return MediaTypeError;
}
MediaType ClassifyMediaFile(NSString *file) {
MediaType ClassifyMediaFile(id file) {
struct stat st;
ssize_t size;
unsigned char buffer[128];
int fd;
const char *path = [file fileSystemRepresentation];
const char *path = [file fileSystemRepresentation]; // or URL
const char *ext = extname(path);
unsigned ext_hash = hash(ext);
@ -204,12 +204,12 @@ MediaType ClassifyMediaFile(NSString *file) {
memset(buffer, 0, sizeof(buffer));
fd = open(path, O_RDONLY);
if (fd < 0) return MediaTypeErr;
if (fd < 0) return MediaTypeError;
fstat(fd, &st);
size = read(fd, buffer, sizeof(buffer));
close(fd);
if (size <= 0) return MediaTypeErr;
if (size <= 0) return MediaTypeError;
// 13 sector support ? not on an event 512 block boundary.
// = 116480 bytes.
@ -247,11 +247,11 @@ MediaType ClassifyMediaFile(NSString *file) {
// hdv - 3.5 or hard drive.
case _x3('h', 'd', 'v'):
case _x3('r', 'a', 'w'):
if (is_raw_35(st.st_size)) return MediaType_3_5;
if ((st.st_size & 511) == 0) return MediaType_HardDisk;
return MediaTypeUnknown;
case _x3('n', 'i', 'b'):
return MediaType_5_25;
@ -262,7 +262,7 @@ MediaType ClassifyMediaFile(NSString *file) {
case _x3('i', 's', 'o'):
case _x3('c', 'u', 'e'):
case _x3('c', 'd', 'r'):
return MediaType_CD;
return MediaType_CDROM;
case _x3('p', 'n', 'g'):
return MediaType_Picture;

View File

@ -23,6 +23,9 @@ NS_ASSUME_NONNULL_BEGIN
-(IBAction)resetMedia:(id)sender;
-(BOOL)smartRouteURL: (NSURL *)url;
-(BOOL)smartRouteFile: (NSString *)file;
@end
@interface MediaViewController (Bookmark) <Bookmark>

View File

@ -43,6 +43,7 @@ enum {
@property NSString *title;
@property NSInteger index;
@property NSInteger category;
@property (weak)NSOutlineView *view;
-(NSInteger)count;
-(id)objectAtIndex:(NSInteger)index;
@ -141,7 +142,36 @@ enum {
return YES;
}
-(BOOL)pruneChildrenWithOutlineView: (NSOutlineView *)view {
-(BOOL)addURL: (NSURL *)url {
for (MediaItem *item in _children) {
if (![item occupied]) {
[item setUrl: url];
return NO;
}
}
// add an extra item...
if (!_children) _children = [NSMutableArray new];
NSUInteger ix = [_children count];
MediaItem *item = [MediaItem new];
[item setIndex: ix];
[item setCategory: _category];
[item setUrl: url];
[item setValid: ix < _validCount];
[_children addObject: item];
if (_view) {
NSIndexSet *set = [NSIndexSet indexSetWithIndex: ix];
[_view insertItemsAtIndexes: set
inParent: self
withAnimation: NSTableViewAnimationEffectFade];
}
return YES;
}
-(BOOL)pruneChildren {
NSUInteger count = [_children count];
BOOL delta = NO;
if (_validCount == count) return NO;
@ -158,15 +188,15 @@ enum {
}
if (delta) {
if (view)
[view removeItemsAtIndexes: set inParent: self withAnimation: NSTableViewAnimationEffectFade];
if (_view)
[_view removeItemsAtIndexes: set inParent: self withAnimation: NSTableViewAnimationEffectFade];
return YES;
}
return NO;
}
-(BOOL)moveItemFrom: (NSInteger)oldIndex to: (NSInteger)newIndex outlineView: (NSOutlineView *)view {
-(BOOL)moveItemFrom: (NSInteger)oldIndex to: (NSInteger)newIndex {
if (newIndex == oldIndex) return NO;
NSUInteger count = [_children count];
if (oldIndex >= count) return NO;
@ -179,7 +209,7 @@ enum {
} else {
[_children insertObject: item atIndex: newIndex];
}
if (view) [view moveItemAtIndex: oldIndex inParent: self toIndex: newIndex inParent: self];
if (_view) [_view moveItemAtIndex: oldIndex inParent: self toIndex: newIndex inParent: self];
// re-index and re-validate.
unsigned ix = 0;
@ -191,7 +221,7 @@ enum {
++ix;
}
[self pruneChildrenWithOutlineView: view];
[self pruneChildren];
//[view reloadItem: self reloadChildren: YES];
return YES;
}
@ -403,7 +433,7 @@ x = media.name; cat = _data[index]; delta |= [cat setItemCount: x]
[item setString: nil];
delta = YES;
}
if ([cat pruneChildrenWithOutlineView: _outlineView]) delta = YES;
if ([cat pruneChildren]) delta = YES;
}
if (delta) {
[self rebuildRoot];
@ -413,7 +443,9 @@ x = media.name; cat = _data[index]; delta |= [cat setItemCount: x]
static NSString *kDragType = @"private.ample.media";
- (void)viewDidLoad {
NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
[super viewDidLoad];
//NSOutlineView *view = [self view];
@ -424,6 +456,21 @@ static NSString *kDragType = @"private.ample.media";
[_outlineView expandItem: nil expandChildren: YES];
[_outlineView registerForDraggedTypes: @[kDragType]];
for (unsigned i = 0; i < CATEGORY_COUNT; ++i)
[_data[i] setView: _outlineView];
[nc addObserver: self selector: @selector(magicRouteNotification:) name: kNotificationDiskImageMagicRoute object: nil];
}
-(void)viewWillDisappear {
NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
[nc removeObserver: self];
for (unsigned i = 0; i < CATEGORY_COUNT; ++i)
[_data[i] setView: nil];
}
#pragma mark - NSOutlineViewDelegate
@ -620,7 +667,7 @@ static NSString *kDragType = @"private.ample.media";
NSInteger oldIndex = indexes[1];
[_outlineView beginUpdates];
[cat moveItemFrom: oldIndex to: index outlineView: _outlineView];
[cat moveItemFrom: oldIndex to: index];
[_outlineView endUpdates];
[self rebuildArgs];
@ -646,7 +693,7 @@ static NSString *kDragType = @"private.ample.media";
if (![item valid]) {
MediaCategory *cat = [_outlineView parentForItem: item];
[_outlineView beginUpdates];
[cat pruneChildrenWithOutlineView: _outlineView];
[cat pruneChildren];
[_outlineView endUpdates];
}
@ -663,7 +710,7 @@ static NSString *kDragType = @"private.ample.media";
// TODO - don't add to recent disks if this is a bitbanger / midi / printer device.
if (url && tag == 0) {
NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
[nc postNotificationName: @"DiskImageAdded" object: url];
[nc postNotificationName: kNotificationDiskImageAdded object: url];
}
[self rebuildArgs];
@ -677,6 +724,60 @@ static NSString *kDragType = @"private.ample.media";
[self resetDiskImages];
}
-(void)magicRouteNotification: (NSNotification *)notification {
NSDictionary *userInfo = [notification userInfo];
id path = [userInfo objectForKey: @"path"];
if ([path isKindOfClass: [NSURL class]]) {
[self smartRouteURL: path];
return;
}
if ([path isKindOfClass: [NSString class]]) {
NSURL *url = [NSURL fileURLWithPath: path];
[self smartRouteURL: url];
return;
}
}
/*
* given a file, add it to the media list.
* TODO - how to handle if full or media type missing?
*/
-(BOOL)smartRouteURL: (NSURL *)url {
if (!url) return NO;
MediaType mt = ClassifyMediaFile(url);
if (mt < 1) return NO; // unknown / error.
unsigned ix = 0;
switch(mt) {
case MediaType_3_5: ix = kIndexFloppy35; break;
case MediaType_5_25: ix = kIndexFloppy525; break;
case MediaType_Cassette: ix = kIndexCassette; break;
case MediaType_HardDisk: ix = kIndexHardDrive; break;
case MediaType_CDROM: ix = kIndexCDROM; break;
case MediaType_Picture:
case MediaType_MIDI:
case MediaTypeError:
case MediaTypeUnknown:
return NO;
}
MediaCategory *cat = _data[ix];
[cat addURL: url];
[self rebuildArgs];
return YES;
}
-(BOOL)smartRouteFile: (NSString *)file {
return NO;
}
@end
@implementation MediaViewController (Bookmark)
@ -817,5 +918,4 @@ static void CompressArray(NSMutableArray *array) {
return YES;
}
@end