Localization support. Change many names in NJKeyInputField to standard keyboard short...
[enjoyable.git] / Classes / NJMapping.m
index 8cc5724..0e67cd3 100644 (file)
 #import "NJInput.h"
 #import "NJOutput.h"
 
-@implementation NJMapping
+@implementation NJMapping {
+    NSMutableDictionary *_entries;
+}
 
-- (id)initWithName:(NSString *)name {
+// Extra checks during initialization because the data is often loaded
+// from untrusted serializations.
+
+- (id)init {
     if ((self = [super init])) {
-        self.name = name ? name : @"Untitled";
+        self.name = NSLocalizedString(@"Untitled", @"name for new mappings");
         _entries = [[NSMutableDictionary alloc] init];
     }
     return self;
 }
 
+- (id)initWithName:(NSString *)name {
+    if ((self = [self init])) {
+        if ([name isKindOfClass:NSString.class])
+            self.name = name;
+    }
+    return self;
+}
+
+- (id)initWithSerialization:(NSDictionary *)serialization
+                   mappings:(NSArray *)mappings {
+    if ((self = [self initWithName:serialization[@"name"]])) {
+        NSDictionary *entries = serialization[@"entries"];
+        if ([entries isKindOfClass:NSDictionary.class]) {
+            for (id key in entries) {
+                if ([key isKindOfClass:NSString.class]) {
+                    NJOutput *output = [NJOutput outputDeserialize:entries[key]
+                                                      withMappings:mappings];
+                    if (output)
+                        _entries[key] = output;
+                }
+            }
+        }
+    }
+    return self;
+}
+
 - (NJOutput *)objectForKeyedSubscript:(NJInput *)input {
     return input ? _entries[input.uid] : nil;
 }
     return success;
 }
 
+- (NSUInteger)count {
+    return _entries.count;
+}
+
+- (BOOL)hasConflictWith:(NJMapping *)other {
+    if (other.count < self.count)
+        return [other hasConflictWith:self];
+    for (NSString *uid in _entries) {
+        NJOutput *output = other->_entries[uid];
+        if (output && ![output isEqual:_entries[uid]])
+            return YES;
+    }
+    return NO;
+}
+
 + (id)mappingWithContentsOfURL:(NSURL *)url mappings:(NSArray *)mappings error:(NSError **)error {
     NSInputStream *stream = [NSInputStream inputStreamWithURL:url];
     [stream open];
           && [serialization[@"entries"] isKindOfClass:NSDictionary.class])) {
         *error = [NSError errorWithDomain:@"Enjoyable"
                                      code:0
-                              description:@"This isn't a valid mapping file."];
+                              description:NSLocalizedString(@"invalid mapping file",
+                                                            @"error when imported file was JSON but not a mapping")];
         return nil;
     }
     
-    NSDictionary *entries = serialization[@"entries"];
-    NJMapping *mapping = [[NJMapping alloc] initWithName:serialization[@"name"]];
-    for (id key in entries) {
-        NSDictionary *value = entries[key];
-        if ([key isKindOfClass:NSString.class]) {
-            NJOutput *output = [NJOutput outputDeserialize:value
-                                              withMappings:mappings];
-            if (output)
-                mapping.entries[key] = output;
-        }
-    }
-    return mapping;
+    return [[NJMapping alloc] initWithSerialization:serialization
+                                           mappings:mappings];
+}
+
+- (void)mergeEntriesFrom:(NJMapping *)other {
+    if (other)
+        [_entries addEntriesFromDictionary:other->_entries];
 }
 
 @end