NSOutlineView example
NSOutlineView using NSURL and Swift simple example populating directory structure
AppDelegate.swift
import Cocoa
@NSApplicationMain
class AppDelegate: NSObject, NSApplicationDelegate {
var mainWindowController: MainWindowController?
func applicationDidFinishLaunching(aNotification: NSNotification) {
// Insert code here to initialize your application
let mainWindowController = MainWindowController()
mainWindowController.showWindow(self)
self.mainWindowController = mainWindowController
}
func applicationWillTerminate(aNotification: NSNotification) {
// Insert code here to tear down your application
}
func applicationShouldTerminateAfterLastWindowClosed(sender: NSApplication) -> Bool {
return true
}
}
FileItem.swift
class FileItem {
var url: NSURL!
var parent: FileItem?
var isLeaf:Bool = false
static let fileManager = NSFileManager.defaultManager()
static let requiredAttributes = [NSURLIsDirectoryKey]
static let options: NSDirectoryEnumerationOptions = [.SkipsHiddenFiles, .SkipsPackageDescendants, .SkipsSubdirectoryDescendants]
lazy var children: [FileItem]? = {
if let enumerator = fileManager.enumeratorAtURL(self.url, includingPropertiesForKeys:FileItem.requiredAttributes, options: FileItem.options, errorHandler: nil) {
var files = [FileItem]()
while let localURL = enumerator.nextObject() as? NSURL {
do {
let properties = try localURL.resourceValuesForKeys(FileItem.requiredAttributes)
// check this
files.append(FileItem(url: localURL, parent: self, isLeaf: (properties[NSURLIsDirectoryKey] as! NSNumber).boolValue))
} catch {
print("Error reading file attributes")
}
}
return files
}
return nil
}()
init(url: NSURL, parent: FileItem?, isLeaf: Bool){
self.url = url
self.parent = parent
self.isLeaf = isLeaf
}
var displayName: String {
get {
return self.url.lastPathComponent!
}
}
var count: Int {
return (self.children?.count)!
}
func childAtIndex(n: Int) -> FileItem? {
return self.children![n]
}
}
I'm using MainWindowController with xib deleted provided window from app delegate and the IBOutlet for window
import Cocoa
class MainWindowController: NSWindowController {
@IBOutlet weak var outline: NSOutlineView!
private var rootItem: FileItem? = FileItem(url: NSURL(fileURLWithPath:"/"), parent: nil, isLeaf: true)
override func windowDidLoad() {
super.windowDidLoad()
// Implement this method to handle any initialization after your window controller's window has been loaded from its nib file.
}
override var windowNibName: String? {
return "MainWindowController"
}
}
//MARK: - NSOutlineViewDelegate
extension MainWindowController: NSOutlineViewDelegate {
func outlineView(outlineView: NSOutlineView, viewForTableColumn tableColumn: NSTableColumn?, item: AnyObject) -> NSView? {
let view = outline.makeViewWithIdentifier("TextCell", owner: self) as? NSTableCellView
if let it = item as? FileItem {
if let textField = view?.textField {
textField.stringValue = it.displayName
}
} else {
if let textField = view?.textField {
textField.stringValue = self.rootItem!.displayName
}
}
return view
}
}
//MARK: - NSOutlineViewDataSource
extension MainWindowController: NSOutlineViewDataSource {
func outlineView(outlineView: NSOutlineView, child index: Int, ofItem item: AnyObject?) -> AnyObject {
if let it = item as? FileItem {
return it.childAtIndex(index)!
}
return rootItem!
}
func outlineView(outlineView: NSOutlineView, numberOfChildrenOfItem item: AnyObject?) -> Int {
if let it = item as? FileItem {
return it.count
}
return 1
}
func outlineView(outlineView: NSOutlineView, isItemExpandable item: AnyObject) -> Bool {
if let it = item as? FileItem {
if it.count > 0 {
return true
}
}
return false
}
}
Example here OutlineView
It's a modified version of this example NSOutlineViewInSwift
This example uses a simple two layer hierarchy of two parents Foo and Bar who each have two kids, Foox, Fooz and Barx, Barz respectively, the outline view is the default one with just two columns and the identifier of the second column is set to "children".
NSDictionary *firstParent = @{@"parent": @"Foo", @"children": @[@"Foox", @"Fooz"]};
NSDictionary *secondParent = @{@"parent": @"Bar", @"children": @[@"Barx", @"Barz"]};
NSArray *list = @[firstParent, secondParent];
- (BOOL)outlineView:(NSOutlineView *)outlineView isItemExpandable:(id)item
{
if ([item isKindOfClass:[NSDictionary class]]) {
return YES;
}else {
return NO;
}
}
- (NSInteger)outlineView:(NSOutlineView *)outlineView numberOfChildrenOfItem:(id)item
{
if (item == nil) { //item is nil when the outline view wants to inquire for root level items
return [list count];
}
if ([item isKindOfClass:[NSDictionary class]]) {
return [[item objectForKey:@"children"] count];
}
return 0;
}
- (id)outlineView:(NSOutlineView *)outlineView child:(NSInteger)index ofItem:(id)item
{
if (item == nil) { //item is nil when the outline view wants to inquire for root level items
return [list objectAtIndex:index];
}
if ([item isKindOfClass:[NSDictionary class]]) {
return [[item objectForKey:@"children"] objectAtIndex:index];
}
return nil;
}
- (id)outlineView:(NSOutlineView *)outlineView objectValueForTableColumn:(NSTableColumn *)theColumn byItem:(id)item
{
if ([[theColumn identifier] isEqualToString:@"children"]) {
if ([item isKindOfClass:[NSDictionary class]]) {
return [NSString stringWithFormat:@"%i kids",[[item objectForKey:@"children"] count]];
}
return item;
}else{
if ([item isKindOfClass:[NSDictionary class]]) {
return [item objectForKey:@"parent"];
}
}
return nil;
}