=== modified file 'src/Core/Banshee.Core/Banshee.Collection/AlbumInfo.cs'
--- src/Core/Banshee.Core/Banshee.Collection/AlbumInfo.cs	2008-08-19 18:05:46 +0000
+++ src/Core/Banshee.Core/Banshee.Collection/AlbumInfo.cs	2009-02-04 04:32:00 +0000
@@ -36,7 +36,9 @@
     public class AlbumInfo : CacheableItem
     {
         private string title;
+        private string title_sort;
         private string artist_name;
+        private string artist_name_sort;
         private bool is_compilation;
         private string artwork_id;
         private DateTime release_date = DateTime.MinValue;
@@ -56,11 +58,21 @@
             set { artist_name = value; }
         }
         
+        public virtual string ArtistNameSort {
+            get { return artist_name_sort; }
+            set { artist_name_sort = value; }
+        }
+        
         public virtual string Title {
             get { return title; }
             set { title = value; }
         }
         
+        public virtual string TitleSort {
+            get { return title_sort; }
+            set { title_sort = value; }
+        }
+        
         public virtual bool IsCompilation {
             get { return is_compilation; }
             set { is_compilation = value; }

=== modified file 'src/Core/Banshee.Core/Banshee.Collection/ArtistInfo.cs'
--- src/Core/Banshee.Core/Banshee.Collection/ArtistInfo.cs	2008-05-25 18:48:34 +0000
+++ src/Core/Banshee.Core/Banshee.Collection/ArtistInfo.cs	2009-02-04 04:32:00 +0000
@@ -31,15 +31,17 @@
     public class ArtistInfo : CacheableItem
     {
         private string name;
+        private string name_sort;
         private string musicbrainz_id;
         
         public ArtistInfo ()
         {
         }
         
-        public ArtistInfo(string name)
+        public ArtistInfo(string name, string name_sort)
         {
             this.name = name;
+            this.name_sort = name_sort;
         }
                 
         public virtual string MusicBrainzId {
@@ -51,5 +53,10 @@
             get { return name; }
             set { name = value; }
         }
+        
+        public virtual string NameSort {
+            get { return name_sort; }
+            set { name_sort = value; }
+        }
     }
 }

=== modified file 'src/Core/Banshee.Core/Banshee.Collection/TrackInfo.cs'
--- src/Core/Banshee.Core/Banshee.Collection/TrackInfo.cs	2008-10-12 20:39:37 +0000
+++ src/Core/Banshee.Core/Banshee.Collection/TrackInfo.cs	2009-02-04 04:32:00 +0000
@@ -67,10 +67,14 @@
         private long file_mtime;
 
         private string artist_name;
+        private string artist_name_sort;
         private string album_title;
+        private string album_title_sort;
         private string album_artist;
+        private string album_artist_sort;
         private bool is_compilation;
         private string track_title;
+        private string track_title_sort;
         private string genre;
         private string composer;
         private string conductor;
@@ -204,12 +208,24 @@
             set { artist_name = value; }
         }
 
+        [Exportable (ExportName = "artistsort")]
+        public virtual string ArtistNameSort {
+            get { return artist_name_sort; }
+            set { artist_name_sort = value; }
+        }
+
         [Exportable (ExportName = "album")]
         public virtual string AlbumTitle {
             get { return album_title; }
             set { album_title = value; }
         }
 
+        [Exportable (ExportName = "albumsort")]
+        public virtual string AlbumTitleSort {
+            get { return album_title_sort; }
+            set { album_title_sort = value; }
+        }
+
         [Exportable]
         public virtual string AlbumArtist {
             get { return IsCompilation ? album_artist ?? Catalog.GetString ("Various Artists") : ArtistName; }
@@ -217,6 +233,12 @@
         }
         
         [Exportable]
+        public virtual string AlbumArtistSort {
+            get { return IsCompilation ? album_artist_sort ?? Catalog.GetString ("Various Artists") : ArtistNameSort; }
+            set { album_artist_sort = value; }
+        }
+        
+        [Exportable]
         public virtual bool IsCompilation {
             get { return is_compilation; }
             set { is_compilation = value; }
@@ -228,6 +250,12 @@
             set { track_title = value; }
         }
         
