diff --git a/MacPass/Base.lproj/MainMenu.xib b/MacPass/Base.lproj/MainMenu.xib index 8db4e4ba..31f8eb34 100644 --- a/MacPass/Base.lproj/MainMenu.xib +++ b/MacPass/Base.lproj/MainMenu.xib @@ -151,9 +151,9 @@ - + - + @@ -167,16 +167,20 @@ - + - + - + + + + + @@ -357,6 +361,7 @@ CA + diff --git a/MacPass/MPAppDelegate.h b/MacPass/MPAppDelegate.h index 2e40e15c..6c159652 100644 --- a/MacPass/MPAppDelegate.h +++ b/MacPass/MPAppDelegate.h @@ -33,6 +33,7 @@ APPKIT_EXTERN NSString *const MPDidChangeStoredKeyFilesSettings; @property (strong) IBOutlet NSMenuItem *fileNewMenuItem; @property (strong) IBOutlet NSMenu *itemMenu; @property (strong) IBOutlet NSMenu *importMenu; +@property (strong) IBOutlet NSMenu *exportMenu; @property (strong, readonly) MPEntryContextMenuDelegate *itemActionMenuDelegate; diff --git a/MacPass/MPAppDelegate.m b/MacPass/MPAppDelegate.m index 742bcd0d..7ccae156 100644 --- a/MacPass/MPAppDelegate.m +++ b/MacPass/MPAppDelegate.m @@ -240,22 +240,36 @@ typedef NS_OPTIONS(NSInteger, MPAppStartupState) { NSString *saveTitle = displayDots ? NSLocalizedString(@"SAVE_WITH_DOTS", "Save file menu item title when save will prompt for a location to save or ask for a password/key") : NSLocalizedString(@"SAVE", "Save file menu item title when save will just save the file"); self.saveMenuItem.title = saveTitle; } - if(menu == self.fixAutotypeMenuItem.menu) { + else if(menu == self.fixAutotypeMenuItem.menu) { self.fixAutotypeMenuItem.hidden = !(NSEvent.modifierFlags & NSAlternateKeyMask); } - if(menu == self.importMenu) { + else if(menu == self.importMenu) { NSMenuItem *exportXML = menu.itemArray.firstObject; [menu removeAllItems]; + [menu addItem:exportXML]; for(MPPlugin * plugin in MPPluginHost.sharedHost.importPlugins) { NSMenuItem *importItem = [[NSMenuItem alloc] init]; [plugin prepareImportMenuItem:importItem]; importItem.submenu = nil; // kill any potential submenu! importItem.representedObject = plugin.identifier; importItem.target = nil; - importItem.action = @selector(importFromPlugin:); + importItem.action = @selector(importWithPlugin:); [menu addItem:importItem]; } - [menu insertItem:exportXML atIndex:0]; + } + else if(menu == self.exportMenu) { + NSMenuItem *importXML = menu.itemArray.firstObject; + [menu removeAllItems]; + [menu addItem:importXML]; + for(MPPlugin * plugin in MPPluginHost.sharedHost.exportPlugins) { + NSMenuItem *exportItem = [[NSMenuItem alloc] init]; + [plugin prepareExportMenuItem:exportItem]; + exportItem.submenu = nil; // kill any potential submenu! + exportItem.representedObject = plugin.identifier; + exportItem.target = nil; + exportItem.action = @selector(exportWithPlugin:); + [menu addItem:exportItem]; + } } } diff --git a/MacPass/MPDocumentWindowController.h b/MacPass/MPDocumentWindowController.h index 2b51042c..0927427e 100644 --- a/MacPass/MPDocumentWindowController.h +++ b/MacPass/MPDocumentWindowController.h @@ -58,7 +58,8 @@ - (IBAction)exportAsXML:(id)sender; - (IBAction)mergeWithOther:(id)sender; - (IBAction)importFromXML:(id)sender; -- (IBAction)importFromPlugin:(id)sender; +- (IBAction)importWithPlugin:(id)sender; +- (IBAction)exportWithPlugin:(id)sender; - (IBAction)lock:(id)sender; - (IBAction)createGroup:(id)sender; diff --git a/MacPass/MPDocumentWindowController.m b/MacPass/MPDocumentWindowController.m index 5f7e8595..85fa5f06 100644 --- a/MacPass/MPDocumentWindowController.m +++ b/MacPass/MPDocumentWindowController.m @@ -279,7 +279,7 @@ typedef void (^MPPasswordChangedBlock)(BOOL didChangePassword); }]; } -- (void)importFromPlugin:(id)sender { +- (void)importWithPlugin:(id)sender { if(![sender isKindOfClass:NSMenuItem.class]) { return; } @@ -304,6 +304,30 @@ typedef void (^MPPasswordChangedBlock)(BOOL didChangePassword); }]; } +- (void)exportWithPlugin:(id)sender { + if(![sender isKindOfClass:NSMenuItem.class]) { + return; + } + NSMenuItem *menuItem = sender; + if(![menuItem.representedObject isKindOfClass:NSString.class]) { + return; + } + + NSWindow *sheetWindow = ((MPDocument *)self.document).windowForSheet; + if(!sheetWindow) { + return; + } + NSString *bundleIdentifier = menuItem.representedObject; + MPPlugin *exportPlugin = (MPPlugin *)[MPPluginHost.sharedHost pluginWithBundleIdentifier:bundleIdentifier]; + NSSavePanel *savePanel = NSSavePanel.savePanel; + [exportPlugin prepareSavePanel:savePanel]; + [savePanel beginSheetModalForWindow:sheetWindow completionHandler:^(NSModalResponse result) { + if(result == NSModalResponseOK) { + [exportPlugin exportTree:((MPDocument *)self.document).tree forRunningSavePanel:savePanel]; + } + }]; +} + - (void)mergeWithOther:(id)sender { NSOpenPanel *openPanel = [NSOpenPanel openPanel]; MPDocument *document = self.document; diff --git a/MacPass/MPPlugin.h b/MacPass/MPPlugin.h index 1a1e82ac..1801c940 100644 --- a/MacPass/MPPlugin.h +++ b/MacPass/MPPlugin.h @@ -141,9 +141,20 @@ FOUNDATION_EXPORT NSString *const MPPluginDescriptionInfoDictionaryKey; @param panel The open panel used for selecting what file(s) to import @return The KPKTree constructed from the selected input file(s) */ -- (KPKTree *)treeForRunningOpenPanel:(NSOpenPanel *)panel; +- (nullable KPKTree *)treeForRunningOpenPanel:(NSOpenPanel *)panel; @end +@protocol MPExportPlugin + +@required + +- (void)prepareExportMenuItem:(NSMenuItem *)item; +- (void)prepareSavePanel:(NSSavePanel *)panel; +- (void)exportTree:(KPKTree *)tree forRunningSavePanel:(NSSavePanel *)panel; + +@end + + #pragma mark Deprecated @interface MPPlugin (Deprecated) diff --git a/MacPass/MPPluginHost.h b/MacPass/MPPluginHost.h index 94e10180..f0edd35e 100644 --- a/MacPass/MPPluginHost.h +++ b/MacPass/MPPluginHost.h @@ -32,6 +32,7 @@ FOUNDATION_EXPORT NSString *const MPPluginHostPluginBundleIdentifiyerKey; @class MPPlugin; @class KPKEntry; @protocol MPImportPlugin; +@protocol MPExportPlugin; @protocol MPAutotypeWindowTitleResolverPlugin; @interface MPPluginHost : NSObject @@ -53,9 +54,10 @@ FOUNDATION_EXPORT NSString *const MPPluginHostPluginBundleIdentifiyerKey; - (NSArray *)avilableMenuItemsForEntries:(NSArray *)entries; @end -@interface MPPluginHost (MPImportPluginSupport) +@interface MPPluginHost (MPImportExportPluginSupport) @property (readonly, copy) NSArray __kindof*> *importPlugins; +@property (readonly, copy) NSArray __kindof*> *exportPlugins; @end diff --git a/MacPass/MPPluginHost.m b/MacPass/MPPluginHost.m index e85366e7..1ef42a01 100644 --- a/MacPass/MPPluginHost.m +++ b/MacPass/MPPluginHost.m @@ -459,11 +459,14 @@ NSString *const MPPluginHostPluginBundleIdentifiyerKey = @"MPPluginHostPluginBun NSString *const MPPluginBundleIdentifierKey = @"MPPluginBundleIdentifierKey"; NSString *const MPImportPluginUTIKey = @"MPImportPluginUTIKey"; -@implementation MPPluginHost (MPImportPluginSupport) +@implementation MPPluginHost (MPImportExportPluginSupport) - (NSArray *)importPlugins { return [self _pluginsConformingToProtocoll:@protocol(MPImportPlugin)]; } +- (NSArray *> *)exportPlugins { + return [self _pluginsConformingToProtocoll:@protocol(MPExportPlugin)]; +} @end