Search criteriy is objetified. Can be stored and saved in preferences.

This is a first step to enable saved searches inside the Keepass database via use of custom data.
This commit is contained in:
michael starke
2014-08-27 19:43:03 +02:00
parent 0286ed4e5c
commit be5889c5b1
13 changed files with 170 additions and 74 deletions

2
HNHUi

Submodule HNHUi updated: 330a06a831...08252931b9

View File

@@ -7,7 +7,6 @@
<objects>
<customObject id="-2" userLabel="File's Owner" customClass="MPContextBarViewController">
<connections>
<outlet property="duplicatePasswordsButton" destination="hMB-2T-pBD" id="dWH-3p-fy6"/>
<outlet property="emptyTrashButton" destination="szx-Hx-OrV" id="i1Y-qB-TW3"/>
<outlet property="exitHistoryButton" destination="pqx-su-vAh" id="JmV-vC-F48"/>
<outlet property="filterLabelTextField" destination="6" id="60"/>
@@ -15,6 +14,7 @@
<outlet property="historyLabel" destination="gGR-f0-dcr" id="slx-9D-8k8"/>
<outlet property="notesButton" destination="SaV-5p-jIX" id="sQc-nE-BOP"/>
<outlet property="passwordButton" destination="Uhl-ck-vVQ" id="I35-Nv-6jK"/>
<outlet property="specialFilterPopUpButton" destination="aPQ-t2-bgz" id="5II-Ml-qg1"/>
<outlet property="titleButton" destination="O7W-cn-eUP" id="Vlg-KG-62R"/>
<outlet property="trashBar" destination="DXf-SC-gVG" id="3aZ-Xc-VDk"/>
<outlet property="urlButton" destination="Bn2-iY-mQ3" id="PNG-kv-PQN"/>
@@ -102,31 +102,38 @@
<action selector="toggleSearchFlags:" target="-1" id="cuN-5p-vZD"/>
</connections>
</button>
<button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="hMB-2T-pBD">
<rect key="frame" x="412" y="6" width="144" height="17"/>
<popUpButton verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="aPQ-t2-bgz">
<rect key="frame" x="493" y="5" width="63" height="19"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<buttonCell key="cell" type="recessed" title="Duplicate Passwords" bezelStyle="recessed" alignment="center" controlSize="small" state="on" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="G1B-En-dc2">
<popUpButtonCell key="cell" type="recessed" title="Item 1" bezelStyle="recessed" alignment="center" lineBreakMode="truncatingTail" state="on" borderStyle="border" imageScaling="proportionallyDown" inset="2" autoenablesItems="NO" selectedItem="LRm-iZ-XrA" id="faz-pC-uGX">
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES" changeBackground="YES" changeGray="YES"/>
<font key="font" metaFont="systemBold" size="12"/>
</buttonCell>
</button>
<menu key="menu" title="OtherViews" autoenablesItems="NO" id="wC4-fF-dLW">
<items>
<menuItem title="Item 1" state="on" id="LRm-iZ-XrA"/>
<menuItem title="Item 2" id="cpr-p6-YAY"/>
<menuItem title="Item 3" id="CFk-71-NYQ"/>
</items>
</menu>
</popUpButtonCell>
</popUpButton>
</subviews>
<constraints>
<constraint firstAttribute="centerY" secondItem="O7W-cn-eUP" secondAttribute="centerY" id="2uC-wS-HDi"/>
<constraint firstAttribute="centerY" secondItem="hMB-2T-pBD" secondAttribute="centerY" id="4rl-iO-76L"/>
<constraint firstItem="O7W-cn-eUP" firstAttribute="leading" secondItem="6" secondAttribute="trailing" constant="8" symbolic="YES" id="5hN-x3-XlX"/>
<constraint firstItem="0R1-PX-dgn" firstAttribute="leading" secondItem="O7W-cn-eUP" secondAttribute="trailing" constant="8" symbolic="YES" id="67f-i6-eOb"/>
<constraint firstAttribute="centerY" secondItem="SaV-5p-jIX" secondAttribute="centerY" id="7ch-eZ-Hzh"/>
<constraint firstItem="aPQ-t2-bgz" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="SaV-5p-jIX" secondAttribute="trailing" constant="8" symbolic="YES" id="91Q-Aq-ulG"/>
<constraint firstItem="aPQ-t2-bgz" firstAttribute="centerY" secondItem="SaV-5p-jIX" secondAttribute="centerY" id="EUG-hL-jbn"/>
<constraint firstAttribute="centerY" secondItem="0R1-PX-dgn" secondAttribute="centerY" id="Huh-PB-cbs"/>
<constraint firstItem="6" firstAttribute="leading" secondItem="1" secondAttribute="leading" constant="8" id="Seo-dI-FzX"/>
<constraint firstItem="Bn2-iY-mQ3" firstAttribute="leading" secondItem="Uhl-ck-vVQ" secondAttribute="trailing" constant="8" id="TCJ-vg-IIt"/>
<constraint firstAttribute="trailing" secondItem="hMB-2T-pBD" secondAttribute="trailing" constant="20" symbolic="YES" id="jAm-sk-ErW"/>
<constraint firstAttribute="trailing" secondItem="aPQ-t2-bgz" secondAttribute="trailing" constant="20" symbolic="YES" id="XFv-Pv-Bzq"/>
<constraint firstItem="SaV-5p-jIX" firstAttribute="leading" secondItem="Bn2-iY-mQ3" secondAttribute="trailing" constant="8" symbolic="YES" id="pAA-uU-moF"/>
<constraint firstAttribute="centerY" secondItem="6" secondAttribute="centerY" id="qak-8F-xbj"/>
<constraint firstItem="Uhl-ck-vVQ" firstAttribute="leading" secondItem="0R1-PX-dgn" secondAttribute="trailing" constant="8" id="u8d-C2-O9h"/>
<constraint firstAttribute="centerY" secondItem="Uhl-ck-vVQ" secondAttribute="centerY" id="uvE-ch-ysK"/>
<constraint firstAttribute="centerY" secondItem="Bn2-iY-mQ3" secondAttribute="centerY" id="xZJ-EZ-Nic"/>
<constraint firstItem="hMB-2T-pBD" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="SaV-5p-jIX" secondAttribute="trailing" constant="8" symbolic="YES" id="zRT-y1-oMu"/>
</constraints>
</customView>
</subviews>
@@ -135,6 +142,8 @@
<constraint firstAttribute="bottom" secondItem="1" secondAttribute="bottom" id="Z4A-sK-v8K"/>
<constraint firstItem="1" firstAttribute="top" secondItem="caQ-XO-RkM" secondAttribute="top" id="a5u-p3-ay5"/>
<constraint firstAttribute="trailing" secondItem="1" secondAttribute="trailing" id="hTR-dg-7Ql"/>
<constraint firstAttribute="trailing" secondItem="1" secondAttribute="trailing" id="mos-cv-3fn"/>
<constraint firstAttribute="trailing" secondItem="1" secondAttribute="trailing" id="rO8-g6-lT3"/>
</constraints>
</view>
</tabViewItem>

