Ограничить доступ к определенным папкам с помощью 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.
}
Другие вопросы по тегам