+        [Exportable (ExportName = "namesort")]
+        public virtual string TrackTitleSort {
+            get { return track_title_sort; }
+            set { track_title_sort = value; }
+        }
+        
         [Exportable]
         public virtual string MusicBrainzId {
             get { return musicbrainz_id; }

=== modified file 'src/Core/Banshee.Core/Banshee.Streaming/CommonTags.cs'
--- src/Core/Banshee.Core/Banshee.Streaming/CommonTags.cs	2008-08-19 18:05:46 +0000
+++ src/Core/Banshee.Core/Banshee.Streaming/CommonTags.cs	2009-02-04 04:32:00 +0000
@@ -33,8 +33,11 @@
     public sealed class CommonTags 
     {
         public const string Title             = "title";
+        public const string TitleSortName     = "title-sortname";
         public const string Artist            = "artist";
+        public const string ArtistSortName    = "artist-sortname";
         public const string Album             = "album";
+        public const string AlbumSortName     = "album-sortname";
         public const string Date              = "date";
         public const string Genre             = "genre";
         public const string Disc              = "disc";
@@ -77,5 +80,8 @@
         public const string MusicBrainzArtistId = "musicbrainz-artistid";
         public const string MusicBrainzAlbumId = "musicbrainz-albumid";
         public const string MusicBrainzDiscId = "musicbrainz-discid";
+        
+        // Deprecated by MB, replaced by ArtistSortName. Kept for compatibility only.
+        public const string MusicBrainzSortName = "musicbrainz-sortname";
     }
 }

=== modified file 'src/Core/Banshee.Core/Banshee.Streaming/SaveTrackMetadataJob.cs'
--- src/Core/Banshee.Core/Banshee.Streaming/SaveTrackMetadataJob.cs	2008-10-03 19:34:53 +0000
+++ src/Core/Banshee.Core/Banshee.Streaming/SaveTrackMetadataJob.cs	2009-02-04 04:32:00 +0000
@@ -68,13 +68,17 @@
             }
             
             file.Tag.Performers = new string [] { track.ArtistName };
+            file.Tag.PerformersSort = new string [] { track.ArtistNameSort };
             file.Tag.Album = track.AlbumTitle;
+            file.Tag.AlbumSort = track.AlbumTitleSort;
             file.Tag.AlbumArtists = track.AlbumArtist == null ? new string [0] : new string [] {track.AlbumArtist};
+            file.Tag.AlbumArtistsSort = (track.AlbumArtistSort == null ? new string [0] : new string [] {track.AlbumArtistSort});
             // Bug in taglib-sharp-2.0.3.0: Crash if you send it a genre of "{ null }"
             // on a song with both ID3v1 and ID3v2 metadata. It's happy with "{}", though.
             // (see http://forum.taglib-sharp.com/viewtopic.php?f=5&t=239 )
             file.Tag.Genres = (track.Genre == null) ? new string[] {} : new string [] { track.Genre };
             file.Tag.Title = track.TrackTitle;
+            file.Tag.TitleSort = track.TrackTitleSort;
             file.Tag.Track = (uint)track.TrackNumber;
             file.Tag.TrackCount = (uint)track.TrackCount;
             file.Tag.Composers = new string [] { track.Composer };

=== modified file 'src/Core/Banshee.Core/Banshee.Streaming/StreamTagger.cs'
--- src/Core/Banshee.Core/Banshee.Streaming/StreamTagger.cs	2009-01-25 20:14:32 +0000
+++ src/Core/Banshee.Core/Banshee.Streaming/StreamTagger.cs	2009-02-04 04:32:00 +0000
@@ -140,11 +140,15 @@
                 FindTrackMediaAttributes (track, file);
     
                 track.ArtistName = Choose (file.Tag.JoinedPerformers, track.ArtistName, preferTrackInfo);
+                track.ArtistNameSort = Choose (file.Tag.JoinedPerformersSort, track.ArtistNameSort, preferTrackInfo);
                 track.AlbumTitle = Choose (file.Tag.Album, track.AlbumTitle, preferTrackInfo);
