mirror of
https://github.com/MacPass/MacPass.git
synced 2025-12-14 00:02:28 +00:00
Merge branch 'encapsulate_search'
This commit is contained in:
@@ -16,6 +16,7 @@
|
||||
4C0728BD17B5B7F7005A7DD9 /* MPPasswordEditWindowController.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C0728BC17B5B7F7005A7DD9 /* MPPasswordEditWindowController.m */; };
|
||||
4C0728BF17B68ED0005A7DD9 /* SavePanelAccessoryView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 4C0728BE17B68ED0005A7DD9 /* SavePanelAccessoryView.xib */; };
|
||||
4C08C3AE17B3022400BBBC95 /* KPKLegacyHeaderWriter.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C08C3AD17B3022400BBBC95 /* KPKLegacyHeaderWriter.m */; };
|
||||
4C0AF62F195C1F2B009E658D /* MPEntrySearchContext.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C0AF62E195C1F2B009E658D /* MPEntrySearchContext.m */; };
|
||||
4C0B038C18E36DA400B9F9C9 /* MPFixAutotypeWindowController.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C0B038A18E36DA400B9F9C9 /* MPFixAutotypeWindowController.m */; };
|
||||
4C0B038D18E36DA400B9F9C9 /* FixAutotypeWindow.xib in Resources */ = {isa = PBXBuildFile; fileRef = 4C0B038B18E36DA400B9F9C9 /* FixAutotypeWindow.xib */; };
|
||||
4C0C59F118B17F10009C7B76 /* DDHotKeyUtilities.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C0C59EF18B17F10009C7B76 /* DDHotKeyUtilities.m */; };
|
||||
@@ -384,6 +385,8 @@
|
||||
4C08C3AC17B3022400BBBC95 /* KPKLegacyHeaderWriter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = KPKLegacyHeaderWriter.h; sourceTree = "<group>"; };
|
||||
4C08C3AD17B3022400BBBC95 /* KPKLegacyHeaderWriter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = KPKLegacyHeaderWriter.m; sourceTree = "<group>"; };
|
||||
4C08C3AF17B3036500BBBC95 /* KPKLegacyFormat.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = KPKLegacyFormat.h; path = Format/KPKLegacyFormat.h; sourceTree = "<group>"; };
|
||||
4C0AF62D195C1F2B009E658D /* MPEntrySearchContext.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPEntrySearchContext.h; sourceTree = "<group>"; };
|
||||
4C0AF62E195C1F2B009E658D /* MPEntrySearchContext.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPEntrySearchContext.m; sourceTree = "<group>"; };
|
||||
4C0B038918E36DA400B9F9C9 /* MPFixAutotypeWindowController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPFixAutotypeWindowController.h; sourceTree = "<group>"; };
|
||||
4C0B038A18E36DA400B9F9C9 /* MPFixAutotypeWindowController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPFixAutotypeWindowController.m; sourceTree = "<group>"; };
|
||||
4C0B038B18E36DA400B9F9C9 /* FixAutotypeWindow.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = FixAutotypeWindow.xib; sourceTree = "<group>"; };
|
||||
@@ -1366,6 +1369,8 @@
|
||||
4C94A0711938DDC20040ABAB /* MPDocument+EditingSession.m */,
|
||||
4C94A06D1938DC8C0040ABAB /* MPEditSession.h */,
|
||||
4C94A06E1938DC8C0040ABAB /* MPEditSession.m */,
|
||||
4C0AF62D195C1F2B009E658D /* MPEntrySearchContext.h */,
|
||||
4C0AF62E195C1F2B009E658D /* MPEntrySearchContext.m */,
|
||||
);
|
||||
name = Model;
|
||||
sourceTree = "<group>";
|
||||
@@ -2304,6 +2309,7 @@
|
||||
4C8EB8C118D399FD00438B08 /* KPKTag.m in Sources */,
|
||||
4C94A06F1938DC8C0040ABAB /* MPEditSession.m in Sources */,
|
||||
4CFC53BF16E94729007396BE /* MPShadowBox.m in Sources */,
|
||||
4C0AF62F195C1F2B009E658D /* MPEntrySearchContext.m in Sources */,
|
||||
4C888C9316EB6F5E003D34A1 /* MPToolbarItem.m in Sources */,
|
||||
4C888C9716EB754B003D34A1 /* MPActionHelper.m in Sources */,
|
||||
4C811C8316ECD06E00C4BAC6 /* MPKeyfilePathControlDelegate.m in Sources */,
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -7,13 +7,15 @@
|
||||
//
|
||||
|
||||
#import "MPContextBarViewController.h"
|
||||
#import "HNHGradientView.h"
|
||||
#import "KPKEntry.h"
|
||||
|
||||
#import "MPDocument+HistoryBrowsing.h"
|
||||
#import "MPDocument+Search.h"
|
||||
#import "MPFlagsHelper.h"
|
||||
#import "MPEntrySearchContext.h"
|
||||
|
||||
#import "NSButton+HNHTextColor.h"
|
||||
#import "MPFlagsHelper.h"
|
||||
#import "HNHGradientView.h"
|
||||
#import "HNHCommon.h"
|
||||
|
||||
NSUInteger const MPContextBarViewControllerActiveFilterMenuItemTag = 1000;
|
||||
@@ -68,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];
|
||||
}
|
||||
|
||||
@@ -122,12 +136,29 @@ typedef NS_ENUM(NSUInteger, MPContextTab) {
|
||||
|
||||
- (void)_updateFilterButtons {
|
||||
MPDocument *document = [[self windowController] document];
|
||||
[self.duplicatePasswordsButton setState:HNHStateForBool(MPTestFlagInOptions(MPEntrySearchDoublePasswords, document.activeFlags))];
|
||||
[self.notesButton setState:HNHStateForBool(MPTestFlagInOptions(MPEntrySearchNotes, document.activeFlags))];
|
||||
[self.passwordButton setState:HNHStateForBool(MPTestFlagInOptions(MPEntrySearchPasswords, document.activeFlags))];
|
||||
[self.titleButton setState:HNHStateForBool(MPTestFlagInOptions(MPEntrySearchTitles, document.activeFlags))];
|
||||
[self.urlButton setState:HNHStateForBool(MPTestFlagInOptions(MPEntrySearchUrls, document.activeFlags))];
|
||||
[self.usernameButton setState:HNHStateForBool(MPTestFlagInOptions(MPEntrySearchUsernames, document.activeFlags))];
|
||||
MPEntrySearchFlags currentFlags = document.searchContext.searchFlags;
|
||||
[self.duplicatePasswordsButton setState:HNHStateForBool(MPTestFlagInOptions(MPEntrySearchDoublePasswords, currentFlags))];
|
||||
[self.notesButton setState:HNHStateForBool(MPTestFlagInOptions(MPEntrySearchNotes, currentFlags))];
|
||||
[self.passwordButton setState:HNHStateForBool(MPTestFlagInOptions(MPEntrySearchPasswords, currentFlags))];
|
||||
[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
|
||||
|
||||
@@ -8,6 +8,8 @@
|
||||
|
||||
#import "MPDocument.h"
|
||||
|
||||
@class MPEntrySearchContext;
|
||||
|
||||
FOUNDATION_EXTERN NSString *const MPDocumentDidEnterSearchNotification;
|
||||
FOUNDATION_EXTERN NSString *const MPDocumentDidChangeSearchFlags;
|
||||
FOUNDATION_EXTERN NSString *const MPDocumentDidExitSearchNotification;
|
||||
@@ -23,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 */
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
|
||||
#import "KPKGroup.h"
|
||||
#import "KPKEntry.h"
|
||||
#import "KPKTimeInfo.h"
|
||||
|
||||
#import "MPFlagsHelper.h"
|
||||
|
||||
@@ -26,21 +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 = 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 {
|
||||
MPDocumentWindowController *windowController = [self windowControllers][0];
|
||||
self.searchString = [windowController.searchField stringValue];
|
||||
if(NO == self.hasSearch) {
|
||||
[[NSNotificationCenter defaultCenter] postNotificationName:MPDocumentDidEnterSearchNotification object:self];
|
||||
[self enterSearchWithContext:[MPEntrySearchContext userContext]];
|
||||
return; // We get called back!
|
||||
}
|
||||
self.hasSearch = YES;
|
||||
MPDocumentWindowController *windowController = [self windowControllers][0];
|
||||
NSString *searchString = [windowController.searchField stringValue];
|
||||
self.searchContext.searchString = searchString;
|
||||
MPDocument __weak *weakSelf = self;
|
||||
dispatch_queue_t backgroundQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
|
||||
dispatch_async(backgroundQueue, ^{
|
||||
@@ -53,8 +63,9 @@ NSString *const kMPDocumentSearchResultsKey = @"kMPDocumentSearchResul
|
||||
}
|
||||
|
||||
- (void)exitSearch:(id)sender {
|
||||
self.searchString = nil;
|
||||
self.hasSearch = NO;
|
||||
[[NSNotificationCenter defaultCenter] removeObserver:self name:NSUndoManagerDidUndoChangeNotification object:self.undoManager];
|
||||
[[NSNotificationCenter defaultCenter] removeObserver:self name:NSUndoManagerDidRedoChangeNotification object:self.undoManager];
|
||||
self.searchContext = nil;
|
||||
[[NSNotificationCenter defaultCenter] postNotificationName:MPDocumentDidExitSearchNotification object:self];
|
||||
}
|
||||
|
||||
@@ -69,38 +80,43 @@ 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];
|
||||
}
|
||||
}
|
||||
|
||||
- (NSArray *)entriesMatchingSearch:(MPEntrySearchContext *)search {
|
||||
return nil;
|
||||
}
|
||||
|
||||
#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) {
|
||||
@@ -126,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];
|
||||
@@ -136,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;
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
#import "KPKVersion.h"
|
||||
#import "MPEntrySearchContext.h"
|
||||
|
||||
/**
|
||||
* Posted when a new group was added to the document.
|
||||
@@ -58,26 +59,9 @@ APPKIT_EXTERN NSString *const MPDocumentGroupKey;
|
||||
@class KPKNode;
|
||||
@class MPEditSession;
|
||||
|
||||
typedef NS_OPTIONS(NSUInteger, MPEntrySearchFlags) {
|
||||
MPEntrySearchNone = 0,
|
||||
MPEntrySearchUrls = (1<<0),
|
||||
MPEntrySearchUsernames = (1<<1),
|
||||
MPEntrySearchTitles = (1<<2),
|
||||
MPEntrySearchPasswords = (1<<3),
|
||||
MPEntrySearchNotes = (1<<4),
|
||||
MPEntrySearchAllAttributes = (1<<5),
|
||||
MPEntrySearchDoublePasswords = (1<<6), // Unused in GUI for now
|
||||
MPEntrySearchAllFlags = (MPEntrySearchDoublePasswords |
|
||||
MPEntrySearchNotes |
|
||||
MPEntrySearchPasswords |
|
||||
MPEntrySearchTitles |
|
||||
MPEntrySearchUrls |
|
||||
MPEntrySearchUsernames |
|
||||
MPEntrySearchAllAttributes )
|
||||
};
|
||||
|
||||
@interface MPDocument : NSDocument
|
||||
|
||||
|
||||
@property (nonatomic, readonly, assign) BOOL encrypted;
|
||||
@property (nonatomic, readonly, assign) NSUInteger unlockCount; // Amount of times the Document was unlocked;
|
||||
|
||||
@@ -102,9 +86,8 @@ typedef NS_OPTIONS(NSUInteger, MPEntrySearchFlags) {
|
||||
/*
|
||||
Search - see MPDocument+Search for further details
|
||||
*/
|
||||
@property (nonatomic, assign) MPEntrySearchFlags activeFlags;
|
||||
@property (nonatomic, copy) NSString *searchString;
|
||||
@property (nonatomic, assign) BOOL hasSearch;
|
||||
@property (nonatomic, readonly) BOOL hasSearch;
|
||||
@property (nonatomic, copy) MPEntrySearchContext *searchContext;
|
||||
@property (nonatomic, strong) NSArray *searchResult;
|
||||
|
||||
/*
|
||||
|
||||
@@ -123,9 +123,6 @@ NSString *const MPDocumentGroupKey = @"MPDocumentGroupKey
|
||||
_encryptedData = nil;
|
||||
_didLockFile = NO;
|
||||
_readOnly = NO;
|
||||
_activeFlags = MPEntrySearchTitles;
|
||||
_hasSearch = NO;
|
||||
_unlockCount = 0;
|
||||
self.tree = [KPKTree templateTree];
|
||||
self.tree.metaData.rounds = [[NSUserDefaults standardUserDefaults] integerForKey:kMPSettingsKeyDefaultPasswordRounds];
|
||||
}
|
||||
@@ -357,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]) {
|
||||
|
||||
56
MacPass/MPEntrySearchContext.h
Normal file
56
MacPass/MPEntrySearchContext.h
Normal file
@@ -0,0 +1,56 @@
|
||||
//
|
||||
// MPEntrySearch.h
|
||||
// MacPass
|
||||
//
|
||||
// Created by Michael Starke on 26.06.14.
|
||||
// Copyright (c) 2014 HicknHack Software GmbH. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
typedef NS_OPTIONS(NSUInteger, MPEntrySearchFlags) {
|
||||
MPEntrySearchNone = 0,
|
||||
MPEntrySearchUrls = (1<<0),
|
||||
MPEntrySearchUsernames = (1<<1),
|
||||
MPEntrySearchTitles = (1<<2),
|
||||
MPEntrySearchPasswords = (1<<3),
|
||||
MPEntrySearchNotes = (1<<4),
|
||||
MPEntrySearchAllAttributes = (1<<5),
|
||||
/* 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 |
|
||||
MPEntrySearchPasswords |
|
||||
MPEntrySearchTitles |
|
||||
MPEntrySearchUrls |
|
||||
MPEntrySearchUsernames |
|
||||
MPEntrySearchAllAttributes )
|
||||
};
|
||||
|
||||
|
||||
/* Wrap serach criteria to be able to store them */
|
||||
@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 (nonatomic, assign) NSInteger searchFlags;
|
||||
@property (nonatomic, copy) NSString *searchString;
|
||||
|
||||
@end
|
||||
82
MacPass/MPEntrySearchContext.m
Normal file
82
MacPass/MPEntrySearchContext.m
Normal file
@@ -0,0 +1,82 @@
|
||||
//
|
||||
// MPEntrySearch.m
|
||||
// MacPass
|
||||
//
|
||||
// Created by Michael Starke on 26.06.14.
|
||||
// Copyright (c) 2014 HicknHack Software GmbH. All rights reserved.
|
||||
//
|
||||
|
||||
#import "MPEntrySearchContext.h"
|
||||
#import "MPSettingsHelper.h"
|
||||
|
||||
@implementation MPEntrySearchContext
|
||||
|
||||
+ (BOOL)supportsSecureCoding {
|
||||
return YES;
|
||||
}
|
||||
|
||||
+ (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:MPEntrySearchTitles|MPEntrySearchUsernames];
|
||||
return self;
|
||||
}
|
||||
|
||||
- (instancetype)initWithString:(NSString *)searchString flags:(MPEntrySearchFlags)flags {
|
||||
self = [super init];
|
||||
if(self) {
|
||||
self.searchFlags = flags;
|
||||
self.searchString = searchString;
|
||||
}
|
||||
return self;
|
||||
|
||||
}
|
||||
|
||||
#pragma mark NSSecureCoding
|
||||
- (void)encodeWithCoder:(NSCoder *)aCoder {
|
||||
[aCoder encodeInteger:self.searchFlags forKey:NSStringFromSelector(@selector(searchFlags))];
|
||||
[aCoder encodeObject:self.searchString forKey:NSStringFromSelector(@selector(searchString))];
|
||||
}
|
||||
|
||||
- (instancetype)initWithCoder:(NSCoder *)aDecoder {
|
||||
self = [self init];
|
||||
self.searchString = [aDecoder decodeObjectOfClass:[NSString class] forKey:NSStringFromSelector(@selector(searchString))];
|
||||
self.searchFlags = [aDecoder decodeIntegerForKey:NSStringFromSelector(@selector(searchFlags))];
|
||||
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
|
||||
@@ -51,7 +51,7 @@ APPKIT_EXTERN NSString *const kMPSettingsKeyEnableGlobalAutotype; //
|
||||
APPKIT_EXTERN NSString *const kMPSettingsKeyGlobalAutotypeKeyDataKey; // The stored Data for the useder defined global autotype key
|
||||
|
||||
/* Search */
|
||||
APPKIT_EXTERN NSString *const kMPSettingsKeyEntrySearchFilterMode;
|
||||
APPKIT_EXTERN NSString *const kMPSettingsKeyEntrySearchFilterContext;
|
||||
|
||||
/* Quicklook */
|
||||
APPKIT_EXTERN NSString *const kMPSettingsKeyEnableQuicklookPreview;
|
||||
|
||||
@@ -37,7 +37,7 @@ NSString *const kMPSettingsKeySendCommandForControlKey = @"SendCo
|
||||
NSString *const kMPSettingsKeyEnableGlobalAutotype = @"EnableGlobalAutotype";
|
||||
NSString *const kMPSettingsKeyGlobalAutotypeKeyDataKey = @"GlobalAutotypeKeyDataKey";
|
||||
|
||||
NSString *const kMPSettingsKeyEntrySearchFilterMode = @"EntrySearchFilterMode";
|
||||
NSString *const kMPSettingsKeyEntrySearchFilterContext = @"EntrySearchFilterContext";
|
||||
|
||||
NSString *const kMPSettingsKeyEnableQuicklookPreview = @"EnableQuicklookPreview";
|
||||
|
||||
@@ -57,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
|
||||
|
||||
@@ -67,6 +68,7 @@ NSString *const kMPDeprecatedSettingsKeyDoubleClickURLToLaunch = @"Do
|
||||
+ (void)migrateDefaults {
|
||||
[self _fixEntryTableSortDescriptors];
|
||||
[self _migrateURLDoubleClickPreferences];
|
||||
[self _migrateEntrySearchFlags];
|
||||
[self _removeDeprecatedValues];
|
||||
}
|
||||
|
||||
@@ -96,7 +98,6 @@ NSString *const kMPDeprecatedSettingsKeyDoubleClickURLToLaunch = @"Do
|
||||
kMPSettingsKeyLegacyHideUsername: @NO,
|
||||
kMPSettingsKeyRememberKeyFilesForDatabases: @NO,
|
||||
kMPSettingsKeySendCommandForControlKey: @YES,
|
||||
kMPSettingsKeyEntrySearchFilterMode: @0,
|
||||
kMPSettingsKeyEnableGlobalAutotype: @NO,
|
||||
kMPSettingsKeyEnableQuicklookPreview: @NO,
|
||||
kMPSettingsKeyCopyGeneratedPasswordToClipboard: @NO,
|
||||
@@ -119,7 +120,8 @@ NSString *const kMPDeprecatedSettingsKeyDoubleClickURLToLaunch = @"Do
|
||||
deprecatedSettings = @[ kMPDeprecatedSettingsKeyRememberKeyFilesForDatabases,
|
||||
kMPDeprecatedSettingsKeyLastDatabasePath,
|
||||
kMPDeprecatedSettingsKeyDocumentsAutotypeFixNoteWasShown,
|
||||
kMPDeprecatedSettingsKeyDoubleClickURLToLaunch ];
|
||||
kMPDeprecatedSettingsKeyDoubleClickURLToLaunch,
|
||||
kMPDeprecatedSettingsKeyEntrySearchFilterMode];
|
||||
});
|
||||
return deprecatedSettings;
|
||||
}
|
||||
@@ -159,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