This is IKBrowser.m in view mode; [Download] [Up]
#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
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.