blob: 9b9f01755d58b50a3377931f916d38828040d317 (
plain)
| 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
 | #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:[self encodeBindingName: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
{
    [_actions setObject:[action copy] forKey:defaultsKeyName];
    [self bind:[self encodeBindingName: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:[self encodeBindingName: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
static NSString *const MASDotSymbolReplacement = @"__dot__";
- (NSString*) encodeBindingName: (NSString*) binding
{
    return [binding stringByReplacingOccurrencesOfString:@"." withString:MASDotSymbolReplacement];
}
- (NSString*) decodeBindingName: (NSString*) binding
{
    return [binding stringByReplacingOccurrencesOfString:MASDotSymbolReplacement withString:@"."];
}
- (BOOL) isRegisteredAction: (NSString*) name
{
    return !![_actions objectForKey:name];
}
- (id) valueForUndefinedKey: (NSString*) key
{
    key = [self decodeBindingName:key];
    return [self isRegisteredAction:key] ?
        [_shortcuts objectForKey:key] :
        [super valueForUndefinedKey:key];
}
- (void) setValue: (id) value forUndefinedKey: (NSString*) key
{
    key = [self decodeBindingName: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) {
        return;
    }
    // Bind new shortcut
    [_shortcuts setObject:newShortcut forKey:key];
    [_shortcutMonitor registerShortcut:newShortcut withAction:[_actions objectForKey:key]];
}
@end
 |