banshee r3019 - in trunk/banshee: . src/Core/Banshee.Core/Banshee.Base src/Core/Banshee.Services/Banshee.Collection.Database src/Core/Banshee.Services/Banshee.Database src/Core/Banshee.Services/Banshee.Playlist src/Core/Banshee.Services/Banshee.SmartPlaylist src/Core/Hyena src/Core/Hyena/Hyena src/Core/Hyena/Hyena.Data.Query



Author: gburt
Date: Fri Jan 25 01:18:35 2008
New Revision: 3019
URL: http://svn.gnome.org/viewvc/banshee?rev=3019&view=rev

Log:
2008-01-24  Gabriel Burt  <gabriel burt gmail com>

	* src/Core/Banshee.Core/Banshee.Base/Utilities.cs:
	* src/Core/Hyena/Hyena/Utilities.cs:
	* src/Core/Hyena/Hyena/Timer.cs: Move Timer and DateTimeUtils to Hyena.

	* src/Core/Banshee.Services/Banshee.Database/BansheeDbFormatMigrator.cs:
	Disambiguate which Timer to use.

	* src/Core/Hyena/Timer.cs: Remove, replaced by Hyena/Timer.cs.

	* src/Core/Banshee.Services/Banshee.Collection.Database/LibraryAlbumInfo.cs:
	Remove unnecessary assignment.

	* src/Core/Banshee.Services/Banshee.SmartPlaylist/SmartPlaylistSource.cs:
	* src/Core/Banshee.Services/Banshee.Playlist/PlaylistSource.cs:
	* src/Core/Banshee.Services/Banshee.Collection.Database/LibraryArtistInfo.cs:
	Wrap IDataReader in using.

	* src/Core/Banshee.Services/Banshee.Collection.Database/LibraryTrackInfo.cs:
	Add using Hyena for DateTimeUtils.

	* src/Core/Banshee.Services/Banshee.Collection.Database/TrackListDatabaseModel.cs:
	Pass field_set to BuildTree methods, and update QueryField constructors
	with new QueryValue setup.  Remove Date and FileSize modifier functions.

	* src/Core/Banshee.Services/Banshee.SmartPlaylist/Migrator.cs: Use new
	QueryValue class.

	* src/Core/Hyena/Hyena.Data.Query/QueryValue.cs:
	* src/Core/Hyena/Hyena.Data.Query/StringQueryValue.cs:
	* src/Core/Hyena/Hyena.Data.Query/IntegerQueryValue.cs:
	* src/Core/Hyena/Hyena.Data.Query/FileSizeQueryValue.cs:
	* src/Core/Hyena/Hyena.Data.Query/DateQueryValue.cs: New files/classes
	that provider parsers and generators for XML/user-query for different data
	types.  Replace QueryField Modifiers.

	* src/Core/Hyena/Hyena.Data.Query/QueryField.cs: Fields now have a
	ValueType associated with them, one of the four QueryValue subclasses
	above.  Turn fields into properties.

	* src/Core/Hyena/Hyena.Data.Query/QueryFieldSet.cs: Add this [] accessor.

	* src/Core/Hyena/Hyena.Data.Query/QueryListNode.cs: Avoid crashing when
	trimming a QueryNode tree that has only a childless NOT node.

	* src/Core/Hyena/Hyena.Data.Query/QueryTermNode.cs: Remove Operator class.
	Replace string Field and Value fields with QueryField and QueryValue
	properties.

	* src/Core/Hyena/Hyena.Data.Query/QueryOperator.cs: Split into its own
	file.  Was previously inside QueryTermNode.

	* src/Core/Hyena/Hyena.Data.Query/QueryParser.cs:
	* src/Core/Hyena/Hyena.Data.Query/XmlQueryParser.cs:
	* src/Core/Hyena/Hyena.Data.Query/UserQueryParser.cs: Require a
	QueryFieldSet for BuildTree method so we can user the relevant ValueType
	for each QueryField as we parse it.

	* src/Core/Hyena/Hyena.Data.Sqlite/DatabaseColumn.cs: Use GetValue and
	SetValue methods of PropertyInfo objects instead of GetGetMethod etc.

	* src/Core/Hyena/Hyena.Data.Sqlite/HyenaSqliteConnection.cs: Add temporary
	debugging messages.

	* src/Core/Hyena/Makefile.am: Add new files, remove old Timer.cs.


Added:
   trunk/banshee/src/Core/Hyena/Hyena.Data.Query/DateQueryValue.cs
   trunk/banshee/src/Core/Hyena/Hyena.Data.Query/FileSizeQueryValue.cs
   trunk/banshee/src/Core/Hyena/Hyena.Data.Query/IntegerQueryValue.cs
   trunk/banshee/src/Core/Hyena/Hyena.Data.Query/QueryOperator.cs
   trunk/banshee/src/Core/Hyena/Hyena.Data.Query/QueryValue.cs
   trunk/banshee/src/Core/Hyena/Hyena.Data.Query/StringQueryValue.cs
   trunk/banshee/src/Core/Hyena/Hyena/Timer.cs
   trunk/banshee/src/Core/Hyena/Hyena/Utilities.cs
Removed:
   trunk/banshee/src/Core/Hyena/Timer.cs
Modified:
   trunk/banshee/ChangeLog
   trunk/banshee/src/Core/Banshee.Core/Banshee.Base/Utilities.cs
   trunk/banshee/src/Core/Banshee.Services/Banshee.Collection.Database/LibraryAlbumInfo.cs
   trunk/banshee/src/Core/Banshee.Services/Banshee.Collection.Database/LibraryArtistInfo.cs
   trunk/banshee/src/Core/Banshee.Services/Banshee.Collection.Database/LibraryTrackInfo.cs
   trunk/banshee/src/Core/Banshee.Services/Banshee.Collection.Database/TrackListDatabaseModel.cs
   trunk/banshee/src/Core/Banshee.Services/Banshee.Database/BansheeDbFormatMigrator.cs
   trunk/banshee/src/Core/Banshee.Services/Banshee.Playlist/PlaylistSource.cs
   trunk/banshee/src/Core/Banshee.Services/Banshee.SmartPlaylist/Migrator.cs
   trunk/banshee/src/Core/Banshee.Services/Banshee.SmartPlaylist/SmartPlaylistSource.cs
   trunk/banshee/src/Core/Hyena/Hyena.Data.Query/QueryField.cs
   trunk/banshee/src/Core/Hyena/Hyena.Data.Query/QueryFieldSet.cs
   trunk/banshee/src/Core/Hyena/Hyena.Data.Query/QueryListNode.cs
   trunk/banshee/src/Core/Hyena/Hyena.Data.Query/QueryParser.cs
   trunk/banshee/src/Core/Hyena/Hyena.Data.Query/QueryTermNode.cs
   trunk/banshee/src/Core/Hyena/Hyena.Data.Query/UserQueryParser.cs
   trunk/banshee/src/Core/Hyena/Hyena.Data.Query/XmlQueryParser.cs
   trunk/banshee/src/Core/Hyena/Makefile.am

Modified: trunk/banshee/src/Core/Banshee.Core/Banshee.Base/Utilities.cs
==============================================================================
--- trunk/banshee/src/Core/Banshee.Core/Banshee.Base/Utilities.cs	(original)
+++ trunk/banshee/src/Core/Banshee.Core/Banshee.Base/Utilities.cs	Fri Jan 25 01:18:35 2008
@@ -118,66 +118,7 @@
             return (Type [])InvokeMethod (assembly, typeName, "GetTypes");
         }
     }
