This is File.m in view mode; [Download] [Up]
#pragma .h #import <Foundation/NSString.h>
#pragma .h #import <IconKit/iconkit.h>
#import <Foundation/NSDictionary.h>
#import <Foundation/NSPathUtilities.h>
#import <Foundation/NSProcessInfo.h>
#import <AppKit/NSWorkspace.h>
#import "File.h"
#import "FileList.h"
#pragma .h typedef struct _FileFlags {
#pragma .h unsigned int imageLoaded:1;
#pragma .h unsigned int acceptingDragImageLoaded:1;
#pragma .h unsigned int parentLoaded:1;
#pragma .h unsigned int childrenLoaded:1;
#pragma .h } FileFlags;
@implementation File: IKFolder
static NSImage *draggedImage = nil;
static NSMutableDictionary *fileMap = nil;
+ (void)initialize
{
if (self == [File class]) {
fileMap = [[NSMutableDictionary alloc] init];
}
return;
}
+ multipleSelectionClass
{
return [FileList class];
}
+ (NSArray *) pasteTypes
{
static NSMutableArray *pasteTypes = nil;
if(pasteTypes == nil) {
pasteTypes = [[NSMutableArray alloc] init];
[pasteTypes addObject:NSFilenamesPboardType];
[pasteTypes addObject:IKidPboardType()];
}
return pasteTypes;
}
+ fileForPath: (NSString *) thePath
{
// <<HACK>> This is really bad since files which we fetched once will never go away !
// But right now we have bigger fish to fry...so ignor this ugly piece of code.
id file = [fileMap objectForKey: thePath];
if( !file )
{
file = [[File alloc] initPath: thePath];
[fileMap setObject:file forKey:thePath];
}
else
{
// Just retain it once more so taht we can release it again
[file retain];
}
return [file autorelease];
}
- initPath: (NSString *) thePath
{
// <<HACK>> Method name should be changed ! initWithPath or initWithFile etc...
NSString * fileType;
NSString * title = [thePath lastPathComponent];
NSDictionary * dict;
if( !title )
return nil;
// <<HACK>> This does not work properly with WindowsNT !!! Too hardcoded !
else if( [title isEqual:@""] ||
[title isEqual:@"/"] )
title = [[NSProcessInfo processInfo] hostName];
// Now we can be sure that the title is what we expect it to be...
self = [super init:title];
if( !self ) return nil;
path = [thePath retain];
// This could be wrapped in "isDictionray" on the MiscKit..
dict = [[NSFileManager defaultManager] fileAttributesAtPath:path traverseLink:NO];
flags.dragAccepting = [[dict fileType] isEqual:NSFileTypeDirectory];
flags.leaf = !flags.dragAccepting;
flags.hidden = NO;
fileFlags.imageLoaded = NO;
fileFlags.acceptingDragImageLoaded = NO;
fileFlags.parentLoaded = NO;
fileFlags.childrenLoaded = !flags.dragAccepting;
// Set some other minor detaiils.
// <<HACK>> This is not really very cleaer..esp the file wrapper part.
isApplication = NO;
isFileWrapper = NO;
fileType = [path pathExtension];
if( [fileType isEqual:@"app"] )
{
isApplication = YES;
isFileWrapper = YES;
flags.dragAccepting = YES;
}
else if( [fileType isEqual:@"rftd"] ||
[fileType isEqual:@"nib"] ||
[fileType isEqual:@"eomodeld"] )
{
isFileWrapper = YES;
flags.dragAccepting = NO;
}
return self;
}
- copyWithZone: (NSZone *) zone;
{
File *copy = [super copyWithZone: zone];
copy->path = [path copyWithZone:zone];
copy->fileFlags = fileFlags;
return copy;
}
- (void)dealloc
{
[path release];
[super dealloc];
}
- image
{
if (!fileFlags.imageLoaded)
image = draggedImage
? [draggedImage retain]
: [[[NSWorkspace sharedWorkspace] iconForFile:path] retain];
fileFlags.imageLoaded = 1;
return image;
}
- acceptingDragImage
{
if( isFileWrapper )
return [self image];
else
return [super acceptingDragImage];
}
- (NSString *) path
{
return path;
}
- parents
{
NSString *directory;
if (!fileFlags.parentLoaded) {
fileFlags.parentLoaded = 1;
directory = [path stringByDeletingLastPathComponent];
if([directory isEqual:@""]) {
[[File fileForPath:@"/"] addChild: self];
} else {
[[File fileForPath:directory] addChild: self];
}
}
return parents;
}
- (void)addParent: parent
{
fileFlags.parentLoaded = 1;
[super addParent: parent];
}
- (void)removeChild:child withAnnouncement:(BOOL)yesNo
{
NSEnumerator *enumerator = [fileMap keyEnumerator];
NSString *key, *p = [child path];
fileFlags.childrenLoaded = 0;
while(key = [enumerator nextObject]) {
if([key hasPrefix:p]) {
[fileMap removeObjectForKey:key];
}
}
[fileMap removeObjectForKey:p];
[super removeChild:child withAnnouncement:yesNo];
}
- children
{
int i, count;
if (!fileFlags.childrenLoaded) {
NSArray *files = [[NSFileManager defaultManager] directoryContentsAtPath:path];
fileFlags.childrenLoaded = 1;
[users setSendAnnouncements: NO];
for(i = 0, count = [files count]; i < count; i++) {
NSString *s = [files objectAtIndex:i];
[self addChild: [File fileForPath:[path stringByAppendingPathComponent:s]]];
}
[users setSendAnnouncements: YES];
}
return children;
}
- (void)copyToPasteboard: (NSPasteboard *) pboard
{
[super copyToPasteboard: pboard];
[pboard addTypes:[NSArray arrayWithObject:NSFilenamesPboardType] owner:nil];
[pboard setPropertyList:[NSArray arrayWithObject:path] forType:NSFilenamesPboardType];
}
+ readFromPasteboard: (NSPasteboard *) pboard
{
id file = nil;
if( (file = [super readFromPasteboard: pboard]) == nil &&
[pboard availableTypeFromArray:[NSArray arrayWithObject:NSFilenamesPboardType]] != NULL) {
id a = [pboard propertyListForType:NSFilenamesPboardType];
if([a isKindOfClass:[NSString class]]) {
file = [File fileForPath:a];
}
else if( [a isKindOfClass:[NSArray class]] )
{
if([a count] > 1)
file = [FileList readFromPasteboard:pboard];
else
file = [File fileForPath:[a objectAtIndex:0]];
}
}
return file;
}
- (unsigned int) draggingEntered: (id <NSDraggingInfo>) sender
{
int n = [sender draggingSequenceNumber];
if (draggingSession != n)
{
// We are an application _and_ a fileWrapper, then we should only support "move" operations
// if we really support the filepath of the dragged objects.
// IF the "command" key is pressed we will actept all dragged files.
if( isApplication && isFileWrapper )
{
dragging = [[[self class] readFromPasteboard : [sender draggingPasteboard]] retain];
draggingSession = n;
if( !dragging )
{
operationMask = NSDragOperationNone;
}
else
{
// if command key
// if( ![self _applicationSupportsFile:[draggedFile path]] )
// return NO;
operationMask = NSDragOperationGeneric;
// else check agaisnt supported filetypes...
}
}
// otherwise we will leave the work to our superclass
// <<NOTE>> This code is really evil since it heavily lelies on the implementation of the super method.
// We might not have been able to do this if the super code was not known ..
else [super draggingEntered:sender];
}
return [self draggingOperation: sender];
}
- (unsigned int) draggingOperation: (id <NSDraggingInfo>) sender
{
unsigned int
choices = operationMask & [sender draggingSourceOperationMask] & ~NSDragOperationPrivate;
while (choices & (choices - 1))
choices &= choices - 1;
return choices;
}
/* shelf listener methods */
+ (void)shelf:sender dragWillEnter: (id <NSDraggingInfo>) source
{
draggedImage = [[source draggedImage] copy];
}
+ (void)shelf:sender dragWillExit: (id <NSDraggingInfo>) source
{
[draggedImage release];
draggedImage = nil;
}
+ (void)shelf:sender dragWillComplete: (id <NSDraggingInfo>) source
{
[draggedImage release];
draggedImage = nil;
}
- (BOOL)performDragOperation:(id <NSDraggingInfo>) source
{
id draggedFile;
id pasteboard = [source draggingPasteboard];
int i;
id infoDict;
id pathArray;
draggedFile = [[self class] readFromPasteboard:pasteboard];
// If we are an application the we propably should open that file.
// If the command key is pressed we will open if no matter
if( isApplication && isFileWrapper )
{
if( [draggedFile isKindOfClass:[File class]] )
{
NSLog( @"Should perform drop... if we are an app...open the file.. %@", [draggedFile path] );
infoDict = [NSMutableDictionary new];
[infoDict setObject:[self path] forKey:@"App"];
[infoDict setObject:[NSArray arrayWithObject:[draggedFile path]] forKey:@"Files"];
if( [[NSUserDefaults standardUserDefaults] boolForKey:@"UseWorkspaceThreads"] )
[NSThread detachNewThreadSelector:@selector(_detachedAppBasedFileOpen:)
toTarget:self
withObject:infoDict];
else
[self performSelector:@selector(_detachedAppBasedFileOpen:)
withObject:infoDict
afterDelay:0.5];
}
else if( [draggedFile isKindOfClass:[FileList class]] )
{
// count, objectAtIndex: etc.
infoDict = [NSMutableDictionary new];
[infoDict setObject:[self path] forKey:@"App"];
pathArray = [NSMutableArray new];
for( i=0; i<[draggedFile count]; i++ )
[pathArray addObject:[[draggedFile objectAtIndex:i] path]];
[infoDict setObject:pathArray forKey:@"Files"];
if( [[NSUserDefaults standardUserDefaults] boolForKey:@"UseWorkspaceThreads"] )
[NSThread detachNewThreadSelector:@selector(_detachedAppBasedFileOpen:)
toTarget:self
withObject:infoDict];
else
[self performSelector:@selector(_detachedAppBasedFileOpen:)
withObject:infoDict
afterDelay:0.5];
}
}
else if( flags.dragAccepting )
{
// Ok...seems like we are a folder and propably should trigger a copy or move operation based on the
// drag modifier that we have... or disable the drag if it violates the file system rules (e.g permission etc)
}
return YES;
}
- (BOOL)_applicationSupportsFile:(id)path
{
// We currently accept every file..no restriction what so ever... hmm.. thats definitly ugly.
// this will change at least for OpenStep applications where the necessary info should be in the Info.dict !
// <<HACK>> It definitly is a hack that we don't have a subclass ExecutableFile : File or that like which would
// handle this properly without all the ifs etc.
return YES;
}
- (void)_detachedAppBasedFileOpen:(id)infoDict
{
// Subppol needed if threaded...
id threadPool = [NSAutoreleasePool new];
id pathEnum = [[infoDict objectForKey:@"Files"] objectEnumerator];
id nextFile;
id appPath = [infoDict objectForKey:@"App"];
NSLog( @"Opening with info... %@", infoDict );
while( nextFile = [pathEnum nextObject] )
[[NSWorkspace sharedWorkspace] openFile:nextFile
withApplication:appPath
andDeactivate:YES];
[threadPool release];
}
@end
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.