From 70ae3cec1c4cda3ae9b4c7ae2ff40191f7f19549 Mon Sep 17 00:00:00 2001 From: matthewleon Date: Thu, 14 Feb 2008 17:48:32 +0000 Subject: [PATCH] Spotlight can do exact searches using quotation marks, IE %a"tom waits" will do a case insensitive search for all music by Tom Waits --- .../NSComparisonPredicate+CogPredicate.h | 4 +- .../NSComparisonPredicate+CogPredicate.m | 13 ++-- Spotlight/SpotlightWindowController.m | 68 ++++++++++++++++--- 3 files changed, 69 insertions(+), 16 deletions(-) diff --git a/Spotlight/NSComparisonPredicate+CogPredicate.h b/Spotlight/NSComparisonPredicate+CogPredicate.h index 60512b738..454eaa5c2 100644 --- a/Spotlight/NSComparisonPredicate+CogPredicate.h +++ b/Spotlight/NSComparisonPredicate+CogPredicate.h @@ -11,6 +11,8 @@ @interface NSComparisonPredicate (CogPredicate) -+ (NSPredicate *)predicateForMdKey:(NSString *)key withString:(NSString *)aString; ++ (NSPredicate*)predicateForMdKey:(NSString*)key + withString:(NSString*)aString + exactString:(BOOL)exactString; @end diff --git a/Spotlight/NSComparisonPredicate+CogPredicate.m b/Spotlight/NSComparisonPredicate+CogPredicate.m index 4d7bb2aea..62ed1931a 100644 --- a/Spotlight/NSComparisonPredicate+CogPredicate.m +++ b/Spotlight/NSComparisonPredicate+CogPredicate.m @@ -14,15 +14,20 @@ static const unsigned OPTIONS = (NSCaseInsensitivePredicateOption| @implementation NSComparisonPredicate (CogPredicate) -+ (NSPredicate *)predicateForMdKey:(NSString *)key withString:(NSString *)aString ++ (NSPredicate*)predicateForMdKey:(NSString *)key + withString:(NSString *)aString + exactString:(BOOL)exactString { - NSString * likeString = [NSString stringWithFormat:@"*%@*", aString]; + // We don't want an exact string, so wrap it in wildcards + if(!exactString) + aString = [NSString stringWithFormat:@"*%@*", aString]; + return [NSComparisonPredicate predicateWithLeftExpression:[NSExpression expressionForKeyPath:key] - rightExpression:[NSExpression expressionForConstantValue:likeString] + rightExpression:[NSExpression expressionForConstantValue:aString] modifier:NSDirectPredicateModifier type:NSLikePredicateOperatorType options:OPTIONS]; } -@end +@end \ No newline at end of file diff --git a/Spotlight/SpotlightWindowController.m b/Spotlight/SpotlightWindowController.m index 5d1d76664..d05acea0f 100644 --- a/Spotlight/SpotlightWindowController.m +++ b/Spotlight/SpotlightWindowController.m @@ -81,49 +81,95 @@ static NSPredicate * musicOnlyPredicate = nil; NSMutableArray *subpredicates = [NSMutableArray arrayWithCapacity:10]; NSScanner *scanner = [NSScanner scannerWithString:self.searchString]; - + BOOL exactString; + NSString * scannedString; + NSMutableString * parsingString; while (![scanner isAtEnd]) { - NSString *scannedString; + exactString = NO; if ([scanner scanUpToString:@" " intoString:&scannedString]) { if ([scannedString length] < MINIMUM_SEARCH_STRING_LENGTH) continue; - if ([scannedString characterAtIndex:0] == '%') + // We use NSMutableString because this string will get abused a bit + // It potentially could be reading the entire search string + + parsingString = [NSMutableString stringWithCapacity: [self.searchString length]]; + [parsingString setString: scannedString]; + + + if ([parsingString characterAtIndex:0] == '%') { - if ([scannedString length] < (MINIMUM_SEARCH_STRING_LENGTH + 2)) + if ([parsingString length] < (MINIMUM_SEARCH_STRING_LENGTH + 2)) continue; + + if ([parsingString characterAtIndex:2] == '\"') + { + exactString = YES; + // If the string does not end in a quotation mark and we're not at the end, + // scan until we find one. + // Allows strings within quotation marks to include spaces + if ([parsingString characterAtIndex:([parsingString length] - 1)] != '\"' && + ![scanner isAtEnd]) + { + NSString *restOfString; + [scanner scanUpToString:@"\"" intoString:&restOfString]; + [parsingString appendFormat:@" %@", restOfString]; + } + else if ([parsingString characterAtIndex:([parsingString length] - 1)] == '\"') + { + // pick off the quotation mark at the end + [parsingString deleteCharactersInRange: + NSMakeRange([parsingString length] - 1, 1)]; + + } + // eliminate beginning quotation mark + [parsingString deleteCharactersInRange: NSMakeRange(2, 1)]; + } // Search for artist - if([scannedString characterAtIndex:1] == 'a') + if([parsingString characterAtIndex:1] == 'a') { [subpredicates addObject: [NSComparisonPredicate predicateForMdKey:@"kMDItemAuthors" - withString:[scannedString substringFromIndex:2]]]; + withString:[parsingString substringFromIndex:2] + exactString:exactString]]; } // Search for album - if([scannedString characterAtIndex:1] == 'l') + if([parsingString characterAtIndex:1] == 'l') { [subpredicates addObject: [NSComparisonPredicate predicateForMdKey:@"kMDItemAlbum" - withString:[scannedString substringFromIndex:2]]]; + withString:[parsingString substringFromIndex:2] + exactString:exactString]]; } // Search for title - if([scannedString characterAtIndex:1] == 't') + if([parsingString characterAtIndex:1] == 't') { [subpredicates addObject: [NSComparisonPredicate predicateForMdKey:@"kMDItemTitle" - withString:[scannedString substringFromIndex:2]]]; + withString:[parsingString substringFromIndex:2] + exactString:exactString]]; + } + + // Search for genre + if([parsingString characterAtIndex:1] == 'g') + { + [subpredicates addObject: + [NSComparisonPredicate predicateForMdKey:@"kMDItemMusicalGenre" + withString:[parsingString substringFromIndex:2] + exactString:exactString]]; } } else { [subpredicates addObject: [NSComparisonPredicate predicateForMdKey:@"*" - withString:scannedString]]; + withString:parsingString + exactString:exactString]]; } } }