#pragma .h #import <AppKit/NSBrowser.h>
#pragma .h 
#pragma .h @protocol IKBrowserDelegate
#pragma .h - (void)browser:(NSBrowser *)sender createRowsForColumn:(int)column inMatrix:(NSMatrix *)matrix;
#pragma .h - browser:sender setColumnIcon:cell for:(int) column;
#pragma .h @end
#pragma .h 
#pragma .h @interface NSObject (IKBrowserDelegateOptionalMethods)
#pragma .h - browser:sender emptyMatrix:matrix  inColumn: (int) column;
#pragma .h - browser:sender removeColumnIcon:cell  for: (int) column;
#pragma .h - browserWillFinishChange:sender;
#pragma .h - browserDidChange:sender;
#pragma .h - browserClicked:sender;
#pragma .h - browserDoubleClicked:sender;
#pragma .h @end
#pragma .h 

#import <AppKit/AppKit.h>
#import <InterfaceBuilder/InterfaceBuilder.h>
#import <math.h>

#import "IKBrowserCell.h"
#import "IKIconPath.h"
#import "IKBrowser.h"

@implementation IKBrowser: NSBrowser
{
    id		iconPath;
    id		scrollView;

    BOOL	autoSynchronize;

    SEL		scroll;
}



#ifndef max
#define max(a,b)	((a) > (b) ? (a):(b))
#endif

- initWithFrame:(NSRect)frameRect
{
    [super initWithFrame:frameRect];
    [self setHasHorizontalScroller:NO];
    [self setAllowsMultipleSelection:YES];
    [self setAcceptsArrowKeys:YES];
    [self setSendsActionOnArrowKeys:YES];
    [self setAutoSynchronize:YES];
    [self setReusesColumns:YES];
    [self setCellClass: [IKBrowserCell  class]];
    [self setTitled:NO];
    return self;
}


- (void)doAwake
{
    id	scroller;

    [self  sizeCells];

    if (!scroll) {
        scroll = [scroller = [scrollView horizontalScroller] action];
        [scroller setAction:@selector(scrolling:)];
        [scroller setTarget:self];
    }
    [iconPath setTarget:self];
    [iconPath setAction:@selector(doClick:)];
    [iconPath setDoubleAction:@selector(doDoubleClick:)];
    [iconPath setBackgroundColor:[NSColor lightGrayColor]];
    [[self window] makeFirstResponder:self];
}

- (NSString *) inspectorClassName
{
     return @"IKBrowserInspector";
}


- iconPath	{	return iconPath;	}
- scrollView	{	return scrollView;	}

- (void)removeAllFolders
{
    int i;
    [[iconPath cells] makeObjectsPerform:@selector(setDelegate:) withObject:nil];
    for(i = [self lastColumn]; i >= 0; i--) {
        [[[self matrixInColumn:i] cells] makeObjectsPerform:@selector(setDelegate:) withObject:nil];
    }
}

- (void)setIconPath: theIconPath
{
    if(iconPath)
        [iconPath release];
    iconPath = theIconPath ? [theIconPath retain] : nil;
    [self doAwake];
}

- (void)setScrollView: theScrollView
{
    if(scrollView)
        [scrollView release];
    scrollView = theScrollView ? [theScrollView retain] : nil;
    [self doAwake];
}

- (id)initWithCoder:(NSCoder *)aDecoder
{
    [super initWithCoder:aDecoder];
	
    iconPath = [[aDecoder decodeObject] retain];
    scrollView = [[aDecoder decodeObject] retain];
    [aDecoder decodeValuesOfObjCTypes:"c", &autoSynchronize];
    [self doAwake];
    return self;
}

- (void)encodeWithCoder:(NSCoder *)aCoder
{
    [super encodeWithCoder:aCoder];
	
    [aCoder encodeObject:iconPath];
    [aCoder encodeObject:scrollView];
    [aCoder encodeValuesOfObjCTypes:"c", &autoSynchronize];
}

- (void)setFrameSize:(NSSize)_newSize
{
    int first = [self firstVisibleColumn];

    [super setFrameSize:(NSSize)_newSize];
    [self scrollColumnToVisible:first];
    [self  sizeCells];
}

- (void)sizeCells
{
    NSSize size =  [scrollView contentSize];
    size.width = floor(size.width / [self numberOfVisibleColumns]);
    [iconPath setCellSize:size];
    [self synchronizePath];	
    [scrollView setLineScroll:size.width];	
    [scrollView setPageScroll:0.0];
}

