ftp.nice.ch/Attic/openStep/developer/resources/MiscKit.2.0.5.s.gnutar.gz#/MiscKit2/Examples/Giger/AppController.m

This is AppController.m in view mode; [Download] [Up]

#import "AppController.h"
#import "ImageView.h"
#import "Thumber.h"

#define THUMBSIZE 80

NSConditionLock *globalLock;
TransferData global;

@interface AppController(PrivateMethods)

- (BOOL)_internalOpenGigernail:(NSString *)filename;
- (BOOL)_internalOpenGigerwww:(NSString *)filename;
- (BOOL)_internalOpenGiger:(NSString *)filename;
- (BOOL)_internalSaveGigernail:(NSString *)filename;
- (BOOL)_internalSaveGigerwww:(NSString *)filename;
- (BOOL)_internalSaveGiger:(NSString *)filename;

@end

@implementation AppController(PrivateMethods)

- (BOOL)_internalSaveGiger:(NSString *)filename
{
        NSArray *cells;

        if(!numberOfThumbnails)
                return NO;
        cells = [thumbView cells];
        if(![NSArchiver archiveRootObject:cells toFile:filename])
                return NO;
        return YES;
}

- (BOOL)_internalOpenGiger:(NSString *)filename
{
        NSArray *cells;

        cells = [NSUnarchiver unarchiveObjectWithFile:filename];
        if(cells){
                [thumbView removeRow:0];
                [thumbView renewRows:0 columns:[cells count]];
                [thumbView addRowWithCells:cells];
                [thumbView sizeToCells];
                [[thumbView window] display];
                numberOfThumbnails = [cells count];
                return YES;
        } else
                return NO;
}

- (BOOL)_internalOpenGigernail:(NSString *)filename
{
        NSString *componentName;
        NSArray *cells, *thumbNames;
        unsigned int i,n;
        NSImage *image;
        NSButtonCell *cell;

        componentName = [NSString stringWithFormat:@"%@/Thumbs.plist",filename];
        thumbNames = [NSArray arrayWithContentsOfFile:componentName];
        if(thumbNames){
                n = [thumbNames count];
                [thumbView removeRow:0];
                [thumbView renewRows:1 columns:n];
                cells = [thumbView cells];
                for(i = 0; i < n; i++){
                        componentName = [NSString stringWithFormat:@"%@/t%d.tiff", filename, i];
                        cell = [cells objectAtIndex:i];
                        image = [[NSImage alloc] initWithContentsOfFile:componentName];
                        [cell setImage:image];
                        [image release];
                        [cell setRepresentedObject:[thumbNames objectAtIndex:i]];
                }
                [thumbView sizeToCells];
                [[thumbView window] display];
                numberOfThumbnails = n;
                return YES;
        } else
                return NO;
}

- (BOOL)_internalOpenGigerwww:(NSString *)filename
{
        NSString *componentName;
        NSArray *cells, *thumbNames;
        unsigned int i,n;
        NSImage *image;
	NSBitmapImageRep *bitmap;
        NSButtonCell *cell;

        componentName = [NSString stringWithFormat:@"%@/Thumbs.plist",filename];
        thumbNames = [NSArray arrayWithContentsOfFile:componentName];
        if(thumbNames){
                n = [thumbNames count];
                [thumbView removeRow:0];
                [thumbView renewRows:1 columns:n];
                cells = [thumbView cells];
                for(i = 0; i < n; i++){
                        componentName = [NSString stringWithFormat:@"%@/t%d.gif", filename, i];
                        cell = [cells objectAtIndex:i];
			bitmap = [imageDecoder decodeFromFile:componentName];
			if(bitmap){
                        	image = [[NSImage alloc] init];
				[image addRepresentation:bitmap];
                        	[cell setImage:image];
                        	[image release];
			}
                        [cell setRepresentedObject:[thumbNames objectAtIndex:i]];
                }
                [thumbView sizeToCells];
                [[thumbView window] display];
                numberOfThumbnails = n;
                return YES;
        } else
                return NO;
}

