• R/O
  • HTTP
  • SSH
  • HTTPS

Frequently used words (click to add to your profile)

javac++androidlinuxc#windowsobjective-ccocoa誰得qtpythonphprubygameguibathyscaphec計画中(planning stage)翻訳omegatframeworktwitterdomtestvb.netdirectxゲームエンジンbtronarduinopreviewer

BathyScapheのSQLiteデータベース内を覗くアプリ


File Info

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

Content

#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