From bbeedd10ce905b60f522d1ffaa835bbde42891b3 Mon Sep 17 00:00:00 2001 From: Pieter de Bie Date: Wed, 27 Aug 2008 21:51:42 +0200 Subject: [PATCH] Rewrite the graphing code This uses more Cocoa classes to draw the lines, making it easier to understand and hopefully maintain. Furthermore, we use less memory now, which is nice, but all the dynamic arrays probably mean more CPU usage. --- GitX.xcodeproj/project.pbxproj | 12 ++++ PBGitGrapher.h | 22 ++----- PBGitGrapher.m | 108 ++++++++++++++++----------------- PBGitRevisionCell.h | 4 +- PBGitRevisionCell.m | 19 +++--- PBGraphCellInfo.h | 23 +++++++ PBGraphCellInfo.m | 21 +++++++ PBLine.h | 23 +++++++ PBLine.m | 32 ++++++++++ 9 files changed, 177 insertions(+), 87 deletions(-) create mode 100644 PBGraphCellInfo.h create mode 100644 PBGraphCellInfo.m create mode 100644 PBLine.h create mode 100644 PBLine.m diff --git a/GitX.xcodeproj/project.pbxproj b/GitX.xcodeproj/project.pbxproj index e85deac..d6cc851 100644 --- a/GitX.xcodeproj/project.pbxproj +++ b/GitX.xcodeproj/project.pbxproj @@ -29,6 +29,8 @@ F56526240E03D85900F03B52 /* WebKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F56526230E03D85900F03B52 /* WebKit.framework */; }; F565262B0E03D89B00F03B52 /* PBWebGitController.m in Sources */ = {isa = PBXBuildFile; fileRef = F565262A0E03D89B00F03B52 /* PBWebGitController.m */; }; F565265A0E03E71B00F03B52 /* commit.html in Resources */ = {isa = PBXBuildFile; fileRef = F56526590E03E71B00F03B52 /* commit.html */; }; + F56CC7290E65E0AD004307B4 /* PBLine.m in Sources */ = {isa = PBXBuildFile; fileRef = F56CC7280E65E0AD004307B4 /* PBLine.m */; }; + F56CC7320E65E0E5004307B4 /* PBGraphCellInfo.m in Sources */ = {isa = PBXBuildFile; fileRef = F56CC7310E65E0E5004307B4 /* PBGraphCellInfo.m */; }; F57ABE0B0E0442DD00A088B8 /* commit.js in Resources */ = {isa = PBXBuildFile; fileRef = F57ABDDE0E0441DE00A088B8 /* commit.js */; }; F57ABE2B0E04435100A088B8 /* prototype.js in Resources */ = {isa = PBXBuildFile; fileRef = F57ABE180E04431D00A088B8 /* prototype.js */; }; F57CC3910E05DDF2000472E2 /* PBEasyPipe.m in Sources */ = {isa = PBXBuildFile; fileRef = F57CC3900E05DDF2000472E2 /* PBEasyPipe.m */; }; @@ -90,6 +92,10 @@ F56526290E03D89B00F03B52 /* PBWebGitController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PBWebGitController.h; sourceTree = ""; }; F565262A0E03D89B00F03B52 /* PBWebGitController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PBWebGitController.m; sourceTree = ""; }; F56526590E03E71B00F03B52 /* commit.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; name = commit.html; path = html/commit.html; sourceTree = ""; }; + F56CC7270E65E0AD004307B4 /* PBLine.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PBLine.h; sourceTree = ""; }; + F56CC7280E65E0AD004307B4 /* PBLine.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PBLine.m; sourceTree = ""; }; + F56CC7300E65E0E5004307B4 /* PBGraphCellInfo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PBGraphCellInfo.h; sourceTree = ""; }; + F56CC7310E65E0E5004307B4 /* PBGraphCellInfo.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PBGraphCellInfo.m; sourceTree = ""; }; F57ABDDE0E0441DE00A088B8 /* commit.js */ = {isa = PBXFileReference; explicitFileType = sourcecode.javascript; fileEncoding = 4; name = commit.js; path = html/commit.js; sourceTree = ""; }; F57ABE180E04431D00A088B8 /* prototype.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = prototype.js; path = html/prototype.js; sourceTree = ""; }; F57CC38F0E05DDF2000472E2 /* PBEasyPipe.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PBEasyPipe.h; sourceTree = ""; }; @@ -232,6 +238,8 @@ F56174540E05887E001DCD79 /* Git */ = { isa = PBXGroup; children = ( + F56CC7300E65E0E5004307B4 /* PBGraphCellInfo.h */, + F56CC7310E65E0E5004307B4 /* PBGraphCellInfo.m */, F5FF4E780E082E440006317A /* PBGitGrapher.h */, F5FF4E790E082E440006317A /* PBGitGrapher.m */, F5945E150E02B0C200706420 /* PBGitRepository.h */, @@ -277,6 +285,8 @@ F513085A0E0740F2000C8BCD /* PBQLOutlineView.m */, F50FE0E10E07BE9600854FCD /* PBGitRevisionCell.h */, F50FE0E20E07BE9600854FCD /* PBGitRevisionCell.m */, + F56CC7270E65E0AD004307B4 /* PBLine.h */, + F56CC7280E65E0AD004307B4 /* PBLine.m */, ); name = Aux; sourceTree = ""; @@ -393,6 +403,8 @@ F5FF4E7A0E082E440006317A /* PBGitGrapher.m in Sources */, 911111F80E594F3F00BF76B4 /* PBRepositoryDocumentController.m in Sources */, 913D5E5F0E556A9300CECEA2 /* PBCLIProxy.mm in Sources */, + F56CC7290E65E0AD004307B4 /* PBLine.m in Sources */, + F56CC7320E65E0E5004307B4 /* PBGraphCellInfo.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/PBGitGrapher.h b/PBGitGrapher.h index 3a421f2..58311ad 100644 --- a/PBGitGrapher.h +++ b/PBGitGrapher.h @@ -8,7 +8,8 @@ #import #import "PBGitCommit.h" - +#import "PBLine.h" +#import "PBGraphCellInfo.h" struct PBGitGraphColumn { NSString* commit; // Commit that we're looking for @@ -18,25 +19,10 @@ struct PBGitGraphColumn { #define PBGitMaxColumns 100 -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; + NSMutableArray* cellsInfo; } - (void) parseCommits: (NSArray *) array; -- (struct PBGitGraphCellInfo) cellInfoForRow: (int) row; +- (PBGraphCellInfo*) cellInfoForRow: (int) row; @end diff --git a/PBGitGrapher.m b/PBGitGrapher.m index e643807..1beff13 100644 --- a/PBGitGrapher.m +++ b/PBGitGrapher.m @@ -14,73 +14,67 @@ - (void) parseCommits: (NSArray *) commits { - cellsInfo = malloc(sizeof(struct PBGitGraphCellInfo) * [commits count]); - memset(cellsInfo, 0, sizeof(struct PBGitGraphCellInfo) * [commits count]); - + cellsInfo = [NSMutableArray arrayWithCapacity: [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; + PBGraphCellInfo* previous; + NSMutableArray* previousLanes = [NSMutableArray array]; + for (PBGitCommit* commit in commits) { int i = 0, newPos = -1; - for (i = 0; i < PBGitMaxColumns; i++) { - info->lowerMapping[i] = -1; - info->upperMapping[i] = -1; - } - + NSMutableArray* currentLanes = [NSMutableArray array]; + NSMutableArray* lines = [NSMutableArray array]; BOOL didFirst = NO; + // First, iterate over earlier columns and pass through any that don't want this commit if (previous != nil) { // We can't count until numColumns here, as it's only used for the width of the cell. - for (i = 0; i < PBGitMaxColumns; i++) { - if ((previous->columns[i].commit) == nil) - continue; - + for (NSString* lane in previousLanes) { + i++; // This is our commit! We should do a "merge": move the line from // our upperMapping to their lowerMapping - if ([previous->columns[i].commit isEqualToString:info->commit]) { + if ([lane isEqualToString:commit.sha]) { if (!didFirst) { didFirst = YES; - info->position = info->numColumns++; - info->columns[info->position].commit = [commit.parents objectAtIndex:0]; + [currentLanes addObject: [commit.parents objectAtIndex:0]]; + newPos = [currentLanes count]; } - newPos = info->position; - info->upperMapping[i] = newPos; + [lines addObject: [PBLine upperLineFrom: i to: newPos]]; } else { // We are not this commit. // Try to find an earlier column for this commit. - int j; + int j = 0; BOOL found = NO; - for (j = 0; j < info->numColumns; j++) { - if (j == info->position) + for (NSString* column in currentLanes) { + j++; + // ??? what is this? + if (j == newPos) continue; - if ([previous->columns[i].commit isEqualToString: info->columns[j].commit]) { + if ([column isEqualToString: lane]) { // We already have a column for this commit. use it instead - newPos = j; - info->upperMapping[previous->lowerMapping[i]] = newPos; + [lines addObject: [PBLine lowerLineFrom: i to: j]]; found = YES; break; } } + // We need a new column for this. if (!found) { - if (previous->columns[i].color == 10) - continue; + // This was used as a hack to stop large lanes from drawing + //if (previous->columns[i].color == 10) + // continue; - newPos = info->numColumns++; - info->columns[newPos] = previous->columns[i]; - info->columns[newPos].color++; - info->upperMapping[newPos] = newPos; + [currentLanes addObject: lane]; + [lines addObject: [PBLine upperLineFrom: [currentLanes count] to: [currentLanes count]]]; + [lines addObject: [PBLine lowerLineFrom: [currentLanes count] to: [currentLanes count]]]; } } // For existing columns, we always just continue straight down - info->lowerMapping[newPos] = newPos; + // ^^ I don't know what that means anymore :( + [lines addObject:[PBLine lowerLineFrom:newPos to:newPos]]; } } @@ -88,9 +82,9 @@ // If we already did the first parent, don't do so again if (!didFirst) { - info->position = info->numColumns++; - info->columns[info->position].commit = [commit.parents objectAtIndex:0]; - info->lowerMapping[info->position] = info->position; + [currentLanes addObject: [commit.parents objectAtIndex:0]]; + newPos = [currentLanes count]; + [lines addObject:[PBLine lowerLineFrom: newPos to: newPos]]; } // Add all other parents @@ -100,39 +94,41 @@ BOOL addedParent = NO; for (NSString* parent in [commit.parents subarrayWithRange:NSMakeRange(1, [commit.parents count] -1)]) { - int i; + int i = 0; BOOL was_displayed = NO; - for (i = 0; i < info->numColumns; i++) - if ([info->columns[i].commit isEqualToString: parent]) { - // TODO! - // !!! BUG - // This overwrites an existing mapping. - // We should instead have the possibility - // to add multiple lower mappings - // As we don't have that now, pieces of the graph are missing - info->lowerMapping[i] = info->position; + for (NSString* column in currentLanes) { + i++; + if ([column isEqualToString: parent]) { + [lines addObject:[PBLine lowerLineFrom: i to: newPos]]; was_displayed = YES; break; } + } if (was_displayed) continue; // Really add this parent addedParent = YES; - info->columns[info->numColumns++].commit = parent; - info->lowerMapping[info->numColumns -1] = info->position; + [currentLanes addObject:parent]; + [lines addObject:[PBLine lowerLineFrom: [currentLanes count] to: newPos]]; } - // A parent was added, so we have room to not indent. - if (addedParent) - info->numColumns--; - previous = info; ++row; + previous = [[PBGraphCellInfo alloc] initWithPosition:newPos andLines:lines]; + + // If a parent was added, we have room to not indent. + if (addedParent) + previous.numColumns = [currentLanes count] - 1; + else + previous.numColumns = [currentLanes count]; + previousLanes = currentLanes; + [cellsInfo addObject: previous]; } } -- (struct PBGitGraphCellInfo) cellInfoForRow: (int) row + +- (PBGraphCellInfo*) cellInfoForRow: (int) row { - return cellsInfo[row]; + return [cellsInfo objectAtIndex: row]; } - (void) finalize diff --git a/PBGitRevisionCell.h b/PBGitRevisionCell.h index 8523b9c..def74c8 100644 --- a/PBGitRevisionCell.h +++ b/PBGitRevisionCell.h @@ -10,9 +10,9 @@ #import "PBGitGrapher.h" @interface PBGitRevisionCell : NSTextFieldCell { - PBGitCellInfo cellInfo; + PBGraphCellInfo* cellInfo; BOOL isReady; } -@property(assign) PBGitCellInfo cellInfo; +@property(assign) PBGraphCellInfo* cellInfo; @end diff --git a/PBGitRevisionCell.m b/PBGitRevisionCell.m index 3d960e2..e17013a 100644 --- a/PBGitRevisionCell.m +++ b/PBGitRevisionCell.m @@ -12,7 +12,7 @@ @implementation PBGitRevisionCell @synthesize cellInfo; --(void) setCellInfo: (PBGitCellInfo) info +-(void) setCellInfo: (PBGraphCellInfo*) info { isReady = YES; cellInfo = info; @@ -68,7 +68,7 @@ NSBezierPath * path = [NSBezierPath bezierPath]; path = [NSBezierPath bezierPathWithOvalInRect:oval]; - [[col objectAtIndex:cellInfo.columns[c].color] set]; + //[[col objectAtIndex:cellInfo.columns[c].color] set]; [path fill]; NSRect smallOval = { columnOrigin.x - 3, columnOrigin.y + r.size.height * 0.5 - 3, 6, 6}; @@ -90,16 +90,13 @@ // Adjust by removing the border ownRect.size.height += 2; ownRect.origin.y -= 1; - ownRect.origin.x += 10; - - int column = 0; + ownRect.origin.x += 0; - // We can't iterate over numColumns here, as there may be connections to be drawn outside our columns. - for (column = 0; column < PBGitMaxColumns; column++) { - if (cellInfo.upperMapping[column] !=-1) - [self drawLineFromColumn:column toColumn: cellInfo.upperMapping[column] inRect:ownRect offset: 0]; - if (cellInfo.lowerMapping[column] !=-1) - [self drawLineFromColumn: column toColumn: cellInfo.lowerMapping[column] inRect:ownRect offset: ownRect.size.height]; + for (PBLine* line in cellInfo.lines) { + if (line.upper == 0) + [self drawLineFromColumn: line.from toColumn: line.to inRect:ownRect offset: ownRect.size.height]; + else + [self drawLineFromColumn:line.from toColumn: line.to inRect:ownRect offset: 0]; } [self drawCircleForColumn: cellInfo.position inRect: ownRect]; diff --git a/PBGraphCellInfo.h b/PBGraphCellInfo.h new file mode 100644 index 0000000..8f4b84b --- /dev/null +++ b/PBGraphCellInfo.h @@ -0,0 +1,23 @@ +// +// PBGraphCellInfo.h +// GitX +// +// Created by Pieter de Bie on 27-08-08. +// Copyright 2008 __MyCompanyName__. All rights reserved. +// + +#import + + +@interface PBGraphCellInfo : NSObject +{ + int position; + NSArray* lines; + int numColumns; +} +@property(readonly) NSArray* lines; +@property(assign) int position, numColumns; + +- (id)initWithPosition: (int) p andLines: (NSArray*) l; + +@end \ No newline at end of file diff --git a/PBGraphCellInfo.m b/PBGraphCellInfo.m new file mode 100644 index 0000000..f5e96b5 --- /dev/null +++ b/PBGraphCellInfo.m @@ -0,0 +1,21 @@ +// +// PBGraphCellInfo.m +// GitX +// +// Created by Pieter de Bie on 27-08-08. +// Copyright 2008 __MyCompanyName__. All rights reserved. +// + +#import "PBGraphCellInfo.h" + + +@implementation PBGraphCellInfo +@synthesize lines, position, numColumns; +- (id)initWithPosition: (int) p andLines: (NSArray*) l +{ + position = p; + lines = l; + + return self; +} +@end \ No newline at end of file diff --git a/PBLine.h b/PBLine.h new file mode 100644 index 0000000..63859e4 --- /dev/null +++ b/PBLine.h @@ -0,0 +1,23 @@ +// +// PBLine.h +// GitX +// +// Created by Pieter de Bie on 27-08-08. +// Copyright 2008 __MyCompanyName__. All rights reserved. +// + +#import + + +@interface PBLine : NSObject +{ + int upper; + int from; + int to; +} +@property(readonly) int upper, from, to; +- (id)initWithUpper: (int) u From: (int) f to: (int) t; ++ (PBLine*) lowerLineFrom:(int) f to: (int) t; ++ (PBLine*) upperLineFrom:(int) f to: (int) t; + +@end \ No newline at end of file diff --git a/PBLine.m b/PBLine.m new file mode 100644 index 0000000..a0c2880 --- /dev/null +++ b/PBLine.m @@ -0,0 +1,32 @@ +// +// PBLine.m +// GitX +// +// Created by Pieter de Bie on 27-08-08. +// Copyright 2008 __MyCompanyName__. All rights reserved. +// + +#import "PBLine.h" + + +@implementation PBLine +@synthesize upper, from, to; +- (id)initWithUpper: (int) u From: (int) f to: (int) t; +{ + upper = u; + from = f; + to = t; + + return self; +} + ++ (PBLine*) lowerLineFrom:(int) f to: (int) t +{ + return [[PBLine alloc] initWithUpper:0 From:f to:t]; +} + ++ (PBLine*) upperLineFrom:(int) f to: (int) t +{ + return [[PBLine alloc] initWithUpper:1 From:f to:t]; +} +@end