// // FileTreeDataSource.m // Cog // // Created by Vincent Spader on 10/14/07. // Copyright 2007 __MyCompanyName__. All rights reserved. // #import "FileTreeDataSource.h" #import "DirectoryNode.h" #import "PathWatcher.h" #import "Logging.h" static NSURL *defaultMusicDirectory(void) { return [[NSFileManager defaultManager] URLForDirectory:NSMusicDirectory inDomain:NSUserDomainMask appropriateForURL:nil create:NO error:nil]; } @interface FileTreeDataSource() @property NSURL *rootURL; @end @implementation FileTreeDataSource { PathNode *rootNode; } + (void)initialize { NSString *path = [defaultMusicDirectory() absoluteString]; NSDictionary *userDefaultsValuesDict = @{@"fileTreeRootURL": path}; [[NSUserDefaults standardUserDefaults] registerDefaults:userDefaultsValuesDict]; } - (void)awakeFromNib { [self.pathControl setTarget:self]; [self.pathControl setAction:@selector(pathControlAction:)]; [[NSUserDefaultsController sharedUserDefaultsController] addObserver:self forKeyPath:@"values.fileTreeRootURL" options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionInitial context:nil]; } - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context { if ([keyPath isEqualToString:@"values.fileTreeRootURL"]) { NSString *url = [[[NSUserDefaultsController sharedUserDefaultsController] defaults] objectForKey:@"fileTreeRootURL"]; DLog(@"File tree root URL: %@\n", url); self.rootURL = [NSURL URLWithString:url]; } } - (void)changeURL:(NSURL *)url { if (url != nil) { [[[NSUserDefaultsController sharedUserDefaultsController] defaults] setObject:[url absoluteString] forKey:@"fileTreeRootURL"]; } } - (void)pathControlAction:(id)sender { NSPathControlItem *item = [self.pathControl clickedPathItem]; if (item != nil && item.URL != nil) { [self changeURL:item.URL]; } } - (NSURL *)rootURL { return [rootNode URL]; } - (void)setRootURL:(NSURL *)rootURL { if (![[NSFileManager defaultManager] fileExistsAtPath:[rootURL path]]) { rootURL = defaultMusicDirectory(); } rootNode = [[DirectoryNode alloc] initWithDataSource:self url:rootURL]; [self.watcher setPath:[rootURL path]]; [self reloadPathNode:rootNode]; } - (PathNode *)nodeForPath:(NSString *)path { NSString *relativePath = [[path stringByReplacingOccurrencesOfString:[[[self rootURL] path] stringByAppendingString:@"/"] withString:@"" options:NSAnchoredSearch range:NSMakeRange(0, [path length]) ] stringByStandardizingPath]; PathNode *node = rootNode; DLog(@"Root | Relative | Path: %@ | %@ | %@", [[self rootURL] path], relativePath, path); for (NSString *c in [relativePath pathComponents]) { DLog(@"COMPONENT: %@", c); BOOL found = NO; for (PathNode *subnode in [node subpaths]) { if ([[[[subnode URL] path] lastPathComponent] isEqualToString:c]) { node = subnode; found = YES; } } if (!found) { DLog(@"Not found!"); return nil; } } return node; } - (void)pathDidChange:(NSString *)path { DLog(@"PATH DID CHANGE: %@", path); //Need to find the corresponding node...and call [node reloadPath], then [self reloadPathNode:node] PathNode *node = [self nodeForPath:path]; DLog(@"NODE IS: %@", node); [node updatePath]; [self reloadPathNode:node]; } - (NSInteger)outlineView:(NSOutlineView *)outlineView numberOfChildrenOfItem:(id)item { PathNode *n = (item == nil ? rootNode : item); return (int) [[n subpaths] count]; } - (BOOL)outlineView:(NSOutlineView *)outlineView isItemExpandable:(id)item { PathNode *n = (item == nil ? rootNode : item); return ![n isLeaf]; } - (id)outlineView:(NSOutlineView *)outlineView child:(NSInteger)index ofItem:(id)item { PathNode *n = (item == nil ? rootNode : item); return [n subpaths][(NSUInteger) index]; } - (id)outlineView:(NSOutlineView *)outlineView objectValueForTableColumn:(NSTableColumn *)tableColumn byItem:(id)item { PathNode *n = (item == nil ? rootNode : item); return n; } - (id )outlineView:(NSOutlineView *)outlineView pasteboardWriterForItem:(id)item { NSPasteboardItem *paste = [[NSPasteboardItem alloc] init]; if (@available(macOS 10.13, *)) { [paste setData:[[item URL] dataRepresentation] forType:NSPasteboardTypeFileURL]; } else { [paste setPropertyList:@[[item URL]] forType:NSFilenamesPboardType]; } return paste; } - (void)reloadPathNode:(PathNode *)item { if (item == rootNode) { [self.outlineView reloadData]; } else { [self.outlineView reloadItem:item reloadChildren:YES]; } } @end