EEAA9CE116E808E600256B64 /* NSMutableArray+MoveObject.m in Sources */ = {isa = PBXBuildFile; fileRef = EEAA9CE016E808E600256B64 /* NSMutableArray+MoveObject.m */; };
EEAA9CE416E816C800256B64 /* NSFileManager+UniqueNames.m in Sources */ = {isa = PBXBuildFile; fileRef = EEAA9CE316E816C800256B64 /* NSFileManager+UniqueNames.m */; };
EEAA9CE716E81C8400256B64 /* NSString+FixFilename.m in Sources */ = {isa = PBXBuildFile; fileRef = EEAA9CE616E81C8400256B64 /* NSString+FixFilename.m */; };
+ EEDFE52816E8957200CD27E0 /* com.yukkurigames.Enjoyable.mapping.icns in Resources */ = {isa = PBXBuildFile; fileRef = EEDFE52716E8957200CD27E0 /* com.yukkurigames.Enjoyable.mapping.icns */; };
/* End PBXBuildFile section */
/* Begin PBXFileReference section */
EEAA9CE316E816C800256B64 /* NSFileManager+UniqueNames.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSFileManager+UniqueNames.m"; sourceTree = "<group>"; };
EEAA9CE516E81C8400256B64 /* NSString+FixFilename.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSString+FixFilename.h"; sourceTree = "<group>"; };
EEAA9CE616E81C8400256B64 /* NSString+FixFilename.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSString+FixFilename.m"; sourceTree = "<group>"; };
+ EEDFE52716E8957200CD27E0 /* com.yukkurigames.Enjoyable.mapping.icns */ = {isa = PBXFileReference; lastKnownFileType = image.icns; path = com.yukkurigames.Enjoyable.mapping.icns; sourceTree = "<group>"; };
EEF86B7316E2241000674B87 /* NJInputPathElement.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = NJInputPathElement.h; sourceTree = "<group>"; };
EEF86B7416E298CD00674B87 /* NJEvents.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = NJEvents.h; sourceTree = "<group>"; };
/* End PBXFileReference section */
29B97317FDCFA39411CA2CEA /* Resources */ = {
isa = PBXGroup;
children = (
+ EEDFE52716E8957200CD27E0 /* com.yukkurigames.Enjoyable.mapping.icns */,
EE03150C16E63481002B2DCE /* Help */,
D5617A080FAEAF8300928B3A /* icon.icns */,
8D1107310486CEB800E47090 /* Info.plist */,
1DDD58160DA1D0A300B32029 /* MainMenu.xib in Resources */,
D5F80A9D0FB0A2FF0006A4DE /* icon.icns in Resources */,
EE03150D16E63481002B2DCE /* Help in Resources */,
+ EEDFE52816E8957200CD27E0 /* com.yukkurigames.Enjoyable.mapping.icns in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
+ <key>UTExportedTypeDeclarations</key>
+ <array>
+ <dict>
+ <key>UTTypeIconFile</key>
+ <string>com.yukkurigames.Enjoyable.mapping.icns</string>
+ <key>UTTypeDescription</key>
+ <string>Enjoyable Mapping</string>
+ <key>UTTypeConformsTo</key>
+ <array>
+ <string>public.data</string>
+ </array>
+ <key>UTTypeIdentifier</key>
+ <string>com.yukkurigames.Enjoyable.mapping</string>
+ <key>UTTypeTagSpecification</key>
+ <dict>
+ <key>public.filename-extension</key>
+ <array>
+ <string>enjoyable</string>
+ </array>
+ <key>public.mime-type</key>
+ <string>application/json</string>
+ </dict>
+ </dict>
+ </array>
+ <key>CFBundleDocumentTypes</key>
+ <array>
+ <dict>
+ <key>CFBundleTypeIconFile</key>
+ <string>com.yukkurigames.Enjoyable.mapping.icns</string>
+ <key>CFBundleTypeExtensions</key>
+ <array>
+ <string>enjoyable</string>
+ </array>
+ <key>CFBundleTypeRole</key>
+ <string>Editor</string>
+ <key>LSItemContentTypes</key>
+ <array>
+ <string>com.yukkurigames.Enjoyable.mapping</string>
+ </array>
+ <key>CFBundleTypeName</key>
+ <string>com.yukkurigames.Enjoyable.mapping</string>
+ <key>LSHandlerRank</key>
+ <string>Owner</string>
+ </dict>
+ </array>
<key>CFBundleDevelopmentRegion</key>
<string>English</string>
<key>CFBundleExecutable</key>
#import "NJMapping.h"
#import "NJInput.h"
+#import "NJOutput.h"
@implementation NJMapping
return success;
}
++ (id)mappingWithContentsOfURL:(NSURL *)url mappings:(NSArray *)mappings error:(NSError **)error {
+ NSInputStream *stream = [NSInputStream inputStreamWithURL:url];
+ [stream open];
+ NSDictionary *serialization = stream && !*error
+ ? [NSJSONSerialization JSONObjectWithStream:stream options:0 error:error]
+ : nil;
+ [stream close];
+
+ if (!serialization && error)
+ return nil;
+
+ if (!([serialization isKindOfClass:NSDictionary.class]
+ && [serialization[@"name"] isKindOfClass:NSString.class]
+ && [serialization[@"entries"] isKindOfClass:NSDictionary.class])) {
+ *error = [NSError errorWithDomain:@"Enjoyable"
+ code:0
+ description:@"This isn't a valid mapping file."];
+ 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;
+}
+
@end
}
- (void)awakeFromNib {
- [tableView registerForDraggedTypes:@[PB_ROW]];
- [tableView setDraggingSourceOperationMask:NSDragOperationCopy forLocal:NO];
+ [tableView registerForDraggedTypes:@[PB_ROW, NSURLPboardType]];
+ [tableView setDraggingSourceOperationMask:NSDragOperationCopy forLocal:NO];
}
- (NJMapping *)objectForKeyedSubscript:(NSString *)name {
return mapping;
}
+- (void)addMappingWithContentsOfURL:(NSURL *)url {
+ NSWindow *window = popoverActivate.window;
+ NSError *error;
+ NJMapping *mapping = [NJMapping mappingWithContentsOfURL:url
+ mappings:_mappings
+ error:&error];
+
+ if (mapping && !error) {
+ BOOL conflict = NO;
+ NJMapping *mergeInto = self[mapping.name];
+ for (id key in mapping.entries) {
+ if (mergeInto.entries[key]
+ && ![mergeInto.entries[key] isEqual:mapping.entries[key]]) {
+ conflict = YES;
+ break;
+ }
+ }
+
+ if (conflict) {
+ NSAlert *conflictAlert = [[NSAlert alloc] init];
+ conflictAlert.messageText = @"Replace existing mappings?";
+ conflictAlert.informativeText =
+ [NSString stringWithFormat:
+ @"This file contains inputs you've already mapped in \"%@\". Do you "
+ @"want to merge them and replace your existing mappings, or import this "
+ @"as a separate mapping?", mapping.name];
+ [conflictAlert addButtonWithTitle:@"Merge"];
+ [conflictAlert addButtonWithTitle:@"Cancel"];
+ [conflictAlert addButtonWithTitle:@"New Mapping"];
+ NSInteger res = [conflictAlert runModal];
+ if (res == NSAlertSecondButtonReturn)
+ return;
+ else if (res == NSAlertThirdButtonReturn)
+ mergeInto = nil;
+ }
+
+ if (mergeInto) {
+ [mergeInto.entries addEntriesFromDictionary:mapping.entries];
+ mapping = mergeInto;
+ } else {
+ [_mappings addObject:mapping];
+ }
+
+ [self activateMapping:mapping];
+ [self mappingsChanged];
+
+ if (conflict && !mergeInto) {
+ [tableView selectRowIndexes:[NSIndexSet indexSetWithIndex:_mappings.count - 1] byExtendingSelection:NO];
+ [tableView editColumn:0 row:_mappings.count - 1 withEvent:nil select:YES];
+ }
+ }
+
+ if (error) {
+ [window presentError:error
+ modalForWindow:window
+ delegate:nil
+ didPresentSelector:nil
+ contextInfo:nil];
+ }
+}
+
- (void)importPressed:(id)sender {
NSOpenPanel *panel = [NSOpenPanel openPanel];
panel.allowedFileTypes = @[ @"enjoyable", @"json", @"txt" ];
completionHandler:^(NSInteger result) {
if (result != NSFileHandlingPanelOKButton)
return;
-
[panel close];
- NSError *error;
- NJMapping *mapping = [self mappingWithURL:panel.URL error:&error];
-
- if (!error) {
- BOOL conflict = NO;
- NJMapping *mergeInto = self[mapping.name];
- for (id key in mapping.entries) {
- if (mergeInto.entries[key]
- && ![mergeInto.entries[key] isEqual:mapping.entries[key]]) {
- conflict = YES;
- break;
- }
- }
-
- if (conflict) {
- NSAlert *conflictAlert = [[NSAlert alloc] init];
- conflictAlert.messageText = @"Replace existing mappings?";
- conflictAlert.informativeText =
- [NSString stringWithFormat:
- @"This file contains inputs you've already mapped in \"%@\". Do you "
- @"want to merge them and replace your existing mappings, or import this "
- @"as a separate mapping?", mapping.name];
- [conflictAlert addButtonWithTitle:@"Merge"];
- [conflictAlert addButtonWithTitle:@"Cancel"];
- [conflictAlert addButtonWithTitle:@"New Mapping"];
- NSInteger res = [conflictAlert runModal];
- if (res == NSAlertSecondButtonReturn)
- return;
- else if (res == NSAlertThirdButtonReturn)
- mergeInto = nil;
- }
-
- if (mergeInto) {
- [mergeInto.entries addEntriesFromDictionary:mapping.entries];
- mapping = mergeInto;
- } else {
- [_mappings addObject:mapping];
- }
-
- [self activateMapping:mapping];
- [self mappingsChanged];
-
- if (conflict && !mergeInto) {
- [tableView selectRowIndexes:[NSIndexSet indexSetWithIndex:_mappings.count - 1] byExtendingSelection:NO];
- [tableView editColumn:0 row:_mappings.count - 1 withEvent:nil select:YES];
- }
- }
-
- if (error) {
- [window presentError:error
- modalForWindow:window
- delegate:nil
- didPresentSelector:nil
- contextInfo:nil];
- }
+ [self addMappingWithContentsOfURL:panel.URL];
}];
-
+
}
- (void)exportPressed:(id)sender {
}
}
-- (BOOL)tableView:(NSTableView *)tableView
+- (BOOL)tableView:(NSTableView *)tableView_
acceptDrop:(id <NSDraggingInfo>)info
row:(NSInteger)row
dropOperation:(NSTableViewDropOperation)dropOperation {
[_mappings moveObjectAtIndex:srcRow toIndex:row];
[self mappingsChanged];
return YES;
+ } else if ([pboard.types containsObject:NSURLPboardType]) {
+ NSURL *url = [NSURL URLFromPasteboard:pboard];
+ NSError *error;
+ NJMapping *mapping = [NJMapping mappingWithContentsOfURL:url
+ mappings:_mappings
+ error:&error];
+ if (error) {
+ [tableView_ presentError:error];
+ return NO;
+ } else {
+ [_mappings insertObject:mapping atIndex:row];
+ [self mappingsChanged];
+ return YES;
+ }
} else {
return NO;
}
NSPasteboard *pboard = [info draggingPasteboard];
if ([pboard.types containsObject:PB_ROW]) {
[tableView_ setDropRow:MAX(1, row) dropOperation:NSTableViewDropAbove];
- return NSDragOperationGeneric;
+ return NSDragOperationMove;
+ } else if ([pboard.types containsObject:NSURLPboardType]) {
+ NSURL *url = [NSURL URLFromPasteboard:pboard];
+ if ([url.pathExtension isEqualToString:@"enjoyable"]) {
+ [tableView_ setDropRow:MAX(1, row) dropOperation:NSTableViewDropAbove];
+ return NSDragOperationCopy;
+ } else {
+ return NSDragOperationNone;
+ }
} else {
return NSDragOperationNone;
}