Created
September 14, 2014 08:56
-
-
Save drkameleon/24f5207a8aa0177b284b to your computer and use it in GitHub Desktop.
View-Based NSOutlineView Example
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
// | |
// AppDelegate.m | |
// sourceList | |
// | |
// Created by Dr.Kameleon on 9/14/14. | |
// Copyright (c) 2014 InSili.co. All rights reserved. | |
// | |
#import "AppDelegate.h" | |
/****************************************************************************** | |
* | |
* NSOutlineView Extension | |
* | |
******************************************************************************/ | |
@interface NSOutlineView (ContextMenu) | |
@end | |
@interface NSObject (NSOutlineViewContextMenuDelegate) | |
- (NSMenu *)outlineView:(NSOutlineView *)outlineView contextMenuForItem:(id)item; | |
@end | |
@implementation NSOutlineView (ContextMenu) | |
- (NSMenu *)menuForEvent:(NSEvent *)theEvent | |
{ | |
int rowIndex = (int)[self rowAtPoint:[self convertPoint:[theEvent locationInWindow] fromView:nil]]; | |
if (rowIndex >= 0) | |
{ | |
[self abortEditing]; | |
id item = [self itemAtRow:rowIndex]; | |
if (item) | |
{ | |
id obj = [self delegate]; | |
if ([obj respondsToSelector:@selector(outlineView:shouldSelectItem:)] && | |
[obj outlineView:self shouldSelectItem:item]) | |
{ | |
[self selectRowIndexes:[NSIndexSet indexSetWithIndex:rowIndex] byExtendingSelection:NO]; | |
} | |
if ([obj respondsToSelector:@selector(outlineView:contextMenuForItem:)]) | |
{ | |
return [obj outlineView:self contextMenuForItem:item]; | |
} | |
} | |
} | |
else // click in no man's land | |
{ | |
[self deselectAll:self]; | |
return [self menu]; | |
} | |
return nil; | |
} | |
@end | |
/****************************************************************************** | |
* | |
* Main Part | |
* | |
******************************************************************************/ | |
@implementation AppDelegate | |
/********************************* | |
Helpers | |
*********************************/ | |
#define HAS_KEY(X,Y) ([self dictionary:(X) containsKey:(Y)]) | |
- (BOOL)dictionary:(NSDictionary*)dict containsKey: (NSString *)key { | |
BOOL retVal = 0; | |
NSArray *allKeys = [dict allKeys]; | |
retVal = [allKeys containsObject:key]; | |
return retVal; | |
} | |
/********************************* | |
Setup | |
*********************************/ | |
- (void)awakeFromNib | |
{ | |
// Setup Delegate/Datasource | |
[_fileView setDataSource:(id<NSOutlineViewDataSource>)self]; | |
[_fileView setDelegate:(id<NSOutlineViewDelegate>)self]; | |
[_fileView setMenu:_rightClickMenu]; | |
// Set some sample tree data | |
_fileTree = | |
@[ | |
@{ @"label": @"FILES", @"isGroup": @YES, @"children":@[ | |
@{ @"label": @"one"}, | |
@{ @"label": @"two", @"children": @[ | |
@{@"label":@"two.1"}, | |
@{@"label":@"two.2"} | |
]} | |
]}, | |
@{ @"label": @"HTML", @"isGroup": @YES, @"children":@[ | |
@{ @"label": @"one"}, | |
@{ @"label": @"two", @"children": @[ | |
@{@"label":@"two.1", @"children":@[ | |
@{ @"label": @"two.1.1"}, | |
@{ @"label": @"two.1.2"} | |
]}, | |
@{@"label":@"two.2"} | |
]} | |
]}, | |
]; | |
// Update view | |
[_fileView sizeLastColumnToFit]; | |
[_fileView setFloatsGroupRows:NO]; | |
[_fileView reloadData]; | |
} | |
/********************************* | |
NSOutlineView | |
*********************************/ | |
//-------------------------- | |
// Generic Setup | |
//-------------------------- | |
- (BOOL)outlineView:(NSOutlineView *)outlineView isItemExpandable:(id)item | |
{ | |
if (HAS_KEY(item,@"children")) return YES; | |
else return NO; | |
} | |
- (NSInteger)outlineView:(NSOutlineView *)outlineView numberOfChildrenOfItem:(id)item | |
{ | |
if (item==nil) return [_fileTree count]; // Root | |
else if (HAS_KEY(item,@"children")) return [item[@"children"] count]; | |
else return 0; | |
} | |
- (id)outlineView:(NSOutlineView *)outlineView child:(NSInteger)index ofItem:(id)item | |
{ | |
if (item == nil) return _fileTree[index]; // Root | |
else if (HAS_KEY(item,@"children")) return item[@"children"][index]; | |
else return nil; | |
} | |
- (BOOL)outlineView:(NSOutlineView *)outlineView isGroupItem:(id)item | |
{ | |
if (HAS_KEY(item, @"isGroup")) return YES; | |
else return NO; | |
} | |
- (BOOL)outlineView:(NSOutlineView *)outlineView shouldSelectItem:(id)item | |
{ | |
if ([self outlineView:outlineView isGroupItem:item]) return NO; | |
else return YES; | |
} | |
//-------------------------- | |
// Set Content & Icons | |
//-------------------------- | |
- (NSView *)outlineView:(NSOutlineView *)outlineView viewForTableColumn:(NSTableColumn *)tableColumn item:(id)item | |
{ | |
NSTableCellView* tcv; | |
if ([self outlineView:outlineView isGroupItem:item]) { | |
tcv = [outlineView makeViewWithIdentifier:@"HeaderCell" owner:self]; | |
tcv.textField.stringValue = item[@"label"]; | |
} | |
else | |
{ | |
tcv = [outlineView makeViewWithIdentifier:@"DataCell" owner:self]; | |
tcv.textField.stringValue = item[@"label"]; | |
NSImage* cellImage; | |
if (HAS_KEY(item,@"children")) cellImage = [[NSWorkspace sharedWorkspace] iconForFileType:NSFileTypeForHFSTypeCode(kGenericFolderIcon)]; | |
else cellImage = [[NSWorkspace sharedWorkspace] iconForFileType:NSFileTypeRegular]; | |
[cellImage setSize:NSMakeSize(15.0, 15.0)]; | |
tcv.imageView.image = cellImage; | |
} | |
return tcv; | |
} | |
//-------------------------- | |
// Selection tracking | |
//-------------------------- | |
- (void)outlineViewSelectionDidChange:(NSNotification *)notification { | |
if ([_fileView selectedRow] != -1) { | |
id item = [_fileView itemAtRow:[_fileView selectedRow]]; | |
NSLog(@"Selected item : %@",item); | |
} | |
} | |
//-------------------------- | |
// Right-click menu | |
//-------------------------- | |
- (NSMenu*)outlineView:(NSOutlineView*)outlineView contextMenuForItem:(id)item { | |
// Show menu depending on item being right-clicked | |
return nil; | |
} | |
@end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment