mirror of
https://github.com/kennethreitz-archive/gitx.git
synced 2026-06-05 23:40:18 +00:00
e60bb3226c
Sending the arguments with the openURL:... message allows the repository document to modify it's UI without the UI flashing between states as it opens.
Covers all the existing functionality of the CLI, but modifies:
- "--all" "--local" "--branch" change the branch filter
- cleaned up the usage (help) text and added info on missing commands
- looks up the full ref name of refs so the name of a branch or tag can be entered (the user can enter "master" instead of "refs/heads/master")
Modified the History Controller to watch for and react to branch filter changes.
The GitX.h file is generated by the 'sdp' tool in a run script build phase called 'Generate Scripting Bridge Header' based on the content of GitX.sdef. It is used by the Scripting Bridge so that other apps (in this case the gitx CLI) can call Applescript commands on GitX in objective-c.
384 lines
13 KiB
Objective-C
384 lines
13 KiB
Objective-C
//
|
||
// 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 "PBServicesController.h"
|
||
#import "PBGitXProtocol.h"
|
||
#import "PBPrefsWindowController.h"
|
||
#import "PBNSURLPathUserDefaultsTransfomer.h"
|
||
#import "PBGitDefaults.h"
|
||
#import "PBCloneRepositoryPanel.h"
|
||
#import "Sparkle/SUUpdater.h"
|
||
|
||
@implementation ApplicationController
|
||
|
||
- (ApplicationController*)init
|
||
{
|
||
#ifdef DEBUG_BUILD
|
||
[NSApp activateIgnoringOtherApps:YES];
|
||
#endif
|
||
|
||
if(!(self = [super init]))
|
||
return nil;
|
||
|
||
if(![[NSBundle bundleWithPath:@"/System/Library/Frameworks/Quartz.framework/Frameworks/QuickLookUI.framework"] load])
|
||
if(![[NSBundle bundleWithPath:@"/System/Library/PrivateFrameworks/QuickLookUI.framework"] load])
|
||
NSLog(@"Could not load QuickLook");
|
||
|
||
/* 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
|
||
{
|
||
[[SUUpdater sharedUpdater] setSendsSystemProfile:YES];
|
||
|
||
// Make sure Git's SSH password requests get forwarded to our little UI tool:
|
||
setenv( "SSH_ASKPASS", [[[NSBundle mainBundle] pathForResource: @"gitx_askpasswd" ofType: @""] UTF8String], 1 );
|
||
setenv( "DISPLAY", "localhost:0", 1 );
|
||
|
||
[self registerServices];
|
||
|
||
BOOL hasOpenedDocuments = NO;
|
||
NSArray *launchedDocuments = [[[PBRepositoryDocumentController sharedDocumentController] documents] copy];
|
||
|
||
// 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 ([launchedDocuments count])
|
||
hasOpenedDocuments = YES;
|
||
|
||
// open any documents that were open the last time the app quit
|
||
if ([PBGitDefaults openPreviousDocumentsOnLaunch]) {
|
||
for (NSString *path in [PBGitDefaults previousDocumentPaths]) {
|
||
NSURL *url = [NSURL fileURLWithPath:path isDirectory:YES];
|
||
NSError *error = nil;
|
||
if (url && [[PBRepositoryDocumentController sharedDocumentController] openDocumentWithContentsOfURL:url display:YES error:&error])
|
||
hasOpenedDocuments = YES;
|
||
}
|
||
}
|
||
|
||
// Try to find the current directory, to open that as a repository
|
||
if ([PBGitDefaults openCurDirOnLaunch] && !hasOpenedDocuments) {
|
||
NSString *curPath = [[[NSProcessInfo processInfo] environment] objectForKey:@"PWD"];
|
||
NSURL *url = nil;
|
||
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])
|
||
hasOpenedDocuments = YES;
|
||
}
|
||
|
||
// to bring the launched documents to the front
|
||
for (PBGitRepository *document in launchedDocuments)
|
||
[document showWindows];
|
||
|
||
if (![[NSApplication sharedApplication] isActive])
|
||
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] && !hasOpenedDocuments)
|
||
[[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) showCloneRepository:(id)sender
|
||
{
|
||
if (!cloneRepositoryPanel)
|
||
cloneRepositoryPanel = [PBCloneRepositoryPanel panel];
|
||
|
||
[cloneRepositoryPanel showWindow:self];
|
||
}
|
||
|
||
- (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;
|
||
}
|
||
|
||
- (void)applicationWillTerminate:(NSNotification *)aNotification
|
||
{
|
||
[PBGitDefaults removePreviousDocumentPaths];
|
||
|
||
if ([PBGitDefaults openPreviousDocumentsOnLaunch]) {
|
||
NSArray *documents = [[PBRepositoryDocumentController sharedDocumentController] documents];
|
||
if ([documents count] > 0) {
|
||
NSMutableArray *paths = [NSMutableArray array];
|
||
for (PBGitRepository *repository in documents)
|
||
[paths addObject:[repository workingDirectory]];
|
||
|
||
[PBGitDefaults setPreviousDocumentPaths:paths];
|
||
}
|
||
}
|
||
}
|
||
|
||
/**
|
||
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
|