+                track.AlbumTitleSort = Choose (file.Tag.AlbumSort, track.AlbumTitleSort, preferTrackInfo);
                 track.AlbumArtist = Choose (file.Tag.FirstAlbumArtist, track.AlbumArtist, preferTrackInfo);
+                track.AlbumArtistSort = Choose (file.Tag.FirstAlbumArtistSort, track.AlbumArtistSort, preferTrackInfo);
                 track.IsCompilation = IsCompilation (file.Tag);
                 
                 track.TrackTitle = Choose (file.Tag.Title, track.TrackTitle, preferTrackInfo);
+                track.TrackTitleSort = Choose (file.Tag.TitleSort, track.TrackTitleSort, preferTrackInfo);
                 track.Genre = Choose (file.Tag.FirstGenre, track.Genre, preferTrackInfo);
                 track.Composer = Choose (file.Tag.FirstComposer, track.Composer, preferTrackInfo);
                 track.Conductor = Choose (file.Tag.Conductor, track.Conductor, preferTrackInfo);
@@ -210,6 +214,10 @@
                     case CommonTags.Artist:
                         track.ArtistName = Choose ((string)tag.Value, track.ArtistName);
                         break;
+                    case CommonTags.ArtistSortName:
+                    case CommonTags.MusicBrainzSortName:
+                        track.ArtistNameSort = Choose ((string)tag.Value, track.ArtistNameSort);
+                        break;
                     case CommonTags.Title:
                         //track.TrackTitle = Choose ((string)tag.Value, track.TrackTitle);
                         string title = Choose ((string)tag.Value, track.TrackTitle);
@@ -234,9 +242,15 @@
                             track.TrackTitle = title;
                         }
                         break;
+                    case CommonTags.TitleSortName:
+                        track.TrackTitleSort = Choose ((string)tag.Value, track.TrackTitleSort);
+                        break;
                     case CommonTags.Album:
                         track.AlbumTitle = Choose ((string)tag.Value, track.AlbumTitle);
                         break;
+                    case CommonTags.AlbumSortName:
+                        track.AlbumTitleSort = Choose ((string)tag.Value, track.AlbumTitleSort);
+                        break;
                     case CommonTags.Disc:
                     case CommonTags.AlbumDiscNumber:
                         int disc = (int)tag.Value;

=== modified file 'src/Core/Banshee.Services/Banshee.Collection.Database/DatabaseAlbumInfo.cs'
--- src/Core/Banshee.Services/Banshee.Collection.Database/DatabaseAlbumInfo.cs	2008-12-29 20:36:08 +0000
+++ src/Core/Banshee.Services/Banshee.Collection.Database/DatabaseAlbumInfo.cs	2009-02-04 04:32:00 +0000
@@ -55,12 +55,6 @@
             (String.IsNullOrEmpty (provider.Where) ? "1=1" : provider.Where)
         ));
 
-        private enum Column : int {
-            AlbumID,
-            Title,
-            ArtistName
-        }
-
         private static int last_artist_id;
         private static string last_title;
         private static DatabaseAlbumInfo last_album;
@@ -72,10 +66,11 @@
             last_album = null;
         }
 
-        public static DatabaseAlbumInfo FindOrCreate (DatabaseArtistInfo artist, string title, bool isCompilation)
+        public static DatabaseAlbumInfo FindOrCreate (DatabaseArtistInfo artist, string title, string title_sort, bool isCompilation)
         {
             DatabaseAlbumInfo album = new DatabaseAlbumInfo ();
             album.Title = title;
+            album.TitleSort = title_sort;
             album.IsCompilation = isCompilation;
             return FindOrCreate (artist, album);
         }
@@ -101,6 +96,18 @@
                         save = true;
                     }
                     
+                    // Ditto artist sort name
+                    if (last_album.ArtistNameSort != artist.NameSort) {
+                        last_album.ArtistNameSort = artist.NameSort;
+                        save = true;
+                    }
+
+                    // And album sort name
+                    if (last_album.TitleSort != album.TitleSort) {
+                        last_album.TitleSort = album.TitleSort;
+                        save = true;
+                    }
+
                     // If the album IsCompilation status has changed, update the saved album info
                     if (last_album.IsCompilation != album.IsCompilation) {
                         last_album.IsCompilation = album.IsCompilation;
@@ -113,6 +120,7 @@
                 } else {
                     album.ArtistId = artist.DbId;
                     album.ArtistName = artist.Name;
+                    album.ArtistNameSort = artist.NameSort;
                     album.Save ();
                     last_album = album;
                 }
