added auto-complete keyword logic to main search window

This commit is contained in:
Patrick Wardle
2015-09-01 21:31:43 -10:00
parent c813cc583d
commit efa77f89b8
12 changed files with 244 additions and 60 deletions
+7 -7
View File
@@ -159,22 +159,22 @@
@property(nonatomic, retain)NSLayoutConstraint* trailingConstraint;
//remote XPC interface
@property(nonatomic, retain) NSXPCConnection* xpcConnection;
@property(nonatomic, retain)NSXPCConnection* xpcConnection;
//flagged items
@property(nonatomic, retain) NSMutableArray* flaggedItems;
//array of autocomplete keywords
//@property NSMutableArray *builtInKeywords;
@property(nonatomic, retain)NSMutableArray* flaggedItems;
//flag for filter field (autocomplete)
@property BOOL completePosting;
//flag for filter field (autocomplete)
@property BOOL commandHandling;
//custom search field for tasks
@property CustomTextField* customTasksFilter;
@property(nonatomic, retain)CustomTextField* customTasksFilter;
//custom search field for items
@property CustomTextField* customItemsFilter;
@property(nonatomic, retain)CustomTextField* customItemsFilter;
/* METHODS */
+6 -1
View File
@@ -109,9 +109,15 @@
//alloc/init custom search field for tasks
customTasksFilter = [[CustomTextField alloc] init];
//set owner
self.customTasksFilter.owner = self;
//alloc/init custom search field for items
customItemsFilter = [[CustomTextField alloc] init];
//set owner
self.customItemsFilter.owner = self;
//set field editor for tasks
[self.customTasksFilter setFieldEditor:YES];
@@ -880,7 +886,6 @@ bail:
return;
}
//display alert about OS not being supported
-(void)showUnsupportedAlert
{
+2 -1
View File
@@ -304,8 +304,9 @@
//delta for pid tag
#define PID_TAG_DELTA 1000
//TODO: CHANGE B4 RELEASE
//search wait time (from app's launch)
#define SEARCH_WAIT_TIME 30
#define SEARCH_WAIT_TIME 1
//pls wait (search) message
#define PLS_WAIT_MESSAGE @"completing (intial) task/dylib/file enumeration please wait"
+3
View File
@@ -16,4 +16,7 @@
}
//'owner'
@property (nonatomic, retain)id owner;
@end
+4 -2
View File
@@ -11,6 +11,7 @@
@implementation CustomTextField
@synthesize owner;
//subclass override
// ->see: http://stackoverflow.com/questions/5163646/how-to-make-nssearchfield-send-action-upon-autocompletion/5360535#5360535
@@ -41,8 +42,9 @@
// ->call up into app delegate to process (filter)
if(movement == NSReturnTextMovement)
{
//call up//filterAutoComplete
[((AppDelegate*)[[NSApplication sharedApplication] delegate]) filterAutoComplete:self];
//call up into owner to process
[owner filterAutoComplete:self];
//[((AppDelegate*)[[NSApplication sharedApplication] delegate]) filterAutoComplete:self];
}
//bail
+13 -6
View File
@@ -8,16 +8,12 @@
#import <Cocoa/Cocoa.h>
#import "CustomTextField.h"
#import "InfoWindowController.h"
#import "VTInfoWindowController.h"
@interface SearchWindowController : NSWindowController
//automatically invoked when user presses 'Enter' in search box
// ->search!
-(IBAction)search:(id)sender;
@interface SearchWindowController : NSWindowController <NSWindowDelegate>
//PROPERTIES
@@ -54,6 +50,14 @@
//overlay view
@property (weak) IBOutlet NSView *overlayView;
//flag for filter field (autocomplete)
@property BOOL completePosting;
//flag for filter field (autocomplete)
@property BOOL commandHandling;
//custom search field
@property (nonatomic, retain)CustomTextField* customSearchField;
/* METHODS */
@@ -62,5 +66,8 @@
// ->make sure everything is cleanly init'd
-(void)prepare;
//search
-(void)search;
@end
+177 -7
View File
@@ -28,6 +28,9 @@
@synthesize searchTable;
@synthesize searchResults;
@synthesize plsWaitMessage;
@synthesize commandHandling;
@synthesize completePosting;
@synthesize customSearchField;
@synthesize vtWindowController;
@synthesize infoWindowController;
@@ -59,6 +62,12 @@
//init array for search results
searchResults = [NSMutableArray array];
//alloc/init custom search field for items
customSearchField = [[CustomTextField alloc] init];
//set owner
self.customSearchField.owner = self;
//first time outlets are nil
// ->thus 'initUI' method called in 'awakeFromNib'
if(nil != self.window)
@@ -204,7 +213,6 @@
self.activityIndicatorLabel.stringValue = [NSString stringWithFormat:@"%@ (%d)", PLS_WAIT_MESSAGE, (int)timeRemaining];
});
}
//update UI on main thread
@@ -231,6 +239,164 @@
return;
}
//automatically invoked when user enters text in filter search boxes
// ->filter tasks and/or items
-(void)controlTextDidChange:(NSNotification *)aNotification
{
//prevent calling "complete" too often
if( (YES != self.completePosting) &&
(YES != self.commandHandling) )
{
//set flag
self.completePosting = YES;
//invoke complete
[aNotification.userInfo[@"NSFieldEditor"] complete:nil];
//unset flag
self.completePosting = NO;
}
return;
}
//delegate method, automatically called
// ->generate list of matches to return for drop-down
-(NSArray *)control:(NSControl *)control textView:(NSTextView *)textView completions:(NSArray *)words forPartialWordRange:(NSRange)charRange indexOfSelectedItem:(NSInteger *)index
{
//matches
NSMutableArray *matches = nil;
//range options
NSUInteger rangeOptions = {0};
//init array for matches
matches = [[NSMutableArray alloc] init];
//init range options
rangeOptions = NSAnchoredSearch | NSCaseInsensitiveSearch;
//check all filters
// note: really check Binary ones, but this should include all!
for(NSString* filter in self.filterObj.binaryFilters)
{
//check if found
// ->add to match when found
if([filter rangeOfString:textView.string options:rangeOptions range:NSMakeRange(0, filter.length)].location != NSNotFound)
{
//add
[matches addObject:filter];
}
}
//sort matches
[matches sortUsingComparator:^(NSString *a, NSString *b)
{
//sort
return [a localizedStandardCompare:b];
}];
//bail
bail:
return matches;
}
//delegate method, automatically invoked
// ->handle invocations for text view
- (BOOL)control:(NSControl *)control textView:(NSTextView *)textView doCommandBySelector:(SEL)commandSelector
{
//flag
BOOL didPerformRequestedSelectorOnTextView = NO;
//invocation
NSInvocation *textViewInvocationForSelector = nil;
//check if text view can handle selector
if(YES != [textView respondsToSelector:commandSelector])
{
//bail
goto bail;
}
//first handle 'enter'
// ->trigger a search
if(commandSelector == @selector(insertNewline:))
{
//search
[self search];
}
//handle all others
else
{
//set iVar flag
self.commandHandling = YES;
//init invocation
textViewInvocationForSelector = [NSInvocation invocationWithMethodSignature:[textView methodSignatureForSelector:commandSelector]];
//set target
[textViewInvocationForSelector setTarget:textView];
//set selector
[textViewInvocationForSelector setSelector:commandSelector];
//invoke selector
[textViewInvocationForSelector invoke];
//unset iVar
self.commandHandling = NO;
}
//indicate that selector was performed
didPerformRequestedSelectorOnTextView = YES;
//bail
bail:
return didPerformRequestedSelectorOnTextView;
}
//callback for custom search fields
// ->handle auto-complete filterings
-(void)filterAutoComplete:(NSTextView*)textView
{
//just call search method
// ->has logic to handle searching
[self search];
return;
}
//automatically invoked
// ->set all NSSearchFields to be instances of our custom NSTextView
-(id)windowWillReturnFieldEditor:(NSWindow *)sender toObject:(id)client
{
//field editor
id fieldEditor = nil;
//ignore non-NSSearchField classes
if(YES != [client isKindOfClass:[NSTextField class]])
{
//ingnore
goto bail;
}
//set task's filter search field
if(client == self.searchBox)
{
//assign for return
fieldEditor = self.customSearchField;
}
//bail
bail:
return fieldEditor;
}
//table delegate
// ->return number of rows
-(NSInteger)numberOfRowsInTableView:(NSTableView *)tableView
@@ -314,9 +480,10 @@ bail:
return;
}
//automatically invoked when user presses 'Enter' in search box
// ->search!
-(IBAction)search:(id)sender
//search
//TODO: SYNC DYLIBS etc
//TODO: search network conns
-(void)search
{
//search string
NSString* searchString = nil;
@@ -359,7 +526,7 @@ bail:
[self.searchTable reloadData];
//grab search string
searchString = [sender stringValue];
searchString = [self.searchBox stringValue];
//grab all tasks
allTasks = ((AppDelegate*)[[NSApplication sharedApplication] delegate]).taskEnumerator.tasks;
@@ -374,8 +541,8 @@ bail:
//ignore
goto bail;
}
}
}
//1st: search for all matching tasks
//sync
@synchronized(allTasks)
@@ -397,6 +564,7 @@ bail:
@synchronized(allTasks)
{
//TODO: B4 RELEASE! SYNC DYLIBS ARRAY!!!
//walk all tasks
// ->scan each for dylib matches, only processing first match
for(NSNumber* taskPid in allTasks)
@@ -471,6 +639,8 @@ bail:
//refresh table to display dylib
[self.searchTable reloadData];
//TODO: search network conns
//bail
bail:
+14 -1
View File
@@ -206,7 +206,20 @@
[NSThread sleepForTimeInterval:0.01f];
}
//TODO: add network connection filtering
//begin network enumeration
// ->for search view
for(NSNumber* key in newTasks)
{
//get task
newTask = newTasks[key];
//enumerate
[newTask enumerateNetworking:xpcConnection];
//nap
// ->helps with UI
[NSThread sleepForTimeInterval:0.01f];
}
return;
}
@@ -3,22 +3,6 @@
type = "1"
version = "2.0">
<Breakpoints>
<BreakpointProxy
BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
<BreakpointContent
shouldBeEnabled = "No"
ignoreCount = "0"
continueAfterRunningActions = "No"
filePath = "SearchWindowController.m"
timestampString = "462088083.337679"
startingColumnNumber = "9223372036854775807"
endingColumnNumber = "9223372036854775807"
startingLineNumber = "319"
endingLineNumber = "319"
landmarkName = "-search:"
landmarkType = "5">
</BreakpointContent>
</BreakpointProxy>
<BreakpointProxy
BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
<BreakpointContent
@@ -90,11 +74,11 @@
ignoreCount = "0"
continueAfterRunningActions = "No"
filePath = "SearchWindowController.m"
timestampString = "462088083.337679"
timestampString = "462871273.447907"
startingColumnNumber = "9223372036854775807"
endingColumnNumber = "9223372036854775807"
startingLineNumber = "183"
endingLineNumber = "183"
startingLineNumber = "196"
endingLineNumber = "196"
landmarkName = "-waitTillPau"
landmarkType = "5">
</BreakpointContent>
@@ -122,11 +106,11 @@
ignoreCount = "0"
continueAfterRunningActions = "No"
filePath = "AppDelegate.m"
timestampString = "462785295.692202"
timestampString = "462870109.066579"
startingColumnNumber = "9223372036854775807"
endingColumnNumber = "9223372036854775807"
startingLineNumber = "1537"
endingLineNumber = "1537"
startingLineNumber = "1544"
endingLineNumber = "1544"
landmarkName = "-selectBottomPaneContent:"
landmarkType = "5">
</BreakpointContent>
@@ -186,11 +170,11 @@
ignoreCount = "0"
continueAfterRunningActions = "No"
filePath = "AppDelegate.m"
timestampString = "462695042.305349"
timestampString = "462870109.066579"
startingColumnNumber = "9223372036854775807"
endingColumnNumber = "9223372036854775807"
startingLineNumber = "206"
endingLineNumber = "206"
startingLineNumber = "214"
endingLineNumber = "214"
landmarkName = "-registerKeypressHandler"
landmarkType = "5">
</BreakpointContent>
@@ -202,11 +186,11 @@
ignoreCount = "0"
continueAfterRunningActions = "No"
filePath = "AppDelegate.m"
timestampString = "462695042.305349"
timestampString = "462870109.066579"
startingColumnNumber = "9223372036854775807"
endingColumnNumber = "9223372036854775807"
startingLineNumber = "223"
endingLineNumber = "223"
startingLineNumber = "231"
endingLineNumber = "231"
landmarkName = "-handleKeypress:"
landmarkType = "5">
</BreakpointContent>
@@ -218,11 +202,11 @@
ignoreCount = "0"
continueAfterRunningActions = "No"
filePath = "AppDelegate.m"
timestampString = "462695042.305349"
timestampString = "462870109.066579"
startingColumnNumber = "9223372036854775807"
endingColumnNumber = "9223372036854775807"
startingLineNumber = "244"
endingLineNumber = "244"
startingLineNumber = "252"
endingLineNumber = "252"
landmarkName = "-handleKeypress:"
landmarkType = "5">
</BreakpointContent>
+2 -3
View File
@@ -21,7 +21,7 @@
<windowStyleMask key="styleMask" titled="YES" closable="YES" miniaturizable="YES" resizable="YES"/>
<windowPositionMask key="initialPositionMask" leftStrut="YES" rightStrut="YES" topStrut="YES" bottomStrut="YES"/>
<rect key="contentRect" x="95" y="481" width="1304" height="425"/>
<rect key="screenRect" x="0.0" y="0.0" width="1920" height="1057"/>
<rect key="screenRect" x="0.0" y="0.0" width="1440" height="877"/>
<value key="minSize" type="size" width="800" height="250"/>
<view key="contentView" id="se5-gp-TjO">
<rect key="frame" x="0.0" y="3" width="1304" height="425"/>
@@ -393,13 +393,12 @@
</scrollView>
<textField verticalHuggingPriority="750" ambiguous="YES" misplaced="YES" translatesAutoresizingMaskIntoConstraints="NO" id="BB9-Xc-q8T">
<rect key="frame" x="20" y="372" width="1264" height="42"/>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" selectable="YES" editable="YES" state="on" borderStyle="bezel" placeholderString="type search term, then press enter" drawsBackground="YES" id="L1f-RR-fvk">
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" selectable="YES" editable="YES" state="on" borderStyle="bezel" placeholderString="type search term, then press enter" drawsBackground="YES" usesSingleLineMode="YES" id="L1f-RR-fvk">
<font key="font" metaFont="system" size="30"/>
<color key="textColor" name="textColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
<connections>
<action selector="search:" target="-2" id="HSs-Yg-DG8"/>
<outlet property="delegate" destination="-2" id="X2H-Xx-qgK"/>
</connections>
</textField>
+1 -1
View File
@@ -41,7 +41,7 @@
<window allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" releasedWhenClosed="NO" showsToolbarButton="NO" animationBehavior="default" id="371">
<windowStyleMask key="styleMask" titled="YES" closable="YES" miniaturizable="YES" resizable="YES" unifiedTitleAndToolbar="YES"/>
<rect key="contentRect" x="0.0" y="0.0" width="1354" height="665"/>
<rect key="screenRect" x="0.0" y="0.0" width="1920" height="1057"/>
<rect key="screenRect" x="0.0" y="0.0" width="1440" height="877"/>
<value key="minSize" type="size" width="1000" height="660"/>
<value key="maxSize" type="size" width="2000" height="660"/>
<view key="contentView" id="372">