2007-10-18 02:52:03 +00:00
|
|
|
//
|
|
|
|
// FileTreeDataSource.m
|
|
|
|
// Cog
|
|
|
|
//
|
|
|
|
// Created by Vincent Spader on 10/14/07.
|
|
|
|
// Copyright 2007 __MyCompanyName__. All rights reserved.
|
|
|
|
//
|
|
|
|
|
|
|
|
#import "FileTreeDataSource.h"
|
|
|
|
|
|
|
|
#import "DirectoryNode.h"
|
2008-02-18 03:27:59 +00:00
|
|
|
#import "PathWatcher.h"
|
2007-10-18 02:52:03 +00:00
|
|
|
|
2013-10-11 12:03:55 +00:00
|
|
|
#import "Logging.h"
|
|
|
|
|
2022-06-21 06:32:40 +00:00
|
|
|
#import "SandboxBroker.h"
|
|
|
|
|
2022-06-15 23:47:43 +00:00
|
|
|
static void *kFileTreeDataSourceContext = &kFileTreeDataSourceContext;
|
|
|
|
|
2021-04-30 01:16:24 +00:00
|
|
|
static NSURL *defaultMusicDirectory(void) {
|
2022-02-07 05:49:27 +00:00
|
|
|
return [[NSFileManager defaultManager] URLForDirectory:NSMusicDirectory
|
|
|
|
inDomain:NSUserDomainMask
|
|
|
|
appropriateForURL:nil
|
|
|
|
create:NO
|
|
|
|
error:nil];
|
2021-01-30 23:14:08 +00:00
|
|
|
}
|
|
|
|
|
2022-02-07 05:49:27 +00:00
|
|
|
@interface FileTreeDataSource ()
|
2007-10-18 02:52:03 +00:00
|
|
|
|
2021-01-30 23:14:08 +00:00
|
|
|
@property NSURL *rootURL;
|
|
|
|
|
2022-06-21 06:32:40 +00:00
|
|
|
@property const void *sbHandle;
|
|
|
|
|
2021-01-30 23:14:08 +00:00
|
|
|
@end
|
|
|
|
|
|
|
|
@implementation FileTreeDataSource {
|
2022-02-07 05:49:27 +00:00
|
|
|
PathNode *rootNode;
|
2022-06-21 06:32:40 +00:00
|
|
|
const void *_sbHandle;
|
2021-01-30 23:14:08 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
+ (void)initialize {
|
2022-02-07 05:49:27 +00:00
|
|
|
NSString *path = [defaultMusicDirectory() absoluteString];
|
|
|
|
NSDictionary *userDefaultsValuesDict = @{ @"fileTreeRootURL": path };
|
|
|
|
[[NSUserDefaults standardUserDefaults] registerDefaults:userDefaultsValuesDict];
|
2021-01-30 23:14:08 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
- (void)awakeFromNib {
|
2022-06-21 06:32:40 +00:00
|
|
|
_sbHandle = NULL;
|
2022-02-07 05:49:27 +00:00
|
|
|
[self.pathControl setTarget:self];
|
|
|
|
[self.pathControl setAction:@selector(pathControlAction:)];
|
|
|
|
[[NSUserDefaultsController sharedUserDefaultsController] addObserver:self
|
|
|
|
forKeyPath:@"values.fileTreeRootURL"
|
|
|
|
options:NSKeyValueObservingOptionNew |
|
|
|
|
NSKeyValueObservingOptionInitial
|
2022-06-15 23:47:43 +00:00
|
|
|
context:kFileTreeDataSourceContext];
|
2021-01-30 23:14:08 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
- (void)observeValueForKeyPath:(NSString *)keyPath
|
|
|
|
ofObject:(id)object
|
|
|
|
change:(NSDictionary *)change
|
|
|
|
context:(void *)context {
|
2022-06-15 23:47:43 +00:00
|
|
|
if(context == kFileTreeDataSourceContext) {
|
|
|
|
if([keyPath isEqualToString:@"values.fileTreeRootURL"]) {
|
|
|
|
NSString *url =
|
|
|
|
[[[NSUserDefaultsController sharedUserDefaultsController] defaults] objectForKey:@"fileTreeRootURL"];
|
|
|
|
DLog(@"File tree root URL: %@\n", url);
|
|
|
|
self.rootURL = [NSURL URLWithString:url];
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
[super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
|
2022-02-07 05:49:27 +00:00
|
|
|
}
|
2021-01-30 23:14:08 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
- (void)changeURL:(NSURL *)url {
|
2022-02-07 05:49:27 +00:00
|
|
|
if(url != nil) {
|
|
|
|
[[[NSUserDefaultsController sharedUserDefaultsController] defaults] setObject:[url absoluteString]
|
|
|
|
forKey:@"fileTreeRootURL"];
|
|
|
|
}
|
2007-10-18 02:52:03 +00:00
|
|
|
}
|
|
|
|
|
2021-01-30 23:14:08 +00:00
|
|
|
- (void)pathControlAction:(id)sender {
|
2022-02-07 05:49:27 +00:00
|
|
|
NSPathControlItem *item = [self.pathControl clickedPathItem];
|
|
|
|
if(item != nil && item.URL != nil) {
|
|
|
|
[self changeURL:item.URL];
|
|
|
|
}
|
2021-01-30 23:14:08 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
- (NSURL *)rootURL {
|
2022-02-07 05:49:27 +00:00
|
|
|
return [rootNode URL];
|
2021-01-30 23:14:08 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
- (void)setRootURL:(NSURL *)rootURL {
|
2022-06-21 06:32:40 +00:00
|
|
|
SandboxBroker *sharedSandboxBroker = [SandboxBroker sharedSandboxBroker];
|
|
|
|
if(self.sbHandle) [sharedSandboxBroker endFolderAccess:self.sbHandle];
|
|
|
|
self.sbHandle = [sharedSandboxBroker beginFolderAccess:rootURL];
|
|
|
|
|
2022-02-07 05:49:27 +00:00
|
|
|
if(![[NSFileManager defaultManager] fileExistsAtPath:[rootURL path]]) {
|
|
|
|
rootURL = defaultMusicDirectory();
|
|
|
|
}
|
2007-10-18 02:52:03 +00:00
|
|
|
|
2022-02-07 05:49:27 +00:00
|
|
|
rootNode = [[DirectoryNode alloc] initWithDataSource:self url:rootURL];
|
2021-01-30 23:14:08 +00:00
|
|
|
|
2022-02-07 05:49:27 +00:00
|
|
|
[self.watcher setPath:[rootURL path]];
|
2021-01-30 23:14:08 +00:00
|
|
|
|
2022-02-07 05:49:27 +00:00
|
|
|
[self reloadPathNode:rootNode];
|
2007-10-18 02:52:03 +00:00
|
|
|
}
|
|
|
|
|
2022-06-21 06:32:40 +00:00
|
|
|
- (const void *)sbHandle {
|
|
|
|
return _sbHandle;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void)setSbHandle:(const void *)sbHandle {
|
|
|
|
_sbHandle = sbHandle;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void)dealloc {
|
|
|
|
if(self.sbHandle) [[SandboxBroker sharedSandboxBroker] endFolderAccess:self.sbHandle];
|
|
|
|
}
|
|
|
|
|
2021-01-30 23:14:08 +00:00
|
|
|
- (PathNode *)nodeForPath:(NSString *)path {
|
2022-02-07 05:49:27 +00:00
|
|
|
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;
|
2021-01-30 23:14:08 +00:00
|
|
|
}
|
2007-10-18 02:52:03 +00:00
|
|
|
|
2021-01-30 23:14:08 +00:00
|
|
|
- (void)pathDidChange:(NSString *)path {
|
2022-02-07 05:49:27 +00:00
|
|
|
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];
|
2007-10-18 02:52:03 +00:00
|
|
|
}
|
|
|
|
|
2021-01-30 23:14:08 +00:00
|
|
|
- (NSInteger)outlineView:(NSOutlineView *)outlineView numberOfChildrenOfItem:(id)item {
|
2022-02-07 05:49:27 +00:00
|
|
|
PathNode *n = (item == nil ? rootNode : item);
|
2007-10-18 02:52:03 +00:00
|
|
|
|
2022-02-07 05:49:27 +00:00
|
|
|
return (int)[[n subpaths] count];
|
2007-10-18 02:52:03 +00:00
|
|
|
}
|
|
|
|
|
2021-01-30 23:14:08 +00:00
|
|
|
- (BOOL)outlineView:(NSOutlineView *)outlineView isItemExpandable:(id)item {
|
2022-02-07 05:49:27 +00:00
|
|
|
PathNode *n = (item == nil ? rootNode : item);
|
2007-10-18 02:52:03 +00:00
|
|
|
|
2022-02-07 05:49:27 +00:00
|
|
|
return ![n isLeaf];
|
2021-01-30 23:14:08 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
- (id)outlineView:(NSOutlineView *)outlineView child:(NSInteger)index ofItem:(id)item {
|
2022-02-07 05:49:27 +00:00
|
|
|
PathNode *n = (item == nil ? rootNode : item);
|
2021-01-30 23:14:08 +00:00
|
|
|
|
2022-02-07 05:49:27 +00:00
|
|
|
return [n subpaths][(NSUInteger)index];
|
2021-01-30 23:14:08 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
- (id)outlineView:(NSOutlineView *)outlineView objectValueForTableColumn:(NSTableColumn *)tableColumn byItem:(id)item {
|
2022-02-07 05:49:27 +00:00
|
|
|
PathNode *n = (item == nil ? rootNode : item);
|
2021-01-30 23:14:08 +00:00
|
|
|
|
2022-02-07 05:49:27 +00:00
|
|
|
return n;
|
2021-01-30 23:14:08 +00:00
|
|
|
}
|
2007-10-18 02:52:03 +00:00
|
|
|
|
2022-02-07 05:49:27 +00:00
|
|
|
- (id<NSPasteboardWriting>)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;
|
2007-10-18 02:52:03 +00:00
|
|
|
}
|
|
|
|
|
2021-01-30 23:14:08 +00:00
|
|
|
- (void)reloadPathNode:(PathNode *)item {
|
2022-02-07 05:49:27 +00:00
|
|
|
if(item == rootNode) {
|
|
|
|
[self.outlineView reloadData];
|
|
|
|
} else {
|
|
|
|
[self.outlineView reloadItem:item reloadChildren:YES];
|
|
|
|
}
|
2007-10-18 02:52:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
@end
|