From 5574b01feda0af7b2547d31f25154b5d0b4415b5 Mon Sep 17 00:00:00 2001 From: Michael Starke Date: Tue, 5 Dec 2017 15:56:06 +0100 Subject: [PATCH] Stubbed custom attribute adding via context menu Made MPContextToolbarButton usable as normal button. Added private API helper for adding buttons to NSUserNotification Remove Autotype plugin API Enhanced custom attribute plugin API Enhanced EntryActionPlugin API to decouple menu items from actual action/target setup Stubbed action on no-open documents NSUserNotifications Stubbed HMACOTP custom attribute setup --- MacPass.xcodeproj/project.pbxproj | 24 ++++-- MacPass/Base.lproj/EntryInspectorView.xib | 39 ++++----- MacPass/MPAddCustomFieldContextMenuDelegate.h | 15 ++++ MacPass/MPAddCustomFieldContextMenuDelegate.m | 58 ++++++++++++++ MacPass/MPAppDelegate.m | 3 + MacPass/MPAutotypeDaemon.m | 12 ++- ...ntextToolbarButton.h => MPContextButton.h} | 8 +- ...ntextToolbarButton.m => MPContextButton.m} | 80 +++++++++---------- MacPass/MPDocumentWindowController.m | 2 +- MacPass/MPEntryInspectorViewController.h | 3 +- MacPass/MPEntryInspectorViewController.m | 15 ++++ MacPass/MPPickcharsParser.m | 2 +- MacPass/MPPlugin.h | 37 +++------ MacPass/MPToolbarDelegate.m | 10 +-- MacPass/MPTreeDelegate.m | 2 +- MacPass/MPUserNotificationCenterDelegate.m | 4 + MacPass/MacPass-Info.plist | 2 + MacPass/NSUserNotification+MPAdditions.h | 15 ++++ MacPass/NSUserNotification+MPAdditions.m | 21 +++++ MacPass/en.lproj/Localizable.strings | 3 + 20 files changed, 243 insertions(+), 112 deletions(-) create mode 100644 MacPass/MPAddCustomFieldContextMenuDelegate.h create mode 100644 MacPass/MPAddCustomFieldContextMenuDelegate.m rename MacPass/{MPContextToolbarButton.h => MPContextButton.h} (83%) rename MacPass/{MPContextToolbarButton.m => MPContextButton.m} (60%) create mode 100644 MacPass/NSUserNotification+MPAdditions.h create mode 100644 MacPass/NSUserNotification+MPAdditions.m diff --git a/MacPass.xcodeproj/project.pbxproj b/MacPass.xcodeproj/project.pbxproj index f119444b..587b1073 100644 --- a/MacPass.xcodeproj/project.pbxproj +++ b/MacPass.xcodeproj/project.pbxproj @@ -12,6 +12,8 @@ 4C01C2421764D8980016D5D0 /* MPContextMenuHelper.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C01C2411764D8980016D5D0 /* MPContextMenuHelper.m */; }; 4C0728BD17B5B7F7005A7DD9 /* MPPasswordEditWindowController.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C0728BC17B5B7F7005A7DD9 /* MPPasswordEditWindowController.m */; }; 4C0728BF17B68ED0005A7DD9 /* SavePanelAccessoryView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 4C0728BE17B68ED0005A7DD9 /* SavePanelAccessoryView.xib */; }; + 4C0949591FD6B89B004F2971 /* NSUserNotification+MPAdditions.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C0949581FD6B89B004F2971 /* NSUserNotification+MPAdditions.m */; }; + 4C09495C1FD6E510004F2971 /* MPAddCustomFieldContextMenuDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C09495B1FD6E510004F2971 /* MPAddCustomFieldContextMenuDelegate.m */; }; 4C0AF62F195C1F2B009E658D /* MPEntrySearchContext.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C0AF62E195C1F2B009E658D /* MPEntrySearchContext.m */; }; 4C0B038C18E36DA400B9F9C9 /* MPFixAutotypeWindowController.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C0B038A18E36DA400B9F9C9 /* MPFixAutotypeWindowController.m */; }; 4C0B038D18E36DA400B9F9C9 /* FixAutotypeWindow.xib in Resources */ = {isa = PBXBuildFile; fileRef = 4C0B038B18E36DA400B9F9C9 /* FixAutotypeWindow.xib */; }; @@ -129,7 +131,7 @@ 4C5FE9AE17843CE20001D5A8 /* MPSelectedAttachmentTableCellView.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C5FE9AD17843CE20001D5A8 /* MPSelectedAttachmentTableCellView.m */; }; 4C61EA0316D2FD0800AC519E /* MPOutlineViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C61EA0216D2FD0800AC519E /* MPOutlineViewController.m */; }; 4C61EA0516D2FFE200AC519E /* OutlineView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 4C61EA0416D2FFE200AC519E /* OutlineView.xib */; }; - 4C63B8FB17A3154D0091BD72 /* MPContextToolbarButton.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C63B8FA17A3154D0091BD72 /* MPContextToolbarButton.m */; }; + 4C63B8FB17A3154D0091BD72 /* MPContextButton.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C63B8FA17A3154D0091BD72 /* MPContextButton.m */; }; 4C65C79C16DD283900E32CFF /* MPToolbarButton.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C65C79B16DD283900E32CFF /* MPToolbarButton.m */; }; 4C65FAE916D16DDB006E0577 /* MPPasswordInputController.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C65FAE716D16DDB006E0577 /* MPPasswordInputController.m */; }; 4C663D411D6D91A900CB6237 /* MPNumberFormatter.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C663D401D6D91A900CB6237 /* MPNumberFormatter.m */; }; @@ -324,6 +326,10 @@ 4C0728BB17B5B7F7005A7DD9 /* MPPasswordEditWindowController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPPasswordEditWindowController.h; sourceTree = ""; }; 4C0728BC17B5B7F7005A7DD9 /* MPPasswordEditWindowController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPPasswordEditWindowController.m; sourceTree = ""; }; 4C0728BE17B68ED0005A7DD9 /* SavePanelAccessoryView.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = SavePanelAccessoryView.xib; sourceTree = ""; }; + 4C0949571FD6B89B004F2971 /* NSUserNotification+MPAdditions.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "NSUserNotification+MPAdditions.h"; sourceTree = ""; }; + 4C0949581FD6B89B004F2971 /* NSUserNotification+MPAdditions.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "NSUserNotification+MPAdditions.m"; sourceTree = ""; }; + 4C09495A1FD6E510004F2971 /* MPAddCustomFieldContextMenuDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MPAddCustomFieldContextMenuDelegate.h; sourceTree = ""; }; + 4C09495B1FD6E510004F2971 /* MPAddCustomFieldContextMenuDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MPAddCustomFieldContextMenuDelegate.m; sourceTree = ""; }; 4C0AF62D195C1F2B009E658D /* MPEntrySearchContext.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPEntrySearchContext.h; sourceTree = ""; }; 4C0AF62E195C1F2B009E658D /* MPEntrySearchContext.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPEntrySearchContext.m; sourceTree = ""; }; 4C0B038918E36DA400B9F9C9 /* MPFixAutotypeWindowController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPFixAutotypeWindowController.h; sourceTree = ""; }; @@ -517,8 +523,8 @@ 4C61EA0116D2FD0800AC519E /* MPOutlineViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPOutlineViewController.h; sourceTree = ""; }; 4C61EA0216D2FD0800AC519E /* MPOutlineViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPOutlineViewController.m; sourceTree = ""; }; 4C61EA0416D2FFE200AC519E /* OutlineView.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = OutlineView.xib; sourceTree = ""; }; - 4C63B8F917A3154D0091BD72 /* MPContextToolbarButton.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPContextToolbarButton.h; sourceTree = ""; }; - 4C63B8FA17A3154D0091BD72 /* MPContextToolbarButton.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPContextToolbarButton.m; sourceTree = ""; }; + 4C63B8F917A3154D0091BD72 /* MPContextButton.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPContextButton.h; sourceTree = ""; }; + 4C63B8FA17A3154D0091BD72 /* MPContextButton.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPContextButton.m; sourceTree = ""; }; 4C65C79A16DD283900E32CFF /* MPToolbarButton.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPToolbarButton.h; sourceTree = ""; }; 4C65C79B16DD283900E32CFF /* MPToolbarButton.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPToolbarButton.m; sourceTree = ""; }; 4C65FAE616D16DDB006E0577 /* MPPasswordInputController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPPasswordInputController.h; sourceTree = ""; }; @@ -1005,6 +1011,8 @@ 4CDA35741EBA0CF2003CD59F /* NSString+MPComposedCharacterAdditions.m */, 4C8F0C771FD05A6A00BE157F /* NSString+MPPrettyPasswordDisplay.h */, 4C8F0C781FD05A6A00BE157F /* NSString+MPPrettyPasswordDisplay.m */, + 4C0949571FD6B89B004F2971 /* NSUserNotification+MPAdditions.h */, + 4C0949581FD6B89B004F2971 /* NSUserNotification+MPAdditions.m */, ); name = Categories; sourceTree = ""; @@ -1094,6 +1102,8 @@ 4CE501331BBC47F500FB819D /* MPTagsTokenFieldDelegate.m */, 4C2F17A01FD69BCA0097418D /* MPUserNotificationCenterDelegate.h */, 4C2F17A11FD69BCA0097418D /* MPUserNotificationCenterDelegate.m */, + 4C09495A1FD6E510004F2971 /* MPAddCustomFieldContextMenuDelegate.h */, + 4C09495B1FD6E510004F2971 /* MPAddCustomFieldContextMenuDelegate.m */, ); name = Delegates; sourceTree = ""; @@ -1515,8 +1525,8 @@ 4C65C79B16DD283900E32CFF /* MPToolbarButton.m */, 4C888C9116EB6F5E003D34A1 /* MPToolbarItem.h */, 4C888C9216EB6F5E003D34A1 /* MPToolbarItem.m */, - 4C63B8F917A3154D0091BD72 /* MPContextToolbarButton.h */, - 4C63B8FA17A3154D0091BD72 /* MPContextToolbarButton.m */, + 4C63B8F917A3154D0091BD72 /* MPContextButton.h */, + 4C63B8FA17A3154D0091BD72 /* MPContextButton.m */, 4C57AE1217BA422B00CA4F34 /* MPSegmentedContextCell.h */, 4C57AE1317BA422B00CA4F34 /* MPSegmentedContextCell.m */, 8345D7271F39023E002B7B0F /* MPPathControl.h */, @@ -1961,7 +1971,7 @@ 4CB33F861EAF54A000C9341E /* KPKNode+MPIsHistory.m in Sources */, 4CCEDE2E179F213B008402BE /* MPNotifications.m in Sources */, 4C17D8E517A1C780006C8C1E /* MPDocumentWindowDelegate.m in Sources */, - 4C63B8FB17A3154D0091BD72 /* MPContextToolbarButton.m in Sources */, + 4C63B8FB17A3154D0091BD72 /* MPContextButton.m in Sources */, 4C1E9885185F71A800943563 /* MPContextBarViewController.m in Sources */, 4C1FA07B18231900003A3F8C /* MPDocument+Autotype.m in Sources */, 4C4B7EE917A45EC6000234C7 /* MPDatePickingViewController.m in Sources */, @@ -1974,9 +1984,11 @@ 8345D7291F39023E002B7B0F /* MPPathControl.m in Sources */, 4CD7223B17A7CB0700F5A1E1 /* MPWorkflowSettingsController.m in Sources */, 4CA08DA017A831B200A6544B /* MPAddEntryContextMenuDelegate.m in Sources */, + 4C09495C1FD6E510004F2971 /* MPAddCustomFieldContextMenuDelegate.m in Sources */, 4CE3E62617AB0D2D00D9E4B4 /* MPAttachmentTableDataSource.m in Sources */, 4C0728BD17B5B7F7005A7DD9 /* MPPasswordEditWindowController.m in Sources */, 4C0F647B17B6BC9C00D9522A /* MPSavePanelAccessoryViewController.m in Sources */, + 4C0949591FD6B89B004F2971 /* NSUserNotification+MPAdditions.m in Sources */, 4C3B42871F935316007B04FD /* MPDayCountFormatter.m in Sources */, 4C57AE1417BA422B00CA4F34 /* MPSegmentedContextCell.m in Sources */, 4CE2961518429AA5005F01CE /* MPAutotypeKeyPress.m in Sources */, diff --git a/MacPass/Base.lproj/EntryInspectorView.xib b/MacPass/Base.lproj/EntryInspectorView.xib index f2048e0b..a3251099 100644 --- a/MacPass/Base.lproj/EntryInspectorView.xib +++ b/MacPass/Base.lproj/EntryInspectorView.xib @@ -1,8 +1,8 @@ - + - + @@ -10,7 +10,7 @@ - + @@ -455,17 +455,6 @@ - + + + + + + + + + + + + + + @@ -513,24 +516,24 @@ - - - + + + @@ -898,7 +901,7 @@ - + diff --git a/MacPass/MPAddCustomFieldContextMenuDelegate.h b/MacPass/MPAddCustomFieldContextMenuDelegate.h new file mode 100644 index 00000000..ce608fe7 --- /dev/null +++ b/MacPass/MPAddCustomFieldContextMenuDelegate.h @@ -0,0 +1,15 @@ +// +// MPAddCustomFieldContextMenuDelegate.h +// MacPass +// +// Created by Michael Starke on 05.12.17. +// Copyright © 2017 HicknHack Software GmbH. All rights reserved. +// + +#import + +@interface MPAddCustomFieldContextMenuDelegate : NSObject + +@property (weak) NSViewController *viewController; + +@end diff --git a/MacPass/MPAddCustomFieldContextMenuDelegate.m b/MacPass/MPAddCustomFieldContextMenuDelegate.m new file mode 100644 index 00000000..48bda314 --- /dev/null +++ b/MacPass/MPAddCustomFieldContextMenuDelegate.m @@ -0,0 +1,58 @@ +// +// MPAddCustomFieldContextMenuDelegate.m +// MacPass +// +// Created by Michael Starke on 05.12.17. +// Copyright © 2017 HicknHack Software GmbH. All rights reserved. +// + +#import "MPAddCustomFieldContextMenuDelegate.h" +#import "KeePassKit/KeePassKit.h" + +NSString *const MPHMACOTPSeedAttributeKey = @"HMACOTP-Seed"; +NSString *const MPHMACOTPConfigAttributeKey = @"HMACOTP-Config"; + +@interface MPAddCustomFieldContextMenuDelegate () +@property (readonly, nonatomic) KPKEntry *entry; +@end + +@implementation MPAddCustomFieldContextMenuDelegate + +- (KPKEntry *)entry { + KPKEntry *entry = self.viewController.representedObject; + if([entry isKindOfClass:KPKEntry.class]) { + return entry; + } + return nil; +} + +- (void)menuNeedsUpdate:(NSMenu *)menu { + [menu removeAllItems]; + [self _setupHOTPMenuItemsToMenu:menu]; +} + +- (void)_setupHOTPMenuItemsToMenu:(NSMenu *)menu { + + BOOL hasConfigAttribute = nil != [self.entry customAttributeWithKey:MPHMACOTPConfigAttributeKey]; + if(!hasConfigAttribute) { + NSMenuItem *item = [[NSMenuItem alloc] initWithTitle:@"Add config" action:@selector(_addHMACConfig:) keyEquivalent:@""]; + item.target = self; + [menu addItem:item]; + } + BOOL hasSeedAttribute = nil != [self.entry customAttributeWithKey:MPHMACOTPSeedAttributeKey]; + if(!hasSeedAttribute) { + NSMenuItem *item = [[NSMenuItem alloc] initWithTitle:@"Add seed" action:@selector(_addHMACSeed:) keyEquivalent:@""]; + item.target = self; + [menu addItem:item]; + } +} + +- (IBAction)_addHMACConfig:(id)sender { + [self.entry addCustomAttribute:[[KPKAttribute alloc] initWithKey:MPHMACOTPConfigAttributeKey value:@""]]; +} + +- (IBAction)_addHMACSeed:(id)sender { + [self.entry addCustomAttribute:[[KPKAttribute alloc] initWithKey:MPHMACOTPSeedAttributeKey value:@""]]; +} + +@end diff --git a/MacPass/MPAppDelegate.m b/MacPass/MPAppDelegate.m index 3837b831..f04b2643 100644 --- a/MacPass/MPAppDelegate.m +++ b/MacPass/MPAppDelegate.m @@ -38,6 +38,7 @@ #import "MPPrettyPasswordTransformer.h" #import "MPTemporaryFileStorageCenter.h" #import "MPValueTransformerHelper.h" +#import "MPUserNotificationCenterDelegate.h" #import "NSApplication+MPAdditions.h" @@ -50,6 +51,7 @@ NSString *const MPDidChangeStoredKeyFilesSettings = @"com.hicknhack.macpass.MPDi @interface MPAppDelegate () { @private MPDockTileHelper *_dockTileHelper; + MPUserNotificationCenterDelegate *_userNotificationCenterDelegate; BOOL _shouldOpenFile; // YES if app was started to open a } @@ -71,6 +73,7 @@ NSString *const MPDidChangeStoredKeyFilesSettings = @"com.hicknhack.macpass.MPDi - (instancetype)init { self = [super init]; if(self) { + _userNotificationCenterDelegate = [[MPUserNotificationCenterDelegate alloc] init]; /* We know that we do not use the variable after instantiation */ #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wunused-variable" diff --git a/MacPass/MPAutotypeDaemon.m b/MacPass/MPAutotypeDaemon.m index 663c315d..2c63ade4 100644 --- a/MacPass/MPAutotypeDaemon.m +++ b/MacPass/MPAutotypeDaemon.m @@ -22,23 +22,20 @@ #import "MPAutotypeDaemon.h" #import "MPDocument.h" - #import "MPAutotypeCommand.h" #import "MPAutotypeContext.h" #import "MPAutotypePaste.h" - #import "MPPasteBoardController.h" #import "MPSettingsHelper.h" - -#import "NSApplication+MPAdditions.h" - #import "MPAutotypeCandidateSelectionViewController.h" -#import "KeePassKit/KeePassKit.h" +#import "NSApplication+MPAdditions.h" +#import "NSUserNotification+MPAdditions.h" #import "DDHotKeyCenter.h" #import "DDHotKey+MacPassAdditions.h" +#import "KeePassKit/KeePassKit.h" #import NSString *const kMPWindowTitleKey = @"kMPWindowTitleKey"; @@ -170,7 +167,8 @@ static MPAutotypeDaemon *_sharedInstance; NSUserNotification *notification = [[NSUserNotification alloc] init]; notification.title = NSApp.applicationName; notification.informativeText = NSLocalizedString(@"AUTOTYPE_OVERLAY_NO_DOCUMENTS", "Notification: Autotype failed, no documents are open"); - + notification.actionButtonTitle = NSLocalizedString(@"OPEN_DOCUMENT", "Action button in Notification to open a document"); + //notification.showsButtons = YES; [NSUserNotificationCenter.defaultUserNotificationCenter deliverNotification:notification]; return; } diff --git a/MacPass/MPContextToolbarButton.h b/MacPass/MPContextButton.h similarity index 83% rename from MacPass/MPContextToolbarButton.h rename to MacPass/MPContextButton.h index 45873e49..521e897e 100644 --- a/MacPass/MPContextToolbarButton.h +++ b/MacPass/MPContextButton.h @@ -22,12 +22,10 @@ #import -@interface MPContextToolbarButton : NSSegmentedControl +@interface MPContextButton : NSSegmentedControl + +@property (nonatomic, strong) NSMenu *contextMenu; - (void)setImage:(NSImage *)image; -- (void)setContextMenu:(NSMenu *)menu; - -- (NSControlSize)controlSize; -- (void)setControlSize:(NSControlSize)controlSize; @end diff --git a/MacPass/MPContextToolbarButton.m b/MacPass/MPContextButton.m similarity index 60% rename from MacPass/MPContextToolbarButton.m rename to MacPass/MPContextButton.m index 3441a80b..0d092156 100644 --- a/MacPass/MPContextToolbarButton.m +++ b/MacPass/MPContextButton.m @@ -20,42 +20,52 @@ // along with this program. If not, see . // -#import "MPContextToolbarButton.h" +#import "MPContextButton.h" #import "MPSegmentedContextCell.h" -@interface MPContextToolbarButton () { - @private - NSMenu *_contextMenu; -} +@interface MPContextButton () @end -@implementation MPContextToolbarButton +@implementation MPContextButton -- (id)initWithFrame:(NSRect)frame { - self = [super initWithFrame:frame]; - if (self) { - NSData *data = [NSKeyedArchiver archivedDataWithRootObject:[self cell]]; - NSKeyedUnarchiver *unarchiver = [[NSKeyedUnarchiver alloc] initForReadingWithData:data]; - MPSegmentedContextCell *cell = [[MPSegmentedContextCell alloc] initWithCoder:unarchiver]; - self.cell = cell; - - self.focusRingType = NSFocusRingTypeNone; - self.segmentCount = 2; - cell.trackingMode = NSSegmentSwitchTrackingMomentary; - self.segmentStyle = NSSegmentStyleTexturedSquare; - [cell setWidth:31 forSegment:0]; - [cell setWidth:17 forSegment:1]; - - NSImage *contextTriangle = [[NSBundle mainBundle] imageForResource:@"contextTriangleTemplate"]; - [self setImage:contextTriangle forSegment:1]; - - cell.contextMenuAction = @selector(showContextMenu:); - cell.contextMenuTarget = self; +- (instancetype)initWithCoder:(NSCoder *)coder { + self = [super initWithCoder:coder]; + if(self) { + [self _setup]; } return self; } +- (instancetype)initWithFrame:(NSRect)frame { + self = [super initWithFrame:frame]; + if (self) { + [self _setup]; + } + return self; +} + +- (void)_setup { + NSData *data = [NSKeyedArchiver archivedDataWithRootObject:[self cell]]; + NSKeyedUnarchiver *unarchiver = [[NSKeyedUnarchiver alloc] initForReadingWithData:data]; + MPSegmentedContextCell *cell = [[MPSegmentedContextCell alloc] initWithCoder:unarchiver]; + self.cell = cell; + + self.focusRingType = NSFocusRingTypeNone; + self.segmentStyle = NSSegmentStyleTexturedSquare; + self.segmentCount = 2; + cell.trackingMode = NSSegmentSwitchTrackingMomentary; + [cell setWidth:31 forSegment:0]; + [cell setWidth:17 forSegment:1]; + cell.trackingMode = NSSegmentSwitchTrackingMomentary; + + NSImage *contextTriangle = [NSBundle.mainBundle imageForResource:@"contextTriangleTemplate"]; + [self setImage:contextTriangle forSegment:1]; + + cell.contextMenuAction = @selector(showContextMenu:); + cell.contextMenuTarget = self; +} + - (void)setContextMenu:(NSMenu *)menu { if(_contextMenu != menu) { _contextMenu = menu; @@ -106,25 +116,11 @@ default: break; } - if([self.superclass instancesRespondToSelector:@selector(setControlSize:)]) { -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wunguarded-availability" - super.controlSize = controlSize; -#pragma clang diagnostic pop - } - else { - self.cell.controlSize = controlSize; - } + super.controlSize = controlSize; } - (NSControlSize)controlSize { - if([self.superclass instancesRespondToSelector:@selector(controlSize)]) { -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wunguarded-availability" - return super.controlSize; -#pragma clang diagnostic pop - } - return self.cell.controlSize; + return super.controlSize; } @end diff --git a/MacPass/MPDocumentWindowController.m b/MacPass/MPDocumentWindowController.m index 96685d73..a54e1a38 100644 --- a/MacPass/MPDocumentWindowController.m +++ b/MacPass/MPDocumentWindowController.m @@ -25,7 +25,7 @@ #import "MPAppDelegate.h" #import "MPAutotypeDaemon.h" #import "MPConstants.h" -#import "MPContextToolbarButton.h" +#import "MPContextButton.h" #import "MPDatabaseSettingsWindowController.h" #import "MPDocument.h" #import "MPDocumentWindowDelegate.h" diff --git a/MacPass/MPEntryInspectorViewController.h b/MacPass/MPEntryInspectorViewController.h index 7a1e7e26..395be4a8 100644 --- a/MacPass/MPEntryInspectorViewController.h +++ b/MacPass/MPEntryInspectorViewController.h @@ -25,6 +25,7 @@ #import @class HNHUIRoundedSecureTextField; +@class MPContextButton; @class MPDocument; @interface MPEntryInspectorViewController : MPViewController @@ -48,7 +49,7 @@ @property (weak) IBOutlet NSTextField *createdTextField; @property (weak) IBOutlet NSTextField *modifiedTextField; -@property (weak) IBOutlet NSButton *addCustomFieldButton; +@property (weak) IBOutlet MPContextButton *addCustomFieldButton; /* Attachments */ @property (weak) IBOutlet NSButtonCell *addAttachmentButton; diff --git a/MacPass/MPEntryInspectorViewController.m b/MacPass/MPEntryInspectorViewController.m index 5bd85619..e395835d 100644 --- a/MacPass/MPEntryInspectorViewController.m +++ b/MacPass/MPEntryInspectorViewController.m @@ -43,6 +43,8 @@ #import "MPActionHelper.h" #import "MPSettingsHelper.h" #import "MPPasteBoardController.h" +#import "MPContextButton.h" +#import "MPAddCustomFieldContextMenuDelegate.h" #import "MPArrayController.h" @@ -67,6 +69,7 @@ typedef NS_ENUM(NSUInteger, MPEntryTab) { MPWindowAssociationsTableViewDelegate *_windowAssociationsTableDelegate; MPWindowTitleComboBoxDelegate *_windowTitleMenuDelegate; MPTagsTokenFieldDelegate *_tagTokenFieldDelegate; + MPAddCustomFieldContextMenuDelegate *_addCustomFieldContextMenuDelegate; } @property (nonatomic, assign) BOOL showPassword; @@ -97,9 +100,12 @@ typedef NS_ENUM(NSUInteger, MPEntryTab) { _windowAssociationsTableDelegate = [[MPWindowAssociationsTableViewDelegate alloc] init]; _windowTitleMenuDelegate = [[MPWindowTitleComboBoxDelegate alloc] init]; _tagTokenFieldDelegate = [[MPTagsTokenFieldDelegate alloc] init]; + _addCustomFieldContextMenuDelegate = [[MPAddCustomFieldContextMenuDelegate alloc] init]; _tagTokenFieldDelegate.viewController = self; _attachmentTableDelegate.viewController = self; _customFieldTableDelegate.viewController = self; + _addCustomFieldContextMenuDelegate.viewController = self; + _activeTab = MPEntryTabGeneral; } return self; @@ -166,6 +172,7 @@ typedef NS_ENUM(NSUInteger, MPEntryTab) { self.tagsTokenField.delegate = _tagTokenFieldDelegate; + [self _setupCustomFieldsButton]; [self _setupViewBindings]; } @@ -542,6 +549,14 @@ typedef NS_ENUM(NSUInteger, MPEntryTab) { } +- (void)_setupCustomFieldsButton { + /* FIXME: this is a bug in MPContextButton preventing the image set in IB to be used */ + [self.addCustomFieldButton setImage:[NSImage imageNamed:NSImageNameAddTemplate]]; + NSMenu *customFieldMenu = [[NSMenu alloc] initWithTitle:NSLocalizedString(@"ADD_CUSTOM_FIELD_CONTEXT_MENU", @"Menu displayed for adding special custom keys")]; + customFieldMenu.delegate = _addCustomFieldContextMenuDelegate; + self.addCustomFieldButton.contextMenu = customFieldMenu; +} + #pragma mark - #pragma mark HNHUITextFieldDelegate - (NSMenu *)textField:(NSTextField *)textField textView:(NSTextView *)view menu:(NSMenu *)menu { diff --git a/MacPass/MPPickcharsParser.m b/MacPass/MPPickcharsParser.m index 9d8bf5d0..497e5631 100644 --- a/MacPass/MPPickcharsParser.m +++ b/MacPass/MPPickcharsParser.m @@ -46,7 +46,7 @@ for(NSString *character in string.composedCharacters) { } - + return nil; } /* diff --git a/MacPass/MPPlugin.h b/MacPass/MPPlugin.h index 4c2a5081..3b290234 100644 --- a/MacPass/MPPlugin.h +++ b/MacPass/MPPlugin.h @@ -27,6 +27,7 @@ NS_ASSUME_NONNULL_BEGIN @class MPPluginHost; @class MPAutotypeCommand; @class KPKEntry; +@class KPKAttribute; @interface MPPlugin : NSObject @@ -35,8 +36,6 @@ NS_ASSUME_NONNULL_BEGIN @property (copy, readonly) NSString *version; @property (nonatomic, strong, readonly) NSBundle *bundle; -@property (readonly) NSString *requiredHostVersion; // the host version required for running the plugin in mayor.minor.path format - /** If your plugin needs initalization override this method but you have to call [super initWithPluginHost:] @@ -59,41 +58,29 @@ NS_ASSUME_NONNULL_BEGIN @end -/* Adopt this protocoll if you plugin supplied additinal autotype commands */ -@protocol MPAutotypePlugin -@required -/** - Returns an array of string of commands supported by this pluing. Leave out enclosing curly brackets! - E.g. if you support {FOO} and {BAR} you will return @[ @"FOO", @"BAR" ]. The autotype system is case insenstivie. - */ -@property (nonatomic,copy) NSArray *commandStrings; -/** - Will be called by the plugin host to generate autotype commands for the corresponding string. - Command strings are considered case insensitive but mostly will be used in upper case. - You should therefore compare case insensitive. - - @param commandString The command string without any enclosing curly brackets. The string is normalized to upper cased. - @param entry The entry for which the command will be used - @return a command for the supplied string, return nil if parsing fails or an unsupported command is supplied - */ -- (MPAutotypeCommand * _Nullable)commandForString:(NSString *)commandString entry:(KPKEntry *)entry; -@end - /* Adopt this protocoll if your plugin supports actions on entries. - Actions will get listed in various places in menues. You should shoudl supply a valid menu item - that is wired up with the correct target and action. Since there's responder chain resolving involved - as well as a + Actions will get listed in various places in menues. + You should not set target nor actions since they will get stripped. + MacPass will call you back via -[MPPlugin performActionFroMenuItem:withEntries:] */ @protocol MPEntryActionPlugin @optional - (NSMenuItem * _Nullable)menuItemForEntry; +- (void)performActionForMenuItem:(NSMenuItem *)item withEntries:(NSArray *)entries; @end @protocol MPCustomAttributePlugin @optional /* Supply a list of attribute keys that will get suggested for autocompletion as well as added to the extend add for custom fields */ @property (nonatomic,copy) NSArray* attributeKeys; +/* + For any attribute created with the special key the plugin will get called to offer a custom generation for the attributes value. + You can e.g. show UI to help the user create a special format. + + If nil is returned, an empty value will be used. + */ +- (NSString *)valueForAttributeWithKey:(NSString *)key; @end @interface MPPlugin (Deprecated) diff --git a/MacPass/MPToolbarDelegate.m b/MacPass/MPToolbarDelegate.m index b548c39f..b7e9355d 100644 --- a/MacPass/MPToolbarDelegate.m +++ b/MacPass/MPToolbarDelegate.m @@ -24,7 +24,7 @@ #import "MPToolbarButton.h" #import "MPToolbarItem.h" -#import "MPContextToolbarButton.h" +#import "MPContextButton.h" #import "MPAddEntryContextMenuDelegate.h" #import "MPActionHelper.h" @@ -103,7 +103,7 @@ NSString *const MPToolbarItemHistory = @"TOOLBAR_HISTORY"; if(!item) { item = [[MPToolbarItem alloc] initWithItemIdentifier:itemIdentifier]; NSString *itemLabel = [self _localizedLabelForToolbarItemIdentifier:itemIdentifier]; - [item setLabel:itemLabel]; + item.label = itemLabel; if([itemIdentifier isEqualToString:MPToolbarItemAction]) { NSPopUpButton *popupButton = [[NSPopUpButton alloc] initWithFrame:NSMakeRect(0, 0, 50, 32) pullsDown:YES]; @@ -135,8 +135,8 @@ NSString *const MPToolbarItemHistory = @"TOOLBAR_HISTORY"; item.view = popupButton; } else if( [itemIdentifier isEqualToString:MPToolbarItemAddEntry]) { - MPContextToolbarButton *button = [[MPContextToolbarButton alloc] initWithFrame:NSMakeRect(0, 0, 32, 32)]; - [button setAction:[self _actionForToolbarItemIdentifier:itemIdentifier]]; + MPContextButton *button = [[MPContextButton alloc] initWithFrame:NSMakeRect(0, 0, 32, 32)]; + button.action = [self _actionForToolbarItemIdentifier:itemIdentifier]; NSImage *image = self.toolbarImages[itemIdentifier]; image.size = NSMakeSize(16, 16); [button setImage:image]; @@ -145,7 +145,7 @@ NSString *const MPToolbarItemHistory = @"TOOLBAR_HISTORY"; NSMenu *menu = [NSMenu allocWithZone:[NSMenu menuZone]]; [menu addItemWithTitle:NSLocalizedString(@"UNKNOWN_TOOLBAR_ITEM", @"") action:NULL keyEquivalent:@""]; menu.delegate = _entryMenuDelegate; - [button setContextMenu:menu]; + button.contextMenu = menu; NSRect fittingRect = button.frame; diff --git a/MacPass/MPTreeDelegate.m b/MacPass/MPTreeDelegate.m index 08fe6b6b..2fd92275 100644 --- a/MacPass/MPTreeDelegate.m +++ b/MacPass/MPTreeDelegate.m @@ -95,7 +95,7 @@ panel.title = NSLocalizedString(@"PICKFIELD_WINDOW_TITLE", @"Window displayed to the user to pick an amout of characters"); [panel center]; if(NSModalResponseOK == [NSApp runModalForWindow:panel]) { - /* add appropriate key press comamnds? or let the pick-char view-controller handel this? */ + /* add appropriate key press commands? or let the pick-char view-controller handel this? */ return pickFieldViewController.pickedValue; } return @""; diff --git a/MacPass/MPUserNotificationCenterDelegate.m b/MacPass/MPUserNotificationCenterDelegate.m index a08f4d43..754d590e 100644 --- a/MacPass/MPUserNotificationCenterDelegate.m +++ b/MacPass/MPUserNotificationCenterDelegate.m @@ -18,4 +18,8 @@ return self; } +- (void)userNotificationCenter:(NSUserNotificationCenter *)center didActivateNotification:(NSUserNotification *)notification { + NSLog(@"%@", notification); +} + @end diff --git a/MacPass/MacPass-Info.plist b/MacPass/MacPass-Info.plist index 12a3e035..5443b699 100644 --- a/MacPass/MacPass-Info.plist +++ b/MacPass/MacPass-Info.plist @@ -2,6 +2,8 @@ + NSUserNotificationAlertStyle + alert CFBundleDevelopmentRegion en CFBundleDocumentTypes diff --git a/MacPass/NSUserNotification+MPAdditions.h b/MacPass/NSUserNotification+MPAdditions.h new file mode 100644 index 00000000..20b9b814 --- /dev/null +++ b/MacPass/NSUserNotification+MPAdditions.h @@ -0,0 +1,15 @@ +// +// NSUserNotification+MPAdditions.h +// MacPass +// +// Created by Michael Starke on 05.12.17. +// Copyright © 2017 HicknHack Software GmbH. All rights reserved. +// + +#import + +@interface NSUserNotification (MPAdditions) + +@property (nonatomic) BOOL showsButtons; + +@end diff --git a/MacPass/NSUserNotification+MPAdditions.m b/MacPass/NSUserNotification+MPAdditions.m new file mode 100644 index 00000000..08b1b44f --- /dev/null +++ b/MacPass/NSUserNotification+MPAdditions.m @@ -0,0 +1,21 @@ +// +// NSUserNotification+MPAdditions.m +// MacPass +// +// Created by Michael Starke on 05.12.17. +// Copyright © 2017 HicknHack Software GmbH. All rights reserved. +// + +#import "NSUserNotification+MPAdditions.h" + +@implementation NSUserNotification (MPAdditions) + +- (BOOL)showsButtons { + return [[self valueForKey:@"_showsButtons"] boolValue]; +} + +- (void)setShowsButtons:(BOOL)showsButtons { + [self setValue:@(showsButtons) forKey:@"_showsButtons"]; +} + +@end diff --git a/MacPass/en.lproj/Localizable.strings b/MacPass/en.lproj/Localizable.strings index 5a61e04f..dc93999d 100644 --- a/MacPass/en.lproj/Localizable.strings +++ b/MacPass/en.lproj/Localizable.strings @@ -372,6 +372,9 @@ /* Open button in the open panel to import an XML file */ "OPEN_BUTTON_IMPORT_XML_OPEN_PANEL" = "Import"; +/* Notification Button */ +"OPEN_DOCUMENT" = "Open Document"; + /* Menu item to open the URL with the default application */ "OPEN_URL" = "Open URL";