View File

@@ -20,6 +20,7 @@
@property (weak) IBOutlet NSButton *urlButton;
@property (weak) IBOutlet NSButton *notesButton;
@property (weak) IBOutlet NSButton *duplicatePasswordsButton;
@property (weak) IBOutlet NSPopUpButton *specialFilterPopUpButton;
- (void)registerNotificationsForDocument:(MPDocument *)document;

View File

@@ -70,12 +70,24 @@ typedef NS_ENUM(NSUInteger, MPContextTab) {
self.emptyTrashButton.textColor = [NSColor whiteColor];
NSInteger tags[] = { MPEntrySearchTitles, MPEntrySearchUsernames, MPEntrySearchPasswords, MPEntrySearchNotes, MPEntrySearchUrls, MPEntrySearchDoublePasswords };
NSArray *buttons = @[self.titleButton, self.usernameButton, self.passwordButton, self.notesButton, self.urlButton, self.duplicatePasswordsButton ];
NSInteger tags[] = { MPEntrySearchTitles, MPEntrySearchUsernames, MPEntrySearchPasswords, MPEntrySearchNotes, MPEntrySearchUrls };
NSArray *buttons = @[self.titleButton, self.usernameButton, self.passwordButton, self.notesButton, self.urlButton ];
for(NSUInteger iIndex = 0; iIndex < [buttons count]; iIndex++) {
[buttons[iIndex] setAction:@selector(toggleSearchFlags:)];
[buttons[iIndex] setTag:tags[iIndex]];
}
NSInteger specialTags[] = { MPEntrySearchDoublePasswords, MPEntrySearchExpiredEntries };
NSArray *titles = @[ NSLocalizedString(@"SEARCH_DUPLICATE_PASSWORDS", ""), NSLocalizedString(@"SEARCH_EXPIRED_ENTRIES", "") ];
NSMenu *specialMenu = [[NSMenu alloc] initWithTitle:@"Special Filters Menu"];
[specialMenu addItemWithTitle:NSLocalizedString(@"SELECT_FILTER_WITH_DOTS", "") action:NULL keyEquivalent:@""];
[[specialMenu itemAtIndex:0] setEnabled:NO];
[[specialMenu itemAtIndex:0] setTag:MPEntrySearchNone];
for(NSInteger iIndex = 0; iIndex < [titles count]; iIndex++) {
NSMenuItem *item = [[NSMenuItem alloc] initWithTitle:titles[iIndex] action:@selector(toggleSearchFlags:) keyEquivalent:@""];
[item setTag:specialTags[iIndex]];
[specialMenu addItem:item];
}
[self.specialFilterPopUpButton setMenu:specialMenu];
[self _updateFilterButtons];
}
@@ -131,6 +143,22 @@ typedef NS_ENUM(NSUInteger, MPContextTab) {
[self.titleButton setState:HNHStateForBool(MPTestFlagInOptions(MPEntrySearchTitles, currentFlags))];
[self.urlButton setState:HNHStateForBool(MPTestFlagInOptions(MPEntrySearchUrls, currentFlags))];
[self.usernameButton setState:HNHStateForBool(MPTestFlagInOptions(MPEntrySearchUsernames, currentFlags))];
NSInteger selectedTag = MPEntrySearchNone;
for(NSMenuItem *item in [[self.specialFilterPopUpButton menu] itemArray]) {
MPEntrySearchFlags flag = [item tag];
if(flag == MPEntrySearchNone) {
[item setState:NSOffState];
[item setEnabled:NO];
}
else {
BOOL isActive = MPTestFlagInOptions(flag, currentFlags);
if(isActive) {
selectedTag = flag;
}
[item setState:HNHStateForBool(isActive)];
}
}
[self.specialFilterPopUpButton selectItemWithTag:selectedTag];
}
@end

