Files
gitx/PBGitWindowController.m
2011-06-15 21:16:02 -06:00

359 lines
11 KiB
Objective-C

//
// PBDetailController.m
// GitX
//
// Created by Pieter de Bie on 16-06-08.
// Copyright 2008 __MyCompanyName__. All rights reserved.
//
#import "PBGitWindowController.h"
#import "PBGitHistoryController.h"
#import "PBGitCommitController.h"
#import "PBGitDefaults.h"
#import "Terminal.h"
#import "PBCloneRepsitoryToSheet.h"
#import "PBCommitHookFailedSheet.h"
#import "PBGitXMessageSheet.h"
#import "PBGitSidebarController.h"
@implementation PBGitWindowController
@synthesize repository;
- (id)initWithRepository:(PBGitRepository*)theRepository displayDefault:(BOOL)displayDefault
{
if (!(self = [self initWithWindowNibName:@"RepositoryWindow"]))
return nil;
self.repository = theRepository;
return self;
}
- (void)windowWillClose:(NSNotification *)notification
{
//DLog(@"Window will close!");
if (sidebarController)
[sidebarController closeView];
if (contentController)
[contentController removeObserver:self forKeyPath:@"status"];
}
- (BOOL)validateMenuItem:(NSMenuItem *)menuItem
{
if ([menuItem action] == @selector(showCommitView:)) {
[menuItem setState:(contentController == sidebarController.commitViewController) ? YES : NO];
return ![repository isBareRepository];
} else if ([menuItem action] == @selector(showHistoryView:)) {
[menuItem setState:(contentController != sidebarController.commitViewController) ? YES : NO];
return ![repository isBareRepository];
}
return YES;
}
- (void) awakeFromNib
{
[[self window] setDelegate:self];
[[self window] setAutorecalculatesContentBorderThickness:NO forEdge:NSMinYEdge];
[[self window] setContentBorderThickness:31.0f forEdge:NSMinYEdge];
sidebarController = [[PBGitSidebarController alloc] initWithRepository:repository superController:self];
[[sidebarController view] setFrame:[sourceSplitView bounds]];
[sourceSplitView addSubview:[sidebarController view]];
[sourceListControlsView addSubview:sidebarController.sourceListControlsView];
[[statusField cell] setBackgroundStyle:NSBackgroundStyleRaised];
[progressIndicator setUsesThreadedAnimation:YES];
NSImage *finderImage = [[NSWorkspace sharedWorkspace] iconForFileType:NSFileTypeForHFSTypeCode(kFinderIcon)];
[finderItem setImage:finderImage];
NSImage *terminalImage = [[NSWorkspace sharedWorkspace] iconForFile:@"/Applications/Utilities/Terminal.app/"];
[terminalItem setImage:terminalImage];
[self showWindow:nil];
[self initChangeLayout];
}
- (void) removeAllContentSubViews
{
if ([contentSplitView subviews])
while ([[contentSplitView subviews] count] > 0)
[[[contentSplitView subviews] lastObject] removeFromSuperviewWithoutNeedingDisplay];
}
- (void) changeContentController:(PBViewController *)controller
{
if (!controller || (contentController == controller))
return;
if (contentController)
[contentController removeObserver:self forKeyPath:@"status"];
[self removeAllContentSubViews];
contentController = controller;
[[contentController view] setFrame:[contentSplitView bounds]];
[contentSplitView addSubview:[contentController view]];
[self setNextResponder: contentController];
[[self window] makeFirstResponder:[contentController firstResponder]];
[contentController updateView];
[contentController addObserver:self forKeyPath:@"status" options:NSKeyValueObservingOptionInitial context:@"statusChange"];
}
- (void) showCommitView:(id)sender
{
[sidebarController selectStage];
}
- (void) showHistoryView:(id)sender
{
[sidebarController selectCurrentBranch];
}
- (void)showCommitHookFailedSheet:(NSString *)messageText infoText:(NSString *)infoText commitController:(PBGitCommitController *)controller
{
[PBCommitHookFailedSheet beginMessageSheetForWindow:[self window] withMessageText:messageText infoText:infoText commitController:controller];
}
- (void)showMessageSheet:(NSString *)messageText infoText:(NSString *)infoText
{
[PBGitXMessageSheet beginMessageSheetForWindow:[self window] withMessageText:messageText infoText:infoText];
}
- (void)showErrorSheet:(NSError *)error
{
if ([[error domain] isEqualToString:PBGitRepositoryErrorDomain])
[PBGitXMessageSheet beginMessageSheetForWindow:[self window] withError:error];
else
[[NSAlert alertWithError:error] beginSheetModalForWindow:[self window] modalDelegate:self didEndSelector:nil contextInfo:nil];
}
- (void)windowDidBecomeKey:(NSNotification *)notification
{
if ([PBGitDefaults refreshAutomatically]) {
[contentController refresh:nil];
}
if ([PBGitDefaults isUseITerm2]) {
[terminalItem setImage:[[NSWorkspace sharedWorkspace] iconForFile:[[NSWorkspace sharedWorkspace] absolutePathForAppBundleWithIdentifier:@"com.googlecode.iterm2"]]];
[terminalItem setLabel:@"iTerm"];
}
else {
[terminalItem setImage:[[NSWorkspace sharedWorkspace] iconForFile:@"/Applications/Utilities/Terminal.app/"]];
[terminalItem setLabel:@"Terminal"];
}
}
- (void)showErrorSheetTitle:(NSString *)title message:(NSString *)message arguments:(NSArray *)arguments output:(NSString *)output
{
NSString *command = [arguments componentsJoinedByString:@" "];
NSString *reason = [NSString stringWithFormat:@"%@\n\ncommand: git %@\n%@", message, command, output];
NSDictionary *userInfo = [NSDictionary dictionaryWithObjectsAndKeys:
title, NSLocalizedDescriptionKey,
reason, NSLocalizedRecoverySuggestionErrorKey,
nil];
NSError *error = [NSError errorWithDomain:PBGitRepositoryErrorDomain code:0 userInfo:userInfo];
[self showErrorSheet:error];
}
- (IBAction) revealInFinder:(id)sender
{
[[NSWorkspace sharedWorkspace] openFile:[repository workingDirectory]];
}
- (IBAction) openInTerminal:(id)sender
{
NSString *workingDirectory = [[repository workingDirectory] stringByAppendingString:@"/"];
if ([PBGitDefaults isUseITerm2]) {
NSStringEncoding encoding;
NSString *resourcePath = [[[NSBundle bundleForClass:[self class]] resourcePath] stringByAppendingPathComponent:@"Start_iTerm2.applescript"];
NSString *scriptSource = [NSString stringWithContentsOfFile:resourcePath usedEncoding:&encoding error:nil];
NSString *iTerm2StartScript = [scriptSource stringByReplacingOccurrencesOfString:@"%%workDir%%" withString:workingDirectory];
NSAppleScript *scriptObject = [[NSAppleScript alloc] initWithSource:iTerm2StartScript];
[scriptObject executeAndReturnError:nil];
}
else {
TerminalApplication *term = [SBApplication applicationWithBundleIdentifier:@"com.apple.Terminal"];
NSString *cmd = [NSString stringWithFormat: @"cd \"%@\"; clear; echo '# Opened by GitX:'; git status", workingDirectory];
[term doScript: cmd in: nil];
[NSThread sleepForTimeInterval: 0.1];
[term activate];
}
}
- (IBAction) cloneTo:(id)sender
{
[PBCloneRepsitoryToSheet beginCloneRepsitoryToSheetForRepository:repository];
}
- (IBAction) refresh:(id)sender
{
[sidebarController.historyViewController refresh: self];
[sidebarController.commitViewController refresh: self];
}
- (void) updateStatus
{
NSString *status = contentController.status;
BOOL isBusy = contentController.isBusy;
if (!status) {
status = @"";
isBusy = NO;
}
[statusField setStringValue:status];
if (isBusy) {
[progressIndicator startAnimation:self];
[progressIndicator setHidden:NO];
}
else {
[progressIndicator stopAnimation:self];
[progressIndicator setHidden:YES];
}
}
- (void) observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
if ([(NSString *)context isEqualToString:@"statusChange"]) {
[self updateStatus];
return;
}
[super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
}
- (void) selectCommitForSha:(NSString *)sha
{
if (contentController != sidebarController.historyViewController)
[sidebarController selectCurrentBranch];
[sidebarController.historyViewController selectCommit:sha];
}
- (NSArray *) menuItemsForPaths:(NSArray *)paths
{
return [sidebarController.historyViewController menuItemsForPaths:paths];
}
- (void)setHistorySearch:(NSString *)searchString mode:(NSInteger)mode
{
[sidebarController setHistorySearch:searchString mode:mode];
}
#pragma mark - SplitView changeLayout
-(void)initChangeLayout
{
splitViews=[NSArray arrayWithObjects:mainSplitView,[[sidebarController historyViewController] historySplitView], nil];
splitViewsSize=[NSMutableArray arrayWithCapacity:[splitViews count]];
for (int n=0; n<[splitViews count]; n++) {
NSSplitView *splitView=[splitViews objectAtIndex:n];
NSView *left=[[splitView subviews] objectAtIndex:0];
[splitViewsSize addObject:[NSNumber numberWithInt:[left frame].size.width]];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(resizeSubviewsHandler:)
name:NSSplitViewWillResizeSubviewsNotification
object:splitView
];
}
}
- (IBAction)changeLayout:(id)sender
{
NSInteger index=[sender selectedSegment];
NSSplitView *splitView=[splitViews objectAtIndex:index];
NSView *left=[[splitView subviews] objectAtIndex:0];
CGFloat pos;
if ([splitView isSubviewCollapsed:left])
pos=[[splitViewsSize objectAtIndex:index] intValue];
else
pos=[splitView minPossiblePositionOfDividerAtIndex:0];
[splitView setPosition:pos ofDividerAtIndex:0 ];
}
- (void)resizeSubviewsHandler:(NSNotification *)notif
{
NSSplitView *splitView=[notif object];
NSInteger index=[splitViews indexOfObject:splitView];
NSView *left=[[splitView subviews] objectAtIndex:0];
NSNumber *pos;
if([splitView isVertical]){
pos=[NSNumber numberWithInt:[left frame].size.width];
}else{
pos=[NSNumber numberWithInt:[left frame].size.height];
}
[splitViewsSize removeObjectAtIndex:index];
[splitViewsSize insertObject:pos atIndex:index];
}
#pragma mark -
#pragma mark SplitView Delegates
- (BOOL)splitView:(NSSplitView *)sp canCollapseSubview:(NSView *)subview
{
return TRUE;
}
- (BOOL)splitView:(NSSplitView *)splitView shouldCollapseSubview:(NSView *)subview forDoubleClickOnDividerAtIndex:(NSInteger)dividerIndex
{
NSUInteger index = [[splitView subviews] indexOfObject:subview];
return index==0;
}
#pragma mark min/max widths while moving the divider
- (CGFloat)splitView:(NSSplitView *)view constrainMinCoordinate:(CGFloat)proposedMin ofSubviewAt:(NSInteger)dividerIndex
{
if (proposedMin < kGitSplitViewMinWidth)
return kGitSplitViewMinWidth;
return proposedMin;
}
- (CGFloat)splitView:(NSSplitView *)view constrainMaxCoordinate:(CGFloat)proposedMax ofSubviewAt:(NSInteger)dividerIndex
{
if (dividerIndex == 0)
return kGitSplitViewMaxWidth;
return proposedMax;
}
#pragma mark constrain sidebar width while resizing the window
- (void)splitView:(NSSplitView *)sender resizeSubviewsWithOldSize:(NSSize)oldSize
{
NSRect newFrame = [sender frame];
float dividerThickness = [sender dividerThickness];
NSView *sourceView = [[sender subviews] objectAtIndex:0];
NSRect sourceFrame = [sourceView frame];
sourceFrame.size.height = newFrame.size.height;
NSView *mainView = [[sender subviews] objectAtIndex:1];
NSRect mainFrame = [mainView frame];
mainFrame.origin.x = sourceFrame.size.width + dividerThickness;
mainFrame.size.width = newFrame.size.width - mainFrame.origin.x;
mainFrame.size.height = newFrame.size.height;
[sourceView setFrame:sourceFrame];
[mainView setFrame:mainFrame];
}
@end