diff --git a/MacPass/MPAppDelegate.h b/MacPass/MPAppDelegate.h index 685a324c..48874237 100644 --- a/MacPass/MPAppDelegate.h +++ b/MacPass/MPAppDelegate.h @@ -8,6 +8,14 @@ #import +typedef enum { + MPContextMenuCreate = 1<<0, + MPContextMenuDelete = 1<<1, + MPContextMenuCopy = 1<<2, + MPContextMenuMinimal = MPContextMenuCreate | MPContextMenuDelete, + MPContextMenuFull = MPContextMenuMinimal | MPContextMenuCopy, +}MPContextMenuItemsFlags; + @class MPDatabaseDocument; @interface MPAppDelegate : NSObject @@ -16,4 +24,10 @@ - (NSString *)applicationName; +/* + Creates an array of menuitems to be used as a menu + Automatically sets up actions, so you need to take care of the responder chain + */ +- (NSArray *)contextMenuItemsWithItems:(MPContextMenuItemsFlags)flags; + @end \ No newline at end of file diff --git a/MacPass/MPAppDelegate.m b/MacPass/MPAppDelegate.m index 1342cabb..ddd96941 100644 --- a/MacPass/MPAppDelegate.m +++ b/MacPass/MPAppDelegate.m @@ -22,8 +22,7 @@ @implementation MPAppDelegate -- (void)applicationDidFinishLaunching:(NSNotification *)aNotification -{ +- (void)applicationDidFinishLaunching:(NSNotification *)aNotification { self.mainWindowController = [[[MPMainWindowController alloc] init] autorelease]; [self.mainWindowController showWindow:[self.mainWindowController window]]; } @@ -51,8 +50,40 @@ [self.settingsController showWindow:_settingsController.window]; } -- (void)toolbarItemPressed:(id)sender { - NSLog(@"Pressed %@", sender); +- (NSArray *)contextMenuItemsWithItems:(MPContextMenuItemsFlags)flags { + BOOL insertCreate = (0 != (flags & MPContextMenuCreate)); + BOOL insertDelete = (0 != (flags & MPContextMenuDelete)); + BOOL insertCopy = (0 != (flags & MPContextMenuCopy)); + + NSMutableArray *items = [NSMutableArray arrayWithCapacity:7]; + if(insertCreate) { + NSMenuItem *newGroup = [[NSMenuItem alloc] initWithTitle:@"New Group" action:@selector(createGroup:) keyEquivalent:@"G"]; + NSMenuItem *newEntry = [[NSMenuItem alloc] initWithTitle:@"New Entry" action:@selector(createEntry:) keyEquivalent:@"E"]; + [items addObjectsFromArray:@[ newGroup, newEntry ]]; + [newEntry release]; + [newGroup release]; + } + if(insertDelete) { + if([items count] > 0) { + [items addObject:[NSMenuItem separatorItem]]; + } + NSMenuItem *delete = [[NSMenuItem alloc] initWithTitle:@"Delete" action:@selector(deleteEntry:) keyEquivalent:@""]; + [items addObject:delete]; + [delete release]; + } + if(insertCopy) { + if([items count] > 0) { + [items addObject:[NSMenuItem separatorItem]]; + } + NSMenuItem *copyUsername = [[NSMenuItem alloc] initWithTitle:@"Copy Username" action:@selector(copyUsername:) keyEquivalent:@"C"]; + NSMenuItem *copyPassword = [[NSMenuItem alloc] initWithTitle:@"Copy Password" action:@selector(copyPassword:) keyEquivalent:@"c"]; + NSMenuItem *openURL = [[NSMenuItem alloc] initWithTitle:@"Open URL" action:@selector(openURL:) keyEquivalent:@"U"]; + [items addObjectsFromArray:@[ copyUsername, copyPassword, openURL]]; + [copyPassword release]; + [copyUsername release]; + [openURL release]; + } + return items; } @end diff --git a/MacPass/MPButtonBarButton.m b/MacPass/MPButtonBarButton.m index 74aa3712..bd33ef8e 100644 --- a/MacPass/MPButtonBarButton.m +++ b/MacPass/MPButtonBarButton.m @@ -34,6 +34,7 @@ [borderGradient drawInRect:drawingRect relativeCenterPosition:NSMakePoint(-1.0, 0)]; drawingRect.origin.x = [self bounds].size.width - 5; [borderGradient drawInRect:drawingRect relativeCenterPosition:NSMakePoint(1.0, 0)]; + [borderGradient release]; } [super drawRect:dirtyRect]; } diff --git a/MacPass/MPEntryViewController.h b/MacPass/MPEntryViewController.h index 3f2cc8a7..37bfa331 100644 --- a/MacPass/MPEntryViewController.h +++ b/MacPass/MPEntryViewController.h @@ -14,6 +14,13 @@ APPKIT_EXTERN NSString *const MPEntryTablePasswordColumnIdentifier; APPKIT_EXTERN NSString *const MPEntryTableParentColumnIdentifier; APPKIT_EXTERN NSString *const MPEntryTableURLColumnIdentifier; +/* Tags to determine what to copy */ +typedef enum { + MPCopyUsername, + MPCopyPassword, + MPCopyURL, + MPCopyWholeEntry, +} MPCopyContentTypeTag; @class KdbGroup; @class MPOutlineViewDelegate; @@ -27,4 +34,10 @@ APPKIT_EXTERN NSString *const MPEntryTableURLColumnIdentifier; /* Clear the Search filter*/ - (void)clearFilter; +- (void)copyUsername:(id)sender; +- (void)copyPassword:(id)sender; +//- (void)copyURL:(id)sender; +//- (void)createEntry:(id)sender; +//- (void)deleteEntry:(id)sender; + @end diff --git a/MacPass/MPEntryViewController.m b/MacPass/MPEntryViewController.m index 70fa71c1..f231a425 100644 --- a/MacPass/MPEntryViewController.m +++ b/MacPass/MPEntryViewController.m @@ -7,6 +7,7 @@ // #import "MPEntryViewController.h" +#import "MPAppDelegate.h" #import "MPOutlineViewDelegate.h" #import "MPDatabaseController.h" #import "MPDatabaseDocument.h" @@ -27,12 +28,6 @@ typedef enum { MPFilterTitles = 8, } MPFilterModeType; -typedef enum { - MPCopyUsername, - MPCopyPassword, - MPCopyURL, - MPCopyWholeEntry, -} MPCopyContentTypeTag; NSString *const MPEntryTableUserNameColumnIdentifier = @"MPUserNameColumnIdentifier"; NSString *const MPEntryTableTitleColumnIdentifier = @"MPTitleColumnIdentifier"; @@ -83,8 +78,8 @@ NSString *const _toggleFilterUsernameButton = @"SearchUsername"; - (void)_showFilterBarAnimated:(BOOL)animate; - (void)_hideStatusBarAnimated:(BOOL)animate; -- (void)_copyEntryData:(id)sender; - (void)_quickCopyEntryData:(id)sender; +- (KdbEntry *)_selectedEntry; @end @@ -333,7 +328,7 @@ NSString *const _toggleFilterUsernameButton = @"SearchUsername"; animate = NO; - + if(!self.isStatusBarVisible) { return; // nothing to do; } @@ -357,84 +352,65 @@ NSString *const _toggleFilterUsernameButton = @"SearchUsername"; #pragma mark EntryMenu - (void)_setupEntryMenu { - NSMenu *menu = [[NSMenu allocWithZone:[NSMenu menuZone]] init]; - NSMenuItem *copyUserItem = [[NSMenuItem allocWithZone:[NSMenu menuZone]] initWithTitle:@"Copy Username" - action:@selector(_copyEntryData:) - keyEquivalent:@"C"]; - [copyUserItem setTag:MPCopyUsername]; - [copyUserItem setTarget:self]; - NSMenuItem *copyPasswordItem = [[NSMenuItem allocWithZone:[NSMenu menuZone]] initWithTitle:@"Copy Password" - action:@selector(_copyEntryData:) - keyEquivalent:@"c"]; - [copyPasswordItem setTag:MPCopyPassword]; - [copyPasswordItem setTarget:self]; - - [menu addItem:copyUserItem]; - [menu addItem:copyPasswordItem]; - [copyUserItem release]; - [copyPasswordItem release]; + NSMenu *menu = [[NSMenu alloc] init]; + NSArray *items = [(MPAppDelegate *)[NSApp delegate] contextMenuItemsWithItems:MPContextMenuFull]; + for(NSMenuItem *item in items) { + [menu addItem:item]; + } [self.entryTable setMenu:menu]; [menu release]; } +#pragma makr Action Helper + +- (KdbEntry *)_selectedEntry { + NSInteger activeRow = [self.entryTable clickedRow]; + /* Fallback to selection e.g. for toolbar actions */ + if(activeRow < 0 ) { + activeRow = [self.entryTable selectedRow]; + } + if(activeRow >= 0 && activeRow <= [[self.entryArrayController arrangedObjects] count]) { + return [self.entryArrayController arrangedObjects][activeRow]; + } + return nil; +} + #pragma mark Actions - (void)_quickCopyEntryData:(id)sender { - NSInteger clickedRow = [self.entryTable clickedRow]; - if(clickedRow < 0 || clickedRow > [[self.entryArrayController arrangedObjects] count]) { - return; - } - KdbEntry *selectedEntry = [self.entryArrayController arrangedObjects][clickedRow]; NSTableColumn *column = [self.entryTable tableColumns][[self.entryTable clickedColumn]]; NSString *identifier = [column identifier]; - NSImage *image = nil; - NSString *lable = nil; if([identifier isEqualToString:MPEntryTablePasswordColumnIdentifier]) { - [[MPPasteBoardController defaultController] copyObjects:@[ selectedEntry.password ]]; - image = [[NSBundle mainBundle] imageForResource:@"00_PasswordTemplate"]; - lable = @"Password copied!"; + [self copyPassword:nil]; } else if([identifier isEqualToString:MPEntryTableUserNameColumnIdentifier]) { - [[MPPasteBoardController defaultController] copyObjects:@[ selectedEntry.username ]]; - image = [[NSBundle mainBundle] imageForResource:@"09_IdentityTemplate"]; - lable = @"Username copied!"; - } - if(image || lable) { - [[MPOverlayWindowController sharedController] displayOverlayImage:image label:lable atView:self.view]; + [self copyUsername:nil]; } } -- (void)_copyEntryData:(id)sender { - NSInteger clickedRow = [self.entryTable clickedRow]; - if(clickedRow < 0 || clickedRow > [[self.entryArrayController arrangedObjects] count]) { - return; - } - KdbEntry *selectedEntry = [self.entryArrayController arrangedObjects][clickedRow]; - - if([sender respondsToSelector:@selector(tag)]) { - MPCopyContentTypeTag contentTag = (MPCopyContentTypeTag)[sender tag]; - SEL contentTypeSelector = @selector(description); - switch (contentTag) { - case MPCopyPassword: - contentTypeSelector = @selector(password); - break; - - case MPCopyUsername: - contentTypeSelector = @selector(username); - break; - - case MPCopyURL: - contentTypeSelector = @selector(URL); - break; - - case MPCopyWholeEntry: - default: - break; - } - [[MPPasteBoardController defaultController] copyObjects:@[ [selectedEntry performSelector:contentTypeSelector] ]]; - } +- (void)copyPassword:(id)sender { + KdbEntry *selectedEntry = [self _selectedEntry]; + if(!selectedEntry) { + return; // nothing found to work with; + } + [[MPPasteBoardController defaultController] copyObjects:@[ selectedEntry.password ]]; + NSImage *image = [[NSBundle mainBundle] imageForResource:@"00_PasswordTemplate"]; + NSString *lable = @"Password copied!"; + [[MPOverlayWindowController sharedController] displayOverlayImage:image label:lable atView:self.view]; +} +- (void)copyUsername:(id)sender { + KdbEntry *selectedEntry = [self _selectedEntry]; + if(!selectedEntry) { + return; // No entry to work with; + } + [[MPPasteBoardController defaultController] copyObjects:@[ selectedEntry.username ] ]; + + [[MPPasteBoardController defaultController] copyObjects:@[ selectedEntry.username ]]; + NSImage *image = [[NSBundle mainBundle] imageForResource:@"09_IdentityTemplate"]; + NSString *lable = @"Username copied!"; + [[MPOverlayWindowController sharedController] displayOverlayImage:image label:lable atView:self.view]; } - (void)_toggleFilterSpace:(id)sender { @@ -453,7 +429,6 @@ NSString *const _toggleFilterUsernameButton = @"SearchUsername"; default: break; } - } - (void)setFilterMode:(MPFilterModeType)newFilterMode { diff --git a/MacPass/MPMainWindowController.h b/MacPass/MPMainWindowController.h index 5b90cdd9..840eb5c1 100644 --- a/MacPass/MPMainWindowController.h +++ b/MacPass/MPMainWindowController.h @@ -20,4 +20,5 @@ Clears the Search filter */ - (void)clearFilter:(id)sender; + @end diff --git a/MacPass/MPMainWindowController.m b/MacPass/MPMainWindowController.m index b8b5c95b..878f53ef 100644 --- a/MacPass/MPMainWindowController.m +++ b/MacPass/MPMainWindowController.m @@ -19,6 +19,7 @@ @interface MPMainWindowController () + @property (assign) IBOutlet NSView *outlineView; @property (assign) IBOutlet NSSplitView *splitView; @property (assign) IBOutlet NSView *contentView; @@ -84,7 +85,7 @@ { [super windowDidLoad]; [self _updateWindowTitle]; - + [[self.welcomeText cell] setBackgroundStyle:NSBackgroundStyleRaised]; const CGFloat minimumWindowWidth = MPMainWindowSplitViewDelegateMinimumContentWidth + MPMainWindowSplitViewDelegateMinimumOutlineWidth + [self.splitView dividerThickness]; diff --git a/MacPass/MPOutlineViewController.h b/MacPass/MPOutlineViewController.h index 259d2e6b..c46e8ad3 100644 --- a/MacPass/MPOutlineViewController.h +++ b/MacPass/MPOutlineViewController.h @@ -10,8 +10,8 @@ @interface MPOutlineViewController : MPViewController -@property (retain, readonly) NSMenu *menu; - - (void)clearSelection; +- (void)createGroup:(id)sender; +- (void)deleteEntry:(id)sender; @end diff --git a/MacPass/MPOutlineViewController.m b/MacPass/MPOutlineViewController.m index b0974082..5501c613 100644 --- a/MacPass/MPOutlineViewController.m +++ b/MacPass/MPOutlineViewController.m @@ -11,6 +11,7 @@ #import "MPOutlineDataSource.h" #import "MPDatabaseController.h" #import "MPDatabaseDocument.h" +#import "MPAppDelegate.h" @interface MPOutlineViewController () @@ -22,8 +23,7 @@ - (void)_didOpenDocument:(NSNotification *)notification; -- (void)_setupMenu; -- (void)_addEntry:(id)sender; +- (NSMenu *)_contextMenu; @end @@ -43,7 +43,6 @@ selector:@selector(_didOpenDocument:) name:MPDatabaseControllerDidLoadDatabaseNotification object:nil]; - [self _setupMenu]; } return self; @@ -61,7 +60,7 @@ - (void)didLoadView { [self.outlineView setDataSource:self.datasource]; [self.outlineView setDelegate:self.outlineDelegate]; - [self.outlineView setMenu:self.menu]; + [self.outlineView setMenu:[self _contextMenu]]; [self.outlineView setAllowsEmptySelection:YES]; } @@ -83,21 +82,23 @@ [self.outlineView deselectAll:nil]; } -- (void)_setupMenu { - NSMenu *menu = [[NSMenu allocWithZone:[NSMenu menuZone]] init]; - [menu addItemWithTitle:@"Add Group" action:@selector(_addEntry:) keyEquivalent:@""]; - [menu addItem: [NSMenuItem separatorItem]]; - [menu addItemWithTitle:@"Delete" action:NULL keyEquivalent:@""]; - for(NSMenuItem *item in [menu itemArray]) { - [item setTarget:self]; +- (NSMenu *)_contextMenu { + NSMenu *menu = [[NSMenu alloc] init]; + NSArray *items = [(MPAppDelegate *)[NSApp delegate] contextMenuItemsWithItems:MPContextMenuMinimal]; + for(NSMenuItem *item in items) { + [menu addItem:item]; } - - self.menu = menu; - [menu release]; + return [menu autorelease]; } -- (void)_addEntry:(id)sender { - NSLog(@"Add Entry"); +- (void)createGroup:(id)sender { + NSLog(@"%@: Create Group", [self class]); } +- (void)deleteEntry:(id)sender { + NSLog(@"%@: Delete Entry", [self class]); +} + + + @end diff --git a/MacPass/MPToolbarDelegate.m b/MacPass/MPToolbarDelegate.m index 504a096c..46108444 100644 --- a/MacPass/MPToolbarDelegate.m +++ b/MacPass/MPToolbarDelegate.m @@ -8,8 +8,7 @@ #import "MPToolbarDelegate.h" #import "MPIconHelper.h" -#import "MPMainWindowController.h" -#import "MPPathBar.h" +#import "MPAppDelegate.h" #import "MPToolbarButton.h" NSString *const MPToolbarItemAddGroup = @"AddGroup"; @@ -30,13 +29,12 @@ NSString *const MPToolbarItemSearch = @"Search"; @implementation MPToolbarDelegate -- (id)init -{ +- (id)init { self = [super init]; if (self) { - self.toolbarIdentifiers = @[ MPToolbarItemAddEntry, MPToolbarItemDelete, MPToolbarItemEdit, MPToolbarItemAddGroup, MPToolbarItemAction, NSToolbarFlexibleSpaceItemIdentifier, MPToolbarItemSearch ]; - self.toolbarImages = [self createToolbarImages]; - self.toolbarItems = [[NSMutableDictionary alloc] initWithCapacity:[self.toolbarIdentifiers count]]; + _toolbarIdentifiers = [@[ MPToolbarItemAddEntry, MPToolbarItemDelete, MPToolbarItemEdit, MPToolbarItemAddGroup, MPToolbarItemAction, NSToolbarFlexibleSpaceItemIdentifier, MPToolbarItemSearch ] retain]; + _toolbarImages = [[self createToolbarImages] retain]; + _toolbarItems = [[NSMutableDictionary alloc] initWithCapacity:[self.toolbarIdentifiers count]]; } return self; } @@ -53,7 +51,6 @@ NSString *const MPToolbarItemSearch = @"Search"; NSToolbarItem *item = self.toolbarItems[itemIdentifier]; if(!item) { item = [[NSToolbarItem alloc] initWithItemIdentifier:itemIdentifier]; - [item setAction:@selector(toolbarItemPressed:)]; NSString *label = NSLocalizedString(itemIdentifier, @""); [item setLabel:label]; @@ -73,25 +70,25 @@ NSString *const MPToolbarItemSearch = @"Search"; [[popupButton cell] setImageScaling:NSImageScaleProportionallyDown]; [popupButton setTitle:@""]; [popupButton sizeToFit]; - /* - Built menu - */ - NSMenu *menu = [NSMenu allocWithZone:[NSMenu menuZone]]; - NSMenuItem *menuItem = [[NSMenuItem allocWithZone:[NSMenu menuZone]] initWithTitle:@"" action:NULL keyEquivalent:@""]; - [menuItem setImage:self.toolbarImages[itemIdentifier]]; - [menu addItem:menuItem]; - [menu addItemWithTitle:@"Foo" action:NULL keyEquivalent:@""]; - [menu addItemWithTitle:@"Bar" action:NULL keyEquivalent:@""]; + NSRect newFrame = [popupButton frame]; newFrame.size.width += 20; + + + NSMenu *menu = [[NSMenu allocWithZone:[NSMenu menuZone]] init]; + NSMenuItem *actionImageItem = [[NSMenuItem allocWithZone:[NSMenu menuZone]] initWithTitle:@"" action:NULL keyEquivalent:@""]; + [actionImageItem setImage:self.toolbarImages[MPToolbarItemAction]]; + [menu addItem:actionImageItem]; + [actionImageItem release]; + NSArray *menuItems = [(MPAppDelegate *)[NSApp delegate] contextMenuItemsWithItems:MPContextMenuFull]; + for(NSMenuItem *item in menuItems) { + [menu addItem:item]; + } [popupButton setFrame:newFrame]; [popupButton setMenu:menu]; - /* - Cleanup - */ - [menuItem release]; [menu release]; + [item setView:popupButton]; [popupButton release]; } @@ -142,5 +139,4 @@ NSString *const MPToolbarItemSearch = @"Search"; return imageDict; } - @end diff --git a/MacPass/MPViewController.h b/MacPass/MPViewController.h index 6908be43..006674ed 100644 --- a/MacPass/MPViewController.h +++ b/MacPass/MPViewController.h @@ -12,6 +12,7 @@ - (void)didLoadView; - (NSResponder *)reconmendedFirstResponder; + - (void)updateResponderChain; @end diff --git a/MacPass/MPViewController.m b/MacPass/MPViewController.m index d63e191f..588b1a61 100644 --- a/MacPass/MPViewController.m +++ b/MacPass/MPViewController.m @@ -26,6 +26,7 @@ - (void)updateResponderChain { if(self.view) { + NSLog(@"Updated responder chain"); NSResponder *nextResponder = [[self view] nextResponder]; [[self view] setNextResponder:self]; [self setNextResponder:nextResponder]; diff --git a/MacPass/MacPass-Info.plist b/MacPass/MacPass-Info.plist index c94602e5..c7871a12 100644 --- a/MacPass/MacPass-Info.plist +++ b/MacPass/MacPass-Info.plist @@ -21,7 +21,7 @@ CFBundleSignature ???? CFBundleVersion - 3C8 + 3E4 LSMinimumSystemVersion ${MACOSX_DEPLOYMENT_TARGET} NSHumanReadableCopyright