Merge commit 'origin/jg/tree_context'
[GitX.git] / PBGitGrapher.mm
blobf9daf8492e37c26ee74f0cace1019a300ee7bef0
1 //
2 //  PBGitGrapher.m
3 //  GitX
4 //
5 //  Created by Pieter de Bie on 17-06-08.
6 //  Copyright 2008 __MyCompanyName__. All rights reserved.
7 //
9 #import "PBGitGrapher.h"
10 #import "PBGitCommit.h"
11 #import "PBGitLane.h"
12 #import "PBGitGraphLine.h"
13 #import <list>
14 #import "git/oid.h"
16 using namespace std;
18 @implementation PBGitGrapher
20 #define MAX_LANES 32
22 - (id) initWithRepository: (PBGitRepository*) repo
24         pl = new std::list<PBGitLane *>;
26         PBGitLane::resetColors();
27         return self;
30 void add_line(struct PBGitGraphLine *lines, int *nLines, int upper, int from, int to, int index)
32         // TODO: put in one thing
33         struct PBGitGraphLine a = { upper, from, to, index };
34         lines[(*nLines)++] = a;
37 - (void) decorateCommit: (PBGitCommit *) commit
39         int i = 0, newPos = -1;
40         std::list<PBGitLane *> *currentLanes = new std::list<PBGitLane *>;
41         std::list<PBGitLane *> *previousLanes = (std::list<PBGitLane *> *)pl;
43         int maxLines = (previousLanes->size() + commit.nParents + 2) * 2;
44         struct PBGitGraphLine *lines = (struct PBGitGraphLine *)malloc(sizeof(struct PBGitGraphLine) * maxLines);
45         int currentLine = 0;
47         PBGitLane *currentLane = NULL;
48         BOOL didFirst = NO;
49         
50         // First, iterate over earlier columns and pass through any that don't want this commit
51         if (previous != nil) {
52                 // We can't count until numColumns here, as it's only used for the width of the cell.
53                 std::list<PBGitLane *>::iterator it = previousLanes->begin();
54                 for (; it != previousLanes->end(); ++it) {
55                         i++;
56                         // This is our commit! We should do a "merge": move the line from
57                         // our upperMapping to their lowerMapping
58                         if ((*it)->isCommit([commit sha])) {
59                                 if (!didFirst) {
60                                         didFirst = YES;
61                                         currentLanes->push_back(*it);
62                                         currentLane = currentLanes->back();
63                                         newPos = currentLanes->size();
64                                         add_line(lines, &currentLine, 1, i, newPos,(*it)->index());
65                                         if (commit.nParents)
66                                                 add_line(lines, &currentLine, 0, newPos, newPos,(*it)->index());
67                                 }
68                                 else {
69                                         add_line(lines, &currentLine, 1, i, newPos,(*it)->index());
70                                         delete *it;
71                                 }
72                         }
73                         else {
74                                 // We are not this commit.
75                                 currentLanes->push_back(*it);
76                                 add_line(lines, &currentLine, 1, i, currentLanes->size(),(*it)->index());
77                                 add_line(lines, &currentLine, 0, currentLanes->size(), currentLanes->size(), (*it)->index());
78                         }
79                         // For existing columns, we always just continue straight down
80                         // ^^ I don't know what that means anymore :(
82                 }
83         }
84         //Add your own parents
86         // If we already did the first parent, don't do so again
87         if (!didFirst && currentLanes->size() < MAX_LANES && commit.nParents) {
88                 PBGitLane *newLane = new PBGitLane(commit.parentShas);
89                 currentLanes->push_back(newLane);
90                 newPos = currentLanes->size();
91                 add_line(lines, &currentLine, 0, newPos, newPos, newLane->index());
92         }
94         // Add all other parents
96         // If we add at least one parent, we can go back a single column.
97         // This boolean will tell us if that happened
98         BOOL addedParent = NO;
100         int parentIndex;
101         for (parentIndex = 1; parentIndex < commit.nParents; ++parentIndex) {
102                 git_oid *parent = commit.parentShas + parentIndex;
103                 int i = 0;
104                 BOOL was_displayed = NO;
105                 std::list<PBGitLane *>::iterator it = currentLanes->begin();
106                 for (; it != currentLanes->end(); ++it) {
107                         i++;
108                         if ((*it)->isCommit(parent)) {
109                                 add_line(lines, &currentLine, 0, i, newPos,(*it)->index());
110                                 was_displayed = YES;
111                                 break;
112                         }
113                 }
114                 if (was_displayed)
115                         continue;
116                 
117                 if (currentLanes->size() >= MAX_LANES)
118                         break;
120                 // Really add this parent
121                 addedParent = YES;
122                 PBGitLane *newLane = new PBGitLane(parent);
123                 currentLanes->push_back(newLane);
124                 add_line(lines, &currentLine, 0, currentLanes->size(), newPos, newLane->index());
125         }
127         previous = [[PBGraphCellInfo alloc] initWithPosition:newPos andLines:lines];
128         if (currentLine > maxLines)
129                 NSLog(@"Number of lines: %i vs allocated: %i", currentLine, maxLines);
131         previous.nLines = currentLine;
132         previous.sign = commit.sign;
134         // If a parent was added, we have room to not indent.
135         if (addedParent)
136                 previous.numColumns = currentLanes->size() - 1;
137         else
138                 previous.numColumns = currentLanes->size();
140         // Update the current lane to point to the new parent
141         if (currentLane && commit.nParents > 0)
142                 currentLane->setSha(commit.parentShas[0]);
143         else
144                 currentLanes->remove(currentLane);
146         delete previousLanes;
148         pl = currentLanes;
149         commit.lineInfo = previous;
152 - (void) finalize
154         std::list<PBGitLane *> *lanes = (std::list<PBGitLane *> *)pl;
155         std::list<PBGitLane *>::iterator it = lanes->begin();
156         for (; it != lanes->end(); ++it)
157                 delete *it;
159         delete lanes;
161         [super finalize];
163 @end