- (void)synchronizePath
{
    id      clipView;
    NSPoint origin;
    NSSize  size;
    int     cells, i, last;

    if (autoSynchronize) {
        size = [iconPath cellSize];

        cells = max([self firstVisibleColumn] + [self numberOfVisibleColumns], [self lastColumn]+1);

        if([iconPath numberOfColumns] != cells) {
            [iconPath renewRows:1 columns:cells];
            [iconPath sizeToCells];
        }
        last = [self lastColumn];
        [iconPath deselectSelectedCell];
        [iconPath selectCellAtRow:0 column:last];
        for(i = 0; i < last; i++)
            [[iconPath cellAtRow:0 column:i] setBranch:YES];
        for(i = last; i < cells; i++)
            [[iconPath cellAtRow:0 column:i] setBranch:NO];
        [iconPath setNeedsDisplay:YES];

        origin.x = floor(size.width) * [self firstVisibleColumn];
        origin.y = 0.0;

        clipView = [scrollView contentView];
        [clipView scrollToPoint:origin];
        [scrollView reflectScrolledClipView:clipView];
    }
}

- (void)setAutoSynchronize: (BOOL) flag;
{
    autoSynchronize = flag;
}

- (void)newSelection
{
    if (autoSynchronize) {
        id del = [self delegate];
        if (del && [del respondsToSelector: @selector(browser:setColumnIcon:for:)]) {
            [del browser:self setColumnIcon:[iconPath selectedCell] for: [self lastColumn]];
        }
    }
}

- (void)beginUpdate
{
    [iconPath endEditing];
    [[self window] disableFlushWindow];
}

- (void)endUpdate
{
    id del = [self delegate];

    [iconPath displayIfNeeded];

    if (del && [del respondsToSelector: @selector(browserWillFinishChange:)])
        [del browserWillFinishChange: self];

    [[self window] enableFlushWindow];
    [[self window] makeFirstResponder:self];

    if (del && [del respondsToSelector: @selector(browserDidChange:)])
        [del browserDidChange: self];
}

- (void)addColumn
{
    [super addColumn];
    [self synchronizePath];
    [self newSelection];
}

- (void)setLastColumn:(int)n
{
    NSMutableArray *columnMatrices = [[NSMutableArray alloc] init],
                   *pathCells = [[NSMutableArray alloc] init];
    int		   i = n, m = [self lastColumn];
    id             del = [self delegate];

    while (i++ < m) {
        [columnMatrices addObject:[self matrixInColumn:i]];
        [pathCells addObject:[iconPath cellAtRow:0 column:i]];
    }

    [super setLastColumn:n];
    [self synchronizePath];

    i = [columnMatrices count];
    while (i--) {
        if (del && [del respondsToSelector:@selector(browser:emptyMatrix:inColumn:)])
            [del browser:self emptyMatrix:[columnMatrices objectAtIndex:i] inColumn: n + i + 1];

        if (del && [del respondsToSelector:@selector(browser:removeColumnIcon:for:)])
            [del browser: self  removeColumnIcon: [pathCells objectAtIndex: i]  for: n + i + 1];
    }

    [columnMatrices release];
    [pathCells release];
}

- (void)setReusesColumns:(BOOL)flag
{
    if (flag == YES)
        [super setReusesColumns:flag];
}

- (BOOL)setPath:(NSString *)path
{
    int  n;
    id   current = nil;
    id	del = [self delegate];

    [self  setAutoSynchronize:NO];
    [self beginUpdate];

    [super setPath:path];
    if ([self  lastColumn] == [self  selectedColumn])
        [self addColumn];
    [self setAutoSynchronize:YES];
    [self synchronizePath];

    for (n = 0;  n <= [self  lastColumn];  n++) {
        current = [iconPath cellAtRow:0 column:n];
        [current  setBranch:YES];
        if (del && [del respondsToSelector: @selector(browser:setColumnIcon:for:)])
            [del browser: self  setColumnIcon: current  for: n];
    }

    [current setBranch:NO];
    [iconPath setNeedsDisplay:YES];
    [[scrollView horizontalScroller] setNeedsDisplay:YES];

    [self endUpdate];

    return YES;
}

