From e33a9fdc93b8ecf12b0dcafaa5384755f98415f7 Mon Sep 17 00:00:00 2001 From: michael starke Date: Tue, 30 Jul 2013 00:23:25 +0200 Subject: [PATCH] Enhanced Context menu on outline view --- KeePassKit | 2 +- MacPass.xcodeproj/project.pbxproj | 24 +++- MacPass/KdbGroup+MPAdditions.m | 4 + MacPass/KdbGroup+MPTreeTools.h | 12 +- MacPass/MPActionHelper.h | 20 +++- MacPass/MPActionHelper.m | 3 +- MacPass/MPAppDelegate.m | 2 +- MacPass/MPContextToolbarButton.m | 8 +- MacPass/MPDatabaseSettingsWindowController.h | 2 +- MacPass/MPDatabaseSettingsWindowController.m | 4 +- MacPass/MPDocument.h | 1 + MacPass/MPDocument.m | 15 ++- MacPass/MPDocumentWindowController.h | 4 + MacPass/MPDocumentWindowController.m | 14 ++- MacPass/MPEntryViewController.m | 6 +- MacPass/MPGroupInspectorViewController.m | 4 +- MacPass/MPIconHelper.h | 37 +++--- MacPass/MPIconHelper.m | 17 +-- MacPass/MPIconSelectViewController.m | 2 +- MacPass/MPOutlineMenuDelegate.h | 17 +++ MacPass/MPOutlineMenuDelegate.m | 114 +++++++++++++++++++ MacPass/MPOutlineViewController.h | 7 +- MacPass/MPOutlineViewController.m | 20 +++- MacPass/MPToolbarDelegate.m | 10 +- MacPass/de.lproj/Localizable.strings | Bin 11178 -> 12416 bytes MacPass/en.lproj/Localizable.strings | Bin 12298 -> 11712 bytes 26 files changed, 278 insertions(+), 71 deletions(-) create mode 100644 MacPass/MPOutlineMenuDelegate.h create mode 100644 MacPass/MPOutlineMenuDelegate.m diff --git a/KeePassKit b/KeePassKit index a5840cde..e1edcc11 160000 --- a/KeePassKit +++ b/KeePassKit @@ -1 +1 @@ -Subproject commit a5840cdee0c1f5c0591ee466bafee8f191d03801 +Subproject commit e1edcc115b261eb0b157675e748b00182b468aad diff --git a/MacPass.xcodeproj/project.pbxproj b/MacPass.xcodeproj/project.pbxproj index 88b0b773..930c66c2 100644 --- a/MacPass.xcodeproj/project.pbxproj +++ b/MacPass.xcodeproj/project.pbxproj @@ -126,6 +126,7 @@ 4C5AA591179549A1008ECAD7 /* KPKXmlTreeWriter.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C5AA590179549A1008ECAD7 /* KPKXmlTreeWriter.m */; }; 4C5BF67B175C01F300D53DF7 /* MPUppercaseStringValueTransformer.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C5BF67A175C01F300D53DF7 /* MPUppercaseStringValueTransformer.m */; }; 4C5EC302177B700D00DA955B /* MPRootAdapter.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C5EC301177B700D00DA955B /* MPRootAdapter.m */; }; + 4C5FA86D17A5F26800C781C9 /* KPKDataStreamWriter.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C5FA86C17A5F26800C781C9 /* KPKDataStreamWriter.m */; }; 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 */; }; @@ -195,6 +196,7 @@ 4C888C9316EB6F5E003D34A1 /* MPToolbarItem.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C888C9216EB6F5E003D34A1 /* MPToolbarItem.m */; }; 4C888C9716EB754B003D34A1 /* MPActionHelper.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C888C9616EB754B003D34A1 /* MPActionHelper.m */; }; 4C8A173D1790AA41008B5C17 /* NSData+Keyfile.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C8A173C1790AA41008B5C17 /* NSData+Keyfile.m */; }; + 4C8B36AB17A6ED4B005E1FF1 /* MPOutlineMenuDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C8B36AA17A6ED4B005E1FF1 /* MPOutlineMenuDelegate.m */; }; 4C8FECC816D57E3200BF26CF /* QuartzCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4C8FECC716D57E3200BF26CF /* QuartzCore.framework */; }; 4C96D15417A12E4F00D931FA /* 99_CreatedTemplate.pdf in Resources */ = {isa = PBXBuildFile; fileRef = 4C96D15317A12E4F00D931FA /* 99_CreatedTemplate.pdf */; }; 4C9D6AA917615199001C660C /* HNHRoundedSecureTextFieldCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C9D6AA817615199001C660C /* HNHRoundedSecureTextFieldCell.m */; }; @@ -224,7 +226,7 @@ 4CC7EA1B17807E7E0089D4F3 /* HNHRoundedTextFieldCellHelper.m in Sources */ = {isa = PBXBuildFile; fileRef = 4CC7EA1A17807E7E0089D4F3 /* HNHRoundedTextFieldCellHelper.m */; }; 4CCEDE2A179F203B008402BE /* MPOutlineView.m in Sources */ = {isa = PBXBuildFile; fileRef = 4CCEDE29179F203B008402BE /* MPOutlineView.m */; }; 4CCEDE2E179F213B008402BE /* MPNotifications.m in Sources */ = {isa = PBXBuildFile; fileRef = 4CCEDE2D179F213B008402BE /* MPNotifications.m */; }; - 4CCEDE32179F5B6C008402BE /* KPKDataStreamer.m in Sources */ = {isa = PBXBuildFile; fileRef = 4CCEDE31179F5B6C008402BE /* KPKDataStreamer.m */; }; + 4CCEDE32179F5B6C008402BE /* KPKDataStreamReader.m in Sources */ = {isa = PBXBuildFile; fileRef = 4CCEDE31179F5B6C008402BE /* KPKDataStreamReader.m */; }; 4CD3ABBA178F71B50073F5C5 /* KPKTree.m in Sources */ = {isa = PBXBuildFile; fileRef = 4CD3ABB4178F71B50073F5C5 /* KPKTree.m */; }; 4CD3ABBF178F72610073F5C5 /* KPKEntry.m in Sources */ = {isa = PBXBuildFile; fileRef = 4CD3ABBE178F72610073F5C5 /* KPKEntry.m */; }; 4CD3ABC2178F72720073F5C5 /* KPKGroup.m in Sources */ = {isa = PBXBuildFile; fileRef = 4CD3ABC1178F72720073F5C5 /* KPKGroup.m */; }; @@ -484,6 +486,8 @@ 4C5BF67A175C01F300D53DF7 /* MPUppercaseStringValueTransformer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPUppercaseStringValueTransformer.m; sourceTree = ""; }; 4C5EC300177B700D00DA955B /* MPRootAdapter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPRootAdapter.h; sourceTree = ""; }; 4C5EC301177B700D00DA955B /* MPRootAdapter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPRootAdapter.m; sourceTree = ""; }; + 4C5FA86B17A5F26800C781C9 /* KPKDataStreamWriter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = KPKDataStreamWriter.h; sourceTree = ""; }; + 4C5FA86C17A5F26800C781C9 /* KPKDataStreamWriter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = KPKDataStreamWriter.m; sourceTree = ""; }; 4C5FE9AC17843CE20001D5A8 /* MPSelectedAttachmentTableCellView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPSelectedAttachmentTableCellView.h; sourceTree = ""; }; 4C5FE9AD17843CE20001D5A8 /* MPSelectedAttachmentTableCellView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPSelectedAttachmentTableCellView.m; sourceTree = ""; }; 4C61EA0116D2FD0800AC519E /* MPOutlineViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPOutlineViewController.h; sourceTree = ""; }; @@ -621,6 +625,8 @@ 4C888C9616EB754B003D34A1 /* MPActionHelper.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPActionHelper.m; sourceTree = ""; }; 4C8A173B1790AA41008B5C17 /* NSData+Keyfile.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSData+Keyfile.h"; sourceTree = ""; }; 4C8A173C1790AA41008B5C17 /* NSData+Keyfile.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSData+Keyfile.m"; sourceTree = ""; }; + 4C8B36A917A6ED4B005E1FF1 /* MPOutlineMenuDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPOutlineMenuDelegate.h; sourceTree = ""; }; + 4C8B36AA17A6ED4B005E1FF1 /* MPOutlineMenuDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPOutlineMenuDelegate.m; sourceTree = ""; }; 4C8FECC716D57E3200BF26CF /* QuartzCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = QuartzCore.framework; path = System/Library/Frameworks/QuartzCore.framework; sourceTree = SDKROOT; }; 4C96D15317A12E4F00D931FA /* 99_CreatedTemplate.pdf */ = {isa = PBXFileReference; lastKnownFileType = image.pdf; path = 99_CreatedTemplate.pdf; sourceTree = ""; }; 4C9D6AA717615199001C660C /* HNHRoundedSecureTextFieldCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HNHRoundedSecureTextFieldCell.h; sourceTree = ""; }; @@ -680,8 +686,8 @@ 4CCEDE2C179F2122008402BE /* MPNotifications.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MPNotifications.h; sourceTree = ""; }; 4CCEDE2D179F213B008402BE /* MPNotifications.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPNotifications.m; sourceTree = ""; }; 4CCEDE2F179F550D008402BE /* KPKTreeReading.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KPKTreeReading.h; sourceTree = ""; }; - 4CCEDE30179F5B6C008402BE /* KPKDataStreamer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = KPKDataStreamer.h; sourceTree = ""; }; - 4CCEDE31179F5B6C008402BE /* KPKDataStreamer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = KPKDataStreamer.m; sourceTree = ""; }; + 4CCEDE30179F5B6C008402BE /* KPKDataStreamReader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = KPKDataStreamReader.h; sourceTree = ""; }; + 4CCEDE31179F5B6C008402BE /* KPKDataStreamReader.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = KPKDataStreamReader.m; sourceTree = ""; }; 4CD3ABB2178F71B50073F5C5 /* KPKVersion.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = KPKVersion.h; path = Format/KPKVersion.h; sourceTree = ""; }; 4CD3ABB3178F71B50073F5C5 /* KPKTree.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = KPKTree.h; sourceTree = ""; }; 4CD3ABB4178F71B50073F5C5 /* KPKTree.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = KPKTree.m; sourceTree = ""; }; @@ -1105,6 +1111,8 @@ 4CC0D2D017974A5A000B4BDA /* MPAttachmentTableViewDelegate.m */, 4C17D8E317A1C780006C8C1E /* MPDocumentWindowDelegate.h */, 4C17D8E417A1C780006C8C1E /* MPDocumentWindowDelegate.m */, + 4C8B36A917A6ED4B005E1FF1 /* MPOutlineMenuDelegate.h */, + 4C8B36AA17A6ED4B005E1FF1 /* MPOutlineMenuDelegate.m */, ); name = Delegates; sourceTree = ""; @@ -1585,8 +1593,10 @@ 4C1842D4179C6DE400E2F5BC /* KPKHeaderReading.h */, 4C1842D5179C6F1800E2F5BC /* KPKHeaderWriting.h */, 4CCEDE2F179F550D008402BE /* KPKTreeReading.h */, - 4CCEDE30179F5B6C008402BE /* KPKDataStreamer.h */, - 4CCEDE31179F5B6C008402BE /* KPKDataStreamer.m */, + 4CCEDE30179F5B6C008402BE /* KPKDataStreamReader.h */, + 4CCEDE31179F5B6C008402BE /* KPKDataStreamReader.m */, + 4C5FA86B17A5F26800C781C9 /* KPKDataStreamWriter.h */, + 4C5FA86C17A5F26800C781C9 /* KPKDataStreamWriter.m */, ); path = IO; sourceTree = ""; @@ -2013,13 +2023,15 @@ 4CFC873E179DF200000DFC03 /* KPKTimeInfo.m in Sources */, 4CCEDE2A179F203B008402BE /* MPOutlineView.m in Sources */, 4CCEDE2E179F213B008402BE /* MPNotifications.m in Sources */, - 4CCEDE32179F5B6C008402BE /* KPKDataStreamer.m in Sources */, + 4CCEDE32179F5B6C008402BE /* KPKDataStreamReader.m in Sources */, 4C17D8E517A1C780006C8C1E /* MPDocumentWindowDelegate.m in Sources */, 4C63B8FB17A3154D0091BD72 /* MPContextToolbarButton.m in Sources */, 4C4B7EE917A45EC6000234C7 /* MPDatePickingViewController.m in Sources */, 4C4B7EEE17A467E1000234C7 /* MPGroupInspectorViewController.m in Sources */, 4C4B7EF317A467FC000234C7 /* MPEntryInspectorViewController.m in Sources */, 4C4B7EF817A4B335000234C7 /* MPUniqueCharactersFormatter.m in Sources */, + 4C5FA86D17A5F26800C781C9 /* KPKDataStreamWriter.m in Sources */, + 4C8B36AB17A6ED4B005E1FF1 /* MPOutlineMenuDelegate.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/MacPass/KdbGroup+MPAdditions.m b/MacPass/KdbGroup+MPAdditions.m index 655d8363..e6a25b3a 100644 --- a/MacPass/KdbGroup+MPAdditions.m +++ b/MacPass/KdbGroup+MPAdditions.m @@ -10,9 +10,13 @@ #import "KdbGroup+KVOAdditions.h" #import "MPIconHelper.h" +#import "Kdb4Node.h" + @implementation KdbGroup (MPAdditions) - (NSImage *)icon { + if([self respondsToSelector:@selector(customIconUuid)]) { + } return [MPIconHelper icon:(MPIconType)self.image]; } diff --git a/MacPass/KdbGroup+MPTreeTools.h b/MacPass/KdbGroup+MPTreeTools.h index 51920cdb..1f042594 100644 --- a/MacPass/KdbGroup+MPTreeTools.h +++ b/MacPass/KdbGroup+MPTreeTools.h @@ -17,9 +17,17 @@ - (NSArray *)childEntries; /* Returns the entry with the UUID */ - (KdbEntry *)entryForUUID:(UUID *)uuid; -/* Returns the group with the UUID */ +/** + * Searches through all subgroups and loactes the Group with the given UUID + * @param uuid UUID of the searched group + * @return group with matching UUID, otherwise nil + */ - (KdbGroup *)groupForUUID:(UUID *)uuid; - +/** + * Determines, if the reciever is an anchestor of the given group + * @param group The group to test for anchestry + * @return YES, if the receiver is an anchestor of group + */ - (BOOL)isAnchestorOfGroup:(KdbGroup *)group; @end \ No newline at end of file diff --git a/MacPass/MPActionHelper.h b/MacPass/MPActionHelper.h index b53ee40a..231eb3ef 100644 --- a/MacPass/MPActionHelper.h +++ b/MacPass/MPActionHelper.h @@ -9,7 +9,7 @@ #import typedef NS_ENUM(NSUInteger, MPActionType) { - MPUnkownAction, // Netural element to be used for returns + MPUnkownAction, // Neutral element to be used for returns MPActionAddEntry, // Add an new entry MPActionAddGroup, // Add a new group MPActionDelete, // Delete entry or group @@ -19,12 +19,24 @@ typedef NS_ENUM(NSUInteger, MPActionType) { MPActionOpenURL, // open url in default browser MPActionToggleInspector, MPActionLock, // show the lock screen - MPActionEmptyTrash // empties the trashcan, if there is one + MPActionEmptyTrash, // empties the trashcan, if there is one + MPActionDatabaseSettings // Show the settings for the database }; - +/** + * Helper to retrieve commonly used actions + */ @interface MPActionHelper : NSObject - +/** + * Call this to retrieve a selector for a common used action + * @param type The action type as MPActionType + * @return selector for this action type + */ + (SEL)actionOfType:(MPActionType)type; +/** + * Helper to retrieve the MPActionType for a given selection + * @param action Selector to find the type for + * @return MPActionTpype for action, if no match was found MPUnknownAction is returned + */ + (MPActionType)typeForAction:(SEL)action; @end diff --git a/MacPass/MPActionHelper.m b/MacPass/MPActionHelper.m index b16bd45f..eff90ca7 100644 --- a/MacPass/MPActionHelper.m +++ b/MacPass/MPActionHelper.m @@ -24,7 +24,8 @@ @(MPActionOpenURL) : @"openURL:", @(MPActionToggleInspector) : @"toggleInspector:", @(MPActionLock) : @"lock:", - @(MPActionEmptyTrash) : @"emptyTrash:" + @(MPActionEmptyTrash) : @"emptyTrash:", + @(MPActionDatabaseSettings) : @"showDatabaseSettings:" }; }); return actionDict; diff --git a/MacPass/MPAppDelegate.m b/MacPass/MPAppDelegate.m index 5d5b6647..6e26abc4 100644 --- a/MacPass/MPAppDelegate.m +++ b/MacPass/MPAppDelegate.m @@ -60,7 +60,7 @@ } } -- (void)applicationDidFinishLaunching:(NSNotification *)notification { +- (void)applicationDidFinishLaunching:(NSNotification *)notification { serverDaemon = [[MPServerDaemon alloc] init]; lockDaemon = [[MPLockDaemon alloc] init]; diff --git a/MacPass/MPContextToolbarButton.m b/MacPass/MPContextToolbarButton.m index 91181f3b..e87ee3ce 100644 --- a/MacPass/MPContextToolbarButton.m +++ b/MacPass/MPContextToolbarButton.m @@ -14,8 +14,8 @@ self = [super initWithFrame:frame]; if (self) { [self setFocusRingType:NSFocusRingTypeNone]; - [self setSegmentCount:1]; - //[[self cell] setWidth:15 forSegment:1]; + [self setSegmentCount:2]; + [[self cell] setWidth:15 forSegment:1]; [[self cell] setTrackingMode:NSSegmentSwitchTrackingMomentary]; [self setSegmentStyle:NSSegmentStyleTexturedSquare]; } @@ -32,7 +32,7 @@ } - (void)setSegmentCount:(NSInteger)count { - if(count == 1) { + if(count == 2) { [super setSegmentCount:count]; } } @@ -41,6 +41,4 @@ [self setImage:image forSegment:0]; } - - @end diff --git a/MacPass/MPDatabaseSettingsWindowController.h b/MacPass/MPDatabaseSettingsWindowController.h index bc0e75c7..f379672e 100644 --- a/MacPass/MPDatabaseSettingsWindowController.h +++ b/MacPass/MPDatabaseSettingsWindowController.h @@ -14,7 +14,7 @@ typedef NS_ENUM(NSUInteger, MPDatabaseSettingsTab) { MPDatabaseSettingsTabPassword, MPDatabaseSettingsTabDisplay, MPDatabaseSettingsTabAdvanced, - MPDatabaseSettingsTemplatesTab, + MPDatabaseSettingsTabTemplates, }; @class MPDocument; diff --git a/MacPass/MPDatabaseSettingsWindowController.m b/MacPass/MPDatabaseSettingsWindowController.m index fb4779f6..68ae17f9 100644 --- a/MacPass/MPDatabaseSettingsWindowController.m +++ b/MacPass/MPDatabaseSettingsWindowController.m @@ -207,7 +207,7 @@ case MPDatabaseSettingsTabAdvanced: case MPDatabaseSettingsTabGeneral: - case MPDatabaseSettingsTemplatesTab: + case MPDatabaseSettingsTabTemplates: return (_document.version == MPDatabaseVersion4); default: @@ -346,7 +346,7 @@ [[self window] makeFirstResponder:self.passwordTextField]; break; - case MPDatabaseSettingsTemplatesTab: + case MPDatabaseSettingsTabTemplates: break; } } diff --git a/MacPass/MPDocument.h b/MacPass/MPDocument.h index 5b76904b..03cee62f 100644 --- a/MacPass/MPDocument.h +++ b/MacPass/MPDocument.h @@ -49,6 +49,7 @@ APPKIT_EXTERN NSString *const MPDocumnetDidChangeCurrentEntryNotification; @property (weak, readonly, nonatomic) KdbGroup *root; @property (readonly, strong) MPRootAdapter *rootAdapter; @property (weak, readonly) KdbGroup *trash; +@property (weak, readonly) KdbGroup *templates; @property (nonatomic, copy) NSString *password; @property (nonatomic, strong) NSURL *key; diff --git a/MacPass/MPDocument.m b/MacPass/MPDocument.m index a0a072ee..f7118655 100644 --- a/MacPass/MPDocument.m +++ b/MacPass/MPDocument.m @@ -51,6 +51,10 @@ NSString *const MPDocumentRequestPasswordSaveNotification = @"com.hicknhack.macp NSString *const MPDocumentEntryKey = @"MPDocumentEntryKey"; NSString *const MPDocumentGroupKey = @"MPDocumentGroupKey"; +typedef NS_ENUM(NSUInteger, MPAlertType) { + MPAlertTypeEmptryTrash, + MPAlertTypeDeleteTrashed +}; @interface MPDocument () { @private @@ -349,6 +353,15 @@ NSString *const MPDocumentGroupKey = @"MPDocumentGroupKey return nil; } +- (KdbGroup *)templates { + static KdbGroup *_templates = nil; + BOOL templateValid = [((Kdb4Group *)_templates).uuid isEqual:self.treeV4.entryTemplatesGroup]; + if(!templateValid) { + _templates = [self findGroup:self.treeV4.entryTemplatesGroup]; + } + return _templates; +} + - (BOOL)isItemTrashed:(id)item { BOOL validItem = [item isKindOfClass:[KdbEntry class]] || [item isKindOfClass:[KdbGroup class]]; if(!item) { @@ -510,7 +523,7 @@ NSString *const MPDocumentGroupKey = @"MPDocumentGroupKey [alert beginSheetModalForWindow:window modalDelegate:self didEndSelector:@selector(alertDidEnd:returnCode:contextInfo:) contextInfo:NULL]; } -- (void) alertDidEnd:(NSAlert *)alert returnCode:(NSInteger)returnCode contextInfo:(void *)contextInfo { +- (void)alertDidEnd:(NSAlert *)alert returnCode:(NSInteger)returnCode contextInfo:(void *)contextInfo { if(returnCode == NSAlertFirstButtonReturn) { [self _emptyTrash]; } diff --git a/MacPass/MPDocumentWindowController.h b/MacPass/MPDocumentWindowController.h index cddce83d..c5a7ef8e 100644 --- a/MacPass/MPDocumentWindowController.h +++ b/MacPass/MPDocumentWindowController.h @@ -35,8 +35,12 @@ - (void)showEntries; - (void)showPasswordInput; - (void)performFindPanelAction:(id)sender; + - (IBAction)editPassword:(id)sender; - (IBAction)showDatabaseSettings:(id)sender; +- (IBAction)editTemplateGroup:(id)sender; +- (IBAction)editTrashGroup:(id)sender; + - (IBAction)exportDatabase:(id)sender; - (IBAction)lock:(id)sender; diff --git a/MacPass/MPDocumentWindowController.m b/MacPass/MPDocumentWindowController.m index 48696268..310b1956 100644 --- a/MacPass/MPDocumentWindowController.m +++ b/MacPass/MPDocumentWindowController.m @@ -252,11 +252,19 @@ } - (void)editPassword:(id)sender { - [self _showDatabaseSetting:MPDatabaseSettingsTabPassword saveDocument:NO]; + [self _showDatabaseSetting:MPDatabaseSettingsTabPassword]; } - (void)showDatabaseSettings:(id)sender { - [self _showDatabaseSetting:MPDatabaseSettingsTabGeneral saveDocument:NO]; + [self _showDatabaseSetting:MPDatabaseSettingsTabGeneral]; +} + +- (void)editTemplateGroup:(id)sender { + [self _showDatabaseSetting:MPDatabaseSettingsTabTemplates]; +} + +- (void)editTrashGroup:(id)sender { + [self _showDatabaseSetting:MPDatabaseSettingsTabAdvanced]; } - (IBAction)lock:(id)sender { @@ -383,7 +391,7 @@ [self editPassword:nil]; } -- (void)_showDatabaseSetting:(MPDatabaseSettingsTab)tab saveDocument:(BOOL)save{ +- (void)_showDatabaseSetting:(MPDatabaseSettingsTab)tab { if(!self.documentSettingsWindowController) { _documentSettingsWindowController = [[MPDatabaseSettingsWindowController alloc] initWithDocument:[self document]]; [_documentSettingsWindowController setDelegate:self]; diff --git a/MacPass/MPEntryViewController.m b/MacPass/MPEntryViewController.m index ff3146f7..988edc1e 100644 --- a/MacPass/MPEntryViewController.m +++ b/MacPass/MPEntryViewController.m @@ -416,8 +416,10 @@ NSString *const _toggleFilterUsernameButton = @"SearchUsername"; context.duration = STATUS_BAR_ANIMATION_TIME; context.allowsImplicitAnimation = YES; [self.view layoutSubtreeIfNeeded]; - } completionHandler:nil] ; - [[[self windowController] window] makeFirstResponder:self.filterSearchField]; + } completionHandler:^{ + [[[self windowController] window] makeFirstResponder:self.filterSearchField]; + }]; + } - (void)_hideFilterBarAnimated { diff --git a/MacPass/MPGroupInspectorViewController.m b/MacPass/MPGroupInspectorViewController.m index c4eb7083..ceb71053 100644 --- a/MacPass/MPGroupInspectorViewController.m +++ b/MacPass/MPGroupInspectorViewController.m @@ -66,9 +66,9 @@ - (void)_updateBindings { if(self.group) { - [self.titleTextField bind:NSValueBinding toObject:self.group withKeyPath:@"name" options:nil]; + [self.titleTextField bind:NSValueBinding toObject:self.group withKeyPath:@"nameUndoable" options:nil]; if([self.group respondsToSelector:@selector(notes:)]) { - [self.notesTextView bind:NSValueBinding toObject:self.group withKeyPath:@"notes" options:nil]; + [self.notesTextView bind:NSValueBinding toObject:self.group withKeyPath:@"notesUndoable" options:nil]; } else { [self.notesTextView unbind:NSValueBinding]; diff --git a/MacPass/MPIconHelper.h b/MacPass/MPIconHelper.h index e393e6ad..978e3e6f 100644 --- a/MacPass/MPIconHelper.h +++ b/MacPass/MPIconHelper.h @@ -7,7 +7,11 @@ // #import - +/** + * Available IconTypes + * Every Icon after MPCustomIconTypeBegin + * is not suitable for usage as KDB Icon + */ typedef NS_ENUM(NSUInteger, MPIconType) { MPIconPassword, MPIconPackageNetwork, @@ -29,30 +33,37 @@ typedef NS_ENUM(NSUInteger, MPIconType) { MPIconFolder = 48, MPIconPhone = 68, /* Custom Icons not used in Database */ - MPIconInfo = 1000, + MPCustomIconTypeBegin = 1000, + MPIconInfo, MPIconAddFolder, MPIconHardDisk, MPIconCreated, }; +/** + * Helper class to retrieve Icons for Keys. KDB sortes Icons as an Integer + * The Helper maps those numbers to icons. + * It can furthermore be used to retrieve other Icons, that are non-Database Icons + */ @interface MPIconHelper : NSObject -/* - @param type Icon identifier typ MPIconTyp - @returns Icon for given identifier +/** + * Returns the Icon Image for a given type + * @param type Icontype + * @return Image for the IconType */ + (NSImage *)icon:(MPIconType)type; -/* - Available Icons, Use the MPDatabaseIconType to access a individual icon; - @returns all availble Icons + +/** + * Available Icon names (all) + * @return Dictioary with MPIconType keys and NSString values containing their names */ + (NSDictionary *)availableIconNames; -+ (NSArray *)availableIcons; - -/* - @returns a random Icon image +/** + * List of all availabel DatabaseIcons as Images. Sorted by IconIndex + * @return Array of Icons as NSImage objects */ -+ (NSImage *)randomIcon; ++ (NSArray *)databaseIcons; @end diff --git a/MacPass/MPIconHelper.m b/MacPass/MPIconHelper.m index e050a059..9ba47722 100644 --- a/MacPass/MPIconHelper.m +++ b/MacPass/MPIconHelper.m @@ -23,10 +23,13 @@ static NSDictionary *icons; return [NSImage imageNamed:NSImageNameActionTemplate]; } -+ (NSArray *)availableIcons { ++ (NSArray *)databaseIcons { NSDictionary *imageNames = [MPIconHelper availableIconNames]; NSMutableArray *icons = [[NSMutableArray alloc] initWithCapacity:[imageNames count]]; for(NSNumber *iconNumber in [imageNames allKeys]) { + if([iconNumber integerValue] > MPCustomIconTypeBegin) { + continue; // Skip all non-db Keys + } MPIconType iconType = (MPIconType)[iconNumber integerValue]; [icons addObject:[MPIconHelper icon:iconType]]; } @@ -67,16 +70,4 @@ static NSDictionary *icons; }; return imageNames; } - -+ (NSImage *)randomIcon { - static dispatch_once_t onceToken; - dispatch_once(&onceToken, ^{ - srandom([[NSDate date] timeIntervalSince1970]); - }); - - NSArray *types = [[MPIconHelper availableIconNames] allKeys]; - NSUInteger randomIndex = random() % [types count]; - return [MPIconHelper icon:(MPIconType)randomIndex]; -} - @end diff --git a/MacPass/MPIconSelectViewController.m b/MacPass/MPIconSelectViewController.m index 2205602c..74644320 100644 --- a/MacPass/MPIconSelectViewController.m +++ b/MacPass/MPIconSelectViewController.m @@ -31,7 +31,7 @@ [self.iconCollectionView setBackgroundColors:@[[NSColor clearColor]]]; [self.iconCollectionView setSelectable:YES]; [self.iconCollectionView setAllowsMultipleSelection:NO]; - [self.iconCollectionView setContent:[MPIconHelper availableIcons]]; + [self.iconCollectionView setContent:[MPIconHelper databaseIcons]]; } diff --git a/MacPass/MPOutlineMenuDelegate.h b/MacPass/MPOutlineMenuDelegate.h new file mode 100644 index 00000000..ceae57d8 --- /dev/null +++ b/MacPass/MPOutlineMenuDelegate.h @@ -0,0 +1,17 @@ +// +// MPOutlineMenuDelegate.h +// MacPass +// +// Created by Michael Starke on 29.07.13. +// Copyright (c) 2013 HicknHack Software GmbH. All rights reserved. +// + +#import + +@class MPOutlineViewController; + +@interface MPOutlineMenuDelegate : NSObject + +@property (weak) MPOutlineViewController *viewController; + +@end diff --git a/MacPass/MPOutlineMenuDelegate.m b/MacPass/MPOutlineMenuDelegate.m new file mode 100644 index 00000000..0df808bf --- /dev/null +++ b/MacPass/MPOutlineMenuDelegate.m @@ -0,0 +1,114 @@ +// +// MPOutlineMenuDelegate.m +// MacPass +// +// Created by Michael Starke on 29.07.13. +// Copyright (c) 2013 HicknHack Software GmbH. All rights reserved. +// + +#import "MPOutlineMenuDelegate.h" +#import "MPOutlineViewController.h" + +#import "MPRootAdapter.h" +#import "MPDocument.h" + +#import "MPActionHelper.h" +#import "MPContextMenuHelper.h" + +#import "Kdb.h" + +NSString *const _MPOutlineMenuDefault = @"Default"; +NSString *const _MPOutlineMenuTrash = @"Trash"; +NSString *const _MPOutlineMenuTrashItem = @"TrashItem"; +NSString *const _MPOutlineMenuRoot = @"Root"; +NSString *const _MPOutlineMenuTemplate = @"Template"; + +@implementation MPOutlineMenuDelegate + +- (void)menuNeedsUpdate:(NSMenu *)menu { + /* + Scenarios are + + 1. Root adapter + 2. Normal Group + 3. Template Group + 4. Trash Group + 5. Trashed Item + */ + + id item = [self.viewController itemUnderMouse]; + if( [item isKindOfClass:[MPRootAdapter class]]) { + [self _updateRootMenu:menu]; + } + + if( [item isKindOfClass:[KdbGroup class]]) { + KdbGroup *group = (KdbGroup *)item; + MPDocument *document = [[NSDocumentController sharedDocumentController] currentDocument]; + if(group && document.trash == group) { + [self _updateTrashMenu:menu]; + } + else if([document isItemTrashed:group]) { + [self _updateTrashItemMenu:menu]; + } + else { + [self _updateDefaultMenu:menu]; + } + } +} + +- (void)_updateRootMenu:(NSMenu *)menu { + if([[menu title] isEqualToString:_MPOutlineMenuRoot]) { + return; // nothing to do, all fine + } + [menu removeAllItems]; + [menu addItemWithTitle:NSLocalizedString(@"CHANGE_DATABASE_NAME", "") + action:[MPActionHelper actionOfType:MPActionDatabaseSettings] + keyEquivalent:@""]; + + [menu setTitle:_MPOutlineMenuRoot]; +} + +- (void)_updateTrashMenu:(NSMenu *)menu { + if([[menu title] isEqualToString:_MPOutlineMenuTrash]) { + return; // nothing to do, all fine + } + [menu removeAllItems]; + [menu addItemWithTitle:NSLocalizedString(@"CHANGE_TRASH_GROUP", "") + action:@selector(editTrashGroup:) + keyEquivalent:@""]; + [menu addItem:[NSMenuItem separatorItem]]; + [menu addItemWithTitle:NSLocalizedString(@"EMPTY_TRASH", "") + action:[MPActionHelper actionOfType:MPActionEmptyTrash] + keyEquivalent:@""]; + + [menu setTitle:_MPOutlineMenuTrash]; +} + +- (void)_updateTrashItemMenu:(NSMenu *)menu { + if([[menu title] isEqualToString:_MPOutlineMenuTrashItem]) { + return; // nothing to do, all fine + } + [menu removeAllItems]; + [menu addItemWithTitle:NSLocalizedString(@"DELETE", "") + action:[MPActionHelper actionOfType:MPActionDelete] + keyEquivalent:@""]; + [menu addItem:[NSMenuItem separatorItem]]; + [menu addItemWithTitle:NSLocalizedString(@"EMPTY_TRASH", "") + action:[MPActionHelper actionOfType:MPActionEmptyTrash] + keyEquivalent:@""]; + + [menu setTitle:_MPOutlineMenuTrashItem]; +} + + +- (void)_updateDefaultMenu:(NSMenu *)menu { + if([[menu title] isEqualToString:_MPOutlineMenuDefault]) { + return; // nothing to do, all fine + } + [menu removeAllItems]; + for(NSMenuItem *item in [MPContextMenuHelper contextMenuItemsWithItems:MPContextMenuMinimal]) { + [menu addItem:item]; + } +} + +@end diff --git a/MacPass/MPOutlineViewController.h b/MacPass/MPOutlineViewController.h index 290fd211..061cf314 100644 --- a/MacPass/MPOutlineViewController.h +++ b/MacPass/MPOutlineViewController.h @@ -15,7 +15,7 @@ APPKIT_EXTERN NSString *const MPOutlineViewDidChangeGroupSelection; @class HNHGradientView; @class MPDocumentWindowController; -@interface MPOutlineViewController : MPViewController +@interface MPOutlineViewController : MPViewController @property (weak) IBOutlet HNHGradientView *bottomBar; @@ -27,5 +27,10 @@ APPKIT_EXTERN NSString *const MPOutlineViewDidChangeGroupSelection; - (void)createGroup:(id)sender; - (void)createEntry:(id)sender; - (void)deleteNode:(id)sender; +/** + * Retrieves the current item for the current mouse location + * @return Item under mouse. If the mouse isn't inside the view, nil is returned + */ +- (id)itemUnderMouse; @end diff --git a/MacPass/MPOutlineViewController.m b/MacPass/MPOutlineViewController.m index e8f0c93c..3608ee8d 100644 --- a/MacPass/MPOutlineViewController.m +++ b/MacPass/MPOutlineViewController.m @@ -17,6 +17,7 @@ #import "MPUppercaseStringValueTransformer.h" #import "MPRootAdapter.h" #import "MPNotifications.h" +#import "MPOutlineMenuDelegate.h" #import "KdbLib.h" #import "Kdb4Node.h" @@ -31,6 +32,8 @@ NSString *const _MPOutlinveViewHeaderViewIdentifier = @"HeaderCell"; @interface MPOutlineViewController () { BOOL _bindingEstablished; + MPOutlineMenuDelegate *_menuDelegate; + } @property (weak) IBOutlet NSOutlineView *outlineView; @property (weak) IBOutlet NSButton *addGroupButton; @@ -56,6 +59,8 @@ NSString *const _MPOutlinveViewHeaderViewIdentifier = @"HeaderCell"; _bindingEstablished = NO; _datasource = [[MPOutlineDataSource alloc] init]; _databaseNameWrapper = NSLocalizedString(@"NEW_DATABASE", "Name for a newly created Database"); + _menuDelegate = [[MPOutlineMenuDelegate alloc] init]; + _menuDelegate.viewController = self; } return self; @@ -138,6 +143,16 @@ NSString *const _MPOutlinveViewHeaderViewIdentifier = @"HeaderCell"; document.selectedItem = document.selectedGroup; } +- (id)itemUnderMouse { + NSPoint mouseLocation = [[self.outlineView window] mouseLocationOutsideOfEventStream]; + NSPoint localPoint = [self.outlineView convertPoint:mouseLocation fromView:[[self.outlineView window] contentView]]; + NSInteger row = [self.outlineView rowAtPoint:localPoint]; + if(row == -1) { + return nil; // No row was hit + } + return [[self.outlineView itemAtRow:row] representedObject]; +} + #pragma mark Validation - (BOOL)validateMenuItem:(NSMenuItem *)menuItem { @@ -234,10 +249,7 @@ NSString *const _MPOutlinveViewHeaderViewIdentifier = @"HeaderCell"; - (NSMenu *)_contextMenu { NSMenu *menu = [[NSMenu alloc] init]; - NSArray *items = [MPContextMenuHelper contextMenuItemsWithItems:MPContextMenuMinimal]; - for(NSMenuItem *item in items) { - [menu addItem:item]; - } + [menu setDelegate:_menuDelegate]; return menu; } diff --git a/MacPass/MPToolbarDelegate.m b/MacPass/MPToolbarDelegate.m index a643419d..66fdb952 100644 --- a/MacPass/MPToolbarDelegate.m +++ b/MacPass/MPToolbarDelegate.m @@ -84,18 +84,12 @@ NSString *const MPToolbarItemInspector = @"TOOLBAR_INSPECTOR"; } else if( [itemIdentifier isEqualToString:MPToolbarItemAddEntry]) { MPContextToolbarButton *button = [[MPContextToolbarButton alloc] initWithFrame:NSMakeRect(0, 0, 32, 32)]; + [button setAction:[self _actionForToolbarItemIdentifier:itemIdentifier]]; NSImage *image = self.toolbarImages[itemIdentifier]; [image setSize:NSMakeSize(16, 16)]; [button setImage:image]; [button sizeToFit]; - [button setAction:[self _actionForToolbarItemIdentifier:itemIdentifier]]; - - NSMenu *menu = [[NSMenu allocWithZone:[NSMenu menuZone]] init]; - [menu addItemWithTitle:@"Test" action:NULL keyEquivalent:@""]; - [menu addItemWithTitle:@"More" action:NULL keyEquivalent:@""]; - [button setMenu:menu]; - - + NSRect fittingRect = [button frame]; fittingRect.size.width = MAX( (CGFloat)32.0,fittingRect.size.width); [button setFrame:fittingRect]; diff --git a/MacPass/de.lproj/Localizable.strings b/MacPass/de.lproj/Localizable.strings index 2468a48b721d4f3a31f2e36edbf5cd21a0591092..f36901826b1c2d16ebe63c20d9f8ba235381d34c 100644 GIT binary patch delta 1995 zcmb7_&rTCj6vhuRA`+sBMk5R3fH4M0bma!4@~@?&(2}+YxET>DZG^UIL1p8(a%nV^ z=sUP&?+f@2Jc7^Q@4MqL{fER%?wvb#?ws?T?>pzrkM)mRUn*Zem%@>O<>L^%FDkZWHQTi^&kL*%7_S&Dx07SF&uZKr z+ps&|?xAD_XFG$p#W1{j{cfkdk~N*B3bq$n*X__6;iHS+Z_Kl9SQX1Vyt`*J@(?~7 zTnm2>J`F!zdJ#?zy$nx=X2RO#TsSg3ef(|s+Su)fHp%fUpOtOZnQrk^1+-`7aCBlU z+?co$_)w4sQkGCRxo;5kGWQg7$`O!*n1qDrePs8@USn?$`yTfe^S-;cm_<{3%EOXQ ziJTh#V}epv2w)}8@NEqsMdnp5?UeXvf&Fe}boM##3Y=czWUdWd35EJ=^OpT45UX%m zJB3@b@Z{z#k|7dIM$dzzv{?dT#z9DUS;K5gl5y2>b$~<3C6TM_30RZoB?9X5Ck~?c zvrde4X5Z2rl>}Oej}@|~T?jdR!>HRk7f~8FkrZhMU?0gls6Gu%&}V_6aD4y0*td?25;kJxk6kj_1fSInEQ*s&XKOma&>X*p{gPfm$Ns z42Kdx5zXBc*Ga7g^p=qz(Rd3!b{$wHeT6gqfd>5(FF~rp&4F8ZeSoTzMPVfMHaXX5Wea8vi-iTCv zQf3!l3jK(0q+QMK^F;NtQm%@y9ecpeW&prL7TXT4pf%lR2kd+9V1qYRR(cmzS-0bU z?5eG#5LsQd*p}0s?ZvlXg$Sc0P)qKOGVVL)b(|PnXWvVTqujp}sRrZH*FBHO-A&L( z@PC7RkF0wzlz>#RNDOf&(miG|T41g_G4#A+LGs&Z??TFmysOOr2h+>gSz!3xOoKwn z8{t#I_fxa8bLj6@v`qMG@=hgAMrB6QF!aA{ku9Dp099w4f>C$c=AF_nk>{-DGRz-U F*B_4XPKW>i delta 308 zcmZojTopbcWAYhE4sKNj1qKg>e1=knqKSgC6N|hi3kY%WgG7B9G8yuK;w22JAem!M zaP{E~sX&+w6x}SuxP^JLgA&K&F4hiaRR)L23)v(m&rp+^yn;1gvK5;XoZZ8w2WOvR z^D^gR&}YyB+7b-3A&DUuXdcKe1)y#DK++jV7BEx-S;;`rVz6i~ke4=Do=bGH7<(MZ zEuOv%i9oq*kT_6%5s)qcy19fQ2WT41q-3~BX+XJDpj--2t_-L%2WT=#ofd=s zF<8V8$O0Lu#9+<91tgJ7VThl+QC^W3#e~ThaT;yb;ku^^0Ea{|RR910 delta 385 zcmX>Q-IXBy|DQgC7J~wVDiFIcBr;So6a!g_4CxH{6V<(yxfl@A9t`;mr3^&~1we&b z4EhuEL)DR$`7&fOL~)!B|zVlFysJDgqfBMH!Te)mkN|i0m_vD wb>;v~2dM)F%4A)3+sPfgL6dXXT_zt;;Fvst*K6`7c7w@wl3@1cC+v4r0V^R>m;e9(