Switch branches/tags
Nothing to show
Find file Copy path
Fetching contributors…
Cannot retrieve contributors at this time
159 lines (133 sloc) 4.57 KB
#import "RepoMenuItem.h"
#import "RepoInstance.h"
#import "MainController.h"
#import "LogMenuView.h"
#import "BubbleFactory.h"
@implementation RepoMenuItem
static NSImage *green;
static NSImage *yellow;
static NSImage *red;
static NSImage *blue;
- (RepoInstance *)repository {
return repo;
- (void) doUpdateMenu: (NSNotification *)notif {
[lastUpdate release];
lastUpdate = [NSDate date];
[lastUpdate retain];
NSArray *logs = [repo logs];
NSArray *pending = [repo pending];
int i;
NSMutableArray *dateStrings = [NSMutableArray arrayWithCapacity: [logs count]];
NSMutableArray *logStrings = [NSMutableArray arrayWithCapacity: [logs count]];
NSMutableArray *hashs = [NSMutableArray arrayWithCapacity: [logs count]];
for (i = 0; i < [logs count]; i++) {
NSString *dateString = [dateFormatter stringFromDate: [[logs objectAtIndex: i] objectForKey: @"date"]];
NSString *logString = [[logs objectAtIndex: i] objectForKey: @"message"];
[dateStrings addObject: dateString];
[logStrings addObject: logString];
[hashs addObject: [[logs objectAtIndex: i] objectForKey: @"hash"]];
dispatch_async(dispatch_get_main_queue(), ^{
int i;
if ([repo hasLocal]) {
[self setOffStateImage: red];
} else if ([repo hasRemote]) {
[self setOffStateImage: yellow];
} else {
[self setOffStateImage: green];
NSMenuItem *mi;
[sub removeAllItems];
for (i = 0; i < [dateStrings count]; i++) {
mi = [sub addItemWithTitle: @"" action: nil keyEquivalent: @""];
NSString *dateString = [dateStrings objectAtIndex: i];
NSString *messageString = [logStrings objectAtIndex: i];
LogMenuView *lmv = [[LogMenuView alloc] initWithFrame: NSMakeRect(0, 0, 400, 20)];
[lmv setAutoresizingMask: NSViewWidthSizable];
if ([pending containsObject: [hashs objectAtIndex: i]]) {
[lmv setPending: YES];
} else {
[lmv setPending: NO];
[lmv setDate: dateString];
[lmv setMessage: messageString];
[mi setView: lmv];
if ([repo hasLocal]) {
mi = [sub addItemWithTitle: @"Commit Local Changes" action: @selector(commitFromMenu:) keyEquivalent: @""];
[mi setRepresentedObject: repo];
[mi setTarget: [MainController sharedInstance]];
[lock unlock];
- (void) updateMenu: (NSNotification *)notif {
// We must lock on a consistent thread. The only way to do that is to lock on
// the main thread. Sigh.
// NOTE: This lock IS unlocked. Though you can't see it here. We have to call
// into the main queue in order to actually do the visual updates. It is
// unlocked there. Unlocking here would unlock potentially early.
dispatch_async(dispatch_get_main_queue(), ^{
if (![lock tryLock])
dispatch_async(dispatch_get_global_queue(0, 0), ^{
[self doUpdateMenu: notif];
- (id) initWithRepository: (RepoInstance *)rep {
self = [super initWithTitle: [rep shortTitle] ? [rep shortTitle] : @"" action: nil keyEquivalent: @""];
repo = rep;
[repo retain];
[self setToolTip: [repo repository]];
lock = [[NSLock alloc] init];
[rep setMenuItem: self];
[self setTarget: rep];
if (!green) {
green = [BubbleFactory getGreenOfSize: 10];
[green retain];
red = [BubbleFactory getRedOfSize: 10];
[red retain];
yellow = [BubbleFactory getYellowOfSize: 10];
[yellow retain];
blue = [BubbleFactory getBlueOfSize: 10];
[blue retain];
dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setTimeStyle: NSDateFormatterShortStyle];
[dateFormatter setDateStyle: NSDateFormatterMediumStyle];
[dateFormatter setDoesRelativeDateFormatting: YES];
dateAttributes = [NSDictionary dictionaryWithObjectsAndKeys:
[NSColor grayColor],
[NSFont labelFontOfSize: 10],
[dateAttributes retain];
logAttributes = [NSDictionary dictionaryWithObjectsAndKeys:
[NSColor blackColor],
[NSFont systemFontOfSize: 14],
[logAttributes retain];
datePendingAttributes = [NSDictionary dictionaryWithObjectsAndKeys:
[NSColor redColor],
[NSFont systemFontOfSize: 10],
[datePendingAttributes retain];
sub = [[NSMenu alloc] initWithTitle: [repo repository]];
[sub retain];
[self setSubmenu: sub];
dispatch_async(dispatch_get_global_queue(0, 0), ^{
[self updateMenu: nil];
// Update the menu no matter what the notification is. We may have to filter some out later on to not go into an
// endless loop.
[[NSNotificationCenter defaultCenter] addObserver: self selector: @selector(updateMenu:) name: nil object: rep];
return self;