- (BOOL)_internalSaveGigernail:(NSString *)filename
{
        NSString *fileComponentName;
        NSData *tiffData;
	NSFileManager *fm = [NSFileManager defaultManager];
	BOOL isDir;
	NSMutableString *plistString;
	NSArray *cells;
	NSButtonCell *cell;
        unsigned int i;

        if(!numberOfThumbnails)
            	return NO;
        if([fm fileExistsAtPath:filename isDirectory:&isDir]){
                if(![fm removeFileAtPath:filename handler:nil]){
                        NSLog(@"Could not remove old directory %@", filename);
                        NSBeep();
                        return NO;
                }
        }
        if(![fm createDirectoryAtPath:filename attributes:nil]){
                NSLog(@"Could not create directory %@", filename);
                NSBeep();
                return NO;
        }
        plistString = [[NSMutableString alloc] init];
        [plistString appendString:@"(\n"];
        cells = [thumbView cells];
        for(i = 0; i < numberOfThumbnails; i++){
                cell = [cells objectAtIndex:i];
                fileComponentName = [NSString stringWithFormat:@"%@/t%d.tiff", filename, i];
                tiffData = [[cell image] TIFFRepresentation];
                if(![tiffData writeToFile:fileComponentName atomically:YES]){
                        NSLog(@"Could not write thumbnail %@", fileComponentName);
                        NSBeep();
                }
                [plistString appendFormat:@"\t\"%@\",\n", [cell representedObject]];
        }
        [plistString appendString:@")\n"];
        fileComponentName = [NSString stringWithFormat:@"%@/Thumbs.plist", filename];
        if(![plistString writeToFile:fileComponentName atomically:YES]){
                NSLog(@"Could not write plist");
                NSBeep();
        }
        [plistString release];
        return YES;
}

- (BOOL)_internalSaveGigerwww:(NSString *)filename
{
        NSString *fileComponentName;
        NSData *tiffData, *gifData;
	NSFileManager *fm = [NSFileManager defaultManager];
	BOOL isDir;
	NSMutableString *plistString;
	NSArray *cells;
	NSButtonCell *cell;
        unsigned int i;
        NSAutoreleasePool *pool;
        NSPasteboard *filterPB;

        if(!numberOfThumbnails)
            	return NO;
        if([fm fileExistsAtPath:filename isDirectory:&isDir]){
                if(![fm removeFileAtPath:filename handler:nil]){
                        NSLog(@"Could not remove old directory %@", filename);
                        NSBeep();
                        return NO;
                }
        }
        if(![fm createDirectoryAtPath:filename attributes:nil]){
                NSLog(@"Could not create directory %@", filename);
                NSBeep();
                return NO;
        }
        plistString = [[NSMutableString alloc] init];
        [plistString appendString:@"(\n"];
        cells = [thumbView cells];
        for(i = 0; i < numberOfThumbnails; i++){
                pool = [[NSAutoreleasePool alloc] init];
                cell = [cells objectAtIndex:i];
                fileComponentName = [NSString stringWithFormat:@"%@/t%d.gif", filename, i];
                tiffData = [[cell image] TIFFRepresentation];
                filterPB = [NSPasteboard pasteboardByFilteringData:tiffData ofType:NSTIFFPboardType];
                gifData = [filterPB dataForType:@"image format gif"];
                if(gifData && ![gifData writeToFile:fileComponentName atomically:YES]){
                        NSLog(@"Could not write thumbnail %@", fileComponentName);
                        NSBeep();
                }
                [plistString appendFormat:@"\t\"%@\",\n", [cell representedObject]];
                [filterPB releaseGlobally];
                [pool release];
        }
        [plistString appendString:@")\n"];
        fileComponentName = [NSString stringWithFormat:@"%@/Thumbs.plist", filename];
        if(![plistString writeToFile:fileComponentName atomically:YES]){
                NSLog(@"Could not write plist");
                NSBeep();
        }
        [plistString release];
        return YES;
}


