mirror of
https://github.com/objective-see/TaskExplorer.git
synced 2026-03-22 07:02:39 +00:00
added auto-complete keyword logic to main search window
This commit is contained in:
+7
-7
@@ -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
@@ -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
|
||||
{
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -16,4 +16,7 @@
|
||||
|
||||
}
|
||||
|
||||
//'owner'
|
||||
@property (nonatomic, retain)id owner;
|
||||
|
||||
@end
|
||||
|
||||
+4
-2
@@ -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
|
||||
|
||||
@@ -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
@@ -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
@@ -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;
|
||||
}
|
||||
|
||||
BIN
Binary file not shown.
+15
-31
@@ -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
@@ -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>
|
||||
|
||||
@@ -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">
|
||||
|
||||
Reference in New Issue
Block a user