diff --git a/ApplicationController.m b/ApplicationController.m index 5b559df..94ad4af 100644 --- a/ApplicationController.m +++ b/ApplicationController.m @@ -225,8 +225,9 @@ if (![[aTableColumn identifier] isEqualToString:@"subject"]) return; - NSNumber* n = [NSNumber numberWithInt:(rowIndex % 2)]; - [aCell setCommit:n]; - + if (self.repository.revisionList.grapher) { + PBGitGrapher* g = self.repository.revisionList.grapher; + [aCell setCellInfo: [g cellInfoForRow:rowIndex]]; + } } @end diff --git a/GitX.xcodeproj/project.pbxproj b/GitX.xcodeproj/project.pbxproj index a30ef63..b2841be 100644 --- a/GitX.xcodeproj/project.pbxproj +++ b/GitX.xcodeproj/project.pbxproj @@ -32,6 +32,7 @@ F5B721C40E05CF7E00AF29DC /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = F5B721C20E05CF7E00AF29DC /* MainMenu.xib */; }; F5DFFA6C0E075D8800617813 /* PBEasyFS.m in Sources */ = {isa = PBXBuildFile; fileRef = F5DFFA6B0E075D8800617813 /* PBEasyFS.m */; }; F5FF4E180E0829C20006317A /* PBGitRevList.m in Sources */ = {isa = PBXBuildFile; fileRef = F5FF4E170E0829C20006317A /* PBGitRevList.m */; }; + F5FF4E7A0E082E440006317A /* PBGitGrapher.m in Sources */ = {isa = PBXBuildFile; fileRef = F5FF4E790E082E440006317A /* PBGitGrapher.m */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ @@ -79,6 +80,8 @@ F5DFFA6B0E075D8800617813 /* PBEasyFS.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PBEasyFS.m; sourceTree = ""; }; F5FF4E160E0829C20006317A /* PBGitRevList.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PBGitRevList.h; sourceTree = ""; }; F5FF4E170E0829C20006317A /* PBGitRevList.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PBGitRevList.m; sourceTree = ""; }; + F5FF4E780E082E440006317A /* PBGitGrapher.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PBGitGrapher.h; sourceTree = ""; }; + F5FF4E790E082E440006317A /* PBGitGrapher.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PBGitGrapher.m; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -185,6 +188,8 @@ F56174540E05887E001DCD79 /* Git */ = { isa = PBXGroup; children = ( + F5FF4E780E082E440006317A /* PBGitGrapher.h */, + F5FF4E790E082E440006317A /* PBGitGrapher.m */, F5945E150E02B0C200706420 /* PBGitRepository.h */, F5945E160E02B0C200706420 /* PBGitRepository.m */, F56524EE0E02D45200F03B52 /* PBGitCommit.h */, @@ -317,6 +322,7 @@ F5DFFA6C0E075D8800617813 /* PBEasyFS.m in Sources */, F50FE0E30E07BE9600854FCD /* PBGitRevisionCell.m in Sources */, F5FF4E180E0829C20006317A /* PBGitRevList.m in Sources */, + F5FF4E7A0E082E440006317A /* PBGitGrapher.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -352,10 +358,10 @@ GCC_MODEL_TUNING = G5; GCC_OPTIMIZATION_LEVEL = 0; GCC_PRECOMPILE_PREFIX_HEADER = YES; - GCC_PREFIX_HEADER = GitTest_Prefix.pch; + GCC_PREFIX_HEADER = GitX_Prefix.pch; INFOPLIST_FILE = Info.plist; INSTALL_PATH = "$(HOME)/Applications"; - PRODUCT_NAME = GitTest; + PRODUCT_NAME = GitX; WRAPPER_EXTENSION = app; ZERO_LINK = YES; }; diff --git a/PBGitGrapher.h b/PBGitGrapher.h new file mode 100644 index 0000000..97cfe09 --- /dev/null +++ b/PBGitGrapher.h @@ -0,0 +1,42 @@ +// +// PBGitGrapher.h +// GitX +// +// Created by Pieter de Bie on 17-06-08. +// Copyright 2008 __MyCompanyName__. All rights reserved. +// + +#import +#import "PBGitCommit.h" + + +struct PBGitGraphColumn { + NSString* commit; // Commit that we're looking for + int color; +}; + + +#define PBGitMaxColumns 10 + +struct PBGitGraphCellInfo { + struct PBGitGraphColumn columns[PBGitMaxColumns]; + int upperMapping[PBGitMaxColumns]; //How are the offsets compared to previous cell? + int lowerMapping[PBGitMaxColumns]; //How are the offsets compared to this cell? + int position; + NSString* commit; // Commit in cell + int numColumns; + int numNewColumns; +}; + +void add_commit_to_graph(struct PBGitGraphCellInfo* info, NSString* parent, int* mapping_index); + +typedef struct PBGitGraphCellInfo PBGitCellInfo; + + +@interface PBGitGrapher : NSObject { + PBGitCellInfo* cellsInfo; +} + +- (void) parseCommits: (NSArray *) array; +- (struct PBGitGraphCellInfo) cellInfoForRow: (int) row; +@end diff --git a/PBGitGrapher.m b/PBGitGrapher.m new file mode 100644 index 0000000..46a1004 --- /dev/null +++ b/PBGitGrapher.m @@ -0,0 +1,87 @@ +// +// PBGitGrapher.m +// GitX +// +// Created by Pieter de Bie on 17-06-08. +// Copyright 2008 __MyCompanyName__. All rights reserved. +// + +#import "PBGitGrapher.h" +#import "PBGitCommit.h" + +@implementation PBGitGrapher +static NSColor** PBGitGraphColors; + +- (void) parseCommits: (NSArray *) commits +{ + cellsInfo = malloc(sizeof(struct PBGitGraphCellInfo) * [commits count]); + memset(cellsInfo, 0, sizeof(struct PBGitGraphCellInfo) * [commits count]); + + int row = 0; + + struct PBGitGraphCellInfo *previous = nil; + for (PBGitCommit* commit in commits) { + struct PBGitGraphCellInfo *info = &(cellsInfo[row]); + info->commit = commit.sha; + info->numColumns = 0; + + int i = 0, newPos = -1; + BOOL didFirst = NO; + // First, iterate over earlier columns and pass through any that don't want this commit + if (previous != nil) { + for (i = 0; i < 10; i++) { + if ((previous->columns[i].commit) == nil) + continue; + if ([previous->columns[i].commit isEqualToString:info->commit]) { + if (!didFirst) { + didFirst = YES; + info->position = info->numColumns++; + info->columns[info->position].commit = [commit.parents objectAtIndex:0]; + info->columns[info->position].color = previous->columns[i].color; + } + newPos = info->position; + } + else { + newPos = info->numColumns++; + info->columns[newPos] = previous->columns[i]; + if (newPos > 1) + info->columns[newPos].color = (info->columns[newPos - 1].color + 1) % 4; + } + + info->upperMapping[newPos] = i; + if (previous) + previous->lowerMapping[i] = newPos; + + } + } + + //Add your own parents! + BOOL doFirst = YES; + + for (NSString* parent in commit.parents) { + if (doFirst) { + doFirst = NO; + if (didFirst) + continue; + info->position = info->numColumns++; + info->columns[info->position].commit = parent; + continue; + } + + info->columns[info->numColumns++].commit = parent; + } + previous = info; + ++row; + } +} +- (struct PBGitGraphCellInfo) cellInfoForRow: (int) row +{ + return cellsInfo[row]; +} + +- (void) finalize +{ + free(cellsInfo); + [super finalize]; +} +@end diff --git a/PBGitRepository.m b/PBGitRepository.m index bd9264c..ff0b273 100644 --- a/PBGitRepository.m +++ b/PBGitRepository.m @@ -14,7 +14,7 @@ @implementation PBGitRepository -@synthesize path; +@synthesize path, revisionList; static NSString* gitPath; + (void) initialize diff --git a/PBGitRevList.h b/PBGitRevList.h index 635e60a..c601d4b 100644 --- a/PBGitRevList.h +++ b/PBGitRevList.h @@ -12,10 +12,13 @@ @interface PBGitRevList : NSObject { NSArray* commits; NSArray* parameters; + id grapher; id repository; } - initWithRepository:(id)repo andRevListParameters:(NSArray*) params; @property(retain) NSArray* commits; +@property(retain) id grapher; + @end diff --git a/PBGitRevList.m b/PBGitRevList.m index c8356aa..d50328b 100644 --- a/PBGitRevList.m +++ b/PBGitRevList.m @@ -9,10 +9,11 @@ #import "PBGitRevList.h" #import "PBGitRepository.h" #import "PBGitCommit.h" +#import "PBGitGrapher.h" @implementation PBGitRevList -@synthesize commits; +@synthesize commits, grapher; - initWithRepository: (id) repo andRevListParameters: (NSArray*) params { parameters = params; @@ -72,10 +73,16 @@ } [self performSelectorOnMainThread:@selector(setCommits:) withObject:newArray waitUntilDone:YES]; + + PBGitGrapher* g = [[PBGitGrapher alloc] init]; + [g parseCommits: self.commits]; + [self performSelectorOnMainThread:@selector(setGrapher:) withObject:g waitUntilDone:YES]; + [self performSelectorOnMainThread:@selector(setCommits:) withObject:newArray waitUntilDone:YES]; + NSTimeInterval duration = [[NSDate date] timeIntervalSinceDate:start]; NSLog(@"Loaded %i commits in %f seconds", num, duration); - [NSThread exit]; } + @end diff --git a/PBGitRevisionCell.h b/PBGitRevisionCell.h index d0d047a..8523b9c 100644 --- a/PBGitRevisionCell.h +++ b/PBGitRevisionCell.h @@ -7,10 +7,12 @@ // #import +#import "PBGitGrapher.h" @interface PBGitRevisionCell : NSTextFieldCell { - NSNumber* commit; + PBGitCellInfo cellInfo; + BOOL isReady; } -@property(retain) NSNumber* commit; +@property(assign) PBGitCellInfo cellInfo; @end diff --git a/PBGitRevisionCell.m b/PBGitRevisionCell.m index 6028439..457eac3 100644 --- a/PBGitRevisionCell.m +++ b/PBGitRevisionCell.m @@ -10,15 +10,90 @@ @implementation PBGitRevisionCell -@synthesize commit; + +@synthesize cellInfo; +-(void) setCellInfo: (PBGitCellInfo) info +{ + isReady = YES; + cellInfo = info; +} + +- (id) initWithCoder: (id) coder +{ + self = [super initWithCoder:coder]; + if (self != nil) { + isReady = NO; + } + return self; +} + +- (void) drawLineForColumn: (int)c inRect: (NSRect) r +{ + NSArray* col = [NSArray arrayWithObjects:[NSColor redColor], [NSColor blueColor], + [NSColor orangeColor], [NSColor blackColor], [NSColor greenColor], nil]; + + int columnWidth = 10; + NSPoint origin = r.origin; + + NSPoint source; + NSPoint center; + NSPoint destination; + + center = NSMakePoint( origin.x + columnWidth * c, origin.y + r.size.height * 0.5); + + if (cellInfo.upperMapping[c] == cellInfo.position && c != cellInfo.upperMapping[c]) { + source = NSMakePoint(origin.x + columnWidth * cellInfo.upperMapping[c], origin.y + r.size.height * 0.5); + destination = NSMakePoint( origin.x + columnWidth * cellInfo.lowerMapping[c], origin.y + r.size.height); + } else if (cellInfo.lowerMapping[c] == cellInfo.position && c != cellInfo.lowerMapping[c]) { + source = NSMakePoint( origin.x + columnWidth * cellInfo.upperMapping[c], origin.y); + destination = NSMakePoint( origin.x + columnWidth * c, origin.y + r.size.height); + } else { + source = NSMakePoint( origin.x + columnWidth * cellInfo.upperMapping[c], origin.y); + destination = NSMakePoint( origin.x + columnWidth * cellInfo.lowerMapping[c], origin.y + r.size.height); + } + + [[col objectAtIndex:cellInfo.columns[c].color] set]; + + NSBezierPath * path = [NSBezierPath bezierPath]; + [path setLineWidth:2]; + + [path moveToPoint:source]; + [path lineToPoint: center]; + [path lineToPoint: destination]; + [path stroke]; + + +} + +- (void) drawCircleForColumn: (int) c inRect: (NSRect) r +{ + NSArray* col = [NSArray arrayWithObjects:[NSColor redColor], [NSColor blueColor], + [NSColor orangeColor], [NSColor blackColor], [NSColor greenColor], nil]; + + int columnWidth = 10; + NSPoint origin = r.origin; + NSPoint columnOrigin = { origin.x + columnWidth * c, origin.y}; + + NSRect oval = { columnOrigin.x - 5, columnOrigin.y + r.size.height * 0.5 - 5, 10, 10}; + + + NSBezierPath * path = [NSBezierPath bezierPath]; + path = [NSBezierPath bezierPathWithOvalInRect:oval]; + [[col objectAtIndex:cellInfo.columns[c].color] set]; + [path fill]; + + NSRect smallOval = { columnOrigin.x - 3, columnOrigin.y + r.size.height * 0.5 - 3, 6, 6}; + [[NSColor whiteColor] set]; + path = [NSBezierPath bezierPathWithOvalInRect:smallOval]; + [path fill]; +} - (void) drawWithFrame: (NSRect) rect inView:(NSView *)view { - - // Don't do all this drawing for now. - [super drawWithFrame:rect inView:view]; - return; - float pathWidth = 20; + if (!isReady) + return [super drawWithFrame:rect inView:view]; + + float pathWidth = 10 + 10 * cellInfo.numColumns; NSRect ownRect; NSDivideRect(rect, &ownRect, &rect, pathWidth, NSMinXEdge); @@ -26,42 +101,18 @@ // Adjust by removing the border ownRect.size.height += 2; ownRect.origin.y -= 1; + ownRect.origin.x += 10; - NSPoint origin = ownRect.origin; - NSPoint middle = { origin.x + pathWidth / 2, origin.y + ownRect.size.height * 0.5 }; - - [[NSColor redColor] set]; - NSBezierPath * path = [NSBezierPath bezierPath]; - [path moveToPoint:NSMakePoint(middle.x, origin.y)]; - [path setLineWidth:2]; - [path lineToPoint: NSMakePoint(middle.x, origin.y + ownRect.size.height)]; - [path stroke]; - [path setLineWidth:1]; - - - NSRect oval = { middle.x - 5, middle.y -5, 10, 10}; - [[NSColor orangeColor] set]; - path = [NSBezierPath bezierPathWithOvalInRect:oval]; - [path fill]; - - if ([self.commit intValue] == 0) - [[NSColor redColor] set]; - else - [[NSColor blueColor] set]; - - [path stroke]; - - NSRect smallOval = { middle.x - 3, middle.y - 3, 6, 6}; - [[NSColor whiteColor] set]; - path = [NSBezierPath bezierPathWithOvalInRect:smallOval]; - [path fill]; - [[NSColor blackColor] set]; - [path stroke]; + int column = 0; + for (column = 0; column < cellInfo.numColumns; column++) { + if (cellInfo.columns[column].color >= 0) + [self drawLineForColumn: column inRect: ownRect]; + } + [self drawCircleForColumn: cellInfo.position inRect: ownRect]; [super drawWithFrame:rect inView:view]; - [[NSColor blueColor] set]; - //[path stroke]; + isReady = NO; } @end