[Path Suggester] Automatically pop where required

The Path Suggester will now automatically open when new files are added
to the playlist and a given path is not in the sandbox settings. It will
also pop for both the File Tree and MIDI SoundFont path configuration
settings being changed.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
lastfm
Christopher Snowhill 2022-06-24 00:29:50 -07:00
parent b6621da410
commit ba33218ddf
17 changed files with 138 additions and 30 deletions

View File

@ -7,6 +7,7 @@
@class PlaylistController;
@class PlaylistView;
@class PlaylistLoader;
@class PreferencesController;
@interface AppController : NSObject {
IBOutlet NSObjectController *currentEntryController;
@ -47,6 +48,8 @@
IBOutlet FileTreeViewController *fileTreeViewController;
IBOutlet PreferencesController *preferencesController;
NSOperationQueue *queue; // Since we are the app delegate, we take care of the op queue
NSMutableSet *expandedNodes;
@ -94,6 +97,9 @@
- (IBAction)toggleMiniMode:(id)sender;
- (IBAction)toggleToolbarStyle:(id)sender;
- (void)showPathSuggester;
+ (void)globalShowPathSuggester;
@property NSWindow *mainWindow;
@property NSWindow *miniWindow;

View File

@ -28,12 +28,16 @@
#import "Shortcuts.h"
#import <MASShortcut/Shortcut.h>
#import "PreferencesController.h"
@import Firebase;
void *kAppControllerContext = &kAppControllerContext;
BOOL kAppControllerShuttingDown = NO;
static AppController *kAppController = nil;
@implementation AppController {
BOOL _isFullToolbarStyle;
}
@ -70,6 +74,8 @@ BOOL kAppControllerShuttingDown = NO;
[self initDefaults];
queue = [[NSOperationQueue alloc] init];
kAppController = self;
}
return self;
@ -705,4 +711,12 @@ BOOL kAppControllerShuttingDown = NO;
}
}
- (void)showPathSuggester {
[preferencesController showPathSuggester:self];
}
+ (void)globalShowPathSuggester {
[kAppController showPathSuggester];
}
@end

View File

