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