@@ -129,7 +137,9 @@
             if (found != album) {
                 // Overwrite the found album
                 album.Title = found.Title;
+                album.TitleSort = found.TitleSort;
                 album.ArtistName = found.ArtistName;
+                album.ArtistNameSort = found.ArtistNameSort;
                 album.IsCompilation = found.IsCompilation;
                 album.dbid = found.DbId;
                 album.ArtistId = found.ArtistId;
@@ -184,17 +194,29 @@
             set { base.Title = value; }
         }
         
-        [DatabaseColumn(Select = false)]
-        protected string TitleLowered {
-            get { return Title == null ? null : Title.ToLower (); }
+        [DatabaseColumn]
+        public override string TitleSort {
+            get { return base.TitleSort; }
+            set { base.TitleSort = value; }
         }
-
+        
         [DatabaseColumn]
         public override string ArtistName {
             get { return base.ArtistName; }
             set { base.ArtistName = value; }
         }
 
+        [DatabaseColumn]
+        public override string ArtistNameSort {
+            get { return base.ArtistNameSort; }
+            set { base.ArtistNameSort = value; }
+        }
+
+        [DatabaseColumn(Select = false)]
+        protected string TitleLowered {
+            get { return Title == null ? null : Title.ToLower (); }
+        }
+
         [DatabaseColumn(Select = false)]
         protected string ArtistNameLowered {
             get { return ArtistName == null ? null : ArtistName.ToLower (); }

=== modified file 'src/Core/Banshee.Services/Banshee.Collection.Database/DatabaseAlbumListModel.cs'
--- src/Core/Banshee.Services/Banshee.Collection.Database/DatabaseAlbumListModel.cs	2008-09-03 14:28:58 +0000
+++ src/Core/Banshee.Services/Banshee.Collection.Database/DatabaseAlbumListModel.cs	2009-02-04 04:32:00 +0000
@@ -51,7 +51,8 @@
                         (SELECT CoreTracks.AlbumID FROM CoreTracks, CoreCache{0}
                             WHERE CoreCache.ModelID = {1} AND
                                   CoreCache.ItemId = {2} {3})
-                    ORDER BY CoreAlbums.TitleLowered, CoreAlbums.ArtistNameLowered";
+                    ORDER BY BANSHEE_SORTNAME_KEY(CoreAlbums.TitleSort, CoreAlbums.Title),
+                             BANSHEE_SORTNAME_KEY(CoreAlbums.ArtistNameSort, CoreAlbums.ArtistName)";
         }
         
         public override string FilterColumn {

=== modified file 'src/Core/Banshee.Services/Banshee.Collection.Database/DatabaseArtistInfo.cs'
--- src/Core/Banshee.Services/Banshee.Collection.Database/DatabaseArtistInfo.cs	2008-08-19 18:05:46 +0000
+++ src/Core/Banshee.Services/Banshee.Collection.Database/DatabaseArtistInfo.cs	2009-02-04 04:32:00 +0000
@@ -55,11 +55,6 @@
             (String.IsNullOrEmpty (provider.Where) ? "1=1" : provider.Where)
         ));
 
-        private enum Column : int {
-            ArtistID,
-            Name
-        }
-
         private static string last_artist_name = null;
         private static DatabaseArtistInfo last_artist = null;
 
@@ -69,10 +64,11 @@
             last_artist = null;
         }
         
-        public static DatabaseArtistInfo FindOrCreate (string artistName)
+        public static DatabaseArtistInfo FindOrCreate (string artistName, string artistNameSort)
         {
             DatabaseArtistInfo artist = new DatabaseArtistInfo ();
             artist.Name = artistName;
+            artist.NameSort = artistNameSort;
             return FindOrCreate (artist);
         }
 
