Files
textmate/Applications/TextMate/src/AppController Menus.mm
Allan Odgaard 402e1f79b1 Use one bundle menu delegate for all menus
This avoids the problem of keeping the delegate retained while the menu is up (the menu item exists).
2013-02-12 20:11:50 +01:00

118 lines
4.0 KiB
Plaintext

#import "AppController.h"
#import <oak/oak.h>
#import <text/ctype.h>
#import <bundles/bundles.h>
#import <command/parser.h>
#import <cf/cf.h>
#import <ns/ns.h>
#import <OakAppKit/NSMenu Additions.h>
#import <OakAppKit/NSMenuItem Additions.h>
#import <OakAppKit/OakToolTip.h>
#import <OakFoundation/NSString Additions.h>
#import <oak/debug.h>
#import <BundleMenu/BundleMenu.h>
OAK_DEBUG_VAR(AppController_Menus);
@implementation AppController (BundlesMenu)
- (void)performBundleItemWithUUIDStringFrom:(id)anArgument
{
[NSApp sendAction:@selector(performBundleItemWithUUIDString:) to:nil from:[anArgument representedObject]];
}
- (BOOL)menuHasKeyEquivalent:(NSMenu*)aMenu forEvent:(NSEvent*)theEvent target:(id*)aTarget action:(SEL*)anAction
{
D(DBF_AppController_Menus, bug("%s (%s)\n", ns::glyphs_for_event_string(to_s(theEvent)).c_str(), to_s(theEvent).c_str()););
return NO;
}
- (void)bundlesMenuNeedsUpdate:(NSMenu*)aMenu
{
D(DBF_AppController_Menus, bug("\n"););
for(int i = aMenu.numberOfItems; i--; )
{
if([[aMenu itemAtIndex:i] isSeparatorItem])
break;
[aMenu removeItemAtIndex:i];
}
std::multimap<std::string, bundles::item_ptr, text::less_t> ordered;
citerate(item, bundles::query(bundles::kFieldAny, NULL_STR, scope::wildcard, bundles::kItemTypeBundle))
ordered.insert(std::make_pair((*item)->name(), *item));
iterate(pair, ordered)
{
if(pair->second->menu().empty())
continue;
NSMenuItem* menuItem = [aMenu addItemWithTitle:[NSString stringWithCxxString:pair->first] action:NULL keyEquivalent:@""];
menuItem.submenu = [[NSMenu alloc] initWithTitle:[NSString stringWithCxxString:pair->second->uuid()]];
menuItem.submenu.delegate = [BundleMenuDelegate sharedInstance];
}
if(ordered.empty())
[aMenu addItemWithTitle:@"No Bundles Loaded" action:@selector(nop:) keyEquivalent:@""];
}
- (void)themesMenuNeedsUpdate:(NSMenu*)aMenu
{
D(DBF_AppController_Menus, bug("\n"););
[aMenu removeAllItems];
std::multimap<std::string, bundles::item_ptr, text::less_t> ordered;
citerate(item, bundles::query(bundles::kFieldAny, NULL_STR, scope::wildcard, bundles::kItemTypeTheme))
ordered.insert(std::make_pair((*item)->name(), *item));
iterate(pair, ordered)
{
NSMenuItem* menuItem = [aMenu addItemWithTitle:[NSString stringWithCxxString:pair->first] action:@selector(takeThemeUUIDFrom:) keyEquivalent:@""];
[menuItem setKeyEquivalentCxxString:key_equivalent(pair->second)];
[menuItem setRepresentedObject:[NSString stringWithCxxString:pair->second->uuid()]];
}
if(ordered.empty())
[aMenu addItemWithTitle:@"No Themes Loaded" action:@selector(nop:) keyEquivalent:@""];
}
- (void)spellingMenuNeedsUpdate:(NSMenu*)aMenu
{
D(DBF_AppController_Menus, bug("\n"););
for(int i = aMenu.numberOfItems; i--; )
{
NSMenuItem* item = [aMenu itemAtIndex:i];
if([item action] == @selector(takeSpellingLanguageFrom:))
[aMenu removeItemAtIndex:i];
}
std::multimap<std::string, NSString*, text::less_t> ordered;
NSSpellChecker* spellChecker = [NSSpellChecker sharedSpellChecker];
for(NSString* lang in [spellChecker availableLanguages])
{
D(DBF_AppController_Menus, bug("%s\n", [lang UTF8String]););
NSString* str = (NSString*)CFBridgingRelease(CFLocaleCopyDisplayNameForPropertyValue(CFLocaleGetSystem(), kCFLocaleIdentifier, (__bridge CFStringRef)lang));
D(DBF_AppController_Menus, bug("→ %s\n", [(str ?: lang) UTF8String]););
ordered.insert(std::make_pair(to_s(str ?: lang), lang));
}
iterate(it, ordered)
{
D(DBF_AppController_Menus, bug("Add Item: %s\n", it->first.c_str()););
NSMenuItem* menuItem = [aMenu addItemWithTitle:[NSString stringWithCxxString:it->first] action:@selector(takeSpellingLanguageFrom:) keyEquivalent:@""];
D(DBF_AppController_Menus, bug("Represented Object: %s\n", [it->second UTF8String]););
menuItem.representedObject = it->second;
}
}
- (void)menuNeedsUpdate:(NSMenu*)aMenu
{
if(aMenu == bundlesMenu)
[self bundlesMenuNeedsUpdate:aMenu];
else if(aMenu == themesMenu)
[self themesMenuNeedsUpdate:aMenu];
else if(aMenu == spellingMenu)
[self spellingMenuNeedsUpdate:aMenu];
}
@end