@end

@implementation AppController

- (oneway void)provideGlobalData
{
    	NSAutoreleasePool *subpool;
        NSBitmapImageRep *bitmap;

	[globalLock lock];

	if(global.full){
		NSZoneFree(NSDefaultMallocZone(),global.imagePlanes);
		[global.bitmap release];
		[global.image release];
                [global.filename release];
		global.full = NO;
	}

	if(isRunning && currentJob < [filenames count]){
		
                
                global.filename = [[filenames objectAtIndex:currentJob] retain];

		
                global.image = [[NSImage alloc] init];
                bitmap = [imageDecoder decodeFromFile:global.filename];

                if(!global.image || !bitmap){
                    	[global.filename release];
                        global.full = NO;
                        [globalLock unlockWithCondition:HAS_DATA];
                        return;
                }
		[global.image addRepresentation:bitmap];

                subpool = [[NSAutoreleasePool alloc] init];
		global.bitmap = [[NSBitmapImageRep alloc] initWithData:[global.image TIFFRepresentation]];
                [subpool release];
                
                if(!global.bitmap){
                        [global.filename release];
                        [global.image release];
                        global.full = NO;
                        [globalLock unlockWithCondition:HAS_DATA];
                        return;
                }
		
		global.imageInfo.bitsPerPixel = [global.bitmap bitsPerPixel];
        	global.imageInfo.samplesPerPixel = [global.bitmap samplesPerPixel];	
        	global.imageInfo.bitsPerSample = [global.bitmap bitsPerSample];       
        	global.imageInfo.isPlanar = [global.bitmap isPlanar];
		global.imageInfo.hasAlpha = [global.bitmap hasAlpha];
        	global.imageInfo.numberOfPlanes = [global.bitmap numberOfPlanes];
        	global.imageInfo.bytesPerPlane = [global.bitmap bytesPerPlane];
        	global.imageInfo.bytesPerRow = [global.bitmap bytesPerRow];
        	global.imageInfo.pixelsHigh = [global.bitmap pixelsHigh];
        	global.imageInfo.pixelsWide = [global.bitmap pixelsWide];
		
                // normally it should be global.imageInfo.samplesPerPixel
                // but due to a bug ?? it only works with something greater like 10
		// global.imagePlanes = NSZoneMalloc(NSDefaultMallocZone(),
                //		global.imageInfo.samplesPerPixel * sizeof(unsigned char *));
                global.imagePlanes = NSZoneMalloc(NSDefaultMallocZone(), 10 * sizeof(unsigned char *));
                
		[global.bitmap getBitmapDataPlanes:global.imagePlanes];
        	global.imageData = [global.bitmap bitmapData];
                
		global.full = YES;
                				
	}
        [globalLock unlockWithCondition:HAS_DATA];
}

