blob: b266af8aa1c87d7a86bc04c716f2373ec730da08 [file] [log] [blame]
// Copyright 2016 The Tulsi Authors. All rights reserved.
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// See the License for the specific language governing permissions and
// limitations under the License.
import Cocoa
/// Convenience subclass of NSOpenPanel that acts as its own delegate and applies a filtering
/// function for -panel:shouldEnableURL:.
class FilteredOpenPanel: NSOpenPanel, NSOpenSavePanelDelegate {
typealias FilterFunc = (_ sender: FilteredOpenPanel, _ shouldEnableURL: URL) -> Bool
var filterFunc: FilterFunc? = nil
static func filteredOpenPanel(_ filter: FilterFunc?) -> FilteredOpenPanel {
let panel = FilteredOpenPanel()
panel.filterFunc = filter
panel.delegate = panel
return panel
/// Creates a filtered NSOpenPanel that accepts any non-package directories and any files whose
/// last path component is in the given array of names.
static func filteredOpenPanelAcceptingNonPackageDirectoriesAndFilesNamed(_ names: [String]) -> FilteredOpenPanel {
return filteredOpenPanel(filterNonPackageDirectoriesOrFilesMatchingNames(names))
// MARK: - NSOpenSavePanelDelegate
func panel(_ sender: Any, shouldEnable url: URL) -> Bool {
return filterFunc?(self, url) ?? true
// MARK: - Internal methods
static func filterNonPackageDirectoriesOrFilesMatchingNames(_ validFiles: [String]) -> FilterFunc {
return { (sender: AnyObject, url: URL) -> Bool in
var isDir: AnyObject?
var isPackage: AnyObject?
do {
try (url as NSURL).getResourceValue(&isDir, forKey: URLResourceKey.isDirectoryKey)
try (url as NSURL).getResourceValue(&isPackage, forKey: URLResourceKey.isPackageKey)
if let isDir = isDir as? NSNumber, let isPackage = isPackage as? NSNumber, !isPackage.boolValue {
if isDir.boolValue { return true }
return validFiles.contains(url.lastPathComponent)
} catch _ {
// Treat any exception as an invalid URL.
return false