Created
May 21, 2020 11:05
-
-
Save chriseidhof/bbd625be8f34d65b5943b44340d5bf09 to your computer and use it in GitHub Desktop.
NSBrowser Delegate Wrapper
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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