Skip to content

Commit 9200d3e

Browse files
committed
blame
1 parent 84ea632 commit 9200d3e

File tree

9 files changed

+399
-20
lines changed

9 files changed

+399
-20
lines changed

GLFileView.h

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,23 @@
88

99
#import <Cocoa/Cocoa.h>
1010
#import "PBWebController.h"
11-
11+
#import "MGScopeBarDelegateProtocol.h"
1212
#import "PBGitCommit.h"
1313
#import "PBGitHistoryController.h"
1414
#import "PBRefContextDelegate.h"
1515

16+
@class PBGitGradientBarView;
1617

17-
@interface GLFileView : PBWebController {
18+
@interface GLFileView : PBWebController <MGScopeBarDelegate> {
1819
IBOutlet PBGitHistoryController* historyController;
20+
IBOutlet MGScopeBar *typeBar;
21+
NSMutableArray *groups;
1922
}
2023

24+
- (void)showFile;
25+
- (void)didLoad;
26+
- (NSString *)parseBlame:(NSString *)txt;
27+
28+
@property(retain) NSMutableArray *groups;
29+
2130
@end

GLFileView.m

Lines changed: 161 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,14 @@
77
//
88

99
#import "GLFileView.h"
10+
#import "PBGitGradientBarView.h"
1011

12+
#define GROUP_LABEL @"Label" // string
13+
#define GROUP_SEPARATOR @"HasSeparator" // BOOL as NSNumber
14+
#define GROUP_SELECTION_MODE @"SelectionMode" // MGScopeBarGroupSelectionMode (int) as NSNumber
15+
#define GROUP_ITEMS @"Items" // array of dictionaries, each containing the following keys:
16+
#define ITEM_IDENTIFIER @"Identifier" // string
17+
#define ITEM_NAME @"Name" // string
1118

1219
@implementation GLFileView
1320

@@ -17,17 +24,170 @@ - (void) awakeFromNib
1724
//repository = historyController.repository;
1825
[super awakeFromNib];
1926
[historyController.treeController addObserver:self forKeyPath:@"selection" options:0 context:@"treeController"];
27+
28+
self.groups = [NSMutableArray arrayWithCapacity:0];
29+
30+
NSArray *items = [NSArray arrayWithObjects:
31+
[NSDictionary dictionaryWithObjectsAndKeys:
32+
startFile, ITEM_IDENTIFIER,
33+
@"Source", ITEM_NAME,
34+
nil],
35+
[NSDictionary dictionaryWithObjectsAndKeys:
36+
@"blame", ITEM_IDENTIFIER,
37+
@"Blame", ITEM_NAME,
38+
nil],
39+
nil];
40+
[self.groups addObject:[NSDictionary dictionaryWithObjectsAndKeys:
41+
[NSNumber numberWithBool:NO], GROUP_SEPARATOR,
42+
[NSNumber numberWithInt:MGRadioSelectionMode], GROUP_SELECTION_MODE, // single selection group.
43+
items, GROUP_ITEMS,
44+
nil]];
45+
[typeBar reloadData];
2046
}
2147

