From 21f299bdff47ac417c5498223db5bf6022fe69e6 Mon Sep 17 00:00:00 2001 From: michael starke Date: Tue, 25 Feb 2014 22:23:53 +0100 Subject: [PATCH] Moved search to MPDocument. Not working properly at the moment --- KeePassKit | 2 +- MacPass.xcodeproj/project.pbxproj | 14 +-- MacPass/ContextBar.xib | 31 +++--- MacPass/MPAttachmentTableDataSource.m | 2 +- MacPass/MPContextBarViewController.h | 5 +- MacPass/MPContextBarViewController.m | 90 ++++------------ MacPass/MPDocument+Attachment.h | 15 +++ MacPass/MPDocument+Attachments.m | 2 +- MacPass/MPDocument+Search.h | 27 +++++ ...entSearchService.m => MPDocument+Search.m} | 102 +++++++++--------- MacPass/MPDocument.h | 27 +++-- MacPass/MPDocument.m | 1 + MacPass/MPDocumentSearchService.h | 44 -------- MacPass/MPDocumentWindowController.h | 7 +- MacPass/MPDocumentWindowController.m | 12 +-- MacPass/MPEntryViewController.h | 4 - MacPass/MPEntryViewController.m | 74 +++++++------ MacPass/MPToolbarDelegate.h | 2 + MacPass/MPToolbarDelegate.m | 16 ++- 19 files changed, 228 insertions(+), 249 deletions(-) create mode 100644 MacPass/MPDocument+Attachment.h create mode 100644 MacPass/MPDocument+Search.h rename MacPass/{MPDocumentSearchService.m => MPDocument+Search.m} (57%) delete mode 100644 MacPass/MPDocumentSearchService.h diff --git a/KeePassKit b/KeePassKit index 09201a81..37809f65 160000 --- a/KeePassKit +++ b/KeePassKit @@ -1 +1 @@ -Subproject commit 09201a8103900a3819e3b8c03b3c74d242c996b1 +Subproject commit 37809f65a67bfe4a97efdec2b727be4d2878f736 diff --git a/MacPass.xcodeproj/project.pbxproj b/MacPass.xcodeproj/project.pbxproj index 1c2beded..c2c19cae 100644 --- a/MacPass.xcodeproj/project.pbxproj +++ b/MacPass.xcodeproj/project.pbxproj @@ -22,6 +22,7 @@ 4C0F647817B6B65E00D9522A /* MPSheetWindowController.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C0F647717B6B65E00D9522A /* MPSheetWindowController.m */; }; 4C0F647B17B6BC9C00D9522A /* MPSavePanelAccessoryViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C0F647A17B6BC9C00D9522A /* MPSavePanelAccessoryViewController.m */; }; 4C10412C178CDD44001B5239 /* NSDate+Humanized.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C10412B178CDD44001B5239 /* NSDate+Humanized.m */; }; + 4C15B74618BCA3B1003F8008 /* MPDocument+Search.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C15B74518BCA3B1003F8008 /* MPDocument+Search.m */; }; 4C17D8E517A1C780006C8C1E /* MPDocumentWindowDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C17D8E417A1C780006C8C1E /* MPDocumentWindowDelegate.m */; }; 4C17F105184E630200E85625 /* 14_BatteryTemplate.pdf in Resources */ = {isa = PBXBuildFile; fileRef = 4C17F104184E630200E85625 /* 14_BatteryTemplate.pdf */; }; 4C17F108184E6B6C00E85625 /* 31_PrintTemplate.pdf in Resources */ = {isa = PBXBuildFile; fileRef = 4C17F106184E6B6C00E85625 /* 31_PrintTemplate.pdf */; }; @@ -199,7 +200,6 @@ 4C8A173D1790AA41008B5C17 /* NSData+Keyfile.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C8A173C1790AA41008B5C17 /* NSData+Keyfile.m */; }; 4C8B36AB17A6ED4B005E1FF1 /* MPOutlineContextMenuDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C8B36AA17A6ED4B005E1FF1 /* MPOutlineContextMenuDelegate.m */; }; 4C8FECC816D57E3200BF26CF /* QuartzCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4C8FECC716D57E3200BF26CF /* QuartzCore.framework */; }; - 4C94DFCB1892860400F42F18 /* MPDocumentSearchService.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C94DFCA1892860400F42F18 /* MPDocumentSearchService.m */; }; 4C96D15417A12E4F00D931FA /* 99_CreatedTemplate.pdf in Resources */ = {isa = PBXBuildFile; fileRef = 4C96D15317A12E4F00D931FA /* 99_CreatedTemplate.pdf */; }; 4C9D6AA917615199001C660C /* HNHRoundedSecureTextFieldCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C9D6AA817615199001C660C /* HNHRoundedSecureTextFieldCell.m */; }; 4CA08DA017A831B200A6544B /* MPAddEntryContextMenuDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 4CA08D9F17A831B200A6544B /* MPAddEntryContextMenuDelegate.m */; }; @@ -375,6 +375,9 @@ 4C10412B178CDD44001B5239 /* NSDate+Humanized.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSDate+Humanized.m"; sourceTree = ""; }; 4C13904C17ADD1A300A62934 /* KPKTreeCrypting.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KPKTreeCrypting.h; sourceTree = ""; }; 4C13904D17ADD3BE00A62934 /* KPKTreeWriting.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KPKTreeWriting.h; sourceTree = ""; }; + 4C15B73C18BCA379003F8008 /* MPDocument+Attachment.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "MPDocument+Attachment.h"; sourceTree = ""; }; + 4C15B74418BCA3B1003F8008 /* MPDocument+Search.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "MPDocument+Search.h"; sourceTree = ""; }; + 4C15B74518BCA3B1003F8008 /* MPDocument+Search.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "MPDocument+Search.m"; sourceTree = ""; }; 4C17D8E317A1C780006C8C1E /* MPDocumentWindowDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPDocumentWindowDelegate.h; sourceTree = ""; }; 4C17D8E417A1C780006C8C1E /* MPDocumentWindowDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPDocumentWindowDelegate.m; sourceTree = ""; }; 4C17F104184E630200E85625 /* 14_BatteryTemplate.pdf */ = {isa = PBXFileReference; lastKnownFileType = image.pdf; path = 14_BatteryTemplate.pdf; sourceTree = ""; }; @@ -690,8 +693,6 @@ 4C8B36A917A6ED4B005E1FF1 /* MPOutlineContextMenuDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPOutlineContextMenuDelegate.h; sourceTree = ""; }; 4C8B36AA17A6ED4B005E1FF1 /* MPOutlineContextMenuDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPOutlineContextMenuDelegate.m; sourceTree = ""; }; 4C8FECC716D57E3200BF26CF /* QuartzCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = QuartzCore.framework; path = System/Library/Frameworks/QuartzCore.framework; sourceTree = SDKROOT; }; - 4C94DFC91892860400F42F18 /* MPDocumentSearchService.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPDocumentSearchService.h; sourceTree = ""; }; - 4C94DFCA1892860400F42F18 /* MPDocumentSearchService.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPDocumentSearchService.m; sourceTree = ""; }; 4C96D15317A12E4F00D931FA /* 99_CreatedTemplate.pdf */ = {isa = PBXFileReference; lastKnownFileType = image.pdf; name = 99_CreatedTemplate.pdf; path = Icons/99_CreatedTemplate.pdf; sourceTree = ""; }; 4C9D6AA717615199001C660C /* HNHRoundedSecureTextFieldCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HNHRoundedSecureTextFieldCell.h; sourceTree = ""; }; 4C9D6AA817615199001C660C /* HNHRoundedSecureTextFieldCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HNHRoundedSecureTextFieldCell.m; sourceTree = ""; }; @@ -1209,8 +1210,6 @@ 4C37A84215B8B495005EF8EE /* Model */ = { isa = PBXGroup; children = ( - 4C94DFC91892860400F42F18 /* MPDocumentSearchService.h */, - 4C94DFCA1892860400F42F18 /* MPDocumentSearchService.m */, 4C37A83E15B8B474005EF8EE /* MPOutlineDataSource.h */, 4C37A83F15B8B474005EF8EE /* MPOutlineDataSource.m */, 4C569D9F17652BFE00595B62 /* MPEntryTableDataSource.h */, @@ -1220,9 +1219,12 @@ 6E719715172058BA00E4C5FC /* MPDatabaseVersion.h */, 4CE5B548173AFBA700207B39 /* MPDocument.h */, 4CE5B549173AFBA700207B39 /* MPDocument.m */, + 4C15B73C18BCA379003F8008 /* MPDocument+Attachment.h */, 4C3666401787327E00B249F1 /* MPDocument+Attachments.m */, 4C1FA07918231900003A3F8C /* MPDocument+Autotype.h */, 4C1FA07A18231900003A3F8C /* MPDocument+Autotype.m */, + 4C15B74418BCA3B1003F8008 /* MPDocument+Search.h */, + 4C15B74518BCA3B1003F8008 /* MPDocument+Search.m */, ); name = Model; sourceTree = ""; @@ -2259,8 +2261,8 @@ 4C5CD36317D15DCA000B7F38 /* KPKSalsa20RandomStream.m in Sources */, 4CC6DB7A17D23719002C6091 /* KPKNode+IconImage.m in Sources */, 4CC6DB7D17D23DCE002C6091 /* KPKUTIs.m in Sources */, + 4C15B74618BCA3B1003F8008 /* MPDocument+Search.m in Sources */, 4CEED1C617D7BD0E007180F1 /* NSError+Messages.m in Sources */, - 4C94DFCB1892860400F42F18 /* MPDocumentSearchService.m in Sources */, 4C00E33817D8FA3500F37192 /* DDHotKeyCenter.m in Sources */, 4C224B4217DFCB2400FF6AEE /* MPNumericalInputFormatter.m in Sources */, ); diff --git a/MacPass/ContextBar.xib b/MacPass/ContextBar.xib index 76f38ef0..295e47f2 100644 --- a/MacPass/ContextBar.xib +++ b/MacPass/ContextBar.xib @@ -1,5 +1,5 @@ - + @@ -21,10 +21,6 @@ - - - - @@ -36,7 +32,7 @@ - + @@ -45,7 +41,7 @@ - - - - - - + + + + + + + + + + @@ -179,7 +185,6 @@ - diff --git a/MacPass/MPAttachmentTableDataSource.m b/MacPass/MPAttachmentTableDataSource.m index 5673b390..18ad9902 100644 --- a/MacPass/MPAttachmentTableDataSource.m +++ b/MacPass/MPAttachmentTableDataSource.m @@ -21,7 +21,7 @@ // #import "MPAttachmentTableDataSource.h" -#import "MPDocument.h" +#import "MPDocument+Attachment.h" @implementation MPAttachmentTableDataSource diff --git a/MacPass/MPContextBarViewController.h b/MacPass/MPContextBarViewController.h index edb0cd72..a4edf3c0 100644 --- a/MacPass/MPContextBarViewController.h +++ b/MacPass/MPContextBarViewController.h @@ -7,7 +7,7 @@ // #import "MPViewController.h" -#import "MPDocumentSearchService.h" +#import "MPDocument+Search.h" @protocol MPContextBarDelegate @@ -38,7 +38,4 @@ - (void)showHistory; - (void)showTrash; -- (void)enable; -- (void)disable; - @end diff --git a/MacPass/MPContextBarViewController.m b/MacPass/MPContextBarViewController.m index 71c367a5..a347e652 100644 --- a/MacPass/MPContextBarViewController.m +++ b/MacPass/MPContextBarViewController.m @@ -9,7 +9,7 @@ #import "MPContextBarViewController.h" #import "HNHGradientView.h" #import "KPKEntry.h" -#import "MPDocumentSearchService.h" +#import "MPDocument+Search.h" #import "NSButton+HNHTextColor.h" @@ -31,7 +31,6 @@ typedef NS_ENUM(NSUInteger, MPContextTab) { } @property (nonatomic, assign) MPContextTab activeTab; -@property (nonatomic, assign) BOOL hasFilter; /* Filter */ @property (weak) IBOutlet NSButton *filterDoneButton; @@ -56,32 +55,34 @@ typedef NS_ENUM(NSUInteger, MPContextTab) { - (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil { self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]; if (self) { - _hasFilter = NO; _delegateRespondsToDidExitFilter = NO; _delegateRespondsToDidExitHistory = NO; _delegateRespondsToShouldEmptyTrash = NO; _delegateRespondsToDidChangeFilter = NO; + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(_updateFilterButtons) + name:MPDocumentDidChangeSearchFlags + object:nil]; } return self; } +- (void)dealloc { + [[NSNotificationCenter defaultCenter] removeObserver:self]; +} + - (void)didLoadView { - + [[self.filterLabelTextField cell] setBackgroundStyle:NSBackgroundStyleRaised]; self.historyBar.activeGradient = [[NSGradient alloc] initWithStartingColor:[NSColor redColor] endingColor:[NSColor greenColor]]; - NSArray *activeColors = @[ - [NSColor colorWithCalibratedWhite:0.2 alpha:1], - [NSColor colorWithCalibratedWhite:0.4 alpha:1] - ]; - NSArray *inactiveColors = @[ [NSColor colorWithCalibratedWhite:0.3 alpha:1], - [NSColor colorWithCalibratedWhite:0.6 alpha:1] - ]; + NSArray *activeColors = @[[NSColor colorWithCalibratedWhite:0.2 alpha:1],[NSColor colorWithCalibratedWhite:0.4 alpha:1]]; + NSArray *inactiveColors = @[[NSColor colorWithCalibratedWhite:0.3 alpha:1],[NSColor colorWithCalibratedWhite:0.6 alpha:1]]; self.trashBar.activeGradient = [[NSGradient alloc] initWithColors:activeColors]; self.trashBar.inactiveGradient = [[NSGradient alloc] initWithColors:inactiveColors]; [[self view] bind:NSSelectedIndexBinding toObject:self withKeyPath:@"activeTab" options:nil]; - + self.emptyTrashButton.textColor = [NSColor whiteColor]; if(self.nextKeyView) { @@ -93,17 +94,6 @@ typedef NS_ENUM(NSUInteger, MPContextTab) { } #pragma mark Properties -- (void)setFilterMode:(MPFilterMode)newFilterMode { - if(_filterMode != newFilterMode) { - if(newFilterMode == MPEntrySearchNone) { - newFilterMode = MPFilterTitles; - } - _filterMode = newFilterMode; - [self _updateFilterMenu]; - [self _didChangeFilter]; - } -} - - (void)setDelegate:(id)delegate { if(self.delegate != delegate) { _delegate = delegate; @@ -114,50 +104,10 @@ typedef NS_ENUM(NSUInteger, MPContextTab) { } } -- (void)disable { -} - -- (void)enable { - [self.filterSearchField setEnabled:YES]; - /* First responder handling */ - switch (self.activeTab) { - case MPContextTabTrash: - break; - - case MPContextTabFilter: - [[[self view] window] makeFirstResponder:self.filterSearchField]; - break; - - case MPContextTabHistory: - break; - - default: - break; - } -} - -- (void)exitFilter:(id)sender { - if(!self.hasFilter) { - return; // Nothing to do; - } - if(![self showsFilter]) { - return; // We arent displaying the filter view - } - self.hasFilter = NO; - [self.filterSearchField setStringValue:@""]; - if(_delegateRespondsToDidExitFilter) { - [self.delegate contextBarDidExitFilter]; - } -} - - (void)showFilter { - self.hasFilter = YES; /* Select text if already visible */ - if([self showsFilter]) { - [self.filterSearchField selectText:self]; - } self.activeTab = MPContextTabFilter; - [self _updateFilterMenu]; + [self _updateFilterButtons]; } - (void)showHistory { @@ -184,16 +134,14 @@ typedef NS_ENUM(NSUInteger, MPContextTab) { return self.activeTab == MPContextTabTrash; } -- (NSString *)filterString { - return [self.filterSearchField stringValue]; -} - -- (BOOL)control:(NSControl*)control textView:(NSTextView*)textView doCommandBySelector:(SEL)commandSelector { +/* + - (BOOL)control:(NSControl*)control textView:(NSTextView*)textView doCommandBySelector:(SEL)commandSelector { if(commandSelector == @selector(insertNewline:)) { [self _didChangeFilter]; } return NO; } +*/ - (void)_didChangeFilter { if(_delegateRespondsToDidChangeFilter) { @@ -206,4 +154,8 @@ typedef NS_ENUM(NSUInteger, MPContextTab) { // only the entry view has to be bound, the rest not } +- (void)_updateFilterButtons { + MPDocument *document = [[self windowController] document]; +} + @end diff --git a/MacPass/MPDocument+Attachment.h b/MacPass/MPDocument+Attachment.h new file mode 100644 index 00000000..5d9f7836 --- /dev/null +++ b/MacPass/MPDocument+Attachment.h @@ -0,0 +1,15 @@ +// +// MPDocument+Attachment.h +// MacPass +// +// Created by Michael Starke on 25.02.14. +// Copyright (c) 2014 HicknHack Software GmbH. All rights reserved. +// + +#import "MPDocument.h" + +@interface MPDocument (Attachments) + +- (void)addAttachment:(NSURL *)location toEntry:(KPKEntry *)anEntry; + +@end \ No newline at end of file diff --git a/MacPass/MPDocument+Attachments.m b/MacPass/MPDocument+Attachments.m index 8b77b966..3c6f8b23 100644 --- a/MacPass/MPDocument+Attachments.m +++ b/MacPass/MPDocument+Attachments.m @@ -20,7 +20,7 @@ // along with this program. If not, see . // -#import "MPDocument.h" +#import "MPDocument+Attachment.h" #import "KPKEntry.h" #import "KPKBinary.h" diff --git a/MacPass/MPDocument+Search.h b/MacPass/MPDocument+Search.h new file mode 100644 index 00000000..7f3394cc --- /dev/null +++ b/MacPass/MPDocument+Search.h @@ -0,0 +1,27 @@ +// +// MPDocument+Search.h +// MacPass +// +// Created by Michael Starke on 25.02.14. +// Copyright (c) 2014 HicknHack Software GmbH. All rights reserved. +// + +#import "MPDocument.h" + +FOUNDATION_EXPORT NSString *const MPDocumentDidEnterSearchNotification; +FOUNDATION_EXTERN NSString *const MPDocumentDidChangeSearchNotification; +FOUNDATION_EXPORT NSString *const MPDocumentDidChangeSearchFlags; +FOUNDATION_EXTERN NSString *const MPDocumentDidExitSearchNotification; + +@interface MPDocument (Search) + +- (NSArray *)entriesInDocument:(MPDocument *)document matching:(NSString *)string; + +/* Should be called by the NSSearchTextField to update the search string */ +- (IBAction)updateSearch:(id)sender; +/* exits searching mode */ +- (IBAction)exitSearch:(id)sender; +/* called by the filter toggle buttons */ +- (IBAction)toggleFlags:(id)sender; + +@end diff --git a/MacPass/MPDocumentSearchService.m b/MacPass/MPDocument+Search.m similarity index 57% rename from MacPass/MPDocumentSearchService.m rename to MacPass/MPDocument+Search.m index d129e36a..a71b4e1a 100644 --- a/MacPass/MPDocumentSearchService.m +++ b/MacPass/MPDocument+Search.m @@ -1,69 +1,69 @@ // -// MPSearchHelper.m +// MPDocument+Search.m // MacPass // -// Created by Michael Starke on 24/01/14. +// Created by Michael Starke on 25.02.14. // Copyright (c) 2014 HicknHack Software GmbH. All rights reserved. // -#import "MPDocumentSearchService.h" +#import "MPDocument+Search.h" #import "MPDocument.h" #import "KPKGroup.h" #import "KPKEntry.h" #import "MPFlagsHelper.h" -NSString *const MPDocumentSearchServiceDidChangeSearchNotification = @"com.hicknhack.macpass.MPDocumentSearchServiceDidChangeSearchNotification"; -NSString *const MPDocumentSearchServiceDidClearSearchNotification = @"com.hicknhack.macpass.MPDocumentSearchServiceDidClearSearchNotification"; -NSString *const MPDocumentSearchServiceDidExitSearchNotification = @"com.hicknhack.macpass.MPDocumentSearchServiceDidExitSearchNotification"; +NSString *const MPDocumentDidEnterSearchNotification = @"com.hicknhack.macpass.MPDocumentDidEnterSearchNotification"; +NSString *const MPDocumentDidChangeSearchNotification = @"com.hicknhack.macpass.MPDocumentDidChangeSearchNotification"; +NSString *const MPDocumentDidChangeSearchFlags = @"com.hicknhack.macpass.MPDocumentDidChangeSearchFlagsNotification"; +NSString *const MPDocumentDidExitSearchNotification = @"com.hicknhack.macpass.MPDocumentDidExitSearchNotification"; -@implementation MPDocumentSearchService - -static MPDocumentSearchService *_kMPSearchServiceInstance; - -+ (instancetype)sharedService { - static dispatch_once_t onceToken; - dispatch_once(&onceToken, ^{ - _kMPSearchServiceInstance = [[MPDocumentSearchService alloc] init]; - }); - return _kMPSearchServiceInstance; -} - -- (instancetype)init { - NSAssert(_kMPSearchServiceInstance == nil, @"only one shared instance allowed"); - self = [super init]; - if(self) { - _activeFlags = MPEntrySearchTitles; // Default search is set to titles - } - return self; -} +@implementation MPDocument (Search) #pragma mark Actions -- (void)updateSearch:(id)sender { - if(sender != self.searchField) { - return; // Wrong sender - } - self.searchString = [self.searchField stringValue]; - [[NSNotificationCenter defaultCenter] postNotificationName:MPDocumentSearchServiceDidChangeSearchNotification object:self]; + +- (void)performFindPanelAction:(id)sender { + [[NSNotificationCenter defaultCenter] postNotificationName:MPDocumentDidEnterSearchNotification object:self]; } -- (void)clearSearch:(id)sender { - if(sender != self.searchField) { - return; // Wrong sender - } - [self.searchField setStringValue:@""]; - self.searchString = nil; - [[NSNotificationCenter defaultCenter] postNotificationName:MPDocumentSearchServiceDidClearSearchNotification object:self]; +- (void)updateSearch:(id)sender { + [[NSNotificationCenter defaultCenter] postNotificationName:MPDocumentDidChangeSearchNotification object:self]; } - (void)exitSearch:(id)sender { - [self.searchField setStringValue:@""]; self.searchString = nil; - [[NSNotificationCenter defaultCenter] postNotificationName:MPDocumentSearchServiceDidExitSearchNotification object:self]; + [[NSNotificationCenter defaultCenter] postNotificationName:MPDocumentDidExitSearchNotification object:self]; } -- (NSArray *)entriesInDocument:(MPDocument *)document matching:(NSString *)string usingSearchMode:(MPEntrySearchFlags)mode { +- (void)toggleFlags:(id)sender { + if(![sender respondsToSelector:@selector(tag)]) { + return; // We nee to read the button tag + } + if([sender respondsToSelector:@selector(state)]) { + return; // We need to read the button state + } + MPEntrySearchFlags toggleFlag = [sender tag]; + switch([sender state]) { + case NSOffState: + toggleFlag ^= MPEntrySearchAllFlags; + break; + case NSOnState: + /* On is fine */ + break; + default: + NSAssert(NO, @"Internal state is inconsistent"); + return; + } + MPEntrySearchFlags newFlags = self.activeFlags & toggleFlag; + if(newFlags == self.activeFlags) { + self.activeFlags = (newFlags == MPEntrySearchNone) ? MPEntrySearchTitles : newFlags; + [[NSNotificationCenter defaultCenter] postNotificationName:MPDocumentDidChangeSearchFlags object:self]; + } +} + +#pragma mark Search +- (NSArray *)entriesInDocument:(MPDocument *)document matching:(NSString *)string { /* Filter double passwords */ - if(MPTestFlagInOptions(MPEntrySearchDoublePasswords, mode)) { + if(MPTestFlagInOptions(MPEntrySearchDoublePasswords, self.activeFlags)) { __block NSMutableDictionary *passwordToEntryMap; /* Build up a usage map */ [[document.root childEntries] enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) { @@ -88,7 +88,7 @@ static MPDocumentSearchService *_kMPSearchServiceInstance; return doublePasswords; } /* Filter using predicates */ - NSArray *predicates = [self _filterPredicatesForMode:mode withString:string]; + NSArray *predicates = [self _filterPredicatesWithString:string]; if(predicates) { NSPredicate *fullFilter = [NSCompoundPredicate orPredicateWithSubpredicates:predicates]; return [[document.root childEntries] filteredArrayUsingPredicate:fullFilter]; @@ -101,7 +101,7 @@ static MPDocumentSearchService *_kMPSearchServiceInstance; NSArray *allOptions = @[ @(MPEntrySearchUrls), @(MPEntrySearchUsernames), @(MPEntrySearchTitles), @(MPEntrySearchPasswords) , @(MPEntrySearchNotes), @(MPEntrySearchDoublePasswords) ]; - + NSIndexSet *indexes = [allOptions indexesOfObjectsPassingTest:^BOOL(id obj, NSUInteger idx, BOOL *stop) { MPEntrySearchFlags flag = [obj integerValue]; return MPTestFlagInOptions(flag, mode); @@ -109,22 +109,22 @@ static MPDocumentSearchService *_kMPSearchServiceInstance; return [allOptions objectsAtIndexes:indexes]; } -- (NSArray *)_filterPredicatesForMode:(MPEntrySearchFlags)mode withString:(NSString *)string{ +- (NSArray *)_filterPredicatesWithString:(NSString *)string{ NSMutableArray *prediactes = [[NSMutableArray alloc] initWithCapacity:4]; - if(MPTestFlagInOptions(MPEntrySearchTitles, mode)) { + if(MPTestFlagInOptions(MPEntrySearchTitles, self.activeFlags)) { [prediactes addObject:[NSPredicate predicateWithFormat:@"SELF.title CONTAINS[cd] %@", string]]; } - if(MPTestFlagInOptions(MPEntrySearchUsernames, mode)) { + if(MPTestFlagInOptions(MPEntrySearchUsernames, self.activeFlags)) { [prediactes addObject:[NSPredicate predicateWithFormat:@"SELF.username CONTAINS[cd] %@", string]]; } - if(MPTestFlagInOptions(MPEntrySearchUrls, mode)) { + if(MPTestFlagInOptions(MPEntrySearchUrls, self.activeFlags)) { [prediactes addObject:[NSPredicate predicateWithFormat:@"SELF.url CONTAINS[cd] %@", string]]; } - if(MPTestFlagInOptions(MPEntrySearchPasswords, mode)) { + if(MPTestFlagInOptions(MPEntrySearchPasswords, self.activeFlags)) { [prediactes addObject:[NSPredicate predicateWithFormat:@"SELF.password CONTAINS[cd] %@", string]]; } - if(MPTestFlagInOptions(MPEntrySearchNotes, mode)) { + if(MPTestFlagInOptions(MPEntrySearchNotes, self.activeFlags)) { [prediactes addObject:[NSPredicate predicateWithFormat:@"SELF.notes CONTAINS[cd] %@", string]]; } return prediactes; diff --git a/MacPass/MPDocument.h b/MacPass/MPDocument.h index 9cfc7ba1..ee4c504c 100644 --- a/MacPass/MPDocument.h +++ b/MacPass/MPDocument.h @@ -39,6 +39,17 @@ APPKIT_EXTERN NSString *const MPDocumentGroupKey; @class KPKAttribute; @class KPKCompositeKey; +typedef NS_OPTIONS(NSUInteger, MPEntrySearchFlags) { + MPEntrySearchNone = 0, + MPEntrySearchUrls = (1<<0), + MPEntrySearchUsernames = (1<<1), + MPEntrySearchTitles = (1<<2), + MPEntrySearchPasswords = (1<<3), + MPEntrySearchNotes = (1<<4), + MPEntrySearchDoublePasswords = (1<<5), + MPEntrySearchAllFlags = (MPEntrySearchDoublePasswords | MPEntrySearchNotes | MPEntrySearchPasswords | MPEntrySearchTitles | MPEntrySearchUrls | MPEntrySearchUsernames) +}; + @interface MPDocument : NSDocument @property (nonatomic, readonly, assign) BOOL encrypted; @@ -50,8 +61,6 @@ APPKIT_EXTERN NSString *const MPDocumentGroupKey; @property (nonatomic, weak) KPKGroup *templates; @property (nonatomic, strong, readonly) KPKCompositeKey *compositeKey; -//@property (nonatomic, copy) NSString *password; -//@property (nonatomic, strong) NSURL *key; @property (assign, readonly, getter = isReadOnly) BOOL readOnly; @property (nonatomic, readonly, assign) KPKVersion versionForFileType; @@ -63,6 +72,12 @@ APPKIT_EXTERN NSString *const MPDocumentGroupKey; @property (nonatomic, weak) KPKGroup *selectedGroup; @property (nonatomic, weak) id selectedItem; +/* + Search - see MPDocument+Search for further details + */ +@property (nonatomic, assign) MPEntrySearchFlags activeFlags; +@property (nonatomic, copy) NSString *searchString; + + (KPKVersion)versionForFileType:(NSString *)fileType; + (NSString *)fileTypeForVersion:(KPKVersion)version; @@ -146,10 +161,4 @@ APPKIT_EXTERN NSString *const MPDocumentGroupKey; */ - (IBAction)createEntryFromTemplate:(id)sender; -@end - -@interface MPDocument (Attachments) - -- (void)addAttachment:(NSURL *)location toEntry:(KPKEntry *)anEntry; - -@end +@end \ No newline at end of file diff --git a/MacPass/MPDocument.m b/MacPass/MPDocument.m index cda5206c..405e350f 100644 --- a/MacPass/MPDocument.m +++ b/MacPass/MPDocument.m @@ -111,6 +111,7 @@ NSString *const MPDocumentGroupKey = @"MPDocumentGroupKey _encryptedData = nil; _didLockFile = NO; _readOnly = NO; + _activeFlags = MPEntrySearchTitles; self.tree = [KPKTree templateTree]; } return self; diff --git a/MacPass/MPDocumentSearchService.h b/MacPass/MPDocumentSearchService.h deleted file mode 100644 index e41a2282..00000000 --- a/MacPass/MPDocumentSearchService.h +++ /dev/null @@ -1,44 +0,0 @@ -// -// MPSearchHelper.h -// MacPass -// -// Created by Michael Starke on 24/01/14. -// Copyright (c) 2014 HicknHack Software GmbH. All rights reserved. -// - -#import - -@class MPDocument; - -FOUNDATION_EXTERN NSString *const MPDocumentSearchServiceDidChangeSearchNotification; -FOUNDATION_EXTERN NSString *const MPDocumentSearchServiceDidClearSearchNotification; -FOUNDATION_EXTERN NSString *const MPDocumentSearchServiceDidExitSearchNotification; - -typedef NS_OPTIONS(NSUInteger, MPEntrySearchFlags) { - MPEntrySearchNone = 0, - MPEntrySearchUrls = (1<<0), - MPEntrySearchUsernames = (1<<1), - MPEntrySearchTitles = (1<<2), - MPEntrySearchPasswords = (1<<3), - MPEntrySearchNotes = (1<<4), - MPEntrySearchDoublePasswords = (1<<5) -}; - -@interface MPDocumentSearchService : NSObject - -@property (nonatomic, assign) MPEntrySearchFlags activeFlags; -@property (nonatomic, copy) NSString *searchString; -@property (nonatomic, weak) NSSearchField *searchField; - -+ (instancetype)sharedService; -- (NSArray *)entriesInDocument:(MPDocument *)document matching:(NSString *)string usingSearchMode:(MPEntrySearchFlags)mode; -- (NSArray *)optionsEnabledInMode:(MPEntrySearchFlags)mode; - -/* Should be called by the NSSearchTextField to update the search string */ -- (IBAction)updateSearch:(id)sender; -/* Clears the search string, but doesn't exit searching */ -- (IBAction)clearSearch:(id)sender; -/* exits searching mode */ -- (IBAction)exitSearch:(id)sender; - -@end diff --git a/MacPass/MPDocumentWindowController.h b/MacPass/MPDocumentWindowController.h index fb2f863d..eb22ae98 100644 --- a/MacPass/MPDocumentWindowController.h +++ b/MacPass/MPDocumentWindowController.h @@ -24,11 +24,14 @@ @property (readonly, strong) MPInspectorViewController *inspectorViewController; @property (readonly, strong) MPToolbarDelegate *toolbarDelegate; +#pragma mark Search +- (NSSearchField *)searchField; + - (void)showEntries; - (void)showPasswordInput; -- (IBAction)performFindPanelAction:(id)sender; -- (IBAction)cancelSearch:(id)sender; +#pragma mark Actions +- (IBAction)performFindPanelAction:(id)sender; - (IBAction)saveDocument:(id)sender; - (IBAction)editPassword:(id)sender; diff --git a/MacPass/MPDocumentWindowController.m b/MacPass/MPDocumentWindowController.m index 71b2fa38..65737058 100644 --- a/MacPass/MPDocumentWindowController.m +++ b/MacPass/MPDocumentWindowController.m @@ -121,6 +121,10 @@ typedef NS_ENUM(NSUInteger, MPAlertContext) { [_splitView setAutosaveName:@"SplitView"]; } +- (NSSearchField *)searchField { + return self.toolbarDelegate.searchField; +} + - (void)_setContentViewController:(MPViewController *)viewController { NSView *newContentView = nil; @@ -217,14 +221,6 @@ typedef NS_ENUM(NSUInteger, MPAlertContext) { }]; } -- (void)performFindPanelAction:(id)sender { - [self.entryViewController showFilter:sender]; -} - -- (void)cancelSearch:(id)sender { - [self.entryViewController clearFilter:sender]; -} - - (void)showPasswordInput { if(!self.passwordInputController) { self.passwordInputController = [[MPPasswordInputController alloc] init]; diff --git a/MacPass/MPEntryViewController.h b/MacPass/MPEntryViewController.h index ed65baff..d23714d5 100644 --- a/MacPass/MPEntryViewController.h +++ b/MacPass/MPEntryViewController.h @@ -35,10 +35,6 @@ typedef NS_ENUM( NSUInteger, MPCopyContentTypeTag) { /* Call this after alle viewcontroller are loaded */ - (void)setupNotifications:(MPDocumentWindowController *)windowController; -/* Clear the Search filter*/ -- (void)showFilter:(id)sender; -- (void)clearFilter:(id)sender; - /* Copy/Paste */ - (void)copyUsername:(id)sender; - (void)copyPassword:(id)sender; diff --git a/MacPass/MPEntryViewController.m b/MacPass/MPEntryViewController.m index 4a89dff8..6b82b580 100644 --- a/MacPass/MPEntryViewController.m +++ b/MacPass/MPEntryViewController.m @@ -10,17 +10,18 @@ #import "MPAppDelegate.h" #import "MPOutlineViewController.h" #import "MPDocument.h" -#import "MPIconHelper.h" +#import "MPDocument+Search.h" #import "MPDocumentWindowController.h" #import "MPPasteBoardController.h" #import "MPOverlayWindowController.h" #import "MPContextBarViewController.h" -#import "MPDocumentSearchService.h" -#import "MPContextMenuHelper.h" -#import "MPActionHelper.h" -#import "MPSettingsHelper.h" #import "MPConstants.h" + +#import "MPActionHelper.h" +#import "MPContextMenuHelper.h" +#import "MPIconHelper.h" +#import "MPSettingsHelper.h" #import "MPEntryTableDataSource.h" #import "MPStringLengthValueTransformer.h" #import "MPStripLineBreaksTransformer.h" @@ -97,14 +98,17 @@ NSString *const _MPTAbleSecurCellView = @"PasswordCell"; _dataSource.viewController = self; _menuDelegate = [[MPEntryContextMenuDelegate alloc] init]; _contextBarViewController = [[MPContextBarViewController alloc] init]; + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(_updateSearchResults:) + name:MPDocumentDidChangeSearchNotification + object:nil]; + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(showFilter:) name:MPDocumentDidEnterSearchNotification object:nil]; } return self; } - (void)dealloc { [[NSNotificationCenter defaultCenter] removeObserver:self]; - [self unbind:@"filterMode"]; - } - (void)didLoadView { @@ -173,8 +177,8 @@ NSString *const _MPTAbleSecurCellView = @"PasswordCell"; [[attachmentsColumn headerCell] setStringValue:NSLocalizedString(@"ATTACHMENTS", "")]; [[modifiedColumn headerCell] setStringValue:NSLocalizedString(@"MODIFIED", "")]; - [self.entryTable bind:NSContentBinding toObject:self.entryArrayController withKeyPath:@"arrangedObjects" options:nil]; - [self.entryTable bind:NSSortDescriptorsBinding toObject:self.entryArrayController withKeyPath:@"sortDescriptors" options:nil]; + [self.entryTable bind:NSContentBinding toObject:self.entryArrayController withKeyPath:NSStringFromSelector(@selector(arrangedObjects)) options:nil]; + [self.entryTable bind:NSSortDescriptorsBinding toObject:self.entryArrayController withKeyPath:NSStringFromSelector(@selector(sortDescriptors)) options:nil]; [self.entryTable setDataSource:_dataSource]; // bind NSArrayController sorting so that sort order gets auto-saved @@ -223,19 +227,19 @@ NSString *const _MPTAbleSecurCellView = @"PasswordCell"; if(isTitleColumn || isGroupColumn) { view = [tableView makeViewWithIdentifier:_MPTableImageCellView owner:self]; if( isTitleColumn ) { - [[view textField] bind:NSValueBinding toObject:entry withKeyPath:@"title" options:nil]; - [[view imageView] bind:NSValueBinding toObject:entry withKeyPath:@"iconImage" options:nil]; + [[view textField] bind:NSValueBinding toObject:entry withKeyPath:NSStringFromSelector(@selector(title)) options:nil]; + [[view imageView] bind:NSValueBinding toObject:entry withKeyPath:NSStringFromSelector(@selector(iconImage)) options:nil]; } else { NSAssert(entry.parent != nil, @"Entry needs to have a parent"); - [[view textField] bind:NSValueBinding toObject:entry.parent withKeyPath:@"name" options:nil]; - [[view imageView] bind:NSValueBinding toObject:entry.parent withKeyPath:@"iconImage" options:nil]; + [[view textField] bind:NSValueBinding toObject:entry.parent withKeyPath:NSStringFromSelector(@selector(name)) options:nil]; + [[view imageView] bind:NSValueBinding toObject:entry.parent withKeyPath:NSStringFromSelector(@selector(iconImage)) options:nil]; } } else if(isPasswordColum) { view = [tableView makeViewWithIdentifier:_MPTAbleSecurCellView owner:self]; NSDictionary *options = @{ NSValueTransformerBindingOption : [NSValueTransformer valueTransformerForName:MPStringLengthValueTransformerName] }; - [[view textField] bind:NSValueBinding toObject:entry withKeyPath:@"password" options:options]; + [[view textField] bind:NSValueBinding toObject:entry withKeyPath:NSStringFromSelector(@selector(password)) options:options]; } else { view = [tableView makeViewWithIdentifier:_MPTableStringCellView owner:self]; @@ -322,22 +326,17 @@ NSString *const _MPTAbleSecurCellView = @"PasswordCell"; document.selectedEntry = nil; } } -#pragma mark MPContextBarDelegate -- (void)contextBarDidExitFilter { - [[self.entryTable tableColumnWithIdentifier:MPEntryTableParentColumnIdentifier] setHidden:YES]; - MPDocument *document = [[self windowController] document]; - document.selectedItem = document.selectedGroup; - [self _updateContextBar]; -} - -- (void)contextBarDidChangeFilter { +#pragma mark MPDocumentSearchServiceNotifications +- (void)_updateSearchResults:(NSNotification *)notification { + if(!_isDisplayingContextBar || ![self.contextBarViewController showsFilter]) { + [self showFilter:nil]; + } dispatch_queue_t backgroundQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); dispatch_async(backgroundQueue, ^{ MPDocument *document = [[self windowController] document]; - - self.filteredEntries = [MPDocumentSearchService entriesInDocument:document - matching:self.contextBarViewController.filterString - usingFilterMode:self.contextBarViewController.filterMode]; + NSString *searchString = [[[self windowController] searchField] stringValue]; + self.filteredEntries = [document entriesInDocument:document + matching:searchString]; dispatch_sync(dispatch_get_main_queue(), ^{ document.selectedEntry = nil; @@ -348,7 +347,19 @@ NSString *const _MPTAbleSecurCellView = @"PasswordCell"; }); } -- (void)showFilter:(id)sender { +#pragma mark MPContextBarDelegate +- (void)contextBarDidExitFilter { + [[self.entryTable tableColumnWithIdentifier:MPEntryTableParentColumnIdentifier] setHidden:YES]; + MPDocument *document = [[self windowController] document]; + document.selectedItem = document.selectedGroup; + [self _updateContextBar]; +} + +- (void)showFilter:(NSNotification *)notification { + MPDocument *currentDocument = [[self windowController] document]; + if(notification && [notification object] != currentDocument) { + return; // Wrong document + } [self.contextBarViewController showFilter]; [self _showContextBar]; } @@ -411,9 +422,7 @@ NSString *const _MPTAbleSecurCellView = @"PasswordCell"; context.duration = STATUS_BAR_ANIMATION_TIME; context.allowsImplicitAnimation = YES; [self.view layoutSubtreeIfNeeded]; - } completionHandler:^{ - [self.contextBarViewController enable]; - }]; + } completionHandler:nil]; } - (void)_hideContextBar { @@ -422,7 +431,6 @@ NSString *const _MPTAbleSecurCellView = @"PasswordCell"; } self.contextBarTopConstraint.constant = -31; [[self view] addConstraint:self.tableToTopConstraint]; - [self.contextBarViewController disable]; [NSAnimationContext runAnimationGroup:^(NSAnimationContext* context) { context.duration = STATUS_BAR_ANIMATION_TIME; @@ -473,7 +481,7 @@ NSString *const _MPTAbleSecurCellView = @"PasswordCell"; KPKEntry *targetEntry = [self _clickedOrSelectedEntry]; MPActionType actionType = [MPActionHelper typeForAction:[menuItem action]]; - + switch (actionType) { case MPActionCopyUsername: return [targetEntry.username length] > 0; diff --git a/MacPass/MPToolbarDelegate.h b/MacPass/MPToolbarDelegate.h index 76433117..c68ade84 100644 --- a/MacPass/MPToolbarDelegate.h +++ b/MacPass/MPToolbarDelegate.h @@ -26,4 +26,6 @@ @interface MPToolbarDelegate : NSObject +@property (weak, readonly) NSSearchField *searchField; + @end diff --git a/MacPass/MPToolbarDelegate.m b/MacPass/MPToolbarDelegate.m index 8c7be1a5..e8c7d9e8 100644 --- a/MacPass/MPToolbarDelegate.m +++ b/MacPass/MPToolbarDelegate.m @@ -32,7 +32,7 @@ #import "MPIconHelper.h" #import "MPDocumentWindowController.h" -#import "MPDocumentSearchService.h" +#import "MPDocument+Search.h" NSString *const MPToolbarItemLock = @"TOOLBAR_LOCK"; NSString *const MPToolbarItemAddGroup = @"TOOLBAR_ADD_GROUP"; @@ -66,10 +66,15 @@ NSString *const MPToolbarItemSearch = @"TOOLBAR_SEARCH"; _toolbarImages = [self createToolbarImages]; _toolbarItems = [[NSMutableDictionary alloc] initWithCapacity:[self.toolbarIdentifiers count]]; _entryMenuDelegate = [[MPAddEntryContextMenuDelegate alloc] init]; + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_didExitSearch:) name:MPDocumentDidExitSearchNotification object:self]; } return self; } +- (void)dealloc { + [[NSNotificationCenter defaultCenter] removeObserver:self]; +} + - (NSToolbarItem *)toolbar:(NSToolbar *)toolbar itemForItemIdentifier:(NSString *)itemIdentifier willBeInsertedIntoToolbar:(BOOL)flag { NSToolbarItem *item = self.toolbarItems[itemIdentifier]; @@ -134,11 +139,12 @@ NSString *const MPToolbarItemSearch = @"TOOLBAR_SEARCH"; } else if( [itemIdentifier isEqualToString:MPToolbarItemSearch]){ NSSearchField *searchField = [[NSSearchField alloc] init]; - [searchField setAction:@selector(performFindPanelAction:)]; + [searchField setAction:@selector(updateSearch:)]; NSSearchFieldCell *cell = [searchField cell]; - [[cell cancelButtonCell] setAction:@selector(cancelSearch:)]; + [[cell cancelButtonCell] setAction:@selector(exitSearch:)]; [[cell cancelButtonCell] setTarget:nil]; [item setView:searchField]; + self.searchField = searchField; } else { NSButton *button = [[MPToolbarButton alloc] initWithFrame:NSMakeRect(0, 0, 32, 32)]; @@ -212,4 +218,8 @@ NSString *const MPToolbarItemSearch = @"TOOLBAR_SEARCH"; return [MPActionHelper actionOfType:actionType]; } +- (void)_didExitSearch:(NSNotification *)notification { + [self.searchField setStringValue:@""]; +} + @end