@@ -89,6 +85,10 @@
             using (IDataReader reader = ServiceManager.DbConnection.Query (select_command, artist.Name)) {
                 if (reader.Read ()) {
                     last_artist = provider.Load (reader);
+                    if (last_artist.NameSort != artist.NameSort) {
+                        last_artist.NameSort = artist.NameSort;
+                        last_artist.Save ();
+                    }
                 } else {
                     artist.Save ();
                     last_artist = artist;
@@ -105,13 +105,14 @@
             if (found != artist) {
                 // Overwrite the found artist
                 artist.Name = found.Name;
+                artist.NameSort = found.NameSort;
                 artist.dbid = found.DbId;
                 artist.Save ();
             }
             return artist;
         }
         
-        public DatabaseArtistInfo () : base (null)
+        public DatabaseArtistInfo () : base (null, null)
         {
         }
 
@@ -131,18 +132,24 @@
             get { return base.Name; }
             set { base.Name = value; }
         }
-               
+
+        [DatabaseColumn(Select = false)]
+        protected string NameLowered {
+            get { return Name == null ? null : Name.ToLower (); }
+        }
+
+        [DatabaseColumn]
+        public override string NameSort {
+            get { return base.NameSort; }
+            set { base.NameSort = value; }
+        }
+
         [DatabaseColumn("MusicBrainzID")]
         public override string MusicBrainzId {
             get { return base.MusicBrainzId; }
             set { base.MusicBrainzId = value; }
         }
         
-        [DatabaseColumn(Select = false)]
-        protected string NameLowered {
-            get { return Name == null ? null : Name.ToLower (); }
-        }
-
         public override string ToString ()
         {
             return String.Format ("DatabaseArtistInfo<DbId: {0}, Name: {1}>", DbId, Name);

=== modified file 'src/Core/Banshee.Services/Banshee.Collection.Database/DatabaseArtistListModel.cs'
--- src/Core/Banshee.Services/Banshee.Collection.Database/DatabaseArtistListModel.cs	2008-07-22 13:33:10 +0000
+++ src/Core/Banshee.Services/Banshee.Collection.Database/DatabaseArtistListModel.cs	2009-02-04 04:32:00 +0000
@@ -43,14 +43,14 @@
     {
         public DatabaseArtistListModel (Banshee.Sources.DatabaseSource source, DatabaseTrackListModel trackModel, BansheeDbConnection connection, string uuid) 
             : base (Banshee.Query.BansheeQuery.ArtistField.Name, Banshee.Query.BansheeQuery.ArtistField.Label, 
-                    source, trackModel, connection, DatabaseArtistInfo.Provider, new ArtistInfo (null), uuid)
+                    source, trackModel, connection, DatabaseArtistInfo.Provider, new ArtistInfo (null, null), uuid)
         {
             ReloadFragmentFormat = @"
                 FROM CoreArtists WHERE CoreArtists.ArtistID IN
                     (SELECT CoreTracks.ArtistID FROM CoreTracks, CoreCache{0}
                         WHERE CoreCache.ModelID = {1} AND
                               CoreCache.ItemID = {2} {3})
-                    ORDER BY NameLowered";
+                    ORDER BY BANSHEE_SORTNAME_KEY(NameSort, Name)";
         }
         
         public override string FilterColumn {

=== modified file 'src/Core/Banshee.Services/Banshee.Collection.Database/DatabaseTrackInfo.cs'
--- src/Core/Banshee.Services/Banshee.Collection.Database/DatabaseTrackInfo.cs	2009-01-28 01:29:07 +0000
+++ src/Core/Banshee.Services/Banshee.Collection.Database/DatabaseTrackInfo.cs	2009-02-04 04:32:00 +0000
@@ -125,11 +125,11 @@
         }
         
         public DatabaseArtistInfo Artist {
-            get { return DatabaseArtistInfo.FindOrCreate (ArtistName); }
+            get { return DatabaseArtistInfo.FindOrCreate (ArtistName, ArtistNameSort); }
         }
 
         public DatabaseAlbumInfo Album {
-            get { return DatabaseAlbumInfo.FindOrCreate (DatabaseArtistInfo.FindOrCreate (AlbumArtist), AlbumTitle, IsCompilation); }
+            get { return DatabaseAlbumInfo.FindOrCreate (DatabaseArtistInfo.FindOrCreate (AlbumArtist, AlbumArtistSort), AlbumTitle, AlbumTitleSort, IsCompilation); }
         }
 
         private static bool notify_saved = true;
@@ -241,6 +241,24 @@
             }
         }
 
