123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233 |
- //
- // MenuProxy.m
- // MacGap
- //
- // Created by Joe Hildebrand on 1/14/12.
- // Copyright (c) 2012 Twitter. All rights reserved.
- //
- #import <objc/runtime.h>
- #import <JavaScriptCore/JavaScript.h>
- #import "MenuProxy.h"
- #import "MenuItemProxy.h"
- static char REPRESENTED_OBJECT;
- @interface NSMenu (represented)
- @property (strong) id representedObject;
- @end
- @implementation NSMenu (represented)
- - (id) representedObject
- {
- return objc_getAssociatedObject(self, &REPRESENTED_OBJECT);
- }
- - (void) setRepresentedObject:(id)representedObject
- {
- objc_setAssociatedObject(self,
- &REPRESENTED_OBJECT,
- representedObject,
- OBJC_ASSOCIATION_RETAIN);
- }
- @end
- @implementation MenuProxy
- - (id) initWithContext:(JSContextRef)aContext andMenu:(NSMenu*)aMenu
- {
- self = [super initWithContext:aContext];
- if (!self)
- return nil;
- menu = aMenu;
- menu.representedObject = self;
- return self;
- }
- + (MenuProxy*)proxyWithContext:(JSContextRef)aContext andMenu:(NSMenu*)aMenu
- {
- // singleton-ish.
- MenuProxy *ret = [aMenu representedObject];
- if (ret)
- {
- NSLog(@"MP cache hit");
- return ret;
- }
- return [[MenuProxy alloc] initWithContext:aContext andMenu:aMenu];
- }
- - (void) dealloc
- {
- menu.representedObject = nil;
- }
- - (NSString*) description
- {
- return [menu description];
- }
- static BOOL isNullish(id o)
- {
- if (!o)
- return YES;
- if ([o isKindOfClass:[WebUndefined class]])
- return YES;
- return NO;
- }
- - (MenuItemProxy*)addItemWithTitle:(NSString*)title
- keyEquivalent:(NSString*)keyCommand
- callback:(WebScriptObject*)aCallback
- atIndex:(NSInteger)index
- {
- if (isNullish(title))
- title = @"";
-
- NSString *aKey = [MenuProxy getKeyFromString:keyCommand];
- NSMenuItem *item = nil;
-
- if(index) {
- item = [menu insertItemWithTitle:title action:nil keyEquivalent:aKey atIndex:index ];
- } else {
- item = [menu addItemWithTitle:title action:nil keyEquivalent:aKey ];
-
- }
-
- // Set the modifiers.
- NSUInteger modifiers = [MenuProxy getModifiersFromString:keyCommand];
- [item setKeyEquivalentModifierMask:modifiers];
-
- if(!menu.supermenu) {
- NSMenu *s = [[NSMenu alloc] initWithTitle:title];
- [item setSubmenu:s];
- }
-
- MenuItemProxy *mip = [MenuItemProxy proxyWithContext:context andMenuItem:item];
- if (!isNullish(aCallback))
- [mip setCallback:aCallback];
-
-
- return mip;
- }
- + (NSString*)getKeyFromString:(NSString*)keyCommand {
- if (isNullish(keyCommand))
- keyCommand = @"";
- // Obtain the key (if there are modifiers, it will be the last character).
- NSString *aKey = @"";
- if ([keyCommand length] > 0) {
- aKey = [keyCommand substringFromIndex:[keyCommand length] - 1];
- }
- return aKey;
- }
- + (NSUInteger*)getModifiersFromString:(NSString*)keyCommand {
- // aKeys may optionally specify one or more modifiers.
- NSUInteger modifiers = 0;
-
- if ([keyCommand rangeOfString:@"caps"].location != NSNotFound) modifiers += NSAlphaShiftKeyMask;
- if ([keyCommand rangeOfString:@"shift"].location != NSNotFound) modifiers += NSShiftKeyMask;
- if ([keyCommand rangeOfString:@"cmd"].location != NSNotFound) modifiers += NSCommandKeyMask;
- if ([keyCommand rangeOfString:@"ctrl"].location != NSNotFound) modifiers += NSControlKeyMask;
- if ([keyCommand rangeOfString:@"opt"].location != NSNotFound) modifiers += NSAlternateKeyMask;
- if ([keyCommand rangeOfString:@"alt"].location != NSNotFound) modifiers += NSAlternateKeyMask;
- return modifiers;
- }
- - (MenuItemProxy*)addSeparator
- {
- NSMenuItem *sep = [NSMenuItem separatorItem];
- [menu addItem:sep];
- return [MenuItemProxy proxyWithContext:context andMenuItem:sep];
- }
- - (MenuItemProxy*)itemForKey:(id)key
- {
- if (isNullish(key))
- return nil;
- NSMenuItem *item = nil;
- if ([key isKindOfClass:[NSNumber class]])
- {
- item = [menu itemAtIndex:[key intValue]];
- }
- else if ([key isKindOfClass:[NSString class]])
- {
- item = [menu itemWithTitle:key];
- if (!item)
- {
- // Try again, with ... appended. e.g. "Save..."
- item = [menu itemWithTitle:
- [key stringByAppendingString:@"\u2026"]];
- }
- }
- if (!item)
- return nil;
- return [MenuItemProxy proxyWithContext:context andMenuItem:item];
- }
- - (MenuProxy*)removeItem:(id)key
- {
- if (isNullish(key))
- return nil;
-
- NSMenuItem *item = nil;
- if ([key isKindOfClass:[NSNumber class]])
- {
- item = [menu itemAtIndex:[key intValue]];
- }
- else if ([key isKindOfClass:[NSString class]])
- {
- item = [menu itemWithTitle:key];
- if (!item)
- {
- // Try again, with ... appended. e.g. "Save..."
- item = [menu itemWithTitle:
- [key stringByAppendingString:@"\u2026"]];
- }
- }
- if (!item)
- return nil;
-
- [menu removeItem:item];
- return [MenuProxy proxyWithContext:context andMenu:menu];
- }
- + (BOOL) isSelectorExcludedFromWebScript:(SEL)selector
- {
- return [self webScriptNameForSelector:selector] == nil;
- }
- + (BOOL) isKeyExcludedFromWebScript:(const char*)name
- {
- return YES;
- }
- + (NSString*) webScriptNameForSelector:(SEL)selector
- {
- id result = nil;
-
- if (selector == @selector(addItemWithTitle:keyEquivalent:callback:atIndex:)) {
- result = @"addItem";
- }
- else if (selector == @selector(addSeparator)) {
- result = @"addSeparator";
- }
- else if (selector == @selector(itemForKey:)) {
- result = @"getItem";
- }
- else if (selector == @selector(removeItem:)) {
- result = @"removeMenu";
- }
-
- return result;
- }
- @end
|