MPDocument now does the searching and notifies anyone that want to be informed

This commit is contained in:
michael starke
2014-02-27 21:31:45 +01:00
parent c1d6574172
commit 4273e41142
4 changed files with 84 additions and 49 deletions

View File

@@ -8,16 +8,21 @@
#import "MPDocument.h" #import "MPDocument.h"
FOUNDATION_EXPORT NSString *const MPDocumentDidEnterSearchNotification; FOUNDATION_EXTERN NSString *const MPDocumentDidEnterSearchNotification;
FOUNDATION_EXTERN NSString *const MPDocumentDidChangeSearchNotification; FOUNDATION_EXTERN NSString *const MPDocumentDidChangeSearchFlags;
FOUNDATION_EXPORT NSString *const MPDocumentDidChangeSearchFlags;
FOUNDATION_EXTERN NSString *const MPDocumentDidExitSearchNotification; FOUNDATION_EXTERN NSString *const MPDocumentDidExitSearchNotification;
FOUNDATION_EXPORT NSString *const MPDocumentDidChangeSearchResults; /**
* Posted by the document, when the search results have been updated. This is only called when searching.
* If the search is exited, it will be notified by MPDocumentDidExitSearchNotification
* The userInfo dictionary has one key kMPDocumentSearchResultsKey with an NSArray of KPKEntries mathching the search.
*/
FOUNDATION_EXTERN NSString *const MPDocumentDidChangeSearchResults;
/* keys used in userInfo dictionaries on notifications */
FOUNDATION_EXTERN NSString *const kMPDocumentSearchResultsKey;
@interface MPDocument (Search) @interface MPDocument (Search)
- (NSArray *)entriesInDocument:(MPDocument *)document matching:(NSString *)string;
/* Should be called by the NSSearchTextField to update the search string */ /* Should be called by the NSSearchTextField to update the search string */
- (IBAction)updateSearch:(id)sender; - (IBAction)updateSearch:(id)sender;
/* exits searching mode */ /* exits searching mode */

View File