- takePathFrom: sender
{
    [self  setPath: [sender stringValue]];
    return self;
}

- resetColumn:(int)n usingPath: (NSString *) path
{
    [self reloadColumn:n];

    if (path) {
        [self setPath:path];
    } else {
        [self beginUpdate];
        [self setLastColumn:n];
        [[self matrixInColumn:n] selectCellAtRow:-1 column:-1];
        [self endUpdate];
    }
    return self;
}

- scrolling: sender
{
    if ([sender hitPart] != NSScrollerKnob) {
        [self scrollViaScroller:sender];
        [self synchronizePath];
   } else
        [scrollView performSelector:scroll withObject:sender];
    return self;
}

- iconSelected: sender
{
    [self setAutoSynchronize:NO];
    [self beginUpdate];
    [self setLastColumn:[iconPath selectedColumn]];

    [[self matrixInColumn:[self lastColumn]] selectCellAtRow:-1 column:-1];

    [self setAutoSynchronize:YES];
    [self synchronizePath];
    [self endUpdate];
    [self sendAction];	
    return self;
}

- (void)doClick:(id)sender
{
    id  del = [self delegate];
    int col = -1;
    [self setAutoSynchronize:NO];
    [self beginUpdate];

    if(sender == iconPath) {
        col = [sender selectedColumn];
        [self setLastColumn:col];
    } else {
        [super doClick:sender];
        if ([self lastColumn] == [self selectedColumn])
            [self addColumn];
    }
    [self setAutoSynchronize:YES];
    [self synchronizePath];
    [self newSelection];
    [self endUpdate];
    if(col != -1)
        [[self matrixInColumn:col] deselectAllCells];	// das darf nicht frueher kommen !?!?!?
    if(del && [del respondsToSelector:@selector(browserClicked:)]) {
        [del browserClicked:self];
    }
}

- (void)doDoubleClick:(id)sender
{
    id del = [self delegate];
    if(del && [del respondsToSelector:@selector(browserDoubleClicked:)]) {
        [del browserDoubleClicked:self];
    }
    [super doDoubleClick:sender];
}

- (void)keyDown:(NSEvent *)theEvent 
{
    int  r, c = [self selectedColumn],
         n, m;
    id   matrix;
    BOOL clickNow;
    NSString *chars = [theEvent characters];

    switch ([chars characterAtIndex:0]) {
        case NSLeftArrowFunctionKey:
            matrix = [self  matrixInColumn: c - 1];
            r = [matrix  selectedRow];
            clickNow = YES;
            break;

        case NSRightArrowFunctionKey:
            matrix = [self  matrixInColumn: c + 1];
            r = 0;
            clickNow = YES;
            break;

        case NSUpArrowFunctionKey:
            [matrix = [self matrixInColumn: c] getNumberOfRows: &n  columns: &m];
            r = ([matrix  selectedRow] + n - 1) % n;
            clickNow = NO;
            break;

        case NSDownArrowFunctionKey:
            [matrix = [self matrixInColumn: c] getNumberOfRows: &n  columns: &m];
            r = ([matrix  selectedRow] + 1) % n;
            clickNow = NO;
            break;

        default:
            return;
            break;
    }

    [matrix scrollCellToVisibleAtRow:r column:0];

    [matrix selectCellAtRow:r column:0];
    if (matrix && ([matrix  selectedRow] != -1) && clickNow)
        [self doClick:matrix];
}

/*

The empty extra column that an IKBrowser puts in for a leaf selection messes up the selectAll: message, so that gets fixed here.

*/


- (void)selectAll:(id)sender
{
    int r, c;

    [[self  matrixInColumn: [self  lastColumn]]  getNumberOfRows: &r  columns: &c];

    if (r == 0)
        [self  setLastColumn: [self  lastColumn] - 1];

    [super selectAll:sender];
    if ([self  lastColumn] == [self  selectedColumn])
        [self addColumn];
}

- (NSArray *)selectionInColumn: (int) column
{
    NSArray  *selection = nil;
    NSMatrix *matrix = [self  matrixInColumn: column];
    int      i;

    if (matrix != nil) {
        NSMutableArray *a = [NSMutableArray array];
        selection = [matrix selectedCells];

        for (i = 0; i < [selection count]; i++)
            [a addObject:[[selection objectAtIndex:i] delegate]];
        selection = a;
    }
    return selection;
}


@end
