Merge commit 'origin/master'
[GitX.git] / PBGitHistoryController.m
blobfb4d88633cdbae0c7aa93c1a85e5446616c3ddd6
1 //
2 //  PBGitHistoryView.m
3 //  GitX
4 //
5 //  Created by Pieter de Bie on 19-09-08.
6 //  Copyright 2008 __MyCompanyName__. All rights reserved.
7 //
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;
20 - (void)awakeFromNib
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];
35         }
36         else
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]];
44         [super awakeFromNib];
47 - (void) updateKeys
49         NSArray* selection = [commitController selectedObjects];
50         
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]];
55         
56         if ([selection count] > 0)
57                 realCommit = [selection objectAtIndex:0];
58         else
59                 realCommit = nil;
60         
61         self.webCommit = nil;
62         self.rawCommit = nil;
63         self.gitTree = nil;
64         
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;
69         }
70 }       
73 - (void) setSelectedTab: (int) number
75         selectedTab = number;
76         [[NSUserDefaults standardUserDefaults] setInteger:selectedTab forKey:@"Repository Window Selected Tab Index"];
77         [self updateKeys];
80 - (void) observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
82     if ([(NSString *)context isEqualToString: @"commitChange"]) {
83                 [self updateKeys];
84                 return;
85         }
86         else if ([(NSString *)context isEqualToString: @"treeChange"]) {
87                 [self updateQuicklookForce: NO];
88         }
89         else if([(NSString *)context isEqualToString:@"branchChange"]) {
90                 // Reset the sorting
91                 commitController.sortDescriptors = [NSArray array];
92         }
93         else {
94                 [super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
95         }
98 - (IBAction) openSelectedFile: sender
100         NSArray* selectedFiles = [treeController selectedObjects];
101         if ([selectedFiles count] == 0)
102                 return;
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];
122         else
123                 [super keyDown: event];
126 - (void) copyCommitInfo
128         PBGitCommit *commit = [[commitController selectedObjects] objectAtIndex:0];
129         if (!commit)
130                 return;
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];
136         
139 - (IBAction) toggleQuickView: sender
141         id panel = [QLPreviewPanel sharedPreviewPanel];
142         if ([panel isOpen]) {
143                 [panel closePanel];
144         } else {
145                 [[QLPreviewPanel sharedPreviewPanel] makeKeyAndOrderFrontWithEffect:1];
146                 [self updateQuicklookForce: YES];
147         }
150 - (void) updateQuicklookForce: (BOOL) force
152         if (!force && ![[QLPreviewPanel sharedPreviewPanel] isOpen])
153                 return;
154         
155         NSArray* selectedFiles = [treeController selectedObjects];
156         
157         if ([selectedFiles count] == 0)
158                 return;
159         
160         NSMutableArray* fileNames = [NSMutableArray array];
161         for (PBGitTree* tree in selectedFiles) {
162                 NSString* s = [tree tmpFileNameForContents];
163                 if (s)
164                         [fileNames addObject:[NSURL fileURLWithPath: s]];
165         }
166         
167         [[QLPreviewPanel sharedPreviewPanel] setURLs:fileNames currentIndex:0 preservingDisplayState:YES];
168         
171 - (IBAction) refresh: sender
173         [repository reloadRefs];
174         [repository.revisionList reload];
177 - (void) updateView
179         [self refresh:nil];
182 - (NSResponder *)firstResponder;
184         return commitList;
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;
201 - (void) removeView
203         [webView close];
204         [commitController removeObserver:self forKeyPath:@"selection"];
205         [treeController removeObserver:self forKeyPath:@"selection"];
206         [repository removeObserver:self forKeyPath:@"currentBranch"];
208         [super removeView];
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]];
218                 [item bind:@"value"
219                   toObject:column
220            withKeyPath:@"hidden"
221                    options:[NSDictionary dictionaryWithObject:@"NSNegateBoolean" forKey:NSValueTransformerNameBindingOption]];
222                 [menu addItem:item];
223         }
224         return menu;
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:@"/"];
244         NSString *path;
245         NSWorkspace *ws = [NSWorkspace sharedWorkspace];
247         for (NSString *filePath in [sender representedObject]) {
248                 path = [workingDirectory stringByAppendingPathComponent:filePath];
249                 [ws selectFile: path inFileViewerRootedAtPath:path];
250         }
254 - (void)openFilesAction:(id)sender
256         NSString *workingDirectory = [[repository workingDirectory] stringByAppendingString:@"/"];
257         NSString *path;
258         NSWorkspace *ws = [NSWorkspace sharedWorkspace];
260         for (NSString *filePath in [sender representedObject]) {
261                 path = [workingDirectory stringByAppendingPathComponent:filePath];
262                 [ws openFile:path];
263         }
267 - (NSMenu *)contextMenuForTreeView
269         NSArray *filePaths = [[treeController selectedObjects] valueForKey:@"fullPath"];
271         NSMenu *menu = [[NSMenu alloc] init];
272         for (NSMenuItem *item in [self menuItemsForPaths:filePaths])
273                 [menu addItem:item];
274         return menu;
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:)
282                                                                                                  keyEquivalent:@""];
283         NSMenuItem *finderItem = [[NSMenuItem alloc] initWithTitle:@"Show in Finder"
284                                                                                                                 action:@selector(showInFinderAction:)
285                                                                                                  keyEquivalent:@""];
286         NSMenuItem *openFilesItem = [[NSMenuItem alloc] initWithTitle:multiple? @"Open Files" : @"Open File"
287                                                                                                                    action:@selector(openFilesAction:)
288                                                                                                         keyEquivalent:@""];
290         NSArray *menuItems = [NSArray arrayWithObjects:historyItem, finderItem, openFilesItem, nil];
291         for (NSMenuItem *item in menuItems) {
292                 [item setTarget:self];
293                 [item setRepresentedObject:paths];
294         }
296         return menuItems;
299 @end