From 5a098b9d007989df7c72f39ed9334b58f2c741a1 Mon Sep 17 00:00:00 2001 From: Kelvin Sherlock Date: Sat, 10 Jul 2021 01:15:34 -0400 Subject: [PATCH] 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. --- Ample/Ample.h | 2 + Ample/Ample.m | 3 + Ample/Base.lproj/DiskImages.xib | 1 + Ample/DiskImagesWindowController.m | 11 ++- Ample/Media.h | 6 +- Ample/Media.m | 24 +++--- Ample/MediaViewController.h | 3 + Ample/MediaViewController.m | 124 ++++++++++++++++++++++++++--- 8 files changed, 146 insertions(+), 28 deletions(-) diff --git a/Ample/Ample.h b/Ample/Ample.h index 5dd804a..ba7e7a0 100644 --- a/Ample/Ample.h +++ b/Ample/Ample.h @@ -40,6 +40,8 @@ extern NSString *kDownloadExtension; extern NSString *kDefaultDownloadURL; extern NSString *kDefaultDownloadExtension; +extern NSString *kNotificationDiskImageAdded; +extern NSString *kNotificationDiskImageMagicRoute; @protocol Bookmark -(BOOL)loadBookmark: (NSDictionary *)bookmark; diff --git a/Ample/Ample.m b/Ample/Ample.m index 2bb3560..f1b2c1f 100644 --- a/Ample/Ample.m +++ b/Ample/Ample.m @@ -135,3 +135,6 @@ NSString *kDefaultDownloadExtension = @"DefaultDownloadExtension"; NSString *kDownloadURL = @"DownloadURL"; NSString *kDownloadExtension = @"DownloadExtension"; + +NSString *kNotificationDiskImageAdded = @"Disk Image Added"; +NSString *kNotificationDiskImageMagicRoute = @"Disk Image Magic Route"; diff --git a/Ample/Base.lproj/DiskImages.xib b/Ample/Base.lproj/DiskImages.xib index 6c6f528..adb78dd 100644 --- a/Ample/Base.lproj/DiskImages.xib +++ b/Ample/Base.lproj/DiskImages.xib @@ -100,6 +100,7 @@ + diff --git a/Ample/DiskImagesWindowController.m b/Ample/DiskImagesWindowController.m index 57412b4..ede9e68 100644 --- a/Ample/DiskImagesWindowController.m +++ b/Ample/DiskImagesWindowController.m @@ -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) diff --git a/Ample/Media.h b/Ample/Media.h index 4d069b3..6b2af0b 100644 --- a/Ample/Media.h +++ b/Ample/Media.h @@ -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 */ diff --git a/Ample/Media.m b/Ample/Media.m index 464a4f7..7e99358 100644 --- a/Ample/Media.m +++ b/Ample/Media.m @@ -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; diff --git a/Ample/MediaViewController.h b/Ample/MediaViewController.h index 04174b0..17adb78 100644 --- a/Ample/MediaViewController.h +++ b/Ample/MediaViewController.h @@ -23,6 +23,9 @@ NS_ASSUME_NONNULL_BEGIN -(IBAction)resetMedia:(id)sender; +-(BOOL)smartRouteURL: (NSURL *)url; +-(BOOL)smartRouteFile: (NSString *)file; + @end @interface MediaViewController (Bookmark) diff --git a/Ample/MediaViewController.m b/Ample/MediaViewController.m index c19b34c..d223761 100644 --- a/Ample/MediaViewController.m +++ b/Ample/MediaViewController.m @@ -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