- (oneway void)displayGlobalData
{
        NSButtonCell *cell;
        NSWindow *window = [thumbView window];
        NSImage *thumbnail, *thumbSharpenedNail;
	NSBitmapImageRep *thumbBitmap, *thumbSharpenedBitmap;

	[globalLock lock];

        if(!global.full){
            	[globalLock unlockWithCondition:NO_DATA];
            	currentJob++;
                if(isRunning && currentJob < [filenames count])
                	[thumber thumbWithSize:THUMBSIZE];
                else {
                    	job = NO;
                        isRunning = NO;
                        [statusTextField setStringValue:@""];
                        [window display];
			[NSApp updateWindows];
                }        
		return;
        }

        if(global.thumbnailPlanes){

            thumbBitmap = [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:global.thumbnailPlanes
                            pixelsWide:global.thumbnailInfo.pixelsWide
                            pixelsHigh:global.thumbnailInfo.pixelsHigh
                            bitsPerSample:global.thumbnailInfo.bitsPerSample
                            samplesPerPixel:global.thumbnailInfo.samplesPerPixel
                            hasAlpha:global.thumbnailInfo.hasAlpha
                            isPlanar:global.thumbnailInfo.isPlanar
                            colorSpaceName:[global.bitmap colorSpaceName]
                            bytesPerRow:global.thumbnailInfo.bytesPerRow
                            bitsPerPixel:global.thumbnailInfo.bitsPerPixel];

            thumbSharpenedBitmap = [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:global.thumbnailSharpenedPlanes
                            pixelsWide:global.thumbnailInfo.pixelsWide
                            pixelsHigh:global.thumbnailInfo.pixelsHigh
                            bitsPerSample:global.thumbnailInfo.bitsPerSample
                            samplesPerPixel:global.thumbnailInfo.samplesPerPixel
                            hasAlpha:global.thumbnailInfo.hasAlpha
                            isPlanar:global.thumbnailInfo.isPlanar
                            colorSpaceName:[global.bitmap colorSpaceName]
                            bytesPerRow:global.thumbnailInfo.bytesPerRow
                            bitsPerPixel:global.thumbnailInfo.bitsPerPixel];

	
		thumbnail = [[NSImage alloc] init];
		[thumbnail addRepresentation:thumbBitmap];

		thumbSharpenedNail = [[NSImage alloc] init];
		[thumbSharpenedNail addRepresentation:thumbSharpenedBitmap];
        
		[thumbBitmap release];
		[thumbSharpenedBitmap release];

		[thumbnail lockFocus];
		[thumbSharpenedNail compositeToPoint:NSZeroPoint operation:NSCompositeSourceOver];
		[thumbnail unlockFocus];


        	[thumbSharpenedNail release];
        } else
            thumbnail = [global.image retain];

        [thumbView addColumn];
        cell = (NSButtonCell *)[[thumbView cells] lastObject];
        [cell setImage:thumbnail];
        [thumbnail release];
        [cell setRepresentedObject:global.filename];

        [globalLock unlockWithCondition:NO_DATA];
        
        [thumbView sizeToCells];
        [thumbView scrollCellToVisibleAtRow:0 column:[[thumbView cells] count] - 1];
        [window display];
        numberOfThumbnails++;
    	currentJob++;
        if(isRunning && currentJob < [filenames count])
        	[thumber thumbWithSize:THUMBSIZE];
        else {
                job = NO;
                isRunning = NO;
                [statusTextField setStringValue:@""];
                [window display];
		[NSApp updateWindows];                
        }                
}

- (BOOL)isRunning
{
        return isRunning;
}

- (void)setThumber:(id)aThumber
{
    	if(thumber == aThumber)
            	return;
        [thumber release];
        thumber = [aThumber retain];
        [thumber setProtocolForProxy:@protocol(ThumberMethods)];
}

- (void)stopThumbs:(id)sender
{
        isRunning = NO;
}

- (void)addDirectory:(id)sender
{
        NSWindow *window = [thumbView window];
        NSString *filename, *dirname;
        NSFileManager *fm = [NSFileManager defaultManager];
        NSDirectoryEnumerator *dir;
        NSArray *imageFileTypes = [imageDecoder imageUnfilteredFileTypes];
        NSMutableArray *fn;

        [openPanel setAllowsMultipleSelection:NO];
        [openPanel setCanChooseDirectories:YES];
        [openPanel setCanChooseFiles:NO];
        [openPanel setTitle:@"Add Images from"];
        if([openPanel runModal]){
                [statusTextField setStringValue:@"Making thumbnails"];
                [thumbView deselectAllCells];
                [window display];
                [window flushWindow];
                PSWait();
                dirname = [[openPanel filenames] objectAtIndex:0];
                dir = [fm enumeratorAtPath:dirname];
		if(filenames)
			[filenames release];
                fn = [[NSMutableArray alloc] init];
                while(filename = [dir nextObject]){
                        if([imageFileTypes containsObject:[filename pathExtension]]){
                            	filename = [NSString stringWithFormat:@"%@/%@",dirname,filename];
				[fn addObject:filename];
                    	}
                }
                filenames = [fn copy];
                [fn release];
		isRunning = YES;
                job = YES;
		currentJob = 0;
                [thumber thumbWithSize:THUMBSIZE];

        }
}

