/* ** Sources.m ** ** Copyright (c) 2004 ** ** Author: Yen-Ju Chen ** ** This program is free software; you can redistribute it and/or modify ** it under the terms of the GNU General Public License as published by ** the Free Software Foundation; either version 2 of the License, or ** (at your option) any later version. ** ** This program 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 General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program; if not, write to the Free Software ** Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "Sources.h" #include "FolderSource.h" #include "SmartFolderSource.h" #include "LibrarySource.h" /* Source array of dictionary */ static NSString *SourceTypeKey = @"SourceTypeKey"; static NSString *LibrarySourceType = @"LibrarySourceType"; static NSString *NoteSourceType = @"NoteSourceType"; static NSString *FolderSourceType = @"FolderSourceType"; static NSString *SmartFolderSourceType = @"SmartFolderSourceType"; static NSString *SearchSourceType = @"SearchSourceType"; static NSString *UnknownSourceType = @"UnknownSourcetype"; static NSString *SourceResourcePathKey = @"SourceResourcePathKey"; static NSString *SourceContainerKey = @"SourceContainerKey"; static NSString *SourceIndexPathKey = @"SourceIndexPathKey"; static Sources *sharedInstance = nil; SourceType SourceTypeFromString (NSString *type) { if ([type isEqualToString: LibrarySourceType]) return SourceLibraryType; else if ([type isEqualToString: NoteSourceType]) return SourceNoteType; else if ([type isEqualToString: FolderSourceType]) return SourceFolderType; else if ([type isEqualToString: SmartFolderSourceType]) return SourceSmartFolderType; else if ([type isEqualToString: SearchSourceType]) return SourceSearchType; else return SourceUnknownType; } @interface NSDictionary (SourceTypeComparison) - (NSComparisonResult) sourceCompareType: (NSDictionary *) dictionary; @end @implementation NSDictionary (SourceTypeComparison) - (NSComparisonResult) sourceCompareType: (NSDictionary *) dictionary { /* Compare type first */ SourceType selfType = SourceTypeFromString([self objectForKey: SourceTypeKey]); SourceType otherType = SourceTypeFromString([dictionary objectForKey: SourceTypeKey]); if (selfType == otherType) { return [(NSString *)[self objectForKey: TitleKey] caseInsensitiveCompare: [dictionary objectForKey: TitleKey]]; } else if (selfType < otherType) { return NSOrderedAscending; } else { return NSOrderedDescending; } } @end @implementation Sources - (NSString *) _stringFromType: (SourceType) type { NSString *typeString; switch(type) { case SourceLibraryType: typeString = LibrarySourceType; break; case SourceNoteType: typeString = NoteSourceType; break; case SourceFolderType: typeString = FolderSourceType; break; case SourceSmartFolderType: typeString = SmartFolderSourceType; break; case SourceSearchType: typeString = SearchSourceType; break; default: typeString = nil; } return typeString; } /* override */ - (BOOL) isDuplicatedTitle: (NSString *) title skipIndex: (unsigned int) index { if ([title isEqualToString: sSearch]) { return YES; } return [super isDuplicatedTitle: title skipIndex: index]; } - (void) setTitle: (NSString *) title atIndex: (unsigned int) index { [super setTitle: title atIndex: index]; [self sort]; } /* sorting */ - (void) sort { [container sortUsingSelector: @selector(sourceCompareType:)]; } /* write accessory */ - (void) newSource: (NSString *) title ofType: (SourceType) type { /*8 Check the vaoid type */ NSString *typeString = [self _stringFromType: type]; if ((typeString == nil) || (title == nil))return; unsigned int index = [self newTitle: title]; [self setType: type atIndex: index]; if (type != SourceNoteType) { [self setUniqueNumber: NSNotFound atIndex: index]; } [self sort]; } - (void) newSource: (NSString *) title ofType: (SourceType) type atIndex: (unsigned int) row { /*8 Check the vaoid type */ NSString *typeString = [self _stringFromType: type]; if ((typeString == nil) || (title == nil))return; if (row >= [self count]) { [self newSource: title ofType: type]; return; } unsigned int index = [self newTitle: title atIndex: row]; [self setType: type atIndex: index]; if (type != SourceNoteType) { [self setUniqueNumber: NSNotFound atIndex: index]; } } - (void) setType: (SourceType) type atIndex: (unsigned int) index { NSString *typeString = [self _stringFromType: type]; if (typeString == nil) return; [self setObject: [self _stringFromType: type] atIndex: index forKey: SourceTypeKey]; if (type != SourceNoteType) { [self setUniqueNumber: NSNotFound atIndex: index]; } } - (void) setResourcePath: (NSString *) resource atIndex: (unsigned int) index { if ((index == NSNotFound) || (index >= [self count]) || (resource == nil)) return; [self setObject: resource atIndex: index forKey: SourceResourcePathKey]; } - (void) setIndexPath: (NSString *) absolutePath atIndex: (unsigned int) index { if ((index == NSNotFound) || (index >= [self count]) || (absolutePath == nil)) return; [self setObject: absolutePath atIndex: index forKey: SourceIndexPathKey]; } - (void) removeContainerAtIndex: (unsigned int) index { if ((index == NSNotFound) || (index >= [self count])) return; [(NSMutableDictionary *)[container objectAtIndex: index] removeObjectForKey: SourceContainerKey]; } /* read accessory */ - (SourceType) typeOfSourceAtIndex: (unsigned int) index { if (index >= [self count]) return SourceErrorType; NSString *type = [self objectAtIndex: index forKey: SourceTypeKey]; return SourceTypeFromString(type); } - (NSString *) resourcePathAtIndex: (unsigned int) index { if ((index == NSNotFound) || (index >= [self count])) return; return [self objectAtIndex: index forKey: SourceResourcePathKey]; } - (NSString *) resourceFullPathAtIndex: (unsigned int) index { if ((index == NSNotFound) || (index >= [self count])) return; NSString *path = [self objectAtIndex: index forKey: SourceResourcePathKey]; return [[[self path] stringByDeletingLastPathComponent] stringByAppendingPathComponent: path]; } - (NSString *) indexPathAtIndex: (unsigned int) index { if ((index == NSNotFound) || (index >= [self count])) return; return [self objectAtIndex: index forKey: SourceIndexPathKey]; } - (void) setContainer: (id) object atIndex: (unsigned int) index { if ((index == NSNotFound) || (index >= [self count]) || (object == nil)) return; [self setObject: object atIndex: index forKey: SourceContainerKey]; } - (id) containerAtIndex: (unsigned int) index { if ((index == NSNotFound) || (index >= [self count])) return nil; return [(NSDictionary *)[container objectAtIndex: index] objectForKey: SourceContainerKey]; } /* Basic methods */ + (Sources *) sharedSources { if (sharedInstance == nil) { sharedInstance = [[Sources alloc] init]; } return sharedInstance; } - (void) _loadOtherSources { /* Load Folder */ unsigned int i, count = [self count]; SourceType type; id object; NSString *loadPath; for(i = 0; i < count; i++) { type = [self typeOfSourceAtIndex: i]; loadPath = [self resourceFullPathAtIndex: i]; switch(type) { case SourceFolderType: object = [[FolderSource alloc] init]; break; case SourceSmartFolderType: object = [[SmartFolderSource alloc] init]; break; case SourceNoteType: /* Fix old version */ if ([self uniqueNumberAtIndex: i] == NSNotFound) { LibrarySource *library = [LibrarySource sharedSource]; unsigned int index = [library indexOfTitle: [self titleAtIndex: i]]; unsigned int uid = [library uniqueNumberAtIndex: index]; [self setUniqueNumber: uid atIndex: i]; } continue; case SourceSearchType: /* never load */ default: continue; } [object loadSourceAtPath: loadPath]; [self setContainer: object atIndex: i]; } } /* called in applicationWillFinishLaunching */ - (BOOL) loadSourceAtPath: (NSString *) path { BOOL loadResult, isDir, rebuildSource = YES; NSFileManager *fm = [NSFileManager defaultManager]; if ([super loadSourceAtPath: path] == NO) return NO; NSString *sourcePath = [self path]; if (sourcePath == nil) return NO; if ([fm fileExistsAtPath: sourcePath isDirectory: &isDir]) { if (isDir == YES) { int result = NSRunAlertPanel(sFileError, [NSString stringWithFormat: sSourceNotValid_, sourcePath], sRebuild, sCancelAndQuit, nil, nil); if (result != NSAlertDefaultReturn) { return NO; } if ([fm removeFileAtPath: sourcePath handler: nil] == NO) { NSRunAlertPanel(sFileError, [NSString stringWithFormat: sCannotRebuildSource_, sourcePath], sQuit, nil, nil, nil); return NO; } rebuildSource = YES; } else { BOOL loadResult = [self readFromFile: sourcePath]; if (loadResult == NO) { int result = NSRunAlertPanel(sFileError, [NSString stringWithFormat: sSourceNotValid_, sourcePath], sRebuild, sCancelAndQuit, nil, nil); if (result != NSAlertDefaultReturn) { return NO; } if ([fm removeFileAtPath: sourcePath handler: nil] == NO) { NSRunAlertPanel(sFileError, [NSString stringWithFormat: sCannotRebuildSource_, sourcePath], sQuit, nil, nil, nil); return NO; } } else { /* make a backup */ makeBackup(sourcePath); rebuildSource = NO; [self _loadOtherSources]; } } } else { /* Check backup file */ NSString *backup = [sourcePath stringByAppendingString: @"~"]; loadResult = [self readFromFile: backup]; if (loadResult == YES) { int result = NSRunAlertPanel(sFileError, [NSString stringWithFormat: sFileNotExistWantBackup____, sSource, sourcePath, sSource, sSource], sYES, sNO, nil, nil); if (result == NSAlertDefaultReturn) { [self _loadOtherSources]; return YES; } } rebuildSource = YES; } if (rebuildSource == YES) { [container removeAllObjects]; [self newSource: sLibrary ofType: SourceLibraryType]; } return YES; } /* Called in shouldTerminate */ - (BOOL) unloadSourceAtPath: (NSString *) absolutePath { /* unload each Folder */ unsigned i, count = [self count]; unsigned int index; SourceType type; BOOL result; id object; NSString *path; /* remove search first */ index = [self indexOfTitle: sSearch]; [self removeObjectAtIndex: index]; for (i = 0; i < count; i++) { type = [self typeOfSourceAtIndex: i]; switch(type) { case SourceFolderType: case SourceSmartFolderType: object = [self containerAtIndex: i]; if (object == nil) { NSLog(@"internal Error: SourceResourceName exist, but there is no SourceContainer."); continue; } path = [self resourceFullPathAtIndex: i]; result = [object unloadSourceAtPath: path]; if (result == NO) return NO; [self removeContainerAtIndex: i]; break; } } /* Always saved to fixed file */ if ([super unloadSourceAtPath: nil] == NO) { int result = NSRunAlertPanel(sFileErrorWrite, [NSString stringWithFormat: sCannotSaveSource_, [self path]], sDontQuit, sQuit, nil, nil); if (result == NSAlertDefaultReturn) return NO; } return YES; } @end