+        [VirtualDatabaseColumn ("NameSort", "CoreArtists", "ArtistID", "ArtistID")]
+        protected string ArtistNameSortField {
+            get { return ArtistNameSort; }
+            set { base.ArtistNameSort = value; }
+        }
+
+        public override string ArtistNameSort {
+            get { return base.ArtistNameSort; }
+            set {
+                value = CleanseString (value, ArtistNameSort);
+                if (value == null)
+                    return;
+
+                base.ArtistNameSort = value;
+                artist_changed = true;
+            }
+        }
+
         [VirtualDatabaseColumn ("Title", "CoreAlbums", "AlbumID", "AlbumID")]
         protected string AlbumTitleField {
             get { return AlbumTitle; }
@@ -259,6 +277,24 @@
             }
         }
 
+        [VirtualDatabaseColumn ("TitleSort", "CoreAlbums", "AlbumID", "AlbumID")]
+        protected string AlbumTitleSortField {
+            get { return AlbumTitleSort; }
+            set { base.AlbumTitleSort = value; }
+        }
+
+        public override string AlbumTitleSort {
+            get { return base.AlbumTitleSort; }
+            set {
+                value = CleanseString (value, AlbumTitleSort);
+                if (value == null)
+                    return;
+
+                base.AlbumTitleSort = value;
+                album_changed = true;
+            }
+        }
+
         [VirtualDatabaseColumn ("ArtistName", "CoreAlbums", "AlbumID", "AlbumID")]
         protected string AlbumArtistField {
             get { return AlbumArtist; }
@@ -277,6 +313,24 @@
             }
         }
         
+        [VirtualDatabaseColumn ("ArtistNameSort", "CoreAlbums", "AlbumID", "AlbumID")]
+        protected string AlbumArtistSortField {
+            get { return AlbumArtistSort; }
+            set { base.AlbumArtistSort = value; }
+        }
+
+        public override string AlbumArtistSort {
+            get { return base.AlbumArtistSort; }
+            set {
+                value = CleanseString (value, AlbumArtistSort);
+                if (value == null)
+                    return;
+
+                base.AlbumArtistSort = value;
+                album_changed = true;
+            }
+        }
+        
         [VirtualDatabaseColumn ("IsCompilation", "CoreAlbums", "AlbumID", "AlbumID")]
         protected bool IsCompilationField {
             get { return IsCompilation; }
@@ -396,6 +450,12 @@
             set { base.TrackTitle = value; }
         }
         
