From 0a42e55f0e9d06b0e86e4535fab4091f68014b98 Mon Sep 17 00:00:00 2001 From: michael starke Date: Wed, 17 Jul 2013 01:02:02 +0200 Subject: [PATCH] Added custom-field copy to the context menu on entries. It's not fully functional as it's not correctly using the click but always the selected entry! --- KeePassKit | 2 +- MacPass.xcodeproj/project.pbxproj | 6 +++ MacPass/Base.lproj/InspectorView.xib | 4 +- MacPass/MPEntryMenuDelegate.h | 16 ++++++++ MacPass/MPEntryMenuDelegate.m | 54 +++++++++++++++++++++++++++ MacPass/MPEntryViewController.h | 2 + MacPass/MPEntryViewController.m | 36 +++++++++++++++--- MacPass/de.lproj/Localizable.strings | Bin 8728 -> 9218 bytes MacPass/en.lproj/Localizable.strings | Bin 8182 -> 8656 bytes 9 files changed, 112 insertions(+), 8 deletions(-) create mode 100644 MacPass/MPEntryMenuDelegate.h create mode 100644 MacPass/MPEntryMenuDelegate.m diff --git a/KeePassKit b/KeePassKit index a030f320..4a383312 160000 --- a/KeePassKit +++ b/KeePassKit @@ -1 +1 @@ -Subproject commit a030f3209e47040ed71a821f7e0a57d48d364161 +Subproject commit 4a3833128e2290b0cbb5f3a6695039bdbae9f39a diff --git a/MacPass.xcodeproj/project.pbxproj b/MacPass.xcodeproj/project.pbxproj index 2a67ccb2..e5779f38 100644 --- a/MacPass.xcodeproj/project.pbxproj +++ b/MacPass.xcodeproj/project.pbxproj @@ -207,6 +207,7 @@ 4CD884B715BD47080042BBF8 /* DocumentWindow.xib in Resources */ = {isa = PBXBuildFile; fileRef = 4CD884B615BD47080042BBF8 /* DocumentWindow.xib */; }; 4CDB5C421794AA4F0017667E /* KPKTree+Serializing.m in Sources */ = {isa = PBXBuildFile; fileRef = 4CDB5C411794AA4F0017667E /* KPKTree+Serializing.m */; }; 4CDF01A316D1B76700D0AC08 /* MPEntryViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 4CDF01A216D1B76700D0AC08 /* MPEntryViewController.m */; }; + 4CE298EB1795FC2A00DF7BDB /* MPEntryMenuDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 4CE298EA1795FC2A00DF7BDB /* MPEntryMenuDelegate.m */; }; 4CE39ABF16ECE34A000FE29D /* MPIconSelectViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 4CE39ABE16ECE34A000FE29D /* MPIconSelectViewController.m */; }; 4CE39AC116ECE359000FE29D /* IconSelection.xib in Resources */ = {isa = PBXBuildFile; fileRef = 4CE39AC016ECE359000FE29D /* IconSelection.xib */; }; 4CE39AC416ECE4F7000FE29D /* MPPopupImageView.m in Sources */ = {isa = PBXBuildFile; fileRef = 4CE39AC316ECE4F7000FE29D /* MPPopupImageView.m */; }; @@ -603,6 +604,8 @@ 4CDB5C411794AA4F0017667E /* KPKTree+Serializing.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = "KPKTree+Serializing.m"; path = "../Core/KPKTree+Serializing.m"; sourceTree = ""; }; 4CDF01A116D1B76700D0AC08 /* MPEntryViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPEntryViewController.h; sourceTree = ""; }; 4CDF01A216D1B76700D0AC08 /* MPEntryViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPEntryViewController.m; sourceTree = ""; }; + 4CE298E91795FC2A00DF7BDB /* MPEntryMenuDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPEntryMenuDelegate.h; sourceTree = ""; }; + 4CE298EA1795FC2A00DF7BDB /* MPEntryMenuDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPEntryMenuDelegate.m; sourceTree = ""; }; 4CE39ABD16ECE34A000FE29D /* MPIconSelectViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPIconSelectViewController.h; sourceTree = ""; }; 4CE39ABE16ECE34A000FE29D /* MPIconSelectViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPIconSelectViewController.m; sourceTree = ""; }; 4CE39AC016ECE359000FE29D /* IconSelection.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = IconSelection.xib; sourceTree = ""; }; @@ -950,6 +953,8 @@ 4C3BD51416D276F800389F1F /* MPToolbarDelegate.m */, 4C811C8116ECD06E00C4BAC6 /* MPKeyfilePathControlDelegate.h */, 4C811C8216ECD06E00C4BAC6 /* MPKeyfilePathControlDelegate.m */, + 4CE298E91795FC2A00DF7BDB /* MPEntryMenuDelegate.h */, + 4CE298EA1795FC2A00DF7BDB /* MPEntryMenuDelegate.m */, ); name = Delegates; sourceTree = ""; @@ -1784,6 +1789,7 @@ 4CF62B86179385D700B660B6 /* KPKAttribute.m in Sources */, 4CDB5C421794AA4F0017667E /* KPKTree+Serializing.m in Sources */, 4C5AA591179549A1008ECAD7 /* KPKXmlTreeWriter.m in Sources */, + 4CE298EB1795FC2A00DF7BDB /* MPEntryMenuDelegate.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/MacPass/Base.lproj/InspectorView.xib b/MacPass/Base.lproj/InspectorView.xib index 66d02b5e..36c0ad64 100644 --- a/MacPass/Base.lproj/InspectorView.xib +++ b/MacPass/Base.lproj/InspectorView.xib @@ -136,7 +136,7 @@ - 268 + -2147483380 {{184, 5}, {45, 19}} @@ -165,7 +165,7 @@ - 268 + -2147483380 {{237, 5}, {36, 19}} diff --git a/MacPass/MPEntryMenuDelegate.h b/MacPass/MPEntryMenuDelegate.h new file mode 100644 index 00000000..322a3fd8 --- /dev/null +++ b/MacPass/MPEntryMenuDelegate.h @@ -0,0 +1,16 @@ +// +// MPEntryMenuDelegate.h +// MacPass +// +// Created by Michael Starke on 17.07.13. +// Copyright (c) 2013 HicknHack Software GmbH. All rights reserved. +// + +#import +@class MPEntryViewController; + +@interface MPEntryMenuDelegate : NSObject + +@property (weak) MPEntryViewController *viewController; + +@end diff --git a/MacPass/MPEntryMenuDelegate.m b/MacPass/MPEntryMenuDelegate.m new file mode 100644 index 00000000..555bf0bb --- /dev/null +++ b/MacPass/MPEntryMenuDelegate.m @@ -0,0 +1,54 @@ +// +// MPEntryMenuDelegate.m +// MacPass +// +// Created by Michael Starke on 17.07.13. +// Copyright (c) 2013 HicknHack Software GmbH. All rights reserved. +// + +#import "MPEntryMenuDelegate.h" +#import "MPEntryViewController.h" + +#import "Kdb4Node.h" + +static NSUInteger const kMPCustomFieldMenuItem = 1000; +static NSUInteger const kMPAttachmentsMenuItem = 2000; + +@implementation MPEntryMenuDelegate + +- (void)menuNeedsUpdate:(NSMenu *)menu { + NSMenuItem *fieldsMenu = [menu itemWithTag:kMPCustomFieldMenuItem]; + NSMenuItem *attachmentsMenu = [menu itemWithTag:kMPAttachmentsMenuItem]; + if(fieldsMenu) { + [menu removeItem:fieldsMenu]; + } + if(attachmentsMenu) { + [menu removeItem:attachmentsMenu]; + } + + NSMenuItem *lastItem = [[menu itemArray] lastObject]; + if([lastItem isSeparatorItem]) { + [menu removeItem:lastItem]; + } + + if([self.viewController.selectedEntry isKindOfClass:[Kdb4Entry class]]) { + Kdb4Entry *entry = (Kdb4Entry *)self.viewController.selectedEntry; + if([entry.stringFields count] > 0) { + [menu addItem:[NSMenuItem separatorItem]]; + NSMenuItem *customFieldsItem = [[NSMenuItem alloc] init]; + NSMenu *submenu = [[NSMenu alloc] initWithTitle:@"Fields"]; + [customFieldsItem setTitle:NSLocalizedString(@"COPY_CUSTOM_FIELDS", "Submenu to Copy custom fields")]; + [customFieldsItem setTag:kMPCustomFieldMenuItem]; + for (StringField *field in entry.stringFields) { + NSString *title = [NSString stringWithFormat:NSLocalizedString(@"COPY_FIELD_%@", "Mask for title to copy field value"), field.key]; + NSMenuItem *item = [[NSMenuItem alloc] initWithTitle:title action:@selector(copyCustomField:) keyEquivalent:@""]; + [item setTag:[entry.stringFields indexOfObject:field]]; + [submenu addItem:item]; + } + [customFieldsItem setSubmenu:submenu]; + [menu addItem:customFieldsItem]; + } + } +} + +@end diff --git a/MacPass/MPEntryViewController.h b/MacPass/MPEntryViewController.h index 50230d25..cf389183 100644 --- a/MacPass/MPEntryViewController.h +++ b/MacPass/MPEntryViewController.h @@ -48,9 +48,11 @@ typedef NS_ENUM( NSUInteger, MPCopyContentTypeTag) { /* Copy/Paste */ - (void)copyUsername:(id)sender; - (void)copyPassword:(id)sender; +- (void)copyCustomField:(id)sender; - (void)copyURL:(id)sender; - (void)openURL:(id)sender; + /* Entry Handling*/ - (void)deleteNode:(id)sender; diff --git a/MacPass/MPEntryViewController.m b/MacPass/MPEntryViewController.m index cacbf81a..67594129 100644 --- a/MacPass/MPEntryViewController.m +++ b/MacPass/MPEntryViewController.m @@ -20,10 +20,12 @@ #import "MPConstants.h" #import "MPEntryTableDataSource.h" #import "MPStringLengthValueTransformer.h" +#import "MPEntryMenuDelegate.h" #import "HNHTableHeaderCell.h" #import "HNHGradientView.h" +#import "Kdb4Node.h" #import "KdbGroup+MPTreeTools.h" #import "KdbGroup+Undo.h" #import "KdbEntry+Undo.h" @@ -43,6 +45,7 @@ typedef NS_ENUM(NSUInteger,MPOVerlayInfoType) { MPOverlayInfoPassword, MPOverlayInfoUsername, MPOverlayInfoURL, + MPOverlayInfoCustom }; NSString *const MPEntryTableUserNameColumnIdentifier = @"MPUserNameColumnIdentifier"; @@ -59,7 +62,9 @@ NSString *const _toggleFilterURLButton = @"SearchURL"; NSString *const _toggleFilterTitleButton = @"SearchTitle"; NSString *const _toggleFilterUsernameButton = @"SearchUsername"; -@interface MPEntryViewController () +@interface MPEntryViewController () { + MPEntryMenuDelegate *_menuDelegate; +} @property (strong) NSArrayController *entryArrayController; @property (strong) NSArray *filteredEntries; @@ -103,6 +108,9 @@ NSString *const _toggleFilterUsernameButton = @"SearchUsername"; _entryArrayController = [[NSArrayController alloc] init]; _dataSource = [[MPEntryTableDataSource alloc] init]; _dataSource.viewController = self; + _menuDelegate = [[MPEntryMenuDelegate alloc] init]; + _menuDelegate.viewController = self; + _selectedEntry = nil; } return self; @@ -396,7 +404,7 @@ NSString *const _toggleFilterUsernameButton = @"SearchUsername"; } } -- (void)_copyToPasteboard:(NSString *)data overlayInfo:(MPOVerlayInfoType)overlayInfoType { +- (void)_copyToPasteboard:(NSString *)data overlayInfo:(MPOVerlayInfoType)overlayInfoType name:(NSString *)name{ if(data) { [[MPPasteBoardController defaultController] copyObjects:@[ data ]]; } @@ -417,6 +425,11 @@ NSString *const _toggleFilterUsernameButton = @"SearchUsername"; infoImage = [[NSBundle mainBundle] imageForResource:@"09_IdentityTemplate"]; infoText = NSLocalizedString(@"COPIED_USERNAME", @"Username was copied to the pasteboard"); break; + + case MPOverlayInfoCustom: + infoImage = [[NSBundle mainBundle] imageForResource:@"00_PasswordTemplate"]; + infoText = [NSString stringWithFormat:NSLocalizedString(@"COPIED_FIELD_%@", "Field nam that was copied to the pasteboard"), name]; + break; } [[MPOverlayWindowController sharedController] displayOverlayImage:infoImage label:infoText atView:self.view]; } @@ -430,7 +443,9 @@ NSString *const _toggleFilterUsernameButton = @"SearchUsername"; for(NSMenuItem *item in items) { [menu addItem:item]; } + [menu setDelegate:_menuDelegate]; [self.entryTable setMenu:menu]; + } #pragma makr Action Helper @@ -452,21 +467,32 @@ NSString *const _toggleFilterUsernameButton = @"SearchUsername"; - (void)copyPassword:(id)sender { KdbEntry *selectedEntry = [self _clickedOrSelectedEntry]; if(selectedEntry) { - [self _copyToPasteboard:selectedEntry.password overlayInfo:MPOverlayInfoPassword]; + [self _copyToPasteboard:selectedEntry.password overlayInfo:MPOverlayInfoPassword name:nil]; } } - (void)copyUsername:(id)sender { KdbEntry *selectedEntry = [self _clickedOrSelectedEntry]; if(selectedEntry) { - [self _copyToPasteboard:selectedEntry.username overlayInfo:MPOverlayInfoUsername]; + [self _copyToPasteboard:selectedEntry.username overlayInfo:MPOverlayInfoUsername name:nil]; + } +} + +- (void)copyCustomField:(id)sender { + KdbEntry *selectedEntry = [self _clickedOrSelectedEntry]; + if(selectedEntry && [selectedEntry isKindOfClass:[Kdb4Entry class]]) { + Kdb4Entry *entry = (Kdb4Entry *)selectedEntry; + NSUInteger index = [sender tag]; + NSAssert((index >= 0) && (index < [entry.stringFields count]), @"Index for custom field needs to be valid"); + StringField *field = entry.stringFields[index]; + [self _copyToPasteboard:field.value overlayInfo:MPOverlayInfoCustom name:field.key]; } } - (void)copyURL:(id)sender { KdbEntry *selectedEntry = [self _clickedOrSelectedEntry]; if(selectedEntry) { - [self _copyToPasteboard:selectedEntry.url overlayInfo:MPOverlayInfoURL]; + [self _copyToPasteboard:selectedEntry.url overlayInfo:MPOverlayInfoURL name:nil]; } } diff --git a/MacPass/de.lproj/Localizable.strings b/MacPass/de.lproj/Localizable.strings index 5da3bc8da004044a7c53b886044e2d0e1383afb8..d25a066184bb959bf6326068aa26bccf1afcdb2d 100644 GIT binary patch delta 348 zcmbQ?(&VwBjak}_A(J7MA%`J_L4hHUA(0^$NS82V09hrI9a(~9-55L>Tp4^ATo~dR zR2du?lz{TKK&%AfO%`Nn-u!}j8l!$NLn%WNP;)BKkW#P_`9RW{A)ldup%TbS28tE~ z4bBH!kT&@uhp4MFgFiz6LnP2(XNFLQV1^JN-xtV3SQ(6Doh#6x>0t9yf#!t+Sw%qe zQYZgrRjl^~I=7f18z`Ozw4n${mjG3l0KElL3$hjD0+?IUki1+5)R_Zx8%UiNgFXWn j&_;y25H3OYyf@f1P|y`Iq_P1ugF>T_DSGoMRzDd4VhlhF delta 25 hcmZqjnBlUajd}7tmZZ&7Sf(*fp1={Zc@Mjr3;>Eh3Ge^_ diff --git a/MacPass/en.lproj/Localizable.strings b/MacPass/en.lproj/Localizable.strings index 805634a5946ab69ef9dabd5210dca0f72d59f45a..6f27091378b0083c60c1a639518f13cd35e55594 100644 GIT binary patch delta 342 zcmZ9I&k6xi7{!nOvXGPwDJdHp_7XKH8Bt?nCCrHY8JVH1Z0+v@C{IA1K*`$ESUYnS zvAFm9y7xQh{O*009?D7gBx;zzzzjN4SfGzNtBo-`TO_?&riMDIP*Fh-8I+OceUU2- z1tykKt&3|QCc@sqoC) dXYP*!y$Jq(!hsUEKvXQu6;m!q!}e*p_)L686d delta 21 dcmccM{LOwt3iD