adium 3353:91b268e34c44: Implementation of ticket #14354: Contac...

commits at adium.im commits at adium.im
Sun Oct 10 22:25:08 UTC 2010


details:	http://hg.adium.im/adium/rev/91b268e34c44
revision:	3353:91b268e34c44
author:		Paul Vet <original.roju at gmail.com>
date:		Sat Oct 09 20:47:43 2010 -0400

Implementation of ticket #14354: Contact list search should treat whitespace-separated words as keywords

Instead of searching contacts for the literal string, break it on word boundaries and search for contacts containing all of the keywords. Allows for quick searches, e.g. searching for Jonathan Dovercourt is as simple as "Jo Do".
Subject: adium 3354:4c1ce49f878c: Implementation of ticket #14354: Contact list search should treat whitespace-separated words as keywords

details:	http://hg.adium.im/adium/rev/4c1ce49f878c
revision:	3354:4c1ce49f878c
author:		Paul Vet <original.roju at gmail.com>
date:		Sun Oct 10 11:27:15 2010 -0400

Implementation of ticket #14354: Contact list search should treat whitespace-separated words as keywords

Instead of searching contacts for the literal string, break it on word boundaries and search for contacts containing all of the keywords. Allows for quick searches, e.g. searching for Jonathan Dovercourt is as simple as "Jo Do".

Fixed memory management critiques by xnyhps and put in an explanitory comment for the choice of using CFStringTokenizer.

diffs (80 lines):

diff -r 4e63449cae1f -r 4c1ce49f878c Copyright.txt
--- a/Copyright.txt	Wed Oct 06 22:44:19 2010 +0200
+++ b/Copyright.txt	Sun Oct 10 11:27:15 2010 -0400
@@ -91,6 +91,7 @@
 Mike Timm
 Wesley Underwood
 Vinay Venkatesh
+Paul Vet
 Brion Vibber
 Matt Watson
 Zachary West
diff -r 4e63449cae1f -r 4c1ce49f878c Frameworks/Adium Framework/Source/AIContactHidingController.h
--- a/Frameworks/Adium Framework/Source/AIContactHidingController.h	Wed Oct 06 22:44:19 2010 +0200
+++ b/Frameworks/Adium Framework/Source/AIContactHidingController.h	Sun Oct 10 11:27:15 2010 -0400
@@ -44,4 +44,5 @@
 @property (readonly, nonatomic) NSString *contactFilteringSearchString;
 - (BOOL)filterContacts:(NSString *)inSearchString;
 - (BOOL)visibilityOfListObject:(AIListObject *)listObject inContainer:(id<AIContainingObject>)container;
+- (NSPredicate*) createPredicateWithSearchString: (NSString *) inSearchString;
 @end
diff -r 4e63449cae1f -r 4c1ce49f878c Frameworks/Adium Framework/Source/AIContactHidingController.m
--- a/Frameworks/Adium Framework/Source/AIContactHidingController.m	Wed Oct 06 22:44:19 2010 +0200
+++ b/Frameworks/Adium Framework/Source/AIContactHidingController.m	Sun Oct 10 11:27:15 2010 -0400
@@ -51,7 +51,7 @@
 		matchedContacts = [[NSMutableDictionary alloc] init];
 		
 		// contains[cd] - c = case insensitive, d = diacritic insensitive
-		filterPredicateTemplate = [[NSPredicate predicateWithFormat:@"displayName contains[cd] $SEARCH_STRING OR formattedUID contains[cd] $SEARCH_STRING OR uid contains[cd] $SEARCH_STRING"] retain];
+		filterPredicateTemplate = [[NSPredicate predicateWithFormat:@"displayName contains[cd] $KEYWORD OR formattedUID contains[cd] $KEYWORD OR uid contains[cd] $KEYWORD"] retain];
 	}
 	return self;
 }
@@ -200,7 +200,7 @@
 		return YES;
 	
 	if (!filterPredicate)
-		filterPredicate = [[filterPredicateTemplate predicateWithSubstitutionVariables:[NSDictionary dictionaryWithObject:inSearchString forKey:@"SEARCH_STRING"]] retain];
+		filterPredicate = [[self createPredicateWithSearchString:inSearchString] retain];
 	
 	// If the given contact is a meta contact, check all of its contained objects.
 	if ([listObject conformsToProtocol:@protocol(AIContainingObject)]) {
@@ -216,4 +216,38 @@
 	}
 }
 
+/*!
+ * @brief Generate a predicate by splitting the search string into keywords
+ * @param inSearchString The search string to split
+ * @result Returns an NSPredicate to compare a contact to, or if inSearchString is empty, a predicate that matches everything
+ */
+- (NSPredicate*) createPredicateWithSearchString: (NSString *) inSearchString
+{
+	// Special-case the empty search-string
+	if (!inSearchString || ![inSearchString length]) 
+		return [NSPredicate predicateWithFormat: @"TRUEPREDICATE"];
+
+	NSMutableArray *subpredicates = [[NSMutableArray alloc] init];
+	
+	// Tokenize the string looking for words and iterate over tokens, storing an NSPredicate for each keyword
+	// Use CFStringTokenizer for multi-language support and to handle empty tokens
+	CFStringTokenizerRef tokenizer = CFStringTokenizerCreate(nil, (CFStringRef)inSearchString, CFRangeMake(0, inSearchString.length), kCFStringTokenizerUnitWord, NULL);
+	CFStringTokenizerTokenType tokenType;
+	while ((tokenType = CFStringTokenizerAdvanceToNextToken(tokenizer)) != kCFStringTokenizerTokenNone) {
+		CFRange range = CFStringTokenizerGetCurrentTokenRange(tokenizer);
+		NSRange nsRange = NSMakeRange(range.location, range.length);
+		NSString* keyword = [inSearchString substringWithRange: nsRange];
+		NSPredicate* predicate = [filterPredicateTemplate predicateWithSubstitutionVariables: [NSDictionary dictionaryWithObject:keyword forKey:@"KEYWORD"]];
+		[subpredicates addObject: predicate];
+	}
+	
+	// Build a compound predicate based on the predicate for each token.
+	NSPredicate* retval = [NSCompoundPredicate andPredicateWithSubpredicates:subpredicates];
+
+	CFRelease(tokenizer);
+	[subpredicates release];
+	
+	return retval;
+}
+
 @end




More information about the commits mailing list