122 lines
3.7 KiB
Mathematica
122 lines
3.7 KiB
Mathematica
![]() |
#import "MASShortcutBinder.h"
|
|||
|
#import "MASShortcut.h"
|
|||
|
|
|||
|
@interface MASShortcutBinder ()
|
|||
|
@property(strong) NSMutableDictionary *actions;
|
|||
|
@property(strong) NSMutableDictionary *shortcuts;
|
|||
|
@end
|
|||
|
|
|||
|
@implementation MASShortcutBinder
|
|||
|
|
|||
|
#pragma mark Initialization
|
|||
|
|
|||
|
- (id) init
|
|||
|
{
|
|||
|
self = [super init];
|
|||
|
[self setActions:[NSMutableDictionary dictionary]];
|
|||
|
[self setShortcuts:[NSMutableDictionary dictionary]];
|
|||
|
[self setShortcutMonitor:[MASShortcutMonitor sharedMonitor]];
|
|||
|
[self setBindingOptions:@{NSValueTransformerNameBindingOption: NSKeyedUnarchiveFromDataTransformerName}];
|
|||
|
return self;
|
|||
|
}
|
|||
|
|
|||
|
- (void) dealloc
|
|||
|
{
|
|||
|
for (NSString *bindingName in [_actions allKeys]) {
|
|||
|
[self unbind:bindingName];
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
+ (instancetype) sharedBinder
|
|||
|
{
|
|||
|
static dispatch_once_t once;
|
|||
|
static MASShortcutBinder *sharedInstance;
|
|||
|
dispatch_once(&once, ^{
|
|||
|
sharedInstance = [[self alloc] init];
|
|||
|
});
|
|||
|
return sharedInstance;
|
|||
|
}
|
|||
|
|
|||
|
#pragma mark Registration
|
|||
|
|
|||
|
- (void) bindShortcutWithDefaultsKey: (NSString*) defaultsKeyName toAction: (dispatch_block_t) action
|
|||
|
{
|
|||
|
NSAssert([defaultsKeyName rangeOfString:@"."].location == NSNotFound,
|
|||
|
@"Illegal character in binding name (“.”), please see http://git.io/x5YS.");
|
|||
|
NSAssert([defaultsKeyName rangeOfString:@" "].location == NSNotFound,
|
|||
|
@"Illegal character in binding name (“ ”), please see http://git.io/x5YS.");
|
|||
|
[_actions setObject:[action copy] forKey:defaultsKeyName];
|
|||
|
[self bind:defaultsKeyName
|
|||
|
toObject:[NSUserDefaultsController sharedUserDefaultsController]
|
|||
|
withKeyPath:[@"values." stringByAppendingString:defaultsKeyName]
|
|||
|
options:_bindingOptions];
|
|||
|
}
|
|||
|
|
|||
|
- (void) breakBindingWithDefaultsKey: (NSString*) defaultsKeyName
|
|||
|
{
|
|||
|
[_shortcutMonitor unregisterShortcut:[_shortcuts objectForKey:defaultsKeyName]];
|
|||
|
[_shortcuts removeObjectForKey:defaultsKeyName];
|
|||
|
[_actions removeObjectForKey:defaultsKeyName];
|
|||
|
[self unbind:defaultsKeyName];
|
|||
|
}
|
|||
|
|
|||
|
- (void) registerDefaultShortcuts: (NSDictionary*) defaultShortcuts
|
|||
|
{
|
|||
|
NSValueTransformer *transformer = [_bindingOptions valueForKey:NSValueTransformerBindingOption];
|
|||
|
if (transformer == nil) {
|
|||
|
NSString *transformerName = [_bindingOptions valueForKey:NSValueTransformerNameBindingOption];
|
|||
|
if (transformerName) {
|
|||
|
transformer = [NSValueTransformer valueTransformerForName:transformerName];
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
NSAssert(transformer != nil, @"Can’t register default shortcuts without a transformer.");
|
|||
|
|
|||
|
[defaultShortcuts enumerateKeysAndObjectsUsingBlock:^(NSString *defaultsKey, MASShortcut *shortcut, BOOL *stop) {
|
|||
|
id value = [transformer reverseTransformedValue:shortcut];
|
|||
|
[[NSUserDefaults standardUserDefaults] registerDefaults:@{defaultsKey:value}];
|
|||
|
}];
|
|||
|
}
|
|||
|
|
|||
|
#pragma mark Bindings
|
|||
|
|
|||
|
- (BOOL) isRegisteredAction: (NSString*) name
|
|||
|
{
|
|||
|
return !![_actions objectForKey:name];
|
|||
|
}
|
|||
|
|
|||
|
- (id) valueForUndefinedKey: (NSString*) key
|
|||
|
{
|
|||
|
return [self isRegisteredAction:key] ?
|
|||
|
[_shortcuts objectForKey:key] :
|
|||
|
[super valueForUndefinedKey:key];
|
|||
|
}
|
|||
|
|
|||
|
- (void) setValue: (id) value forUndefinedKey: (NSString*) key
|
|||
|
{
|
|||
|
if (![self isRegisteredAction:key]) {
|
|||
|
[super setValue:value forUndefinedKey:key];
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
MASShortcut *newShortcut = value;
|
|||
|
MASShortcut *currentShortcut = [_shortcuts objectForKey:key];
|
|||
|
|
|||
|
// Unbind previous shortcut if any
|
|||
|
if (currentShortcut != nil) {
|
|||
|
[_shortcutMonitor unregisterShortcut:currentShortcut];
|
|||
|
}
|
|||
|
|
|||
|
// Just deleting the old shortcut
|
|||
|
if (newShortcut == nil) {
|
|||
|
[_shortcuts removeObjectForKey:key];
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
// Bind new shortcut
|
|||
|
[_shortcuts setObject:newShortcut forKey:key];
|
|||
|
[_shortcutMonitor registerShortcut:newShortcut withAction:[_actions objectForKey:key]];
|
|||
|
}
|
|||
|
|
|||
|
@end
|