mirror of
https://github.com/MacPass/MacPass.git
synced 2025-12-14 11:42:30 +00:00
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:
2
HNHUi
2
HNHUi
Submodule HNHUi updated: 330a06a831...08252931b9
@@ -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>
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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]) {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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.
Reference in New Issue
Block a user