Index: src/PlayerInterface.cs
===================================================================
RCS file: /cvs/gnome/banshee/src/PlayerInterface.cs,v
retrieving revision 1.184
diff -u -d -r1.184 PlayerInterface.cs
--- src/PlayerInterface.cs	17 Jun 2006 02:08:33 -0000	1.184
+++ src/PlayerInterface.cs	18 Jun 2006 10:28:20 -0000
@@ -36,6 +36,9 @@
 using Gdk;
 using Glade;
 using System.IO;
+using System.Globalization;
+using System.Collections.Generic;
+using System.Text.RegularExpressions;
 
 using Sql;
 using Banshee.Widgets;
@@ -948,7 +951,8 @@
             if(args.Source == SourceManager.ActiveSource) {
                 UpdateViewName(args.Source);
                 
-                if(playlistModel.Count() == 0 && args.Source.Count > 0) {
+                if(playlistModel.Count() == 0 && args.Source.Count > 0
+                   && !searchEntry.IsQueryAvailable) {
                     playlistModel.ReloadSource();
                 } else if(source_update_draw_timeout == 0) {
                     source_update_draw_timeout = GLib.Timeout.Add(500, delegate {
@@ -1304,42 +1308,90 @@
                 return false;
             }
             
-            string query = searchEntry.Query.ToLower();
+            string query = searchEntry.Query;
             string field = searchEntry.Field;
-            string match = null;
+            string[] matches;
             
             if(field == Catalog.GetString("Artist Name")) {
-                match = ti.Artist;
+                matches = new string[] {ti.Artist};
             } else if(field == Catalog.GetString("Song Name")) {
-                match = ti.Title;
+                matches = new string[] {ti.Title};
             } else if(field == Catalog.GetString("Album Title")) {
-                match = ti.Album;
+                matches = new string[] {ti.Album};
             } else if(field == Catalog.GetString("Genre")) {
-                match = ti.Genre;
+                matches = new string[] {ti.Genre};
             } else {
-                string [] matches = {
+                matches = new string[] {
                     ti.Artist,
                     ti.Album,
                     ti.Title,
                     ti.Genre
                 };
-
-                foreach(string m in matches) {
-                    if(m == null || m == String.Empty) {
+            }
+            
+            List<string> words_include = new List<string>();
+            List<string> words_exclude = new List<string>();
+            Array.ForEach<string>(
+                Regex.Split(query, @"\s+"),
+                delegate(string word) {
+                    if(word.StartsWith("-")) {
+                        words_exclude.Add(word.Substring(1));
+                    } else {
+                        words_include.Add(word);
+                    }
+                }
+            );
+            
+            foreach(string word in words_exclude) {
+                foreach(string match in matches) {
+                    if(match == null || match == string.Empty) {
                         continue;
                     }
-
-                    string ml = m.ToLower();
-                    if(ml.IndexOf(query) >= 0 || ml.IndexOf("the " + query) >= 0) {
-                        return true;
+                
+                    if(RelaxedStringIndexOf(match, word) >= 0) {
+                        return false;
                     }
                 }
+            }
+            bool found;
+            foreach(string word in words_include) {
+                found = false;
+                foreach(string match in matches) {
+                    if(match == null || match == string.Empty) {
+                        continue;
+                    }
                 
-                return false;
+                    if(RelaxedStringIndexOf(match, word) >= 0) {
+                        found = true;
+                        break;
+                    }
+                }
+                if(!found) {
+                    return false;
+                }
             }
-                    
-            match = match.ToLower();
-            return match.IndexOf(query) >= 0 || match.IndexOf("the " + query) >= 0;
+            
+            return true;
+        }
+        
+        /// <summary>
+        /// Works the same as String.IndexOf() except it ignores the differences
+        /// in case and nonspacing combining characters (such as diacritics).
+        /// </summary>
+        /// <remarks>
+        /// It also ignores the differences between Japanese hiragana and
+        /// katakana characters and the differences in character width (for
+        /// example, Japanese katakana characters can be written as full-width
+        /// or half-width). But I don't know Japanese so this might be an
+        /// overkill.
+        /// </remarks>
+        private int RelaxedStringIndexOf(string haystack, string needle)
+        {
+            return CultureInfo.CurrentCulture.CompareInfo.IndexOf(
+                haystack,
+                needle,
+                CompareOptions.IgnoreCase | CompareOptions.IgnoreNonSpace |
+                CompareOptions.IgnoreKanaType | CompareOptions.IgnoreWidth);
         }
         
         private void OnSimpleSearch(object o, EventArgs args)
