/* NSColorList.m Manage named lists of NSColors. Copyright (C) 1996, 2000 Free Software Foundation, Inc. Author: Scott Christley Date: 1996 Author: Nicola Pero Date: January 2000 This file is part of the GNUstep GUI Library. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include #include #include #include #include #include #include #include #include #include #include #include // The list of available color lists is created only once -- this has // a drawback, that you need to restart your program to get the color // lists read again. static NSMutableArray *_gnustep_available_color_lists = nil; static NSLock *_gnustep_color_list_lock = nil; @implementation NSColorList // // Class methods // + (void)initialize { if (self == [NSColorList class]) { [self setVersion: 2]; } } /* * Private Method which loads the color lists. * Invoke if _gnustep_available_color_lists == nil * before any operation with that object or its lock. * * The aim is to defer reading the available color lists * till we really need to, so that only programs which really use * this feature get the overhead. */ + (void) _loadAvailableColorLists { NSString *dir; NSString *file; NSEnumerator *e; NSFileManager *fm = [NSFileManager defaultManager]; NSDirectoryEnumerator *de; NSColorList *newList; // Create the global array of color lists _gnustep_available_color_lists = [[NSMutableArray alloc] init]; /* * Load color lists found in standard paths into the array * FIXME: Check exactly where in the directory tree we should scan. */ e = [NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSAllDomainsMask, YES) objectEnumerator]; while ((dir = (NSString *)[e nextObject])) { dir = [dir stringByAppendingPathComponent: @"Colors"]; de = [fm enumeratorAtPath: dir]; while ((file = [de nextObject])) { if ([[file pathExtension] isEqualToString: @"clr"]) { file = [file stringByDeletingPathExtension]; newList = AUTORELEASE ([[NSColorList alloc] initWithName: file fromFile: dir]); [_gnustep_available_color_lists addObject: newList]; } } } // And create its access lock _gnustep_color_list_lock = [[NSLock alloc] init]; } /* * Getting All Color Lists */ + (NSArray*) availableColorLists { NSArray *a; if (_gnustep_available_color_lists == nil) [NSColorList _loadAvailableColorLists]; // Serialize access to color list [_gnustep_color_list_lock lock]; a = [NSArray arrayWithArray: _gnustep_available_color_lists]; [_gnustep_color_list_lock unlock]; return a; } /* * Getting a Color List by Name */ + (NSColorList *) colorListNamed: (NSString *)name { NSColorList *r; NSEnumerator *e; BOOL found = NO; if (_gnustep_available_color_lists == nil) [NSColorList _loadAvailableColorLists]; // Serialize access to color list [_gnustep_color_list_lock lock]; e = [_gnustep_available_color_lists objectEnumerator]; while ((r = (NSColorList *)[e nextObject])) { if ([[r name] isEqualToString: name]) { found = YES; break; } } [_gnustep_color_list_lock unlock]; if (found) return r; else return nil; } /* * Instance methods */ - (id) initWithName: (NSString *)name { return [self initWithName: name fromFile: nil]; } - (id) initWithName: (NSString *)name fromFile: (NSString *)path { NSColorList *cl; BOOL could_load = NO; ASSIGN (_name, name); if (path != nil) { ASSIGN (_fullFileName, [[path stringByAppendingPathComponent: name] stringByAppendingPathExtension: @"clr"]); // Unarchive the color list // TODO [Optm]: Rewrite to initialize directly without unarchiving // in another object cl = (NSColorList*)[NSUnarchiver unarchiveObjectWithFile: _fullFileName]; if (cl && [cl isKindOfClass: [NSColorList class]]) { could_load = YES; _is_editable = [[NSFileManager defaultManager] isWritableFileAtPath: _fullFileName]; ASSIGN(_colorDictionary, [NSMutableDictionary dictionaryWithDictionary: cl->_colorDictionary]); ASSIGN(_orderedColorKeys, [NSMutableArray arrayWithArray: cl->_orderedColorKeys]); } } if (could_load == NO) { _fullFileName = nil; _colorDictionary = [[NSMutableDictionary alloc] init]; _orderedColorKeys = [[NSMutableArray alloc] init]; _is_editable = YES; } return self; } - (void) dealloc { RELEASE (_name); TEST_RELEASE (_fullFileName); RELEASE (_colorDictionary); RELEASE (_orderedColorKeys); [super dealloc]; } /* * Getting a Color List by Name */ - (NSString *) name { return _name; } /* * Managing Colors by Key */ - (NSArray *) allKeys { return [NSArray arrayWithArray: _orderedColorKeys]; } - (NSColor *) colorWithKey: (NSString *)key { return [_colorDictionary objectForKey: key]; } - (void) insertColor: (NSColor *)color key: (NSString *)key atIndex: (unsigned)location { if (_is_editable == NO) [NSException raise: NSColorListNotEditableException format: @"Color list cannot be edited\n"]; [_colorDictionary setObject: color forKey: key]; [_orderedColorKeys removeObject: key]; [_orderedColorKeys insertObject: key atIndex: location]; [[NSNotificationCenter defaultCenter] postNotificationName: NSColorListChangedNotification object: self]; } - (void) removeColorWithKey: (NSString *)key { if (_is_editable == NO) [NSException raise: NSColorListNotEditableException format: @"Color list cannot be edited\n"]; [_colorDictionary removeObjectForKey: key]; [_orderedColorKeys removeObject: key]; [[NSNotificationCenter defaultCenter] postNotificationName: NSColorListChangedNotification object: self]; } - (void) setColor: (NSColor *)aColor forKey: (NSString *)key { if (_is_editable == NO) [NSException raise: NSColorListNotEditableException format: @"Color list cannot be edited\n"]; [_colorDictionary setObject: aColor forKey: key]; if ([_orderedColorKeys containsObject: key] == NO) [_orderedColorKeys addObject: key]; [[NSNotificationCenter defaultCenter] postNotificationName: NSColorListChangedNotification object: self]; } /* * Editing */ - (BOOL) isEditable { return _is_editable; } /* * Writing and Removing Files */ - (BOOL) writeToFile: (NSString *)path { NSFileManager *fm = [NSFileManager defaultManager]; NSString *tmpPath; BOOL isDir; BOOL success; BOOL path_is_standard = YES; /* * We need to initialize before saving, to avoid the new file being * counted as a different list thus making us appear twice */ if (_gnustep_available_color_lists == nil) [NSColorList _loadAvailableColorLists]; if (path == nil || ([fm fileExistsAtPath: path isDirectory: &isDir] == NO)) { // FIXME the standard path for saving color lists? path = [[NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES) objectAtIndex: 0] stringByAppendingPathComponent: @"Colors"]; isDir = YES; } if (isDir) { ASSIGN (_fullFileName, [[path stringByAppendingPathComponent: _name] stringByAppendingPathExtension: @"clr"]); } else // it is a file { _fullFileName = path; if ([[path pathExtension] isEqual: @"clr"] == YES) { ASSIGN (_fullFileName, path); } else { ASSIGN (_fullFileName, [[path stringByDeletingPathExtension] stringByAppendingPathExtension: @"clr"]); } } // Check if the path is a standard path if ([[path lastPathComponent] isEqualToString: @"Colors"] == NO) path_is_standard = NO; else { tmpPath = [path stringByDeletingLastPathComponent]; if (![NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSAllDomainsMask, YES) containsObject: tmpPath]) { path_is_standard = NO; } } /* * If path is standard and it does not exist, try to create it. * System standard paths should always be assumed to exist; * this will normally then only try to create user paths. */ if (path_is_standard && ([fm fileExistsAtPath: path] == NO)) { if([fm createDirectoryAtPath: path attributes: nil]) { NSLog (@"Created standard directory %@", path); } else { NSLog (@"Failed attemp to create directory %@", path); } } success = [NSArchiver archiveRootObject: self toFile: _fullFileName]; if (success && path_is_standard) { [_gnustep_color_list_lock lock]; if ([_gnustep_available_color_lists containsObject: self] == NO) [_gnustep_available_color_lists addObject: self]; [_gnustep_color_list_lock unlock]; return YES; } return NO; } - (void) removeFile { if (_fullFileName && _is_editable) { // Remove the file [[NSFileManager defaultManager] removeFileAtPath: _fullFileName handler: nil]; // Remove the color list from the global list of colors if (_gnustep_available_color_lists == nil) [NSColorList _loadAvailableColorLists]; [_gnustep_color_list_lock lock]; [_gnustep_available_color_lists removeObject: self]; [_gnustep_color_list_lock unlock]; // Reset file name _fullFileName = nil; } } - (void) encodeWithCoder: (NSCoder*)aCoder { [aCoder encodeObject: _name]; [aCoder encodeObject: _colorDictionary]; [aCoder encodeObject: _orderedColorKeys]; } - (id) initWithCoder: (NSCoder*)aDecoder { [aDecoder decodeValueOfObjCType: @encode(id) at: &_name]; [aDecoder decodeValueOfObjCType: @encode(id) at: &_colorDictionary]; [aDecoder decodeValueOfObjCType: @encode(id) at: &_orderedColorKeys]; return self; } @end