- (void)addImages:(id)sender
{
        NSWindow *window = [thumbView window];

    	[openPanel setAllowsMultipleSelection:YES];
        [openPanel setCanChooseDirectories:NO];
        [openPanel setCanChooseFiles:YES];
        [openPanel setTitle:@"Add Images"];
        if([openPanel runModalForTypes:[imageDecoder imageUnfilteredFileTypes]]){
                [statusTextField setStringValue:@"Making thumbnails"];
                [thumbView deselectAllCells];
                [window display];
                [window flushWindow];
                PSWait();
		if(filenames)
			[filenames release];
                filenames = [[openPanel filenames] copy];

		isRunning = YES;
                job = YES;
		currentJob = 0;
                [thumber thumbWithSize:THUMBSIZE];
	}
}

- (void)showImage:(id)sender
{
	NSImage *image;
	NSBitmapImageRep *bitmap;
        NSButtonCell *cell;
        NSString *filename;

        cell = (NSButtonCell *)[thumbView selectedCell];
        filename = (NSString *)[cell representedObject];
        if(!filename){
                NSBeep();
                return;
        }        
        bitmap = [imageDecoder decodeFromFile:filename];
        if(bitmap){
                image = [[NSImage alloc] init];
            	[image addRepresentation:bitmap];
	} else {
            	NSBeep();
            	return;
        }
        [statusTextField setStringValue:filename];
	[imageView setImage:image];
	[imageView setImageName:filename];
        [[imageView window] display];
        [image release];
}

static BOOL alreadyAwake = NO;

- (void)awakeFromNib
{
    	NSScrollView *ms;
        NSSize msSize;

	if(alreadyAwake)
            	return;
        alreadyAwake = YES;
        numberOfThumbnails = 0;
        [thumbView setAllowsEmptySelection:YES];
        [thumbView removeRow:0];
        [thumbView renewRows:1 columns:0];
        [thumbView setCellSize:NSMakeSize(THUMBSIZE + 5, THUMBSIZE + 5)];
    	[thumbView setAutoresizingMask:0];
    	[thumbView sizeToCells];
        [thumbView setDoubleAction:@selector(showImage:)];
        [thumbView setTarget:self];
        [thumbView setPostsFrameChangedNotifications:YES];
        [thumbView deselectAllCells];
        ms = [thumbView enclosingScrollView];
        msSize = [NSScrollView frameSizeForContentSize:[thumbView frame].size
            	hasHorizontalScroller:[ms hasHorizontalScroller]
            	hasVerticalScroller:[ms hasVerticalScroller]
            	borderType:[ms borderType]];
        [ms setFrameSize:msSize];
        [self splitView:splitView resizeSubviewsWithOldSize:[splitView frame].size];
	savePanel = [NSSavePanel savePanel];
        openPanel = [NSOpenPanel openPanel];
}        	

- (void)applicationDidFinishLaunching:(NSNotification *)notification
{
	NSPort *port1;
        NSPort *port2;
        NSArray *portArray;

        isRunning = NO;
	job = NO;
	filenames = nil;
	currentJob = 0;
	global.full = NO;

	globalLock = [[NSConditionLock alloc] initWithCondition:NO_DATA];
	imageDecoder = [[MiscImageDecoderController alloc] init];

        port1 = [NSPort port];
        port2 = [NSPort port];

        serverConnection = [[NSConnection alloc] initWithReceivePort:port1 sendPort:port2];
        [serverConnection setRootObject:self];

        portArray = [NSArray arrayWithObjects:port2, port1, nil];
        [NSThread detachNewThreadSelector:@selector(connectWithPorts:)
                                 toTarget:[Thumber class] withObject:portArray];
    	
        [[imageView window] makeKeyAndOrderFront:self];
}

