2 // GitTest_AppDelegate.m
5 // Created by Pieter de Bie on 13-06-08.
6 // Copyright __MyCompanyName__ 2008 . All rights reserved.
9 #import "ApplicationController.h"
10 #import "PBGitRevisionCell.h"
11 #import "PBGitWindowController.h"
12 #import "PBRepositoryDocumentController.h"
13 #import "PBCLIProxy.h"
14 #import "PBServicesController.h"
15 #import "PBGitXProtocol.h"
16 #import "PBPrefsWindowController.h"
17 #import "PBNSURLPathUserDefaultsTransfomer.h"
18 #import "PBGitDefaults.h"
20 @implementation ApplicationController
23 - (ApplicationController*)init
26 [NSApp activateIgnoringOtherApps:YES];
29 if(self = [super init]) {
30 if(![[NSBundle bundleWithPath:@"/System/Library/PrivateFrameworks/QuickLookUI.framework"] load])
31 NSLog(@"Could not load QuickLook");
33 self.cliProxy = [PBCLIProxy new];
36 /* Value Transformers */
37 NSValueTransformer *transformer = [[PBNSURLPathUserDefaultsTransfomer alloc] init];
38 [NSValueTransformer setValueTransformer:transformer forName:@"PBNSURLPathUserDefaultsTransfomer"];
40 // Make sure the PBGitDefaults is initialized, by calling a random method
41 [PBGitDefaults class];
45 - (void)registerServices
48 [NSURLProtocol registerClass:[PBGitXProtocol class]];
50 // Register the service class
51 PBServicesController *services = [[PBServicesController alloc] init];
52 [NSApp setServicesProvider:services];
54 // Force update the services menu if we have a new services version
55 int serviceVersion = [[NSUserDefaults standardUserDefaults] integerForKey:@"Services Version"];
56 if (serviceVersion < 2)
58 NSLog(@"Updating services menu…");
59 NSUpdateDynamicServices();
60 [[NSUserDefaults standardUserDefaults] setInteger:2 forKey:@"Services Version"];
64 - (void)applicationDidFinishLaunching:(NSNotification*)notification
66 [self registerServices];
68 // Only try to open a default document if there are no documents open already.
69 // For example, the application might have been launched by double-clicking a .git repository,
70 // or by dragging a folder to the app icon
71 if ([[[PBRepositoryDocumentController sharedDocumentController] documents] count])
74 if (![[NSApplication sharedApplication] isActive])
79 // Try to find the current directory, to open that as a repository
80 if ([PBGitDefaults openCurDirOnLaunch]) {
81 NSString *curPath = [[[NSProcessInfo processInfo] environment] objectForKey:@"PWD"];
83 url = [NSURL fileURLWithPath:curPath];
86 // Try to open the found URL
88 if (url && [[PBRepositoryDocumentController sharedDocumentController] openDocumentWithContentsOfURL:url display:YES error:&error])
91 // The current directory was not enabled or could not be opened (most likely it’s not a git repository).
92 // show an open panel for the user to select a repository to view
93 if ([PBGitDefaults showOpenPanelOnLaunch])
94 [[PBRepositoryDocumentController sharedDocumentController] openDocument:self];
97 - (void) windowWillClose: sender
99 [firstResponder terminate: sender];
102 - (IBAction)openPreferencesWindow:(id)sender
104 [[PBPrefsWindowController sharedPrefsWindowController] showWindow:nil];
107 - (IBAction)showAboutPanel:(id)sender
109 NSString *gitversion = [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleGitVersion"];
110 NSMutableDictionary *dict = [[NSMutableDictionary alloc] init];
112 [dict addEntriesFromDictionary:[[NSDictionary alloc] initWithObjectsAndKeys:gitversion, @"Version", nil]];
115 [dict addEntriesFromDictionary:[[NSDictionary alloc] initWithObjectsAndKeys:@"GitX (DEBUG)", @"ApplicationName", nil]];
118 [NSApp orderFrontStandardAboutPanelWithOptions:dict];
121 - (IBAction)installCliTool:(id)sender;
124 NSString* installationPath = @"/usr/local/bin/";
125 NSString* installationName = @"gitx";
126 NSString* toolPath = [[NSBundle mainBundle] pathForResource:@"gitx" ofType:@""];
128 AuthorizationRef auth;
129 if (AuthorizationCreate(NULL, kAuthorizationEmptyEnvironment, kAuthorizationFlagDefaults, &auth) == errAuthorizationSuccess) {
130 char const* mkdir_arg[] = { "-p", [installationPath UTF8String], NULL};
131 char const* mkdir = "/bin/mkdir";
132 AuthorizationExecuteWithPrivileges(auth, mkdir, kAuthorizationFlagDefaults, (char**)mkdir_arg, NULL);
133 char const* arguments[] = { "-f", "-s", [toolPath UTF8String], [[installationPath stringByAppendingString: installationName] UTF8String], NULL };
134 char const* helperTool = "/bin/ln";
135 if (AuthorizationExecuteWithPrivileges(auth, helperTool, kAuthorizationFlagDefaults, (char**)arguments, NULL) == errAuthorizationSuccess) {
137 int pid = wait(&status);
138 if (pid != -1 && WIFEXITED(status) && WEXITSTATUS(status) == 0)
141 errno = WEXITSTATUS(status);
144 AuthorizationFree(auth, kAuthorizationFlagDefaults);
149 [[NSAlert alertWithMessageText:@"Installation Complete"
153 informativeTextWithFormat:@"The gitx tool has been installed to %@", installationPath] runModal];
155 [[NSAlert alertWithMessageText:@"Installation Failed"
159 informativeTextWithFormat:@"Installation to %@ failed", installationPath] runModal];
164 Returns the support folder for the application, used to store the Core Data
165 store file. This code uses a folder named "GitTest" for
166 the content, either in the NSApplicationSupportDirectory location or (if the
167 former cannot be found), the system's temporary directory.
170 - (IBAction) showHelp:(id) sender
172 [[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:@"http://gitx.frim.nl/user_manual.html"]];
175 - (NSString *)applicationSupportFolder {
177 NSArray *paths = NSSearchPathForDirectoriesInDomains(NSApplicationSupportDirectory, NSUserDomainMask, YES);
178 NSString *basePath = ([paths count] > 0) ? [paths objectAtIndex:0] : NSTemporaryDirectory();
179 return [basePath stringByAppendingPathComponent:@"GitTest"];
184 Creates, retains, and returns the managed object model for the application
185 by merging all of the models found in the application bundle.
188 - (NSManagedObjectModel *)managedObjectModel {
190 if (managedObjectModel != nil) {
191 return managedObjectModel;
194 managedObjectModel = [[NSManagedObjectModel mergedModelFromBundles:nil] retain];
195 return managedObjectModel;
200 Returns the persistent store coordinator for the application. This
201 implementation will create and return a coordinator, having added the
202 store for the application to it. (The folder for the store is created,
206 - (NSPersistentStoreCoordinator *) persistentStoreCoordinator {
208 if (persistentStoreCoordinator != nil) {
209 return persistentStoreCoordinator;
212 NSFileManager *fileManager;
213 NSString *applicationSupportFolder = nil;
217 fileManager = [NSFileManager defaultManager];
218 applicationSupportFolder = [self applicationSupportFolder];
219 if ( ![fileManager fileExistsAtPath:applicationSupportFolder isDirectory:NULL] ) {
220 [fileManager createDirectoryAtPath:applicationSupportFolder attributes:nil];
223 url = [NSURL fileURLWithPath: [applicationSupportFolder stringByAppendingPathComponent: @"GitTest.xml"]];
224 persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel: [self managedObjectModel]];
225 if (![persistentStoreCoordinator addPersistentStoreWithType:NSXMLStoreType configuration:nil URL:url options:nil error:&error]){
226 [[NSApplication sharedApplication] presentError:error];
229 return persistentStoreCoordinator;
234 Returns the managed object context for the application (which is already
235 bound to the persistent store coordinator for the application.)
238 - (NSManagedObjectContext *) managedObjectContext {
240 if (managedObjectContext != nil) {
241 return managedObjectContext;
244 NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator];
245 if (coordinator != nil) {
246 managedObjectContext = [[NSManagedObjectContext alloc] init];
247 [managedObjectContext setPersistentStoreCoordinator: coordinator];
250 return managedObjectContext;
255 Returns the NSUndoManager for the application. In this case, the manager
256 returned is that of the managed object context for the application.
259 - (NSUndoManager *)windowWillReturnUndoManager:(NSWindow *)window {
260 return [[self managedObjectContext] undoManager];
265 Performs the save action for the application, which is to send the save:
266 message to the application's managed object context. Any encountered errors
267 are presented to the user.
270 - (IBAction) saveAction:(id)sender {
272 NSError *error = nil;
273 if (![[self managedObjectContext] save:&error]) {
274 [[NSApplication sharedApplication] presentError:error];
280 Implementation of the applicationShouldTerminate: method, used here to
281 handle the saving of changes in the application managed object context
282 before the application terminates.
285 - (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender {
288 int reply = NSTerminateNow;
290 if (managedObjectContext != nil) {
291 if ([managedObjectContext commitEditing]) {
292 if ([managedObjectContext hasChanges] && ![managedObjectContext save:&error]) {
294 // This error handling simply presents error information in a panel with an
295 // "Ok" button, which does not include any attempt at error recovery (meaning,
296 // attempting to fix the error.) As a result, this implementation will
297 // present the information to the user and then follow up with a panel asking
298 // if the user wishes to "Quit Anyway", without saving the changes.
300 // Typically, this process should be altered to include application-specific
303 BOOL errorResult = [[NSApplication sharedApplication] presentError:error];
305 if (errorResult == YES) {
306 reply = NSTerminateCancel;
311 int alertReturn = NSRunAlertPanel(nil, @"Could not save changes while quitting. Quit anyway?" , @"Quit anyway", @"Cancel", nil);
312 if (alertReturn == NSAlertAlternateReturn) {
313 reply = NSTerminateCancel;
320 reply = NSTerminateCancel;
329 Implementation of dealloc, to release the retained variables.
334 [managedObjectContext release], managedObjectContext = nil;
335 [persistentStoreCoordinator release], persistentStoreCoordinator = nil;
336 [managedObjectModel release], managedObjectModel = nil;