Split NJMappingController view handling off into NJMappingViewController. This is...
authorJoe Wreschnig <joe.wreschnig@gmail.com>
Sun, 17 Mar 2013 17:06:08 +0000 (18:06 +0100)
committerJoe Wreschnig <joe.wreschnig@gmail.com>
Sun, 17 Mar 2013 17:06:08 +0000 (18:06 +0100)
24 files changed:
Categories/NSMutableArray+MoveObject.h
Categories/NSMutableArray+MoveObject.m
Classes/EnjoyableApplicationDelegate.h
Classes/EnjoyableApplicationDelegate.m
Classes/NJDeviceController.h
Classes/NJDeviceController.m
Classes/NJDeviceViewController.h
Classes/NJDeviceViewController.m
Classes/NJMapping.h
Classes/NJMapping.m
Classes/NJMappingsController.h
Classes/NJMappingsController.m
Classes/NJMappingsViewController.h [new file with mode: 0644]
Classes/NJMappingsViewController.m [new file with mode: 0644]
Classes/NJOutput.h
Classes/NJOutput.m
Classes/NJOutputKeyPress.m
Classes/NJOutputMapping.m
Classes/NJOutputMouseButton.m
Classes/NJOutputMouseMove.m
Classes/NJOutputMouseScroll.m
Enjoyable.xcodeproj/project.pbxproj
Info.plist
Resources/English.lproj/MainMenu.xib

index ce62234..e8ac0b0 100644 (file)
 @interface NSMutableArray (MoveObject)
 
 - (void)moveObjectAtIndex:(NSUInteger)src toIndex:(NSUInteger)dst;
-    // Move the object at index src to (pre-move) index dst. Other
+    // Move the object at index src to (post-move) index dst. Other
     // objects shift up or down as necessary to make room, as in
-    // insertObject:atIndex:. Because the object is also removed from
-    // the source index, its resulting index may be one less than dst.
+    // insertObject:atIndex:.
 
 - (BOOL)moveFirstwards:(id)object upTo:(NSUInteger)minIndex;
 - (BOOL)moveLastwards:(id)object upTo:(NSUInteger)maxIndex;
index 6c7987e..a02b98b 100644 (file)
@@ -13,7 +13,7 @@
 - (void)moveObjectAtIndex:(NSUInteger)src toIndex:(NSUInteger)dst {
     id obj = self[src];
     [self removeObjectAtIndex:src];
-    [self insertObject:obj atIndex:dst > src ? dst - 1 : dst];
+    [self insertObject:obj atIndex:dst];
 }
 
 - (BOOL)moveFirstwards:(id)object upTo:(NSUInteger)minIndex {
index acea8a9..b28269b 100644 (file)
@@ -21,5 +21,7 @@
 @property (nonatomic, strong) IBOutlet NJMappingsController *mappingsController;
 
 - (IBAction)restoreToForeground:(id)sender;
+- (IBAction)importMappingClicked:(id)sender;
+- (IBAction)exportMappingClicked:(id)sender;
 
 @end
index db62f53..fe781ef 100644 (file)
 
 - (BOOL)application:(NSApplication *)sender openFile:(NSString *)filename {
     [self restoreToForeground:sender];
-    NSURL *url = [NSURL fileURLWithPath:filename];
-    [self.mappingsController addMappingWithContentsOfURL:url];
-    return YES;
+    NSError *error;
+    NSURL *URL = [NSURL fileURLWithPath:filename];
+    NJMapping *mapping = [NJMapping mappingWithContentsOfURL:URL
+                                                    mappings:self.mappingsController
+                                                       error:&error];
+    if (mapping) {
+        [self.mappingsController addOrMergeMapping:mapping];
+        return YES;
+    } else {
+        [window presentError:error
+              modalForWindow:window
+                    delegate:nil
+          didPresentSelector:nil
+                 contextInfo:nil];
+        return NO;
+    }
 }
 
 - (void)mappingWasChosen:(NJMapping *)mapping {
 
 - (void)mappingListShouldOpen {
     [self restoreToForeground:self];
-    [self.mappingsController mappingPressed:self];
+    [self.mappingsController.mvc mappingTriggerClicked:self];
 }
 
 - (void)loginItemPromptDidEnd:(NSWindow *)sheet
     return NO;
 }
 
+- (void)importMappingClicked:(id)sender {
+    NSOpenPanel *panel = [NSOpenPanel openPanel];
+    panel.allowedFileTypes = @[ @"enjoyable", @"json", @"txt" ];
+    [panel beginSheetModalForWindow:window
+                  completionHandler:^(NSInteger result) {
+                      if (result != NSFileHandlingPanelOKButton)
+                          return;
+                      [panel close];
+                      NSError *error;
+                      NJMapping *mapping = [NJMapping mappingWithContentsOfURL:panel.URL
+                                                                      mappings:self.mappingsController
+                                                                         error:&error];
+                      if (mapping) {
+                          [self.mappingsController addOrMergeMapping:mapping];
+                      } else {
+                          [window presentError:error
+                                modalForWindow:window
+                                      delegate:nil
+                            didPresentSelector:nil
+                                   contextInfo:nil];
+                      }
+                  }];
+    
+}
+
+- (void)exportMappingClicked:(id)sender {
+    NSSavePanel *panel = [NSSavePanel savePanel];
+    panel.allowedFileTypes = @[ @"enjoyable" ];
+    NJMapping *mapping = self.mappingsController.currentMapping;
+    panel.nameFieldStringValue = [mapping.name stringByFixingPathComponent];
+    [panel beginSheetModalForWindow:window
+                  completionHandler:^(NSInteger result) {
+                      if (result != NSFileHandlingPanelOKButton)
+                          return;
+                      [panel close];
+                      NSError *error;
+                      if (![mapping writeToURL:panel.URL error:&error]) {
+                          [window presentError:error
+                                modalForWindow:window
+                                      delegate:nil
+                            didPresentSelector:nil
+                                   contextInfo:nil];
+                      }
+                  }];
+}
+
+
 
 @end
index fcc09ef..29b8b38 100644 (file)
@@ -9,11 +9,9 @@
 #import "NJHIDManager.h"
 #import "NJDeviceViewController.h"
 
-@class NJDevice;
 @class NJInput;
 @class NJMappingsController;
 @class NJOutputController;
-@class NJDeviceViewController;
 
 @interface NJDeviceController : NSObject <NJDeviceViewControllerDelegate,
                                           NJHIDManagerDelegate> {
index b0e8de3..329b353 100644 (file)
     [_continuousOutputsTick invalidate];
 }
 
-- (id)elementForUID:(NSString *)uid {
-    for (NJDevice *dev in _devices) {
-        id item = [dev elementForUID:uid];
-        if (item)
-            return item;
-    }
-    return nil;
-}
-
 - (void)addRunningOutput:(NJOutput *)output {
     // Axis events will trigger every small movement, don't keep
     // re-adding them or they trigger multiple times each time.
     self.simulatingEvents = sender.state == NSOnState;
 }
 
-- (void)deviceViewControllerDidSelectNothing:(NJDeviceViewController *)devices {
+- (NSInteger)numberOfDevicesInDeviceList:(NJDeviceViewController *)dvc {
+    return _devices.count;
+}
+
+- (NJDevice *)deviceViewController:(NJDeviceViewController *)dvc
+                    deviceForIndex:(NSUInteger)idx {
+    return _devices[idx];
+}
+
+- (id)deviceViewController:(NJDeviceViewController *)dvc
+             elementForUID:(NSString *)uid {
+    for (NJDevice *dev in _devices) {
+        id item = [dev elementForUID:uid];
+        if (item)
+            return item;
+    }
+    return nil;
+}
+
+- (void)deviceViewControllerDidSelectNothing:(NJDeviceViewController *)dvc {
     [outputController loadCurrent];
 }
 
-- (void)deviceViewController:(NJDeviceViewController *)devices
+- (void)deviceViewController:(NJDeviceViewController *)dvc
              didSelectBranch:(NJInputPathElement *)handler {
     [outputController loadCurrent];
 }
 
-- (void)deviceViewController:(NJDeviceViewController *)devices
+- (void)deviceViewController:(NJDeviceViewController *)dvc
             didSelectHandler:(NJInputPathElement *)handler {
     [outputController loadCurrent];
 }
 
-- (void)deviceViewController:(NJDeviceViewController *)devices
+- (void)deviceViewController:(NJDeviceViewController *)dvc
              didSelectDevice:(NJInputPathElement *)device {
     [outputController loadCurrent];
 }
index 9e1a43f..6d039af 100644 (file)
@@ -20,9 +20,6 @@
 
 @property (nonatomic, weak) IBOutlet id <NJDeviceViewControllerDelegate> delegate;
 
-@property (nonatomic, copy) NSArray *devices;
-    // Assigning directly will trigger a full reload.
-
 - (void)addedDevice:(NJDevice *)device atIndex:(NSUInteger)idx;
 - (void)removedDevice:(NJDevice *)device atIndex:(NSUInteger)idx;
     // But using these will animate nicely.
 
 @protocol NJDeviceViewControllerDelegate <NSObject>
 
-- (void)deviceViewController:(NJDeviceViewController *)devices
+- (NSInteger)numberOfDevicesInDeviceList:(NJDeviceViewController *)dvc;
+- (NJDevice *)deviceViewController:(NJDeviceViewController *)dvc
+                    deviceForIndex:(NSUInteger)idx;
+- (NJInputPathElement *)deviceViewController:(NJDeviceViewController *)dvc
+                               elementForUID:(NSString *)uid;
+
+
+- (void)deviceViewController:(NJDeviceViewController *)dvc
              didSelectDevice:(NJInputPathElement *)device;
-- (void)deviceViewController:(NJDeviceViewController *)devices
+- (void)deviceViewController:(NJDeviceViewController *)dvc
              didSelectBranch:(NJInputPathElement *)handler;
-- (void)deviceViewController:(NJDeviceViewController *)devices
+- (void)deviceViewController:(NJDeviceViewController *)dvc
             didSelectHandler:(NJInputPathElement *)handler;
-- (void)deviceViewControllerDidSelectNothing:(NJDeviceViewController *)devices;
+- (void)deviceViewControllerDidSelectNothing:(NJDeviceViewController *)dvc;
 
 @end
index 3d20e65..dfb2dca 100644 (file)
@@ -11,7 +11,6 @@
 #import "NJInputPathElement.h"
 
 @implementation NJDeviceViewController {
-    NSMutableArray *_devices;
     NSMutableArray *_expanded;
 }
 
@@ -22,7 +21,6 @@
             expanded = @[];
         _expanded = [[NSMutableArray alloc] initWithCapacity:MAX(16, _expanded.count)];
         [_expanded addObjectsFromArray:expanded];
-        _devices = [[NSMutableArray alloc] initWithCapacity:16];
     }
     return self;
 }
     }
 }
 
