Enhanced Context menu on outline view

This commit is contained in:
michael starke
2013-07-30 00:23:25 +02:00
parent 514477d6fc
commit e33a9fdc93
26 changed files with 278 additions and 71 deletions

View File

@@ -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 = "<group>"; };
4C5EC300177B700D00DA955B /* MPRootAdapter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPRootAdapter.h; sourceTree = "<group>"; };
4C5EC301177B700D00DA955B /* MPRootAdapter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPRootAdapter.m; sourceTree = "<group>"; };
4C5FA86B17A5F26800C781C9 /* KPKDataStreamWriter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = KPKDataStreamWriter.h; sourceTree = "<group>"; };
4C5FA86C17A5F26800C781C9 /* KPKDataStreamWriter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = KPKDataStreamWriter.m; sourceTree = "<group>"; };
4C5FE9AC17843CE20001D5A8 /* MPSelectedAttachmentTableCellView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPSelectedAttachmentTableCellView.h; sourceTree = "<group>"; };
4C5FE9AD17843CE20001D5A8 /* MPSelectedAttachmentTableCellView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPSelectedAttachmentTableCellView.m; sourceTree = "<group>"; };
4C61EA0116D2FD0800AC519E /* MPOutlineViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPOutlineViewController.h; sourceTree = "<group>"; };
@@ -621,6 +625,8 @@
4C888C9616EB754B003D34A1 /* MPActionHelper.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPActionHelper.m; sourceTree = "<group>"; };
4C8A173B1790AA41008B5C17 /* NSData+Keyfile.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSData+Keyfile.h"; sourceTree = "<group>"; };
4C8A173C1790AA41008B5C17 /* NSData+Keyfile.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSData+Keyfile.m"; sourceTree = "<group>"; };
4C8B36A917A6ED4B005E1FF1 /* MPOutlineMenuDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPOutlineMenuDelegate.h; sourceTree = "<group>"; };
4C8B36AA17A6ED4B005E1FF1 /* MPOutlineMenuDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPOutlineMenuDelegate.m; sourceTree = "<group>"; };
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 = "<group>"; };
4C9D6AA717615199001C660C /* HNHRoundedSecureTextFieldCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HNHRoundedSecureTextFieldCell.h; sourceTree = "<group>"; };
@@ -680,8 +686,8 @@
4CCEDE2C179F2122008402BE /* MPNotifications.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MPNotifications.h; sourceTree = "<group>"; };
4CCEDE2D179F213B008402BE /* MPNotifications.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPNotifications.m; sourceTree = "<group>"; };
4CCEDE2F179F550D008402BE /* KPKTreeReading.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KPKTreeReading.h; sourceTree = "<group>"; };
4CCEDE30179F5B6C008402BE /* KPKDataStreamer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = KPKDataStreamer.h; sourceTree = "<group>"; };
4CCEDE31179F5B6C008402BE /* KPKDataStreamer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = KPKDataStreamer.m; sourceTree = "<group>"; };
4CCEDE30179F5B6C008402BE /* KPKDataStreamReader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = KPKDataStreamReader.h; sourceTree = "<group>"; };
4CCEDE31179F5B6C008402BE /* KPKDataStreamReader.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = KPKDataStreamReader.m; sourceTree = "<group>"; };
4CD3ABB2178F71B50073F5C5 /* KPKVersion.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = KPKVersion.h; path = Format/KPKVersion.h; sourceTree = "<group>"; };
4CD3ABB3178F71B50073F5C5 /* KPKTree.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = KPKTree.h; sourceTree = "<group>"; };
4CD3ABB4178F71B50073F5C5 /* KPKTree.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = KPKTree.m; sourceTree = "<group>"; };
@@ -1105,6 +1111,8 @@
4CC0D2D017974A5A000B4BDA /* MPAttachmentTableViewDelegate.m */,
4C17D8E317A1C780006C8C1E /* MPDocumentWindowDelegate.h */,
4C17D8E417A1C780006C8C1E /* MPDocumentWindowDelegate.m */,
4C8B36A917A6ED4B005E1FF1 /* MPOutlineMenuDelegate.h */,
4C8B36AA17A6ED4B005E1FF1 /* MPOutlineMenuDelegate.m */,
);
name = Delegates;
sourceTree = "<group>";
@@ -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 = "<group>";
@@ -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;
};

View File

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

View File

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

View File

@@ -9,7 +9,7 @@
#import <Foundation/Foundation.h>
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

View File

@@ -24,7 +24,8 @@
@(MPActionOpenURL) : @"openURL:",
@(MPActionToggleInspector) : @"toggleInspector:",
@(MPActionLock) : @"lock:",
@(MPActionEmptyTrash) : @"emptyTrash:"
@(MPActionEmptyTrash) : @"emptyTrash:",
@(MPActionDatabaseSettings) : @"showDatabaseSettings:"
};
});
return actionDict;

View File

@@ -60,7 +60,7 @@
}
}
- (void)applicationDidFinishLaunching:(NSNotification *)notification {
- (void)applicationDidFinishLaunching:(NSNotification *)notification {
serverDaemon = [[MPServerDaemon alloc] init];
lockDaemon = [[MPLockDaemon alloc] init];

View File

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

View File

@@ -14,7 +14,7 @@ typedef NS_ENUM(NSUInteger, MPDatabaseSettingsTab) {
MPDatabaseSettingsTabPassword,
MPDatabaseSettingsTabDisplay,
MPDatabaseSettingsTabAdvanced,
MPDatabaseSettingsTemplatesTab,
MPDatabaseSettingsTabTemplates,
};
@class MPDocument;

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -7,7 +7,11 @@
//
#import <Foundation/Foundation.h>
/**
* 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

View File

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

View File

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

View File

@@ -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 <Foundation/Foundation.h>
@class MPOutlineViewController;
@interface MPOutlineMenuDelegate : NSObject <NSMenuDelegate>
@property (weak) MPOutlineViewController *viewController;
@end

View File

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

View File

@@ -15,7 +15,7 @@ APPKIT_EXTERN NSString *const MPOutlineViewDidChangeGroupSelection;
@class HNHGradientView;
@class MPDocumentWindowController;
@interface MPOutlineViewController : MPViewController <NSOutlineViewDelegate>
@interface MPOutlineViewController : MPViewController <NSOutlineViewDelegate, NSMenuDelegate>
@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

View File

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

View File

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

Binary file not shown.

Binary file not shown.