Let FSItem create finderTags when requested

This does mean that we are taxing our main thread with disk access. This is mainly a problem for users who are using network mounted file systems, but it does provide better abstraction in the code, and should this turn out to be a performance issue, I think a better approach is to fetch the tags in a dispatch queue (initiated by FSItem), and then use KVC to update the property once the tags have been loaded, although ideally such system would use some sort of batching, so that we do not dispatch in each property accessor.

Could also have the background directory scanner set a boolean property to indicate if the item has tags, as most items do not, and in that case, we can bypass the disk access. But this then only does half the job of encapsulating how tags are stored.
This commit is contained in:
Allan Odgaard
2018-07-08 17:51:37 +02:00
parent 11fa1841b3
commit fef19f8465
5 changed files with 24 additions and 10 deletions

View File

@@ -12,6 +12,7 @@ PUBLIC @interface OakFinderTag : NSObject
@end
PUBLIC @interface OakFinderTagManager : NSObject
+ (NSArray<OakFinderTag*>*)finderTagsForURL:(NSURL*)aURL;
+ (NSArray<OakFinderTag*>*)finderTagsFromData:(NSData*)data;
+ (NSColor*)backgroundColorForLabel:(NSUInteger)label;
+ (NSColor*)foregroundColorForLabel:(NSUInteger)label;

View File

@@ -1,6 +1,7 @@
#import "OakFinderTag.h"
#import <OakFoundation/OakFoundation.h>
#import <OakAppKit/NSColor Additions.h>
#import <io/path.h>
@implementation OakFinderTag
- (instancetype)initWithDisplayName:(NSString*)name label:(NSUInteger)label markedFavorite:(BOOL)markedFavorite
@@ -43,6 +44,20 @@ static struct label_colors_t { NSString* name; NSString* backgroundColor; NSStri
};
@implementation OakFinderTagManager
+ (NSArray<OakFinderTag*>*)finderTagsForURL:(NSURL*)aURL
{
if(aURL.filePathURL)
{
std::string const bplist = path::get_attr(aURL.fileSystemRepresentation, "com.apple.metadata:_kMDItemUserTags");
if(bplist != NULL_STR)
{
NSData* data = [NSData dataWithBytes:(void*)bplist.data() length:bplist.size()];
return [self finderTagsFromData:data];
}
}
return @[ ];
}
+ (NSArray<OakFinderTag*>*)finderTagsFromData:(NSData*)data
{
id plist = [NSPropertyListSerialization propertyListFromData:data mutabilityOption:NSPropertyListImmutable format:nil errorDescription:nil];

View File

@@ -105,8 +105,6 @@ struct tracking_t : fs::event_callback_t
{
fs_item_t (dev_t device, dirent const* entry, std::string const& path) : device(device), inode(entry->d_fileno), path(path), target(NULL_STR), is_directory(false), is_link(false), treat_as_directory(false), sort_as_directory(false)
{
tag_data = path::tag_data(path);
if(entry->d_type == DT_LNK)
{
std::string const resolved = path::resolve_head(path);
@@ -139,7 +137,6 @@ struct tracking_t : fs::event_callback_t
ino_t inode;
std::string path;
std::string target;
std::string tag_data;
bool is_directory;
bool is_link;
bool treat_as_directory;
@@ -255,9 +252,6 @@ struct tracking_t : fs::event_callback_t
if(allowExpandingLinks && fsItem.is_link && fsItem.sort_as_directory && item.leaf)
item.leaf = NO;
if(fsItem.tag_data != NULL_STR)
item.finderTags = [OakFinderTagManager finderTagsFromData:[NSData dataWithBytes:(void*)fsItem.tag_data.data() length:fsItem.tag_data.size()]];
[array addObject:item];
pathsOnDisk.insert(fsItem.path);
}

View File

@@ -3,6 +3,7 @@
#import <OakFoundation/NSString Additions.h>
#import <OakAppKit/OakFileIconImage.h>
#import <OakAppKit/OakFileManager.h>
#import <OakAppKit/OakFinderTag.h>
#import <OakAppKit/IOAlertPanel.h>
#import <ns/ns.h>
#import <io/path.h>
@@ -65,6 +66,13 @@ static ino_t inode (std::string const& path)
return [self.url path];
}
- (NSArray<OakFinderTag*>*)finderTags
{
if(!_finderTags)
_finderTags = [OakFinderTagManager finderTagsForURL:self.url];
return _finderTags;
}
- (scm::status::type)scmStatus
{
return [_icon isKindOfClass:[OakFileIconImage class]] ? ((OakFileIconImage*)_icon).scmStatus : scm::status::unknown;

View File

@@ -48,10 +48,6 @@ static NSArray* convert (std::map<std::string, scm::status::type> const& pathsMa
item.scmStatus = hideSCMBadge ? scm::status::none : pair.second;
item.missing = pair.second == scm::status::deleted;
std::string const tag_data = path::tag_data(pair.first);
if(tag_data != NULL_STR)
item.finderTags = [OakFinderTagManager finderTagsFromData:[NSData dataWithBytes:(void*)tag_data.data() length:tag_data.size()]];
[res addObject:item];
}
return res;