Testing: add missing file
[GitX.git] / PBGitHistoryController.m
bloba9fde362b408cb2f0a71a05f7095e2ce656a7947
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         [historySplitView setTopMin:33.0 andBottomMin:100.0];
45         [historySplitView uncollapse];
46         [super awakeFromNib];
49 - (void) updateKeys
51         NSArray* selection = [commitController selectedObjects];
52         
53         // Remove any references in the QLPanel
54         //[[QLPreviewPanel sharedPreviewPanel] setURLs:[NSArray array] currentIndex:0 preservingDisplayState:YES];
55         // We have to do this manually, as NSTreeController leaks memory?
56         //[treeController setSelectionIndexPaths:[NSArray array]];
57         
58         if ([selection count] > 0)
59                 realCommit = [selection objectAtIndex:0];
60         else
61                 realCommit = nil;
62         
63         self.webCommit = nil;
64         self.rawCommit = nil;
65         self.gitTree = nil;
66         
67         switch (self.selectedTab) {
68                 case 0: self.webCommit = realCommit;                    break;
69                 case 1: self.gitTree   = realCommit.tree;       break;
70         }
71 }       
74 - (void) setSelectedTab: (int) number
76         selectedTab = number;
77         [[NSUserDefaults standardUserDefaults] setInteger:selectedTab forKey:@"Repository Window Selected Tab Index"];
78         [self updateKeys];
81 - (void) observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
83     if ([(NSString *)context isEqualToString: @"commitChange"]) {
84                 [self updateKeys];
85                 return;
86         }
87         else if ([(NSString *)context isEqualToString: @"treeChange"]) {
88                 [self updateQuicklookForce: NO];
89         }
90         else if([(NSString *)context isEqualToString:@"branchChange"]) {
91                 // Reset the sorting
92                 commitController.sortDescriptors = [NSArray array];
93         }
94         else {
95                 [super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
96         }
99 - (IBAction) openSelectedFile: sender
101         NSArray* selectedFiles = [treeController selectedObjects];
102         if ([selectedFiles count] == 0)
103                 return;
104         PBGitTree* tree = [selectedFiles objectAtIndex:0];
105         NSString* name = [tree tmpFileNameForContents];
106         [[NSWorkspace sharedWorkspace] openTempFile:name];
109 - (IBAction) setDetailedView: sender {
110         self.selectedTab = 0;
112 - (IBAction) setRawView: sender {
113         self.selectedTab = 1;
115 - (IBAction) setTreeView: sender {
116         self.selectedTab = 2;
119 - (void)keyDown:(NSEvent*)event
121         if ([[event charactersIgnoringModifiers] isEqualToString: @"f"] && [event modifierFlags] & NSAlternateKeyMask && [event modifierFlags] & NSCommandKeyMask)
122                 [superController.window makeFirstResponder: searchField];
123         else
124                 [super keyDown: event];
127 - (void) copyCommitInfo
129         PBGitCommit *commit = [[commitController selectedObjects] objectAtIndex:0];
130         if (!commit)
131                 return;
132         NSString *info = [NSString stringWithFormat:@"%@ (%@)", [[commit realSha] substringToIndex:10], [commit subject]];
134         NSPasteboard *a =[NSPasteboard generalPasteboard];
135         [a declareTypes:[NSArray arrayWithObject:NSStringPboardType] owner:self];
136         [a setString:info forType: NSStringPboardType];
137         
140 - (IBAction) toggleQuickView: sender
142         id panel = [QLPreviewPanel sharedPreviewPanel];
143         if ([panel isOpen]) {
144                 [panel closePanel];
145         } else {
146                 [[QLPreviewPanel sharedPreviewPanel] makeKeyAndOrderFrontWithEffect:1];
147                 [self updateQuicklookForce: YES];
148         }
151 - (void) updateQuicklookForce: (BOOL) force
153         if (!force && ![[QLPreviewPanel sharedPreviewPanel] isOpen])
154                 return;
155         
156         NSArray* selectedFiles = [treeController selectedObjects];
157         
158         if ([selectedFiles count] == 0)
159                 return;
160         
161         NSMutableArray* fileNames = [NSMutableArray array];
162         for (PBGitTree* tree in selectedFiles) {
163                 NSString* s = [tree tmpFileNameForContents];
164                 if (s)
165                         [fileNames addObject:[NSURL fileURLWithPath: s]];
166         }
167         
168         [[QLPreviewPanel sharedPreviewPanel] setURLs:fileNames currentIndex:0 preservingDisplayState:YES];
169         
172 - (IBAction) refresh: sender
174         [repository reloadRefs];
175         [repository.revisionList reload];
178 - (void) updateView
180         [self refresh:nil];
183 - (NSResponder *)firstResponder;
185         return commitList;
188 - (void) selectCommit: (NSString*) commit
190         NSPredicate* selection = [NSPredicate predicateWithFormat:@"realSha == %@", commit];
191         NSArray* selectedCommits = [repository.revisionList.commits filteredArrayUsingPredicate:selection];
192         [commitController setSelectedObjects: selectedCommits];
193         int index = [[commitController selectionIndexes] firstIndex];
194         [commitList scrollRowToVisible: index];
197 - (BOOL) hasNonlinearPath
199         return [commitController filterPredicate] || [[commitController sortDescriptors] count] > 0;
202 - (void) removeView
204         [webView close];
205         [commitController removeObserver:self forKeyPath:@"selection"];
206         [treeController removeObserver:self forKeyPath:@"selection"];
207         [repository removeObserver:self forKeyPath:@"currentBranch"];
209         [super removeView];
212 #pragma mark Table Column Methods
213 - (NSMenu *)tableColumnMenu
215         NSMenu *menu = [[NSMenu alloc] initWithTitle:@"Table columns menu"];
216         for (NSTableColumn *column in [commitList tableColumns]) {
217                 NSMenuItem *item = [[NSMenuItem alloc] init];
218                 [item setTitle:[[column headerCell] stringValue]];
219                 [item bind:@"value"
220                   toObject:column
221            withKeyPath:@"hidden"
222                    options:[NSDictionary dictionaryWithObject:@"NSNegateBoolean" forKey:NSValueTransformerNameBindingOption]];
223                 [menu addItem:item];
224         }
225         return menu;
228 #pragma mark Tree Context Menu Methods
230 - (void)showCommitsFromTree:(id)sender
232         // TODO: Enable this from webview as well!
234         NSMutableArray *filePaths = [NSMutableArray arrayWithObjects:@"HEAD", @"--", NULL];
235         [filePaths addObjectsFromArray:[sender representedObject]];
237         PBGitRevSpecifier *revSpec = [[PBGitRevSpecifier alloc] initWithParameters:filePaths];
239         repository.currentBranch = [repository addBranch:revSpec];
242 - (void)showInFinderAction:(id)sender
244         NSString *workingDirectory = [[repository workingDirectory] stringByAppendingString:@"/"];
245         NSString *path;
246         NSWorkspace *ws = [NSWorkspace sharedWorkspace];
248         for (NSString *filePath in [sender representedObject]) {
249                 path = [workingDirectory stringByAppendingPathComponent:filePath];
250                 [ws selectFile: path inFileViewerRootedAtPath:path];
251         }
255 - (void)openFilesAction:(id)sender
257         NSString *workingDirectory = [[repository workingDirectory] stringByAppendingString:@"/"];
258         NSString *path;
259         NSWorkspace *ws = [NSWorkspace sharedWorkspace];
261         for (NSString *filePath in [sender representedObject]) {
262                 path = [workingDirectory stringByAppendingPathComponent:filePath];
263                 [ws openFile:path];
264         }
268 - (NSMenu *)contextMenuForTreeView
270         NSArray *filePaths = [[treeController selectedObjects] valueForKey:@"fullPath"];
272         NSMenu *menu = [[NSMenu alloc] init];
273         for (NSMenuItem *item in [self menuItemsForPaths:filePaths])
274                 [menu addItem:item];
275         return menu;
278 - (NSArray *)menuItemsForPaths:(NSArray *)paths
280         BOOL multiple = [paths count] != 1;
281         NSMenuItem *historyItem = [[NSMenuItem alloc] initWithTitle:multiple? @"Show history of files" : @"Show history of file"
282                                                                                                                  action:@selector(showCommitsFromTree:)
283                                                                                                  keyEquivalent:@""];
284         NSMenuItem *finderItem = [[NSMenuItem alloc] initWithTitle:@"Show in Finder"
285                                                                                                                 action:@selector(showInFinderAction:)
286                                                                                                  keyEquivalent:@""];
287         NSMenuItem *openFilesItem = [[NSMenuItem alloc] initWithTitle:multiple? @"Open Files" : @"Open File"
288                                                                                                                    action:@selector(openFilesAction:)
289                                                                                                         keyEquivalent:@""];
291         NSArray *menuItems = [NSArray arrayWithObjects:historyItem, finderItem, openFilesItem, nil];
292         for (NSMenuItem *item in menuItems) {
293                 [item setTarget:self];
294                 [item setRepresentedObject:paths];
295         }
297         return menuItems;
300 - (BOOL)splitView:(NSSplitView *)sender canCollapseSubview:(NSView *)subview {
301         return TRUE;
304 - (BOOL)splitView:(NSSplitView *)splitView shouldCollapseSubview:(NSView *)subview forDoubleClickOnDividerAtIndex:(NSInteger)dividerIndex {
305         int index = [[splitView subviews] indexOfObject:subview];
306         // this method (and canCollapse) are called by the splitView to decide how to collapse on double-click
307         // we compare our two subviews, so that always the smaller one is collapsed.
308         if([[[splitView subviews] objectAtIndex:index] frame].size.height < [[[splitView subviews] objectAtIndex:((index+1)%2)] frame].size.height) {
309                 return TRUE;
310         }
311         return FALSE;
314 - (CGFloat)splitView:(NSSplitView *)sender constrainMinCoordinate:(CGFloat)proposedMin ofSubviewAt:(NSInteger)offset {
315         return proposedMin + historySplitView.topViewMin;
318 - (CGFloat)splitView:(NSSplitView *)sender constrainMaxCoordinate:(CGFloat)proposedMax ofSubviewAt:(NSInteger)offset {
319         if(offset == 1)
320                 return proposedMax - historySplitView.bottomViewMin;
321         return [sender frame].size.height;
324 @end