View File

@@ -25,6 +25,8 @@ FOUNDATION_EXTERN NSString *const kMPDocumentSearchResultsKey;
@interface MPDocument (Search)
- (void)enterSearchWithContext:(MPEntrySearchContext *)context;
/* Should be called by the NSSearchTextField to update the search string */
- (IBAction)updateSearch:(id)sender;
/* exits searching mode */
@@ -32,6 +34,4 @@ FOUNDATION_EXTERN NSString *const kMPDocumentSearchResultsKey;
/* called by the filter toggle buttons */
- (IBAction)toggleSearchFlags:(id)sender;
- (NSArray *)entriesMatchingSearch:(MPEntrySearchContext *)search;
@end

View File

@@ -12,6 +12,7 @@
#import "KPKGroup.h"
#import "KPKEntry.h"
#import "KPKTimeInfo.h"
#import "MPFlagsHelper.h"
@@ -26,25 +27,30 @@ NSString *const kMPDocumentSearchResultsKey = @"kMPDocumentSearchResul
@implementation MPDocument (Search)
#pragma mark Actions
- (void)performFindPanelAction:(id)sender {
self.hasSearch = YES;
- (void)enterSearchWithContext:(MPEntrySearchContext *)context {
/* the search context is loaded via defaults */
self.searchContext = [[MPEntrySearchContext alloc] init];
self.searchContext = context;
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(updateSearch:) name:NSUndoManagerDidRedoChangeNotification object:self.undoManager];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(updateSearch:) name:NSUndoManagerDidUndoChangeNotification object:self.undoManager];
[[NSNotificationCenter defaultCenter] postNotificationName:MPDocumentDidEnterSearchNotification object:self];
[self updateSearch:self];
}
#pragma mark Actions
- (void)performFindPanelAction:(id)sender {
[self enterSearchWithContext:[MPEntrySearchContext userContext]];
}
- (void)updateSearch:(id)sender {
if(NO == self.hasSearch) {
[self enterSearchWithContext:[MPEntrySearchContext userContext]];
return; // We get called back!
}
MPDocumentWindowController *windowController = [self windowControllers][0];
NSString *searchString = [windowController.searchField stringValue];
/* Update the search string */
self.searchContext = [[MPEntrySearchContext alloc] initWithString:searchString flags:self.searchContext.searchFlags];
if(NO == self.hasSearch) {
[[NSNotificationCenter defaultCenter] postNotificationName:MPDocumentDidEnterSearchNotification object:self];
}
self.hasSearch = YES;
self.searchContext.searchString = searchString;
MPDocument __weak *weakSelf = self;
dispatch_queue_t backgroundQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_async(backgroundQueue, ^{
@@ -57,10 +63,9 @@ NSString *const kMPDocumentSearchResultsKey = @"kMPDocumentSearchResul
}
- (void)exitSearch:(id)sender {
[[NSNotificationCenter defaultCenter] removeObserver:self name:NSUndoManagerDidUndoChangeNotification object:self.undoManager];
[[NSNotificationCenter defaultCenter] removeObserver:self name:NSUndoManagerDidRedoChangeNotification object:self.undoManager];
self.searchContext = nil;
/*self.searchString = nil;
self.hasSearch = NO;
*/
[[NSNotificationCenter defaultCenter] postNotificationName:MPDocumentDidExitSearchNotification object:self];
}
@@ -75,29 +80,30 @@ NSString *const kMPDocumentSearchResultsKey = @"kMPDocumentSearchResul
MPEntrySearchFlags toggleFlag = [sender tag];
MPEntrySearchFlags newFlags = MPEntrySearchNone;
BOOL isDoublePasswordFlag = (toggleFlag == MPEntrySearchDoublePasswords);
BOOL isExpiredFlag = (toggleFlag == MPEntrySearchExpiredEntries);
NSButton *button = sender;
switch([button state]) {
case NSOffState:
toggleFlag ^= MPEntrySearchAllFlags;
newFlags = isDoublePasswordFlag ? oldFlags : (self.activeFlags & toggleFlag);
newFlags = isDoublePasswordFlag ? oldFlags : (self.searchContext.searchFlags & toggleFlag);
break;
case NSOnState:
if(isDoublePasswordFlag) {
oldFlags = self.activeFlags;
newFlags = MPEntrySearchDoublePasswords;
if(isDoublePasswordFlag || isExpiredFlag ) {
oldFlags = self.searchContext.searchFlags;
newFlags = toggleFlag;//MPEntrySearchDoublePasswords;
}
else {
/* always mask the double passwords in case another button was pressed */
self.activeFlags &= (MPEntrySearchDoublePasswords ^ MPEntrySearchAllFlags);
newFlags = self.activeFlags | toggleFlag;
self.searchContext.searchFlags &= ((MPEntrySearchDoublePasswords | MPEntrySearchExpiredEntries) ^ MPEntrySearchAllFlags);
newFlags = self.searchContext.searchFlags | toggleFlag;
}
break;
default:
NSAssert(NO, @"Internal state is inconsistent");
return;
}
if(newFlags != self.activeFlags) {
self.activeFlags = (newFlags == MPEntrySearchNone) ? MPEntrySearchTitles : newFlags;
if(newFlags != self.searchContext.searchFlags) {
self.searchContext.searchFlags = (newFlags == MPEntrySearchNone) ? MPEntrySearchTitles : newFlags;
[[NSNotificationCenter defaultCenter] postNotificationName:MPDocumentDidChangeSearchFlags object:self];
[self updateSearch:self];
}
@@ -110,7 +116,7 @@ NSString *const kMPDocumentSearchResultsKey = @"kMPDocumentSearchResul
#pragma mark Search
- (NSArray *)_findEntriesMatchingCurrentSearch {
/* Filter double passwords */
if(MPTestFlagInOptions(MPEntrySearchDoublePasswords, self.activeFlags)) {
if(MPTestFlagInOptions(MPEntrySearchDoublePasswords, self.searchContext.searchFlags)) {
__block NSMutableDictionary *passwordToEntryMap = [[NSMutableDictionary alloc] initWithCapacity:100];
/* Build up a usage map */
[[self.root childEntries] enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
@@ -136,8 +142,15 @@ NSString *const kMPDocumentSearchResultsKey = @"kMPDocumentSearchResul
}];
return doublePasswords;
}
if(MPTestFlagInOptions(MPEntrySearchExpiredEntries, self.searchContext.searchFlags)) {
NSPredicate *expiredPredicate = [NSPredicate predicateWithBlock:^BOOL(id evaluatedObject, NSDictionary *bindings) {
KPKNode *node = evaluatedObject;
return node.timeInfo.isExpired;
}];
return [[self.root childEntries] filteredArrayUsingPredicate:expiredPredicate];
}
/* Filter using predicates */
NSArray *predicates = [self _filterPredicatesWithString:self.searchString];
NSArray *predicates = [self _filterPredicatesWithString:self.searchContext.searchString];
if(predicates) {
NSPredicate *fullFilter = [NSCompoundPredicate orPredicateWithSubpredicates:predicates];
return [[self.root childEntries] filteredArrayUsingPredicate:fullFilter];
@@ -146,34 +159,22 @@ NSString *const kMPDocumentSearchResultsKey = @"kMPDocumentSearchResul
return [self.root childEntries];
}
- (NSArray *)optionsEnabledInMode:(MPEntrySearchFlags)mode {
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);
}];
return [allOptions objectsAtIndexes:indexes];
}
- (NSArray *)_filterPredicatesWithString:(NSString *)string{
NSMutableArray *prediactes = [[NSMutableArray alloc] initWithCapacity:4];
if(MPTestFlagInOptions(MPEntrySearchTitles, self.activeFlags)) {
if(MPTestFlagInOptions(MPEntrySearchTitles, self.searchContext.searchFlags)) {
[prediactes addObject:[NSPredicate predicateWithFormat:@"SELF.title CONTAINS[cd] %@", string]];
}
if(MPTestFlagInOptions(MPEntrySearchUsernames, self.activeFlags)) {
if(MPTestFlagInOptions(MPEntrySearchUsernames, self.searchContext.searchFlags)) {
[prediactes addObject:[NSPredicate predicateWithFormat:@"SELF.username CONTAINS[cd] %@", string]];
}
if(MPTestFlagInOptions(MPEntrySearchUrls, self.activeFlags)) {
if(MPTestFlagInOptions(MPEntrySearchUrls, self.searchContext.searchFlags)) {
[prediactes addObject:[NSPredicate predicateWithFormat:@"SELF.url CONTAINS[cd] %@", string]];
}
if(MPTestFlagInOptions(MPEntrySearchPasswords, self.activeFlags)) {
if(MPTestFlagInOptions(MPEntrySearchPasswords, self.searchContext.searchFlags)) {
[prediactes addObject:[NSPredicate predicateWithFormat:@"SELF.password CONTAINS[cd] %@", string]];
}
if(MPTestFlagInOptions(MPEntrySearchNotes, self.activeFlags)) {
if(MPTestFlagInOptions(MPEntrySearchNotes, self.searchContext.searchFlags)) {
[prediactes addObject:[NSPredicate predicateWithFormat:@"SELF.notes CONTAINS[cd] %@", string]];
}
return prediactes;

View File

@@ -61,6 +61,7 @@ APPKIT_EXTERN NSString *const MPDocumentGroupKey;
@interface MPDocument : NSDocument
@property (nonatomic, readonly, assign) BOOL encrypted;
@property (nonatomic, readonly, assign) NSUInteger unlockCount; // Amount of times the Document was unlocked;
@@ -85,7 +86,7 @@ APPKIT_EXTERN NSString *const MPDocumentGroupKey;
/*
Search - see MPDocument+Search for further details
*/
@property (nonatomic, readonly, assign) BOOL hasSearch;
@property (nonatomic, readonly) BOOL hasSearch;
@property (nonatomic, copy) MPEntrySearchContext *searchContext;
@property (nonatomic, strong) NSArray *searchResult;

View File

@@ -354,6 +354,10 @@ NSString *const MPDocumentGroupKey = @"MPDocumentGroupKey
return [self findGroup:self.tree.metaData.entryTemplatesGroup];
}
- (BOOL)hasSearch {
return self.searchContext != nil;
}
- (void)setTrash:(KPKGroup *)trash {
if(self.useTrash) {
if(![self.tree.metaData.recycleBinUuid isEqual:trash.uuid]) {

View File

@@ -16,8 +16,11 @@ typedef NS_OPTIONS(NSUInteger, MPEntrySearchFlags) {
MPEntrySearchPasswords = (1<<3),
MPEntrySearchNotes = (1<<4),
MPEntrySearchAllAttributes = (1<<5),
MPEntrySearchDoublePasswords = (1<<6), // Unused in GUI for now
MPEntrySearchExpiredEntries = (1<<7), // Unused for now
/* The following two flags should be used like enums.
They are not intented to be used in conjunktion with any other flag */
MPEntrySearchDoublePasswords = (1<<6),
MPEntrySearchExpiredEntries = (1<<7),
/* All search flags that are combineable combined */
MPEntrySearchAllFlags = (MPEntrySearchDoublePasswords |
MPEntrySearchExpiredEntries |
MPEntrySearchNotes |
@@ -30,12 +33,24 @@ typedef NS_OPTIONS(NSUInteger, MPEntrySearchFlags) {
/* Wrap serach criteria to be able to store them */
@interface MPEntrySearchContext : NSObject <NSSecureCoding>
@interface MPEntrySearchContext : NSObject <NSSecureCoding,NSCopying>
/**
* Returns a default search context initalized with sane values.
*
* @return The default search context
*/
+ (instancetype)defaultContext;
/**
* Returns the search context using the users preferences. If none are found, a default context is created
*
* @return Search context configured to the users data. If nothing is configures, defaultContext is used
*/
+ (instancetype)userContext;
- (instancetype)initWithString:(NSString *)searchString flags:(MPEntrySearchFlags)flags;
@property (readonly, assign) NSInteger searchFlags;
@property (readonly, copy) NSString *searchString;
@property (nonatomic, assign) NSInteger searchFlags;
@property (nonatomic, copy) NSString *searchString;
@end

View File

@@ -7,13 +7,7 @@
//
#import "MPEntrySearchContext.h"
@interface MPEntrySearchContext ()
@property (assign) NSInteger searchFlags;
@property (copy) NSString *searchString;
@end
#import "MPSettingsHelper.h"
@implementation MPEntrySearchContext
@@ -22,11 +16,19 @@
}
+ (instancetype)defaultContext {
return [[MPEntrySearchContext alloc] init];
}
+ (instancetype)userContext {
NSData *data = [[NSUserDefaults standardUserDefaults] dataForKey:kMPSettingsKeyEntrySearchFilterContext];
if(data) {
return [NSKeyedUnarchiver unarchiveObjectWithData:data];
}
return [self defaultContext];
}
- (instancetype)init {
self = [self initWithString:nil flags:MPEntrySearchNone];
self = [self initWithString:nil flags:MPEntrySearchTitles|MPEntrySearchUsernames];
return self;
}
@@ -40,6 +42,7 @@
}
#pragma mark NSSecureCoding
- (void)encodeWithCoder:(NSCoder *)aCoder {
[aCoder encodeInteger:self.searchFlags forKey:NSStringFromSelector(@selector(searchFlags))];
[aCoder encodeObject:self.searchString forKey:NSStringFromSelector(@selector(searchString))];
@@ -52,4 +55,28 @@
return self;
}
#pragma mark NSCopying
- (id)copyWithZone:(NSZone *)zone {
return [[MPEntrySearchContext alloc] initWithString:self.searchString flags:self.searchFlags];
}
- (void)setSearchFlags:(NSInteger)searchFlags {
if(_searchFlags != searchFlags) {
_searchFlags = searchFlags;
[self _updatePreferences];
}
}
- (void)setSearchString:(NSString *)searchString {
if(![_searchString isEqualToString:searchString]) {
_searchString = [searchString copy];
[self _updatePreferences];
}
}
- (void )_updatePreferences {
NSData *myData = [NSKeyedArchiver archivedDataWithRootObject:self];
[[NSUserDefaults standardUserDefaults] setObject:myData forKey:kMPSettingsKeyEntrySearchFilterContext];
[[NSUserDefaults standardUserDefaults] synchronize];
}
@end

View File

@@ -49,7 +49,6 @@ NSString *const kMPSettingsKeyPasswordCharacterFlags = @"Passwo
NSString *const kMPSettingsKeyPasswordUseCustomString = @"PasswordUseCustomString";
NSString *const kMPSettingsKeyPasswordCustomString = @"PasswordCustomString";
/* Depricated */
NSString *const kMPSettingsKeyDoubleClickURLAction = @"DoubleClickURLAction";
NSString *const kMPSettingsKeyDoubleClickTitleAction = @"DoubleClickTitleAction";
@@ -58,6 +57,7 @@ NSString *const kMPDeprecatedSettingsKeyRememberKeyFilesForDatabases = @"kM
NSString *const kMPDeprecatedSettingsKeyLastDatabasePath = @"MPLastDatabasePath";
NSString *const kMPDeprecatedSettingsKeyDocumentsAutotypeFixNoteWasShown = @"DocumentsAutotypeFixNoteWasShown";
NSString *const kMPDeprecatedSettingsKeyDoubleClickURLToLaunch = @"DoubleClickURLToLaunch";
NSString *const kMPDeprecatedSettingsKeyEntrySearchFilterMode = @"EntrySearchFilterMode";
@implementation MPSettingsHelper
@@ -68,6 +68,7 @@ NSString *const kMPDeprecatedSettingsKeyDoubleClickURLToLaunch = @"Do
+ (void)migrateDefaults {
[self _fixEntryTableSortDescriptors];
[self _migrateURLDoubleClickPreferences];
[self _migrateEntrySearchFlags];
[self _removeDeprecatedValues];
}
@@ -97,7 +98,6 @@ NSString *const kMPDeprecatedSettingsKeyDoubleClickURLToLaunch = @"Do
kMPSettingsKeyLegacyHideUsername: @NO,
kMPSettingsKeyRememberKeyFilesForDatabases: @NO,
kMPSettingsKeySendCommandForControlKey: @YES,
kMPSettingsKeyEntrySearchFilterMode: @0,
kMPSettingsKeyEnableGlobalAutotype: @NO,
kMPSettingsKeyEnableQuicklookPreview: @NO,
kMPSettingsKeyCopyGeneratedPasswordToClipboard: @NO,
@@ -120,7 +120,8 @@ NSString *const kMPDeprecatedSettingsKeyDoubleClickURLToLaunch = @"Do
deprecatedSettings = @[ kMPDeprecatedSettingsKeyRememberKeyFilesForDatabases,
kMPDeprecatedSettingsKeyLastDatabasePath,
kMPDeprecatedSettingsKeyDocumentsAutotypeFixNoteWasShown,
kMPDeprecatedSettingsKeyDoubleClickURLToLaunch ];
kMPDeprecatedSettingsKeyDoubleClickURLToLaunch,
kMPDeprecatedSettingsKeyEntrySearchFilterMode];
});
return deprecatedSettings;
}
@@ -160,4 +161,13 @@ NSString *const kMPDeprecatedSettingsKeyDoubleClickURLToLaunch = @"Do
}
}
+ (void)_migrateEntrySearchFlags {
NSInteger flags = [[NSUserDefaults standardUserDefaults] integerForKey:kMPDeprecatedSettingsKeyEntrySearchFilterMode];
if(flags != 0) {
MPEntrySearchContext *context = [[MPEntrySearchContext alloc] initWithString:nil flags:flags];
NSData *contextData = [NSKeyedArchiver archivedDataWithRootObject:context];
[[NSUserDefaults standardUserDefaults] setObject:contextData forKey:kMPSettingsKeyEntrySearchFilterContext];
}
}
@end

View File

@@ -1,8 +1,8 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="5053" systemVersion="13C64" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES">
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="5056" systemVersion="13E28" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES">
<dependencies>
<deployment defaultVersion="1080" identifier="macosx"/>
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="5053"/>
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="5056"/>
</dependencies>
<objects>
<customObject id="-2" userLabel="File's Owner" customClass="MPOutlineViewController">

Binary file not shown.