- (BOOL)application:(NSApplication *)theApplication openFile:(NSString *)filename
{
    	NSString *extension;
        
        extension = [filename pathExtension];
        if([extension isEqualToString:@"giger"]){
            	return [self _internalOpenGiger:filename];
        }  else if([extension isEqualToString:@"gigernail"]){
            return [self _internalOpenGigernail:filename];
        } else if([extension isEqualToString:@"gigerwww"]){
            return [self _internalOpenGigerwww:filename];
        }
        return NO;
}

- (void)saveDocument:(id)sender
{
        NSString *filename;
        NSString *extension;

        if(!numberOfThumbnails)
            	return;
        [savePanel setRequiredFileType:@"giger"];
        [savePanel setTitle:@"Save"];
        [savePanel setAccessoryView:saveFileTypeMatrix];
        if([savePanel runModal]){
            	filename = [savePanel filename];
            	extension = [filename pathExtension];
                if([extension isEqualToString:@"giger"])
                        [self _internalSaveGiger:filename];
                else if([extension isEqualToString:@"gigernail"])
                        [self _internalSaveGigernail:filename];
                else
                        [self _internalSaveGigerwww:filename];
        }        
}

- (void)saveChangeFileType:(id)sender
{
	int tag = [sender selectedTag];

        if(tag == 0)
            [savePanel setRequiredFileType:@"giger"];
        else if(tag == 1)
            [savePanel setRequiredFileType:@"gigernail"];
        else
            [savePanel setRequiredFileType:@"gigerwww"];
}        
    	
- (void)openDocument:(id)sender
{
        NSString *filename;
        NSString *extension;

        [openPanel setAllowsMultipleSelection:NO];
        [openPanel setCanChooseDirectories:NO];
        [openPanel setCanChooseFiles:YES];
        [openPanel setTitle:@"Open"];
        if([openPanel runModalForTypes:[NSArray arrayWithObjects:@"giger",@"gigernail",@"gigerwww",nil]]){
            	filename = [[openPanel filenames] objectAtIndex:0];
            	extension = [filename pathExtension];
    		if([extension isEqualToString:@"giger"])
                    	[self _internalOpenGiger:filename];
                else if([extension isEqualToString:@"gigernail"])
                    	[self _internalOpenGigernail:filename];
                else
                    	[self _internalOpenGigerwww:filename];
        }
}

- (void)showInfo:(id)sender
{
        if(!infoPanel){
                [NSBundle loadNibNamed:@"Info" owner:self];
            	[infoPanel setBecomesKeyOnlyIfNeeded:YES];
        }
    	[infoPanel orderFront:self];
}
        
- (void)saveImage:(id)sender
{
        NSString *filename;
        NSData *tiffData;

        if(![imageView image])
                return;
        [savePanel setRequiredFileType:@"tiff"];
        [savePanel setTitle:@"Save Image"];
        if([savePanel runModal]){
            	filename = [savePanel filename];
                tiffData = [[imageView image] TIFFRepresentation];
                if(![tiffData writeToFile:filename atomically:YES])
                        NSBeep();
        }
}

- (void)openImage:(id)sender
{
        NSString *filename;
        NSImage *image;
	NSBitmapImageRep *bitmap;

        [openPanel setAllowsMultipleSelection:NO];
        [openPanel setCanChooseDirectories:NO];
        [openPanel setCanChooseFiles:YES];
        [openPanel setTitle:@"Open Image"];
        if([openPanel runModalForTypes:[imageDecoder imageUnfilteredFileTypes]]){
            	filename = [[openPanel filenames] objectAtIndex:0];
                bitmap = [imageDecoder decodeFromFile:filename];
        	if(bitmap){
                	image = [[NSImage alloc] init];
            		[image addRepresentation:bitmap];
		} else {
            		NSBeep();
            		return;
        	}
                [statusTextField setStringValue:filename];
                [imageView setImage:image];
                [imageView setImageName:filename];
                [[imageView window] display];
                [image release];
        }
}

