12

For learning purposes i would like to convert a cell-based NSOutlineView to a view-based one,

basically i would like the following:

  • instead of a normal cell, i'd like an 'image and text table cell view'
  • the image can be the stock NSApplicationIcon and the text can just be 'hello world' :)
  • I'd like to do this without using bindings and NSTreeController

Here is the 'worlds simplest NSOutlineView' example http://www.cocoasteam.com/Cocoa_Steam/Worlds_Simplest_Demo.html

I wonder if someone could modify it to make it view-based and work like i said above :) :)

I've tried looking at apple examples, and searching elsewhere on the internet but i still can't get it to work - so thanks very much in advance :)

Charles
  • 50,943
  • 13
  • 104
  • 142
horseyguy
  • 29,455
  • 20
  • 103
  • 145

4 Answers4

9

I have created a little sample project which does just that.

  • Display a list of items
  • Edit the items in a master-detail fashion
  • Remove and add items
  • Usage of bindings

Check out besi/mac-quickies on github. Most of the stuff is either done in IB or can be found in the AppDelegate

screenshot

Besi
  • 22,579
  • 24
  • 131
  • 223
8

OK, so you want an NSOutlineView with ImageAndTextCell cells, right?

Let's do one of the most typical examples of this kind : a simple file explorer.

What we'll need :

  • an NSOutlineView (put an outline to your AppDelegate, as fileOutlineView)
  • create 3 columns in the Outline with the following Identifiers (set them up in Interface Builder) : NameColumn, SizeColumn, ModifiedColumn

Now, as for the rest, I'll do it all programmatically, so that you get a good idea of what's going on...

How to set it up (e.g. in - (void)awakeFromNib):

// set the Data Source and Delegate
[fileOutlineView setDataSource:(id<NSOutlineViewDataSource>)self];
[fileOutlineView setDelegate:(id<NSOutlineViewDelegate>)self];

// set the first column's cells as `ImageAndTextCell`s
ImageAndTextCell* iatc = [[ImageAndTextCell alloc] init];
[iatc setEditable:NO];
[[[fileOutlineView tableColumns] objectAtIndex:0] setDataCell:iatc];

Connecting the dots :

/*******************************************************
 *
 * OUTLINE-VIEW DATASOURCE
 *
 *******************************************************/

- (BOOL)outlineView:(NSOutlineView *)outlineView isItemExpandable:(id)item
{        
    if ([item isFolder])
        return YES;
    else
        return NO;
}

- (NSInteger)outlineView:(NSOutlineView *)outlineView numberOfChildrenOfItem:(id)item
{    
    if (item==nil)
    {
        // Root
        return [[filePath folderContentsWithPathAndBackIgnoringHidden] count];
    }
    else
    {        
        if ([item isFolder])
        {
            return [[item folderContentsWithPathAndBackIgnoringHidden] count];
        }
        else
        {
            return 0;
        }
    }
}

- (id)outlineView:(NSOutlineView *)outlineView child:(NSInteger)index ofItem:(id)item
{
    if (item == nil)
    { 
        // Root
        return [[filePath folderContentsWithPathAndBackIgnoringHidden] objectAtIndex:index];
    }

    if ([item isFolder])
    {
        return [[item folderContentsWithPathAndBackIgnoringHidden] objectAtIndex:index];
    }

    // File
    return nil;
}

- (id)outlineView:(NSOutlineView *)outlineView objectValueForTableColumn:(NSTableColumn *)theColumn byItem:(id)item
{          
    if ([[theColumn identifier] isEqualToString:@"NameColumn"])
    {
        return [item lastPathComponent];
    }
    else if ([[theColumn identifier] isEqualToString:@"SizeColumn"])
    {
        if ([item isFolder]) return @"--";
        else return [NSString stringWithFormat:@"%d",[item getFileSize]];
    }
    else if ([[theColumn identifier] isEqualToString:@"ModifiedColumn"])
    {
        if ([item isFolder]) return @"";
        else return [NSString stringWithFormat:@"%@",[item getDateModified]];
    }

    // Never reaches here
    return nil;
}

