Skip to content

Instantly share code, notes, and snippets.

@chriseidhof
Created May 21, 2020 11:05
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save chriseidhof/bbd625be8f34d65b5943b44340d5bf09 to your computer and use it in GitHub Desktop.
Save chriseidhof/bbd625be8f34d65b5943b44340d5bf09 to your computer and use it in GitHub Desktop.
NSBrowser Delegate Wrapper
import Cocoa
// Insipired by http://dcandi.com/post/cocoa-filesystem-browser/
extension URL {
var isDirectory: Bool {
return (try? resourceValues(forKeys: [.isDirectoryKey]))?.isDirectory ?? false
}
var fileIcon : NSImage {
(try? resourceValues(forKeys: [.effectiveIconKey]))?.effectiveIcon as? NSImage ?? NSImage()
}
var smallFileIcon: NSImage{
let icon = fileIcon
icon.size = NSMakeSize(16.0, 16.0)
return icon
}
}
struct Directory {
var url: URL
var contents: [URL]
init(url: URL) throws {
self.url = url
guard url.isDirectory else {
contents = []
return
}
let urls = try FileManager.default.contentsOfDirectory(
at: url,
includingPropertiesForKeys: nil,
options: FileManager.DirectoryEnumerationOptions.skipsHiddenFiles)
self.contents = urls
}
}
extension Directory: TreeLike {
var numberOfChildren: Int {
contents.count
}
func child(at index: Int) -> Self {
try! Directory(url: contents[index])
}
var isLeafItem: Bool {
!url.isDirectory
}
var objectValue: String {
url.lastPathComponent
}
}
class ViewController: NSViewController {
let delegate = BrowserDelegate<Directory, FileCell>(rootItem: try! Directory(url: URL(fileURLWithPath: "/")), configure: { cell, dir in
cell.image = dir.url.smallFileIcon
})
@IBOutlet var browser: NSBrowser! {
didSet {
browser.delegate = delegate
browser.setCellClass(FileCell.self)
}
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
override var representedObject: Any? {
didSet {
// Update the view, if already loaded.
}
}
}
protocol TreeLike {
associatedtype ObjectValue
var numberOfChildren: Int { get }
func child(at index: Int) -> Self
var isLeafItem: Bool { get }
var objectValue: ObjectValue { get }
}
final class BrowserDelegate<A: TreeLike, Cell: Any>: NSObject, NSBrowserDelegate {
var rootItem: A?
let configure: (Cell, A) -> ()
init(rootItem: A, configure: @escaping (Cell, A) -> ()) {
self.rootItem = rootItem
self.configure = configure
}
func rootItem(for browser: NSBrowser) -> Any? {
return rootItem
}
func browser(_ browser: NSBrowser, numberOfChildrenOfItem item: Any?) -> Int {
let item = item as! A
return item.numberOfChildren
}
func browser(_ browser: NSBrowser, child index: Int, ofItem item: Any?) -> Any {
let item = item as! A
return item.child(at: index)
}
func browser(_ browser: NSBrowser, isLeafItem item: Any?) -> Bool {
let a = item as! A
return a.isLeafItem
}
func browser(_ browser: NSBrowser, objectValueForItem item: Any?) -> Any? {
let a = item as! A
return a.objectValue
}
func browser(_ sender: NSBrowser, willDisplayCell cell: Any, atRow row: Int, column: Int) {
configure(cell as! Cell, sender.item(atRow: row, inColumn: column) as! A)
}
}
class FileCell: NSBrowserCell {
override init(imageCell i: NSImage?) {
super.init(imageCell: i)
isLeaf = true
}
override init(textCell s: String) {
super.init(textCell: s)
isLeaf = true
}
required init(coder c: NSCoder) {
super.init(coder: c)
isLeaf = true
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment