diff --git a/GitX.xcodeproj/project.pbxproj b/GitX.xcodeproj/project.pbxproj index ecb9aa790..f14f9c13a 100644 --- a/GitX.xcodeproj/project.pbxproj +++ b/GitX.xcodeproj/project.pbxproj @@ -50,6 +50,8 @@ D8083DC4111F90F300337480 /* PBCloneRepsitoryToSheet.m in Sources */ = {isa = PBXBuildFile; fileRef = D8083DC3111F90F300337480 /* PBCloneRepsitoryToSheet.m */; }; D8083DCD111F918900337480 /* PBCloneRepsitoryToSheet.xib in Resources */ = {isa = PBXBuildFile; fileRef = D8083DCB111F918900337480 /* PBCloneRepsitoryToSheet.xib */; }; D8083E03111FA33700337480 /* PBCloneRepositoryPanel.m in Sources */ = {isa = PBXBuildFile; fileRef = D8083E02111FA33700337480 /* PBCloneRepositoryPanel.m */; }; + D828A40D1127B18700F09D11 /* PBSourceViewCell.m in Sources */ = {isa = PBXBuildFile; fileRef = D828A40C1127B18700F09D11 /* PBSourceViewCell.m */; }; + D828A4111127B1C400F09D11 /* PBSourceViewBadge.m in Sources */ = {isa = PBXBuildFile; fileRef = D828A4101127B1C400F09D11 /* PBSourceViewBadge.m */; }; D8357535112640F100DE249D /* PBRemoteProgressSheet.xib in Resources */ = {isa = PBXBuildFile; fileRef = D8C1B77110E875CF009B7F8B /* PBRemoteProgressSheet.xib */; }; D854948610D5C01B0083B917 /* PBCreateBranchSheet.m in Sources */ = {isa = PBXBuildFile; fileRef = D854948510D5C01B0083B917 /* PBCreateBranchSheet.m */; }; D85810551127476E007F254B /* StageView.png in Resources */ = {isa = PBXBuildFile; fileRef = D85810541127476E007F254B /* StageView.png */; }; @@ -248,6 +250,10 @@ D8083E01111FA33700337480 /* PBCloneRepositoryPanel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PBCloneRepositoryPanel.h; sourceTree = ""; }; D8083E02111FA33700337480 /* PBCloneRepositoryPanel.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PBCloneRepositoryPanel.m; sourceTree = ""; }; D823487410CB382C00944BDE /* Terminal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Terminal.h; sourceTree = ""; }; + D828A40B1127B18700F09D11 /* PBSourceViewCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PBSourceViewCell.h; sourceTree = ""; }; + D828A40C1127B18700F09D11 /* PBSourceViewCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PBSourceViewCell.m; sourceTree = ""; }; + D828A40F1127B1C400F09D11 /* PBSourceViewBadge.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PBSourceViewBadge.h; sourceTree = ""; }; + D828A4101127B1C400F09D11 /* PBSourceViewBadge.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PBSourceViewBadge.m; sourceTree = ""; }; D854948410D5C01B0083B917 /* PBCreateBranchSheet.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PBCreateBranchSheet.h; sourceTree = ""; }; D854948510D5C01B0083B917 /* PBCreateBranchSheet.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PBCreateBranchSheet.m; sourceTree = ""; }; D854949310D5C3E20083B917 /* English */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = English; path = English.lproj/PBCreateBranchSheet.xib; sourceTree = ""; }; @@ -727,6 +733,10 @@ children = ( F58DB55710566D3500CFDF4A /* PBGitSidebarController.h */, F58DB55810566D3500CFDF4A /* PBGitSidebarController.m */, + D828A40B1127B18700F09D11 /* PBSourceViewCell.h */, + D828A40C1127B18700F09D11 /* PBSourceViewCell.m */, + D828A40F1127B1C400F09D11 /* PBSourceViewBadge.h */, + D828A4101127B1C400F09D11 /* PBSourceViewBadge.m */, D8FDDA58114335B0005647F6 /* Source View Items */, ); name = Sidebar; @@ -1119,6 +1129,8 @@ D8FDDA6F114335E8005647F6 /* PBGitSVStageItem.m in Sources */, D8FDDA70114335E8005647F6 /* PBGitSVTagItem.m in Sources */, D8A4BB6F11337D5C00E92D51 /* PBGitGradientBarView.m in Sources */, + D828A40D1127B18700F09D11 /* PBSourceViewCell.m in Sources */, + D828A4111127B1C400F09D11 /* PBSourceViewBadge.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/PBGitHistoryController.h b/PBGitHistoryController.h index 666ed794d..1d059c31f 100644 --- a/PBGitHistoryController.h +++ b/PBGitHistoryController.h @@ -14,8 +14,10 @@ @class PBGitSidebarController; @class PBGitGradientBarView; +@class PBRefController; @interface PBGitHistoryController : PBViewController { + IBOutlet PBRefController *refController; IBOutlet NSSearchField *searchField; IBOutlet NSArrayController* commitController; IBOutlet NSTreeController* treeController; @@ -38,6 +40,7 @@ @property (retain) PBGitCommit *webCommit, *rawCommit; @property (retain) PBGitTree* gitTree; @property (readonly) NSArrayController *commitController; +@property (readonly) PBRefController *refController; - (IBAction) setDetailedView: sender; - (IBAction) setRawView: sender; diff --git a/PBGitHistoryController.m b/PBGitHistoryController.m index 9100735e9..758b5aae7 100644 --- a/PBGitHistoryController.m +++ b/PBGitHistoryController.m @@ -20,7 +20,7 @@ @implementation PBGitHistoryController -@synthesize selectedTab, webCommit, rawCommit, gitTree, commitController; +@synthesize selectedTab, webCommit, rawCommit, gitTree, commitController, refController; - (void)awakeFromNib { diff --git a/PBGitHistoryView.xib b/PBGitHistoryView.xib index 52f687487..81df53f26 100644 --- a/PBGitHistoryView.xib +++ b/PBGitHistoryView.xib @@ -1643,6 +1643,14 @@ 328 + + + refController + + + + 329 + @@ -2263,7 +2271,7 @@ - 328 + 329 @@ -2366,6 +2374,7 @@ commitList fileBrowser historySplitView + refController scopeBarView searchField treeController @@ -2378,6 +2387,7 @@ NSTableView NSOutlineView PBCollapsibleSplitView + PBRefController PBGitGradientBarView NSSearchField NSTreeController @@ -2458,7 +2468,6 @@ pushDefaultRemoteForRef: pushToRemote: pushUpdatesToRemote: - rebaseActiveBranch: rebaseHeadBranch: showTagInfoSheet: @@ -2478,7 +2487,6 @@ PBRefMenuItem PBRefMenuItem PBRefMenuItem - PBRefMenuItem diff --git a/PBGitSidebarController.h b/PBGitSidebarController.h index 56d6935ef..c0c76e06c 100644 --- a/PBGitSidebarController.h +++ b/PBGitSidebarController.h @@ -31,5 +31,7 @@ - (void) selectStage; - (void) selectCurrentBranch; +- (NSMenu *) menuForRow:(NSInteger)row; + @property(readonly) NSMutableArray *items; @end diff --git a/PBGitSidebarController.m b/PBGitSidebarController.m index d4b5d86a7..ce3d09a84 100644 --- a/PBGitSidebarController.m +++ b/PBGitSidebarController.m @@ -10,6 +10,8 @@ #import "PBSourceViewItems.h" #import "PBGitHistoryController.h" #import "PBGitCommitController.h" +#import "PBRefController.h" +#import "PBSourceViewCell.h" #import "NSOutlineViewExt.h" @interface PBGitSidebarController () @@ -127,8 +129,10 @@ - (BOOL)outlineView:(NSOutlineView *)outlineView isGroupItem:(id)item return [item isGroupItem]; } -- (void)outlineView:(NSOutlineView *)outlineView willDisplayCell:(id)cell forTableColumn:(NSTableColumn *)tableColumn item:(id)item +- (void)outlineView:(NSOutlineView *)outlineView willDisplayCell:(PBSourceViewCell *)cell forTableColumn:(NSTableColumn *)tableColumn item:(PBSourceViewItem *)item { + cell.isCheckedOut = [item.revSpecifier isEqualTo:[repository headRef]]; + [cell setImage:[item icon]]; } @@ -204,4 +208,32 @@ - (id)outlineView:(NSOutlineView *)outlineView objectValueForTableColumn:(NSTabl return [(PBSourceViewItem *)item title]; } + +#pragma mark Menus + +- (NSMenu *) menuForRow:(NSInteger)row +{ + PBSourceViewItem *viewItem = [sourceView itemAtRow:row]; + + PBGitRef *ref = nil; + + // create a ref for a remote because they don't store one + if ([self outlineView:sourceView isItemExpandable:viewItem] && (viewItem.parent == remotes)) + ref = [PBGitRef refFromString:[kGitXRemoteRefPrefix stringByAppendingString:[viewItem title]]]; + else + ref = [[viewItem revSpecifier] ref]; + + if (!ref) + return nil; + + NSArray *menuItems = [historyViewController.refController menuItemsForRef:ref]; + + NSMenu *menu = [[NSMenu alloc] init]; + [menu setAutoenablesItems:NO]; + for (NSMenuItem *item in menuItems) + [menu addItem:item]; + + return menu; +} + @end diff --git a/PBGitSidebarView.xib b/PBGitSidebarView.xib index e598b9a42..067b02aba 100644 --- a/PBGitSidebarView.xib +++ b/PBGitSidebarView.xib @@ -340,7 +340,7 @@ com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin - PBIconAndTextCell + PBSourceViewCell com.apple.InterfaceBuilder.CocoaPlugin {{482, 590}, {153, 354}} com.apple.InterfaceBuilder.CocoaPlugin @@ -406,13 +406,17 @@ PBIconAndTextCell.h + + PBSourceViewCell + PBIconAndTextCell + + IBProjectSource + PBSourceViewCell.h + + PBViewController NSViewController - - viewToolbar - NSToolbar - IBProjectSource PBViewController.h @@ -889,14 +893,6 @@ AppKit.framework/Headers/NSTextFieldCell.h - - NSToolbar - NSObject - - IBFrameworkSource - AppKit.framework/Headers/NSToolbar.h - - NSView diff --git a/PBSourceViewBadge.h b/PBSourceViewBadge.h new file mode 100644 index 000000000..1754000d7 --- /dev/null +++ b/PBSourceViewBadge.h @@ -0,0 +1,19 @@ +// +// PBSourceViewBadge.h +// GitX +// +// Created by Nathan Kinsinger on 2/13/10. +// Copyright 2010 Nathan Kinsinger. All rights reserved. +// + +#import + + +@interface PBSourceViewBadge : NSObject { + +} + ++ (NSImage *) checkedOutBadgeForCell:(NSTextFieldCell *)cell; ++ (NSImage *) numericBadge:(NSInteger)number forCell:(NSTextFieldCell *)cell; + +@end diff --git a/PBSourceViewBadge.m b/PBSourceViewBadge.m new file mode 100644 index 000000000..8f00a06cb --- /dev/null +++ b/PBSourceViewBadge.m @@ -0,0 +1,121 @@ +// +// PBSourceViewBadge.m +// GitX +// +// Created by Nathan Kinsinger on 2/13/10. +// Copyright 2010 Nathan Kinsinger. All rights reserved. +// + +#import "PBSourceViewBadge.h" +#import "PBSourceViewCell.h" + + +@implementation PBSourceViewBadge + + ++ (NSColor *) badgeHighlightColor +{ + return [NSColor colorWithCalibratedHue:0.612 saturation:0.275 brightness:0.735 alpha:1.000]; +} + + ++ (NSColor *) badgeBackgroundColor +{ + return [NSColor colorWithCalibratedWhite:0.6 alpha:1.00]; +} + + ++ (NSColor *) badgeColorForCell:(NSTextFieldCell *)cell +{ + if ([cell isHighlighted]) + return [NSColor whiteColor]; + + if ([[[cell controlView] window] isMainWindow]) + return [self badgeHighlightColor]; + + return [self badgeBackgroundColor]; +} + + ++ (NSColor *) badgeTextColorForCell:(NSTextFieldCell *)cell +{ + if (![cell isHighlighted]) + return [NSColor whiteColor]; + + if (![[[cell controlView] window] isKeyWindow]) + if ([[[cell controlView] window] isMainWindow]) + return [self badgeHighlightColor]; + else + return [self badgeBackgroundColor]; + + if ([[[cell controlView] window] firstResponder] == [cell controlView]) + return [self badgeHighlightColor]; + + return [self badgeBackgroundColor]; +} + + ++ (NSMutableDictionary *) badgeTextAttributes +{ + NSMutableDictionary *badgeTextAttributes = nil; + if (!badgeTextAttributes) { + NSMutableParagraphStyle *centerStyle = [[NSMutableParagraphStyle alloc] init]; + [centerStyle setAlignment:NSCenterTextAlignment]; + + badgeTextAttributes = [NSMutableDictionary dictionary]; + [badgeTextAttributes setObject:[NSFont fontWithName:@"Helvetica-Bold" size:[NSFont systemFontSize] - 2] forKey:NSFontAttributeName]; + [badgeTextAttributes setObject:centerStyle forKey:NSParagraphStyleAttributeName]; + } + + return badgeTextAttributes; +} + + + +#pragma mark - +#pragma mark badges + ++ (NSImage *) badge:(NSString *)badge forCell:(NSTextFieldCell *)cell +{ + NSColor *badgeColor = [self badgeColorForCell:cell]; + + NSColor *textColor = [self badgeTextColorForCell:cell]; + NSMutableDictionary *badgeTextAttributes = [self badgeTextAttributes]; + [badgeTextAttributes setObject:textColor forKey:NSForegroundColorAttributeName]; + NSAttributedString *badgeString = [[NSAttributedString alloc] initWithString:badge attributes:badgeTextAttributes]; + + float imageHeight = ceilf([badgeString size].height); + float radius = ceilf(imageHeight / 4) * 2; + float minWidth = ceilf(radius * 2.5); + + float imageWidth = ceilf([badgeString size].width + radius); + if (imageWidth < minWidth) + imageWidth = minWidth; + NSRect badgeRect = NSMakeRect(0, 0, imageWidth, imageHeight); + + NSBezierPath *badgePath = [NSBezierPath bezierPathWithRoundedRect:badgeRect xRadius:radius yRadius:radius]; + + NSImage *badgeImage = [[NSImage alloc] initWithSize:badgeRect.size]; + [badgeImage lockFocus]; + + [badgeColor set]; + [badgePath fill]; + + [badgeString drawInRect:badgeRect]; + + [badgeImage unlockFocus]; + + return badgeImage; +} + ++ (NSImage *) checkedOutBadgeForCell:(NSTextFieldCell *)cell +{ + return [self badge:@"✔" forCell:cell]; +} + ++ (NSImage *) numericBadge:(NSInteger)number forCell:(NSTextFieldCell *)cell +{ + return [self badge:[NSString stringWithFormat:@"%d", number] forCell:cell]; +} + +@end diff --git a/PBSourceViewCell.h b/PBSourceViewCell.h new file mode 100644 index 000000000..5b8839245 --- /dev/null +++ b/PBSourceViewCell.h @@ -0,0 +1,19 @@ +// +// PBSourceViewCell.h +// GitX +// +// Created by Nathan Kinsinger on 1/7/10. +// Copyright 2010 Nathan Kinsinger. All rights reserved. +// + +#import +#import "PBIconAndTextCell.h" + + +@interface PBSourceViewCell : PBIconAndTextCell { + BOOL isCheckedOut; +} + +@property (assign) BOOL isCheckedOut; + +@end diff --git a/PBSourceViewCell.m b/PBSourceViewCell.m new file mode 100644 index 000000000..eb60bca7a --- /dev/null +++ b/PBSourceViewCell.m @@ -0,0 +1,55 @@ +// +// PBSourceViewCell.m +// GitX +// +// Created by Nathan Kinsinger on 1/7/10. +// Copyright 2010 Nathan Kinsinger. All rights reserved. +// + +#import "PBSourceViewCell.h" +#import "PBGitSidebarController.h" +#import "PBSourceViewBadge.h" + + + + +@implementation PBSourceViewCell + +@synthesize isCheckedOut; + +# pragma mark context menu delegate methods + +- (NSMenu *) menuForEvent:(NSEvent *)event inRect:(NSRect)rect ofView:(NSOutlineView *)view +{ + NSPoint point = [view convertPoint:[event locationInWindow] fromView:nil]; + NSInteger row = [view rowAtPoint:point]; + + PBGitSidebarController *controller = [view delegate]; + + return [controller menuForRow:row]; +} + + +#pragma mark drawing + +- (void)drawWithFrame:(NSRect)cellFrame inView:(NSView *)outlineView +{ + if (isCheckedOut) { + NSImage *checkedOutImage = [PBSourceViewBadge checkedOutBadgeForCell:self]; + NSSize imageSize = [checkedOutImage size]; + NSRect imageFrame; + NSDivideRect(cellFrame, &imageFrame, &cellFrame, imageSize.width + 3, NSMaxXEdge); + imageFrame.size = imageSize; + + if ([outlineView isFlipped]) + imageFrame.origin.y += floor((cellFrame.size.height + imageFrame.size.height) / 2); + else + imageFrame.origin.y += ceil((cellFrame.size.height - imageFrame.size.height) / 2); + + [checkedOutImage compositeToPoint:imageFrame.origin operation:NSCompositeSourceOver]; + } + + [super drawWithFrame:cellFrame inView:outlineView]; +} + +@end