/*******************************************************
 *
 * OUTLINE-VIEW DELEGATE
 *
 *******************************************************/

- (BOOL)outlineView:(NSOutlineView *)outlineView shouldSelectItem:(id)item
{
    return YES;
}

- (BOOL)outlineView:(NSOutlineView *)outlineView isGroupItem:(id)item
{
    return NO;
}

- (void)outlineView:(NSOutlineView *)outlineView willDisplayCell:(id)cell forTableColumn:(NSTableColumn *)tableColumn item:(id)item {
    [cell setDrawsBackground:NO];

    if ([item isFileHidden]) [cell setTextColor:[NSColor grayColor]];
    else [cell setTextColor:[NSColor whiteColor]];

    if ([[tableColumn identifier] isEqualToString:@"NameColumn"])
    {
        if ([item isFolder])
            [cell setImage:[[NSWorkspace sharedWorkspace] iconForFileType:NSFileTypeForHFSTypeCode(kGenericFolderIcon)] size:15.0];
        else
            [cell setImage:[[NSWorkspace sharedWorkspace] iconForFile:item] size:15.0];

        if ([item isFileHidden])
        {
            [cell setFileHidden:YES];
        }
        else
        {
            [cell setFileHidden:NO];
        }

    }

}

Hint : ImageAndTextCell class can be found here. You'll also notice a few other methods I'm using, which are obviously NOT supported by Cocoa (e.g. isFileHidden, isFolder or folderContentsWithPathAndBackIgnoringHidden) but it's not that difficult to implement them yourself...)

Dr.Kameleon
  • 22,532
  • 20
  • 115
  • 223
  • 20
    I do not see how this is correct. ImageAndTextCell is of type NSCell, NOT NSView. The question was about a view based NSOutlineView. Your example is just about creating a custom NSCell subclass which we have been able to do for years. For NSTableView there are plenty of example for how to use NSView instead of NSCell. Looks a lot like iOS. I have not found any NSOutlineView examples sadly. – Erik Engheim Feb 23 '13 at 08:15
  • 1
    @Adam- view based tables use NSTableCellViews as their views. From there you can add any content to them. What Dr.Kameleon has said is exactly right. The whole point of view based tables is that you can add any view object you want (Be it a cell, button, image well... whatever) – Patrick Nov 13 '13 at 13:40
  • 2
    This is not about creating a view based outline view. – JeremyP Dec 10 '13 at 12:40
1

To return view to OutlineView column Instead of using datasource method that return objectValue:

- (id)outlineView:(NSOutlineView *)outlineView objectValueForTableColumn:(NSTableColumn *)theColumn byItem:(id)item

USE THE DATASOURCE METHOD THAT RETURN VIEW!!!!!!!!:

- (NSView *)outlineView:(NSOutlineView *)outlineView viewForTableColumn:(NSTableColumn *)tableColumn item:(id)item

everything else is the same(minimal req is the first three datasource methods, you don't need the delegate methods) but, you can't use willdisplaycell its called only for cell based , do everything to the view in the viefortablecolumn method like this:

if ([[tableColumn identifier] isEqualToString:@"YourColumnIdentifier"]){
    NSTableCellView *cell = [outlineView makeViewWithIdentifier:@"YourViewsIdentifier" owner:self];
    [cell.textField setStringValue:[(YourItem *)item name]];
    [cell.imageView setImage:[(YourItem *)item image]];
    return cell;
}

return nil;

and don't forget to set identifiers , and to set the OutlineView to be View Based(in IB ...).

pkamb
  • 33,281
  • 23
  • 160
  • 191
Oleg Sh.
  • 49
  • 1
  • OK, that works but the result is very ugly. OutlineView appears behind the view : So, this is not quite the same as view-based NSTableView. – Chrstpsln Dec 29 '15 at 14:22
0

Check TableViewPlayground, also View Based NSTableView Basic to Advanced from WWDC 2011.

keegan3d
  • 10,357
  • 9
  • 53
  • 77
  • 3
    Thanks, i've already checked that example and i find it wayyy too bloated and confusing. I need a very very simple example to grok it i think (im also kinda new to cocoa:P) – horseyguy Apr 10 '12 at 08:31