+        [DatabaseColumn]
+        public override string TrackTitleSort {
+            get { return base.TrackTitleSort; }
+            set { base.TrackTitleSort = value; }
+        }
+        
         [DatabaseColumn(Select = false)]
         protected string TitleLowered {
             get { return TrackTitle == null ? null : TrackTitle.ToLower (); }

=== modified file 'src/Core/Banshee.Services/Banshee.Database/BansheeDbFormatMigrator.cs'
--- src/Core/Banshee.Services/Banshee.Database/BansheeDbFormatMigrator.cs	2009-01-26 01:41:24 +0000
+++ src/Core/Banshee.Services/Banshee.Database/BansheeDbFormatMigrator.cs	2009-02-04 04:32:00 +0000
@@ -52,8 +52,8 @@
         // NOTE: Whenever there is a change in ANY of the database schema,
         //       this version MUST be incremented and a migration method
         //       MUST be supplied to match the new version number
-        protected const int CURRENT_VERSION = 22;
-        protected const int CURRENT_METADATA_VERSION = 4;
+        protected const int CURRENT_VERSION = 23;
+        protected const int CURRENT_METADATA_VERSION = 5;
         
 #region Migration Driver
         
@@ -551,6 +551,21 @@
         
 #endregion
 
+#region Version 23
+
+        [DatabaseVersion (23)]
+        private bool Migrate_23 ()
+        {
+            Execute ("ALTER TABLE CoreArtists ADD COLUMN NameSort TEXT");
+            Execute ("ALTER TABLE CoreAlbums ADD COLUMN ArtistNameSort TEXT");
+            Execute ("ALTER TABLE CoreAlbums ADD COLUMN TitleSort TEXT");
+            Execute ("ALTER TABLE CoreTracks ADD COLUMN TitleSort TEXT");
+
+            return true;
+        }
+        
+#endregion
+
 #pragma warning restore 0169
         
 #region Fresh database setup
@@ -615,6 +630,7 @@
                     
                     Title               TEXT,
                     TitleLowered        TEXT,
+                    TitleSort           TEXT,
                     TrackNumber         INTEGER,
                     TrackCount          INTEGER,
                     Disc                INTEGER,
@@ -658,6 +674,7 @@
 
                     Title               TEXT,
                     TitleLowered        TEXT,
+                    TitleSort           TEXT,
 
                     ReleaseDate         INTEGER,
                     Duration            INTEGER,
@@ -666,6 +683,7 @@
                     
                     ArtistName          TEXT,
                     ArtistNameLowered   TEXT,
+                    ArtistNameSort      TEXT,
                     
                     Rating              INTEGER
                 )
@@ -680,6 +698,7 @@
                     MusicBrainzID       TEXT,
                     Name                TEXT,
                     NameLowered         TEXT,
+                    NameSort            TEXT,
                     Rating              INTEGER
                 )
             ");

=== added file 'src/Core/Banshee.Services/Banshee.Database/CustomSqliteFunctions.cs'
--- src/Core/Banshee.Services/Banshee.Database/CustomSqliteFunctions.cs	1970-01-01 00:00:00 +0000
+++ src/Core/Banshee.Services/Banshee.Database/CustomSqliteFunctions.cs	2009-02-04 04:37:15 +0000
@@ -0,0 +1,48 @@
+//
+// CustomSqliteFunctions.cs
+//
+// Author:
+//   John Millikin <jmillikin@gmail.com>
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
+using System;
+using System.Reflection;
+using System.Text;
+using Mono.Data.Sqlite;
+
+namespace Banshee.Database
+{
+    [SqliteFunction (Name = "BANSHEE_SORTNAME_KEY", FuncType = FunctionType.Scalar, Arguments = 2)]
+    internal class SortKeyFunction : SqliteFunction
+    {
+        public override object Invoke (object[] args)
+        {
+            object sortname = args[0], fallback = args[1];
+            if (System.DBNull.Value.Equals (fallback) || fallback == null)
+                fallback = "";
+            if (System.DBNull.Value.Equals (sortname) || sortname == null)
+                sortname = fallback;
+            
+            return sortname.ToString ().ToLower ();
+        }
+    }
+}

=== modified file 'src/Core/Banshee.Services/Banshee.Query/BansheeQuery.cs'
--- src/Core/Banshee.Services/Banshee.Query/BansheeQuery.cs	2009-01-26 02:09:07 +0000
+++ src/Core/Banshee.Services/Banshee.Query/BansheeQuery.cs	2009-02-04 04:32:00 +0000
@@ -337,7 +337,7 @@
             PlayCountField.ShortLabel   = Catalog.GetString ("Plays");
         }
 