@ -25,17 +25,17 @@
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<splitView dividerStyle="thin" vertical="YES" translatesAutoresizingMaskIntoConstraints="NO" id="2123">
<rect key="frame" x="0.0" y="353" width="1015" height="47"/>
<rect key="frame" x="0.0" y="371" width="1030" height="29"/>
<subviews>
<scrollView fixedFrame="YES" borderType="none" autohidesScrollers="YES" horizontalLineScroll="24" horizontalPageScroll="0.0" verticalLineScroll="24" verticalPageScroll="0.0" hasHorizontalScroller="NO" usesPredominantAxisScrolling="NO" id="206" userLabel="Scroll View - Playlist View">
<rect key="frame" x="0.0" y="0.0" width="1015" height="46"/>
<rect key="frame" x="0.0" y="0.0" width="1030" height="29"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<clipView key="contentView" drawsBackground="NO" copiesOnScroll="NO" id="KWC-Ti-8KY">
<rect key="frame" x="0.0" y="0.0" width="1015" height="46"/>
<autoresizingMask key="autoresizingMask"/>
<rect key="frame" x="0.0" y="0.0" width="1030" height="29"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<tableView focusRingType="none" verticalHuggingPriority="750" allowsExpansionToolTips="YES" alternatingRowBackgroundColors="YES" autosaveName="Playlist" rowHeight="18" headerView="1517" viewBased="YES" id="207" customClass="PlaylistView">
<rect key="frame" x="0.0" y="0.0" width="1015" height="29"/>
<rect key="frame" x="0.0" y="0.0" width="1030" height="12"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<size key="intercellSpacing" width="3" height="6"/>
<color key="backgroundColor" name="controlBackgroundColor" catalog="System" colorSpace="catalog"/>
@ -229,7 +229,7 @@
<tableColumnResizingMask key="resizingMask" resizeWithTable="YES" userResizable="YES"/>
<prototypeCellViews>
<tableCellView id="gpC-Oe-Rog">
<rect key="frame" x="234.5" y="3" width="149.5" height="18"/>
<rect key="frame" x="235" y="3" width="149" height="18"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" translatesAutoresizingMaskIntoConstraints="NO" id="1WK-qN-Mgj">
@ -316,7 +316,7 @@
<tableColumnResizingMask key="resizingMask" resizeWithTable="YES" userResizable="YES"/>
<prototypeCellViews>
<tableCellView id="hhB-nv-e78">
<rect key="frame" x="540.5" y="3" width="95.5" height="18"/>
<rect key="frame" x="541" y="3" width="95" height="18"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" translatesAutoresizingMaskIntoConstraints="NO" id="tHy-sM-HDB">
@ -401,7 +401,7 @@
<tableColumnResizingMask key="resizingMask" resizeWithTable="YES" userResizable="YES"/>
<prototypeCellViews>
<tableCellView id="rRl-p9-Awr">
<rect key="frame" x="735.5" y="3" width="144" height="18"/>
<rect key="frame" x="736" y="3" width="144" height="18"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" translatesAutoresizingMaskIntoConstraints="NO" id="yW6-2w-6mN">
@ -441,7 +441,7 @@
<tableColumnResizingMask key="resizingMask" resizeWithTable="YES" userResizable="YES"/>
<prototypeCellViews>
<tableCellView id="hgh-VE-5kl">
<rect key="frame" x="882.5" y="3" width="38.5" height="18"/>
<rect key="frame" x="883" y="3" width="38" height="18"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" translatesAutoresizingMaskIntoConstraints="NO" id="yEY-MI-d3o">
@ -628,7 +628,7 @@
<autoresizingMask key="autoresizingMask"/>
</scroller>
<tableHeaderView key="headerView" wantsLayer="YES" id="1517">
<rect key="frame" x="0.0" y="0.0" width="1015" height="17"/>
<rect key="frame" x="0.0" y="0.0" width="1030" height="17"/>
<autoresizingMask key="autoresizingMask"/>
</tableHeaderView>
</scrollView>
@ -641,7 +641,7 @@
</connections>
</splitView>
<textField verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="778">
<rect key="frame" x="377" y="4" width="261" height="14"/>
<rect key="frame" x="385" y="4" width="261" height="14"/>
<textFieldCell key="cell" controlSize="small" lineBreakMode="truncatingTail" sendsActionOnEndEditing="YES" alignment="center" title="Total Duration: 00 hours 00 minutes 00 seconds" bezelStyle="round" id="1473">
<font key="font" metaFont="controlContent" size="11"/>
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
@ -1970,6 +1970,7 @@ Gw
</declaredKeys>
<classReference key="objectClass" className="PlaylistEntry"/>
<connections>
<outlet property="appController" destination="226" id="lmS-HT-dqn"/>
<outlet property="playbackController" destination="705" id="2121"/>
<outlet property="playlistLoader" destination="1319" id="1321"/>
<outlet property="spotlightWindowController" destination="1675" id="1709"/>
@ -2004,6 +2005,7 @@ Gw
<outlet property="playlistController" destination="218" id="236"/>
<outlet property="playlistLoader" destination="1319" id="1322"/>
<outlet property="playlistView" destination="207" id="1257"/>
<outlet property="preferencesController" destination="1217" id="cps-Ql-RlL"/>
<outlet property="randomizeButton" destination="2467" id="swo-wn-Yr8"/>
<outlet property="repeatButton" destination="1640" id="twI-AO-RJG"/>
<outlet property="showAlbumColumn" destination="1340" id="1350"/>

View File

