[File Tree] Significantly improve the watcher

- Switch to fine grained folder and file watching responses
- Navigate the PathNode tree using a fast dictionary of path components
- Quickly refresh the file tree by locating parent nodes to refresh

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
main
Christopher Snowhill 2022-07-06 22:39:47 -07:00
parent 1c3717eb84
commit da053d7282
6 changed files with 64 additions and 20 deletions

View File

@ -130,34 +130,40 @@ static NSURL *defaultMusicDirectory(void) {
withString:@""
options:NSAnchoredSearch
range:NSMakeRange(0, [path length])] stringByStandardizingPath];
if([relativePath isEqualToString:[[self rootURL] path]])
relativePath = @"";
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;
}
PathNode *subnode = [[node subpathsLookup] objectForKey:c];
if(!subnode) return nil;
node = subnode;
}
return node;
}
- (void)pathDidChange:(NSString *)path {
- (void)pathDidChange:(NSString *)path flags:(FSEventStreamEventFlags)flags {
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];
PathNode *node;
do {
node = [self nodeForPath:path];
path = [path stringByDeletingLastPathComponent];
if(!path || [path length] < 2) return;
} while(!node);
if(flags & kFSEventStreamEventFlagItemRemoved) {
DLog(@"Removing node: %@", node);
PathNode *parentNode = [self nodeForPath:path];
[parentNode updatePath];
[self reloadPathNode:parentNode];
} else {
DLog(@"NODE IS: %@", node);
[node updatePath];
[self reloadPathNode:node];
}
}
- (NSInteger)outlineView:(NSOutlineView *)outlineView numberOfChildrenOfItem:(id)item {

View File

@ -16,9 +16,13 @@
NSURL *url;
NSString *display; // The pretty path to display.
NSString *lastPathComponent;
NSImage *icon;
NSArray *subpaths;
NSMutableDictionary *subpathsLookup;
}
- (id)initWithDataSource:(FileTreeDataSource *)ds url:(NSURL *)u;
@ -34,6 +38,12 @@
- (NSString *)display;
- (void)setDisplay:(NSString *)s;
- (NSString *)lastPathComponent;
- (void)setLastPathComponent:(NSString *)s;
- (NSDictionary *)subpathsLookup;
- (void)setSubpathsLookup:(NSMutableDictionary *)d;
- (NSImage *)icon;
- (BOOL)isLeaf;

View File

@ -60,6 +60,8 @@ NSURL *resolveAliases(NSURL *url) {
display = [[NSFileManager defaultManager] displayNameAtPath:[u path]];
lastPathComponent = [[u path] lastPathComponent];
icon = [[NSWorkspace sharedWorkspace] iconForFile:[url path]];
[icon setSize:NSMakeSize(16.0, 16.0)];
@ -134,6 +136,19 @@ NSURL *resolveAliases(NSURL *url) {
- (void)setSubpaths:(NSArray *)s {
subpaths = s;
subpathsLookup = [[NSMutableDictionary alloc] init];
for(PathNode *node in s) {
[subpathsLookup setObject:node forKey:node.lastPathComponent];
}
}
- (NSDictionary *)subpathsLookup {
return subpathsLookup;
}
- (void)setSubpathsLookup:(NSMutableDictionary *)d {
subpathsLookup = d;
}
- (BOOL)isLeaf {
@ -152,4 +167,12 @@ NSURL *resolveAliases(NSURL *url) {
return icon;
}
- (NSString *)lastPathComponent {
return lastPathComponent;
}
- (void)setLastPathComponent:(NSString *)s {
lastPathComponent = s;
}
@end

View File

@ -25,6 +25,6 @@
@protocol PathWatcherDelegate
- (void)pathDidChange:(NSString *)path;
- (void)pathDidChange:(NSString *)path flags:(FSEventStreamEventFlags)flags;
@end

View File

@ -22,7 +22,7 @@ const FSEventStreamEventId eventIds[]) {
printf("Callback called\n");
for(i = 0; i < numEvents; i++) {
NSString *pathString = [[NSString alloc] initWithUTF8String:paths[i]];
[[pathWatcher delegate] pathDidChange:pathString];
[[pathWatcher delegate] pathDidChange:pathString flags:eventFlags[i]];
}
}
@ -62,7 +62,7 @@ const FSEventStreamEventId eventIds[]) {
(__bridge CFArrayRef)pathsToWatch,
kFSEventStreamEventIdSinceNow, // Or a previous event ID
1.0, // latency in seconds
kFSEventStreamCreateFlagNone // Watch this and all its subdirectories
kFSEventStreamCreateFlagFileEvents // Watch this and all its subdirectories
);
FSEventStreamScheduleWithRunLoop(stream, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);

View File

@ -41,6 +41,11 @@
- (void)setSubpaths:(id)s {
subpaths = s;
subpathsLookup = [[NSMutableDictionary alloc] init];
for(PathNode *node in s) {
[subpathsLookup setObject:node forKey:node.lastPathComponent];
}
}
- (unsigned int)countOfSubpaths {