5 // Created by Pieter de Bie on 19-09-08.
6 // Copyright 2008 __MyCompanyName__. All rights reserved.
9 #import "PBGitHistoryController.h"
10 #import "CWQuickLook.h"
11 #import "PBGitGrapher.h"
12 #import "PBGitRevisionCell.h"
13 #import "PBCommitList.h"
14 #define QLPreviewPanel NSClassFromString(@"QLPreviewPanel")
17 @implementation PBGitHistoryController
18 @synthesize selectedTab, webCommit, rawCommit, gitTree, commitController;
22 self.selectedTab = [[NSUserDefaults standardUserDefaults] integerForKey:@"Repository Window Selected Tab Index"];;
23 [commitController addObserver:self forKeyPath:@"selection" options:(NSKeyValueObservingOptionNew,NSKeyValueObservingOptionOld) context:@"commitChange"];
24 [treeController addObserver:self forKeyPath:@"selection" options:0 context:@"treeChange"];
25 [repository addObserver:self forKeyPath:@"currentBranch" options:0 context:@"branchChange"];
26 NSSize cellSpacing = [commitList intercellSpacing];
27 cellSpacing.height = 0;
28 [commitList setIntercellSpacing:cellSpacing];
29 [fileBrowser setTarget:self];
30 [fileBrowser setDoubleAction:@selector(openSelectedFile:)];
32 if (!repository.currentBranch) {
33 [repository reloadRefs];
34 [repository readCurrentBranch];
37 [repository lazyReload];
39 // Set a sort descriptor for the subject column in the history list, as
40 // It can't be sorted by default (because it's bound to a PBGitCommit)
41 [[commitList tableColumnWithIdentifier:@"subject"] setSortDescriptorPrototype:[[NSSortDescriptor alloc] initWithKey:@"subject" ascending:YES]];
42 // Add a menu that allows a user to select which columns to view
43 [[commitList headerView] setMenu:[self tableColumnMenu]];
49 NSArray* selection = [commitController selectedObjects];
51 // Remove any references in the QLPanel
52 //[[QLPreviewPanel sharedPreviewPanel] setURLs:[NSArray array] currentIndex:0 preservingDisplayState:YES];
53 // We have to do this manually, as NSTreeController leaks memory?
54 //[treeController setSelectionIndexPaths:[NSArray array]];
56 if ([selection count] > 0)
57 realCommit = [selection objectAtIndex:0];
65 switch (self.selectedTab) {
66 case 0: self.webCommit = realCommit; break;
67 case 1: self.rawCommit = realCommit; break;
68 case 2: self.gitTree = realCommit.tree; break;
73 - (void) setSelectedTab: (int) number
76 [[NSUserDefaults standardUserDefaults] setInteger:selectedTab forKey:@"Repository Window Selected Tab Index"];
80 - (void) observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
82 if ([(NSString *)context isEqualToString: @"commitChange"]) {
86 else if ([(NSString *)context isEqualToString: @"treeChange"]) {
87 [self updateQuicklookForce: NO];
89 else if([(NSString *)context isEqualToString:@"branchChange"]) {
91 commitController.sortDescriptors = [NSArray array];
94 [super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
98 - (IBAction) openSelectedFile: sender
100 NSArray* selectedFiles = [treeController selectedObjects];
101 if ([selectedFiles count] == 0)
103 PBGitTree* tree = [selectedFiles objectAtIndex:0];
104 NSString* name = [tree tmpFileNameForContents];
105 [[NSWorkspace sharedWorkspace] openTempFile:name];
108 - (IBAction) setDetailedView: sender {
109 self.selectedTab = 0;
111 - (IBAction) setRawView: sender {
112 self.selectedTab = 1;
114 - (IBAction) setTreeView: sender {
115 self.selectedTab = 2;
118 - (void)keyDown:(NSEvent*)event
120 if ([[event charactersIgnoringModifiers] isEqualToString: @"f"] && [event modifierFlags] & NSAlternateKeyMask && [event modifierFlags] & NSCommandKeyMask)
121 [superController.window makeFirstResponder: searchField];
123 [super keyDown: event];
126 - (void) copyCommitInfo
128 PBGitCommit *commit = [[commitController selectedObjects] objectAtIndex:0];
131 NSString *info = [NSString stringWithFormat:@"%@ (%@)", [[commit realSha] substringToIndex:10], [commit subject]];
133 NSPasteboard *a =[NSPasteboard generalPasteboard];
134 [a declareTypes:[NSArray arrayWithObject:NSStringPboardType] owner:self];
135 [a setString:info forType: NSStringPboardType];
139 - (IBAction) toggleQuickView: sender
141 id panel = [QLPreviewPanel sharedPreviewPanel];
142 if ([panel isOpen]) {
145 [[QLPreviewPanel sharedPreviewPanel] makeKeyAndOrderFrontWithEffect:1];
146 [self updateQuicklookForce: YES];
150 - (void) updateQuicklookForce: (BOOL) force
152 if (!force && ![[QLPreviewPanel sharedPreviewPanel] isOpen])
155 NSArray* selectedFiles = [treeController selectedObjects];
157 if ([selectedFiles count] == 0)
160 NSMutableArray* fileNames = [NSMutableArray array];
161 for (PBGitTree* tree in selectedFiles) {
162 NSString* s = [tree tmpFileNameForContents];
164 [fileNames addObject:[NSURL fileURLWithPath: s]];
167 [[QLPreviewPanel sharedPreviewPanel] setURLs:fileNames currentIndex:0 preservingDisplayState:YES];
171 - (IBAction) refresh: sender
173 [repository reloadRefs];
174 [repository.revisionList reload];
182 - (NSResponder *)firstResponder;
187 - (void) selectCommit: (NSString*) commit
189 NSPredicate* selection = [NSPredicate predicateWithFormat:@"realSha == %@", commit];
190 NSArray* selectedCommits = [repository.revisionList.commits filteredArrayUsingPredicate:selection];
191 [commitController setSelectedObjects: selectedCommits];
192 int index = [[commitController selectionIndexes] firstIndex];
193 [commitList scrollRowToVisible: index];
196 - (BOOL) hasNonlinearPath
198 return [commitController filterPredicate] || [[commitController sortDescriptors] count] > 0;
204 [commitController removeObserver:self forKeyPath:@"selection"];
205 [treeController removeObserver:self forKeyPath:@"selection"];
206 [repository removeObserver:self forKeyPath:@"currentBranch"];
211 #pragma mark Table Column Methods
212 - (NSMenu *)tableColumnMenu
214 NSMenu *menu = [[NSMenu alloc] initWithTitle:@"Table columns menu"];
215 for (NSTableColumn *column in [commitList tableColumns]) {
216 NSMenuItem *item = [[NSMenuItem alloc] init];
217 [item setTitle:[[column headerCell] stringValue]];
220 withKeyPath:@"hidden"
221 options:[NSDictionary dictionaryWithObject:@"NSNegateBoolean" forKey:NSValueTransformerNameBindingOption]];
227 #pragma mark Tree Context Menu Methods
229 - (void)showCommitsFromTree:(id)sender
231 // TODO: Enable this from webview as well!
233 NSMutableArray *filePaths = [NSMutableArray arrayWithObjects:@"HEAD", @"--", NULL];
234 [filePaths addObjectsFromArray:[sender representedObject]];
236 PBGitRevSpecifier *revSpec = [[PBGitRevSpecifier alloc] initWithParameters:filePaths];
238 repository.currentBranch = [repository addBranch:revSpec];
241 - (void)showInFinderAction:(id)sender
243 NSString *workingDirectory = [[repository workingDirectory] stringByAppendingString:@"/"];
245 NSWorkspace *ws = [NSWorkspace sharedWorkspace];
247 for (NSString *filePath in [sender representedObject]) {
248 path = [workingDirectory stringByAppendingPathComponent:filePath];
249 [ws selectFile: path inFileViewerRootedAtPath:path];
254 - (void)openFilesAction:(id)sender
256 NSString *workingDirectory = [[repository workingDirectory] stringByAppendingString:@"/"];
258 NSWorkspace *ws = [NSWorkspace sharedWorkspace];
260 for (NSString *filePath in [sender representedObject]) {
261 path = [workingDirectory stringByAppendingPathComponent:filePath];
267 - (NSMenu *)contextMenuForTreeView
269 NSArray *filePaths = [[treeController selectedObjects] valueForKey:@"fullPath"];
271 NSMenu *menu = [[NSMenu alloc] init];
272 for (NSMenuItem *item in [self menuItemsForPaths:filePaths])
277 - (NSArray *)menuItemsForPaths:(NSArray *)paths
279 BOOL multiple = [paths count] != 1;
280 NSMenuItem *historyItem = [[NSMenuItem alloc] initWithTitle:multiple? @"Show history of files" : @"Show history of file"
281 action:@selector(showCommitsFromTree:)
283 NSMenuItem *finderItem = [[NSMenuItem alloc] initWithTitle:@"Show in Finder"
284 action:@selector(showInFinderAction:)
286 NSMenuItem *openFilesItem = [[NSMenuItem alloc] initWithTitle:multiple? @"Open Files" : @"Open File"
287 action:@selector(openFilesAction:)
290 NSArray *menuItems = [NSArray arrayWithObjects:historyItem, finderItem, openFilesItem, nil];
291 for (NSMenuItem *item in menuItems) {
292 [item setTarget:self];
293 [item setRepresentedObject:paths];