Ограничить доступ к определенным папкам с помощью NSOpenPanel
Я использую NSOpenPanel, чтобы позволить пользователю выбрать папку для сохранения документов. Я хотел бы ограничить, в какую папку (с точки зрения иерархии) они могут сохранить. По сути, я хочу помешать им выбрать любую папку выше:
/Users/ имя пользователя /
Итак, папка
/Users/ имя пользователя / Кошки /
было бы приемлемо, но
/Users/ имя пользователя /
/ Применение / Кошки /
не будет позволено Мне было интересно, как реализовать это ограничение.
Благодарю.
2 ответа
Обратите внимание, что NSOpenPanel
наследуется от NSSavePanel
который, в свою очередь, определяет делегата и соответствующий протокол делегата NSOpenSavePanelDelegate
, Вы можете использовать делегата, чтобы расширить поведение открытой панели, чтобы включить ограничение, которое вы указали в своем вопросе.
Например, предполагая, что делегат приложения реализует ограничение открытой панели, приведите его в соответствие с NSOpenSavePanelDelegate
протокол:
@interface AppDelegate : NSObject <NSApplicationDelegate, NSOpenSavePanelDelegate>
@end
В реализации вашего делегата приложения скажите открытой панели, что делегат приложения действует как делегат открытой панели:
NSOpenPanel *openPanel = [NSOpenPanel openPanel];
[openPanel setDirectory:NSHomeDirectory()];
[openPanel setCanChooseDirectories:NO];
[openPanel setDelegate:self];
[openPanel runModal];
И реализовать следующие методы делегата:
- (BOOL)panel:(id)sender shouldEnableURL:(NSURL *)url {
NSString *path = [url path];
NSString *homeDir = NSHomeDirectory();
return [path hasPrefix:homeDir] && ! [path isEqualToString:homeDir];
}
- (void)panel:(id)sender didChangeToDirectoryURL:(NSURL *)url {
NSString *path = [url path];
NSString *homeDir = NSHomeDirectory();
// If the user has changed to a non home directory, send him back home!
if (! [path hasPrefix:homeDir]) [sender setDirectory:homeDir];
}
- (BOOL)panel:(id)sender validateURL:(NSURL *)url error:(NSError **)outError {
NSString *path = [url path];
NSString *homeDir = NSHomeDirectory();
if (![path hasPrefix:homeDir]) {
if (outError)
*outError = ; // create an appropriate NSError instance
return NO;
}
return YES;
}
Итак, я попытался обновить это для Swift 5.5.
Я включаю все методы делегата для ясности для всех, кто наткнется на это.
class Utility {
var homeDirectory: URL?
func openPanel(url: URL, sender: Any) -> URL? {
let openPanel = NSOpenPanel()
openPanel.canChooseDirectories = true
openPanel.canChooseFiles = false
openPanel.delegate = self
appHomeDirectory = url
openPanel.directoryURL = homeDirectory
openPanel.showsHiddenFiles = false
openPanel.canCreateDirectories = true
switch openPanel.runModal() {
case .OK:
print("OK")
case .cancel:
print("Cancel")
case .abort:
print("Abort")
case .continue:
print("Continue")
case .stop:
print("Stop")
default:
print("Unknown Response")
}
return nil
}
func panel(_ sender: Any, didChangeToDirectoryURL url: URL?) {
guard let _url = url else {
return
}
print("didChangeToDirectoryURL")
print("url: \(_url)")
}
func panel(_ sender: Any, shouldEnable url: URL) -> Bool {
guard let homeDirectory = self.homeDirectory else {
// Since homeDirectory cannot be set
return false
}
print("shouldEnable")
print("url path: \(url.path)")
print("homeDirectory path: \(homeDirectory.path)")
print("url.path.hasSuffix(homeDirectory.path): \(url.path.hasSuffix(homeDirectory.path))")
// Removing the last path component of the sent URL
print("url.deletingLastPathComponent().path.hasSuffix(homeDirectory.path): \(url.deletingLastPathComponent().path.hasSuffix(homeDirectory.path))")
if url == homeDirectory {
// This ensures the user can get back into the homeDirectory if
// they navigated above the homeDirectory.
return true
} else {
// Delete the last path component and then compare if the suffix of the url
// path is the same as the homeDirectory path and return result.
return (url.deletingLastPathComponent().path.hasSuffix(homeDirectory.path))
}
}
func panel(_ sender: Any, validate url: URL) throws {
print("validate")
print("url: \(url)")
}
func panel(_ sender: Any, willExpand expanding: Bool) {
print("willExpand")
print("expanding: \(expanding)")
}
func panelSelectionDidChange(_ sender: Any?) {
print("panelSelectionDidChange")
}
}
В моем ViewController у меня есть экземпляр «Utility» как «утилита» и IBAction для кнопки изображения, которая имеет идентификатор раскадровки «fileBrowseImageButton».
Применение:
@IBAction func fileBrowseImageButtonClicked(sender: Any?) {
guard let url = utility.openPanel(url: url, sender: sender as! NSButton) else {
return
}
// Do whatever needed with the returned url.
}