// // GitTest_AppDelegate.m // GitTest // // Created by Pieter de Bie on 13-06-08. // Copyright __MyCompanyName__ 2008 . All rights reserved. // #import "ApplicationController.h" #import "PBGitRevisionCell.h" #import "PBGitWindowController.h" #import "PBRepositoryDocumentController.h" #import "PBCLIProxy.h" #import "PBServicesController.h" #import "PBGitXProtocol.h" #import "PBPrefsWindowController.h" #import "PBNSURLPathUserDefaultsTransfomer.h" #import "PBGitDefaults.h" @implementation ApplicationController @synthesize cliProxy; - (ApplicationController*)init { #ifdef DEBUG_BUILD [NSApp activateIgnoringOtherApps:YES]; #endif if(self = [super init]) { if(![[NSBundle bundleWithPath:@"/System/Library/PrivateFrameworks/QuickLookUI.framework"] load]) NSLog(@"Could not load QuickLook"); self.cliProxy = [PBCLIProxy new]; } /* Value Transformers */ NSValueTransformer *transformer = [[PBNSURLPathUserDefaultsTransfomer alloc] init]; [NSValueTransformer setValueTransformer:transformer forName:@"PBNSURLPathUserDefaultsTransfomer"]; // Make sure the PBGitDefaults is initialized, by calling a random method [PBGitDefaults class]; return self; } - (void)registerServices { // Register URL [NSURLProtocol registerClass:[PBGitXProtocol class]]; // Register the service class PBServicesController *services = [[PBServicesController alloc] init]; [NSApp setServicesProvider:services]; // Force update the services menu if we have a new services version int serviceVersion = [[NSUserDefaults standardUserDefaults] integerForKey:@"Services Version"]; if (serviceVersion < 2) { NSLog(@"Updating services menu…"); NSUpdateDynamicServices(); [[NSUserDefaults standardUserDefaults] setInteger:2 forKey:@"Services Version"]; } } - (void)applicationDidFinishLaunching:(NSNotification*)notification { [self registerServices]; // Only try to open a default document if there are no documents open already. // For example, the application might have been launched by double-clicking a .git repository, // or by dragging a folder to the app icon if ([[[PBRepositoryDocumentController sharedDocumentController] documents] count]) return; if (![[NSApplication sharedApplication] isActive]) return; NSURL *url = nil; // Try to find the current directory, to open that as a repository if ([PBGitDefaults openCurDirOnLaunch]) { NSString *curPath = [[[NSProcessInfo processInfo] environment] objectForKey:@"PWD"]; if (curPath) url = [NSURL fileURLWithPath:curPath]; } // Try to open the found URL NSError *error = nil; if (url && [[PBRepositoryDocumentController sharedDocumentController] openDocumentWithContentsOfURL:url display:YES error:&error]) return; // The current directory was not enabled or could not be opened (most likely it’s not a git repository). // show an open panel for the user to select a repository to view if ([PBGitDefaults showOpenPanelOnLaunch]) [[PBRepositoryDocumentController sharedDocumentController] openDocument:self]; } - (void) windowWillClose: sender { [firstResponder terminate: sender]; } - (IBAction)openPreferencesWindow:(id)sender { [[PBPrefsWindowController sharedPrefsWindowController] showWindow:nil]; } - (IBAction)showAboutPanel:(id)sender { NSString *gitversion = [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleGitVersion"]; NSMutableDictionary *dict = [[NSMutableDictionary alloc] init]; if (gitversion) [dict addEntriesFromDictionary:[[NSDictionary alloc] initWithObjectsAndKeys:gitversion, @"Version", nil]]; #ifdef DEBUG_BUILD [dict addEntriesFromDictionary:[[NSDictionary alloc] initWithObjectsAndKeys:@"GitX (DEBUG)", @"ApplicationName", nil]]; #endif [NSApp orderFrontStandardAboutPanelWithOptions:dict]; } - (IBAction)installCliTool:(id)sender; { BOOL success = NO; NSString* installationPath = @"/usr/local/bin/"; NSString* installationName = @"gitx"; NSString* toolPath = [[NSBundle mainBundle] pathForResource:@"gitx" ofType:@""]; if (toolPath) { AuthorizationRef auth; if (AuthorizationCreate(NULL, kAuthorizationEmptyEnvironment, kAuthorizationFlagDefaults, &auth) == errAuthorizationSuccess) { char const* mkdir_arg[] = { "-p", [installationPath UTF8String], NULL}; char const* mkdir = "/bin/mkdir"; AuthorizationExecuteWithPrivileges(auth, mkdir, kAuthorizationFlagDefaults, (char**)mkdir_arg, NULL); char const* arguments[] = { "-f", "-s", [toolPath UTF8String], [[installationPath stringByAppendingString: installationName] UTF8String], NULL }; char const* helperTool = "/bin/ln"; if (AuthorizationExecuteWithPrivileges(auth, helperTool, kAuthorizationFlagDefaults, (char**)arguments, NULL) == errAuthorizationSuccess) { int status; int pid = wait(&status); if (pid != -1 && WIFEXITED(status) && WEXITSTATUS(status) == 0) success = true; else errno = WEXITSTATUS(status); } AuthorizationFree(auth, kAuthorizationFlagDefaults); } } if (success) { [[NSAlert alertWithMessageText:@"Installation Complete" defaultButton:nil alternateButton:nil otherButton:nil informativeTextWithFormat:@"The gitx tool has been installed to %@", installationPath] runModal]; } else { [[NSAlert alertWithMessageText:@"Installation Failed" defaultButton:nil alternateButton:nil otherButton:nil informativeTextWithFormat:@"Installation to %@ failed", installationPath] runModal]; } } /** Returns the support folder for the application, used to store the Core Data store file. This code uses a folder named "GitTest" for the content, either in the NSApplicationSupportDirectory location or (if the former cannot be found), the system's temporary directory. */ - (IBAction) showHelp:(id) sender { [[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:@"http://gitx.frim.nl/user_manual.html"]]; } - (NSString *)applicationSupportFolder { NSArray *paths = NSSearchPathForDirectoriesInDomains(NSApplicationSupportDirectory, NSUserDomainMask, YES); NSString *basePath = ([paths count] > 0) ? [paths objectAtIndex:0] : NSTemporaryDirectory(); return [basePath stringByAppendingPathComponent:@"GitTest"]; } /** Creates, retains, and returns the managed object model for the application by merging all of the models found in the application bundle. */ - (NSManagedObjectModel *)managedObjectModel { if (managedObjectModel != nil) { return managedObjectModel; } managedObjectModel = [[NSManagedObjectModel mergedModelFromBundles:nil] retain]; return managedObjectModel; } /** Returns the persistent store coordinator for the application. This implementation will create and return a coordinator, having added the store for the application to it. (The folder for the store is created, if necessary.) */ - (NSPersistentStoreCoordinator *) persistentStoreCoordinator { if (persistentStoreCoordinator != nil) { return persistentStoreCoordinator; } NSFileManager *fileManager; NSString *applicationSupportFolder = nil; NSURL *url; NSError *error; fileManager = [NSFileManager defaultManager]; applicationSupportFolder = [self applicationSupportFolder]; if ( ![fileManager fileExistsAtPath:applicationSupportFolder isDirectory:NULL] ) { [fileManager createDirectoryAtPath:applicationSupportFolder attributes:nil]; } url = [NSURL fileURLWithPath: [applicationSupportFolder stringByAppendingPathComponent: @"GitTest.xml"]]; persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel: [self managedObjectModel]]; if (![persistentStoreCoordinator addPersistentStoreWithType:NSXMLStoreType configuration:nil URL:url options:nil error:&error]){ [[NSApplication sharedApplication] presentError:error]; } return persistentStoreCoordinator; } /** Returns the managed object context for the application (which is already bound to the persistent store coordinator for the application.) */ - (NSManagedObjectContext *) managedObjectContext { if (managedObjectContext != nil) { return managedObjectContext; } NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator]; if (coordinator != nil) { managedObjectContext = [[NSManagedObjectContext alloc] init]; [managedObjectContext setPersistentStoreCoordinator: coordinator]; } return managedObjectContext; } /** Returns the NSUndoManager for the application. In this case, the manager returned is that of the managed object context for the application. */ - (NSUndoManager *)windowWillReturnUndoManager:(NSWindow *)window { return [[self managedObjectContext] undoManager]; } /** Performs the save action for the application, which is to send the save: message to the application's managed object context. Any encountered errors are presented to the user. */ - (IBAction) saveAction:(id)sender { NSError *error = nil; if (![[self managedObjectContext] save:&error]) { [[NSApplication sharedApplication] presentError:error]; } } /** Implementation of the applicationShouldTerminate: method, used here to handle the saving of changes in the application managed object context before the application terminates. */ - (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender { NSError *error; int reply = NSTerminateNow; if (managedObjectContext != nil) { if ([managedObjectContext commitEditing]) { if ([managedObjectContext hasChanges] && ![managedObjectContext save:&error]) { // This error handling simply presents error information in a panel with an // "Ok" button, which does not include any attempt at error recovery (meaning, // attempting to fix the error.) As a result, this implementation will // present the information to the user and then follow up with a panel asking // if the user wishes to "Quit Anyway", without saving the changes. // Typically, this process should be altered to include application-specific // recovery steps. BOOL errorResult = [[NSApplication sharedApplication] presentError:error]; if (errorResult == YES) { reply = NSTerminateCancel; } else { int alertReturn = NSRunAlertPanel(nil, @"Could not save changes while quitting. Quit anyway?" , @"Quit anyway", @"Cancel", nil); if (alertReturn == NSAlertAlternateReturn) { reply = NSTerminateCancel; } } } } else { reply = NSTerminateCancel; } } return reply; } /** Implementation of dealloc, to release the retained variables. */ - (void) dealloc { [managedObjectContext release], managedObjectContext = nil; [persistentStoreCoordinator release], persistentStoreCoordinator = nil; [managedObjectModel release], managedObjectModel = nil; [super dealloc]; } @end