@@ -8,32 +8,47 @@
#import "MPDocument+Search.h" #import "MPDocument+Search.h"
#import "MPDocument.h" #import "MPDocument.h"
#import "MPDocumentWindowController.h"
#import "KPKGroup.h" #import "KPKGroup.h"
#import "KPKEntry.h" #import "KPKEntry.h"
#import "MPFlagsHelper.h" #import "MPFlagsHelper.h"
NSString *const MPDocumentDidEnterSearchNotification = @"com.hicknhack.macpass.MPDocumentDidEnterSearchNotification"; NSString *const MPDocumentDidEnterSearchNotification = @"com.hicknhack.macpass.MPDocumentDidEnterSearchNotification";
NSString *const MPDocumentDidChangeSearchNotification = @"com.hicknhack.macpass.MPDocumentDidChangeSearchNotification";
NSString *const MPDocumentDidChangeSearchFlags = @"com.hicknhack.macpass.MPDocumentDidChangeSearchFlagsNotification"; NSString *const MPDocumentDidChangeSearchFlags = @"com.hicknhack.macpass.MPDocumentDidChangeSearchFlagsNotification";
NSString *const MPDocumentDidExitSearchNotification = @"com.hicknhack.macpass.MPDocumentDidExitSearchNotification"; NSString *const MPDocumentDidExitSearchNotification = @"com.hicknhack.macpass.MPDocumentDidExitSearchNotification";
NSString *const MPDocumentDidChangeSearchResults = @"com.hicknhack.macpass.MPDocumentDidChangeSearchResults";
NSString *const kMPDocumentSearchResultsKey = @"kMPDocumentSearchResultsKey";
@implementation MPDocument (Search) @implementation MPDocument (Search)
#pragma mark Actions #pragma mark Actions
- (void)performFindPanelAction:(id)sender { - (void)performFindPanelAction:(id)sender {
self.hasSearch = YES; self.hasSearch = YES;
NSWindow *window = [[self windowControllers][0] window];
NSToolbar *toolbar = [window toolbar];
if(![toolbar isVisible]) {
[toolbar setVisible:YES];
}
[[NSNotificationCenter defaultCenter] postNotificationName:MPDocumentDidEnterSearchNotification object:self]; [[NSNotificationCenter defaultCenter] postNotificationName:MPDocumentDidEnterSearchNotification object:self];
} }
- (void)updateSearch:(id)sender { - (void)updateSearch:(id)sender {
MPDocumentWindowController *windowController = [self windowControllers][0];
self.searchString = [windowController.searchField stringValue];
if(NO == self.hasSearch) {
[[NSNotificationCenter defaultCenter] postNotificationName:MPDocumentDidEnterSearchNotification object:self];
}
self.hasSearch = YES; self.hasSearch = YES;
[[NSNotificationCenter defaultCenter] postNotificationName:MPDocumentDidChangeSearchNotification object:self]; MPDocument __weak *weakSelf = self;
dispatch_queue_t backgroundQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_async(backgroundQueue, ^{
NSArray *results = [weakSelf _findEntriesMatchingCurrentSearch];
dispatch_sync(dispatch_get_main_queue(), ^{
weakSelf.selectedEntry = nil;
[[NSNotificationCenter defaultCenter] postNotificationName:MPDocumentDidChangeSearchResults object:weakSelf userInfo:@{ kMPDocumentSearchResultsKey: results }];
});
});
} }
- (void)exitSearch:(id)sender { - (void)exitSearch:(id)sender {
@@ -65,16 +80,18 @@ NSString *const MPDocumentDidExitSearchNotification = @"com.hicknhack.macpass.
if(newFlags == self.activeFlags) { if(newFlags == self.activeFlags) {
self.activeFlags = (newFlags == MPEntrySearchNone) ? MPEntrySearchTitles : newFlags; self.activeFlags = (newFlags == MPEntrySearchNone) ? MPEntrySearchTitles : newFlags;
[[NSNotificationCenter defaultCenter] postNotificationName:MPDocumentDidChangeSearchFlags object:self]; [[NSNotificationCenter defaultCenter] postNotificationName:MPDocumentDidChangeSearchFlags object:self];
[self updateSearch:self];
} }
} }
#pragma mark Search #pragma mark Search
- (NSArray *)entriesInDocument:(MPDocument *)document matching:(NSString *)string { - (NSArray *)_findEntriesMatchingCurrentSearch {
/* Filter double passwords */ /* Filter double passwords */
MPDocument __weak *weakSelf = self;
if(MPTestFlagInOptions(MPEntrySearchDoublePasswords, self.activeFlags)) { if(MPTestFlagInOptions(MPEntrySearchDoublePasswords, self.activeFlags)) {
__block NSMutableDictionary *passwordToEntryMap; __block NSMutableDictionary *passwordToEntryMap;
/* Build up a usage map */ /* Build up a usage map */
[[document.root childEntries] enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) { [[weakSelf.root childEntries] enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
KPKEntry *entry = obj; KPKEntry *entry = obj;
NSMutableSet *entrySet = passwordToEntryMap[entry.password]; NSMutableSet *entrySet = passwordToEntryMap[entry.password];
if(entrySet) { if(entrySet) {
@@ -96,13 +113,13 @@ NSString *const MPDocumentDidExitSearchNotification = @"com.hicknhack.macpass.
return doublePasswords; return doublePasswords;
} }
/* Filter using predicates */ /* Filter using predicates */
NSArray *predicates = [self _filterPredicatesWithString:string]; NSArray *predicates = [self _filterPredicatesWithString:self.searchString];
if(predicates) { if(predicates) {
NSPredicate *fullFilter = [NSCompoundPredicate orPredicateWithSubpredicates:predicates]; NSPredicate *fullFilter = [NSCompoundPredicate orPredicateWithSubpredicates:predicates];
return [[document.root childEntries] filteredArrayUsingPredicate:fullFilter]; return [[self.root childEntries] filteredArrayUsingPredicate:fullFilter];
} }
/* No filter, just return everything */ /* No filter, just return everything */
return [document.root childEntries]; return [self.root childEntries];
} }
- (NSArray *)optionsEnabledInMode:(MPEntrySearchFlags)mode { - (NSArray *)optionsEnabledInMode:(MPEntrySearchFlags)mode {
@@ -117,10 +134,6 @@ NSString *const MPDocumentDidExitSearchNotification = @"com.hicknhack.macpass.
return [allOptions objectsAtIndexes:indexes]; return [allOptions objectsAtIndexes:indexes];
} }
- (void)_updateSearch {
self.searchResult = [self entriesInDocument:self matching:self.searchString];
}
- (NSArray *)_filterPredicatesWithString:(NSString *)string{ - (NSArray *)_filterPredicatesWithString:(NSString *)string{
NSMutableArray *prediactes = [[NSMutableArray alloc] initWithCapacity:4]; NSMutableArray *prediactes = [[NSMutableArray alloc] initWithCapacity:4];

View File

@@ -33,6 +33,7 @@ typedef NS_ENUM(NSUInteger, MPAlertContext) {
@private @private
id _firstResponder; id _firstResponder;
BOOL _saveAfterPasswordChange; BOOL _saveAfterPasswordChange;
BOOL _didShowToolbarForSearch;
} }
@property (strong) IBOutlet NSSplitView *splitView; @property (strong) IBOutlet NSSplitView *splitView;
@@ -57,6 +58,7 @@ typedef NS_ENUM(NSUInteger, MPAlertContext) {
if( self ) { if( self ) {
_firstResponder = nil; _firstResponder = nil;
_saveAfterPasswordChange = NO; _saveAfterPasswordChange = NO;
_didShowToolbarForSearch = NO;
_toolbarDelegate = [[MPToolbarDelegate alloc] init]; _toolbarDelegate = [[MPToolbarDelegate alloc] init];
_outlineViewController = [[MPOutlineViewController alloc] init]; _outlineViewController = [[MPOutlineViewController alloc] init];
_entryViewController = [[MPEntryViewController alloc] init]; _entryViewController = [[MPEntryViewController alloc] init];
@@ -77,12 +79,13 @@ typedef NS_ENUM(NSUInteger, MPAlertContext) {
[[self window] setDelegate:self.documentWindowDelegate]; [[self window] setDelegate:self.documentWindowDelegate];
[[self window] registerForDraggedTypes:@[NSURLPboardType]]; [[self window] registerForDraggedTypes:@[NSURLPboardType]];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_didRevertDocument:) name:MPDocumentDidRevertNotifiation object:[self document]];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(showEntries) name:MPDocumentDidUnlockDatabaseNotification object:[self document]];
MPDocument *document = [self document]; MPDocument *document = [self document];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_didRevertDocument:) name:MPDocumentDidRevertNotifiation object:document];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(showEntries) name:MPDocumentDidUnlockDatabaseNotification object:document];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_didEnterSearch:) name:MPDocumentDidEnterSearchNotification object:document];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_didExitSearch:) name:MPDocumentDidExitSearchNotification object:document];
[_entryViewController regsiterNotificationsForDocument:document]; [_entryViewController regsiterNotificationsForDocument:document];
[_inspectorViewController regsiterNotificationsForDocument:document]; [_inspectorViewController regsiterNotificationsForDocument:document];
[_outlineViewController regsiterNotificationsForDocument:document]; [_outlineViewController regsiterNotificationsForDocument:document];
@@ -112,7 +115,7 @@ typedef NS_ENUM(NSUInteger, MPAlertContext) {
if(!showInspector) { if(!showInspector) {
[inspectorView removeFromSuperview]; [inspectorView removeFromSuperview];
} }
if(document.encrypted) { if(document.encrypted) {
[self showPasswordInput]; [self showPasswordInput];
} }
@@ -159,11 +162,32 @@ typedef NS_ENUM(NSUInteger, MPAlertContext) {
[self.window makeFirstResponder:[viewController reconmendedFirstResponder]]; [self.window makeFirstResponder:[viewController reconmendedFirstResponder]];
} }
#pragma mark MPDocument notifications
- (void)_didRevertDocument:(NSNotification *)notification { - (void)_didRevertDocument:(NSNotification *)notification {
[self.outlineViewController clearSelection]; [self.outlineViewController clearSelection];
[self showPasswordInput]; [self showPasswordInput];
} }
- (void)_didEnterSearch:(NSNotificationCenter *)notification {
/* Hide again after search ? */
NSWindow *window = [self window];
NSToolbar *toolbar = [window toolbar];
if(![toolbar isVisible]) {
_didShowToolbarForSearch = YES;
[toolbar setVisible:YES];
}
}
- (void)_didExitSearch:(NSNotification *)notification {
/* Hide again after search ? */
NSWindow *window = [self window];
NSToolbar *toolbar = [window toolbar];
if(_didShowToolbarForSearch && [toolbar isVisible]) {
_didShowToolbarForSearch = NO;
[toolbar setVisible:NO];
}
}
#pragma mark Actions #pragma mark Actions
- (void)saveDocument:(id)sender { - (void)saveDocument:(id)sender {
_saveAfterPasswordChange = NO; _saveAfterPasswordChange = NO;
@@ -359,7 +383,7 @@ typedef NS_ENUM(NSUInteger, MPAlertContext) {
[_inspectorViewController updateResponderChain]; [_inspectorViewController updateResponderChain];
[_outlineViewController updateResponderChain]; [_outlineViewController updateResponderChain];
[_outlineViewController showOutline]; [_outlineViewController showOutline];
/* Restore the State the inspector view was in before the view change */ /* Restore the State the inspector view was in before the view change */
if(removeInspector) { if(removeInspector) {
[inspectorView removeFromSuperview]; [inspectorView removeFromSuperview];

View File

@@ -195,21 +195,21 @@ NSString *const _MPTAbleSecurCellView = @"PasswordCell";
name:MPDocumentCurrentItemChangedNotification name:MPDocumentCurrentItemChangedNotification
object:document]; object:document];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(_updateSearchResults:)
name:MPDocumentDidChangeSearchNotification
object:document];
[[NSNotificationCenter defaultCenter] addObserver:self [[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(_didEnterSearch:) selector:@selector(_didEnterSearch:)
name:MPDocumentDidEnterSearchNotification name:MPDocumentDidEnterSearchNotification
object:document]; object:document];
[[NSNotificationCenter defaultCenter] addObserver:self [[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(_didExitSearch:) selector:@selector(_didExitSearch:)
name:MPDocumentDidExitSearchNotification name:MPDocumentDidExitSearchNotification
object:document]; object:document];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(_didUpdateSearchResults:)
name:MPDocumentDidChangeSearchResults
object:document];
[self.contextBarViewController registerNotificationsForDocument:document]; [self.contextBarViewController registerNotificationsForDocument:document];
} }
@@ -337,22 +337,15 @@ NSString *const _MPTAbleSecurCellView = @"PasswordCell";
} }
} }
#pragma mark MPDocumentSearchServiceNotifications #pragma mark MPDocumentSearchServiceNotifications
- (void)_updateSearchResults:(NSNotification *)notification { - (void)_didUpdateSearchResults:(NSNotification *)notification {
BOOL main = [NSThread isMainThread];
[self _showContextBar]; [self _showContextBar];
dispatch_queue_t backgroundQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); NSArray *result = [notification userInfo][kMPDocumentSearchResultsKey];
dispatch_async(backgroundQueue, ^{ NSAssert(result != nil, @"Resutls should never be nil");
MPDocument *document = [[self windowController] document]; self.filteredEntries = result;
NSString *searchString = [[[self windowController] searchField] stringValue]; [self.entryArrayController unbind:NSContentArrayBinding];
self.filteredEntries = [document entriesInDocument:document [self.entryArrayController setContent:self.filteredEntries];
matching:searchString]; [[self.entryTable tableColumnWithIdentifier:MPEntryTableParentColumnIdentifier] setHidden:NO];
dispatch_sync(dispatch_get_main_queue(), ^{
document.selectedEntry = nil;
[self.entryArrayController unbind:NSContentArrayBinding];
[self.entryArrayController setContent:self.filteredEntries];
[[self.entryTable tableColumnWithIdentifier:MPEntryTableParentColumnIdentifier] setHidden:NO];
});
});
} }
#pragma mark NSDocument+Search Notifications #pragma mark NSDocument+Search Notifications