-- (id)elementForUID:(NSString *)uid {
-    for (NJInputPathElement *dev in _devices) {
-        id item = [dev elementForUID:uid];
-        if (item)
-            return item;
-    }
-    return nil;
-}
-
 - (void)expandRecursiveByUID:(NSString *)uid {
-    [self expandRecursive:[self elementForUID:uid]];
+    [self expandRecursive:[self.delegate deviceViewController:self elementForUID:uid]];
 }
 
 - (void)reexpandAll {
         [self expandRecursiveByUID:uid];
     if (self.inputsTree.selectedRow == -1) {
         NSString *selectedUid = [NSUserDefaults.standardUserDefaults objectForKey:@"selected input"];
-        id item = [self elementForUID:selectedUid];
+        id item = [self.delegate deviceViewController:self elementForUID:selectedUid];
         [self.inputsTree selectItem:item];
     }
 }
 
-- (void)setDevices:(NSArray *)devices {
-    _devices = [devices mutableCopy];
-    id item = self.inputsTree.selectedItem;
-    [self.inputsTree selectItem:nil];
-    [self.inputsTree reloadData];
-    [self reexpandAll];
-    [self.inputsTree selectItem:item];
-    self.noDevicesNotice.hidden = self.devices.count || !self.hidStoppedNotice.isHidden;
-}
-
 - (void)addedDevice:(NJDevice *)device atIndex:(NSUInteger)idx {
-    [_devices insertObject:device atIndex:idx];
     [self.inputsTree beginUpdates];
     [self.inputsTree insertItemsAtIndexes:[[NSIndexSet alloc] initWithIndex:idx]
                                   inParent:nil
 }
 
 - (void)removedDevice:(NJDevice *)device atIndex:(NSUInteger)idx {
-    [_devices removeObjectAtIndex:idx];
+    BOOL anyDevices = !![self.delegate numberOfDevicesInDeviceList:self];
     [self.inputsTree beginUpdates];
     [self.inputsTree removeItemsAtIndexes:[[NSIndexSet alloc] initWithIndex:idx]
                                   inParent:nil
                              withAnimation:NSTableViewAnimationSlideLeft];
     [self.inputsTree endUpdates];
-    self.noDevicesNotice.hidden = self.devices.count || !self.hidStoppedNotice.isHidden;
+    self.noDevicesNotice.hidden = anyDevices || !self.hidStoppedNotice.isHidden;
 }
 
 - (void)hidStarted {
-    self.noDevicesNotice.hidden = !!self.devices.count;
+    self.noDevicesNotice.hidden = !![self.delegate numberOfDevicesInDeviceList:self];
     self.hidStoppedNotice.hidden = YES;
 }
 
 - (void)hidStopped {
+    self.noDevicesNotice.hidden = YES;
     self.hidStoppedNotice.hidden = NO;
-    self.devices = @[];
+    [self.inputsTree reloadData];
 }
 
 - (void)expandAndSelectItem:(NJInputPathElement *)item {
 
 - (NSInteger)outlineView:(NSOutlineView *)outlineView
   numberOfChildrenOfItem:(NJInputPathElement *)item {
-    return item ? item.children.count : _devices.count;
+    if (item)
+        return item.children.count;
+    else
+        return [self.delegate numberOfDevicesInDeviceList:self];
+
 }
 
 - (BOOL)outlineView:(NSOutlineView *)outlineView
    isItemExpandable:(NJInputPathElement *)item {
-    return item ? [[item children] count] > 0: YES;
+    return item ? item.children.count > 0: YES;
 }
 
 - (id)outlineView:(NSOutlineView *)outlineView
             child:(NSInteger)index
            ofItem:(NJInputPathElement *)item {
-    return item ? item.children[index] : _devices[index];
+    if (item)
+        return item.children[index];
+    else
+        return [self.delegate deviceViewController:self deviceForIndex:index];
 }
 
 - (id)outlineView:(NSOutlineView *)outlineView
@@ -152,13 +138,15 @@ objectValueForTableColumn:(NSTableColumn *)tableColumn
 
 - (void)outlineViewItemDidExpand:(NSNotification *)notification {
     NSString *uid = [notification.userInfo[@"NSObject"] uid];
-    if (![_expanded containsObject:uid])
+    if (![_expanded containsObject:uid]) {
         [_expanded addObject:uid];
-
+        [NSUserDefaults.standardUserDefaults setObject:_expanded forKey:@"expanded rows"];
+    }
 }
 
 - (void)outlineViewItemDidCollapse:(NSNotification *)notification {
     [_expanded removeObject:[notification.userInfo[@"NSObject"] uid]];
+    [NSUserDefaults.standardUserDefaults setObject:_expanded forKey:@"expanded rows"];
 }
 
 - (BOOL)outlineView:(NSOutlineView *)outlineView
index 8b80012..0d5db89 100644 (file)
 @property (nonatomic, readonly) NSUInteger count;
 
 + (id)mappingWithContentsOfURL:(NSURL *)url
-                      mappings:(NSArray *)mappings
+                      mappings:(id <NSFastEnumeration>)mappings
                          error:(NSError **)error;
 
 - (id)initWithName:(NSString *)name;
 - (id)initWithSerialization:(NSDictionary *)serialization
-                   mappings:(NSArray *)mappings;
+                   mappings:(id <NSFastEnumeration>)mappings;
 
 - (NJOutput *)objectForKeyedSubscript:(NJInput *)input;
 - (void)setObject:(NJOutput *)output forKeyedSubscript:(NJInput *)input;
index 0e67cd3..04f6e68 100644 (file)
@@ -34,7 +34,7 @@
 }
 
 - (id)initWithSerialization:(NSDictionary *)serialization
-                   mappings:(NSArray *)mappings {
+                   mappings:(id <NSFastEnumeration>)mappings {
     if ((self = [self initWithName:serialization[@"name"]])) {
         NSDictionary *entries = serialization[@"entries"];
         if ([entries isKindOfClass:NSDictionary.class]) {
     return NO;
 }
 
-+ (id)mappingWithContentsOfURL:(NSURL *)url mappings:(NSArray *)mappings error:(NSError **)error {
++ (id)mappingWithContentsOfURL:(NSURL *)url mappings:(id <NSFastEnumeration>)mappings error:(NSError **)error {
     NSInputStream *stream = [NSInputStream inputStreamWithURL:url];
     [stream open];
     NSDictionary *serialization = stream && !*error
index a4d9c18..39aaf79 100644 (file)
@@ -9,36 +9,20 @@
 @class NJMapping;
 @class NJOutputController;
 
-@interface NJMappingsController : NSObject <NSTableViewDataSource,
-                                            NSTableViewDelegate,
-                                            NSOpenSavePanelDelegate,
-                                            NSPopoverDelegate,
-                                            NSFastEnumeration>
-{
-    IBOutlet NSButton *removeButton;
-    IBOutlet NSTableView *tableView;
-    IBOutlet NSButton *popoverActivate;
-    IBOutlet NSPopover *popover;
-    IBOutlet NSButton *moveUp;
-    IBOutlet NSButton *moveDown;
-}
+#import "NJMappingsViewController.h"
+
+@interface NJMappingsController : NSObject <NSFastEnumeration,
+                                            NJMappingsViewControllerDelegate>
 
 @property (nonatomic, readonly) NJMapping *currentMapping;
+@property (nonatomic, strong) IBOutlet NJMappingsViewController *mvc;
 
 - (NJMapping *)objectForKeyedSubscript:(NSString *)name;
 - (NJMapping *)objectAtIndexedSubscript:(NSUInteger)idx;
-- (void)addMappingWithContentsOfURL:(NSURL *)url;
 - (void)activateMapping:(NJMapping *)mapping;
 - (void)activateMappingForProcess:(NSRunningApplication *)app;
+- (void)addOrMergeMapping:(NJMapping *)mapping;
 - (void)save;
 - (void)load;
 
-- (IBAction)mappingPressed:(id)sender;
-- (IBAction)addPressed:(id)sender;
-- (IBAction)removePressed:(id)sender;
-- (IBAction)moveUpPressed:(id)sender;
-- (IBAction)moveDownPressed:(id)sender;
-- (IBAction)importPressed:(id)sender;
-- (IBAction)exportPressed:(id)sender;
-
 @end
index c3209ac..531de12 100644 (file)
     return self;
 }
 
-- (void)awakeFromNib {
-    [tableView registerForDraggedTypes:@[PB_ROW, NSURLPboardType]];
-    [tableView setDraggingSourceOperationMask:NSDragOperationCopy forLocal:NO];
-}
-
 - (NJMapping *)objectForKeyedSubscript:(NSString *)name {
     for (NJMapping *mapping in _mappings)
         if ([name isEqualToString:mapping.name])
 }
 
 - (void)mappingsSet {
-    [tableView reloadData];
-    [self updateInterfaceForCurrentMapping];
     [NSNotificationCenter.defaultCenter
         postNotificationName:NJEventMappingListChanged
                       object:self
                     userInfo:@{ NJMappingListKey: _mappings,
                                 NJMappingKey: _currentMapping }];
+    [self.mvc changedActiveMappingToIndex:[_mappings indexOfObjectIdenticalTo:_currentMapping]];
 }
 
 - (void)mappingsChanged {
     _manualMapping = oldMapping;
 }
 
-- (void)updateInterfaceForCurrentMapping {
-    NSUInteger selected = [_mappings indexOfObject:_currentMapping];
-    removeButton.enabled = selected != 0;
-    moveUp.enabled = selected > 1;
-    moveDown.enabled = selected && selected != _mappings.count - 1;
-    popoverActivate.title = _currentMapping.name;
-    [tableView selectRowIndexes:[NSIndexSet indexSetWithIndex:selected] byExtendingSelection:NO];
-    [NSUserDefaults.standardUserDefaults setInteger:selected forKey:@"selected"];
-}
-
 - (void)activateMapping:(NJMapping *)mapping {
     if (!mapping)
         mapping = _manualMapping;
     NSLog(@"Switching to mapping %@.", mapping.name);
     _manualMapping = mapping;
     _currentMapping = mapping;
-    [self updateInterfaceForCurrentMapping];
+    [self.mvc changedActiveMappingToIndex:[_mappings indexOfObjectIdenticalTo:_currentMapping]];
     [NSNotificationCenter.defaultCenter
          postNotificationName:NJEventMappingChanged
                        object:self
                      userInfo:@{ NJMappingKey : _currentMapping }];
 }
 
-- (IBAction)addPressed:(id)sender {
-    [self mappingPressed:sender];
-    NJMapping *newMapping = [[NJMapping alloc] init];
-    [_mappings addObject:newMapping];
-    [self activateMapping:newMapping];
-    [self mappingsChanged];
-    [tableView editColumn:0 row:_mappings.count - 1 withEvent:nil select:YES];
-}
-
-- (IBAction)removePressed:(id)sender {
-    if (tableView.selectedRow == 0)
-        return;
-    
-    NSInteger selectedRow = tableView.selectedRow;
-    [_mappings removeObjectAtIndex:selectedRow];
-    [self activateMapping:_mappings[MIN(selectedRow, _mappings.count - 1)]];
-    [self mappingsChanged];
-}
-
-- (void)tableViewSelectionDidChange:(NSNotification *)notify {
-    [self activateMapping:self[tableView.selectedRow]];
-}
-
-- (id)tableView:(NSTableView *)view objectValueForTableColumn:(NSTableColumn *)column row:(NSInteger)index {
-    return self[index].name;
-}
-
-- (void)tableView:(NSTableView *)view
-   setObjectValue:(NSString *)obj
-   forTableColumn:(NSTableColumn *)col
-              row:(NSInteger)index {
-    self[index].name = obj;
-    [self mappingsChanged];
-}
-
-- (NSInteger)numberOfRowsInTableView:(NSTableView *)tableView {
-    return _mappings.count;
-}
-
-- (BOOL)tableView:(NSTableView *)view shouldEditTableColumn:(NSTableColumn *)column row:(NSInteger)index {
-    return YES;
-}
-
 - (void)save {
     NSLog(@"Saving mappings to defaults.");
     NSMutableArray *ary = [[NSMutableArray alloc] initWithCapacity:_mappings.count];
         _mappings = newMappings;
         if (selected >= newMappings.count)
             selected = 0;
+        [self.mvc reloadData];
         [self activateMapping:_mappings[selected]];
         [self mappingsSet];
     }
     switch (returnCode) {
         case NSAlertFirstButtonReturn: // Merge
             [oldMapping mergeEntriesFrom:newMapping];
+            _currentMapping = nil;
             [self activateMapping:oldMapping];
             [self mappingsChanged];
             break;
         case NSAlertThirdButtonReturn: // New Mapping
+            [self.mvc.mappingList beginUpdates];
             [_mappings addObject:newMapping];
+            [self.mvc addedMappingAtIndex:_mappings.count - 1 startEditing:NO];
+            [self.mvc.mappingList endUpdates];
             [self activateMapping:newMapping];
             [self mappingsChanged];
-            [self mappingPressed:alert];
-            [tableView selectRowIndexes:[NSIndexSet indexSetWithIndex:_mappings.count - 1] byExtendingSelection:NO];
-            [tableView editColumn:0 row:_mappings.count - 1 withEvent:nil select:YES];
             break;
         default: // Cancel, other.
             break;
     }
 }
 
-- (void)addMappingWithContentsOfURL:(NSURL *)url {
-    NSWindow *window = popoverActivate.window;
-    NSError *error;
-    NJMapping *mapping = [NJMapping mappingWithContentsOfURL:url
-                                                    mappings:_mappings
-                                                       error:&error];
-    
+- (void)addOrMergeMapping:(NJMapping *)mapping {
+    [self addOrMergeMapping:mapping atIndex:-1];
+}
+
+- (void)addOrMergeMapping:(NJMapping *)mapping atIndex:(NSInteger)idx {
+    NSWindow *window = NSApplication.sharedApplication.keyWindow;
     if (mapping) {
         NJMapping *mergeInto = self[mapping.name];
         if ([mergeInto hasConflictWith:mapping]) {
             [conflictAlert addButtonWithTitle:NSLocalizedString(@"import and merge", @"button to merge imported mappings")];
             [conflictAlert addButtonWithTitle:NSLocalizedString(@"cancel import", @"button to cancel import")];
             [conflictAlert addButtonWithTitle:NSLocalizedString(@"import new mapping", @"button to import as new mapping")];
-            [conflictAlert beginSheetModalForWindow:popoverActivate.window
+            [conflictAlert beginSheetModalForWindow:window
                                       modalDelegate:self
                                      didEndSelector:@selector(mappingConflictDidResolve:returnCode:contextInfo:)
                                         contextInfo:(void *)CFBridgingRetain(@{ @"old mapping": mergeInto,
             [self activateMapping:mergeInto];
             [self mappingsChanged];
         } else {
-            [_mappings addObject:mapping];
+            if (idx == -1)
+                idx = _mappings.count - 1;
+            [self.mvc.mappingList beginUpdates];
+            [_mappings insertObject:mapping atIndex:idx];
+            [self.mvc addedMappingAtIndex:idx startEditing:NO];
+            [self.mvc.mappingList endUpdates];
             [self activateMapping:mapping];
             [self mappingsChanged];
         }
-    } else {
-        [window presentError:error
-              modalForWindow:window
-                    delegate:nil
-          didPresentSelector:nil
-                 contextInfo:nil];
     }
 }
 
-- (void)importPressed:(id)sender {
-    NSOpenPanel *panel = [NSOpenPanel openPanel];
-    panel.allowedFileTypes = @[ @"enjoyable", @"json", @"txt" ];
-    NSWindow *window = NSApplication.sharedApplication.keyWindow;
-    [panel beginSheetModalForWindow:window
-                  completionHandler:^(NSInteger result) {
-                      if (result != NSFileHandlingPanelOKButton)
-                          return;
-                      [panel close];
-                      [self addMappingWithContentsOfURL:panel.URL];
-                  }];
-    
-}
-
-- (void)exportPressed:(id)sender {
-    NSSavePanel *panel = [NSSavePanel savePanel];
-    panel.allowedFileTypes = @[ @"enjoyable" ];
-    NJMapping *mapping = _currentMapping;
-    panel.nameFieldStringValue = [mapping.name stringByFixingPathComponent];
-    NSWindow *window = NSApplication.sharedApplication.keyWindow;
-    [panel beginSheetModalForWindow:window
-                  completionHandler:^(NSInteger result) {
-                      if (result != NSFileHandlingPanelOKButton)
-                          return;
-                      [panel close];
-                      NSError *error;
-                      [mapping writeToURL:panel.URL error:&error];
-                      if (error) {
-                          [window presentError:error
-                                modalForWindow:window
-                                      delegate:nil
-                            didPresentSelector:nil
-                                   contextInfo:nil];
-                      }
-                  }];
-}
-
-- (IBAction)mappingPressed:(id)sender {
-    [popover showRelativeToRect:popoverActivate.bounds
-                         ofView:popoverActivate
-                  preferredEdge:NSMinXEdge];
+- (NSInteger)numberOfMappings:(NJMappingsViewController *)dvc {
+    return _mappings.count;
 }
 
-- (void)popoverWillShow:(NSNotification *)notification {
-    popoverActivate.state = NSOnState;
+- (NJMapping *)mappingsViewController:(NJMappingsViewController *)dvc
+                      mappingForIndex:(NSUInteger)idx {
+    return _mappings[idx];
 }
 
-- (void)popoverWillClose:(NSNotification *)notification {
-    popoverActivate.state = NSOffState;
+- (void)mappingsViewController:(NJMappingsViewController *)mvc
+          editedMappingAtIndex:(NSInteger)index {
+    [self mappingsChanged];
 }
 
-- (IBAction)moveUpPressed:(id)sender {
-    if ([_mappings moveFirstwards:_currentMapping upTo:1])
-        [self mappingsChanged];
+- (BOOL)mappingsViewController:(NJMappingsViewController *)mvc
+       canMoveMappingFromIndex:(NSInteger)fromIdx
+                       toIndex:(NSInteger)toIdx {
+    return fromIdx != toIdx && fromIdx != 0 && toIdx != 0 && toIdx < (NSInteger)_mappings.count;
 }
 
-- (IBAction)moveDownPressed:(id)sender {
-    if ([_mappings moveLastwards:_currentMapping])
-        [self mappingsChanged];
+- (void)mappingsViewController:(NJMappingsViewController *)mvc
+          moveMappingFromIndex:(NSInteger)fromIdx
+                       toIndex:(NSInteger)toIdx {
+    [_mappings moveObjectAtIndex:fromIdx toIndex:toIdx];
+    [self mappingsChanged];
 }
 
-- (BOOL)tableView:(NSTableView *)tableView_
-       acceptDrop:(id <NSDraggingInfo>)info
-              row:(NSInteger)row
-    dropOperation:(NSTableViewDropOperation)dropOperation {
-    NSPasteboard *pboard = [info draggingPasteboard];
-    if ([pboard.types containsObject:PB_ROW]) {
-        NSString *value = [pboard stringForType:PB_ROW];
-        NSUInteger srcRow = [value intValue];
-        [_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;
-    }
+- (BOOL)mappingsViewController:(NJMappingsViewController *)mvc
+       canRemoveMappingAtIndex:(NSInteger)idx {
+    return idx != 0;
 }
 
-- (NSDragOperation)tableView:(NSTableView *)tableView_
-                validateDrop:(id <NSDraggingInfo>)info
-                 proposedRow:(NSInteger)row
-       proposedDropOperation:(NSTableViewDropOperation)dropOperation {
-    NSPasteboard *pboard = [info draggingPasteboard];
-    if ([pboard.types containsObject:PB_ROW]) {
-        [tableView_ setDropRow:MAX(1, row) dropOperation:NSTableViewDropAbove];
-        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;
-    }
+- (void)mappingsViewController:(NJMappingsViewController *)mvc
+          removeMappingAtIndex:(NSInteger)idx {
+    NJMapping *old = self[idx];
+    [self.mvc.mappingList beginUpdates];
+    [_mappings removeObjectAtIndex:idx];
+    [self.mvc removedMappingAtIndex:idx];
+    [self.mvc.mappingList endUpdates];
+    if (old == _currentMapping)
+        [self activateMapping:self[MIN(idx, _mappings.count - 1)]];
+    [self mappingsChanged];
 }
 
-- (NSArray *)tableView:(NSTableView *)tableView_
-namesOfPromisedFilesDroppedAtDestination:(NSURL *)dropDestination
-forDraggedRowsWithIndexes:(NSIndexSet *)indexSet {
-    NJMapping *toSave = self[indexSet.firstIndex];
-    NSString *filename = [[toSave.name stringByFixingPathComponent]
-                          stringByAppendingPathExtension:@"enjoyable"];
-    NSURL *dst = [dropDestination URLByAppendingPathComponent:filename];
-    dst = [NSFileManager.defaultManager generateUniqueURLWithBase:dst];     
-    NSError *error;
-    if (![toSave writeToURL:dst error:&error]) {
-        [tableView_ presentError:error];
-        return @[];
-    } else {
-        return @[dst.lastPathComponent];
-    }
+- (BOOL)mappingsViewController:(NJMappingsViewController *)mvc
+          importMappingFromURL:(NSURL *)url
+                       atIndex:(NSInteger)index
+                         error:(NSError **)error {
+    NJMapping *mapping = [NJMapping mappingWithContentsOfURL:url
+                                                    mappings:_mappings
+                                                       error:error];
+    [self addOrMergeMapping:mapping atIndex:index];
+    return !!mapping;
+}
+
+- (void)mappingsViewController:(NJMappingsViewController *)mvc
+                    addMapping:(NJMapping *)mapping {
+    [self.mvc.mappingList beginUpdates];
+    [_mappings addObject:mapping];
+    [self.mvc addedMappingAtIndex:_mappings.count - 1 startEditing:YES];
+    [self.mvc.mappingList endUpdates];
+    [self activateMapping:mapping];
+    [self mappingsChanged];
 }
 
-- (BOOL)tableView:(NSTableView *)tableView_
-writeRowsWithIndexes:(NSIndexSet *)rowIndexes
-     toPasteboard:(NSPasteboard *)pboard {
-    if (rowIndexes.count == 1 && rowIndexes.firstIndex != 0) {
-        [pboard declareTypes:@[PB_ROW, NSFilesPromisePboardType] owner:nil];
-        [pboard setString:@(rowIndexes.firstIndex).stringValue forType:PB_ROW];
-        [pboard setPropertyList:@[@"enjoyable"] forType:NSFilesPromisePboardType];
-        return YES;
-    } else if (rowIndexes.count == 1 && rowIndexes.firstIndex == 0) {
-        [pboard declareTypes:@[NSFilesPromisePboardType] owner:nil];
-        [pboard setPropertyList:@[@"enjoyable"] forType:NSFilesPromisePboardType];
-        return YES;
-    } else {
-        return NO;
-    }
+- (void)mappingsViewController:(NJMappingsViewController *)mvc
+                  choseMappingAtIndex:(NSInteger)idx {
+    [self activateMapping:self[idx]];
 }
 
 @end
diff --git a/Classes/NJMappingsViewController.h b/Classes/NJMappingsViewController.h
new file mode 100644 (file)
index 0000000..2d0bd25
--- /dev/null
@@ -0,0 +1,72 @@
+//
+//  NJMappingsViewController.h
+//  Enjoyable
+//
+//  Created by Joe Wreschnig on 3/17/13.
+//
+//
+
+@class NJMapping;
+@protocol NJMappingsViewControllerDelegate;
+
+@interface NJMappingsViewController : NSViewController <NSTableViewDataSource,
+                                                        NSTableViewDelegate,
+                                                        NSOpenSavePanelDelegate,
+                                                        NSPopoverDelegate>
+
+@property (nonatomic, weak) IBOutlet id <NJMappingsViewControllerDelegate> delegate;
+
+@property (nonatomic, strong) IBOutlet NSButton *removeMapping;
+@property (nonatomic, strong) IBOutlet NSTableView *mappingList;
+@property (nonatomic, strong) IBOutlet NSButton *mappingListTrigger;
+@property (nonatomic, strong) IBOutlet NSPopover *mappingListPopover;
+@property (nonatomic, strong) IBOutlet NSButton *moveUp;
+@property (nonatomic, strong) IBOutlet NSButton *moveDown;
+
+- (IBAction)addClicked:(id)sender;
+- (IBAction)removeClicked:(id)sender;
+- (IBAction)moveUpClicked:(id)sender;
+- (IBAction)moveDownClicked:(id)sender;
+- (IBAction)mappingTriggerClicked:(id)sender;
+
+- (void)addedMappingAtIndex:(NSInteger)index startEditing:(BOOL)startEditing;
+- (void)removedMappingAtIndex:(NSInteger)index;
+- (void)changedActiveMappingToIndex:(NSInteger)index;
+
+- (void)reloadData;
+
+@end
+
+@protocol NJMappingsViewControllerDelegate
+
+- (NSInteger)numberOfMappings:(NJMappingsViewController *)dvc;
+- (NJMapping *)mappingsViewController:(NJMappingsViewController *)dvc
+                      mappingForIndex:(NSUInteger)idx;
+
+
+- (void)mappingsViewController:(NJMappingsViewController *)mvc
+          editedMappingAtIndex:(NSInteger)index;
+
+- (BOOL)mappingsViewController:(NJMappingsViewController *)mvc
+       canMoveMappingFromIndex:(NSInteger)fromIdx
+                       toIndex:(NSInteger)toIdx;
+- (void)mappingsViewController:(NJMappingsViewController *)mvc
+          moveMappingFromIndex:(NSInteger)fromIdx
+                       toIndex:(NSInteger)toIdx;
+
+- (BOOL)mappingsViewController:(NJMappingsViewController *)mvc
+       canRemoveMappingAtIndex:(NSInteger)idx;
+- (void)mappingsViewController:(NJMappingsViewController *)mvc
+          removeMappingAtIndex:(NSInteger)idx;
+
+- (BOOL)mappingsViewController:(NJMappingsViewController *)mvc
+          importMappingFromURL:(NSURL *)url
+                       atIndex:(NSInteger)index
+                         error:(NSError **)error;
+- (void)mappingsViewController:(NJMappingsViewController *)mvc
+                    addMapping:(NJMapping *)mapping;
+
+- (void)mappingsViewController:(NJMappingsViewController *)mvc
+           choseMappingAtIndex:(NSInteger)idx;
+
+@end
diff --git a/Classes/NJMappingsViewController.m b/Classes/NJMappingsViewController.m
new file mode 100644 (file)
index 0000000..fd9ce41
--- /dev/null
@@ -0,0 +1,233 @@
+//
+//  NJMappingsViewController.m
+//  Enjoyable
+//
+//  Created by Joe Wreschnig on 3/17/13.
+//
+//
+
+#import "NJMappingsViewController.h"
+
+#import "NJMapping.h"
+
+#define PB_ROW @"com.yukkurigames.Enjoyable.MappingRow"
+
+
+@implementation NJMappingsViewController
+
+- (void)awakeFromNib {
+    [self.mappingList registerForDraggedTypes:@[PB_ROW, NSURLPboardType]];
+    [self.mappingList setDraggingSourceOperationMask:NSDragOperationCopy forLocal:NO];
+}
+
+- (IBAction)addClicked:(id)sender {
+    NJMapping *newMapping = [[NJMapping alloc] init];
+    [self.delegate mappingsViewController:self addMapping:newMapping];
+}
+
+- (IBAction)removeClicked:(id)sender {
+    [self.delegate mappingsViewController:self
+                     removeMappingAtIndex:self.mappingList.selectedRow];
+}
+
+- (IBAction)moveUpClicked:(id)sender {
+    NSInteger fromIdx = self.mappingList.selectedRow;
+    NSInteger toIdx = fromIdx - 1;
+    [self.delegate mappingsViewController:self
+                     moveMappingFromIndex:fromIdx
+                                  toIndex:toIdx];
+    [self.mappingList beginUpdates];
+    [self.mappingList moveRowAtIndex:fromIdx toIndex:toIdx];
+    [self.mappingList endUpdates];
+    [self.mappingList scrollRowToVisible:toIdx];
+    [self.mappingList selectRowIndexes:[[NSIndexSet alloc] initWithIndex:toIdx]
+                  byExtendingSelection:NO];
+}
+
+- (IBAction)moveDownClicked:(id)sender {
+    NSInteger fromIdx = self.mappingList.selectedRow;
+    NSInteger toIdx = fromIdx + 1;
+    [self.delegate mappingsViewController:self
+                     moveMappingFromIndex:fromIdx
+                                  toIndex:toIdx];
+    [self.mappingList beginUpdates];
+    [self.mappingList moveRowAtIndex:fromIdx toIndex:toIdx];
+    [self.mappingList endUpdates];
+    [self.mappingList scrollRowToVisible:toIdx];
+    [self.mappingList selectRowIndexes:[[NSIndexSet alloc] initWithIndex:toIdx]
+                  byExtendingSelection:NO];
+}
+
+- (IBAction)mappingTriggerClicked:(id)sender {
+    [self.mappingListPopover showRelativeToRect:self.mappingListTrigger.bounds
+                                         ofView:self.mappingListTrigger
+                                  preferredEdge:NSMinXEdge];
+    self.mappingListTrigger.state = NSOnState;
+}
+
+- (void)popoverWillShow:(NSNotification *)notification {
+    self.mappingListTrigger.state = NSOnState;
+}
+
+- (void)popoverWillClose:(NSNotification *)notification {
+    self.mappingListTrigger.state = NSOffState;
+}
+
+- (void)addedMappingAtIndex:(NSInteger)index startEditing:(BOOL)startEditing {
+    [self.mappingList abortEditing];
+    [self.mappingList beginUpdates];
+    [self.mappingList insertRowsAtIndexes:[[NSIndexSet alloc] initWithIndex:index]
+                            withAnimation:startEditing ? 0 : NSTableViewAnimationSlideLeft];
+    [self.mappingList endUpdates];
+    if (startEditing) {
+        [self.mappingListTrigger performClick:self];
+        [self.mappingList editColumn:0 row:index withEvent:nil select:YES];
+        [self.mappingList scrollRowToVisible:index];
+    }
+}
+
+- (void)removedMappingAtIndex:(NSInteger)index {
+    [self.mappingList abortEditing];
+    [self.mappingList beginUpdates];
+    [self.mappingList removeRowsAtIndexes:[[NSIndexSet alloc] initWithIndex:index]
+                            withAnimation:NSTableViewAnimationEffectFade];
+    [self.mappingList endUpdates];
+}
+
+- (void)changedActiveMappingToIndex:(NSInteger)index {
+    NJMapping *mapping = [self.delegate mappingsViewController:self
+                                               mappingForIndex:index];
+    self.removeMapping.enabled = [self.delegate mappingsViewController:self
+                                               canRemoveMappingAtIndex:index];
+    self.moveUp.enabled = [self.delegate mappingsViewController:self
+                                        canMoveMappingFromIndex:index toIndex:index - 1];
+    self.moveDown.enabled = [self.delegate mappingsViewController:self
+                                          canMoveMappingFromIndex:index toIndex:index + 1];
+    self.mappingListTrigger.title = mapping.name;
+    [self.mappingList selectRowIndexes:[NSIndexSet indexSetWithIndex:index] byExtendingSelection:NO];
+    [self.mappingList scrollRowToVisible:index];
+    [NSUserDefaults.standardUserDefaults setInteger:index forKey:@"selected"];
+   
+}
+
+- (void)tableViewSelectionDidChange:(NSNotification *)note {
+    [self.mappingList abortEditing];
+    NSTableView *tableView = note.object;
+    [self.delegate mappingsViewController:self
+                      choseMappingAtIndex:tableView.selectedRow];
+}
+
+- (id)tableView:(NSTableView *)view objectValueForTableColumn:(NSTableColumn *)column row:(NSInteger)index {
+    return [self.delegate mappingsViewController:self
+                                 mappingForIndex:index].name;
+}
+
+- (void)tableView:(NSTableView *)view
+   setObjectValue:(NSString *)obj
+   forTableColumn:(NSTableColumn *)col
+              row:(NSInteger)index {
+    NJMapping *mapping = [self.delegate mappingsViewController:self
+                                               mappingForIndex:index];
+    mapping.name = obj;
+    [self.delegate mappingsViewController:self editedMappingAtIndex:index];
+}
+
+- (NSInteger)numberOfRowsInTableView:(NSTableView *)tableView {
+    return [self.delegate numberOfMappings:self];
+}
+
+- (BOOL)tableView:(NSTableView *)tableView
+       acceptDrop:(id <NSDraggingInfo>)info
+              row:(NSInteger)row
+    dropOperation:(NSTableViewDropOperation)dropOperation {
+    NSPasteboard *pboard = [info draggingPasteboard];
+    if ([pboard.types containsObject:PB_ROW]) {
+        NSString *value = [pboard stringForType:PB_ROW];
+        NSInteger srcRow = [value intValue];
+        row -= srcRow < row;
+        [self.mappingList beginUpdates];
+        [self.mappingList moveRowAtIndex:srcRow toIndex:row];
+        [self.mappingList endUpdates];
+        [self.delegate mappingsViewController:self
+                         moveMappingFromIndex:srcRow
+                                      toIndex:row];
+        return YES;
+    } else if ([pboard.types containsObject:NSURLPboardType]) {
+        NSURL *url = [NSURL URLFromPasteboard:pboard];
+        NSError *error;
+        if (![self.delegate mappingsViewController:self
+                              importMappingFromURL:url
+                                           atIndex:row
+                                             error:&error]) {
+            [tableView presentError:error];
+            return NO;
+        } else {
+            return YES;
+        }
+    } else {
+        return NO;
+    }
+}
+
+- (NSDragOperation)tableView:(NSTableView *)tableView
+                validateDrop:(id <NSDraggingInfo>)info
+                 proposedRow:(NSInteger)row
+       proposedDropOperation:(NSTableViewDropOperation)dropOperation {
+    NSPasteboard *pboard = [info draggingPasteboard];
+    if ([pboard.types containsObject:PB_ROW]) {
+        [tableView setDropRow:MAX(1, row) dropOperation:NSTableViewDropAbove];
+        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;
+    }
+}
+
+- (NSArray *)tableView:(NSTableView *)tableView
+namesOfPromisedFilesDroppedAtDestination:(NSURL *)dropDestination
+forDraggedRowsWithIndexes:(NSIndexSet *)indexSet {
+    NJMapping *toSave = [self.delegate mappingsViewController:self
+                                              mappingForIndex:indexSet.firstIndex];
+    NSString *filename = [[toSave.name stringByFixingPathComponent]
+                          stringByAppendingPathExtension:@"enjoyable"];
+    NSURL *dst = [dropDestination URLByAppendingPathComponent:filename];
+    dst = [NSFileManager.defaultManager generateUniqueURLWithBase:dst];
+    NSError *error;
+    if (![toSave writeToURL:dst error:&error]) {
+        [tableView presentError:error];
+        return @[];
+    } else {
+        return @[dst.lastPathComponent];
+    }
+}
+
+- (BOOL)tableView:(NSTableView *)tableView
+writeRowsWithIndexes:(NSIndexSet *)rowIndexes
+     toPasteboard:(NSPasteboard *)pboard {
+    if (rowIndexes.count == 1 && rowIndexes.firstIndex != 0) {
+        [pboard declareTypes:@[PB_ROW, NSFilesPromisePboardType] owner:nil];
+        [pboard setString:@(rowIndexes.firstIndex).stringValue forType:PB_ROW];
+        [pboard setPropertyList:@[@"enjoyable"] forType:NSFilesPromisePboardType];
+        return YES;
+    } else if (rowIndexes.count == 1 && rowIndexes.firstIndex == 0) {
+        [pboard declareTypes:@[NSFilesPromisePboardType] owner:nil];
+        [pboard setPropertyList:@[@"enjoyable"] forType:NSFilesPromisePboardType];
+        return YES;
+    } else {
+        return NO;
+    }
+}
+
+- (void)reloadData {
+    [self.mappingList reloadData];
+}
+
+@end
+
index b82c4e7..5d4d470 100644 (file)
@@ -20,7 +20,7 @@
 
 - (NSDictionary *)serialize;
 + (NJOutput *)outputDeserialize:(NSDictionary *)serialization
-                   withMappings:(NSArray *)mappings;
+                   withMappings:(id <NSFastEnumeration>)mappings;
 + (NSString *)serializationCode;
 
 @end
index 409b3e6..35a56d9 100644 (file)
@@ -37,7 +37,7 @@
 }
 
 + (NJOutput *)outputDeserialize:(NSDictionary *)serialization
-                  withMappings:(NSArray *)mappings {
+                  withMappings:(id <NSFastEnumeration>)mappings {
     // Don't crash loading old/bad mappings (but don't load them either).
     if (![serialization isKindOfClass:NSDictionary.class])
         return nil;
index 1cc7e65..e80aba5 100644 (file)
@@ -22,7 +22,7 @@
 }
 
 + (NJOutput *)outputDeserialize:(NSDictionary *)serialization
-                  withMappings:(NSArray *)mappings {
+                  withMappings:(id <NSFastEnumeration>)mappings {
     NJOutputKeyPress *output = [[NJOutputKeyPress alloc] init];
     output.keyCode = [serialization[@"key"] intValue];
     return output;
index fa8fda1..28a84ab 100644 (file)
@@ -24,7 +24,7 @@
 }
 
 + (NJOutputMapping *)outputDeserialize:(NSDictionary *)serialization
-                        withMappings:(NSArray *)mappings {
+                        withMappings:(id <NSFastEnumeration>)mappings {
     NSString *name = serialization[@"name"];
     NJOutputMapping *output = [[NJOutputMapping alloc] init];
     for (NJMapping *mapping in mappings) {
index 5ddb69d..e01e763 100644 (file)
@@ -37,7 +37,7 @@
 }
 
 + (NJOutput *)outputDeserialize:(NSDictionary *)serialization
-                  withMappings:(NSArray *)mappings {
+                  withMappings:(id <NSFastEnumeration>)mappings {
     NJOutputMouseButton *output = [[NJOutputMouseButton alloc] init];
     output.button = [serialization[@"button"] intValue];
     return output;
index be8b076..8591923 100644 (file)
@@ -23,7 +23,7 @@
 }
 
 + (NJOutput *)outputDeserialize:(NSDictionary *)serialization
-                  withMappings:(NSArray *)mappings {
+                  withMappings:(id <NSFastEnumeration>)mappings {
     NJOutputMouseMove *output = [[NJOutputMouseMove alloc] init];
     output.axis = [serialization[@"axis"] intValue];
     output.speed = [serialization[@"speed"] floatValue];
index b97a3e7..6fdc918 100644 (file)
@@ -22,7 +22,7 @@
 }
 
 + (NJOutput *)outputDeserialize:(NSDictionary *)serialization
-                  withMappings:(NSArray *)mappings {
+                  withMappings:(id <NSFastEnumeration>)mappings {
     NJOutputMouseScroll *output = [[NJOutputMouseScroll alloc] init];
     output.direction = [serialization[@"direction"] intValue];
     output.speed = [serialization[@"speed"] floatValue];
index e633c35..27ca44a 100644 (file)
@@ -17,6 +17,7 @@
                EE52145C16F3E8BD00E3C574 /* NSOutlineView+ItemAccessors.m in Sources */ = {isa = PBXBuildFile; fileRef = EE52145B16F3E8BD00E3C574 /* NSOutlineView+ItemAccessors.m */; };
                EE52145F16F404D500E3C574 /* NJDeviceViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = EE52145E16F404D500E3C574 /* NJDeviceViewController.m */; };
                EE6A122E16E8F46300EDBD32 /* Icon.icns in Resources */ = {isa = PBXBuildFile; fileRef = EE6A122D16E8F46300EDBD32 /* Icon.icns */; };
+               EE83ACEC16F545EA00083E94 /* NJMappingsViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = EE83ACEB16F545EA00083E94 /* NJMappingsViewController.m */; };
                EE8455DD16F0E46B00F32A01 /* NSRunningApplication+LoginItem.m in Sources */ = {isa = PBXBuildFile; fileRef = EE8455DC16F0E46B00F32A01 /* NSRunningApplication+LoginItem.m */; };
                EED4CE6E16ED692400C65AA8 /* NJMappingMenuController.m in Sources */ = {isa = PBXBuildFile; fileRef = EED4CE6D16ED692400C65AA8 /* NJMappingMenuController.m */; };
                EED4CE7716EE195100C65AA8 /* Sparkle.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = EED4CE7616EE195100C65AA8 /* Sparkle.framework */; };
@@ -85,6 +86,8 @@
                EE52145D16F404D500E3C574 /* NJDeviceViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = NJDeviceViewController.h; path = Classes/NJDeviceViewController.h; sourceTree = "<group>"; };
                EE52145E16F404D500E3C574 /* NJDeviceViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = NJDeviceViewController.m; path = Classes/NJDeviceViewController.m; sourceTree = "<group>"; };
                EE6A122D16E8F46300EDBD32 /* Icon.icns */ = {isa = PBXFileReference; lastKnownFileType = image.icns; path = Icon.icns; sourceTree = "<group>"; };
+               EE83ACEA16F545EA00083E94 /* NJMappingsViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = NJMappingsViewController.h; path = Classes/NJMappingsViewController.h; sourceTree = "<group>"; };
+               EE83ACEB16F545EA00083E94 /* NJMappingsViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = NJMappingsViewController.m; path = Classes/NJMappingsViewController.m; sourceTree = "<group>"; };
                EE8455DB16F0E46B00F32A01 /* NSRunningApplication+LoginItem.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "NSRunningApplication+LoginItem.h"; path = "Categories/NSRunningApplication+LoginItem.h"; sourceTree = "<group>"; };
                EE8455DC16F0E46B00F32A01 /* NSRunningApplication+LoginItem.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = "NSRunningApplication+LoginItem.m"; path = "Categories/NSRunningApplication+LoginItem.m"; sourceTree = "<group>"; };
                EED4CE6C16ED692400C65AA8 /* NJMappingMenuController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = NJMappingMenuController.h; path = Classes/NJMappingMenuController.h; sourceTree = "<group>"; };
                                EEE703DB16F089FE002FDD69 /* NJHIDManager.m */,
                                EE52145D16F404D500E3C574 /* NJDeviceViewController.h */,
                                EE52145E16F404D500E3C574 /* NJDeviceViewController.m */,
+                               EE83ACEA16F545EA00083E94 /* NJMappingsViewController.h */,
+                               EE83ACEB16F545EA00083E94 /* NJMappingsViewController.m */,
                        );
                        name = Classes;
                        sourceTree = "<group>";
                                EE8455DD16F0E46B00F32A01 /* NSRunningApplication+LoginItem.m in Sources */,
                                EE52145C16F3E8BD00E3C574 /* NSOutlineView+ItemAccessors.m in Sources */,
                                EE52145F16F404D500E3C574 /* NJDeviceViewController.m in Sources */,
+                               EE83ACEC16F545EA00083E94 /* NJMappingsViewController.m in Sources */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
index 0b9f61d..673fcbd 100644 (file)
@@ -46,7 +46,7 @@
        <key>CFBundleSignature</key>
        <string>????</string>
        <key>CFBundleVersion</key>
-       <string>328</string>
+       <string>444</string>
        <key>LSApplicationCategoryType</key>
        <string>public.app-category.utilities</string>
        <key>NSHumanReadableCopyright</key>
index 48ed439..6afbc50 100644 (file)
@@ -37,7 +37,6 @@
                        <string>NSToolbarFlexibleSpaceItem</string>
                        <string>NSToolbarItem</string>
                        <string>NSView</string>
-                       <string>NSViewController</string>
                        <string>NSWindowTemplate</string>
                </array>
                <array key="IBDocument.PluginDependencies">
@@ -567,7 +566,7 @@ aW5nLg</string>
                                                                                                        <string key="NSFrameSize">{232, 321}</string>
                                                                                                        <reference key="NSSuperview" ref="698362889"/>
                                                                                                        <reference key="NSWindow"/>
-                                                                                                       <reference key="NSNextKeyView" ref="1036252745"/>
+                                                                                                       <reference key="NSNextKeyView" ref="892486973"/>
                                                                                                        <bool key="NSEnabled">YES</bool>
                                                                                                        <bool key="NSAllowsLogicalLayoutDirection">NO</bool>
                                                                                                        <bool key="NSControlAllowsExpansionToolTips">YES</bool>
@@ -697,7 +696,7 @@ aW5nLg</string>
                                                                        <string key="NSFrameSize">{234, 323}</string>
                                                                        <reference key="NSSuperview" ref="734312853"/>
                                                                        <reference key="NSWindow"/>
-                                                                       <reference key="NSNextKeyView" ref="892486973"/>
+                                                                       <reference key="NSNextKeyView" ref="698362889"/>
                                                                        <int key="NSsFlags">150034</int>
                                                                        <reference key="NSVScroller" ref="1036252745"/>
                                                                        <reference key="NSHScroller" ref="892486973"/>
@@ -767,7 +766,6 @@ aW5nLg</string>
                                                                        <string key="NSFrame">{{343, 31}, {70, 18}}</string>
                                                                        <reference key="NSSuperview" ref="471332453"/>
                                                                        <reference key="NSWindow"/>
-                                                                       <reference key="NSNextKeyView"/>
                                                                        <string key="NSReuseIdentifierKey">_NS:9</string>
                                                                        <bool key="NSEnabled">YES</bool>
                                                                        <object class="NSButtonCell" key="NSCell" id="868379451">
@@ -1192,7 +1190,7 @@ aW5nLg</string>
                                <bool key="NSWindowIsRestorable">YES</bool>
                        </object>
                        <object class="NSCustomView" id="671181514">
-                               <nil key="NSNextResponder"/>
+                               <reference key="NSNextResponder"/>
                                <int key="NSvFlags">256</int>
                                <array class="NSMutableArray" key="NSSubviews">
                                        <object class="NSScrollView" id="443618264">
@@ -1208,6 +1206,7 @@ aW5nLg</string>
                                                                                <int key="NSvFlags">256</int>
                                                                                <string key="NSFrameSize">{198, 198}</string>
                                                                                <reference key="NSSuperview" ref="947403733"/>
+                                                                               <reference key="NSWindow"/>
                                                                                <reference key="NSNextKeyView" ref="553414014"/>
                                                                                <bool key="NSEnabled">YES</bool>
                                                                                <bool key="NSAllowsLogicalLayoutDirection">NO</bool>
@@ -1265,6 +1264,7 @@ aW5nLg</string>
                                                                </array>
                                                                <string key="NSFrame">{{1, 1}, {198, 198}}</string>
                                                                <reference key="NSSuperview" ref="443618264"/>
+                                                               <reference key="NSWindow"/>
                                                                <reference key="NSNextKeyView" ref="762432499"/>
                                                                <reference key="NSDocView" ref="762432499"/>
                                                                <reference key="NSBGColor" ref="834857663"/>
@@ -1275,6 +1275,7 @@ aW5nLg</string>
                                                                <int key="NSvFlags">-2147483392</int>
                                                                <string key="NSFrame">{{306, 1}, {15, 403}}</string>
                                                                <reference key="NSSuperview" ref="443618264"/>
+                                                               <reference key="NSWindow"/>
                                                                <reference key="NSNextKeyView" ref="861276216"/>
                                                                <bool key="NSAllowsLogicalLayoutDirection">NO</bool>
                                                                <reference key="NSTarget" ref="443618264"/>
@@ -1286,6 +1287,7 @@ aW5nLg</string>
                                                                <int key="NSvFlags">-2147483392</int>
                                                                <string key="NSFrame">{{-100, -100}, {366, 16}}</string>
                                                                <reference key="NSSuperview" ref="443618264"/>
+                                                               <reference key="NSWindow"/>
                                                                <reference key="NSNextKeyView" ref="947403733"/>
                                                                <bool key="NSAllowsLogicalLayoutDirection">NO</bool>
                                                                <int key="NSsFlags">1</int>
@@ -1296,6 +1298,7 @@ aW5nLg</string>
                                                </array>
                                                <string key="NSFrame">{{0, 20}, {200, 200}}</string>
                                                <reference key="NSSuperview" ref="671181514"/>
+                                               <reference key="NSWindow"/>
                                                <reference key="NSNextKeyView" ref="947403733"/>
                                                <int key="NSsFlags">150034</int>
                                                <reference key="NSVScroller" ref="968378655"/>
@@ -1311,6 +1314,7 @@ aW5nLg</string>
                                                <int key="NSvFlags">268</int>
                                                <string key="NSFrame">{{66, -1}, {68, 23}}</string>
                                                <reference key="NSSuperview" ref="671181514"/>
+                                               <reference key="NSWindow"/>
                                                <reference key="NSNextKeyView" ref="1023366520"/>
                                                <string key="NSReuseIdentifierKey">_NS:22</string>
                                                <bool key="NSEnabled">YES</bool>
@@ -1339,6 +1343,7 @@ aW5nLg</string>
                                                <int key="NSvFlags">292</int>
                                                <string key="NSFrame">{{0, -1}, {34, 23}}</string>
                                                <reference key="NSSuperview" ref="671181514"/>
+                                               <reference key="NSWindow"/>
                                                <reference key="NSNextKeyView" ref="456935010"/>
                                                <bool key="NSEnabled">YES</bool>
                                                <object class="NSButtonCell" key="NSCell" id="867532725">
@@ -1365,6 +1370,7 @@ aW5nLg</string>
                                                <int key="NSvFlags">292</int>
                                                <string key="NSFrame">{{166, -1}, {34, 23}}</string>
                                                <reference key="NSSuperview" ref="671181514"/>
+                                               <reference key="NSWindow"/>
                                                <bool key="NSEnabled">YES</bool>
                                                <object class="NSButtonCell" key="NSCell" id="828611353">
                                                        <int key="NSCellFlags">67108864</int>
@@ -1386,6 +1392,7 @@ aW5nLg</string>
                                                <int key="NSvFlags">292</int>
                                                <string key="NSFrame">{{133, -1}, {34, 23}}</string>
                                                <reference key="NSSuperview" ref="671181514"/>
+                                               <reference key="NSWindow"/>
                                                <reference key="NSNextKeyView" ref="1043784903"/>
                                                <bool key="NSEnabled">YES</bool>
                                                <object class="NSButtonCell" key="NSCell" id="57592747">
@@ -1408,6 +1415,7 @@ aW5nLg</string>
                                                <int key="NSvFlags">292</int>
                                                <string key="NSFrame">{{33, -1}, {34, 23}}</string>
                                                <reference key="NSSuperview" ref="671181514"/>
+                                               <reference key="NSWindow"/>
                                                <reference key="NSNextKeyView" ref="149148392"/>
                                                <bool key="NSEnabled">YES</bool>
                                                <object class="NSButtonCell" key="NSCell" id="1008023024">
@@ -1431,6 +1439,8 @@ aW5nLg</string>
                                        </object>
                                </array>
                                <string key="NSFrameSize">{200, 220}</string>
+                               <reference key="NSSuperview"/>
+                               <reference key="NSWindow"/>
                                <reference key="NSNextKeyView" ref="443618264"/>
                                <string key="NSClassName">NSView</string>
                        </object>
@@ -1446,7 +1456,6 @@ aW5nLg</string>
                        <object class="NSCustomObject" id="801536542">
                                <string key="NSClassName">NJOutputController</string>
                        </object>
-                       <object class="NSViewController" id="328152383"/>
                        <object class="NSPopover" id="586993839">
                                <nil key="NSNextResponder"/>
                                <int key="NSAppearance">0</int>
@@ -1542,6 +1551,9 @@ aW5nLg</string>
                        <object class="NSCustomObject" id="647344717">
                                <string key="NSClassName">NJDeviceViewController</string>
                        </object>
+                       <object class="NSCustomObject" id="70919963">
+                               <string key="NSClassName">NJMappingsViewController</string>
+                       </object>
                </array>
                <object class="IBObjectContainer" key="IBDocument.Objects">
                        <array class="NSMutableArray" key="connectionRecords">
@@ -1643,19 +1655,19 @@ aW5nLg</string>
                                </object>
                                <object class="IBConnectionRecord">
                                        <object class="IBOutletConnection" key="connection">
-                                               <string key="label">delegate</string>
+                                               <string key="label">dataSource</string>
                                                <reference key="source" ref="762432499"/>
-                                               <reference key="destination" ref="468285243"/>
+                                               <reference key="destination" ref="70919963"/>
                                        </object>
-                                       <int key="connectionID">517</int>
+                                       <int key="connectionID">1001</int>
                                </object>
                                <object class="IBConnectionRecord">
                                        <object class="IBOutletConnection" key="connection">
-                                               <string key="label">dataSource</string>
+                                               <string key="label">delegate</string>
                                                <reference key="source" ref="762432499"/>
-                                               <reference key="destination" ref="468285243"/>
+                                               <reference key="destination" ref="70919963"/>
                                        </object>
-                                       <int key="connectionID">518</int>
+                                       <int key="connectionID">1002</int>
                                </object>
                                <object class="IBConnectionRecord">
                                        <object class="IBOutletConnection" key="connection">
@@ -1763,115 +1775,35 @@ aW5nLg</string>
                                </object>
                                <object class="IBConnectionRecord">
                                        <object class="IBActionConnection" key="connection">
-                                               <string key="label">removePressed:</string>
-                                               <reference key="source" ref="468285243"/>
-                                               <reference key="destination" ref="456935010"/>
-                                       </object>
-                                       <int key="connectionID">516</int>
-                               </object>
-                               <object class="IBConnectionRecord">
-                                       <object class="IBOutletConnection" key="connection">
-                                               <string key="label">removeButton</string>
-                                               <reference key="source" ref="468285243"/>
-                                               <reference key="destination" ref="456935010"/>
-                                       </object>
-                                       <int key="connectionID">519</int>
-                               </object>
-                               <object class="IBConnectionRecord">
-                                       <object class="IBOutletConnection" key="connection">
-                                               <string key="label">tableView</string>
-                                               <reference key="source" ref="468285243"/>
-                                               <reference key="destination" ref="762432499"/>
-                                       </object>
-                                       <int key="connectionID">520</int>
-                               </object>
-                               <object class="IBConnectionRecord">
-                                       <object class="IBActionConnection" key="connection">
-                                               <string key="label">exportPressed:</string>
-                                               <reference key="source" ref="468285243"/>
+                                               <string key="label">exportMappingClicked:</string>
+                                               <reference key="source" ref="207406104"/>
                                                <reference key="destination" ref="888617891"/>
                                        </object>
-                                       <int key="connectionID">815</int>
+                                       <int key="connectionID">1015</int>
                                </object>
                                <object class="IBConnectionRecord">
                                        <object class="IBActionConnection" key="connection">
-                                               <string key="label">importPressed:</string>
-                                               <reference key="source" ref="468285243"/>
+                                               <string key="label">importMappingClicked:</string>
+                                               <reference key="source" ref="207406104"/>
                                                <reference key="destination" ref="187155117"/>
                                        </object>
-                                       <int key="connectionID">816</int>
-                               </object>
-                               <object class="IBConnectionRecord">
-                                       <object class="IBActionConnection" key="connection">
-                                               <string key="label">mappingPressed:</string>
-                                               <reference key="source" ref="468285243"/>
-                                               <reference key="destination" ref="227597319"/>
-                                       </object>
-                                       <int key="connectionID">855</int>
-                               </object>
-                               <object class="IBConnectionRecord">
-                                       <object class="IBOutletConnection" key="connection">
-                                               <string key="label">popover</string>
-                                               <reference key="source" ref="468285243"/>
-                                               <reference key="destination" ref="586993839"/>
-                                       </object>
-                                       <int key="connectionID">856</int>
-                               </object>
-                               <object class="IBConnectionRecord">
-                                       <object class="IBOutletConnection" key="connection">
-                                               <string key="label">popoverActivate</string>
-                                               <reference key="source" ref="468285243"/>
-                                               <reference key="destination" ref="227597319"/>
-                                       </object>
-                                       <int key="connectionID">857</int>
-                               </object>
-                               <object class="IBConnectionRecord">
-                                       <object class="IBActionConnection" key="connection">
-                                               <string key="label">addPressed:</string>
-                                               <reference key="source" ref="468285243"/>
-                                               <reference key="destination" ref="861276216"/>
-                                       </object>
-                                       <int key="connectionID">515</int>
+                                       <int key="connectionID">1016</int>
                                </object>
                                <object class="IBConnectionRecord">
                                        <object class="IBActionConnection" key="connection">
-                                               <string key="label">moveUpPressed:</string>
-                                               <reference key="source" ref="468285243"/>
-                                               <reference key="destination" ref="1023366520"/>
-                                       </object>
-                                       <int key="connectionID">899</int>
-                               </object>
-                               <object class="IBConnectionRecord">
-                                       <object class="IBActionConnection" key="connection">
-                                               <string key="label">moveDownPressed:</string>
-                                               <reference key="source" ref="468285243"/>
-                                               <reference key="destination" ref="1043784903"/>
-                                       </object>
-                                       <int key="connectionID">900</int>
-                               </object>
-                               <object class="IBConnectionRecord">
-                                       <object class="IBOutletConnection" key="connection">
-                                               <string key="label">moveUp</string>
-                                               <reference key="source" ref="468285243"/>
-                                               <reference key="destination" ref="1023366520"/>
+                                               <string key="label">performClick:</string>
+                                               <reference key="source" ref="861276216"/>
+                                               <reference key="destination" ref="331930027"/>
                                        </object>
-                                       <int key="connectionID">901</int>
+                                       <int key="connectionID">1012</int>
                                </object>
                                <object class="IBConnectionRecord">
                                        <object class="IBOutletConnection" key="connection">
-                                               <string key="label">moveDown</string>
-                                               <reference key="source" ref="468285243"/>
-                                               <reference key="destination" ref="1043784903"/>
-                                       </object>
-                                       <int key="connectionID">902</int>
-                               </object>
-                               <object class="IBConnectionRecord">
-                                       <object class="IBActionConnection" key="connection">
-                                               <string key="label">addPressed:</string>
+                                               <string key="label">mvc</string>
                                                <reference key="source" ref="468285243"/>
-                                               <reference key="destination" ref="331930027"/>
+                                               <reference key="destination" ref="70919963"/>
                                        </object>
-                                       <int key="connectionID">971</int>
+                                       <int key="connectionID">995</int>
                                </object>
                                <object class="IBConnectionRecord">
                                        <object class="IBOutletConnection" key="connection">
@@ -2057,29 +1989,21 @@ aW5nLg</string>
                                        </object>
                                        <int key="connectionID">871</int>
                                </object>
-                               <object class="IBConnectionRecord">
-                                       <object class="IBOutletConnection" key="connection">
-                                               <string key="label">view</string>
-                                               <reference key="source" ref="328152383"/>
-                                               <reference key="destination" ref="671181514"/>
-                                       </object>
-                                       <int key="connectionID">854</int>
-                               </object>
                                <object class="IBConnectionRecord">
                                        <object class="IBOutletConnection" key="connection">
                                                <string key="label">contentViewController</string>
                                                <reference key="source" ref="586993839"/>
-                                               <reference key="destination" ref="328152383"/>
+                                               <reference key="destination" ref="70919963"/>
                                        </object>
-                                       <int key="connectionID">852</int>
+                                       <int key="connectionID">996</int>
                                </object>
                                <object class="IBConnectionRecord">
                                        <object class="IBOutletConnection" key="connection">
                                                <string key="label">delegate</string>
                                                <reference key="source" ref="586993839"/>
-                                               <reference key="destination" ref="468285243"/>
+                                               <reference key="destination" ref="70919963"/>
                                        </object>
-                                       <int key="connectionID">853</int>
+                                       <int key="connectionID">1004</int>
                                </object>
                                <object class="IBConnectionRecord">
                                        <object class="IBActionConnection" key="connection">
@@ -2217,6 +2141,110 @@ aW5nLg</string>
                                        </object>
                                        <int key="connectionID">989</int>
                                </object>
+                               <object class="IBConnectionRecord">
+                                       <object class="IBOutletConnection" key="connection">
+                                               <string key="label">delegate</string>
+                                               <reference key="source" ref="70919963"/>
+                                               <reference key="destination" ref="468285243"/>
+                                       </object>
+                                       <int key="connectionID">994</int>
+                               </object>
+                               <object class="IBConnectionRecord">
+                                       <object class="IBOutletConnection" key="connection">
+                                               <string key="label">view</string>
+                                               <reference key="source" ref="70919963"/>
+                                               <reference key="destination" ref="671181514"/>
+                                       </object>
+                                       <int key="connectionID">997</int>
+                               </object>
+                               <object class="IBConnectionRecord">
+                                       <object class="IBActionConnection" key="connection">
+                                               <string key="label">mappingTriggerClicked:</string>
+                                               <reference key="source" ref="70919963"/>
+                                               <reference key="destination" ref="496378711"/>
+                                       </object>
+                                       <int key="connectionID">998</int>
+                               </object>
+                               <object class="IBConnectionRecord">
+                                       <object class="IBOutletConnection" key="connection">
+                                               <string key="label">mappingListTrigger</string>
+                                               <reference key="source" ref="70919963"/>
+                                               <reference key="destination" ref="227597319"/>
+                                       </object>
+                                       <int key="connectionID">999</int>
+                               </object>
+                               <object class="IBConnectionRecord">
+                                       <object class="IBOutletConnection" key="connection">
+                                               <string key="label">mappingListPopover</string>
+                                               <reference key="source" ref="70919963"/>
+                                               <reference key="destination" ref="586993839"/>
+                                       </object>
+                                       <int key="connectionID">1000</int>
+                               </object>
+                               <object class="IBConnectionRecord">
+                                       <object class="IBOutletConnection" key="connection">
+                                               <string key="label">mappingList</string>
+                                               <reference key="source" ref="70919963"/>
+                                               <reference key="destination" ref="762432499"/>
+                                       </object>
+                                       <int key="connectionID">1003</int>
+                               </object>
+                               <object class="IBConnectionRecord">
+                                       <object class="IBActionConnection" key="connection">
+                                               <string key="label">removeClicked:</string>
+                                               <reference key="source" ref="70919963"/>
+                                               <reference key="destination" ref="456935010"/>
+                                       </object>
+                                       <int key="connectionID">1005</int>
+                               </object>
+                               <object class="IBConnectionRecord">
+                                       <object class="IBOutletConnection" key="connection">
+                                               <string key="label">removeMapping</string>
+                                               <reference key="source" ref="70919963"/>
+                                               <reference key="destination" ref="456935010"/>
+                                       </object>
+                                       <int key="connectionID">1006</int>
+                               </object>
+                               <object class="IBConnectionRecord">
+                                       <object class="IBActionConnection" key="connection">
+                                               <string key="label">addClicked:</string>
+                                               <reference key="source" ref="70919963"/>
+                                               <reference key="destination" ref="861276216"/>
+                                       </object>
+                                       <int key="connectionID">1007</int>
+                               </object>
+                               <object class="IBConnectionRecord">
+                                       <object class="IBActionConnection" key="connection">
+                                               <string key="label">moveDownClicked:</string>
+                                               <reference key="source" ref="70919963"/>
+                                               <reference key="destination" ref="1043784903"/>
+                                       </object>
+                                       <int key="connectionID">1008</int>
+                               </object>
+                               <object class="IBConnectionRecord">
+                                       <object class="IBActionConnection" key="connection">
+                                               <string key="label">moveUpClicked:</string>
+                                               <reference key="source" ref="70919963"/>
+                                               <reference key="destination" ref="1023366520"/>
+                                       </object>
+                                       <int key="connectionID">1009</int>
+                               </object>
+                               <object class="IBConnectionRecord">
+                                       <object class="IBOutletConnection" key="connection">
+                                               <string key="label">moveDown</string>
+                                               <reference key="source" ref="70919963"/>
+                                               <reference key="destination" ref="1043784903"/>
+                                       </object>
+                                       <int key="connectionID">1010</int>
+                               </object>
+                               <object class="IBConnectionRecord">
+                                       <object class="IBOutletConnection" key="connection">
+                                               <string key="label">moveUp</string>
+                                               <reference key="source" ref="70919963"/>
+                                               <reference key="destination" ref="1023366520"/>
+                                       </object>
+                                       <int key="connectionID">1011</int>
+                               </object>
                        </array>
                        <object class="IBMutableOrderedSet" key="objectRecords">
                                <array key="orderedObjects">
@@ -2555,12 +2583,6 @@ aW5nLg</string>
                                                <reference key="object" ref="658903347"/>
                                                <reference key="parent" ref="1043384830"/>
                                        </object>
-                                       <object class="IBObjectRecord">
-                                               <int key="objectID">850</int>
-                                               <reference key="object" ref="328152383"/>
-                                               <reference key="parent" ref="0"/>
-                                               <string key="objectName">Popover View Controller</string>
-                                       </object>
                                        <object class="IBObjectRecord">
                                                <int key="objectID">851</int>
                                                <reference key="object" ref="586993839"/>
@@ -3052,6 +3074,11 @@ aW5nLg</string>
                                                <reference key="object" ref="647344717"/>
                                                <reference key="parent" ref="0"/>
                                        </object>
+                                       <object class="IBObjectRecord">
+                                               <int key="objectID">993</int>
+                                               <reference key="object" ref="70919963"/>
+                                               <reference key="parent" ref="0"/>
+                                       </object>
                                </array>
                        </object>
                        <dictionary class="NSMutableDictionary" key="flattenedProperties">
@@ -3163,7 +3190,6 @@ aW5nLg</string>
                                <string key="837.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
                                <boolean value="NO" key="837.toolbarItem.selectable"/>
                                <string key="849.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
-                               <string key="850.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
                                <string key="851.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
                                <string key="862.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
                                <string key="863.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
@@ -3304,29 +3330,38 @@ aW5nLg</string>
                                <string key="974.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
                                <string key="975.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
                                <string key="983.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
+                               <string key="993.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
                        </dictionary>
                        <dictionary class="NSMutableDictionary" key="unlocalizedProperties"/>
                        <nil key="activeLocalization"/>
                        <dictionary class="NSMutableDictionary" key="localizations"/>
                        <nil key="sourceID"/>
-                       <int key="maxID">992</int>
+                       <int key="maxID">1016</int>
                </object>
                <object class="IBClassDescriber" key="IBDocument.Classes">
                        <array class="NSMutableArray" key="referencedPartialClassDescriptions">
                                <object class="IBPartialClassDescription">
                                        <string key="className">EnjoyableApplicationDelegate</string>
                                        <string key="superclassName">NSObject</string>
-                                       <object class="NSMutableDictionary" key="actions">
-                                               <string key="NS.key.0">restoreToForeground:</string>
-                                               <string key="NS.object.0">id</string>
-                                       </object>
-                                       <object class="NSMutableDictionary" key="actionInfosByName">
-                                               <string key="NS.key.0">restoreToForeground:</string>
-                                               <object class="IBActionInfo" key="NS.object.0">
+                                       <dictionary class="NSMutableDictionary" key="actions">
+                                               <string key="exportMappingClicked:">id</string>
+                                               <string key="importMappingClicked:">id</string>
+                                               <string key="restoreToForeground:">id</string>
+                                       </dictionary>
+                                       <dictionary class="NSMutableDictionary" key="actionInfosByName">
+                                               <object class="IBActionInfo" key="exportMappingClicked:">
+                                                       <string key="name">exportMappingClicked:</string>
+                                                       <string key="candidateClassName">id</string>
+                                               </object>
+                                               <object class="IBActionInfo" key="importMappingClicked:">
+                                                       <string key="name">importMappingClicked:</string>
+                                                       <string key="candidateClassName">id</string>
+                                               </object>
+                                               <object class="IBActionInfo" key="restoreToForeground:">
                                                        <string key="name">restoreToForeground:</string>
                                                        <string key="candidateClassName">id</string>
                                                </object>
-                                       </object>
+                                       </dictionary>
                                        <dictionary class="NSMutableDictionary" key="outlets">
                                                <string key="dockMenu">NSMenu</string>
                                                <string key="mappingsController">NJMappingsController</string>
@@ -3480,54 +3515,80 @@ aW5nLg</string>
                                <object class="IBPartialClassDescription">
                                        <string key="className">NJMappingsController</string>
                                        <string key="superclassName">NSObject</string>
+                                       <object class="NSMutableDictionary" key="outlets">
+                                               <string key="NS.key.0">mvc</string>
+                                               <string key="NS.object.0">NJMappingsViewController</string>
+                                       </object>
+                                       <object class="NSMutableDictionary" key="toOneOutletInfosByName">
+                                               <string key="NS.key.0">mvc</string>
+                                               <object class="IBToOneOutletInfo" key="NS.object.0">
+                                                       <string key="name">mvc</string>
+                                                       <string key="candidateClassName">NJMappingsViewController</string>
+                                               </object>
+                                       </object>
+                                       <object class="IBClassDescriptionSource" key="sourceIdentifier">
+                                               <string key="majorKey">IBProjectSource</string>
+                                               <string key="minorKey">./Classes/NJMappingsController.h</string>
+                                       </object>
+                               </object>
+                               <object class="IBPartialClassDescription">
+                                       <string key="className">NJMappingsViewController</string>
+                                       <string key="superclassName">NSViewController</string>
                                        <dictionary class="NSMutableDictionary" key="actions">
-                                               <string key="addPressed:">id</string>
-                                               <string key="exportPressed:">id</string>
-                                               <string key="importPressed:">id</string>
-                                               <string key="mappingPressed:">id</string>
-                                               <string key="moveDownPressed:">id</string>
-                                               <string key="moveUpPressed:">id</string>
-                                               <string key="removePressed:">id</string>
+                                               <string key="addClicked:">id</string>
+                                               <string key="mappingTriggerClicked:">id</string>
+                                               <string key="moveDownClicked:">id</string>
+                                               <string key="moveUpClicked:">id</string>
+                                               <string key="removeClicked:">id</string>
                                        </dictionary>
                                        <dictionary class="NSMutableDictionary" key="actionInfosByName">
-                                               <object class="IBActionInfo" key="addPressed:">
-                                                       <string key="name">addPressed:</string>
+                                               <object class="IBActionInfo" key="addClicked:">
+                                                       <string key="name">addClicked:</string>
                                                        <string key="candidateClassName">id</string>
                                                </object>
-                                               <object class="IBActionInfo" key="exportPressed:">
-                                                       <string key="name">exportPressed:</string>
+                                               <object class="IBActionInfo" key="mappingTriggerClicked:">
+                                                       <string key="name">mappingTriggerClicked:</string>
                                                        <string key="candidateClassName">id</string>
                                                </object>
-                                               <object class="IBActionInfo" key="importPressed:">
-                                                       <string key="name">importPressed:</string>
+                                               <object class="IBActionInfo" key="moveDownClicked:">
+                                                       <string key="name">moveDownClicked:</string>
                                                        <string key="candidateClassName">id</string>
                                                </object>
-                                               <object class="IBActionInfo" key="mappingPressed:">
-                                                       <string key="name">mappingPressed:</string>
+                                               <object class="IBActionInfo" key="moveUpClicked:">
+                                                       <string key="name">moveUpClicked:</string>
                                                        <string key="candidateClassName">id</string>
                                                </object>
-                                               <object class="IBActionInfo" key="moveDownPressed:">
-                                                       <string key="name">moveDownPressed:</string>
-                                                       <string key="candidateClassName">id</string>
-                                               </object>
-                                               <object class="IBActionInfo" key="moveUpPressed:">
-                                                       <string key="name">moveUpPressed:</string>
-                                                       <string key="candidateClassName">id</string>
-                                               </object>
-                                               <object class="IBActionInfo" key="removePressed:">
-                                                       <string key="name">removePressed:</string>
+                                               <object class="IBActionInfo" key="removeClicked:">
+                                                       <string key="name">removeClicked:</string>
                                                        <string key="candidateClassName">id</string>
                                                </object>
                                        </dictionary>
                                        <dictionary class="NSMutableDictionary" key="outlets">
+                                               <string key="delegate">id</string>
+                                               <string key="mappingList">NSTableView</string>
+                                               <string key="mappingListPopover">NSPopover</string>
+                                               <string key="mappingListTrigger">NSButton</string>
                                                <string key="moveDown">NSButton</string>
                                                <string key="moveUp">NSButton</string>
-                                               <string key="popover">NSPopover</string>
-                                               <string key="popoverActivate">NSButton</string>
-                                               <string key="removeButton">NSButton</string>
-                                               <string key="tableView">NSTableView</string>
+                                               <string key="removeMapping">NSButton</string>
                                        </dictionary>
                                        <dictionary class="NSMutableDictionary" key="toOneOutletInfosByName">
+                                               <object class="IBToOneOutletInfo" key="delegate">
+                                                       <string key="name">delegate</string>
+                                                       <string key="candidateClassName">id</string>
+                                               </object>
+                                               <object class="IBToOneOutletInfo" key="mappingList">
+                                                       <string key="name">mappingList</string>
+                                                       <string key="candidateClassName">NSTableView</string>
+                                               </object>
+                                               <object class="IBToOneOutletInfo" key="mappingListPopover">
+                                                       <string key="name">mappingListPopover</string>
+                                                       <string key="candidateClassName">NSPopover</string>
+                                               </object>
+                                               <object class="IBToOneOutletInfo" key="mappingListTrigger">
+                                                       <string key="name">mappingListTrigger</string>
+                                                       <string key="candidateClassName">NSButton</string>
+                                               </object>
                                                <object class="IBToOneOutletInfo" key="moveDown">
                                                        <string key="name">moveDown</string>
                                                        <string key="candidateClassName">NSButton</string>
@@ -3536,26 +3597,14 @@ aW5nLg</string>
                                                        <string key="name">moveUp</string>
                                                        <string key="candidateClassName">NSButton</string>
                                                </object>
-                                               <object class="IBToOneOutletInfo" key="popover">
-                                                       <string key="name">popover</string>
-                                                       <string key="candidateClassName">NSPopover</string>
-                                               </object>
-                                               <object class="IBToOneOutletInfo" key="popoverActivate">
-                                                       <string key="name">popoverActivate</string>
-                                                       <string key="candidateClassName">NSButton</string>
-                                               </object>
-                                               <object class="IBToOneOutletInfo" key="removeButton">
-                                                       <string key="name">removeButton</string>
+                                               <object class="IBToOneOutletInfo" key="removeMapping">
+                                                       <string key="name">removeMapping</string>
                                                        <string key="candidateClassName">NSButton</string>
                                                </object>
-                                               <object class="IBToOneOutletInfo" key="tableView">
-                                                       <string key="name">tableView</string>
-                                                       <string key="candidateClassName">NSTableView</string>
-                                               </object>
                                        </dictionary>
                                        <object class="IBClassDescriptionSource" key="sourceIdentifier">
                                                <string key="majorKey">IBProjectSource</string>
-                                               <string key="minorKey">./Classes/NJMappingsController.h</string>
+                                               <string key="minorKey">./Classes/NJMappingsViewController.h</string>
                                        </object>
                                </object>
                                <object class="IBPartialClassDescription">