-    
-    public class DateTimeUtil
-    {
-        public static readonly DateTime LocalUnixEpoch = new DateTime (1970, 1, 1).ToLocalTime ();
-
-        public static DateTime ToDateTime (long time)
-        {
-            return FromTimeT (time);
-        }
-
-        public static long FromDateTime (DateTime time)
-        {
-            return ToTimeT (time);
-        }
-
-        public static DateTime FromTimeT (long time)
-        {
-            return LocalUnixEpoch.AddSeconds (time);
-        }
-
-        public static long ToTimeT (DateTime time)
-        {
-            return (long)time.Subtract (LocalUnixEpoch).TotalSeconds;
-        }
-
-        public static string FormatDuration (long time) {
-            return (time > 3600 ? 
-                    String.Format ("{0}:{1:00}:{2:00}", time / 3600, (time / 60) % 60, time % 60) :
-                    String.Format ("{0}:{1:00}", time / 60, time % 60));
-        }
-    }
 
-    public class Timer : IDisposable
-    {
-        private DateTime start;
-        private string label;
-        
-        public Timer (string label) 
-        {
-            this.label = label;
-            start = DateTime.Now;
-        }
-
-        public TimeSpan ElapsedTime {
-            get {
-                return DateTime.Now - start;
-            }
-        }
-
-        public void WriteElapsed (string message)
-        {
-            Console.WriteLine ("{0} {1} {2}", label, message, ElapsedTime);
-        }
-
-        public void Dispose ()
-        {
-            WriteElapsed ("timer stopped:");
-        }
-    }
-    
     public static class ThreadAssist
     {
         private static Thread main_thread;

Modified: trunk/banshee/src/Core/Banshee.Services/Banshee.Collection.Database/LibraryAlbumInfo.cs
==============================================================================
--- trunk/banshee/src/Core/Banshee.Services/Banshee.Collection.Database/LibraryAlbumInfo.cs	(original)
+++ trunk/banshee/src/Core/Banshee.Services/Banshee.Collection.Database/LibraryAlbumInfo.cs	Fri Jan 25 01:18:35 2008
@@ -73,7 +73,6 @@
                     Title = reader[(int) Column.Title] as string;
                     ArtistName = artist.Name;
                 } else {
-                    dbid = -1;
                     artist_id = artist.DbId;
                     Title = title;
                     Save ();

Modified: trunk/banshee/src/Core/Banshee.Services/Banshee.Collection.Database/LibraryArtistInfo.cs
==============================================================================
--- trunk/banshee/src/Core/Banshee.Services/Banshee.Collection.Database/LibraryArtistInfo.cs	(original)
+++ trunk/banshee/src/Core/Banshee.Services/Banshee.Collection.Database/LibraryArtistInfo.cs	Fri Jan 25 01:18:35 2008
@@ -66,17 +66,14 @@
             if (artistName == null || artistName.Trim () == String.Empty)
                 artistName = Catalog.GetString ("Unknown Artist");
 
-            IDataReader reader = ServiceManager.DbConnection.ExecuteReader (select_command.ApplyValues (artistName));
-
-            if (reader.Read ()) {
-                LoadFromReader (reader);
-            } else {
-                dbid = -1;
-                Name = artistName;
-                Save ();
+            using (IDataReader reader = ServiceManager.DbConnection.ExecuteReader (select_command.ApplyValues (artistName))) {
+                if (reader.Read ()) {
+                    LoadFromReader (reader);
+                } else {
+                    Name = artistName;
+                    Save ();
+                }
             }
-
-            reader.Dispose ();
         }
 
         public LibraryArtistInfo(IDataReader reader) : base(null)

Modified: trunk/banshee/src/Core/Banshee.Services/Banshee.Collection.Database/LibraryTrackInfo.cs
==============================================================================
--- trunk/banshee/src/Core/Banshee.Services/Banshee.Collection.Database/LibraryTrackInfo.cs	(original)
+++ trunk/banshee/src/Core/Banshee.Services/Banshee.Collection.Database/LibraryTrackInfo.cs	Fri Jan 25 01:18:35 2008
@@ -29,6 +29,7 @@
 using System;
 using System.Data;
 
+using Hyena;
 using Hyena.Data.Sqlite;
 
 using Banshee.Base;

Modified: trunk/banshee/src/Core/Banshee.Services/Banshee.Collection.Database/TrackListDatabaseModel.cs
==============================================================================
--- trunk/banshee/src/Core/Banshee.Services/Banshee.Collection.Database/TrackListDatabaseModel.cs	(original)
+++ trunk/banshee/src/Core/Banshee.Services/Banshee.Collection.Database/TrackListDatabaseModel.cs	Fri Jan 25 01:18:35 2008
@@ -78,7 +78,7 @@
                 filter_query = null;
             } else {
                 Hyena.Data.Query.UserQueryParser qp = new UserQueryParser (Filter);
-                QueryNode n = qp.BuildTree ();
+                QueryNode n = qp.BuildTree (field_set);
 
                 filter_query = n.ToSql (field_set);
 
@@ -88,7 +88,7 @@
                 Console.WriteLine ("Xml for Query: {0}", n.ToXml (field_set));
                 Console.WriteLine ("Sql for Query: {0}", filter_query);
                 Hyena.Data.Query.QueryParser qp2 = new XmlQueryParser (n.ToXml (field_set));
-                QueryNode n2 = qp2.BuildTree ();
+                QueryNode n2 = qp2.BuildTree (field_set);
                 if (n2 != null) {
                     Console.WriteLine ("User query for Xml: {0}", n2.ToUserQuery ());
                 } else
@@ -253,7 +253,7 @@
         public override int IndexOf (TrackInfo track)
         {
             LibraryTrackInfo library_track = track as LibraryTrackInfo;
-            return library_track == null ? -1 : cache.IndexOf (library_track.DbId);
+            return library_track == null ? -1 : cache.IndexOf ((int)library_track.DbId);
         }
 
         public override TrackInfo this[int index] {
@@ -393,80 +393,80 @@
 
         protected static QueryFieldSet field_set = new QueryFieldSet (
             new QueryField (
-                "artist", Catalog.GetString ("Artist"), "CoreArtists.Name", QueryFieldType.Text, true,
+                "artist", Catalog.GetString ("Artist"), "CoreArtists.Name", true,
                 // Translators: These are unique search fields.  Please, no spaces. Blank ok.
                 Catalog.GetString ("by"), Catalog.GetString ("artist"), Catalog.GetString ("artists"),
                 "by", "artist", "artists"
             ),
             new QueryField (
-                "album", Catalog.GetString ("Album"), "CoreAlbums.Title", QueryFieldType.Text, true,
+                "album", Catalog.GetString ("Album"), "CoreAlbums.Title", true,
                 // Translators: These are unique search fields.  Please, no spaces. Blank ok.
                 Catalog.GetString ("on"), Catalog.GetString ("album"), Catalog.GetString ("from"),
                 "on", "album", "from", "albumtitle"
             ),
             new QueryField (
-                "title", Catalog.GetString ("Track Title"), "CoreTracks.Title", QueryFieldType.Text, true,
+                "title", Catalog.GetString ("Track Title"), "CoreTracks.Title", true,
                 // Translators: These are unique search fields.  Please, no spaces. Blank ok.
                 Catalog.GetString ("title"), Catalog.GetString ("titled"), Catalog.GetString ("name"), Catalog.GetString ("named"),
                 "title", "titled", "name", "named"
             ),
             new QueryField (
-                "year", Catalog.GetString ("Year"), "CoreTracks.Year", QueryFieldType.Numeric,
+                "year", Catalog.GetString ("Year"), "CoreTracks.Year", typeof(IntegerQueryValue),
                 // Translators: These are unique search fields.  Please, no spaces. Blank ok.
                 Catalog.GetString ("year"), Catalog.GetString ("released"), Catalog.GetString ("yr"),
                 "year", "released", "yr"
             ),
             new QueryField (
-                "rating", Catalog.GetString ("Rating"), "CoreTracks.Rating", QueryFieldType.Numeric,
+                "rating", Catalog.GetString ("Rating"), "CoreTracks.Rating", typeof(IntegerQueryValue),
                 // Translators: These are unique search fields.  Please, no spaces. Blank ok.
                 Catalog.GetString ("rating"), Catalog.GetString ("stars"),
                 "rating", "stars"
             ),
             new QueryField (
-                "playcount", Catalog.GetString ("Play Count"), "CoreTracks.PlayCount", QueryFieldType.Numeric,
+                "playcount", Catalog.GetString ("Play Count"), "CoreTracks.PlayCount", typeof(IntegerQueryValue),
                 // Translators: These are unique search fields.  Please, no spaces. Blank ok.
                 Catalog.GetString ("plays"), Catalog.GetString ("playcount"), Catalog.GetString ("listens"),
                 "plays", "playcount", "numberofplays", "listens"
             ),
             new QueryField (
-                "skipcount", Catalog.GetString ("Skip Count"), "CoreTracks.SkipCount", QueryFieldType.Numeric,
+                "skipcount", Catalog.GetString ("Skip Count"), "CoreTracks.SkipCount", typeof(IntegerQueryValue),
                 // Translators: These are unique search fields.  Please, no spaces. Blank ok.
                 Catalog.GetString ("skips"), Catalog.GetString ("skipcount"),
                 "skips", "skipcount"
             ),
             new QueryField (
-                "filesize", Catalog.GetString ("File Size"), "CoreTracks.FileSize", QueryFieldType.Numeric, FileSizeModifier,
+                "filesize", Catalog.GetString ("File Size"), "CoreTracks.FileSize", typeof(FileSizeQueryValue),
                 // Translators: These are unique search fields.  Please, no spaces. Blank ok.
                 Catalog.GetString ("size"), Catalog.GetString ("filesize"),
                 "size", "filesize"
             ),
             new QueryField (
-                "uri", Catalog.GetString ("File Path"), "CoreTracks.Uri", QueryFieldType.Text,
+                "uri", Catalog.GetString ("File Path"), "CoreTracks.Uri",
                 // Translators: These are unique search fields.  Please, no spaces. Blank ok.
                 Catalog.GetString ("uri"), Catalog.GetString ("path"), Catalog.GetString ("file"), Catalog.GetString ("location"),
                 "uri", "path", "file", "location"
             ),
             new QueryField (
-                "duration", Catalog.GetString ("Duration"), "CoreTracks.Duration", QueryFieldType.Numeric,
+                "duration", Catalog.GetString ("Duration"), "CoreTracks.Duration", typeof(IntegerQueryValue),
                 // Translators: These are unique search fields.  Please, no spaces. Blank ok.
                 Catalog.GetString ("duration"), Catalog.GetString ("length"), Catalog.GetString ("time"),
                 "duration", "length", "time"
             ),
             new QueryField (
-                "mimetype", Catalog.GetString ("Mime Type"), "CoreTracks.MimeType {0} OR CoreTracks.Uri {0}", QueryFieldType.Text,
+                "mimetype", Catalog.GetString ("Mime Type"), "CoreTracks.MimeType {0} OR CoreTracks.Uri {0}",
                 // Translators: These are unique search fields.  Please, no spaces. Blank ok.
                 Catalog.GetString ("type"), Catalog.GetString ("mimetype"), Catalog.GetString ("format"), Catalog.GetString ("ext"),
                 "type", "mimetype", "format", "ext", "mime"
             ),
             new QueryField (
                     // (strftime("%s", current_timestamp) - DateAddedStamp + 3600)
-                "lastplayed", Catalog.GetString ("Last Played Date"), "CoreTracks.LastPlayedStamp", QueryFieldType.Numeric, DateTimeModifier,
+                "lastplayed", Catalog.GetString ("Last Played Date"), "CoreTracks.LastPlayedStamp", typeof(DateQueryValue),
                 // Translators: These are unique search fields.  Please, no spaces. Blank ok.
                 Catalog.GetString ("lastplayed"), Catalog.GetString ("played"), Catalog.GetString ("playedon"),
                 "lastplayed", "played", "playedon"
             ),
             new QueryField (
-                "added", Catalog.GetString ("Imported Date"), "CoreTracks.DateAddedStamp", QueryFieldType.Numeric, DateTimeModifier,
+                "added", Catalog.GetString ("Imported Date"), "CoreTracks.DateAddedStamp", typeof(DateQueryValue),
                 // Translators: These are unique search fields.  Please, no spaces. Blank ok.
                 Catalog.GetString ("added"), Catalog.GetString ("imported"), Catalog.GetString ("addedon"), Catalog.GetString ("dateadded"), Catalog.GetString ("importedon"),
                 "added", "imported", "addedon", "dateadded", "importedon"
@@ -480,40 +480,5 @@
                 "duration", "length", "time"
             )*/
         );
-        
-        private static string FileSizeModifier (string input)
-        {
-            long value = 0;
-            
-            if (input.Length < 2) {
-                return input;
-            } else if (input[input.Length - 1] == 'b' || input[input.Length - 1] == 'B') {
-                input = input.Substring (0, input.Length - 1);
-            }
-            
-            if (!Int64.TryParse (input.Substring (0, input.Length - 1), out value)) {
-                return input;
-            }
-            
-            switch (input[input.Length - 1]) {
-                case 'k': case 'K': value *= 1024; break;
-                case 'm': case 'M': value *= 1048576; break;
-                case 'g': case 'G': value *= 1073741824; break;
-                case 't': case 'T': value *= 1099511627776; break;
-                default: break;
-            }
-            
-            return Convert.ToString (value);
-        }
-        
-        private static string DateTimeModifier (string input)
-        {
-            // TODO: Add support for relative strings like "yesterday", "3 weeks ago", "5 days ago"
-            try {
-                return DateTimeUtil.ToTimeT (DateTime.Parse (input)).ToString ();
-            } catch {
-                return "0";
-            }
-        }
     }
 }

