BathyScapheのSQLiteデータベース内を覗くアプリ
Révision | 1a0185e4c8ac650f5189d10bb15ceacc84689b19 |
---|---|
Taille | 10,644 octets |
l'heure | 2008-07-06 10:19:03 |
Auteur | masakih |
Message de Log | 情報削除時に同時にFavoritesも削除。
git-svn-id: svn+ssh://macmini/usr/local/svnrepos/BSDBViewer/BSDBViewer@13 477addb1-df5c-4826-a637-c2b1bdcd60d4
|
#import "BSDBViewer.h"
#import "BSDBBoardSource.h"
#import "BSDBThreadSource.h"
@implementation BSDBViewer
static NSString *const BSDBViewerSQLiteDBKey = @"BSDBViewerSQLiteDBKey";
static NSString *const InProgressKey = @"inProgress";
NSString *resolveAlias(NSString *path)
{
NSString *newPath = nil;
FSRef ref;
char *newPathCString;
Boolean isDir, wasAliased;
OSStatus err;
err = FSPathMakeRef( (UInt8 *)[path fileSystemRepresentation], &ref, NULL );
if( err == dirNFErr ) {
NSString *lastPath = [path lastPathComponent];
NSString *parent = [path stringByDeletingLastPathComponent];
NSString *f;
if( [@"/" isEqualTo:parent] ) return nil;
parent = resolveAlias( parent );
if( !parent ) return nil;
f = [parent stringByAppendingPathComponent:lastPath];
err = FSPathMakeRef( (UInt8 *)[f fileSystemRepresentation], &ref, NULL );
}
if( err != noErr ) {
return nil;
}
err = FSResolveAliasFile( &ref, TRUE, &isDir, &wasAliased );
if( err != noErr ) {
return nil;
}
newPathCString = (char *)malloc( sizeof(unichar) * 1024 );
if( !newPathCString ) {
return nil;
}
err = FSRefMakePath( &ref, (UInt8 *)newPathCString, sizeof(unichar) * 1024 );
if( err != noErr ) {
goto final;
}
newPath = [NSString stringWithUTF8String:newPathCString];
final:
free( (char *)newPathCString );
return newPath;
}
+ (NSString *)appSupportFolder
{
OSErr err;
FSRef ref;
UInt8 path[PATH_MAX];
err = FSFindFolder(kUserDomain, kApplicationSupportFolderType, YES, &ref);
if( noErr != err) return nil;
err = FSRefMakePath(&ref, path, PATH_MAX);
if(noErr != err) return nil;
return [[NSFileManager defaultManager] stringWithFileSystemRepresentation:(char *)path
length:strlen((char *)path)];
}
+ (NSString *)BSSupportFolder
{
id res = [self appSupportFolder];
res = [res stringByAppendingPathComponent:@"BathyScaphe"];
return resolveAlias(res);
}
+ (NSString *)BSDocumentFolder
{
id res = [self BSSupportFolder];
res = [res stringByAppendingPathComponent:@"Documents"];
return resolveAlias(res);
}
+ (NSString *)databasePath
{
id res = [self BSSupportFolder];
res = [res stringByAppendingPathComponent:@"BathyScaphe.db"];
return resolveAlias(res);
}
+ (SQLiteDB *)sqliteDB
{
SQLiteDB *result = nil;
NSThread *thread = [NSThread currentThread];
id info = [thread threadDictionary];
result = [info objectForKey:BSDBViewerSQLiteDBKey];
if(!result) {
result = [[[SQLiteDB alloc] initWithDatabasePath:[self databasePath]] autorelease];
if(!result) {
NSLog(@"Can not allocate SQLiteDB.");
return nil;
}
[info setObject:result forKey:BSDBViewerSQLiteDBKey];
[result open];
}
return result;
}
- (SQLiteDB *)sqliteDB
{
return [[self class] sqliteDB];
}
- (NSString *)nameOfBathyScaphe
{
NSUserDefaults *d = [NSUserDefaults standardUserDefaults];
NSString *bundleID = [d stringForKey:@"OpenApplicationBundleID"];
if(!bundleID) return @"BathyScaphe";
NSWorkspace *w = [NSWorkspace sharedWorkspace];
NSString *app = [w absolutePathForAppBundleWithIdentifier:bundleID];
if(!app) return @"BathyScaphe";
return [app lastPathComponent];
}
#pragma mark-
- (void)setInProgress:(BOOL)new
{
//
}
- (BOOL)inProgress
{
return progressStack != 0;
}
- (void)incrementProgressStack
{
[self willChangeValueForKey:InProgressKey];
progressStack++;
[self didChangeValueForKey:InProgressKey];
}
- (void)decrementProgressStack
{
[self willChangeValueForKey:InProgressKey];
progressStack--;
[self didChangeValueForKey:InProgressKey];
}
#pragma mark-
- (NSString *)boardNameFromBoardID:(id)boardID
{
NSString *result = [boardNameCache objectForKey:boardID];
if(result) return result;
NSString *query = [NSString stringWithFormat:@"SELECT boardname FROM boardInfo "
@"WHERE boardid = %@"
,
boardID];
SQLiteDB *db = [self sqliteDB];
id cursor;
if([db beginTransaction]) {
cursor = [db cursorForSQL:query];
if([db lastErrorID] != 0) {
NSLog(@"Fail Sending Query: %@", query);
NSLog(@"SQLite Error: %@", [db lastError]);
}
[db commitTransaction];
}
NSString *boardName = [cursor valueForColumn:@"boardname" atRow:0];
if(!boardName) return nil;
[boardNameCache setObject:boardName forKey:boardID];
return boardName;
}
- (NSString *)pathForThreadID:(id)threadID boardID:(id)boardID
{
if(!threadID || !boardID) return nil;
NSString *path = [[self class] BSDocumentFolder];
NSString *boardName = [self boardNameFromBoardID:boardID];
if(!boardName) {
NSLog(@"Can not find boardName from boardID(%@).", boardID);
return nil;
}
path = [path stringByAppendingPathComponent:boardName];
path = [path stringByAppendingPathComponent:threadID];
path = [path stringByAppendingPathExtension:@"thread"];
return path;
}
- (void) openInBSThreadID:(id)threadID boardID:(id)boardID
{
[[NSWorkspace sharedWorkspace] openFile:[self pathForThreadID:threadID boardID:boardID]
withApplication:[self nameOfBathyScaphe]];
}
- (void)openThreadsInBS:(NSArray *)infos
{
id enume = [infos objectEnumerator];
id obj;
id targetBoardID = [threadSource boardID];
while(obj = [enume nextObject]) {
id threadID = [obj objectForKey:@"threadid"];
if(!threadID) continue;
[self openInBSThreadID:threadID boardID:targetBoardID];
}
}
- (void)deleteThreadInformations:(NSArray *)infos
{
NSString *query =
@"DELETE FROM ? "
@"WHERE "
@"boardid = ? "
@"AND "
@"threadid = ?";
SQLiteDB *db = [self sqliteDB];
SQLiteReservedQuery *deleQ = [db reservedQuery:query];
id enume = [infos objectEnumerator];
id obj;
id targetBoardID = [threadSource boardID];
[self incrementProgressStack];
[db beginTransaction];
while(obj = [enume nextObject]) {
id info = [obj objectForKey:@"threadid"];
if(!info) continue;
NSArray *values = [NSArray arrayWithObjects:
@"ThreadInfo",
targetBoardID, info, nil];
[deleQ cursorForBindValues:values];
if([db lastErrorID] != 0) {
NSLog(@"Fail DELETE thread info: %@", obj);
NSLog(@"Fail Sending Query: %@", query);
NSLog(@"SQLite Error: %@", [db lastError]);
goto abort;
}
values = [NSArray arrayWithObjects:
@"Favorites",
targetBoardID, info, nil];
[deleQ cursorForBindValues:values];
if([db lastErrorID] != 0) {
NSLog(@"Fail DELETE Favorites: %@", obj);
NSLog(@"Fail Sending Query: %@", query);
NSLog(@"SQLite Error: %@", [db lastError]);
goto abort;
}
}
[db commitTransaction];
[threadSource update:self];
[self decrementProgressStack];
return;
abort:
[db rollbackTransaction];
[self decrementProgressStack];
}
- (NSArray *)targetObjectsInTableView:(id)view arrayController:(NSArrayController *)ac
{
NSArray *result;
NSEvent *event = [NSApp currentEvent];
NSPoint mouse = [event locationInWindow];
mouse = [view convertPoint:mouse fromView:nil];
unsigned rowAtMouse = [view rowAtPoint:mouse];
NSIndexSet *selected = [view selectedRowIndexes];
if([selected containsIndex:rowAtMouse]) {
result = [ac selectedObjects];
} else {
result = [NSArray arrayWithObject:[[ac arrangedObjects] objectAtIndex:rowAtMouse]];
}
return result;
}
- (IBAction)deleteThreadInfo:(id)sender
{
NSArray *infos = [self targetObjectsInTableView:threadView arrayController:threadArrayController];
[self performSelector:@selector(deleteThreadInformations:)
withObject:infos
afterDelay:0.0];
}
- (IBAction)showThreadInfo:(id)sender
{
}
- (IBAction)openInBathyScaphe:(id)sender
{
NSArray *infos = [self targetObjectsInTableView:threadView arrayController:threadArrayController];
[self performSelector:@selector(openThreadsInBS:)
withObject:infos
afterDelay:0.0];
}
#pragma mark-
- (void)beginUpdateBoardData:(id)dataSource
{
[self incrementProgressStack];
}
- (void)finishUpdateBoardData:(id)dataSource
{
[self decrementProgressStack];
}
- (void)beginUpdateThreadData:(id)dataSource
{
[self incrementProgressStack];
}
- (void)finishUpdateThreadData:(id)dataSource
{
[self decrementProgressStack];
}
- (void)awakeFromNib
{
[boardSource update:self];
[window setExcludedFromWindowsMenu:YES];
}
@end
@implementation BSDBViewer(NSMenuValidation)
- (BOOL)validateMenuItem:(NSMenuItem *)menuItem
{
if(@selector(showThreadInfo:) == [menuItem action]) return NO;
if(@selector(openInBathyScaphe:) == [menuItem action]) {
id selection = [self targetObjectsInTableView:threadView
arrayController:threadArrayController];
if([selection count] != 1) return NO;
NSString *path = [self pathForThreadID:[[selection objectAtIndex:0] objectForKey:@"threadid"]
boardID:[threadSource boardID]];
if(!path) return NO;
BOOL isDir = NO;
if(![[NSFileManager defaultManager] fileExistsAtPath:path isDirectory:&isDir]
|| isDir) return NO;
}
return YES;
}
@end
@implementation BSDBViewer(NSApplicationDelegate)
- (void)applicationDidFinishLaunching:(NSNotification *)notification
{
[NSValueTransformer setValueTransformer:[[[BSDBDateTransformer alloc] init] autorelease]
forName:@"BSDBDateTransformer"];
[NSValueTransformer setValueTransformer:[[[BSDBNumberTransformer alloc] init] autorelease]
forName:@"BSDBNumberTransformer"];
}
- (BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication *)sender
{
return YES;
}
@end
@implementation BSDBViewer(NSTableViewDelegate)
- (void)boardListSelectionDidChange
{
NSIndexSet *selectedIndexes = [boardArrayController selectionIndexes];
if([selectedIndexes count] != 1) return;
id selection = [boardArrayController valueForKeyPath:@"selection.boardid"];
[threadSource setBoardID:selection];
}
- (void)tableViewSelectionDidChange:(NSNotification *)notification
{
id obj = [notification object];
if([obj isEqual:boardView]) {
[self boardListSelectionDidChange];
return;
}
}
@end
#pragma mark-
@implementation BSDBDateTransformer
- (id)transformedValue:(id)value
{
if(!value) return nil;
return [NSDate dateWithTimeIntervalSince1970:[value doubleValue]];
}
- (id)reverseTransformedValue:(id)value
{
if(!value) return nil;
return [NSString stringWithFormat:@"%.0f",[value timeIntervalSince1970]];
}
@end
@implementation BSDBNumberTransformer
- (id)transformedValue:(id)value
{
if(!value) return nil;
return [NSNumber numberWithInt:[value intValue]];
}
- (id)reverseTransformedValue:(id)value
{
if(!value) return nil;
return [NSString stringWithFormat:@"%d",[value intValue]];
}
@end
#pragma mark-
@implementation NSString(BSDBViewerOrdering)
- (NSComparisonResult)numericCompare:(id)obj
{
if(!obj) return NSOrderedDescending;
return [self compare:obj options:NSNumericSearch];
}
@end