2248
- (void) observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
2349
{
2450
//NSLog(@"keyPath=%@ change=%@ context=%@ object=%@ \n %@",keyPath,change,context,object,[historyController.treeController selectedObjects]);
51+
[self showFile];
52+
}
53+
54+
- (void) showFile
55+
{
2556
NSArray *files=[historyController.treeController selectedObjects];
2657
if ([files count]>0) {
2758
PBGitTree *file=[files objectAtIndex:0];
28-
NSString *fileTxt=[file textContents];
59+
60+
NSString *fileTxt=@"";
61+
if(startFile==@"fileview")
62+
fileTxt=[file textContents];
63+
if(startFile==@"blame")
64+
fileTxt=[self parseBlame:[file blame]];
65+
2966
id script = [view windowScriptObject];
3067
[script callWebScriptMethod:@"showFile" withArguments:[NSArray arrayWithObject:fileTxt]];
3168
}
3269
}
70+
71+
#pragma mark MGScopeBarDelegate methods
72+
73+
74+
- (int)numberOfGroupsInScopeBar:(MGScopeBar *)theScopeBar
75+
{
76+
return [self.groups count];
77+
}
78+
79+
80+
- (NSArray *)scopeBar:(MGScopeBar *)theScopeBar itemIdentifiersForGroup:(int)groupNumber
81+
{
82+
return [[self.groups objectAtIndex:groupNumber] valueForKeyPath:[NSString stringWithFormat:@"%@.%@", GROUP_ITEMS, ITEM_IDENTIFIER]];
83+
}
84+
85+
86+
- (NSString *)scopeBar:(MGScopeBar *)theScopeBar labelForGroup:(int)groupNumber
87+
{
88+
return [[self.groups objectAtIndex:groupNumber] objectForKey:GROUP_LABEL]; // might be nil, which is fine (nil means no label).
89+
}
90+
91+
92+
- (NSString *)scopeBar:(MGScopeBar *)theScopeBar titleOfItem:(NSString *)identifier inGroup:(int)groupNumber
93+
{
94+
NSArray *items = [[self.groups objectAtIndex:groupNumber] objectForKey:GROUP_ITEMS];
95+
if (items) {
96+
for (NSDictionary *item in items) {
97+
if ([[item objectForKey:ITEM_IDENTIFIER] isEqualToString:identifier]) {
98+
return [item objectForKey:ITEM_NAME];
99+
break;
100+
}
101+
}
102+
}
103+
return nil;
104+
}
105+
106+
107+
- (MGScopeBarGroupSelectionMode)scopeBar:(MGScopeBar *)theScopeBar selectionModeForGroup:(int)groupNumber
108+
{
109+
return [[[self.groups objectAtIndex:groupNumber] objectForKey:GROUP_SELECTION_MODE] intValue];
110+
}
111+
112+
- (void)scopeBar:(MGScopeBar *)theScopeBar selectedStateChanged:(BOOL)selected forItem:(NSString *)identifier inGroup:(int)groupNumber
113+
{
114+
startFile=identifier;
115+
NSString *path = [NSString stringWithFormat:@"html/views/%@", identifier];
116+
NSString *html = [[NSBundle mainBundle] pathForResource:@"index" ofType:@"html" inDirectory:path];
117+
//NSLog(@"[FileViewerController scopeBar:selectedStateChanged] -> file: '%@' (%@)",html,identifier);
118+
NSURLRequest * request = [NSURLRequest requestWithURL:[NSURL fileURLWithPath:html]];
119+
[[view mainFrame] loadRequest:request];
120+
}
121+
122+
- (void) didLoad
123+
{
124+
[self showFile];
125+
}
126+
127+
- (NSString *) parseBlame:(NSString *)txt
128+
{
129+
txt=[txt stringByReplacingOccurrencesOfString:@"<" withString:@"&lt;"];
130+
txt=[txt stringByReplacingOccurrencesOfString:@">" withString:@"&gt;"];
131+
132+
NSArray *lines = [txt componentsSeparatedByString:@"\n"];
133+
NSString *line;
134+
NSMutableDictionary *headers=[NSMutableDictionary dictionary];
135+
NSMutableString *res=[NSMutableString string];
136+
137+
[res appendString:@"<table class='blocks'>\n"];
138+
int i=0;
139+
while(i<[lines count]){
140+
line=[lines objectAtIndex:i];
141+
NSArray *header=[line componentsSeparatedByString:@" "];
142+
if([header count]==4){
143+
int nLines=[(NSString *)[header objectAtIndex:3] intValue];
144+
[res appendFormat:@"<tr class='block l%d'>\n",nLines];
145+
line=[lines objectAtIndex:++i];
146+
if([[[line componentsSeparatedByString:@" "] objectAtIndex:0] isEqual:@"author"]){
147+
NSString *author=line;
148+
NSString *summary=nil;
149+
while(summary==nil){
150+
line=[lines objectAtIndex:i++];
151+
if([[[line componentsSeparatedByString:@" "] objectAtIndex:0] isEqual:@"summary"]){
152+
summary=line;
153+
}
154+
}
155+
NSString *block=[NSString stringWithFormat:@"<td><p class='author'>%@</p><p class='summary'>%@</p></td>\n<td>\n",author,summary];
156+
[headers setObject:block forKey:[header objectAtIndex:0]];
157+
}
158+
[res appendString:[headers objectForKey:[header objectAtIndex:0]]];
159+
160+
NSMutableString *code=[NSMutableString string];
161+
do{
162+
line=[lines objectAtIndex:i++];
163+
}while([line characterAtIndex:0]!='\t');
164+
line=[line stringByReplacingOccurrencesOfString:@"\t" withString:@"&nbsp;&nbsp;&nbsp;&nbsp;"];
165+
[code appendString:line];
166+
[code appendString:@"\n"];
167+
168+
int n;
169+
for(n=1;n<nLines;n++){
170+
line=[lines objectAtIndex:i++];
171+
do{
172+
line=[lines objectAtIndex:i++];
173+
}while([line characterAtIndex:0]!='\t');
174+
line=[line stringByReplacingOccurrencesOfString:@"\t" withString:@"&nbsp;&nbsp;&nbsp;&nbsp;"];
175+
[code appendString:line];
176+
[code appendString:@"\n"];
177+
}
178+
[res appendFormat:@"<pre class='first-line: %@;brush: objc'>%@</pre>",[header objectAtIndex:2],code];
179+
[res appendString:@"</td>\n"];
180+
}else{
181+
break;
182+
}
183+
[res appendString:@"</tr>\n"];
184+
}
185+
[res appendString:@"</table>\n"];
186+
//NSLog(@"%@",res);
187+
188+
return (NSString *)res;
189+
}
190+
191+
@synthesize groups;
192+
33193
@end