Modified: trunk/banshee/src/Core/Banshee.Services/Banshee.Database/BansheeDbFormatMigrator.cs
==============================================================================
--- trunk/banshee/src/Core/Banshee.Services/Banshee.Database/BansheeDbFormatMigrator.cs	(original)
+++ trunk/banshee/src/Core/Banshee.Services/Banshee.Database/BansheeDbFormatMigrator.cs	Fri Jan 25 01:18:35 2008
@@ -31,6 +31,8 @@
 using System.Reflection;
 using System.Threading;
 
+using Timer=Hyena.Timer;
+
 namespace Banshee.Database
 {
     public class BansheeDbFormatMigrator

Modified: trunk/banshee/src/Core/Banshee.Services/Banshee.Playlist/PlaylistSource.cs
==============================================================================
--- trunk/banshee/src/Core/Banshee.Services/Banshee.Playlist/PlaylistSource.cs	(original)
+++ trunk/banshee/src/Core/Banshee.Services/Banshee.Playlist/PlaylistSource.cs	Fri Jan 25 01:18:35 2008
@@ -202,19 +202,17 @@
         {
             List<PlaylistSource> sources = new List<PlaylistSource> ();
 
-            IDataReader reader = ServiceManager.DbConnection.ExecuteReader (
-                "SELECT PlaylistID, Name, SortColumn, SortType FROM CorePlaylists"
-            );
-            
-            while (reader.Read ()) {
-                PlaylistSource playlist = new PlaylistSource (
-                    reader[1] as string, Convert.ToInt32 (reader[0]),
-                    Convert.ToInt32 (reader[2]), Convert.ToInt32 (reader[3])
-                );
-                sources.Add (playlist);
+            using (IDataReader reader = ServiceManager.DbConnection.ExecuteReader (
+                "SELECT PlaylistID, Name, SortColumn, SortType FROM CorePlaylists")) {
+                while (reader.Read ()) {
+                    PlaylistSource playlist = new PlaylistSource (
+                        reader[1] as string, Convert.ToInt32 (reader[0]),
+                        Convert.ToInt32 (reader[2]), Convert.ToInt32 (reader[3])
+                    );
+                    sources.Add (playlist);
+                }
             }
             
-            reader.Dispose();
             return sources;
         }
     }

Modified: trunk/banshee/src/Core/Banshee.Services/Banshee.SmartPlaylist/Migrator.cs
==============================================================================
--- trunk/banshee/src/Core/Banshee.Services/Banshee.SmartPlaylist/Migrator.cs	(original)
+++ trunk/banshee/src/Core/Banshee.Services/Banshee.SmartPlaylist/Migrator.cs	Fri Jan 25 01:18:35 2008
@@ -130,8 +130,12 @@
                                 continue;
                             }
                         }
