Fixed responder chain issues with ViewControllers

Context menu and copy actions now working (unfinished)
This commit is contained in:
michael starke
2013-03-04 01:24:11 +01:00
parent 4c59a137a2
commit 03bb227c16
13 changed files with 151 additions and 116 deletions

View File

@@ -8,6 +8,14 @@
#import <Cocoa/Cocoa.h>
typedef enum {
MPContextMenuCreate = 1<<0,
MPContextMenuDelete = 1<<1,
MPContextMenuCopy = 1<<2,
MPContextMenuMinimal = MPContextMenuCreate | MPContextMenuDelete,
MPContextMenuFull = MPContextMenuMinimal | MPContextMenuCopy,
}MPContextMenuItemsFlags;
@class MPDatabaseDocument;
@interface MPAppDelegate : NSObject <NSApplicationDelegate>
@@ -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

View File

@@ -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

View File

@@ -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];
}

View File

@@ -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

View File

@@ -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 {

View File

@@ -20,4 +20,5 @@
Clears the Search filter
*/
- (void)clearFilter:(id)sender;
@end

View File

@@ -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];

View File

@@ -10,8 +10,8 @@
@interface MPOutlineViewController : MPViewController
@property (retain, readonly) NSMenu *menu;
- (void)clearSelection;
- (void)createGroup:(id)sender;
- (void)deleteEntry:(id)sender;
@end

View File

@@ -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

View File

@@ -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

View File

@@ -12,6 +12,7 @@
- (void)didLoadView;
- (NSResponder *)reconmendedFirstResponder;
- (void)updateResponderChain;
@end

View File

@@ -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];

View File

@@ -21,7 +21,7 @@
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>3C8</string>
<string>3E4</string>
<key>LSMinimumSystemVersion</key>
<string>${MACOSX_DEPLOYMENT_TARGET}</string>
<key>NSHumanReadableCopyright</key>