diff --git a/GitX.xcodeproj/project.pbxproj b/GitX.xcodeproj/project.pbxproj index 907f618..46c6917 100644 --- a/GitX.xcodeproj/project.pbxproj +++ b/GitX.xcodeproj/project.pbxproj @@ -65,6 +65,8 @@ F513085B0E0740F2000C8BCD /* PBQLOutlineView.m in Sources */ = {isa = PBXBuildFile; fileRef = F513085A0E0740F2000C8BCD /* PBQLOutlineView.m */; }; F5140DC90E8A8EB20091E9F3 /* RoundedRectangle.m in Sources */ = {isa = PBXBuildFile; fileRef = F5140DC80E8A8EB20091E9F3 /* RoundedRectangle.m */; }; F523CEB60ED3399200DDD714 /* PBGitIndexController.m in Sources */ = {isa = PBXBuildFile; fileRef = F523CEB50ED3399200DDD714 /* PBGitIndexController.m */; }; + F528210A1056A7C1001D1511 /* PBSourceViewRemote.m in Sources */ = {isa = PBXBuildFile; fileRef = F52821091056A7C1001D1511 /* PBSourceViewRemote.m */; }; + F528210D1056A7EB001D1511 /* PBSourceViewAction.m in Sources */ = {isa = PBXBuildFile; fileRef = F528210C1056A7EB001D1511 /* PBSourceViewAction.m */; }; F52BCE030E84208300AA3741 /* PBGitHistoryView.xib in Resources */ = {isa = PBXBuildFile; fileRef = F52BCE020E84208300AA3741 /* PBGitHistoryView.xib */; }; F52BCE070E84211300AA3741 /* PBGitHistoryController.m in Sources */ = {isa = PBXBuildFile; fileRef = F52BCE060E84211300AA3741 /* PBGitHistoryController.m */; }; F53C4DF70E97FC630022AD59 /* PBGitBinary.m in Sources */ = {isa = PBXBuildFile; fileRef = F53C4DF60E97FC630022AD59 /* PBGitBinary.m */; }; @@ -78,6 +80,7 @@ F56524F00E02D45200F03B52 /* PBGitCommit.m in Sources */ = {isa = PBXBuildFile; fileRef = F56524EF0E02D45200F03B52 /* PBGitCommit.m */; }; F56526240E03D85900F03B52 /* WebKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F56526230E03D85900F03B52 /* WebKit.framework */; }; F565262B0E03D89B00F03B52 /* PBWebHistoryController.m in Sources */ = {isa = PBXBuildFile; fileRef = F565262A0E03D89B00F03B52 /* PBWebHistoryController.m */; }; + F567B88D1057FA9F000DB976 /* NSOutlineViewExt.m in Sources */ = {isa = PBXBuildFile; fileRef = F567B88C1057FA9F000DB976 /* NSOutlineViewExt.m */; }; F567CC64106E6BC80059BB9D /* PBGitRepository.m in Sources */ = {isa = PBXBuildFile; fileRef = F5945E160E02B0C200706420 /* PBGitRepository.m */; }; F567CC65106E6BC90059BB9D /* PBGitBinary.m in Sources */ = {isa = PBXBuildFile; fileRef = F53C4DF60E97FC630022AD59 /* PBGitBinary.m */; }; F567CC66106E6BC90059BB9D /* PBGitConfig.m in Sources */ = {isa = PBXBuildFile; fileRef = 93FCCBA80EA8AF450061B02B /* PBGitConfig.m */; }; @@ -115,6 +118,13 @@ F5886A330ED5D5580066E74C /* PBGitRevSpecifier.m in Sources */ = {isa = PBXBuildFile; fileRef = F53FF2040E7ABB5300389171 /* PBGitRevSpecifier.m */; }; F5886A340ED5D55D0066E74C /* PBGitBinary.m in Sources */ = {isa = PBXBuildFile; fileRef = F53C4DF60E97FC630022AD59 /* PBGitBinary.m */; }; F5886A360ED5D56E0066E74C /* PBGitTree.m in Sources */ = {isa = PBXBuildFile; fileRef = F56174560E058893001DCD79 /* PBGitTree.m */; }; + F58DB55910566D3500CFDF4A /* PBGitSidebarController.m in Sources */ = {isa = PBXBuildFile; fileRef = F58DB55810566D3500CFDF4A /* PBGitSidebarController.m */; }; + F58DB56010566E3900CFDF4A /* PBGitSidebarView.xib in Resources */ = {isa = PBXBuildFile; fileRef = F58DB55F10566E3900CFDF4A /* PBGitSidebarView.xib */; }; + F58DB5E8105671B600CFDF4A /* PBSourceViewItem.m in Sources */ = {isa = PBXBuildFile; fileRef = F58DB5E7105671B600CFDF4A /* PBSourceViewItem.m */; }; + F58DB7711056860900CFDF4A /* branch.tiff in Resources */ = {isa = PBXBuildFile; fileRef = F58DB76D1056860900CFDF4A /* branch.tiff */; }; + F58DB7721056860900CFDF4A /* remote.tiff in Resources */ = {isa = PBXBuildFile; fileRef = F58DB76E1056860900CFDF4A /* remote.tiff */; }; + F58DB7731056860900CFDF4A /* folder.tiff in Resources */ = {isa = PBXBuildFile; fileRef = F58DB76F1056860900CFDF4A /* folder.tiff */; }; + F58DB7741056860900CFDF4A /* tag.tiff in Resources */ = {isa = PBXBuildFile; fileRef = F58DB7701056860900CFDF4A /* tag.tiff */; }; F59116E60E843BB50072CCB1 /* PBGitCommitView.xib in Resources */ = {isa = PBXBuildFile; fileRef = F59116E50E843BB50072CCB1 /* PBGitCommitView.xib */; }; F59116E90E843BCB0072CCB1 /* PBGitCommitController.m in Sources */ = {isa = PBXBuildFile; fileRef = F59116E80E843BCB0072CCB1 /* PBGitCommitController.m */; }; F593DF780E9E636C003A8559 /* PBFileChangesTableView.m in Sources */ = {isa = PBXBuildFile; fileRef = F593DF770E9E636C003A8559 /* PBFileChangesTableView.m */; }; @@ -256,6 +266,10 @@ F5140DC80E8A8EB20091E9F3 /* RoundedRectangle.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RoundedRectangle.m; sourceTree = ""; }; F523CEB40ED3399100DDD714 /* PBGitIndexController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PBGitIndexController.h; sourceTree = ""; }; F523CEB50ED3399200DDD714 /* PBGitIndexController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PBGitIndexController.m; sourceTree = ""; }; + F52821081056A7C1001D1511 /* PBSourceViewRemote.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PBSourceViewRemote.h; sourceTree = ""; }; + F52821091056A7C1001D1511 /* PBSourceViewRemote.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PBSourceViewRemote.m; sourceTree = ""; }; + F528210B1056A7EB001D1511 /* PBSourceViewAction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PBSourceViewAction.h; sourceTree = ""; }; + F528210C1056A7EB001D1511 /* PBSourceViewAction.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PBSourceViewAction.m; sourceTree = ""; }; F52BCE020E84208300AA3741 /* PBGitHistoryView.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = PBGitHistoryView.xib; sourceTree = ""; }; F52BCE050E84211300AA3741 /* PBGitHistoryController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PBGitHistoryController.h; sourceTree = ""; }; F52BCE060E84211300AA3741 /* PBGitHistoryController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PBGitHistoryController.m; sourceTree = ""; }; @@ -277,6 +291,8 @@ F56526230E03D85900F03B52 /* WebKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = WebKit.framework; path = /System/Library/Frameworks/WebKit.framework; sourceTree = ""; }; F56526290E03D89B00F03B52 /* PBWebHistoryController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PBWebHistoryController.h; sourceTree = ""; }; F565262A0E03D89B00F03B52 /* PBWebHistoryController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PBWebHistoryController.m; sourceTree = ""; }; + F567B88B1057FA9F000DB976 /* NSOutlineViewExt.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NSOutlineViewExt.h; sourceTree = ""; }; + F567B88C1057FA9F000DB976 /* NSOutlineViewExt.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = NSOutlineViewExt.m; sourceTree = ""; }; F567CC39106E6B910059BB9D /* GitXTesting.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = GitXTesting.framework; sourceTree = BUILT_PRODUCTS_DIR; }; F567CC3A106E6B910059BB9D /* GitXTesting-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "GitXTesting-Info.plist"; sourceTree = ""; }; F569AE920F2CBD7C00C2FFA7 /* Credits.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = Credits.html; sourceTree = ""; }; @@ -296,6 +312,15 @@ F5886A0A0ED5D27A0066E74C /* speedtest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = speedtest.m; sourceTree = ""; }; F5886A100ED5D33D0066E74C /* SpeedTest.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = SpeedTest.app; sourceTree = BUILT_PRODUCTS_DIR; }; F5886A120ED5D33D0066E74C /* SpeedTest-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "SpeedTest-Info.plist"; sourceTree = ""; }; + F58DB55710566D3500CFDF4A /* PBGitSidebarController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PBGitSidebarController.h; sourceTree = ""; }; + F58DB55810566D3500CFDF4A /* PBGitSidebarController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PBGitSidebarController.m; sourceTree = ""; }; + F58DB55F10566E3900CFDF4A /* PBGitSidebarView.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = PBGitSidebarView.xib; sourceTree = ""; }; + F58DB5E6105671B600CFDF4A /* PBSourceViewItem.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PBSourceViewItem.h; sourceTree = ""; }; + F58DB5E7105671B600CFDF4A /* PBSourceViewItem.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PBSourceViewItem.m; sourceTree = ""; }; + F58DB76D1056860900CFDF4A /* branch.tiff */ = {isa = PBXFileReference; lastKnownFileType = image.tiff; name = branch.tiff; path = Images/branch.tiff; sourceTree = ""; }; + F58DB76E1056860900CFDF4A /* remote.tiff */ = {isa = PBXFileReference; lastKnownFileType = image.tiff; name = remote.tiff; path = Images/remote.tiff; sourceTree = ""; }; + F58DB76F1056860900CFDF4A /* folder.tiff */ = {isa = PBXFileReference; lastKnownFileType = image.tiff; name = folder.tiff; path = Images/folder.tiff; sourceTree = ""; }; + F58DB7701056860900CFDF4A /* tag.tiff */ = {isa = PBXFileReference; lastKnownFileType = image.tiff; name = tag.tiff; path = Images/tag.tiff; sourceTree = ""; }; F59116E50E843BB50072CCB1 /* PBGitCommitView.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = PBGitCommitView.xib; sourceTree = ""; }; F59116E70E843BCB0072CCB1 /* PBGitCommitController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PBGitCommitController.h; sourceTree = ""; }; F59116E80E843BCB0072CCB1 /* PBGitCommitController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PBGitCommitController.m; sourceTree = ""; }; @@ -453,6 +478,10 @@ 29B97315FDCFA39411CA2CEA /* Other Sources */ = { isa = PBXGroup; children = ( + F58DB76D1056860900CFDF4A /* branch.tiff */, + F58DB76E1056860900CFDF4A /* remote.tiff */, + F58DB76F1056860900CFDF4A /* folder.tiff */, + F58DB7701056860900CFDF4A /* tag.tiff */, 3BC07F4A0ED5A5C5009A7768 /* HistoryViewTemplate.png */, 3BC07F4B0ED5A5C5009A7768 /* CommitViewTemplate.png */, F56ADDD70ED19F9E002AC78F /* AddBranchTemplate.png */, @@ -488,6 +517,7 @@ D8FDD9F511432A12005647F6 /* PBCloneRepositoryPanel.xib */, 47DBDB680E94EF6500671A1E /* Preferences.xib */, F569AE920F2CBD7C00C2FFA7 /* Credits.html */, + F58DB55F10566E3900CFDF4A /* PBGitSidebarView.xib */, ); name = Resources; sourceTree = ""; @@ -575,6 +605,7 @@ F57CC3850E05DDC1000472E2 /* Controllers */ = { isa = PBXGroup; children = ( + F58DB55610566D1F00CFDF4A /* Sidebar */, F5B161BB0EAB6E0C005A1DE1 /* Diff */, F5EF8C880E9D498F0050906B /* History */, F5E927F90E883EF600056E75 /* Commit */, @@ -632,6 +663,8 @@ F5FC41F20EBCBD4300191D80 /* PBGitXProtocol.h */, F5FC41F30EBCBD4300191D80 /* PBGitXProtocol.m */, D823487410CB382C00944BDE /* Terminal.h */, + F567B88B1057FA9F000DB976 /* NSOutlineViewExt.h */, + F567B88C1057FA9F000DB976 /* NSOutlineViewExt.m */, ); name = Aux; sourceTree = ""; @@ -644,6 +677,21 @@ name = SpeedTest; sourceTree = ""; }; + F58DB55610566D1F00CFDF4A /* Sidebar */ = { + isa = PBXGroup; + children = ( + F58DB55710566D3500CFDF4A /* PBGitSidebarController.h */, + F58DB55810566D3500CFDF4A /* PBGitSidebarController.m */, + F58DB5E6105671B600CFDF4A /* PBSourceViewItem.h */, + F58DB5E7105671B600CFDF4A /* PBSourceViewItem.m */, + F52821081056A7C1001D1511 /* PBSourceViewRemote.h */, + F52821091056A7C1001D1511 /* PBSourceViewRemote.m */, + F528210B1056A7EB001D1511 /* PBSourceViewAction.h */, + F528210C1056A7EB001D1511 /* PBSourceViewAction.m */, + ); + name = Sidebar; + sourceTree = ""; + }; F59F1DD2105C4FDE00115F88 /* Index */ = { isa = PBXGroup; children = ( @@ -889,6 +937,11 @@ D8083C47111F136400337480 /* PBAddRemoteSheet.xib in Resources */, D8083DCD111F918900337480 /* PBCloneRepsitoryToSheet.xib in Resources */, D8FDD9F711432A12005647F6 /* PBCloneRepositoryPanel.xib in Resources */, + F58DB56010566E3900CFDF4A /* PBGitSidebarView.xib in Resources */, + F58DB7711056860900CFDF4A /* branch.tiff in Resources */, + F58DB7721056860900CFDF4A /* remote.tiff in Resources */, + F58DB7731056860900CFDF4A /* folder.tiff in Resources */, + F58DB7741056860900CFDF4A /* tag.tiff in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -1014,6 +1067,11 @@ D8083C44111F106800337480 /* PBAddRemoteSheet.m in Sources */, D8083DC4111F90F300337480 /* PBCloneRepsitoryToSheet.m in Sources */, D8083E03111FA33700337480 /* PBCloneRepositoryPanel.m in Sources */, + F58DB55910566D3500CFDF4A /* PBGitSidebarController.m in Sources */, + F58DB5E8105671B600CFDF4A /* PBSourceViewItem.m in Sources */, + F567B88D1057FA9F000DB976 /* NSOutlineViewExt.m in Sources */, + F528210A1056A7C1001D1511 /* PBSourceViewRemote.m in Sources */, + F528210D1056A7EB001D1511 /* PBSourceViewAction.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/Images/branch.tiff b/Images/branch.tiff new file mode 100644 index 0000000..dc35b5b Binary files /dev/null and b/Images/branch.tiff differ diff --git a/Images/folder.tiff b/Images/folder.tiff new file mode 100644 index 0000000..c6a7b14 Binary files /dev/null and b/Images/folder.tiff differ diff --git a/Images/remote.tiff b/Images/remote.tiff new file mode 100644 index 0000000..24f81d4 Binary files /dev/null and b/Images/remote.tiff differ diff --git a/Images/tag.tiff b/Images/tag.tiff new file mode 100644 index 0000000..0532a45 Binary files /dev/null and b/Images/tag.tiff differ diff --git a/NSOutlineViewExt.h b/NSOutlineViewExt.h new file mode 100644 index 0000000..64c0186 --- /dev/null +++ b/NSOutlineViewExt.h @@ -0,0 +1,15 @@ +// +// NSOutlineViewExit.h +// GitX +// +// Created by Pieter de Bie on 9/9/09. +// Copyright 2009 __MyCompanyName__. All rights reserved. +// + +#import + + +@interface NSOutlineView (PBExpandParents) + +- (void)PBExpandItem:(id)item expandParents:(BOOL)expand; +@end diff --git a/NSOutlineViewExt.m b/NSOutlineViewExt.m new file mode 100644 index 0000000..57531f8 --- /dev/null +++ b/NSOutlineViewExt.m @@ -0,0 +1,25 @@ +// +// NSOutlineViewExit.m +// GitX +// +// Created by Pieter de Bie on 9/9/09. +// Copyright 2009 __MyCompanyName__. All rights reserved. +// + +#import "NSOutlineViewExt.h" + + +@implementation NSOutlineView (PBExpandParents) + +- (void)PBExpandItem:(id)item expandParents:(BOOL)expand +{ + NSMutableArray *parents = [NSMutableArray array]; + while (item) { + [parents insertObject:item atIndex:0]; + item = [item parent]; + } + + for (id p in parents) + [self expandItem:p]; +} +@end diff --git a/PBGitHistoryController.h b/PBGitHistoryController.h index bd0635e..20893f6 100644 --- a/PBGitHistoryController.h +++ b/PBGitHistoryController.h @@ -12,7 +12,10 @@ #import "PBViewController.h" #import "PBCollapsibleSplitView.h" +@class PBGitSidebarController; + @interface PBGitHistoryController : PBViewController { + PBGitSidebarController *sidebarController; IBOutlet NSSearchField *searchField; IBOutlet NSArrayController* commitController; IBOutlet NSTreeController* treeController; diff --git a/PBGitHistoryController.m b/PBGitHistoryController.m index d28c9b2..cc676fa 100644 --- a/PBGitHistoryController.m +++ b/PBGitHistoryController.m @@ -14,6 +14,7 @@ #import "PBCreateBranchSheet.h" #import "PBCreateTagSheet.h" #import "PBAddRemoteSheet.h" +#import "PBGitSidebarController.h" #define QLPreviewPanel NSClassFromString(@"QLPreviewPanel") @@ -32,6 +33,19 @@ [fileBrowser setTarget:self]; [fileBrowser setDoubleAction:@selector(openSelectedFile:)]; + [historySplitView removeFromSuperview]; + NSSplitView *newView = [[NSSplitView alloc] initWithFrame:[historySplitView frame]]; + + sidebarController = [[PBGitSidebarController alloc] initWithRepository:repository superController:superController]; + [newView setDividerStyle:NSSplitViewDividerStyleThin]; + [newView addSubview:[sidebarController view]]; + [newView addSubview:historySplitView]; + [newView setVertical:YES]; + [newView adjustSubviews]; + [newView setAutoresizingMask: NSViewWidthSizable | NSViewHeightSizable]; + + [[self view] addSubview:newView]; + if (!repository.currentBranch) { [repository reloadRefs]; [repository readCurrentBranch]; diff --git a/PBGitRevSpecifier.m b/PBGitRevSpecifier.m index 529275d..398a175 100644 --- a/PBGitRevSpecifier.m +++ b/PBGitRevSpecifier.m @@ -47,9 +47,19 @@ [revspec setDescription:@"Local branches"]; return revspec; } + - (BOOL) isSimpleRef { - return ([parameters count] == 1 && ![[parameters objectAtIndex:0] hasPrefix:@"-"]); + if ([parameters count] > 1) + return NO; + + NSString *param = [parameters objectAtIndex:0]; + if ([param hasPrefix:@"-"] || + [param rangeOfCharacterFromSet:[NSCharacterSet characterSetWithCharactersInString:@"^@{}~:"]].location != NSNotFound || + [param rangeOfString:@".."].location != NSNotFound) + return NO; + + return YES; } - (NSString*) simpleRef diff --git a/PBGitSidebarController.h b/PBGitSidebarController.h new file mode 100644 index 0000000..9bc7581 --- /dev/null +++ b/PBGitSidebarController.h @@ -0,0 +1,27 @@ +// +// PBGitSidebar.h +// GitX +// +// Created by Pieter de Bie on 9/8/09. +// Copyright 2009 __MyCompanyName__. All rights reserved. +// + +#import +#import "PBViewController.h" + +@class PBSourceViewAction, PBSourceViewItem; + +@interface PBGitSidebarController : PBViewController { + IBOutlet NSWindow *window; + IBOutlet NSOutlineView *sourceView; + + NSMutableArray *items; + + /* Specific things */ + PBSourceViewAction *commitAction; + + PBSourceViewItem *branches, *remotes, *tags, *custom; +} + +@property(readonly) NSMutableArray *items; +@end diff --git a/PBGitSidebarController.m b/PBGitSidebarController.m new file mode 100644 index 0000000..b19eaaa --- /dev/null +++ b/PBGitSidebarController.m @@ -0,0 +1,207 @@ +// +// PBGitSidebar.m +// GitX +// +// Created by Pieter de Bie on 9/8/09. +// Copyright 2009 __MyCompanyName__. All rights reserved. +// + +#import "PBGitSidebarController.h" +#import "PBSourceViewItem.h" +#import "NSOutlineViewExt.h" +#import "PBSourceViewAction.h" + +@interface PBGitSidebarController () + +- (void)populateList; +- (void)updateSelection; +- (void)addRevSpec:(PBGitRevSpecifier *)revSpec; +@end + +@implementation PBGitSidebarController +@synthesize items; + +- (id)initWithRepository:(PBGitRepository *)theRepository superController:(PBGitWindowController *)controller +{ + self = [super initWithRepository:theRepository superController:controller]; + [sourceView setDelegate:self]; + items = [NSMutableArray array]; + + return self; +} + +- (void)awakeFromNib +{ + [super awakeFromNib]; + window.contentView = self.view; + [self populateList]; + + [repository addObserver:self forKeyPath:@"currentBranch" options:0 context:@"currentBranchChange"]; + [self updateSelection]; +} + +- (void) observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context +{ + if ([@"currentBranchChange" isEqualTo:context]) + [self updateSelection]; +} + +- (void)updateSelection +{ + PBGitRevSpecifier *rev = repository.currentBranch; + if (!rev) + return; + + PBSourceViewItem *item = nil; + for (PBSourceViewItem *it in items) + if (item = [it findRev:rev]) + break; + + if (!item) { + [self addRevSpec:rev]; + // Try to find the just added item again. + // TODO: refactor with above. + for (PBSourceViewItem *it in items) + if (item = [it findRev:rev]) + break; + } + + [sourceView PBExpandItem:item expandParents:YES]; + NSInteger index = [sourceView rowForItem:item]; + + [sourceView selectRow:index byExtendingSelection:NO]; +} + +- (void)addRevSpec:(PBGitRevSpecifier *)rev +{ + if (![rev isSimpleRef]) { + [custom addChild:[PBSourceViewItem itemWithRevSpec:rev]]; + return; + } + + NSArray *pathComponents = [[rev simpleRef] componentsSeparatedByString:@"/"]; + if ([pathComponents count] < 2) + [branches addChild:[PBSourceViewItem itemWithRevSpec:rev]]; + else if ([[pathComponents objectAtIndex:1] isEqualToString:@"heads"]) + [branches addRev:rev toPath:[pathComponents subarrayWithRange:NSMakeRange(2, [pathComponents count] - 2)]]; + else if ([[rev simpleRef] hasPrefix:@"refs/tags/"]) + [tags addRev:rev toPath:[pathComponents subarrayWithRange:NSMakeRange(2, [pathComponents count] - 2)]]; + else if ([[rev simpleRef] hasPrefix:@"refs/remotes/"]) + [remotes addRev:rev toPath:[pathComponents subarrayWithRange:NSMakeRange(2, [pathComponents count] - 2)]]; +} + +#pragma mark NSOutlineView delegate methods + +- (void)outlineViewSelectionDidChange:(NSNotification *)notification +{ + NSInteger index = [sourceView selectedRow]; + PBSourceViewItem *item = [sourceView itemAtRow:index]; + + if ([item revSpecifier]) { + [[repository windowController] showHistoryView:self]; + repository.currentBranch = [item revSpecifier]; + return; + } + + if (item == commitAction) + [[repository windowController] showCommitView:self]; + + /* ... */ + + + /* Handle Remotes */ +} + +#pragma mark NSOutlineView delegate methods +- (BOOL)outlineView:(NSOutlineView *)outlineView isGroupItem:(id)item +{ + return [item isGroupItem]; +} + +- (void)outlineView:(NSOutlineView *)outlineView willDisplayCell:(id)cell forTableColumn:(NSTableColumn *)tableColumn item:(id)item +{ + [cell setImage:[item icon]]; +} + +- (BOOL)outlineView:(NSOutlineView *)outlineView shouldSelectItem:(id)item +{ + return ![item isGroupItem]; +} + +// +// The next two methods are necessary to hide the triangle for uncollapsible items +// That is, items which should always be displayed, such as the action items. +// +- (BOOL)outlineView:(NSOutlineView *)outlineView shouldCollapseItem:(id)item +{ + return !([item isUncollapsible]); +} + +- (void)outlineView:(NSOutlineView *)outlineView willDisplayOutlineCell:(id)cell forTableColumn:(NSTableColumn *)tableColumn item:(id)item +{ + [cell setTransparent:[item isUncollapsible]]; +} + +- (void)populateList +{ + PBSourceViewItem *actions = [PBSourceViewItem groupItemWithTitle:@"Actions"]; + + actions.isUncollapsible = YES; + + commitAction = [PBSourceViewAction itemWithTitle:@"Index / Commit"]; + commitAction.icon = [NSImage imageNamed:@"CommitViewTemplate"]; + [actions addChild:commitAction]; + + branches = [PBSourceViewItem groupItemWithTitle:@"Branches"]; + remotes = [PBSourceViewItem groupItemWithTitle:@"Remotes"]; + tags = [PBSourceViewItem groupItemWithTitle:@"Tags"]; + custom = [PBSourceViewItem groupItemWithTitle:@"Custom"]; + + for (PBGitRevSpecifier *rev in repository.branches) + [self addRevSpec:rev]; + + //[items addObject:actions]; + + [items addObject:branches]; + [items addObject:remotes]; + [items addObject:tags]; + [items addObject:custom]; + + [sourceView reloadData]; + [sourceView expandItem:branches expandChildren:YES]; + [sourceView expandItem:actions]; + + NSAssert(branches == [sourceView itemAtRow:0], @"First item is not the Branches"); + [sourceView reloadItem:nil reloadChildren:YES]; + +} + +#pragma mark NSOutlineView Datasource methods + +- (id)outlineView:(NSOutlineView *)outlineView child:(NSInteger)index ofItem:(id)item +{ + if (!item) + return [items objectAtIndex:index]; + + return [[(PBSourceViewItem *)item children] objectAtIndex:index]; +} + +- (BOOL)outlineView:(NSOutlineView *)outlineView isItemExpandable:(id)item +{ + return [[(PBSourceViewItem *)item children] count]; +} + +- (NSInteger)outlineView:(NSOutlineView *)outlineView numberOfChildrenOfItem:(id)item +{ + if (!item) + return [items count]; + + return [[(PBSourceViewItem *)item children] count]; +} + +- (id)outlineView:(NSOutlineView *)outlineView objectValueForTableColumn:(NSTableColumn *)tableColumn byItem:(id)item +{ + return [(PBSourceViewItem *)item title]; +} + +@end diff --git a/PBGitSidebarView.xib b/PBGitSidebarView.xib new file mode 100644 index 0000000..c264858 --- /dev/null +++ b/PBGitSidebarView.xib @@ -0,0 +1,459 @@ + + + + 1050 + 9L31a + 677 + 949.54 + 353.00 + + YES + + + + + YES + com.apple.InterfaceBuilderKit + com.apple.InterfaceBuilder.CocoaPlugin + + + YES + + YES + + + YES + + + + YES + + PBGitSidebarController + + + FirstResponder + + + NSApplication + + + 15 + 2 + {{196, 106}, {186, 404}} + 603979776 + Window + NSWindow + + {3.40282e+38, 3.40282e+38} + + + 274 + {186, 404} + + + {{0, 0}, {1280, 1002}} + {3.40282e+38, 3.40282e+38} + + + + 4370 + + YES + + + 2304 + + YES + + + 4352 + {151, 352} + + YES + + + 256 + {{197, 0}, {16, 17}} + + + YES + + 1.500000e+02 + 1.600000e+01 + 1.000000e+03 + + 75628032 + 0 + + + LucidaGrande + 1.100000e+01 + 3100 + + + 3 + MC4zMzMzMzI5OQA + + + 6 + System + headerTextColor + + 3 + MAA + + + + + 337772096 + 2048 + Text Cell + + LucidaGrande + 1.300000e+01 + 1044 + + + + 6 + System + controlBackgroundColor + + 3 + MC42NjY2NjY2OQA + + + + 6 + System + controlTextColor + + + + 3 + YES + YES + + + + 3.000000e+00 + + 6 + System + _sourceListBackgroundColor + + 1 + MC44MzkyMTU3IDAuODY2NjY2NjcgMC44OTgwMzkyMgA + + + + 6 + System + gridColor + + 3 + MC41AA + + + 2.000000e+01 + -767557632 + 4 + 15 + 0 + YES + 1 + 1.400000e+01 + + + {153, 354} + + + + + 4 + + + + -2147483392 + {{137, 1}, {15, 338}} + + + _doScroller: + 9.969879e-01 + + + + 256 + {{-100, -100}, {196, 15}} + + 1 + + _doScroller: + 5.714286e-01 + + + {153, 354} + + + 528 + + + + QSAAAEEgAABBoAAAQaAAAA + + + YES + + + + + YES + + + window + + + + 5 + + + + view + + + + 25 + + + + sourceView + + + + 26 + + + + dataSource + + + + 34 + + + + delegate + + + + 35 + + + + + YES + + 0 + + YES + + + + + + -2 + + + RmlsZSdzIE93bmVyA + + + -1 + + + First Responder + + + -3 + + + Application + + + 2 + + + YES + + + + + + 3 + + + + + 8 + + + YES + + + + + + + + 9 + + + + + 10 + + + + + 11 + + + YES + + + + + + 13 + + + YES + + + + + + 16 + + + + + 21 + + + + + + + YES + + YES + -1.IBPluginDependency + -2.IBPluginDependency + -3.IBPluginDependency + 10.IBPluginDependency + 11.IBPluginDependency + 13.IBPluginDependency + 16.CustomClassName + 16.IBPluginDependency + 2.IBEditorWindowLastContentRect + 2.IBPluginDependency + 2.IBWindowTemplateEditedContentRect + 2.NSWindowTemplate.visibleAtLaunch + 3.IBPluginDependency + 8.IBEditorWindowLastContentRect + 8.IBPluginDependency + 9.IBPluginDependency + + + YES + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilderKit + com.apple.InterfaceBuilderKit + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + PBIconAndTextCell + com.apple.InterfaceBuilder.CocoaPlugin + {{297, 477}, {186, 404}} + com.apple.InterfaceBuilder.CocoaPlugin + {{297, 477}, {186, 404}} + + com.apple.InterfaceBuilder.CocoaPlugin + {{105, 545}, {153, 354}} + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + + + + YES + + YES + + + YES + + + + + YES + + YES + + + YES + + + + 35 + + + + YES + + PBGitSidebarController + PBViewController + + YES + + YES + sourceView + window + + + YES + NSOutlineView + NSWindow + + + + IBProjectSource + PBGitSidebarController.h + + + + PBIconAndTextCell + NSTextFieldCell + + IBProjectSource + PBIconAndTextCell.h + + + + PBViewController + NSViewController + + viewToolbar + NSToolbar + + + IBProjectSource + PBViewController.h + + + + + 0 + GitX.xcodeproj + 3 + + diff --git a/PBGitWindowController.h b/PBGitWindowController.h index 9b15482..ed5162a 100644 --- a/PBGitWindowController.h +++ b/PBGitWindowController.h @@ -9,7 +9,8 @@ #import #import "PBGitRepository.h" -@class PBViewController; +@class PBViewController, PBGitSidebarController; + @interface PBGitWindowController : NSWindowController { __weak PBGitRepository* repository; int selectedViewIndex; diff --git a/PBGitWindowController.m b/PBGitWindowController.m index 1b4b322..1b8c88e 100644 --- a/PBGitWindowController.m +++ b/PBGitWindowController.m @@ -11,6 +11,7 @@ #import "PBGitCommitController.h" #import "Terminal.h" #import "PBCloneRepsitoryToSheet.h" +#import "PBGitSidebarController.h" @implementation PBGitWindowController @@ -19,17 +20,16 @@ - (id)initWithRepository:(PBGitRepository*)theRepository displayDefault:(BOOL)displayDefault { - if(self = [self initWithWindowNibName:@"RepositoryWindow"]) - { - self.repository = theRepository; - [self showWindow:nil]; - } - - if (displayDefault) { + if (!(self = [self initWithWindowNibName:@"RepositoryWindow"])) + return nil; + + self.repository = theRepository; + [self showWindow:nil]; + + if (displayDefault) self.selectedViewIndex = [[NSUserDefaults standardUserDefaults] integerForKey:@"selectedViewIndex"]; - } else { + else self.selectedViewIndex = -1; - } return self; } diff --git a/PBSourceViewAction.h b/PBSourceViewAction.h new file mode 100644 index 0000000..763d254 --- /dev/null +++ b/PBSourceViewAction.h @@ -0,0 +1,17 @@ +// +// PBSourceViewAction.h +// GitX +// +// Created by Pieter de Bie on 9/8/09. +// Copyright 2009 __MyCompanyName__. All rights reserved. +// + +#import +#import "PBSourceViewItem.h" + +@interface PBSourceViewAction : PBSourceViewItem { + NSImage *icon; +} + +@property(retain) NSImage *icon; +@end diff --git a/PBSourceViewAction.m b/PBSourceViewAction.m new file mode 100644 index 0000000..344b967 --- /dev/null +++ b/PBSourceViewAction.m @@ -0,0 +1,15 @@ +// +// PBSourceViewAction.m +// GitX +// +// Created by Pieter de Bie on 9/8/09. +// Copyright 2009 __MyCompanyName__. All rights reserved. +// + +#import "PBSourceViewAction.h" + + +@implementation PBSourceViewAction +@synthesize icon; + +@end diff --git a/PBSourceViewItem.h b/PBSourceViewItem.h new file mode 100644 index 0000000..1748f5a --- /dev/null +++ b/PBSourceViewItem.h @@ -0,0 +1,43 @@ +// +// PBSourceViewItem.h +// GitX +// +// Created by Pieter de Bie on 9/8/09. +// Copyright 2009 __MyCompanyName__. All rights reserved. +// + +#import + +@class PBGitRevSpecifier; + +@interface PBSourceViewItem : NSObject { + NSMutableArray *children; + + NSString *title; + PBGitRevSpecifier *revSpecifier; + PBSourceViewItem *parent; + + BOOL isGroupItem; + BOOL isUncollapsible; +} + ++ (id)groupItemWithTitle:(NSString *)title; ++ (id)itemWithRevSpec:(PBGitRevSpecifier *)revSpecifier; ++ (id)itemWithTitle:(NSString *)title; + +- (void)addChild:(PBSourceViewItem *)child; + +// This adds the ref to the path, which should match the item's title, +// so "refs/heads/pu/pb/sidebar" would have the path [@"pu", @"pb", @"sidebare"] +// to the 'local' branch thing +- (void)addRev:(PBGitRevSpecifier *)revSpecifier toPath:(NSArray *)path; +- (PBSourceViewItem *)findRev:(PBGitRevSpecifier *)rev; + +- (NSImage *)icon; + +@property(retain) NSString *title; +@property(readonly) NSMutableArray *children; +@property(assign) BOOL isGroupItem, isUncollapsible; +@property(retain) PBGitRevSpecifier *revSpecifier; +@property(retain) PBSourceViewItem *parent; +@end diff --git a/PBSourceViewItem.m b/PBSourceViewItem.m new file mode 100644 index 0000000..b7f4045 --- /dev/null +++ b/PBSourceViewItem.m @@ -0,0 +1,113 @@ +// +// PBSourceViewItem.m +// GitX +// +// Created by Pieter de Bie on 9/8/09. +// Copyright 2009 __MyCompanyName__. All rights reserved. +// + +#import "PBSourceViewItem.h" +#import "PBGitRevSpecifier.h" + +@implementation PBSourceViewItem +@synthesize parent, title, isGroupItem, children, revSpecifier, isUncollapsible; + +- (id)init +{ + if (!(self = [super init])) + return nil; + + children = [NSMutableArray array]; + return self; +} + ++ (id)groupItemWithTitle:(NSString *)title +{ + PBSourceViewItem *item = [[[self class] alloc] init]; + item.title = title; + item.isGroupItem = YES; + return item; +} + ++ (id)itemWithRevSpec:(PBGitRevSpecifier *)revSpecifier +{ + PBSourceViewItem *item = [[[self class] alloc] init]; + item.revSpecifier = revSpecifier; + + return item; +} + ++ (id)itemWithTitle:(NSString *)title; +{ + PBSourceViewItem *item = [[[self class] alloc] init]; + item.title = title; + return item; +} + +- (void)addChild:(PBSourceViewItem *)child +{ + [self.children addObject:child]; + child.parent = self; +} + +- (void)addRev:(PBGitRevSpecifier *)theRevSpecifier toPath:(NSArray *)path +{ + if ([path count] == 1) { + PBSourceViewItem *item = [PBSourceViewItem itemWithRevSpec:theRevSpecifier]; + [self addChild:item]; + return; + } + + NSString *firstTitle = [path objectAtIndex:0]; + PBSourceViewItem *node = nil; + for (PBSourceViewItem *child in [self children]) + if ([child.title isEqualToString:firstTitle]) + node = child; + + if (!node) { + node = [PBSourceViewItem itemWithTitle:firstTitle]; + [self addChild:node]; + } + + [node addRev:theRevSpecifier toPath:[path subarrayWithRange:NSMakeRange(1, [path count] - 1)]]; +} + +- (PBSourceViewItem *)findRev:(PBGitRevSpecifier *)rev +{ + if (rev == revSpecifier) + return self; + + PBSourceViewItem *item = nil; + for (PBSourceViewItem *child in children) + if (item = [child findRev:rev]) + return item; + + return nil; +} + +- (NSString *)title +{ + if (title) + return title; + + return [[revSpecifier description] lastPathComponent]; +} + +- (NSImage *)icon +{ + if ([self isGroupItem]) + return nil; + + if (self.parent && !self.parent.parent && [self.parent.title isEqualToString:@"Remotes"]) + return [NSImage imageNamed:@"remote"]; + + if (self.parent && !self.parent.parent && [self.parent.title isEqualToString:@"Tags"]) + return [NSImage imageNamed:@"tag"]; + + if ([[self children] count]) + return [NSImage imageNamed:@"folder"]; + + return [NSImage imageNamed:@"branch"]; +} + +@end diff --git a/PBSourceViewRemote.h b/PBSourceViewRemote.h new file mode 100644 index 0000000..edb5d98 --- /dev/null +++ b/PBSourceViewRemote.h @@ -0,0 +1,16 @@ +// +// PBSourceViewRemote.h +// GitX +// +// Created by Pieter de Bie on 9/8/09. +// Copyright 2009 __MyCompanyName__. All rights reserved. +// + +#import +#import "PBSourceViewItem.h" + +@interface PBSourceViewRemote : PBSourceViewItem { + +} + +@end diff --git a/PBSourceViewRemote.m b/PBSourceViewRemote.m new file mode 100644 index 0000000..b8ccd84 --- /dev/null +++ b/PBSourceViewRemote.m @@ -0,0 +1,18 @@ +// +// PBSourceViewRemote.m +// GitX +// +// Created by Pieter de Bie on 9/8/09. +// Copyright 2009 __MyCompanyName__. All rights reserved. +// + +#import "PBSourceViewRemote.h" + + +@implementation PBSourceViewRemote + +- (NSImage *)icon +{ + return [NSImage imageNamed:@"remote"]; +} +@end