|
| 1 | +#import "SSYSpotlighter.h" |
| 2 | + |
| 3 | +@interface SSYSpotlighter () |
| 4 | + |
| 5 | +@property (copy) NSString* searchKey ; |
| 6 | +@property (assign) NSObject <SSYSpotlighterDelegate> * delegate ; |
| 7 | +@property (retain) NSMetadataQuery *query; |
| 8 | + |
| 9 | +@end |
| 10 | + |
| 11 | + |
| 12 | +@implementation SSYSpotlighter |
| 13 | + |
| 14 | +@synthesize searchKey = m_searchKey ; |
| 15 | +@synthesize delegate = m_delegate ; |
| 16 | +@synthesize query = m_query ; |
| 17 | + |
| 18 | + |
| 19 | +- (id)initWithSearchKey:(NSString*)searchKey |
| 20 | + delegate:(NSObject <SSYSpotlighterDelegate> *)delegate { |
| 21 | + self = [super init] ; |
| 22 | + if (self) { |
| 23 | + [self setSearchKey:searchKey] ; |
| 24 | + [self setDelegate:delegate] ; |
| 25 | + } |
| 26 | + |
| 27 | + return self ; |
| 28 | +} |
| 29 | + |
| 30 | +- (void)dealloc { |
| 31 | + [[NSNotificationCenter defaultCenter] removeObserver:self] ; |
| 32 | + [m_query removeObserver:self |
| 33 | + forKeyPath:@"results"] ; |
| 34 | + |
| 35 | + [m_searchKey release] ; |
| 36 | + [m_query release] ; |
| 37 | + |
| 38 | + [super dealloc] ; |
| 39 | +} |
| 40 | + |
| 41 | +- (void)observeValueForKeyPath:(NSString *)keyPath |
| 42 | + ofObject:(id)object |
| 43 | + change:(NSDictionary *)change |
| 44 | + context:(void *)context { |
| 45 | + NSUInteger currentResultsCount = [[self query] resultCount] ; |
| 46 | + NSMutableArray* newPaths = [[NSMutableArray alloc] init] ; |
| 47 | + for (NSUInteger i=m_resultsAlreadyReported; i<currentResultsCount; i++) { |
| 48 | + NSString* path = [[[self query] resultAtIndex:i] valueForKey:(NSString*)kMDItemPath] ; |
| 49 | + // Defensive programming |
| 50 | + if (path) { |
| 51 | + [newPaths addObject:path] ; |
| 52 | + } |
| 53 | + } |
| 54 | + NSArray* answer = [newPaths copy] ; |
| 55 | + [newPaths release] ; |
| 56 | + [[self delegate] spotlighter:self |
| 57 | + didFindPaths:answer] ; |
| 58 | + [answer release] ; |
| 59 | + |
| 60 | + m_resultsAlreadyReported = currentResultsCount ; |
| 61 | +} |
| 62 | + |
| 63 | +- (void)queryNote:(NSNotification *)note { |
| 64 | + if ([[note name] isEqualToString:NSMetadataQueryDidFinishGatheringNotification]) { |
| 65 | + [[self query] stopQuery] ; |
| 66 | + [[self delegate] didFinishSpotlighter:self] ; |
| 67 | + } |
| 68 | +} |
| 69 | + |
| 70 | +- (void)start { |
| 71 | + if (![[NSThread currentThread] isMainThread]) { |
| 72 | + NSLog(@"SSYSpotlighter-NSMetadataQuery started on non-main thread. This will not work.") ; |
| 73 | + return ; |
| 74 | + } |
| 75 | + NSMetadataQuery* query = [[[NSMetadataQuery alloc] init] autorelease] ; |
| 76 | + [self setQuery:query] ; |
| 77 | + |
| 78 | + [[NSNotificationCenter defaultCenter] addObserver:self |
| 79 | + selector:@selector(queryNote:) |
| 80 | + name:nil |
| 81 | + object:[self query]] ; |
| 82 | + |
| 83 | + [query addObserver:self |
| 84 | + forKeyPath:@"results" |
| 85 | + options:0 |
| 86 | + context:NULL] ; |
| 87 | + |
| 88 | + // Create a compound predicate that searches for any keypath which has a value like the search key. This broadens the search results to include things such as the author, title, and other attributes not including the content. This is done in code for two reasons: 1. The predicate parser does not yet support "* = Foo" type of parsing, and 2. It is an example of creating a predicate in code, which is much "safer" than using a search string. |
| 89 | + NSUInteger options = (NSCaseInsensitivePredicateOption|NSDiacriticInsensitivePredicateOption) ; |
| 90 | + NSPredicate *pred = [NSComparisonPredicate |
| 91 | + predicateWithLeftExpression:[NSExpression expressionForKeyPath:@"*"] |
| 92 | + rightExpression:[NSExpression expressionForConstantValue:[self searchKey]] |
| 93 | + modifier:NSDirectPredicateModifier |
| 94 | + type:NSLikePredicateOperatorType |
| 95 | + options:options] ; |
| 96 | + |
| 97 | + // Exclude email messages and contacts |
| 98 | + NSPredicate* exclusionPredicate = [NSPredicate predicateWithFormat:@"(kMDItemContentType != 'com.apple.mail.emlx') && (kMDItemContentType != 'public.vcard')"]; |
| 99 | + pred = [NSCompoundPredicate andPredicateWithSubpredicates:[NSArray arrayWithObjects: |
| 100 | + pred, |
| 101 | + exclusionPredicate, |
| 102 | + nil]] ; |
| 103 | + |
| 104 | + [query setPredicate:pred] ; |
| 105 | + [query startQuery] ; |
| 106 | +} |
| 107 | + |
| 108 | +@end |
0 commit comments