@ -1025,6 +1025,7 @@
8399D4E11805A55000B503B1 /* XmlContainer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = XmlContainer.h; sourceTree = "<group>"; };
839DA7CB274A2D4C001B18E5 /* NSDictionary+Merge.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSDictionary+Merge.h"; sourceTree = "<group>"; };
839DA7CE274A2D4C001B18E5 /* NSDictionary+Merge.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSDictionary+Merge.m"; sourceTree = "<group>"; };
839E3B53286595D700880EA2 /* GeneralPane.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = GeneralPane.h; path = Preferences/Preferences/GeneralPane.h; sourceTree = "<group>"; };
83A3B72F283AE6AA00CC6593 /* ColorToValueTransformer.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = ColorToValueTransformer.m; path = Preferences/Preferences/ColorToValueTransformer.m; sourceTree = "<group>"; };
83A3B733283AE6AA00CC6593 /* ColorToValueTransformer.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = ColorToValueTransformer.h; path = Preferences/Preferences/ColorToValueTransformer.h; sourceTree = "<group>"; };
83AA7D00279EBC8200087AA4 /* libavcodec.59.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libavcodec.59.dylib; path = ThirdParty/ffmpeg/lib/libavcodec.59.dylib; sourceTree = "<group>"; };
@ -1883,6 +1884,7 @@
8E07AAEA0AAC90DC00A4B32F /* Preferences */ = {
isa = PBXGroup;
children = (
839E3B53286595D700880EA2 /* GeneralPane.h */,
ED69CF0925BE74BB0090B90D /* Shortcuts.h */,
17D1B2610F633D2C00694C57 /* PreferencePanePlugin.h */,
17D1B25B0F633A4F00694C57 /* PreferencePluginController.h */,

View File

@ -15,6 +15,8 @@
#import "SandboxBroker.h"
#import "AppController.h"
static void *kFileTreeDataSourceContext = &kFileTreeDataSourceContext;
static NSURL *defaultMusicDirectory(void) {
@ -75,6 +77,10 @@ static NSURL *defaultMusicDirectory(void) {
if(url != nil) {
[[[NSUserDefaultsController sharedUserDefaultsController] defaults] setObject:[url absoluteString]
forKey:@"fileTreeRootURL"];
if(![[SandboxBroker sharedSandboxBroker] areAllPathsSafe:@[url]]) {
[AppController globalShowPathSuggester];
}
}
}

View File

@ -18,6 +18,7 @@
@class PlaylistEntry;
@class SpotlightWindowController;
@class PlaybackController;
@class AppController;
typedef NS_ENUM(NSInteger, RepeatMode) {
RepeatModeNoRepeat = 0,
@ -43,6 +44,7 @@ typedef NS_ENUM(NSInteger, URLOrigin) {
IBOutlet PlaylistLoader *playlistLoader;
IBOutlet SpotlightWindowController *spotlightWindowController;
IBOutlet PlaybackController *playbackController;
IBOutlet AppController *appController;
NSValueTransformer *statusImageTransformer;

View File

@ -23,6 +23,9 @@
#import "Cog-Swift.h"
#import "AppController.h"
#import "SandboxBroker.h"
#define UNDO_STACK_LIMIT 0
extern BOOL kAppControllerShuttingDown;
@ -1677,6 +1680,11 @@ static void *playlistControllerContext = &playlistControllerContext;
[self firstSawTrack:pe];
}
NSArray *nsurls = [urls valueForKey:@"url"];
if(![[SandboxBroker sharedSandboxBroker] areAllPathsSafe:nsurls]) {
[appController showPathSuggester];
}
CGEventRef event = CGEventCreate(NULL);
CGEventFlags mods = CGEventGetFlags(event);
CFRelease(event);

View File

@ -17,6 +17,9 @@
@property(readonly, copy) NSString *title;
@property(readonly) NSImage *icon;
@optional
- (IBAction)showPathSuggester:(id)sender;
@end
@protocol PreferencePanePlugin <NSObject>

View File

@ -8,6 +8,10 @@
#import "MIDIPane.h"
#import "SandboxBroker.h"
#import "AppController.h"
@implementation MIDIPane
- (NSString *)title {
@ -34,6 +38,13 @@
NSInteger result = [panel runModal];
if(result == NSModalResponseOK) {
[[NSUserDefaults standardUserDefaults] setValue:[[panel URL] path] forKey:@"soundFontPath"];
id sandboxBrokerClass = NSClassFromString(@"SandboxBroker");
NSURL *pathUrl = [panel URL];
if(![[sandboxBrokerClass sharedSandboxBroker] areAllPathsSafe:@[pathUrl]]) {
id appControllerClass = NSClassFromString(@"AppController");
[appControllerClass globalShowPathSuggester];
}
}
}

View File

@ -95,8 +95,21 @@ static NSURL *defaultMoviesDirectory(void) {
NSMutableArray *items = [[NSMutableArray alloc] init];
NSMutableArray *itemPaths = [[NSMutableArray alloc] init];
for(PlaylistEntry *pe in results) {
NSURL *url = [sandboxBrokerClass urlWithoutFragment:pe.url];
NSMutableArray *array = [[results valueForKey:@"url"] mutableCopy];
// Add other system paths to this setting
NSString *fileTreePath = [[NSUserDefaults standardUserDefaults] stringForKey:@"fileTreeRootURL"];
if(fileTreePath && [fileTreePath length]) {
[array addObject:[NSURL URLWithString:fileTreePath]];
}
NSString *soundFontPath = [[NSUserDefaults standardUserDefaults] stringForKey:@"soundFontPath"];
if(soundFontPath && [soundFontPath length]) {
[array addObject:[NSURL fileURLWithPath:soundFontPath]];
}
for(NSURL *fileUrl in array) {
NSURL *url = [sandboxBrokerClass urlWithoutFragment:fileUrl];
if([sandboxBrokerClass isPath:url aSubdirectoryOf:defaultMusic] ||
[sandboxBrokerClass isPath:url
aSubdirectoryOf:defaultDownloads] ||

View File

@ -116,6 +116,7 @@
837C0D3F1C50954000CAE18F /* MIDIPluginBehaviorArrayController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MIDIPluginBehaviorArrayController.m; sourceTree = "<group>"; };
8384913618081ECB00E7332D /* Logging.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Logging.h; path = ../../Utils/Logging.h; sourceTree = "<group>"; };
8384917518084D9F00E7332D /* appearance.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = appearance.png; path = Icons/appearance.png; sourceTree = "<group>"; };
839E3B5728659B2700880EA2 /* AppController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AppController.h; path = ../../Application/AppController.h; sourceTree = "<group>"; };
83A3B72A283AE04800CC6593 /* ColorToValueTransformer.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ColorToValueTransformer.h; sourceTree = "<group>"; };
83A3B72B283AE04800CC6593 /* ColorToValueTransformer.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ColorToValueTransformer.m; sourceTree = "<group>"; };
83AC57372861A54D009D6F50 /* PathSuggester.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = PathSuggester.h; sourceTree = "<group>"; };
@ -202,6 +203,7 @@
08FB77AFFE84173DC02AAC07 /* Classes */ = {
isa = PBXGroup;
children = (
839E3B5728659B2700880EA2 /* AppController.h */,
83AC573E2861B77E009D6F50 /* SandboxBroker.h */,
8307D30828604ECF000FF8EB /* PlaylistController.h */,
83F27E711810E41A00CEF538 /* Transformers */,
@ -287,7 +289,6 @@
32C88E010371C26100C91783 /* Other Sources */ = {
isa = PBXGroup;
children = (
8363BABF284E450E00E5C9DD /* pffft.h */,
ED69CF0B25BE75330090B90D /* Shortcuts.h */,
32DBCF630370AF2F00C91783 /* Preferences_Prefix.pch */,
);

View File

@ -14,5 +14,6 @@
}
- (IBAction)showPreferences:(id)sender;
- (IBAction)showPathSuggester:(id)sender;
@end

View File

@ -12,7 +12,7 @@
@implementation PreferencesController
- (IBAction)showPreferences:(id)sender {
- (void)initWindow {
if(nil == window) {
// Determine path to the sample preference panes
NSString *pluginPath = [[NSBundle mainBundle] pathForResource:@"Preferences" ofType:@"preferencePane"];
@ -22,9 +22,20 @@
window = [[PreferencesWindow alloc] initWithPreferencePanes:[pluginController preferencePanes]];
}
}
- (IBAction)showPreferences:(id)sender {
[self initWindow];
// Show the preferences window.
[window show];
}
- (IBAction)showPathSuggester:(id)sender {
[self initWindow];
// Show the path suggester
[window showPathSuggester];
}
@end

View File

@ -22,5 +22,6 @@
defer:(BOOL)flag NS_UNAVAILABLE;
- (void)show;
- (void)showPathSuggester;
@end

View File

@ -151,6 +151,19 @@
[self makeKeyAndOrderFront:self];
}
- (void)showPathSuggester {
NSString *name = NSLocalizedPrefString(@"General");
[self loadPaneNamed:name display:NO];
[self makeKeyAndOrderFront:self];
id<PreferencePane> pane = preferencePanes[name];
if(pane && [pane respondsToSelector:@selector(showPathSuggester:)]) {
[pane showPathSuggester:self];
}
}
// Close on Esc pressed.
- (void)cancelOperation:(id)sender {
[self close];

View File

@ -24,6 +24,8 @@ NS_ASSUME_NONNULL_BEGIN
- (const void *)beginFolderAccess:(NSURL *)fileUrl;
- (void)endFolderAccess:(const void *)handle;
- (BOOL)areAllPathsSafe:(NSArray *)urls;
@end
NS_ASSUME_NONNULL_END

View File

@ -151,13 +151,6 @@ static inline void dispatch_sync_reentrant(dispatch_queue_t queue, dispatch_bloc
}
- (SandboxEntry *)recursivePathTest:(NSURL *)url {
for(SandboxEntry *entry in storage) {
if(entry.path && [SandboxBroker isPath:url aSubdirectoryOf:[NSURL fileURLWithPath:entry.path]]) {
entry.refCount += 1;
return entry;
}
}
__block SandboxEntry *ret = nil;
dispatch_sync_reentrant(dispatch_get_main_queue(), ^{
@ -194,10 +187,6 @@ static inline void dispatch_sync_reentrant(dispatch_queue_t queue, dispatch_bloc
ret.secureUrl = secureUrl;
[storage addObject:ret];
[secureUrl startAccessingSecurityScopedResource];
return ret;
}
@ -208,14 +197,28 @@ static inline void dispatch_sync_reentrant(dispatch_queue_t queue, dispatch_bloc
NSURL *folderUrl = [[SandboxBroker urlWithoutFragment:fileUrl] URLByDeletingLastPathComponent];
if(![folderUrl isFileURL]) return NULL;
SandboxEntry *entry;
SandboxEntry *_entry = nil;
@synchronized(self) {
entry = [self recursivePathTest:folderUrl];
for(SandboxEntry *entry in storage) {
if(entry.path && [SandboxBroker isPath:folderUrl aSubdirectoryOf:[NSURL fileURLWithPath:entry.path]]) {
entry.refCount += 1;
_entry = entry;
break;
}
}
if(!_entry) {
_entry = [self recursivePathTest:folderUrl];
}
}
if(entry) {
return CFBridgingRetain(entry);
if(_entry) {
[storage addObject:_entry];
[_entry.secureUrl startAccessingSecurityScopedResource];
return CFBridgingRetain(_entry);
} else {
return NULL;
}
@ -242,4 +245,13 @@ static inline void dispatch_sync_reentrant(dispatch_queue_t queue, dispatch_bloc
}
}
- (BOOL)areAllPathsSafe:(NSArray *)urls {
for(NSURL *url in urls) {
if(![self recursivePathTest:url]) {
return NO;
}
}
return YES;
}
@end