Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Fetching contributors…

Cannot retrieve contributors at this time

298 lines (236 sloc) 10.693 kb
//
// PBGitCommitController.m
// GitX
//
// Created by Pieter de Bie on 19-09-08.
// Copyright 2008 __MyCompanyName__. All rights reserved.
//
#import "PBGitCommitController.h"
#import "NSFileHandleExt.h"
#import "PBChangedFile.h"
#import "PBWebChangesController.h"
#import "PBGitIndex.h"
#import "PBNiceSplitView.h"
#define kCommitSplitViewPositionDefault @"Commit SplitView Position"
@interface PBGitCommitController ()
- (void)refreshFinished:(NSNotification *)notification;
- (void)commitWithVerification:(BOOL) doVerify;
- (void)commitStatusUpdated:(NSNotification *)notification;
- (void)commitFinished:(NSNotification *)notification;
- (void)commitFailed:(NSNotification *)notification;
- (void)commitHookFailed:(NSNotification *)notification;
- (void)amendCommit:(NSNotification *)notification;
- (void)indexChanged:(NSNotification *)notification;
- (void)indexOperationFailed:(NSNotification *)notification;
- (void)saveCommitSplitViewPosition;
@end
@implementation PBGitCommitController
@synthesize index;
- (id)initWithRepository:(PBGitRepository *)theRepository superController:(PBGitWindowController *)controller
{
if (!(self = [super initWithRepository:theRepository superController:controller]))
return nil;
index = [[PBGitIndex alloc] initWithRepository:theRepository workingDirectory:[NSURL fileURLWithPath:[theRepository workingDirectory]]];
[index refresh];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(refreshFinished:) name:PBGitIndexFinishedIndexRefresh object:index];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(commitStatusUpdated:) name:PBGitIndexCommitStatus object:index];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(commitFinished:) name:PBGitIndexFinishedCommit object:index];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(commitFailed:) name:PBGitIndexCommitFailed object:index];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(commitHookFailed:) name:PBGitIndexCommitHookFailed object:index];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(amendCommit:) name:PBGitIndexAmendMessageAvailable object:index];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(indexChanged:) name:PBGitIndexIndexUpdated object:index];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(indexOperationFailed:) name:PBGitIndexOperationFailed object:index];
return self;
}
- (void)awakeFromNib
{
[super awakeFromNib];
[commitMessageView setTypingAttributes:[NSDictionary dictionaryWithObject:[NSFont fontWithName:@"Monaco" size:12.0] forKey:NSFontAttributeName]];
[unstagedFilesController setFilterPredicate:[NSPredicate predicateWithFormat:@"hasUnstagedChanges == 1"]];
[cachedFilesController setFilterPredicate:[NSPredicate predicateWithFormat:@"hasStagedChanges == 1"]];
[unstagedFilesController setSortDescriptors:[NSArray arrayWithObjects:
[[NSSortDescriptor alloc] initWithKey:@"status" ascending:false],
[[NSSortDescriptor alloc] initWithKey:@"path" ascending:true], nil]];
[cachedFilesController setSortDescriptors:[NSArray arrayWithObject:
[[NSSortDescriptor alloc] initWithKey:@"path" ascending:true]]];
[cachedFilesController setAutomaticallyRearrangesObjects:NO];
[unstagedFilesController setAutomaticallyRearrangesObjects:NO];
[commitSplitView setHidden:YES];
[self performSelector:@selector(restoreCommitSplitViewPositiion) withObject:nil afterDelay:0];
}
- (void)closeView
{
[self saveCommitSplitViewPosition];
[webController closeView];
}
- (NSResponder *)firstResponder;
{
return commitMessageView;
}
- (IBAction)signOff:(id)sender
{
if (![repository.config valueForKeyPath:@"user.name"] || ![repository.config valueForKeyPath:@"user.email"])
return [[repository windowController] showMessageSheet:@"User's name not set" infoText:@"Signing off a commit requires setting user.name and user.email in your git config"];
NSString *SOBline = [NSString stringWithFormat:@"Signed-off-by: %@ <%@>",
[repository.config valueForKeyPath:@"user.name"],
[repository.config valueForKeyPath:@"user.email"]];
if([commitMessageView.string rangeOfString:SOBline].location == NSNotFound) {
NSArray *selectedRanges = [commitMessageView selectedRanges];
commitMessageView.string = [NSString stringWithFormat:@"%@\n\n%@",
commitMessageView.string, SOBline];
[commitMessageView setSelectedRanges: selectedRanges];
}
}
- (void) refresh:(id) sender
{
self.isBusy = YES;
self.status = @"Refreshing index…";
[index refresh];
// Reload refs (in case HEAD changed)
[repository reloadRefs];
}
- (void) updateView
{
[self refresh:nil];
}
- (IBAction) commit:(id) sender
{
[self commitWithVerification:YES];
}
- (IBAction) forceCommit:(id) sender
{
[self commitWithVerification:NO];
}
- (void) commitWithVerification:(BOOL) doVerify
{
if ([[NSFileManager defaultManager] fileExistsAtPath:[repository.fileURL.path stringByAppendingPathComponent:@"MERGE_HEAD"]]) {
[[repository windowController] showMessageSheet:@"Cannot commit merges" infoText:@"GitX cannot commit merges yet. Please commit your changes from the command line."];
return;
}
if ([[cachedFilesController arrangedObjects] count] == 0) {
[[repository windowController] showMessageSheet:@"No changes to commit" infoText:@"You must first stage some changes before committing"];
return;
}
NSString *commitMessage = [commitMessageView string];
if ([commitMessage length] < 3) {
[[repository windowController] showMessageSheet:@"Commitmessage missing" infoText:@"Please enter a commit message before committing"];
return;
}
[cachedFilesController setSelectionIndexes:[NSIndexSet indexSet]];
[unstagedFilesController setSelectionIndexes:[NSIndexSet indexSet]];
self.isBusy = YES;
[commitMessageView setEditable:NO];
[index commitWithMessage:commitMessage andVerify:doVerify];
}
# pragma mark PBGitIndex Notification handling
- (void)refreshFinished:(NSNotification *)notification
{
self.isBusy = NO;
self.status = @"Index refresh finished";
}
- (void)commitStatusUpdated:(NSNotification *)notification
{
self.status = [[notification userInfo] objectForKey:@"description"];
}
- (void)commitFinished:(NSNotification *)notification
{
[commitMessageView setEditable:YES];
[commitMessageView setString:@""];
[webController setStateMessage:[NSString stringWithFormat:[[notification userInfo] objectForKey:@"description"]]];
}
- (void)commitFailed:(NSNotification *)notification
{
self.isBusy = NO;
NSString *reason = [[notification userInfo] objectForKey:@"description"];
self.status = [@"Commit failed: " stringByAppendingString:reason];
[commitMessageView setEditable:YES];
[[repository windowController] showMessageSheet:@"Commit failed" infoText:reason];
}
- (void)commitHookFailed:(NSNotification *)notification
{
self.isBusy = NO;
NSString *reason = [[notification userInfo] objectForKey:@"description"];
self.status = [@"Commit hook failed: " stringByAppendingString:reason];
[commitMessageView setEditable:YES];
[[repository windowController] showCommitHookFailedSheet:@"Commit hook failed" infoText:reason commitController:self];
}
- (void)amendCommit:(NSNotification *)notification
{
// Replace commit message with the old one if it's less than 3 characters long.
// This is just a random number.
if ([[commitMessageView string] length] > 3)
return;
NSString *message = [[notification userInfo] objectForKey:@"message"];
commitMessageView.string = message;
}
- (void)indexChanged:(NSNotification *)notification
{
[cachedFilesController rearrangeObjects];
[unstagedFilesController rearrangeObjects];
if ([[cachedFilesController arrangedObjects] count]) {
[commitButton setEnabled:YES];
} else {
[commitButton setEnabled:NO];
}
}
- (void)indexOperationFailed:(NSNotification *)notification
{
[[repository windowController] showMessageSheet:@"Index operation failed" infoText:[[notification userInfo] objectForKey:@"description"]];
}
#pragma mark NSSplitView delegate methods
#define kCommitSplitViewTopViewMin 150
#define kCommitSplitViewBottomViewMin 100
- (CGFloat)splitView:(NSSplitView *)splitView constrainMinCoordinate:(CGFloat)proposedMin ofSubviewAt:(NSInteger)dividerIndex
{
if (splitView == commitSplitView)
return kCommitSplitViewTopViewMin;
return proposedMin;
}
- (CGFloat)splitView:(NSSplitView *)splitView constrainMaxCoordinate:(CGFloat)proposedMax ofSubviewAt:(NSInteger)dividerIndex
{
if (splitView == commitSplitView)
return [splitView frame].size.height - [splitView dividerThickness] - kCommitSplitViewBottomViewMin;
return proposedMax;
}
// while the user resizes the window keep the lower (changes/message) view constant and just resize the upper view
// unless the upper view gets too small
- (void)resizeCommitSplitView
{
NSRect newFrame = [commitSplitView frame];
float dividerThickness = [commitSplitView dividerThickness];
NSView *upperView = [[commitSplitView subviews] objectAtIndex:0];
NSRect upperFrame = [upperView frame];
upperFrame.size.width = newFrame.size.width;
NSView *lowerView = [[commitSplitView subviews] objectAtIndex:1];
NSRect lowerFrame = [lowerView frame];
lowerFrame.size.width = newFrame.size.width;
upperFrame.size.height = newFrame.size.height - lowerFrame.size.height - dividerThickness;
if (upperFrame.size.height < kCommitSplitViewTopViewMin)
upperFrame.size.height = kCommitSplitViewTopViewMin;
lowerFrame.size.height = newFrame.size.height - upperFrame.size.height - dividerThickness;
lowerFrame.origin.y = newFrame.size.height - lowerFrame.size.height;
[upperView setFrame:upperFrame];
[lowerView setFrame:lowerFrame];
}
- (void)splitView:(NSSplitView *)splitView resizeSubviewsWithOldSize:(NSSize)oldSize
{
if (splitView == commitSplitView)
[self resizeCommitSplitView];
}
// NSSplitView does not save and restore the position of the splitView correctly so do it manually
- (void)saveCommitSplitViewPosition
{
float position = [[[commitSplitView subviews] objectAtIndex:0] frame].size.height;
[[NSUserDefaults standardUserDefaults] setFloat:position forKey:kCommitSplitViewPositionDefault];
[[NSUserDefaults standardUserDefaults] synchronize];
}
// make sure this happens after awakeFromNib
- (void)restoreCommitSplitViewPositiion
{
float position = [[NSUserDefaults standardUserDefaults] floatForKey:kCommitSplitViewPositionDefault];
if (position < 1.0)
position = [commitSplitView frame].size.height - 225;
[commitSplitView setPosition:position ofDividerAtIndex:0];
[commitSplitView setHidden:NO];
}
@end
Jump to Line
Something went wrong with that request. Please try again.