-                        term.Field = field.PrimaryAlias;
-                        term.Value = v1;
+
+                        //if (term.Field.IndexOf ("LastPlayedStamp") != -1) {
+                        //} else if (term.Field.IndexOf ("DateAddedStamp") != -1) {
+                        //}
+                        term.Field = field;
+                        term.Value = QueryValue.CreateFromUserQuery (v1, field);
                         root.AddChild (term);
 
                         switch (op.GetType ().ToString ()) {
@@ -187,10 +191,6 @@
                                 break;
                         }
 
-                        if (term.Field.IndexOf ("LastPlayedStamp") != -1) {
-                        } else if (term.Field.IndexOf ("DateAddedStamp") != -1) {
-                        }
-
                         Console.WriteLine ("..{0}\n=>{1}", condition, term.ToString ());
 
                         // Set the column

Modified: trunk/banshee/src/Core/Banshee.Services/Banshee.SmartPlaylist/SmartPlaylistSource.cs
==============================================================================
--- trunk/banshee/src/Core/Banshee.Services/Banshee.SmartPlaylist/SmartPlaylistSource.cs	(original)
+++ trunk/banshee/src/Core/Banshee.Services/Banshee.SmartPlaylist/SmartPlaylistSource.cs	Fri Jan 25 01:18:35 2008
@@ -283,21 +283,19 @@
         {
             List<SmartPlaylistSource> sources = new List<SmartPlaylistSource> ();
 
-            IDataReader reader = ServiceManager.DbConnection.ExecuteReader (
-                "SELECT SmartPlaylistID, Name, Condition, OrderBy, OrderDir, LimitNumber, LimitCriterion FROM CoreSmartPlaylists"
-            );
-            
-            while (reader.Read ()) {
-                SmartPlaylistSource playlist = new SmartPlaylistSource (
-                    Convert.ToInt32 (reader[0]), reader[1] as string,
-                    reader[2] as string, reader[3] as string,
-                    reader[4] as string, reader[5] as string,
-                    reader[6] as string
-                );
-                sources.Add (playlist);
+            using (IDataReader reader = ServiceManager.DbConnection.ExecuteReader (
+                "SELECT SmartPlaylistID, Name, Condition, OrderBy, OrderDir, LimitNumber, LimitCriterion FROM CoreSmartPlaylists")) {
+                while (reader.Read ()) {
+                    SmartPlaylistSource playlist = new SmartPlaylistSource (
+                        Convert.ToInt32 (reader[0]), reader[1] as string,
+                        reader[2] as string, reader[3] as string,
+                        reader[4] as string, reader[5] as string,
+                        reader[6] as string
+                    );
+                    sources.Add (playlist);
+                }
             }
             
-            reader.Dispose();
             return sources;
         }
 

Added: trunk/banshee/src/Core/Hyena/Hyena.Data.Query/DateQueryValue.cs
==============================================================================
--- (empty file)
+++ trunk/banshee/src/Core/Hyena/Hyena.Data.Query/DateQueryValue.cs	Fri Jan 25 01:18:35 2008
@@ -0,0 +1,97 @@
+//
+// DateQueryValue.cs
+//
+// Authors:
+//   Gabriel Burt <gburt novell com>
+//
+// Copyright (C) 2007-2008 Novell, Inc.
+//
+// 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.Xml;
+using System.Text;
+
+using Hyena;
+
+namespace Hyena.Data.Query
+{
+    public class DateQueryValue : QueryValue
+    {
+        protected DateTime value;
+        protected bool relative = false;
+        protected long offset = 0;
+
+        public override string XmlElementName {
+            get { return "date"; }
+        }
+
+        public override object Value {
+            get { return value; }
+        }
+
+        public override void ParseUserQuery (string input)
+        {
+            // TODO: Add support for relative strings like "yesterday", "3 weeks ago", "5 days ago"
+            try {
+                value = DateTime.Parse (input);
+                IsEmpty = false;
+            } catch {
+                IsEmpty = true;
+            }
+        }
+
+        public override string ToUserQuery ()
+        {
+            if (value.Hour == 0 && value.Minute == 0 && value.Second == 0) {
+                return value.ToString ("yyyy-MM-dd");
+            } else {
+                return value.ToString ();
+            }
+        }
+
+        public override void ParseXml (XmlElement node)
+        {
+            try {
+                if (node.HasAttribute ("type") && node.GetAttribute ("type") == "rel") {
+                    relative = true;
+                    offset = Convert.ToInt64 (node.InnerText);
+                } else {
+                    value = DateTime.Parse (node.InnerText);
+                }
+                IsEmpty = false;
+            } catch {
+                IsEmpty = true;
+            }
+        }
+
+        public override string ToSql ()
+        {
+            return DateTimeUtil.FromDateTime (
+                (relative ? DateTime.Now + TimeSpan.FromSeconds ((double) offset) : value)
+            ).ToString ();
+        }
+
+        public DateTime DateTime {
+            get { return value; }
+        }
+    }
+}

Added: trunk/banshee/src/Core/Hyena/Hyena.Data.Query/FileSizeQueryValue.cs
==============================================================================
--- (empty file)
+++ trunk/banshee/src/Core/Hyena/Hyena.Data.Query/FileSizeQueryValue.cs	Fri Jan 25 01:18:35 2008
@@ -0,0 +1,99 @@
+//
+// FileSizeQueryValue.cs
+//
+// Authors:
+//   Gabriel Burt <gburt novell com>
+//   Aaron Bockover <abockover novell com>
+//
+// Copyright (C) 2007-2008 Novell, Inc.
+//
+// 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.Xml;
+using System.Text;
+
+using Hyena;
+
+namespace Hyena.Data.Query
+{
+    public enum FileSizeFactor {
+        None = 1,
+        KB = 1024,
+        MB = 1048576,
+        GB = 1073741824
+    }
+
+    public class FileSizeQueryValue : IntegerQueryValue
+    {
+        private FileSizeFactor factor = FileSizeFactor.None;
+        public FileSizeFactor Factor {
+            get { return factor; }
+        }
+
+        public override void ParseUserQuery (string input)
+        {
+            if (input.Length > 1 && (input[input.Length - 1] == 'b' || input[input.Length - 1] == 'B')) {
+                input = input.Substring (0, input.Length - 1);
+            }
+
+            base.ParseUserQuery (input);
+
+            if (IsEmpty && input.Length > 1) {
+                base.ParseUserQuery (input.Substring (0, input.Length - 1));
+            }
+
+            if (!IsEmpty) {
+                switch (input[input.Length - 1]) {
+                    case 'k': case 'K': factor = FileSizeFactor.KB; break;
+                    case 'm': case 'M': factor = FileSizeFactor.MB; break;
+                    case 'g': case 'G': factor = FileSizeFactor.GB; break;
+                    default : factor = FileSizeFactor.None; break;
+                }
+                value *= (long) factor;
+            }
+        }
+
+        public override void ParseXml (XmlElement node)
+        {
+            base.ParseUserQuery (node.InnerText);
+            if (!IsEmpty && value != 0) {
+                foreach (FileSizeFactor factor in Enum.GetValues (typeof(FileSizeFactor))) {
+                    if (value >= (long) factor) {
+                        this.factor = factor;
+                    }
+                }
+            }
+        }
+
+        public override string ToUserQuery ()
+        {
+            if (factor != FileSizeFactor.None) {
+                return String.Format ("{0}{1}",
+                    IntValue == 0 ? 0 : (IntValue / (long) factor),
+                    factor.ToString ()
+                );
+            } else {
+                return base.ToUserQuery ();
+            }
+        }
+    }
+}

Added: trunk/banshee/src/Core/Hyena/Hyena.Data.Query/IntegerQueryValue.cs
==============================================================================
--- (empty file)
+++ trunk/banshee/src/Core/Hyena/Hyena.Data.Query/IntegerQueryValue.cs	Fri Jan 25 01:18:35 2008
@@ -0,0 +1,63 @@
+//
+// IntegerQueryValue.cs
+//
+// Authors:
+//   Gabriel Burt <gburt novell com>
+//
+// Copyright (C) 2007-2008 Novell, Inc.
+//
+// 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.Xml;
+using System.Text;
+
+using Hyena;
+
+namespace Hyena.Data.Query
+{
+    public class IntegerQueryValue : QueryValue
+    {
+        protected long value;
+
+        public override string XmlElementName {
+            get { return "int"; }
+        }
+
+        public override void ParseUserQuery (string input)
+        {
+            IsEmpty = !Int64.TryParse (input, out value);
+        }
+
+        public override void ParseXml (XmlElement node)
+        {
+            ParseUserQuery (node.InnerText);
+        }
+
+        public override object Value {
+            get { return value; }
+        }
+
+        public long IntValue {
+            get { return value; }
+        }
+    }
+}

Modified: trunk/banshee/src/Core/Hyena/Hyena.Data.Query/QueryField.cs
==============================================================================
--- trunk/banshee/src/Core/Hyena/Hyena.Data.Query/QueryField.cs	(original)
+++ trunk/banshee/src/Core/Hyena/Hyena.Data.Query/QueryField.cs	Fri Jan 25 01:18:35 2008
@@ -33,53 +33,67 @@
 
 namespace Hyena.Data.Query
 {
-    public enum QueryFieldType
-    {
-        Text,
-        Numeric
-    }
-
     public class QueryField
     {
-        public delegate string ModifierHandler (string input);
+        private Type value_type;
+        public Type ValueType {
+            get { return value_type; }
+        }
+
+        private string name;
+        public string Name {
+            get { return name; }
+            set { name = value; }
+        }
 
-        public string Name;
-        public string Label;
-        public string [] Aliases;
-        public string Column;
-        public bool Default;
-        public QueryFieldType QueryFieldType;
-        public ModifierHandler Modifier;
+        private string label;
+        public string Label {
+            get { return label; }
+            set { label = value; }
+        }
 
-        public QueryField (string name, string label, string column, QueryFieldType type, params string [] aliases) 
-            : this (name, label, column, type, false, null, aliases)
-        {
+        private string [] aliases;
+        public string [] Aliases {
+            get { return aliases; }
+        }
+
+        public string PrimaryAlias {
+            get { return aliases[0]; }
+        }
+
+        private string column;
+        public string Column {
+            get { return column; }
+        }
+
+        private bool is_default;
+        public bool IsDefault {
+            get { return is_default; }
         }
-        
-        public QueryField (string name, string label, string column, QueryFieldType type, ModifierHandler modifier, params string [] aliases) 
-            : this (name, label, column, type, false, modifier, aliases)
+
+        public QueryField (string name, string label, string column, params string [] aliases)
+            : this (name, label, column, false, aliases)
         {
         }
-        
-        public QueryField (string name, string label, string column, QueryFieldType type, bool isDefault, params string [] aliases)
-            : this (name, label, column, type, isDefault, null, aliases)
+
+        public QueryField (string name, string label, string column, bool isDefault, params string [] aliases)
+            : this (name, label, column, typeof(StringQueryValue), isDefault, aliases)
         {
         }
-        
-        public QueryField (string name, string label, string column, QueryFieldType type, bool isDefault, 
-            ModifierHandler modifier, params string [] aliases)
+
+        public QueryField (string name, string label, string column, Type valueType, params string [] aliases)
+            : this (name, label, column, valueType, false, aliases)
         {
-            Name = name;
-            Label = label;
-            Column = column;
-            QueryFieldType = type;
-            Default = isDefault;
-            Modifier = modifier;
-            Aliases = aliases;
         }
 
-        public string PrimaryAlias {
-            get { return Aliases [0]; }
+        public QueryField (string name, string label, string column, Type valueType, bool isDefault, params string [] aliases)
+        {
+            this.name = name;
+            this.label = label;
+            this.column = column;
+            this.value_type = valueType;
+            this.is_default = isDefault;
+            this.aliases = aliases;
         }
 
         public string ToTermString (string op, string value)

Modified: trunk/banshee/src/Core/Hyena/Hyena.Data.Query/QueryFieldSet.cs
==============================================================================
--- trunk/banshee/src/Core/Hyena/Hyena.Data.Query/QueryFieldSet.cs	(original)
+++ trunk/banshee/src/Core/Hyena/Hyena.Data.Query/QueryFieldSet.cs	Fri Jan 25 01:18:35 2008
@@ -59,5 +59,9 @@
                 return map[alias.ToLower ()];
             return null;
         }
+
+        public QueryField this [string alias] {
+            get { return GetByAlias (alias); }
+        }
     }
 }

Modified: trunk/banshee/src/Core/Hyena/Hyena.Data.Query/QueryListNode.cs
==============================================================================
--- trunk/banshee/src/Core/Hyena/Hyena.Data.Query/QueryListNode.cs	(original)
+++ trunk/banshee/src/Core/Hyena/Hyena.Data.Query/QueryListNode.cs	Fri Jan 25 01:18:35 2008
@@ -137,8 +137,13 @@
                 child.Trim ();
 
             if (Keyword == Keyword.Not) {
-                if (ChildCount != 1)
-                    Parent.RemoveChild (this);
+                if (ChildCount != 1) {
+                    if (Parent != null) {
+                        Parent.RemoveChild (this);
+                    } else {
+                        return null;
+                    }
+                }
             } else {
                 if (ChildCount <= 1) {
                     if (Parent != null) {

Added: trunk/banshee/src/Core/Hyena/Hyena.Data.Query/QueryOperator.cs
==============================================================================
--- (empty file)
+++ trunk/banshee/src/Core/Hyena/Hyena.Data.Query/QueryOperator.cs	Fri Jan 25 01:18:35 2008
@@ -0,0 +1,91 @@
+//
+// QueryOperator.cs
+//
+// Author:
+//   Aaron Bockover <abockover novell com>
+//   Gabriel Burt <gburt novell com>
+//
+// Copyright (C) 2007-2008 Novell, Inc.
+//
+// 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.Xml;
+using System.Text;
+using System.Collections.Generic;
+
+namespace Hyena.Data.Query
+{
+    public class Operator
+    {
+        public string Name;
+        public string UserOperator;
+        
+        private static List<Operator> operators = new List<Operator> ();
+        private static Dictionary<string, Operator> by_op = new Dictionary<string, Operator> ();
+        private static Dictionary<string, Operator> by_name = new Dictionary<string, Operator> ();
+
+        protected Operator (string name, string userOp)
+        {
+            Name = name;
+            UserOperator = userOp;
+        }
+
+        static Operator () {
+            // Note, order of these is important since if = was before ==, the value of the
+            // term would start with the second =, etc.
+            Add (new Operator ("equals", "=="));
+            Add (new Operator ("lessThanEquals", "<="));
+            Add (new Operator ("greaterThanEquals", ">="));
+            //Add (new Operator ("notEqual", "!="));
+            Add (new Operator ("startsWith", "="));
+            //Add (new Operator ("doesNotContain", "!:"));
+            Add (new Operator ("contains", ":"));
+            Add (new Operator ("lessThan", "<"));
+            Add (new Operator ("greaterThan", ">"));
+        }
+
+        public static IEnumerable<Operator> Operators {
+            get { return operators; }
+        }
+
+        private static void Add (Operator op)
+        {
+            operators.Add (op);
+            by_op.Add (op.UserOperator, op);
+            by_name.Add (op.Name, op);
+        }
+
+        public static Operator GetByUserOperator (string op)
+        {
+            return (by_op.ContainsKey (op)) ? by_op [op] : null;
+        }
+
+        public static Operator GetByName (string name)
+        {
+            return (by_name.ContainsKey (name)) ? by_name [name] : null;
+        }
+
+        public static Operator Default {
+            get { return Operator.GetByUserOperator (":"); }
+        }
+    }
+}

Modified: trunk/banshee/src/Core/Hyena/Hyena.Data.Query/QueryParser.cs
==============================================================================
--- trunk/banshee/src/Core/Hyena/Hyena.Data.Query/QueryParser.cs	(original)
+++ trunk/banshee/src/Core/Hyena/Hyena.Data.Query/QueryParser.cs	Fri Jan 25 01:18:35 2008
@@ -55,7 +55,7 @@
             InputReader = reader;
         }
 
-        public abstract QueryNode BuildTree ();
+        public abstract QueryNode BuildTree (QueryFieldSet fieldSet);
         public abstract void Reset ();
         
         public StreamReader InputReader {

Modified: trunk/banshee/src/Core/Hyena/Hyena.Data.Query/QueryTermNode.cs
==============================================================================
--- trunk/banshee/src/Core/Hyena/Hyena.Data.Query/QueryTermNode.cs	(original)
+++ trunk/banshee/src/Core/Hyena/Hyena.Data.Query/QueryTermNode.cs	Fri Jan 25 01:18:35 2008
@@ -34,107 +34,50 @@
 
 namespace Hyena.Data.Query
 {
-    public class Operator
-    {
-        public string Name;
-        public string UserOperator;
-        
-        private static List<Operator> operators = new List<Operator> ();
-        private static Dictionary<string, Operator> by_op = new Dictionary<string, Operator> ();
-        private static Dictionary<string, Operator> by_name = new Dictionary<string, Operator> ();
-
-        static Operator () {
-            // Note, order of these is important since if = was before ==, the value of the
-            // term would start with the second =, etc.
-            Add (new Operator ("equals", "=="));
-            Add (new Operator ("lessThanEquals", "<="));
-            Add (new Operator ("greaterThanEquals", ">="));
-            //Add (new Operator ("notEqual", "!="));
-            Add (new Operator ("startsWith", "="));
-            //Add (new Operator ("doesNotContain", "!:"));
-            Add (new Operator ("contains", ":"));
-            Add (new Operator ("lessThan", "<"));
-            Add (new Operator ("greaterThan", ">"));
-        }
-
-        public static IEnumerable<Operator> Operators {
-            get { return operators; }
-        }
-
-        private static void Add (Operator op)
-        {
-            operators.Add (op);
-            by_op.Add (op.UserOperator, op);
-            by_name.Add (op.Name, op);
-        }
-
-        public static Operator GetByUserOperator (string op)
-        {
-            return (by_op.ContainsKey (op)) ? by_op [op] : null;
-        }
-
-        public static Operator GetByName (string name)
-        {
-            return (by_name.ContainsKey (name)) ? by_name [name] : null;
-        }
-
-        public static Operator DefaultOperator {
-            get { return Operator.GetByUserOperator (":"); }
-        }
-
-        public Operator (string name, string userOp)
-        {
-            Name = name;
-            UserOperator = userOp;
-        }
-    }
-
     public class QueryTermNode : QueryNode
     {
-        private string field;
-        private string field_value;
-        private Operator op;
+        private QueryField field;
+        private Operator op = Operator.Default;
+        private QueryValue qvalue;
 
-        //private static string [] operators = new string [] {":", "==", "<=", ">=", "=", "<", ">"};
-
-        public QueryTermNode () : base ()
-        {
-            // Set default operator
-            op = Operator.DefaultOperator;
-        }
-
-        public QueryTermNode (string value) : base ()
+        public static QueryTermNode ParseUserQuery (QueryFieldSet field_set, string token)
         {
+            QueryTermNode node = new QueryTermNode ();
             int field_separator = 0;
             foreach (Operator op in Operator.Operators) {
-                field_separator = value.IndexOf (op.UserOperator);
+                field_separator = token.IndexOf (op.UserOperator);
                 if (field_separator != -1) {
-                    this.op = op;
+                    node.Operator = op;
                     break;
                 }
             }
 
             if (field_separator > 0) {
-                Field = value.Substring (0, field_separator);
-                Value = value.Substring (field_separator + op.UserOperator.Length);
-            } else {
-                this.field_value = value;
-                this.op = Operator.DefaultOperator;
+                node.Field = field_set[token.Substring (0, field_separator)];
+                if (node.Field != null) {
+                    token = token.Substring (field_separator + node.Operator.UserOperator.Length);
+                }
             }
+
+            node.Value = QueryValue.CreateFromUserQuery (token, node.Field);
+
+            return node;
+        }
+
+        public QueryTermNode () : base ()
+        {
         }
 
         public override QueryNode Trim ()
         {
-            if ((field_value == null || field_value == String.Empty) && Parent != null)
+            if ((qvalue == null || qvalue.IsEmpty) && Parent != null)
                 Parent.RemoveChild (this);
             return this;
         }
         
         public override void AppendUserQuery (StringBuilder sb)
         {
-            sb.Append (
-                QueryField.ToTermString (Field, Operator.UserOperator, Value)
-            );
+            sb.Append (Field == null ? Value.ToUserQuery () : Field.ToTermString (Operator.UserOperator, Value.ToUserQuery ()));
         }
 
         public override void AppendXml (XmlDocument doc, XmlNode parent, QueryFieldSet fieldSet)
@@ -142,49 +85,51 @@
             XmlElement op_node = doc.CreateElement (op.Name);
             parent.AppendChild (op_node);
 
-            QueryField field = fieldSet.GetByAlias (Field);
+            QueryField field = Field;
             if (field != null) {
                 XmlElement field_node = doc.CreateElement ("field");
                 field_node.SetAttribute ("name", field.Name);
                 op_node.AppendChild (field_node);
             }
 
-            XmlElement val_node = doc.CreateElement ("string");
-            val_node.InnerText = Value;
+            XmlElement val_node = doc.CreateElement (Value.XmlElementName);
+            Value.AppendXml (val_node);
             op_node.AppendChild (val_node);
         }
 
         public override void AppendSql (StringBuilder sb, QueryFieldSet fieldSet)
         {
-            string alias = Field;
-            
-            if (fieldSet.GetByAlias (alias) == null) {
+            if (Field == null) {
                 sb.Append ("(");
-                int emitted = 0, i = 0;
+                int emitted = 0;
                 
                 foreach (QueryField field in fieldSet.Fields) {
-                    if (field.Default)
+                    if (field.IsDefault)
                         if (EmitTermMatch (sb, field, emitted > 0))
                             emitted++;
                 }
                 
                 sb.Append (")");
             } else {
-                EmitTermMatch (sb, fieldSet.GetByAlias (alias), false);
+                EmitTermMatch (sb, Field, false);
             }
         }
 
         private bool EmitTermMatch (StringBuilder sb, QueryField field, bool emit_or)
         {
-            if (field.QueryFieldType == QueryFieldType.Text)
+            if (Value.IsEmpty)
+                return false;
+
+            if (field.ValueType == typeof(StringQueryValue)) {
                 return EmitStringMatch (sb, field, emit_or);
-            else
+            } else {
                 return EmitNumericMatch (sb, field, emit_or);
+            }
         }
 
         private bool EmitStringMatch (StringBuilder sb, QueryField field, bool emit_or)
         {
-            string safe_value = (field.Modifier == null ? Value : field.Modifier (Value)).Replace("'", "''");
+            string safe_value = Value.ToSql ().Replace("'", "''");
             
             if (emit_or)
                 sb.Append (" OR ");
@@ -217,12 +162,6 @@
 
         private bool EmitNumericMatch (StringBuilder sb, QueryField field, bool emit_or)
         {
-            long num = 0;
-            
-            if (!Int64.TryParse (field.Modifier == null ? Value : field.Modifier (Value), out num)) {
-                return false;
-            }
-            
             if (emit_or) {
                 sb.Append (" OR ");
             }
@@ -231,18 +170,18 @@
                 case ":":
                 case "=":
                 case "==":
-                    sb.Append (field.FormatSql ("= {0}", num));
+                    sb.Append (field.FormatSql ("= {0}", Value.ToSql ()));
                     break;
 
                 default:
-                    sb.Append (field.FormatSql ("{1} {0}", num, Operator.UserOperator));
+                    sb.Append (field.FormatSql ("{1} {0}", Value.ToSql (), Operator.UserOperator));
                     break;
             }
             
             return true;
         }
         
-        public string Field {
+        public QueryField Field {
             get { return field; }
             set { field = value; }
         }
@@ -252,9 +191,9 @@
             set { op = value; }
         }
         
-        public string Value {
-            get { return field_value; }
-            set { field_value = value; }
+        public QueryValue Value {
+            get { return qvalue; }
+            set { qvalue = value; }
         }
     }
 }

Added: trunk/banshee/src/Core/Hyena/Hyena.Data.Query/QueryValue.cs
==============================================================================
--- (empty file)
+++ trunk/banshee/src/Core/Hyena/Hyena.Data.Query/QueryValue.cs	Fri Jan 25 01:18:35 2008
@@ -0,0 +1,101 @@
+//
+// QueryValue.cs
+//
+// Authors:
+//   Gabriel Burt <gburt novell com>
+//
+// Copyright (C) 2007-2008 Novell, Inc.
+//
+// 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.Xml;
+using System.Text;
+
+using Hyena;
+
+namespace Hyena.Data.Query
+{
+    public abstract class QueryValue
+    {
+        private static Type [] subtypes = new Type [] {typeof(StringQueryValue), typeof(IntegerQueryValue), typeof(FileSizeQueryValue), typeof(DateQueryValue)};
+
+        public static QueryValue CreateFromUserQuery (string input, QueryField field)
+        {
+            QueryValue val = (field == null) ? new StringQueryValue () : Activator.CreateInstance (field.ValueType) as QueryValue;
+            val.ParseUserQuery (input);
+            return val;
+        }
+
+        public static QueryValue CreateFromXml (XmlElement parent, QueryField field)
+        {
+            if (field != null) {
+                QueryValue val = Activator.CreateInstance (field.ValueType) as QueryValue;
+                return CreateFromXml (val, parent) ? val : null;
+            } else {
+                foreach (Type subtype in subtypes) {
+                    QueryValue val = Activator.CreateInstance (subtype) as QueryValue;
+                    if (CreateFromXml (val, parent)) {
+                        return val;
+                    }
+                }
+            }
+            return null;
+        }
+
+        private static bool CreateFromXml (QueryValue val, XmlElement parent)
+        {
+            XmlElement val_node = parent[val.XmlElementName];
+            if (val_node != null) {
+                val.ParseXml (val_node);
+                return !val.IsEmpty;
+            }
+            return false;
+        }
+
+        private bool is_empty = true;
+        public bool IsEmpty {
+            get { return is_empty; }
+            protected set { is_empty = value; }
+        }
+
+        public abstract object Value { get; }
+        public abstract string XmlElementName { get; }
+
+        public virtual void AppendXml (XmlElement node)
+        {
+            node.InnerText = Value.ToString ();
+        }
+
+        public virtual string ToUserQuery ()
+        {
+            return Value.ToString ();
+        }
+
+        public virtual string ToSql ()
+        {
+            return Value.ToString ();
+        }
+
+        public abstract void ParseUserQuery (string input);
+        public abstract void ParseXml (XmlElement node);
+    }
+}

Added: trunk/banshee/src/Core/Hyena/Hyena.Data.Query/StringQueryValue.cs
==============================================================================
--- (empty file)
+++ trunk/banshee/src/Core/Hyena/Hyena.Data.Query/StringQueryValue.cs	Fri Jan 25 01:18:35 2008
@@ -0,0 +1,61 @@
+//
+// StringQueryValue.cs
+//
+// Authors:
+//   Gabriel Burt <gburt novell com>
+//
+// Copyright (C) 2007-2008 Novell, Inc.
+//
+// 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.Xml;
+using System.Text;
+
+using Hyena;
+
+namespace Hyena.Data.Query
+{
+    public class StringQueryValue : QueryValue
+    {
+        protected string value;
+
+        public override string XmlElementName {
+            get { return "string"; }
+        }
+
+        public override object Value {
+            get { return value; }
+        }
+
+        public override void ParseUserQuery (string input)
+        {
+            value = input;
+            IsEmpty = String.IsNullOrEmpty (value);
+        }
+
+        public override void ParseXml (XmlElement node)
+        {
+            value = node.InnerText;
+            IsEmpty = String.IsNullOrEmpty (value);
+        }
+    }
+}

Modified: trunk/banshee/src/Core/Hyena/Hyena.Data.Query/UserQueryParser.cs
==============================================================================
--- trunk/banshee/src/Core/Hyena/Hyena.Data.Query/UserQueryParser.cs	(original)
+++ trunk/banshee/src/Core/Hyena/Hyena.Data.Query/UserQueryParser.cs	Fri Jan 25 01:18:35 2008
@@ -44,14 +44,17 @@
         private int token_start_line;
         private bool eos_consumed;
 
+        private QueryListNode root;
+        private QueryFieldSet field_set;
+
         public UserQueryParser () : base () {}
         public UserQueryParser (string inputQuery) : base (inputQuery) {}
         public UserQueryParser (Stream stream) : base (stream) {}
         public UserQueryParser (StreamReader reader) : base (reader) {}
 
-        QueryListNode root;
-        public override QueryNode BuildTree ()
+        public override QueryNode BuildTree (QueryFieldSet fieldSet)
         {
+            field_set = fieldSet;
             root = current_parent = new QueryListNode (Keyword.And);
             bool last_was_term = false;
             
@@ -145,7 +148,7 @@
                     break;
 
                 case TokenID.Term:
-                    NodePush (new QueryTermNode (token.Term));
+                    NodePush (QueryTermNode.ParseUserQuery (field_set, token.Term));
                     break;
             }
         }
@@ -203,6 +206,8 @@
             }
         }
 
+        // TODO: Allow white space before/after term operators
+
         private bool IsStringTerminationChar (char ch, bool allow_whitespace)
         {
             return (!allow_whitespace && Char.IsWhiteSpace (ch)) || ch == '(' || ch == ')' || ch == '|' || ch == ',';
@@ -216,13 +221,10 @@
             while (true) {
                 if (IsStringTerminationChar (peek, in_string)) {
                     break;
-                } else if (!in_string && peek == '"') {
-                    in_string = true;
-                } else if (in_string && peek == '"') {
-                    in_string = false;
+                } else if (peek == '"') {
+                    in_string = !in_string;
                 } else {
                     buffer.Append (peek);
-                    
                     if (reader.EndOfStream) {
                         break;
                     }

Modified: trunk/banshee/src/Core/Hyena/Hyena.Data.Query/XmlQueryParser.cs
==============================================================================
--- trunk/banshee/src/Core/Hyena/Hyena.Data.Query/XmlQueryParser.cs	(original)
+++ trunk/banshee/src/Core/Hyena/Hyena.Data.Query/XmlQueryParser.cs	Fri Jan 25 01:18:35 2008
@@ -36,15 +36,18 @@
     public class XmlQueryParser : QueryParser
     {
         private string str;
+        private QueryFieldSet field_set;
 
         public XmlQueryParser () : base () {}
+
         public XmlQueryParser (string str)
         {
             this.str = str;
         }
 
-        public override QueryNode BuildTree ()
+        public override QueryNode BuildTree (QueryFieldSet fieldSet)
         {
+            field_set = fieldSet;
             XmlDocument doc = new XmlDocument ();
             try {
                 doc.LoadXml (str);
@@ -70,7 +73,7 @@
                 return null;
 
             QueryListNode list = null;
-            Console.WriteLine ("Parsing node: {0}", node.Name);
+            //Console.WriteLine ("Parsing node: {0}", node.Name);
             switch (node.Name.ToLower ()) {
                 case "and":
                     list = new QueryListNode (Keyword.And);
@@ -83,16 +86,21 @@
                     break;
                 default:
                     QueryTermNode term = new QueryTermNode ();
+
+                    // Get the operator from the term's name
                     term.Operator = Operator.GetByName (node.Name);
 
+                    // Get the field (if any) that this term applies to
                     if (node["field"] != null)
-                        term.Field = node["field"].GetAttribute ("name");
+                        term.Field = field_set [node["field"].GetAttribute ("name")];
 
-                    if (node["string"] != null)
-                        term.Value = node["string"].InnerText;
+                    // Get the value
+                    term.Value = QueryValue.CreateFromXml (node, term.Field);
 
-                    if (parent != null)
+                    if (parent != null) {
                         parent.AddChild (term);
+                    }
+
                     return term;
             }
 
@@ -100,6 +108,7 @@
                 if (parent != null)
                     parent.AddChild (list);
 
+                // Recursively parse the children of a QueryListNode
                 foreach (XmlNode child in node.ChildNodes) {
                     Parse (child as XmlElement, list);
                 }

Added: trunk/banshee/src/Core/Hyena/Hyena/Timer.cs
==============================================================================
--- (empty file)
+++ trunk/banshee/src/Core/Hyena/Hyena/Timer.cs	Fri Jan 25 01:18:35 2008
@@ -0,0 +1,58 @@
+//
+// Timer.cs
+//
+// Author:
+//   Aaron Bockover <abockover novell com>
+//
+// Copyright (C) 2007 Novell, Inc.
+//
+// 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;
+
+namespace Hyena
+{
+    public class Timer : IDisposable
+    {
+        private DateTime start;
+        private string label;
+        
+        public Timer (string label) 
+        {
+            this.label = label;
+            start = DateTime.Now;
+        }
+
+        public TimeSpan ElapsedTime {
+            get { return DateTime.Now - start; }
+        }
+
+        public void WriteElapsed (string message)
+        {
+            Console.WriteLine ("{0} {1} {2}", label, message, ElapsedTime);
+        }
+
+        public void Dispose ()
+        {
+            WriteElapsed ("timer stopped:");
+        }
+    }
+}

Added: trunk/banshee/src/Core/Hyena/Hyena/Utilities.cs
==============================================================================
--- (empty file)
+++ trunk/banshee/src/Core/Hyena/Hyena/Utilities.cs	Fri Jan 25 01:18:35 2008
@@ -0,0 +1,63 @@
+//
+// Utilities.cs
+//
+// Author:
+//   Aaron Bockover <abockover novell com>
+//
+// Copyright (C) 2007 Novell, Inc.
+//
+// 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;
+
+namespace Hyena
+{
+    public class DateTimeUtil
+    {
+        public static readonly DateTime LocalUnixEpoch = new DateTime (1970, 1, 1).ToLocalTime ();
+
+        public static DateTime ToDateTime (long time)
+        {
+            return FromTimeT (time);
+        }
+
+        public static long FromDateTime (DateTime time)
+        {
+            return ToTimeT (time);
+        }
+
+        public static DateTime FromTimeT (long time)
+        {
+            return LocalUnixEpoch.AddSeconds (time);
+        }
+
+        public static long ToTimeT (DateTime time)
+        {
+            return (long)time.Subtract (LocalUnixEpoch).TotalSeconds;
+        }
+
+        public static string FormatDuration (long time) {
+            return (time > 3600 ? 
+                    String.Format ("{0}:{1:00}:{2:00}", time / 3600, (time / 60) % 60, time % 60) :
+                    String.Format ("{0}:{1:00}", time / 60, time % 60));
+        }
+    }
+}

Modified: trunk/banshee/src/Core/Hyena/Makefile.am
==============================================================================
--- trunk/banshee/src/Core/Hyena/Makefile.am	(original)
+++ trunk/banshee/src/Core/Hyena/Makefile.am	Fri Jan 25 01:18:35 2008
@@ -12,13 +12,19 @@
 	Hyena.CommandLine/LayoutGroup.cs \
 	Hyena.CommandLine/LayoutGroupAttribute.cs \
 	Hyena.CommandLine/LayoutOption.cs \
+	Hyena.Data.Query/DateQueryValue.cs \
+	Hyena.Data.Query/FileSizeQueryValue.cs \
+	Hyena.Data.Query/IntegerQueryValue.cs \
 	Hyena.Data.Query/QueryField.cs \
 	Hyena.Data.Query/QueryFieldSet.cs \
 	Hyena.Data.Query/QueryListNode.cs \
 	Hyena.Data.Query/QueryNode.cs \
+	Hyena.Data.Query/QueryOperator.cs \
 	Hyena.Data.Query/QueryParser.cs \
 	Hyena.Data.Query/QueryTermNode.cs \
 	Hyena.Data.Query/QueryToken.cs \
+	Hyena.Data.Query/QueryValue.cs \
+	Hyena.Data.Query/StringQueryValue.cs \
 	Hyena.Data.Query/UserQueryParser.cs \
 	Hyena.Data.Query/XmlQueryParser.cs \
 	Hyena.Data.Sqlite/DatabaseColumn.cs \
@@ -41,8 +47,9 @@
 	Hyena.Data/PropertyStore.cs \
 	Hyena.Data/SortType.cs \
 	Hyena/IUndoAction.cs \
+	Hyena/Timer.cs \
 	Hyena/UndoManager.cs \
-	Timer.cs
+	Hyena/Utilities.cs
 
 include $(top_srcdir)/build/build.mk
 



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]