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"
FOUNDATION_EXPORT NSString *const MPDocumentDidEnterSearchNotification;
FOUNDATION_EXTERN NSString *const MPDocumentDidChangeSearchNotification;
FOUNDATION_EXPORT NSString *const MPDocumentDidChangeSearchFlags;
FOUNDATION_EXTERN NSString *const MPDocumentDidEnterSearchNotification;
FOUNDATION_EXTERN NSString *const MPDocumentDidChangeSearchFlags;
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)
- (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 */

View File

@@ -8,32 +8,47 @@
#import "MPDocument+Search.h"
#import "MPDocument.h"
#import "MPDocumentWindowController.h"
#import "KPKGroup.h"
#import "KPKEntry.h"
#import "MPFlagsHelper.h"
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";
NSString *const MPDocumentDidChangeSearchResults = @"com.hicknhack.macpass.MPDocumentDidChangeSearchResults";
NSString *const kMPDocumentSearchResultsKey = @"kMPDocumentSearchResultsKey";
@implementation MPDocument (Search)
#pragma mark Actions
- (void)performFindPanelAction:(id)sender {
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];
}
- (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;
[[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 {
@@ -65,16 +80,18 @@ NSString *const MPDocumentDidExitSearchNotification = @"com.hicknhack.macpass.
if(newFlags == self.activeFlags) {
self.activeFlags = (newFlags == MPEntrySearchNone) ? MPEntrySearchTitles : newFlags;
[[NSNotificationCenter defaultCenter] postNotificationName:MPDocumentDidChangeSearchFlags object:self];
[self updateSearch:self];
}
}
#pragma mark Search
- (NSArray *)entriesInDocument:(MPDocument *)document matching:(NSString *)string {
- (NSArray *)_findEntriesMatchingCurrentSearch {
/* Filter double passwords */
MPDocument __weak *weakSelf = self;
if(MPTestFlagInOptions(MPEntrySearchDoublePasswords, self.activeFlags)) {
__block NSMutableDictionary *passwordToEntryMap;
/* 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;
NSMutableSet *entrySet = passwordToEntryMap[entry.password];
if(entrySet) {
@@ -96,13 +113,13 @@ NSString *const MPDocumentDidExitSearchNotification = @"com.hicknhack.macpass.
return doublePasswords;
}
/* Filter using predicates */
NSArray *predicates = [self _filterPredicatesWithString:string];
NSArray *predicates = [self _filterPredicatesWithString:self.searchString];
if(predicates) {
NSPredicate *fullFilter = [NSCompoundPredicate orPredicateWithSubpredicates:predicates];
return [[document.root childEntries] filteredArrayUsingPredicate:fullFilter];
return [[self.root childEntries] filteredArrayUsingPredicate:fullFilter];
}
/* No filter, just return everything */
return [document.root childEntries];
return [self.root childEntries];
}
- (NSArray *)optionsEnabledInMode:(MPEntrySearchFlags)mode {
@@ -117,10 +134,6 @@ NSString *const MPDocumentDidExitSearchNotification = @"com.hicknhack.macpass.
return [allOptions objectsAtIndexes:indexes];
}
- (void)_updateSearch {
self.searchResult = [self entriesInDocument:self matching:self.searchString];
}
- (NSArray *)_filterPredicatesWithString:(NSString *)string{
NSMutableArray *prediactes = [[NSMutableArray alloc] initWithCapacity:4];

View File

@@ -33,6 +33,7 @@ typedef NS_ENUM(NSUInteger, MPAlertContext) {
@private
id _firstResponder;
BOOL _saveAfterPasswordChange;
BOOL _didShowToolbarForSearch;
}
@property (strong) IBOutlet NSSplitView *splitView;
@@ -57,6 +58,7 @@ typedef NS_ENUM(NSUInteger, MPAlertContext) {
if( self ) {
_firstResponder = nil;
_saveAfterPasswordChange = NO;
_didShowToolbarForSearch = NO;
_toolbarDelegate = [[MPToolbarDelegate alloc] init];
_outlineViewController = [[MPOutlineViewController alloc] init];
_entryViewController = [[MPEntryViewController alloc] init];
@@ -77,12 +79,13 @@ typedef NS_ENUM(NSUInteger, MPAlertContext) {
[[self window] setDelegate:self.documentWindowDelegate];
[[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];
[[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];
[_inspectorViewController regsiterNotificationsForDocument:document];
[_outlineViewController regsiterNotificationsForDocument:document];
@@ -112,7 +115,7 @@ typedef NS_ENUM(NSUInteger, MPAlertContext) {
if(!showInspector) {
[inspectorView removeFromSuperview];
}
if(document.encrypted) {
[self showPasswordInput];
}
@@ -159,11 +162,32 @@ typedef NS_ENUM(NSUInteger, MPAlertContext) {
[self.window makeFirstResponder:[viewController reconmendedFirstResponder]];
}
#pragma mark MPDocument notifications
- (void)_didRevertDocument:(NSNotification *)notification {
[self.outlineViewController clearSelection];
[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
- (void)saveDocument:(id)sender {
_saveAfterPasswordChange = NO;
@@ -359,7 +383,7 @@ typedef NS_ENUM(NSUInteger, MPAlertContext) {
[_inspectorViewController updateResponderChain];
[_outlineViewController updateResponderChain];
[_outlineViewController showOutline];
/* Restore the State the inspector view was in before the view change */
if(removeInspector) {
[inspectorView removeFromSuperview];

View File

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