GitX.xcodeproj/project.pbxproj

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,12 @@
2323
/* Begin PBXBuildFile section */
2424
056438B70ED0C40B00985397 /* DetailViewTemplate.png in Resources */ = {isa = PBXBuildFile; fileRef = 056438B60ED0C40B00985397 /* DetailViewTemplate.png */; };
2525
310DC1D81240599E0017A0F7 /* GLFileView.m in Sources */ = {isa = PBXBuildFile; fileRef = 310DC1D71240599E0017A0F7 /* GLFileView.m */; };
26+
31460CB2124185BA00B90AED /* AppController.m in Sources */ = {isa = PBXBuildFile; fileRef = 31460C7B124185BA00B90AED /* AppController.m */; };
27+
31460CD2124185BA00B90AED /* MGRecessedPopUpButtonCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 31460CA7124185BA00B90AED /* MGRecessedPopUpButtonCell.m */; };
28+
31460CD3124185BA00B90AED /* MGScopeBar.m in Sources */ = {isa = PBXBuildFile; fileRef = 31460CA9124185BA00B90AED /* MGScopeBar.m */; };
29+
31460CD4124185BA00B90AED /* ReadMe.txt in Resources */ = {isa = PBXBuildFile; fileRef = 31460CAF124185BA00B90AED /* ReadMe.txt */; };
30+
31460CD5124185BA00B90AED /* Source Code License.rtf in Resources */ = {isa = PBXBuildFile; fileRef = 31460CB0124185BA00B90AED /* Source Code License.rtf */; };
31+
31460CD6124185BA00B90AED /* TODO in Resources */ = {isa = PBXBuildFile; fileRef = 31460CB1124185BA00B90AED /* TODO */; };
2632
3BC07F4C0ED5A5C5009A7768 /* HistoryViewTemplate.png in Resources */ = {isa = PBXBuildFile; fileRef = 3BC07F4A0ED5A5C5009A7768 /* HistoryViewTemplate.png */; };
2733
3BC07F4D0ED5A5C5009A7768 /* CommitViewTemplate.png in Resources */ = {isa = PBXBuildFile; fileRef = 3BC07F4B0ED5A5C5009A7768 /* CommitViewTemplate.png */; };
2834
47DBDB580E94EDE700671A1E /* DBPrefsWindowController.m in Sources */ = {isa = PBXBuildFile; fileRef = 47DBDB570E94EDE700671A1E /* DBPrefsWindowController.m */; };
@@ -246,6 +252,17 @@
246252
29B97325FDCFA39411CA2CEA /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = /System/Library/Frameworks/Foundation.framework; sourceTree = "<absolute>"; };
247253
310DC1D61240599E0017A0F7 /* GLFileView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GLFileView.h; sourceTree = "<group>"; };
248254
310DC1D71240599E0017A0F7 /* GLFileView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GLFileView.m; sourceTree = "<group>"; };
255+
31460C7A124185BA00B90AED /* AppController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppController.h; sourceTree = "<group>"; };
256+
31460C7B124185BA00B90AED /* AppController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AppController.m; sourceTree = "<group>"; };
257+
31460CA6124185BA00B90AED /* MGRecessedPopUpButtonCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGRecessedPopUpButtonCell.h; sourceTree = "<group>"; };
258+
31460CA7124185BA00B90AED /* MGRecessedPopUpButtonCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MGRecessedPopUpButtonCell.m; sourceTree = "<group>"; };
259+
31460CA8124185BA00B90AED /* MGScopeBar.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGScopeBar.h; sourceTree = "<group>"; };
260+
31460CA9124185BA00B90AED /* MGScopeBar.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MGScopeBar.m; sourceTree = "<group>"; };
261+
31460CAD124185BA00B90AED /* MGScopeBar_Prefix.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGScopeBar_Prefix.pch; sourceTree = "<group>"; };
262+
31460CAE124185BA00B90AED /* MGScopeBarDelegateProtocol.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGScopeBarDelegateProtocol.h; sourceTree = "<group>"; };
263+
31460CAF124185BA00B90AED /* ReadMe.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = ReadMe.txt; sourceTree = "<group>"; };
264+
31460CB0124185BA00B90AED /* Source Code License.rtf */ = {isa = PBXFileReference; lastKnownFileType = text.rtf; path = "Source Code License.rtf"; sourceTree = "<group>"; };
265+
31460CB1124185BA00B90AED /* TODO */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = TODO; sourceTree = "<group>"; };
249266
32CA4F630368D1EE00C91783 /* GitX_Prefix.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GitX_Prefix.pch; sourceTree = "<group>"; };
250267
3BC07F4A0ED5A5C5009A7768 /* HistoryViewTemplate.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = HistoryViewTemplate.png; path = Images/HistoryViewTemplate.png; sourceTree = "<group>"; };
251268
3BC07F4B0ED5A5C5009A7768 /* CommitViewTemplate.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = CommitViewTemplate.png; path = Images/CommitViewTemplate.png; sourceTree = "<group>"; };
@@ -568,6 +585,7 @@
568585
29B97314FDCFA39411CA2CEA /* GitTest */ = {
569586
isa = PBXGroup;
570587
children = (
588+
31460C79124185B900B90AED /* MGScopeBar */,
571589
F5886A080ED5D26B0066E74C /* SpeedTest */,
572590
913D5E420E5563FD00CECEA2 /* cli */,
573591
D89E9B4C1218C22A0097A90B /* GitXScripting */,
@@ -668,6 +686,24 @@
668686
name = FileView;
669687
sourceTree = "<group>";
670688
};
689+
31460C79124185B900B90AED /* MGScopeBar */ = {
690+
isa = PBXGroup;
691+
children = (
692+
31460C7A124185BA00B90AED /* AppController.h */,
693+
31460C7B124185BA00B90AED /* AppController.m */,
694+
31460CA6124185BA00B90AED /* MGRecessedPopUpButtonCell.h */,
695+
31460CA7124185BA00B90AED /* MGRecessedPopUpButtonCell.m */,
696+
31460CA8124185BA00B90AED /* MGScopeBar.h */,
697+
31460CA9124185BA00B90AED /* MGScopeBar.m */,
698+
31460CAD124185BA00B90AED /* MGScopeBar_Prefix.pch */,
699+
31460CAE124185BA00B90AED /* MGScopeBarDelegateProtocol.h */,
700+
31460CAF124185BA00B90AED /* ReadMe.txt */,
701+
31460CB0124185BA00B90AED /* Source Code License.rtf */,
702+
31460CB1124185BA00B90AED /* TODO */,
703+
);
704+
path = MGScopeBar;
705+
sourceTree = "<group>";
706+
};
671707
47DBDB920E94F47200671A1E /* Preference Icons */ = {
672708
isa = PBXGroup;
673709
children = (
@@ -1185,6 +1221,9 @@
11851221
D8022FE811E124A0003C21F6 /* PBGitXMessageSheet.xib in Resources */,
11861222
D8F01C4B12182F19007F729F /* GitX.sdef in Resources */,
11871223
D8F4AB7912298CE200D6D53C /* rewindImage.pdf in Resources */,
1224+
31460CD4124185BA00B90AED /* ReadMe.txt in Resources */,
1225+
31460CD5124185BA00B90AED /* Source Code License.rtf in Resources */,
1226+
31460CD6124185BA00B90AED /* TODO in Resources */,
11881227
);
11891228
runOnlyForDeploymentPostprocessing = 0;
11901229
};
@@ -1335,6 +1374,9 @@
13351374
D8B4DC571220D1E4004166D6 /* PBHistorySearchController.m in Sources */,
13361375
D8712A00122B14EC00012334 /* GitXTextFieldCell.m in Sources */,
13371376
310DC1D81240599E0017A0F7 /* GLFileView.m in Sources */,
1377+
31460CB2124185BA00B90AED /* AppController.m in Sources */,
1378+
31460CD2124185BA00B90AED /* MGRecessedPopUpButtonCell.m in Sources */,
1379+
31460CD3124185BA00B90AED /* MGScopeBar.m in Sources */,
13381380
);
13391381
runOnlyForDeploymentPostprocessing = 0;
13401382
};

0 commit comments

Comments
 (0)