-        private const string default_sort = @"CoreAlbums.ArtistNameLowered ASC, CoreAlbums.TitleLowered ASC, CoreTracks.Disc ASC, CoreTracks.TrackNumber ASC";
+        private const string default_sort = @"BANSHEE_SORTNAME_KEY(CoreAlbums.ArtistNameSort, CoreAlbums.ArtistName) ASC, BANSHEE_SORTNAME_KEY(CoreAlbums.TitleSort, CoreAlbums.Title) ASC, CoreTracks.Disc ASC, CoreTracks.TrackNumber ASC";
         public static string GetSort (string key)
         {
             return GetSort (key, false);
@@ -353,40 +353,40 @@
                 case "track":
                 case "grouping":
                     sort_query = String.Format (@"
-                        CoreAlbums.ArtistNameLowered ASC, 
-                        CoreAlbums.TitleLowered ASC, 
+                        BANSHEE_SORTNAME_KEY(CoreAlbums.ArtistNameSort, CoreAlbums.ArtistName) ASC, 
+                        BANSHEE_SORTNAME_KEY(CoreAlbums.TitleSort, CoreAlbums.Title) ASC, 
                         CoreTracks.Disc ASC,
                         CoreTracks.TrackNumber {0}", ascDesc); 
                     break;
 
                 case "albumartist":
                     sort_query = String.Format (@"
-                        CoreAlbums.ArtistNameLowered {0}, 
-                        CoreAlbums.TitleLowered ASC, 
+                        BANSHEE_SORTNAME_KEY(CoreAlbums.ArtistNameSort, CoreAlbums.ArtistName) {0}, 
+                        BANSHEE_SORTNAME_KEY(CoreAlbums.TitleSort, CoreAlbums.Title) ASC, 
                         CoreTracks.Disc ASC,
                         CoreTracks.TrackNumber ASC", ascDesc); 
                     break;
 
                 case "artist":
                     sort_query = String.Format (@"
-                        CoreArtists.NameLowered {0}, 
-                        CoreAlbums.TitleLowered ASC,
+                        BANSHEE_SORTNAME_KEY(CoreArtists.NameSort, CoreArtists.Name) {0}, 
+                        BANSHEE_SORTNAME_KEY(CoreAlbums.TitleSort, CoreAlbums.Title) ASC,
                         CoreTracks.Disc ASC,
                         CoreTracks.TrackNumber ASC", ascDesc); 
                     break;
 
                 case "album":
                     sort_query = String.Format (@"
-                        CoreAlbums.TitleLowered {0},
+                        BANSHEE_SORTNAME_KEY(CoreAlbums.TitleSort, CoreAlbums.Title) {0},
                         CoreTracks.Disc ASC,
                         CoreTracks.TrackNumber ASC", ascDesc); 
                     break;
 
                 case "title":
                     sort_query = String.Format (@"
-                        CoreTracks.TitleLowered {0},
-                        CoreAlbums.ArtistNameLowered ASC, 
-                        CoreAlbums.TitleLowered ASC", ascDesc); 
+                        BANSHEE_SORTNAME_KEY(CoreTracks.TitleSort, CoreTracks.Title) {0},
+                        BANSHEE_SORTNAME_KEY(CoreAlbums.ArtistNameSort, CoreAlbums.ArtistName) ASC, 
+                        BANSHEE_SORTNAME_KEY(CoreAlbums.TitleSort, CoreAlbums.Title) ASC", ascDesc); 
                     break;
 
                 case "random":
@@ -395,8 +395,8 @@
 
                 case "disc":
                     sort_query = String.Format (@"
-                        CoreAlbums.ArtistNameLowered ASC, 
-                        CoreAlbums.TitleLowered ASC, 
+                        BANSHEE_SORTNAME_KEY(CoreAlbums.ArtistNameSort, CoreAlbums.ArtistName) ASC, 
+                        BANSHEE_SORTNAME_KEY(CoreAlbums.TitleSort, CoreAlbums.Title) ASC, 
                         CoreTracks.Disc {0},
                         CoreTracks.TrackNumber ASC", ascDesc);
                     break;

=== modified file 'src/Core/Banshee.Services/Makefile.am'
--- src/Core/Banshee.Services/Makefile.am	2009-02-02 18:28:57 +0000
+++ src/Core/Banshee.Services/Makefile.am	2009-02-04 04:34:24 +0000
@@ -48,6 +48,7 @@
 	Banshee.Database/BansheeDbFormatMigrator.cs \
 	Banshee.Database/BansheeModelCache.cs \
 	Banshee.Database/BansheeModelProvider.cs \
+	Banshee.Database/CustomSqliteFunctions.cs \
 	Banshee.Equalizer/EqualizerManager.cs \
 	Banshee.Equalizer/EqualizerSetting.cs \
 	Banshee.Equalizer/EqualizerSettingEvent.cs \