- (void)remove:(id)sender
{
    	NSArray *selectedCells;
        NSMutableArray *cells;

        selectedCells = [thumbView selectedCells];
        if([selectedCells count] == 0)
            return;
        cells = [[thumbView cells] mutableCopy];
        [cells removeObjectsInArray:selectedCells];
        [thumbView removeRow:0];
        numberOfThumbnails = [cells count];
        if(numberOfThumbnails == 0){
            	[thumbView renewRows:1 columns:0];
        } else {    
        	[thumbView renewRows:0 columns:[cells count]];
        	[thumbView addRowWithCells:cells];
        }        
        [thumbView sizeToCells];
        [[thumbView window] display];
}

- (void)newDocument:(id)sender;
{
    	if(numberOfThumbnails == 0)
            	return;
    	numberOfThumbnails = 0;
        [thumbView removeRow:0];
        [thumbView renewRows:1 columns:0];
        [thumbView sizeToCells];
        [[thumbView window] display];
}

- (void)splitView:(NSSplitView *)sender resizeSubviewsWithOldSize:(NSSize)oldSize
{
        NSRect upper,lower;
        NSView *upperView;
        NSView *lowerView;
        float delta, thumbHeight;

        upperView = (NSView *)[[sender subviews] objectAtIndex:0];
        lowerView = (NSView *)[[sender subviews] objectAtIndex:1];
        upper = [upperView frame];
	thumbHeight = upper.size.height;        
        [sender adjustSubviews];
        upper = [upperView frame];
        lower = [lowerView frame];
         if(upper.size.height > thumbHeight){
                delta = upper.size.height - thumbHeight;
                upper.size.height = thumbHeight;
                lower.size.height += delta;
                [upperView setFrame:upper];
                [lowerView setFrame:lower];
        } else if (upper.size.height < thumbHeight){
                delta = thumbHeight - upper.size.height;
                upper.size.height = thumbHeight;
                lower.size.height -= delta;
                if(lower.size.height < 0)
                    	lower.size.height = 0;
                [upperView setFrame:upper];
                [lowerView setFrame:lower];
        }        
}

- (void)splitView:(NSSplitView *)sender constrainMinCoordinate:(float *)min
    maxCoordinate:(float *)max ofSubviewAt:(int)offset
{
    	NSScrollView *ms;
    	NSSize msSize;
    
        if(offset == 0){
            ms = [thumbView enclosingScrollView];
            msSize = [NSScrollView frameSizeForContentSize:[thumbView frame].size
                                     hasHorizontalScroller:[ms hasHorizontalScroller]
                                       hasVerticalScroller:[ms hasVerticalScroller]
                                                borderType:[ms borderType]];

            *min = 0.0;
            *max = msSize.height;
        }
}

- (BOOL)validateMenuItem:(NSMenuItem *)anItem
{
    NSString *menuTitle = [anItem title];

    if([menuTitle isEqualToString:@"New"]){
        if(isRunning || numberOfThumbnails == 0)
            return NO;
        else
            return YES;
    }
    if([menuTitle isEqualToString:@"Open..."]){
        if(isRunning)
            return NO;
        else
            return YES;
    }
    if([menuTitle isEqualToString:@"Save..."]){
        if(isRunning || numberOfThumbnails == 0)
            return NO;
        else
            return YES;
    }
    if([menuTitle isEqualToString:@"Add Images..."]){
        if(isRunning)
            return NO;
        else
            return YES;
    }
    if([menuTitle isEqualToString:@"Add Directory..."]){
        if(isRunning)
            return NO;
        else
            return YES;
    }
    if([menuTitle isEqualToString:@"Remove"]){
        if(isRunning || [[thumbView selectedCells] count] == 0)
            return NO;
        else
            return YES;
    }    
    if([menuTitle isEqualToString:@"Stop Thumbnails"]){
        if(!isRunning)
            return NO;
        else
            return YES;
    }
    if([menuTitle isEqualToString:@"Save Image..."]){
        if(![imageView image])
            return NO;
        else
            return YES;
    }
    return YES;
}

@end

These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.