/* ============================================================================= PROJECT: Filie FILE: UKFolderMetaStorage.m COPYRIGHT: (c) 2004 by M. Uli Kusterer, all rights reserved. AUTHORS: M. Uli Kusterer - UK LICENSES: GNU GPL REVISIONS: 2004-11-30 UK Created. ========================================================================== */ // ----------------------------------------------------------------------------- // Headers: // ----------------------------------------------------------------------------- #import #import "UKFolderMetaStorage.h" @implementation UKFolderMetaStorage // ----------------------------------------------------------------------------- // storageForURL: // Factory method that creates a storage object for an item (usually a // file) that has the specified URL. Calls initForURL:. // // REVISIONS: // 2004-12-22 UK Documented. // ----------------------------------------------------------------------------- +(id) storageForURL: (NSURL*)url { return [[[[self class] alloc] initForURL: url] autorelease]; } // ----------------------------------------------------------------------------- // initForURL: // Constructor that creates a storage object for an item (usually a // file) that has the specified URL. // // REVISIONS: // 2004-12-22 UK Documented. // ----------------------------------------------------------------------------- -(id) initForURL: (NSURL*)url { self = [super init]; if( !self ) return nil; folderURL = [url retain]; NSURL* storeURL = [self storageFileURL]; NSData* data = [NSData dataWithContentsOfURL: storeURL]; if( data ) { NS_DURING storage = [[NSUnarchiver unarchiveObjectWithData: data] retain]; NS_HANDLER NSLog(@"Error loading meta storage file %@",storeURL); storage = nil; NS_ENDHANDLER } if( !storage ) storage = [[NSMutableDictionary alloc] init]; return self; } // ----------------------------------------------------------------------------- // dealloc: // Destructor. // // REVISIONS: // 2004-12-22 UK Documented. // ----------------------------------------------------------------------------- -(void) dealloc { [self synchronize]; [storage release]; [folderURL release]; [super dealloc]; } // ----------------------------------------------------------------------------- // setObject:forKey: // Attach a property with the specified key/value combination to the // file/folder represented by this storage. Used to e.g. keep around the // dimensions of the window displayed for a folder. // // REVISIONS: // 2004-12-22 UK Documented. // ----------------------------------------------------------------------------- -(void) setObject: (id)obj forKey: (NSString*)key { [storage setObject: obj forKey: key]; } // ----------------------------------------------------------------------------- // objectForKey: // Return a property of the storage's file based on its key. Counterpart // to setObject:forKey:. // // REVISIONS: // 2004-12-22 UK Documented. // ----------------------------------------------------------------------------- -(id) objectForKey: (NSString*)key { return [storage objectForKey: key]; } // ----------------------------------------------------------------------------- // dictionaryForFile: // Return a dictionary of properties for a particular file in this storage, // specified by its name (not by its path). This usually only makes sense // if this storage is for a folder or smart folder which may contain other // files. // // Returns NIL if there is no information for a file of that name in the // storage yet. // // REVISIONS: // 2004-12-22 UK Documented. // ----------------------------------------------------------------------------- -(NSMutableDictionary*) dictionaryForFile: (NSString*)filename { NSMutableDictionary* dict = [storage objectForKey: @"FileInfo"]; return [dict objectForKey: filename]; } // ----------------------------------------------------------------------------- // newDictionaryForFile: // Like dictionaryForFile:, but this creates a dictionary and associates // it with the specified file name if there isn't one yet. // // REVISIONS: // 2004-12-22 UK Documented. // ----------------------------------------------------------------------------- -(NSMutableDictionary*) newDictionaryForFile: (NSString*)filename { NSMutableDictionary* dict = [storage objectForKey: @"FileInfo"]; if( !dict ) { dict = [NSMutableDictionary dictionary]; [storage setObject: dict forKey: @"FileInfo"]; } NSMutableDictionary* info = [dict objectForKey: filename]; if( !info ) { info = [NSMutableDictionary dictionary]; [dict setObject: info forKey: filename]; } return info; } // ----------------------------------------------------------------------------- // synchronize: // Write changes made to the storage to disk. // // REVISIONS: // 2004-12-22 UK Documented. // ----------------------------------------------------------------------------- -(BOOL) synchronize { NSURL* storeURL = [self storageFileURL]; NSData* data = [NSArchiver archivedDataWithRootObject: storage]; return [data writeToURL: storeURL atomically: NO]; } // ----------------------------------------------------------------------------- // clean: // Remove any unused entries for files that no longer exist from the // storage. Not yet implemented. Should probably change to use the file // data source to find out whether a file exists. // // REVISIONS: // 2004-12-22 UK Documented. // ----------------------------------------------------------------------------- -(void) clean { } // ----------------------------------------------------------------------------- // setDisplayRect: // Shorthand for storing the @"DisplayRect" property in the storage. Used // for saving position and dimensions of the window. // // REVISIONS: // 2004-12-22 UK Documented. // ----------------------------------------------------------------------------- -(void) setDisplayRect: (NSRect)box { [storage setObject: [NSValue valueWithRect: box] forKey: @"DisplayRect"]; } // ----------------------------------------------------------------------------- // displayRect: // Shorthand for getting the @"DisplayRect" property from the storage. // Counterpart to setDisplayRect:. // // REVISIONS: // 2004-12-22 UK Documented. // ----------------------------------------------------------------------------- -(NSRect) displayRect { NSValue* val = [storage objectForKey: @"DisplayRect"]; if( !val ) return NSMakeRect(50,50,512,342); return [val rectValue]; } // ----------------------------------------------------------------------------- // folderURL: // Return the URL for which this storage was created. This is the URL // passed to initForURL. // // REVISIONS: // 2004-12-22 UK Documented. // ----------------------------------------------------------------------------- -(void) testFolderURL { NSFileManager* fm = [NSFileManager defaultManager]; BOOL dir; self = [UKFolderMetaStorage storageForURL: [NSURL fileURLWithPath: @"~/"]]; UKTrue( [fm fileExistsAtPath: [[self folderURL] path] isDirectory: &dir] ); self = [UKFolderMetaStorage storageForURL: [NSURL fileURLWithPath: @"/TestMustFail"]]; UKFalse( [fm fileExistsAtPath: [[self folderURL] path] isDirectory: &dir] ); } -(NSURL*) folderURL { return folderURL; } // ----------------------------------------------------------------------------- // storageFileURL: // Return the URL for the on-disk file used for the storage. Used // internally to make it easy to change the scheme used. // // REVISIONS: // 2004-12-22 UK Documented. // ----------------------------------------------------------------------------- -(void) testStorageFileURL { NSFileManager* fm = [NSFileManager defaultManager]; NSURL* url; NSString* folder; NSString* systemStore = [@"~/GNUstep/Library/Etoile/Workspace" stringByExpandingTildeInPath]; NSString* localStore; NSString* theName; BOOL dir; self = [UKFolderMetaStorage storageForURL: [NSURL fileURLWithPath: @"~/"]]; url = [self storageFileURL]; NSLog(@"Folder %@", [[self folderURL] path]); UKTrue( [fm isReadableFileAtPath: [[[self folderURL] path] stringByStandardizingPath]] ); UKTrue( [fm isReadableFileAtPath: [[self folderURL] path]] ); UKNotNil( url ); UKTrue( [fm fileExistsAtPath: systemStore isDirectory: &dir] ); systemStore = [systemStore stringByAppendingPathComponent: @"Meta Data"]; UKTrue( [fm fileExistsAtPath: systemStore isDirectory: &dir] ); localStore = [[[self folderURL] path] stringByAppendingPathComponent: @".Filie_Store"]; NSLog(@"%@ %@", [[[self storageFileURL] path] stringByStandardizingPath], [localStore stringByStandardizingPath]); UKStringsEqual( [[[self storageFileURL] path] stringByStandardizingPath], [localStore stringByStandardizingPath]); self = [UKFolderMetaStorage storageForURL: [NSURL fileURLWithPath: @"/bin"]]; theName = [[folderURL absoluteString] stringByAddingPercentEscapesUsingEncoding: NSUTF8StringEncoding]; UKFalse( [fm isReadableFileAtPath: [[self folderURL] path]] ); UKFalse( [fm isReadableFileAtPath: [[self folderURL] path]] ); UKStringsEqual( [[[self storageFileURL] path] stringByStandardizingPath], [[systemStore stringByAppendingPathComponent: theName] stringByStandardizingPath] ); } -(NSURL*) storageFileURL { NSString* storageFolder = nil; NSString* theName = nil; BOOL dir; // Pre-generate some path stuff we may need: #ifndef __ETOILE__ storageFolder = [@"~/Library/Application Support/Filie/" stringByExpandingTildeInPath]; if( ![[NSFileManager defaultManager] fileExistsAtPath: storageFolder isDirectory: &dir] ) [[NSFileManager defaultManager] createDirectoryAtPath:storageFolder attributes:[NSDictionary dictionary]]; #else storageFolder = [@"~/GNUstep/Library/Etoile" stringByExpandingTildeInPath]; if( ![[NSFileManager defaultManager] fileExistsAtPath: storageFolder isDirectory: &dir] ) [[NSFileManager defaultManager] createDirectoryAtPath:storageFolder attributes:[NSDictionary dictionary]]; storageFolder = [@"~/GNUstep/Library/Etoile/Workspace" stringByExpandingTildeInPath]; if( ![[NSFileManager defaultManager] fileExistsAtPath: storageFolder isDirectory: &dir] ) [[NSFileManager defaultManager] createDirectoryAtPath:storageFolder attributes:[NSDictionary dictionary]]; #endif storageFolder = [storageFolder stringByAppendingPathComponent: @"Meta Data"]; if( ![[NSFileManager defaultManager] fileExistsAtPath: storageFolder isDirectory: &dir] ) [[NSFileManager defaultManager] createDirectoryAtPath:storageFolder attributes:[NSDictionary dictionary]]; // FIXME: write a test for remote URL. // Remote URL or so? Generate local storage file: if( ![folderURL isFileURL] ) { theName = [[folderURL absoluteString] stringByAddingPercentEscapesUsingEncoding: NSUTF8StringEncoding]; return [NSURL fileURLWithPath: [storageFolder stringByAppendingPathComponent: theName]]; } // Generate path for .Filie_Store file, if that isn't writable, generate local storage file: NSString* storePath = [[folderURL path] stringByAppendingPathComponent: @".Filie_Store"]; // FIXME: is this commented line really needed ? //if( ![[[NSFileManager defaultManager] fileSystemAttributesAtPath: storePath] fileIsImmutable] // && if ( ![[NSFileManager defaultManager] isWritableFileAtPath: [folderURL path]] || ![[NSFileManager defaultManager] isReadableFileAtPath: [folderURL path]] ) { theName = [[folderURL absoluteString] stringByAddingPercentEscapesUsingEncoding: NSUTF8StringEncoding]; return [NSURL fileURLWithPath: [storageFolder stringByAppendingPathComponent: theName]]; } else return [NSURL fileURLWithPath: storePath]; } // ----------------------------------------------------------------------------- // isEmpty: // Returns YES if this is a new, empty storage. You can use this to // optimize your code when a folder is initially loaded. // // REVISIONS: // 2004-12-22 UK Documented. // ----------------------------------------------------------------------------- -(BOOL) isEmpty { NSDictionary* infos = [storage objectForKey: @"FileInfo"]; return( !infos || [infos count] == 0 ); } @end